@alloy-js/python 0.5.0-dev.0 → 0.5.0-dev.2
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.
- package/dist/dev/src/builtins/python.js +46 -0
- package/dist/dev/src/builtins/python.js.map +1 -1
- package/dist/dev/src/components/ClassDeclaration.js +19 -10
- package/dist/dev/src/components/ClassDeclaration.js.map +1 -1
- package/dist/dev/src/components/ClassMethodDeclaration.js +20 -5
- package/dist/dev/src/components/ClassMethodDeclaration.js.map +1 -1
- package/dist/dev/src/components/DataclassDeclaration.js +14 -12
- package/dist/dev/src/components/DataclassDeclaration.js.map +1 -1
- package/dist/dev/src/components/DecoratorList.js +55 -0
- package/dist/dev/src/components/DecoratorList.js.map +1 -0
- package/dist/dev/src/components/EnumDeclaration.js +21 -12
- package/dist/dev/src/components/EnumDeclaration.js.map +1 -1
- package/dist/dev/src/components/FunctionBase.js +21 -10
- package/dist/dev/src/components/FunctionBase.js.map +1 -1
- package/dist/dev/src/components/FutureStatement.js +1 -1
- package/dist/dev/src/components/MethodBase.js +16 -4
- package/dist/dev/src/components/MethodBase.js.map +1 -1
- package/dist/dev/src/components/PropertyDeclaration.js +68 -17
- package/dist/dev/src/components/PropertyDeclaration.js.map +1 -1
- package/dist/dev/src/components/PydanticClassDeclaration.js +136 -0
- package/dist/dev/src/components/PydanticClassDeclaration.js.map +1 -0
- package/dist/dev/src/components/SourceFile.js +44 -32
- package/dist/dev/src/components/SourceFile.js.map +1 -1
- package/dist/dev/src/components/StaticMethodDeclaration.js +19 -5
- package/dist/dev/src/components/StaticMethodDeclaration.js.map +1 -1
- package/dist/dev/src/components/index.js +1 -0
- package/dist/dev/src/components/index.js.map +1 -1
- package/dist/dev/test/callsignatures.test.js +471 -297
- package/dist/dev/test/callsignatures.test.js.map +1 -1
- package/dist/dev/test/class-method-declaration.test.js +21 -10
- package/dist/dev/test/class-method-declaration.test.js.map +1 -1
- package/dist/dev/test/classdeclarations.test.js +480 -381
- package/dist/dev/test/classdeclarations.test.js.map +1 -1
- package/dist/dev/test/classinstantiations.test.js +201 -168
- package/dist/dev/test/classinstantiations.test.js.map +1 -1
- package/dist/dev/test/constructordeclaration.test.js +22 -11
- package/dist/dev/test/constructordeclaration.test.js.map +1 -1
- package/dist/dev/test/dataclassdeclarations.test.js +345 -358
- package/dist/dev/test/dataclassdeclarations.test.js.map +1 -1
- package/dist/dev/test/decoratorlist.test.js +131 -0
- package/dist/dev/test/decoratorlist.test.js.map +1 -0
- package/dist/dev/test/dundermethoddeclaration.test.js +22 -11
- package/dist/dev/test/dundermethoddeclaration.test.js.map +1 -1
- package/dist/dev/test/enums.test.js +231 -166
- package/dist/dev/test/enums.test.js.map +1 -1
- package/dist/dev/test/externals.test.js +57 -45
- package/dist/dev/test/externals.test.js.map +1 -1
- package/dist/dev/test/factories.test.js +124 -50
- package/dist/dev/test/factories.test.js.map +1 -1
- package/dist/dev/test/functioncallexpressions.test.js +199 -164
- package/dist/dev/test/functioncallexpressions.test.js.map +1 -1
- package/dist/dev/test/functiondeclaration.test.js +452 -265
- package/dist/dev/test/functiondeclaration.test.js.map +1 -1
- package/dist/dev/test/imports.test.js +273 -221
- package/dist/dev/test/imports.test.js.map +1 -1
- package/dist/dev/test/memberexpressions.test.js +1237 -972
- package/dist/dev/test/memberexpressions.test.js.map +1 -1
- package/dist/dev/test/methoddeclaration.test.js +200 -45
- package/dist/dev/test/methoddeclaration.test.js.map +1 -1
- package/dist/dev/test/namepolicies.test.js +130 -94
- package/dist/dev/test/namepolicies.test.js.map +1 -1
- package/dist/dev/test/propertydeclaration.test.js +177 -46
- package/dist/dev/test/propertydeclaration.test.js.map +1 -1
- package/dist/dev/test/pydanticclassdeclarations.test.js +1089 -0
- package/dist/dev/test/pydanticclassdeclarations.test.js.map +1 -0
- package/dist/dev/test/pydocs.test.js +888 -715
- package/dist/dev/test/pydocs.test.js.map +1 -1
- package/dist/dev/test/references.test.js +42 -35
- package/dist/dev/test/references.test.js.map +1 -1
- package/dist/dev/test/sourcefiles.test.js +1109 -841
- package/dist/dev/test/sourcefiles.test.js.map +1 -1
- package/dist/dev/test/staticmethoddeclaration.test.js +21 -10
- package/dist/dev/test/staticmethoddeclaration.test.js.map +1 -1
- package/dist/dev/test/type-checking-imports.test.js +408 -359
- package/dist/dev/test/type-checking-imports.test.js.map +1 -1
- package/dist/dev/test/typereference.test.js +55 -40
- package/dist/dev/test/typereference.test.js.map +1 -1
- package/dist/dev/test/uniontypeexpression.test.js +222 -146
- package/dist/dev/test/uniontypeexpression.test.js.map +1 -1
- package/dist/dev/test/utils.js +39 -77
- package/dist/dev/test/utils.js.map +1 -1
- package/dist/dev/test/values.test.js +237 -101
- package/dist/dev/test/values.test.js.map +1 -1
- package/dist/dev/test/variables.test.js +321 -203
- package/dist/dev/test/variables.test.js.map +1 -1
- package/dist/dev/test/vitest.setup.js +2 -0
- package/dist/dev/test/vitest.setup.js.map +1 -0
- package/dist/src/builtins/python.d.ts +30 -0
- package/dist/src/builtins/python.d.ts.map +1 -1
- package/dist/src/builtins/python.js +46 -0
- package/dist/src/builtins/python.js.map +1 -1
- package/dist/src/components/ClassDeclaration.d.ts +21 -0
- package/dist/src/components/ClassDeclaration.d.ts.map +1 -1
- package/dist/src/components/ClassDeclaration.js +6 -1
- package/dist/src/components/ClassDeclaration.js.map +1 -1
- package/dist/src/components/ClassMethodDeclaration.d.ts +5 -1
- package/dist/src/components/ClassMethodDeclaration.d.ts.map +1 -1
- package/dist/src/components/ClassMethodDeclaration.js +14 -3
- package/dist/src/components/ClassMethodDeclaration.js.map +1 -1
- package/dist/src/components/DataclassDeclaration.d.ts.map +1 -1
- package/dist/src/components/DataclassDeclaration.js +10 -4
- package/dist/src/components/DataclassDeclaration.js.map +1 -1
- package/dist/src/components/DecoratorList.d.ts +43 -0
- package/dist/src/components/DecoratorList.d.ts.map +1 -0
- package/dist/src/components/DecoratorList.js +47 -0
- package/dist/src/components/DecoratorList.js.map +1 -0
- package/dist/src/components/EnumDeclaration.d.ts +9 -0
- package/dist/src/components/EnumDeclaration.d.ts.map +1 -1
- package/dist/src/components/EnumDeclaration.js +6 -1
- package/dist/src/components/EnumDeclaration.js.map +1 -1
- package/dist/src/components/FunctionBase.d.ts +31 -1
- package/dist/src/components/FunctionBase.d.ts.map +1 -1
- package/dist/src/components/FunctionBase.js +9 -2
- package/dist/src/components/FunctionBase.js.map +1 -1
- package/dist/src/components/FutureStatement.d.ts +1 -1
- package/dist/src/components/FutureStatement.js +1 -1
- package/dist/src/components/MethodBase.d.ts.map +1 -1
- package/dist/src/components/MethodBase.js +10 -2
- package/dist/src/components/MethodBase.js.map +1 -1
- package/dist/src/components/PropertyDeclaration.d.ts +29 -0
- package/dist/src/components/PropertyDeclaration.d.ts.map +1 -1
- package/dist/src/components/PropertyDeclaration.js +48 -1
- package/dist/src/components/PropertyDeclaration.js.map +1 -1
- package/dist/src/components/PydanticClassDeclaration.d.ts +120 -0
- package/dist/src/components/PydanticClassDeclaration.d.ts.map +1 -0
- package/dist/src/components/PydanticClassDeclaration.js +116 -0
- package/dist/src/components/PydanticClassDeclaration.js.map +1 -0
- package/dist/src/components/SourceFile.d.ts +2 -2
- package/dist/src/components/SourceFile.d.ts.map +1 -1
- package/dist/src/components/SourceFile.js +12 -0
- package/dist/src/components/SourceFile.js.map +1 -1
- package/dist/src/components/StaticMethodDeclaration.d.ts +3 -0
- package/dist/src/components/StaticMethodDeclaration.d.ts.map +1 -1
- package/dist/src/components/StaticMethodDeclaration.js +13 -3
- package/dist/src/components/StaticMethodDeclaration.js.map +1 -1
- package/dist/src/components/index.d.ts +1 -0
- package/dist/src/components/index.d.ts.map +1 -1
- package/dist/src/components/index.js +1 -0
- package/dist/src/components/index.js.map +1 -1
- package/dist/test/callsignatures.test.js +346 -272
- package/dist/test/callsignatures.test.js.map +1 -1
- package/dist/test/class-method-declaration.test.js +7 -4
- package/dist/test/class-method-declaration.test.js.map +1 -1
- package/dist/test/classdeclarations.test.js +316 -277
- package/dist/test/classdeclarations.test.js.map +1 -1
- package/dist/test/classinstantiations.test.js +112 -103
- package/dist/test/classinstantiations.test.js.map +1 -1
- package/dist/test/constructordeclaration.test.js +7 -4
- package/dist/test/constructordeclaration.test.js.map +1 -1
- package/dist/test/dataclassdeclarations.test.js +153 -178
- package/dist/test/dataclassdeclarations.test.js.map +1 -1
- package/dist/test/decoratorlist.test.d.ts +2 -0
- package/dist/test/decoratorlist.test.d.ts.map +1 -0
- package/dist/test/decoratorlist.test.js +83 -0
- package/dist/test/decoratorlist.test.js.map +1 -0
- package/dist/test/dundermethoddeclaration.test.js +7 -4
- package/dist/test/dundermethoddeclaration.test.js.map +1 -1
- package/dist/test/enums.test.js +172 -143
- package/dist/test/enums.test.js.map +1 -1
- package/dist/test/externals.test.js +24 -24
- package/dist/test/externals.test.js.map +1 -1
- package/dist/test/factories.test.js +75 -33
- package/dist/test/factories.test.js.map +1 -1
- package/dist/test/functioncallexpressions.test.js +117 -106
- package/dist/test/functioncallexpressions.test.js.map +1 -1
- package/dist/test/functiondeclaration.test.js +256 -173
- package/dist/test/functiondeclaration.test.js.map +1 -1
- package/dist/test/imports.test.js +171 -143
- package/dist/test/imports.test.js.map +1 -1
- package/dist/test/memberexpressions.test.js +582 -453
- package/dist/test/memberexpressions.test.js.map +1 -1
- package/dist/test/methoddeclaration.test.js +106 -19
- package/dist/test/methoddeclaration.test.js.map +1 -1
- package/dist/test/namepolicies.test.js +90 -78
- package/dist/test/namepolicies.test.js.map +1 -1
- package/dist/test/propertydeclaration.test.js +90 -15
- package/dist/test/propertydeclaration.test.js.map +1 -1
- package/dist/test/pydanticclassdeclarations.test.d.ts +2 -0
- package/dist/test/pydanticclassdeclarations.test.d.ts.map +1 -0
- package/dist/test/pydanticclassdeclarations.test.js +773 -0
- package/dist/test/pydanticclassdeclarations.test.js.map +1 -0
- package/dist/test/pydocs.test.js +573 -532
- package/dist/test/pydocs.test.js.map +1 -1
- package/dist/test/references.test.js +31 -28
- package/dist/test/references.test.js.map +1 -1
- package/dist/test/sourcefiles.test.js +700 -580
- package/dist/test/sourcefiles.test.js.map +1 -1
- package/dist/test/staticmethoddeclaration.test.js +7 -4
- package/dist/test/staticmethoddeclaration.test.js.map +1 -1
- package/dist/test/type-checking-imports.test.js +297 -284
- package/dist/test/type-checking-imports.test.js.map +1 -1
- package/dist/test/typereference.test.js +29 -22
- package/dist/test/typereference.test.js.map +1 -1
- package/dist/test/uniontypeexpression.test.js +124 -88
- package/dist/test/uniontypeexpression.test.js.map +1 -1
- package/dist/test/utils.d.ts +10 -17
- package/dist/test/utils.d.ts.map +1 -1
- package/dist/test/utils.js +32 -74
- package/dist/test/utils.js.map +1 -1
- package/dist/test/values.test.js +135 -67
- package/dist/test/values.test.js.map +1 -1
- package/dist/test/variables.test.js +201 -151
- package/dist/test/variables.test.js.map +1 -1
- package/dist/test/vitest.setup.d.ts +2 -0
- package/dist/test/vitest.setup.d.ts.map +1 -0
- package/dist/test/vitest.setup.js +2 -0
- package/dist/test/vitest.setup.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/api/components/ClassDeclaration.md +10 -7
- package/docs/api/components/ClassEnumDeclaration.md +9 -6
- package/docs/api/components/ClassMethodDeclaration.md +7 -5
- package/docs/api/components/DataclassDeclaration.md +9 -5
- package/docs/api/components/DunderMethodDeclaration.md +7 -5
- package/docs/api/components/FunctionDeclaration.md +9 -5
- package/docs/api/components/FutureStatement.md +1 -1
- package/docs/api/components/MethodDeclaration.md +11 -6
- package/docs/api/components/PropertyDeclaration.md +11 -8
- package/docs/api/components/PydanticClassDeclaration.md +146 -0
- package/docs/api/components/SourceFile.md +20 -8
- package/docs/api/components/StaticMethodDeclaration.md +7 -5
- package/docs/api/components/index.md +1 -0
- package/docs/api/index.md +3 -3
- package/docs/api/types/CommonFunctionProps.md +4 -3
- package/docs/api/types/PydanticModelConfigDictProps.md +32 -0
- package/docs/api/types/index.md +1 -0
- package/docs/api/variables/index.md +3 -0
- package/docs/api/variables/pydanticModule.md +27 -0
- package/docs/api/variables/pydanticSettingsModule.md +7 -0
- package/docs/api/variables/typingModule.md +9 -0
- package/package.json +4 -4
- package/src/builtins/python.ts +539 -1
- package/src/components/ClassDeclaration.tsx +23 -0
- package/src/components/ClassMethodDeclaration.tsx +9 -1
- package/src/components/DataclassDeclaration.tsx +18 -11
- package/src/components/DecoratorList.tsx +50 -0
- package/src/components/EnumDeclaration.tsx +11 -0
- package/src/components/FunctionBase.tsx +34 -3
- package/src/components/FutureStatement.tsx +1 -1
- package/src/components/MethodBase.tsx +6 -2
- package/src/components/PropertyDeclaration.tsx +48 -1
- package/src/components/PydanticClassDeclaration.tsx +222 -0
- package/src/components/SourceFile.tsx +6 -1
- package/src/components/StaticMethodDeclaration.tsx +7 -1
- package/src/components/index.ts +1 -0
- package/temp/api.json +1158 -86
- package/test/callsignatures.test.tsx +309 -283
- package/test/class-method-declaration.test.tsx +3 -4
- package/test/classdeclarations.test.tsx +277 -235
- package/test/classinstantiations.test.tsx +115 -109
- package/test/constructordeclaration.test.tsx +9 -6
- package/test/dataclassdeclarations.test.tsx +256 -349
- package/test/decoratorlist.test.tsx +114 -0
- package/test/dundermethoddeclaration.test.tsx +3 -4
- package/test/enums.test.tsx +84 -71
- package/test/externals.test.tsx +25 -25
- package/test/factories.test.tsx +64 -22
- package/test/functioncallexpressions.test.tsx +123 -109
- package/test/functiondeclaration.test.tsx +218 -140
- package/test/imports.test.tsx +119 -91
- package/test/memberexpressions.test.tsx +265 -207
- package/test/methoddeclaration.test.tsx +115 -24
- package/test/namepolicies.test.tsx +69 -69
- package/test/propertydeclaration.test.tsx +71 -7
- package/test/pydanticclassdeclarations.test.tsx +704 -0
- package/test/pydocs.test.tsx +531 -579
- package/test/references.test.tsx +24 -23
- package/test/sourcefiles.test.tsx +527 -492
- package/test/staticmethoddeclaration.test.tsx +3 -4
- package/test/type-checking-imports.test.tsx +206 -218
- package/test/typereference.test.tsx +15 -12
- package/test/uniontypeexpression.test.tsx +74 -61
- package/test/utils.tsx +26 -110
- package/test/values.test.tsx +82 -32
- package/test/variables.test.tsx +162 -142
- package/test/vitest.setup.ts +1 -0
- package/vitest.config.ts +3 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
|
|
2
|
+
import { Prose, code, refkey } from "@alloy-js/core";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { pydanticModule, pydanticSettingsModule, typingModule } from "../src/builtins/python.js";
|
|
5
|
+
import * as py from "../src/index.js";
|
|
6
|
+
import { TestOutput, TestOutputDirectory } from "./utils.js";
|
|
7
|
+
describe("PydanticClassDeclaration", () => {
|
|
8
|
+
it("forwards class-level decorators above `class`", () => {
|
|
9
|
+
expect(_$createComponent(TestOutput, {
|
|
10
|
+
path: "models.py",
|
|
11
|
+
externals: [pydanticModule, typingModule],
|
|
12
|
+
get children() {
|
|
13
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
14
|
+
name: "User",
|
|
15
|
+
get decorators() {
|
|
16
|
+
return [code`@${typingModule["."].final}`];
|
|
17
|
+
},
|
|
18
|
+
get children() {
|
|
19
|
+
return _$createComponent(py.VariableDeclaration, {
|
|
20
|
+
instanceVariable: true,
|
|
21
|
+
omitNone: true,
|
|
22
|
+
name: "id",
|
|
23
|
+
type: "int"
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
})).toRenderTo(`
|
|
29
|
+
from pydantic import BaseModel
|
|
30
|
+
from typing import final
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@final
|
|
34
|
+
class User(BaseModel):
|
|
35
|
+
id: int
|
|
36
|
+
|
|
37
|
+
`);
|
|
38
|
+
});
|
|
39
|
+
it("emits a pydantic model with BaseModel, fields, and Field import", () => {
|
|
40
|
+
expect(_$createComponent(TestOutput, {
|
|
41
|
+
path: "models.py",
|
|
42
|
+
externals: [pydanticModule],
|
|
43
|
+
get children() {
|
|
44
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
45
|
+
name: "User",
|
|
46
|
+
get children() {
|
|
47
|
+
return [_$createComponent(py.VariableDeclaration, {
|
|
48
|
+
instanceVariable: true,
|
|
49
|
+
omitNone: true,
|
|
50
|
+
name: "id",
|
|
51
|
+
type: "int"
|
|
52
|
+
}), _$createComponent(py.VariableDeclaration, {
|
|
53
|
+
instanceVariable: true,
|
|
54
|
+
name: "name",
|
|
55
|
+
type: "str",
|
|
56
|
+
get initializer() {
|
|
57
|
+
return code`${pydanticModule["."].Field}(default="anon")`;
|
|
58
|
+
}
|
|
59
|
+
})];
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
})).toRenderTo(`
|
|
64
|
+
from pydantic import BaseModel
|
|
65
|
+
from pydantic import Field
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class User(BaseModel):
|
|
69
|
+
id: int
|
|
70
|
+
name: str = Field(default="anon")
|
|
71
|
+
|
|
72
|
+
`);
|
|
73
|
+
});
|
|
74
|
+
it("inherits from another pydantic model via bases", () => {
|
|
75
|
+
const baseRef = refkey();
|
|
76
|
+
expect(_$createComponent(TestOutput, {
|
|
77
|
+
path: "models.py",
|
|
78
|
+
externals: [pydanticModule],
|
|
79
|
+
get children() {
|
|
80
|
+
return _$createComponent(py.StatementList, {
|
|
81
|
+
get children() {
|
|
82
|
+
return [_$createComponent(py.PydanticClassDeclaration, {
|
|
83
|
+
name: "User",
|
|
84
|
+
refkey: baseRef,
|
|
85
|
+
get children() {
|
|
86
|
+
return _$createComponent(py.VariableDeclaration, {
|
|
87
|
+
instanceVariable: true,
|
|
88
|
+
omitNone: true,
|
|
89
|
+
name: "id",
|
|
90
|
+
type: "int"
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}), _$createComponent(py.PydanticClassDeclaration, {
|
|
94
|
+
name: "Admin",
|
|
95
|
+
bases: [baseRef],
|
|
96
|
+
get children() {
|
|
97
|
+
return _$createComponent(py.VariableDeclaration, {
|
|
98
|
+
instanceVariable: true,
|
|
99
|
+
omitNone: true,
|
|
100
|
+
name: "role",
|
|
101
|
+
type: "str"
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
})];
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
})).toRenderTo(`
|
|
109
|
+
from pydantic import BaseModel
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class User(BaseModel):
|
|
113
|
+
id: int
|
|
114
|
+
|
|
115
|
+
class Admin(User):
|
|
116
|
+
role: str
|
|
117
|
+
|
|
118
|
+
`);
|
|
119
|
+
});
|
|
120
|
+
it("supports required, optional, Field default, and plain default", () => {
|
|
121
|
+
expect(_$createComponent(TestOutput, {
|
|
122
|
+
path: "models.py",
|
|
123
|
+
externals: [pydanticModule],
|
|
124
|
+
get children() {
|
|
125
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
126
|
+
name: "Item",
|
|
127
|
+
get children() {
|
|
128
|
+
return [_$createComponent(py.VariableDeclaration, {
|
|
129
|
+
instanceVariable: true,
|
|
130
|
+
omitNone: true,
|
|
131
|
+
name: "sku",
|
|
132
|
+
type: "str"
|
|
133
|
+
}), _$createComponent(py.VariableDeclaration, {
|
|
134
|
+
instanceVariable: true,
|
|
135
|
+
name: "notes",
|
|
136
|
+
get type() {
|
|
137
|
+
return _$createComponent(py.UnionTypeExpression, {
|
|
138
|
+
children: ["str", "None"]
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}), _$createComponent(py.VariableDeclaration, {
|
|
142
|
+
instanceVariable: true,
|
|
143
|
+
name: "label",
|
|
144
|
+
type: "str",
|
|
145
|
+
get initializer() {
|
|
146
|
+
return code`${pydanticModule["."].Field}(default="untitled")`;
|
|
147
|
+
}
|
|
148
|
+
}), _$createComponent(py.VariableDeclaration, {
|
|
149
|
+
instanceVariable: true,
|
|
150
|
+
name: "qty",
|
|
151
|
+
type: "int",
|
|
152
|
+
initializer: 1
|
|
153
|
+
})];
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
})).toRenderTo(`
|
|
158
|
+
from pydantic import BaseModel
|
|
159
|
+
from pydantic import Field
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class Item(BaseModel):
|
|
163
|
+
sku: str
|
|
164
|
+
notes: str | None = None
|
|
165
|
+
label: str = Field(default="untitled")
|
|
166
|
+
qty: int = 1
|
|
167
|
+
|
|
168
|
+
`);
|
|
169
|
+
});
|
|
170
|
+
it("emits class docstring", () => {
|
|
171
|
+
const doc = _$createComponent(py.ClassDoc, {
|
|
172
|
+
get description() {
|
|
173
|
+
return [_$createComponent(Prose, {
|
|
174
|
+
children: "Payload for an API request."
|
|
175
|
+
})];
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
expect(_$createComponent(TestOutput, {
|
|
179
|
+
path: "models.py",
|
|
180
|
+
externals: [pydanticModule],
|
|
181
|
+
get children() {
|
|
182
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
183
|
+
name: "RequestBody",
|
|
184
|
+
doc: doc,
|
|
185
|
+
get children() {
|
|
186
|
+
return _$createComponent(py.VariableDeclaration, {
|
|
187
|
+
instanceVariable: true,
|
|
188
|
+
omitNone: true,
|
|
189
|
+
name: "value",
|
|
190
|
+
type: "str"
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
})).toRenderTo(`
|
|
196
|
+
from pydantic import BaseModel
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class RequestBody(BaseModel):
|
|
200
|
+
"""
|
|
201
|
+
Payload for an API request.
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
value: str
|
|
205
|
+
|
|
206
|
+
`);
|
|
207
|
+
});
|
|
208
|
+
it("resolves refkey across files with pydantic imports", () => {
|
|
209
|
+
const modelRef = refkey();
|
|
210
|
+
expect(_$createComponent(TestOutputDirectory, {
|
|
211
|
+
externals: [pydanticModule],
|
|
212
|
+
get children() {
|
|
213
|
+
return [_$createComponent(py.SourceFile, {
|
|
214
|
+
path: "models.py",
|
|
215
|
+
get children() {
|
|
216
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
217
|
+
name: "User",
|
|
218
|
+
refkey: modelRef,
|
|
219
|
+
get children() {
|
|
220
|
+
return _$createComponent(py.VariableDeclaration, {
|
|
221
|
+
instanceVariable: true,
|
|
222
|
+
omitNone: true,
|
|
223
|
+
name: "id",
|
|
224
|
+
type: "int"
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}), _$createComponent(py.SourceFile, {
|
|
230
|
+
path: "service.py",
|
|
231
|
+
get children() {
|
|
232
|
+
return _$createComponent(py.FunctionDeclaration, {
|
|
233
|
+
name: "load_user",
|
|
234
|
+
returnType: modelRef,
|
|
235
|
+
parameters: [{
|
|
236
|
+
name: "user_id",
|
|
237
|
+
type: "int"
|
|
238
|
+
}],
|
|
239
|
+
children: "return User(id=user_id)"
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
})];
|
|
243
|
+
}
|
|
244
|
+
})).toRenderTo({
|
|
245
|
+
"models.py": `
|
|
246
|
+
from pydantic import BaseModel
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class User(BaseModel):
|
|
250
|
+
id: int
|
|
251
|
+
|
|
252
|
+
`,
|
|
253
|
+
"service.py": `
|
|
254
|
+
from typing import TYPE_CHECKING
|
|
255
|
+
|
|
256
|
+
if TYPE_CHECKING:
|
|
257
|
+
from models import User
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def load_user(user_id: int) -> User:
|
|
261
|
+
return User(id=user_id)
|
|
262
|
+
|
|
263
|
+
`
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
it("emits model_config = ConfigDict(...) from top-level config props", () => {
|
|
267
|
+
expect(_$createComponent(TestOutput, {
|
|
268
|
+
path: "models.py",
|
|
269
|
+
externals: [pydanticModule],
|
|
270
|
+
get children() {
|
|
271
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
272
|
+
name: "User",
|
|
273
|
+
frozen: true,
|
|
274
|
+
extra: "forbid",
|
|
275
|
+
validateAssignment: true,
|
|
276
|
+
get children() {
|
|
277
|
+
return _$createComponent(py.VariableDeclaration, {
|
|
278
|
+
instanceVariable: true,
|
|
279
|
+
omitNone: true,
|
|
280
|
+
name: "id",
|
|
281
|
+
type: "int"
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
})).toRenderTo(`
|
|
287
|
+
from pydantic import BaseModel
|
|
288
|
+
from pydantic import ConfigDict
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
class User(BaseModel):
|
|
292
|
+
model_config = ConfigDict(frozen=True, extra="forbid", validate_assignment=True)
|
|
293
|
+
id: int
|
|
294
|
+
|
|
295
|
+
`);
|
|
296
|
+
});
|
|
297
|
+
it("emits model_config = ConfigDict(...) from modelConfig", () => {
|
|
298
|
+
expect(_$createComponent(TestOutput, {
|
|
299
|
+
path: "models.py",
|
|
300
|
+
externals: [pydanticModule],
|
|
301
|
+
get children() {
|
|
302
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
303
|
+
name: "User",
|
|
304
|
+
modelConfig: {
|
|
305
|
+
frozen: true,
|
|
306
|
+
extra: "forbid",
|
|
307
|
+
validateAssignment: true
|
|
308
|
+
},
|
|
309
|
+
get children() {
|
|
310
|
+
return _$createComponent(py.VariableDeclaration, {
|
|
311
|
+
instanceVariable: true,
|
|
312
|
+
omitNone: true,
|
|
313
|
+
name: "id",
|
|
314
|
+
type: "int"
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
})).toRenderTo(`
|
|
320
|
+
from pydantic import BaseModel
|
|
321
|
+
from pydantic import ConfigDict
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class User(BaseModel):
|
|
325
|
+
model_config = ConfigDict(frozen=True, extra="forbid", validate_assignment=True)
|
|
326
|
+
id: int
|
|
327
|
+
|
|
328
|
+
`);
|
|
329
|
+
});
|
|
330
|
+
it("gives precedence to top-level config props over modelConfig", () => {
|
|
331
|
+
expect(_$createComponent(TestOutput, {
|
|
332
|
+
path: "models.py",
|
|
333
|
+
externals: [pydanticModule],
|
|
334
|
+
get children() {
|
|
335
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
336
|
+
name: "User",
|
|
337
|
+
modelConfig: {
|
|
338
|
+
frozen: false,
|
|
339
|
+
extra: "allow"
|
|
340
|
+
},
|
|
341
|
+
frozen: true,
|
|
342
|
+
extra: "forbid"
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
})).toRenderTo(`
|
|
346
|
+
from pydantic import BaseModel
|
|
347
|
+
from pydantic import ConfigDict
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
class User(BaseModel):
|
|
351
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
352
|
+
|
|
353
|
+
`);
|
|
354
|
+
});
|
|
355
|
+
it("supports additional typed ConfigDict props", () => {
|
|
356
|
+
expect(_$createComponent(TestOutput, {
|
|
357
|
+
path: "models.py",
|
|
358
|
+
externals: [pydanticModule],
|
|
359
|
+
get children() {
|
|
360
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
361
|
+
name: "User",
|
|
362
|
+
useEnumValues: true,
|
|
363
|
+
coerceNumbersToStr: true,
|
|
364
|
+
validateReturn: true,
|
|
365
|
+
strMinLength: 1,
|
|
366
|
+
strMaxLength: 128,
|
|
367
|
+
serJsonBytes: "base64",
|
|
368
|
+
valJsonBytes: "hex"
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
})).toRenderTo(`
|
|
372
|
+
from pydantic import BaseModel
|
|
373
|
+
from pydantic import ConfigDict
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
class User(BaseModel):
|
|
377
|
+
model_config = ConfigDict(coerce_numbers_to_str=True, ser_json_bytes="base64", str_min_length=1, str_max_length=128, use_enum_values=True, val_json_bytes="hex", validate_return=True)
|
|
378
|
+
|
|
379
|
+
`);
|
|
380
|
+
});
|
|
381
|
+
it("imports SecretStr when used as a field type", () => {
|
|
382
|
+
expect(_$createComponent(TestOutput, {
|
|
383
|
+
path: "models.py",
|
|
384
|
+
externals: [pydanticModule],
|
|
385
|
+
get children() {
|
|
386
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
387
|
+
name: "Credentials",
|
|
388
|
+
get children() {
|
|
389
|
+
return _$createComponent(py.VariableDeclaration, {
|
|
390
|
+
instanceVariable: true,
|
|
391
|
+
omitNone: true,
|
|
392
|
+
name: "token",
|
|
393
|
+
get type() {
|
|
394
|
+
return pydanticModule["."].SecretStr;
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
})).toRenderTo(`
|
|
401
|
+
from pydantic import BaseModel
|
|
402
|
+
from typing import TYPE_CHECKING
|
|
403
|
+
|
|
404
|
+
if TYPE_CHECKING:
|
|
405
|
+
from pydantic import SecretStr
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
class Credentials(BaseModel):
|
|
409
|
+
token: SecretStr
|
|
410
|
+
|
|
411
|
+
`);
|
|
412
|
+
});
|
|
413
|
+
it("emits arbitrary model_config via modelConfigExpression", () => {
|
|
414
|
+
expect(_$createComponent(TestOutput, {
|
|
415
|
+
path: "models.py",
|
|
416
|
+
externals: [pydanticModule],
|
|
417
|
+
get children() {
|
|
418
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
419
|
+
name: "M",
|
|
420
|
+
get modelConfigExpression() {
|
|
421
|
+
return code`${pydanticModule["."].ConfigDict}(frozen=True, extra="allow")`;
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
})).toRenderTo(`
|
|
426
|
+
from pydantic import BaseModel
|
|
427
|
+
from pydantic import ConfigDict
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
class M(BaseModel):
|
|
431
|
+
model_config = ConfigDict(frozen=True, extra="allow")
|
|
432
|
+
|
|
433
|
+
`);
|
|
434
|
+
});
|
|
435
|
+
it("supports RootModel as explicit bases entry", () => {
|
|
436
|
+
expect(_$createComponent(TestOutput, {
|
|
437
|
+
path: "models.py",
|
|
438
|
+
externals: [pydanticModule],
|
|
439
|
+
get children() {
|
|
440
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
441
|
+
name: "Tags",
|
|
442
|
+
get bases() {
|
|
443
|
+
return [code`${pydanticModule["."].RootModel}[list[str]]`];
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
})).toRenderTo(`
|
|
448
|
+
from pydantic import RootModel
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
class Tags(RootModel[list[str]]):
|
|
452
|
+
pass
|
|
453
|
+
|
|
454
|
+
`);
|
|
455
|
+
});
|
|
456
|
+
it("places Pydantic validators above classmethod", () => {
|
|
457
|
+
expect(_$createComponent(TestOutput, {
|
|
458
|
+
path: "models.py",
|
|
459
|
+
externals: [pydanticModule],
|
|
460
|
+
get children() {
|
|
461
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
462
|
+
name: "User",
|
|
463
|
+
get children() {
|
|
464
|
+
return [_$createComponent(py.VariableDeclaration, {
|
|
465
|
+
instanceVariable: true,
|
|
466
|
+
omitNone: true,
|
|
467
|
+
name: "name",
|
|
468
|
+
type: "str"
|
|
469
|
+
}), _$createComponent(py.ClassMethodDeclaration, {
|
|
470
|
+
name: "strip_name",
|
|
471
|
+
get decorators() {
|
|
472
|
+
return [code`@${pydanticModule["."].field_validator}("name", mode="before")`];
|
|
473
|
+
},
|
|
474
|
+
parameters: [{
|
|
475
|
+
name: "value",
|
|
476
|
+
type: "str"
|
|
477
|
+
}],
|
|
478
|
+
returnType: "str",
|
|
479
|
+
children: "return value.strip()"
|
|
480
|
+
})];
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
})).toRenderTo(`
|
|
485
|
+
from pydantic import BaseModel
|
|
486
|
+
from pydantic import field_validator
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
class User(BaseModel):
|
|
490
|
+
name: str
|
|
491
|
+
@field_validator("name", mode="before")
|
|
492
|
+
@classmethod
|
|
493
|
+
def strip_name(cls, value: str) -> str:
|
|
494
|
+
return value.strip()
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
`);
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
describe("Pydantic ecosystem emitters", () => {
|
|
501
|
+
it("typing module resolves Any and similar annotations", () => {
|
|
502
|
+
expect(_$createComponent(TestOutput, {
|
|
503
|
+
path: "models.py",
|
|
504
|
+
externals: [typingModule],
|
|
505
|
+
get children() {
|
|
506
|
+
return _$createComponent(py.FunctionDeclaration, {
|
|
507
|
+
name: "identity",
|
|
508
|
+
get parameters() {
|
|
509
|
+
return [{
|
|
510
|
+
name: "x",
|
|
511
|
+
type: typingModule["."].Any
|
|
512
|
+
}];
|
|
513
|
+
},
|
|
514
|
+
get returnType() {
|
|
515
|
+
return typingModule["."].Any;
|
|
516
|
+
},
|
|
517
|
+
children: "return x"
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
})).toRenderTo(`
|
|
521
|
+
from typing import TYPE_CHECKING
|
|
522
|
+
|
|
523
|
+
if TYPE_CHECKING:
|
|
524
|
+
from typing import Any
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
def identity(x: Any) -> Any:
|
|
528
|
+
return x
|
|
529
|
+
|
|
530
|
+
`);
|
|
531
|
+
});
|
|
532
|
+
it("pydantic.types constrains field annotations", () => {
|
|
533
|
+
expect(_$createComponent(TestOutput, {
|
|
534
|
+
path: "models.py",
|
|
535
|
+
externals: [pydanticModule],
|
|
536
|
+
get children() {
|
|
537
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
538
|
+
name: "Score",
|
|
539
|
+
get children() {
|
|
540
|
+
return _$createComponent(py.VariableDeclaration, {
|
|
541
|
+
instanceVariable: true,
|
|
542
|
+
omitNone: true,
|
|
543
|
+
name: "points",
|
|
544
|
+
get type() {
|
|
545
|
+
return pydanticModule.types.PositiveInt;
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
})).toRenderTo(`
|
|
552
|
+
from pydantic import BaseModel
|
|
553
|
+
from typing import TYPE_CHECKING
|
|
554
|
+
|
|
555
|
+
if TYPE_CHECKING:
|
|
556
|
+
from pydantic.types import PositiveInt
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
class Score(BaseModel):
|
|
560
|
+
points: PositiveInt
|
|
561
|
+
|
|
562
|
+
`);
|
|
563
|
+
});
|
|
564
|
+
it("postponed annotations support forward references in fields", () => {
|
|
565
|
+
expect(_$createComponent(TestOutputDirectory, {
|
|
566
|
+
externals: [pydanticModule],
|
|
567
|
+
get children() {
|
|
568
|
+
return _$createComponent(py.SourceFile, {
|
|
569
|
+
path: "models.py",
|
|
570
|
+
get futureImports() {
|
|
571
|
+
return [_$createComponent(py.FutureStatement, {
|
|
572
|
+
feature: "annotations"
|
|
573
|
+
})];
|
|
574
|
+
},
|
|
575
|
+
get children() {
|
|
576
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
577
|
+
name: "Node",
|
|
578
|
+
get children() {
|
|
579
|
+
return [_$createComponent(py.VariableDeclaration, {
|
|
580
|
+
instanceVariable: true,
|
|
581
|
+
omitNone: true,
|
|
582
|
+
name: "label",
|
|
583
|
+
type: "str"
|
|
584
|
+
}), _$createComponent(py.VariableDeclaration, {
|
|
585
|
+
instanceVariable: true,
|
|
586
|
+
name: "child",
|
|
587
|
+
type: code`"Node" | None`
|
|
588
|
+
})];
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
})).toRenderTo({
|
|
595
|
+
"models.py": `
|
|
596
|
+
from __future__ import annotations
|
|
597
|
+
|
|
598
|
+
from pydantic import BaseModel
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
class Node(BaseModel):
|
|
602
|
+
label: str
|
|
603
|
+
child: "Node" | None = None
|
|
604
|
+
|
|
605
|
+
`
|
|
606
|
+
});
|
|
607
|
+
});
|
|
608
|
+
it("model_config can use pydantic.alias_generators", () => {
|
|
609
|
+
expect(_$createComponent(TestOutput, {
|
|
610
|
+
path: "models.py",
|
|
611
|
+
externals: [pydanticModule],
|
|
612
|
+
get children() {
|
|
613
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
614
|
+
name: "M",
|
|
615
|
+
get modelConfigExpression() {
|
|
616
|
+
return code`${pydanticModule["."].ConfigDict}(alias_generator=${pydanticModule.alias_generators.to_camel})`;
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
})).toRenderTo(`
|
|
621
|
+
from pydantic import BaseModel
|
|
622
|
+
from pydantic import ConfigDict
|
|
623
|
+
from pydantic.alias_generators import to_camel
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
class M(BaseModel):
|
|
627
|
+
model_config = ConfigDict(alias_generator=to_camel)
|
|
628
|
+
|
|
629
|
+
`);
|
|
630
|
+
});
|
|
631
|
+
it("pydantic_settings exposes BaseSettings", () => {
|
|
632
|
+
expect(_$createComponent(TestOutput, {
|
|
633
|
+
path: "config.py",
|
|
634
|
+
externals: [pydanticSettingsModule],
|
|
635
|
+
get children() {
|
|
636
|
+
return _$createComponent(py.ClassDeclaration, {
|
|
637
|
+
name: "AppSettings",
|
|
638
|
+
get bases() {
|
|
639
|
+
return [pydanticSettingsModule["."].BaseSettings];
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
})).toRenderTo(`
|
|
644
|
+
from pydantic_settings import BaseSettings
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
class AppSettings(BaseSettings):
|
|
648
|
+
pass
|
|
649
|
+
|
|
650
|
+
`);
|
|
651
|
+
});
|
|
652
|
+
it("emits @computed_field above @property via PropertyDeclaration", () => {
|
|
653
|
+
expect(_$createComponent(TestOutput, {
|
|
654
|
+
path: "models.py",
|
|
655
|
+
externals: [pydanticModule],
|
|
656
|
+
get children() {
|
|
657
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
658
|
+
name: "Square",
|
|
659
|
+
get children() {
|
|
660
|
+
return [_$createComponent(py.VariableDeclaration, {
|
|
661
|
+
instanceVariable: true,
|
|
662
|
+
omitNone: true,
|
|
663
|
+
name: "width",
|
|
664
|
+
type: "float"
|
|
665
|
+
}), _$createComponent(py.PropertyDeclaration, {
|
|
666
|
+
name: "area",
|
|
667
|
+
type: "float",
|
|
668
|
+
get decorators() {
|
|
669
|
+
return [code`@${pydanticModule["."].computed_field}`];
|
|
670
|
+
},
|
|
671
|
+
children: "return self.width ** 2"
|
|
672
|
+
})];
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
})).toRenderTo(`
|
|
677
|
+
from pydantic import BaseModel
|
|
678
|
+
from pydantic import computed_field
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
class Square(BaseModel):
|
|
682
|
+
width: float
|
|
683
|
+
@computed_field
|
|
684
|
+
@property
|
|
685
|
+
def area(self) -> float:
|
|
686
|
+
return self.width ** 2
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
`);
|
|
690
|
+
});
|
|
691
|
+
it("emits computed_field on an instance method", () => {
|
|
692
|
+
expect(_$createComponent(TestOutput, {
|
|
693
|
+
path: "models.py",
|
|
694
|
+
externals: [pydanticModule],
|
|
695
|
+
get children() {
|
|
696
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
697
|
+
name: "Square",
|
|
698
|
+
get children() {
|
|
699
|
+
return [_$createComponent(py.VariableDeclaration, {
|
|
700
|
+
instanceVariable: true,
|
|
701
|
+
omitNone: true,
|
|
702
|
+
name: "width",
|
|
703
|
+
type: "float"
|
|
704
|
+
}), _$createComponent(py.MethodDeclaration, {
|
|
705
|
+
name: "area",
|
|
706
|
+
get decorators() {
|
|
707
|
+
return [code`@${pydanticModule["."].computed_field}`];
|
|
708
|
+
},
|
|
709
|
+
returnType: "float",
|
|
710
|
+
children: "return self.width ** 2"
|
|
711
|
+
})];
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
})).toRenderTo(`
|
|
716
|
+
from pydantic import BaseModel
|
|
717
|
+
from pydantic import computed_field
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
class Square(BaseModel):
|
|
721
|
+
width: float
|
|
722
|
+
@computed_field
|
|
723
|
+
def area(self) -> float:
|
|
724
|
+
return self.width ** 2
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
`);
|
|
728
|
+
});
|
|
729
|
+
it("emits model_validator above classmethod", () => {
|
|
730
|
+
expect(_$createComponent(TestOutput, {
|
|
731
|
+
path: "models.py",
|
|
732
|
+
externals: [pydanticModule],
|
|
733
|
+
get children() {
|
|
734
|
+
return _$createComponent(py.PydanticClassDeclaration, {
|
|
735
|
+
name: "Bag",
|
|
736
|
+
get children() {
|
|
737
|
+
return [_$createComponent(py.VariableDeclaration, {
|
|
738
|
+
instanceVariable: true,
|
|
739
|
+
omitNone: true,
|
|
740
|
+
name: "items",
|
|
741
|
+
type: "list"
|
|
742
|
+
}), _$createComponent(py.ClassMethodDeclaration, {
|
|
743
|
+
name: "ensure_items",
|
|
744
|
+
get decorators() {
|
|
745
|
+
return [code`@${pydanticModule["."].model_validator}(mode="before")`];
|
|
746
|
+
},
|
|
747
|
+
parameters: [{
|
|
748
|
+
name: "data",
|
|
749
|
+
type: "dict"
|
|
750
|
+
}],
|
|
751
|
+
returnType: "dict",
|
|
752
|
+
children: "return data"
|
|
753
|
+
})];
|
|
754
|
+
}
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
})).toRenderTo(`
|
|
758
|
+
from pydantic import BaseModel
|
|
759
|
+
from pydantic import model_validator
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
class Bag(BaseModel):
|
|
763
|
+
items: list
|
|
764
|
+
@model_validator(mode="before")
|
|
765
|
+
@classmethod
|
|
766
|
+
def ensure_items(cls, data: dict) -> dict:
|
|
767
|
+
return data
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
`);
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
//# sourceMappingURL=pydanticclassdeclarations.test.js.map
|