|
2 | 2 | # SPDX-License-Identifier: BSD 3-Clause License |
3 | 3 | # Update sync code stubs |
4 | 4 | import ast |
| 5 | +import subprocess |
5 | 6 |
|
6 | | -import kr8s._objects as base_objects |
| 7 | +ELLIPSIS_NODE = ast.parse("...").body |
| 8 | +# TODO: Preserve docstrings in method/function definitions |
| 9 | +# TODO: Remove unused imports |
7 | 10 |
|
| 11 | +# Load the AST for the base object definitions |
8 | 12 | with open("kr8s/_objects.py") as base_source_fh: |
9 | 13 | base_source = base_source_fh.read() |
10 | 14 | base_tree = ast.parse(base_source) |
11 | 15 |
|
12 | | - |
| 16 | +# Load the AST for the sync API |
13 | 17 | with open("kr8s/objects.py") as source_fh: |
14 | 18 | source = source_fh.read() |
15 | 19 | tree = ast.parse(source) |
16 | 20 |
|
17 | | - # Update module docstring |
18 | | - if isinstance(tree.body[0], ast.Expr) and isinstance( |
19 | | - tree.body[0].value, ast.Constant |
20 | | - ): |
21 | | - tree.body[0].value.value += ( |
22 | | - "\n" |
23 | | - "WARNING: This typing stub file was generated by ci/gen_stubs.py\n" |
24 | | - "DO NOT MODIFY DIRECTLY\n" |
25 | | - ) |
26 | | - |
27 | | - for node in tree.body: |
28 | | - if isinstance(node, ast.ImportFrom): |
29 | | - if node.level != 1: |
30 | | - tree.body.remove(node) |
31 | | - |
32 | | - elif isinstance(node, ast.ClassDef): |
33 | | - # Clear the sync decorator |
34 | | - for decorator in node.decorator_list: |
35 | | - if isinstance(decorator, ast.Name) and decorator.id == "sync": |
36 | | - node.decorator_list.remove(decorator) |
37 | | - node.body = [subnode for subnode in node.body if not isinstance(subnode, ast.Assign)] |
38 | | - # Populate public methods from base classes |
39 | | - for base in node.bases: |
40 | | - if isinstance(base, ast.Name): |
41 | | - # import the base class in this script with importlib |
42 | | - base_class = getattr(base_objects, base.id[1:]) |
43 | | - # iterate over the methods of the base class |
44 | | - for base_class_attr in base_class.__dict__.keys(): |
45 | | - method = getattr(base_class, base_class_attr) |
46 | | - if callable(method): |
47 | | - if not base_class_attr.startswith("_") and not base_class_attr.startswith("async_"): |
48 | | - node.body.append(ast.parse(f"def {base_class_attr}(self): ...").body[0]) |
49 | | - |
50 | | - |
51 | | - else: |
52 | | - pass |
53 | | - |
54 | | - with open("kr8s/objects_tmp.pyi", "w") as target_fh: |
55 | | - target_fh.write(ast.unparse(tree)) |
| 21 | +# Update module docstring |
| 22 | +if isinstance(tree.body[0], ast.Expr) and isinstance(tree.body[0].value, ast.Constant): |
| 23 | + tree.body[0].value.value += ( |
| 24 | + "\n" |
| 25 | + "WARNING: This typing stub file was generated by ci/gen_stubs.py\n" |
| 26 | + "DO NOT MODIFY DIRECTLY\n" |
| 27 | + ) |
| 28 | + |
| 29 | + |
| 30 | +# Add all imports from base_tree (these will be pruned later) |
| 31 | +for node in base_tree.body: |
| 32 | + if isinstance(node, ast.Import): |
| 33 | + tree.body.insert(2, node) |
| 34 | + elif isinstance(node, ast.ImportFrom): |
| 35 | + # If not __future__ import, add it |
| 36 | + if node.module != "__future__": |
| 37 | + tree.body.insert(2, node) |
| 38 | + |
| 39 | +for node_index, node in enumerate(tree.body): |
| 40 | + |
| 41 | + # # Remove non-relative imports |
| 42 | + # if isinstance(node, ast.ImportFrom): |
| 43 | + # if node.level != 1: |
| 44 | + # tree.body.remove(node) |
| 45 | + |
| 46 | + # Update class definitions |
| 47 | + if isinstance(node, ast.ClassDef): |
| 48 | + # Replace the class definitions with the bass class |
| 49 | + for base_node in base_tree.body: |
| 50 | + if isinstance(base_node, ast.ClassDef) and base_node.name == node.name: |
| 51 | + if node.name == "APIObject": |
| 52 | + base_node.bases = node.bases |
| 53 | + |
| 54 | + # Replace all methods with type stubs |
| 55 | + for subnode_index, subnode in enumerate(base_node.body): |
| 56 | + if isinstance(subnode, ast.FunctionDef): |
| 57 | + subnode.body = ELLIPSIS_NODE |
| 58 | + elif isinstance(subnode, ast.AsyncFunctionDef): |
| 59 | + base_node.body[subnode_index] = ast.FunctionDef( |
| 60 | + name=subnode.name, |
| 61 | + args=subnode.args, |
| 62 | + body=ELLIPSIS_NODE, |
| 63 | + decorator_list=subnode.decorator_list, |
| 64 | + returns=subnode.returns, |
| 65 | + type_comment=subnode.type_comment, |
| 66 | + type_params=subnode.type_params, |
| 67 | + lineno=subnode.lineno, |
| 68 | + ) |
| 69 | + pass |
| 70 | + elif isinstance(subnode, ast.AnnAssign): |
| 71 | + # Remove value |
| 72 | + subnode.value = None |
| 73 | + else: |
| 74 | + pass |
| 75 | + |
| 76 | + tree.body[node_index] = base_node |
| 77 | + |
| 78 | + elif isinstance(node, ast.FunctionDef): |
| 79 | + # Replace all functions with version from bass_tree |
| 80 | + for base_node in base_tree.body: |
| 81 | + if ( |
| 82 | + isinstance(base_node, ast.FunctionDef) |
| 83 | + or isinstance(base_node, ast.AsyncFunctionDef) |
| 84 | + ) and base_node.name == node.name: |
| 85 | + # Replace the function definition |
| 86 | + tree.body[node_index] = ast.FunctionDef( |
| 87 | + name=base_node.name, |
| 88 | + args=base_node.args, |
| 89 | + body=ELLIPSIS_NODE, |
| 90 | + decorator_list=base_node.decorator_list, |
| 91 | + returns=base_node.returns, |
| 92 | + type_comment=base_node.type_comment, |
| 93 | + type_params=base_node.type_params, |
| 94 | + lineno=base_node.lineno, |
| 95 | + ) |
| 96 | + else: |
| 97 | + pass |
| 98 | + |
| 99 | +with open("kr8s/objects.pyi", "w") as target_fh: |
| 100 | + target_fh.write(ast.unparse(tree)) |
| 101 | + |
| 102 | +# Run black and ruff |
| 103 | +subprocess.run(["black", "kr8s/objects.pyi"]) |
| 104 | +subprocess.run(["ruff", "check", "--fix", "kr8s/objects.pyi"]) |
0 commit comments