@alloy-js/python 0.2.0-dev.3 → 0.2.0-dev.4

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 (205) hide show
  1. package/dist/src/builtins/python.d.ts +3 -0
  2. package/dist/src/builtins/python.d.ts.map +1 -1
  3. package/dist/src/builtins/python.js +6 -0
  4. package/dist/src/builtins/python.js.map +1 -1
  5. package/dist/src/components/CallSignature.d.ts +4 -15
  6. package/dist/src/components/CallSignature.d.ts.map +1 -1
  7. package/dist/src/components/CallSignature.js +13 -67
  8. package/dist/src/components/CallSignature.js.map +1 -1
  9. package/dist/src/components/ClassMethodDeclaration.d.ts +22 -0
  10. package/dist/src/components/ClassMethodDeclaration.d.ts.map +1 -0
  11. package/dist/src/components/ClassMethodDeclaration.js +32 -0
  12. package/dist/src/components/ClassMethodDeclaration.js.map +1 -0
  13. package/dist/src/components/ConstructorDeclaration.d.ts +21 -0
  14. package/dist/src/components/ConstructorDeclaration.d.ts.map +1 -0
  15. package/dist/src/components/ConstructorDeclaration.js +35 -0
  16. package/dist/src/components/ConstructorDeclaration.js.map +1 -0
  17. package/dist/src/components/DunderMethodDeclaration.d.ts +21 -0
  18. package/dist/src/components/DunderMethodDeclaration.d.ts.map +1 -0
  19. package/dist/src/components/DunderMethodDeclaration.js +29 -0
  20. package/dist/src/components/DunderMethodDeclaration.js.map +1 -0
  21. package/dist/src/components/EnumDeclaration.d.ts +11 -32
  22. package/dist/src/components/EnumDeclaration.d.ts.map +1 -1
  23. package/dist/src/components/EnumDeclaration.js +10 -48
  24. package/dist/src/components/EnumDeclaration.js.map +1 -1
  25. package/dist/src/components/EnumMember.js +3 -3
  26. package/dist/src/components/EnumMember.js.map +1 -1
  27. package/dist/src/components/FunctionBase.d.ts +48 -0
  28. package/dist/src/components/FunctionBase.d.ts.map +1 -0
  29. package/dist/src/components/FunctionBase.js +91 -0
  30. package/dist/src/components/FunctionBase.js.map +1 -0
  31. package/dist/src/components/FunctionDeclaration.d.ts +11 -31
  32. package/dist/src/components/FunctionDeclaration.d.ts.map +1 -1
  33. package/dist/src/components/FunctionDeclaration.js +22 -79
  34. package/dist/src/components/FunctionDeclaration.js.map +1 -1
  35. package/dist/src/components/MethodBase.d.ts +29 -0
  36. package/dist/src/components/MethodBase.d.ts.map +1 -0
  37. package/dist/src/components/MethodBase.js +32 -0
  38. package/dist/src/components/MethodBase.js.map +1 -0
  39. package/dist/src/components/MethodDeclaration.d.ts +22 -0
  40. package/dist/src/components/MethodDeclaration.d.ts.map +1 -0
  41. package/dist/src/components/MethodDeclaration.js +34 -0
  42. package/dist/src/components/MethodDeclaration.js.map +1 -0
  43. package/dist/src/components/PropertyDeclaration.d.ts +71 -0
  44. package/dist/src/components/PropertyDeclaration.d.ts.map +1 -0
  45. package/dist/src/components/PropertyDeclaration.js +227 -0
  46. package/dist/src/components/PropertyDeclaration.js.map +1 -0
  47. package/dist/src/components/PyDoc.d.ts +107 -42
  48. package/dist/src/components/PyDoc.d.ts.map +1 -1
  49. package/dist/src/components/PyDoc.js +845 -181
  50. package/dist/src/components/PyDoc.js.map +1 -1
  51. package/dist/src/components/SourceFile.d.ts +24 -0
  52. package/dist/src/components/SourceFile.d.ts.map +1 -1
  53. package/dist/src/components/SourceFile.js +28 -1
  54. package/dist/src/components/SourceFile.js.map +1 -1
  55. package/dist/src/components/StaticMethodDeclaration.d.ts +22 -0
  56. package/dist/src/components/StaticMethodDeclaration.d.ts.map +1 -0
  57. package/dist/src/components/StaticMethodDeclaration.js +32 -0
  58. package/dist/src/components/StaticMethodDeclaration.js.map +1 -0
  59. package/dist/src/components/TypeArguments.d.ts +9 -0
  60. package/dist/src/components/TypeArguments.d.ts.map +1 -0
  61. package/dist/src/components/TypeArguments.js +18 -0
  62. package/dist/src/components/TypeArguments.js.map +1 -0
  63. package/dist/src/components/TypeReference.d.ts +14 -0
  64. package/dist/src/components/TypeReference.d.ts.map +1 -0
  65. package/dist/src/components/TypeReference.js +29 -0
  66. package/dist/src/components/TypeReference.js.map +1 -0
  67. package/dist/src/components/UnionTypeExpression.d.ts +1 -2
  68. package/dist/src/components/UnionTypeExpression.d.ts.map +1 -1
  69. package/dist/src/components/UnionTypeExpression.js +3 -11
  70. package/dist/src/components/UnionTypeExpression.js.map +1 -1
  71. package/dist/src/components/VariableDeclaration.d.ts.map +1 -1
  72. package/dist/src/components/VariableDeclaration.js +3 -3
  73. package/dist/src/components/VariableDeclaration.js.map +1 -1
  74. package/dist/src/components/index.d.ts +10 -0
  75. package/dist/src/components/index.d.ts.map +1 -1
  76. package/dist/src/components/index.js +9 -0
  77. package/dist/src/components/index.js.map +1 -1
  78. package/dist/src/parameter-descriptor.d.ts +1 -4
  79. package/dist/src/parameter-descriptor.d.ts.map +1 -1
  80. package/dist/src/parameter-descriptor.js +7 -1
  81. package/dist/src/parameter-descriptor.js.map +1 -1
  82. package/dist/src/symbol-creation.d.ts +4 -0
  83. package/dist/src/symbol-creation.d.ts.map +1 -1
  84. package/dist/src/symbol-creation.js +12 -0
  85. package/dist/src/symbol-creation.js.map +1 -1
  86. package/dist/src/symbols/factories.d.ts +15 -0
  87. package/dist/src/symbols/factories.d.ts.map +1 -0
  88. package/dist/src/symbols/factories.js +28 -0
  89. package/dist/src/symbols/factories.js.map +1 -0
  90. package/dist/src/symbols/index.d.ts +1 -0
  91. package/dist/src/symbols/index.d.ts.map +1 -1
  92. package/dist/src/symbols/index.js +1 -0
  93. package/dist/src/symbols/index.js.map +1 -1
  94. package/dist/src/symbols/reference.d.ts +1 -1
  95. package/dist/src/symbols/reference.d.ts.map +1 -1
  96. package/dist/src/symbols/reference.js +1 -1
  97. package/dist/src/symbols/reference.js.map +1 -1
  98. package/dist/src/utils.d.ts.map +1 -1
  99. package/dist/src/utils.js +1 -1
  100. package/dist/src/utils.js.map +1 -1
  101. package/dist/test/callsignatures.test.js +42 -64
  102. package/dist/test/callsignatures.test.js.map +1 -1
  103. package/dist/test/class-method-declaration.test.d.ts +2 -0
  104. package/dist/test/class-method-declaration.test.d.ts.map +1 -0
  105. package/dist/test/class-method-declaration.test.js +61 -0
  106. package/dist/test/class-method-declaration.test.js.map +1 -0
  107. package/dist/test/classdeclarations.test.js +6 -8
  108. package/dist/test/classdeclarations.test.js.map +1 -1
  109. package/dist/test/constructordeclaration.test.d.ts +2 -0
  110. package/dist/test/constructordeclaration.test.d.ts.map +1 -0
  111. package/dist/test/constructordeclaration.test.js +58 -0
  112. package/dist/test/constructordeclaration.test.js.map +1 -0
  113. package/dist/test/dundermethoddeclaration.test.d.ts +2 -0
  114. package/dist/test/dundermethoddeclaration.test.d.ts.map +1 -0
  115. package/dist/test/dundermethoddeclaration.test.js +65 -0
  116. package/dist/test/dundermethoddeclaration.test.js.map +1 -0
  117. package/dist/test/enums.test.js +14 -16
  118. package/dist/test/enums.test.js.map +1 -1
  119. package/dist/test/externals.test.js +2 -4
  120. package/dist/test/externals.test.js.map +1 -1
  121. package/dist/test/factories.test.d.ts +2 -0
  122. package/dist/test/factories.test.d.ts.map +1 -0
  123. package/dist/test/factories.test.js +78 -0
  124. package/dist/test/factories.test.js.map +1 -0
  125. package/dist/test/functiondeclaration.test.js +213 -59
  126. package/dist/test/functiondeclaration.test.js.map +1 -1
  127. package/dist/test/memberexpressions.test.js +1 -1
  128. package/dist/test/memberexpressions.test.js.map +1 -1
  129. package/dist/test/methoddeclaration.test.d.ts +2 -0
  130. package/dist/test/methoddeclaration.test.d.ts.map +1 -0
  131. package/dist/test/methoddeclaration.test.js +239 -0
  132. package/dist/test/methoddeclaration.test.js.map +1 -0
  133. package/dist/test/namepolicies.test.js +1 -2
  134. package/dist/test/namepolicies.test.js.map +1 -1
  135. package/dist/test/propertydeclaration.test.d.ts +2 -0
  136. package/dist/test/propertydeclaration.test.d.ts.map +1 -0
  137. package/dist/test/propertydeclaration.test.js +229 -0
  138. package/dist/test/propertydeclaration.test.js.map +1 -0
  139. package/dist/test/pydocs.test.js +926 -126
  140. package/dist/test/pydocs.test.js.map +1 -1
  141. package/dist/test/references.test.js +1 -5
  142. package/dist/test/references.test.js.map +1 -1
  143. package/dist/test/sourcefiles.test.js +90 -1
  144. package/dist/test/sourcefiles.test.js.map +1 -1
  145. package/dist/test/staticmethoddeclaration.test.d.ts +2 -0
  146. package/dist/test/staticmethoddeclaration.test.d.ts.map +1 -0
  147. package/dist/test/staticmethoddeclaration.test.js +61 -0
  148. package/dist/test/staticmethoddeclaration.test.js.map +1 -0
  149. package/dist/test/typereference.test.d.ts +2 -0
  150. package/dist/test/typereference.test.d.ts.map +1 -0
  151. package/dist/test/typereference.test.js +51 -0
  152. package/dist/test/typereference.test.js.map +1 -0
  153. package/dist/test/uniontypeexpression.test.js +152 -15
  154. package/dist/test/uniontypeexpression.test.js.map +1 -1
  155. package/dist/test/variables.test.js +28 -19
  156. package/dist/test/variables.test.js.map +1 -1
  157. package/dist/tsconfig.tsbuildinfo +1 -1
  158. package/package.json +2 -2
  159. package/src/builtins/python.ts +7 -0
  160. package/src/components/CallSignature.tsx +17 -69
  161. package/src/components/ClassMethodDeclaration.tsx +34 -0
  162. package/src/components/ConstructorDeclaration.tsx +37 -0
  163. package/src/components/DunderMethodDeclaration.tsx +30 -0
  164. package/src/components/EnumDeclaration.tsx +16 -44
  165. package/src/components/EnumMember.tsx +3 -3
  166. package/src/components/FunctionBase.tsx +88 -0
  167. package/src/components/FunctionDeclaration.tsx +18 -82
  168. package/src/components/MethodBase.tsx +53 -0
  169. package/src/components/MethodDeclaration.tsx +27 -0
  170. package/src/components/PropertyDeclaration.tsx +264 -0
  171. package/src/components/PyDoc.tsx +795 -195
  172. package/src/components/SourceFile.tsx +29 -0
  173. package/src/components/StaticMethodDeclaration.tsx +34 -0
  174. package/src/components/TypeArguments.tsx +24 -0
  175. package/src/components/TypeReference.tsx +33 -0
  176. package/src/components/UnionTypeExpression.tsx +4 -15
  177. package/src/components/VariableDeclaration.tsx +1 -3
  178. package/src/components/index.ts +10 -0
  179. package/src/parameter-descriptor.ts +6 -5
  180. package/src/symbol-creation.ts +17 -0
  181. package/src/symbols/factories.ts +39 -0
  182. package/src/symbols/index.ts +1 -0
  183. package/src/symbols/reference.tsx +3 -5
  184. package/src/utils.ts +0 -2
  185. package/temp/api.json +5281 -2273
  186. package/test/callsignatures.test.tsx +102 -74
  187. package/test/class-method-declaration.test.tsx +53 -0
  188. package/test/classdeclarations.test.tsx +7 -9
  189. package/test/constructordeclaration.test.tsx +48 -0
  190. package/test/dundermethoddeclaration.test.tsx +53 -0
  191. package/test/enums.test.tsx +14 -16
  192. package/test/externals.test.tsx +5 -7
  193. package/test/factories.test.tsx +72 -0
  194. package/test/functiondeclaration.test.tsx +196 -44
  195. package/test/memberexpressions.test.tsx +7 -2
  196. package/test/methoddeclaration.test.tsx +202 -0
  197. package/test/namepolicies.test.tsx +1 -2
  198. package/test/propertydeclaration.test.tsx +192 -0
  199. package/test/pydocs.test.tsx +1093 -129
  200. package/test/references.test.tsx +1 -1
  201. package/test/sourcefiles.test.tsx +100 -1
  202. package/test/staticmethoddeclaration.test.tsx +49 -0
  203. package/test/typereference.test.tsx +52 -0
  204. package/test/uniontypeexpression.test.tsx +169 -34
  205. package/test/variables.test.tsx +27 -16
