Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions docs/source/contributing/conventions/test-coverage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,19 @@ The rules those tables carry:
A code that fails is never skipped.
* **A failing case is an entry, never a changed argument.** An ``EXPECTED_FAILURES``
entry records the status, a failure-detail fragment narrow enough to match one
site, and the defect: the ``file:line`` that causes it and the issue that tracks it.
site, and the defect: the function, class or method that causes it, by name, and the
issue that tracks it.
Routing a case around a defect hides it: the generator's ``HIP_COPIES`` once put two
parameters in every HIP packet, so the unrepresentable length of a lone one
(:issue:`651`) was never constructed.
``KNOWN_DEGRADED`` entries have a different shape -- a fragment and a reason -- and
they record why the probe's placeholder payload cannot reach the target, not a
defect to fix, so the ``file:line``-and-issue rule does not apply to them.
defect to fix, so the name-and-issue rule does not apply to them.
* **A regression is fixed; a pre-existing defect is recorded.** A case that a change
breaks -- including a code it registers that does not close -- is fixed in that
change, not added to a table. A newly found defect that predates the change gets an
entry naming the ``file:line`` that causes it, as the failure message asks, and an
issue.
entry naming the function, class or method that causes it, as the failure message
asks, and an issue.
* **The tables are checked in both directions.** In the option suite, an entry whose
case starts passing turns ``test_round_trip_is_identity_or_a_recorded_gap`` red, and
one naming a case that no longer exists fails
Expand Down
18 changes: 9 additions & 9 deletions docs/source/contributing/workflows.rst
Original file line number Diff line number Diff line change
Expand Up @@ -769,19 +769,19 @@ grepping every workflow file for its name:
- ``unit-tests.yml``
* - ``Compat Python 3.11``
- job ``compatibility``, matrix leg ``3.11``
- ``python-compatibility.yml``, ``.github/python-versions.toml:19``
- ``python-compatibility.yml``, key ``"3.11"`` of ``.github/python-versions.toml``
* - ``Compat Python 3.12``
- job ``compatibility``, matrix leg ``3.12``
- ``python-compatibility.yml``, ``.github/python-versions.toml:20``
- ``python-compatibility.yml``, key ``"3.12"`` of ``.github/python-versions.toml``
* - ``Compat Python 3.13``
- job ``compatibility``, matrix leg ``3.13``
- ``python-compatibility.yml``, ``.github/python-versions.toml:21``
- ``python-compatibility.yml``, key ``"3.13"`` of ``.github/python-versions.toml``
* - ``Compat Python 3.14``
- job ``compatibility``, matrix leg ``3.14``
- ``python-compatibility.yml``, ``.github/python-versions.toml:22``
- ``python-compatibility.yml``, key ``"3.14"`` of ``.github/python-versions.toml``
* - ``Compat Python 3.15``
- job ``compatibility``, matrix leg ``3.15``
- ``python-compatibility.yml``, ``.github/python-versions.toml:23``
- ``python-compatibility.yml``, key ``"3.15"`` of ``.github/python-versions.toml``

That is the list after `#1633 <https://github.com/JarryShaw/PyPCAPKit/issues/1633>`__,
which added ``Compat Python 3.15`` and removed ``Compat Python 3.10``. Moving a version
Expand All @@ -791,8 +791,8 @@ between the tiers below means editing the ruleset in the same change.
``required-checks`` job in ``unit-tests.yml``. ``Compat Python`` is defined by
one, the ``name:`` of the ``compatibility`` job in ``python-compatibility.yml``, whose
``matrix`` comes from :file:`.github/python-versions.toml`: the required legs
are its supported tier (``python-versions.toml:19-23``), and its KTLO legs
(``python-versions.toml:16-18``) have names ending in ``(KTLO)``, so no required
are its supported tier (keys ``"3.11"`` to ``"3.15"``), and its KTLO legs
(keys ``"3.8"`` to ``"3.10"``) have names ending in ``(KTLO)``, so no required
context matches one. The comment above ``required-checks`` mentions the string
without defining it.

