zrb 1.0.0b9__py3-none-any.whl → 1.0.0b10__py3-none-any.whl
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.
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/.coveragerc +11 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/.gitignore +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/add_column_task.py +4 -4
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +5 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +107 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +67 -4
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/test/my_module/my_entity/test_create_my_entity.py +53 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/test/my_module/my_entity/test_delete_my_entity.py +62 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/test/my_module/my_entity/test_read_my_entity.py +65 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/test/my_module/my_entity/test_update_my_entity.py +61 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +57 -13
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +2 -2
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py +6 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py +10 -6
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task.py +56 -12
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task_util.py +10 -4
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_service.py +136 -52
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/parser.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +1 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_auth_tables.py +46 -43
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/8ed025bcc845_create_permissions.py +69 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py +5 -2
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service.py +16 -21
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +193 -43
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/auth.py +57 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +6 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py +1 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/user.py +9 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/_util/access_token.py +19 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/permission/test_create_permission.py +59 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/permission/test_delete_permission.py +68 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/permission/test_read_permission.py +71 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/permission/test_update_permission.py +66 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/test_user_session.py +195 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_health_and_readiness.py +28 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_homepage.py +17 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_not_found_error.py +16 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test.sh +7 -0
- zrb/task/base_task.py +10 -10
- zrb/util/codemod/modification_mode.py +3 -0
- zrb/util/codemod/modify_class.py +58 -0
- zrb/util/codemod/modify_class_parent.py +68 -0
- zrb/util/codemod/modify_class_property.py +128 -0
- zrb/util/codemod/modify_dict.py +75 -0
- zrb/util/codemod/modify_function.py +65 -0
- zrb/util/codemod/modify_function_call.py +68 -0
- zrb/util/codemod/modify_method.py +88 -0
- zrb/util/codemod/{prepend_code_to_module.py → modify_module.py} +2 -3
- zrb/util/file.py +3 -2
- {zrb-1.0.0b9.dist-info → zrb-1.0.0b10.dist-info}/METADATA +1 -1
- {zrb-1.0.0b9.dist-info → zrb-1.0.0b10.dist-info}/RECORD +53 -36
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/migrate.py +0 -3
- zrb/util/codemod/append_code_to_class.py +0 -35
- zrb/util/codemod/append_code_to_function.py +0 -38
- zrb/util/codemod/append_code_to_method.py +0 -55
- zrb/util/codemod/append_key_to_dict.py +0 -51
- zrb/util/codemod/append_param_to_function_call.py +0 -39
- zrb/util/codemod/prepend_parent_to_class.py +0 -38
- zrb/util/codemod/prepend_property_to_class.py +0 -55
- {zrb-1.0.0b9.dist-info → zrb-1.0.0b10.dist-info}/WHEEL +0 -0
- {zrb-1.0.0b9.dist-info → zrb-1.0.0b10.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
import libcst as cst
|
2
|
+
|
3
|
+
from zrb.util.codemod.modification_mode import APPEND, PREPEND, REPLACE
|
4
|
+
|
5
|
+
|
6
|
+
def replace_parent_class(
|
7
|
+
original_code: str, class_name: str, parent_class_name: str
|
8
|
+
) -> str:
|
9
|
+
return _modify_parent_class(original_code, class_name, parent_class_name, REPLACE)
|
10
|
+
|
11
|
+
|
12
|
+
def append_parent_class(
|
13
|
+
original_code: str, class_name: str, parent_class_name: str
|
14
|
+
) -> str:
|
15
|
+
return _modify_parent_class(original_code, class_name, parent_class_name, APPEND)
|
16
|
+
|
17
|
+
|
18
|
+
def prepend_parent_class(
|
19
|
+
original_code: str, class_name: str, parent_class_name: str
|
20
|
+
) -> str:
|
21
|
+
return _modify_parent_class(original_code, class_name, parent_class_name, PREPEND)
|
22
|
+
|
23
|
+
|
24
|
+
def _modify_parent_class(
|
25
|
+
original_code: str, class_name: str, parent_class_name: str, mode: int
|
26
|
+
) -> str:
|
27
|
+
# Parse the original code into a module
|
28
|
+
module = cst.parse_module(original_code)
|
29
|
+
# Initialize transformer with the class name and parent class name
|
30
|
+
transformer = _ParentClassAdder(class_name, parent_class_name, mode)
|
31
|
+
# Apply the transformation
|
32
|
+
modified_module = module.visit(transformer)
|
33
|
+
# Check if the class was found
|
34
|
+
if not transformer.class_found:
|
35
|
+
raise ValueError(f"Class {class_name} not found in the provided code.")
|
36
|
+
# Return the modified code
|
37
|
+
return modified_module.code
|
38
|
+
|
39
|
+
|
40
|
+
class _ParentClassAdder(cst.CSTTransformer):
|
41
|
+
def __init__(self, class_name: str, parent_class_name: str, mode: int):
|
42
|
+
self.class_name = class_name
|
43
|
+
self.parent_class_name = parent_class_name
|
44
|
+
self.class_found = False
|
45
|
+
self.mode = mode
|
46
|
+
|
47
|
+
def leave_ClassDef(
|
48
|
+
self, original_node: cst.ClassDef, updated_node: cst.ClassDef
|
49
|
+
) -> cst.ClassDef:
|
50
|
+
# Check if this is the target class
|
51
|
+
if original_node.name.value == self.class_name:
|
52
|
+
self.class_found = True
|
53
|
+
if self.mode == REPLACE:
|
54
|
+
new_bases = (cst.Arg(value=cst.Name(self.parent_class_name)),)
|
55
|
+
return updated_node.with_changes(bases=new_bases)
|
56
|
+
if self.mode == PREPEND:
|
57
|
+
new_bases = (
|
58
|
+
cst.Arg(value=cst.Name(self.parent_class_name)),
|
59
|
+
*updated_node.bases,
|
60
|
+
)
|
61
|
+
return updated_node.with_changes(bases=new_bases)
|
62
|
+
if self.mode == APPEND:
|
63
|
+
new_bases = (
|
64
|
+
*updated_node.bases,
|
65
|
+
cst.Arg(value=cst.Name(self.parent_class_name)),
|
66
|
+
)
|
67
|
+
return updated_node.with_changes(bases=new_bases)
|
68
|
+
return updated_node
|
@@ -0,0 +1,128 @@
|
|
1
|
+
import libcst as cst
|
2
|
+
|
3
|
+
from zrb.util.codemod.modification_mode import APPEND, PREPEND
|
4
|
+
|
5
|
+
|
6
|
+
def append_property_to_class(
|
7
|
+
original_code: str,
|
8
|
+
class_name: str,
|
9
|
+
property_name: str,
|
10
|
+
annotation: str,
|
11
|
+
default_value: str,
|
12
|
+
) -> str:
|
13
|
+
return _modify_class_property(
|
14
|
+
original_code, class_name, property_name, annotation, default_value, APPEND
|
15
|
+
)
|
16
|
+
|
17
|
+
|
18
|
+
def prepend_property_to_class(
|
19
|
+
original_code: str,
|
20
|
+
class_name: str,
|
21
|
+
property_name: str,
|
22
|
+
annotation: str,
|
23
|
+
default_value: str,
|
24
|
+
) -> str:
|
25
|
+
return _modify_class_property(
|
26
|
+
original_code, class_name, property_name, annotation, default_value, PREPEND
|
27
|
+
)
|
28
|
+
|
29
|
+
|
30
|
+
def _modify_class_property(
|
31
|
+
original_code: str,
|
32
|
+
class_name: str,
|
33
|
+
property_name: str,
|
34
|
+
annotation: str,
|
35
|
+
default_value: str,
|
36
|
+
mode: int,
|
37
|
+
) -> str:
|
38
|
+
# Parse the original code into a module
|
39
|
+
module = cst.parse_module(original_code)
|
40
|
+
# Initialize transformer with the class name, property name, annotation, and default value
|
41
|
+
transformer = _ClassPropertyModifier(
|
42
|
+
class_name, property_name, annotation, default_value, mode
|
43
|
+
)
|
44
|
+
# Apply the transformation
|
45
|
+
modified_module = module.visit(transformer)
|
46
|
+
# Check if the class was found
|
47
|
+
if not transformer.class_found:
|
48
|
+
raise ValueError(f"Class {class_name} not found in the provided code.")
|
49
|
+
# Return the modified code
|
50
|
+
return modified_module.code
|
51
|
+
|
52
|
+
|
53
|
+
class _ClassPropertyModifier(cst.CSTTransformer):
|
54
|
+
def __init__(
|
55
|
+
self,
|
56
|
+
class_name: str,
|
57
|
+
property_name: str,
|
58
|
+
annotation: str,
|
59
|
+
default_value: str,
|
60
|
+
mode: int,
|
61
|
+
):
|
62
|
+
self.class_name = class_name
|
63
|
+
self.property_name = property_name
|
64
|
+
self.annotation = cst.Annotation(cst.parse_expression(annotation))
|
65
|
+
self.default_value = cst.parse_expression(default_value)
|
66
|
+
self.class_found = False
|
67
|
+
self.mode = mode
|
68
|
+
|
69
|
+
def leave_ClassDef(
|
70
|
+
self, original_node: cst.ClassDef, updated_node: cst.ClassDef
|
71
|
+
) -> cst.ClassDef:
|
72
|
+
# Check if this is the target class
|
73
|
+
if original_node.name.value == self.class_name:
|
74
|
+
self.class_found = True
|
75
|
+
# Create the annotated property with a default value
|
76
|
+
new_property = cst.SimpleStatementLine(
|
77
|
+
body=[
|
78
|
+
cst.AnnAssign(
|
79
|
+
target=cst.Name(self.property_name),
|
80
|
+
annotation=self.annotation,
|
81
|
+
value=self.default_value,
|
82
|
+
)
|
83
|
+
]
|
84
|
+
)
|
85
|
+
if self.mode == PREPEND:
|
86
|
+
new_body = cst.IndentedBlock(
|
87
|
+
body=(new_property,) + updated_node.body.body
|
88
|
+
)
|
89
|
+
return updated_node.with_changes(body=new_body)
|
90
|
+
if self.mode == APPEND:
|
91
|
+
# Identify properties and methods
|
92
|
+
properties = []
|
93
|
+
methods = []
|
94
|
+
for stmt in updated_node.body.body:
|
95
|
+
if isinstance(stmt, cst.SimpleStatementLine) and isinstance(
|
96
|
+
stmt.body[0], (cst.AnnAssign, cst.Assign)
|
97
|
+
):
|
98
|
+
properties.append(stmt)
|
99
|
+
elif isinstance(stmt, cst.FunctionDef):
|
100
|
+
methods.append(stmt)
|
101
|
+
if properties:
|
102
|
+
# Class has properties
|
103
|
+
last_property_index = updated_node.body.body.index(properties[-1])
|
104
|
+
new_body = cst.IndentedBlock(
|
105
|
+
body=(
|
106
|
+
updated_node.body.body[: last_property_index + 1]
|
107
|
+
+ (new_property,)
|
108
|
+
+ updated_node.body.body[last_property_index + 1 :]
|
109
|
+
)
|
110
|
+
)
|
111
|
+
return updated_node.with_changes(body=new_body)
|
112
|
+
if methods:
|
113
|
+
# Class doesn't have properties but has methods
|
114
|
+
first_method_index = updated_node.body.body.index(methods[0])
|
115
|
+
new_body = cst.IndentedBlock(
|
116
|
+
body=(
|
117
|
+
updated_node.body.body[:first_method_index]
|
118
|
+
+ (new_property,)
|
119
|
+
+ updated_node.body.body[first_method_index:]
|
120
|
+
)
|
121
|
+
)
|
122
|
+
return updated_node.with_changes(body=new_body)
|
123
|
+
# Class is empty, add add the bottom
|
124
|
+
new_body = cst.IndentedBlock(
|
125
|
+
body=updated_node.body.body + (new_property,)
|
126
|
+
)
|
127
|
+
return updated_node.with_changes(body=new_body)
|
128
|
+
return updated_node
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import libcst as cst
|
2
|
+
|
3
|
+
from zrb.util.codemod.modification_mode import APPEND, PREPEND
|
4
|
+
|
5
|
+
|
6
|
+
def prepend_key_to_dict(
|
7
|
+
original_code: str, dictionary_name: str, new_key: str, new_value: str
|
8
|
+
) -> str:
|
9
|
+
return _modify_dict(original_code, dictionary_name, new_key, new_value, PREPEND)
|
10
|
+
|
11
|
+
|
12
|
+
def append_key_to_dict(
|
13
|
+
original_code: str, dictionary_name: str, new_key: str, new_value: str
|
14
|
+
) -> str:
|
15
|
+
return _modify_dict(original_code, dictionary_name, new_key, new_value, APPEND)
|
16
|
+
|
17
|
+
|
18
|
+
def _modify_dict(
|
19
|
+
original_code: str, dictionary_name: str, new_key: str, new_value: str, mode: int
|
20
|
+
) -> str:
|
21
|
+
# Parse the original code into a module
|
22
|
+
module = cst.parse_module(original_code)
|
23
|
+
# Initialize the transformer with the necessary information
|
24
|
+
transformer = _DictionaryModifier(dictionary_name, new_key, new_value, mode)
|
25
|
+
# Apply the transformation
|
26
|
+
modified_module = module.visit(transformer)
|
27
|
+
# Error handling: raise an error if the dictionary is not found
|
28
|
+
if not transformer.found:
|
29
|
+
raise ValueError(
|
30
|
+
f"Dictionary {dictionary_name} not found in the provided code."
|
31
|
+
)
|
32
|
+
# Return the modified code
|
33
|
+
return modified_module.code
|
34
|
+
|
35
|
+
|
36
|
+
class _DictionaryModifier(cst.CSTTransformer):
|
37
|
+
def __init__(self, dictionary_name: str, new_key: str, new_value: str, mode: int):
|
38
|
+
self.dictionary_name = dictionary_name
|
39
|
+
self.new_key = new_key
|
40
|
+
self.new_value = new_value
|
41
|
+
self.found = False
|
42
|
+
self.mode = mode
|
43
|
+
|
44
|
+
def leave_Assign(
|
45
|
+
self, original_node: cst.Assign, updated_node: cst.Assign
|
46
|
+
) -> cst.Assign:
|
47
|
+
# Extract the first target from updated_node, which will be an AssignTarget
|
48
|
+
target = updated_node.targets[0]
|
49
|
+
# Check if the target is a Name (which should represent the dictionary)
|
50
|
+
if (
|
51
|
+
isinstance(target.target, cst.Name)
|
52
|
+
and target.target.value == self.dictionary_name
|
53
|
+
):
|
54
|
+
# Check if it's a dictionary initialization (e.g., my_dict = {...})
|
55
|
+
if isinstance(updated_node.value, cst.Dict):
|
56
|
+
self.found = True
|
57
|
+
if self.mode == PREPEND:
|
58
|
+
new_entries = (
|
59
|
+
cst.DictElement(
|
60
|
+
key=cst.SimpleString(f'"{self.new_key}"'),
|
61
|
+
value=cst.SimpleString(f'"{self.new_value}"'),
|
62
|
+
),
|
63
|
+
) + updated_node.value.elements
|
64
|
+
new_dict = updated_node.value.with_changes(elements=new_entries)
|
65
|
+
return updated_node.with_changes(value=new_dict)
|
66
|
+
if self.mode == APPEND:
|
67
|
+
new_entries = updated_node.value.elements + (
|
68
|
+
cst.DictElement(
|
69
|
+
key=cst.SimpleString(f'"{self.new_key}"'),
|
70
|
+
value=cst.SimpleString(f'"{self.new_value}"'),
|
71
|
+
),
|
72
|
+
)
|
73
|
+
new_dict = updated_node.value.with_changes(elements=new_entries)
|
74
|
+
return updated_node.with_changes(value=new_dict)
|
75
|
+
return updated_node
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import libcst as cst
|
2
|
+
|
3
|
+
from zrb.util.codemod.modification_mode import APPEND, PREPEND, REPLACE
|
4
|
+
|
5
|
+
|
6
|
+
def replace_function_code(original_code: str, function_name: str, new_code: str) -> str:
|
7
|
+
return _modify_function(original_code, function_name, new_code, REPLACE)
|
8
|
+
|
9
|
+
|
10
|
+
def prepend_code_to_function(
|
11
|
+
original_code: str, function_name: str, new_code: str
|
12
|
+
) -> str:
|
13
|
+
return _modify_function(original_code, function_name, new_code, PREPEND)
|
14
|
+
|
15
|
+
|
16
|
+
def append_code_to_function(
|
17
|
+
original_code: str, function_name: str, new_code: str
|
18
|
+
) -> str:
|
19
|
+
return _modify_function(original_code, function_name, new_code, APPEND)
|
20
|
+
|
21
|
+
|
22
|
+
def _modify_function(
|
23
|
+
original_code: str, function_name: str, new_code: str, mode: int
|
24
|
+
) -> str:
|
25
|
+
# Parse the original code into a module
|
26
|
+
module = cst.parse_module(original_code)
|
27
|
+
# Initialize the transformer with the necessary information
|
28
|
+
transformer = _FunctionCodeModifier(function_name, new_code, mode)
|
29
|
+
# Apply the transformation
|
30
|
+
modified_module = module.visit(transformer)
|
31
|
+
# Error handling: raise an error if the class or function is not found
|
32
|
+
if not transformer.function_found:
|
33
|
+
raise ValueError(f"Function {function_name} not found.")
|
34
|
+
# Return the modified code
|
35
|
+
return modified_module.code
|
36
|
+
|
37
|
+
|
38
|
+
class _FunctionCodeModifier(cst.CSTTransformer):
|
39
|
+
def __init__(self, function_name: str, new_code: str, mode: int):
|
40
|
+
self.function_name = function_name
|
41
|
+
# Use parse_module to handle multiple statements
|
42
|
+
self.new_code = cst.parse_module(new_code).body
|
43
|
+
self.function_found = False
|
44
|
+
self.mode = mode
|
45
|
+
|
46
|
+
def leave_FunctionDef(
|
47
|
+
self, original_node: cst.ClassDef, updated_node: cst.ClassDef
|
48
|
+
) -> cst.ClassDef:
|
49
|
+
# Check if the class matches the target class
|
50
|
+
if original_node.name.value == self.function_name:
|
51
|
+
self.function_found = True
|
52
|
+
if self.mode == REPLACE:
|
53
|
+
new_body = updated_node.body.with_changes(body=tuple(self.new_code))
|
54
|
+
return updated_node.with_changes(body=new_body)
|
55
|
+
if self.mode == PREPEND:
|
56
|
+
new_body = updated_node.body.with_changes(
|
57
|
+
body=tuple(self.new_code) + updated_node.body.body
|
58
|
+
)
|
59
|
+
return updated_node.with_changes(body=new_body)
|
60
|
+
if self.mode == APPEND:
|
61
|
+
new_body = updated_node.body.with_changes(
|
62
|
+
body=updated_node.body.body + tuple(self.new_code)
|
63
|
+
)
|
64
|
+
return updated_node.with_changes(body=new_body)
|
65
|
+
return updated_node
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import libcst as cst
|
2
|
+
|
3
|
+
from zrb.util.codemod.modification_mode import APPEND, PREPEND, REPLACE
|
4
|
+
|
5
|
+
|
6
|
+
def replace_function_call_param(
|
7
|
+
original_code: str, function_name: str, new_param: str
|
8
|
+
) -> str:
|
9
|
+
return _modify_function_call(original_code, function_name, new_param, REPLACE)
|
10
|
+
|
11
|
+
|
12
|
+
def prepend_param_to_function_call(
|
13
|
+
original_code: str, function_name: str, new_param: str
|
14
|
+
) -> str:
|
15
|
+
return _modify_function_call(original_code, function_name, new_param, PREPEND)
|
16
|
+
|
17
|
+
|
18
|
+
def append_param_to_function_call(
|
19
|
+
original_code: str, function_name: str, new_param: str
|
20
|
+
) -> str:
|
21
|
+
return _modify_function_call(original_code, function_name, new_param, APPEND)
|
22
|
+
|
23
|
+
|
24
|
+
def _modify_function_call(
|
25
|
+
original_code: str, function_name: str, new_param: str, mode: int
|
26
|
+
) -> str:
|
27
|
+
# Parse the original code into a module
|
28
|
+
module = cst.parse_module(original_code)
|
29
|
+
# Initialize the transformer with the necessary information
|
30
|
+
transformer = _FunctionCallParamModifier(function_name, new_param, mode)
|
31
|
+
# Apply the transformation
|
32
|
+
modified_module = module.visit(transformer)
|
33
|
+
# Error handling: raise an error if the function call is not found
|
34
|
+
if not transformer.param_added:
|
35
|
+
raise ValueError(
|
36
|
+
f"Function call to {function_name} not found in the provided code."
|
37
|
+
)
|
38
|
+
# Return the modified code
|
39
|
+
return modified_module.code
|
40
|
+
|
41
|
+
|
42
|
+
class _FunctionCallParamModifier(cst.CSTTransformer):
|
43
|
+
def __init__(self, func_name: str, new_param: str, mode: int):
|
44
|
+
self.func_name = func_name
|
45
|
+
# Parse the new parameter to ensure it’s a valid CST node
|
46
|
+
self.new_param = cst.parse_expression(new_param)
|
47
|
+
self.param_added = False
|
48
|
+
self.mode = mode
|
49
|
+
|
50
|
+
def leave_Call(self, original_node: cst.Call, updated_node: cst.Call) -> cst.Call:
|
51
|
+
# Check if the function call name matches the target function
|
52
|
+
if (
|
53
|
+
isinstance(original_node.func, cst.Name)
|
54
|
+
and original_node.func.value == self.func_name
|
55
|
+
):
|
56
|
+
if self.mode == REPLACE:
|
57
|
+
new_args = (cst.Arg(value=self.new_param),)
|
58
|
+
self.param_added = True
|
59
|
+
return updated_node.with_changes(args=new_args)
|
60
|
+
if self.mode == PREPEND:
|
61
|
+
new_args = (cst.Arg(value=self.new_param),) + updated_node.args
|
62
|
+
self.param_added = True
|
63
|
+
return updated_node.with_changes(args=new_args)
|
64
|
+
if self.mode == APPEND:
|
65
|
+
new_args = updated_node.args + (cst.Arg(value=self.new_param),)
|
66
|
+
self.param_added = True
|
67
|
+
return updated_node.with_changes(args=new_args)
|
68
|
+
return updated_node
|
@@ -0,0 +1,88 @@
|
|
1
|
+
import libcst as cst
|
2
|
+
|
3
|
+
from zrb.util.codemod.modification_mode import APPEND, PREPEND, REPLACE
|
4
|
+
|
5
|
+
|
6
|
+
def replace_method_code(
|
7
|
+
original_code: str, class_name: str, method_name: str, new_code: str
|
8
|
+
) -> str:
|
9
|
+
return _modify_method(original_code, class_name, method_name, new_code, REPLACE)
|
10
|
+
|
11
|
+
|
12
|
+
def prepend_code_to_method(
|
13
|
+
original_code: str, class_name: str, method_name: str, new_code: str
|
14
|
+
) -> str:
|
15
|
+
return _modify_method(original_code, class_name, method_name, new_code, PREPEND)
|
16
|
+
|
17
|
+
|
18
|
+
def append_code_to_method(
|
19
|
+
original_code: str, class_name: str, method_name: str, new_code: str
|
20
|
+
) -> str:
|
21
|
+
return _modify_method(original_code, class_name, method_name, new_code, APPEND)
|
22
|
+
|
23
|
+
|
24
|
+
def _modify_method(
|
25
|
+
original_code: str, class_name: str, method_name: str, new_code: str, mode: int
|
26
|
+
) -> str:
|
27
|
+
# Parse the original code into a module
|
28
|
+
module = cst.parse_module(original_code)
|
29
|
+
# Initialize the transformer with the necessary information
|
30
|
+
transformer = _MethodModifier(class_name, method_name, new_code, mode)
|
31
|
+
# Apply the transformation
|
32
|
+
modified_module = module.visit(transformer)
|
33
|
+
# Error handling: raise an error if the class or function is not found
|
34
|
+
if not transformer.class_found:
|
35
|
+
raise ValueError(f"Class {class_name} not found in the provided code.")
|
36
|
+
if not transformer.method_found:
|
37
|
+
raise ValueError(f"Method {method_name} not found in class {class_name}.")
|
38
|
+
# Return the modified code
|
39
|
+
return modified_module.code
|
40
|
+
|
41
|
+
|
42
|
+
class _MethodModifier(cst.CSTTransformer):
|
43
|
+
def __init__(self, class_name: str, method_name: str, new_code: str, mode: int):
|
44
|
+
self.class_name = class_name
|
45
|
+
self.method_name = method_name
|
46
|
+
# Use parse_module to handle multiple statements
|
47
|
+
self.new_code = cst.parse_module(new_code).body
|
48
|
+
self.class_found = False
|
49
|
+
self.method_found = False
|
50
|
+
self.mode = mode
|
51
|
+
|
52
|
+
def leave_ClassDef(
|
53
|
+
self, original_node: cst.ClassDef, updated_node: cst.ClassDef
|
54
|
+
) -> cst.ClassDef:
|
55
|
+
# Check if the class matches the target class
|
56
|
+
if original_node.name.value == self.class_name:
|
57
|
+
self.class_found = True
|
58
|
+
# Now, modify function definitions inside this class
|
59
|
+
new_body = []
|
60
|
+
for (
|
61
|
+
item
|
62
|
+
) in updated_node.body.body: # Access body.body, not just updated_node.body
|
63
|
+
if (
|
64
|
+
isinstance(item, cst.FunctionDef)
|
65
|
+
and item.name.value == self.method_name
|
66
|
+
):
|
67
|
+
# Modify the target function by adding the new code
|
68
|
+
if self.mode == REPLACE:
|
69
|
+
body_with_new_code = item.body.with_changes(
|
70
|
+
body=tuple(self.new_code)
|
71
|
+
)
|
72
|
+
new_body.append(item.with_changes(body=body_with_new_code))
|
73
|
+
if self.mode == PREPEND:
|
74
|
+
body_with_new_code = item.body.with_changes(
|
75
|
+
body=tuple(self.new_code) + item.body.body
|
76
|
+
)
|
77
|
+
new_body.append(item.with_changes(body=body_with_new_code))
|
78
|
+
|
79
|
+
if self.mode == APPEND:
|
80
|
+
body_with_new_code = item.body.with_changes(
|
81
|
+
body=item.body.body + tuple(self.new_code)
|
82
|
+
)
|
83
|
+
new_body.append(item.with_changes(body=body_with_new_code))
|
84
|
+
self.method_found = True
|
85
|
+
else:
|
86
|
+
new_body.append(item)
|
87
|
+
return updated_node.with_changes(body=cst.IndentedBlock(new_body))
|
88
|
+
return updated_node
|
@@ -5,8 +5,7 @@ def prepend_code_to_module(original_code: str, new_code: str) -> str:
|
|
5
5
|
stripped_line = line.strip()
|
6
6
|
if stripped_line.startswith("import") or stripped_line.startswith("from"):
|
7
7
|
last_import_index = i
|
8
|
-
|
8
|
+
else:
|
9
9
|
break
|
10
|
-
|
11
|
-
lines.insert(last_import_index + 1, new_code)
|
10
|
+
lines.insert(last_import_index + 1, new_code)
|
12
11
|
return "\n".join(lines)
|
zrb/util/file.py
CHANGED
@@ -15,10 +15,11 @@ def write_file(file_path: str, content: str | list[str]):
|
|
15
15
|
content = "\n".join([line for line in content if line is not None])
|
16
16
|
dir_path = os.path.dirname(file_path)
|
17
17
|
os.makedirs(dir_path, exist_ok=True)
|
18
|
+
should_add_eol = content.endswith("\n")
|
19
|
+
# Remove trailing newlines, but keep one if the file originally ended up with newline
|
18
20
|
content = re.sub(r"\n{3,}$", "\n\n", content)
|
19
|
-
# Remove trailing newlines, but keep one if it exists
|
20
21
|
content = content.rstrip("\n")
|
21
|
-
if
|
22
|
+
if should_add_eol:
|
22
23
|
content += "\n"
|
23
24
|
with open(file_path, "w") as f:
|
24
25
|
f.write(content)
|