Skip to content

fix(corekit): let _py_abc cache its ABC lookups on sentinel types (#1960) - #1966

Merged
JarryShaw merged 2 commits into
mainfrom
fix/1960-sentinel-py-abc
Oct 20, 2026
Merged

JarryShaw merged 2 commits into
mainfrom
fix/1960-sentinel-py-abc

Conversation

@JarryShaw

Copy link
Copy Markdown
Owner

What is the purpose of your pull request?

  • fix — corrects a defect

Description of your pull request and other information

Without the C _abc module, as on GraalPy, abc falls back to _py_abc. That rebinds _abc_negative_cache and _abc_negative_cache_version on a class during isinstance. SentinelMeta.__setattr__ refused every write, so isinstance(1, NullType) raised TypeError, which broke JSON dumping and extraction there (#1960).

It now lets exactly those two names through, and only where the type already holds them, which only _py_abc arranges. Every other write, every delete, and register on a concrete type is still refused. The docstring and the sentinel-convention page note the exception.

tests/corekit/test_sentinel_py_abc_1960_unit.py runs the checks in a child interpreter that really takes the _py_abc fallback (abc.ABCMeta is _py_abc.ABCMeta). It fails without the fix on 3.14 and 3.8.

Closes #1960

)

- SentinelMeta.__setattr__ now lets a frozen sentinel type rebind
  _abc_negative_cache and _abc_negative_cache_version, and only where the
  type's own __dict__ already holds them, which only _py_abc puts there.
  Without the C _abc module, isinstance against a sentinel type raised
  TypeError. Every other write and every delete is still refused.
- New test runs the checks in a child interpreter that really falls back to
  _py_abc, and pins that the names stay refused under the C module.
- The SentinelMeta docstring and the sentinel convention page name the
  exception.

Closes #1960
@JarryShaw JarryShaw added fix Pull requests that fix a defect (fix: subject prefix) review: running A cross-review is in flight against the current head - no verdict yet labels Oct 20, 2026
@JarryShaw JarryShaw moved this to In review in PyPCAPKit Oct 20, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

GOOD TO GO at 3e433b8a8. A Sonnet review read _py_abc for both 3.8 and 3.14. After __new__, its only class-attribute writes are the two allowed cache names in __subclasscheck__. The invalidation counter lives on _py_abc.ABCMeta, never on a sentinel type. Deliberately poisoning the negative cache could produce a wrong "no" but never a wrong "yes". _abc_cache, _abc_registry and all other writes stay refused, and on C _abc builds both names are still refused. The test's fallback is real (abc.ABCMeta is _py_abc.ABCMeta). It fails without the fix (17 failed), and tests/corekit, the tier guard and the doc claims pass.

@JarryShaw JarryShaw added review: good-to-go Cross-review at the current head says ready; CI state is separate review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: running A cross-review is in flight against the current head - no verdict yet review: good-to-go Cross-review at the current head says ready; CI state is separate labels Oct 20, 2026
- The _PY_ABC_CACHE comment, the SentinelMeta docstring and the sentinel
  convention page name abc, _py_abc and ABCMeta.__new__ as literals rather
  than roles, since ABCMeta.__new__ is not in the Python inventory.
@JarryShaw

Copy link
Copy Markdown
Owner Author

NEEDS CHANGES at 3e433b8a8. Project tests fails test_docs_unresolvable_roles_1919_unit.py::DeadTargetTests::test_no_dead_target_appears. The new _PY_ABC_CACHE comment writes :meth:~abc.ABCMeta.new``, which is not in the Python inventory. A follow-up commit writes it as a literal. The review missed it because it never ran the #1919 guard.

@JarryShaw JarryShaw added review: running A cross-review is in flight against the current head - no verdict yet and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment labels Oct 20, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

GOOD TO GO at a5cc70842. A Sonnet delta review confirmed the new commit only turns the ABCMeta.__new__ and abc roles in sentinels.py and sentinel-convention.rst into literals, with no code change. No other role in the PR's prose points at an unresolvable target. The #1919 and #1936 guards, the new #1960 test, the sentinel exports test and the doc-claims test pass.

@JarryShaw JarryShaw added review: good-to-go Cross-review at the current head says ready; CI state is separate and removed review: running A cross-review is in flight against the current head - no verdict yet labels Oct 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage: 90.07% (unit tier, Python 3.15, a5cc70842, Unit Tests run success)

Package Statements Missed Branches Partial Cover
pcapkit (top level) 104 2 20 2 96.77%
pcapkit/const 19597 881 2618 867 92.11%
pcapkit/corekit 2505 70 792 36 96.54%
pcapkit/dumpkit 276 3 100 3 98.40%
pcapkit/foundation 2916 164 1016 34 93.59%
pcapkit/interface 138 7 52 5 93.68%
pcapkit/protocols 17411 224 4580 189 98.10%
pcapkit/toolkit 872 177 298 8 77.18%
pcapkit/utilities 522 2 158 4 99.12%
pcapkit/vendor 4431 2341 1018 156 43.64%

Per-file detail: the coverage-html artifact of this run.

@JarryShaw
JarryShaw merged commit 66bf7c0 into main Oct 20, 2026
57 checks passed
@JarryShaw
JarryShaw deleted the fix/1960-sentinel-py-abc branch October 20, 2026 01:55
@github-project-automation github-project-automation Bot moved this from In review to Done in PyPCAPKit Oct 20, 2026
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Oct 20, 2026
@JarryShaw JarryShaw added this to the PyPCAPKit v1.5 milestone Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Pull requests that fix a defect (fix: subject prefix)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

fix(corekit): sentinel types refuse the ABC cache writes _py_abc makes, so isinstance fails without C _abc

1 participant