From 02ed50c546390272dc67d21004fdb362dcd2bb9a Mon Sep 17 00:00:00 2001 From: Jarry Shaw Date: Fri, 16 Oct 2026 15:55:59 -0400 Subject: [PATCH] docs(tests): third whole-repo pass over tests (#1103) Counted numbers, per the ruling on #1103: - Drop counts of members, rows, registries, call sites, modules, crawlers, legs, warnings and test cases from test docstrings and comments, rewording them count-free or naming the constant that holds the set. - Keep spec quantities, measurements that justify a design choice, and figures that derive a constant an assertion pins. Accuracy: - The AppType isinstance claim matches pcapkit.protocols, and the _make_port literals are placed in the TCP, UDP and SCTP modules. - The bs4-importing crawler figure was wrong; the prose is count-free. - test_const_enum_get's sweep arithmetic no longer matched the pinned size; it names the sets that compose the population instead. - tests/_tiers.py names the helpers conftest actually drives. Timed context: drop "now", "today" and "any more" in touched sentences. Refs #1103 --- tests/_dependency_gates.py | 16 +- tests/_support.py | 12 +- tests/_tiers.py | 9 +- tests/cli/test_main.py | 18 +-- tests/conftest.py | 14 +- tests/const/test_const_apptype_split_unit.py | 87 +++++------ tests/const/test_const_enum_builtin_parity.py | 10 +- tests/const/test_const_enum_get.py | 44 +++--- tests/const/test_const_enum_no_mint.py | 40 ++--- tests/const/test_const_ethertype_862_unit.py | 2 +- .../test_const_ftp_featcode_case_903_unit.py | 6 +- tests/const/test_const_linktype_209_unit.py | 4 +- tests/corekit/test_enum_lookup_base_unit.py | 4 +- .../test_enum_lookup_reparent_877_unit.py | 6 +- .../test_enum_lookup_reparent_930_unit.py | 14 +- tests/corekit/test_fields_collections.py | 6 +- tests/corekit/test_fields_ipaddress.py | 4 +- tests/corekit/test_fields_misc.py | 8 +- tests/corekit/test_sentinel_exports_unit.py | 20 +-- tests/corekit/test_sentinels_housing_unit.py | 20 +-- .../test_nameless_enum_rendering_unit.py | 40 +++-- tests/foundation/registry/test_protocols.py | 6 +- tests/integration/test_pcapng_end_to_end.py | 2 +- tests/project/test_annotation_names.py | 16 +- tests/project/test_capture_tracking.py | 22 +-- tests/project/test_ci_timing.py | 2 +- tests/project/test_conventions_doc_claims.py | 141 +++++++++--------- tests/project/test_coverage_data_guard.py | 2 +- .../test_docs_ambiguous_xrefs_1775_unit.py | 14 +- .../test_generators_import_their_own_tree.py | 4 +- tests/project/test_isort_clean.py | 24 +-- ...test_no_moved_name_re_exports_1744_unit.py | 4 +- tests/project/test_public_api.py | 63 ++++---- tests/project/test_pyshark_encap_map.py | 2 +- tests/project/test_python_versions_1660.py | 8 +- tests/project/test_release_gates.py | 34 ++--- tests/project/test_rfc_anchor_fragments.py | 18 +-- .../test_rfc_constants_one_home_1739_unit.py | 4 +- .../test_sentinels_doc_page_934_unit.py | 10 +- .../test_stdlib_feature_probes_1709_unit.py | 8 +- tests/project/test_unit_tests_queue.py | 2 +- tests/project/test_workflow_run_verdict.py | 12 +- .../test_workflows_at_a_glance_1732.py | 2 +- .../test_construction_keyword_check_unit.py | 4 +- .../test_option_generator_tcp_base_unit.py | 4 +- tests/protocols/test_option_roundtrip_unit.py | 14 +- tests/test_base_class_contract.py | 10 +- tests/test_docstring_contract.py | 6 +- tests/test_support_helpers.py | 12 +- tests/test_tier_guard.py | 51 +++---- tests/utilities/test_compat.py | 8 +- .../vendor/test_crawler_reachability_unit.py | 2 +- tests/vendor/test_ipx_socket_unit.py | 4 +- tests/vendor/test_user_agent_unit.py | 4 +- tests/vendor/test_vendor_dest_path_unit.py | 4 +- tests/vendor/test_vendor_exit_code_unit.py | 2 +- tests/vendor/test_vendor_missing_body_unit.py | 4 +- .../test_vendor_reg_apptype_generator_unit.py | 18 +-- .../test_vendor_snapshot_restore_unit.py | 2 +- 59 files changed, 469 insertions(+), 464 deletions(-) diff --git a/tests/_dependency_gates.py b/tests/_dependency_gates.py index 128d092774..67e6c38ffd 100644 --- a/tests/_dependency_gates.py +++ b/tests/_dependency_gates.py @@ -22,7 +22,7 @@ every ``test_*.py`` looking at :func:`unittest.skipUnless` decorators on classes *and* on methods. A text search finds the method-level ones and misses the class-level ones entirely, which is most of them: ``HAS_EMOJI``'s - 14 methods are gated by two class decorators. + methods, for one, are gated by class decorators alone. 2. **What the flag requires**, from :func:`flag_requirements` -- the module names its defining expression probes, read out of the source rather than listed here. A flag defined in one module and imported by another @@ -117,14 +117,14 @@ #: The workflow holding every blocking job that runs :program:`pytest`. #: :file:`experimental.yml` runs the unit tier as well, on legs nothing waits on -#: (#1732), and is not read here. Five other workflows install ``.[all]`` +#: (#1732), and is not read here. Other workflows install ``.[all]`` #: somewhere -- a docs build, a conda recipe, a vendor crawl, the lint pass, #: and the release packaging workflow -- and none of them invokes the suite; #: :file:`python-compatibility.yml` installs a bare ``.`` and only compiles and #: imports, and :file:`codeql-analysis.yml` installs nothing explicitly at all #: (CodeQL's own autobuild step). That is exactly why this module keys on *jobs that -#: run pytest* rather than on install lines anywhere in the workflow tree: three -#: of those five install ``.[all,dev]`` -- carrying ``pypcapfile``, ``pyshark`` +#: run pytest* rather than on install lines anywhere in the workflow tree: some +#: of those install ``.[all,dev]`` -- carrying ``pypcapfile``, ``pyshark`` #: and ``scapy`` through the ``dev`` extra #910 added when it narrowed ``all`` #: to core addons only -- so a guard reading those lines would satisfy nearly #: every flag here vacuously. @@ -1174,9 +1174,9 @@ def flag_requirements() -> 'dict[tuple[str, str], frozenset[str]]': """``(module, flag)`` -> the modules that flag needs importable. Resolved per file rather than per flag name, which matters for exactly one - flag and matters a lot: ``HAS_RUNTIME`` names the four core dependencies in + flag and matters a lot: ``HAS_RUNTIME`` names the core dependencies in every module but one, and in - :file:`tests/foundation/engines/test_runtime_engines.py` it names those four + :file:`tests/foundation/engines/test_runtime_engines.py` it names those plus ``dpkt``, ``scapy`` and ``pyshark``. Keyed on the name alone, that one module's requirements would be demanded of every other module that gates on it, or they would excuse it. @@ -1563,8 +1563,8 @@ def dependency_gate_gaps(workflow: 'Optional[pathlib.Path]' = None) -> 'tuple[Ga Aggregated per ``(flag, job)`` rather than per gate: one missing extra darkens every gate on that flag at once, and a reader wants "the ``test`` - job reaches 14 ``HAS_CRYPTO`` methods and installs no ``cryptography``", - not fourteen copies of it. + job reaches N ``HAS_CRYPTO`` methods and installs no ``cryptography``", + not one copy of it per method. """ requirements = flag_requirements() diff --git a/tests/_support.py b/tests/_support.py index e573f9de84..9ce7010a0c 100644 --- a/tests/_support.py +++ b/tests/_support.py @@ -363,7 +363,7 @@ def load_module(module_name: str, relative_path: str, Both halves of that write to :data:`sys.modules` -- the stub parents, and ``module_name`` itself -- so both are taken back off again when ``test`` finishes, via :func:`restore_modules_after`. Before issue #674 they were not, - and five test modules left a bare ``pcapkit`` bound for whatever ran next. + and test modules left a bare ``pcapkit`` bound for whatever ran next. Args: module_name: Dotted name to execute the file under, e.g. @@ -405,12 +405,12 @@ def load_module(module_name: str, relative_path: str, def bootstrap_core_modules(test: 'Optional[unittest.TestCase]' = None) -> dict[str, object]: """Execute the core :mod:`pcapkit` modules from source, in dependency order. - The seven modules the unit tier needs before it can test anything else, each + The modules the unit tier needs before it can test anything else, each loaded by :func:`load_module` and so each restored when ``test`` finishes. The restore is arranged here as well as in :func:`load_module`, and deliberately: :func:`restore_modules_after` registers one cleanup per test however many times it is called, so the snapshot kept is the one taken here, - before the first of the seven loads wrote anything. + before the first of those loads wrote anything. Args: test: The running test. Found from the calling frames when omitted, as in @@ -465,7 +465,7 @@ def install_fake_protocol_module(test: 'unittest.TestCase') -> type: which is what puts :data:`sys.modules` back afterwards. Required rather than optional so that a future caller cannot install the stand-in without arranging for its removal -- the mistake is a - :exc:`TypeError` at the call rather than twelve unrelated failures + :exc:`TypeError` at the call rather than a run of unrelated failures in another directory. Returns: @@ -694,7 +694,7 @@ def _running_test_case() -> 'Optional[unittest.TestCase]': has to be *handed* the running test is a helper every call site can forget to hand it to, and forgetting is silent. Issue #674 is the bill for that -- :func:`bootstrap_core_modules` and :func:`load_module` left stub ``pcapkit`` - entries in :data:`sys.modules` at five call sites, not one of which looked + entries in :data:`sys.modules` at call sites none of which looked wrong, and the resulting failures landed in a different directory. The *nearest* enclosing ``self`` wins, and that is the right one rather than @@ -871,7 +871,7 @@ def isolate_modules(test: 'unittest.TestCase', difference is the whole of issue #660: purging on the way *in* protects the test that does it and nothing else, so a test that replaces ``pcapkit.protocols.protocol`` with a stand-in and then finishes leaves that - stand-in bound for whatever runs next. Twelve tests in + stand-in bound for whatever runs next. Tests in :mod:`tests.project.test_public_api` and :mod:`tests.project.test_documentation_claims` failed with ``TypeError: type 'ProtocolBase' is not subscriptable`` on exactly that, and only when the diff --git a/tests/_tiers.py b/tests/_tiers.py index 60f544e822..8a7ded3517 100644 --- a/tests/_tiers.py +++ b/tests/_tiers.py @@ -26,7 +26,7 @@ on demand and gitignored. A machine that has run ``make samples`` has them all, so the test passes locally and then fails on a fresh CI checkout with a missing-file error that blames the fixture rather than the tier rule. It has -happened three times (GitHub pull requests #372 and #384, and once more), and +happened more than once (GitHub pull requests #372 and #384 among them), and each time it cost a CI round-trip to work out. So this module answers, cheaply and without needing the fixtures themselves: @@ -49,9 +49,10 @@ * :func:`is_roundtrip_sweep` -- is this unit-tier module one of the round-trip sweeps, which only the ``latest`` leg of the ``test`` job runs (#1732)? -:file:`tests/conftest.py` drives the first four at collection time, and -:func:`tests._support.sample_path` consults :func:`check_unit_tier_read` on -every call. Both paths no-op when git cannot answer, so an unpacked source +:file:`tests/conftest.py` runs :func:`is_unit_tier` and :func:`audit_module` -- +and through it :func:`committed_captures` and :func:`explain` -- at collection +time, and :func:`tests._support.sample_path` consults :func:`check_unit_tier_read` +on every call. Both paths no-op when git cannot answer, so an unpacked source tarball still runs its tests. :func:`fixture_tier_paths` is what the ``integration`` job of diff --git a/tests/cli/test_main.py b/tests/cli/test_main.py index ea21088109..f1b0ccf464 100644 --- a/tests/cli/test_main.py +++ b/tests/cli/test_main.py @@ -2,20 +2,20 @@ """:mod:`pcapkit.__main__`, against stand-ins for everything it imports. The command line tool is tested without the library behind it: :mod:`pcapkit`, -:mod:`pcapkit.foundation.extraction`, :mod:`pcapkit.interface`, three -:mod:`pcapkit.utilities` modules and :mod:`emoji` are all replaced with +:mod:`pcapkit.foundation.extraction`, :mod:`pcapkit.interface`, the +:mod:`pcapkit.utilities` modules it imports and :mod:`emoji` are all replaced with stand-ins, so what is under test is the argument wiring and nothing else. The real thing runs in :mod:`tests.integration.test_cli_subprocess`. :data:`sys.modules` is process-global, so binding a stand-in over a real module name is a write that outlives the test unless something undoes it -- and these stand-ins are *emptier* than what they replace, which is the quiet kind. Issue -#688: this file wrote nine names and put none of them back -- the seven stand-ins +#688: this file wrote those names and put none of them back -- the stand-ins above, the bare ``pcapkit.foundation`` parent they hang from, and ``pcapkit.__main__`` itself. Pairing it with :mod:`tests.project.test_public_api` -gave ten errors: nine ``ImportError: cannot import name 'show_flag_values' from -'pcapkit.utilities.compat'`` and one for ``SeekError``, because the real library's -next import found a ``pcapkit.utilities.compat`` carrying exactly one name. +gave a run of ``ImportError: cannot import name 'show_flag_values' from +'pcapkit.utilities.compat'`` errors and one for ``SeekError``, because the real +library's next import found a ``pcapkit.utilities.compat`` carrying exactly one name. That is the same defect as issues #660 and #674, and it is fixed the same way: :func:`tests._support.isolate_modules` in ``setUp``, which purges the region on @@ -65,7 +65,7 @@ #: How many module names :func:`summarise_names` spells out before it starts #: counting instead. Bounded because the interesting list is long: on a warm -#: module table the :mod:`pcapkit` region holds some three hundred names, so an +#: module table the :mod:`pcapkit` region holds hundreds of names, so an #: unbounded report of what a leak did to it is twelve kilobytes of failure #: message that nobody reads -- measured, at 12089 characters. NAMES_IN_FAILURE_MESSAGE = 8 @@ -107,8 +107,8 @@ def setUp(self) -> None: def assert_module_table_restored(self, before: 'dict[str, types.ModuleType]') -> None: """The :data:`ISOLATED` region of :data:`sys.modules` is as it was found. - The regression assertion for issue #688, and exact in all three - directions a restore can be wrong: a name this test added, a name it + The regression assertion for issue #688, and exact in every + direction a restore can be wrong: a name this test added, a name it dropped, and a name it rebound to something else. Absence matters as much as presence -- ``pcapkit.utilities.compat`` did not exist before a test here ran on a cold table, so it must not exist after one either, and a diff --git a/tests/conftest.py b/tests/conftest.py index c001ddec06..86a591e9fe 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -128,7 +128,7 @@ def pytest_sessionstart(session: 'pytest.Session') -> 'None': region is empty at the pin and restored to empty after every test, which makes each of the tests that does not purge for itself -- :mod:`tests.project` is the bulk of them -- pay a fresh ``import pcapkit`` it used to get from the - warm table. Measured over the 96 tests of ``tests/project/``: 1.59s with no + warm table. Measured over ``tests/project/``: 1.59s with no guard at all, **9.34s** guarded from a cold table, **0.35s** guarded from a warm one. The last is the fastest of the three because the import it would otherwise do inside the first test has moved here instead. @@ -161,8 +161,8 @@ def pytest_sessionstart(session: 'pytest.Session') -> 'None': in ``TCP``/``UDP`` and :attr:`AppType.__registries__ `. The next direct import of the submodule then built a second ``TCP`` and ``UDP``, and - :mod:`tests.project.test_conventions_doc_claims` counted both generations: - ``127 != 129`` registries on the 3.10-3.13 unit legs of PR #1560. + :mod:`tests.project.test_conventions_doc_claims` counted both generations, and + its registry count came out wrong on the 3.10-3.13 unit legs of PR #1560. Failure here is not an error. A checkout without the runtime dependencies installed cannot import the package at all -- which is a supported way to run @@ -244,9 +244,9 @@ def restore_module_table() -> 'Iterator[None]': :class:`~typing.Generic` stayed bound after the test that installed it, and the next test to import :mod:`pcapkit` died on ``TypeError: type 'ProtocolBase' is not subscriptable`` at - ``pcapkit/protocols/misc/pcap/frame.py:69`` -- twelve tests in + ``pcapkit/protocols/misc/pcap/frame.py:69`` -- a run of tests in :mod:`tests.project`, and only when the polluting file happened to be - collected first. Three separate files turned out to leak this way, one of + collected first. Several files turned out to leak this way, one of which -- :mod:`tests.cli.test_main` -- did not import :mod:`tests._support` at all. @@ -259,8 +259,8 @@ def restore_module_table() -> 'Iterator[None]': that will be written, which is the difference between the failure being unlikely and being impossible. - Two of the three were fixed at their call sites when this guard landed, and - the third was not: :mod:`tests.cli.test_main` kept its own purge loop, which + The others were fixed at their call sites when this guard landed, but + :mod:`tests.cli.test_main` was not: it kept its own purge loop, which purges and restores nothing, and this fixture went on quietly healing it for every test. That is issue #688 -- it took an audit rather than a failing run to find, because a guard that repairs a leak also hides it. It is now fixed diff --git a/tests/const/test_const_apptype_split_unit.py b/tests/const/test_const_apptype_split_unit.py index b74c4d09ea..d4f9e1c253 100644 --- a/tests/const/test_const_apptype_split_unit.py +++ b/tests/const/test_const_apptype_split_unit.py @@ -2,7 +2,7 @@ """The application layer registry as a per-transport package. GitHub issue #732. :file:`pcapkit/const/reg/apptype.py` was one -:class:`~aenum.StrEnum` holding 8,182 members across every transport protocol, +:class:`~aenum.StrEnum` holding the members of every transport protocol, with a ``__members_proto__`` mapping that kept **one** member per ``(transport, port)`` pair -- so of the three services IANA assigns to port 80, two were reachable only by attribute name and none of that was visible from a @@ -11,15 +11,15 @@ transport protocol, each keyed on port by a :class:`~pcapkit.corekit.multidict.MultiDict` that keeps every assignment. -Four properties carry the design and none of them held before, so each is +These properties carry the design and none of them held before, so each is asserted directly rather than left to the generic sweeps in :mod:`tests.const.test_const_enum_builtin_parity`: #. the base holds **no** members, which is not a tidiness preference -- :mod:`aenum` refuses to subclass an enumeration that has any, so a single - member on the base makes all four registries impossible to declare; -#. a member is still an ``AppType``, which is what keeps the seven - ``isinstance`` sites in :mod:`pcapkit.protocols` working across the split; + member on the base makes every per-transport registry impossible to declare; +#. a member is still an ``AppType``, which is what keeps the ``isinstance`` + check against it in :mod:`pcapkit.protocols` working across the split; #. a colliding port keeps **every** service IANA assigned it, answering with one canonical member and keeping the rest reachable as named aliases; #. :func:`~aenum.extend_enum` on an occupied port *appends* rather than @@ -43,13 +43,14 @@ def _dunder_sample(registry: 'type') -> 'list': """The members of ``registry`` the byte-identity sweep formats, in row order. - GitHub issue #1062. Sweeping every member ran 37,173 subtests, and per-test - coverage contexts found only **4** distinct arc sets among them: ``repr`` - and ``str``, each with and without an ``(aliases: ...)`` suffix -- the - registry, the port and the service name never change which code runs. So - the sample keeps every member that carries an alias (the suffix branch), + GitHub issue #1062. Sweeping every member ran a subtest per member, and + per-test coverage contexts found only a few distinct arc sets among them: + ``repr`` and ``str``, each with and without an ``(aliases: ...)`` suffix -- + the registry, the port and the service name never change which code runs. + So the sample keeps every member that carries an alias (the suffix branch), the first and last row, and an evenly spaced stride through the rest, which - covers all four sets across the registries and is the same list on every run. + covers every one of those sets across the registries and is the same list + on every run. """ members = list(registry) @@ -106,7 +107,7 @@ class AppTypeSplitTests(unittest.TestCase): """The shape of the split registry.""" def test_the_base_registry_holds_no_members(self) -> None: - """And that is what makes the four registries declarable at all.""" + """And that is what makes the per-transport registries declarable at all.""" import aenum from pcapkit.const.reg.apptype import AppType, TransportProtocol @@ -131,7 +132,7 @@ class Impossible(WithMembers): # pylint: disable=unused-variable self.assertEqual(len(AppType.__members__), 0) def test_a_member_is_still_an_apptype(self) -> None: - """What the seven ``isinstance`` sites in :mod:`pcapkit.protocols` rely on.""" + """What the ``isinstance`` check in :mod:`pcapkit.protocols` relies on.""" from pcapkit.const.reg.apptype import DCCP, SCTP, TCP, UDP, AppType for cls in (TCP, UDP, SCTP, DCCP): @@ -187,9 +188,9 @@ def test_a_port_lookup_returns_the_canonical_service(self) -> None: """One member, and the one the rest of the world names. IANA names no precedence among the services it registers on a port, and - registry row order does not supply one: of the 44 colliding - ``(port, transport)`` pairs it answers 28 the way :file:`/etc/services` - does and 16 differently, giving ``l2f`` for 1701 and ``shilp`` for 2049. + registry row order does not supply one: on the colliding + ``(port, transport)`` pairs it answers some the way :file:`/etc/services` + does and others differently, giving ``l2f`` for 1701 and ``shilp`` for 2049. So the canonical member is curated from :file:`/etc/services`, which is what :func:`socket.getservbyport` reads. @@ -424,8 +425,8 @@ def test_register_alias_refuses_the_base_registry(self) -> None: ``register_alias`` cannot pick a transport for the caller the way ``get``/``get_all`` do through their ``proto=`` keyword: per-transport - registration is the point, so it has to be called on one of the four - subclasses directly. + registration is the point, so it has to be called on one of the + per-transport subclasses directly. """ from pcapkit.const.reg.apptype import AppType @@ -484,7 +485,7 @@ def test_extend_enum_appends_to_an_occupied_port(self) -> None: self.assertIn('unit-test-80', [member.svc for member in UDP.get_all(80)]) def test_every_registry_rejects_a_negative_value(self) -> None: - """GitHub issue #647's guard, now over five classes rather than one. + """GitHub issue #647's guard, over the base and every per-transport registry. ``ValueError`` specifically, and from every one of them: an ``IntEnum`` with ``settings=NoAlias`` -- the other way to keep two members on one port @@ -541,7 +542,7 @@ def test_a_service_name_is_not_a_port_lookup(self) -> None: self.assertNotIn(-1, TCP.__registry__) def test_unassigned_rows_are_documented_rather_than_declared(self) -> None: - """The 1,004 ``port == -1`` rows and the 704 with no transport protocol. + """The ``port == -1`` rows, and the rows with no transport protocol. They are not members -- there is nothing for a member to be valued on -- so they are rendered as a ``list-table`` in the docstring of the registry @@ -564,16 +565,16 @@ def test_unassigned_rows_are_documented_rather_than_declared(self) -> None: def test_a_real_port_with_no_transport_no_longer_resolves(self) -> None: """The one deliberate behaviour change, pinned so it cannot happen twice. - 124 registry entries carry a real port with an **empty** transport + Some registry entries carry a real port with an **empty** transport protocol column, and the old ``_missing_`` consulted them as a fallback tier after the transport-specific lookup missed -- so ``get(51, proto=tcp)`` answered ``reserved``, claiming a TCP assignment IANA never - made. They are documented on the base class now, and the lookup answers - an unknown port instead, which is the honest answer -- as of GitHub issue + made. They are documented on the base class instead, and the lookup + answers an unknown port, which is the honest answer -- since GitHub issue #860 step 2 PR 2, an unregistered one rather than a permanent mint, so there is nothing left for :meth:`_purge_member` to undo (it no-ops when the name it is asked to remove was never added, which is exactly what - happens here now; kept anyway as a harmless guard against a regression + happens here; kept anyway as a harmless guard against a regression that reintroduced minting). """ from pcapkit.const.reg.apptype import TCP, AppType @@ -626,9 +627,9 @@ def test_get_rejects_an_out_of_range_port_as_the_constructor_does(self) -> None: self.assertEqual(minted.port, 59000) def test_a_span_on_two_transports_answers_each_with_its_own_row(self) -> None: - """GitHub issue #760: source order decided, so the TCP row answered all four. + """GitHub issue #760: source order decided, so the TCP row answered every registry. - IANA registers exactly two port *spans* on more than one transport + IANA registers some port *spans* on more than one transport protocol, and the crawler rendered one ``_missing_`` branch per registry row -- two branches with an identical condition, the second unreachable. Every registry therefore answered with the first: ``AppType.get(6010, @@ -718,7 +719,7 @@ def test_every_transport_named_span_is_claimed_by_one_registry(self) -> None: # which would pass on a prefix collision -- e.g. `claim` # ending in ``TransportProtocol.tc`` would falsely match a # condition actually naming ``TransportProtocol.tcp``. Not - # reachable today, since none of the five declared names + # reachable, since none of the declared names # is a prefix of another, but the check should not depend # on that being true to stay correct. self.assertTrue(condition.endswith(claim), condition) @@ -859,7 +860,7 @@ def test_no_member_carries_a_multi_transport_proto(self) -> None: This test used to sweep every multi-transport member through ``AppType.get(m.port, proto=m.proto)`` and require each of them to be *refused*, because a member's own ``proto`` was the whole set IANA assigned - the service and so named up to four registries. Retyping ``proto`` to the + the service and so named several registries. Retyping ``proto`` to the single transport protocol of the registry the member lives in removes that population outright, and a member's own ``proto`` is now the one thing a lookup can always be given. @@ -1092,16 +1093,15 @@ def test_no_lookup_call_site_in_the_library_builds_a_composite_proto(self) -> No """Why refusing one breaks nothing, asserted rather than taken on trust. The refusal is only safe while every library caller passes a single - transport protocol. There are four call sites into the base registry's lookup - outside :mod:`pcapkit.const`: one in ``Transport._make_port``, which passes - the ``proto`` its six call sites hand it -- a literal member every time, two - per transport in the TCP, UDP and SCTP protocol modules -- and three in the - shared ``PortEnumField.post_process`` in :mod:`pcapkit.corekit.fields.numbers`, - which binds ``proto`` to the member its constructor was handed and then uses - it for ``_dispatch`` and both ``get`` calls. That constructor is called six - times, two per transport in the TCP, UDP and SCTP schemas, each with a - literal member (GitHub issue #1516). None of them can pass a composite, - because none of those modules builds one. + transport protocol. Outside :mod:`pcapkit.const`, the base registry's lookup + is called from ``Transport._make_port``, which passes the ``proto`` its own + callers hand it -- a literal member every time, from the TCP, UDP and SCTP + protocol modules -- and from the shared ``PortEnumField.post_process`` in + :mod:`pcapkit.corekit.fields.numbers`, which binds ``proto`` to the member + its constructor was handed and then uses it for ``_dispatch`` and its + ``get`` calls. That constructor is called from the TCP, UDP and SCTP + schemas, each time with a literal member (GitHub issue #1516). None of + them can pass a composite, because none of those modules builds one. Read off disk rather than through :func:`inspect.getsource`, so this needs no import of :mod:`pcapkit.protocols` -- whose runtime dependencies this @@ -1201,10 +1201,11 @@ def test_no_lookup_call_site_in_the_library_builds_a_composite_proto(self) -> No self.assertEqual(bindings, [('pcapkit/corekit/fields/numbers.py', 'self._proto')]) self.assertEqual(stored, [('pcapkit/corekit/fields/numbers.py', 'proto')]) - # The sixteen the sweep found, so a new one cannot appear without this test - # saying so. ``transport.py`` holds the single lookup and the six literal - # ``_make_port`` arguments that feed it; ``numbers.py`` holds the port - # field's three, and each schema module constructs that field twice. + # The sites the sweep found, so a new one cannot appear without this test + # saying so. ``transport.py`` holds the lookup, fed by the literal + # ``_make_port`` arguments in the TCP, UDP and SCTP modules; ``numbers.py`` + # holds the port field's, and each schema module constructs that field + # once per port. self.assertEqual(sorted(lookups), [ 'pcapkit/corekit/fields/numbers.py _dispatch(proto=proto)', 'pcapkit/corekit/fields/numbers.py get(proto=proto)', @@ -1378,7 +1379,7 @@ def test_every_member_renders_its_own_registrys_transport_protocol(self) -> None derives its expectation from ``member.proto`` instead and so is invariant across this change by construction. - Swept over every declared member of all four registries rather than + Swept over every declared member of every per-transport registry rather than spot-checked, since the blast radius is most of the enumeration. That the sweep reached every one is checked against the members the generated modules declare (see :func:`_declared`), not against counts a vendor diff --git a/tests/const/test_const_enum_builtin_parity.py b/tests/const/test_const_enum_builtin_parity.py index 9033a057f7..7c2900f6d0 100644 --- a/tests/const/test_const_enum_builtin_parity.py +++ b/tests/const/test_const_enum_builtin_parity.py @@ -116,12 +116,12 @@ #: Each was rendering a registry that GitHub issue #647 found unguarded. #: #: Keyed to each template's own guard text rather than one literal shared by -#: all four, kept as a dict rather than collapsed back to one shared literal: +#: all of them, kept as a dict rather than collapsed back to one shared literal: #: GitHub issue #792 moved ``pcapkit.vendor.reg.apptype.apptype``'s copy to an -#: f-string first, deliberately leaving the other three on ``%`` so its own -#: diff over a 12,391-member file stayed reviewable, and GitHub issue #798 -#: swept the remaining three onto the same f-string form. All four now agree, -#: but the dict stays: a future bespoke guard is not guaranteed to match this +#: f-string first, deliberately leaving the others on ``%`` so its own diff over +#: the registry's very large generated file stayed reviewable, and GitHub issue +#: #798 swept the rest onto the same f-string form. They all agree, but the +#: dict stays: a future bespoke guard is not guaranteed to match this #: one's shape, and what #647 actually needs pinned is that each template #: still carries *a* guard rejecting an invalid value, not that every template #: shares one literal. diff --git a/tests/const/test_const_enum_get.py b/tests/const/test_const_enum_get.py index 05ba88da2b..3301da61ef 100644 --- a/tests/const/test_const_enum_get.py +++ b/tests/const/test_const_enum_get.py @@ -14,38 +14,36 @@ The sweep below is the one #584 asked for before fixing ("the real scope is likely wider since most ``const/`` modules are generated from the same -skeleton"). Measured: of the 118 :class:`~aenum.IntEnum` and +skeleton"). Measured: across the :class:`~aenum.IntEnum` and :class:`~aenum.IntFlag` registries defined under :mod:`pcapkit.const`, the -defect was live in 110 -- not just the three the issue named. Three of the -remaining eight never raise on an out-of-range integer because they auto-extend -the whole space, and five carry no ``get(key, default)`` at all. +defect was live in all but a handful -- not just the three the issue named. Of +the rest, some never raise on an out-of-range integer because they auto-extend +the whole space, and the others carry no ``get(key, default)`` at all. -GitHub issue #647 moved one of those three into the sweep, so the arithmetic -was 111 + 2 + 5. :class:`~pcapkit.const.tcp.flags.Flags` resolved every -integer only because it defined no ``_missing_`` to bound its domain; it does -now, so its ``get`` has a failure for ``default`` to fall back from like the -other 110. +GitHub issue #647 moved one of the auto-extending registries into the sweep. +:class:`~pcapkit.const.tcp.flags.Flags` resolved every integer only because it +defined no ``_missing_`` to bound its domain; it defines one, so its ``get`` +has a failure for ``default`` to fall back from like the others. GitHub issue #860 step 2 then brought :class:`~pcapkit.const.ftp.return_code. GroupingInformation` and :class:`~pcapkit.const.ftp.return_code.ResponseKind` onto :class:`~pcapkit.corekit.enum.EnumRegistry`, giving each the base -``get(key, default)`` it never had before -- two fewer of the five with no -integer ``default`` at all, two more in the main sweep. The full arithmetic, -spelled out completely rather than left to imply a total that silently -dropped :class:`~pcapkit.const.pcapng.filter_type.FilterType` (in +``get(key, default)`` it never had before -- moving both out of the set with +no integer ``default`` at all and into the main sweep. The full composition, +spelled out rather than left to imply a total that silently dropped +:class:`~pcapkit.const.pcapng.filter_type.FilterType` (in :data:`EXPECTED_WITHOUT_A_CACHEABLE_FALLBACK`, excused from the main sweep -for a separate reason and covered by its own test below) the way the "111 + -2 + 5" phrasing above always did: 112 (main sweep) + 2 -(:data:`EXPECTED_TO_RESOLVE_ANYTHING`) + 3 -(:data:`EXPECTED_WITHOUT_AN_INTEGER_DEFAULT`) + 1 (``FilterType``) = 118, -matching :meth:`test_the_sweep_size_is_pinned`. - -Two more registries are outside this sweep because they are -:class:`~aenum.StrEnum` rather than integer enums, and both were deliberately +for a separate reason and covered by its own test below): the main sweep, +plus :data:`EXPECTED_TO_RESOLVE_ANYTHING`, plus +:data:`EXPECTED_WITHOUT_AN_INTEGER_DEFAULT`, plus ``FilterType`` -- together, +the population :meth:`test_the_sweep_size_is_pinned` counts. + +Some registries are outside this sweep because they are +:class:`~aenum.StrEnum` rather than integer enums, and were deliberately left alone: :class:`~pcapkit.const.pcapng.option_type.OptionType` and :class:`~pcapkit.const.reg.apptype.AppType` each carry a bespoke integer fallback that already resolves every value, so neither drops a default by -raising. The two string-keyed registries +raising. The string-keyed registries :class:`~pcapkit.const.ftp.command.Command` and :class:`~pcapkit.const.http.method.Method` have no integer path at all; they are the subject of #582 and #583 instead. @@ -320,7 +318,7 @@ def test_the_sweep_size_is_pinned(self) -> None: f'sweep is missing: {expected - names}') def test_every_integer_path_consults_the_default(self) -> None: - """The registry-wide form of #584, across all 120 integer registries.""" + """The registry-wide form of #584, across every integer registry.""" covered = 0 for obj in self.enums: qualname = _qualname(obj) diff --git a/tests/const/test_const_enum_no_mint.py b/tests/const/test_const_enum_no_mint.py index d12f40860c..f540a74aad 100644 --- a/tests/const/test_const_enum_no_mint.py +++ b/tests/const/test_const_enum_no_mint.py @@ -42,7 +42,7 @@ untouched because they do not inherit :class:`~pcapkit.corekit.enum. EnumRegistry` and so have no ``_unregistered_member`` to convert to until GitHub issue #860 lands (blocked on #859); :class:`~pcapkit.const.reg. -apptype.apptype.AppType` is the largest of those at 766 still-minting +apptype.apptype.AppType` is by far the largest of those in still-minting branches. :class:`~pcapkit.const.mh.cga_type.CGAType` keeps minting too, but for a different reason: its ``Tag_`` mint is not an IANA-style range at all (see its own module for why), so the ruling never touched it. @@ -110,11 +110,11 @@ :class:`~pcapkit.const.reg.apptype.sctp.SCTP`, :class:`~pcapkit.const.reg.apptype.dccp.DCCP`) now mix in :class:`~pcapkit.corekit.enum.EnumRegistry` and no longer mint on either of -AppType's two mint sites -- the 766 ``_missing_`` branches, and the one more -inside ``get()`` itself. See :class:`AppTypeUnmintConvertedTests` below, -including the deliberate scope decision on the 8 of those 766 branches that -name a real (if IANA-assigned to a whole span rather than declared -individually) service rather than a placeholder. +AppType's mint sites -- its ``_missing_`` branches, and the one more inside +``get()`` itself. See :class:`AppTypeUnmintConvertedTests` below, including +the deliberate scope decision on those branches that name a real (if +IANA-assigned to a whole span rather than declared individually) service rather +than a placeholder. Untouched, per the owner's ruling on #860 settling the ``needs: decision`` that issue re-opened: :class:`~pcapkit.const.ftp.command.CommandType` keeps @@ -2365,26 +2365,26 @@ class AppTypeUnmintConvertedTests(unittest.TestCase): :class:`~pcapkit.const.reg.apptype.dccp.DCCP` -- brought onto :class:`~pcapkit.corekit.enum.EnumRegistry` and stopped from minting. - Largest of the 9 bespoke classes #860 step 2 converts: measured on - ``c411d072a`` by an AST walk over :meth:`AppType._missing_`, 766 - range-bounded branches -- 754 ``unassigned_`` and 4 - ``reserved_`` placeholders, plus 8 branches naming a real service - IANA assigns to a whole span rather than to one declared member each - (``x11`` for TCP and again for UDP, ``active-net``, ``satvid-datalnk``, - ``vrml-multi-use``, ``ircu``, ``swx``, ``flex-lm``) -- plus one more, - independent mint site inside :meth:`AppType.get` itself - (``PORT__``, labelled ``'unknown'``, for a port neither + Largest of the bespoke classes #860 step 2 converts: an AST walk over + :meth:`AppType._missing_` on ``c411d072a`` found range-bounded branches + -- placeholders (``unassigned_`` and ``reserved_``), and + branches naming a real service IANA assigns to a whole span rather than + to one declared member each (``x11`` for TCP and again for UDP, + ``active-net``, ``satvid-datalnk``, ``vrml-multi-use``, ``ircu``, ``swx``, + ``flex-lm``) -- plus one more, independent mint site inside + :meth:`AppType.get` itself (``PORT__``, labelled + ``'unknown'``, for a port neither ``_missing_``'s ranges nor the registry's own declared members cover). A deliberate scope decision, stated here because a reviewer could - reasonably expect the ``FEATCode`` precedent instead: the 8 real-name + reasonably expect the ``FEATCode`` precedent instead: the real-name spans above convert to :meth:`~pcapkit.corekit.enum. - EnumRegistry._unregistered_member` exactly like the 758 placeholder - spans, *not* declared as real, individually-listed members the way #860 - step 2's PR 1 declared ``FEATCode``'s 15. ``FEATCode``'s fix addressed a + EnumRegistry._unregistered_member` exactly like the placeholder spans, + *not* declared as real, individually-listed members the way #860 step 2's + PR 1 declared ``FEATCode``'s. ``FEATCode``'s fix addressed a *different* defect -- a const module minting members as a side effect of merely being imported, which does not exist here, since every one of - these 766 spans mints only on an actual port lookup -- and the owner's + these spans mints only on an actual port lookup -- and the owner's ruling for the whole ``AppType`` family draws no distinction between a real name and a placeholder: GitHub issue #860 settled that ``get()`` must not mint regardless of whether the value it would construct is a diff --git a/tests/const/test_const_ethertype_862_unit.py b/tests/const/test_const_ethertype_862_unit.py index 67516964f0..fe8792cb90 100644 --- a/tests/const/test_const_ethertype_862_unit.py +++ b/tests/const/test_const_ethertype_862_unit.py @@ -23,7 +23,7 @@ :meth:`~pcapkit.vendor.reg.ethertype.EtherType._insert_range` places each new range immediately ahead of the first already-placed range that fully contains it, leaving every non-overlapping pair in the CSV's own row order. Sweeping -all 56 range tests in the committed, generated file (measured directly against +every range test in the committed, generated file (measured directly against ``main`` at ``70fa92010``, the #861 merge commit this issue was blocked on) found this to be the *only* containment pair among them -- no other subsumed range exists in :class:`~pcapkit.const.reg.ethertype.EtherType` today, so diff --git a/tests/const/test_const_ftp_featcode_case_903_unit.py b/tests/const/test_const_ftp_featcode_case_903_unit.py index b52849db77..c11e3a87a9 100644 --- a/tests/const/test_const_ftp_featcode_case_903_unit.py +++ b/tests/const/test_const_ftp_featcode_case_903_unit.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- """``FEATCode.get`` must be case-insensitive, per RFC 5797 Section 2. -GitHub issue #903, the registry-wide case-sensitivity audit. Of the 127 -registries under :mod:`pcapkit.const` and the 24 non-registry enumerations +GitHub issue #903, the registry-wide case-sensitivity audit. Of the +registries under :mod:`pcapkit.const` and the non-registry enumerations elsewhere, :class:`~pcapkit.const.ftp.command.FEATCode` is the one the audit found on the wrong side of the owner's ruling: it did no case folding at all, so it ran the case-sensitive default, while the document defining the very @@ -174,7 +174,7 @@ def test_no_two_members_collide_when_folded(self) -> 'None': case-insensitive comparison."* If that ever stopped holding in the crawled registry, folding would start resolving one of the colliding pair arbitrarily -- so it is asserted rather than assumed. Measured - across all 151 enumerations in the tree while auditing #903: + across every enumeration in the tree while auditing #903: :class:`~pcapkit.const.hip.parameter.Parameter` is the *only* one with a name-fold collision (``R1_Counter`` against ``R1_COUNTER``, both IANA-registered), and **no** enumeration anywhere has a ``str``-value diff --git a/tests/const/test_const_linktype_209_unit.py b/tests/const/test_const_linktype_209_unit.py index f3602e1021..21368927a6 100644 --- a/tests/const/test_const_linktype_209_unit.py +++ b/tests/const/test_const_linktype_209_unit.py @@ -582,8 +582,8 @@ class LinkTypeGeneratorSignedOrUnderscoredValueTests(unittest.TestCase): same class of under-count the range-expansion fix above closes, just for a different reason ``_expand`` can fail to recognise a value. - Not reachable against tcpdump's live table today: every one of the 220 - committed members matches a plain unsigned decimal, so this is a latent + Not reachable against tcpdump's live table: every committed member + matches a plain unsigned decimal, so this is a latent hole rather than a live defect, exactly as #844 and #852's original word-only rule was. :meth:`process`'s ``_expand`` now tries ``int(temp)`` directly, before the en-dash range check, so it recognises the same diff --git a/tests/corekit/test_enum_lookup_base_unit.py b/tests/corekit/test_enum_lookup_base_unit.py index d90833c565..6738556682 100644 --- a/tests/corekit/test_enum_lookup_base_unit.py +++ b/tests/corekit/test_enum_lookup_base_unit.py @@ -15,7 +15,7 @@ What this module pins, and why each part is worth pinning: -* the split is where it was ruled to be -- three methods on the base, the five +* the split is where it was ruled to be -- the lookup methods on the base, the mutating ones still on :class:`~pcapkit.corekit.enum.EnumRegistry`, asserted as an **exact** partition rather than as mere presence, so that a later change cannot quietly migrate one across (:class:`TwoTierSplitTests`); @@ -191,7 +191,7 @@ def test_the_bare_base_offers_no_way_to_mutate(self) -> 'None': self.assertFalse(hasattr(EnumLookup, name)) def test_registries_still_reach_every_mutating_method(self) -> 'None': - """And the registry tier keeps all five, inherited or not.""" + """And the registry tier keeps every mutating method, inherited or not.""" for name in MUTATING: with self.subTest(method=name): self.assertTrue(callable(getattr(_PickleInt, name))) diff --git a/tests/corekit/test_enum_lookup_reparent_877_unit.py b/tests/corekit/test_enum_lookup_reparent_877_unit.py index 927992a48a..34f2057bf0 100644 --- a/tests/corekit/test_enum_lookup_reparent_877_unit.py +++ b/tests/corekit/test_enum_lookup_reparent_877_unit.py @@ -244,7 +244,7 @@ def test_wireguard_key_label_get(self) -> None: def test_a_pure_reparent_still_refuses_an_unknown_name(self) -> None: """The base's own contract -- raise, never mint -- reaches these nine - for free, exactly as it does the 124 registries.""" + for free, exactly as it does the registries.""" from pcapkit.corekit.infoclass import FinalisedState with self.assertRaises(KeyError): @@ -287,8 +287,8 @@ def test_unrecognised_name_still_raises_naming_the_key(self) -> None: the refusal now reaches the caller as the base's own :exc:`~pcapkit.utilities.exceptions.EnumKeyError`. Updated from the pre-#923 tree, which asserted ``assertNotIsInstance(..., KeyError)``: - that assertion described the minority shape -- #923's census found 119 - of the 127 concrete subclasses answering a name miss with a + that assertion described the minority shape -- #923's census found + most concrete subclasses answering a name miss with a :exc:`KeyError` -- and #923's ruling is that a name miss follows stdlib ``E['nosuch']`` and stays :exc:`KeyError`-derived. The message is unchanged, so the two ``assertIn``\\ s below are the same ones that diff --git a/tests/corekit/test_enum_lookup_reparent_930_unit.py b/tests/corekit/test_enum_lookup_reparent_930_unit.py index c12b30af58..996af557fd 100644 --- a/tests/corekit/test_enum_lookup_reparent_930_unit.py +++ b/tests/corekit/test_enum_lookup_reparent_930_unit.py @@ -2,8 +2,8 @@ """GitHub issue #930, the blocked half of #877's phase 2: re-parenting the last seven non-registry enumerations onto :class:`~pcapkit.corekit.enum.EnumLookup`. -GitHub pull request #921 re-parented 17 of the 24 non-registry enumerations and deliberately -left seven alone, because the files holding them were still open under other pull +GitHub pull request #921 re-parented every other non-registry enumeration and deliberately +left these seven alone, because the files holding them were still open under other pull requests at the time: :mod:`pcapkit.const.ftp.command` (``CommandType``, ``ConformanceRequirement``) under #913, and :mod:`pcapkit.protocols.internet.esp` (``ESPStatus``) plus :mod:`pcapkit.protocols.internet.mh` @@ -37,7 +37,7 @@ and ``list(cls)`` agree at 6 and 4 -- so what each docstring called "Backport support for original codes" was the int-or-name dual resolution :meth:`~pcapkit.corekit.enum.EnumLookup.get` already provides for every other -:class:`int`-valued registry in this tree. Checked before acting on it: none of the 20 call +:class:`int`-valued registry in this tree. Checked before acting on it: none of the call sites either override had (all in tests, none in :mod:`pcapkit`) passed a key the base would have resolved differently. There was nothing left to backport, so ``get``/``get_all`` on both now come from the base alone, the same as the five classes below that were pure @@ -661,10 +661,10 @@ class ZeroRemainOutsideEnumLookupTests(unittest.TestCase): """The census this issue exists to finish: a runtime walk over every importable :mod:`pcapkit.*` module (vendor templates excluded), filtering on ``issubclass(cls, EnumLookup)``, must now find **zero** enumerations - outside the hierarchy -- the assertion that stops this recurring a - fourth time. Nested classes are walked too, since GitHub issue #877's own - count of 24 non-registry enumerations includes the seven ``httpv2`` - ``Flags`` classes nested inside schema classes. + outside the hierarchy -- the assertion that stops this recurring yet + again. Nested classes are walked too, since GitHub issue #877's own + census of non-registry enumerations includes the ``httpv2`` ``Flags`` + classes nested inside schema classes. """ def test_the_walk_found_something_to_count(self) -> None: diff --git a/tests/corekit/test_fields_collections.py b/tests/corekit/test_fields_collections.py index 4ad4a04f7b..ddebda439e 100644 --- a/tests/corekit/test_fields_collections.py +++ b/tests/corekit/test_fields_collections.py @@ -116,7 +116,7 @@ def test_the_area_left_unread_after_the_eool_is_reported_as_padding(self) -> Non class OptionFieldForeignBaseSchemaTests(unittest.TestCase): """Base schemas that the read-the-type-field-only shortcut does not fit. - Nothing in this package declares one -- all 34 ``OptionField`` declarations put + Nothing in this package declares one -- every ``OptionField`` declaration puts the type field first as a fixed-width number -- but ``OptionField`` is public and :mod:`pcapkit.foundation.registry` invites third-party protocols to register their own base schemas, which need not. @@ -330,8 +330,8 @@ class ListFieldSchemaItemTests(unittest.TestCase): ``field``, discarding whatever the copy carries. C.f. #433. No declaration in this package passes either argument, so nothing here - parses differently today; both cases below construct a ``ListField`` - directly rather than through one of the four in-tree declarations, since + parses differently; both cases below construct a ``ListField`` + directly rather than through one of the in-tree declarations, since those are exactly the shape that hides the bug. """ diff --git a/tests/corekit/test_fields_ipaddress.py b/tests/corekit/test_fields_ipaddress.py index 1a99485a15..406c4ae985 100644 --- a/tests/corekit/test_fields_ipaddress.py +++ b/tests/corekit/test_fields_ipaddress.py @@ -158,7 +158,7 @@ def test_pre_process_malformed_value_raises_in_library_error(self) -> None: :exc:`FieldValueError` for a value that is merely the wrong IP version. So ``except BaseError`` could not reliably catch a bad field value: whether the exception was in-library depended on *how* the - value was wrong. All four public field classes must now raise + value was wrong. Every public field class must raise :exc:`FieldValueError` here too, with the original :mod:`ipaddress` message preserved. """ @@ -521,7 +521,7 @@ def test_switch_backed_address_makers_reject_a_bool(self) -> None: with no error at all, and ``addr=True`` gave an IPv4 ``MPTCPAddAddress`` with ``address=IPv4Address('0.0.0.1')``. - The five ``mh`` sites are covered next to the rest of that module, in + The ``mh`` sites are covered next to the rest of that module, in ``MHUnitTests.test_mh_length_derived_addresses_reject_a_bool``. """ from pcapkit.const.hip.parameter import Parameter diff --git a/tests/corekit/test_fields_misc.py b/tests/corekit/test_fields_misc.py index 70fce943f7..973e9e6f93 100644 --- a/tests/corekit/test_fields_misc.py +++ b/tests/corekit/test_fields_misc.py @@ -214,12 +214,12 @@ def _resolve(module: 'str', name: 'str', attr: 'str') -> 'tuple[object, object]' def test_address_typed_switch_branches_already_reject_a_bool(self) -> None: """Every address-typed branch of every address-typed switch already refuses a bool. - Eighteen branches over ten switches in four protocol modules -- not just - :mod:`~pcapkit.protocols.schema.internet.mh`'s six -- because the claim + Every such branch, across the protocol modules -- not just + :mod:`~pcapkit.protocols.schema.internet.mh`'s -- because the claim being pinned is about ``SwitchField`` in general, so a fix scoped to one module would not settle it. Measured on ``main`` at ``27bb315d5``, i.e. - *before* #508's fix: all thirty-six probes (eighteen branches x - ``True``/``False``) raised, and none was laundered. That is what makes a + *before* #508's fix: every probe (each branch, with ``True`` and with + ``False``) raised, and none was laundered. That is what makes a guard in ``SwitchField`` dead code. """ from pcapkit.corekit.fields.misc import SwitchField diff --git a/tests/corekit/test_sentinel_exports_unit.py b/tests/corekit/test_sentinel_exports_unit.py index 3c75d73d6b..c2765c1f46 100644 --- a/tests/corekit/test_sentinel_exports_unit.py +++ b/tests/corekit/test_sentinel_exports_unit.py @@ -40,11 +40,11 @@ object like this one, but under the privacy ruling stated below, which treats a sentinel documented as private as having no place in :attr:`__all__` at all. -A follow-up to this same issue moved all four *definitions* into +A follow-up to this same issue moved every sentinel's *definition* into :mod:`pcapkit.corekit.sentinels`: the owner chose one shared module over one module per sentinel, on #911. The shared module is where the ``Type`` naming convention and the rules for when to add ``__bool__``, ``__copy__`` or ``__reduce__`` -can sit together, which four near-empty files would scatter. +can sit together, which a near-empty file per sentinel would scatter. Every assertion above still holds unchanged, since it is about each original module's ``__all__``, which the re-export shims left untouched; what changed is only :attr:`type.__module__` for the four types, which @@ -52,7 +52,7 @@ checks against :data:`CANONICAL_MODULE` rather than against a different module per sentinel. -GitHub issue #937 later renamed two of the four *objects* to SCREAMING_SNAKE -- +GitHub issue #937 later renamed two of the *objects* to SCREAMING_SNAKE -- ``NoValue`` to ``NO_VALUE`` and ``_Absent`` to ``ABSENT``, the latter also dropping its leading underscore -- so every instance name agrees on one casing. Privacy for what is now ``ABSENT`` stopped being signalled by the name at all and became @@ -138,21 +138,21 @@ # every ``assertIs`` against the canonical one would fail. The sentinels are read # through :func:`_sentinels` after :func:`~tests._support.reimport_once_per_class`. -#: Repository root, for the two tests that read a file rather than import it. +#: Repository root, for the tests that read a file rather than import it. ROOT = pathlib.Path(__file__).resolve().parents[2] -#: Where all four sentinels are now *defined*: the single shared module GitHub +#: Where every sentinel is *defined*: the single shared module GitHub #: issue #911 chose over one module per sentinel. Each entry in :data:`SENTINELS` #: below used to name a different module here (``pcapkit.corekit.module``, #: ``pcapkit.corekit.fields.field``, ``pcapkit.corekit.enum`` and -#: ``pcapkit.protocols.protocol`` respectively); all four now report this one. +#: ``pcapkit.protocols.protocol`` respectively); each reports this one. CANONICAL_MODULE = 'pcapkit.corekit.sentinels' #: Every sentinel in the tree that follows the house ``Type`` convention, -#: as ``(instance name, instance, type)``. Four, not the three +#: as ``(instance name, instance, type)``. That is more sentinels than #: :file:`docs/source/contributing/conventions/sentinel-convention.rst` used to #: document -- see the module docstring. -#: All four now share :data:`CANONICAL_MODULE` as their defining module, which is +#: Every one shares :data:`CANONICAL_MODULE` as its defining module, which is #: why a per-entry module column is no longer part of this tuple -- see #: :data:`PUBLIC_SENTINELS` below for the (still distinct) *shim* locations. #: Built by :func:`_sentinels` from the live import, not at module load. @@ -367,7 +367,7 @@ def test_every_sentinel_object_is_screaming_snake(self) -> 'None': Neither ``NoValue`` (``N``, ``o``, ``V``, ... mixed case) nor ``_Absent`` (leading underscore, mixed case) matches ``^[A-Z][A-Z0-9_]*$``, so this test fails twice over on that tree -- once for each -- and passes on this one for - all four. + every sentinel. """ pattern = re.compile(r'^[A-Z][A-Z0-9_]*$') @@ -491,7 +491,7 @@ class SentinelBehaviourTests(_ReimportCase): documents. Not part of the export change, and asserted here because the doc edit that goes - with it makes claims about all four -- an undocumented ``__bool__`` or a missing + with it makes claims about every sentinel -- an undocumented ``__bool__`` or a missing ``__repr__`` would make the corrected prose wrong in a way no other test sees. """ diff --git a/tests/corekit/test_sentinels_housing_unit.py b/tests/corekit/test_sentinels_housing_unit.py index c16e88cf4e..bae6ca5564 100644 --- a/tests/corekit/test_sentinels_housing_unit.py +++ b/tests/corekit/test_sentinels_housing_unit.py @@ -1,18 +1,18 @@ # -*- coding: utf-8 -*- -"""GitHub issue #911's housing half: one module for all four sentinels. +"""GitHub issue #911's housing half: one module for every sentinel. The `__all__` half of #911 landed as #916 and is pinned by :mod:`tests.corekit.test_sentinel_exports_unit`. The owner left the second -question -- where the four sentinels should be *defined* -- open, offering +question -- where the sentinels should be *defined* -- open, offering either one module per sentinel or one module for all of them, and settled it with -a one-line ruling once offered the choice: one module for all four. +a one-line ruling once offered the choice: one module for all of them. -So :mod:`pcapkit.corekit.sentinels` is now the single defining module for all -four -- :class:`~pcapkit.corekit.sentinels.NullType`, +So :mod:`pcapkit.corekit.sentinels` is the single defining module for every +sentinel -- :class:`~pcapkit.corekit.sentinels.NullType`, :class:`~pcapkit.corekit.sentinels.NoValueType`, :class:`~pcapkit.corekit.sentinels.NoDefaultType` and -:class:`~pcapkit.corekit.sentinels.AbsentType`, and their four instances. The -four original modules (:mod:`pcapkit.corekit.module`, +:class:`~pcapkit.corekit.sentinels.AbsentType`, and their instances. The +original modules (:mod:`pcapkit.corekit.module`, :mod:`pcapkit.corekit.fields.field`, :mod:`pcapkit.corekit.enum` and :mod:`pcapkit.protocols.protocol`) kept a re-export of each until GitHub issue #1744 dropped them, under the ruling on #1715 that a moved name keeps no @@ -51,7 +51,7 @@ "on purpose" rather than left to the pre-existing ``cyclic-import`` findings :command:`pylint` reports for this package, which run to hundreds and would swallow one more without comment: that :mod:`pcapkit.corekit.sentinels` itself -imports nothing from any of the four modules it is now depended on by, so the +imports nothing from any of the modules that depend on it, so the dependency graph between them is a star with :mod:`pcapkit.corekit.sentinels` at the centre and no edge pointing back into it. @@ -129,7 +129,7 @@ def test_sentinels_module_imports_none_of_its_four_consumers(self) -> 'None': :mod:`pcapkit.corekit.enum` or :mod:`pcapkit.protocols.protocol` -- each of which imports *it*. Walked with :mod:`ast` rather than grepped for the dotted name as plain text, because the module's own docstring above - names all four *in prose*, explaining where each sentinel used to live -- + names those modules *in prose*, explaining where each sentinel used to live -- a text search would flag that explanation as if it were the cycle it is warning readers there is no longer any risk of. @@ -178,7 +178,7 @@ def test_sentinels_module_imports_cleanly_on_its_own(self) -> 'None': def test_each_consumer_module_still_imports_cleanly_on_its_own(self) -> 'None': """The other direction: importing a consumer first must not deadlock either. - Each of the four is tried as the *first* thing imported after a purge, + Each consumer is tried as the *first* thing imported after a purge, one at a time -- the order a cycle would actually be sensitive to, since a cycle through ``pcapkit.corekit.sentinels`` would surface as whichever of the two modules is entered second finding the other only diff --git a/tests/dumpkit/test_nameless_enum_rendering_unit.py b/tests/dumpkit/test_nameless_enum_rendering_unit.py index 2c8b1a336c..6d99bf4f75 100644 --- a/tests/dumpkit/test_nameless_enum_rendering_unit.py +++ b/tests/dumpkit/test_nameless_enum_rendering_unit.py @@ -104,10 +104,10 @@ class NamelessEnumRenderingTests(unittest.TestCase): sixteen-bit field :class:`~pcapkit.const.tcp.flags.Flags` bounds its :meth:`~enum.Enum._missing_` to. That guard is correct, so the probe was what had to move: a value the registry is right to refuse cannot also be a - value the dumper renders. Every one of the library's six flag registries - carries such a guard, at three distinct widths, so exempting the guarded + value the dumper renders. Every one of the library's flag registries + carries such a guard, at differing widths, so exempting the guarded ones instead would have left this half of the sweep with nothing in it at - all. (GitHub issue #808 retyped the seventh, ``TransportProtocol``, out of + all. (GitHub issue #808 retyped another, ``TransportProtocol``, out of this sweep entirely -- see ``test_no_flag_registry_renders_the_literal_none``'s docstring below.) @@ -244,12 +244,12 @@ def test_no_flag_registry_renders_the_literal_none(self) -> None: """Every flag enumeration in the library, swept rather than sampled. The sweep is the point: #648 was first reported against - :class:`pcapkit.const.tcp.flags.Flags` alone, and five of the six flag - registries turn out to be nameless at zero -- ``Flags`` plus the four + :class:`pcapkit.const.tcp.flags.Flags` alone, and most of the flag + registries turn out to be nameless at zero -- ``Flags`` plus the Mobility Header flag registries. Naming them here would rot the moment - a seventh is added, so they are discovered. + another is added, so they are discovered. - GitHub issue #808 dropped this sweep from seven registries to six: + GitHub issue #808 dropped one registry from this sweep: :class:`~pcapkit.const.reg.apptype.TransportProtocol` was a bounded :class:`~aenum.IntFlag` before that issue and is a plain :class:`~aenum.IntEnum` after, so it no longer matches the @@ -311,9 +311,9 @@ def test_no_flag_registry_renders_the_literal_none(self) -> None: def test_a_value_past_the_field_is_refused_rather_than_rendered(self) -> None: """#702 -- the probe that was wrong, asserted the right way round. - All six flag registries bound their :meth:`~enum.Enum._missing_` to - the width of their own field, and the widths differ: three bits for - :class:`~pcapkit.const.ftp.command.CommandType`, eight for three of the + Every flag registry bounds its :meth:`~enum.Enum._missing_` to + the width of its own field, and the widths differ: three bits for + :class:`~pcapkit.const.ftp.command.CommandType`, eight for the other Mobility Header flags, sixteen for ``BindingUpdateFlag`` and :class:`~pcapkit.const.tcp.flags.Flags`. One literal therefore cannot mean "past the field" for all of them, which is the whole reason @@ -324,20 +324,19 @@ def test_a_value_past_the_field_is_refused_rather_than_rendered(self) -> None: holds only if the mask :func:`_field_mask` computes is exactly the bound each registry wrote down for itself. - Until GitHub issue #808 there were seven registries and four distinct - widths here, the fourth being + Until GitHub issue #808 another width sat here too, :class:`~pcapkit.const.reg.apptype.TransportProtocol`'s four bits -- derived as ``max(cls.__members__.values()) * 2 - 1`` since it extended itself at runtime and could not hard-code a bound. #808 retyped it to a plain :class:`~aenum.IntEnum`, dropping it out of :func:`_flag_registries`' - sweep entirely (see the class docstring above), which is why three - widths remain rather than four. + sweep entirely (see the class docstring above), which is why its width + no longer appears. - ``65536`` survives here, as the bound of the two sixteen-bit registries + ``65536`` survives here, as the bound of the sixteen-bit registries -- asserted as the rejection it always was, rather than as a value the dumper was expected to render. Which also keeps the ``raise`` in those - guards covered: five of the six were never reached by any test, and the - sixth was reached only by this file failing on it. + guards covered: all but one were never reached by any test, and that + one was reached only by this file failing on it. """ registries = _flag_registries() @@ -441,7 +440,7 @@ def _field_mask(registry: 'FlagRegistry') -> int: """The width of *registry*'s field, as an all-ones mask. Every flag registry in the library bounds its :meth:`~enum.Enum._missing_` - to the field its declared bits live in, and for all six of them that bound + to the field its declared bits live in, and for every one of them that bound is exactly the smallest all-ones mask covering every declared bit -- ``0xFFFF`` for ``Flags``' ``1 << 4 .. 1 << 15``, ``0xFF`` for the eight-bit Mobility Header flags, ``0x07`` for the three-bit @@ -493,9 +492,8 @@ def _nameless_values(registry: 'FlagRegistry') -> 'tuple[int, ...]': A registry whose declared bits fill its field has no nameless value at all and yields an empty tuple. :class:`~pcapkit.const.ftp.command.CommandType` - is of that shape, declaring ``0`` as ``undefined``, which is why five of - the six registries :func:`_flag_registries` discovers are nameless at zero - rather than all six. + is of that shape, declaring ``0`` as ``undefined``, which is why not every + registry :func:`_flag_registries` discovers is nameless at zero. :class:`~pcapkit.const.reg.apptype.TransportProtocol` used to be a second example of the same shape before GitHub issue #808 retyped it out of the sweep entirely -- see :func:`_field_mask`'s docstring. diff --git a/tests/foundation/registry/test_protocols.py b/tests/foundation/registry/test_protocols.py index 1943638008..d0d91f6d52 100644 --- a/tests/foundation/registry/test_protocols.py +++ b/tests/foundation/registry/test_protocols.py @@ -282,7 +282,7 @@ def test_sibling_registries_name_what_they_displaced(self) -> None: :func:`~pcapkit.foundation.registry.protocols.register_protocol`, and it is the part of #681 that does generalise. - All seven code-keyed registrars are covered, including the two that reach + Every code-keyed registrar is covered, including those that reach :meth:`Transport.register ` through :class:`~pcapkit.protocols.transport.tcp.TCP` and @@ -847,8 +847,8 @@ def test_register_apptype_null_sentinel_still_means_absent_with_a_class_module(s def test_register_tcp_bad_class_name_raises_protocolerror(self) -> None: """GitHub issue #832: the fix is family-wide, not one function. - :func:`register_apptype` is not the only one of the nine ``register_*`` - wrappers that builds a :class:`~pcapkit.corekit.module.ModuleDescriptor` + :func:`register_apptype` is not the only ``register_*`` + wrapper that builds a :class:`~pcapkit.corekit.module.ModuleDescriptor` from a :class:`str` ``module`` -- :func:`register_tcp` is a sibling that shares the same :attr:`ModuleDescriptor.klass` resolution, so it must fail a bad class name the same way. diff --git a/tests/integration/test_pcapng_end_to_end.py b/tests/integration/test_pcapng_end_to_end.py index e02c8a0f17..89e2d992fe 100644 --- a/tests/integration/test_pcapng_end_to_end.py +++ b/tests/integration/test_pcapng_end_to_end.py @@ -8,7 +8,7 @@ pins the exact block inventory *and* dumps a real report file, which is the part that was never covered. -The six fixtures and what each is for are documented in the module docstring of +The fixtures and what each is for are documented in the module docstring of :file:`examples/generators/pcapng.py`, which also records the parser defects they provoke -- those show up as log noise here and are not assertions. diff --git a/tests/project/test_annotation_names.py b/tests/project/test_annotation_names.py index eb248c6f52..76d1f37cc3 100644 --- a/tests/project/test_annotation_names.py +++ b/tests/project/test_annotation_names.py @@ -5,8 +5,8 @@ need inside an ``if TYPE_CHECKING:`` block. Nothing at runtime evaluates those strings, so a name that is *never imported at all* costs nothing until a type checker or a documentation build looks at it -- at which point it is an error in a -file that has been passing tests for months. Issue #642 found three, and mypy -2.3.1 agreed the three were the complete set: +file that has been passing tests for months. Issue #642 found these, and mypy +2.3.1 agreed they were the complete set: .. code-block:: text @@ -16,16 +16,16 @@ This module is the same check without mypy: cheap enough to run on every commit, and it does not depend on a type checker being installed or on which version of -one. Run against the tree that carried those three defects it reports exactly -those three, name for name and line for line, which is what says it is measuring +one. Run against the tree that carried those defects it reports exactly +those, name for name and line for line, which is what says it is measuring the right thing. A deliberate non-goal: this says nothing about whether the annotations resolve at *runtime*. They do not, and not because of anything this catches -- ``TYPE_CHECKING`` is :data:`False` when the interpreter runs, so a ``TYPE_CHECKING``-only import is absent from the module namespace either way. -:func:`typing.get_type_hints` raises :exc:`NameError` on five of the six annotated -functions in :mod:`pcapkit.utilities.logging`, four of them for ``Optional`` and +:func:`typing.get_type_hints` raises :exc:`NameError` on most of the annotated +functions in :mod:`pcapkit.utilities.logging`, mostly for ``Optional`` and ``Union``, which *are* imported in its ``TYPE_CHECKING`` block. Making those resolve is a repository-wide decision about the idiom, not a missing import, and is out of scope here. What this module pins is the narrower and entirely @@ -56,8 +56,8 @@ def annotation_strings(tree: 'ast.AST') -> 'Iterator[tuple[str, int]]': """Yield every string literal ``tree`` uses as a type, with its line number. - Four places a string is a type rather than a value, and all four are used in - this package: a variable annotation, a parameter annotation, a return + These are the places a string is a type rather than a value, and each is used + in this package: a variable annotation, a parameter annotation, a return annotation, and the first argument of :func:`typing.cast`. The ``cast`` case is the one that is easiest to miss and is exactly where ``ipv6_route.py:271``'s ``Optional`` hid -- :func:`typing.cast` never diff --git a/tests/project/test_capture_tracking.py b/tests/project/test_capture_tracking.py index 140330c2ea..fce869df18 100644 --- a/tests/project/test_capture_tracking.py +++ b/tests/project/test_capture_tracking.py @@ -9,11 +9,11 @@ inputs -- :file:`out.json`, :file:`out.plist`, :file:`out.txt` and :file:`pcapng.txt`, via ``make fixtures`` there. -Those four reports were tracked once, and GitHub issue #685 is why they are not -any more. A tracked report has no reader: no test asserts on one, and the -documentation only quotes them as prose. So a parser change that alters how a +Those reports were tracked once, and GitHub issue #685 is why they are not. A +tracked report has no reader: no test asserts on one, and the documentation +only quotes them as prose. So a parser change that alters how a frame renders leaves the committed copy wrong with nothing anywhere to say so -- -:file:`pcapng.txt` sat recording ``packet -> NIL`` for four blocks that had +:file:`pcapng.txt` sat recording ``packet -> NIL`` for blocks that had started carrying their captured octets, and it was found by somebody reading the file rather than by anything failing. @@ -24,10 +24,10 @@ * ``git add -f examples/captures/out.txt`` on a freshly rebuilt report puts the staleness straight back, :file:`.gitignore` notwithstanding -- and so would a new ``!examples/captures/...`` exception line; -* an over-eager cleanup that dropped the two real inputs as well would break the +* an over-eager cleanup that dropped the real inputs as well would break the whole unit tier, which is entitled to read them on a fresh clone. -The rule is stated by *suffix* rather than as a list of the two names, so adding +The rule is stated by *suffix* rather than as a list of names, so adding a genuine input capture needs no edit here while committing a rendered report fails immediately. That is the same trade :mod:`tests._tiers` makes, and this module reuses its answer rather than shelling out to git a second time. @@ -45,12 +45,12 @@ #: Reports rendered by :file:`examples/legacy_smoke/`, none of which git tracks. #: Named explicitly, rather than derived as "everything without a capture -#: suffix", because these four are the ones that were tracked and the ones any +#: suffix", because these are the ones that were tracked and the ones any #: regression would most likely reinstate. RENDERED_REPORTS = ('out.json', 'out.plist', 'out.txt', 'pcapng.txt') #: The captures that must stay committed, because nothing regenerates them: -#: :file:`in.pcap` is read by roughly fifty modules and :file:`dhcp.pcapng` by -#: nine, and the unit tier reads both on a fresh clone. +#: :file:`in.pcap` and :file:`dhcp.pcapng` are each read by many test modules, +#: and the unit tier reads both on a fresh clone. INPUT_CAPTURES = ('dhcp.pcapng', 'in.pcap') @@ -94,7 +94,7 @@ def test_no_rendered_report_is_tracked(self) -> None: Redundant with :meth:`test_every_tracked_file_is_an_input_capture` today and deliberately so: that test's reach depends on :data:`~tests._tiers.CAPTURE_SUFFIXES`, and a future ``.txt`` capture - format would widen the suffix list and quietly let these four back in. + format would widen the suffix list and quietly let these back in. """ for name in RENDERED_REPORTS: @@ -140,7 +140,7 @@ class ReportReadTests(unittest.TestCase): This is the regression untracking invites, and it is *not* covered by the tier guard's own audit. That audit only flags a **unit-tier** module reading - a capture git does not track. These four are worse than untracked: nothing + a capture git does not track. These reports are worse than untracked: nothing rebuilds them as part of fixture generation either, because :file:`examples/generators/make_samples.py` does not produce them -- only ``make fixtures`` under :file:`examples/legacy_smoke/` does, and neither CI diff --git a/tests/project/test_ci_timing.py b/tests/project/test_ci_timing.py index 867eaca3c1..a980f427d5 100644 --- a/tests/project/test_ci_timing.py +++ b/tests/project/test_ci_timing.py @@ -844,7 +844,7 @@ def test_the_legs_the_review_reads_exist(self) -> 'None': self.assertEqual([f'Python {version}' for version in coverage], [ci_timing.COVERAGE_JOB]) def test_the_reusable_workflow_asks_for_no_write_permission(self) -> 'None': - """Its four callers grant ``contents: read``, so a write scope would break them.""" + """Its callers grant ``contents: read``, so a write scope would break them.""" code = '\n'.join(line.split('#', 1)[0] for line in self.text.splitlines()) self.assertNotRegex(code, r'(?m)^\s+[\w-]+:\s*write\s*$') diff --git a/tests/project/test_conventions_doc_claims.py b/tests/project/test_conventions_doc_claims.py index b38d525afe..c53ee04fe8 100644 --- a/tests/project/test_conventions_doc_claims.py +++ b/tests/project/test_conventions_doc_claims.py @@ -2,7 +2,7 @@ """Claims the split *House Conventions* pages make that the tree can be asked about. :file:`docs/source/contributing/conventions.rst` used to record every design ruling -on one 966-line page, and most of what it records is reasoning -- which no test can +on a single page, and most of what it records is reasoning -- which no test can check. Some of it is not: a count of classes, a per-class classification, a retired name, an exception type. Those are the parts that rot silently, because Sphinx builds without ``-W`` and without ``nitpicky``, so a page whose every factual claim has gone @@ -15,7 +15,7 @@ structure: * :class:`ConventionAnchorTests` -- every ``.. _label:`` anchor, one now per - file. Before the split the original four lived on one page, and + file. Before the split the original anchors lived on one page, and ``tests/corekit/test_sentinel_exports_unit.py`` sliced the file *between* two of them -- which is exactly what GitHub issue #930 named as the split's concrete blocker, since separating those two anchors into different files made that slice @@ -32,7 +32,7 @@ * :class:`ExtensionHeaderClassificationTests` -- the page's bases-per-header table against the declarations themselves. ``tests/protocols/internet/test_ipv6_ext_unit.py`` already pins the *code* to the ruling; nothing pinned the *page* to the code, which is - the half that goes stale when a ninth header lands. + the half that goes stale when a new header lands. * :class:`RetiredNameTests` -- the #924 ruling that the ``IPv6_GenericExt`` name goes for good. A ruling that a name must not exist is exactly the kind a later change reintroduces without noticing. @@ -41,25 +41,25 @@ :exc:`~pcapkit.utilities.exceptions.EnumKeyError`. * :class:`GetOverrideContractTests` -- what a ``get`` override owes the base: ``@classmethod`` for delegation, which Python forces rather than anyone ruling - (#913's precedent, followed by #908), plus the three rulings part 1 harvested -- + (#913's precedent, followed by #908), plus the rulings part 1 harvested -- ``quiet=True`` on the raise (#933), no suppression standing in for an honoured signature (#935), and deletion rather than repair when the override only reimplements the base (#940). Includes the guard for the audit row #940 falsified, - which rendered fine and failed nothing while claiming two overrides that no longer + which rendered fine and failed nothing while claiming overrides that no longer exist. * :class:`AenumRoleExclusionTests` -- GitHub issue #934 part C's ruling that ``aenum`` cannot be cross-referenced at all (``conf.py`` excludes it: its - ``objects.inv`` carries zero ``py:`` objects), converted to plain literals rather + ``objects.inv`` carries no ``py:`` objects), converted to plain literals rather than roles. A forbidden role needs a test or it comes back, exactly as :class:`RetiredNameTests` guards a retired name. Pins the other half of the same - fix alongside it: the four sentinel references #934 part B qualified stay + fix alongside it: the sentinel references #934 part B qualified stay qualified, since none of ``AbsentType``, ``NoValueType`` or ``ABSENT`` resolves unqualified outside :file:`docs/source/pcapkit/corekit/sentinels.rst`'s own module context. Both checks scan every split page rather than one file, since either could in principle land on any of them. -* :class:`ProcessConventionTests` -- the three *process* rulings #918 harvested onto - the fifth page, :file:`process.rst`: what the ``all`` extra carries (#910), what a +* :class:`ProcessConventionTests` -- the *process* rulings #918 harvested onto + :file:`process.rst`: what the ``all`` extra carries (#910), what a changelog entry is, and what the issue and pull request labels mean. Grounded in :file:`pyproject.toml`, :file:`docs/source/changelog/1.5.0.rst` and :file:`.github/PULL_REQUEST_TEMPLATE.md` rather than in the owner's phrasing, which @@ -99,9 +99,10 @@ INDEX = CONVENTIONS_DIR / 'index.rst' #: Every ``.. _label:`` anchor, in the narrative order the pre-split page carried -#: them in -- which is also the order the index's toctree lists the files in. The -#: first three predate #918; ``extension-header-subclassing`` arrived with it, and -#: ``process`` came last, on the owner's ruling that the three settled *process* +#: them in -- which is also the order the index's toctree lists the files in. +#: ``mint-criterion``, ``sentinel-convention`` and ``registry-protocol`` predate +#: #918; ``extension-header-subclassing`` arrived with it, and ``process`` came +#: next, on the owner's ruling that the settled *process* #: rulings -- the ``all`` extra, what a changelog entry is, and what the labels #: mean -- get a page of their own rather than being wedged onto a code-convention #: page. ``documentation`` came after it, carrying the rulings GitHub issue #719 @@ -209,9 +210,9 @@ def _every_enumeration() -> 'dict[type, str]': Both the :mod:`enum` and :mod:`aenum` flavours, because the tree uses both and a walk over one of them silently under-reports. Nested classes are walked too: the - seven ``Flags`` enumerations under - :mod:`pcapkit.protocols.schema.application.httpv2` are all nested, and they are - what makes the difference between 17 non-registry enumerations and 24. + ``Flags`` enumerations under + :mod:`pcapkit.protocols.schema.application.httpv2` are all nested, so a walk + that skipped nested classes would under-report the non-registry population. :mod:`pcapkit.vendor` is skipped. Its modules are crawlers whose classes are :class:`~pcapkit.vendor.default.Vendor` subclasses named after registries rather @@ -238,10 +239,10 @@ def _every_enumeration() -> 'dict[type, str]': def walk(container: 'type') -> 'None': """Recurse through ``container``'s own attributes. - Into **every** nested class, not only the enumerations: the seven ``Flags`` - are nested inside schema classes, which are not enumerations themselves, so a - recursion that only followed enumerations would never reach them -- and would - under-report the non-registry population by exactly those seven. + Into **every** nested class, not only the enumerations: the ``Flags`` + enumerations are nested inside schema classes, which are not enumerations + themselves, so a recursion that only followed enumerations would never reach + them -- and would under-report the non-registry population by exactly those. """ if container in visited: @@ -420,9 +421,9 @@ def test_the_page_says_phase_two_is_complete_and_the_walk_agrees(self) -> 'None' """*"No enumeration remains outside the hierarchy"* -- against a runtime walk. GitHub issue #930 finished phase 2, so the page says it landed for every - non-registry enumeration. That replaces two figure checks, on how many - remained outside and how many of the total had landed (#1811): both said - the same thing as the walk finding none outside, which is what fails here + non-registry enumeration. That replaces the figure checks on how many + remained outside and how many of the total had landed (#1811), which said + no more than the walk finding none outside -- and that is what fails here once an enumeration is added outside :class:`~pcapkit.corekit.enum.EnumLookup`. """ for claim in ('the phase landed for every non-registry enumeration', @@ -696,18 +697,18 @@ class AenumRoleExclusionTests(unittest.TestCase): """GitHub issue #934 part C's ruling: ``aenum`` cannot be cross-referenced. ``docs/source/conf.py`` excludes ``aenum`` from ``intersphinx_mapping`` - deliberately -- its ``objects.inv`` carries zero ``py:`` objects, so no + deliberately -- its ``objects.inv`` carries no ``py:`` objects, so no ``:mod:``/``:class:``/``:func:``/etc. role naming it could ever resolve. Part - B converted the six such roles this page carried to plain double-backtick + B converted every such role this page carried to plain double-backtick literals rather than leaving them promising a link that can never exist. A forbidden role needs a test, or a later edit reintroduces one without noticing -- exactly the failure mode :class:`RetiredNameTests` guards a retired name against. - The other half of the same fix is pinned alongside it: the four references to + The other half of the same fix is pinned alongside it: the references to ``AbsentType``, ``NoValueType`` and ``ABSENT`` that part B qualified to their real dotted path under ``pcapkit.corekit.sentinels`` have to stay qualified, - since none of the three resolves by its bare name outside + since none of them resolves by its bare name outside :file:`docs/source/pcapkit/corekit/sentinels.rst`'s own ``.. module::`` context. @@ -716,11 +717,11 @@ class AenumRoleExclusionTests(unittest.TestCase): #: Any Sphinx py-domain role whose target starts with ``aenum``, tilde-prefixed #: or not. Matches ``:mod:`aenum``` and ``:class:`~aenum.Enum``` alike; would #: also catch a role type never seen on this page (``:func:`aenum.something```), - #: since the ban is on naming ``aenum`` in a role at all, not on the six - #: specific roles #934 part C found. + #: since the ban is on naming ``aenum`` in a role at all, not on the specific + #: roles #934 part C found. FORBIDDEN_AENUM_ROLE = re.compile(r':(?:mod|class|meth|func|attr|exc|obj|data):`~?aenum\b') - #: The four qualified sentinel references part B's fix relies on: the role, + #: The qualified sentinel references part B's fix relies on: the role, #: the dotted target, and how many times that exact pairing has to appear. QUALIFIED_SENTINEL_REFS = ( (':class:', '~pcapkit.corekit.sentinels.AbsentType', 2), @@ -735,7 +736,7 @@ def test_no_aenum_role_appears(self) -> 'None': plain double-backtick literal (``` ``aenum.Enum`` ```) and in prose (*"the aenum flavours"*) throughout these pages, which is exactly the point of the fix -- only the unresolvable *role* form is banned. Scanned - across every split page plus the index, since the six roles #934 part C + across every split page plus the index, since the roles #934 part C found could each have landed in any of them. """ @@ -753,8 +754,8 @@ def test_the_qualified_sentinel_targets_stay_qualified(self) -> 'None': ``AbsentType``, ``NoValueType`` and ``ABSENT`` each resolve only against the sentinels page's own module context (GitHub pull request #936); written bare - anywhere on these pages, none of the three resolves at all. All four - qualified references happen to live in + anywhere on these pages, none of them resolves at all. The qualified + references happen to live in :file:`sentinel-convention.rst`, but this scans every split page plus the index so a later move of one does not go unnoticed. @@ -773,14 +774,15 @@ class GetOverrideContractTests(unittest.TestCase): """What a ``get`` override owes the base, as recorded onto *The Registry Protocol* by GitHub issue #918 part 1. - Three of the four items are quoted from the owner on their own threads -- #933 on - ``quiet=True``, #935 on an advertised signature that is refused, #940 on deleting - an override that only reimplements the base. The fourth, the ``@classmethod`` - requirement for delegation, is **not** a ruling and is not quoted as one: it is + All but one of the items are rulings the owner gave on their own threads -- #933 + on ``quiet=True``, #935 on an advertised signature that is refused, #940 on + deleting an override that only reimplements the base. The remaining one, the + ``@classmethod`` requirement for delegation, is **not** a ruling and is not + presented as one: it is forced by the language, since zero-argument :func:`super` inside a ``@staticmethod`` has nothing to bind, and #913 set the shape that #908 then followed. Each states something the tree can be asked about. The page's - half is what rots: the same four claims are already pinned in ``tests/corekit`` + half is what rots: the same claims are already pinned in ``tests/corekit`` and ``tests/protocols`` against the *code*, so a later change that moves the code fails there, while a page still describing the old shape fails nothing. This class is the other direction, and it is how the stale audit row this change @@ -820,7 +822,7 @@ def test_a_delegating_override_is_a_classmethod(self) -> 'None': from pcapkit.const.http.method import Method from pcapkit.const.pcapng.option_type import OptionType - # Membership before indexing, for all three. `vars(klass)['get']` raises a bare + # Membership before indexing, for each class. `vars(klass)['get']` raises a bare # `KeyError: 'get'` when a class folds its own override into the inherited base # -- which is exactly what GitHub pull request #940 did to the mh/ngap helpers, # so it is a live failure mode rather than a hypothetical one. The KeyError @@ -856,7 +858,7 @@ def test_a_delegating_override_is_a_classmethod(self) -> 'None': 'OptionType.get now delegates, so the page is wrong to list it ' 'as the surviving staticmethod') - # Execute the three outcomes rather than assert the page names them. The + # Execute the outcomes rather than assert the page names them. The # first draft of this test only grepped for the error string, and the # string it grepped for was the wrong one -- the page claimed # `RuntimeError: super(): no arguments` for a shape that actually raises @@ -882,7 +884,7 @@ def get(): # type: ignore[override] # noqa: D102 # "obj must be an instance or subtype of type" while 3.13+ say "obj # (instance of str) is not an instance or subtype of type (Cls)". Only # `instance or subtype of type` is common to both, and pinning either - # full sentence would fail three of the five required Compat legs -- + # full sentence would fail the required Compat legs that word it the other way -- # invisible locally, since this venv is 3.14. self.assertIn('instance or subtype of type', str(caught.exception), 'zero-argument super() in a staticmethod binds the first ' @@ -902,13 +904,13 @@ def get(): # type: ignore[override] # noqa: D102 flat = self._flat() # Each wording pinned by a needle unique to it. The shared substring - # ``instance or subtype of type`` occurs **three** times on the page -- both - # quoted errors plus the sentence explaining what they share -- so asserting it + # ``instance or subtype of type`` occurs more than once on the page -- in both + # quoted errors and in the sentence explaining what they share -- so asserting it # pinned neither: corrupting the 3.13+ quote to something false still passed. # - # **Fourth instance of one defect shape**, after ``labels: bug`` (a bare token - # matched elsewhere), the bare ``26`` (matched by the page's own ``wc -l`` - # output) and ``quiet=True`` (four occurrences). The rule, stated once here + # **A recurring defect shape**, after ``labels: bug`` (a bare token matched + # elsewhere), a bare figure (matched by the page's own ``wc -l`` output) and + # ``quiet=True`` (several occurrences). The rule, stated once here # because it kept being rediscovered: **an assertIn whose needle appears more # than once on the page pins nothing** -- a later occurrence satisfies it and # the claim it guards can be inverted freely. Count occurrences before @@ -981,10 +983,10 @@ def _restore() -> 'None': 'reversal rather than his first answer, which is the whole reason ' 'both answers are on the issue') # Anchored to the headline sentence, not the bare token. `quiet=True` occurs - # four times on the page, so `assertIn('``quiet=True``')` was satisfied by a + # more than once on the page, so `assertIn('``quiet=True``')` was satisfied by a # later mention -- inverting the ruling itself to `quiet=False` failed nothing. - # Third instance of this shape: the `labels: bug` assertion and the bare `26` - # both passed the same way, so the rule is now explicit -- never assert a token + # The same shape as the `labels: bug` assertion and the bare figure, which + # passed the same way, so the rule is explicit -- never assert a token # that appears more than once on the page it is meant to pin. self.assertIn('Raise the way the base raises, which means** ``quiet=True``', flat, 'the page no longer states the ruling as its headline, so a ' @@ -993,11 +995,11 @@ def _restore() -> 'None': def test_the_two_redundant_overrides_are_gone(self) -> 'None': """#940: the owner ruled for deleting the redundant overrides, not widening them. - Three things at once, because the ruling is only settled if all three hold: + Several things at once, because the ruling is only settled if they all hold: neither class defines ``get``, the module defines none at all, and the ``[override]``/``arguments-differ`` pair the old signatures needed went with them. Scoped to that exact pair rather than to ``arguments-differ`` alone, - which mh.py still carries four times for ``read`` and ``__post_init__`` -- + which mh.py still carries for ``read`` and ``__post_init__`` -- unrelated to any ``get``, and measured before asserting on it. """ @@ -1102,15 +1104,15 @@ def _optional_dependencies() -> 'dict[str, list[str]]': **Verified against** :mod:`tomllib` **rather than asserted.** A second version matched arrays with a non-greedy bracket pattern, which stopped at the first - literal ``]`` -- which mis-parsed **3 of the 14** extras, silently: + literal ``]`` -- which mis-parsed several extras, silently: * ``vendor`` came back **empty**, because the ``]`` inside ``"requests[socks]"`` closed the match early. - * ``dev`` silently dropped its last two entries for the same reason. + * ``dev`` silently dropped its trailing entries for the same reason. * ``test`` was truncated at a ``]`` inside a *comment* and then picked up a quoted example from the prose, **inventing a dependency called** ``9 skipped``. - No shipped assertion read those three keys, so no test gave a wrong verdict -- but + No shipped assertion read those keys, so no test gave a wrong verdict -- but ``dev`` and ``vendor`` are both described in the page's own prose, so the next assertion to check either would have got wrong data with nothing raised. That is precisely the "renders fine and fails nothing" failure this suite exists to close, @@ -1173,7 +1175,7 @@ def _optional_dependencies() -> 'dict[str, list[str]]': class ProcessConventionTests(unittest.TestCase): - """The three process rulings :file:`process.rst` carries, against the tree. + """The process rulings :file:`process.rst` carries, against the tree. Each check pins the *claim the page makes* next to the *fact behind it*, and deliberately pins neither against the owner's own phrasing. Quoting him is what @@ -1211,7 +1213,7 @@ def test_the_extras_reader_agrees_with_tomllib(self) -> 'None': The reader exists because :mod:`tomllib` is 3.11+ and CI still tests 3.8-3.10 (#1633's KTLO legs), so the assertions above cannot use it. That makes the reader itself an unverified dependency of every extras claim on the page -- and its second - version mis-parsed **3 of the 14** extras silently, inventing a requirement + version mis-parsed several extras silently, inventing a requirement called ``9 skipped`` out of comment prose. So wherever a real parser *is* available -- which is every interpreter from 3.11 @@ -1249,7 +1251,7 @@ def test_the_all_extra_is_exactly_the_three_core_addon_extras(self) -> 'None': Two halves, because either can rot without the other. The tree half asks :file:`pyproject.toml` whether ``all`` is still the union of ``cli``, ``crypto`` and ``NGAP`` and nothing else -- the shape GitHub issue #910's - ruling produced, eight requirements down to three. The page half asks whether + ruling produced, narrowed to the core addons. The page half asks whether the ``toml`` block on the page still shows that same list, since a page that prints a stale ``all =`` line is worse than one that prints none. @@ -1272,11 +1274,11 @@ def test_the_all_extra_is_exactly_the_three_core_addon_extras(self) -> 'None': def test_the_page_keeps_the_engine_and_installability_exclusions_apart(self) -> 'None': """The two exclusion reasons are the part a reader collapses into one. - #910 excluded the four third-party engines **by kind** -- they are not core + #910 excluded the third-party engines **by kind** -- they are not core addons -- where ``PyPCAP`` and ``PCAP_CT`` were already out for *installability*, which the ruling did not touch. Reading those as one reason is what let the list drift the first time, so the page has to state both. The - tree half checks the six engine extras still exist to be excluded from, since + tree half checks the engine extras still exist to be excluded from, since a prose distinction about extras that no longer exist is not a distinction. """ @@ -1388,11 +1390,11 @@ def test_the_page_names_every_commit_type_the_template_ticks(self) -> 'None': def test_the_page_names_what_the_tree_has(self) -> 'None': """Every claim the page makes that has local ground truth. - A cross-review corrupted **46** claims on these two pages simultaneously and + A cross-review once corrupted a batch of claims on these pages at once and the suite stayed green, which is the honest measure of how much of the prose was decorative. This closes the subset that has local ground truth: a path - the page cites, a module it names. The page states no entry count any more - (#1103's ruling, #1811), so none is pinned. + the page cites, a module it names. The page states no entry count (#1103's + ruling, #1811), so none is pinned. **What stays unpinned, and why, so the gap is stated rather than implied.** Every claim whose ground truth is a GitHub query -- the label count, which @@ -1476,7 +1478,7 @@ def test_the_page_says_the_labels_are_set_by_hand(self) -> 'None': # came to name ``github_actions`` as dependabot-applied when # .github/dependabot.yml configures only ``pip``, so dependabot can never open a # workflow bump here. Saying a hand-applied label is a machine default is this - # section's own point stated backwards, and the two places the page mentioned it + # section's own point stated backwards, and the places the page mentioned it # disagreed with each other about ``python``. dependabot = (ROOT / '.github' / 'dependabot.yml').read_text(encoding='utf-8') ecosystems = re.findall(r'package-ecosystem:\s*"([^"]+)"', dependabot) @@ -1493,8 +1495,9 @@ def test_the_page_says_the_labels_are_set_by_hand(self) -> 'None': # the tool with the label is checked instead, so the phrasing no longer matters. # # Proximity is not the test, and a first attempt at #949 that used it was wrong: - # the section states **twice**, deliberately, that ``github_actions`` is *not* - # dependabot's, and both of those sentences name the tool and the label together. + # the section states more than once, deliberately, that ``github_actions`` is + # *not* dependabot's, and each of those sentences names the tool and the label + # together. # Distinguishing an attribution from a denial by looking for a negation nearby # also failed -- the attributing bullet's own sentence ends "so it never opens a # workflow bump here", so the negation is present in the sentence that makes the @@ -1559,8 +1562,8 @@ def test_every_issue_link_number_matches_its_own_url(self) -> 'None': """A ``#NNN`` label and the issue or pull number in its own URL must agree. Purely local, needing no network, and it closes the largest single class of - unpinned claim on these pages: a cross-review corrupted roughly thirty link - numbers across both files and not one was caught, because nothing compared the + unpinned claim on these pages: a cross-review corrupted a run of link + numbers across these files and not one was caught, because nothing compared the displayed number against the target. A mismatch is invisible to a reader -- the text says #918 and the link goes to #919 -- and Sphinx cannot warn, since both halves are well-formed. @@ -1606,15 +1609,15 @@ def test_the_page_describes_the_changelog_grouping_as_it_is(self) -> 'None': """The current shape of ``1.5.0.rst``, counted rather than eyeballed. This replaces a check on the file's *previous* shape. The page used to say the - entries carried three inline kind labels in a given number of separate runs, + entries carried inline kind labels in a given number of separate runs, and this test measured those runs and required the figure in the prose. The by-module restructure removed the inline labels outright, so that test did not merely go stale -- it went **vacuous**: its ``re.findall`` matched nothing, - ``runs`` was empty, and both of its ``assertGreater`` floors failed before the + ``runs`` was empty, and its ``assertGreater`` floors failed before the prose needle was ever reached. A test whose subject has been deleted cannot be repaired by updating a number. - What is checked now is the shape that actually shipped: one ``-`` underlined + What is checked is the shape that actually shipped: one ``-`` underlined section per top-level module plus one for what belongs to none, each carrying ``~`` underlined kind subsections, with no inline kind label left anywhere. The page used to state the section count as well, pinned here; it states the shape diff --git a/tests/project/test_coverage_data_guard.py b/tests/project/test_coverage_data_guard.py index 2def3f2d24..8c69fb0c4b 100644 --- a/tests/project/test_coverage_data_guard.py +++ b/tests/project/test_coverage_data_guard.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Tests for the coverage leg's check that no process's data file went missing. -#1387: PR #1345's coverage leg combined 29 data files where #1341's combined 30, +#1387: PR #1345's coverage leg combined fewer data files than #1341's did, with every test passing in both, and posted 85.85% against about 88.9%. A process that dies before coverage's atexit save leaves no ``.coverage.*`` file, and ``coverage combine`` reports what is left as the whole. So the ``Run unit diff --git a/tests/project/test_docs_ambiguous_xrefs_1775_unit.py b/tests/project/test_docs_ambiguous_xrefs_1775_unit.py index 9bef58679a..bda27c3867 100644 --- a/tests/project/test_docs_ambiguous_xrefs_1775_unit.py +++ b/tests/project/test_docs_ambiguous_xrefs_1775_unit.py @@ -1,23 +1,23 @@ # -*- coding: utf-8 -*- """Pins the fixes for the docs build's ambiguous cross-references. -GitHub issue #1775: the docs build gave 36 ``more than one target found for +GitHub issue #1775: the docs build gave ``more than one target found for cross-reference`` warnings, and every one of those links landed on the wrong -object. They had three causes, each fixed where it starts rather than at the +object. They had these causes, each fixed where it starts rather than at the references: -* A bare builtin name in a type -- ``dict`` 21 times, ``type`` 3, ``set`` 1 -- was +* A bare builtin name in a type -- ``dict``, ``type``, ``set`` -- was suffix-matched to registry members such as ``TCP.dict``. ``resolve_builtins_exactly`` in :file:`docs/source/conf.py` stops it. * Napoleon read a URL's colon in a registry member's docstring as Google's inline ``type: description`` form, and the bogus type was then parsed as references -- - ``http`` 3, ``Echo`` 1. ``save_enum_member_docstring`` and + ``http``, ``Echo``. ``save_enum_member_docstring`` and ``restore_enum_member_docstring`` undo it. -* 44 hand-written ``.. data::`` and ``.. function::`` directives spelled out their +* Hand-written ``.. data::`` and ``.. function::`` directives spelled out their full dotted name under a ``.. module::`` that already supplied it, so each was registered as ``..``. The exact lookup for a TypeVar such as ``_AT`` then failed, and the fuzzy one found every ``_AT`` in the package -- - the other 7 warnings. + the remaining warnings. The hook tests drive the hooks with the nodes Sphinx's own producers build and with napoleon itself, and check that ``setup`` connects each one where the build @@ -220,7 +220,7 @@ def test_other_names_keep_their_fuzzy_search(self) -> 'None': self.assertEqual(reference['reftitle'], probe) def test_setup_connects_it_to_doctree_read(self) -> 'None': - """Unconnected, the hook never runs and the 25 builtin warnings come back.""" + """Unconnected, the hook never runs and the builtin warnings come back.""" wired = [(event, priority) for event, handler, priority in connections(self.conf) if handler is self.conf.resolve_builtins_exactly] self.assertEqual(wired, [('doctree-read', 500)]) diff --git a/tests/project/test_generators_import_their_own_tree.py b/tests/project/test_generators_import_their_own_tree.py index 0db9364843..a4a0f8db4f 100644 --- a/tests/project/test_generators_import_their_own_tree.py +++ b/tests/project/test_generators_import_their_own_tree.py @@ -5,9 +5,9 @@ :file:`examples/generators/`, not the tree root, so ``import pcapkit`` fell through to whatever was installed. An editable install pins one checkout, so a worktree's generators silently built their fixtures from *that* checkout's -library: 257 captured cases instead of 266, with nothing failing. +library: fewer captured cases than the tree defines, with nothing failing. -Each generator that imports :mod:`pcapkit` now puts its own tree root first on +Each generator that imports :mod:`pcapkit` puts its own tree root first on :data:`sys.path`. The probe below proves it from a scratch worktree, whose path no install points at, and with ``PYTHONPATH`` and ``PYTHONSAFEPATH`` stripped. The probe script lives outside the tree, so -- exactly as when a generator is run diff --git a/tests/project/test_isort_clean.py b/tests/project/test_isort_clean.py index 73c23db638..1c0352463b 100644 --- a/tests/project/test_isort_clean.py +++ b/tests/project/test_isort_clean.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -"""Pins ``make isort`` clean on all four of its lines (#757). +"""Pins ``make isort`` clean on every one of its lines (#757). #757 was filed from a reproduction that ran bare ``isort --check-only --diff pcapkit/protocols/schema/schema.py``, with none of the flags ``make isort`` @@ -15,7 +15,7 @@ ("120 for ``pylint`` and 100 for ``isort``, not PEP 8's 79"): a deliberate, written-down split, not a misconfiguration. Under *that* width the ``misc`` import is not flagged at all (89 < 100). What *was* flagged, on the commit -this test landed with, were three things the whole-tree line's flags alone +this test landed with, were things the whole-tree line's flags alone would not have caught: * :file:`pcapkit/protocols/schema/schema.py` -- its ``pcapkit.utilities.warnings`` @@ -31,7 +31,7 @@ ``Ether, IPv6, Raw``). Also the util/examples-generators line only; only import order changed, since this module is loaded and run at test time, not just read at review time. - Three test modules load it by path via + These test modules load it by path via ``importlib.util.spec_from_file_location``: :file:`tests/protocols/test_option_generator_tcp_base_unit.py`, :file:`tests/protocols/test_option_coverage_runtime.py`, and @@ -41,7 +41,7 @@ directly, too. So this module does not re-litigate the width. It just pins isort's own -verdict on each of the four lines -- via real ``isort`` invocations with the +verdict on each of those lines -- via real ``isort`` invocations with the Makefile's exact flags, not a hand-rolled guess about what those flags imply -- so a future edit that reintroduces an unsorted or mis-wrapped import anywhere ``make isort`` reaches fails here instead of surfacing as "clean locally, red @@ -51,8 +51,8 @@ ``__init__.py`` files that sit at least one directory below :file:`pcapkit/const/` or :file:`pcapkit/vendor/` -- the const and vendor lines have no ``--skip-glob``, so between them they re-cover whichever of -the 71 files the whole-tree line skips happen to live there, even though -the whole-tree line skips all 71 package-wide. The const and vendor lines +the files the whole-tree line skips happen to live there, even though +the whole-tree line skips them package-wide. The const and vendor lines used to be one, :file:`pcapkit/const/*/*.py` and :file:`pcapkit/vendor/*/*.py` combined into a single brace-expanded glob that stopped at a fixed two levels, which the #754 split outgrew the moment @@ -138,12 +138,12 @@ :file:`lint.yml` already runs ``make mypy`` over the whole package, so a pytest copy would be a *second* copy, while that same workflow's header records that ``isort`` is deliberately -not one of the four linters it installs -- it appears only in +not one of the linters it installs -- it appears only in :file:`cron-vendor.yml`, as a formatter that rewrites the generated constants on a schedule rather than as a check. So declining the install line here would have left ``make isort``'s verdict checked nowhere at all, which is what #766 -objected to. It is cheap enough to be uncontroversial, too: all four lines -below take about 1.5s together, the "costs nothing per leg" category the test +objected to. It is cheap enough to be uncontroversial, too: the lines below +take about 1.5s together, the "costs nothing per leg" category the test job's own install comment puts ``DPKT`` in rather than the ``Scapy`` one. ``isort`` is in ``Pipfile``'s ``[dev-packages]`` too, as of #810 -- that being @@ -322,7 +322,7 @@ def _isort_recipe_line_numbers() -> 'list[int]': ``isort:`` or another such line, a blank line, or a comment line at column 0 -- make itself treats a blank or a column-0 ``#`` line inside a recipe as transparent rather than as ending the rule (measured with - ``make -n isort`` as the oracle: it still reports the same four commands + ``make -n isort`` as the oracle: it still reports the same commands with either dropped in between two recipe lines, which an earlier revision of this function got wrong by breaking on the first line that was not tab-indented, comment or not). The first following line that is @@ -334,7 +334,7 @@ def _isort_recipe_line_numbers() -> 'list[int]': a dependency rather than declaring it, must not be mistaken for the target this function is looking for. The one case this does not defend against is a ``define``/``endef`` block whose body contains a bare - ``isort:`` at column 0 followed by four or more tab-indented lines -- + ``isort:`` at column 0 followed by tab-indented lines -- nothing in this file uses ``define``, so it is undefended rather than handled. @@ -388,7 +388,7 @@ def _isort_recipe_line_numbers() -> 'list[int]': @unittest.skipUnless(HAS_ISORT, 'isort is not installed') class TestIsortIsCleanOnThePackage(unittest.TestCase): - """``make isort`` must not be red on a clean checkout, on any of its four + """``make isort`` must not be red on a clean checkout, on any of its lines (#757). """ diff --git a/tests/project/test_no_moved_name_re_exports_1744_unit.py b/tests/project/test_no_moved_name_re_exports_1744_unit.py index aeb51501bd..69153ff082 100644 --- a/tests/project/test_no_moved_name_re_exports_1744_unit.py +++ b/tests/project/test_no_moved_name_re_exports_1744_unit.py @@ -8,7 +8,7 @@ documented as importable there. A module that still uses a name it imports from the new home keeps the import, so the old path resolving through it is expected. -Six checks pin that: +These checks pin that: * :class:`TestNotExported` -- no removed name is in its old module's ``__all__``; @@ -22,7 +22,7 @@ * :class:`TestNoReExportProse` -- no docstring under :mod:`pcapkit` and no page under ``docs/`` says a removed name is importable, re-exported or available at its old path; -* :class:`TestVersionRemoved` -- the two paths that shipped in 1.4.x carry +* :class:`TestVersionRemoved` -- the paths that shipped in 1.4.x carry ``versionremoved:: 1.5.0`` in the module docstring and on the docs page, per #1103; the beta-only ones are deleted with no directive. diff --git a/tests/project/test_public_api.py b/tests/project/test_public_api.py index e1af71309f..894075ce8f 100644 --- a/tests/project/test_public_api.py +++ b/tests/project/test_public_api.py @@ -8,7 +8,7 @@ #. every name in every public module's :attr:`__all__` actually resolves; #. every public package lists everything public it holds, bar an allowlist of exclusions that had to be written down one at a time; -#. the three re-export aggregators list *everything* public they hold, with no +#. the re-export aggregators list *everything* public they hold, with no allowlist at all. The first two exist because of GitHub issue #515. ``pcapkit/protocols/data`` @@ -41,19 +41,19 @@ the ``vendor`` extra: this module is unit-tier -- see :mod:`tests._tiers` -- so it has to pass on ``pip install -e '.[test]'``. Both were already in the ``test`` extra, since #507 (:file:`pyproject.toml`), so the skip never bought anything. -Dropping it (#1772) brought in 144 modules and 19 packages, and found two +Dropping it (#1772) brought in the vendor modules and packages, and found packages holding public attributes their :attr:`__all__` omitted: :mod:`pcapkit.vendor.ipx` leaked ``path``, the temporary of its ``sys.path`` -save-and-restore, now named ``_path``; :mod:`pcapkit.vendor`'s five are recorded +save-and-restore, since renamed ``_path``; :mod:`pcapkit.vendor`'s are recorded in :data:`DELIBERATE_NON_EXPORTS`. No import is wrapped in a skip, either. That is deliberate and also measured: with ``dpkt``, ``scapy``, ``emoji``, ``cryptography`` and ``pycrate`` all absent, every -one of the 325 non-vendor modules there were when this module was written still +non-vendor module there was when this module was written still imported, because each optional dependency is guarded at its import site -- e.g. ``pcapkit/toolkit/scapy.py`` catches :exc:`ModuleNotFoundError` and degrades to ``scapy = None`` with a warning. The vendor modules need nothing past the ``test`` -extra at import time: the two NGAP crawlers import ``pycrate`` only inside the +extra at import time: the NGAP crawlers import ``pycrate`` only inside the method that reads it. So an import failure in this sweep is a real defect and is allowed to fail the test, rather than being softened into a skip that would let the next :attr:`__all__` bug through. @@ -75,32 +75,32 @@ :data:`DELIBERATE_NON_EXPORTS` is where the decisions are recorded, and it is load-bearing rather than an escape hatch: without it the assertion is unsatisfiable, and with it every exclusion is something somebody wrote down and a -reviewer can argue with. Of the 45, 23 were genuine omissions and are exported as -of the commit that added this assertion -- among them the six +reviewer can argue with. Of those, about half were genuine omissions and are +exported as of the commit that added this assertion -- among them the ``register_*_callback`` and ``register_extractor_*`` functions that -:mod:`pcapkit.foundation` withheld while listing the other 27 registry functions, +:mod:`pcapkit.foundation` withheld while listing the other registry functions, ``ReassemblyManager`` and ``TraceFlowManager``, which are defined *below* the -:attr:`__all__` literal that forgot them and imported by name from six modules, and -the three decorators :mod:`pcapkit.utilities` then advertised in its own module +:attr:`__all__` literal that forgot them and imported by name from several modules, +and the decorators :mod:`pcapkit.utilities` then advertised in its own module docstring (since moved to :mod:`pcapkit.corekit.decorators` and dropped from that -package by #1735). The 22 that remain are listed with their reasons, as are the -five :mod:`pcapkit.vendor` added once it joined the sweep (#1772), and +package by #1735). The rest are listed with their reasons, as are the names +:mod:`pcapkit.vendor` added once it joined the sweep (#1772), and :meth:`~PublicAPISurfaceTests.test_the_non_export_allowlist_is_tight` stops the list rotting into a silencer: every entry has to name a package that exists, an attribute that package really holds, and a name its :attr:`__all__` really omits, so an entry stops being true the moment the tree moves under it. :data:`AGGREGATORS` keeps an assertion of its own even though the package-wide one -now covers those three, because the guarantee is a stronger one: it admits no -allowlist at all. Those three packages are pure re-export surfaces -- each +covers those packages too, because the guarantee is a stronger one: it admits no +allowlist at all. Those packages are pure re-export surfaces -- each wildcard-imports its children and re-lists their names, so every public attribute it has came from a child that already chose to export it, and any name missing from its :attr:`__all__` is an oversight by construction. That is precisely how #515 happened, and this is the assertion that makes the next one fail immediately instead of in three years. -Three further assertions cover the rest of the family, because a name can fail to -be exported in more ways than by being misspelled. Each of the three failed +Further assertions cover the rest of the family, because a name can fail to +be exported in more ways than by being misspelled. Each of them failed against the tree this module was written on, and each is fixed in the same commit: * :meth:`~PublicAPISurfaceTests.test_no_misspelled_all` -- @@ -108,7 +108,7 @@ leading underscores. Nothing reads that name, so the package simply had no :attr:`__all__`: ``hasattr(module, '__all__')`` was :data:`False` and ``from pcapkit.const.pcapng import *`` fell back to "every public name", - leaking its 7 submodules on top of the 7 enums it meant to publish. This is the + leaking its submodules on top of the enums it meant to publish. This is the quietest member of the family -- a misspelling here does not raise, it silently widens the public surface. * :meth:`~PublicAPISurfaceTests.test_every_public_package_declares_all` -- the @@ -153,7 +153,7 @@ class exists at ``pcapkit/const/mh/handover_initiate_status.py`` and is used by #: The packages whose whole job is to re-export their children, and which #: therefore have to list every public name they hold -- with no allowlist, unlike -#: every other package. See the module docstring for why these three are held to +#: every other package. See the module docstring for why these are held to #: the stricter form. AGGREGATORS = ( 'pcapkit.protocols.data', @@ -170,11 +170,12 @@ class exists at ``pcapkit/const/mh/handover_initiate_status.py`` and is used by #: **The abstract bases** -- ``Field``, ``Engine``, ``Reassembly``, #: ``IP_Reassembly``, ``TraceFlow``, ``Protocol``, ``Application``, ``Internet``, #: ``Link``, ``Transport``. Each is imported by its package explicitly, under a -#: "Base Class" comment, and left out of that package's :attr:`__all__`; nine -#: packages do the same thing the same way. Neither :mod:`pcapkit.all` -- the -#: library index, whose stated job is to hold "all things from :mod:`pcapkit`" -- -#: nor :mod:`pcapkit.corekit` exports any of them either. Three independent export -#: surfaces agreeing is a convention rather than nine separate oversights, so they +#: "Base Class" comment, and left out of that package's :attr:`__all__`; every +#: package listed below for one does the same thing the same way. Neither +#: :mod:`pcapkit.all` -- the library index, whose stated job is to hold "all +#: things from :mod:`pcapkit`" -- nor :mod:`pcapkit.corekit` exports any of them +#: either. Independent export surfaces agreeing is a convention rather than a +#: string of separate oversights, so they #: stay reachable by their documented dotted path and out of ``import *``. #: :mod:`pcapkit.vendor` imports its base ``Vendor`` the same way, and has a #: sharper reason: its :attr:`__all__` is also the default target list @@ -189,7 +190,7 @@ class exists at ``pcapkit/const/mh/handover_initiate_status.py`` and is used by #: **Import-time machinery, and one leaked loop variable.** #: :mod:`pcapkit` imports ``BaseError``, ``DEVMODE`` and ``DevModeWarning`` to wire #: up the ``tbtrim`` excepthook, not to publish them -- the top-level surface is -#: interface functions, macros and protocols, and those three are documented under +#: interface functions, macros and protocols, and those names are documented under #: :mod:`pcapkit.utilities`. ``ROOT`` is bound only on the non-``DEVMODE`` branch, #: so exporting it would make ``from pcapkit import *`` raise #: :exc:`AttributeError` under ``PCAPKIT_DEVMODE=1`` -- a fresh #515 rather than a @@ -284,10 +285,10 @@ class PublicAPISurfaceTests(unittest.TestCase): def test_public_modules_were_actually_found(self) -> None: # A bug in the walk above would turn every other test in this class into # a silent pass over an empty list, so pin the shape of what it returns. - # The floor is deliberately far below the 325 modules / 52 packages found - # when this was written: it catches "found nothing", not "the library - # gained a module". The two vendor packages are pinned because the subtree - # was excluded until #1772, and both held __all__ gaps the exclusion hid. + # The floor is deliberately far below the population found when this was + # written: it catches "found nothing", not "the library gained a module". + # The vendor packages are pinned because the subtree was excluded until + # #1772, and each held __all__ gaps the exclusion hid. modules = public_modules() packages = [name for name, is_package in modules if is_package] @@ -421,7 +422,7 @@ def test_no_duplicate_all_entries(self) -> None: def test_aggregators_export_every_public_attribute(self) -> None: # The converse of test_every_all_entry_resolves, and viable only here -- - # see the module docstring for the measurement behind that. These three + # see the module docstring for the measurement behind that. These # packages re-export their children wholesale, so a public attribute they # hold but do not list is an oversight rather than a judgement call. for name in AGGREGATORS: @@ -435,7 +436,7 @@ def test_aggregators_export_every_public_attribute(self) -> None: def test_every_public_package_exports_every_public_attribute(self) -> None: # The same converse as above, over every public package rather than the - # three aggregators, against DELIBERATE_NON_EXPORTS: issue #533. This is the + # aggregators alone, against DELIBERATE_NON_EXPORTS: issue #533. This is the # only assertion in the class that reads __all__ as the *expectation* -- # every other one reads it as the input, and an attribute that exists while # nothing names it satisfies all of them. @@ -459,7 +460,7 @@ def test_every_public_package_exports_every_public_attribute(self) -> None: def test_the_non_export_allowlist_is_tight(self) -> None: # DELIBERATE_NON_EXPORTS is the whole reason the assertion above can be - # satisfied at all, so it gets an assertion of its own. Any of three kinds of + # satisfied at all, so it gets an assertion of its own. Any of these kinds of # staleness turns an entry into an exclusion nobody decided, silently # excusing the next real omission of that name: the package is gone, the # attribute is gone, or the name has since been added to __all__ and the diff --git a/tests/project/test_pyshark_encap_map.py b/tests/project/test_pyshark_encap_map.py index 741353f385..db7996d79f 100644 --- a/tests/project/test_pyshark_encap_map.py +++ b/tests/project/test_pyshark_encap_map.py @@ -145,7 +145,7 @@ class ParseParenthesisedNumberTests(unittest.TestCase): """:func:`~pyshark_encap_map.parse_parenthesised_number`'s own robustness. **What this does not pin, stated plainly because it was previously - overclaimed here:** #851/#850's real defect -- 10 of 157 rows lost, + overclaimed here:** #851/#850's real defect -- rows lost, including ``null`` -- was in how the original ad hoc script extracted the *name* portion of a PDML ``showname`` such as ``"Encapsulation type: NULL/Loopback (15)"``. This generator never does that extraction at all; diff --git a/tests/project/test_python_versions_1660.py b/tests/project/test_python_versions_1660.py index bdb801e2b0..8090782f77 100644 --- a/tests/project/test_python_versions_1660.py +++ b/tests/project/test_python_versions_1660.py @@ -2,10 +2,10 @@ """#1660: the Python version tiers are declared once, in :file:`.github/python-versions.toml`. Before #1660 every matrix spelt its versions out, so a tier change -- 3.11 -reaching end-of-life, a new pre-release -- meant editing some 27 files by hand. -Now :file:`util/python_versions.py` reads the file, and each workflow takes its -matrices, and each single-interpreter job its ``latest``, from that script's -step outputs. Four things are pinned here: +reaching end-of-life, a new pre-release -- meant editing many files by hand. +:file:`util/python_versions.py` reads the file instead, and each workflow takes +its matrices, and each single-interpreter job its ``latest``, from that script's +step outputs. These things are pinned here: * **The file and the script.** :func:`python_versions.load` rejects a malformed file, ``latest`` is the newest supported CPython (the owner's ruling on diff --git a/tests/project/test_release_gates.py b/tests/project/test_release_gates.py index 3b4c4aa920..77f66a4148 100644 --- a/tests/project/test_release_gates.py +++ b/tests/project/test_release_gates.py @@ -27,13 +27,13 @@ Be clear about how far that generalises, though, because it is easy to overstate. :data:`PUBLISHING_MARKERS` is what decides "publishing", and it is a finite, -hand-maintained list of five substrings. So the rule generalises across job +hand-maintained list of substrings. So the rule generalises across job *identity* and not across publishing *mechanism*: a job uploading by some route -none of those five names -- ``twine upload``, a fork of a pinned action under +none of those names -- ``twine upload``, a fork of a pinned action under another name, a ``curl`` straight at an index -- matches no marker, and would pass this test while genuinely ungated. -:class:`TestMarkersStillMatch` only keeps the existing five from going blind; it -cannot invent a sixth. Adding a publishing route to this workflow therefore means +:class:`TestMarkersStillMatch` only keeps the existing markers from going blind; +it cannot invent another. Adding a publishing route to this workflow therefore means adding its marker here, and that is a maintenance obligation rather than something the test enforces. @@ -48,8 +48,8 @@ tier runs on a fresh clone with no network and no token. It is written down in the workflow's own comment and in #641 instead. * **Whether GitHub requests one approval per environment or one per matrix leg.** - ``pypi`` is a 7-leg matrix and ``conda`` a 10-leg one. That is a property of - the Actions runner, observable only from a real run -- and now moot for both, + ``pypi`` and ``conda`` are both matrix jobs. That is a property of + the Actions runner, observable only from a real run -- and moot for both, since #887 removed their required reviewers. The question would resurface only if a matrix job were gated by its own environment again. @@ -103,7 +103,7 @@ despite every earlier test in this module passing. #962: the same argument, one layer up, now against the ``if:`` expressions -themselves. Four review rounds on #961 produced twenty mutations of a single +themselves. Review rounds on #961 produced mutation after mutation of a single clause, and each strengthening of the text assertions was defeated by one the previous round had not anticipated -- because vocabulary is not structure and structure is not meaning. :class:`TestGateExpressionsEvaluateCorrectly` @@ -1906,8 +1906,8 @@ def test_each_gated_job_has_its_own_environment(self) -> None: indexes -- OIDC trusted publishing and ``ANACONDA_TOKEN`` -- and ``tag``'s write to ``main`` uses a third, so sharing one environment would still merge those blast radii even though, since #887, only - ``github-release`` carries a reviewer of its own; the other three are - held by depending on it instead. That each *does* depend on it is + ``github-release`` carries a reviewer of its own; the other gated jobs + are held by depending on it instead. That each *does* depend on it is :class:`TestGatedJobsDependOnGithub`'s check, not this one -- this test only stops the four gates from being collapsed back into one. @@ -1936,7 +1936,7 @@ def test_pypi_and_anaconda_are_separate(self) -> None: class TestGatedJobsDependOnGithub(WorkflowMixin, unittest.TestCase): """#887: with only ``github-release`` still holding a required reviewer, - the other three gated jobs have to reach it through ``needs:`` instead, + the other gated jobs have to reach it through ``needs:`` instead, or removing their own reviewer left them ungated in every sense that matters. @@ -2102,7 +2102,7 @@ def test_the_gate_skips_when_everything_is_already_published(self) -> None: self.assertFalse(evaluate_condition(declared_if(self.jobs[job]), context)) def test_a_version_tagged_elsewhere_releases_nothing_off_a_v_tag(self) -> None: - """#1748: the gate and all four publishers skip for ``v1.5.0b12``'s shape. + """#1748: the gate and every publisher skip for ``v1.5.0b12``'s shape. Its tag names ``2025da5e5`` and Anaconda holds 1 of its 10 files, so ``conda`` used to run on every later commit -- after the gate -- and fail @@ -2389,8 +2389,8 @@ class TestGateExpressionsEvaluateCorrectly(WorkflowMixin, unittest.TestCase): rather than matched as text. :class:`TestEvidenceBasedGating` above asserts over the conditions' - spelling, and four review rounds on #961 showed where that ends: twenty - mutations of one clause, three successive strengthenings, and each + spelling, and the review rounds on #961 showed where that ends: mutation + after mutation of one clause, successive strengthenings, and each strengthening defeated by a mutation the previous round had not thought of. The reason is structural rather than a matter of the assertions not being clever enough -- a gate's job is to produce an answer, and no amount @@ -2722,15 +2722,15 @@ class TestGateMutationsChangeTheTruthTable(WorkflowMixin, unittest.TestCase): #: mutations have to be the *small* edits a review round produces -- a #: regenerated condition would differ in ways nobody would have typed. #: - #: The first eight are the mutations #962 names; the next six are this - #: module's own, covering the clauses the issue only points at -- the + #: The mutations #962 names come first, then this module's own, covering + #: the clauses the issue only points at -- the #: publishing predecessors' equality pair, the ``startsWith`` #: short-circuit, and reading somebody else's evidence. The ``!= 'true'`` #: row is #967's, and is the only row here that the table as #962 left it #: did not catch at all: it is rejected by exactly one scenario -- the #: ``null`` evidence row :func:`gate_rows` grew for it -- and by no text - #: assertion. The three after it are #1052's, for the release test gate - #: conjunct that issue added, and the last three are #1748's, for its + #: assertion. The rows after it are #1052's, for the release test gate + #: conjunct that issue added, and the last rows are #1748's, for its #: released-elsewhere conjunct. MUTATIONS = [ ('the && before the version_check clause becomes ||', diff --git a/tests/project/test_rfc_anchor_fragments.py b/tests/project/test_rfc_anchor_fragments.py index 27ec828537..98025f4eaa 100644 --- a/tests/project/test_rfc_anchor_fragments.py +++ b/tests/project/test_rfc_anchor_fragments.py @@ -80,10 +80,10 @@ top-level section, so those citations became ``:rfc:`959#section-4``` -- which :data:`ACCEPTED_FRAGMENT` above already accepts as well-formed. -Eleven sites carried it, not the six #944 reported: that issue grepped -:mod:`pcapkit` only, and a cross-review of the fix found four more rendered +More sites carried it than #944 reported: that issue grepped +:mod:`pcapkit` only, and a cross-review of the fix found further rendered roles in :file:`docs/source/contributing/conventions/registry-protocol.rst` -and one in :file:`tests/const/test_const_enum_no_mint.py`. A further two +and one in :file:`tests/const/test_const_enum_no_mint.py`. Others cited ``959#section-5.3``, equally dead, in :file:`tests/protocols/application/test_ftp_unit.py` and :file:`docs/source/changelog/1.5.0.rst`; #947 ruled ``#section-5`` for those. @@ -176,7 +176,7 @@ #: Where :func:`_dead_anchor_citations` looks, as ``(directory, glob patterns)``. #: Wider than :func:`_malformed_fragments`'s ``pcapkit``-only sweep on purpose: #: a dead anchor in a ``.rst`` page renders for readers exactly as one in a -#: docstring does, and four of the five sites this caught were in ``.rst``. +#: docstring does, and most of the sites this caught were in ``.rst``. DEAD_ANCHOR_SCAN: 'tuple[tuple[str, tuple[str, ...]], ...]' = ( ('pcapkit', ('*.py',)), ('docs/source', ('*.rst', '*.py')), @@ -285,7 +285,7 @@ def _dead_anchor_citations() -> 'list[DeadAnchorFinding]': function answers a narrower question than its predecessor pretended to. Scans :data:`DEAD_ANCHOR_SCAN` rather than :mod:`pcapkit` alone: scanning one - directory is what let five dead-anchor sites sit unnoticed outside it, four of them + directory is what let dead-anchor sites sit unnoticed outside it, most of them in ``.rst`` where they rendered for readers exactly as a docstring's would. """ @@ -314,7 +314,7 @@ class RFCAnchorFragmentTests(unittest.TestCase): :meth:`test_no_malformed_fragments` sweeps :mod:`pcapkit` only; :meth:`test_no_known_dead_anchor_citations` sweeps :data:`DEAD_ANCHOR_SCAN`, which also covers :file:`docs/source` and :file:`tests`, because scanning one directory - is what let five dead-anchor sites sit unnoticed outside :mod:`pcapkit`. + is what let dead-anchor sites sit unnoticed outside :mod:`pcapkit`. """ @@ -338,10 +338,10 @@ def test_no_malformed_fragments(self) -> 'None': def test_the_documentation_exemption_holds_on_every_known_mechanism(self) -> 'None': """:func:`_is_documentation` on each input that defeated the old masker. - This is the regression suite for five rounds of review, and it exists because + This is the regression suite for several rounds of review, and it exists because each of those rounds fixed the mechanism the previous postmortem had named and then missed the next one. Pinning the *table* rather than the latest fix is the - difference: a sixth mechanism has to be added here to be considered handled, and + difference: a new mechanism has to be added here to be considered handled, and a redesign has to keep every row passing. The rows are the real inputs, not paraphrases of them. Four are false negatives @@ -394,7 +394,7 @@ def test_the_documentation_exemption_holds_on_every_known_mechanism(self) -> 'No ('a citation opened like the idiom but not closed like it', 'names ``%s and more', True), # Pins **any** whitespace rather than a literal space. Narrowing - # ``isspace()`` to ``== ' '`` passed all fifteen earlier rows, because the + # ``isspace()`` to ``== ' '`` passed every earlier row, because the # only row reaching that branch used a plain space -- so the boundary # condition the comment above relies on was asserted for one whitespace # character out of the set it names. A reader writing the idiom after a diff --git a/tests/project/test_rfc_constants_one_home_1739_unit.py b/tests/project/test_rfc_constants_one_home_1739_unit.py index 044478737c..d9a0de8fc3 100644 --- a/tests/project/test_rfc_constants_one_home_1739_unit.py +++ b/tests/project/test_rfc_constants_one_home_1739_unit.py @@ -7,7 +7,7 @@ or :mod:`pcapkit.const` module -- and every reader imports it from there. Such a constant is never configurable, and the old homes do not re-export it. -Four checks pin that: +These checks pin that: * :class:`TestHomes` -- each constant is defined in its home, with the value the RFC or the format gives it; @@ -15,7 +15,7 @@ name, at module or class level, and none spells the distinctive literals (the PCAP and PCAP-NG magic numbers and the PCAP timestamp resolutions) itself; * :class:`TestReaders` -- each reader imports the constant from its home and - reads it, and :mod:`pcapkit.toolkit.pypcapfile`, which defined four of them, + reads it, and :mod:`pcapkit.toolkit.pypcapfile`, which defined several of them, no longer binds those names at all; * :class:`TestNotReinlined` -- no module in :data:`SWEPT`, the homes included, spells a homed value anywhere but in the home's own definition: not as an diff --git a/tests/project/test_sentinels_doc_page_934_unit.py b/tests/project/test_sentinels_doc_page_934_unit.py index 013597bd87..e7f7256692 100644 --- a/tests/project/test_sentinels_doc_page_934_unit.py +++ b/tests/project/test_sentinels_doc_page_934_unit.py @@ -4,11 +4,11 @@ GitHub issue #934: what is now :file:`docs/source/contributing/conventions/sentinel-convention.rst` (GitHub issue #918 split it out of the single-page :file:`conventions.rst` that carried -it at the time) cross-references :mod:`pcapkit.corekit.sentinels` five times -(the ``:mod:`` role, at lines 165, 168, 171, 174 and 261 of the pre-split page), -and none of them used to resolve, because no page under :file:`docs/source/` -documented that module -- confirmed by an explicit nitpicky ``sphinx-build`` -before this page existed, and again after, to confirm the fix. +it at the time) cross-references :mod:`pcapkit.corekit.sentinels` repeatedly +(the ``:mod:`` role), and none of those references used to resolve, because +no page under :file:`docs/source/` documented that module -- confirmed by an +explicit nitpicky ``sphinx-build`` before this page existed, and again after, +to confirm the fix. This does **not** re-test Sphinx's cross-reference resolution itself -- as :file:`tests/project/test_documentation_claims.py` explains at length, whether a diff --git a/tests/project/test_stdlib_feature_probes_1709_unit.py b/tests/project/test_stdlib_feature_probes_1709_unit.py index 7be9ae9f17..a022b5d05f 100644 --- a/tests/project/test_stdlib_feature_probes_1709_unit.py +++ b/tests/project/test_stdlib_feature_probes_1709_unit.py @@ -5,15 +5,15 @@ :mod:`pcapkit` needs a name or a behaviour that only some supported interpreters have, it asks :data:`sys.version_info`, in :mod:`pcapkit.utilities.compat` when the answer is a name to re-export, rather than probing with :func:`getattr` or -:func:`hasattr`. Issue #1709 found six probes, each with a string literal naming -the attribute. Five ask a module or builtin class: +:func:`hasattr`. Issue #1709 found these probes, each with a string literal naming +the attribute. Most ask a module or builtin class: * ``getattr(inspect, 'get_annotations', None)``, in :file:`pcapkit/corekit/infoclass.py` and :file:`pcapkit/protocols/protocol.py`; * ``getattr(types, 'UnionType', None)``, in :file:`pcapkit/corekit/infoclass.py`; * ``hasattr(dict, '__reversed__')``, twice in :file:`pcapkit/corekit/infoclass.py`. -The sixth asks an instance, so nothing about its receiver marks it: it is a +One asks an instance, so nothing about its receiver marks it: it is a version probe because of the attribute it names. * ``getattr(node, 'end_lineno', node.lineno)``, in @@ -24,7 +24,7 @@ probe of any object for an attribute in :data:`VERSIONED`. A computed attribute name, as in ``getattr(hashlib, digest)``, is a lookup rather than a question about the interpreter, and is not matched. Run against the tree before issue -#1709, it reports exactly those six and the two :data:`EXEMPT` entries. +#1709, it reports exactly those and the :data:`EXEMPT` entries. This module is unit-tier: it reads source text and never imports the package. diff --git a/tests/project/test_unit_tests_queue.py b/tests/project/test_unit_tests_queue.py index b43e132027..656f744bf2 100644 --- a/tests/project/test_unit_tests_queue.py +++ b/tests/project/test_unit_tests_queue.py @@ -47,7 +47,7 @@ ROOT = pathlib.Path(__file__).resolve().parents[2] WORKFLOW = ROOT / '.github' / 'workflows' / 'unit-tests.yml' -#: The four legs a docs-only pull request may skip. +#: The legs a docs-only pull request may skip. LEGS = ('test', 'integration', 'engine-tests', 'pypcap-parity') diff --git a/tests/project/test_workflow_run_verdict.py b/tests/project/test_workflow_run_verdict.py index f0d0feb488..855580e666 100644 --- a/tests/project/test_workflow_run_verdict.py +++ b/tests/project/test_workflow_run_verdict.py @@ -2,10 +2,10 @@ """Tests that Conda Update, Vendor Update and GitHub Pages act only under a verdict for the commit they build (#1643). -All three chain off ``Unit Tests`` completing and check out ``github.sha``, which +Each chains off ``Unit Tests`` completing and checks out ``github.sha``, which for a ``workflow_run`` is ``main``'s tip when the event is raised -- not the commit the completed run verified. Conda Update 38325136710 was raised 2 s after the run -for 9083163f5 succeeded, ran on 2e941bbb7 (three merged pull requests later), and +for 9083163f5 succeeded, ran on 2e941bbb7 (with later pull requests merged), and pushed f4f94bcad at 00:03:38Z; 2e941bbb7's own run 38323130015 finished at 00:13:35Z. @@ -368,7 +368,7 @@ def _context(event_name: 'str' = 'workflow_run', conclusion: 'str' = 'success', #: ``[(row, context, whether verdict's if: holds, whether the acting job's does)]``, -#: for all three workflows; :data:`None` asserts nothing about that job. +#: for every workflow above; :data:`None` asserts nothing about that job. ROWS = [ ('run 38325136710: the verdict is for an older commit', _context(verified='false'), True, False), @@ -400,7 +400,7 @@ def _context(event_name: 'str' = 'workflow_run', conclusion: 'str' = 'success', class TestEachWorkflowGatesOnTheVerdict(unittest.TestCase): - """The ``verdict`` job, and the job it gates, in each of the three workflows.""" + """The ``verdict`` job, and the job it gates, in each of those workflows.""" @classmethod def setUpClass(cls) -> None: @@ -419,7 +419,7 @@ def test_each_acting_job_needs_the_verdict(self) -> None: self.assertIn('verdict', declared_needs(self._jobs(workflow)[job])) def test_every_scenario_decides_correctly(self) -> None: - """The table above, for both jobs, in all three workflows.""" + """The table above, for both jobs, in every workflow.""" violations = [] # type: list[str] for workflow, job in ACTING_JOBS.items(): jobs = self.jobs[workflow] @@ -447,7 +447,7 @@ def test_a_skipped_verdict_cannot_cascade_into_the_acting_job(self) -> None: self.assertTrue(declared_if(self._jobs(workflow)[job]).startswith('!cancelled() && ')) def test_the_verdict_job_is_one_job_in_three_places(self) -> None: - """Identical text, so a fix to one cannot leave the other two behind.""" + """Identical text, so a fix to one cannot leave the others behind.""" blocks = {workflow: self._jobs(workflow)['verdict'] for workflow in ACTING_JOBS} self.assertEqual(len(set(blocks.values())), 1, sorted(blocks)) diff --git a/tests/project/test_workflows_at_a_glance_1732.py b/tests/project/test_workflows_at_a_glance_1732.py index fafb0783d4..9c801c60f4 100644 --- a/tests/project/test_workflows_at_a_glance_1732.py +++ b/tests/project/test_workflows_at_a_glance_1732.py @@ -56,7 +56,7 @@ def workflow_name(text: 'str') -> 'str': def expected_row(path: 'pathlib.Path', text: 'str') -> 'list[Any]': - """The seven cells the table should give this workflow file; "other" as a list.""" + """The cells the table should give this workflow file; "other" as a list.""" events = triggers(text) def branches(event: 'str') -> 'str': diff --git a/tests/protocols/test_construction_keyword_check_unit.py b/tests/protocols/test_construction_keyword_check_unit.py index 1c5e555775..64d4514a7a 100644 --- a/tests/protocols/test_construction_keyword_check_unit.py +++ b/tests/protocols/test_construction_keyword_check_unit.py @@ -461,8 +461,8 @@ def test_a_direct_make_call_is_not_checked(self) -> None: :meth:`HTTP.make ` itself to reach its versioned implementation. - Closing it would mean interposing on each of the thirty ``make`` - implementations rather than on the one place their keywords meet, which is + Closing it would mean interposing on every ``make`` + implementation rather than on the one place their keywords meet, which is a larger change than #617. Written down here because the alternative is somebody inferring from the docstrings that ``make`` validates, and because if the gap is ever closed this test goes red and gets deleted. diff --git a/tests/protocols/test_option_generator_tcp_base_unit.py b/tests/protocols/test_option_generator_tcp_base_unit.py index e1a323eac2..5fb983863a 100644 --- a/tests/protocols/test_option_generator_tcp_base_unit.py +++ b/tests/protocols/test_option_generator_tcp_base_unit.py @@ -4,7 +4,7 @@ Every frame in :file:`examples/captures/options-tcp.pcap` is a TCP segment whose header comes from :data:`examples.generators.options.TCP_BASE` and whose only per-case difference is the one option it carries. So that mapping is the -description of twenty-five fixture frames, and a key it spells wrongly is a +description of every one of those fixture frames, and a key it spells wrongly is a description that does not match the octets. Nothing warned when one did. :meth:`TCP.make @@ -41,7 +41,7 @@ out independently is what makes the failure read ``0 != 1``, which is the defect, rather than ``KeyError: 'seq_no'``, which is a symptom of it. -It also gives the twenty-five fixture frames a stated contract. Changing +It also gives those fixture frames a stated contract. Changing ``TCP_BASE``'s values changes the bytes of ``options-tcp.pcap``, so it should take two edits and a moment's thought, not one. diff --git a/tests/protocols/test_option_roundtrip_unit.py b/tests/protocols/test_option_roundtrip_unit.py index bba9af1e0c..ccfee9430f 100644 --- a/tests/protocols/test_option_roundtrip_unit.py +++ b/tests/protocols/test_option_roundtrip_unit.py @@ -112,11 +112,13 @@ class Gap(NamedTuple): #: timestamp and so is not stable between runs. #: #: Make it as specific as the message allows, because a fragment that matches - #: half the tree does not pin anything: ``'invalid format'`` alone occurs 205 - #: times across 13 modules (31 in :file:`pcapkit/protocols/internet/hip.py`, 26 in - #: :file:`pcapkit/protocols/transport/tcp.py`), so it is satisfied by a regression at any of - #: them. Prefer the alias and whatever bracketed code the message carries -- - #: ``'TCP: [OptNo 28] invalid format'`` narrows those 26 sites to the one + #: half the tree does not pin anything: ``'invalid format'`` alone occurs at + #: sites across many modules (dozens each in + #: :file:`pcapkit/protocols/internet/hip.py` and + #: :file:`pcapkit/protocols/transport/tcp.py`), so it is satisfied by a + #: regression at any of them. Prefer the alias and whatever bracketed code the + #: message carries -- ``'TCP: [OptNo 28] invalid format'`` narrows the TCP + #: sites to the one #: option that can print ``28``. The tuple form is for messages whose stable #: parts are not contiguous, so that a fragment does not have to bake in a #: rendering that is itself defective. @@ -393,7 +395,7 @@ class Gap(NamedTuple): # -- PCAP-NG -------------------------------------------------------------- - # Thirty-three PCAP-NG entries used to be recorded here, for four defects + # PCAP-NG entries used to be recorded here, for the defects # that #1267-#1270 fixed. ``PCAPNG.__post_init__`` carried the make pass's # option count into its own re-parse, so every option with an "only one" # guard tripped it (27 options). ``if_IPv6addr`` declared 8 octets for 17. diff --git a/tests/test_base_class_contract.py b/tests/test_base_class_contract.py index aaa978c336..a656191387 100644 --- a/tests/test_base_class_contract.py +++ b/tests/test_base_class_contract.py @@ -29,11 +29,11 @@ over it could miss a site and nothing would fail. It missed one twice -- issue #506 (a runtime import in ``schema/schema.py`` unreachable for three years) and issue #513 (the ``extraction.py`` gates rejecting the library's own -built-ins for three years). These two tests replace the convention with +built-ins for three years). These tests replace the convention with something that fails. -The sweep and the migration are both complete: all 82 sites are renamed, the -last 54 (all ``ProtocolBase``, across ``pcapkit/protocols/`` and three +The sweep and the migration are both complete: every site is renamed, the +last of them (all ``ProtocolBase``, across ``pcapkit/protocols/`` and some ``pcapkit/foundation/`` modules) having landed in #514 part (c) once #726 and #742 merged. :data:`PENDING_ALIAS_PATHS` is therefore empty -- its intended end state -- and :func:`is_pending` is trivially ``False`` for every path; the dict @@ -133,7 +133,7 @@ #: Paths still carrying the alias because another open pull request owns them, #: mapped to that pull request. A prefix rather than a file list, because #726 -#: owns the whole ``pcapkit/protocols/`` subtree and enumerating its ~50 sites +#: owns the whole ``pcapkit/protocols/`` subtree and enumerating its sites #: would turn this into a changelog. #: #: Each entry is a promise, not an exemption: when the named pull request lands, @@ -141,7 +141,7 @@ #: state**, and :meth:`BaseClassAliasTests.test_no_library_module_imports_a_base_under_its_public_name` #: fails on an entry that has stopped matching anything, so a stale promise #: cannot sit here unnoticed once its pull request merges. #514 part (c) landed -#: the last 54 sites, so this is now empty and every alias check below runs +#: the last sites, so this is empty and every alias check below runs #: unconditionally. PENDING_ALIAS_PATHS = {} # type: dict[str, int] diff --git a/tests/test_docstring_contract.py b/tests/test_docstring_contract.py index d26df326e6..45e8ee4e7e 100644 --- a/tests/test_docstring_contract.py +++ b/tests/test_docstring_contract.py @@ -16,9 +16,9 @@ docstring written tomorrow is checked tomorrow rather than being a snapshot of what was wrong in 2026. -Four properties are asserted, and the split between them is deliberate -- +These properties are asserted, and the split between them is deliberate -- each is sound on its own, and the softer judgements are recorded rather than -asserted. The first three derive their answer from the code; the fourth cannot, +asserted. All but the last derive their answer from the code; the last cannot, and says so: :meth:`DocstringParameterTests.test_documented_parameters_exist` @@ -223,7 +223,7 @@ class Known(NamedTuple): KNOWN_DEFECTS = ( # NOTE: the ``register_extractor_engine`` entry that used to head this tuple # is gone because the defect is fixed -- it documented 'engine' where the - # parameter is 'name', which is #546's item 2. The remaining 34 register_* + # parameter is 'name', which is #546's item 2. The remaining register_* # functions in that file were checked at the same time and none of them # carries the same defect, so there is nothing left to record here for it. Known(Finding('pcapkit/vendor/mh/binding_ack_flag.py', 'context', 'soup'), diff --git a/tests/test_support_helpers.py b/tests/test_support_helpers.py index 3713f7ac88..7f66abee73 100644 --- a/tests/test_support_helpers.py +++ b/tests/test_support_helpers.py @@ -28,7 +28,7 @@ more cause: :class:`SnapshotRestoreTests` and :class:`StandInsDoNotOutliveTheirTestTests` cover :func:`~tests._support.isolate_modules` and the snapshot/restore pair beneath it, -which exist because issue #660 -- twelve failures in :mod:`tests.project`, +which exist because issue #660 -- a run of failures in :mod:`tests.project`, visible only in some collection orders -- was a stand-in module left bound in :data:`sys.modules` by a test that had finished. @@ -564,8 +564,8 @@ class LoadedModulesDoNotOutliveTheirTestTests(unittest.TestCase): hides the next one. The polluting cases are *borrowed* rather than written here, so what is pinned - is the behaviour of call sites the suite actually has. All five leaked before - the fix, and none of them looked wrong. + is the behaviour of call sites the suite actually has. Every one of them + leaked before the fix, and none of them looked wrong. """ @@ -654,8 +654,8 @@ def runTest(self) -> None: class ArrangedRestoreTests(unittest.TestCase): """The guards and the bookkeeping around :func:`~tests._support.restore_modules_after`. - Four things that have to hold for the #674 fix to be more than a patch on - five call sites: the snapshot kept is the earliest one, the test found on the + What has to hold for the #674 fix to be more than a patch on the call + sites it touched: the snapshot kept is the earliest one, the test found on the stack is the running one rather than any object that happens to be called ``self``, a loader that cannot find a test to restore for refuses rather than proceeding, and :func:`~tests._support.ensure_package` refuses to bind a stub @@ -734,7 +734,7 @@ def test_an_idle_test_case_in_a_local_named_self_is_not_used(self) -> None: and a cleanup registered on a test that has already finished is never run, so the stubs outlive the test exactly as in #674 but with no error to show for it. Measured before :func:`~tests._support._is_running_test` was - consulted: ten names left bound, silently. + consulted: names left bound, silently. Contrived, and deliberately so: no call site in the suite looks like this, which is the point. The heuristic has to be sound for the call sites diff --git a/tests/test_tier_guard.py b/tests/test_tier_guard.py index 03d8c4182d..c30f3e7298 100644 --- a/tests/test_tier_guard.py +++ b/tests/test_tier_guard.py @@ -992,8 +992,8 @@ def test_asking_for_an_extra_of_a_requirement_is_not_symmetric(self) -> None: ``beautifulsoup4[html5lib]`` installs ``beautifulsoup4``, so it provides it. Plain ``beautifulsoup4`` does not install ``html5lib``, so it does not provide ``beautifulsoup4[html5lib]``. A matcher that compared only - distribution names would call the ``test`` extra sufficient for the four - vendor modules that need :mod:`html5lib`, and the 41 methods they hold + distribution names would call the ``test`` extra sufficient for the + vendor modules that need :mod:`html5lib`, and the methods they hold would read as covered while they went on skipping. """ @@ -1013,7 +1013,7 @@ def test_a_version_specifier_and_a_marker_do_not_defeat_matching(self) -> None: self.assertFalse(_dependency_gates.provided_by(requirements, 'dpkt')) def test_the_extras_read_back_what_pyproject_declares(self) -> None: - """Spot checks on the four extras the rest of this suite reasons about.""" + """Spot checks on the extras the rest of this suite reasons about.""" declared = _dependency_gates.declared_requirements() self.assertEqual([requirement.text for requirement in declared['crypto']], @@ -1048,8 +1048,8 @@ def test_a_bracket_inside_a_requirement_does_not_end_the_array(self) -> None: def test_all_is_narrowed_to_core_addons_by_910(self) -> None: """#910: ``all`` means core addons only, not every engine an end user might want. - The owner's ruling narrowed ``all`` from 8 requirements to 3 -- ``cli``, - ``crypto`` and ``pycrate`` (``NGAP``) stay, and the four 3rd-party + The owner's ruling narrowed ``all`` to the core addons -- ``cli``, + ``crypto`` and ``pycrate`` (``NGAP``) stay, and the third-party capture engines that used to be bundled here (``dpkt``, ``scapy``, ``pyshark``, ``pypcapfile``) move out to their own on-demand extras, covered by :meth:`test_dev_carries_what_all_used_to_for_the_toolchain`. @@ -1208,7 +1208,7 @@ def test_every_shape_the_suite_writes_a_flag_in_resolves(self) -> None: Each of these is the only shape some real module uses, so a resolver that handled only the obvious ``find_spec('x') is not None`` would - silently report four of the five as gating on nothing -- and a flag that + silently report most of them as gating on nothing -- and a flag that requires nothing can never be a gap, which is failure by silence again. """ @@ -1319,13 +1319,13 @@ def test_a_flag_gated_where_it_is_not_defined_resolves_through_the_import(self) ) def test_one_flag_name_may_mean_two_things_and_is_resolved_per_module(self) -> None: - """``HAS_RUNTIME`` is the four core dependencies, except in one module. + """``HAS_RUNTIME`` is the core dependencies, except in one module. :file:`tests/foundation/engines/test_runtime_engines.py` reuses the name - for those four plus ``dpkt``, ``scapy`` and ``pyshark``. Resolved by - name instead of per module, either that module's three extra - requirements would be demanded of the hundred-odd others, or the - hundred-odd would excuse it -- and it is the one HAS_RUNTIME gate in the + for those plus ``dpkt``, ``scapy`` and ``pyshark``. Resolved by + name instead of per module, either that module's extra + requirements would be demanded of every other module, or the + others would excuse it -- and it is the one HAS_RUNTIME gate in the suite that really does go dark. """ @@ -1356,8 +1356,8 @@ def test_only_the_jobs_that_run_pytest_are_considered(self) -> None: """Keyed on running the suite, not on holding an install line. The ``changelog`` job of this workflow installs nothing and runs a - generator, and five other workflows install ``.[all]`` somewhere, - three as ``.[all,dev]`` -- which carries ``pypcapfile``, + generator, and other workflows install ``.[all]`` somewhere, + some as ``.[all,dev]`` -- which carries ``pypcapfile``, ``pyshark`` and ``scapy`` through the ``dev`` extra #910 added when it narrowed ``all`` to core addons only -- without ever invoking :program:`pytest`. A guard that looked at install lines anywhere in @@ -1585,9 +1585,9 @@ def test_the_four_gates_737_and_740_fixed_are_covered_on_every_job_reaching_them """What this guard exists to stop regressing, named one flag at a time. #737 added ``DPKT`` and #740 added ``crypto``, ``cli`` and ``NGAP`` to - the install lines. Nothing held those four in place, which is #745's + the install lines. Nothing held those in place, which is #745's whole complaint -- deleting ``crypto`` from the ``test`` job would - re-dark 14 ESP methods and go green. + re-dark the ESP methods and go green. """ gaps = {gap.flag for gap in _dependency_gates.dependency_gate_gaps()} @@ -1618,10 +1618,10 @@ def test_the_vendor_extra_closes_engine_tests_but_not_test_or_gate(self) -> None ``engine-tests`` (#751) already reaches these gates through the same ignore-shape selection as ``test`` -- see this guard's own ``HAS_VENDOR_DEPS`` exclusion -- and it has never been one of ruleset - 23497679's 15 required checks, so it already was the "job that exists + 23497679's required checks, so it already was the "job that exists and reports without gating a merge" #738's ruling asked for. Installing - ``vendor`` there, rather than opening a sixth job, is what closes the - 41-method gap on it. It is also the only *per-pull-request* job with + ``vendor`` there, rather than opening another job, is what closes the + gap on it. It is also the only *per-pull-request* job with that property: ``gate`` reaches these gates too but never runs on a pull request at all (only via a release's ``gate-only: true`` call), and ``integration``'s fixture-tier selection never reaches @@ -2047,11 +2047,11 @@ def test_dropping_isort_from_the_test_extra_is_caught(self) -> None: 'the exclusion list would swallow the gap this test relies on') def test_removing_dpkt_is_caught_on_every_job_that_installs_it(self) -> None: - """#729's defect, restaged. Four jobs install ``DPKT`` via a comma list; all four go dark. + """#729's defect, restaged. Every job installing ``DPKT`` via a comma list goes dark. - #751 added ``engine-tests`` and ``pypcap-parity`` to the three this test + #751 added ``engine-tests`` and ``pypcap-parity`` to the jobs this test used to name, each carrying its own ``DPKT`` for the same reason as the - original three -- ``engine-tests`` for + original ones -- ``engine-tests`` for :file:`tests/foundation/engines/test_runtime_engines.py`'s reused ``HAS_RUNTIME``, ``pypcap-parity`` for :file:`examples/generators/make_samples.py`. @@ -2063,8 +2063,9 @@ def test_removing_dpkt_is_caught_on_every_job_that_installs_it(self) -> None: -- and, separately, engine-tests no longer reaches test_runtime_engines.py regardless (see the HAS_RUNTIME exclusion), so there is no longer a DPKT-via-engine-tests gap for this doctoring - to reopen. Four jobs, not five. (#1538 later dropped that DPKT cell - outright: it ran only test_dpkt_unit.py, which ``test`` runs too.) + to reopen, and it is not among the jobs checked here. (#1538 later + dropped that DPKT cell outright: it ran only test_dpkt_unit.py, which + ``test`` runs too.) """ text = _dependency_gates.WORKFLOW.read_text(encoding='utf-8') @@ -2101,7 +2102,7 @@ def test_swapping_pypcap_parity_to_pcap_ct_is_an_ambiguous_satisfaction(self) -> """#762, direction one: the wrong half of the ``pcap`` ambiguity, installed. ``pypcap-parity`` swapped from the ``PyPCAP`` extra to ``PCAP_CT`` still - reaches all 4 ``HAS_PYPCAP`` gates, and + reaches every ``HAS_PYPCAP`` gate, and :func:`~tests._dependency_gates.dependency_gate_gaps` still calls them satisfied -- pcap-ct ships the same top-level ``pcap`` module, so this is exactly the blind spot :func:`~tests._dependency_gates.dependency_gate_gaps` @@ -2382,7 +2383,7 @@ def test_a_test_paths_arm_with_no_matching_extra_arm_is_caught(self) -> None: Commenting out one engine's ``EXTRA=`` arm -- rather than renaming it, which the new matrix-list-vs-case-arms equality check above would catch first, for a different reason -- leaves Scapy declared in the ``engine:`` list and still - present in ``engine_paths`` (so the equality check sees the same five engines on + present in ``engine_paths`` (so the equality check sees the same engines on both sides and stays quiet), but with no ``EXTRA=`` arm of its own: exactly the shape the per-engine loop's own check exists for. diff --git a/tests/utilities/test_compat.py b/tests/utilities/test_compat.py index 17c0911633..55e505b935 100644 --- a/tests/utilities/test_compat.py +++ b/tests/utilities/test_compat.py @@ -234,9 +234,9 @@ def assert_aenum_is_not_poisoned(self) -> None: Checked here, immediately, rather than left to show up as the symptom, because the symptom is unrecoverable and lands somewhere else. Nothing this file can do afterwards puts a memoised value back, so the useful - moment to notice is the test that caused it -- not the ten tests of - :mod:`tests.project.test_public_api` that failed on it three directories - away. + moment to notice is the test that caused it -- not the tests of + :mod:`tests.project.test_public_api` that failed on it in another + directory. """ real = sys.version_info[:2] @@ -445,7 +445,7 @@ def test_faking_the_version_leaves_aenum_reading_the_real_one(self) -> None: ``pcapkit/const/reg/apptype.py:26`` did for ``TransportProtocol`` when #687 was found, and it is the statement that raised ``AttributeError: 'TransportProtocol' object has no attribute - '__set_name__'`` for ten tests of :mod:`tests.project.test_public_api` + '__set_name__'`` for tests of :mod:`tests.project.test_public_api` when this file ran before them under :mod:`unittest`. Asserting on it here costs two lines and no ``import pcapkit``, which keeps this module in the unit tier (see :mod:`tests._tiers`). diff --git a/tests/vendor/test_crawler_reachability_unit.py b/tests/vendor/test_crawler_reachability_unit.py index 29c2822c09..400a37030a 100644 --- a/tests/vendor/test_crawler_reachability_unit.py +++ b/tests/vendor/test_crawler_reachability_unit.py @@ -81,7 +81,7 @@ #: Whether the crawler machinery is importable at all. Importing #: :mod:`pcapkit.vendor` pulls in every subpackage unconditionally: #: :mod:`pcapkit.vendor.default` imports :mod:`requests` at module scope and -#: seven of the crawlers import :mod:`bs4` at module scope, so both are needed +#: several of the crawlers import :mod:`bs4` at module scope, so both are needed #: for this file rather than optional to it. (:mod:`pcapkit.vendor`'s own #: ``try: import bs4`` downgrades the *warning*, not the #: :exc:`ModuleNotFoundError` raised by the crawler imports below it.) diff --git a/tests/vendor/test_ipx_socket_unit.py b/tests/vendor/test_ipx_socket_unit.py index aa62341fe1..be52b6677e 100644 --- a/tests/vendor/test_ipx_socket_unit.py +++ b/tests/vendor/test_ipx_socket_unit.py @@ -40,12 +40,12 @@ #: Whether the crawler machinery is importable at all. Two packages are needed #: and neither is optional to this file: ``pcapkit.vendor.default`` imports #: :mod:`requests` at module scope, and :mod:`pcapkit.vendor` then imports every -#: crawler unconditionally, seven of which import :mod:`bs4` at module scope -- +#: crawler unconditionally, several of which import :mod:`bs4` at module scope -- #: so importing *one* crawler needs both. (:mod:`pcapkit.vendor`'s own #: ``try: import bs4`` suppresses the warning, not the ``ModuleNotFoundError`` #: raised by the crawler imports below it.) #: -#: Both now ship in the ``test`` extra as well as ``vendor`` +#: Both ship in the ``test`` extra as well as ``vendor`` #: (:file:`pyproject.toml`), because CI installs ``.[test]`` and a skipped pin #: guards nothing. The guard is kept as belt-and-braces for an environment that #: lacks them anyway, so this file skips rather than erroring -- the same way diff --git a/tests/vendor/test_user_agent_unit.py b/tests/vendor/test_user_agent_unit.py index 91d8a8c4a7..bbf9a9d810 100644 --- a/tests/vendor/test_user_agent_unit.py +++ b/tests/vendor/test_user_agent_unit.py @@ -56,8 +56,8 @@ #: Every distribution importing :mod:`pcapkit.vendor` needs. ``requests`` is the #: obvious one -- ``pcapkit.vendor.default`` imports it at module scope -- but it #: is not sufficient: importing ``pcapkit.vendor.default`` imports the -#: ``pcapkit.vendor`` package first, and its :file:`__init__.py` pulls in all -#: seventeen subpackages, seven of which ``import bs4`` at module scope. So a +#: ``pcapkit.vendor`` package first, and its :file:`__init__.py` pulls in every +#: subpackage, several of which ``import bs4`` at module scope. So a #: guard on ``requests`` alone lets the suite error instead of skipping on a #: machine that happens to have ``requests`` and not ``beautifulsoup4``. VENDOR_DEPS = ('requests', 'bs4', 'html5lib') diff --git a/tests/vendor/test_vendor_dest_path_unit.py b/tests/vendor/test_vendor_dest_path_unit.py index 474f67747a..4093cb0d80 100644 --- a/tests/vendor/test_vendor_dest_path_unit.py +++ b/tests/vendor/test_vendor_dest_path_unit.py @@ -87,9 +87,9 @@ two-dependency gate :file:`tests/vendor/test_crawler_reachability_unit.py` uses, because importing :mod:`pcapkit.vendor.default` first imports the :mod:`pcapkit.vendor` package, whose :file:`__init__.py` pulls in every -crawler subpackage unconditionally -- seven of which ``import bs4`` at module +crawler subpackage unconditionally -- several of which ``import bs4`` at module scope. ``html5lib`` is deliberately *not* in the gate: it appears nowhere at -module scope, only as the string parser name in six crawlers' +module scope, only as the string parser name in the crawlers' ``bs4.BeautifulSoup(text, 'html5lib')`` calls at actual crawl time, which nothing here reaches -- no test in this file calls :meth:`Vendor.__init__` or :meth:`~Vendor.context`. ``requests`` and ``beautifulsoup4`` both ship in the diff --git a/tests/vendor/test_vendor_exit_code_unit.py b/tests/vendor/test_vendor_exit_code_unit.py index 92868dd094..2173ac2f25 100644 --- a/tests/vendor/test_vendor_exit_code_unit.py +++ b/tests/vendor/test_vendor_exit_code_unit.py @@ -69,7 +69,7 @@ #: ``vendor_module`` default-target-list fallback this suite patches), which #: pulls in every crawler subpackage unconditionally -- #: :mod:`pcapkit.vendor.default` imports :mod:`requests` at module scope and -#: seven crawlers import :mod:`bs4` at module scope. +#: several crawlers import :mod:`bs4` at module scope. VENDOR_DEPS = ('requests', 'bs4') #: Whether the crawler machinery is importable at all. Both ship in the diff --git a/tests/vendor/test_vendor_missing_body_unit.py b/tests/vendor/test_vendor_missing_body_unit.py index 443ca0e612..7bb134fee5 100644 --- a/tests/vendor/test_vendor_missing_body_unit.py +++ b/tests/vendor/test_vendor_missing_body_unit.py @@ -30,8 +30,8 @@ miss.append(f' #: {desc}') miss.append(f" return cls._unregistered_member(value, '{self.safe_name(name)}')") -Measured: 53 crawlers emit 109 such non-returning lines between them, and -three registries under :mod:`pcapkit.const` carry exactly that shape today. +Measured: many crawlers emit such non-returning lines between them, and +registries under :mod:`pcapkit.const` carry exactly that shape. A crawler hard-coding a range-guarded body as a list literal is writing something valid, so the guard below checks only that a hard-coded body *ends* in a ``return`` and that no emitted line re-enters ``_missing_`` for diff --git a/tests/vendor/test_vendor_reg_apptype_generator_unit.py b/tests/vendor/test_vendor_reg_apptype_generator_unit.py index 216deb72df..dbeb3600ae 100644 --- a/tests/vendor/test_vendor_reg_apptype_generator_unit.py +++ b/tests/vendor/test_vendor_reg_apptype_generator_unit.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -"""Three mechanical shapes :mod:`pcapkit.vendor.reg.apptype.apptype` must keep. +"""The mechanical shapes :mod:`pcapkit.vendor.reg.apptype.apptype` must keep. GitHub issue #744: every one of :class:`~pcapkit.const.reg.apptype.apptype.AppType`'s -~12,391 members used to be an *annotated* assignment -- +members used to be an *annotated* assignment -- ``tcpmux: 'TCP' = 1, 'tcpmux', TransportProtocol.get('tcp') | TransportProtocol.get('udp')`` -- which put one forward-ref string per member into the class's ``__annotations__``. Sphinx's default autodoc calls @@ -33,7 +33,7 @@ as a plain one -- infers the class attribute's type as ``int`` while the ``auto()``-valued siblings (``tcp``, ``udp``, ``sctp``, ``dccp``) infer as ``Any``. That is what made ``TransportProtocol.undefined`` disagree with its -own ``'TransportProtocol'`` annotation at the four sites that default to it -- +own ``'TransportProtocol'`` annotation at the sites that default to it -- the class attribute ``__transport__``, and the ``proto`` parameter on ``__new__``, ``get`` and ``get_all``. The fix wraps the literal in :func:`~typing.cast` so mypy infers ``TransportProtocol`` there too, without @@ -41,7 +41,7 @@ so ``TransportProtocol.undefined`` stays the same ``0`` -- ``TransportProtocol(0) is undefined`` and ``bool(undefined)`` is ``False`` -- and the same genuine ``TransportProtocol`` member it always was: the ``proto`` sentinel default at -all four sites, and what the base registry's ``_missing_`` extends +each of those sites, and what the base registry's ``_missing_`` extends unassigned/reserved rows from. Two rejected alternatives, measured rather than argued: an explicit member annotation (``undefined: 'TransportProtocol' = 0``) does not fix this at all, it only *relocates* the error -- mypy still reports @@ -75,9 +75,9 @@ test_undefined_member_is_cast_rather_than_a_bare_literal`'s own docstring for the measurements.) -The first two are pinned two ways: directly against the generator's own +#744 and #768 are pinned two ways: directly against the generator's own :meth:`~pcapkit.vendor.reg.apptype.apptype.AppType.flag`, which needs no -network access since it is a ``@staticmethod``, and against the five files it +network access since it is a ``@staticmethod``, and against the files it actually produced, committed under :mod:`pcapkit.const.reg.apptype`. #770 is pinned against that same base module -- a plain source-text assertion that the member stays wrapped in ``cast`` rather than reverting to a bare literal, plus @@ -161,10 +161,10 @@ def test_flag_emits_attribute_access_not_get_calls(self) -> None: self.assertNotIn('.get(', AppType.flag(protos)) def test_generated_registries_carry_no_per_member_annotation(self) -> None: - """GitHub issue #744, against what the five committed files produced. + """GitHub issue #744, against what the committed files produced. - Before the fix, ``TCP.__annotations__`` alone held 6,150 entries -- - 6,147 members plus its three class-level attributes. Only the + Before the fix, ``TCP.__annotations__`` alone held an entry for every + member on top of its class-level attributes. Only the class-level attributes each registry declares exactly once should remain: ``__transport__``, ``__registry__``, ``__canonical__``, and -- on the memberless base only -- ``__registries__``. diff --git a/tests/vendor/test_vendor_snapshot_restore_unit.py b/tests/vendor/test_vendor_snapshot_restore_unit.py index a50cdec5dd..0b30143d8c 100644 --- a/tests/vendor/test_vendor_snapshot_restore_unit.py +++ b/tests/vendor/test_vendor_snapshot_restore_unit.py @@ -178,7 +178,7 @@ #: :mod:`pcapkit.vendor.__main__` imports :mod:`pcapkit.vendor` (for its #: ``vendor_module`` default-target-list fallback), which pulls in every #: crawler subpackage unconditionally -- :mod:`pcapkit.vendor.default` -#: itself imports :mod:`requests` at module scope and seven crawlers import +#: itself imports :mod:`requests` at module scope and several crawlers import #: :mod:`bs4` at module scope. VENDOR_DEPS = ('requests', 'bs4')