Skip to content

Add py.typed marker to the published distribution (PEP 561) #7

Description

@S2thend

Add py.typed marker to the published distribution (PEP 561)

Problem

loopgraph ships type hints throughout its public API (verified by browsing
loopgraph/persistence/snapshot.py etc.), but the PyPI distribution does
not include a py.typed marker file
at the package root.

Per PEP 561, type checkers (mypy, pyright, pyre) only honor inline type
annotations from a third-party package if either:

  1. The package contains a py.typed file at the top level, AND that file
    is shipped in the published wheel; or
  2. Type stubs are provided in a separate loopgraph-stubs distribution.

Without that marker, type checkers treat every member of loopgraph as
Any. Downstream consumers using strict mode (mypy's strict = true,
pyright's strict, etc.) then get spurious errors any time they touch
loopgraph types.

Concrete consequence we hit

A downstream project subclasses loopgraph.persistence.SnapshotStore
(a typing.Protocol):

from loopgraph.persistence import SnapshotStore

class MyStore(SnapshotStore):
    ...

Under mypy strict (which enables disallow_subclassing_any = True),
this fires:

error: Class cannot subclass "SnapshotStore" (has type "Any")  [misc]

The fix on the consumer side is one of:
- Add # type: ignore[misc] — works locally but CI (running mypy under a
different package-resolution path) then flags it as [unused-ignore].
Tug-of-war.
- Relax disallow_subclassing_any = false for the importing package —
loses strict coverage for unrelated subclasses.
- (Best, but not in our control:) loopgraph publishes py.typed.

We've shipped the second workaround for now. We'd love to roll it back
once this issue lands.

Verification — what's missing in the wheel

A current wheel inspection:

pip download loopgraph --no-deps -d /tmp/lg-wheel
unzip -l /tmp/lg-wheel/loopgraph-*.whl | grep py.typed
# (no output)

Compare with e.g. requests, which ships requests/py.typed and is
properly typed downstream.

Fix — PEP 561 distribution config

Three pieces, all in pyproject.toml (or setup.cfg if using setuptools
declarative):

1. Create the marker at loopgraph/py.typed — empty file is fine.
(Already exists in the source tree per find . -name py.typed.)
2. Ship it in the wheel — for setuptools-based packaging, add to
pyproject.toml:

[tool.setuptools.package-data]
loopgraph = ["py.typed"]

2. Or if using find: layout with setup.cfg:

[options]
include_package_data = True

[options.package_data]
loopgraph = py.typed

2. For Poetry / Hatch / flit, the equivalent is "include py.typed in
the package payload."
3. Verify in a clean build:

python -m build --wheel
unzip -l dist/loopgraph-*.whl | grep py.typed
# loopgraph/py.typed

Why this is one-line-of-config

The source tree already has the marker (loopgraph/py.typed exists per
the upstream repo). The wheel just doesn't pull it in because
include_package_data defaults differently across build backends. Adding
the explicit package-data entry is the canonical fix.

Optional follow-ups (not blocking)

- Add a CI step that does python -m build --wheel && unzip -l ... | grep py.typed so the marker can't quietly disappear from a future release.
- Consider running mypy --strict against a tiny downstream-style
subclass test in CI — catches regressions in inline-annotation
coverage too.

Version where the fix should land

Any minor release. Downstream pinning to a fixed minor is fine; we just
need to bump our floor when the fix lands.

---

Adjust the maintainer-tone / issue tracker formatting to taste. If their build backend is Hatch or Poetry rather than setuptools, the `package-data`
snippet swaps out — quick check of their `pyproject.toml` `[build-system]` block before posting saves a follow-up comment.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions