@alloy-js/python 0.3.0-dev.5 → 0.3.0-dev.6

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 (53) hide show
  1. package/dist/src/components/FutureStatement.d.ts +35 -0
  2. package/dist/src/components/FutureStatement.d.ts.map +1 -0
  3. package/dist/src/components/FutureStatement.js +31 -0
  4. package/dist/src/components/FutureStatement.js.map +1 -0
  5. package/dist/src/components/SourceFile.d.ts +8 -2
  6. package/dist/src/components/SourceFile.d.ts.map +1 -1
  7. package/dist/src/components/SourceFile.js +124 -8
  8. package/dist/src/components/SourceFile.js.map +1 -1
  9. package/dist/src/components/index.d.ts +1 -0
  10. package/dist/src/components/index.d.ts.map +1 -1
  11. package/dist/src/components/index.js +1 -0
  12. package/dist/src/components/index.js.map +1 -1
  13. package/dist/test/classdeclarations.test.js +2 -0
  14. package/dist/test/classdeclarations.test.js.map +1 -1
  15. package/dist/test/dataclassdeclarations.test.js +13 -0
  16. package/dist/test/dataclassdeclarations.test.js.map +1 -1
  17. package/dist/test/enums.test.js +7 -0
  18. package/dist/test/enums.test.js.map +1 -1
  19. package/dist/test/externals.test.js +2 -0
  20. package/dist/test/externals.test.js.map +1 -1
  21. package/dist/test/functiondeclaration.test.js +2 -0
  22. package/dist/test/functiondeclaration.test.js.map +1 -1
  23. package/dist/test/methoddeclaration.test.js +1 -0
  24. package/dist/test/methoddeclaration.test.js.map +1 -1
  25. package/dist/test/namepolicies.test.js +1 -0
  26. package/dist/test/namepolicies.test.js.map +1 -1
  27. package/dist/test/propertydeclaration.test.js +1 -0
  28. package/dist/test/propertydeclaration.test.js.map +1 -1
  29. package/dist/test/pydocs.test.js +1 -1
  30. package/dist/test/pydocs.test.js.map +1 -1
  31. package/dist/test/sourcefiles.test.js +921 -39
  32. package/dist/test/sourcefiles.test.js.map +1 -1
  33. package/dist/test/utils.d.ts +2 -2
  34. package/dist/test/utils.d.ts.map +1 -1
  35. package/dist/test/utils.js +9 -9
  36. package/dist/test/utils.js.map +1 -1
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +1 -1
  39. package/src/components/FutureStatement.tsx +38 -0
  40. package/src/components/SourceFile.tsx +128 -8
  41. package/src/components/index.ts +1 -0
  42. package/temp/api.json +122 -2
  43. package/test/classdeclarations.test.tsx +2 -0
  44. package/test/dataclassdeclarations.test.tsx +13 -0
  45. package/test/enums.test.tsx +7 -0
  46. package/test/externals.test.tsx +2 -0
  47. package/test/functiondeclaration.test.tsx +2 -0
  48. package/test/methoddeclaration.test.tsx +1 -0
  49. package/test/namepolicies.test.tsx +1 -0
  50. package/test/propertydeclaration.test.tsx +1 -0
  51. package/test/pydocs.test.tsx +1 -1
  52. package/test/sourcefiles.test.tsx +754 -48
  53. package/test/utils.tsx +10 -5