Expand Down Expand Up @@ -1006,8 +1006,8 @@ monitor`` ends the sampler, ``if: always()``. The file is uploaded as
only where the runner survives the tests. `always()
<https://docs.github.com/en/actions/reference/workflows-and-actions/expressions#always>`__
runs a step "even when canceled", and docs.github.com says nothing of a runner's
shutdown, after which the runner evaluates no later step's condition (actions/runner
``src/Runner.Worker/StepsRunner.cs:205-208``, at ``796cc18ff``). Job 116057255255
shutdown, after which the runner evaluates no later step's condition (actions/runner's
``StepsRunner.RunAsync``, at ``796cc18ff``). Job 116057255255
skipped every step after its tests, ``Post Run actions/checkout@v7`` too, whose
`post-if
<https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax#runspost-if>`__
Expand Down
2 changes: 1 addition & 1 deletion tests/corekit/_roundtrip.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class Gap(NamedTuple):

#: GitHub issue tracking the defect.
issue: 'Optional[int]'
#: The defect, with the ``file:line`` that causes it.
#: The defect, naming the function, class or method that causes it.
defect: 'str'
#: Status every case below reports, or a tuple of which each reports one.
status: 'str | tuple[str, ...]'
Expand Down
2 changes: 1 addition & 1 deletion tests/foundation/_roundtrip.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class Gap(NamedTuple):

#: GitHub issue tracking the defect.
issue: 'Optional[int]'
#: The defect, with the ``file:line`` that causes it.
#: The defect, naming the function, class or method that causes it.
defect: 'str'
#: Status every case below reports, or the statuses of which each must
#: report one.
Expand Down
24 changes: 13 additions & 11 deletions tests/project/test_python_versions_1660.py
Original file line number Diff line number Diff line change
Expand Up @@ -990,22 +990,24 @@ def test_the_required_contexts_table_is_the_supported_tier(self) -> None:
page = prose(ROOT / 'docs' / 'source' / 'contributing' / 'workflows.rst')
self.assertEqual(re.findall(r'\* - ``Compat Python (3\.\d+)``', page), self.supported)

def test_the_workflows_page_cites_each_version_on_its_line(self) -> None:
"""The required contexts' rows, and the two tiers' spans under them, cite the file by line."""
lines = TIER_FILE.read_text(encoding='utf-8').splitlines()
def test_the_workflows_page_cites_each_version_by_its_key(self) -> None:
"""The required contexts' rows, and the two tiers' spans under them, cite the file's keys (#2165).

A key names its entry; a line number has to be looked up, so none is cited.

"""
page = prose(ROOT / 'docs' / 'source' / 'contributing' / 'workflows.rst')
rows = re.findall(r'``Compat Python (3\.\d+)`` .*? ``\.github/python-versions\.toml:(\d+)``', page)
self.assertNotRegex(page, r'python-versions\.toml:\d')
rows = re.findall(r'``Compat Python (3\.\d+)`` .*? key ``"(3\.\d+)"`` of ``\.github/python-versions\.toml``',
page)
self.assertEqual([version for version, _ in rows], self.supported)
for version, line in rows:
for version, key in rows:
with self.subTest(version=version):
self.assertTrue(lines[int(line) - 1].startswith(f'"{version}" = '), lines[int(line) - 1])
self.assertEqual(key, version)
for label, versions in (('supported tier', self.supported), ('KTLO legs', self.ktlo)):
spans = re.findall(rf'its {label} \(``python-versions\.toml:(\d+)-(\d+)``\)', page)
spans = re.findall(rf'its {label} \(keys ``"(3\.\d+)"`` to ``"(3\.\d+)"``\)', page)
with self.subTest(tier=label):
self.assertEqual(len(spans), 1, spans)
first, last = map(int, spans[0])
self.assertEqual([line.split(' = ', 1)[0] for line in lines[first - 1:last]],
[f'"{version}"' for version in versions])
self.assertEqual(spans, [(versions[0], versions[-1])])

def test_the_bug_report_template_offers_supported_versions(self) -> None:
text = (ROOT / '.github' / 'ISSUE_TEMPLATE' / 'bug_report.md').read_text(encoding='utf-8')
Expand Down
4 changes: 2 additions & 2 deletions tests/project/test_python_versions_update_1660.py
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ def test_every_claim_and_rewriter_matches_once_on_main(self) -> None:
workflows = module.load_workflows(ROOT)
data = module.pv.load()
values = module.pv.outputs(data)
facts = module.make_facts(data, values, workflows, (ROOT / module.TIER_FILE).read_text(encoding='utf-8'))
facts = module.make_facts(data, values, workflows)
for path in module.TARGETS:
if path == module.TIER_FILE:
continue
Expand All @@ -696,7 +696,7 @@ def test_every_claim_and_rewriter_matches_once_on_main(self) -> None:
self.assertEqual(rewritten, text)

