Repository navigation
fix(corekit): make every sentinel a singleton and give NO_VALUE a repr (#1841, #1842) - #1876
Conversation
#1841, #1842) - Add a private abstract base, `_Sentinel`, to `pcapkit.corekit.sentinels`. It carries `__new__`, `__copy__`, `__deepcopy__`, `__reduce__` and `__repr__`. So calling the type, copy, deepcopy and pickle at every protocol give back the one object for `NULL`, `NO_VALUE`, `NO_DEFAULT` and `ABSENT`. - `__reduce__` pickles a sentinel by its module-level name. `_get_null` stays so that pickles written before this change still load. - `NO_VALUE` reprs as `<NO_VALUE>`, not as an object address. - Update the sentinel convention page and the sentinels API page. - Add tests: singleton behaviour, pickles written by the previous module, a parsed HOPOPT MPL schema and a deep-copied field, and the repr. Closes #1841 Closes #1842
|
Verdict: GOOD TO GO at
One limit, stated for your call. My note recording the ruling added that pickles written before this change must load as the singleton. That holds at protocols 2–5, and for |
|
Maybe we can directly use Also, prefer making everything in a sentinel class immutable, such as |
|
Understood. The plan for this PR:
A worker will add this as a new commit. The review label resets when it lands. |
…uilt-in reprs (#1841, #1842) - Rename the private `_Sentinel` base to `Sentinel`, export it, and document it; no alias is kept under the old name. - Add `SentinelMeta`, an `abc.ABCMeta` subclass that makes each concrete sentinel's instance as its class statement runs, refuses attribute writes on every sentinel type with `TypeError`, and refuses subclassing or `register` on a concrete one, as `type(None)` does. - Sentinel instances get empty `__slots__` and raise `AttributeError` on every attribute write or delete, as `None` does. - A sentinel reprs and prints as its own name (`NO_VALUE`), as `None` does; `AbsentType` drops its own `__repr__`. - Update the sentinels API page, the sentinel convention page, and the tests that pinned the old reprs; add parity tests against the built-in singletons. Closes #1841 Closes #1842
|
Verdict: GOOD TO GO at
Not blocking:
|
|
Coverage: 90.07% (unit tier, Python 3.15,
Per-file detail: the |
|
Verdict: NEEDS CHANGES at
parameter = inspect.signature(field).parameters['default']On Python 3.8, Fix: read the constructor's own signature, |
…ALUE repr test (#1841) - `test_no_value_reprs_as_its_own_name` called `inspect.signature` on the field class. On Python 3.8 that reports `Generic.__new__`'s `(*args, **kwds)` for a `Generic` subclass, so `parameters['default']` raised `KeyError` on the KTLO leg. Read `field.__init__` instead, which every version reports alike. Closes #1841
|
Verdict: GOOD TO GO at
My own mutation checks from the earlier verdict still apply: allowing type attribute assignment fails 31 tests, and dropping the subclass check fails 4. |
Please follow the guide below
You will be asked some questions, please read them carefully and answer honestly
Put an
xinto all the boxes [ ] relevant to your pull request (like that [x])Use Preview tab to see how your pull request will actually look like
Searched for similar pull requests
Followed the coding style (
make pylint,make mypy,make isort)make testpasses, and a test case covers the change. Narrow runs only, listed below.Added a changelog entry under
docs/source/changelog/and regeneratedCHANGELOG.md, if the change is user-visible: N/A — centralised in docs(changelog): shared 1.5.0 changelog — long-lived, merges last (#610, #616, #617, #618, #620) #657What is the purpose of your pull request?
Tick the commit type your subject line carries.
fix— corrects a defectfeat— adds a featureperf— changes performance, not behaviourrefactor— changes neither behaviour nor performancetest— tests onlydocs— documentation onlyci— workflows or build toolingrelease— bumps the version or rolls up a distributionchore— anything else_Sentinel, topcapkit.corekit.sentinels. Itcarries
__new__,__copy__,__deepcopy__,__reduce__and__repr__.So calling the type, copy, deepcopy and pickle at every protocol give back
the one object for
NULL,NO_VALUE,NO_DEFAULTandABSENT.__reduce__pickles a sentinel by its module-level name._get_nullstaysso that pickles written before this change still load.
NO_VALUEreprs as<NO_VALUE>, not as an object address.a parsed HOPOPT MPL schema and a deep-copied field, and the repr.
Closes #1841
Closes #1842
Known limit, documented and pinned by a test: a pickle of
NO_VALUE,NO_DEFAULTorABSENTwritten before this change at protocol 0 or 1 still loads, but not as the singleton. Those pickles rebuild throughcopyreg._reconstructor, which callsobject.__new__directly, so the class cannot intervene. Protocol 2 and above, and every pickle written after this change, load as the singleton.