mapFolding 0.8.3__py3-none-any.whl → 0.8.4__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 +2 -2
- mapFolding/basecamp.py +11 -5
- mapFolding/filesystem.py +134 -109
- mapFolding/oeis.py +1 -1
- mapFolding/someAssemblyRequired/__init__.py +37 -18
- mapFolding/someAssemblyRequired/_theTypes.py +35 -0
- mapFolding/someAssemblyRequired/_tool_Make.py +92 -0
- mapFolding/someAssemblyRequired/_tool_Then.py +65 -0
- mapFolding/someAssemblyRequired/_toolboxAntecedents.py +326 -0
- mapFolding/someAssemblyRequired/_toolboxContainers.py +306 -0
- mapFolding/someAssemblyRequired/_toolboxPython.py +76 -0
- mapFolding/someAssemblyRequired/ingredientsNumba.py +17 -24
- mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +114 -169
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +247 -0
- mapFolding/someAssemblyRequired/transformDataStructures.py +167 -100
- mapFolding/someAssemblyRequired/transformationTools.py +63 -685
- mapFolding/syntheticModules/numbaCount_doTheNeedful.py +36 -33
- mapFolding/theDao.py +13 -11
- mapFolding/theSSOT.py +69 -112
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/METADATA +2 -1
- mapfolding-0.8.4.dist-info/RECORD +49 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/WHEEL +1 -1
- tests/conftest.py +34 -29
- tests/test_computations.py +40 -31
- tests/test_filesystem.py +3 -3
- mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +0 -413
- mapfolding-0.8.3.dist-info/RECORD +0 -43
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from inspect import getsource as inspect_getsource
|
|
3
|
+
from mapFolding.someAssemblyRequired import ast_Identifier, str_nameDOTname
|
|
4
|
+
from os import PathLike
|
|
5
|
+
from pathlib import Path, PurePath
|
|
6
|
+
from types import ModuleType
|
|
7
|
+
from typing import Any, Literal
|
|
8
|
+
import ast
|
|
9
|
+
import importlib
|
|
10
|
+
import importlib.util
|
|
11
|
+
|
|
12
|
+
# TODO Identify the logic that narrows the type and can help the user during static type checking.
|
|
13
|
+
|
|
14
|
+
class NodeTourist(ast.NodeVisitor):
|
|
15
|
+
def __init__(self, findThis, doThat): # type: ignore
|
|
16
|
+
self.findThis = findThis
|
|
17
|
+
self.doThat = doThat
|
|
18
|
+
self.nodeCaptured = None
|
|
19
|
+
|
|
20
|
+
def visit(self, node): # type: ignore
|
|
21
|
+
if self.findThis(node):
|
|
22
|
+
nodeActionReturn = self.doThat(node) # type: ignore
|
|
23
|
+
if nodeActionReturn is not None:
|
|
24
|
+
self.nodeCaptured = nodeActionReturn # type: ignore
|
|
25
|
+
self.generic_visit(node)
|
|
26
|
+
|
|
27
|
+
def captureLastMatch(self, node): # type: ignore
|
|
28
|
+
"""Capture the last matched node that produces a non-None result.
|
|
29
|
+
|
|
30
|
+
This method traverses the entire tree starting at the given node
|
|
31
|
+
and returns the last non-None value produced by applying doThat
|
|
32
|
+
to a matching node. It will continue traversing after finding a match,
|
|
33
|
+
and the value captured can be replaced by later matches.
|
|
34
|
+
|
|
35
|
+
Parameters:
|
|
36
|
+
node: The AST node to start traversal from
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
The result of applying doThat to the last matching node that returned
|
|
40
|
+
a non-None value, or None if no match found or all matches returned None
|
|
41
|
+
"""
|
|
42
|
+
self.nodeCaptured = None
|
|
43
|
+
self.visit(node) # type: ignore
|
|
44
|
+
return self.nodeCaptured
|
|
45
|
+
|
|
46
|
+
class NodeChanger(ast.NodeTransformer):
|
|
47
|
+
def __init__(self, findThis, doThat): # type: ignore
|
|
48
|
+
self.findThis = findThis
|
|
49
|
+
self.doThat = doThat
|
|
50
|
+
|
|
51
|
+
def visit(self, node): # type: ignore
|
|
52
|
+
if self.findThis(node):
|
|
53
|
+
return self.doThat(node) # type: ignore
|
|
54
|
+
return super().visit(node)
|
|
55
|
+
|
|
56
|
+
def importLogicalPath2Callable(logicalPathModule: str_nameDOTname, identifier: ast_Identifier, packageIdentifierIfRelative: ast_Identifier | None = None) -> Callable[..., Any]:
|
|
57
|
+
moduleImported: ModuleType = importlib.import_module(logicalPathModule, packageIdentifierIfRelative)
|
|
58
|
+
return getattr(moduleImported, identifier)
|
|
59
|
+
|
|
60
|
+
def importPathFilename2Callable(pathFilename: PathLike[Any] | PurePath, identifier: ast_Identifier, moduleIdentifier: ast_Identifier | None = None) -> Callable[..., Any]:
|
|
61
|
+
pathFilename = Path(pathFilename)
|
|
62
|
+
|
|
63
|
+
importlibSpecification = importlib.util.spec_from_file_location(moduleIdentifier or pathFilename.stem, pathFilename)
|
|
64
|
+
if importlibSpecification is None or importlibSpecification.loader is None: raise ImportError(f"I received\n\t`{pathFilename = }`,\n\t`{identifier = }`, and\n\t`{moduleIdentifier = }`.\n\tAfter loading, \n\t`importlibSpecification` {'is `None`' if importlibSpecification is None else 'has a value'} and\n\t`importlibSpecification.loader` is unknown.")
|
|
65
|
+
|
|
66
|
+
moduleImported_jk_hahaha: ModuleType = importlib.util.module_from_spec(importlibSpecification)
|
|
67
|
+
importlibSpecification.loader.exec_module(moduleImported_jk_hahaha)
|
|
68
|
+
return getattr(moduleImported_jk_hahaha, identifier)
|
|
69
|
+
|
|
70
|
+
def parseLogicalPath2astModule(logicalPathModule: str_nameDOTname, packageIdentifierIfRelative: ast_Identifier|None=None, mode:str='exec') -> ast.AST:
|
|
71
|
+
moduleImported: ModuleType = importlib.import_module(logicalPathModule, packageIdentifierIfRelative)
|
|
72
|
+
sourcePython: str = inspect_getsource(moduleImported)
|
|
73
|
+
return ast.parse(sourcePython, mode=mode)
|
|
74
|
+
|
|
75
|
+
def parsePathFilename2astModule(pathFilename: PathLike[Any] | PurePath, mode:str='exec') -> ast.AST:
|
|
76
|
+
return ast.parse(Path(pathFilename).read_text(), mode=mode)
|
|
@@ -20,7 +20,8 @@ algorithm implementation into a highly-optimized Numba version.
|
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
from collections.abc import Callable, Sequence
|
|
23
|
-
from mapFolding.someAssemblyRequired import
|
|
23
|
+
from mapFolding.someAssemblyRequired import Make
|
|
24
|
+
from mapFolding.someAssemblyRequired._toolboxContainers import IngredientsFunction
|
|
24
25
|
from numba.core.compiler import CompilerBase as numbaCompilerBase
|
|
25
26
|
from typing import Any, cast, Final, TYPE_CHECKING
|
|
26
27
|
import ast
|
|
@@ -71,10 +72,11 @@ parametersNumbaFailEarly: Final[ParametersNumba] = {
|
|
|
71
72
|
'no_cfunc_wrapper': False,
|
|
72
73
|
'no_cpython_wrapper': False,
|
|
73
74
|
'nopython': True,
|
|
74
|
-
'parallel': False,
|
|
75
|
+
'parallel': False,
|
|
76
|
+
}
|
|
75
77
|
"""For a production function: speed is irrelevant, error discovery is paramount, must be compatible with anything downstream."""
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
parametersNumbaDefault: Final[ParametersNumba] = {
|
|
78
80
|
'_nrt': True,
|
|
79
81
|
'boundscheck': False,
|
|
80
82
|
'cache': True,
|
|
@@ -90,13 +92,13 @@ parametersNumbaDEFAULT: Final[ParametersNumba] = {
|
|
|
90
92
|
"""Middle of the road: fast, lean, but will talk to non-jitted functions."""
|
|
91
93
|
|
|
92
94
|
parametersNumbaParallelDEFAULT: Final[ParametersNumba] = {
|
|
93
|
-
**
|
|
95
|
+
**parametersNumbaDefault,
|
|
94
96
|
'_nrt': True,
|
|
95
97
|
'parallel': True, }
|
|
96
98
|
"""Middle of the road: fast, lean, but will talk to non-jitted functions."""
|
|
97
99
|
|
|
98
100
|
parametersNumbaSuperJit: Final[ParametersNumba] = {
|
|
99
|
-
**
|
|
101
|
+
**parametersNumbaDefault,
|
|
100
102
|
'no_cfunc_wrapper': True,
|
|
101
103
|
'no_cpython_wrapper': True, }
|
|
102
104
|
"""Speed, no helmet, no talking to non-jitted functions."""
|
|
@@ -125,15 +127,6 @@ parametersNumbaMinimum: Final[ParametersNumba] = {
|
|
|
125
127
|
Z0Z_numbaDataTypeModule = 'numba'
|
|
126
128
|
Z0Z_decoratorCallable = 'jit'
|
|
127
129
|
|
|
128
|
-
def thisIsNumbaDotJit(Ima: ast.AST) -> bool:
|
|
129
|
-
return ifThis.isCallNamespace_Identifier(Z0Z_numbaDataTypeModule, Z0Z_decoratorCallable)(Ima)
|
|
130
|
-
|
|
131
|
-
def thisIsJit(Ima: ast.AST) -> bool:
|
|
132
|
-
return ifThis.isCall_Identifier(Z0Z_decoratorCallable)(Ima)
|
|
133
|
-
|
|
134
|
-
def thisIsAnyNumbaJitDecorator(Ima: ast.AST) -> bool:
|
|
135
|
-
return thisIsNumbaDotJit(Ima) or thisIsJit(Ima)
|
|
136
|
-
|
|
137
130
|
def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, parametersNumba: ParametersNumba | None = None) -> IngredientsFunction:
|
|
138
131
|
def Z0Z_UnhandledDecorators(astCallable: ast.FunctionDef) -> ast.FunctionDef:
|
|
139
132
|
# TODO: more explicit handling of decorators. I'm able to ignore this because I know `algorithmSource` doesn't have any decorators.
|
|
@@ -143,7 +136,7 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
143
136
|
warnings.warn(f"Removed decorator {ast.unparse(decoratorItem)} from {astCallable.name}")
|
|
144
137
|
return astCallable
|
|
145
138
|
|
|
146
|
-
def makeSpecialSignatureForNumba(signatureElement: ast.arg) -> ast.Subscript | ast.Name | None:
|
|
139
|
+
def makeSpecialSignatureForNumba(signatureElement: ast.arg) -> ast.Subscript | ast.Name | None: # type: ignore
|
|
147
140
|
if isinstance(signatureElement.annotation, ast.Subscript) and isinstance(signatureElement.annotation.slice, ast.Tuple):
|
|
148
141
|
annotationShape: ast.expr = signatureElement.annotation.slice.elts[0]
|
|
149
142
|
if isinstance(annotationShape, ast.Subscript) and isinstance(annotationShape.slice, ast.Tuple):
|
|
@@ -162,7 +155,7 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
162
155
|
ndarrayName = signatureElement.arg
|
|
163
156
|
Z0Z_hacky_dtype: str = ndarrayName
|
|
164
157
|
datatype_attr = datatypeAST or Z0Z_hacky_dtype
|
|
165
|
-
ingredientsFunction.imports.
|
|
158
|
+
ingredientsFunction.imports.addImportFrom_asStr(datatypeModuleDecorator, datatype_attr)
|
|
166
159
|
datatypeNumba = ast.Name(id=datatype_attr, ctx=ast.Load())
|
|
167
160
|
|
|
168
161
|
return ast.Subscript(value=datatypeNumba, slice=shapeAST, ctx=ast.Load())
|
|
@@ -179,9 +172,9 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
179
172
|
# Efficient translation of Python scalar types to Numba types https://github.com/hunterhogan/mapFolding/issues/8
|
|
180
173
|
# For now, let Numba infer them.
|
|
181
174
|
continue
|
|
182
|
-
signatureElement: ast.Subscript | ast.Name | None = makeSpecialSignatureForNumba(parameter)
|
|
183
|
-
if signatureElement:
|
|
184
|
-
|
|
175
|
+
# signatureElement: ast.Subscript | ast.Name | None = makeSpecialSignatureForNumba(parameter)
|
|
176
|
+
# if signatureElement:
|
|
177
|
+
# list_arg4signature_or_function.append(signatureElement)
|
|
185
178
|
|
|
186
179
|
if ingredientsFunction.astFunctionDef.returns and isinstance(ingredientsFunction.astFunctionDef.returns, ast.Name):
|
|
187
180
|
theReturn: ast.Name = ingredientsFunction.astFunctionDef.returns
|
|
@@ -192,15 +185,15 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
192
185
|
|
|
193
186
|
ingredientsFunction.astFunctionDef = Z0Z_UnhandledDecorators(ingredientsFunction.astFunctionDef)
|
|
194
187
|
if parametersNumba is None:
|
|
195
|
-
parametersNumba =
|
|
196
|
-
listDecoratorKeywords: list[ast.keyword] = [Make.
|
|
188
|
+
parametersNumba = parametersNumbaDefault
|
|
189
|
+
listDecoratorKeywords: list[ast.keyword] = [Make.keyword(parameterName, Make.Constant(parameterValue)) for parameterName, parameterValue in parametersNumba.items()]
|
|
197
190
|
|
|
198
191
|
decoratorModule: str = Z0Z_numbaDataTypeModule
|
|
199
192
|
decoratorCallable: str = Z0Z_decoratorCallable
|
|
200
|
-
ingredientsFunction.imports.
|
|
193
|
+
ingredientsFunction.imports.addImportFrom_asStr(decoratorModule, decoratorCallable)
|
|
201
194
|
# Leave this line in so that global edits will change it.
|
|
202
|
-
astDecorator: ast.Call = Make.
|
|
203
|
-
astDecorator: ast.Call = Make.
|
|
195
|
+
astDecorator: ast.Call = Make.Call(Make.Name(decoratorCallable), list_argsDecorator, listDecoratorKeywords)
|
|
196
|
+
astDecorator: ast.Call = Make.Call(Make.Name(decoratorCallable), list_astKeywords=listDecoratorKeywords)
|
|
204
197
|
|
|
205
198
|
ingredientsFunction.astFunctionDef.decorator_list = [astDecorator]
|
|
206
199
|
return ingredientsFunction
|
|
@@ -22,190 +22,135 @@ to generate a fresh optimized implementation.
|
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
24
|
from mapFolding.someAssemblyRequired import (
|
|
25
|
-
|
|
26
|
-
extractFunctionDef,
|
|
25
|
+
be,
|
|
27
26
|
ifThis,
|
|
28
|
-
|
|
27
|
+
Make,
|
|
28
|
+
NodeChanger,
|
|
29
|
+
NodeTourist,
|
|
30
|
+
Then,
|
|
31
|
+
Z0Z_inlineThisFunctionWithTheseValues,
|
|
32
|
+
Z0Z_lameFindReplace,
|
|
33
|
+
Z0Z_makeDictionaryReplacementStatements,
|
|
34
|
+
又,
|
|
35
|
+
)
|
|
36
|
+
from mapFolding.someAssemblyRequired._toolboxContainers import (
|
|
37
|
+
astModuleToIngredientsFunction,
|
|
29
38
|
IngredientsModule,
|
|
30
39
|
LedgerOfImports,
|
|
31
|
-
Make,
|
|
32
|
-
makeDictionaryReplacementStatements,
|
|
33
|
-
NodeCollector,
|
|
34
|
-
NodeReplacer,
|
|
35
40
|
RecipeSynthesizeFlow,
|
|
36
|
-
Then,
|
|
37
|
-
write_astModule,
|
|
38
|
-
Z0Z_replaceMatchingASTnodes,
|
|
39
|
-
inlineThisFunctionWithTheseValues,
|
|
40
41
|
)
|
|
41
42
|
from mapFolding.someAssemblyRequired.ingredientsNumba import decorateCallableWithNumba
|
|
42
43
|
from mapFolding.someAssemblyRequired.transformDataStructures import shatter_dataclassesDOTdataclass
|
|
43
|
-
from mapFolding.
|
|
44
|
+
from mapFolding.someAssemblyRequired.transformationTools import write_astModule
|
|
44
45
|
import ast
|
|
45
46
|
|
|
46
|
-
def
|
|
47
|
-
astFunctionDef = extractFunctionDef(astModule, identifierFunctionDef)
|
|
48
|
-
if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
|
|
49
|
-
return IngredientsFunction(astFunctionDef, LedgerOfImports(astModule))
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()) -> None:
|
|
47
|
+
def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
53
48
|
# TODO a tool to automatically remove unused variables from the ArgumentsSpecification (return, and returns) _might_ be nice.
|
|
54
|
-
# TODO remember that `sequentialCallable` and `sourceSequentialCallable` are two different values.
|
|
55
49
|
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
(numbaFlow.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
ingredientsDispatcher.astFunctionDef
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
NodeReplacer(
|
|
142
|
-
findThis = ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(numbaFlow.sourceDataclassInstance))
|
|
143
|
-
, doThat = Then.replaceWith(newAssign)
|
|
144
|
-
).visit(ingredientsDispatcher.astFunctionDef)
|
|
145
|
-
|
|
146
|
-
# sourceSequentialCallable
|
|
147
|
-
shatteredDataclass = shatter_dataclassesDOTdataclass(numbaFlow.logicalPathModuleDataclass, numbaFlow.sourceDataclassIdentifier, numbaFlow.sourceDataclassInstance)
|
|
148
|
-
|
|
149
|
-
ingredientsDispatcher.imports.update(shatteredDataclass.ledgerDataclassANDFragments)
|
|
150
|
-
|
|
151
|
-
NodeReplacer(
|
|
152
|
-
findThis = ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.sourceSequentialCallable) # NOTE source
|
|
153
|
-
, doThat = Then.insertThisAbove(shatteredDataclass.listAnnAssign4DataclassUnpack)
|
|
154
|
-
).visit(ingredientsDispatcher.astFunctionDef)
|
|
155
|
-
NodeReplacer(
|
|
156
|
-
findThis = ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.sourceSequentialCallable) # NOTE source
|
|
157
|
-
, doThat = Then.insertThisBelow([shatteredDataclass.astAssignDataclassRepack])
|
|
158
|
-
).visit(ingredientsDispatcher.astFunctionDef)
|
|
159
|
-
NodeReplacer(
|
|
160
|
-
findThis = ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.sourceSequentialCallable) # NOTE source
|
|
161
|
-
, doThat = Then.replaceWith(Make.astAssign(listTargets=[shatteredDataclass.astTuple4AssignTargetsToFragments], value=Make.astCall(Make.astName(numbaFlow.sequentialCallable), shatteredDataclass.listNameDataclassFragments4Parameters)))
|
|
162
|
-
).visit(ingredientsDispatcher.astFunctionDef)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
# ===========================================================
|
|
166
|
-
ingredientsParallel.astFunctionDef.args = Make.astArgumentsSpecification(args=shatteredDataclass.list_ast_argAnnotated4ArgumentsSpecification)
|
|
167
|
-
NodeReplacer(
|
|
168
|
-
findThis = ifThis.isReturn
|
|
169
|
-
, doThat = Then.replaceWith(Make.astReturn(shatteredDataclass.astTuple4AssignTargetsToFragments))
|
|
170
|
-
).visit(ingredientsParallel.astFunctionDef)
|
|
171
|
-
|
|
172
|
-
NodeReplacer(
|
|
173
|
-
findThis = ifThis.isReturn
|
|
174
|
-
, doThat = Then.replaceWith(Make.astReturn(shatteredDataclass.countingVariableName))
|
|
175
|
-
).visit(ingredientsParallel.astFunctionDef)
|
|
50
|
+
|
|
51
|
+
listAllIngredientsFunctions = [
|
|
52
|
+
(ingredientsInitialize := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableInitialize)),
|
|
53
|
+
(ingredientsParallel := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableParallel)),
|
|
54
|
+
(ingredientsSequential := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableSequential)),
|
|
55
|
+
(ingredientsDispatcher := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableDispatcher)),
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
# Inline functions ========================================================
|
|
59
|
+
dictionaryReplacementStatements = Z0Z_makeDictionaryReplacementStatements(numbaFlow.source_astModule)
|
|
60
|
+
# NOTE Replacements statements are based on the identifiers in the _source_, so operate on the source identifiers.
|
|
61
|
+
ingredientsInitialize.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsInitialize.astFunctionDef, dictionaryReplacementStatements)
|
|
62
|
+
ingredientsParallel.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsParallel.astFunctionDef, dictionaryReplacementStatements)
|
|
63
|
+
ingredientsSequential.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsSequential.astFunctionDef, dictionaryReplacementStatements)
|
|
64
|
+
|
|
65
|
+
# assignRecipeIdentifiersToCallable. =============================
|
|
66
|
+
# TODO How can I use `RecipeSynthesizeFlow` as the SSOT for the pairs of items that may need to be replaced?
|
|
67
|
+
# NOTE reminder: you are updating these `ast.Name` here (and not in a more general search) because this is a
|
|
68
|
+
# narrow search for `ast.Call` so you won't accidentally replace unrelated `ast.Name`.
|
|
69
|
+
listFindReplace = [(numbaFlow.sourceCallableDispatcher, numbaFlow.callableDispatcher),
|
|
70
|
+
(numbaFlow.sourceCallableInitialize, numbaFlow.callableInitialize),
|
|
71
|
+
(numbaFlow.sourceCallableParallel, numbaFlow.callableParallel),
|
|
72
|
+
(numbaFlow.sourceCallableSequential, numbaFlow.callableSequential),]
|
|
73
|
+
for ingredients in listAllIngredientsFunctions:
|
|
74
|
+
for source_Identifier, recipe_Identifier in listFindReplace:
|
|
75
|
+
updateCallName = NodeChanger(ifThis.isCall_Identifier(source_Identifier), Then.DOTfunc(Then.replaceWith(Make.Name(recipe_Identifier))))
|
|
76
|
+
updateCallName.visit(ingredients.astFunctionDef)
|
|
77
|
+
|
|
78
|
+
ingredientsDispatcher.astFunctionDef.name = numbaFlow.callableDispatcher
|
|
79
|
+
ingredientsInitialize.astFunctionDef.name = numbaFlow.callableInitialize
|
|
80
|
+
ingredientsParallel.astFunctionDef.name = numbaFlow.callableParallel
|
|
81
|
+
ingredientsSequential.astFunctionDef.name = numbaFlow.callableSequential
|
|
82
|
+
|
|
83
|
+
# Assign identifiers per the recipe. ==============================
|
|
84
|
+
listFindReplace = [(numbaFlow.sourceDataclassInstance, numbaFlow.dataclassInstance),
|
|
85
|
+
(numbaFlow.sourceDataclassInstanceTaskDistribution, numbaFlow.dataclassInstanceTaskDistribution),
|
|
86
|
+
(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.concurrencyManagerNamespace),]
|
|
87
|
+
for ingredients in listAllIngredientsFunctions:
|
|
88
|
+
for source_Identifier, recipe_Identifier in listFindReplace:
|
|
89
|
+
updateName = NodeChanger(ifThis.isName_Identifier(source_Identifier), Then.DOTid(Then.replaceWith(recipe_Identifier)))
|
|
90
|
+
update_arg = NodeChanger(ifThis.isArgument_Identifier(source_Identifier), Then.DOTarg(Then.replaceWith(recipe_Identifier)))
|
|
91
|
+
updateName.visit(ingredients.astFunctionDef)
|
|
92
|
+
update_arg.visit(ingredients.astFunctionDef)
|
|
93
|
+
|
|
94
|
+
updateConcurrencyManager = NodeChanger(ifThis.isCallAttributeNamespace_Identifier(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.sourceConcurrencyManagerIdentifier)
|
|
95
|
+
, Then.DOTfunc(Then.replaceWith(Make.Attribute(Make.Name(numbaFlow.concurrencyManagerNamespace), numbaFlow.concurrencyManagerIdentifier))))
|
|
96
|
+
updateConcurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
|
|
97
|
+
|
|
98
|
+
# shatter Dataclass =======================================================
|
|
99
|
+
instance_Identifier = numbaFlow.dataclassInstance
|
|
100
|
+
getTheOtherRecord_damn = numbaFlow.dataclassInstanceTaskDistribution
|
|
101
|
+
shatteredDataclass = shatter_dataclassesDOTdataclass(numbaFlow.logicalPathModuleDataclass, numbaFlow.sourceDataclassIdentifier, instance_Identifier)
|
|
102
|
+
ingredientsDispatcher.imports.update(shatteredDataclass.ledger)
|
|
103
|
+
|
|
104
|
+
# Change callable parameters and Call to the callable at the same time ====
|
|
105
|
+
# TODO How can I use ast and/or other tools to ensure that when I change a callable, I also change the statements that call the callable?
|
|
106
|
+
# Asked differently, how do I integrate separate statements into a "subroutine", and that subroutine is "atomic/indivisible"?
|
|
107
|
+
# sequentialCallable =========================================================
|
|
108
|
+
ingredientsSequential.astFunctionDef.args = Make.argumentsSpecification(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
|
109
|
+
astCallSequentialCallable = Make.Call(Make.Name(numbaFlow.callableSequential), shatteredDataclass.listName4Parameters)
|
|
110
|
+
changeReturnSequentialCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(shatteredDataclass.fragments4AssignmentOrParameters)))
|
|
111
|
+
ingredientsSequential.astFunctionDef.returns = shatteredDataclass.signatureReturnAnnotation
|
|
112
|
+
replaceAssignSequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.replaceWith(Make.Assign(listTargets=[shatteredDataclass.fragments4AssignmentOrParameters], value=astCallSequentialCallable)))
|
|
113
|
+
|
|
114
|
+
unpack4sequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.insertThisAbove(shatteredDataclass.listUnpack))
|
|
115
|
+
repack4sequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.insertThisBelow([shatteredDataclass.repack]))
|
|
116
|
+
|
|
117
|
+
changeReturnSequentialCallable.visit(ingredientsSequential.astFunctionDef)
|
|
118
|
+
replaceAssignSequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
119
|
+
unpack4sequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
120
|
+
repack4sequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
121
|
+
|
|
122
|
+
ingredientsSequential.astFunctionDef = Z0Z_lameFindReplace(ingredientsSequential.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
|
|
123
|
+
|
|
124
|
+
# parallelCallable =========================================================
|
|
125
|
+
ingredientsParallel.astFunctionDef.args = Make.argumentsSpecification(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
|
126
|
+
replaceCall2concurrencyManager = NodeChanger(ifThis.isCallAttributeNamespace_Identifier(numbaFlow.concurrencyManagerNamespace, numbaFlow.concurrencyManagerIdentifier), Then.replaceWith(Make.Call(Make.Attribute(Make.Name(numbaFlow.concurrencyManagerNamespace), numbaFlow.concurrencyManagerIdentifier), listArguments=[Make.Name(numbaFlow.callableParallel)] + shatteredDataclass.listName4Parameters)))
|
|
127
|
+
|
|
128
|
+
# NOTE I am dissatisfied with this logic for many reasons, including that it requires separate NodeCollector and NodeReplacer instances.
|
|
129
|
+
astCallConcurrencyResult: list[ast.Call] = []
|
|
130
|
+
get_astCallConcurrencyResult: NodeTourist = NodeTourist(ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(getTheOtherRecord_damn)), lambda node: NodeTourist(be.Call, Then.appendTo(astCallConcurrencyResult)).visit(node)) # pyright: ignore[reportUnknownArgumentType, reportUnknownLambdaType]
|
|
131
|
+
get_astCallConcurrencyResult.visit(ingredientsDispatcher.astFunctionDef)
|
|
132
|
+
replaceAssignParallelCallable = NodeChanger(ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(getTheOtherRecord_damn)), Then.DOTvalue(Then.replaceWith(astCallConcurrencyResult[0])))
|
|
133
|
+
replaceAssignParallelCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
134
|
+
changeReturnParallelCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(shatteredDataclass.countingVariableName)))
|
|
176
135
|
ingredientsParallel.astFunctionDef.returns = shatteredDataclass.countingVariableAnnotation
|
|
177
|
-
replacementMap = {statement.value: statement.target for statement in shatteredDataclass.listAnnAssign4DataclassUnpack}
|
|
178
|
-
ingredientsParallel.astFunctionDef = Z0Z_replaceMatchingASTnodes(ingredientsParallel.astFunctionDef, replacementMap) # type: ignore
|
|
179
|
-
ingredientsParallel = decorateCallableWithNumba(ingredientsParallel)
|
|
180
136
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
ingredientsSequential.astFunctionDef.returns = shatteredDataclass.astSubscriptPrimitiveTupleAnnotations4FunctionDef_returns
|
|
192
|
-
replacementMap = {statement.value: statement.target for statement in shatteredDataclass.listAnnAssign4DataclassUnpack}
|
|
193
|
-
ingredientsSequential.astFunctionDef = Z0Z_replaceMatchingASTnodes(ingredientsSequential.astFunctionDef, replacementMap) # type: ignore
|
|
137
|
+
unpack4parallelCallable = NodeChanger(ifThis.isAssignAndValueIsCallAttributeNamespace_Identifier(numbaFlow.concurrencyManagerNamespace, numbaFlow.concurrencyManagerIdentifier), Then.insertThisAbove(shatteredDataclass.listUnpack))
|
|
138
|
+
|
|
139
|
+
unpack4parallelCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
140
|
+
replaceCall2concurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
|
|
141
|
+
changeReturnParallelCallable.visit(ingredientsParallel.astFunctionDef)
|
|
142
|
+
|
|
143
|
+
ingredientsParallel.astFunctionDef = Z0Z_lameFindReplace(ingredientsParallel.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
|
|
144
|
+
|
|
145
|
+
# numba decorators =========================================
|
|
146
|
+
ingredientsParallel = decorateCallableWithNumba(ingredientsParallel)
|
|
194
147
|
ingredientsSequential = decorateCallableWithNumba(ingredientsSequential)
|
|
195
|
-
# End old organization
|
|
196
|
-
# ===========================================================
|
|
197
148
|
|
|
198
|
-
# ===========================================================
|
|
199
|
-
|
|
200
|
-
# ===========================================================
|
|
201
|
-
# Module-level transformations
|
|
202
|
-
ingredientsModuleNumbaUnified = IngredientsModule(
|
|
203
|
-
ingredientsFunction=[ingredientsInitialize,
|
|
204
|
-
ingredientsParallel,
|
|
205
|
-
ingredientsSequential,
|
|
206
|
-
ingredientsDispatcher], imports=LedgerOfImports(numbaFlow.source_astModule))
|
|
149
|
+
# Module-level transformations ===========================================================
|
|
150
|
+
ingredientsModuleNumbaUnified = IngredientsModule(ingredientsFunction=listAllIngredientsFunctions, imports=LedgerOfImports(numbaFlow.source_astModule))
|
|
207
151
|
|
|
208
|
-
write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.
|
|
152
|
+
write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.packageIdentifier)
|
|
209
153
|
|
|
154
|
+
theNumbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()
|
|
210
155
|
if __name__ == '__main__':
|
|
211
|
-
makeNumbaFlow()
|
|
156
|
+
makeNumbaFlow(theNumbaFlow)
|