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
15 changes: 13 additions & 2 deletions gitgalaxy/standards/language_standards/languages/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,14 @@
r"\b(eval|exec|subprocess\.(?:call|Popen|run)|os\.system|pickle\.loads?|yaml\.unsafe_load|shell=True)\b"
),
# 9. io (I/O & Network Boundaries)
# #2593: `os\.`/`sys\.` used to match ANY `os.x`/`sys.x` attribute access, which
# overlaps the `globals` rule's `os.environ`/`sys.argv`/`sys.path` (those are shared
# process state, not an I/O boundary) -- one planted `os.environ` or `sys.argv` read
# was double-counted as both `globals` and `io`. Negative lookaheads carve out exactly
# those three tokens so `os.path`/`os.open`/`sys.stdin`/etc. still count as `io`.
"io": re.compile(
r"\b(open|requests|httpx|aiohttp|boto3|os\.|sys\.|pathlib|socket|sqlalchemy|psycopg2?|asyncpg)\b"
r"\b(open|requests|httpx|aiohttp|boto3|pathlib|socket|sqlalchemy|psycopg2?|asyncpg)\b"
r"|\bos\.(?!environ\b)|\bsys\.(?!argv\b|path\b)"
),
# 10. api (Public Surface Area)
# Implicit public defaults (undercased root definitions) + explicit __all__.
Expand All @@ -199,7 +205,12 @@
# 13. doc (Structured Documentation)
"doc": re.compile(r'"""|\'\'\'|:param|:return|:raises|:type|\b(?:Args|Returns|Yields|Raises|Attributes):\b'),
# 14. test (Testing & Assertions)
"test": re.compile(r"\b(unittest|pytest|TestCase|fixture|patch)\b|def[ \t]+test_|\bassert\b|\bMock\b"),
# #2593: `assert` is a general-purpose validation keyword already owned by `safety`
# (see that rule above) -- it isn't itself a testing signal, so a runtime invariant
# check in production code (`assert isinstance(value, int)`, no test framework in
# sight) was being double-counted as `test` too. Removed; `def test_`/unittest/pytest/
# fixture/patch/Mock already cover real testing idioms without it.
"test": re.compile(r"\b(unittest|pytest|TestCase|fixture|patch)\b|def[ \t]+test_|\bMock\b"),
# --- PHASE 3: SPECIALIZED SENSORS (Architecture & Hidden Complexity) ---
# 15. concurrency (Asynchronous Execution)
"concurrency": re.compile(
Expand Down
48 changes: 48 additions & 0 deletions tests/extraction/languages/test_python_strict.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
("safety_bypasses", "except Exception:\n log(e)", "except ValueError:\n log(e)"),
("high_risk_execution", "eval(user_input)", "print('safe')"),
("io", "with open('f.txt') as f:\n pass", "opened = True"),
("io", "os.path.join(a, b)", "os.environ.get('X')"),
("io", "sys.stdin.read()", "sys.argv[0]"),
("state_mutation", "self.value = 1", "print(self.value)"),
("dead_code", "# def old_unused_function():", "# just a note"),
("doc", '"""A module docstring."""', '"a regular string"'),
Expand Down Expand Up @@ -87,6 +89,7 @@
("ml_traditional", "from sklearn.linear_model import LogisticRegression", "from scipy import stats"),
("structural_boundaries", "return x", "yield x"),
("test", "def test_addition():\n assert 1 + 1 == 2", "def calculate_addition(a, b):\n return a + b"),
("test", "unittest.TestCase", "assert isinstance(value, int)"),
("vectorized_math", "result = A @ B", "result = a * b"),

# === DEEP/ADVERSARIAL CASES FOR HIGH-AMBIGUITY SIGNATURES ===
Expand Down Expand Up @@ -138,6 +141,51 @@ def test_python_signature_positive_and_negative(signature, positive, negative):
)


def test_python_io_excludes_globals_overlap():
"""
Regression test for #2593 (rosetta): `io`'s `os\\.`/`sys\\.` used to match
ANY `os.x`/`sys.x` attribute, overlapping `globals`' own `os.environ`/
`sys.argv`/`sys.path` -- one planted globals read was double-counted as
`io` too. Negative lookaheads carve out exactly those three tokens;
every other `os.`/`sys.` attribute access must still count as `io`, and
the carved-out tokens must still count as `globals`.
"""
io = PY_RULES["io"]
globals_rule = PY_RULES["globals"]

assert not io.search("os.environ.get('X')"), "io incorrectly matched os.environ (owned by globals)"
assert not io.search("sys.argv[0]"), "io incorrectly matched sys.argv (owned by globals)"
assert not io.search("sys.path.append(x)"), "io incorrectly matched sys.path (owned by globals)"
assert io.search("os.path.join(a, b)"), "io failed to match a real os. attribute (os.path)"
assert io.search("os.remove(path)"), "io failed to match a real os. attribute (os.remove)"
assert io.search("sys.stdin.read()"), "io failed to match a real sys. attribute (sys.stdin)"

assert globals_rule.search("os.environ.get('X')"), "globals failed to match os.environ"
assert globals_rule.search("sys.argv[0]"), "globals failed to match sys.argv"


def test_python_test_excludes_bare_assert():
"""
Regression test for #2593 (rosetta): `test` used to include `\\bassert\\b`,
double-counting every `assert` already owned by `safety` -- a runtime
invariant check in production code (no test framework in sight) was
miscounted as a testing signal. `assert` alone must no longer match
`test`, but must still match `safety`; real testing idioms are unaffected.
"""
test_rule = PY_RULES["test"]
safety = PY_RULES["safety"]

assert not test_rule.search("assert isinstance(value, int)"), (
"test incorrectly matched a bare assert (owned by safety, not a testing signal)"
)
assert safety.search("assert isinstance(value, int)"), "safety failed to match assert"
assert test_rule.search("import unittest"), "test failed to match unittest"
assert test_rule.search("import pytest"), "test failed to match pytest"
assert test_rule.search("def test_foo():"), "test failed to match a def test_ function"
assert test_rule.search("mock.patch('x')"), "test failed to match patch"
assert test_rule.search("Mock()"), "test failed to match Mock"


def test_python_comprehensions_was_fixed_from_a_javascript_copy_paste():
"""
Regression test: python's comprehensions rule used to be
Expand Down
Loading
Loading