Skip to content

Ship type stubs as a jsonpatch-stubs package - #249

Merged
stefankoegl merged 5 commits into
masterfrom
claude/nifty-brahmagupta-n8vroj
Nov 2, 2026
Merged

stefankoegl merged 5 commits into
masterfrom
claude/nifty-brahmagupta-n8vroj

Conversation

@stefankoegl

@stefankoegl stefankoegl commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

Fixes #158.

mypy reports module is installed, but missing library stubs or py.typed marker for jsonpatch. PEP 561 has no py.typed marker for single-file modules, so this ships the types as a stub-only package, jsonpatch-stubs, inside the jsonpatch distribution. Type checkers pick it up automatically, and jsonpatch.py stays a single module without changes.

Changes

  • jsonpatch-stubs/__init__.pyi: stubs for the public API.
    • JSON documents are Any, since they can be any JSON value and the module accepts arbitrary Mapping / Sequence types, which a recursive JSON type would reject.
    • Patches are str | bytes | Iterable[Mapping[str, Any]].
    • from_string / from_diff return Self, so subclasses get instances of themselves.
    • DiffBuilder is typed loosely, as it is mostly an implementation detail.
  • setup.py: includes the stub package in the distribution and adds the Typing :: Typed classifier. MANIFEST.in adds the new type test to the sdist.
  • requirements.txt: requires jsonpointer>=3.8, the first jsonpointer release with type stubs, so JsonPointer and pointer_cls have real types.
  • pyproject.toml: mypy configuration (strict).
  • New CI job typing:
    • mypy.stubtest checks that the stubs agree with jsonpatch.py. It fails on missing names, mismatched parameters, or changed defaults.
    • mypy --strict type-checks typical usage (typetests/usage.py) against the installed distribution, including a custom JsonPointer subclass as pointer_cls. It also includes calls that must be rejected, marked with # type: ignore[...]; strict mode fails if they stop producing that error.
  • README.md: a short "Type hints" section, including a reminder to update the stubs when the API changes.

Testing

  • The built wheel and sdist contain jsonpatch-stubs/__init__.pyi, and twine check --strict passes.
  • mypy resolves import jsonpatch to the installed stubs, also with --python-version 3.10.
  • stubtest and the usage check pass with jsonpointer 3.8. With jsonpointer 3.7 (untyped), the usage check fails as expected.
  • tests.py (256 tests) and property_tests.py pass. flake8 passes.

Release notes

The third-party types-jsonpatch package on PyPI (2022 alpha releases) installs into the same jsonpatch-stubs/ directory and pins jsonpatch==1.32. Installing it downgrades jsonpatch, and uninstalling it deletes jsonpatch's own stubs. The release notes should tell users to uninstall it before upgrading.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Pewzpj8LrcYUx1DeTxFCMg

mypy reported "module is installed, but missing library stubs or py.typed
marker" for jsonpatch. PEP 561 has no py.typed marker for single-file
modules, so the types are shipped as a stub-only package, jsonpatch-stubs,
in the same distribution, which type checkers pick up automatically. This
keeps jsonpatch.py a single module without annotations.

JSON documents are typed as Any, as they can be any JSON value and the
module accepts arbitrary Mapping / Sequence types. Patches are typed as
str | bytes | Iterable[Mapping[str, Any]].

A new CI job runs mypy's stubtest to check that the stubs agree with
jsonpatch.py, and type-checks typical usage (typetests/usage.py) against
the installed distribution with mypy --strict, including usage that must
be rejected.

Released jsonpointer versions are untyped, so pyproject.toml tells mypy to
ignore that; the stubs also pass against the typed jsonpointer from
stefankoegl/python-json-pointer#106.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pewzpj8LrcYUx1DeTxFCMg
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pewzpj8LrcYUx1DeTxFCMg
@coveralls

coveralls commented Nov 2, 2026 •

Copy link
Copy Markdown

Coverage Status

coverage: 100.0%. remained the same — claude/nifty-brahmagupta-n8vroj into master

jsonpointer 3.8 includes its own type stubs, so mypy no longer needs to
ignore it, and JsonPointer / pointer_cls in the jsonpatch stubs now have
real types instead of Any. The usage type test now also covers a custom
JsonPointer subclass as pointer_cls, and rejects a pointer_cls that is not
one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pewzpj8LrcYUx1DeTxFCMg

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The stub fails to explicitly re-export JsonPointer and omits JsonPointerException, causing type-checking errors for existing usage supported by the runtime module.

1 open issue
What changed in this PR

This PR addresses missing type information by shipping a jsonpatch-stubs package alongside the existing single-file runtime module.

Changes:

  • Adds public API stubs and includes them in the distribution.
  • Adds strict mypy usage checks and a CI job to verify stub compatibility.
  • Documents type support and how to maintain the stubs.
File Description
typetests/​usage.py Checks valid usage, inferred types, and rejected calls.
setup.py Packages the stubs and declares typing support.
README.md Documents type hints and verification commands.
pyproject.toml Configures strict mypy checks and the jsonpointer override.
MANIFEST.in Includes the type-checking examples in source distributions.
jsonpatch-stubs/​__init__.pyi Defines types for the jsonpatch API.
.github/​workflows/​test.yaml Adds stub compatibility and usage checks to CI.

Review effort: Balanced

Comment thread jsonpatch-stubs/__init__.pyi Resolved
jsonpatch.py imports both from jsonpointer, so jsonpatch.JsonPointer and
jsonpatch.JsonPointerException work at runtime (ext_tests.py catches the
latter). In a .pyi file, imports are private unless re-exported with a
same-name alias, so type checkers rejected these uses. stubtest doesn't
notice, as it skips names defined in other modules, so the usage type
test now covers them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pewzpj8LrcYUx1DeTxFCMg

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The JsonPatch.from_string annotation omits bytearray, rejecting an input supported at runtime, and should include it in the parameter union.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Medium severity Include bytearray in the from_string input type

jsonpatch-stubs/​__init__.pyi:106

The default JSON loader accepts bytearray, and from_string forwards its input unchanged, so JsonPatch.from_string(bytearray(b'[]')) works at runtime but is rejected by this annotation. Include bytearray in this parameter's union to preserve that supported input. apply_patch can retain its narrower union because it dispatches strings and bytes separately.

1 resolved since last review

Review effort: Balanced

The default loader (json.loads) accepts bytearray, and from_string passes
its input on unchanged, so JsonPatch.from_string(bytearray(...)) works at
runtime. apply_patch keeps str | bytes: it treats a bytearray as a
sequence of operations and fails, so the usage test checks that type
checkers reject that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pewzpj8LrcYUx1DeTxFCMg

Copy link
Copy Markdown
Owner Author

Addressed the bytearray point from the latest review in ac82662: JsonPatch.from_string now accepts str | bytes | bytearray. apply_patch keeps str | bytes, since at runtime it treats a bytearray as a sequence of operations and raises InvalidJsonPatch; typetests/usage.py checks both.


Generated by Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

There are no active review issues for the bundled type-stub changes.

No open issues 🎉

Review effort: Balanced

@stefankoegl
stefankoegl merged commit 9e780d5 into master Nov 2, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing Type Hints

4 participants