@@ -0,0 +1,38 @@
1
+ import { type Children } from "@alloy-js/core";
2
+
3
+ export interface FutureStatementProps {
4
+ /**
5
+ * The name of the feature to import from __future__.
6
+ */
7
+ feature: string;
8
+ }
9
+
10
+ /**
11
+ * A future statement that imports features from __future__.
12
+ *
13
+ * Future statements are directives to the compiler that a particular module
14
+ * should be compiled using syntax or semantics from a future Python release.
15
+ * They must appear near the top of the module, after the module docstring (if any).
16
+ *
17
+ * Use this in the `futureImports` prop of SourceFile to ensure proper placement.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * <SourceFile path="models.py" futureImports={<FutureStatement feature="annotations" />}>
22
+ * <ClassDeclaration name="User">
23
+ * <PropertyDeclaration name="manager" type="User" />
24
+ * </ClassDeclaration>
25
+ * </SourceFile>
26
+ * ```
27
+ * renders to
28
+ * ```py
29
+ * from __future__ import annotations
30
+ *
31
+ *
32
+ * class User:
33
+ * manager: User
34
+ * ```
35
+ */
36
+ export function FutureStatement(props: FutureStatementProps): Children {
37
+ return <>from __future__ import {props.feature}</>;
38
+ }
@@ -1,7 +1,9 @@
1
1
  import {
2
+ childrenArray,
2
3
  ComponentContext,
3
4
  SourceFile as CoreSourceFile,
4
5
  createNamedContext,
6
+ isComponentCreator,
5
7
  List,
6
8
  Scope,
7
9
  Show,
@@ -12,8 +14,51 @@ import {
12
14
  import { join } from "pathe";
13
15
  import { PythonModuleScope } from "../symbols/index.js";
14
16
  import { ImportStatements } from "./ImportStatement.js";
17
+ import { SimpleCommentBlock } from "./PyDoc.js";
15
18
  import { Reference } from "./Reference.js";
16
19
 
20
+ // Non top-level definitions
21
+ const NON_DEFINITION_NAMES = new Set([
22
+ "VariableDeclaration",
23
+ "MemberExpression",
24
+ "FunctionCallExpression",
25
+ "ClassInstantiation",
26
+ "Reference",
27
+ ]);
28
+
29
+ // Wrapper components that we should look inside to find the actual first child
30
+ const WRAPPER_COMPONENT_NAMES = new Set(["StatementList"]);
31
+
32
+ /**
33
+ * Checks if the first child is a top-level definition (function or class).
34
+ * PEP 8 requires 2 blank lines before top-level function and class definitions,
35
+ * but not before other statements like variable assignments.
36
+ *
37
+ * Returns true only if there are children and the first child is a definition.
38
+ */
39
+ function firstChildIsDefinition(children: Children | undefined): boolean {
40
+ if (!children) return false;
41
+ const arr = childrenArray(() => children);
42
+ if (arr.length === 0) return false;
43
+ const first = arr[0];
44
+
45
+ // Non-component children (strings, numbers, refkeys, etc.) are not definitions
46
+ if (!isComponentCreator(first)) {
47
+ return false;
48
+ }
49
+
50
+ const name = first.component.name;
51
+ if (NON_DEFINITION_NAMES.has(name)) {
52
+ return false;
53
+ }
54
+ // Look inside wrapper components
55
+ if (WRAPPER_COMPONENT_NAMES.has(name) && first.props?.children) {
56
+ return firstChildIsDefinition(first.props.children as Children);
57
+ }
58
+ // If we get here, it's likely a definition (FunctionDeclaration, ClassDeclaration, etc.)
59
+ return true;
60
+ }
61
+
17
62
  export interface PythonSourceFileContext {
18
63
  scope: PythonModuleScope;
19
64
  /** The module name for this file, e.g. 'test' for test.py */
@@ -37,17 +82,23 @@ export interface SourceFileProps {
37
82
  */
38
83
  children?: Children;
39
84
  /**
40
- * Header comment to add to the file, which will be rendered at the top of the file.
85
+ * Content to render at the very top of the file, before everything else.
86
+ * Use this for shebang lines, encoding declarations, or license headers.
41
87
  */
42
88
  header?: Children;
43
89
  /**
44
- * Comment to add to the header, which will be rendered as a comment in the file.
90
+ * Comment to add at the top of the file, rendered as a Python comment block.
91
+ * This is a convenience prop for adding copyright notices or other comments.
45
92
  */
46
93
  headerComment?: string;
47
94
  /**
48
95
  * Documentation for this module, which will be rendered as a module-level docstring.
49
96
  */
50
97
  doc?: Children;
98
+ /**
99
+ * __future__ imports to render after the docstring but before regular imports.
100
+ */
101
+ futureImports?: Children;
51
102
  }
52
103
 
53
104
  /**
@@ -100,21 +151,90 @@ export function SourceFile(props: SourceFileProps) {
100
151
  module: path,
101
152
  };
102
153
 
154
+ // Check if there are any children
155
+ const hasChildren =
156
+ props.children !== undefined &&
157
+ childrenArray(() => props.children).length > 0;
158
+
159
+ // PEP 8 requires 2 blank lines before top-level function/class definitions
160
+ const needsExtraSpacing = firstChildIsDefinition(props.children);
161
+
162
+ // Check if there's any preamble content (header, doc, imports, etc.)
163
+ const hasPreamble =
164
+ props.header !== undefined ||
165
+ props.headerComment !== undefined ||
166
+ props.doc !== undefined ||
167
+ props.futureImports !== undefined;
168
+
103
169
  return (
104
- <CoreSourceFile path={props.path} filetype="py" reference={Reference}>
105
- <Show when={scope.importedModules.size > 0}>
106
- <ImportStatements records={scope.importedModules} />
107
- <hbr />
170
+ <CoreSourceFile
171
+ path={props.path}
172
+ filetype="py"
173
+ reference={Reference}
174
+ header={props.header}
175
+ >
176
+ {/* Extra blank line after header when followed by doc/futureImports/children (not headerComment) */}
177
+ <Show
178
+ when={
179
+ props.header !== undefined &&
180
+ props.headerComment === undefined &&
181
+ (props.doc !== undefined ||
182
+ props.futureImports !== undefined ||
183
+ hasChildren)
184
+ }
185
+ >
108
186
  <hbr />
109
187
  </Show>
188
+ <Show when={props.headerComment !== undefined}>
189
+ <SimpleCommentBlock>{props.headerComment}</SimpleCommentBlock>
190
+ {/* When followed by doc: just newline (no blank line) */}
191
+ <Show when={props.doc !== undefined}>
192
+ <hbr />
193
+ </Show>
194
+ {/* When followed by futureImports or children directly (no doc): blank line */}
195
+ <Show
196
+ when={
197
+ props.doc === undefined &&
198
+ (props.futureImports !== undefined || hasChildren)
199
+ }
200
+ >
201
+ <hbr />
202
+ <hbr />
203
+ </Show>
204
+ </Show>
110
205
  <Show when={props.doc !== undefined}>
111
206
  {props.doc}
112
- <hbr />
207
+ <Show when={props.futureImports !== undefined || hasChildren}>
208
+ <hbr />
209
+ </Show>
210
+ </Show>
211
+ <Show when={props.futureImports !== undefined}>
212
+ {props.futureImports}
213
+ <Show when={hasChildren}>
214
+ <hbr />
215
+ <hbr />
216
+ </Show>
217
+ </Show>
218
+ <Show when={scope.importedModules.size > 0}>
219
+ <ImportStatements records={scope.importedModules} />
220
+ <Show when={hasChildren}>
221
+ <hbr />
222
+ <hbr />
223
+ </Show>
224
+ </Show>
225
+ {/* Extra blank line before top-level definitions */}
226
+ <Show
227
+ when={
228
+ needsExtraSpacing && (hasPreamble || scope.importedModules.size > 0)
229
+ }
230
+ >
113
231
  <hbr />
114
232
  </Show>
115
233
  <PythonSourceFileContext.Provider value={sfContext}>
116
234
  <Scope value={scope}>
117
- <List doubleHardline>{props.children}</List>
235
+ <Show when={hasChildren}>
236
+ <List doubleHardline>{props.children}</List>
237
+ </Show>
118
238
  </Scope>
119
239
  </PythonSourceFileContext.Provider>
120
240
  </CoreSourceFile>
@@ -12,6 +12,7 @@ export * from "./EnumMember.js";
12
12
  export type { CommonFunctionProps } from "./FunctionBase.js";
13
13
  export * from "./FunctionCallExpression.js";
14
14
  export * from "./FunctionDeclaration.js";
15
+ export * from "./FutureStatement.js";
15
16
  export * from "./ImportStatement.js";
16
17
  export * from "./LexicalScope.js";
17
18
  export * from "./MemberExpression.js";
package/temp/api.json CHANGED
@@ -4350,6 +4350,98 @@
4350
4350
  ],
4351
4351
  "extendsTokenRanges": []
4352
4352
  },
