@alloy-js/python 0.5.0-dev.0 → 0.5.0-dev.1
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/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/classdeclarations.test.js +85 -52
- package/dist/dev/test/classdeclarations.test.js.map +1 -1
- package/dist/dev/test/dataclassdeclarations.test.js +122 -89
- package/dist/dev/test/dataclassdeclarations.test.js.map +1 -1
- package/dist/dev/test/decoratorlist.test.js +84 -0
- package/dist/dev/test/decoratorlist.test.js.map +1 -0
- package/dist/dev/test/enums.test.js +41 -10
- package/dist/dev/test/enums.test.js.map +1 -1
- package/dist/dev/test/functiondeclaration.test.js +81 -61
- package/dist/dev/test/functiondeclaration.test.js.map +1 -1
- package/dist/dev/test/methoddeclaration.test.js +117 -26
- package/dist/dev/test/methoddeclaration.test.js.map +1 -1
- package/dist/dev/test/propertydeclaration.test.js +109 -7
- package/dist/dev/test/propertydeclaration.test.js.map +1 -1
- package/dist/dev/test/pydanticclassdeclarations.test.js +1137 -0
- package/dist/dev/test/pydanticclassdeclarations.test.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/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/classdeclarations.test.js +25 -0
- package/dist/test/classdeclarations.test.js.map +1 -1
- package/dist/test/dataclassdeclarations.test.js +25 -0
- 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 +60 -0
- package/dist/test/decoratorlist.test.js.map +1 -0
- package/dist/test/enums.test.js +27 -0
- package/dist/test/enums.test.js.map +1 -1
- package/dist/test/functiondeclaration.test.js +16 -0
- package/dist/test/functiondeclaration.test.js.map +1 -1
- package/dist/test/methoddeclaration.test.js +67 -0
- package/dist/test/methoddeclaration.test.js.map +1 -1
- package/dist/test/propertydeclaration.test.js +71 -1
- 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 +829 -0
- package/dist/test/pydanticclassdeclarations.test.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/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/StaticMethodDeclaration.tsx +7 -1
- package/src/components/index.ts +1 -0
- package/temp/api.json +1142 -84
- package/test/classdeclarations.test.tsx +27 -0
- package/test/dataclassdeclarations.test.tsx +25 -0
- package/test/decoratorlist.test.tsx +95 -0
- package/test/enums.test.tsx +29 -0
- package/test/functiondeclaration.test.tsx +17 -0
- package/test/methoddeclaration.test.tsx +70 -0
- package/test/propertydeclaration.test.tsx +66 -1
- package/test/pydanticclassdeclarations.test.tsx +836 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Children, For } from "@alloy-js/core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Props for {@link DecoratorList}.
|
|
5
|
+
*/
|
|
6
|
+
export interface DecoratorListProps {
|
|
7
|
+
/**
|
|
8
|
+
* Decorators rendered top-to-bottom. The first entry is rendered topmost,
|
|
9
|
+
* which (by Python's bottom-up application order) is the outermost decorator
|
|
10
|
+
* — i.e. it is applied **last** and wraps the result of everything below it.
|
|
11
|
+
*
|
|
12
|
+
* Falsy entries (other than `0`) are skipped, so conditional decorators can
|
|
13
|
+
* be written inline as `condition && <Decorator/>`.
|
|
14
|
+
*/
|
|
15
|
+
decorators?: Children[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Renders a list of decorators, one per line, with a single hardline between
|
|
20
|
+
* adjacent decorators and a trailing hardline only when at least one decorator
|
|
21
|
+
* is present.
|
|
22
|
+
*
|
|
23
|
+
* This is the canonical decorator-rendering primitive for method-, function-,
|
|
24
|
+
* and property-like components. Centralizing it ensures the decorator stack
|
|
25
|
+
* composes consistently — no stray blank lines between decorators, and no
|
|
26
|
+
* trailing newline when the list is empty.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* <DecoratorList decorators={[code`@field_validator("name")`, "@classmethod"]} />
|
|
31
|
+
* ```
|
|
32
|
+
* Renders:
|
|
33
|
+
* ```python
|
|
34
|
+
* @field_validator("name")
|
|
35
|
+
* @classmethod
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* Internal helper, not exported from the package. Used by
|
|
40
|
+
* `MethodDeclarationBase`, `ClassMethodDeclaration`, `StaticMethodDeclaration`,
|
|
41
|
+
* and `PropertyDeclaration` to render their `decorators` prop above the
|
|
42
|
+
* intrinsic decorator (`@classmethod`, `@staticmethod`, `@property`) or `def`.
|
|
43
|
+
*/
|
|
44
|
+
export function DecoratorList(props: DecoratorListProps) {
|
|
45
|
+
return (
|
|
46
|
+
<For each={props.decorators ?? []} hardline ender={<hbr />} skipFalsy>
|
|
47
|
+
{(dec) => dec}
|
|
48
|
+
</For>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { enumModule } from "../builtins/python.js";
|
|
8
8
|
import { createPythonSymbol } from "../symbol-creation.js";
|
|
9
9
|
import { BaseDeclarationProps } from "./Declaration.js";
|
|
10
|
+
import { DecoratorList } from "./DecoratorList.jsx";
|
|
10
11
|
import { EnumMember, EnumMemberProps } from "./EnumMember.js";
|
|
11
12
|
import { MemberScope } from "./MemberScope.jsx";
|
|
12
13
|
import { PythonBlock } from "./PythonBlock.jsx";
|
|
@@ -113,6 +114,15 @@ export interface ClassEnumProps extends EnumPropsBase {
|
|
|
113
114
|
* Indicates that the enum members should be auto-generated.
|
|
114
115
|
*/
|
|
115
116
|
auto?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Decorators rendered above `class <Name>(<BaseType>):`. See
|
|
119
|
+
* {@link ClassDeclarationProps.decorators} for the source-order and falsy
|
|
120
|
+
* skip semantics.
|
|
121
|
+
*
|
|
122
|
+
* Not available on functional-enum syntax (`Name = Enum(...)`), which is a
|
|
123
|
+
* variable assignment rather than a class definition.
|
|
124
|
+
*/
|
|
125
|
+
decorators?: Children[];
|
|
116
126
|
}
|
|
117
127
|
|
|
118
128
|
/**
|
|
@@ -203,6 +213,7 @@ export function ClassEnumDeclaration(props: ClassEnumProps) {
|
|
|
203
213
|
}
|
|
204
214
|
return (
|
|
205
215
|
<CoreDeclaration symbol={sym}>
|
|
216
|
+
<DecoratorList decorators={props.decorators} />
|
|
206
217
|
class {sym.name}({enumModule["."][baseType]})
|
|
207
218
|
<MemberScope ownerSymbol={sym}>
|
|
208
219
|
<PythonBlock opener=":">
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { createContentSlot, Name, Show } from "@alloy-js/core";
|
|
1
|
+
import { createContentSlot, Name, Show, type Children } from "@alloy-js/core";
|
|
2
2
|
import { PythonOutputSymbol } from "../index.js";
|
|
3
3
|
import { getCallSignatureProps } from "../utils.js";
|
|
4
4
|
import { CallSignature, CallSignatureProps } from "./CallSignature.jsx";
|
|
5
5
|
import { BaseDeclarationProps, Declaration } from "./Declaration.js";
|
|
6
|
+
import { DecoratorList } from "./DecoratorList.jsx";
|
|
6
7
|
import { LexicalScope } from "./LexicalScope.jsx";
|
|
7
8
|
import { PythonBlock } from "./PythonBlock.jsx";
|
|
8
9
|
|
|
@@ -19,6 +20,35 @@ export interface CommonFunctionProps
|
|
|
19
20
|
CallSignatureProps {
|
|
20
21
|
/** Indicates that the function is async. */
|
|
21
22
|
async?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Decorators rendered above `def`, in source order — `decorators[0]` is
|
|
25
|
+
* topmost. By Python's bottom-up application order, the topmost entry is
|
|
26
|
+
* the **outermost** decorator (applied last) and wraps the result of every
|
|
27
|
+
* decorator below it.
|
|
28
|
+
*
|
|
29
|
+
* Each entry should produce a complete decorator line (typically starting
|
|
30
|
+
* with `@`). Falsy entries (other than `0`) are skipped, so conditional
|
|
31
|
+
* decorators can be provided inline when needed.
|
|
32
|
+
*
|
|
33
|
+
* When used through wrappers that emit an intrinsic decorator
|
|
34
|
+
* (`ClassMethodDeclaration` → `@classmethod`,
|
|
35
|
+
* `StaticMethodDeclaration` → `@staticmethod`,
|
|
36
|
+
* `PropertyDeclaration` → `@property`), these decorators are rendered
|
|
37
|
+
* **above** the intrinsic line — the correct position for Pydantic's
|
|
38
|
+
* `@field_validator` / `@model_validator` and other wrappers that must
|
|
39
|
+
* see the underlying function, not a descriptor.
|
|
40
|
+
*
|
|
41
|
+
* When used on plain `MethodDeclaration` / `FunctionDeclaration`, these
|
|
42
|
+
* decorators are rendered above `@abstractmethod` (if `abstract` is set)
|
|
43
|
+
* and above `def`.
|
|
44
|
+
*
|
|
45
|
+
* Do **not** pass intrinsic decorators here — i.e. `@classmethod`,
|
|
46
|
+
* `@staticmethod`, `@property`, or `@abstractmethod`. Those are emitted by
|
|
47
|
+
* the matching component (`ClassMethodDeclaration`, `StaticMethodDeclaration`,
|
|
48
|
+
* `PropertyDeclaration`, or the `abstract` flag) and would otherwise be
|
|
49
|
+
* stacked twice in the output, producing invalid Python.
|
|
50
|
+
*/
|
|
51
|
+
decorators?: Children[];
|
|
22
52
|
}
|
|
23
53
|
|
|
24
54
|
/**
|
|
@@ -54,6 +84,7 @@ export interface BaseFunctionDeclarationProps extends CommonFunctionProps {
|
|
|
54
84
|
* ```
|
|
55
85
|
*/
|
|
56
86
|
export function BaseFunctionDeclaration(props: BaseFunctionDeclarationProps) {
|
|
87
|
+
const { decorators, sym, ...declarationProps } = props;
|
|
57
88
|
const asyncKwd = props.async ? "async " : "";
|
|
58
89
|
let parameters;
|
|
59
90
|
switch (props.functionType) {
|
|
@@ -66,11 +97,11 @@ export function BaseFunctionDeclaration(props: BaseFunctionDeclarationProps) {
|
|
|
66
97
|
default:
|
|
67
98
|
parameters = props.parameters;
|
|
68
99
|
}
|
|
69
|
-
const sym: PythonOutputSymbol = props.sym;
|
|
70
100
|
const ContentSlot = createContentSlot();
|
|
71
101
|
return (
|
|
72
102
|
<>
|
|
73
|
-
<
|
|
103
|
+
<DecoratorList decorators={decorators} />
|
|
104
|
+
<Declaration {...declarationProps} nameKind="function" symbol={sym}>
|
|
74
105
|
{asyncKwd}def <Name />
|
|
75
106
|
<LexicalScope name={sym.name}>
|
|
76
107
|
<CallSignature
|
|
@@ -18,7 +18,7 @@ export interface FutureStatementProps {
|
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* ```tsx
|
|
21
|
-
* <SourceFile path="models.py" futureImports={<FutureStatement feature="annotations" />}>
|
|
21
|
+
* <SourceFile path="models.py" futureImports={[<FutureStatement feature="annotations" />]}>
|
|
22
22
|
* <ClassDeclaration name="User">
|
|
23
23
|
* <PropertyDeclaration name="manager" type="User" />
|
|
24
24
|
* </ClassDeclaration>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { abcModule } from "../builtins/python.js";
|
|
2
|
+
import { DecoratorList } from "./DecoratorList.jsx";
|
|
2
3
|
import {
|
|
3
4
|
BaseFunctionDeclaration,
|
|
4
5
|
BaseFunctionDeclarationProps,
|
|
@@ -36,8 +37,10 @@ export function MethodDeclarationBase(
|
|
|
36
37
|
props: MethodDeclarationBaseProps &
|
|
37
38
|
Pick<BaseFunctionDeclarationProps, "functionType" | "sym">,
|
|
38
39
|
) {
|
|
40
|
+
const { decorators, abstract, ...rest } = props;
|
|
41
|
+
|
|
39
42
|
const abstractMethod =
|
|
40
|
-
|
|
43
|
+
abstract ?
|
|
41
44
|
<>
|
|
42
45
|
@{abcModule["."].abstractmethod}
|
|
43
46
|
<hbr />
|
|
@@ -46,8 +49,9 @@ export function MethodDeclarationBase(
|
|
|
46
49
|
|
|
47
50
|
return (
|
|
48
51
|
<>
|
|
52
|
+
<DecoratorList decorators={decorators} />
|
|
49
53
|
{abstractMethod}
|
|
50
|
-
<BaseFunctionDeclaration {...
|
|
54
|
+
<BaseFunctionDeclaration {...rest} />
|
|
51
55
|
</>
|
|
52
56
|
);
|
|
53
57
|
}
|
|
@@ -16,6 +16,7 @@ import { PythonOutputSymbol } from "../index.js";
|
|
|
16
16
|
import { ParameterDescriptor } from "../parameter-descriptor.js";
|
|
17
17
|
import { createMethodSymbol } from "../symbols/factories.js";
|
|
18
18
|
import { Atom } from "./Atom.jsx";
|
|
19
|
+
import { DecoratorList } from "./DecoratorList.jsx";
|
|
19
20
|
import { CommonFunctionProps } from "./FunctionBase.js";
|
|
20
21
|
import { MethodDeclarationBase } from "./MethodBase.js";
|
|
21
22
|
|
|
@@ -72,6 +73,29 @@ const PropertyContext = createContext<Children | undefined>();
|
|
|
72
73
|
* The property must be declared within a class. The getter method is
|
|
73
74
|
* automatically generated using the `@property` decorator. Use the nested
|
|
74
75
|
* `Setter` and `Deleter` components to add mutators.
|
|
76
|
+
*
|
|
77
|
+
* Use **`decorators`** for decorators that must appear **above** the intrinsic
|
|
78
|
+
* `@property` (for example Pydantic `@computed_field`, `@typing.final`,
|
|
79
|
+
* `@typing.override`). The first array entry is rendered topmost, matching
|
|
80
|
+
* Python source order.
|
|
81
|
+
*
|
|
82
|
+
* @example Pydantic computed field
|
|
83
|
+
* ```tsx
|
|
84
|
+
* <py.PropertyDeclaration
|
|
85
|
+
* name="area"
|
|
86
|
+
* type="float"
|
|
87
|
+
* decorators={[code`@${pydanticModule["."].computed_field}`]}
|
|
88
|
+
* >
|
|
89
|
+
* return self.width ** 2
|
|
90
|
+
* </py.PropertyDeclaration>
|
|
91
|
+
* ```
|
|
92
|
+
* Generates:
|
|
93
|
+
* ```python
|
|
94
|
+
* @computed_field
|
|
95
|
+
* @property
|
|
96
|
+
* def area(self) -> float:
|
|
97
|
+
* return self.width ** 2
|
|
98
|
+
* ```
|
|
75
99
|
*/
|
|
76
100
|
export interface PropertyDeclarationProps {
|
|
77
101
|
name: string;
|
|
@@ -80,6 +104,12 @@ export interface PropertyDeclarationProps {
|
|
|
80
104
|
refkey?: Refkey;
|
|
81
105
|
abstract?: boolean;
|
|
82
106
|
doc?: Children;
|
|
107
|
+
/**
|
|
108
|
+
* Decorators rendered above the intrinsic `@property` line, in source order
|
|
109
|
+
* (`decorators[0]` is topmost / applied last). Use for decorators that wrap
|
|
110
|
+
* the resulting property, e.g. Pydantic's `@computed_field`.
|
|
111
|
+
*/
|
|
112
|
+
decorators?: Children[];
|
|
83
113
|
}
|
|
84
114
|
|
|
85
115
|
export function PropertyDeclaration(props: PropertyDeclarationProps) {
|
|
@@ -120,6 +150,7 @@ export function PropertyDeclaration(props: PropertyDeclarationProps) {
|
|
|
120
150
|
<PropertyMethodDeclaration
|
|
121
151
|
abstract={props.abstract}
|
|
122
152
|
doc={props.doc}
|
|
153
|
+
decorators={props.decorators}
|
|
123
154
|
>
|
|
124
155
|
{unkeyedChildren}
|
|
125
156
|
</PropertyMethodDeclaration>
|
|
@@ -155,13 +186,15 @@ export interface PropertyMethodDeclarationProps
|
|
|
155
186
|
function PropertyMethodDeclaration(props: PropertyMethodDeclarationProps) {
|
|
156
187
|
const propertySymbol = useContext(DeclarationContext) as PythonOutputSymbol;
|
|
157
188
|
const propertyType = useContext(PropertyContext);
|
|
189
|
+
const { decorators, ...rest } = props;
|
|
158
190
|
|
|
159
191
|
return (
|
|
160
192
|
<>
|
|
193
|
+
<DecoratorList decorators={decorators} />
|
|
161
194
|
{code`@property`}
|
|
162
195
|
<hbr />
|
|
163
196
|
<MethodDeclarationBase
|
|
164
|
-
{...
|
|
197
|
+
{...rest}
|
|
165
198
|
name={propertySymbol.name}
|
|
166
199
|
functionType="instance"
|
|
167
200
|
returnType={propertyType}
|
|
@@ -219,6 +252,13 @@ function PropertyMethodBase(props: PropertyMethodBaseProps) {
|
|
|
219
252
|
* def value(self, value: int) -> None:
|
|
220
253
|
* self._value = value
|
|
221
254
|
* ```
|
|
255
|
+
*
|
|
256
|
+
* @remarks
|
|
257
|
+
* The intrinsic `@<name>.setter` decorator is always rendered topmost (it must
|
|
258
|
+
* remain the outermost decorator). Any `decorators` passed to this component
|
|
259
|
+
* are rendered **between** `@<name>.setter` and `def`, which is the correct
|
|
260
|
+
* position for wrappers that should decorate the underlying function before
|
|
261
|
+
* `setter` re-binds it to the property (e.g. `@deprecated`, `@abstractmethod`).
|
|
222
262
|
*/
|
|
223
263
|
PropertyDeclaration.Setter = taggedComponent(
|
|
224
264
|
setterTag,
|
|
@@ -253,6 +293,13 @@ PropertyDeclaration.Setter = taggedComponent(
|
|
|
253
293
|
* def value(self) -> None:
|
|
254
294
|
* del self._value
|
|
255
295
|
* ```
|
|
296
|
+
*
|
|
297
|
+
* @remarks
|
|
298
|
+
* The intrinsic `@<name>.deleter` decorator is always rendered topmost (it
|
|
299
|
+
* must remain the outermost decorator). Any `decorators` passed to this
|
|
300
|
+
* component are rendered **between** `@<name>.deleter` and `def`, which is
|
|
301
|
+
* the correct position for wrappers that should decorate the underlying
|
|
302
|
+
* function before `deleter` re-binds it to the property.
|
|
256
303
|
*/
|
|
257
304
|
PropertyDeclaration.Deleter = taggedComponent(
|
|
258
305
|
deleterTag,
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import {
|
|
2
|
+
For,
|
|
3
|
+
List,
|
|
4
|
+
childrenArray,
|
|
5
|
+
splitProps,
|
|
6
|
+
type Children,
|
|
7
|
+
} from "@alloy-js/core";
|
|
8
|
+
import { snakeCase } from "change-case";
|
|
9
|
+
import { pydanticModule } from "../builtins/python.js";
|
|
10
|
+
import { Atom } from "./Atom.jsx";
|
|
11
|
+
import type { ClassDeclarationProps } from "./ClassDeclaration.js";
|
|
12
|
+
import { ClassDeclaration } from "./ClassDeclaration.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Keyword-style options for Pydantic v2 `ConfigDict`, using camelCase prop names
|
|
16
|
+
* that map to snake_case Python arguments (for example `validateAssignment` →
|
|
17
|
+
* `validate_assignment`).
|
|
18
|
+
*/
|
|
19
|
+
export interface PydanticModelConfigDictProps {
|
|
20
|
+
/** Resolve field aliases from a configured alias generator. */
|
|
21
|
+
aliasGenerator?: string;
|
|
22
|
+
/** Allow non-pydantic/arbitrary Python types in field annotations. */
|
|
23
|
+
arbitraryTypesAllowed?: boolean;
|
|
24
|
+
/** Coerce numeric input values to strings for `str` fields. */
|
|
25
|
+
coerceNumbersToStr?: boolean;
|
|
26
|
+
/** Behavior for unknown input keys: allow, forbid, or ignore. */
|
|
27
|
+
extra?: "allow" | "forbid" | "ignore";
|
|
28
|
+
/** Populate models from object attributes (ORM-style) instead of mapping keys. */
|
|
29
|
+
fromAttributes?: boolean;
|
|
30
|
+
/** Make models immutable (`frozen=True`). */
|
|
31
|
+
frozen?: boolean;
|
|
32
|
+
/** Hide input values in validation error messages. */
|
|
33
|
+
hideInputInErrors?: boolean;
|
|
34
|
+
/** Include JSON schema extras via a plain JSON-serializable object. */
|
|
35
|
+
jsonSchemaExtra?: Record<string, unknown>;
|
|
36
|
+
/** Use aliases in error locations instead of field names. */
|
|
37
|
+
locByAlias?: boolean;
|
|
38
|
+
/** Allow population by field name even when aliases are defined. */
|
|
39
|
+
populateByName?: boolean;
|
|
40
|
+
/** Re-validate model/dataclass instances on assignment boundaries. */
|
|
41
|
+
revalidateInstances?: "always" | "never" | "subclass-instances";
|
|
42
|
+
/** JSON serialization format for bytes values. */
|
|
43
|
+
serJsonBytes?: "utf8" | "base64" | "hex";
|
|
44
|
+
/** JSON serialization behavior for Infinity/NaN values. */
|
|
45
|
+
serJsonInfNan?: "null" | "constants" | "strings";
|
|
46
|
+
/** Upper-bound for constrained string lengths at model level. */
|
|
47
|
+
strMaxLength?: number;
|
|
48
|
+
/** Lower-bound for constrained string lengths at model level. */
|
|
49
|
+
strMinLength?: number;
|
|
50
|
+
/** Strip leading/trailing whitespace from all `str` fields. */
|
|
51
|
+
strStripWhitespace?: boolean;
|
|
52
|
+
/** Convert all `str` values to lowercase. */
|
|
53
|
+
strToLower?: boolean;
|
|
54
|
+
/** Convert all `str` values to uppercase. */
|
|
55
|
+
strToUpper?: boolean;
|
|
56
|
+
/** Enable strict validation globally for the model. */
|
|
57
|
+
strict?: boolean;
|
|
58
|
+
/** Use enum `.value` instead of enum instances during serialization. */
|
|
59
|
+
useEnumValues?: boolean;
|
|
60
|
+
/** JSON validation format for bytes values. */
|
|
61
|
+
valJsonBytes?: "utf8" | "base64" | "hex";
|
|
62
|
+
/** Re-validate when attributes are assigned after model creation. */
|
|
63
|
+
validateAssignment?: boolean;
|
|
64
|
+
/** Validate default values in addition to provided input values. */
|
|
65
|
+
validateDefault?: boolean;
|
|
66
|
+
/** Validate return values for call validators. */
|
|
67
|
+
validateReturn?: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const PydanticModelConfigKeys = [
|
|
71
|
+
"aliasGenerator",
|
|
72
|
+
"arbitraryTypesAllowed",
|
|
73
|
+
"coerceNumbersToStr",
|
|
74
|
+
"frozen",
|
|
75
|
+
"extra",
|
|
76
|
+
"fromAttributes",
|
|
77
|
+
"hideInputInErrors",
|
|
78
|
+
"jsonSchemaExtra",
|
|
79
|
+
"locByAlias",
|
|
80
|
+
"populateByName",
|
|
81
|
+
"revalidateInstances",
|
|
82
|
+
"serJsonBytes",
|
|
83
|
+
"serJsonInfNan",
|
|
84
|
+
"strMinLength",
|
|
85
|
+
"strMaxLength",
|
|
86
|
+
"strStripWhitespace",
|
|
87
|
+
"strToLower",
|
|
88
|
+
"strToUpper",
|
|
89
|
+
"strict",
|
|
90
|
+
"useEnumValues",
|
|
91
|
+
"valJsonBytes",
|
|
92
|
+
"validateAssignment",
|
|
93
|
+
"validateDefault",
|
|
94
|
+
"validateReturn",
|
|
95
|
+
] as const satisfies readonly (keyof PydanticModelConfigDictProps)[];
|
|
96
|
+
|
|
97
|
+
export interface PydanticClassDeclarationProps
|
|
98
|
+
extends ClassDeclarationProps,
|
|
99
|
+
PydanticModelConfigDictProps {
|
|
100
|
+
/**
|
|
101
|
+
* Canonical structured config object for `ConfigDict(...)`. Values here are
|
|
102
|
+
* merged with top-level config props.
|
|
103
|
+
*
|
|
104
|
+
* Top-level config props take precedence over `modelConfig` when the same key
|
|
105
|
+
* is provided in both places.
|
|
106
|
+
*/
|
|
107
|
+
modelConfig?: PydanticModelConfigDictProps;
|
|
108
|
+
/**
|
|
109
|
+
* Emits `model_config = <expression>` verbatim (use for arbitrary `ConfigDict`
|
|
110
|
+
* kwargs or dynamic config). Takes precedence over both `modelConfig` and
|
|
111
|
+
* top-level config props.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* A typical value emits `ConfigDict(frozen=True, extra="forbid")`.
|
|
115
|
+
*/
|
|
116
|
+
modelConfigExpression?: Children;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Renders a Python class that subclasses Pydantic's `BaseModel`:
|
|
121
|
+
* `class Name(BaseModel): ...`.
|
|
122
|
+
*
|
|
123
|
+
* When `bases` is omitted, the class extends `pydanticModule["."].BaseModel`.
|
|
124
|
+
* Pass `bases` to inherit from another generated class (or to combine bases explicitly).
|
|
125
|
+
*
|
|
126
|
+
* Optional `modelConfig={{...}}` and top-level config props (for example
|
|
127
|
+
* `frozen`, `strict`, `extra`) emit `model_config = ConfigDict(...)` for common
|
|
128
|
+
* Pydantic v2 model settings (see {@link PydanticModelConfigDictProps}).
|
|
129
|
+
* When both are used, top-level props override `modelConfig` keys.
|
|
130
|
+
*
|
|
131
|
+
* Fields are ordinary class body declarations; use `pydanticModule["."].Field` in
|
|
132
|
+
* initializers when you need `Field(...)`.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```tsx
|
|
136
|
+
* import { pydanticModule } from "@alloy-js/python";
|
|
137
|
+
* import * as py from "@alloy-js/python";
|
|
138
|
+
*
|
|
139
|
+
* <py.PydanticClassDeclaration name="User" frozen>
|
|
140
|
+
* <py.VariableDeclaration instanceVariable omitNone name="id" type="int" />
|
|
141
|
+
* <py.VariableDeclaration
|
|
142
|
+
* instanceVariable
|
|
143
|
+
* name="name"
|
|
144
|
+
* type="str"
|
|
145
|
+
* initializer={"Field(default=\"anonymous\")"}
|
|
146
|
+
* />
|
|
147
|
+
* </py.PydanticClassDeclaration>
|
|
148
|
+
* ```
|
|
149
|
+
*
|
|
150
|
+
* ```py
|
|
151
|
+
* from pydantic import BaseModel
|
|
152
|
+
* from pydantic import ConfigDict
|
|
153
|
+
* from pydantic import Field
|
|
154
|
+
*
|
|
155
|
+
* class User(BaseModel):
|
|
156
|
+
* model_config = ConfigDict(frozen=True)
|
|
157
|
+
* id: int
|
|
158
|
+
* name: str = Field(default="anonymous")
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export function PydanticClassDeclaration(props: PydanticClassDeclarationProps) {
|
|
162
|
+
const [modelConfigProps, bodyProps, rest] = splitProps(
|
|
163
|
+
props,
|
|
164
|
+
PydanticModelConfigKeys,
|
|
165
|
+
["modelConfig", "modelConfigExpression", "children"],
|
|
166
|
+
);
|
|
167
|
+
const bases = rest.bases ?? [pydanticModule["."].BaseModel];
|
|
168
|
+
const { modelConfig, modelConfigExpression, children } = bodyProps;
|
|
169
|
+
|
|
170
|
+
const configEntries: Array<[string, unknown]> = [];
|
|
171
|
+
if (modelConfigExpression === undefined) {
|
|
172
|
+
for (const key of PydanticModelConfigKeys) {
|
|
173
|
+
const value = modelConfigProps[key] ?? modelConfig?.[key];
|
|
174
|
+
if (value === undefined) continue;
|
|
175
|
+
configEntries.push([snakeCase(key), value]);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const hasStructuredModelConfig =
|
|
179
|
+
modelConfigExpression === undefined && configEntries.length > 0;
|
|
180
|
+
const hasExpressionModelConfig = modelConfigExpression !== undefined;
|
|
181
|
+
|
|
182
|
+
const bodyItems: Children[] = [];
|
|
183
|
+
if (hasExpressionModelConfig) {
|
|
184
|
+
bodyItems.push(
|
|
185
|
+
<>
|
|
186
|
+
{"model_config = "}
|
|
187
|
+
{modelConfigExpression}
|
|
188
|
+
</>,
|
|
189
|
+
);
|
|
190
|
+
} else if (hasStructuredModelConfig) {
|
|
191
|
+
bodyItems.push(
|
|
192
|
+
<>
|
|
193
|
+
{"model_config = "}
|
|
194
|
+
{pydanticModule["."].ConfigDict}
|
|
195
|
+
{"("}
|
|
196
|
+
<For each={configEntries} comma space>
|
|
197
|
+
{([k, v]) => (
|
|
198
|
+
<>
|
|
199
|
+
{k}=<Atom jsValue={v} />
|
|
200
|
+
</>
|
|
201
|
+
)}
|
|
202
|
+
</For>
|
|
203
|
+
{")"}
|
|
204
|
+
</>,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
bodyItems.push(...childrenArray(() => children));
|
|
208
|
+
|
|
209
|
+
return (
|
|
210
|
+
<ClassDeclaration
|
|
211
|
+
name={rest.name}
|
|
212
|
+
bases={bases}
|
|
213
|
+
doc={rest.doc}
|
|
214
|
+
refkey={rest.refkey}
|
|
215
|
+
decorators={rest.decorators}
|
|
216
|
+
>
|
|
217
|
+
<List hardline>
|
|
218
|
+
<For each={bodyItems}>{(item) => item}</For>
|
|
219
|
+
</List>
|
|
220
|
+
</ClassDeclaration>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createMethodSymbol } from "../symbols/factories.js";
|
|
2
|
+
import { DecoratorList } from "./DecoratorList.jsx";
|
|
2
3
|
import type { CommonFunctionProps } from "./FunctionBase.js";
|
|
3
4
|
import { MethodDeclarationBase } from "./MethodBase.js";
|
|
4
5
|
|
|
@@ -17,6 +18,9 @@ import { MethodDeclarationBase } from "./MethodBase.js";
|
|
|
17
18
|
* def identity(value: int) -> None:
|
|
18
19
|
* return value
|
|
19
20
|
* ```
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* Use **`decorators`** for decorators that must appear above `@staticmethod`.
|
|
20
24
|
*/
|
|
21
25
|
export interface StaticMethodDeclarationProps extends CommonFunctionProps {
|
|
22
26
|
abstract?: boolean;
|
|
@@ -24,11 +28,13 @@ export interface StaticMethodDeclarationProps extends CommonFunctionProps {
|
|
|
24
28
|
|
|
25
29
|
export function StaticMethodDeclaration(props: StaticMethodDeclarationProps) {
|
|
26
30
|
const sym = createMethodSymbol(props.name, { refkeys: props.refkey });
|
|
31
|
+
const { decorators, ...rest } = props;
|
|
27
32
|
return (
|
|
28
33
|
<>
|
|
34
|
+
<DecoratorList decorators={decorators} />
|
|
29
35
|
{"@staticmethod"}
|
|
30
36
|
<hbr />
|
|
31
|
-
<MethodDeclarationBase functionType="static" {...
|
|
37
|
+
<MethodDeclarationBase functionType="static" {...rest} sym={sym} />
|
|
32
38
|
</>
|
|
33
39
|
);
|
|
34
40
|
}
|
package/src/components/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ export * from "./MemberScope.jsx";
|
|
|
19
19
|
export type { MethodDeclarationBaseProps } from "./MethodBase.js";
|
|
20
20
|
export * from "./MethodDeclaration.js";
|
|
21
21
|
export * from "./PropertyDeclaration.js";
|
|
22
|
+
export * from "./PydanticClassDeclaration.js";
|
|
22
23
|
export * from "./PyDoc.js";
|
|
23
24
|
export * from "./PythonBlock.js";
|
|
24
25
|
export * from "./Reference.js";
|