forgetest: the implementation hash walks a sibling imported as from . import x too

_imported walked a relative import only when it names a module (`from
.x import y`): a level-1 ImportFrom with no module, `from . import x`,
was passed over, so the suite module x joined no hash through it. The
guard on the suite's package imports reads levels 2 and 0 alone, so it
passed that spelling, and its own message sends an absolute import
there: "import it relatively (from .. or from .)". So the guard and the
walk did not read the same spellings: on a scratch copy of the catalog,
forgectrl.auth's import of setup.py written `from . import setup`
passed the guard, and an edit to setup.py's decode(), which the test
calls, left forgectrl.auth's implementation hash where it was.
homeoff.py imports cloud.py so (`from . import cloud as logs`); its
`from .cloud import log_lines_since, log_size` on the next line keeps
cloud.py in the walk, so no hash misses a module.

_imported now walks every level-1 relative import: one with no module
walks each name it imports as <suite>/<name>.py, the name and not its
alias (a name that is no module of the suite is passed over, as a
module was). The docstrings of _imported and sibling_imports, and the
comment of the guard's case, name both spellings.

Proof: forgetest-ci "Unit tests" (`python -B -m unittest discover -s
tests -v` in forgetest): test_manifest.py runs 39 tests, OK, on Windows
with python 3.14 and on Ubuntu 24.04 with python 3.12.
test_a_sibling_imported_inside_a_function_moves_the_tests_that_run_it
gains a leg in which m.two imports judge.py as `from . import judge as
j`: an edit to judge.py moves m.two and not m.one. Negative controls on
scratch copies: catalog.py as it was fails that leg (the two hashes are
equal), and so does the walk that reads the alias (j) in place of the
name. On a scratch copy of the catalog with forgectrl.auth's import
written `from . import setup`, an edit to setup.py's decode() now moves
forgectrl.auth's hash. The coverage lint on the tree manifest from the
recipe pins reports 0 uncovered paths, 0 host-tested row problems, 43
tests. pyflakes reports no undefined name.

Acceptance: none. The source_sha of 43 of 43 tests is unchanged: the
one module-less sibling import outside the registry (suite/__init__.py,
which has no tests) is homeoff.py's, and cloud.py is in its walk
already. catalog.py is the registry and no shared judge, forgetest is
in no fingerprint, and tests/ are in no fingerprint.
This commit is contained in:
ScottW514
2026-10-17 07:17:14 -04:00
parent 614efb23e4
commit 7a71dd80b5
2 changed files with 23 additions and 11 deletions
+12 -2
View File
@@ -536,8 +536,9 @@ class CatalogTests(unittest.TestCase):
# a suite module does import, at its top level or inside a function
# or a block, has to be on it (or be the registry, which judges
# nothing), or that judge would be in no fingerprint. The sibling
# walk follows the relative spelling alone, so a suite module
# imports the package by no absolute name.
# walk follows the relative spellings alone (`from .x import` and
# `from . import x`), so a suite module imports the package by no
# absolute name.
import ast
import glob
paths = catalog.shared_judge_paths()
@@ -724,6 +725,15 @@ def two(ctx):
a4, b4 = self.shas()
self.assertNotEqual(a3, a4)
self.assertNotEqual(b3, b4)
# the spelling with no module (`from . import x`, as homeoff.py imports cloud.py) is
# walked the same
self.write(self.MODULE.replace("def two(ctx):\n",
"def two(ctx):\n from . import judge as j\n j.judge(2)\n"))
a8, b8 = self.shas()
write_judge("def judge(x):\n return x > 4\n")
a9, b9 = self.shas()
self.assertEqual(a8, a9)
self.assertNotEqual(b8, b9)
def test_line_endings_do_not_count(self):
a1, b1 = self.shas()