4353
+ {
4354
+ "kind": "Function",
4355
+ "canonicalReference": "@alloy-js/python!FutureStatement:function(1)",
4356
+ "docComment": "/**\n * A future statement that imports features from __future__.\n *\n * Future statements are directives to the compiler that a particular module\n * should be compiled using syntax or semantics from a future Python release.\n * They must appear near the top of the module, after the module docstring (if any).\n *\n * Use this in the `futureImports` prop of SourceFile to ensure proper placement.\n *\n * @example\n * ```tsx\n * <SourceFile path=\"models.py\" futureImports={<FutureStatement feature=\"annotations\" />}>\n * <ClassDeclaration name=\"User\">\n * <PropertyDeclaration name=\"manager\" type=\"User\" />\n * </ClassDeclaration>\n * </SourceFile>\n * ```\n *\n * renders to\n * ```py\n * from __future__ import annotations\n *\n *\n * class User:\n * manager: User\n * ```\n *\n */\n",
4357
+ "excerptTokens": [
4358
+ {
4359
+ "kind": "Content",
4360
+ "text": "export declare function FutureStatement(props: "
4361
+ },
4362
+ {
4363
+ "kind": "Reference",
4364
+ "text": "FutureStatementProps",
4365
+ "canonicalReference": "@alloy-js/python!FutureStatementProps:interface"
4366
+ },
4367
+ {
4368
+ "kind": "Content",
4369
+ "text": "): "
4370
+ },
4371
+ {
4372
+ "kind": "Reference",
4373
+ "text": "Children",
4374
+ "canonicalReference": "@alloy-js/core!Children:type"
4375
+ },
4376
+ {
4377
+ "kind": "Content",
4378
+ "text": ";"
4379
+ }
4380
+ ],
4381
+ "fileUrlPath": "src/components/FutureStatement.tsx",
4382
+ "returnTypeTokenRange": {
4383
+ "startIndex": 3,
4384
+ "endIndex": 4
4385
+ },
4386
+ "releaseTag": "Public",
4387
+ "overloadIndex": 1,
4388
+ "parameters": [
4389
+ {
4390
+ "parameterName": "props",
4391
+ "parameterTypeTokenRange": {
4392
+ "startIndex": 1,
4393
+ "endIndex": 2
4394
+ },
4395
+ "isOptional": false
4396
+ }
4397
+ ],
4398
+ "name": "FutureStatement"
4399
+ },
4400
+ {
4401
+ "kind": "Interface",
4402
+ "canonicalReference": "@alloy-js/python!FutureStatementProps:interface",
4403
+ "docComment": "",
4404
+ "excerptTokens": [
4405
+ {
4406
+ "kind": "Content",
4407
+ "text": "export interface FutureStatementProps "
4408
+ }
4409
+ ],
4410
+ "fileUrlPath": "src/components/FutureStatement.tsx",
4411
+ "releaseTag": "Public",
4412
+ "name": "FutureStatementProps",
4413
+ "preserveMemberOrder": false,
4414
+ "members": [
4415
+ {
4416
+ "kind": "PropertySignature",
4417
+ "canonicalReference": "@alloy-js/python!FutureStatementProps#feature:member",
4418
+ "docComment": "/**\n * The name of the feature to import from __future__.\n */\n",
4419
+ "excerptTokens": [
4420
+ {
4421
+ "kind": "Content",
4422
+ "text": "feature: "
4423
+ },
4424
+ {
4425
+ "kind": "Content",
4426
+ "text": "string"
4427
+ },
4428
+ {
4429
+ "kind": "Content",
4430
+ "text": ";"
4431
+ }
4432
+ ],
4433
+ "isReadonly": false,
4434
+ "isOptional": false,
4435
+ "releaseTag": "Public",
4436
+ "name": "feature",
4437
+ "propertyTypeTokenRange": {
4438
+ "startIndex": 1,
4439
+ "endIndex": 2
4440
+ }
4441
+ }
4442
+ ],
4443
+ "extendsTokenRanges": []
4444
+ },
4353
4445
  {
4354
4446
  "kind": "Function",
4355
4447
  "canonicalReference": "@alloy-js/python!GeneratorDoc:function(1)",
@@ -9986,10 +10078,38 @@
9986
10078
  "endIndex": 2
9987
10079
  }
