Skip to content

Commit e1d3171

Browse files
committed
fix(codegen): escape Python keyword property names in models
@seamapi/types 1.963.0 adds a "from" property to SeamEvent. "from" is a Python hard keyword, so the generated dataclass field and from_dict keyword argument produced invalid Python and `make format` failed during the Generate code job. Sanitize property names that collide with Python hard keywords by suffixing the identifier with an underscore (e.g. `from` -> `from_`) while preserving the original name as the dict key in from_dict. No existing property name is a hard keyword, so all other generated output is unchanged. Regenerate models and routes against @seamapi/types 1.963.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SZXq8XXHtqU379agmLxk5u
1 parent 7f0159c commit e1d3171

6 files changed

Lines changed: 87 additions & 5 deletions

File tree

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
@dataclass
22
class {{className}}:
33
{{#each properties}}
4-
{{name}}: {{type}}
4+
{{safeName}}: {{type}}
55
{{/each}}
66

77
@staticmethod
88
def from_dict(d: Dict[str, Any]):
99
return {{className}}(
1010
{{#each properties}}
11-
{{name}}={{#if isDictParam}}DeepAttrDict({{/if}}d.get("{{name}}", None){{#if isDictParam}}){{/if}},
11+
{{safeName}}={{#if isDictParam}}DeepAttrDict({{/if}}d.get("{{name}}", None){{#if isDictParam}}){{/if}},
1212
{{/each}}
1313
)

codegen/lib/layouts/models.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,61 @@ import { flattenObjSchema } from '../openapi/flatten-obj-schema.js'
1111
import type { ObjSchema, OpenapiSchema } from '../openapi/types.js'
1212
import { getMethodLayoutContext } from './route.js'
1313

14+
// Python hard keywords cannot be used as identifiers. When a property name
15+
// collides with one (e.g. "from"), the dataclass field and keyword argument
16+
// are suffixed with an underscore while the original name is preserved as the
17+
// dict key. No existing property name is a hard keyword, so this leaves all
18+
// other generated output unchanged.
19+
const PYTHON_KEYWORDS = new Set([
20+
'False',
21+
'None',
22+
'True',
23+
'and',
24+
'as',
25+
'assert',
26+
'async',
27+
'await',
28+
'break',
29+
'class',
30+
'continue',
31+
'def',
32+
'del',
33+
'elif',
34+
'else',
35+
'except',
36+
'finally',
37+
'for',
38+
'from',
39+
'global',
40+
'if',
41+
'import',
42+
'in',
43+
'is',
44+
'lambda',
45+
'nonlocal',
46+
'not',
47+
'or',
48+
'pass',
49+
'raise',
50+
'return',
51+
'try',
52+
'while',
53+
'with',
54+
'yield',
55+
])
56+
57+
const toSafeIdentifier = (name: string): string =>
58+
PYTHON_KEYWORDS.has(name) ? `${name}_` : name
59+
1460
export interface ModelsLayoutContext {
1561
resources: Array<{
1662
className: string
17-
properties: Array<{ name: string; type: string; isDictParam: boolean }>
63+
properties: Array<{
64+
name: string
65+
safeName: string
66+
type: string
67+
isDictParam: boolean
68+
}>
1869
}>
1970
abstractClasses: Array<{
2071
className: string
@@ -55,6 +106,7 @@ export const setModelsLayoutContext = (
55106
const type = mapPythonType(propertySchema)
56107
return {
57108
name,
109+
safeName: toSafeIdentifier(name),
58110
type,
59111
isDictParam: type.startsWith('Dict') || name === 'properties',
60112
}

seam/routes/access_codes.py

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

seam/routes/access_grants.py

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

seam/routes/devices.py

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

seam/routes/models.py

Lines changed: 20 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)