@alloy-js/python 0.2.0-dev.2 → 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 (209) 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/MemberExpression.d.ts.map +1 -1
  36. package/dist/src/components/MemberExpression.js +12 -13
  37. package/dist/src/components/MemberExpression.js.map +1 -1
  38. package/dist/src/components/MethodBase.d.ts +29 -0
  39. package/dist/src/components/MethodBase.d.ts.map +1 -0
  40. package/dist/src/components/MethodBase.js +32 -0
  41. package/dist/src/components/MethodBase.js.map +1 -0
  42. package/dist/src/components/MethodDeclaration.d.ts +22 -0
  43. package/dist/src/components/MethodDeclaration.d.ts.map +1 -0
  44. package/dist/src/components/MethodDeclaration.js +34 -0
  45. package/dist/src/components/MethodDeclaration.js.map +1 -0
  46. package/dist/src/components/PropertyDeclaration.d.ts +71 -0
  47. package/dist/src/components/PropertyDeclaration.d.ts.map +1 -0
  48. package/dist/src/components/PropertyDeclaration.js +227 -0
  49. package/dist/src/components/PropertyDeclaration.js.map +1 -0
  50. package/dist/src/components/PyDoc.d.ts +107 -42
  51. package/dist/src/components/PyDoc.d.ts.map +1 -1
  52. package/dist/src/components/PyDoc.js +845 -181
  53. package/dist/src/components/PyDoc.js.map +1 -1
  54. package/dist/src/components/SourceFile.d.ts +24 -0
  55. package/dist/src/components/SourceFile.d.ts.map +1 -1
  56. package/dist/src/components/SourceFile.js +28 -1
  57. package/dist/src/components/SourceFile.js.map +1 -1
  58. package/dist/src/components/StaticMethodDeclaration.d.ts +22 -0
  59. package/dist/src/components/StaticMethodDeclaration.d.ts.map +1 -0
  60. package/dist/src/components/StaticMethodDeclaration.js +32 -0
  61. package/dist/src/components/StaticMethodDeclaration.js.map +1 -0
  62. package/dist/src/components/TypeArguments.d.ts +9 -0
  63. package/dist/src/components/TypeArguments.d.ts.map +1 -0
  64. package/dist/src/components/TypeArguments.js +18 -0
  65. package/dist/src/components/TypeArguments.js.map +1 -0
  66. package/dist/src/components/TypeReference.d.ts +14 -0
  67. package/dist/src/components/TypeReference.d.ts.map +1 -0
  68. package/dist/src/components/TypeReference.js +29 -0
  69. package/dist/src/components/TypeReference.js.map +1 -0
  70. package/dist/src/components/UnionTypeExpression.d.ts +1 -2
  71. package/dist/src/components/UnionTypeExpression.d.ts.map +1 -1
  72. package/dist/src/components/UnionTypeExpression.js +3 -11
  73. package/dist/src/components/UnionTypeExpression.js.map +1 -1
  74. package/dist/src/components/VariableDeclaration.d.ts.map +1 -1
  75. package/dist/src/components/VariableDeclaration.js +3 -3
  76. package/dist/src/components/VariableDeclaration.js.map +1 -1
  77. package/dist/src/components/index.d.ts +10 -0
  78. package/dist/src/components/index.d.ts.map +1 -1
  79. package/dist/src/components/index.js +9 -0
  80. package/dist/src/components/index.js.map +1 -1
  81. package/dist/src/parameter-descriptor.d.ts +1 -4
  82. package/dist/src/parameter-descriptor.d.ts.map +1 -1
  83. package/dist/src/parameter-descriptor.js +7 -1
  84. package/dist/src/parameter-descriptor.js.map +1 -1
  85. package/dist/src/symbol-creation.d.ts +4 -0
  86. package/dist/src/symbol-creation.d.ts.map +1 -1
  87. package/dist/src/symbol-creation.js +12 -0
  88. package/dist/src/symbol-creation.js.map +1 -1
  89. package/dist/src/symbols/factories.d.ts +15 -0
  90. package/dist/src/symbols/factories.d.ts.map +1 -0
  91. package/dist/src/symbols/factories.js +28 -0
  92. package/dist/src/symbols/factories.js.map +1 -0
  93. package/dist/src/symbols/index.d.ts +1 -0
  94. package/dist/src/symbols/index.d.ts.map +1 -1
  95. package/dist/src/symbols/index.js +1 -0
  96. package/dist/src/symbols/index.js.map +1 -1
  97. package/dist/src/symbols/reference.d.ts +1 -1
  98. package/dist/src/symbols/reference.d.ts.map +1 -1
  99. package/dist/src/symbols/reference.js +1 -1
  100. package/dist/src/symbols/reference.js.map +1 -1
  101. package/dist/src/utils.d.ts.map +1 -1
  102. package/dist/src/utils.js +1 -1
  103. package/dist/src/utils.js.map +1 -1
  104. package/dist/test/callsignatures.test.js +42 -64
  105. package/dist/test/callsignatures.test.js.map +1 -1
  106. package/dist/test/class-method-declaration.test.d.ts +2 -0
  107. package/dist/test/class-method-declaration.test.d.ts.map +1 -0
  108. package/dist/test/class-method-declaration.test.js +61 -0
  109. package/dist/test/class-method-declaration.test.js.map +1 -0
  110. package/dist/test/classdeclarations.test.js +6 -8
  111. package/dist/test/classdeclarations.test.js.map +1 -1
  112. package/dist/test/constructordeclaration.test.d.ts +2 -0
  113. package/dist/test/constructordeclaration.test.d.ts.map +1 -0
  114. package/dist/test/constructordeclaration.test.js +58 -0
  115. package/dist/test/constructordeclaration.test.js.map +1 -0
  116. package/dist/test/dundermethoddeclaration.test.d.ts +2 -0
  117. package/dist/test/dundermethoddeclaration.test.d.ts.map +1 -0
  118. package/dist/test/dundermethoddeclaration.test.js +65 -0
  119. package/dist/test/dundermethoddeclaration.test.js.map +1 -0
  120. package/dist/test/enums.test.js +14 -16
  121. package/dist/test/enums.test.js.map +1 -1
  122. package/dist/test/externals.test.js +2 -4
  123. package/dist/test/externals.test.js.map +1 -1
  124. package/dist/test/factories.test.d.ts +2 -0
  125. package/dist/test/factories.test.d.ts.map +1 -0
  126. package/dist/test/factories.test.js +78 -0
  127. package/dist/test/factories.test.js.map +1 -0
  128. package/dist/test/functiondeclaration.test.js +213 -59
  129. package/dist/test/functiondeclaration.test.js.map +1 -1
  130. package/dist/test/memberexpressions.test.js +1 -1
  131. package/dist/test/memberexpressions.test.js.map +1 -1
  132. package/dist/test/methoddeclaration.test.d.ts +2 -0
  133. package/dist/test/methoddeclaration.test.d.ts.map +1 -0
  134. package/dist/test/methoddeclaration.test.js +239 -0
  135. package/dist/test/methoddeclaration.test.js.map +1 -0
  136. package/dist/test/namepolicies.test.js +1 -2
  137. package/dist/test/namepolicies.test.js.map +1 -1
  138. package/dist/test/propertydeclaration.test.d.ts +2 -0
  139. package/dist/test/propertydeclaration.test.d.ts.map +1 -0
  140. package/dist/test/propertydeclaration.test.js +229 -0
  141. package/dist/test/propertydeclaration.test.js.map +1 -0
  142. package/dist/test/pydocs.test.js +926 -126
  143. package/dist/test/pydocs.test.js.map +1 -1
  144. package/dist/test/references.test.js +1 -5
  145. package/dist/test/references.test.js.map +1 -1
  146. package/dist/test/sourcefiles.test.js +90 -1
  147. package/dist/test/sourcefiles.test.js.map +1 -1
  148. package/dist/test/staticmethoddeclaration.test.d.ts +2 -0
  149. package/dist/test/staticmethoddeclaration.test.d.ts.map +1 -0
  150. package/dist/test/staticmethoddeclaration.test.js +61 -0
  151. package/dist/test/staticmethoddeclaration.test.js.map +1 -0
  152. package/dist/test/typereference.test.d.ts +2 -0
  153. package/dist/test/typereference.test.d.ts.map +1 -0
  154. package/dist/test/typereference.test.js +51 -0
  155. package/dist/test/typereference.test.js.map +1 -0
  156. package/dist/test/uniontypeexpression.test.js +152 -15
  157. package/dist/test/uniontypeexpression.test.js.map +1 -1
  158. package/dist/test/variables.test.js +28 -19
  159. package/dist/test/variables.test.js.map +1 -1
  160. package/dist/tsconfig.tsbuildinfo +1 -1
  161. package/package.json +2 -2
  162. package/src/builtins/python.ts +7 -0
  163. package/src/components/CallSignature.tsx +17 -69
  164. package/src/components/ClassMethodDeclaration.tsx +34 -0
  165. package/src/components/ConstructorDeclaration.tsx +37 -0
  166. package/src/components/DunderMethodDeclaration.tsx +30 -0
  167. package/src/components/EnumDeclaration.tsx +16 -44
  168. package/src/components/EnumMember.tsx +3 -3
  169. package/src/components/FunctionBase.tsx +88 -0
  170. package/src/components/FunctionDeclaration.tsx +18 -82
  171. package/src/components/MemberExpression.tsx +6 -19
  172. package/src/components/MethodBase.tsx +53 -0
  173. package/src/components/MethodDeclaration.tsx +27 -0
  174. package/src/components/PropertyDeclaration.tsx +264 -0
  175. package/src/components/PyDoc.tsx +795 -195
  176. package/src/components/SourceFile.tsx +29 -0
  177. package/src/components/StaticMethodDeclaration.tsx +34 -0
  178. package/src/components/TypeArguments.tsx +24 -0
  179. package/src/components/TypeReference.tsx +33 -0
  180. package/src/components/UnionTypeExpression.tsx +4 -15
  181. package/src/components/VariableDeclaration.tsx +1 -3
  182. package/src/components/index.ts +10 -0
  183. package/src/parameter-descriptor.ts +6 -5
  184. package/src/symbol-creation.ts +17 -0
  185. package/src/symbols/factories.ts +39 -0
  186. package/src/symbols/index.ts +1 -0
  187. package/src/symbols/reference.tsx +3 -5
  188. package/src/utils.ts +0 -2
  189. package/temp/api.json +5281 -2273
  190. package/test/callsignatures.test.tsx +102 -74
  191. package/test/class-method-declaration.test.tsx +53 -0
  192. package/test/classdeclarations.test.tsx +7 -9
  193. package/test/constructordeclaration.test.tsx +48 -0
  194. package/test/dundermethoddeclaration.test.tsx +53 -0
  195. package/test/enums.test.tsx +14 -16
  196. package/test/externals.test.tsx +5 -7
  197. package/test/factories.test.tsx +72 -0
  198. package/test/functiondeclaration.test.tsx +196 -44
  199. package/test/memberexpressions.test.tsx +7 -2
  200. package/test/methoddeclaration.test.tsx +202 -0
  201. package/test/namepolicies.test.tsx +1 -2
  202. package/test/propertydeclaration.test.tsx +192 -0
  203. package/test/pydocs.test.tsx +1093 -129
  204. package/test/references.test.tsx +1 -1
  205. package/test/sourcefiles.test.tsx +100 -1
  206. package/test/staticmethoddeclaration.test.tsx +49 -0
  207. package/test/typereference.test.tsx +52 -0
  208. package/test/uniontypeexpression.test.tsx +169 -34
  209. package/test/variables.test.tsx +27 -16