def test_a_claim_rewrites_each_group_and_never_spans_a_break(self) -> None:
"""#1811 retired the count claims and their spelt-out words; a claim states versions and lines."""
"""#1811 retired the count claims and their spelt-out words, #2165 the line ones: a claim states versions."""
module = updater()
claim = module.Claim(r'(3\.\d+) to (3\.\d+)', lambda facts: ('3.12', '3.16'))
self.assertEqual(module.apply_claims('Tests 3.11 to 3.15.', [claim], {}), ('Tests 3.12 to 3.16.', []))
Expand Down
4 changes: 3 additions & 1 deletion tests/project/test_resource_monitor_1740.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,9 @@ class TestTheDocsSayIt(unittest.TestCase):
def test_the_workflows_page_describes_the_monitor(self) -> None:
page = prose(ROOT / 'docs' / 'source' / 'contributing' / 'workflows.rst')
for phrase in ('``Start the resource monitor``', '``[monitor]``', '``resource-monitor-<version>``',
'``Stop the resource monitor``', 'src/Runner.Worker/StepsRunner.cs:205-208'):
'``Stop the resource monitor``',
# #2165: the runner's shutdown check, cited by its method rather than by line.
"actions/runner's ``StepsRunner.RunAsync``, at ``796cc18ff``"):
with self.subTest(phrase=phrase):
self.assertIn(phrase, page)

Expand Down
2 changes: 1 addition & 1 deletion tests/protocols/_edge_roundtrip.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class Gap(NamedTuple):

#: GitHub issue tracking the defect, or :data:`None` if not filed yet.
issue: 'Optional[int]'
#: The defect, with the ``file:line`` that causes it.
#: The defect, naming the function, class or method that causes it.
defect: 'str'
#: Expected status of every case below, or the statuses one root cause
#: shows as, of which each case must report one.
Expand Down
6 changes: 3 additions & 3 deletions tests/protocols/test_dispatch_registry_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,9 @@ def test_dispatch_reaches_target_or_is_a_recorded_degrade(self) -> None:
outcome.reached, True,
f'{case.label} no longer dispatches to {case.target!r}: '
f'chain was {outcome.chain!r} ({outcome.detail}). If this '
f'is a newly found defect, add it to KNOWN_DEGRADED with '
f'the file:line that causes it -- do not change the case '
f'to avoid it.'
f'is a newly found defect, add it to KNOWN_DEGRADED naming '
f'the function, class or method that causes it -- do not '
f'change the case to avoid it.'
)
continue

Expand Down
7 changes: 4 additions & 3 deletions tests/protocols/test_option_roundtrip_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ class Gap(NamedTuple):
#: messages whose stable parts are not contiguous, so that a fragment does
#: not have to bake in a rendering that is itself defective.
fragment: 'str | tuple[str, ...]'
#: The defect, named with the ``file:line`` that causes it. This is the
#: field that makes the entry worth keeping rather than just silencing.
#: The defect, naming the function, class or method that causes it. This is
#: the field that makes the entry worth keeping rather than just silencing.
defect: 'str'


Expand Down Expand Up @@ -594,7 +594,8 @@ def test_round_trip_is_identity_or_a_recorded_gap(self) -> None:
outcome.status, 'OK',
f'{case.label} no longer round-trips: {outcome.detail}. '
f'If this is a newly found defect, add it to '
f'EXPECTED_FAILURES with the file:line that causes it -- '
f'EXPECTED_FAILURES naming the function, class or method that '
f'causes it -- '
f'do not change the case to avoid it.'
)
continue
Expand Down
29 changes: 8 additions & 21 deletions util/update_python_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,12 +966,6 @@ def span(tier: 'list[str]') -> 'Optional[tuple[str, str]]':
return (tier[0], tier[-1]) if consecutive([pv.key(version)[1] for version in tier]) else None


def lines_of(facts: 'dict[str, Any]', tier: 'str') -> 'Optional[tuple[int, int]]':
"""The tier file lines of a CPython tier, if they are one run of lines."""
numbers = [facts['tier_lines'][version] for version in facts[tier]]
return (numbers[0], numbers[-1]) if consecutive(numbers) else None


