Metadata-Version: 2.4
Name: pdfunlock-cli
Version: 1.0.0
Summary: Remove password protection from PDF files you own, given the correct password.
Project-URL: Homepage, https://github.com/akurathisasidhar/pdfunlock
Project-URL: Issues, https://github.com/akurathisasidhar/pdfunlock/issues
Author-email: Sasidhar Akurathi <akurathisasidhar4@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Sasidhar Akurathi
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: cli,decrypt,password,pdf,unlock
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: pypdf[crypto]>=4.0
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Description-Content-Type: text/markdown

# pdfunlock

[![PyPI](https://img.shields.io/pypi/v/pdfunlock-cli)](https://pypi.org/project/pdfunlock-cli/)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)

A small command-line tool that removes password protection from PDF files **you own**, when you supply the **correct password**.

> **What it is not:** pdfunlock does not crack, guess, brute-force, or bypass passwords. If you don't know the password, this tool cannot (and will not) help.

## Installation

```bash
pip install pdfunlock-cli
```

Or with [pipx](https://pipx.pypa.io/) for an isolated install:

```bash
pipx install pdfunlock-cli
```

Either way you get the `pdfunlock` command and the `pdfunlock` Python module.

Requires Python 3.10 or newer.

## Usage

```text
pdfunlock PDF_FILE [OPTIONS]

Options:
  -o, --output PATH    Output path for the decrypted PDF.
                       Defaults to <name>_unlocked.pdf next to the input.
  -p, --password TEXT  Password for the PDF. If omitted, you are prompted
                       securely (input is never echoed).
  --in-place           Overwrite the original file instead of writing a copy.
  -V, --version        Show the version and exit.
  --help               Show this message and exit.
```

### Examples

Decrypt a PDF, prompting securely for the password:

```console
$ pdfunlock protected.pdf
Password for protected.pdf:
Success: decrypted PDF saved to 'protected_unlocked.pdf'.
```

Choose where the decrypted copy is written:

```console
$ pdfunlock protected.pdf --output unlocked.pdf
Password for protected.pdf:
Success: decrypted PDF saved to 'unlocked.pdf'.
```

Pass the password on the command line (note: visible in shell history — prefer the prompt):

```console
$ pdfunlock protected.pdf --password mypassword
Success: decrypted PDF saved to 'protected_unlocked.pdf'.
```

Overwrite the original file:

```console
$ pdfunlock protected.pdf --in-place
Password for protected.pdf:
Success: decrypted PDF saved to 'protected.pdf'.
```

Wrong password? You get a clear error and a non-zero exit code:

```console
$ pdfunlock protected.pdf --password oops
Incorrect password for 'protected.pdf'.
```

Already-unprotected files are handled gracefully too:

```console
$ pdfunlock plain.pdf --password anything
'plain.pdf' is not password-protected. Nothing to do.
```

### Python API

The same functionality is available as a library:

```python
from pdfunlock import unlock_pdf, InvalidPasswordError

try:
    out = unlock_pdf("protected.pdf", "mypassword")
    print(f"Saved to {out}")
except InvalidPasswordError:
    print("Wrong password")
```

## Development

```bash
git clone https://github.com/akurathisasidhar/pdfunlock
cd pdfunlock

# Create a virtual environment
python -m venv .venv
.venv\Scripts\activate        # Windows
source .venv/bin/activate     # macOS / Linux

# Editable install with dev tools
pip install -e ".[dev]"

# Run the test suite
pytest

# With coverage
pytest --cov=pdfunlock
```

Project layout:

```
pdfunlock/
├── pyproject.toml
├── LICENSE
├── README.md
├── src/
│   └── pdfunlock/
│       ├── __init__.py     # public API + version
│       ├── cli.py          # Typer CLI entry point
│       ├── core.py         # decryption logic
│       ├── exceptions.py   # error types
│       └── py.typed        # PEP 561 marker
└── tests/
    ├── conftest.py         # generates test PDFs on the fly
    ├── test_core.py
    └── test_cli.py
```

## Publishing

Build the source distribution and wheel:

```bash
python -m build
```

Test the wheel locally before uploading:

```bash
pip install dist/pdfunlock_cli-1.0.0-py3-none-any.whl
pdfunlock --version
```

Upload to TestPyPI first (recommended):

```bash
twine upload --repository testpypi dist/*
pip install --index-url https://test.pypi.org/simple/ pdfunlock-cli
```

Then publish to PyPI:

```bash
twine upload dist/*
```

To release a new version: bump `__version__` in `src/pdfunlock/__init__.py`, rebuild, and re-upload.

## License

[MIT](LICENSE)