@@ -0,0 +1,72 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import * as py from "../src/index.js";
3
+ import { toSourceText } from "./utils.js";
4
+
5
+ describe("Symbol factories", () => {
6
+ it("createMethodSymbol throws outside class", () => {
7
+ expect(() => {
8
+ toSourceText([<py.MethodDeclaration name="m" />]);
9
+ }).toThrow('Method "m" must be declared inside a class (member scope)');
10
+ });
11
+
12
+ it("createMethodSymbol succeeds inside class", () => {
13
+ const result = toSourceText([
14
+ <py.ClassDeclaration name="C">
15
+ <py.MethodDeclaration name="m" />
16
+ </py.ClassDeclaration>,
17
+ ]);
18
+ expect(result).toContain("def m(self):");
19
+ });
20
+
21
+ it("createFunctionSymbol usable in member scope (top-level function component still works nested)", () => {
22
+ const result = toSourceText([
23
+ <py.ClassDeclaration name="C">
24
+ <py.StatementList>
25
+ <py.FunctionDeclaration name="f" />
26
+ </py.StatementList>
27
+ </py.ClassDeclaration>,
28
+ ]);
29
+ // Nested free functions render without self/cls
30
+ expect(result).toContain("def f():");
31
+ });
32
+ });
33
+
34
+ describe("Validation Errors", () => {
35
+ it("throws error when PropertyDeclaration is used outside of a class", () => {
36
+ expect(() => {
37
+ toSourceText([<py.PropertyDeclaration name="x" />]);
38
+ }).toThrow('Method "x" must be declared inside a class (member scope)');
39
+ });
40
+
41
+ it("throws error when MethodDeclaration is used outside of a class", () => {
42
+ expect(() => {
43
+ toSourceText([<py.MethodDeclaration name="my_method" />]);
44
+ }).toThrow(
45
+ 'Method "my_method" must be declared inside a class (member scope)',
46
+ );
47
+ });
48
+
49
+ it("throws error when ClassMethodDeclaration is used outside of a class", () => {
50
+ expect(() => {
51
+ toSourceText([<py.ClassMethodDeclaration name="my_class_method" />]);
52
+ }).toThrow(
53
+ 'Method "my_class_method" must be declared inside a class (member scope)',
54
+ );
55
+ });
56
+
57
+ it("throws error when StaticMethodDeclaration is used outside of a class", () => {
58
+ expect(() => {
59
+ toSourceText([<py.StaticMethodDeclaration name="my_static_method" />]);
60
+ }).toThrow(
61
+ 'Method "my_static_method" must be declared inside a class (member scope)',
62
+ );
63
+ });
64
+
65
+ it("throws error when DunderMethodDeclaration is used outside of a class", () => {
66
+ expect(() => {
67
+ toSourceText([<py.DunderMethodDeclaration name="__init__" />]);
68
+ }).toThrow(
69
+ 'Method "__init__" must be declared inside a class (member scope)',
70
+ );
71
+ });
72
+ });
@@ -1,7 +1,8 @@
1
- import { namekey, refkey } from "@alloy-js/core";
1
+ import { code, namekey, refkey } from "@alloy-js/core";
2
2
  import { d } from "@alloy-js/core/testing";