#: The sentences restating the tiers, by file. Never a workflow (see the module docstring).
CLAIMS = {
'pyproject.toml': (
Expand All @@ -995,9 +989,9 @@ def lines_of(facts: 'dict[str, Any]', tier: 'str') -> 'Optional[tuple[int, int]]
'docs/source/contributing/workflows.rst': (
Claim(r'The \*\*supported\*\* tier, (3\.\d+)-(3\.\d+),', lambda f: span(f['supported'])),
Claim(r'end-of-life (3\.\d+)-(3\.\d+), still built', lambda f: span(f['ktlo'])),
Claim(r'the required legs are its supported tier \(``python-versions\.toml:(\d+)-(\d+)``\)',
lambda f: lines_of(f, 'supported')),
Claim(r'its KTLO legs \(``python-versions\.toml:(\d+)-(\d+)``\)', lambda f: lines_of(f, 'ktlo')),
Claim(r'the required legs are its supported tier \(keys ``"(3\.\d+)"`` to ``"(3\.\d+)"``\)',
lambda f: span(f['supported'])),
Claim(r'its KTLO legs \(keys ``"(3\.\d+)"`` to ``"(3\.\d+)"``\)', lambda f: span(f['ktlo'])),
Claim(r'and the ``Compat Python (3\.\d+)``-``(3\.\d+)`` legs', lambda f: span(f['supported'])),
Claim(r'the ``Python (3\.\d+)`` leg of ``test`` \(matrix key ``coverage: true``\)',
lambda f: (f['latest'],)),
Expand All @@ -1022,7 +1016,8 @@ def lines_of(facts: 'dict[str, Any]', tier: 'str') -> 'Optional[tuple[int, int]]
#: One row of the workflows page's required-contexts table.
COMPAT_ROW = re.compile(r'^(?P<indent>[ \t]*)\* - ``Compat Python (?P<version>3\.\d+)``\n'
r'(?P<inner>[ \t]*)- job ``compatibility``, matrix leg ``(?P=version)``\n'
r'(?P=inner)- (?P<where>``[^`\n]+``), ``\.github/python-versions\.toml:\d+``\n', re.M)
r'(?P=inner)- (?P<where>``[^`\n]+``), key ``"(?P=version)"`` '
r'of ``\.github/python-versions\.toml``\n', re.M)
BUG_VERSIONS = re.compile(r'(Python Version: \[e\.g\. )([^\]\n]+)(\])')


Expand All @@ -1047,8 +1042,7 @@ def rewrite_compat_rows(text: 'str', facts: 'dict[str, Any]') -> 'tuple[str, lis
first = matches[0]
block = ''.join(f'{first["indent"]}* - ``Compat Python {version}``\n'
f'{first["inner"]}- job ``compatibility``, matrix leg ``{version}``\n'
f'{first["inner"]}- {first["where"]}, '
f'``.github/python-versions.toml:{facts["tier_lines"][version]}``\n'
f'{first["inner"]}- {first["where"]}, key ``"{version}"`` of ``.github/python-versions.toml``\n'
for version in facts['supported'])
return text[:first.start()] + block + text[matches[-1].end():], []

Expand All @@ -1074,21 +1068,14 @@ def rewrite_bug_template(text: 'str', facts: 'dict[str, Any]') -> 'tuple[str, li
TARGETS = tuple(sorted({TIER_FILE} | set(CLAIMS) | set(REWRITERS)))


def make_facts(data: 'dict[str, Any]', values: 'dict[str, str]', workflows: 'dict[str, Any]',
tier_file: 'str') -> 'dict[str, Any]':
def make_facts(data: 'dict[str, Any]', values: 'dict[str, str]', workflows: 'dict[str, Any]') -> 'dict[str, Any]':
"""What the prose states, computed from the new tiers and the workflows' matrices."""
tier_lines = {}
for number, line in enumerate(tier_file.splitlines(), 1):
match = ENTRY.match(line)
if match and pv.SPELLING['cpython'].fullmatch(match['version']):
tier_lines[match['version']] = number
return {
'latest': data['latest'],
'supported': pv.tier(data, 'cpython', 'supported'),
'ktlo': pv.tier(data, 'cpython', 'ktlo'),
'experimental': [version for impl in data['versions'] for version in pv.tier(data, impl, 'experimental')],
'required': required_contexts(workflows, values),
'tier_lines': tier_lines,
}


Expand Down Expand Up @@ -1167,7 +1154,7 @@ def compute_plan(root: 'pathlib.Path', sources: 'dict[str, Any]') -> 'tuple[dict
validate(new_tier_text)
after_values = pv.outputs(after)

facts = make_facts(after, after_values, workflows, new_tier_text)
facts = make_facts(after, after_values, workflows)
texts = {TIER_FILE: new_tier_text}
for path in TARGETS:
if path == TIER_FILE:
Expand Down
Loading