@kernlang/python 3.5.6 → 3.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/adapters/django.d.ts +49 -0
  2. package/dist/adapters/django.js +151 -0
  3. package/dist/adapters/django.js.map +1 -0
  4. package/dist/adapters/fastapi.d.ts +43 -0
  5. package/dist/adapters/fastapi.js +139 -0
  6. package/dist/adapters/fastapi.js.map +1 -0
  7. package/dist/codegen-body-python.d.ts +17 -5
  8. package/dist/codegen-body-python.js +83 -67
  9. package/dist/codegen-body-python.js.map +1 -1
  10. package/dist/core/expr/helpers.d.ts +5 -0
  11. package/dist/core/expr/helpers.js +62 -0
  12. package/dist/core/expr/helpers.js.map +1 -0
  13. package/dist/core/expr/index.d.ts +9 -0
  14. package/dist/core/expr/index.js +2046 -0
  15. package/dist/core/expr/index.js.map +1 -0
  16. package/dist/core/handlers/index.d.ts +74 -0
  17. package/dist/core/handlers/index.js +462 -0
  18. package/dist/core/handlers/index.js.map +1 -0
  19. package/dist/fastapi-portable.js +3 -2
  20. package/dist/fastapi-portable.js.map +1 -1
  21. package/dist/fastapi-response.d.ts +0 -6
  22. package/dist/fastapi-response.js +2 -2217
  23. package/dist/fastapi-response.js.map +1 -1
  24. package/dist/fastapi-route.js +24 -3
  25. package/dist/fastapi-route.js.map +1 -1
  26. package/dist/fastapi-utils.d.ts +2 -1
  27. package/dist/fastapi-utils.js +2 -58
  28. package/dist/fastapi-utils.js.map +1 -1
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.js +2 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/ir-semantics/python-leg.js +5 -0
  33. package/dist/ir-semantics/python-leg.js.map +1 -1
  34. package/dist/targets/python.d.ts +27 -0
  35. package/dist/targets/python.js +130 -4
  36. package/dist/targets/python.js.map +1 -1
  37. package/package.json +2 -2
@@ -2,6 +2,102 @@ import { countTokens, serializeIR } from '@kernlang/core';
2
2
  import { emitImports } from '../core/emit-imports.js';
3
3
  import { emitModels } from '../core/emit-models.js';
4
4
  import { collectFenceDiagnostics } from '../core/fence-diagnostics.js';
5
+ import { emitPureHandlers } from '../core/handlers/index.js';
6
+ import { findServerNode } from '../fastapi-utils.js';
7
+ /**
8
+ * The PyDotDict / _DotList shim, emitted at the top of every `--emit=backend`
9
+ * Python module that contains pure handlers. Re-exported so the conformance
10
+ * harness can import the SAME bytes instead of maintaining a near-duplicate
11
+ * string (Wave 3 round-3 agon-review finding D — kimi 0.90 / claude 0.50 /
12
+ * zai 0.65 convergence on the drift hazard).
13
+ *
14
+ * Design notes (cumulative across Wave 3 review rounds):
15
+ * • Python name-mangling: an identifier with two leading underscores
16
+ * INSIDE a class body becomes `_ClassName__name`. So `__DotDict(val)`
17
+ * inside `__DotDict`'s own methods would resolve to `_DotDict__DotDict`
18
+ * (NameError). Route dict recursion through `cls = type(self); cls(val)`,
19
+ * and use `_DotList` (single underscore — NOT mangled) as the list
20
+ * idempotency marker.
21
+ * • Cached write-back (`self[key] = val`) makes both branches O(1) on
22
+ * re-access and persists in-handler writes — `body.profile.name = "x"`
23
+ * now sticks. SIDE EFFECT: a dotted read mutates the parent dict; raw
24
+ * `body.items()` iteration sees wrapped values. Intentional.
25
+ * • `_DotList.__getitem__` auto-wraps elements so post-access append/insert
26
+ * of plain dicts still reads back as `__DotDict` — `body.rows.append({a:1});
27
+ * body.rows[0].a` works (round-3 codex 0.86 + agy 0.95 regression close).
28
+ * Bound at module level so the `__DotDict` reference inside it isn't
29
+ * subject to class-body name-mangling.
30
+ * • `__delattr__` mirrors `__getattr__`'s camelCase fallback; the
31
+ * `from None` suppresses chained KeyError tracebacks (round-3 claude 0.70).
32
+ */
33
+ export const DOT_DICT_SHIM_PY = `class _DotList(list):
34
+ pass
35
+
36
+
37
+ class __DotDict(dict):
38
+ def __getattr__(self, name):
39
+ try:
40
+ val = self[name]
41
+ key = name
42
+ except KeyError:
43
+ camel = ''.join(x.capitalize() or '_' for x in name.split('_'))
44
+ camel = camel[0].lower() + camel[1:] if camel else ''
45
+ if camel in self:
46
+ val = self[camel]
47
+ key = camel
48
+ else:
49
+ raise AttributeError(name) from None
50
+ cls = type(self)
51
+ def _wrap(x):
52
+ if isinstance(x, cls):
53
+ return x
54
+ if isinstance(x, _DotList):
55
+ return x
56
+ if isinstance(x, dict):
57
+ return cls(x)
58
+ if isinstance(x, list):
59
+ return _DotList([_wrap(y) for y in x])
60
+ return x
61
+ if isinstance(val, dict) and not isinstance(val, cls):
62
+ val = cls(val)
63
+ self[key] = val
64
+ elif isinstance(val, list) and not isinstance(val, _DotList):
65
+ val = _DotList([_wrap(x) for x in val])
66
+ self[key] = val
67
+ return val
68
+
69
+ def __setattr__(self, name, value):
70
+ self[name] = value
71
+
72
+ def __delattr__(self, name):
73
+ try:
74
+ del self[name]
75
+ except KeyError:
76
+ camel = ''.join(x.capitalize() or '_' for x in name.split('_'))
77
+ camel = camel[0].lower() + camel[1:] if camel else ''
78
+ if camel in self:
79
+ del self[camel]
80
+ else:
81
+ raise AttributeError(name) from None
82
+
83
+
84
+ def _dotlist_getitem(self, index):
85
+ val = list.__getitem__(self, index)
86
+ if isinstance(val, (__DotDict, _DotList)):
87
+ return val
88
+ if isinstance(val, dict):
89
+ wrapped = __DotDict(val)
90
+ list.__setitem__(self, index, wrapped)
91
+ return wrapped
92
+ if isinstance(val, list):
93
+ wrapped = _DotList(val)
94
+ list.__setitem__(self, index, wrapped)
95
+ return wrapped
96
+ return val
97
+
98
+
99
+ _DotList.__getitem__ = _dotlist_getitem
100
+ `;
5
101
  /**
6
102
  * First-class `python` transpiler target. Lowering KERN types and models to pure Python.
7
103
  */
