diff --git a/README.md b/README.md index 26aa152..ab76569 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Anything else is an implementation detail and may change without a major version ## Key design choices -- **Zero external dependencies in the core.** Detection, anonymization, and mapping run on stdlib alone. Heavy features (spaCy, Faker, pdfplumber) are opt-in extras. +- **Minimal dependencies.** Detection, anonymization, and mapping run on stdlib alone; `typer` (used by the CLI) is the only required install-time dep. Heavy features (spaCy, Faker, pdfplumber) are opt-in extras. - **Checksums written from scratch.** PESEL, NIP, REGON, Luhn, mod-97 IBAN — the library's core value, not outsourced. - **Reversibility is a contract.** Every `anonymize()` call returns a `Mapping` that enables perfect restoration, preserving source formatting (dashes, spaces). - **Polish-first.** Native handling of Polish identifiers and, via the `[ner]` extra, Polish names and addresses through `pl_core_news_lg`. diff --git a/src/llm_safe_pl/__init__.py b/src/llm_safe_pl/__init__.py index 70dfe18..5bcd4b2 100644 --- a/src/llm_safe_pl/__init__.py +++ b/src/llm_safe_pl/__init__.py @@ -4,10 +4,12 @@ implementation detail and may change without a major version bump. """ +from importlib.metadata import version as _version + from llm_safe_pl.models import AnonymizeResult, Mapping, Match, PIIType from llm_safe_pl.shield import Shield -__version__ = "0.1.0" +__version__ = _version("llm-safe-pl") __all__ = [ "AnonymizeResult", diff --git a/src/llm_safe_pl/anonymizer.py b/src/llm_safe_pl/anonymizer.py index ff624ef..7b6c73c 100644 --- a/src/llm_safe_pl/anonymizer.py +++ b/src/llm_safe_pl/anonymizer.py @@ -25,7 +25,6 @@ def __init__( ) -> None: self._detectors = detectors self._mapping = mapping - self._strategy = strategy def detect(self, text: str) -> list[Match]: """Find all PII matches with overlaps resolved, without mutating Mapping.""" diff --git a/src/llm_safe_pl/cli.py b/src/llm_safe_pl/cli.py index c96a312..df17cf6 100644 --- a/src/llm_safe_pl/cli.py +++ b/src/llm_safe_pl/cli.py @@ -18,6 +18,7 @@ import typer +from llm_safe_pl import __version__ from llm_safe_pl.models import Mapping from llm_safe_pl.shield import Shield @@ -27,6 +28,28 @@ ) +def _version_callback(value: bool) -> None: + if value: + typer.echo(__version__) + raise typer.Exit() + + +@app.callback() +def _root( + version: Annotated[ + bool, + typer.Option( + "--version", + "-V", + callback=_version_callback, + is_eager=True, + help="Show the version and exit.", + ), + ] = False, +) -> None: + """llm-safe-pl — reversible PII anonymization for Polish documents.""" + + def _read_text(path: Path) -> str: """Read a text file, accepting UTF-8 (±BOM) and UTF-16 (±endianness) with BOM.""" data = path.read_bytes() diff --git a/tests/test_cli.py b/tests/test_cli.py index 176706c..ef6eb0e 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,6 +2,7 @@ from typer.testing import CliRunner +from llm_safe_pl import __version__ from llm_safe_pl.cli import app @@ -14,3 +15,15 @@ def test_cli_help_exits_zero() -> None: def test_cli_no_args_shows_help() -> None: result = CliRunner().invoke(app, []) assert "Usage" in result.output + + +def test_cli_version_flag_prints_version() -> None: + result = CliRunner().invoke(app, ["--version"]) + assert result.exit_code == 0 + assert __version__ in result.output + + +def test_cli_short_version_flag_prints_version() -> None: + result = CliRunner().invoke(app, ["-V"]) + assert result.exit_code == 0 + assert __version__ in result.output