mapFolding 0.9.3__py3-none-any.whl → 0.9.5__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.
- mapFolding/__init__.py +41 -7
- mapFolding/basecamp.py +100 -9
- mapFolding/beDRY.py +7 -15
- mapFolding/dataBaskets.py +12 -0
- mapFolding/datatypes.py +4 -4
- mapFolding/oeis.py +2 -7
- mapFolding/someAssemblyRequired/RecipeJob.py +97 -3
- mapFolding/someAssemblyRequired/Z0Z_makeSomeModules.py +326 -0
- mapFolding/someAssemblyRequired/__init__.py +37 -29
- mapFolding/someAssemblyRequired/_theTypes.py +19 -19
- mapFolding/someAssemblyRequired/_tool_Make.py +12 -6
- mapFolding/someAssemblyRequired/_tool_Then.py +59 -21
- mapFolding/someAssemblyRequired/_toolboxAST.py +57 -0
- mapFolding/someAssemblyRequired/_toolboxAntecedents.py +123 -40
- mapFolding/someAssemblyRequired/_toolboxContainers.py +128 -37
- mapFolding/someAssemblyRequired/_toolboxPython.py +52 -50
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +274 -0
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +6 -4
- mapFolding/someAssemblyRequired/toolboxNumba.py +3 -27
- mapFolding/someAssemblyRequired/transformationTools.py +47 -177
- mapFolding/syntheticModules/daoOfMapFolding.py +74 -0
- mapFolding/syntheticModules/dataPacking.py +25 -0
- mapFolding/syntheticModules/initializeCount.py +49 -0
- mapFolding/syntheticModules/theorem2.py +49 -0
- mapFolding/syntheticModules/theorem2Numba.py +45 -0
- mapFolding/syntheticModules/theorem2Trimmed.py +43 -0
- {mapfolding-0.9.3.dist-info → mapfolding-0.9.5.dist-info}/METADATA +2 -1
- mapfolding-0.9.5.dist-info/RECORD +59 -0
- {mapfolding-0.9.3.dist-info → mapfolding-0.9.5.dist-info}/WHEEL +1 -1
- tests/test_computations.py +4 -2
- mapFolding/Z0Z_flowControl.py +0 -99
- mapfolding-0.9.3.dist-info/RECORD +0 -51
- /mapFolding/{theDaoOfMapFolding.py → daoOfMapFolding.py} +0 -0
- {mapfolding-0.9.3.dist-info → mapfolding-0.9.5.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.9.3.dist-info → mapfolding-0.9.5.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.9.3.dist-info → mapfolding-0.9.5.dist-info}/top_level.txt +0 -0
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
"""
|
|
2
2
|
AST Node Transformation Actions for Python Code Manipulation
|
|
3
3
|
|
|
4
|
-
This module provides the Then class with static methods for generating callable
|
|
5
|
-
|
|
6
|
-
These action functions are used primarily with NodeChanger and NodeTourist to
|
|
4
|
+
This module provides the Then class with static methods for generating callable action functions that specify what to do
|
|
5
|
+
with AST nodes that match predicates. These action functions are used primarily with NodeChanger and NodeTourist to
|
|
7
6
|
transform or extract information from AST nodes.
|
|
8
7
|
|
|
9
|
-
The module also contains the grab class that provides functions for modifying
|
|
10
|
-
|
|
11
|
-
fine-grained control when transforming AST structures.
|
|
8
|
+
The module also contains the grab class that provides functions for modifying specific attributes of AST nodes while
|
|
9
|
+
preserving their structure, enabling fine-grained control when transforming AST structures.
|
|
12
10
|
|
|
13
|
-
Together, these classes provide a complete system for manipulating AST nodes
|
|
14
|
-
|
|
11
|
+
Together, these classes provide a complete system for manipulating AST nodes once they have been identified using
|
|
12
|
+
predicate functions from ifThis.
|
|
15
13
|
"""
|
|
16
14
|
|
|
17
15
|
from collections.abc import Callable, Sequence
|
|
@@ -23,15 +21,21 @@ class grab:
|
|
|
23
21
|
"""
|
|
24
22
|
Modify specific attributes of AST nodes while preserving the node structure.
|
|
25
23
|
|
|
26
|
-
The grab class provides static methods that create transformation functions to modify
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
entire node.
|
|
24
|
+
The grab class provides static methods that create transformation functions to modify specific attributes of AST
|
|
25
|
+
nodes. Unlike DOT which provides read-only access, grab allows for targeted modifications of node attributes without
|
|
26
|
+
replacing the entire node.
|
|
30
27
|
|
|
31
|
-
Each method returns a function that takes a node, applies a transformation to a
|
|
32
|
-
|
|
33
|
-
control when transforming AST structures.
|
|
28
|
+
Each method returns a function that takes a node, applies a transformation to a specific attribute of that node, and
|
|
29
|
+
returns the modified node. This enables fine-grained control when transforming AST structures.
|
|
34
30
|
"""
|
|
31
|
+
@staticmethod
|
|
32
|
+
def andDoAllOf(listOfActions: list[Callable[[NodeORattribute], NodeORattribute]]) -> Callable[[NodeORattribute], NodeORattribute]:
|
|
33
|
+
def workhorse(node: NodeORattribute) -> NodeORattribute:
|
|
34
|
+
for action in listOfActions:
|
|
35
|
+
node = action(node)
|
|
36
|
+
return node
|
|
37
|
+
return workhorse
|
|
38
|
+
|
|
35
39
|
@staticmethod
|
|
36
40
|
def argAttribute(action: Callable[[ast_Identifier | None], ast_Identifier]) -> Callable[[ast.arg | ast.keyword], ast.arg | ast.keyword]:
|
|
37
41
|
def workhorse(node: ast.arg | ast.keyword) -> ast.arg | ast.keyword:
|
|
@@ -39,6 +43,20 @@ class grab:
|
|
|
39
43
|
return node
|
|
40
44
|
return workhorse
|
|
41
45
|
|
|
46
|
+
@staticmethod
|
|
47
|
+
def attrAttribute(action: Callable[[ast_Identifier], ast_Identifier]) -> Callable[[ast.Attribute], ast.Attribute]:
|
|
48
|
+
def workhorse(node: ast.Attribute) -> ast.Attribute:
|
|
49
|
+
node.attr = action(node.attr)
|
|
50
|
+
return node
|
|
51
|
+
return workhorse
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def comparatorsAttribute(action: Callable[[list[ast.expr]], list[ast.expr]]) -> Callable[[ast.Compare], ast.Compare]:
|
|
55
|
+
def workhorse(node: ast.Compare) -> ast.Compare:
|
|
56
|
+
node.comparators = action(node.comparators)
|
|
57
|
+
return node
|
|
58
|
+
return workhorse
|
|
59
|
+
|
|
42
60
|
@staticmethod
|
|
43
61
|
def funcAttribute(action: Callable[[ast.expr], ast.expr]) -> Callable[[ast.Call], ast.Call]:
|
|
44
62
|
def workhorse(node: ast.Call) -> ast.Call:
|
|
@@ -60,6 +78,27 @@ class grab:
|
|
|
60
78
|
return node
|
|
61
79
|
return workhorse
|
|
62
80
|
|
|
81
|
+
@staticmethod
|
|
82
|
+
def leftAttribute(action: Callable[[ast.expr], ast.expr]) -> Callable[[ast.BinOp | ast.Compare], ast.BinOp | ast.Compare]:
|
|
83
|
+
def workhorse(node: ast.BinOp | ast.Compare) -> ast.BinOp | ast.Compare:
|
|
84
|
+
node.left = action(node.left)
|
|
85
|
+
return node
|
|
86
|
+
return workhorse
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def opsAttribute(action: Callable[[list[ast.cmpop]], list[ast.cmpop]]) -> Callable[[ast.Compare], ast.Compare]:
|
|
90
|
+
def workhorse(node: ast.Compare) -> ast.Compare:
|
|
91
|
+
node.ops = action(node.ops)
|
|
92
|
+
return node
|
|
93
|
+
return workhorse
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def testAttribute(action: Callable[[ast.expr], ast.expr]) -> Callable[[ast.Assert | ast.If | ast.IfExp | ast.While], ast.Assert | ast.If | ast.IfExp | ast.While]:
|
|
97
|
+
def workhorse(node: ast.Assert | ast.If | ast.IfExp | ast.While) -> ast.Assert | ast.If | ast.IfExp | ast.While:
|
|
98
|
+
node.test = action(node.test)
|
|
99
|
+
return node
|
|
100
|
+
return workhorse
|
|
101
|
+
|
|
63
102
|
@staticmethod
|
|
64
103
|
def valueAttribute(action: Callable[[Any], Any]) -> Callable[[astClassHasDOTvalue], astClassHasDOTvalue]:
|
|
65
104
|
def workhorse(node: astClassHasDOTvalue) -> astClassHasDOTvalue:
|
|
@@ -71,13 +110,12 @@ class Then:
|
|
|
71
110
|
"""
|
|
72
111
|
Provide action functions that specify what to do with AST nodes that match predicates.
|
|
73
112
|
|
|
74
|
-
The Then class contains static methods that generate action functions used with
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
extraction, and collection operations.
|
|
113
|
+
The Then class contains static methods that generate action functions used with NodeChanger and NodeTourist to
|
|
114
|
+
transform or extract information from AST nodes that match specific predicates. These actions include node
|
|
115
|
+
replacement, insertion, extraction, and collection operations.
|
|
78
116
|
|
|
79
|
-
When paired with predicates from the ifThis class, Then methods complete the
|
|
80
|
-
|
|
117
|
+
When paired with predicates from the ifThis class, Then methods complete the pattern-matching-and-action workflow
|
|
118
|
+
for AST manipulation.
|
|
81
119
|
"""
|
|
82
120
|
@staticmethod
|
|
83
121
|
def appendTo(listOfAny: list[Any]) -> Callable[[ast.AST | ast_Identifier], ast.AST | ast_Identifier]:
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from mapFolding.someAssemblyRequired import ast_Identifier, ifThis, IngredientsFunction, LedgerOfImports, NodeTourist, Then
|
|
2
|
+
from mapFolding.theSSOT import raiseIfNoneGitHubIssueNumber3
|
|
3
|
+
import ast
|
|
4
|
+
|
|
5
|
+
def astModuleToIngredientsFunction(astModule: ast.AST, identifierFunctionDef: ast_Identifier) -> IngredientsFunction:
|
|
6
|
+
"""
|
|
7
|
+
Extract a function definition from an AST module and create an `IngredientsFunction`.
|
|
8
|
+
|
|
9
|
+
This function finds a function definition with the specified identifier in the given AST module, extracts it, and
|
|
10
|
+
stores all module imports in the `LedgerOfImports`.
|
|
11
|
+
|
|
12
|
+
Parameters:
|
|
13
|
+
astModule: The AST module containing the function definition.
|
|
14
|
+
identifierFunctionDef: The name of the function to extract.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
ingredientsFunction: `IngredientsFunction` object containing the `ast.FunctionDef` and _all_ imports from the
|
|
18
|
+
source module.
|
|
19
|
+
|
|
20
|
+
Raises:
|
|
21
|
+
raiseIfNoneGitHubIssueNumber3: If the function definition is not found.
|
|
22
|
+
"""
|
|
23
|
+
astFunctionDef = extractFunctionDef(astModule, identifierFunctionDef)
|
|
24
|
+
if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
|
|
25
|
+
return IngredientsFunction(astFunctionDef, LedgerOfImports(astModule))
|
|
26
|
+
|
|
27
|
+
def extractClassDef(module: ast.AST, identifier: ast_Identifier) -> ast.ClassDef | None:
|
|
28
|
+
"""
|
|
29
|
+
Extract a class definition with a specific name from an AST module.
|
|
30
|
+
|
|
31
|
+
This function searches through an AST module for a class definition that matches the provided identifier and returns
|
|
32
|
+
it if found.
|
|
33
|
+
|
|
34
|
+
Parameters:
|
|
35
|
+
module: The AST module to search within.
|
|
36
|
+
identifier: The name of the class to find.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
astClassDef|None: The matching class definition AST node, or `None` if not found.
|
|
40
|
+
"""
|
|
41
|
+
return NodeTourist(ifThis.isClassDef_Identifier(identifier), Then.extractIt).captureLastMatch(module)
|
|
42
|
+
|
|
43
|
+
def extractFunctionDef(module: ast.AST, identifier: ast_Identifier) -> ast.FunctionDef | None:
|
|
44
|
+
"""
|
|
45
|
+
Extract a function definition with a specific name from an AST module.
|
|
46
|
+
|
|
47
|
+
This function searches through an AST module for a function definition that matches the provided identifier and
|
|
48
|
+
returns it if found.
|
|
49
|
+
|
|
50
|
+
Parameters:
|
|
51
|
+
module: The AST module to search within.
|
|
52
|
+
identifier: The name of the function to find.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
astFunctionDef|None: The matching function definition AST node, or `None` if not found.
|
|
56
|
+
"""
|
|
57
|
+
return NodeTourist(ifThis.isFunctionDef_Identifier(identifier), Then.extractIt).captureLastMatch(module)
|
|
@@ -1,35 +1,38 @@
|
|
|
1
1
|
"""
|
|
2
2
|
AST Node Predicate and Access Utilities for Pattern Matching and Traversal
|
|
3
3
|
|
|
4
|
-
This module provides utilities for accessing and matching AST nodes in a consistent way.
|
|
5
|
-
|
|
4
|
+
This module provides utilities for accessing and matching AST nodes in a consistent way. It contains three primary
|
|
5
|
+
classes:
|
|
6
6
|
|
|
7
|
-
1. DOT: Provides consistent accessor methods for AST node attributes across different
|
|
8
|
-
|
|
7
|
+
1. DOT: Provides consistent accessor methods for AST node attributes across different node types, simplifying the access
|
|
8
|
+
to node properties.
|
|
9
9
|
|
|
10
|
-
2. be: Offers type-guard functions that verify AST node types, enabling safe type
|
|
11
|
-
|
|
10
|
+
2. be: Offers type-guard functions that verify AST node types, enabling safe type narrowing for static type checking and
|
|
11
|
+
improving code safety.
|
|
12
12
|
|
|
13
|
-
3. ifThis: Contains predicate functions for matching AST nodes based on various criteria,
|
|
14
|
-
|
|
13
|
+
3. ifThis: Contains predicate functions for matching AST nodes based on various criteria, enabling precise targeting of
|
|
14
|
+
nodes for analysis or transformation.
|
|
15
15
|
|
|
16
|
-
These utilities form the foundation of the pattern-matching component in the AST
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
type verification (be), and data access (DOT).
|
|
16
|
+
These utilities form the foundation of the pattern-matching component in the AST manipulation framework, working in
|
|
17
|
+
conjunction with the NodeChanger and NodeTourist classes to enable precise and targeted code transformations. Together,
|
|
18
|
+
they implement a declarative approach to AST manipulation that separates node identification (ifThis), type verification
|
|
19
|
+
(be), and data access (DOT).
|
|
21
20
|
"""
|
|
22
21
|
|
|
23
22
|
from collections.abc import Callable
|
|
24
23
|
from mapFolding.someAssemblyRequired import (
|
|
25
24
|
ast_Identifier,
|
|
25
|
+
astClassHasDOTbody,
|
|
26
|
+
astClassHasDOTbody_expr,
|
|
27
|
+
astClassHasDOTbodyList_stmt,
|
|
26
28
|
astClassHasDOTnameNotName,
|
|
29
|
+
astClassHasDOTnameNotNameAlways,
|
|
30
|
+
astClassHasDOTnameNotNameOptionally,
|
|
27
31
|
astClassHasDOTtarget,
|
|
28
|
-
astClassHasDOTtargetAttributeNameSubscript,
|
|
29
32
|
astClassHasDOTtarget_expr,
|
|
33
|
+
astClassHasDOTtargetAttributeNameSubscript,
|
|
30
34
|
astClassHasDOTvalue,
|
|
31
35
|
astClassHasDOTvalue_expr,
|
|
32
|
-
astClassOptionallyHasDOTnameNotName,
|
|
33
36
|
astClassHasDOTvalue_exprNone,
|
|
34
37
|
ImaCallToName,
|
|
35
38
|
)
|
|
@@ -40,13 +43,12 @@ class DOT:
|
|
|
40
43
|
"""
|
|
41
44
|
Access attributes and sub-nodes of AST elements via consistent accessor methods.
|
|
42
45
|
|
|
43
|
-
The DOT class provides static methods to access specific attributes of different
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
AST structure details.
|
|
46
|
+
The DOT class provides static methods to access specific attributes of different types of AST nodes in a consistent
|
|
47
|
+
way. This simplifies attribute access across various node types and improves code readability by abstracting the
|
|
48
|
+
underlying AST structure details.
|
|
47
49
|
|
|
48
|
-
DOT is designed for safe, read-only access to node properties, unlike the grab
|
|
49
|
-
|
|
50
|
+
DOT is designed for safe, read-only access to node properties, unlike the grab class which is designed for modifying
|
|
51
|
+
node attributes.
|
|
50
52
|
"""
|
|
51
53
|
@staticmethod
|
|
52
54
|
@overload
|
|
@@ -72,6 +74,16 @@ class DOT:
|
|
|
72
74
|
def attr(node: ast.Attribute) -> ast_Identifier:
|
|
73
75
|
return node.attr
|
|
74
76
|
|
|
77
|
+
@staticmethod
|
|
78
|
+
@overload
|
|
79
|
+
def body(node: astClassHasDOTbodyList_stmt) -> list[ast.stmt]:...
|
|
80
|
+
@staticmethod
|
|
81
|
+
@overload
|
|
82
|
+
def body(node: astClassHasDOTbody_expr) -> ast.expr:...
|
|
83
|
+
@staticmethod
|
|
84
|
+
def body(node: astClassHasDOTbody) -> ast.expr | list[ast.stmt]:
|
|
85
|
+
return node.body
|
|
86
|
+
|
|
75
87
|
@staticmethod
|
|
76
88
|
@overload
|
|
77
89
|
def func(node: ImaCallToName) -> ast.Name:...
|
|
@@ -88,12 +100,12 @@ class DOT:
|
|
|
88
100
|
|
|
89
101
|
@staticmethod
|
|
90
102
|
@overload
|
|
91
|
-
def name(node:
|
|
103
|
+
def name(node: astClassHasDOTnameNotNameAlways) -> ast_Identifier:...
|
|
92
104
|
@staticmethod
|
|
93
105
|
@overload
|
|
94
|
-
def name(node:
|
|
106
|
+
def name(node: astClassHasDOTnameNotNameOptionally) -> ast_Identifier | None:...
|
|
95
107
|
@staticmethod
|
|
96
|
-
def name(node: astClassHasDOTnameNotName
|
|
108
|
+
def name(node: astClassHasDOTnameNotName) -> ast_Identifier | None:
|
|
97
109
|
return node.name
|
|
98
110
|
|
|
99
111
|
@staticmethod
|
|
@@ -129,18 +141,16 @@ class be:
|
|
|
129
141
|
"""
|
|
130
142
|
Provide type-guard functions for safely verifying AST node types during manipulation.
|
|
131
143
|
|
|
132
|
-
The be class contains static methods that perform runtime type verification of AST nodes,
|
|
133
|
-
|
|
134
|
-
conditional branches. These type-guards:
|
|
144
|
+
The be class contains static methods that perform runtime type verification of AST nodes, returning TypeGuard
|
|
145
|
+
results that enable static type checkers to narrow node types in conditional branches. These type-guards:
|
|
135
146
|
|
|
136
|
-
1. Improve code safety by preventing operations on incompatible node types
|
|
137
|
-
2. Enable IDE tooling to provide better autocompletion and error detection
|
|
138
|
-
3. Document expected node types in a way that's enforced by the type system
|
|
139
|
-
4. Support pattern-matching workflows where node types must be verified before access
|
|
147
|
+
1. Improve code safety by preventing operations on incompatible node types.
|
|
148
|
+
2. Enable IDE tooling to provide better autocompletion and error detection.
|
|
149
|
+
3. Document expected node types in a way that's enforced by the type system.
|
|
150
|
+
4. Support pattern-matching workflows where node types must be verified before access.
|
|
140
151
|
|
|
141
|
-
When used with conditional statements, these type-guards allow for precise,
|
|
142
|
-
|
|
143
|
-
capabilities, even in complex transformation scenarios.
|
|
152
|
+
When used with conditional statements, these type-guards allow for precise, type-safe manipulation of AST nodes
|
|
153
|
+
while maintaining full static type checking capabilities, even in complex transformation scenarios.
|
|
144
154
|
"""
|
|
145
155
|
@staticmethod
|
|
146
156
|
def AnnAssign(node: ast.AST) -> TypeGuard[ast.AnnAssign]:
|
|
@@ -170,6 +180,14 @@ class be:
|
|
|
170
180
|
def ClassDef(node: ast.AST) -> TypeGuard[ast.ClassDef]:
|
|
171
181
|
return isinstance(node, ast.ClassDef)
|
|
172
182
|
|
|
183
|
+
@staticmethod
|
|
184
|
+
def Compare(node: ast.AST) -> TypeGuard[ast.Compare]:
|
|
185
|
+
return isinstance(node, ast.Compare)
|
|
186
|
+
|
|
187
|
+
@staticmethod
|
|
188
|
+
def Constant(node: ast.AST) -> TypeGuard[ast.Constant]:
|
|
189
|
+
return isinstance(node, ast.Constant)
|
|
190
|
+
|
|
173
191
|
@staticmethod
|
|
174
192
|
def FunctionDef(node: ast.AST) -> TypeGuard[ast.FunctionDef]:
|
|
175
193
|
return isinstance(node, ast.FunctionDef)
|
|
@@ -178,10 +196,26 @@ class be:
|
|
|
178
196
|
def keyword(node: ast.AST) -> TypeGuard[ast.keyword]:
|
|
179
197
|
return isinstance(node, ast.keyword)
|
|
180
198
|
|
|
199
|
+
@staticmethod
|
|
200
|
+
def If(node: ast.AST) -> TypeGuard[ast.If]:
|
|
201
|
+
return isinstance(node, ast.If)
|
|
202
|
+
|
|
203
|
+
@staticmethod
|
|
204
|
+
def Gt(node: ast.AST) -> TypeGuard[ast.Gt]:
|
|
205
|
+
return isinstance(node, ast.Gt)
|
|
206
|
+
|
|
207
|
+
@staticmethod
|
|
208
|
+
def LtE(node: ast.AST) -> TypeGuard[ast.LtE]:
|
|
209
|
+
return isinstance(node, ast.LtE)
|
|
210
|
+
|
|
181
211
|
@staticmethod
|
|
182
212
|
def Name(node: ast.AST) -> TypeGuard[ast.Name]:
|
|
183
213
|
return isinstance(node, ast.Name)
|
|
184
214
|
|
|
215
|
+
@staticmethod
|
|
216
|
+
def Not(node: ast.AST) -> TypeGuard[ast.Not]:
|
|
217
|
+
return isinstance(node, ast.Not)
|
|
218
|
+
|
|
185
219
|
@staticmethod
|
|
186
220
|
def Return(node: ast.AST) -> TypeGuard[ast.Return]:
|
|
187
221
|
return isinstance(node, ast.Return)
|
|
@@ -194,17 +228,28 @@ class be:
|
|
|
194
228
|
def Subscript(node: ast.AST) -> TypeGuard[ast.Subscript]:
|
|
195
229
|
return isinstance(node, ast.Subscript)
|
|
196
230
|
|
|
231
|
+
@staticmethod
|
|
232
|
+
def Tuple(node: ast.AST) -> TypeGuard[ast.Tuple]:
|
|
233
|
+
return isinstance(node, ast.Tuple)
|
|
234
|
+
|
|
235
|
+
@staticmethod
|
|
236
|
+
def UnaryOp(node: ast.AST) -> TypeGuard[ast.UnaryOp]:
|
|
237
|
+
return isinstance(node, ast.UnaryOp)
|
|
238
|
+
|
|
239
|
+
@staticmethod
|
|
240
|
+
def While(node: ast.AST) -> TypeGuard[ast.While]:
|
|
241
|
+
return isinstance(node, ast.While)
|
|
242
|
+
|
|
197
243
|
class ifThis:
|
|
198
244
|
"""
|
|
199
245
|
Provide predicate functions for matching and filtering AST nodes based on various criteria.
|
|
200
246
|
|
|
201
|
-
The ifThis class contains static methods that generate predicate functions used to test
|
|
202
|
-
|
|
203
|
-
|
|
247
|
+
The ifThis class contains static methods that generate predicate functions used to test whether AST nodes match
|
|
248
|
+
specific criteria. These predicates can be used with NodeChanger and NodeTourist to identify and process specific
|
|
249
|
+
patterns in the AST.
|
|
204
250
|
|
|
205
|
-
The class provides predicates for matching various node types, attributes, identifiers,
|
|
206
|
-
|
|
207
|
-
transformation.
|
|
251
|
+
The class provides predicates for matching various node types, attributes, identifiers, and structural patterns,
|
|
252
|
+
enabling precise targeting of AST elements for analysis or transformation.
|
|
208
253
|
"""
|
|
209
254
|
@staticmethod
|
|
210
255
|
def _Identifier(identifier: ast_Identifier) -> Callable[[ast_Identifier | None], TypeGuard[ast_Identifier] | bool]:
|
|
@@ -257,6 +302,40 @@ class ifThis:
|
|
|
257
302
|
def isAttributeNamespace_Identifier(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Attribute] | bool]:
|
|
258
303
|
return lambda node: ifThis.isAttributeName(node) and ifThis.isName_Identifier(namespace)(DOT.value(node)) and ifThis._Identifier(identifier)(DOT.attr(node))
|
|
259
304
|
|
|
305
|
+
@staticmethod
|
|
306
|
+
def isAttributeNamespace_IdentifierGreaterThan0(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Compare] | bool]:
|
|
307
|
+
return lambda node: (be.Compare(node)
|
|
308
|
+
and ifThis.isAttributeNamespace_Identifier(namespace, identifier)(node.left)
|
|
309
|
+
and be.Gt(node.ops[0])
|
|
310
|
+
and ifThis.isConstant_value(0)(node.comparators[0]))
|
|
311
|
+
|
|
312
|
+
@staticmethod
|
|
313
|
+
def isUnaryNotAttributeNamespace_Identifier(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.UnaryOp] | bool]:
|
|
314
|
+
return lambda node: (be.UnaryOp(node)
|
|
315
|
+
and be.Not(node.op)
|
|
316
|
+
and ifThis.isAttributeNamespace_Identifier(namespace, identifier)(node.operand))
|
|
317
|
+
|
|
318
|
+
@staticmethod
|
|
319
|
+
def isIfUnaryNotAttributeNamespace_Identifier(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.If] | bool]:
|
|
320
|
+
return lambda node: (be.If(node)
|
|
321
|
+
and ifThis.isUnaryNotAttributeNamespace_Identifier(namespace, identifier)(node.test))
|
|
322
|
+
|
|
323
|
+
@staticmethod
|
|
324
|
+
def isIfAttributeNamespace_IdentifierGreaterThan0(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.If] | bool]:
|
|
325
|
+
return lambda node: (be.If(node)
|
|
326
|
+
and ifThis.isAttributeNamespace_IdentifierGreaterThan0(namespace, identifier)(node.test))
|
|
327
|
+
|
|
328
|
+
@staticmethod
|
|
329
|
+
def isWhileAttributeNamespace_IdentifierGreaterThan0(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.While] | bool]:
|
|
330
|
+
return lambda node: (be.While(node)
|
|
331
|
+
and ifThis.isAttributeNamespace_IdentifierGreaterThan0(namespace, identifier)(node.test))
|
|
332
|
+
|
|
333
|
+
@staticmethod
|
|
334
|
+
def isAttributeNamespace_IdentifierLessThanOrEqual(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Compare] | bool]:
|
|
335
|
+
return lambda node: (be.Compare(node)
|
|
336
|
+
and ifThis.isAttributeNamespace_Identifier(namespace, identifier)(node.left)
|
|
337
|
+
and be.LtE(node.ops[0]))
|
|
338
|
+
|
|
260
339
|
@staticmethod
|
|
261
340
|
def isAugAssign_targetIs(targetPredicate: Callable[[ast.expr], TypeGuard[ast.expr] | bool]) -> Callable[[ast.AST], TypeGuard[ast.AugAssign] | bool]:
|
|
262
341
|
def workhorse(node: ast.AST) -> TypeGuard[ast.AugAssign] | bool:
|
|
@@ -282,6 +361,10 @@ class ifThis:
|
|
|
282
361
|
def isClassDef_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.ClassDef] | bool]:
|
|
283
362
|
return lambda node: be.ClassDef(node) and ifThis._Identifier(identifier)(DOT.name(node))
|
|
284
363
|
|
|
364
|
+
@staticmethod
|
|
365
|
+
def isConstant_value(value: Any) -> Callable[[ast.AST], TypeGuard[ast.Constant] | bool]:
|
|
366
|
+
return lambda node: be.Constant(node) and DOT.value(node) == value
|
|
367
|
+
|
|
285
368
|
@staticmethod
|
|
286
369
|
def isFunctionDef_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.FunctionDef] | bool]:
|
|
287
370
|
return lambda node: be.FunctionDef(node) and ifThis._Identifier(identifier)(DOT.name(node))
|
|
@@ -19,9 +19,11 @@ specific optimizations and transformations.
|
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
21
|
from collections import defaultdict
|
|
22
|
-
from collections.abc import Sequence
|
|
23
|
-
from
|
|
24
|
-
from
|
|
22
|
+
from collections.abc import Callable, Sequence
|
|
23
|
+
from copy import deepcopy
|
|
24
|
+
from typing import Any
|
|
25
|
+
from mapFolding.someAssemblyRequired import ast_Identifier, DOT, ifThis, Make, NodeTourist, parseLogicalPath2astModule, str_nameDOTname, Then
|
|
26
|
+
from mapFolding.theSSOT import raiseIfNoneGitHubIssueNumber3, The
|
|
25
27
|
from pathlib import Path, PurePosixPath
|
|
26
28
|
from Z0Z_tools import updateExtendPolishDictionaryLists
|
|
27
29
|
import ast
|
|
@@ -32,8 +34,7 @@ class LedgerOfImports:
|
|
|
32
34
|
Track and manage import statements for programmatically generated code.
|
|
33
35
|
|
|
34
36
|
LedgerOfImports acts as a registry for import statements, maintaining a clean separation between the logical
|
|
35
|
-
structure of imports and their textual representation.
|
|
36
|
-
It enables:
|
|
37
|
+
structure of imports and their textual representation. It enables:
|
|
37
38
|
|
|
38
39
|
1. Tracking regular imports and import-from statements.
|
|
39
40
|
2. Adding imports programmatically during code transformation.
|
|
@@ -46,8 +47,6 @@ class LedgerOfImports:
|
|
|
46
47
|
"""
|
|
47
48
|
# TODO When resolving the ledger of imports, remove self-referential imports
|
|
48
49
|
|
|
49
|
-
type_ignores: list[ast.TypeIgnore]
|
|
50
|
-
|
|
51
50
|
def __init__(self, startWith: ast.AST | None = None, type_ignores: list[ast.TypeIgnore] | None = None) -> None:
|
|
52
51
|
self.dictionaryImportFrom: dict[str_nameDOTname, list[tuple[ast_Identifier, ast_Identifier | None]]] = defaultdict(list)
|
|
53
52
|
self.listImport: list[str_nameDOTname] = []
|
|
@@ -77,8 +76,6 @@ class LedgerOfImports:
|
|
|
77
76
|
self.type_ignores.extend(type_ignores)
|
|
78
77
|
|
|
79
78
|
def addImportFrom_asStr(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier, asname: ast_Identifier | None = None, type_ignores: list[ast.TypeIgnore] | None = None) -> None:
|
|
80
|
-
if moduleWithLogicalPath not in self.dictionaryImportFrom:
|
|
81
|
-
self.dictionaryImportFrom[moduleWithLogicalPath] = []
|
|
82
79
|
self.dictionaryImportFrom[moduleWithLogicalPath].append((name, asname))
|
|
83
80
|
if type_ignores:
|
|
84
81
|
self.type_ignores.extend(type_ignores)
|
|
@@ -131,7 +128,8 @@ class LedgerOfImports:
|
|
|
131
128
|
Parameters:
|
|
132
129
|
*fromLedger: One or more other `LedgerOfImports` objects from which to merge.
|
|
133
130
|
"""
|
|
134
|
-
|
|
131
|
+
updatedDictionary = updateExtendPolishDictionaryLists(self.dictionaryImportFrom, *(ledger.dictionaryImportFrom for ledger in fromLedger), destroyDuplicates=True, reorderLists=True)
|
|
132
|
+
self.dictionaryImportFrom = defaultdict(list, updatedDictionary)
|
|
135
133
|
for ledger in fromLedger:
|
|
136
134
|
self.listImport.extend(ledger.listImport)
|
|
137
135
|
self.type_ignores.extend(ledger.type_ignores)
|
|
@@ -175,22 +173,21 @@ class IngredientsModule:
|
|
|
175
173
|
"""
|
|
176
174
|
Assemble a complete Python module from its constituent AST components.
|
|
177
175
|
|
|
178
|
-
IngredientsModule provides a structured container for all elements needed to
|
|
179
|
-
|
|
176
|
+
IngredientsModule provides a structured container for all elements needed to generate a complete Python module,
|
|
177
|
+
including:
|
|
180
178
|
|
|
181
|
-
1. Import statements aggregated from all module components
|
|
182
|
-
2. Prologue code that runs before function definitions
|
|
183
|
-
3. Function definitions with their dependencies
|
|
184
|
-
4. Epilogue code that runs after function definitions
|
|
185
|
-
5. Entry point code executed when the module runs as a script
|
|
186
|
-
6. Type ignores and other annotations
|
|
179
|
+
1. Import statements aggregated from all module components.
|
|
180
|
+
2. Prologue code that runs before function definitions.
|
|
181
|
+
3. Function definitions with their dependencies.
|
|
182
|
+
4. Epilogue code that runs after function definitions.
|
|
183
|
+
5. Entry point code executed when the module runs as a script.
|
|
184
|
+
6. Type ignores and other annotations.
|
|
187
185
|
|
|
188
|
-
This class enables programmatic assembly of Python modules with a clear
|
|
189
|
-
|
|
190
|
-
proper ordering and relationships between components.
|
|
186
|
+
This class enables programmatic assembly of Python modules with a clear separation between different structural
|
|
187
|
+
elements, while maintaining the proper ordering and relationships between components.
|
|
191
188
|
|
|
192
|
-
The modular design allows transformations to be applied to specific parts
|
|
193
|
-
|
|
189
|
+
The modular design allows transformations to be applied to specific parts of a module while preserving the overall
|
|
190
|
+
structure.
|
|
194
191
|
|
|
195
192
|
Parameters:
|
|
196
193
|
ingredientsFunction (None): One or more `IngredientsFunction` that will appended to `listIngredientsFunctions`.
|
|
@@ -315,22 +312,20 @@ class RecipeSynthesizeFlow:
|
|
|
315
312
|
"""
|
|
316
313
|
Configure the generation of new modules, including Numba-accelerated code modules.
|
|
317
314
|
|
|
318
|
-
RecipeSynthesizeFlow defines the complete blueprint for transforming an original
|
|
319
|
-
|
|
315
|
+
RecipeSynthesizeFlow defines the complete blueprint for transforming an original Python algorithm into an optimized,
|
|
316
|
+
accelerated implementation. It specifies:
|
|
320
317
|
|
|
321
|
-
1. Source code locations and identifiers
|
|
322
|
-
2. Target code locations and identifiers
|
|
323
|
-
3. Naming conventions for generated modules and functions
|
|
324
|
-
4. File system paths for output files
|
|
325
|
-
5. Import relationships between components
|
|
318
|
+
1. Source code locations and identifiers.
|
|
319
|
+
2. Target code locations and identifiers.
|
|
320
|
+
3. Naming conventions for generated modules and functions.
|
|
321
|
+
4. File system paths for output files.
|
|
322
|
+
5. Import relationships between components.
|
|
326
323
|
|
|
327
|
-
This configuration class serves as a single source of truth for the code generation
|
|
328
|
-
|
|
329
|
-
customization of the transformation assembly line.
|
|
324
|
+
This configuration class serves as a single source of truth for the code generation process, ensuring consistency
|
|
325
|
+
across all generated artifacts while enabling customization of the transformation assembly line.
|
|
330
326
|
|
|
331
|
-
The transformation process uses this configuration to extract functions from the
|
|
332
|
-
|
|
333
|
-
properly structured optimized modules with all necessary imports.
|
|
327
|
+
The transformation process uses this configuration to extract functions from the source module, transform them
|
|
328
|
+
according to optimization rules, and output properly structured optimized modules with all necessary imports.
|
|
334
329
|
"""
|
|
335
330
|
# ========================================
|
|
336
331
|
# Source
|
|
@@ -449,7 +444,7 @@ class ShatteredDataclass:
|
|
|
449
444
|
fragments4AssignmentOrParameters: ast.Tuple = dummyTuple
|
|
450
445
|
"""AST tuple used as target for assignment to capture returned fragments."""
|
|
451
446
|
|
|
452
|
-
|
|
447
|
+
imports: LedgerOfImports = dataclasses.field(default_factory=LedgerOfImports)
|
|
453
448
|
"""Import records for the dataclass and its constituent parts."""
|
|
454
449
|
|
|
455
450
|
list_argAnnotated4ArgumentsSpecification: list[ast.arg] = dataclasses.field(default_factory=list)
|
|
@@ -475,3 +470,99 @@ class ShatteredDataclass:
|
|
|
475
470
|
|
|
476
471
|
signatureReturnAnnotation: ast.Subscript = dummySubscript
|
|
477
472
|
"""tuple-based return type annotation for function definitions."""
|
|
473
|
+
|
|
474
|
+
@dataclasses.dataclass
|
|
475
|
+
class DeReConstructField2ast:
|
|
476
|
+
"""
|
|
477
|
+
Transform a dataclass field into AST node representations for code generation.
|
|
478
|
+
|
|
479
|
+
This class extracts and transforms a dataclass Field object into various AST node
|
|
480
|
+
representations needed for code generation. It handles the conversion of field
|
|
481
|
+
attributes, type annotations, and metadata into AST constructs that can be used
|
|
482
|
+
to reconstruct the field in generated code.
|
|
483
|
+
|
|
484
|
+
The class is particularly important for decomposing dataclass fields (like those in
|
|
485
|
+
ComputationState) to enable their use in specialized contexts like Numba-optimized
|
|
486
|
+
functions, where the full dataclass cannot be directly used but its contents need
|
|
487
|
+
to be accessible.
|
|
488
|
+
|
|
489
|
+
Each field is processed according to its type and metadata to create appropriate
|
|
490
|
+
variable declarations, type annotations, and initialization code as AST nodes.
|
|
491
|
+
"""
|
|
492
|
+
dataclassesDOTdataclassLogicalPathModule: dataclasses.InitVar[str_nameDOTname]
|
|
493
|
+
dataclassClassDef: dataclasses.InitVar[ast.ClassDef]
|
|
494
|
+
dataclassesDOTdataclassInstance_Identifier: dataclasses.InitVar[ast_Identifier]
|
|
495
|
+
field: dataclasses.InitVar[dataclasses.Field[Any]]
|
|
496
|
+
|
|
497
|
+
ledger: LedgerOfImports = dataclasses.field(default_factory=LedgerOfImports)
|
|
498
|
+
|
|
499
|
+
name: ast_Identifier = dataclasses.field(init=False)
|
|
500
|
+
typeBuffalo: type[Any] | str | Any = dataclasses.field(init=False)
|
|
501
|
+
default: Any | None = dataclasses.field(init=False)
|
|
502
|
+
default_factory: Callable[..., Any] | None = dataclasses.field(init=False)
|
|
503
|
+
repr: bool = dataclasses.field(init=False)
|
|
504
|
+
hash: bool | None = dataclasses.field(init=False)
|
|
505
|
+
init: bool = dataclasses.field(init=False)
|
|
506
|
+
compare: bool = dataclasses.field(init=False)
|
|
507
|
+
metadata: dict[Any, Any] = dataclasses.field(init=False)
|
|
508
|
+
kw_only: bool = dataclasses.field(init=False)
|
|
509
|
+
|
|
510
|
+
astName: ast.Name = dataclasses.field(init=False)
|
|
511
|
+
ast_keyword_field__field: ast.keyword = dataclasses.field(init=False)
|
|
512
|
+
ast_nameDOTname: ast.Attribute = dataclasses.field(init=False)
|
|
513
|
+
astAnnotation: ast.expr = dataclasses.field(init=False)
|
|
514
|
+
ast_argAnnotated: ast.arg = dataclasses.field(init=False)
|
|
515
|
+
astAnnAssignConstructor: ast.AnnAssign|ast.Assign = dataclasses.field(init=False)
|
|
516
|
+
Z0Z_hack: tuple[ast.AnnAssign|ast.Assign, str] = dataclasses.field(init=False)
|
|
517
|
+
|
|
518
|
+
def __post_init__(self, dataclassesDOTdataclassLogicalPathModule: str_nameDOTname, dataclassClassDef: ast.ClassDef, dataclassesDOTdataclassInstance_Identifier: ast_Identifier, field: dataclasses.Field[Any]) -> None:
|
|
519
|
+
self.compare = field.compare
|
|
520
|
+
self.default = field.default if field.default is not dataclasses.MISSING else None
|
|
521
|
+
self.default_factory = field.default_factory if field.default_factory is not dataclasses.MISSING else None
|
|
522
|
+
self.hash = field.hash
|
|
523
|
+
self.init = field.init
|
|
524
|
+
self.kw_only = field.kw_only if field.kw_only is not dataclasses.MISSING else False
|
|
525
|
+
self.metadata = dict(field.metadata)
|
|
526
|
+
self.name = field.name
|
|
527
|
+
self.repr = field.repr
|
|
528
|
+
self.typeBuffalo = field.type
|
|
529
|
+
|
|
530
|
+
self.astName = Make.Name(self.name)
|
|
531
|
+
self.ast_keyword_field__field = Make.keyword(self.name, self.astName)
|
|
532
|
+
self.ast_nameDOTname = Make.Attribute(Make.Name(dataclassesDOTdataclassInstance_Identifier), self.name)
|
|
533
|
+
|
|
534
|
+
sherpa = NodeTourist(ifThis.isAnnAssign_targetIs(ifThis.isName_Identifier(self.name)), Then.extractIt(DOT.annotation)).captureLastMatch(dataclassClassDef)
|
|
535
|
+
if sherpa is None: raise raiseIfNoneGitHubIssueNumber3
|
|
536
|
+
else: self.astAnnotation = sherpa
|
|
537
|
+
|
|
538
|
+
self.ast_argAnnotated = Make.arg(self.name, self.astAnnotation)
|
|
539
|
+
|
|
540
|
+
dtype = self.metadata.get('dtype', None)
|
|
541
|
+
if dtype:
|
|
542
|
+
moduleWithLogicalPath: str_nameDOTname = 'numpy'
|
|
543
|
+
annotationType = 'ndarray'
|
|
544
|
+
self.ledger.addImportFrom_asStr(moduleWithLogicalPath, annotationType)
|
|
545
|
+
self.ledger.addImportFrom_asStr(moduleWithLogicalPath, 'dtype')
|
|
546
|
+
axesSubscript = Make.Subscript(Make.Name('tuple'), Make.Name('uint8'))
|
|
547
|
+
dtype_asnameName: ast.Name = self.astAnnotation # type: ignore
|
|
548
|
+
if dtype_asnameName.id == 'Array3D':
|
|
549
|
+
axesSubscript = Make.Subscript(Make.Name('tuple'), Make.Tuple([Make.Name('uint8'), Make.Name('uint8'), Make.Name('uint8')]))
|
|
550
|
+
ast_expr = Make.Subscript(Make.Name(annotationType), Make.Tuple([axesSubscript, Make.Subscript(Make.Name('dtype'), dtype_asnameName)]))
|
|
551
|
+
constructor = 'array'
|
|
552
|
+
self.ledger.addImportFrom_asStr(moduleWithLogicalPath, constructor)
|
|
553
|
+
dtypeIdentifier: ast_Identifier = dtype.__name__
|
|
554
|
+
self.ledger.addImportFrom_asStr(moduleWithLogicalPath, dtypeIdentifier, dtype_asnameName.id)
|
|
555
|
+
self.astAnnAssignConstructor = Make.AnnAssign(self.astName, ast_expr, Make.Call(Make.Name(constructor), list_astKeywords=[Make.keyword('dtype', dtype_asnameName)]))
|
|
556
|
+
self.astAnnAssignConstructor = Make.Assign([self.astName], Make.Call(Make.Name(constructor), list_astKeywords=[Make.keyword('dtype', dtype_asnameName)]))
|
|
557
|
+
self.Z0Z_hack = (self.astAnnAssignConstructor, 'array')
|
|
558
|
+
elif isinstance(self.astAnnotation, ast.Name):
|
|
559
|
+
self.astAnnAssignConstructor = Make.AnnAssign(self.astName, self.astAnnotation, Make.Call(self.astAnnotation, [Make.Constant(-1)]))
|
|
560
|
+
self.Z0Z_hack = (self.astAnnAssignConstructor, 'scalar')
|
|
561
|
+
elif isinstance(self.astAnnotation, ast.Subscript):
|
|
562
|
+
elementConstructor: ast_Identifier = self.metadata['elementConstructor']
|
|
563
|
+
self.ledger.addImportFrom_asStr(dataclassesDOTdataclassLogicalPathModule, elementConstructor)
|
|
564
|
+
takeTheTuple: ast.Tuple = deepcopy(self.astAnnotation.slice) # type: ignore
|
|
565
|
+
self.astAnnAssignConstructor = Make.AnnAssign(self.astName, self.astAnnotation, takeTheTuple)
|
|
566
|
+
self.Z0Z_hack = (self.astAnnAssignConstructor, elementConstructor)
|
|
567
|
+
if isinstance(self.astAnnotation, ast.Name):
|
|
568
|
+
self.ledger.addImportFrom_asStr(dataclassesDOTdataclassLogicalPathModule, self.astAnnotation.id) # pyright: ignore [reportUnknownArgumentType, reportUnknownMemberType, reportIJustCalledATypeGuardMethod_WTF]
|