Snapshot generated 2026-08-09 against main. Source: LANGUAGE_DEFINITIONS["python"] in
gitgalaxy/standards/language_standards.py, tests/extraction/languages/test_python.py /
test_python_strict.py, closed GitHub issues, and
gitgalaxy-raw-output. Re-run the
language-status skill's data-gathering commands before trusting these numbers if this doc looks
old relative to last_updated below.
| Field | Value |
|---|---|
_meta.status |
production |
_meta.target_version |
Python 3.14 |
_meta.blueprint_version |
6.30 |
_meta.last_updated |
2026-03-11 |
lexical_family |
line_exclusive (single # line comments only, no native block-comment syntax — the engine's heuristic pass handles triple-quoted-string-as-docstring separately, see §5) |
| Structural signature keys wired | 61 / 64 (3 explicit None, see §4) |
Extraction-gauntlet tests (test_python.py) |
60 |
Strict-signature tests (test_python_strict.py) |
92 |
| Total dedicated Python test cases | 152 |
Real-world function recall vs. ast ground truth (real pipeline) |
~60% — see §9 |
| Real-world function recall, isolated slicing (no prism upstream) | 100% — see §9 |
Real-world class recall vs. ast ground truth |
100% — see §9 |
- Extensions:
.py .py3 .py2 .pyw .pyi .pyx .pxd .pxi .pyz .pyzw .bzl .gyp .gypi .vpython .vpython3 .rpy .smk— modern/legacy suffixes, typed stubs, Cython, and Bazel/GYP/Snakemake build-tooling dialects that are secretly Python. - Exact filenames:
setup.py,SConstruct,SConscript,BUCK,BUILD,wscript,Snakefile— extensionless build/config scripts. - Discriminators:
.py,requirements.txt,pyproject.toml,Pipfile,Pipfile.lock,tox.ini,poetry.lock,setup.cfg— ecosystem anchors used to disambiguate. - Shebangs:
python,python3,python2,pypy,pypy3,jython. embedded_pythonis a separate language entry (own status doc, not this one) for Python embedded inside another host file (e.g. Django templates, Jupyter-adjacent contexts) — don't conflate the two when reading test counts.
Grouped by the phase headers language_standards.py and how_to_add_a_language.md use.
Description is what Python's actual regex matches, not the generic cross-language definition.
Topology & structure
| Key | What it captures for Python |
|---|---|
branch |
if elif else for while with try finally match case and or |
args |
def/async def/lambda parameter blocks, including PEP 695 (3.12+) bounded generics (def Foo[T: Sequence[int]](x: T)) |
structural_boundaries |
def class return import from as pass continue break await assert del global nonlocal type |
func_start |
Anchors def/async def, stepping over up to 5 decorator lines and PEP 695 generic brackets |
class_start |
Anchors class, same decorator/generic step-over, captures class name + base-class list |
Safety & risk
| Key | What it captures for Python |
|---|---|
safety |
try except except* finally assert isinstance issubclass hasattr getattr dataclass BaseModel Field TypeGuard override |
safety_bypasses |
Bare pass, bare/untyped except:/except Exception, wildcard from x import *, # type: ignore, Any/cast, empty []/{} literal init |
high_risk_execution |
eval exec subprocess.call/Popen/run os.system pickle.loads yaml.unsafe_load shell=True |
io |
open requests httpx aiohttp boto3 os. sys. pathlib socket sqlalchemy psycopg2 asyncpg |
api |
Top-level def/class without a leading underscore, __all__ =, FastAPI/Flask-style @app.get/post/put/delete route decorators (implicit-public-by-default, per Rule 1 of the engine's generation rules) |
state_mutation |
global/nonlocal, self./cls. attribute assignment, walrus operator (:=), list/dict mutator calls (.append/.extend/.update/.pop/.remove/.insert/.clear) |
dead_code |
Commented-out # def/class/import/if/for/while/try/return |
doc |
Triple-quoted docstrings, Sphinx-style :param/:return/:raises/:type, Google-style Args:/Returns:/Yields:/Raises:/Attributes: |
test |
unittest pytest TestCase fixture patch, def test_, assert, Mock |
Architecture & domain sensors
| Key | What it captures for Python |
|---|---|
concurrency |
async await asyncio threading multiprocessing ThreadPoolExecutor TaskGroup gather create_task |
ui_framework |
streamlit django.shortcuts flask.render_template gradio dash fasthtml jinja2 render |
closures |
lambda |
globals |
os.environ sys.argv sys.path, globals(), locals() |
decorators |
Any @-prefixed line |
generics |
typing generics (List/Dict/Set/Tuple/Optional/Union/TypeVar/Generic/Any/Callable/Mapping[...]), lowercase builtin generics (list/dict/set/tuple/type[...]), -> return annotations |
comprehensions |
[...for...] / {...for...} / (...for...) shapes, bounded to 500 chars per side (list/dict/set comprehensions and generator expressions — Python has no .map(/.filter( builtin, so it doesn't share JS's comprehensions idiom) |
scientific |
import/from referencing numpy pandas scipy matplotlib opencv cv2 |
hardware_bridge |
import/from referencing serialport usb bluetooth socket.io websocket printer webgl |
cryptography |
import/from referencing crypto bcrypt x509 tls ssl jsonwebtoken argon2 |
reflection_metaprogramming |
Dunder hooks (__getattr__ __setattr__ __del__ __call__ __new__ ...), @staticmethod/@classmethod/@property, getattr/setattr/inspect. |
llm_api / llm_orchestrator / llm_vector_store / ml_traditional / dl_frameworks |
Shared cross-language GLOBAL_ AI/ML SDK sensors (issue #322 moved these off a hand-pasted per-language duplicate) |
import |
from X import, import X, __import__(, importlib.import_module( |
_dependency_capture |
Extracts the exact dotted module path from all four import forms above (feeds the dependency DAG) |
_named_token_capture |
Captures the raw name list from from X import ... |
ownership |
__author__ =, Author:, Created by: |
Specialized subsystems
| Key | What it captures for Python |
|---|---|
planned_debt / fragile_debt |
Shared GLOBAL_ TODO/FIXME-family markers |
spec_exposure |
[SPEC-123], [spec ...], [audit ...] traceability tags |
ssr_boundaries |
render_template HttpResponse JSONResponse TemplateResponse WSGIApplication ASGIApplication |
events |
Signal receiver post_save pre_save asyncio.Event EventDispatcher emit send blinker |
dependency_injection |
Depends Provide Inject Container dependency_injector fastapi.Depends |
pointers |
ctypes.POINTER c_void_p byref |
Resource management & stability
| Key | What it captures for Python |
|---|---|
telemetry |
logging/logger/structlog/sentry_sdk/datadog/loguru .info/.error/.warn/.warning/.debug/.trace/.log/.exception/.critical |
debug_prints |
print(, input( |
explicit_casts |
int str float list dict set tuple bool bytes cast( |
panics_and_aborts |
raise quit exit sys.exit abort |
thread_sleeps |
time.sleep asyncio.sleep Thread.join |
bitwise_ops |
<< >> ^ ~ |
sync_locks |
Lock RLock Semaphore BoundedSemaphore Event Condition Barrier |
immutability_locks |
Final frozenset mappingproxy immutable |
cleanup |
close( __exit__( del( shutdown( cleanup( |
encapsulation |
Leading-underscore naming convention (Python's only privacy signal — no private keyword) |
listeners |
on_event add_listener subscribe callback handler |
test_skip |
pytest.mark.skip unittest.skip mock. MagicMock |
Advanced algorithmic / hybrid domain / AppSec sensors
| Key | What it captures for Python |
|---|---|
lazy_evaluation |
yield, yield from, Generator/AsyncGenerator/Iterator/AsyncIterator |
vectorized_math |
einsum matmul tensordot vdot bmm, .dot(, the @ matrix-multiplication operator between operands |
serialization_parsing |
pickle.loads/Unpickler marshal.loads ast.literal_eval |
regex_execution |
re.compile/search/match/sub/findall/split |
time_date_logic |
datetime.datetime timedelta time.sleep time.time calendar |
ipc_rpc_bridges |
multiprocessing subprocess xmlrpc socketserver |
memory_scraping |
String-built /proc/ paths, /proc/<pid>/mem |
exfiltration_camouflage |
requests.post/urllib.request/httpx.post calls whose arguments mention checkmarx/telemetry/metrics/audit/log (case-insensitive — flags exfiltration traffic dressed up as observability) |
Three keys are hard-set to None in Python's rules dict (Rule 4 of the engine's generation
rules: explicitly None, never a forced-fit regex, when a dimension doesn't exist natively):
macros— Python has no C-style preprocessor.memory_alloc— memory is GC-managed; there's no manual allocation to track.inline_asm— no native inline-assembly construct.
Two gaps are deliberately documented rather than fixed, via known_limitation-named tests in
test_python.py:
- No whitespace tolerance between a function name and a PEP 695 generic bracket.
def Foo[T](...)matches;def Foo\n[T](...)does not. Judged not worth fixing — no real formatter (black,ruff format) ever produces that exact vertical split; real-world splitting happens between modifiers/parens/inside the bracket's contents, never between an identifier and the generic bracket immediately following it. _dependency_capturematches inside triple-quoted strings. Unlikefunc_start(shielded by Mode C's indentation-based slicing before matching),_dependency_captureruns against fully unshielded raw file content for every language, unconditionally — animport os-shaped line sitting at true line-start inside a Python triple-quoted string still produces a phantom dependency-graph edge. This is recurring bug class 10 intests/extraction/how_to_harden_extraction.md, present for every language, not Python-specific — documented here rather than silently worked around.
- Extraction gauntlet (
func_start/args/class_start/_dependency_capture): 60 tests intests/extraction/languages/test_python.py— valid/invalid/pathological cases per rule, plus the PEP 695 regression tests and the two known-limitation tests above. Fully migrated to the per-language file (epic #813, issue #818) — nothing left in the old monolithic gauntlet files for Python. - Strict signature suite (all other wired keys): 92 tests in
tests/extraction/languages/test_python_strict.py— positive match, negative/false-positive match, cross-rule ambiguity, and ReDoS-immunity checks per signature (epic #518, issue #606; deepened further by issue #1072's AI/ML sensor pass, see §7).
Epic-level hardening passes:
- #606 — Strict parsing tests for Python structural signatures (epic #518).
- #818 — Extraction hardening for Python (epic #813): PEP 695 nested-bracket fixes to
args/func_start/class_start, deepened valid/invalid/pathological case counts. - #1072 — Closed a real security-relevant gap: Python's entire AI/ML extension pack (
llm_api,llm_orchestrator,llm_vector_store,dl_frameworks,ml_traditional,vectorized_math) plus 13 other keys (closures,comprehensions,lazy_evaluation,api,cryptography,encapsulation,exfiltration_camouflage,hardware_bridge,import,memory_scraping,structural_boundaries,test,bitwise_ops) had zero test coverage despite being wired and live.
Cross-language fixes that touched Python along the way:
- #322 — Moved Python's (and JavaScript's) hand-pasted AI/LLM SDK detection onto the shared
GLOBAL_LLM_*/GLOBAL_ML_*/GLOBAL_DL_*pattern used by every other language. - #713 — Fixed
spec_exposure's unbounded[^\]]*ReDoS shape, copy-pasted across 28 languages including Python. - #1041 — Nested functions were silently dropped from extraction (affected every language routed through the same extractor path, Python included).
Real defects found via this doc's own §9 measured-accuracy pass, since fixed:
- #1182 (CLOSED, merged #1188) —
_calculate_block_metricstruncated every extracted name to 40 chars, corrupting any function/method name longer than that. - #1183 (CLOSED, merged #1190) —
_partition_segments's embedded-language handshake could false-trigger on<script/<stylesubstrings appearing inside an ordinary string/regex literal (not real embedded code), permanently misrouting the rest of the file to the wrong language's rules. - #1184 (fixed, PR #1192 open pending merge) —
_build_indentation_safe_stream(and the equivalent Mode D/E shields) stripped comments in a separate pass after string-shielding; an English contraction apostrophe inside a#comment (don't,it's) was indistinguishable from a real string-open quote, cascading into large dead zones of dropped functions. Fixed by merging comment-shielding into the same single-pass alternation as string-shielding, mirroring_build_brace_safe_stream's already-correct design.
Real defect found via this same pass, still open:
- #1193 (OPEN) —
prism.py's_strip_single_line_commentsdrives its delimiter list from theline_exclusivelexical family as a whole rather than per-language, so;(real comment char only forassembly/agc_assembly) and%(real comment char only formatlab) get treated as comment starts in the other 18line_exclusivelanguages too, including Python — with zero string-shielding, so;/%inside a string literal also triggers false truncation. This is the dominant reason real-pipeline recall (§9) is still far below the isolated-slicing number.
Search performed via gh issue list --search 'in:title "Extraction hardening: python"' /
'in:title "Strict parsing tests: python"' / 'in:title python' (2026-08-09) — the last query
also surfaces engine-wide bugs (#1052, #1055, metrics/scoring issues) that mention Python
incidentally without changing its signature rules; excluded here as not language-coverage-specific.
Four repos from the v2.4.7 batch, chosen for a size/shape spread rather than four similar
mid-size projects:
cpython— Python's own reference implementation (the CPython interpreter + stdlib). The most adversarial Python codebase available: decades of eras, C-extension boundary code, and every syntax generation the language has shipped. Scanned in 12.78s.django— large, long-lived production framework; heavy use ofapi/ssr_boundaries/events/dependency_injection-relevant patterns (signals, ORM, class-based views). Scanned in 18.06s.requests— small, canonical single-purpose library; a useful low-noise baseline. Scanned in 0.45s.black— a formatter that itself requires a full AST internally, scanned by an engine that has none; a pointed contrast case. Scanned in 1.12s.
Each _galaxy_llm.md is the human-readable architectural brief; _galaxy_audit.json.gz and
_galaxy_sbom.json.gz in the same directory carry the raw per-file signature counts and SBOM if
deeper inspection is needed.
Everything above describes what's wired and how it's tested in isolation — adversarial
snippets hand-picked to probe one rule at a time. This section is different: it measures what
the engine actually gets right on real, unmodified production code, using Python's own
ast module as ground truth. This is empirically stronger evidence than the unit-test suite
alone, because it exercises the segment-routing and scope-boundary machinery that sits between
"a regex matched" and "a function got correctly recorded" — machinery the isolated per-rule
tests don't touch.
Methodology: regenerated a fresh, full (not incremental — see the caution below) self-scan
of GitGalaxy's own repo (python tests/tools/self_scan.py, full precision, pinned to the exact
commit scanned), giving 228 Python files / 2,436 real functions / 61 real classes per
ast.parse(). For each file, diffed ast.walk()'s FunctionDef/AsyncFunctionDef/ClassDef
names (and each function's real parameter count) against function_data/class_data rows for
that file. Cross-checked the branch keyword rule separately using Python's tokenize module as
an independent ground truth, and by running the compiled branch regex directly against
prism-shielded code_stream (bypassing the DB entirely) to isolate the rule's own accuracy from
downstream aggregation. Also ran _slice_by_indentation() directly against each file's raw
content (bypassing prism.split_streams() entirely) to isolate the Mode C slicing logic's own
accuracy from whatever prism.py does upstream of it — this split turned out to matter a lot,
see the #1193 discussion below.
Caution for future re-runs: self_scan.py defaults to an incremental scan when
docs/self_scan/gitgalaxy_master.db already exists, which rehydrates cached per-file results for
any file whose content hasn't changed since the baseline commit. That's the right default for
normal orientation use, but it's wrong for measuring accuracy after an engine change (detector.py
changed, not the scanned files) — incremental mode silently reused pre-fix results the first time
this measurement was re-run post-#1184, understating the fix's effect. Delete the DB
(rm docs/self_scan/gitgalaxy_master.db) to force a full rescan before trusting a post-engine-fix
measurement.
| Signal | Result | Read as |
|---|---|---|
Class extraction (class_start) |
100% recall (61/61) | Fully reliable on this corpus |
Function extraction, isolated Mode C slicing (bypasses prism.py) |
100% recall (2436/2436) | _slice_by_indentation itself is now fully correct — confirms #1184's fix |
Function extraction, real production pipeline (prism.split_streams → detector.splice) |
~60% recall (1465/2436) | See #1193 below — the gap between this row and the one above is #1193 |
| Function-name precision (of functions found via the real pipeline) | ~98.7% (1446/1465) | Engine essentially never invents a function once it finds one at all |
| Args-count exact match (for functions that were found) | ~35% | Also downstream of #1193 — a truncated/corrupted signature line breaks arg-count parsing too |
branch keyword rule, run directly against shielded code |
~133% of a tokenize-based ground truth (catches everything, plus false-positive hits inside string literals this check doesn't shield against) |
Simple keyword-alternation rules are far more reliable than boundary/entity extraction — but this specific comparison over-counts by design, see caveat below |
The branch percentage exceeding 100% is expected, not alarming: this check runs the raw regex
against code_stream with no further per-occurrence shielding, so it also matches if/for/etc.
appearing inside string literals — a looser check than what the detector's actual pipeline does
downstream. It's included to demonstrate that keyword-alternation rules are inherently more
robust than boundary-extraction rules (over-counting is a far gentler failure mode than the
under-counting boundary extraction suffers from), not as a precision claim.
Four real, filed defects were found via this pass across two rounds of measurement — three now fixed, one still open. Each has a concrete reproduction, not a vague "heuristics are imprecise" hand-wave:
- #1182 (CLOSED) — 40-character
name truncation.
detector.py's_calculate_block_metricsdid"name": name[:40]. 984 of this corpus's 2,436 functions (40%) have real names over 40 chars — this codebase's own long descriptive test-naming convention routinely exceeds it. A naming-fidelity bug, not a recall bug — it was initially mistaken for hallucinated/phantom functions during the first audit pass (a truncated name and its real counterpart look like two unrelated functions in a naive diff) until corrected for. Fixed by removing the truncation. - #1183 (CLOSED) — mid-file
language "gravity" false-triggers.
_partition_segmentscould be misled by a Python string/regex literal that merely contained embedded-language delimiter text as data (confirmed case: a dict literal intest_prism.pydescribing a"<script>"trigger pattern, itself test data for the embedded-language detector) into permanently misrouting the rest of the file to a different language's rules. Root cause:detector.py's own copy ofHANDSHAKE_REGISTRYhad drifted out of sync with the canonical, properly-anchored version inlanguage_standards.py. Fixed by deriving it from the canonical source instead of hand-duplicating it. - #1184 (fixed, PR
#1192 pending merge) — scope-loss
"dead zones." Contiguous ranges of real, ordinary functions (
__init__,main,cleanup) went missing in real production files (prism.py,guidestar_lens.py,galaxyscope.py) with no language-drift trigger present. Root cause:_build_indentation_safe_stream(and the equivalent Mode D/E shields) stripped comments in a separate pass after string-shielding, so an English contraction apostrophe inside a#comment (don't,it's) was indistinguishable from a real string-open quote — it would pair with whatever'came next anywhere later in the file and blank out everything in between. Confirmed fully fixed in isolation: direct_slice_by_indentation()calls now hit 100% recall on this exact corpus (row 2 of the table above) — but this is not what the real pipeline number reflects, see #1193. - #1193 (OPEN) —
line_exclusivecomment delimiters shared across languages that don't use them.prism.py's_strip_single_line_commentsdrives its delimiter list from theline_exclusivefamily config as a whole (# <# #> =begin =end ; dnl %), applied identically to all 20 languages in that family.;is only real forassembly/agc_assembly;%only formatlab. For the other 18 — Python included — a bare;or%anywhere in the source is misread as a comment start, silently truncating the rest of that line fromcode_stream. There's also zero string-shielding in that stripper, so;/%inside a string literal (e.g. a SQL query string, ordetector.py's ownr";"terminator pattern) triggers the same false truncation. This is why the real-pipeline recall row above (~60%) is still far below the isolated-slicing row (100%) even with #1184 fixed — #1193 corruptscode_streambefore_slice_by_indentationever sees it, and the resulting odd/unbalanced quote count can cascade into further loss downstream, the same cascading mechanism #1184 fixed, just triggered upstream inprism.pyinstead of indetector.py. Not yet fixed; root cause is understood and a fix direction is proposed in the issue, but implementing and verifying it is separate follow-on work.
Net effect of this round: #1182 and #1183 are fully resolved (verified via the real pipeline).
#1184 is fully resolved at the layer it touches — _slice_by_indentation itself is now
provably 100% correct on this corpus — but #1193 sits upstream of it in the real pipeline and
wasn't discovered until after #1184 shipped, which is why real-pipeline recall barely moved
between the two measurement rounds despite #1184 being a genuine, verified fix. This is worth
internalizing for future rounds: a component being provably correct in isolation does not mean
the pipeline that feeds it is — measure the real pipeline, not just the component you just fixed.
Scaling this beyond Python: ast is stdlib-only, so this exact technique is Python-specific.
For other languages, tree-sitter-language-pack (verified on PyPI, ships pre-compiled grammars
for 371 languages, no per-language compiler toolchain required) is the most promising path to
the same style of ground-truth diff across most of GitGalaxy's other 45 signature-bearing
languages. Genuinely no practical AST ground truth exists for the legacy/esoteric languages
(COBOL, JCL, Fortran, Assembly, ABAP, MATLAB, LiveCode, Apex) — the same reason GitGalaxy exists
for them in the first place.