Skip to main content

A Python module privacy checker for keeping public interfaces intentional.

Project description

Privata

License CI PyPI Python Versions Docs

Privata logo

Find Python code that looks public but is only used privately.

Privata is a static checker for keeping module boundaries intentional. It scans your production Python modules and reports four kinds of interface drift:

  • public top-level functions, classes, variables, and type aliases that are only used inside their own module
  • imports of private modules such as pkg._internal from outside their owning package subtree
  • imports of private top-level symbols such as pkg.service._Helper from another production module
  • literal __all__ declarations that are stale, incomplete, or exporting names that do not exist

It is designed for packages and applications where helper() should become _helper() once it is no longer part of the production interface. Test imports do not count, so tests can still reach internals without forcing those internals to stay public.

Example

Given:

# src/example/service.py
def helper() -> int:
    return 1


def run() -> int:
    return helper()

Privata reports:

Found 1 public symbols that could be made private:

  src/example/service.py:1: function `helper`

Install

uv tool install privata

For local development:

uv sync --extra dev --group docs
uv run pre-commit install

Usage

Run Privata from a project root:

privata .

Privata uses tach.toml source_roots when present. Otherwise it prefers src/ when that directory exists, and falls back to scanning the project root while ignoring tests, virtualenvs, build output, docs output, and hidden tooling directories.

Use Privata as a pre-commit hook in another repository:

repos:
  - repo: https://github.com/basnijholt/privata
    rev: v0.1.2
    hooks:
      - id: privata

For a less strict setup that only runs when requested:

repos:
  - repo: https://github.com/basnijholt/privata
    rev: v0.1.2
    hooks:
      - id: privata-manual
pre-commit run --hook-stage manual privata-manual --all-files

Full output can include multiple issue types:

Found 2 public symbols that could be made private:

  src/example/service.py:12: function `helper`
  src/example/service.py:21: class `InternalState`

Found 1 private module imports outside their package subtree:

  src/example/api.py:3: imports private module `example.worker._runtime`

Found 1 private symbol imports from production modules:

  src/example/api.py:4: imports private symbol `example.worker.runtime._Helper`

Found 1 __all__ export issues:

  src/example/__init__.py:5: public name `Service` missing from __all__

If the project is clean:

No module privacy issues found.

What Privata Checks

  • Public top-level functions, classes, variables, and type aliases in production source roots.
  • Whether those symbols are imported by another production module under those roots.
  • Whether private modules such as pkg._internal are imported outside their containing package subtree.
  • Whether private top-level symbols are imported from another production module.
  • Whether literal __all__ declarations exactly match public top-level bindings.
  • Console entry points in pyproject.toml.
  • Uvicorn entry points in shell scripts and Dockerfiles.
  • Symbols exported through package __init__.py and __all__.
  • Tach [[interfaces]] entries, when tach.toml is present.
  • Module names defined by more than one file across source roots (e.g. src/utils.py next to tests/utils.py, or pkg.py next to pkg/__init__.py). Such names are ambiguous at import time and only one file per name can be scanned, so Privata reports the collision instead of silently picking one.

Privata intentionally ignores imports from tests/. If only tests import a symbol, Privata treats that symbol as private.

Exception — test helper modules in a test source root: when tach.toml lists a directory such as tests/ under source_roots, non-test files inside that root (e.g. tests/something.py) are scanned as ordinary modules. Imports from co-located test files do count as cross-module usage in this case, because those helper modules exist solely to serve the test suite. A symbol that at least one test file imports is treated as public; a symbol that no test file imports is still flagged as a private candidate.

Development

uv run pytest  # enforces 100% coverage
uv run pre-commit run --all-files
uv build

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

privata-0.6.0.tar.gz (82.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

privata-0.6.0-py3-none-any.whl (18.8 kB view details)

Uploaded Python 3

File details

Details for the file privata-0.6.0.tar.gz.

File metadata

  • Download URL: privata-0.6.0.tar.gz
  • Upload date:
  • Size: 82.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for privata-0.6.0.tar.gz
Algorithm Hash digest
SHA256 5cfc87610313cd8a7991f816077f14aa8323646bb4e61a2e0f67200e1c903132
MD5 e45b284ad52dc3c0626fdee65be5e632
BLAKE2b-256 e611bfac40922e63c1c93139c807d15a9d67a3026377be0140e8e78102cfd075

See more details on using hashes here.

Provenance

The following attestation bundles were made for privata-0.6.0.tar.gz:

Publisher: release.yml on basnijholt/privata

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file privata-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: privata-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 18.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for privata-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ad6a57b5cbcbd38902919bf75f7e970766c4b6f37010abe16cfa184445af25ca
MD5 6a4ef581c996cf8ae94f2ea40dfc99c0
BLAKE2b-256 14f2996a4eed4eb3bfd9cefc91cf9c29a07effefc92295c0e6e5fc4494022260

See more details on using hashes here.

Provenance

The following attestation bundles were made for privata-0.6.0-py3-none-any.whl:

Publisher: release.yml on basnijholt/privata

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page