9988
10080
  },
10081
+ {
10082
+ "kind": "PropertySignature",
10083
+ "canonicalReference": "@alloy-js/python!SourceFileProps#futureImports:member",
10084
+ "docComment": "/**\n * __future__ imports to render after the docstring but before regular imports.\n */\n",
10085
+ "excerptTokens": [
10086
+ {
10087
+ "kind": "Content",
10088
+ "text": "futureImports?: "
10089
+ },
10090
+ {
10091
+ "kind": "Reference",
10092
+ "text": "Children",
10093
+ "canonicalReference": "@alloy-js/core!Children:type"
10094
+ },
10095
+ {
10096
+ "kind": "Content",
10097
+ "text": ";"
10098
+ }
10099
+ ],
10100
+ "isReadonly": false,
10101
+ "isOptional": true,
10102
+ "releaseTag": "Public",
10103
+ "name": "futureImports",
10104
+ "propertyTypeTokenRange": {
10105
+ "startIndex": 1,
10106
+ "endIndex": 2
10107
+ }
10108
+ },
9989
10109
  {
9990
10110
  "kind": "PropertySignature",
9991
10111
  "canonicalReference": "@alloy-js/python!SourceFileProps#header:member",
9992
- "docComment": "/**\n * Header comment to add to the file, which will be rendered at the top of the file.\n */\n",
10112
+ "docComment": "/**\n * Content to render at the very top of the file, before everything else.\n * Use this for shebang lines, encoding declarations, or license headers.\n */\n",
9993
10113
  "excerptTokens": [
9994
10114
  {
9995
10115
  "kind": "Content",
@@ -10017,7 +10137,7 @@
10017
10137
  {
10018
10138
  "kind": "PropertySignature",
10019
10139
  "canonicalReference": "@alloy-js/python!SourceFileProps#headerComment:member",
10020
- "docComment": "/**\n * Comment to add to the header, which will be rendered as a comment in the file.\n */\n",
10140
+ "docComment": "/**\n * Comment to add at the top of the file, rendered as a Python comment block.\n * This is a convenience prop for adding copyright notices or other comments.\n */\n",
10021
10141
  "excerptTokens": [
10022
10142
  {
10023
10143
  "kind": "Content",
@@ -108,6 +108,7 @@ describe("Python Class", () => {
108
108
  const mod2Expected = d`
109
109
  from mod1 import A
110
110
 
111
+
111
112
  class B(A):
112
113
  pass
113
114
 
@@ -116,6 +117,7 @@ describe("Python Class", () => {
116
117
  const mod3Expected = d`
117
118
  from folder.mod2 import B
118
119
 
120
+
119
121
  class C(B):
120
122
  pass
121
123
 
@@ -27,6 +27,7 @@ describe("DataclassDeclaration", () => {
27
27
  d`
28
28
  from dataclasses import dataclass
29
29
 
30
+
30
31
  @dataclass
31
32
  class User:
32
33
  """
@@ -74,6 +75,7 @@ describe("DataclassDeclaration", () => {
74
75
  from dataclasses import dataclass
75
76
  from dataclasses import KW_ONLY
76
77
 
78
+
77
79
  @dataclass
78
80
  class User:
79
81
  id: int
@@ -106,6 +108,7 @@ describe("DataclassDeclaration", () => {
106
108
  d`
107
109
  from dataclasses import dataclass
108
110
 
111
+
109
112
  @dataclass(frozen=True, slots=True, kw_only=True)
110
113
  class User:
111
114
  id: int
@@ -141,6 +144,7 @@ describe("DataclassDeclaration", () => {
141
144
  d`
142
145
  from dataclasses import dataclass
143
146
 
147
+
144
148
  @dataclass(init=True, repr=False, eq=True, order=False, unsafe_hash=True, frozen=True, match_args=False, kw_only=True, slots=True, weakref_slot=False)
145
149
  class User:
146
150
  pass
@@ -178,6 +182,7 @@ describe("DataclassDeclaration", () => {
178
182
  d`
179
183
  from dataclasses import dataclass
180
184
 
185
+
181
186
  @dataclass(slots=True, weakref_slot=True)
182
187
  class User:
183
188
  pass
@@ -213,6 +218,7 @@ describe("DataclassDeclaration", () => {
213
218
  d`
214
219
  from dataclasses import dataclass
215
220
 
221
+
216
222
  @dataclass(order=True)
217
223
  class User:
218
224
  pass
@@ -398,6 +404,7 @@ describe("DataclassDeclaration", () => {
398
404
  d`
399
405
  from dataclasses import dataclass
400
406
 
407
+
401
408
  @dataclass(kw_only=True)
402
409
  class User:
403
410
  id: int
@@ -421,6 +428,7 @@ describe("DataclassDeclaration", () => {
421
428
  d`
422
429
  from dataclasses import dataclass
423
430
 
431
+
424
432
  @dataclass
425
433
  class User(Base):
426
434
  pass
@@ -503,6 +511,7 @@ describe("DataclassDeclaration", () => {
503
511
  d`
504
512
  from dataclasses import dataclass
505
513
 
514
+
506
515
  @dataclass(unsafe_hash=True)
507
516
  class User:
508
517
  pass
@@ -556,6 +565,7 @@ describe("DataclassDeclaration", () => {
556
565
  d`
557
566
  from dataclasses import dataclass
558
567
 
568
+
559
569
  @dataclass(frozen=True)
560
570
  class User:
561
571
  pass
@@ -578,6 +588,7 @@ describe("DataclassDeclaration", () => {
578
588
  d`
579
589
  from dataclasses import dataclass
580
590
 
591
+
581
592
  @dataclass(slots=True)
582
593
  class User:
583
594
  pass
@@ -627,6 +638,7 @@ describe("DataclassDeclaration", () => {
627
638
  "models.py": `
628
639
  from dataclasses import dataclass
629
640
 
641
+
630
642
  @dataclass
631
643
  class User:
632
644
  id: int
@@ -636,6 +648,7 @@ describe("DataclassDeclaration", () => {
636
648
  "services.py": `
637
649
  from models import User
638
650
 
651
+
639
652
  def get_user() -> User:
640
653
  user: User = User(1, "Alice")
641
654
  return user
@@ -24,6 +24,7 @@ describe("Python Enum", () => {
24
24
  const expected = d`
25
25
  from enum import IntEnum
26
26
 
27
+
27
28
  class Color(IntEnum):
28
29
  RED = 1
29
30
  GREEN = 2
@@ -52,6 +53,7 @@ describe("Python Enum", () => {
52
53
  const expected = d`
53
54
  from enum import IntEnum
54
55
 
56
+
55
57
  class Color(IntEnum):
56
58
  RED = "1"
57
59
  GREEN = 2
@@ -83,6 +85,7 @@ describe("Python Enum", () => {
83
85
  const expected = d`
84
86
  from enum import Enum
85
87
 
88
+
86
89
  class Dog:
87
90
  pass
88
91
 
@@ -113,6 +116,7 @@ describe("Python Enum", () => {
113
116
  from enum import auto
114
117
  from enum import Enum
115
118
 
119
+
116
120
  class Animal(Enum):
117
121
  DOG = auto()
118
122
  CAT = auto()
@@ -144,6 +148,7 @@ describe("Python Enum", () => {
144
148
  from enum import auto
145
149
  from enum import Flag
146
150
 
151
+
147
152
  class Permission(Flag):
148
153
  READ = 1
149
154
  WRITE = auto()
@@ -172,6 +177,7 @@ describe("Python Enum", () => {
172
177
  const expected = d`
173
178
  from enum import Enum
174
179
 
180
+
175
181
  Direction = Enum('Direction', ['NORTH', 'SOUTH', 'EAST', 'WEST'])
176
182
  `;
177
183
  expect(result).toRenderTo(expected);
@@ -194,6 +200,7 @@ describe("Python Enum", () => {
194
200
  const expected = d`
195
201
  from enum import Enum
196
202
 
203
+
197
204
  Priority = Enum('Priority', {'HIGH' : 1, 'MEDIUM' : 2, 'LOW' : 3})
198
205
  `;
199
206
  expect(result).toRenderTo(expected);
@@ -94,6 +94,7 @@ it("uses import from external library in multiple functions", () => {
94
94
  from requests import post
95
95
  from requests.models import Response
96
96
 
97
+
97
98
  def get_user(user_id: int) -> Response:
98
99
  response = get(1)
99
100
  return response.json()
@@ -170,6 +171,7 @@ it("uses import from external library in multiple class methods", () => {
170
171
  from requests import post
171
172
  from requests.models import Response
172
173
 
174
+
173
175
  class UserClient:
174
176
  some_var = 12
175
177
  def get_user(self, user_id: int) -> Response:
@@ -289,6 +289,7 @@ describe("Function Declaration", () => {
289
289
  expect(toSourceText([decl], { externals: [abcModule] })).toBe(d`
290
290
  from abc import abstractmethod
291
291
 
292
+
292
293
  class MyClass:
293
294
  @abstractmethod
294
295
  def methoddef(self, x: int):
@@ -453,6 +454,7 @@ describe("Function Declaration", () => {
453
454
  from mod2 import A
454
455
  from mod2 import B
455
456
 
457
+
456
458
  async def foo(x: A, y: B, *args, **kwargs) -> Foo:
457
459
  pass
458
460
 
@@ -181,6 +181,7 @@ describe("Method-like Declarations", () => {
181
181
  expect(toSourceText([decl], { externals: [abcModule] })).toBe(d`
182
182
  from abc import abstractmethod
183
183
 
184
+
184
185
  class MyClass:
185
186
  @abstractmethod
186
187
  def methoddef(self, x: int):
@@ -34,6 +34,7 @@ it("correct formatting of Enum name and EnumMember names", () => {
34
34
  const expected = d`
35
35
  from enum import Enum
36
36
 
37
+
37
38
  Priority = Enum('Priority', {'HIGH' : 1, 'MEDIUM' : 2, 'LOW_VALUE' : 3})
38
39
  `;
39
40
  expect(result).toRenderTo(expected);
@@ -170,6 +170,7 @@ describe("PropertyDeclaration", () => {
170
170
  expect(toSourceText([decl], { externals: [abcModule] })).toBe(d`
171
171
  from abc import abstractmethod
172
172
 
173
+
173
174
  class MyClass:
174
175
  @property
175
176
  @abstractmethod
@@ -1138,6 +1138,7 @@ describe("Full example", () => {
1138
1138
  const expected = d`
1139
1139
  from enum import IntEnum
1140
1140
 
1141
+
1141
1142
  class Color(IntEnum):
1142
1143
  """
1143
1144
  An enum representing colors.
@@ -1219,7 +1220,6 @@ describe("Full example", () => {
1219
1220
  * Improve error messages
1220
1221
  """
1221
1222
 
1222
-
1223
1223
  default_timeout = 30
1224
1224
 
1225
1225
  max_retries = 3