@@ -10,15 +106,40 @@ export function transpilePython(root, config) {
10
106
  const emit = config?.emit || 'models'; // In Phase 1, target python implies models-only
11
107
  // 1. Demand-driven imports
12
108
  const { lines: preambleLines, imports } = emitImports(root, { pythonModelBackend });
13
- // 2. Core node render
14
- const { code: modelsCode, bodies } = emitModels(root, {
109
+ // 2. Pure route handlers — emit only when caller requested `emit: 'backend'`.
110
+ // The existing models-only path (the default) must stay byte-identical whether
111
+ // a server node is present or not; `python-target.test.ts:60` (`route
112
+ // invariance (decl-driven emit-models)`) is the canonical contract.
113
+ const serverNode = emit === 'backend' ? findServerNode(root) : undefined;
114
+ let handlersCode = '';
115
+ if (serverNode) {
116
+ const handlers = emitPureHandlers(serverNode, imports, root);
117
+ if (handlers.length > 0) {
118
+ const handlerBlocks = handlers.map((h) => `${h.signature}\n${h.bodyLines.join('\n')}`).join('\n\n');
119
+ handlersCode = `\n${DOT_DICT_SHIM_PY}\n\n${handlerBlocks}\n`;
120
+ }
121
+ }
122
+ // 3. Core node render
123
+ const { code: modelsCode } = emitModels(root, {
15
124
  pythonModelBackend,
16
125
  emit,
17
126
  target: 'python',
18
127
  });
19
128
  const lines = [];
20
129
  // Sort and print imports
21
- for (const imp of [...imports].sort()) {
130
+ let filteredImports = [...imports];
131
+ if (emit === 'backend') {
132
+ filteredImports = filteredImports.filter((imp) => {
133
+ const lower = imp.toLowerCase();
134
+ return (!lower.includes('pydantic') &&
135
+ !lower.includes('fastapi') &&
136
+ !lower.includes('django') &&
137
+ !lower.includes('httpexception') &&
138
+ !lower.includes('jsonresponse') &&
139
+ !lower.includes('depends('));
140
+ });
141
+ }
142
+ for (const imp of filteredImports.sort()) {
22
143
  lines.push(imp);
23
144
  }
24
145
  lines.push('');
@@ -28,10 +149,15 @@ export function transpilePython(root, config) {
28
149
  lines.push(...preambleLines);
29
150
  }
30
151
  // Model and type definitions
31
- if (modelsCode.trim().length > 0) {
152
+ if (emit !== 'backend' && modelsCode.trim().length > 0) {
32
153
  lines.push('');
33
154
  lines.push(modelsCode);
34
155
  }
156
+ // Pure handlers (additive)
157
+ if (handlersCode) {
158
+ lines.push('');
159
+ lines.push(handlersCode);
160
+ }
35
161
  const output = lines.join('\n');
36
162
  const irText = serializeIR(root);
37
163
  const irTokenCount = countTokens(irText);
@@ -1 +1 @@
1
- {"version":3,"file":"python.js","sourceRoot":"","sources":["../../src/targets/python.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,MAA2B;IACvE,MAAM,kBAAkB,GAAG,MAAM,EAAE,kBAAkB,IAAI,MAAM,CAAC;IAChE,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,QAAQ,CAAC,CAAC,gDAAgD;IAEvF,2BAA2B;IAC3B,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC,IAAI,EAAE,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAEpF,sBAAsB;IACtB,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE;QACpD,kBAAkB;QAClB,IAAI;QACJ,MAAM,EAAE,QAAQ;KACjB,CAAC,CAAC;IAEH,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,yBAAyB;IACzB,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,kBAAkB;IAClB,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;IAC/B,CAAC;IAED,6BAA6B;IAC7B,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,YAAY,GAAG,YAAY,CAAC,GAAG,GAAG,CAAC,CAAC;IAE3E,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,EAAE;QACb,YAAY;QACZ,YAAY;QACZ,cAAc;QACd,SAAS,EAAE,EAAE;QACb,WAAW,EAAE,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,mBAAmB,IAAI,SAAS,CAAC;KACrF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"python.js","sourceRoot":"","sources":["../../src/targets/python.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kernlang/python",
3
- "version": "3.5.6",
3
+ "version": "3.5.7",
4
4
  "description": "KERN Python backend codegen (FastAPI router target included)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,7 +28,7 @@
28
28
  "python": ">=3.8"
29
29
  },
30
30
  "dependencies": {
31
- "@kernlang/core": "3.5.6"
31
+ "@kernlang/core": "3.5.7"
32
32
  },
33
33
  "scripts": {
34
34
  "build": "tsc -b",