This project has been archived by its maintainers, and is no longer receiving any updates.
exportify
exportify is a CLI tool and library for managing Python package exports: generating __init__.py files with lazy imports (using lateimport), managing __all__ declarations, and validating import consistency.
Exportify was previously developed as an internal dev tool to assist with our CodeWeaver project; it slowly grew in function until it didn't make sense to keep it as part of that project. Here it is for anyone to use.
What it Does
Exportify solves the problem of managing consistency and updates in export patterns across a codebase. It ensures module and package-level __all__ exports are consistent, accurate, and complete. It can also validate
Exportify offers a simple rule-based system for enforcing __all__ and __init__ patterns across a codebase with optional per-file overrides. Comes with sane defaults.
Features
- Lazy
__init__.pygeneration — generates__init__.pyfiles using a lazy__getattr__pattern powered bylateimport, keeping package imports fast and circular-import-free - YAML-driven rule engine — declarative rules control which symbols are exported, with priority ordering and pattern matching
- Export propagation — symbols exported from submodules automatically propagate up the package hierarchy
- Code preservation — manually written code above the
# === MANAGED EXPORTS ===sentinel is preserved across regeneration - Validation — checks that lazy import calls are well-formed and that
__all__declarations are consistent - Cache — SHA-256-based analysis cache for fast incremental updates
Installation
Easiest to install with uv:
uv tool install exportify
or pipx:
pipx install exportify
Python 3.12+ required.
Quick Start
# Create a default config file (.exportify/config.yaml)
exportify init
# Check current project consistency — runs all checks by default
exportify check
# Sync exports and __all__ to match your rules
# Creates missing __init__.py files and updates existing ones
exportify sync
# Preview what sync would change without writing anything
exportify sync --dry-run
# Run health checks and show current status
exportify doctor
Documentation
For new users
| Document | Description |
|---|---|
| Getting Started | Step-by-step tutorial for new projects |
Reference
| Document | Description |
|---|---|
| CLI Reference | Complete command reference with all flags |
| Rule Engine | Rule syntax, priorities, match criteria, provenance |
| Configuration | Initializing and configuring exportify |
Guides
| Document | Description |
|---|---|
| Troubleshooting & FAQ | Common issues and answers |
| Contributing | Development setup and how to contribute |
Internals (for contributors)
| Document | Description |
|---|---|
| Caching | Cache implementation and API |
| Overload Handling | @overload decorator support |
| Provenance Support | Symbol provenance in rules |
| Schema Versioning | Config schema version management |
Configuration
Rules live in .exportify/config.yaml (created by exportify init or written manually). Exportify searches for the config file in this order:
EXPORTIFY_CONFIGenvironment variable (any path).exportify/config.yaml.exportify/config.yml.exportify.yamlin the current working directory.exportify.ymlexportify.yamlexportify.yml
schema_version: "1.0"
rules:
- name: "exclude-private"
priority: 1000
match:
name_pattern: "^_"
action: exclude
- name: "include-public-classes"
priority: 700
match:
name_pattern: "^[A-Z]"
member_types: [class]
action: include
propagate: root
- name: "include-public-functions"
priority: 700
match:
name_pattern: "^[a-z]"
member_types: [function]
action: include
propagate: parent
Rule Priority Bands
| Priority | Purpose |
|---|---|
| 1000 | Absolute exclusions (private, dunders) |
| 900–800 | Infrastructure/framework exclusions |
| 700 | Primary export rules (classes, functions) |
| 600–500 | Import handling |
| 300–400 | Special cases |
| 0–200 | Defaults/fallbacks |
See the Rule Engine docs for the full rule syntax including logical combinations, match criteria, and advanced propagation options.
Propagation Levels
none— export only in the defining moduleparent— export in the defining module and its direct parentroot— export all the way to the package rootcustom— specify explicit target module
Generated Output
Exportify generates __init__.py files using the lazy __getattr__ pattern from lateimport:
# SPDX-FileCopyrightText: 2026 Your Name
#
# SPDX-License-Identifier: MIT
# === MANAGED EXPORTS ===
# This section is automatically generated. Manual edits below this line will be overwritten.
from __future__ import annotations
from typing import TYPE_CHECKING
from types import MappingProxyType
from lateimport import create_late_getattr
if TYPE_CHECKING:
from mypackage.core import MyClass
from mypackage.utils import helper_function
_dynamic_imports: MappingProxyType[str, tuple[str, str]] = MappingProxyType({
"MyClass": (__spec__.parent, "core"),
"helper_function": (__spec__.parent, "utils"),
})
__getattr__ = create_late_getattr(_dynamic_imports, globals(), __name__)
__all__ = ("MyClass", "helper_function")
def __dir__() -> list[str]:
"""List available attributes for the package."""
return list(__all__)
Code Preservation
Add a # === MANAGED EXPORTS === sentinel to an existing __init__.py to protect manually written code above it:
"""My package."""
from .compat import legacy_function # kept across regeneration
# === MANAGED EXPORTS ===
# ... generated section below (managed by exportify)
Everything above the sentinel is left untouched on every sync run.
CLI Reference
| Command | Description |
|---|---|
exportify init |
Initialize project configuration |
exportify check |
Validate exports and __all__ consistency |
exportify sync |
Align project code with export rules |
exportify undo |
Restore files from the last sync run |
exportify doctor |
Run system health checks |
exportify cache clear |
Clear the analysis cache |
exportify cache stats |
Show cache statistics |
See the full CLI reference for all flags and options.
Requirements
- Python 3.12+
lateimport(installed automatically)
License
Dual-licensed under MIT and Apache 2.0. See LICENSE-MIT and LICENSE-Apache-2.0.
Metadata
Release files for exportify 0.2.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| exportify-0.2.7.tar.gz | 97.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| exportify-0.2.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 222.5 kB
Release files / exportify-0.2.7.tar.gz
| Download URL | exportify-0.2.7.tar.gz |
|---|---|
| Size | 97.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fe1f9db65734c9c2fc162ef288475c5e8694538c66f0c90539ec5cd6c924fcdf
|
|
BLAKE2b-256 checksum How to use checksums |
fb406dab7d14d7cd15a19ab96d6b2b02104606cdcb43867a5e77e905bbdd67cc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 24, 2026.
Transparency logRelease files / exportify-0.2.7-py3-none-any.whl
| Download URL | exportify-0.2.7-py3-none-any.whl |
|---|---|
| Size | 125.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3323563b29e94c7e0a1a98f653fa4017e40d3e8fe0409780765790d51265f61d
|
|
BLAKE2b-256 checksum How to use checksums |
6dac0b0a1d7f761a63c4288eb9ac92850dfb949b26f4d1e95f542c8635933745
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 24, 2026.
Transparency log