mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
fix(python): give the alternative-branch shadow a valid reason
A namespace fact stream is checked by cbm_py_namespace_facts_valid, which accepts a shadow only for the value, decorated, unproven-class and unsupported reasons. The withdrawn TYPE_CHECKING re-export carried the compound reason, so the whole stream was rejected and the package published no names at all (a lazy-module package lost its TYPE_CHECKING exports). It now carries the unsupported reason: the builder cannot tell which source the name has at runtime. python_namespace_facts_type_checking_alternatives pins both shapes as complete, valid streams. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
1 parent
eb9594d35c
commit
7c3f50605b
2 files changed
+41
-5
No files matched your search
@@ -757,10 +757,10 @@ static bool py_ns_is_type_checking_if(PyNamespaceBuilder *b, TSNode node) {
|
||||
* at runtime from wherever that branch says (the compat shape: `else: try:
|
||||
* from runtime.place import name`). A static reader cannot tell which source
|
||||
* the module ends up exporting, so every name such an import binds becomes a
|
||||
* SHADOW (the re-export is withdrawn, as for a later assignment); a star
|
||||
* import, or an import form the builder does not read, may bind any name, so
|
||||
* the whole namespace becomes unknown. An iterative walk of the branch: deep
|
||||
* nesting must not exhaust the stack. */
|
||||
* SHADOW (reason UNSUPPORTED: the re-export is withdrawn, as for a later
|
||||
* assignment); a star import, or an import form the builder does not read,
|
||||
* may bind any name, so the whole namespace becomes unknown. An iterative
|
||||
* walk of the branch: deep nesting must not exhaust the stack. */
|
||||
static bool py_ns_alternative_imports(PyNamespaceBuilder *b, TSNode root) {
|
||||
TSTreeCursor cursor = ts_tree_cursor_new(root);
|
||||
bool done = false;
|
||||
@@ -776,7 +776,7 @@ static bool py_ns_alternative_imports(PyNamespaceBuilder *b, TSNode root) {
|
||||
star = b->facts.items[i].kind == CBM_PY_NS_IMPORT_STAR;
|
||||
b->facts.items[i] = (CBMPyNamespaceFact){.kind = CBM_PY_NS_SHADOW,
|
||||
.local_name = b->facts.items[i].local_name,
|
||||
.reason = CBM_PY_NS_REASON_COMPOUND};
|
||||
.reason = CBM_PY_NS_REASON_UNSUPPORTED};
|
||||
}
|
||||
if (star && !b->failure) {
|
||||
b->facts.count = start;
|
||||
|
||||
@@ -12108,6 +12108,41 @@ TEST(python_namespace_facts_preserve_order_and_import_provenance) {
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* The type checker view of `if TYPE_CHECKING:` publishes its consequence (a
|
||||
* lazy-module package: the else branch only installs the module). A name an
|
||||
* elif/else import binds again is withdrawn by a SHADOW: its runtime source is
|
||||
* the alternative. Both streams stay COMPLETE and valid. */
|
||||
TEST(python_namespace_facts_type_checking_alternatives) {
|
||||
CBMFileResult *lazy = extract("from typing import TYPE_CHECKING\n"
|
||||
"if TYPE_CHECKING:\n from .lazy_mod import Lazy\n"
|
||||
"else:\n import sys\n",
|
||||
CBM_LANG_PYTHON, "t", "lz/__init__.py");
|
||||
CBMFileResult *compat = extract("from typing import TYPE_CHECKING\n"
|
||||
"if TYPE_CHECKING:\n from .types_only import Shim\n"
|
||||
"else:\n try:\n from .runtime_impl import Shim\n"
|
||||
" except ImportError:\n Shim = None\n",
|
||||
CBM_LANG_PYTHON, "t", "cmp/__init__.py");
|
||||
bool ok = lazy && compat && lazy->py_namespace.status == CBM_PY_NS_COMPLETE &&
|
||||
compat->py_namespace.status == CBM_PY_NS_COMPLETE &&
|
||||
cbm_py_namespace_facts_valid(&lazy->py_namespace) &&
|
||||
cbm_py_namespace_facts_valid(&compat->py_namespace) &&
|
||||
lazy->py_namespace.count == 3 && compat->py_namespace.count == 3;
|
||||
if (ok) {
|
||||
const CBMPyNamespaceFact *l = lazy->py_namespace.items;
|
||||
const CBMPyNamespaceFact *c = compat->py_namespace.items;
|
||||
ok = l[1].kind == CBM_PY_NS_IMPORT_NAME && strcmp(l[1].local_name, "Lazy") == 0 &&
|
||||
l[2].kind == CBM_PY_NS_SHADOW && strcmp(l[2].local_name, "sys") == 0 &&
|
||||
c[1].kind == CBM_PY_NS_IMPORT_NAME && strcmp(c[1].local_name, "Shim") == 0 &&
|
||||
c[2].kind == CBM_PY_NS_SHADOW && strcmp(c[2].local_name, "Shim") == 0;
|
||||
}
|
||||
if (lazy)
|
||||
cbm_free_result(lazy);
|
||||
if (compat)
|
||||
cbm_free_result(compat);
|
||||
ASSERT_TRUE(ok);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(python_namespace_facts_distinguish_all_operations_and_unknowns) {
|
||||
static const char source[] = "__all__ = ['old']; __all__ = []\n"
|
||||
"__all__ = dynamic\n"
|
||||
@@ -12494,6 +12529,7 @@ SUITE(extraction) {
|
||||
RUN_TEST(python_namespace_facts_distinguish_all_operations_and_unknowns);
|
||||
RUN_TEST(python_namespace_facts_unknown_effects_and_body_stability);
|
||||
RUN_TEST(python_namespace_facts_parse_errors_are_complete_unknown);
|
||||
RUN_TEST(python_namespace_facts_type_checking_alternatives);
|
||||
RUN_TEST(python_namespace_facts_capture_and_copy_fail_atomically);
|
||||
RUN_TEST(python_namespace_facts_validation_rejects_partial_and_unknown_schema);
|
||||
RUN_TEST(python_namespace_facts_compact_spill_and_copy_keep_owned_payload);
|
||||
|
||||
Reference in new issue
Block a user