Metadata-Version: 2.5
Name: pyannotators-patterns
Version: 1.6.139
Summary: Annotator based on Presidio pattern recognizer
Project-URL: Homepage, https://github.com/oterrier/pyannotators_patterns/
Author-email: Olivier Terrier <olivier.terrier@kairntech.com>
License: The MIT License (MIT)
        
        Copyright (c) 2021 Olivier Terrier
        
        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: AUTHORS.md
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.12
Requires-Dist: collections-extended
Requires-Dist: log-with-context
Requires-Dist: presidio-analyzer>=2.2.354
Requires-Dist: pymultirole-plugins<1.7.0,>=1.6.0
Requires-Dist: spacy[lookups]>=3.7.0
Requires-Dist: tldextract>=5.1.2
Requires-Dist: unidecode
Provides-Extra: dev
Requires-Dist: bump2version; extra == 'dev'
Requires-Dist: pre-commit; extra == 'dev'
Provides-Extra: docs
Requires-Dist: lxml-html-clean; extra == 'docs'
Requires-Dist: m2r2; extra == 'docs'
Requires-Dist: sphinx; extra == 'docs'
Requires-Dist: sphinx-rtd-theme; extra == 'docs'
Requires-Dist: sphinxcontrib-apidoc; extra == 'docs'
Provides-Extra: sbom
Requires-Dist: cyclonedx-bom; extra == 'sbom'
Requires-Dist: pip-audit; extra == 'sbom'
Provides-Extra: test
Requires-Dist: dirty-equals; extra == 'test'
Requires-Dist: pip; extra == 'test'
Requires-Dist: pytest; extra == 'test'
Requires-Dist: pytest-check; extra == 'test'
Requires-Dist: pytest-cov; extra == 'test'
Requires-Dist: ruff; extra == 'test'
Description-Content-Type: text/markdown

# pyannotators_patterns

[![license](https://img.shields.io/github/license/oterrier/pyannotators_patterns)](https://github.com/oterrier/pyannotators_patterns/blob/master/LICENSE)
[![tests](https://github.com/oterrier/pyannotators_patterns/workflows/tests/badge.svg)](https://github.com/oterrier/pyannotators_patterns/actions?query=workflow%3Atests)
[![codecov](https://img.shields.io/codecov/c/github/oterrier/pyannotators_patterns)](https://codecov.io/gh/oterrier/pyannotators_patterns)
[![docs](https://img.shields.io/readthedocs/pyannotators_patterns)](https://pyannotators_patterns.readthedocs.io)
[![version](https://img.shields.io/pypi/v/pyannotators_patterns)](https://pypi.org/project/pyannotators_patterns/)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyannotators_patterns)](https://pypi.org/project/pyannotators_patterns/)

Annotator based on Presidio regex pattern recognizers.

## Installation

```
pip install pyannotators-patterns
```

## Development

The build is driven by [Task](https://taskfile.dev) and [uv](https://docs.astral.sh/uv/),
with the shared stages coming from the `python-archetype` submodule.

### Getting started

The stages live in a Git submodule, so **clone with `--recurse-submodules`**:

```bash
git clone --recurse-submodules git@bitbucket.org:kairntech/pyannotators_patterns.git
cd pyannotators_patterns
sh -c "$(curl -sSL https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin
task
```

Already cloned without it? The submodule directory is empty, and `task` fails on:

```
task: No Taskfile found at ".../submodules/python-archetype/resources/Taskfile.yml"
```

which means exactly that, and nothing worse:

```bash
git submodule update --init
```

**Task is the only manual prerequisite.** An archetype cannot bootstrap itself: uv and the
Python interpreter install themselves on demand (every task that runs uv depends on an
internal `install-python` task), but the thing that runs them does not. Make sure
`~/.local/bin` is on your `PATH` — that is where `task` and `uv` both land.

### Running the pipeline

```bash
task stages          # print the pipeline stages, in order
task                 # run the pipeline up to (but excluding) py:publish
task -- --skip-tests # same, without the test stage
task up-to -- py:lint # run the pipeline up to and including one stage
task jenkins         # run every stage, exactly what Jenkins runs
```

`task` with no argument is safe by construction: it runs every stage but the last, and that
bound is computed from the `STAGES` list rather than written down. The last stage is the
only one with an effect outside your machine.

`STAGES`, declared once in `Taskfile.yml`, is the single definition of the pipeline order —
so what you run locally is what Jenkins runs.

### Individual stages

| Task                            | Description                                           |
|---------------------------------|-------------------------------------------------------|
| `task py:sync`                  | Install the project and its dependencies (uv sync)    |
| `task py:lint`                  | `ruff check` and `ruff format --check`                |
| `task py:format`                | Reformat the code with ruff                           |
| `task py:test`                  | Run the test suite                                    |
| `task py:test-marker -- <m>`    | Run the tests carrying one pytest marker              |
| `task py:sbom`                  | Generate a CycloneDX SBOM of the resolved environment |
| `task py:check-vulnerabilities` | Check for known CVEs                                  |
| `task py:check-updates`         | Check for dependency updates                          |
| `task py:build`                 | Build the wheel and sdist (uv build)                  |
| `task py:publish`               | Publish the distributions (uv publish)                |
| `task py:version-file`          | Print the path of the file carrying `__version__`     |
| `task py:set-version VERSION=x` | Write that version into it                            |

`uv.lock` is not versioned here, so `py:sync` always resolves from scratch (`--upgrade`):
a stale lock lying around on a machine would otherwise make you test and audit versions the
CI never sees.

### SBOM & vulnerability check

`task py:sbom` and `task py:check-vulnerabilities` wrap the underlying tools. To run them
by hand:

```bash
uv sync --extra test --extra sbom
uv run cyclonedx-py environment -o sbom.cdx.json --output-format json
uv run pip-audit --skip-editable --format json --output audit-report.json
```

Ask for **all** the extras, not just `sbom`: `uv sync` synchronises rather than adds, so
whatever the requested extras do not pull in gets removed. `--extra sbom` on its own
uninstalls `ruff` and `pytest`, leaving an environment that can no longer lint or test.

`--skip-editable` skips the project itself, which no advisory database can know about. The
tasks do the same, and pip-audit still exits non-zero when it finds a real vulnerability —
which is the contract the CI relies on. Avoid `--strict`: it turns "dependency not found on
PyPI" into a fatal error, so it breaks as soon as the local version is not a published one.