3
3
  import { describe, expect, it } from "vitest";
4
4
  import * as py from "../src/index.js";
5
+ import { abcModule } from "../src/index.js";
5
6
  import {
6
7
  assertFileContents,
7
8
  toSourceText,
@@ -74,24 +75,6 @@ describe("Function Declaration", () => {
74
75
  `);
75
76
  });
76
77
 
77
- it("renders an instance function with a body", () => {
78
- const result = toSourceText([
79
- <py.ClassDeclaration name="MyClass">
80
- <py.FunctionDeclaration name="bar" instanceFunction={true}>
81
- print('hi')
82
- </py.FunctionDeclaration>
83
- </py.ClassDeclaration>,
84
- ]);
85
- expect(result).toRenderTo(d`
86
- class MyClass:
87
- def bar(self):
88
- print('hi')
89
-
90
-
91
-
92
- `);
93
- });
94
-
95
78
  it("renders a function with parameters", () => {
96
79
  const result = toSourceText([
97
80
  <py.FunctionDeclaration
@@ -120,7 +103,10 @@ describe("Function Declaration", () => {
120
103
  it("renders an __init__ function with no body as 'pass'", () => {
121
104
  const result = toSourceText([
122
105
  <py.ClassDeclaration name="MyClass">
123
- <py.InitFunctionDeclaration parameters={[{ name: "x" }]} />
106
+ <py.DunderMethodDeclaration
107
+ name="__init__"
108
+ parameters={[{ name: "x" }]}
109
+ />
124
110
  </py.ClassDeclaration>,
125
111
  ]);
126
112
  expect(result).toRenderTo(d`
@@ -144,7 +130,7 @@ describe("Function Declaration", () => {
144
130
  it("can be an async function with returnType", () => {
145
131
  expect(
146
132
  toSourceText([
147
- <py.FunctionDeclaration async name="foo" returnType="Foo" />,
133
+ <py.FunctionDeclaration async name="foo" returnType={"Foo"} />,
148
134
  ]),
149
135
  ).toBe(d`
150
136
  async def foo() -> Foo:
@@ -154,6 +140,24 @@ describe("Function Declaration", () => {
154
140
  });
155
141
 
156
142
  it("can be an async function with returnType element with Reference", () => {
143
+ expect(
144
+ toSourceText([
145
+ <py.StatementList>
146
+ <py.ClassDeclaration name="Foo" refkey={refkey("Foo")} />
147
+ <py.FunctionDeclaration async name="foo" returnType={refkey("Foo")} />
148
+ </py.StatementList>,
149
+ ]),
150
+ ).toBe(d`
151
+ class Foo:
152
+ pass
153
+
154
+ async def foo() -> Foo:
155
+ pass
156
+
157
+ `);
158
+ });
159
+
160
+ it("can be an async function with returnType element with list of References", () => {
157
161
  expect(
158
162
  toSourceText([
159
163
  <py.StatementList>
@@ -161,7 +165,7 @@ describe("Function Declaration", () => {
161
165
  <py.FunctionDeclaration
162
166
  async
163
167
  name="foo"
164
- returnType={<py.Reference refkey={refkey("Foo")} />}
168
+ returnType={code`list[${refkey("Foo")}]`}
165
169
  />
166
170
  </py.StatementList>,
167
171
  ]),
@@ -169,15 +173,66 @@ describe("Function Declaration", () => {
169
173
  class Foo:
170
174
  pass
171
175
 
172
- async def foo() -> Foo:
176
+ async def foo() -> list[Foo]:
173
177
  pass
174
178
 
175
179
  `);
176
180
  });
177
181
 
182
+ it("can be an async dunder method", () => {
183
+ const decl = (
184
+ <py.StatementList>
185
+ <py.ClassDeclaration name="MyClass">
186
+ <py.StatementList>
187
+ <py.DunderMethodDeclaration
188
+ async
189
+ name="__aenter__"
190
+ returnType={"MyClass"}
191
+ >
192
+ return self
193
+ </py.DunderMethodDeclaration>
194
+ </py.StatementList>
195
+ </py.ClassDeclaration>
196
+ </py.StatementList>
197
+ );
198
+
199
+ expect(toSourceText([decl])).toBe(d`
200
+ class MyClass:
201
+ async def __aenter__(self) -> MyClass:
202
+ return self
203
+
204
+
205
+ `);
206
+ });
207
+
208
+ it("can be an async constructor", () => {
209
+ const decl = (
210
+ <py.StatementList>
211
+ <py.ClassDeclaration name="MyClass">
212
+ <py.StatementList>
213
+ <py.ConstructorDeclaration async returnType={"MyClass"}>
214
+ return super().__new__(cls)
215
+ </py.ConstructorDeclaration>
216
+ </py.StatementList>
217
+ </py.ClassDeclaration>
218
+ </py.StatementList>
219
+ );
220
+
221
+ expect(toSourceText([decl])).toBe(d`
222
+ class MyClass:
223
+ async def __new__(cls) -> MyClass:
224
+ return super().__new__(cls)
225
+
226
+
227
+ `);
228
+ });
229
+
178
230
  it("supports parameters", () => {
179
231
  const decl = (
180
- <py.FunctionDeclaration name="foo" parameters={["a", "b"]}>
232
+ <py.FunctionDeclaration
233
+ name="foo"
234
+ parameters={[{ name: "a" }, { name: "b" }]}
235
+ >
181
236
  return a + b
182
237
  </py.FunctionDeclaration>
183
238
  );
@@ -192,7 +247,7 @@ describe("Function Declaration", () => {
192
247
  const decl = (
193
248
  <py.FunctionDeclaration
194
249
  name="foo"
195
- parameters={["a", "b"]}
250
+ parameters={[{ name: "a" }, { name: "b" }]}
196
251
  typeParameters={["T", "U"]}
197
252
  >
198
253
  return a + b
@@ -205,42 +260,95 @@ describe("Function Declaration", () => {
205
260
 
206
261
  `);
207
262
  });
208
- it("renders function with parameters", () => {
263
+ it("renders abstract methods", () => {
264
+ const parameters = [{ name: "x", type: "int" }];
265
+ const decl = (
266
+ <py.StatementList>
267
+ <py.ClassDeclaration name="MyClass">
268
+ <py.StatementList>
269
+ <py.MethodDeclaration
270
+ name="methoddef"
271
+ parameters={parameters}
272
+ abstract
273
+ />
274
+ <py.ClassMethodDeclaration
275
+ name="classdef"
276
+ parameters={parameters}
277
+ abstract
278
+ />
279
+ <py.StaticMethodDeclaration
280
+ name="staticdef"
281
+ parameters={parameters}
282
+ abstract
283
+ />
284
+ </py.StatementList>
285
+ </py.ClassDeclaration>
286
+ </py.StatementList>
287
+ );
288
+
289
+ expect(toSourceText([decl], { externals: [abcModule] })).toBe(d`
290
+ from abc import abstractmethod
291
+
292
+ class MyClass:
293
+ @abstractmethod
294
+ def methoddef(self, x: int):
295
+ pass
296
+
297
+ @classmethod
298
+ @abstractmethod
299
+ def classdef(cls, x: int):
300
+ pass
301
+
302
+ @staticmethod
303
+ @abstractmethod
304
+ def staticdef(x: int):
305
+ pass
306
+
307
+
308
+ `);
309
+ });
310
+ it("renders dunder methods with parameters", () => {
209
311
  const parameters = [{ name: "x", type: "int" }];
210
312
  const decl = (
211
313
  <py.ClassDeclaration name="MyClass">
212
- <py.FunctionDeclaration
213
- name="foo"
214
- instanceFunction
215
- parameters={parameters}
216
- >
217
- self.attribute = "value"
218
- </py.FunctionDeclaration>
314
+ <py.StatementList>
315
+ <py.DunderMethodDeclaration name="__init__" parameters={parameters}>
316
+ self.attribute = "value"
317
+ </py.DunderMethodDeclaration>
318
+ <py.DunderMethodDeclaration name="__repr__" parameters={parameters}>
319
+ return "MyClass"
320
+ </py.DunderMethodDeclaration>
321
+ </py.StatementList>
219
322
  </py.ClassDeclaration>
220
323
  );
221
324
 
222
325
  expect(toSourceText([decl])).toBe(d`
223
326
  class MyClass:
224
- def foo(self, x: int):
327
+ def __init__(self, x: int):
225
328
  self.attribute = "value"
226
329
 
330
+ def __repr__(self, x: int):
331
+ return "MyClass"
332
+
227
333
 
228
334
  `);
229
335
  });
230
- it("renders __init__ function with parameters", () => {
231
- const parameters = [{ name: "x", type: "int" }];
336
+
337
+ it("renders dunder methods __new__", () => {
232
338
  const decl = (
233
339
  <py.ClassDeclaration name="MyClass">
234
- <py.InitFunctionDeclaration parameters={parameters}>
235
- self.attribute = "value"
236
- </py.InitFunctionDeclaration>
340
+ <py.StatementList>
341
+ <py.ConstructorDeclaration args kwargs>
342
+ pass
343
+ </py.ConstructorDeclaration>
344
+ </py.StatementList>
237
345
  </py.ClassDeclaration>
238
346
  );
239
347
 
240
348
  expect(toSourceText([decl])).toBe(d`
241
349
  class MyClass:
242
- def __init__(self, x: int):
243
- self.attribute = "value"
350
+ def __new__(cls, *args, **kwargs):
351
+ pass
244
352
 
245
353
 
246
354
  `);
@@ -309,12 +417,18 @@ describe("Function Declaration", () => {
309
417
  async
310
418
  name="foo"
311
419
  parameters={[
312
- { name: "x", type: <py.Reference refkey={refkey("A")} /> },
313
- { name: "y", type: <py.Reference refkey={refkey("B")} /> },
420
+ {
421
+ name: "x",
422
+ type: refkey("A"),
423
+ },
424
+ {
425
+ name: "y",
426
+ type: refkey("B"),
427
+ },
314
428
  ]}
315
429
  args={true}
316
430
  kwargs={true}
317
- returnType={<py.Reference refkey={refkey("Foo")} />}
431
+ returnType={refkey("Foo")}
318
432
  />
319
433
  </py.SourceFile>,
320
434
  ]);
@@ -345,4 +459,42 @@ describe("Function Declaration", () => {
345
459
  `,
346
460
  });
347
461
  });
462
+
463
+ it("throws error when PropertyDeclaration is used outside of a class", () => {
464
+ expect(() => {
465
+ toSourceText([<py.PropertyDeclaration name="x" />]);
466
+ }).toThrow('Method "x" must be declared inside a class (member scope)');
467
+ });
468
+
469
+ it("throws error when MethodDeclaration is used outside of a class", () => {
470
+ expect(() => {
471
+ toSourceText([<py.MethodDeclaration name="my_method" />]);
472
+ }).toThrow(
473
+ 'Method "my_method" must be declared inside a class (member scope)',
474
+ );
475
+ });
476
+
477
+ it("throws error when ClassMethodDeclaration is used outside of a class", () => {
478
+ expect(() => {
479
+ toSourceText([<py.ClassMethodDeclaration name="my_class_method" />]);
480
+ }).toThrow(
481
+ 'Method "my_class_method" must be declared inside a class (member scope)',
482
+ );
483
+ });
484
+
485
+ it("throws error when StaticMethodDeclaration is used outside of a class", () => {
486
+ expect(() => {
487
+ toSourceText([<py.StaticMethodDeclaration name="my_static_method" />]);
488
+ }).toThrow(
489
+ 'Method "my_static_method" must be declared inside a class (member scope)',
490
+ );
491
+ });
492
+
493
+ it("throws error when DunderMethodDeclaration is used outside of a class", () => {
494
+ expect(() => {
495
+ toSourceText([<py.DunderMethodDeclaration name="__init__" />]);
496
+ }).toThrow(
497
+ 'Method "__init__" must be declared inside a class (member scope)',
498
+ );
499
+ });
348
500
  });
@@ -424,7 +424,12 @@ describe("with refkeys", () => {
424
424
  const fooRef = refkey();
425
425
  const modelRef = refkey();
426
426
  const parameters: ParameterDescriptor[] = [
427
- { name: "foo", optional: true, refkey: fooRef, type: modelRef },
427
+ {
428
+ name: "foo",
429
+ default: null,
430
+ refkey: fooRef,
431
+ type: modelRef,
432
+ },
428
433
  ];
429
434
  const messageRef = refkey();
430
435
  const template = (
@@ -480,7 +485,7 @@ describe("with refkeys", () => {
480
485
  <VariableDeclaration
481
486
  name="prop1"
482
487
  refkey={interfaceMemberRefkey}
483
- type={"str"}
488
+ type="str"
484
489
  omitNone={true}
485
490
  />
486
491
  </ClassDeclaration>
@@ -0,0 +1,202 @@
1
+ import { d } from "@alloy-js/core/testing";
2
+ import { describe, expect, it } from "vitest";
3
+ import * as py from "../src/index.js";
4
+ import { abcModule } from "../src/index.js";
5
+ import { toSourceText } from "./utils.js";
6
+
7
+ describe("Method-like Declarations", () => {
8
+ it("renders an instance function with a body", () => {
9
+ const result = toSourceText([
10
+ <py.ClassDeclaration name="MyClass">
11
+ <py.MethodDeclaration name="bar">print('hi')</py.MethodDeclaration>
12
+ </py.ClassDeclaration>,
13
+ ]);
14
+ expect(result).toRenderTo(d`
15
+ class MyClass:
16
+ def bar(self):
17
+ print('hi')
18
+
19
+
20
+
21
+ `);
22
+ });
23
+
24
+ it("can be an async method", () => {
25
+ const decl = (
26
+ <py.StatementList>
27
+ <py.ClassDeclaration name="MyClass">
28
+ <py.StatementList>
29
+ <py.MethodDeclaration async name="my_method" returnType="str">
30
+ return "async result"
31
+ </py.MethodDeclaration>
32
+ </py.StatementList>
33
+ </py.ClassDeclaration>
34
+ </py.StatementList>
35
+ );
36
+
37
+ expect(toSourceText([decl])).toBe(d`
38
+ class MyClass:
39
+ async def my_method(self) -> str:
40
+ return "async result"
41
+
42
+
43
+ `);
44
+ });
45
+
46
+ it("can be an async class method", () => {
47
+ const decl = (
48
+ <py.StatementList>
49
+ <py.ClassDeclaration name="MyClass">
50
+ <py.StatementList>
51
+ <py.ClassMethodDeclaration
52
+ async
53
+ name="create_async"
54
+ returnType={"MyClass"}
55
+ >
56
+ return cls()
57
+ </py.ClassMethodDeclaration>
58
+ </py.StatementList>
59
+ </py.ClassDeclaration>
60
+ </py.StatementList>
61
+ );
62
+
63
+ expect(toSourceText([decl])).toBe(d`
64
+ class MyClass:
65
+ @classmethod
66
+ async def create_async(cls) -> MyClass:
67
+ return cls()
68
+
69
+
70
+ `);
71
+ });
72
+
73
+ it("can be an async static method", () => {
74
+ const decl = (
75
+ <py.StatementList>
76
+ <py.ClassDeclaration name="MyClass">
77
+ <py.StatementList>
78
+ <py.StaticMethodDeclaration async name="utility" returnType="str">
79
+ return "utility result"
80
+ </py.StaticMethodDeclaration>
81
+ </py.StatementList>
82
+ </py.ClassDeclaration>
83
+ </py.StatementList>
84
+ );
85
+
86
+ expect(toSourceText([decl])).toBe(d`
87
+ class MyClass:
88
+ @staticmethod
89
+ async def utility() -> str:
90
+ return "utility result"
91
+
92
+
93
+ `);
94
+ });
95
+
96
+ it("renders method with parameters", () => {
97
+ const parameters = [{ name: "x", type: "int" }];
98
+ const decl = (
99
+ <py.ClassDeclaration name="MyClass">
100
+ <py.MethodDeclaration name="foo" parameters={parameters}>
101
+ self.attribute = "value"
102
+ </py.MethodDeclaration>
103
+ </py.ClassDeclaration>
104
+ );
105
+
106
+ expect(toSourceText([decl])).toBe(d`
107
+ class MyClass:
108
+ def foo(self, x: int):
109
+ self.attribute = "value"
110
+
111
+
112
+ `);
113
+ });
114
+
115
+ it("renders class method with parameters", () => {
116
+ const parameters = [{ name: "x", type: "int" }];
117
+ const decl = (
118
+ <py.ClassDeclaration name="MyClass">
119
+ <py.ClassMethodDeclaration name="foo" parameters={parameters}>
120
+ self.attribute = "value"
121
+ </py.ClassMethodDeclaration>
122
+ </py.ClassDeclaration>
123
+ );
124
+
125
+ expect(toSourceText([decl])).toBe(d`
126
+ class MyClass:
127
+ @classmethod
128
+ def foo(cls, x: int):
129
+ self.attribute = "value"
130
+
131
+
132
+ `);
133
+ });
134
+
135
+ it("renders static method with parameters", () => {
136
+ const parameters = [{ name: "x", type: "int" }];
137
+ const decl = (
138
+ <py.ClassDeclaration name="MyClass">
139
+ <py.StaticMethodDeclaration name="foo" parameters={parameters}>
140
+ attribute = "value"
141
+ </py.StaticMethodDeclaration>
142
+ </py.ClassDeclaration>
143
+ );
144
+
145
+ expect(toSourceText([decl])).toBe(d`
146
+ class MyClass:
147
+ @staticmethod
148
+ def foo(x: int):
149
+ attribute = "value"
150
+
151
+
152
+ `);
153
+ });
154
+
155
+ it("renders abstract methods", () => {
156
+ const parameters = [{ name: "x", type: "int" }];
157
+ const decl = (
158
+ <py.StatementList>
159
+ <py.ClassDeclaration name="MyClass">
160
+ <py.StatementList>
161
+ <py.MethodDeclaration
162
+ name="methoddef"
163
+ parameters={parameters}
164
+ abstract
165
+ />
166
+ <py.ClassMethodDeclaration
167
+ name="classdef"
168
+ parameters={parameters}
169
+ abstract
170
+ />
171
+ <py.StaticMethodDeclaration
172
+ name="staticdef"
173
+ parameters={parameters}
174
+ abstract
175
+ />
176
+ </py.StatementList>
177
+ </py.ClassDeclaration>
178
+ </py.StatementList>
179
+ );
180
+
181
+ expect(toSourceText([decl], { externals: [abcModule] })).toBe(d`
182
+ from abc import abstractmethod
183
+
184
+ class MyClass:
185
+ @abstractmethod
186
+ def methoddef(self, x: int):
187
+ pass
188
+
189
+ @classmethod
190
+ @abstractmethod
191
+ def classdef(cls, x: int):
192
+ pass
193
+
194
+ @staticmethod
195
+ @abstractmethod
196
+ def staticdef(x: int):
197
+ pass
198
+
199
+
200
+ `);
201
+ });
202
+ });
@@ -20,9 +20,8 @@ it("correct formatting of class name", () => {
20
20
  it("correct formatting of Enum name and EnumMember names", () => {
21
21
  const result = toSourceText(
22
22
  [
23
- <py.EnumDeclaration
23
+ <py.FunctionalEnumDeclaration
24
24
  name="priority"
25
- style="functional"
26
25
  members={[
27
26
  { name: "high", value: 1 },
28
27
  { name: "Medium", value: 2 },