{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "stack": "python",
  "description": "Python code-graph rules. Adds what the graph needs on top of test-gap-rules/python.json, which already owns sourceExtensions, excludePathGlobs and the test-path predicates. Definition patterns here are deliberately broader than the test-gap publicApiPatterns: the graph wants private declarations too, because Phase 1 narrows scope on the whole package, not just its public surface.",
  "comments": {
    "line": ["#"],
    "block": [],
    "string": ["\"\"\"", "'''", "\"", "'"]
  },
  "definitionPatterns": [
    {
      "id": "class",
      "kind": "class",
      "regex": "\\bclass\\s+([A-Za-z_][A-Za-z0-9_]*)"
    },
    {
      "id": "def",
      "kind": "def",
      "regex": "\\bdef\\s+([A-Za-z_][A-Za-z0-9_]*)"
    }
  ],
  "importPatterns": [
    {
      "id": "from-import",
      "regex": "^\\s*from\\s+[.\\w]*?([A-Za-z_][A-Za-z0-9_]*)\\s+import\\b"
    },
    {
      "id": "import",
      "regex": "^\\s*import\\s+(?:[A-Za-z_][A-Za-z0-9_]*\\.)*([A-Za-z_][A-Za-z0-9_]*)"
    }
  ],
  "referenceKinds": ["class"],
  "referenceKindsNote": "def is deliberately absent, for the reason Swift's rules record for func and the node rules record with measurements: a bare lowercase name matched across files is almost never a call to that exact declaration, and Python's convention of short module-level helpers (main, run, load, parse, setup) makes it worse than most. Functions still reach the graph through their defines edge, so they stay findable by name.",
  "ignoredIdentifiers": [
    "self",
    "cls",
    "class",
    "def",
    "return",
    "import",
    "from",
    "as",
    "in",
    "is",
    "not",
    "and",
    "or",
    "if",
    "elif",
    "else",
    "for",
    "while",
    "break",
    "continue",
    "pass",
    "try",
    "except",
    "finally",
    "raise",
    "with",
    "yield",
    "lambda",
    "global",
    "nonlocal",
    "assert",
    "del",
    "async",
    "await",
    "None",
    "True",
    "False",
    "print",
    "len",
    "str",
    "int",
    "float",
    "bool",
    "list",
    "dict",
    "set",
    "tuple",
    "type",
    "range",
    "open",
    "super",
    "property",
    "staticmethod",
    "classmethod"
  ],
  "note": "There is no block-comment token: a Python triple-quoted docstring is a string literal, and it is listed under `string` so the stripper removes it the same way it removes any other string. Longest tokens come first there, so \"\"\" and ''' are consumed whole before the single-quote forms get a chance to match their first character. Both import patterns capture the LAST dotted segment, which is what the engine resolves against a file basename: `from package.module import Thing` points at module.py, and `import package.module` does the same. `from . import x` and `from .. import x` capture nothing, deliberately - a bare relative package names a directory, and pointing it at an arbitrary file inside would invent an edge nobody wrote."
}