@@ -3,7 +3,11 @@ import { d } from "@alloy-js/core/testing";
3
3
  import { describe, expect, it } from "vitest";
4
4
  import { enumModule } from "../src/builtins/python.js";
5
5
  import * as py from "../src/index.js";
6
- import { toSourceText } from "./utils.jsx";
6
+ import {
7
+ assertFileContents,
8
+ toSourceText,
9
+ toSourceTextMultiple,
10
+ } from "./utils.jsx";
7
11
 
8
12
  describe("PyDoc", () => {
9
13
  it("formats properly", () => {
@@ -128,172 +132,788 @@ describe("PyDocExample", () => {
128
132
  });
129
133
  });
130
134
 
131
- describe("GoogleStyleDocParam", () => {
132
- it("name only", () => {
135
+ describe("SimpleCommentBlock", () => {
136
+ it("renders simple comment block", () => {
133
137
  const res = toSourceText([
134
- <py.PyDoc>
135
- <py.GoogleStyleDocParam name="somebody" />
136
- </py.PyDoc>,
138
+ <py.SimpleCommentBlock>
139
+ This is a simple comment block that spans multiple lines.
140
+ </py.SimpleCommentBlock>,
137
141
  ]);
138
142
  expect(res).toRenderTo(
139
143
  d`
140
- """
141
- somebody
142
- """
144
+ # This is a simple comment block that spans multiple lines.
145
+
146
+ `,
147
+ );
148
+ });
143
149
 
150
+ it("renders comment block with line breaks", () => {
151
+ const res = toSourceText([
152
+ <py.SimpleCommentBlock>
153
+ First line of comment.
154
+ <br />
155
+ Second line of comment.
156
+ </py.SimpleCommentBlock>,
157
+ ]);
158
+ expect(res).toRenderTo(
159
+ d`
160
+ # First line of comment. Second line of comment.
161
+
162
+ `,
163
+ );
164
+ });
165
+ });
144
166
 
167
+ describe("SimpleInlineComment", () => {
168
+ it("renders inline comment", () => {
169
+ const res = toSourceText([
170
+ <>
171
+ x = 42
172
+ <py.SimpleInlineComment>
173
+ This is an inline comment
174
+ </py.SimpleInlineComment>
175
+ </>,
176
+ ]);
177
+ expect(res).toRenderTo(
178
+ d`
179
+ x = 42 # This is an inline comment
145
180
  `,
146
181
  );
147
182
  });
148
- it("name and type", () => {
183
+
184
+ it("renders inline comment with complex text", () => {
149
185
  const res = toSourceText([
150
- <py.PyDoc>
151
- <py.GoogleStyleDocParam name="somebody" type="str" />
152
- </py.PyDoc>,
186
+ <>
187
+ result = calculate()
188
+ <py.SimpleInlineComment>
189
+ TODO: Add error handling here
190
+ </py.SimpleInlineComment>
191
+ </>,
192
+ ]);
193
+ expect(res).toRenderTo(
194
+ d`
195
+ result = calculate() # TODO: Add error handling here
196
+ `,
197
+ );
198
+ });
199
+ });
200
+
201
+ describe("SimpleInlineMemberComment", () => {
202
+ it("renders inline member comment", () => {
203
+ const res = toSourceText([
204
+ <>
205
+ status: int
206
+ <py.SimpleInlineMemberComment>
207
+ HTTP status code
208
+ </py.SimpleInlineMemberComment>
209
+ </>,
210
+ ]);
211
+ expect(res).toRenderTo(
212
+ d`
213
+ status: int #: HTTP status code
214
+ `,
215
+ );
216
+ });
217
+
218
+ it("renders inline member comment for variable declaration", () => {
219
+ const res = toSourceText([
220
+ <>
221
+ max_retries = 3
222
+ <py.SimpleInlineMemberComment>
223
+ Maximum number of retry attempts
224
+ </py.SimpleInlineMemberComment>
225
+ </>,
226
+ ]);
227
+ expect(res).toRenderTo(
228
+ d`
229
+ max_retries = 3 #: Maximum number of retry attempts
230
+ `,
231
+ );
232
+ });
233
+ });
234
+
235
+ describe("New Documentation Components", () => {
236
+ it("ModuleDoc renders correctly", () => {
237
+ const res = toSourceText([
238
+ <py.ModuleDoc
239
+ description={[
240
+ <Prose>
241
+ This module demonstrates documentation as specified by the Google
242
+ Python Style Guide.
243
+ </Prose>,
244
+ ]}
245
+ attributes={[
246
+ {
247
+ name: "module_level_variable1",
248
+ type: "int",
249
+ children: "Module level variables may be documented.",
250
+ },
251
+ ]}
252
+ examples={[<py.PyDocExample>print("mod")</py.PyDocExample>]}
253
+ seeAlso={["another_module.func", "RelatedClass"]}
254
+ warning="Internal API."
255
+ deprecated="Use new_module instead."
256
+ todo={[
257
+ "For module TODOs",
258
+ "You have to also use sphinx.ext.todo extension",
259
+ ]}
260
+ />,
261
+ ]);
262
+
263
+ expect(res).toRenderTo(
264
+ d`
265
+ """
266
+ This module demonstrates documentation as specified by the Google Python Style
267
+ Guide.
268
+
269
+ Attributes:
270
+ module_level_variable1 (int): Module level variables may be documented.
271
+
272
+ Examples:
273
+ >> print("mod")
274
+
275
+ See Also:
276
+ another_module.func
277
+ RelatedClass
278
+
279
+ Warning:
280
+ Internal API.
281
+
282
+ Deprecated:
283
+ Use new_module instead.
284
+
285
+ Todo:
286
+ * For module TODOs
287
+ * You have to also use sphinx.ext.todo extension
288
+ """
289
+
290
+
291
+ `,
292
+ );
293
+ });
294
+
295
+ it("PropertyDoc renders correctly", () => {
296
+ const res = toSourceText([
297
+ <py.PropertyDoc
298
+ description={[
299
+ <Prose>
300
+ Properties should be documented in their getter method.
301
+ </Prose>,
302
+ ]}
303
+ returns="str: The readonly property value."
304
+ examples={[<py.PyDocExample>print(obj.name)</py.PyDocExample>]}
305
+ seeAlso={["other_property"]}
306
+ warning="Access may be slow."
307
+ deprecated="Use full_name instead."
308
+ note="If the setter method contains notable behavior, it should be mentioned here."
309
+ />,
310
+ ]);
311
+
312
+ expect(res).toRenderTo(
313
+ d`
314
+ """
315
+ Properties should be documented in their getter method.
316
+
317
+ Returns:
318
+ str: The readonly property value.
319
+
320
+ Examples:
321
+ >> print(obj.name)
322
+
323
+ See Also:
324
+ other_property
325
+
326
+ Warning:
327
+ Access may be slow.
328
+
329
+ Deprecated:
330
+ Use full_name instead.
331
+
332
+ Note:
333
+ If the setter method contains notable behavior, it should be mentioned here.
334
+ """
335
+
336
+
337
+ `,
338
+ );
339
+ });
340
+
341
+ it("GeneratorDoc renders correctly", () => {
342
+ const res = toSourceText([
343
+ <py.GeneratorDoc
344
+ description={[
345
+ <Prose>
346
+ Generators have a Yields section instead of a Returns section.
347
+ </Prose>,
348
+ ]}
349
+ parameters={[
350
+ {
351
+ name: "n",
352
+ type: "int",
353
+ doc: "The upper limit of the range to generate, from 0 to n - 1.",
354
+ },
355
+ ]}
356
+ yields="int: The next number in the range of 0 to n - 1."
357
+ examples={[<py.PyDocExample>print(next(gen))</py.PyDocExample>]}
358
+ seeAlso={["make_generator"]}
359
+ warning="Do not consume in tight loops without sleep."
360
+ deprecated="Use new_generator instead."
361
+ note="Examples should be written in doctest format."
362
+ />,
363
+ ]);
364
+
365
+ expect(res).toRenderTo(
366
+ d`
367
+ """
368
+ Generators have a Yields section instead of a Returns section.
369
+
370
+ Args:
371
+ n (int): The upper limit of the range to generate, from 0 to n - 1.
372
+
373
+ Yields:
374
+ int: The next number in the range of 0 to n - 1.
375
+
376
+ Examples:
377
+ >> print(next(gen))
378
+
379
+ See Also:
380
+ make_generator
381
+
382
+ Warning:
383
+ Do not consume in tight loops without sleep.
384
+
385
+ Deprecated:
386
+ Use new_generator instead.
387
+
388
+ Note:
389
+ Examples should be written in doctest format.
390
+ """
391
+
392
+
393
+ `,
394
+ );
395
+ });
396
+
397
+ it("ExceptionDoc renders correctly", () => {
398
+ const res = toSourceText([
399
+ <py.ExceptionDoc
400
+ description={[
401
+ <Prose>Exceptions are documented in the same way as classes.</Prose>,
402
+ ]}
403
+ parameters={[
404
+ {
405
+ name: "msg",
406
+ type: "str",
407
+ doc: "Human readable string describing the exception.",
408
+ },
409
+ {
410
+ name: "code",
411
+ type: "int",
412
+ default: undefined,
413
+ doc: "Error code.",
414
+ },
415
+ ]}
416
+ attributes={[
417
+ {
418
+ name: "msg",
419
+ type: "str",
420
+ children: "Human readable string describing the exception.",
421
+ },
422
+ {
423
+ name: "code",
424
+ type: "int",
425
+ children: "Exception error code.",
426
+ },
427
+ ]}
428
+ seeAlso={["BaseException"]}
429
+ deprecated="Use NewException instead."
430
+ note="Do not include the 'self' parameter in the Args section."
431
+ />,
432
+ ]);
433
+
434
+ expect(res).toRenderTo(
435
+ d`
436
+ """
437
+ Exceptions are documented in the same way as classes.
438
+
439
+ Args:
440
+ msg (str): Human readable string describing the exception.
441
+
442
+ code (int): Error code.
443
+
444
+ Attributes:
445
+ msg (str): Human readable string describing the exception.
446
+
447
+ code (int): Exception error code.
448
+
449
+ See Also:
450
+ BaseException
451
+
452
+ Deprecated:
453
+ Use NewException instead.
454
+
455
+ Note:
456
+ Do not include the 'self' parameter in the Args section.
457
+ """
458
+
459
+
460
+ `,
461
+ );
462
+ });
463
+
464
+ it("MethodDoc renders correctly without default note", () => {
465
+ const res = toSourceText([
466
+ <py.MethodDoc
467
+ description={[
468
+ <Prose>Class methods are similar to regular functions.</Prose>,
469
+ ]}
470
+ parameters={[
471
+ {
472
+ name: "param1",
473
+ doc: "The first parameter.",
474
+ },
475
+ {
476
+ name: "param2",
477
+ doc: "The second parameter.",
478
+ },
479
+ ]}
480
+ returns="True if successful, False otherwise."
481
+ overrides="Base.method"
482
+ />,
483
+ ]);
484
+
485
+ expect(res).toRenderTo(
486
+ d`
487
+ """
488
+ Class methods are similar to regular functions.
489
+
490
+ Args:
491
+ param1: The first parameter.
492
+
493
+ param2: The second parameter.
494
+
495
+ Returns:
496
+ True if successful, False otherwise.
497
+
498
+ Overrides:
499
+ Base.method
500
+ """
501
+
502
+
503
+ `,
504
+ );
505
+ });
506
+
507
+ it("MethodDoc renders correctly with custom note", () => {
508
+ const res = toSourceText([
509
+ <py.MethodDoc
510
+ description={[
511
+ <Prose>Class methods are similar to regular functions.</Prose>,
512
+ ]}
513
+ parameters={[
514
+ {
515
+ name: "param1",
516
+ doc: "The first parameter.",
517
+ },
518
+ ]}
519
+ returns="True if successful, False otherwise."
520
+ note="This method has special behavior when called multiple times."
521
+ />,
522
+ ]);
523
+
524
+ expect(res).toRenderTo(
525
+ d`
526
+ """
527
+ Class methods are similar to regular functions.
528
+
529
+ Args:
530
+ param1: The first parameter.
531
+
532
+ Returns:
533
+ True if successful, False otherwise.
534
+
535
+ Note:
536
+ This method has special behavior when called multiple times.
537
+ """
538
+
539
+
540
+ `,
541
+ );
542
+ });
543
+
544
+ it("ModuleDoc with minimal content", () => {
545
+ const res = toSourceText([
546
+ <py.ModuleDoc
547
+ description={[<Prose>Simple module description.</Prose>]}
548
+ />,
549
+ ]);
550
+
551
+ expect(res).toRenderTo(
552
+ d`
553
+ """
554
+ Simple module description.
555
+ """
556
+
557
+
558
+ `,
559
+ );
560
+ });
561
+
562
+ it("ModuleDoc with only todo items", () => {
563
+ const res = toSourceText([
564
+ <py.ModuleDoc
565
+ description={[<Prose>Module with pending tasks.</Prose>]}
566
+ todo={["Implement feature X", "Add more tests", "Update documentation"]}
567
+ />,
568
+ ]);
569
+
570
+ expect(res).toRenderTo(
571
+ d`
572
+ """
573
+ Module with pending tasks.
574
+
575
+ Todo:
576
+ * Implement feature X
577
+ * Add more tests
578
+ * Update documentation
579
+ """
580
+
581
+
582
+ `,
583
+ );
584
+ });
585
+
586
+ it("PropertyDoc minimal (description only)", () => {
587
+ const res = toSourceText([
588
+ <py.PropertyDoc
589
+ description={[<Prose>A simple readonly property.</Prose>]}
590
+ />,
591
+ ]);
592
+
593
+ expect(res).toRenderTo(
594
+ d`
595
+ """
596
+ A simple readonly property.
597
+ """
598
+
599
+
600
+ `,
601
+ );
602
+ });
603
+
604
+ it("PropertyDoc with getter and setter info", () => {
605
+ const res = toSourceText([
606
+ <py.PropertyDoc
607
+ description={[
608
+ <Prose>
609
+ Properties with both a getter and setter should only be documented
610
+ in their getter method.
611
+ </Prose>,
612
+ ]}
613
+ returns=":obj:`list` of :obj:`str`: The property value."
614
+ note="If the setter method contains notable behavior, it should be mentioned here."
615
+ />,
616
+ ]);
617
+
618
+ expect(res).toRenderTo(
619
+ d`
620
+ """
621
+ Properties with both a getter and setter should only be documented in their
622
+ getter method.
623
+
624
+ Returns:
625
+ :obj:\`list\` of :obj:\`str\`: The property value.
626
+
627
+ Note:
628
+ If the setter method contains notable behavior, it should be mentioned here.
629
+ """
630
+
631
+
632
+ `,
633
+ );
634
+ });
635
+
636
+ it("GeneratorDoc with complex parameters", () => {
637
+ const res = toSourceText([
638
+ <py.GeneratorDoc
639
+ description={[
640
+ <Prose>
641
+ A more complex generator example with multiple parameters.
642
+ </Prose>,
643
+ ]}
644
+ parameters={[
645
+ {
646
+ name: "start",
647
+ type: "int",
648
+ default: "0",
649
+ doc: "Starting value for the sequence.",
650
+ },
651
+ {
652
+ name: "stop",
653
+ type: "int",
654
+ doc: "Ending value for the sequence (exclusive).",
655
+ },
656
+ {
657
+ name: "step",
658
+ type: "int",
659
+ default: "1",
660
+ doc: "Step size between values.",
661
+ },
662
+ ]}
663
+ yields="int: The next number in the sequence."
664
+ raises={[
665
+ "ValueError: If step is zero.",
666
+ "TypeError: If parameters are not integers.",
667
+ ]}
668
+ />,
669
+ ]);
670
+
671
+ expect(res).toRenderTo(
672
+ d`
673
+ """
674
+ A more complex generator example with multiple parameters.
675
+
676
+ Args:
677
+ start (int, optional): Starting value for the sequence. Defaults to "0".
678
+
679
+ stop (int): Ending value for the sequence (exclusive).
680
+
681
+ step (int, optional): Step size between values. Defaults to "1".
682
+
683
+ Yields:
684
+ int: The next number in the sequence.
685
+
686
+ Raises:
687
+ ValueError: If step is zero.
688
+
689
+ Raises:
690
+ TypeError: If parameters are not integers.
691
+ """
692
+
693
+
694
+ `,
695
+ );
696
+ });
697
+
698
+ it("ExceptionDoc with comprehensive documentation", () => {
699
+ const res = toSourceText([
700
+ <py.ExceptionDoc
701
+ description={[
702
+ <Prose>A custom exception for authentication failures.</Prose>,
703
+ <Prose>
704
+ This exception is raised when authentication credentials are invalid
705
+ or when authentication tokens have expired.
706
+ </Prose>,
707
+ ]}
708
+ parameters={[
709
+ {
710
+ name: "message",
711
+ type: "str",
712
+ doc: "Human readable error message describing the authentication failure.",
713
+ },
714
+ {
715
+ name: "error_code",
716
+ type: "int",
717
+ default: "401",
718
+ doc: "HTTP error code associated with the authentication failure.",
719
+ },
720
+ {
721
+ name: "retry_after",
722
+ type: "int",
723
+ default: undefined,
724
+ doc: "Number of seconds to wait before retrying authentication.",
725
+ },
726
+ ]}
727
+ attributes={[
728
+ {
729
+ name: "message",
730
+ type: "str",
731
+ children: "The error message.",
732
+ },
733
+ {
734
+ name: "error_code",
735
+ type: "int",
736
+ children: "HTTP status code.",
737
+ },
738
+ {
739
+ name: "retry_after",
740
+ type: "int",
741
+ children: "Retry delay in seconds, if applicable.",
742
+ },
743
+ ]}
744
+ note="This exception should be caught and handled gracefully in production code."
745
+ />,
153
746
  ]);
747
+
154
748
  expect(res).toRenderTo(
155
749
  d`
156
- """
157
- somebody (str)
158
- """
750
+ """
751
+ A custom exception for authentication failures.
159
752
 
753
+ This exception is raised when authentication credentials are invalid or when
754
+ authentication tokens have expired.
160
755
 
161
- `,
756
+ Args:
757
+ message (str): Human readable error message describing the authentication
758
+ failure.
759
+
760
+ error_code (int, optional): HTTP error code associated with the
761
+ authentication failure. Defaults to "401".
762
+
763
+ retry_after (int): Number of seconds to wait before retrying authentication.
764
+
765
+ Attributes:
766
+ message (str): The error message.
767
+
768
+ error_code (int): HTTP status code.
769
+
770
+ retry_after (int): Retry delay in seconds, if applicable.
771
+
772
+ Note:
773
+ This exception should be caught and handled gracefully in production code.
774
+ """
775
+
776
+
777
+ `,
162
778
  );
163
779
  });
164
- it("name, type and description", () => {
780
+
781
+ it("MethodDoc with raises but no returns", () => {
165
782
  const res = toSourceText([
166
- <py.PyDoc>
167
- <py.GoogleStyleDocParam name="somebody" type="str">
168
- Somebody's name.
169
- </py.GoogleStyleDocParam>
170
- </py.PyDoc>,
783
+ <py.MethodDoc
784
+ description={[
785
+ <Prose>
786
+ A method that performs an action but doesn't return a value.
787
+ </Prose>,
788
+ ]}
789
+ parameters={[
790
+ {
791
+ name: "data",
792
+ type: "bytes",
793
+ doc: "Raw data to process.",
794
+ },
795
+ ]}
796
+ raises={[
797
+ "ValueError: If data is empty or invalid.",
798
+ "IOError: If processing fails due to I/O issues.",
799
+ ]}
800
+ />,
171
801
  ]);
802
+
172
803
  expect(res).toRenderTo(
173
804
  d`
174
- """
175
- somebody (str): Somebody's name.
176
- """
805
+ """
806
+ A method that performs an action but doesn't return a value.
177
807
 
808
+ Args:
809
+ data (bytes): Raw data to process.
178
810
 
179
- `,
811
+ Raises:
812
+ ValueError: If data is empty or invalid.
813
+
814
+ Raises:
815
+ IOError: If processing fails due to I/O issues.
816
+ """
817
+
818
+
819
+ `,
180
820
  );
181
821
  });
182
- it("name, type, description, and optional", () => {
822
+
823
+ it("MethodDoc with no parameters", () => {
183
824
  const res = toSourceText([
184
- <py.PyDoc>
185
- <py.GoogleStyleDocParam name="somebody" type="str" optional>
186
- Somebody's name.
187
- </py.GoogleStyleDocParam>
188
- </py.PyDoc>,
825
+ <py.MethodDoc
826
+ description={[
827
+ <Prose>A simple method with no parameters (except self).</Prose>,
828
+ ]}
829
+ returns="bool: True if the operation was successful."
830
+ note="This is a parameterless method that only operates on instance state."
831
+ />,
189
832
  ]);
833
+
190
834
  expect(res).toRenderTo(
191
835
  d`
192
- """
193
- somebody (str, optional): Somebody's name.
194
- """
836
+ """
837
+ A simple method with no parameters (except self).
195
838
 
839
+ Returns:
840
+ bool: True if the operation was successful.
196
841
 
197
- `,
842
+ Note:
843
+ This is a parameterless method that only operates on instance state.
844
+ """
845
+
846
+
847
+ `,
198
848
  );
199
849
  });
200
- it("name, type, description, and optional with default value", () => {
850
+
851
+ it("AttributeDoc standalone usage", () => {
201
852
  const res = toSourceText([
202
853
  <py.PyDoc>
203
- <py.GoogleStyleDocParam
204
- name="somebody"
205
- type="str"
206
- optional
207
- defaultValue="John Doe"
208
- >
209
- Somebody's name.
210
- </py.GoogleStyleDocParam>
854
+ <py.AttributeDoc name="connection_timeout" type="float">
855
+ Maximum time in seconds to wait for a connection to be established.
856
+ </py.AttributeDoc>
211
857
  </py.PyDoc>,
212
858
  ]);
859
+
213
860
  expect(res).toRenderTo(
214
861
  d`
215
862
  """
216
- somebody (str, optional): Somebody's name. Defaults to \"John Doe\".
863
+ connection_timeout (float): Maximum time in seconds to wait for a connection to
864
+ be established.
217
865
  """
218
866
 
219
867
 
220
868
  `,
221
869
  );
222
870
  });
223
- it("name, type, description, and optional with default value with a very long description", () => {
224
- const res = toSourceText(
225
- [
226
- <py.PyDoc>
227
- <py.GoogleStyleDocParam
228
- name="somebody"
229
- type="str"
230
- optional
231
- defaultValue="John Doe"
232
- >
233
- Somebody's name. This can be any string representing a person,
234
- whether it's a first name, full name, nickname, or even a codename
235
- (e.g., "Agent X"). It's used primarily for display purposes,
236
- logging, or greeting messages and is not required to be unique or
237
- validated unless specified by the caller.
238
- </py.GoogleStyleDocParam>
239
- <py.GoogleStyleDocParam name="somebody2" type="str">
240
- Somebody's name. This can be any string representing a person,
241
- whether it's a first name, full name, nickname, or even a codename
242
- (e.g., "Agent X"). It's used primarily for display purposes,
243
- logging, or greeting messages and is not required to be unique or
244
- validated unless specified by the caller.
245
- </py.GoogleStyleDocParam>
246
- </py.PyDoc>,
247
- ],
248
- { printOptions: { printWidth: 80 } },
249
- );
250
- expect(res).toRenderTo(
251
- d`
252
- """
253
- somebody (str, optional): Somebody's name. This can be any string representing a
254
- person, whether it's a first name, full name, nickname, or even a codename
255
- (e.g., "Agent X"). It's used primarily for display purposes, logging, or
256
- greeting messages and is not required to be unique or validated unless
257
- specified by the caller. Defaults to \"John Doe\".
258
-
259
- somebody2 (str): Somebody's name. This can be any string representing a person,
260
- whether it's a first name, full name, nickname, or even a codename (e.g.,
261
- "Agent X"). It's used primarily for display purposes, logging, or greeting
262
- messages and is not required to be unique or validated unless specified by
263
- the caller.
264
- """
265
871
 
872
+ it("GeneratorDoc with examples in description", () => {
873
+ const res = toSourceText([
874
+ <py.GeneratorDoc
875
+ description={[
876
+ <Prose>
877
+ Generators have a Yields section instead of a Returns section.
878
+ </Prose>,
879
+ <py.PyDocExample>
880
+ print([i for i in example_generator(4)])
881
+ <br />
882
+ [0, 1, 2, 3]
883
+ </py.PyDocExample>,
884
+ ]}
885
+ parameters={[
886
+ {
887
+ name: "n",
888
+ type: "int",
889
+ doc: "The upper limit of the range to generate, from 0 to n - 1.",
890
+ },
891
+ ]}
892
+ yields="int: The next number in the range of 0 to n - 1."
893
+ note="Examples should be written in doctest format, and should illustrate how to use the function."
894
+ />,
895
+ ]);
266
896
 
267
- `,
268
- );
269
- });
270
- it("name, type, description, and optional with default value with a description containing a linebreak", () => {
271
- const res = toSourceText(
272
- [
273
- <py.PyDoc>
274
- <py.GoogleStyleDocParam
275
- name="somebody"
276
- type="str"
277
- optional
278
- defaultValue="John Doe"
279
- >
280
- Somebody's name. This is one line
281
- <hbr />
282
- This is another line.
283
- </py.GoogleStyleDocParam>
284
- </py.PyDoc>,
285
- ],
286
- { printOptions: { printWidth: 80 } },
287
- );
288
897
  expect(res).toRenderTo(
289
898
  d`
290
- """
291
- somebody (str, optional): Somebody's name. This is one line
292
- This is another line. Defaults to \"John Doe\".
293
- """
899
+ """
900
+ Generators have a Yields section instead of a Returns section.
294
901
 
902
+ >> print([i for i in example_generator(4)])
903
+ >> [0, 1, 2, 3]
295
904
 
296
- `,
905
+ Args:
906
+ n (int): The upper limit of the range to generate, from 0 to n - 1.
907
+
908
+ Yields:
909
+ int: The next number in the range of 0 to n - 1.
910
+
911
+ Note:
912
+ Examples should be written in doctest format, and should illustrate how to use the function.
913
+ """
914
+
915
+
916
+ `,
297
917
  );
298
918
  });
299
919
  });
@@ -315,13 +935,28 @@ describe("Full example", () => {
315
935
  print(x)
316
936
  </py.PyDocExample>,
317
937
  ]}
938
+ attributes={[
939
+ {
940
+ name: "attr1",
941
+ type: "str",
942
+ children: "Description of attr1.",
943
+ },
944
+ {
945
+ name: "attr2",
946
+ type: "int",
947
+ children: "Description of attr2.",
948
+ },
949
+ ]}
950
+ examples={[<py.PyDocExample>print("class-doc")</py.PyDocExample>]}
951
+ seeAlso={["RelatedClass", "helper_function"]}
952
+ warning="This class is experimental."
953
+ deprecated="Use NewClass instead."
318
954
  parameters={[
319
955
  {
320
956
  name: "somebody",
321
957
  type: "str",
322
- optional: true,
323
958
  default: "John Doe",
324
- doc: "Somebody's name. This can be any string representing a person, whether it's a first name, full name, nickname, or even a codename (e.g., 'Agent X'). It's used primarily for display purposes, logging, or greeting messages and is not required to be unique or validated unless specified by the caller. Defaults to \"John Doe\".",
959
+ doc: "Somebody's name. This can be any string representing a person, whether it's a first name, full name, nickname, or even a codename (e.g., 'Agent X'). It's used primarily for display purposes, logging, or greeting messages and is not required to be unique or validated unless specified by the caller.",
325
960
  },
326
961
  {
327
962
  name: "somebody2",
@@ -329,6 +964,7 @@ describe("Full example", () => {
329
964
  doc: "Somebody's name. This can be any string representing a person, whether it's a first name, full name, nickname, or even a codename (e.g., 'Agent X'). It's used primarily for display purposes, logging, or greeting messages and is not required to be unique or validated unless specified by the caller.",
330
965
  },
331
966
  ]}
967
+ note="Do not include the 'self' parameter in the Args section."
332
968
  style="google"
333
969
  />
334
970
  );
@@ -337,10 +973,10 @@ describe("Full example", () => {
337
973
  <py.ClassDeclaration name="A" doc={doc}>
338
974
  <py.StatementList>
339
975
  <py.VariableDeclaration name="just_name" />
340
- <py.VariableDeclaration name="name_and_type" type="number" />
976
+ <py.VariableDeclaration name="name_and_type" type="int" />
341
977
  <py.VariableDeclaration
342
978
  name="name_type_and_value"
343
- type="number"
979
+ type="int"
344
980
  initializer={12}
345
981
  />
346
982
  </py.StatementList>
@@ -360,6 +996,11 @@ describe("Full example", () => {
360
996
  >> x = "Hello"
361
997
  >> print(x)
362
998
 
999
+ Attributes:
1000
+ attr1 (str): Description of attr1.
1001
+
1002
+ attr2 (int): Description of attr2.
1003
+
363
1004
  Args:
364
1005
  somebody (str, optional): Somebody's name. This can be any string
365
1006
  representing a person, whether it's a first name, full name,
@@ -373,10 +1014,26 @@ describe("Full example", () => {
373
1014
  codename (e.g., 'Agent X'). It's used primarily for display
374
1015
  purposes, logging, or greeting messages and is not required to be
375
1016
  unique or validated unless specified by the caller.
1017
+
1018
+ Examples:
1019
+ >> print("class-doc")
1020
+
1021
+ See Also:
1022
+ RelatedClass
1023
+ helper_function
1024
+
1025
+ Warning:
1026
+ This class is experimental.
1027
+
1028
+ Deprecated:
1029
+ Use NewClass instead.
1030
+
1031
+ Note:
1032
+ Do not include the 'self' parameter in the Args section.
376
1033
  """
377
1034
  just_name = None
378
- name_and_type: number = None
379
- name_type_and_value: number = 12
1035
+ name_and_type: int = None
1036
+ name_type_and_value: int = 12
380
1037
 
381
1038
 
382
1039
  `,
@@ -403,9 +1060,8 @@ describe("Full example", () => {
403
1060
  {
404
1061
  name: "somebody",
405
1062
  type: "str",
406
- optional: true,
407
1063
  default: "John Doe",
408
- doc: "Somebody's name. This can be any string representing a person, whether it's a first name, full name, nickname, or even a codename (e.g., 'Agent X'). It's used primarily for display purposes, logging, or greeting messages and is not required to be unique or validated unless specified by the caller. Defaults to \"John Doe\".",
1064
+ doc: "Somebody's name. This can be any string representing a person, whether it's a first name, full name, nickname, or even a codename (e.g., 'Agent X'). It's used primarily for display purposes, logging, or greeting messages and is not required to be unique or validated unless specified by the caller.",
409
1065
  },
410
1066
  {
411
1067
  name: "somebody2",
@@ -414,7 +1070,9 @@ describe("Full example", () => {
414
1070
  },
415
1071
  ]}
416
1072
  returns="The return value. True for success, False otherwise."
1073
+ yields="int: The next number in the sequence."
417
1074
  raises={["ValueError: If somebody2 is equal to somebody."]}
1075
+ note="This function can be used as both a regular function and a generator."
418
1076
  style="google"
419
1077
  />
420
1078
  );
@@ -463,8 +1121,14 @@ describe("Full example", () => {
463
1121
  Returns:
464
1122
  The return value. True for success, False otherwise.
465
1123
 
1124
+ Yields:
1125
+ int: The next number in the sequence.
1126
+
466
1127
  Raises:
467
1128
  ValueError: If somebody2 is equal to somebody.
1129
+
1130
+ Note:
1131
+ This function can be used as both a regular function and a generator.
468
1132
  """
469
1133
  just_name = None
470
1134
  name_and_type: number = None
@@ -497,9 +1161,14 @@ describe("Full example", () => {
497
1161
  });
498
1162
 
499
1163
  it("classic enum with explicit values", () => {
1164
+ const doc = (
1165
+ <py.ClassDoc
1166
+ description={[<Prose>An enum representing colors.</Prose>]}
1167
+ />
1168
+ );
500
1169
  const result = toSourceText(
501
1170
  [
502
- <py.EnumDeclaration
1171
+ <py.ClassEnumDeclaration
503
1172
  name="Color"
504
1173
  baseType="IntEnum"
505
1174
  members={[
@@ -507,7 +1176,7 @@ describe("Full example", () => {
507
1176
  { name: "GREEN", value: "2", doc: "The color green." },
508
1177
  { name: "BLUE", value: "3", doc: "The color blue." },
509
1178
  ]}
510
- doc="An enum representing colors."
1179
+ doc={doc}
511
1180
  />,
512
1181
  ],
513
1182
  { externals: [enumModule] },
@@ -515,14 +1184,309 @@ describe("Full example", () => {
515
1184
  const expected = d`
516
1185
  from enum import IntEnum
517
1186
 
518
- # An enum representing colors.
519
1187
  class Color(IntEnum):
520
- RED = 1 # The color red.
521
- GREEN = 2 # The color green.
522
- BLUE = 3 # The color blue.
1188
+ """
1189
+ An enum representing colors.
1190
+ """
1191
+
1192
+ RED = 1 #: The color red.
1193
+ GREEN = 2 #: The color green.
1194
+ BLUE = 3 #: The color blue.
523
1195
 
524
1196
 
525
1197
  `;
526
1198
  expect(result).toRenderTo(expected);
527
1199
  });
1200
+
1201
+ it("ModuleDoc with SourceFile integration", () => {
1202
+ const moduleDoc = (
1203
+ <py.ModuleDoc
1204
+ description={[
1205
+ <Prose>
1206
+ This module provides utility functions for data processing. It
1207
+ includes functions for validation, transformation, and analysis.
1208
+ </Prose>,
1209
+ ]}
1210
+ attributes={[
1211
+ {
1212
+ name: "DEFAULT_TIMEOUT",
1213
+ type: "int",
1214
+ children: "Default timeout value in seconds.",
1215
+ },
1216
+ {
1217
+ name: "MAX_RETRIES",
1218
+ type: "int",
1219
+ children: "Maximum number of retry attempts.",
1220
+ },
1221
+ ]}
1222
+ todo={["Add caching functionality", "Improve error messages"]}
1223
+ style="google"
1224
+ />
1225
+ );
1226
+
1227
+ const content = (
1228
+ <py.SourceFile path="utils.py" doc={moduleDoc}>
1229
+ <py.VariableDeclaration name="DEFAULT_TIMEOUT" initializer={30} />
1230
+ <py.VariableDeclaration name="MAX_RETRIES" initializer={3} />
1231
+ <py.FunctionDeclaration name="process_data">
1232
+ pass
1233
+ </py.FunctionDeclaration>
1234
+ </py.SourceFile>
1235
+ );
1236
+
1237
+ const res = toSourceTextMultiple([content]);
1238
+ const file = res.contents.find(
1239
+ (f) => f.kind === "file" && f.path === "utils.py",
1240
+ );
1241
+ expect(file).toBeDefined();
1242
+
1243
+ assertFileContents(res, {
1244
+ "utils.py": d`
1245
+ """
1246
+ This module provides utility functions for data processing. It includes
1247
+ functions for validation, transformation, and analysis.
1248
+
1249
+ Attributes:
1250
+ DEFAULT_TIMEOUT (int): Default timeout value in seconds.
1251
+
1252
+ MAX_RETRIES (int): Maximum number of retry attempts.
1253
+
1254
+ Todo:
1255
+ * Add caching functionality
1256
+ * Improve error messages
1257
+ """
1258
+
1259
+
1260
+ default_timeout = 30
1261
+
1262
+ max_retries = 3
1263
+
1264
+ def process_data():
1265
+ pass
1266
+
1267
+
1268
+ `,
1269
+ });
1270
+ });
1271
+
1272
+ it("GeneratorDoc with FunctionDeclaration integration", () => {
1273
+ const generatorDoc = (
1274
+ <py.GeneratorDoc
1275
+ description={[
1276
+ <Prose>
1277
+ A generator function that yields fibonacci numbers. This is an
1278
+ efficient way to generate the sequence on demand.
1279
+ </Prose>,
1280
+ ]}
1281
+ parameters={[
1282
+ {
1283
+ name: "n",
1284
+ type: "int",
1285
+ doc: "Number of fibonacci numbers to generate.",
1286
+ },
1287
+ ]}
1288
+ yields="int: The next fibonacci number in the sequence."
1289
+ style="google"
1290
+ />
1291
+ );
1292
+
1293
+ const result = toSourceText([
1294
+ <py.FunctionDeclaration name="fibonacci_generator" doc={generatorDoc}>
1295
+ yield 0
1296
+ </py.FunctionDeclaration>,
1297
+ ]);
1298
+
1299
+ expect(result).toRenderTo(
1300
+ d`
1301
+ def fibonacci_generator():
1302
+ """
1303
+ A generator function that yields fibonacci numbers. This is an efficient way
1304
+ to generate the sequence on demand.
1305
+
1306
+ Args:
1307
+ n (int): Number of fibonacci numbers to generate.
1308
+
1309
+ Yields:
1310
+ int: The next fibonacci number in the sequence.
1311
+ """
1312
+ yield 0
1313
+
1314
+
1315
+ `,
1316
+ );
1317
+ });
1318
+
1319
+ it("ExceptionDoc with ClassDeclaration integration", () => {
1320
+ const exceptionDoc = (
1321
+ <py.ExceptionDoc
1322
+ description={[
1323
+ <Prose>
1324
+ Custom exception raised when data validation fails. This exception
1325
+ includes details about the validation error.
1326
+ </Prose>,
1327
+ ]}
1328
+ attributes={[
1329
+ {
1330
+ name: "field_name",
1331
+ type: "str",
1332
+ children: "Name of the field that failed validation.",
1333
+ },
1334
+ {
1335
+ name: "error_code",
1336
+ type: "int",
1337
+ children: "Numeric error code for the validation failure.",
1338
+ },
1339
+ ]}
1340
+ style="google"
1341
+ />
1342
+ );
1343
+
1344
+ const result = toSourceText([
1345
+ <py.ClassDeclaration
1346
+ name="ValidationError"
1347
+ bases={["Exception"]}
1348
+ doc={exceptionDoc}
1349
+ >
1350
+ <py.StatementList>
1351
+ <py.VariableDeclaration name="field_name" type="str" />
1352
+ <py.VariableDeclaration name="error_code" type="int" />
1353
+ </py.StatementList>
1354
+ </py.ClassDeclaration>,
1355
+ ]);
1356
+
1357
+ expect(result).toRenderTo(
1358
+ d`
1359
+ class ValidationError(Exception):
1360
+ """
1361
+ Custom exception raised when data validation fails. This exception includes
1362
+ details about the validation error.
1363
+
1364
+ Attributes:
1365
+ field_name (str): Name of the field that failed validation.
1366
+
1367
+ error_code (int): Numeric error code for the validation failure.
1368
+ """
1369
+ field_name: str = None
1370
+ error_code: int = None
1371
+
1372
+
1373
+ `,
1374
+ );
1375
+ });
1376
+
1377
+ it("PropertyDoc with FunctionDeclaration (as property method) integration", () => {
1378
+ const propertyDoc = (
1379
+ <py.PropertyDoc
1380
+ description={[
1381
+ <Prose>
1382
+ The full name of the person, combining first and last name. This
1383
+ property automatically formats the name with proper capitalization.
1384
+ </Prose>,
1385
+ ]}
1386
+ style="google"
1387
+ />
1388
+ );
1389
+
1390
+ const result = toSourceText([
1391
+ <py.ClassDeclaration name="Person">
1392
+ <py.PropertyDeclaration name="full_name" doc={propertyDoc} type="str">
1393
+ return "John Doe"
1394
+ </py.PropertyDeclaration>
1395
+ </py.ClassDeclaration>,
1396
+ ]);
1397
+
1398
+ expect(result).toRenderTo(
1399
+ d`
1400
+ class Person:
1401
+ @property
1402
+ def full_name(self) -> str:
1403
+ """
1404
+ The full name of the person, combining first and last name. This
1405
+ property automatically formats the name with proper capitalization.
1406
+ """
1407
+ return "John Doe"
1408
+
1409
+
1410
+
1411
+
1412
+
1413
+ `,
1414
+ );
1415
+ });
1416
+
1417
+ it("MethodDoc with FunctionDeclaration (inside class) integration", () => {
1418
+ const methodDoc = (
1419
+ <py.MethodDoc
1420
+ description={[
1421
+ <Prose>
1422
+ Validates the input data according to the defined schema. This
1423
+ method performs comprehensive validation including type checking.
1424
+ </Prose>,
1425
+ ]}
1426
+ parameters={[
1427
+ {
1428
+ name: "data",
1429
+ type: "dict",
1430
+ doc: "The data dictionary to validate.",
1431
+ },
1432
+ {
1433
+ name: "strict",
1434
+ type: "bool",
1435
+ default: "True",
1436
+ doc: "Whether to enforce strict validation rules.",
1437
+ },
1438
+ ]}
1439
+ returns="bool: True if validation passes, False otherwise."
1440
+ raises={["ValidationError: If data format is invalid."]}
1441
+ note="This method modifies the internal validation state."
1442
+ style="google"
1443
+ />
1444
+ );
1445
+
1446
+ const result = toSourceText([
1447
+ <py.ClassDeclaration name="DataValidator">
1448
+ <py.MethodDeclaration
1449
+ name="validate"
1450
+ doc={methodDoc}
1451
+ parameters={[
1452
+ { name: "data", type: "dict" },
1453
+ { name: "strict", type: "bool", default: true },
1454
+ ]}
1455
+ returnType="bool"
1456
+ >
1457
+ return self.validate(data, strict)
1458
+ </py.MethodDeclaration>
1459
+ </py.ClassDeclaration>,
1460
+ ]);
1461
+
1462
+ expect(result).toRenderTo(
1463
+ d`
1464
+ class DataValidator:
1465
+ def validate(self, data: dict, strict: bool = True) -> bool:
1466
+ """
1467
+ Validates the input data according to the defined schema. This method
1468
+ performs comprehensive validation including type checking.
1469
+
1470
+ Args:
1471
+ data (dict): The data dictionary to validate.
1472
+
1473
+ strict (bool, optional): Whether to enforce strict validation rules.
1474
+ Defaults to "True".
1475
+
1476
+ Returns:
1477
+ bool: True if validation passes, False otherwise.
1478
+
1479
+ Raises:
1480
+ ValidationError: If data format is invalid.
1481
+
1482
+ Note:
1483
+ This method modifies the internal validation state.
1484
+ """
1485
+ return self.validate(data, strict)
1486
+
1487
+
1488
+
1489
+ `,
1490
+ );
1491
+ });
528
1492
  });