Enforces the presence and correctness of __all__ in Python modules
Project description
sheridan-iceberg
The public API is the tip of the iceberg.
icebergguards the waterline.
sheridan-iceberg analyzes Python modules and enforces the presence and
correctness of __all__. It uses Python's ast module for static analysis —
no importing of user code.
Features
show— inspect and report the effective public API of any module or project; uses__all__when present, falls back to AST inference;--use-astforces AST-only regardless of__all__check— enforce__all__correctness; IB002 is one-directional (names that appear public in the AST but are absent from__all__), so deliberate re-exports are never flagged as phantom namesfix— auto-repair__all__in place; uses full bidirectional comparison, removing phantom exports as well as adding missing ones- Walks a Python project's modules via AST (safe, no imports)
- Uses
__all__as the authoritative public API surface when present; falls back to inferring non-underscore top-level names when absent - Machine-readable JSON output and human-readable text/tree output
- Works as a pre-commit hook, CLI tool, or GitHub Action
Installation
pip install sheridan-iceberg
Usage
# Report the public API of a project
iceberg show src/
# Show as JSON (machine-readable)
iceberg show src/ --format json
# Ignore __all__ entirely — always use AST inference
iceberg show src/ --use-ast
# Check __all__ declarations against the AST
iceberg check src/
# Suppress IB001 (missing __all__) — only report IB002 and IB003
iceberg check src/ --ignore-missing
# Check with JSON output
iceberg check src/ --format json
# Auto-fix __all__ declarations (bidirectional — also removes phantom exports)
iceberg fix src/
# Preview what fix would change without writing
iceberg fix src/ --dry-run
Example output
iceberg show produces an indented tree by default. When __init__.py
declares __all__, it is the source of truth for the whole package — only
that module is shown:
# iceberg show src/mypackage/
mypackage/
__init__
Role
User
helper
Pass --use-ast to bypass __all__ and see every module's inferred names:
# iceberg show src/mypackage/ --use-ast
mypackage/
__init__
Role
User
helper
core
Alpha
Beta
Gamma
utils
helper
parse
iceberg check reports violations:
src/mypackage/utils.py: IB001 missing __all__ (expected ['helper', 'parse'])
src/mypackage/models.py: IB002 names appear public but missing from __all__: ['Role']
src/mypackage/core.py: IB003 __all__ is not sorted (expected ['Alpha', 'Beta', 'Gamma'])
Exit codes:
show:0always (path existence aside)check:0no issues,1issues found,2path not foundfix:0success,2path not found
JSON output
iceberg show --format json:
[
{
"module": "mypackage.utils",
"path": "src/mypackage/utils.py",
"source": "ast",
"names": ["helper", "parse"]
},
{
"module": "mypackage.models",
"path": "src/mypackage/models.py",
"source": "__all__",
"names": ["Role", "User"]
}
]
The source field is "__all__" when the module has an __all__ (and --use-ast is not set), "ast" otherwise.
iceberg check --format json:
[
{
"code": "IB001",
"path": "src/mypackage/utils.py",
"kind": "missing",
"declared": null,
"expected": ["helper", "parse"]
}
]
Programmatic usage
from sheridan.iceberg import check_api, fix_api, get_public_api
# Get the public API surface — __init__.__all__ is the source of truth
api = get_public_api("src/")
# {"mypackage": ["Role", "User", "helper"]}
# Bypass __all__ and see every module's AST-inferred names
api = get_public_api("src/", use_ast=True)
# {"mypackage": [...], "mypackage.core": [...], "mypackage.utils": [...]}
# Check for __all__ issues
issues = check_api("src/")
# [{"code": "IB002", "path": "...", "kind": "incorrect", "declared": [...], "expected": [...]}]
# Suppress IB001 (missing __all__) — only surface IB002 and IB003
issues = check_api("src/", ignore_missing=True)
# Fix __all__ in place — returns paths of modified files
fixed = fix_api("src/")
# [PosixPath("src/mypackage/core.py")]
# Preview what would change without writing
would_fix = fix_api("src/", dry_run=True)
How inference works
For regular modules, iceberg infers the public API from top-level definitions —
functions, classes, and assignments whose names do not start with _.
For __init__.py files, names re-exported via from x import y are also
counted, since this is the standard Python pattern for building a package's
public surface.
# foo/__init__.py
from foo.snap import Widget # Widget is inferred as public
from foo._bar import _helper # _helper is excluded (underscore)
Submodules are not automatically included. The existence of foo/snap.py
on disk does not add snap to foo.__all__ — the __init__.py is the
explicit gatekeeper. To expose a submodule, import it explicitly:
# foo/__init__.py
from foo import snap # now snap is part of the inferred public API
Test files (test_*.py, *_test.py, conftest.py) are always skipped.
As a pre-commit hook
repos:
- repo: https://github.com/sheridan/sheridan-iceberg
rev: v0.1.0
hooks:
- id: iceberg
Development
# Install dependencies
task install
# Run all checks (lint, format, typecheck, test, iceberg)
task check
# Run individual checks
task lint:check # ruff — read-only
task lint # ruff — autofix
task format:check # formatter — read-only
task format # formatter — write
task typecheck # mypy --strict
task test # pytest --cov
task iceberg:check # dogfood: run iceberg check on itself
task iceberg:show # dogfood: show iceberg's own public API
# Run tests
task test
# Build docs
task docs-serve
CI pipeline (Dagger)
The full CI pipeline runs each gate in its own container via Dagger.
Podman is the default runtime; Docker is supported via CONTAINER_RUNTIME=docker.
# First-time setup (generates ci/sdk/ — run once after clone)
podman machine start # macOS only
task ci-init
# Run the full CI pipeline locally
task ci
# Use Docker instead
CONTAINER_RUNTIME=docker task ci
See CONTRIBUTING.md for details.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sheridan_iceberg-1.0.5.tar.gz.
File metadata
- Download URL: sheridan_iceberg-1.0.5.tar.gz
- Upload date:
- Size: 55.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63c54ee5ce7ecf4ab21b2264b1e21971718c817f3e825d9c3adb3dd0acf45408
|
|
| MD5 |
97d63de2494d2a8606aa9c14be33315b
|
|
| BLAKE2b-256 |
2ee0be4cb9a15a3393ef91d868b905f7f08695edcdf56913250441bbf47081b9
|
Provenance
The following attestation bundles were made for sheridan_iceberg-1.0.5.tar.gz:
Publisher:
publish.yaml on andrewasheridan/iceberg
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sheridan_iceberg-1.0.5.tar.gz -
Subject digest:
63c54ee5ce7ecf4ab21b2264b1e21971718c817f3e825d9c3adb3dd0acf45408 - Sigstore transparency entry: 1155485634
- Sigstore integration time:
-
Permalink:
andrewasheridan/iceberg@d71cda2d5cbcb4bc4addfc08f21a06d844c1b712 -
Branch / Tag:
refs/tags/v1.0.5 - Owner: https://github.com/andrewasheridan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@d71cda2d5cbcb4bc4addfc08f21a06d844c1b712 -
Trigger Event:
push
-
Statement type:
File details
Details for the file sheridan_iceberg-1.0.5-py3-none-any.whl.
File metadata
- Download URL: sheridan_iceberg-1.0.5-py3-none-any.whl
- Upload date:
- Size: 17.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2e357c18542ceefc7e7e169714ff11a626357515b4dfe972c795b5d278fd995
|
|
| MD5 |
2d1fdee0855338a22351d2ed1e9182a1
|
|
| BLAKE2b-256 |
9c78fedb10123c7494c2781735055725848cabff6023b4269092bb02920bc7f9
|
Provenance
The following attestation bundles were made for sheridan_iceberg-1.0.5-py3-none-any.whl:
Publisher:
publish.yaml on andrewasheridan/iceberg
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sheridan_iceberg-1.0.5-py3-none-any.whl -
Subject digest:
e2e357c18542ceefc7e7e169714ff11a626357515b4dfe972c795b5d278fd995 - Sigstore transparency entry: 1155485638
- Sigstore integration time:
-
Permalink:
andrewasheridan/iceberg@d71cda2d5cbcb4bc4addfc08f21a06d844c1b712 -
Branch / Tag:
refs/tags/v1.0.5 - Owner: https://github.com/andrewasheridan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@d71cda2d5cbcb4bc4addfc08f21a06d844c1b712 -
Trigger Event:
push
-
Statement type: