|
Option C Tools
|
Classes | |
| class | LinterContext |
Functions | |
| bool | _strict_config_requested () |
| list[str] | _validate_octrc_schema (dict cfg) |
| None | log (str message, LinterContext|None ctx=None) |
| None | print_header (str title, LinterContext|None ctx=None) |
| bool | report (bool result, str message, bool fix_mode=False, LinterContext|None ctx=None) |
| bool | is_excluded_dir (Path path, set exclude_dirs, list wildcard_exclude_dirs) |
| str | read_file (Path path, LinterContext|None ctx=None) |
| list[Path] | _git_changed_files (Path root) |
| find_python_files (Path root, set|None exclude_dirs=None, list|None wildcard_exclude_dirs=None) | |
| str | expected_path_header (Path path, LinterContext ctx) |
| validate_header_block (list[str] lines, Path path, LinterContext ctx) | |
| int | _header_boundary (list[str] lines, Path path, LinterContext ctx) |
| bool | fix_header_block (Path path, str text, LinterContext ctx) |
| str | preview_header_fix (Path path, LinterContext ctx) |
| check_docstring (str text) | |
| check_dependencies_section (str text) | |
| str|None | _extract_module_docstring (str text) |
| check_diagnostics_profile (str text) | |
| check_dbg_usage (str text, ast.Module|None tree=None) | |
| check_dbg_import (str text, ast.Module|None tree=None) | |
| _walk_function_body (ast.FunctionDef|ast.AsyncFunctionDef func_node) | |
| _direct_body_nodes (func_node) | |
| list[tuple[str, int]] | find_func_pattern_violations (str text, ast.Module|None tree=None) |
| check_func_pattern (str text, ast.Module|None tree=None) | |
| check_syntax_warnings (str text, list[str]|None warnings_list=None) | |
| check_type_hints (str text, ast.Module|None tree=None, bool compact_mode=False) | |
| bool | _is_security_sensitive_name (str name) |
| tuple[bool, str] | check_dbg_assert_safety (str text, ast.Module|None tree=None, str filename="") |
| dict[str, set[str]] | build_test_index (LinterContext ctx) |
| check_tests_exist (Path module_path, LinterContext ctx) | |
| None | _rotate_lint_logs (Path log_dir, int max_files=_MAX_LINT_LOG_FILES) |
| dict | _lint_single_file (Path path, LinterContext ctx, dict active_rules, bool fix_mode, bool dry_run=False) |
| int | run_linter (Path project_root, list[str]|None argv=None) |
| None | main () |
Variables | |
| _OCT_PACKAGE_DIR = Path(__file__).resolve().parent.parent | |
| dict | _DEFAULT_RULES |
| dict | _PROFILES |
| str | SHEBANG = "#!/usr/bin/env python3" |
| str | ENCODING = "# -*- coding: utf-8 -*-" |
| _DEP_SECTION_RE | |
| _DEP_LINE_RE = re.compile(r'^\s*-\s+\S+\s*\([^)]+\)\s*$', re.MULTILINE) | |
| _DEP_BULLET_RE = re.compile(r'^\s*[-*]\s+\S', re.MULTILINE) | |
| _SECURITY_SENSITIVE_KEYWORDS | |
| _IMPORT_STMT_RE | |
Purpose
-------
Provide a strict, deterministic linter for Option C projects that validates
mandatory header blocks, module docstrings, diagnostics profiles, and basic
testing presence, and can optionally auto-fix header blocks.
Responsibilities
----------------
- Walk the project tree from a given Option C project root or directory or single file given as an argument.
- Skip excluded directories and the linter's own files.
- Validate the 4-line mandatory header block for every Python module.
- Validate the presence and structure of the module docstring.
- Validate the presence of a Diagnostics profile block (Domain + L2/L3/L4).
- Validate basic ``_dbg`` usage in non-trivial modules; ``_dbg`` is the
structured debug logger provided by the ``oc_diagnostics`` package
(``from oc_diagnostics import _dbg``).
- Validate the presence of regression tests for each module.
- Optionally auto-fix header blocks while archiving originals.
- Produce a detailed log file and a colorized terminal summary.
- Optionally emit machine-readable JSON to stdout (``--json``).
Diagnostics
-----------
Domain: OCT-LINTER
Levels:
L2 — lifecycle
L3 — semantic details
L4 — deep tracing
Contracts
---------
- Must not modify files unless ``--fix-headers`` is explicitly requested.
- Must treat the provided project root as authoritative for all relative paths.
- Must write a deterministic log file into the project's ``logs/`` directory
when writable; warns and continues if the log directory is unwritable.
- Must not import project modules; analysis is purely static.
- Must be callable both from the OCT CLI and as a standalone module.
Dependencies
------------
- oct.core.exclusions (directory and wildcard exclusion lists)
- oct.core.parsing (safe AST parsing helper)
- oct.core.paths (project-relative path helper)
- oct.core.waivers (inline waiver parsing)
|
protected |
Yield AST nodes that are directly in this function's body (not in nested function bodies). Uses an iterative approach to avoid descending into nested FunctionDef/AsyncFunctionDef.
Definition at line 852 of file oct_lint.py.
|
protected |
Return the text of the first module-level triple-quoted string found before the first ``def`` or ``class`` statement, or ``None`` if absent. Scoping to pre-code text prevents false positives from in-function string literals that happen to contain keywords like 'L2', 'Diagnostics', or 'Domain:'.
Definition at line 747 of file oct_lint.py.
|
protected |
Return .py files modified in the git working tree (staged + unstaged). Phase 4A (G-A7): thin shim over :func:`oct.core.git.git_changed_files`. The core module enforces subprocess discipline, credential redaction, and path-escape filtering; the linter's sole contract here is to preserve the historical "never crash on any git failure" behaviour by collapsing every ``GitError`` back to an empty list.
Definition at line 535 of file oct_lint.py.
|
protected |
Return the line index where file content begins, after any existing header elements. OI-509: thin wrapper that delegates to :func:`oct.core.parsing.header_boundary` so linter and formatter share one implementation.
Definition at line 630 of file oct_lint.py.
|
protected |
|
protected |
Lint one Python file and return a result dict with check outcomes. Thread-safe: logging uses ctx.log_lock internally.
Definition at line 1214 of file oct_lint.py.
|
protected |
Remove old lint log files, keeping only the most recent max_files.
Definition at line 1203 of file oct_lint.py.
|
protected |
Return True when strict-config enforcement is active. Strict mode is opt-in via the ``OCT_STRICT_CONFIG`` environment variable (any truthy value: ``1``, ``true``, ``yes``, ``on``). The ``--strict-config`` CLI flag wired up in ``oct/cli.py`` sets this env var before dispatch.
Definition at line 158 of file oct_lint.py.
|
protected |
Validate the structure of a loaded ``.octrc.json`` dict. Returns a list of human-readable error strings. Empty list means the config is structurally acceptable. Unknown keys are tolerated (forward compat); only known keys are type-checked.
Definition at line 170 of file oct_lint.py.
|
protected |
Yield AST nodes within a function body, stopping at nested function boundaries so that each function gets an independent check.
Definition at line 838 of file oct_lint.py.
| dict[str, set[str]] oct.linter.oct_lint.build_test_index | ( | LinterContext | ctx | ) |
OI-510 / FS-516: one-shot scan of ``ctx.tests_dir`` producing two lookup sets so :func:`check_tests_exist` becomes O(1) per module instead of re-walking the tests tree for every file linted. The index is cached on :attr:`LinterContext.test_index` — subsequent calls return the cached value directly. Returns a dict with: * ``name_stems`` — stems ``<s>`` for which ``test_<s>.py`` exists. * ``imported_stems`` — module stems referenced in any test file by a whole-word ``import`` / ``from`` statement.
Definition at line 1139 of file oct_lint.py.
| tuple[bool, str] oct.linter.oct_lint.check_dbg_assert_safety | ( | str | text, |
| ast.Module | None | tree = None, | ||
| str | filename = "" ) |
Flag ``_dbg_assert`` calls made inside security-sensitive contexts. ``_dbg_assert`` is a diagnostic aid — in production mode it is a no-op. Per AP-16 it must never be used for safety invariants (authentication, authorization, input validation, crypto, etc.). This check walks the AST looking for calls named ``_dbg_assert`` (bare or attribute access) and verifies that none of the enclosing functions, classes, or the module's filename stem contain a security-sensitive keyword.
Definition at line 1064 of file oct_lint.py.
| oct.linter.oct_lint.check_dbg_import | ( | str | text, |
| ast.Module | None | tree = None ) |
Verify that ``_dbg`` is imported from ``oc_diagnostics`` at module level. The canonical import is ``from oc_diagnostics import _dbg``. Files shorter than 20 lines are exempt (same threshold as ``check_dbg_usage``). Aliased imports (``import _dbg as ...``) are not accepted — the Option C spec requires the canonical form.
Definition at line 814 of file oct_lint.py.
| oct.linter.oct_lint.check_dbg_usage | ( | str | text, |
| ast.Module | None | tree = None ) |
Validate that non-trivial modules call ``_dbg()`` for diagnostics. ``_dbg`` is the structured debug logger from ``oc_diagnostics`` (``from oc_diagnostics import _dbg``). Files shorter than 20 lines are considered trivial scaffolding and are exempt from this check. Uses AST parsing to detect actual ``_dbg()`` call nodes, avoiding false positives from comments or string literals.
Definition at line 785 of file oct_lint.py.
| oct.linter.oct_lint.check_dependencies_section | ( | str | text | ) |
Validate the Dependencies section of a module docstring at strict profile. Spec reference: Appendix C — Dependencies docstring format. Each entry must follow ``- module_name (purpose description)`` so ``oct deps`` can parse the dependency graph. Returns ``(ok, msg)``. Empty Dependencies sections are accepted (a module may have no project-internal dependencies); malformed entries are rejected.
Definition at line 715 of file oct_lint.py.
| oct.linter.oct_lint.check_diagnostics_profile | ( | str | text | ) |
Validate that a Diagnostics profile is present in the module docstring. Scopes the search to the module docstring (text before the first ``def``/``class``) to avoid false positives from in-code string literals that happen to contain 'L2', 'L3', 'L4', 'Diagnostics', or 'Domain:'. Falls back to the full file if no module docstring is found.
Definition at line 765 of file oct_lint.py.
| oct.linter.oct_lint.check_docstring | ( | str | text | ) |
Validate that a module docstring exists and contains the required Option C sections.
Definition at line 691 of file oct_lint.py.
| oct.linter.oct_lint.check_func_pattern | ( | str | text, |
| ast.Module | None | tree = None ) |
Validate that every function body containing ``_dbg()`` first defines ``func = "function_name"``. Uses ``ast.parse()`` to build a syntax tree, then walks each function's body (stopping at nested function boundaries) to check for the pattern. Exempt trivial files (< 20 lines) — same threshold as check_dbg_usage. Delegates to :func:`find_func_pattern_violations` for the actual detection; this wrapper converts the result into a ``(bool, message)`` pair for the linter pipeline.
Definition at line 936 of file oct_lint.py.
| oct.linter.oct_lint.check_syntax_warnings | ( | str | text, |
| list[str] | None | warnings_list = None ) |
Check for Python syntax warnings (invalid escape sequences etc.). Python 3.12+ emits ``SyntaxWarning`` for invalid escape sequences in string literals. These will become ``SyntaxError`` in a future Python version, so they should be surfaced as lint findings.
Definition at line 977 of file oct_lint.py.
| oct.linter.oct_lint.check_tests_exist | ( | Path | module_path, |
| LinterContext | ctx ) |
Validate that at least one test file references the module either by naming convention (``test_<module>.py``) or by an explicit import statement (``import <module>`` or ``from <module>``). Two-stage check, now O(1) per call: consults the index built once per :func:`run_linter` invocation by :func:`build_test_index`.
Definition at line 1179 of file oct_lint.py.
| oct.linter.oct_lint.check_type_hints | ( | str | text, |
| ast.Module | None | tree = None, | ||
| bool | compact_mode = False ) |
Validate that public functions have type annotations on all parameters and a return annotation. Private functions (leading underscore) and dunder methods are always exempt — they are internal implementation details (OI-417). The ``compact_mode`` parameter is retained for API compatibility but no longer changes behaviour. Trivial files (< 20 lines) are exempt.
Definition at line 992 of file oct_lint.py.
| str oct.linter.oct_lint.expected_path_header | ( | Path | path, |
| LinterContext | ctx ) |
Compute the expected file identity header for a given module path.
Definition at line 593 of file oct_lint.py.
| list[tuple[str, int]] oct.linter.oct_lint.find_func_pattern_violations | ( | str | text, |
| ast.Module | None | tree = None ) |
Return ``[(func_name, lineno), ...]`` for every function that calls ``_dbg()`` without a prior ``func = "..."`` assignment. Returns an empty list for trivial files (< 20 lines) or files with syntax errors. This is the single source of truth for func-pattern detection — used by :func:`check_func_pattern` (linter pass/fail) and by :func:`oct.formatter.oct_format.fix_func_pattern` (auto-fix).
Definition at line 868 of file oct_lint.py.
| oct.linter.oct_lint.find_python_files | ( | Path | root, |
| set | None | exclude_dirs = None, | ||
| list | None | wildcard_exclude_dirs = None ) |
Yield all Python files under root, excluding the linter itself and
excluded directories.
Parameters
----------
root:
The project root to scan.
exclude_dirs:
Set of directory names to exclude. Defaults to the module-level
``EXCLUDE_DIRS`` constant.
wildcard_exclude_dirs:
List of substrings; directories whose name contains any of these
are excluded. Defaults to ``WILDCARD_EXCLUDE_DIRS``.
Definition at line 551 of file oct_lint.py.
| bool oct.linter.oct_lint.fix_header_block | ( | Path | path, |
| str | text, | ||
| LinterContext | ctx ) |
Rewrite the top of the file to enforce the Option C 4-line header. The original file is archived in a `.linter_archive` directory.
Definition at line 643 of file oct_lint.py.
| bool oct.linter.oct_lint.is_excluded_dir | ( | Path | path, |
| set | exclude_dirs, | ||
| list | wildcard_exclude_dirs ) |
Return True if the directory name should be excluded from scanning.
Definition at line 510 of file oct_lint.py.
| None oct.linter.oct_lint.log | ( | str | message, |
| LinterContext | None | ctx = None ) |
Write a single line to the linter log file. OI-513: ``ctx`` is required in practice — every internal callsite threads it through. The ``None`` branch is kept as a silent no-op so external callers that import ``log()`` standalone do not crash.
Definition at line 468 of file oct_lint.py.
| None oct.linter.oct_lint.main | ( | ) |
Standalone entry point when running this module directly.
Definition at line 2065 of file oct_lint.py.
| str oct.linter.oct_lint.preview_header_fix | ( | Path | path, |
| LinterContext | ctx ) |
Compute what fix_header_block would produce, without writing. Returns the corrected 4-line header block as a string.
Definition at line 672 of file oct_lint.py.
| None oct.linter.oct_lint.print_header | ( | str | title, |
| LinterContext | None | ctx = None ) |
Write a section header to the log.
Definition at line 482 of file oct_lint.py.
| str oct.linter.oct_lint.read_file | ( | Path | path, |
| LinterContext | None | ctx = None ) |
Read a file as UTF-8, returning an empty string on failure.
Definition at line 523 of file oct_lint.py.
| bool oct.linter.oct_lint.report | ( | bool | result, |
| str | message, | ||
| bool | fix_mode = False, | ||
| LinterContext | None | ctx = None ) |
Log a PASS/FAIL (or FIXED) line and return the result.
Definition at line 492 of file oct_lint.py.
| int oct.linter.oct_lint.run_linter | ( | Path | project_root, |
| list[str] | None | argv = None ) |
Run the Option C linter on the given project root.
Parameters
----------
project_root:
The detected Option C project root directory.
argv:
Optional list of command-line arguments (e.g. ["--fix-headers"]).
If None, ``argparse`` will use ``sys.argv``.
Returns
-------
int
Exit code: 0 if all checks passed, 1 if any failures detected.
Definition at line 1530 of file oct_lint.py.
| oct.linter.oct_lint.validate_header_block | ( | list[str] | lines, |
| Path | path, | ||
| LinterContext | ctx ) |
Validate the mandatory 4-line header block. Returns (ok, errors) where: - ok = True if header block is correct - errors = list of error messages
Definition at line 601 of file oct_lint.py.
|
protected |
Definition at line 91 of file oct_lint.py.
|
protected |
Definition at line 712 of file oct_lint.py.
|
protected |
Definition at line 711 of file oct_lint.py.
|
protected |
Definition at line 707 of file oct_lint.py.
|
protected |
Definition at line 1133 of file oct_lint.py.
|
protected |
Definition at line 75 of file oct_lint.py.
|
protected |
Definition at line 105 of file oct_lint.py.
|
protected |
Definition at line 1052 of file oct_lint.py.
| str oct.linter.oct_lint.ENCODING = "# -*- coding: utf-8 -*-" |
Definition at line 412 of file oct_lint.py.
| str oct.linter.oct_lint.SHEBANG = "#!/usr/bin/env python3" |
Definition at line 411 of file oct_lint.py.