oct
Loading...
Searching...
No Matches
venv_sitecustomize.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# oct/tools/venv_sitecustomize.py
4
5"""
6Purpose
7-------
8Pointer stub. Plan 270 P1 moved the real venv repair file to
9`oc_diagnostics/oc_diagnostics/venv_sitecustomize.py` - the package it
10repairs - so the dispatcher layer needs no toolchain to build a usable
11venv. This module keeps oct's historical path alive by naming where the
12file now lives; it is NEVER the file that gets copied.
13
14The repair itself is unchanged: `python -m <anything>` run from the
15monorepo root fails with `cannot import name '_dbg' from
16'oc_diagnostics'`, because Python finds the bare subproject FOLDER
17(`oc_diagnostics\\`, `oct\\`, `oc_chat\\`) on the working directory before
18the editable-installed package. The moved finder makes the installed
19package win over a bare folder, while a real checkout (a worktree's
20package WITH `__init__.py`) still wins over the install.
21
22Install: copy :data:`SOURCE` - not this file - to
23`.venv\\Lib\\site-packages\\sitecustomize.py`. Re-copy after any venv
24rebuild. It is COPIED out, never imported as part of the oct package,
25and it must stay stdlib-pure: any package import here would pre-load
26that package into EVERY interpreter, which breaks fresh-import leaf
27guards (the oc_pricing t1 guard caught exactly that). That is why the
28location is resolved through `importlib.util.find_spec`, which reads
29the spec without importing anything (operator ruling 2026-09-15).
30
31Responsibilities
32----------------
33- :data:`SOURCE` - the real repair file inside the resolvable
34 `oc_diagnostics`, or `None` when no such copy exists.
35
36Diagnostics
37-----------
38Domain: OCT-CORE
39Levels:
40 L2 - reserved (path resolution only; this module must emit nothing)
41 L3 - reserved
42 L4 - reserved
43
44Contracts
45---------
46- stdlib-only, and it never imports `oc_diagnostics`: a spec lookup is
47 all a path resolution needs, and importing the package here would put
48 it in every interpreter that touches this module.
49- Resolves a path and nothing else: no finder is installed, no
50 `sys.meta_path` entry is added, nothing is read and nothing is
51 written.
52- Never raises. `SOURCE` is `None` when `oc_diagnostics` cannot be
53 located or predates the move; callers check before copying.
54"""
55
56# OCT-LINT: disable-file=dbg_import reason="Plan 263: stdlib-only by contract - any package import here pre-loads that package into EVERY interpreter using the venv, which breaks fresh-import leaf guards"
57# OCT-LINT: disable-file=dbg_usage reason="Plan 263: this runs inside the import machinery and is copied out to site-packages, so it can emit nothing"
58
59from __future__ import annotations
60
61import importlib.util
62from pathlib import Path
63
64#: The package whose copy of the repair file this stub points at.
65REPAIR_PACKAGE = "oc_diagnostics"
66
67#: The file's name inside that package.
68REPAIR_FILENAME = "venv_sitecustomize.py"
69
70
71def _locate() -> Path | None:
72 """Find the repair file without importing the package that ships it.
73
74 ``find_spec`` reads the spec a finder would produce and stops there,
75 so nothing is executed and nothing lands in ``sys.modules``.
76 ``submodule_search_locations`` is the package's own directory list,
77 which answers for a regular package and for a namespace package
78 alike - and the namespace case is exactly the broken venv this file
79 exists to repair, so it must not be the case that crashes.
80 """
81 try:
82 spec = importlib.util.find_spec(REPAIR_PACKAGE)
83 except (ImportError, ValueError): # pragma: no cover - defensive
84 return None
85 if spec is None:
86 return None
87 for location in list(spec.submodule_search_locations or ()):
88 candidate = Path(location) / REPAIR_FILENAME
89 if candidate.is_file():
90 return candidate
91 return None
92
93
94#: The real repair file, inside the package it repairs (plan 270 P1).
95SOURCE: Path | None = _locate()
96
97__all__ = ["REPAIR_FILENAME", "REPAIR_PACKAGE", "SOURCE"]