Repository navigation
fix(corekit): export the sentinel objects, not their types - #916
Conversation
|
GOOD TO GO on The risk I flagged — that removing a name from One thing neither the PR nor my brief said, and worth recording: Merge sequencing, verified by me rather than relayed. Confirmed independently: 9 of the 18 new tests fail against On The reviewer also reported a self-inflicted error rather than burying it: it checked out |
Per the owner's ruling on #911 -- "we should ONLY export the objects (like `NULL`) to users" -- which cuts both ways: - `corekit/module.py`: drop `'NullType'` from `__all__`. - `corekit/enum.py`: drop `'NoDefaultType'` from `__all__`. - `corekit/fields/field.py`: **add** `'NoValue'`, exported neither way before. - `docs/source/conventions.rst`: the sentinel section documented three sentinels; there are four. Adds `_Absent`/`_AbsentType`, fixes both counts, records the export rule, and carves out `_NOT_FOUND = object()` in the vendored `cached_property` backport as exempt from it. - `tests/const/test_const_registry_protocol.py`: the one test asserting `'NoDefaultType' in enum.__all__` now asserts the opposite. Breaking only for `import *`: every type stays importable by its dotted path, which is how every in-tree user already names them. `tests/corekit/` and `tests/project/test_public_api.py` pass; Sphinx warnings unchanged at 58.
2581c78 to
d2011a0
Compare
|
Rebased onto Verified blob-identical to the reviewed head — Worth knowing for the sequencing: the new test's |
The `__all__` half of #911 landed as #916; this is the housing half, per the owner's ruling -- "Okay one module for all four it is." - Add pcapkit/corekit/sentinels.py holding NULL/NullType, NoValue/NoValueType, NO_DEFAULT/NoDefaultType and _Absent/_AbsentType, moved from module.py, fields/field.py, enum.py and protocols/protocol.py respectively. - Each original module keeps a re-export so every existing `from <module> import <name>` -- object and type, including the `if TYPE_CHECKING:`-only ones -- keeps working unchanged. - No import cycle: sentinels.py depends only on pcapkit.utilities.compat. - Fix an unrelated, pre-existing staleness found in transit: NoDefaultType's reload example predated #864's non-minting guard and no longer reproduced; replaced with a verified one. - Update conventions.rst's sentinel table and prose to the new module. - Add tests/corekit/test_sentinels_housing_unit.py: cross-module identity and no-cycle checks. Build: isort clean; pylint/mypy unchanged from origin/main on every touched file. tests/corekit/, tests/project/ and tests/protocols/test_construction_keyword_check_unit.py all pass.
The `__all__` half of #911 landed as #916; this is the housing half, per the owner's ruling -- "Okay one module for all four it is." - Add pcapkit/corekit/sentinels.py holding NULL/NullType, NoValue/NoValueType, NO_DEFAULT/NoDefaultType and _Absent/_AbsentType, moved from module.py, fields/field.py, enum.py and protocols/protocol.py respectively. - Each original module keeps a re-export so every existing `from <module> import <name>` -- object and type, including the `if TYPE_CHECKING:`-only ones -- keeps working unchanged. - No import cycle: sentinels.py depends only on pcapkit.utilities.compat. - Fix an unrelated, pre-existing staleness found in transit: NoDefaultType's reload example predated #864's non-minting guard and no longer reproduced; replaced with a verified one. - Update conventions.rst's sentinel table and prose to the new module. - Add tests/corekit/test_sentinels_housing_unit.py: cross-module identity and no-cycle checks. Build: isort clean; pylint/mypy unchanged from origin/main on every touched file. tests/corekit/, tests/project/ and tests/protocols/test_construction_keyword_check_unit.py all pass.
The `__all__` half of #911 landed as #916; this is the housing half, per the owner's ruling -- "Okay one module for all four it is." - Add pcapkit/corekit/sentinels.py holding NULL/NullType, NoValue/NoValueType, NO_DEFAULT/NoDefaultType and _Absent/_AbsentType, moved from module.py, fields/field.py, enum.py and protocols/protocol.py respectively. - Each original module keeps a re-export so every existing `from <module> import <name>` -- object and type, including the `if TYPE_CHECKING:`-only ones -- keeps working unchanged. - No import cycle: sentinels.py depends only on pcapkit.utilities.compat. - Fix an unrelated, pre-existing staleness found in transit: NoDefaultType's reload example predated #864's non-minting guard and no longer reproduced; replaced with a verified one. - Update conventions.rst's sentinel table and prose to the new module. - Add tests/corekit/test_sentinels_housing_unit.py: cross-module identity and no-cycle checks. Build: isort clean; pylint/mypy unchanged from origin/main on every touched file. tests/corekit/, tests/project/ and tests/protocols/test_construction_keyword_check_unit.py all pass.
The `__all__` half of #911 landed as #916; this is the housing half, per the owner's ruling -- "Okay one module for all four it is." - Add pcapkit/corekit/sentinels.py holding NULL/NullType, NoValue/NoValueType, NO_DEFAULT/NoDefaultType and _Absent/_AbsentType, moved from module.py, fields/field.py, enum.py and protocols/protocol.py respectively. - Each original module keeps a re-export so every existing `from <module> import <name>` -- object and type, including the `if TYPE_CHECKING:`-only ones -- keeps working unchanged. - No import cycle: sentinels.py depends only on pcapkit.utilities.compat. - Fix an unrelated, pre-existing staleness found in transit: NoDefaultType's reload example predated #864's non-minting guard and no longer reproduced; replaced with a verified one. - Update conventions.rst's sentinel table and prose to the new module. - Add tests/corekit/test_sentinels_housing_unit.py: cross-module identity and no-cycle checks. Build: isort clean; pylint/mypy unchanged from origin/main on every touched file. tests/corekit/, tests/project/ and tests/protocols/test_construction_keyword_check_unit.py all pass.
The `__all__` half of #911 landed as #916; this is the housing half, per the owner's ruling -- "Okay one module for all four it is." - Add pcapkit/corekit/sentinels.py holding NULL/NullType, NoValue/NoValueType, NO_DEFAULT/NoDefaultType and _Absent/_AbsentType, moved from module.py, fields/field.py, enum.py and protocols/protocol.py respectively. - Each original module keeps a re-export so every existing `from <module> import <name>` -- object and type, including the `if TYPE_CHECKING:`-only ones -- keeps working unchanged. - No import cycle: sentinels.py depends only on pcapkit.utilities.compat. - Fix an unrelated, pre-existing staleness found in transit: NoDefaultType's reload example predated #864's non-minting guard and no longer reproduced; replaced with a verified one. - Update conventions.rst's sentinel table and prose to the new module. - Add tests/corekit/test_sentinels_housing_unit.py: cross-module identity and no-cycle checks. Build: isort clean; pylint/mypy unchanged from origin/main on every touched file. tests/corekit/, tests/project/ and tests/protocols/test_construction_keyword_check_unit.py all pass.
… (#922) The `__all__` half of #911 landed as #916; this is the housing half, per the owner's ruling -- "Okay one module for all four it is." - Add pcapkit/corekit/sentinels.py holding NULL/NullType, NoValue/NoValueType, NO_DEFAULT/NoDefaultType and _Absent/_AbsentType, moved from module.py, fields/field.py, enum.py and protocols/protocol.py respectively. - Each original module keeps a re-export so every existing `from <module> import <name>` -- object and type, including the `if TYPE_CHECKING:`-only ones -- keeps working unchanged. - No import cycle: sentinels.py depends only on pcapkit.utilities.compat. - Fix an unrelated, pre-existing staleness found in transit: NoDefaultType's reload example predated #864's non-minting guard and no longer reproduced; replaced with a verified one. - Update conventions.rst's sentinel table and prose to the new module. - Add tests/corekit/test_sentinels_housing_unit.py: cross-module identity and no-cycle checks. Build: isort clean; pylint/mypy unchanged from origin/main on every touched file. tests/corekit/, tests/project/ and tests/protocols/test_construction_keyword_check_unit.py all pass.
Please follow the guide below
make pylint,make mypy,make isort)make testpasses, and a test case covers the changedocs/source/changelog/and regeneratedCHANGELOG.md, if the change is user-visible -- N/A -- changelog 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?
fixfeatperfrefactortestdocscichoreDescription of your pull request and other information
The unblocked half of #911. The housing question -- one module per sentinel, or one module for all -- is still open, so nothing is moved here, no
sentinels.pyis created and no re-export shim is added.Per the ruling, "we should ONLY export the objects (like
NULL) to users", which cuts both ways:__all__before__all__afterpcapkit/corekit/module.py['NULL', 'NullType', 'ModuleDescriptor']['NULL', 'ModuleDescriptor']pcapkit/corekit/enum.py['NO_DEFAULT', 'NoDefaultType', 'EnumLookup', 'EnumRegistry']['NO_DEFAULT', 'EnumLookup', 'EnumRegistry']pcapkit/corekit/fields/field.py['Field']['NoValue', 'Field']_Absent/_AbsentTypeinpcapkit/protocols/protocol.pyis untouched: private-named, exported neither way, and the ruling is about what users see.breaking, but narrowly. Nothing in the tree star-imports any of these three modules (git grep 'from pcapkit.corekit.module import \*'and the other two: no hits), and every in-tree user names the types insideif TYPE_CHECKING:--NullTypeinfoundation/registry/{foundation,protocols}.py,NoValueTypeincorekit/fields/{ipaddress,misc,numbers,strings}.py-- soimport *is the only surface that narrows.NoDefaultTypehas no in-tree user outsideenum.py.docs/source/conventions.rst's sentinel section documented three sentinels; there are four. Adds the_Absentrow, corrects both counts ("four in the tree", "the four sentinels"), notes why a leading-underscore sentinel was missed by a sweep filtering on capitalised names, records the export rule the code half implements, and carves out_NOT_FOUND = object()atpcapkit/utilities/compat.py:73-- inside the vendoredcached_propertybackport -- as exempt, which the "why a class and notobject()" subsection previously read as a blanket rule with no exception.One existing test encoded the old contract:
tests/const/test_const_registry_protocol.py::NoDefaultSentinelTestsasserted'NoDefaultType' in enum.__all__. It now asserts the opposite, plus that the type is still reachable as an attribute.tests/project/test_public_api.pyis unaffected -- its converse assertion (test_every_public_package_exports_every_public_attribute) covers packages, and none of the three is one;pcapkit/corekit/__init__.pyandpcapkit/corekit/fields/__init__.pyimport by name, never*, so no package namespace changes.New
tests/corekit/test_sentinel_exports_unit.py: 18 tests, 21 subtests. Nine fail onorigin/main-- five on the__all__shape (module,enum,field, the star-import that actually reads__all__, and the identity of the object it binds) and four on the documentation half (the table rows, the counts, the export rule, the carve-out). The rest are regression guards: the sibling exports that must survive the edit (ModuleDescriptor,Field,EnumLookup,EnumRegistry), the types staying importable by dotted path, and the naming convention itself. Two also pin the contract that makesNoValuepublic in the first place -- it is documented as the value ofFieldBase.default, and thedefaultsetter and deleter were both uncovered.sphinx-build -b htmlinto two fresh BUILDDIRs: 58 warnings before, 58 after, identical sets.NullTypeandNoValueTypeare still documented despite leaving__all__, becauseconf.pysetsignore-module-all: Trueand both have an explicitautoclassdirective.tests/corekit/,tests/project/test_public_api.py,tests/const/test_const_registry_protocol.pyandtests/protocols/test_construction_keyword_check_unit.pyundercoverage run -m pytest: 395 passed, 16 skipped.tests/project/separately: 178 passed. Coverage over the touched files, same selection before and after:corekit/fields/field.py87% -> 88%,corekit/enum.pyandcorekit/module.py100% -> 100% (already no headroom),protocols/protocol.py59% unchanged (documented here, not edited). Did not run the full suite.