diff --git a/tests/_dependency_gates.py b/tests/_dependency_gates.py index da5ad5326..51af6cf40 100644 --- a/tests/_dependency_gates.py +++ b/tests/_dependency_gates.py @@ -115,10 +115,11 @@ 'ambiguous_satisfactions', 'describe_ambiguous_satisfaction', ] -#: The workflow holding every job that runs :program:`pytest`, and the only one -#: that runs it at all. Five of the other seven 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; +#: 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]`` +#: 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 @@ -200,7 +201,7 @@ # distribution, so ``beautifulsoup4`` alone does not provide it. That # distinction is the whole reason ``HAS_CRAWLER_DEPS`` is satisfied in CI # and ``HAS_VENDOR_DEPS`` is not: the ``test`` extra carries plain - # ``beautifulsoup4``, and only ``vendor`` and ``all`` carry + # ``beautifulsoup4``, and only ``vendor`` and ``dev`` carry # ``beautifulsoup4[html5lib]``. The second alternative below is not a # second *distribution* -- pyproject.toml never declares bare # ``html5lib`` -- so this is one distribution reached two ways, not the @@ -1156,8 +1157,8 @@ def flag_requirements() -> 'dict[tuple[str, str], frozenset[str]]': every module but one, and in :file:`tests/foundation/engines/test_runtime_engines.py` it names those four plus ``dpkt``, ``scapy`` and ``pyshark``. Keyed on the name alone, that one - module's requirements would be demanded of the 130 others, or the 130 would - excuse it. + module's requirements would be demanded of every other module that gates on + it, or they would excuse it. A module that gates on a flag it imports resolves through the import, so ``tests/integration/test_cli_subprocess.py`` gets ``HAS_EMOJI``'s @@ -1222,10 +1223,11 @@ def gated_scopes() -> 'tuple[Gate, ...]': scan: ``python_files`` in :file:`pyproject.toml` is what pytest collects, so a gate in a helper module gates nothing. Class-level and method-level decorators are both collected, and the class-level ones are the majority -- - ``HAS_DPKT`` reaches 20 methods through 6 class decorators and 8 through a - method decorator -- counted by exact-match AST identifiers the way this - function itself matches them, not by a substring search, which would - (elsewhere) fold ``HAS_PYPCAP`` together with ``HAS_PYPCAPFILE``. + when #745 was fixed, ``HAS_DPKT`` reached 20 methods through 6 class + decorators and 8 through a method decorator -- counted by exact-match AST + identifiers the way this function itself matches them, not by a substring + search, which would (elsewhere) fold ``HAS_PYPCAP`` together with + ``HAS_PYPCAPFILE``. """ gates = [] # type: list[Gate] @@ -1406,7 +1408,7 @@ def _engine_matrix_variants(name: 'str', section: 'str') -> 'Optional[tuple[Job, def pytest_jobs(workflow: 'Optional[pathlib.Path]' = None) -> 'tuple[Job, ...]': """The jobs of ``workflow`` that run :program:`pytest`. - Keyed on running the suite, not on holding an install line: seven other + Keyed on running the suite, not on holding an install line: five other workflows install ``.[all]`` somewhere, three of them as ``.[all,dev]`` -- which does carry ``pypcapfile``, through the ``dev`` extra #910 added when it narrowed ``all`` to core addons only -- and never invoke diff --git a/tests/_support.py b/tests/_support.py index 6973c991d..e573f9de8 100644 --- a/tests/_support.py +++ b/tests/_support.py @@ -960,7 +960,7 @@ def purge_modules(prefixes: Iterable[str]) -> None: change another test can observe: the next one that wants it imports it again and gets an *equivalent* thing from the same source. Binding something *else* over the name is what cannot be undone by re-importing, so restoration is owed by the - helpers that bind, not by this one. Making ~120 call sites pay for a restore none + helpers that bind, not by this one. Making every call site pay for a restore none of them needs would also cost a re-import each, which :func:`tests.conftest.pytest_sessionstart` exists to avoid. diff --git a/tests/_tiers.py b/tests/_tiers.py index 6dfd8ebe1..60f544e82 100644 --- a/tests/_tiers.py +++ b/tests/_tiers.py @@ -204,8 +204,8 @@ 'Exception', 'BaseException', }) -#: ``try`` statement node types. :class:`ast.TryStar` is 3.11+, and CI still runs -#: 3.8-3.10 (#1633), so it is looked up rather than named. +#: ``try`` statement node types. :class:`ast.TryStar` is 3.11+, and CI runs +#: older interpreters as well (#1633), so it is looked up rather than named. _TRY_NODES = (ast.Try,) + ((ast.TryStar,) if hasattr(ast, 'TryStar') else ()) # type: ignore[attr-defined] @@ -887,9 +887,9 @@ def fixture_tier_paths() -> 'tuple[str, ...]': added by :func:`skip_idiom_test_ids` rather than by :func:`skip_idiom_modules` directly, so that pulling in one skip-idiom test does not also pull in every unrelated method the same module happens to - hold. Without that, the two files this suite has today would add roughly a - hundred tests back into this selection to reach the two or three that - actually need it. + hold. Without that, the skip-idiom modules would add every one of their + tests back into this selection -- well over a hundred -- to reach the + handful that actually need it. This is deliberately *not* "the complement of :func:`is_unit_tier`" expressed as a single predicate the way :func:`is_unit_tier` itself is: the diff --git a/tests/const/test_const_apptype_split_unit.py b/tests/const/test_const_apptype_split_unit.py index fcc7eea9c..430fb3675 100644 --- a/tests/const/test_const_apptype_split_unit.py +++ b/tests/const/test_const_apptype_split_unit.py @@ -223,10 +223,12 @@ def test_repr_and_str_grow_an_alias_suffix_only_when_there_is_one(self) -> None: The suffix is display-only: it never reaches ``_value_``, which is the live lookup key in ``_value2member_map_`` and is built once when the - class is created -- see ``test_the_new_dunders_are_byte_identical_to_the_percent_form`` - and ``test_every_member_renders_its_own_registrys_transport_protocol`` - for the sweep over all 12,391 members that pins this for every one of - them, aliased or not. + class is created -- see + ``test_every_member_renders_its_own_registrys_transport_protocol`` for + the sweep over all 12,391 members that pins this for every one of them, + aliased or not, and + ``test_the_new_dunders_are_byte_identical_to_the_percent_form`` for the + sample #1062 formats against the pre-#798 form. """ from pcapkit.const.reg.apptype import TCP @@ -390,7 +392,7 @@ def test_register_alias_refuses_a_port_with_no_canonical_member_yet(self) -> Non """Aliasing names a second service on a port that already has one. A port with nothing there yet is what the generator and ``get``'s own - mint-on-miss are for, not this -- so this refuses rather than quietly + fallback on a miss are for, not this -- so this refuses rather than quietly becoming the port's first and only member. """ from pcapkit.const.reg.apptype import TCP @@ -483,7 +485,8 @@ def test_a_service_name_is_not_a_port_lookup(self) -> None: by transport protocol, so a name never matched and ``AppType.get('ssh')`` returned a **new** member with port ``-1`` instead of the one at 22. Nothing in :mod:`pcapkit` resolves a service by name, so - it now raises; #734 stays open for whether a real name lookup is wanted. + it now raises; #734 was closed on that, with the name lookup removed + rather than repaired. """ from pcapkit.const.reg.apptype import TCP @@ -567,7 +570,7 @@ def test_get_rejects_an_out_of_range_port_as_the_constructor_does(self) -> None: cls.__members__) # Paid for by narrowing nothing: a valid but unassigned port is what the - # mint is *for*, and it still answers with one. + # fallback member is *for*, and it still answers with one. minted = AppType.get(59000, proto=TransportProtocol.tcp) self.addCleanup(self._purge_member, TCP, 'PORT_59000_tcp', 59000) self.assertEqual(minted.svc, 'unknown') @@ -601,8 +604,8 @@ def test_a_span_on_two_transports_answers_each_with_its_own_row(self) -> None: self.assertIs(resolved.proto, cls.__transport__) # A span IANA assigns to TCP and UDP assigns nothing to SCTP, so the third - # registry mints rather than inheriting the TCP row -- which it did, as - # ````. + # registry answers with an ``unknown`` member of its own rather than + # inheriting the TCP row -- which it did, as ````. resolved = AppType.get(6010, proto='sctp') self.addCleanup(self._purge_member, SCTP, 'PORT_6010_sctp', 6010) self.assertEqual(resolved.svc, 'unknown') diff --git a/tests/const/test_const_enum_builtin_parity.py b/tests/const/test_const_enum_builtin_parity.py index f34b3269b..e5f83f1d5 100644 --- a/tests/const/test_const_enum_builtin_parity.py +++ b/tests/const/test_const_enum_builtin_parity.py @@ -384,7 +384,8 @@ def test_the_sweep_size_is_pinned(self) -> None: # 112 became 114 with GitHub issue #880's ngap.ProcedureCode and # ngap.ProtocolIE, moved onto EnumRegistry from hand-rolled IntEnum # classes in pcapkit.protocols.application.ngap -- two more IntEnum - # registries, two more modules, no change to the flag or str counts. + # registries, two more modules, no change to the flag or str counts -- + # and the sum in tests.const.test_const_enum_get became 120 with them. self.assertEqual(len(ints), 114) self.assertEqual(len(flags), 6) self.assertEqual(len(strs), 10) diff --git a/tests/const/test_const_enum_get.py b/tests/const/test_const_enum_get.py index 1f2eea516..05ba88da2 100644 --- a/tests/const/test_const_enum_get.py +++ b/tests/const/test_const_enum_get.py @@ -475,8 +475,8 @@ def test_the_vendor_template_still_emits_the_fix(self) -> None: GitHub issue #775's tier 3 moved #584's fix off the per-file generated ``get()`` entirely: it now lives permanently in - :meth:`~pcapkit.corekit.enum.EnumRegistry.get`, which every one of the - 105 default-template registries *inherits* rather than copies, so + :meth:`~pcapkit.corekit.enum.EnumRegistry.get`, which every + default-template registry *inherits* rather than copies, so there is no longer a ``get()`` block here for a regeneration to drop the fix from -- the block this test used to extract and compare no longer exists in either the template's output or the generated diff --git a/tests/const/test_const_enum_no_mint.py b/tests/const/test_const_enum_no_mint.py index d1b06c230..e79e4b724 100644 --- a/tests/const/test_const_enum_no_mint.py +++ b/tests/const/test_const_enum_no_mint.py @@ -1045,9 +1045,9 @@ def is_manufactured(name_arg: 'Optional[ast.expr]') -> 'bool': # safe one (a false positive is loud and gets a fixture; a false # negative ships quietly), and no real call site under # ``pcapkit/const``/``pcapkit/vendor`` is affected either way - # (measured: the sweep stays at 1012/0). It genuinely does over-flag: - # ``value.upper()`` alone is exempt (it is the receiver case just - # above), but the exact same expression as an *argument* -- + # (measured at round 5: the sweep stayed at 1012/0). It genuinely + # does over-flag: ``value.upper()`` alone is exempt (it is the + # receiver case just above), but the exact same expression as an *argument* -- # ``str(value.upper())``, ``helper(value.upper())`` -- flags, so # wrapping an already-exempt transform in one more call changes the # verdict. ``NAMES.get(value, 'unknown')`` flags while the @@ -1346,7 +1346,7 @@ def test_every_unregistered_member_call_passes_a_non_manufactured_name(self) -> # and the one ``super()._unregistered_member(...)`` forward its own # override makes -- 768 more, in one file, for 1012 total. #775's # final round then added the 52 on EtherType and the 1 on Socket -- - # 53 more, for 1065 total measured on this tree. + # 53 more, for 1065 total when that round landed. self.assertGreaterEqual(call_count, 1065, f'expected at least 1065 _unregistered_member call sites, found {call_count}') # And that the exemption is actually earning its keep, rather than a @@ -1882,16 +1882,15 @@ class BespokeOpenVocabularyUnmintConvertedTests(unittest.TestCase): converted, since the owner's reasoning names ``get`` explicitly and leaving it minting while ``_missing_`` did not would have been a direct contradiction. ``Command``/``Method``'s ``_unregistered_member`` - override canonicalises the constructed value to the same upper-case - ``name`` used for the lookup (rather than the caller's incidental input - casing), which is also what makes ``get('frob')`` and ``get('FROB')`` - compare *equal* even though, with nothing cached any more, they can - never again be *identical* -- see the two production regression tests - this forced: ``tests/protocols/application/test_ftp_unit.py:: - FTPTestCase::test_command_get_is_case_insensitive`` and - ``tests/protocols/application/test_http_unit.py::HTTPTestCase:: - test_method_get_is_case_insensitive``, both updated from ``assertIs`` to - ``assertEqual`` + ``assertIsNot`` for exactly this reason. + override canonicalises the member's *name* to upper case and keeps the + caller's own casing as its value, so ``get('frob')`` and ``get('FROB')`` + are unequal, and a repeated ``get('frob')`` is equal but, with nothing + cached any more, never again *identical* -- see the production + regression test this forced, + ``tests/protocols/application/test_ftp_unit.py::FTPUnitTests::test_command_get_is_case_insensitive``, + which pins exactly that with ``assertEqual``, ``assertIsNot`` and + ``assertNotEqual``. Its HTTP twin was replaced under #896 by + ``tests/protocols/application/test_http_unit.py::HTTPUnitTests::test_method_get_is_now_case_sensitive``. """ @@ -2250,7 +2249,7 @@ class BespokeGetUnchangedTests(unittest.TestCase): :class:`Method` used to resolve case-insensitively the same way (#583), but GitHub issue #896 retired that: RFC 9110 Section 9.1 makes the HTTP method token case-sensitive, unlike FTP's command codes (RFC 959 Section - 4.1), so ``Method.get('Get')`` no longer returns :attr:`Method.GET` -- + 5.3), so ``Method.get('Get')`` no longer returns :attr:`Method.GET` -- see ``test_method_get_is_now_case_sensitive`` below, which replaces the case-insensitive pin this class used to carry for it. ``Method`` still keeps its own ``get()`` rather than the base's, because it still needs to @@ -2609,8 +2608,8 @@ def test_apptype_get_dispatches_via_proto_without_minting(self) -> None: def test_apptype_unrecognised_proto_is_still_refused(self) -> None: """A ``proto`` naming no registry at all -- not one of the two real collision cases ``auto()`` introduced, just an ordinary invalid value - -- is still refused by :meth:`AppType._dispatch`, unaffected by this - PR. (Deliberately not a composite like ``tcp | udp``: under + -- is still refused by :meth:`AppType._dispatch`, unaffected by + #874. (Deliberately not a composite like ``tcp | udp``: under ``auto()`` that now equals ``sctp`` numerically and dispatches there rather than raising, which is the one accepted, explicitly untested consequence of the ``auto()`` change -- see diff --git a/tests/const/test_const_linktype_209_unit.py b/tests/const/test_const_linktype_209_unit.py index 4492ddf1c..f3602e102 100644 --- a/tests/const/test_const_linktype_209_unit.py +++ b/tests/const/test_const_linktype_209_unit.py @@ -76,13 +76,13 @@ #: parse its fixture. Spelled exactly as #: :data:`tests.vendor.test_request_prompt_unit.VENDOR_DEPS` so this file reaches #: the **existing** ``HAS_VENDOR_DEPS`` dependency gate rather than minting a new -#: one -- ``tests/_dependency_gates.py:315`` already accounts for that gate, with -#: ``dark={'test': ('html5lib',), 'gate': ('html5lib',)}``, and ``engine-tests`` -#: closes it by installing the ``vendor`` extra. +#: one -- its entry in :data:`tests._dependency_gates.DEPENDENCY_GATE_EXCLUSIONS` +#: already accounts for that gate, with +#: ``dark={'test': ('html5lib',), 'gate': ('html5lib',)}``. #: #: ``html5lib`` is the one that is actually missing on ``test``: ``requests`` and #: ``bs4`` have shipped in the ``test`` extra since #507, but only -#: ``beautifulsoup4[html5lib]`` -- the ``vendor`` and ``all`` extras -- provides a +#: ``beautifulsoup4[html5lib]`` -- the ``vendor`` and ``dev`` extras -- provides a #: parser (``pyproject.toml:234``, and the note at ``:313-320`` saying so #: deliberately). VENDOR_DEPS = ('requests', 'bs4', 'html5lib') @@ -92,8 +92,9 @@ #: rather than making the whole unit tier depend on the crawlers'. #: #: Consequence worth knowing: :class:`LinkTypeGeneratorLegacyOrderingTests` is the -#: root-cause pin, and it runs only where the ``vendor`` extra is installed -- -#: ``engine-tests`` per-PR, and locally. :class:`LinkType209ConstResolutionTests` +#: root-cause pin, and it runs only where the ``vendor`` extra is installed, +#: which no CI job does since #849 -- so locally only. +#: :class:`LinkType209ConstResolutionTests` #: needs no parser and so still guards the reported symptom everywhere. HAS_VENDOR_DEPS = all(importlib.util.find_spec(name) is not None for name in VENDOR_DEPS) diff --git a/tests/const/test_const_str_payload_870_unit.py b/tests/const/test_const_str_payload_870_unit.py index 142041ff3..e34293cb1 100644 --- a/tests/const/test_const_str_payload_870_unit.py +++ b/tests/const/test_const_str_payload_870_unit.py @@ -29,10 +29,14 @@ comparison of a :class:`~pcapkit.const.http.method.Method` member against its own wire string now succeeds where it used to fail silently (no exception -- just an unexpected :data:`False`). Nothing under :mod:`pcapkit.protocols` -compared a member this way before the fix (the one caller, -:meth:`pcapkit.protocols.application.httpv1.HTTP._read_http_header`, only ever -reads ``.value`` indirectly through :meth:`~pcapkit.const.http.method.Method. -get`, never ``str()`` or ``==`` against the member itself), so the change is +compared a member this way before the fix (the one caller of +:meth:`~pcapkit.const.http.method.Method.get`, +:meth:`pcapkit.protocols.application.httpv1.HTTP._read_start_line`, reached +through :meth:`~pcapkit.protocols.application.httpv1.HTTP._read_http_header` +and :meth:`~pcapkit.protocols.application.httpv1.HTTP.make`, only builds a +member from the wire string, and +:meth:`~pcapkit.protocols.application.httpv1.HTTP._make_start_line` reads +``.value``; neither calls ``str()`` or ``==`` on the member itself), so the change is observable only to external callers and to this module's own dunders (``__repr__``, which reads ``_value_`` and was already correct). diff --git a/tests/corekit/test_enum_get_exception_provenance_923_unit.py b/tests/corekit/test_enum_get_exception_provenance_923_unit.py index 0aa01b183..33a51bbde 100644 --- a/tests/corekit/test_enum_get_exception_provenance_923_unit.py +++ b/tests/corekit/test_enum_get_exception_provenance_923_unit.py @@ -239,10 +239,11 @@ def test_nothing_is_minted_on_either_path(self) -> 'None': class BaseGetQuietnessTests(unittest.TestCase): """The name miss is raised with ``quiet=True``, and that is load-bearing. - :meth:`~pcapkit.const.http.method.Method.get` catches it in order to mint, - so a loud error there would put one :data:`logging.CRITICAL` record on the - logger -- and set :data:`sys.tracebacklimit` to ``0`` process-wide -- for - every *successful* ``Method.get`` call that mints. That is the GitHub issue + :meth:`~pcapkit.const.http.method.Method.get` catches it in order to build + an unregistered member, so a loud error there would put one + :data:`logging.CRITICAL` record on the logger -- and, until #983, set + :data:`sys.tracebacklimit` to ``0`` process-wide -- for every *successful* + ``Method.get`` call that misses. That is the GitHub issue #362 defect :class:`~pcapkit.utilities.exceptions.BaseError` documents ``quiet`` for, and :mod:`pcapkit.protocols.protocol` states the same rule inline: *"A pcapkit exception here would log at CRITICAL for something that @@ -275,8 +276,8 @@ def test_a_name_miss_leaves_tracebacklimit_alone(self) -> 'None': self.assertFalse(hasattr(sys, 'tracebacklimit')) def test_the_minting_override_stays_silent_end_to_end(self) -> 'None': - """The call this is actually for: a ``Method.get`` that mints is a - successful call and must emit nothing at all.""" + """The call this is actually for: a ``Method.get`` that misses and builds + an unregistered member is a successful call and must emit nothing at all.""" from pcapkit.const.http.method import Method with capture(logger) as recorder: diff --git a/tests/corekit/test_fields_numbers_port_option_no_mint_unit.py b/tests/corekit/test_fields_numbers_port_option_no_mint_unit.py index 797b34930..9c0f37bb1 100644 --- a/tests/corekit/test_fields_numbers_port_option_no_mint_unit.py +++ b/tests/corekit/test_fields_numbers_port_option_no_mint_unit.py @@ -174,10 +174,11 @@ def test_a_value_lookup_on_the_resolved_port_still_raises(self) -> None: A direct call to ``.get()`` is different on purpose and stays that way: the owner's ruling and the docstring above are both explicit - that ``get()`` is the public API and minting for a caller who asked - for this exact value directly is defensible, which is also what - ``tests/const/test_const_apptype_split_unit.py`` pins for - ``PORT_59001_tcp``/``PORT_51_tcp``. So this only asserts the + that ``get()`` is the public API and answering a caller who asked for + this exact value directly is defensible -- since #874 with an + unregistered ``unknown`` member rather than a mint -- which is also + what ``tests/const/test_const_apptype_split_unit.py`` pins for ports + 59001 and 51. So this only asserts the value-lookup side, never the ``.get()`` side. """ @@ -307,8 +308,9 @@ def setUp(self) -> None: def test_an_undeclared_option_code_resolves_without_growing_the_registry(self) -> None: """An interface-block option code no ``if`` or ``opt`` row covers. - ``OptionType._missing_`` never declines -- unlike ``AppType``'s, it - mints unconditionally on any miss -- so this fallback cannot consult + ``OptionType._missing_`` never declines an in-range code -- unlike + ``AppType``'s, it answers every such miss with an unregistered member + -- so this fallback cannot consult it the way the port fields consult ``AppType``'s, and instead replicates the read-only membership test ``OptionType.get`` itself runs first. ``.opt_name`` and ``.opt_value`` are read unconditionally diff --git a/tests/corekit/test_sentinels_housing_unit.py b/tests/corekit/test_sentinels_housing_unit.py index 92408da3c..c16e88cf4 100644 --- a/tests/corekit/test_sentinels_housing_unit.py +++ b/tests/corekit/test_sentinels_housing_unit.py @@ -20,8 +20,8 @@ pins that. Each still imports the *object* it uses from here. None of this module exists before that move, which is exactly what makes it a -regression test rather than a description: on ``origin/main`` at ``d31c0aaf6`` -(the tip this branch was cut from), ``import pcapkit.corekit.sentinels`` itself +regression test rather than a description: at ``d31c0aaf6``, a ``main`` +commit from before #922, ``import pcapkit.corekit.sentinels`` itself fails -- .. code-block:: text @@ -48,12 +48,12 @@ asserts that with ``is``, never ``==``. :class:`NoImportCycleTests` pins the other thing the issue asked to be checked -"on purpose" rather than left to the 39 pre-existing ``cyclic-import`` findings -:command:`pylint` already reports for this package (which would swallow a 40th -without comment): that :mod:`pcapkit.corekit.sentinels` itself imports nothing -from any of the four modules it is now depended on by, so the dependency graph -between them is a star with :mod:`pcapkit.corekit.sentinels` at the centre and no -edge pointing back into it. +"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 +dependency graph between them is a star with :mod:`pcapkit.corekit.sentinels` +at the centre and no edge pointing back into it. """ from __future__ import annotations @@ -111,8 +111,8 @@ class NoImportCycleTests(unittest.TestCase): """:mod:`pcapkit.corekit.sentinels` must not import back into a consumer. The issue's own instruction: check for a cycle *deliberately*, because - :command:`pylint` already reports 39 ``cyclic-import`` findings in this - package, so a fortieth would be invisible in the noise rather than caught. + :command:`pylint` already reports hundreds of ``cyclic-import`` findings in + this package, so one more would be invisible in the noise rather than caught. This does not run :command:`pylint` -- that check is done separately and reported alongside #922 -- it instead pins the one fact that actually rules a cycle out for this specific set of modules: that diff --git a/tests/dumpkit/test_common_unit.py b/tests/dumpkit/test_common_unit.py index a15d2f682..c2d19b662 100644 --- a/tests/dumpkit/test_common_unit.py +++ b/tests/dumpkit/test_common_unit.py @@ -546,9 +546,10 @@ def make(number: int, packet: bytes) -> Frame: self.assertEqual([str(entry.message) for entry in caught], []) def test_pcap_dumper_cannot_serialise_a_mapping_frame(self) -> None: - # Why Extractor substitutes a dict-capable trace format for the DPKT, Scapy, - # PyShark and PyPCAPFile engines: their flow-tracing adapters report each - # frame as a plain dict from ``packet2dict``, and this dumper reads + # Why Extractor substitutes a dict-capable trace format for the PyShark + # and PyPCAPFile engines (DPKT and Scapy left that guard in #1507): their + # flow-tracing adapters report each frame as a plain dict from + # ``packet2dict``, and this dumper reads # ``value.packet`` and ``value.frame_info`` off a dissected Frame. Pinned # here so the guard's justification is checked rather than asserted in a # comment -- if this dumper ever learns to take a mapping, the guard is what diff --git a/tests/foundation/registry/test_protocols.py b/tests/foundation/registry/test_protocols.py index e19dfa46c..194363800 100644 --- a/tests/foundation/registry/test_protocols.py +++ b/tests/foundation/registry/test_protocols.py @@ -446,8 +446,8 @@ def test_register_protocol_rejects_a_non_class_with_registry_error(self) -> None def test_top_level_link_internet_and_transport_protocol_wrappers(self) -> None: # Members live in the per-transport registries GitHub issue #732 split # AppType into; the base class itself holds none. 3com-amp3 is registered - # on both TCP and UDP, so either copy carries the multi-bit .proto this - # exercises -- the TCP one is used, arbitrarily. + # on both TCP and UDP, and the TCP copy is used, arbitrarily; since #806 + # its .proto names TCP alone, which the notes below rely on. from pcapkit.const.reg.apptype import TCP as AppType_TCP from pcapkit.const.reg.apptype import UDP as AppType_UDP from pcapkit.const.reg.apptype import TransportProtocol @@ -551,8 +551,9 @@ def test_top_level_link_internet_and_transport_protocol_wrappers(self) -> None: with self.assertRaises(RegistryError): registry.register_apptype(65004, UnitProtocol) - # NOTE: a composite names two registries, and one call registers under - # one transport protocol. + # NOTE: a composite is refused: one call registers under one transport + # protocol, and since #808 dropped the ``IntFlag`` base ``tcp | udp`` is + # a bare ``int`` rather than a member. with self.assertRaises(RegistryError): registry.register_apptype(65005, UnitProtocol, TransportProtocol.tcp | TransportProtocol.udp) @@ -594,10 +595,11 @@ def test_top_level_link_internet_and_transport_protocol_wrappers(self) -> None: # NOTE: a composite name such as ``'tcp|udp'`` raises for the same # reason the equivalent composite member is refused above: one call - # registers under one transport protocol. This is the case that most - # needs covering -- aenum's ``Flag`` getitem parses a ``'|'``-joined - # name into a composite value on its own, so a resolver built on it - # unguarded would accept this silently instead of refusing it. + # registers under one transport protocol. This was the case that most + # needed covering while ``TransportProtocol`` was an ``IntFlag``, until + # #808: aenum's ``Flag`` getitem parsed a ``'|'``-joined name into a + # composite value on its own, so a resolver built on it unguarded would + # have accepted this silently instead of refusing it. with self.assertRaises(RegistryError): registry.register_apptype(65010, UnitProtocol, 'tcp|udp') @@ -650,7 +652,7 @@ def test_top_level_link_internet_and_transport_protocol_wrappers(self) -> None: # NOTE: anything that is neither a ``str`` nor a ``TransportProtocol`` # member raises before the registry loop touches anything. - # ``TransportProtocol`` is an ``IntFlag``, so an unguarded fall-through + # ``TransportProtocol`` is an ``int`` subclass, so an unguarded fall-through # would let ``registries.get(1)`` resolve to ``TCP`` just as # ``registries.get(TransportProtocol.tcp)`` does -- registering the # port and then exploding on ``proto.name`` before ``register_protocol`` diff --git a/tests/project/test_changelog_md.py b/tests/project/test_changelog_md.py index fdd72f2b9..bc82b61b7 100644 --- a/tests/project/test_changelog_md.py +++ b/tests/project/test_changelog_md.py @@ -602,8 +602,9 @@ class ComplaintLocationTests(ChangelogTreeMixin, unittest.TestCase): read back out of the entry holds the construct it was cited for, which the numbers counted against the converted body could not do. - No ``subTest`` here on purpose: this pytest has no ``pytest-subtests``, so a - failing subtest leaves its parent reported as passed. + No ``subTest`` here on purpose: under this repository's pytest a failing + subtest gets a ``SUBFAILED`` line of its own while its parent's line still + reads ``PASSED``. """ diff --git a/tests/project/test_conventions_doc_claims.py b/tests/project/test_conventions_doc_claims.py index e2b90ea46..d51d06202 100644 --- a/tests/project/test_conventions_doc_claims.py +++ b/tests/project/test_conventions_doc_claims.py @@ -446,7 +446,7 @@ def test_the_page_names_every_enumeration_outside_the_hierarchy(self) -> 'None': Vacuous while :attr:`self.outside` is empty -- GitHub issue #930 emptied it, and an empty dict gives the loop below nothing to iterate, so this - method cannot fail no matter what the page says right now. + method cannot fail no matter what the page says. ``test_the_page_states_the_measured_number_outside_the_hierarchy`` is what actually pins the empty state; this one is dormant rather than deleted, for whenever a future regression makes :attr:`self.outside` @@ -982,9 +982,10 @@ def test_the_base_raises_a_name_miss_quietly(self) -> 'None': """#933: the owner ruled that overrides follow the base and stay quiet. Measured rather than read off the source, because the cost the ruling turns - on is the side effect: a loud :class:`BaseError` sets + on is the side effect: a loud :class:`BaseError` logs at + :data:`logging.CRITICAL` and, until #983, also set :data:`sys.tracebacklimit` to ``0`` for the whole process (#362), and a - quiet one leaves it alone. + quiet one does neither. """ import sys diff --git a/tests/project/test_isort_clean.py b/tests/project/test_isort_clean.py index fc4421be2..73c23db63 100644 --- a/tests/project/test_isort_clean.py +++ b/tests/project/test_isort_clean.py @@ -130,11 +130,12 @@ check. The install line is the other half. ``isort`` is now a ``test`` extra -requirement, so the three jobs whose selection collects this module -- -``test``, ``engine-tests`` and ``gate`` -- run it for real rather than -reporting a skip. That is the opposite resolution from ``mypy``'s, whose -:data:`~tests._dependency_gates.DEPENDENCY_GATE_EXCLUSIONS` entry declines the -install line, and the difference is not taste: :file:`lint.yml` already runs +requirement, so the pytest jobs whose selection collects this module -- +``test`` and ``gate``, since #849 took ``engine-tests`` off it -- run it for +real rather than reporting a skip. That is the opposite resolution from +``mypy``'s, whose :data:`~tests._dependency_gates.DEPENDENCY_GATE_EXCLUSIONS` +entry declines the install line, and the difference is not taste: +: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 diff --git a/tests/project/test_public_api.py b/tests/project/test_public_api.py index 0a6b5c98b..f2a4bf80a 100644 --- a/tests/project/test_public_api.py +++ b/tests/project/test_public_api.py @@ -36,22 +36,26 @@ Two scoping decisions, both measured rather than assumed. **:mod:`pcapkit.vendor` is excluded.** Its modules ``import requests`` and -``import bs4``, which come from the ``vendor`` extra (:file:`pyproject.toml`) and -are *not* installed by ``pip install -e '.[test]'``. This module is unit-tier -- -see :mod:`tests._tiers` -- so it has to pass on exactly that install, and -importing :mod:`pcapkit.vendor` there would fail on the missing dependency rather -than on anything to do with :attr:`__all__`. Very little is hidden by the -exclusion, and what is hidden was measured rather than assumed: the same sweep was -run by hand over :mod:`pcapkit.vendor` on a machine that *does* have the extra, -across the package and its 134 public descendants. Every one of them imports, -every one declares :attr:`__all__`, and every entry of every :attr:`__all__` -resolves. The single defect it held was the duplicate described at the end of this -docstring, in :mod:`pcapkit.vendor` and :mod:`pcapkit.vendor.mh`. +``import bs4`` at module scope. The exclusion was written on the premise that +``pip install -e '.[test]'`` -- the install the unit tier, see +:mod:`tests._tiers`, has to pass on -- lacks both, but the ``test`` extra in +:file:`pyproject.toml` has carried ``requests`` and ``beautifulsoup4`` since +#507, so the import is not what keeps it. With ``'vendor'`` dropped from +:data:`EXCLUDED_ROOTS`, every assertion passes over the vendor subtree bar one: +:meth:`~PublicAPISurfaceTests.test_every_public_package_exports_every_public_attribute` +fails for :mod:`pcapkit.vendor`, which holds ``ModuleNotFoundError``, +``Vendor``, ``VendorWarning``, ``stacklevel`` and ``warn`` without listing them, +and for :mod:`pcapkit.vendor.ipx`, which holds ``path``. #1772 tracks those +gaps. When this module was written the same sweep was run by hand over +:mod:`pcapkit.vendor` and its 134 public descendants, and the single defect it +found was the duplicate described at the end of this docstring, in +:mod:`pcapkit.vendor` and :mod:`pcapkit.vendor.mh`. Nothing else is excluded, and no import is wrapped in a skip. That is deliberate and also measured: with ``dpkt``, ``scapy``, ``emoji``, ``cryptography`` and -``pycrate`` all absent, every one of the 325 non-vendor modules still imports, -because each optional dependency is already guarded at its import site -- e.g. +``pycrate`` all absent, every one of the 325 non-vendor modules there were 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. 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 @@ -61,14 +65,15 @@ every public *package*, against a written-down allowlist of exclusions.** That is issue #533, and scope is what makes it a test rather than noise. -Applied to every *module* the converse flags 2848 names across 286. That is not a -failing test, it is a wall: a module's namespace holds whatever it imported in -order to do its job, and none of that is its public surface. Applied to the 52 -public *packages* it flags 45 across 12 -- small enough to read, triage, and write -down one at a time. A package's namespace is a composed thing: it holds what its -:file:`__init__.py` chose to pull in, so a public attribute it has and does not -export is a decision in one direction or the other, and the assertion exists to -make that decision explicit instead of leaving it to be guessed at. +When #533 was measured, the converse applied to every *module* flagged 2848 +names across 286. That is not a failing test, it is a wall: a module's namespace +holds whatever it imported in order to do its job, and none of that is its public +surface. Applied to the 52 public *packages* there were then, it flagged 45 +across 12 -- small enough to read, triage, and write down one at a time. A +package's namespace is a composed thing: it holds what its :file:`__init__.py` +chose to pull in, so a public attribute it has and does not export is a decision +in one direction or the other, and the assertion exists to make that decision +explicit instead of leaving it to be guessed at. :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 @@ -110,7 +115,7 @@ widens the public surface. * :meth:`~PublicAPISurfaceTests.test_every_public_package_declares_all` -- the same defect seen from the other side, and the one that catches "forgot it - entirely" rather than "typed it wrong". All 52 public packages declare + entirely" rather than "typed it wrong". Every public package declares :attr:`__all__` once ``pcapng`` is fixed. * :meth:`~PublicAPISurfaceTests.test_no_duplicate_all_entries` -- ``'MH_HandoverACKStatus'`` appeared *twice* in both :mod:`pcapkit.const` and @@ -133,9 +138,10 @@ class exists at ``pcapkit/const/mh/handover_initiate_status.py`` and is used by ``pcapkit.vendor.__all__``, so the missing ``MH_HandoverInitiateStatus`` kept the ``handover_initiate_status`` crawler out of the default target list *and* out of ``--target mh``, and it had never run. #531 fixed it, and -:mod:`tests.vendor.test_crawler_reachability_unit` guards it with the ``vendor`` -extra installed. The remaining step is to drop ``'vendor'`` from -:data:`EXCLUDED_ROOTS`, so that this module covers it too. +:mod:`tests.vendor.test_crawler_reachability_unit` guards it. Dropping +``'vendor'`` from :data:`EXCLUDED_ROOTS` would let this module cover it too, but +only once the two :attr:`__all__` gaps named above are closed or recorded in +:data:`DELIBERATE_NON_EXPORTS`; #1772 tracks that. """ from __future__ import annotations @@ -147,8 +153,9 @@ class exists at ``pcapkit/const/mh/handover_initiate_status.py`` and is used by import unittest #: First path component under ``pcapkit.`` whose subtree the sweep skips. -#: :mod:`pcapkit.vendor` needs the ``vendor`` extra (``requests``, -#: ``beautifulsoup4``) at import time, and the unit tier does not have it. +#: :mod:`pcapkit.vendor` imports, since the ``test`` extra carries ``requests`` +#: and ``beautifulsoup4``, but two of its packages leave public attributes out +#: of :attr:`__all__` (#1772); see the module docstring. EXCLUDED_ROOTS = frozenset({'vendor'}) #: The packages whose whole job is to re-export their children, and which @@ -423,7 +430,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 all 52 public packages rather than the + # The same converse as above, over every public package rather than the # three aggregators, 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 diff --git a/tests/project/test_release_gates.py b/tests/project/test_release_gates.py index c787b6185..da9621c58 100644 --- a/tests/project/test_release_gates.py +++ b/tests/project/test_release_gates.py @@ -2729,8 +2729,9 @@ class TestGateMutationsChangeTheTruthTable(WorkflowMixin, unittest.TestCase): #: 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 last three are #1052's, for the release test gate - #: conjunct that issue added. + #: 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 + #: released-elsewhere conjunct. MUTATIONS = [ ('the && before the version_check clause becomes ||', "!cancelled() && needs.version_check.result", diff --git a/tests/protocols/test_dispatch_registry_unit.py b/tests/protocols/test_dispatch_registry_unit.py index c6d8d9e53..298397264 100644 --- a/tests/protocols/test_dispatch_registry_unit.py +++ b/tests/protocols/test_dispatch_registry_unit.py @@ -1,12 +1,13 @@ # -*- coding: utf-8 -*- """Every ``__proto__`` dispatch-registry entry, enumerated rather than hand-picked. -GitHub issue #496: :file:`pcapkit/foundation/registry/protocols.py` documents -seven registries -- 39 entries in total as of #904, which added -``Internet.__proto__[TransType.Shim6]`` -- that decide which +GitHub issue #496: the ``__proto__`` dispatch registries decide which :class:`~pcapkit.protocols.protocol.Protocol` subclass parses the next layer. -Nothing walked all of them. :file:`test_registry_runtime.py` checks that a -table entry *resolves* to the right class object, and +#496 named seven of them; #904 took them to 39 entries by adding +``Internet.__proto__[TransType.Shim6]``, and #1574 to 47 across eight tables by +adding the loopback one. Nothing walked all of them. +:file:`test_registry_runtime.py` checks that a table entry *resolves* to the +right class object, and :file:`test_dispatch_bindings_unit.py` checks that eleven hand-picked codes actually parse a packet into the class the table names -- the property that matters, since a resolvable entry whose target cannot parse a packet is @@ -15,7 +16,7 @@ This module closes the gap the same way :file:`test_option_roundtrip_unit.py` closed it for the option/parameter -registries: :func:`examples.generators.dispatch.cases` walks the seven +registries: :func:`examples.generators.dispatch.cases` walks the eight ``__proto__`` tables directly, so a code registered tomorrow gets a case here tomorrow -- or fails :meth:`DispatchRegistryTests .test_every_registered_code_has_a_case`, which is what makes the coverage diff --git a/tests/test_tier_guard.py b/tests/test_tier_guard.py index 8c36a2b22..03d8c4182 100644 --- a/tests/test_tier_guard.py +++ b/tests/test_tier_guard.py @@ -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 six of the seven other workflows install ``.[all]`` - somewhere, several as ``.[all,dev]`` -- which carries ``pypcapfile``, + generator, and five other workflows install ``.[all]`` somewhere, + three 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 diff --git a/tests/toolkit/test_dpkt_reassembly_rawbytes_unit.py b/tests/toolkit/test_dpkt_reassembly_rawbytes_unit.py index 49603d1a3..18293e8ad 100644 --- a/tests/toolkit/test_dpkt_reassembly_rawbytes_unit.py +++ b/tests/toolkit/test_dpkt_reassembly_rawbytes_unit.py @@ -287,9 +287,9 @@ def test_options_transport_inputs_are_the_captured_octets(self) -> None: Each record is read by hand, and each input is the IHL's octets, then the rest up to the Total Length. The number of datagrams is counted here rather than pinned: the capture is generated by ``make samples``, and that - is not currently reproducible -- the same commit produces a 43-frame and a - 44-frame file in different worktrees -- so any absolute count is flaky - whichever value it picks. + was not reproducible when this test was written -- the same commit produced + a 43-frame and a 44-frame file in different worktrees -- so any absolute + count is flaky whichever value it picks. """ from pcapkit.toolkit import dpkt as toolkit diff --git a/tests/utilities/test_compat.py b/tests/utilities/test_compat.py index 7aeef0550..17c091163 100644 --- a/tests/utilities/test_compat.py +++ b/tests/utilities/test_compat.py @@ -442,8 +442,9 @@ def test_faking_the_version_leaves_aenum_reading_the_real_one(self) -> None: The closing lines are the symptom rather than a proxy for it. Building an :class:`aenum.IntFlag` subclass is exactly what - ``pcapkit/const/reg/apptype.py:26`` does, and it is the statement that - raised ``AttributeError: 'TransportProtocol' object has no attribute + ``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` 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 diff --git a/tests/utilities/test_quiet_exceptions.py b/tests/utilities/test_quiet_exceptions.py index 2b3735371..4ed1a1949 100644 --- a/tests/utilities/test_quiet_exceptions.py +++ b/tests/utilities/test_quiet_exceptions.py @@ -158,8 +158,9 @@ def test_prepare_raises_stream_eof_error_quietly(self) -> None: Dropping the ``quiet=True`` would put one ``CRITICAL`` record on :data:`sys.stderr` for every capture parsed to completion, which is the - #362 defect this module exists for -- and would also set - :data:`sys.tracebacklimit` to ``0`` process-wide. + #362 defect this module exists for -- and, outside development mode, + would also replace :data:`sys.excepthook` and + :data:`threading.excepthook` process-wide. """ class DemoSchema: diff --git a/tests/vendor/test_crawler_reachability_unit.py b/tests/vendor/test_crawler_reachability_unit.py index 725f1a072..17f9556e3 100644 --- a/tests/vendor/test_crawler_reachability_unit.py +++ b/tests/vendor/test_crawler_reachability_unit.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Every vendor crawler is reachable from the target list that runs them. -:mod:`pcapkit.vendor` defines 117 crawlers and +Until #531, :mod:`pcapkit.vendor` defined 117 crawlers and :file:`pcapkit/vendor/__main__.py` could only ever run 116 of them, because it does not discover crawlers -- it reads :attr:`__all__`: @@ -22,9 +22,9 @@ The corroborating evidence was in the generated file the crawler owns. :meth:`pcapkit.vendor.default.Vendor.context` emitted a ``:meta private:`` -directive into every enumeration it wrote until #858 replaced the template, -and 116 of the 117 files under :file:`pcapkit/const/*/` carried it. The one -that did not was +directive into every enumeration it wrote until #858 replaced the template. +When #531 landed, 116 of the 117 files under :file:`pcapkit/const/*/` carried +it. The one that did not was :file:`pcapkit/const/mh/handover_initiate_status.py` -- the output of the one crawler that could not be reached. The duplicate dates to commit ``24edd30d2`` (2023-04-17, "added MH enumerations & vendor cralwers"), so the file has been @@ -42,16 +42,14 @@ Relationship to :file:`tests/project/test_public_api.py` (GitHub pull request #527). That module sweeps :attr:`__all__` across the tree for a related family of -defects and deliberately excludes :mod:`pcapkit.vendor` via its -``EXCLUDED_ROOTS``, because it is unit-tier and the ``vendor`` extra is not part -of ``pip install -e '.[test]'``. Its docstring records the remediation as -"drop ``'vendor'`` from :data:`EXCLUDED_ROOTS`". This module is a separate file -rather than that edit, for two reasons: #527 had not merged when this module was -written, so its file did not exist on that branch; and the assertion here is not -the one it makes. It needs the ``vendor`` extra, and the property it checks -- defined -versus reachable -- is about the crawler *registry* rather than about -:attr:`__all__` hygiene. Dropping the exclusion is still worth doing on top of -this, and would give the duplicate a second, cheaper detector. +defects and excludes :mod:`pcapkit.vendor` via its ``EXCLUDED_ROOTS``; its +docstring records why, and #1772 tracks dropping the exclusion. This module is a +separate file rather than that edit, for two reasons: #527 had not merged when +this module was written, so its file did not exist on that branch; and the +assertion here is not the one it makes. The property it checks -- defined versus +reachable -- is about the crawler *registry* rather than about :attr:`__all__` +hygiene. Dropping the exclusion is still worth doing on top of this, and would +give the duplicate a second, cheaper detector. The suite is unit-tier (see :mod:`tests._tiers`): it reads no capture, and it instantiates nothing. That last part is load-bearing rather than incidental. diff --git a/tests/vendor/test_ftp_return_code_unit.py b/tests/vendor/test_ftp_return_code_unit.py index ad827cbc0..86278e420 100644 --- a/tests/vendor/test_ftp_return_code_unit.py +++ b/tests/vendor/test_ftp_return_code_unit.py @@ -49,9 +49,10 @@ #: Every distribution importing :mod:`pcapkit.vendor` needs -- see #: :mod:`tests.vendor.test_user_agent_unit` for why ``requests`` alone is not -#: enough. They ship in the ``vendor`` extra (:file:`pyproject.toml`), not -#: ``test`` -- so these run on ``engine-tests``, which installs ``vendor`` too -#: (#738), and skip on the ``test`` and ``gate`` jobs, which do not. +#: enough. ``html5lib`` ships in the ``vendor`` extra (:file:`pyproject.toml`), +#: not ``test`` -- so these skip on the ``test`` and ``gate`` jobs, which do not +#: install it. ``engine-tests`` ran them for real (#738) until #849 narrowed +#: each of its cells to that engine's own test files. VENDOR_DEPS = ('requests', 'bs4', 'html5lib') #: Whether the crawlers are importable at all. diff --git a/tests/vendor/test_ipx_packet_unit.py b/tests/vendor/test_ipx_packet_unit.py index 49ee5403a..32e74eac4 100644 --- a/tests/vendor/test_ipx_packet_unit.py +++ b/tests/vendor/test_ipx_packet_unit.py @@ -52,10 +52,11 @@ #: and not ``beautifulsoup4``. VENDOR_DEPS = ('requests', 'bs4', 'html5lib') -#: Whether the crawlers are importable at all. They ship in the ``vendor`` extra -#: (:file:`pyproject.toml`), not ``test`` -- so these tests skip on the ``test`` -#: and ``gate`` jobs of :file:`.github/workflows/unit-tests.yml`, which never -#: install ``vendor``, but run for real on ``engine-tests``, which does (#738). +#: Whether the crawlers are importable at all. ``html5lib`` ships in the +#: ``vendor`` extra (:file:`pyproject.toml`), not ``test`` -- so these tests skip +#: on the ``test`` and ``gate`` jobs of :file:`.github/workflows/unit-tests.yml`, +#: which never install ``vendor``. ``engine-tests`` ran them for real (#738) +#: until #849 narrowed each of its cells to that engine's own test files. #: Guarded the same way #: :file:`tests/protocols/test_dispatch_registry_unit.py` guards its own optional #: runtime dependencies, rather than making the whole unit tier depend on the diff --git a/tests/vendor/test_request_prompt_unit.py b/tests/vendor/test_request_prompt_unit.py index 51f6abe2c..d02a2e67b 100644 --- a/tests/vendor/test_request_prompt_unit.py +++ b/tests/vendor/test_request_prompt_unit.py @@ -98,10 +98,11 @@ #: subpackages that ``import bs4`` at module scope. VENDOR_DEPS = ('requests', 'bs4', 'html5lib') -#: Whether the crawlers are importable at all. They ship in the ``vendor`` extra -#: (:file:`pyproject.toml`), not ``test`` -- so these cases skip on the ``test`` -#: and ``gate`` jobs of :file:`.github/workflows/unit-tests.yml`, but run for -#: real on ``engine-tests``, which installs ``vendor`` too (#738). +#: Whether the crawlers are importable at all. ``html5lib`` ships in the +#: ``vendor`` extra (:file:`pyproject.toml`), not ``test`` -- so these cases skip +#: on the ``test`` and ``gate`` jobs of :file:`.github/workflows/unit-tests.yml`. +#: ``engine-tests`` ran them for real (#738) until #849 narrowed each of its +#: cells to that engine's own test files. #: Guarded the way :file:`tests/protocols/test_dispatch_registry_unit.py` guards #: its own optional dependencies rather than making the whole unit tier depend on #: the crawlers'. diff --git a/tests/vendor/test_user_agent_unit.py b/tests/vendor/test_user_agent_unit.py index 7725a8d14..91d8a8c4a 100644 --- a/tests/vendor/test_user_agent_unit.py +++ b/tests/vendor/test_user_agent_unit.py @@ -62,10 +62,11 @@ #: machine that happens to have ``requests`` and not ``beautifulsoup4``. VENDOR_DEPS = ('requests', 'bs4', 'html5lib') -#: Whether the crawlers are importable at all. They ship in the ``vendor`` extra -#: (:file:`pyproject.toml`), not ``test`` -- so these tests skip on the ``test`` -#: and ``gate`` jobs of :file:`.github/workflows/unit-tests.yml`, which never -#: install ``vendor``, but run for real on ``engine-tests``, which does (#738). +#: Whether the crawlers are importable at all. ``html5lib`` ships in the +#: ``vendor`` extra (:file:`pyproject.toml`), not ``test`` -- so these tests skip +#: on the ``test`` and ``gate`` jobs of :file:`.github/workflows/unit-tests.yml`, +#: which never install ``vendor``. ``engine-tests`` ran them for real (#738) +#: until #849 narrowed each of its cells to that engine's own test files. #: Guarded the same way #: :file:`tests/protocols/test_dispatch_registry_unit.py` guards its own optional #: runtime dependencies, rather than making the whole unit tier depend on the diff --git a/tests/vendor/test_vendor_dest_path_unit.py b/tests/vendor/test_vendor_dest_path_unit.py index 6684f780a..474f67747 100644 --- a/tests/vendor/test_vendor_dest_path_unit.py +++ b/tests/vendor/test_vendor_dest_path_unit.py @@ -94,14 +94,12 @@ nothing here reaches -- no test in this file calls :meth:`Vendor.__init__` or :meth:`~Vendor.context`. ``requests`` and ``beautifulsoup4`` both ship in the ``test`` extra precisely so vendor tests can run (:file:`pyproject.toml`, -around line 321), so both classes below run on ``test``, ``engine-tests`` -and ``gate`` -- the only three pytest jobs of -:file:`.github/workflows/unit-tests.yml` that collect anything under -:file:`tests/vendor/` at all, since ``integration`` and ``pypcap-parity`` -never reach it -- unlike :file:`tests/vendor/test_user_agent_unit.py`, whose -own gate also lists ``html5lib`` and so still skips on ``test`` and ``gate``, -though it now runs for real on ``engine-tests`` too, which installs the -``vendor`` extra (#738). +around line 321), so both classes below run on ``test`` and ``gate`` -- the +only pytest jobs of :file:`.github/workflows/unit-tests.yml` that collect +anything under :file:`tests/vendor/` at all, since ``integration`` and +``pypcap-parity`` never reach it and ``engine-tests`` runs only each engine's +own test files since #849 -- unlike :file:`tests/vendor/test_user_agent_unit.py`, +whose own gate also lists ``html5lib`` and so skips on both. """ from __future__ import annotations