mapFolding 0.8.3__py3-none-any.whl → 0.8.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 +6 -3
- mapFolding/basecamp.py +13 -7
- mapFolding/beDRY.py +241 -68
- mapFolding/oeis.py +4 -4
- mapFolding/reference/hunterNumba.py +1 -1
- mapFolding/someAssemblyRequired/__init__.py +40 -20
- mapFolding/someAssemblyRequired/_theTypes.py +53 -0
- mapFolding/someAssemblyRequired/_tool_Make.py +99 -0
- mapFolding/someAssemblyRequired/_tool_Then.py +72 -0
- mapFolding/someAssemblyRequired/_toolboxAntecedents.py +358 -0
- mapFolding/someAssemblyRequired/_toolboxContainers.py +334 -0
- mapFolding/someAssemblyRequired/_toolboxPython.py +62 -0
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py +2 -2
- mapFolding/someAssemblyRequired/newInliner.py +22 -0
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +158 -0
- mapFolding/someAssemblyRequired/toolboxNumba.py +358 -0
- mapFolding/someAssemblyRequired/transformationTools.py +289 -698
- mapFolding/syntheticModules/numbaCount_doTheNeedful.py +36 -33
- mapFolding/theDao.py +13 -11
- mapFolding/theSSOT.py +83 -128
- mapFolding/toolboxFilesystem.py +219 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.5.dist-info}/METADATA +4 -2
- mapfolding-0.8.5.dist-info/RECORD +48 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.5.dist-info}/WHEEL +1 -1
- tests/conftest.py +56 -52
- tests/test_computations.py +42 -32
- tests/test_filesystem.py +4 -4
- tests/test_other.py +2 -2
- tests/test_tasks.py +2 -2
- mapFolding/filesystem.py +0 -129
- mapFolding/someAssemblyRequired/ingredientsNumba.py +0 -206
- mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +0 -211
- mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +0 -413
- mapFolding/someAssemblyRequired/transformDataStructures.py +0 -168
- mapfolding-0.8.3.dist-info/RECORD +0 -43
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.5.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.5.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.8.3.dist-info → mapfolding-0.8.5.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Numba-specific ingredients for optimized code generation.
|
|
3
|
+
|
|
4
|
+
This module provides specialized tools, constants, and types specifically designed
|
|
5
|
+
for transforming Python code into Numba-accelerated implementations. It implements:
|
|
6
|
+
|
|
7
|
+
1. A range of Numba jit decorator configurations for different optimization scenarios
|
|
8
|
+
2. Functions to identify and manipulate Numba decorators in abstract syntax trees
|
|
9
|
+
3. Utilities for applying appropriate Numba typing to transformed code
|
|
10
|
+
4. Parameter management for Numba compilation options
|
|
11
|
+
|
|
12
|
+
The configurations range from conservative options that prioritize compatibility and
|
|
13
|
+
error detection to aggressive optimizations that maximize performance at the cost of
|
|
14
|
+
flexibility. While this module specifically targets Numba, its design follows the pattern
|
|
15
|
+
of generic code transformation tools in the package, allowing similar approaches to be
|
|
16
|
+
applied to other acceleration technologies.
|
|
17
|
+
|
|
18
|
+
This module works in conjunction with transformation tools to convert the general-purpose
|
|
19
|
+
algorithm implementation into a highly-optimized Numba version.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from collections.abc import Callable, Sequence
|
|
23
|
+
from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal, getPathRootJobDEFAULT
|
|
24
|
+
from mapFolding.someAssemblyRequired import IngredientsModule, LedgerOfImports, Make, NodeChanger, NodeTourist, RecipeSynthesizeFlow, Then, ast_Identifier, be, ifThis, parsePathFilename2astModule, str_nameDOTname, IngredientsFunction, ShatteredDataclass
|
|
25
|
+
from mapFolding.someAssemblyRequired.transformationTools import Z0Z_inlineThisFunctionWithTheseValues, Z0Z_lameFindReplace, Z0Z_makeDictionaryReplacementStatements, astModuleToIngredientsFunction, shatter_dataclassesDOTdataclass, write_astModule
|
|
26
|
+
from mapFolding.theSSOT import ComputationState
|
|
27
|
+
from numba.core.compiler import CompilerBase as numbaCompilerBase
|
|
28
|
+
from pathlib import Path, PurePosixPath
|
|
29
|
+
from typing import Any, cast, Final, TYPE_CHECKING
|
|
30
|
+
import ast
|
|
31
|
+
import dataclasses
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
from typing import NotRequired
|
|
35
|
+
except Exception:
|
|
36
|
+
from typing_extensions import NotRequired
|
|
37
|
+
|
|
38
|
+
if TYPE_CHECKING:
|
|
39
|
+
from typing import TypedDict
|
|
40
|
+
else:
|
|
41
|
+
TypedDict = dict[str,Any]
|
|
42
|
+
|
|
43
|
+
theNumbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()
|
|
44
|
+
|
|
45
|
+
class ParametersNumba(TypedDict):
|
|
46
|
+
_dbg_extend_lifetimes: NotRequired[bool]
|
|
47
|
+
_dbg_optnone: NotRequired[bool]
|
|
48
|
+
_nrt: NotRequired[bool]
|
|
49
|
+
boundscheck: NotRequired[bool]
|
|
50
|
+
cache: bool
|
|
51
|
+
debug: NotRequired[bool]
|
|
52
|
+
error_model: str
|
|
53
|
+
fastmath: bool
|
|
54
|
+
forceinline: bool
|
|
55
|
+
forceobj: NotRequired[bool]
|
|
56
|
+
inline: str
|
|
57
|
+
locals: NotRequired[dict[str, Any]]
|
|
58
|
+
looplift: bool
|
|
59
|
+
no_cfunc_wrapper: bool
|
|
60
|
+
no_cpython_wrapper: bool
|
|
61
|
+
no_rewrites: NotRequired[bool]
|
|
62
|
+
nogil: NotRequired[bool]
|
|
63
|
+
nopython: bool
|
|
64
|
+
parallel: bool
|
|
65
|
+
pipeline_class: NotRequired[type[numbaCompilerBase]]
|
|
66
|
+
signature_or_function: NotRequired[Any | Callable[..., Any] | str | tuple[Any, ...]]
|
|
67
|
+
target: NotRequired[str]
|
|
68
|
+
|
|
69
|
+
parametersNumbaFailEarly: Final[ParametersNumba] = { '_nrt': True, 'boundscheck': True, 'cache': True, 'error_model': 'python', 'fastmath': False, 'forceinline': True, 'inline': 'always', 'looplift': False, 'no_cfunc_wrapper': False, 'no_cpython_wrapper': False, 'nopython': True, 'parallel': False, }
|
|
70
|
+
"""For a production function: speed is irrelevant, error discovery is paramount, must be compatible with anything downstream."""
|
|
71
|
+
parametersNumbaDefault: Final[ParametersNumba] = { '_nrt': True, 'boundscheck': False, 'cache': True, 'error_model': 'numpy', 'fastmath': True, 'forceinline': True, 'inline': 'always', 'looplift': False, 'no_cfunc_wrapper': False, 'no_cpython_wrapper': False, 'nopython': True, 'parallel': False, }
|
|
72
|
+
"""Middle of the road: fast, lean, but will talk to non-jitted functions."""
|
|
73
|
+
parametersNumbaParallelDEFAULT: Final[ParametersNumba] = { **parametersNumbaDefault, '_nrt': True, 'parallel': True, }
|
|
74
|
+
"""Middle of the road: fast, lean, but will talk to non-jitted functions."""
|
|
75
|
+
parametersNumbaSuperJit: Final[ParametersNumba] = { **parametersNumbaDefault, 'no_cfunc_wrapper': True, 'no_cpython_wrapper': True, }
|
|
76
|
+
"""Speed, no helmet, no talking to non-jitted functions."""
|
|
77
|
+
parametersNumbaSuperJitParallel: Final[ParametersNumba] = { **parametersNumbaSuperJit, '_nrt': True, 'parallel': True, }
|
|
78
|
+
"""Speed, no helmet, concurrency, no talking to non-jitted functions."""
|
|
79
|
+
parametersNumbaMinimum: Final[ParametersNumba] = { '_nrt': True, 'boundscheck': True, 'cache': True, 'error_model': 'numpy', 'fastmath': True, 'forceinline': False, 'inline': 'always', 'looplift': False, 'no_cfunc_wrapper': False, 'no_cpython_wrapper': False, 'nopython': False, 'forceobj': True, 'parallel': False, }
|
|
80
|
+
|
|
81
|
+
Z0Z_numbaDataTypeModule = 'numba'
|
|
82
|
+
Z0Z_decoratorCallable = 'jit'
|
|
83
|
+
|
|
84
|
+
def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, parametersNumba: ParametersNumba | None = None) -> IngredientsFunction:
|
|
85
|
+
def Z0Z_UnhandledDecorators(astCallable: ast.FunctionDef) -> ast.FunctionDef:
|
|
86
|
+
# TODO: more explicit handling of decorators. I'm able to ignore this because I know `algorithmSource` doesn't have any decorators.
|
|
87
|
+
for decoratorItem in astCallable.decorator_list.copy():
|
|
88
|
+
import warnings
|
|
89
|
+
astCallable.decorator_list.remove(decoratorItem)
|
|
90
|
+
warnings.warn(f"Removed decorator {ast.unparse(decoratorItem)} from {astCallable.name}")
|
|
91
|
+
return astCallable
|
|
92
|
+
|
|
93
|
+
def makeSpecialSignatureForNumba(signatureElement: ast.arg) -> ast.Subscript | ast.Name | None: # type: ignore
|
|
94
|
+
if isinstance(signatureElement.annotation, ast.Subscript) and isinstance(signatureElement.annotation.slice, ast.Tuple):
|
|
95
|
+
annotationShape: ast.expr = signatureElement.annotation.slice.elts[0]
|
|
96
|
+
if isinstance(annotationShape, ast.Subscript) and isinstance(annotationShape.slice, ast.Tuple):
|
|
97
|
+
shapeAsListSlices: list[ast.Slice] = [ast.Slice() for _axis in range(len(annotationShape.slice.elts))]
|
|
98
|
+
shapeAsListSlices[-1] = ast.Slice(step=ast.Constant(value=1))
|
|
99
|
+
shapeAST: ast.Slice | ast.Tuple = ast.Tuple(elts=list(shapeAsListSlices), ctx=ast.Load())
|
|
100
|
+
else:
|
|
101
|
+
shapeAST = ast.Slice(step=ast.Constant(value=1))
|
|
102
|
+
|
|
103
|
+
annotationDtype: ast.expr = signatureElement.annotation.slice.elts[1]
|
|
104
|
+
if (isinstance(annotationDtype, ast.Subscript) and isinstance(annotationDtype.slice, ast.Attribute)):
|
|
105
|
+
datatypeAST = annotationDtype.slice.attr
|
|
106
|
+
else:
|
|
107
|
+
datatypeAST = None
|
|
108
|
+
|
|
109
|
+
ndarrayName = signatureElement.arg
|
|
110
|
+
Z0Z_hacky_dtype: str = ndarrayName
|
|
111
|
+
datatype_attr = datatypeAST or Z0Z_hacky_dtype
|
|
112
|
+
ingredientsFunction.imports.addImportFrom_asStr(datatypeModuleDecorator, datatype_attr)
|
|
113
|
+
datatypeNumba = ast.Name(id=datatype_attr, ctx=ast.Load())
|
|
114
|
+
|
|
115
|
+
return ast.Subscript(value=datatypeNumba, slice=shapeAST, ctx=ast.Load())
|
|
116
|
+
|
|
117
|
+
elif isinstance(signatureElement.annotation, ast.Name):
|
|
118
|
+
return signatureElement.annotation
|
|
119
|
+
return None
|
|
120
|
+
|
|
121
|
+
datatypeModuleDecorator: str = Z0Z_numbaDataTypeModule
|
|
122
|
+
list_argsDecorator: Sequence[ast.expr] = []
|
|
123
|
+
|
|
124
|
+
list_arg4signature_or_function: list[ast.expr] = []
|
|
125
|
+
for parameter in ingredientsFunction.astFunctionDef.args.args:
|
|
126
|
+
# Efficient translation of Python scalar types to Numba types https://github.com/hunterhogan/mapFolding/issues/8
|
|
127
|
+
# For now, let Numba infer them.
|
|
128
|
+
continue
|
|
129
|
+
# signatureElement: ast.Subscript | ast.Name | None = makeSpecialSignatureForNumba(parameter)
|
|
130
|
+
# if signatureElement:
|
|
131
|
+
# list_arg4signature_or_function.append(signatureElement)
|
|
132
|
+
|
|
133
|
+
if ingredientsFunction.astFunctionDef.returns and isinstance(ingredientsFunction.astFunctionDef.returns, ast.Name):
|
|
134
|
+
theReturn: ast.Name = ingredientsFunction.astFunctionDef.returns
|
|
135
|
+
list_argsDecorator = [cast(ast.expr, ast.Call(func=ast.Name(id=theReturn.id, ctx=ast.Load())
|
|
136
|
+
, args=list_arg4signature_or_function if list_arg4signature_or_function else [], keywords=[] ) )]
|
|
137
|
+
elif list_arg4signature_or_function:
|
|
138
|
+
list_argsDecorator = [cast(ast.expr, ast.Tuple(elts=list_arg4signature_or_function, ctx=ast.Load()))]
|
|
139
|
+
|
|
140
|
+
ingredientsFunction.astFunctionDef = Z0Z_UnhandledDecorators(ingredientsFunction.astFunctionDef)
|
|
141
|
+
if parametersNumba is None:
|
|
142
|
+
parametersNumba = parametersNumbaDefault
|
|
143
|
+
listDecoratorKeywords: list[ast.keyword] = [Make.keyword(parameterName, Make.Constant(parameterValue)) for parameterName, parameterValue in parametersNumba.items()]
|
|
144
|
+
|
|
145
|
+
decoratorModule: str = Z0Z_numbaDataTypeModule
|
|
146
|
+
decoratorCallable: str = Z0Z_decoratorCallable
|
|
147
|
+
ingredientsFunction.imports.addImportFrom_asStr(decoratorModule, decoratorCallable)
|
|
148
|
+
# Leave this line in so that global edits will change it.
|
|
149
|
+
astDecorator: ast.Call = Make.Call(Make.Name(decoratorCallable), list_argsDecorator, listDecoratorKeywords)
|
|
150
|
+
astDecorator: ast.Call = Make.Call(Make.Name(decoratorCallable), list_astKeywords=listDecoratorKeywords)
|
|
151
|
+
|
|
152
|
+
ingredientsFunction.astFunctionDef.decorator_list = [astDecorator]
|
|
153
|
+
return ingredientsFunction
|
|
154
|
+
|
|
155
|
+
@dataclasses.dataclass
|
|
156
|
+
class SpicesJobNumba:
|
|
157
|
+
useNumbaProgressBar: bool = True
|
|
158
|
+
numbaProgressBarIdentifier: ast_Identifier = 'ProgressBarGroupsOfFolds'
|
|
159
|
+
parametersNumba = parametersNumbaDefault
|
|
160
|
+
|
|
161
|
+
@dataclasses.dataclass
|
|
162
|
+
class RecipeJob:
|
|
163
|
+
state: ComputationState
|
|
164
|
+
# TODO create function to calculate `foldsTotalEstimated`
|
|
165
|
+
foldsTotalEstimated: int = 0
|
|
166
|
+
shatteredDataclass: ShatteredDataclass = dataclasses.field(default=None, init=True) # type: ignore[assignment, reportAssignmentType]
|
|
167
|
+
|
|
168
|
+
# ========================================
|
|
169
|
+
# Source
|
|
170
|
+
source_astModule = parsePathFilename2astModule(theNumbaFlow.pathFilenameSequential)
|
|
171
|
+
sourceCountCallable: ast_Identifier = theNumbaFlow.callableSequential
|
|
172
|
+
|
|
173
|
+
sourceLogicalPathModuleDataclass: str_nameDOTname = theNumbaFlow.logicalPathModuleDataclass
|
|
174
|
+
sourceDataclassIdentifier: ast_Identifier = theNumbaFlow.dataclassIdentifier
|
|
175
|
+
sourceDataclassInstance: ast_Identifier = theNumbaFlow.dataclassInstance
|
|
176
|
+
|
|
177
|
+
sourcePathPackage: PurePosixPath | None = theNumbaFlow.pathPackage
|
|
178
|
+
sourcePackageIdentifier: ast_Identifier | None = theNumbaFlow.packageIdentifier
|
|
179
|
+
|
|
180
|
+
# ========================================
|
|
181
|
+
# Filesystem (names of physical objects)
|
|
182
|
+
pathPackage: PurePosixPath | None = None
|
|
183
|
+
pathModule: PurePosixPath | None = PurePosixPath(getPathRootJobDEFAULT())
|
|
184
|
+
""" `pathModule` will override `pathPackage` and `logicalPathRoot`."""
|
|
185
|
+
fileExtension: str = theNumbaFlow.fileExtension
|
|
186
|
+
pathFilenameFoldsTotal: PurePosixPath = dataclasses.field(default=None, init=True) # type: ignore[assignment, reportAssignmentType]
|
|
187
|
+
|
|
188
|
+
# ========================================
|
|
189
|
+
# Logical identifiers (as opposed to physical identifiers)
|
|
190
|
+
# ========================================
|
|
191
|
+
packageIdentifier: ast_Identifier | None = None
|
|
192
|
+
logicalPathRoot: str_nameDOTname | None = None
|
|
193
|
+
""" `logicalPathRoot` likely corresponds to a physical filesystem directory."""
|
|
194
|
+
moduleIdentifier: ast_Identifier = dataclasses.field(default=None, init=True) # type: ignore[assignment, reportAssignmentType]
|
|
195
|
+
countCallable: ast_Identifier = sourceCountCallable
|
|
196
|
+
dataclassIdentifier: ast_Identifier | None = sourceDataclassIdentifier
|
|
197
|
+
dataclassInstance: ast_Identifier | None = sourceDataclassInstance
|
|
198
|
+
logicalPathModuleDataclass: str_nameDOTname | None = sourceLogicalPathModuleDataclass
|
|
199
|
+
|
|
200
|
+
def _makePathFilename(self,
|
|
201
|
+
pathRoot: PurePosixPath | None = None,
|
|
202
|
+
logicalPathINFIX: str_nameDOTname | None = None,
|
|
203
|
+
filenameStem: str | None = None,
|
|
204
|
+
fileExtension: str | None = None,
|
|
205
|
+
) -> PurePosixPath:
|
|
206
|
+
if pathRoot is None:
|
|
207
|
+
pathRoot = self.pathPackage or PurePosixPath(Path.cwd())
|
|
208
|
+
if logicalPathINFIX:
|
|
209
|
+
whyIsThisStillAThing: list[str] = logicalPathINFIX.split('.')
|
|
210
|
+
pathRoot = pathRoot.joinpath(*whyIsThisStillAThing)
|
|
211
|
+
if filenameStem is None:
|
|
212
|
+
filenameStem = self.moduleIdentifier
|
|
213
|
+
if fileExtension is None:
|
|
214
|
+
fileExtension = self.fileExtension
|
|
215
|
+
filename: str = filenameStem + fileExtension
|
|
216
|
+
return pathRoot.joinpath(filename)
|
|
217
|
+
|
|
218
|
+
@property
|
|
219
|
+
def pathFilenameModule(self) -> PurePosixPath:
|
|
220
|
+
if self.pathModule is None:
|
|
221
|
+
return self._makePathFilename()
|
|
222
|
+
else:
|
|
223
|
+
return self._makePathFilename(pathRoot=self.pathModule, logicalPathINFIX=None)
|
|
224
|
+
|
|
225
|
+
def __post_init__(self):
|
|
226
|
+
pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(self.state.mapShape))
|
|
227
|
+
|
|
228
|
+
if self.moduleIdentifier is None:
|
|
229
|
+
self.moduleIdentifier = pathFilenameFoldsTotal.stem
|
|
230
|
+
|
|
231
|
+
if self.pathFilenameFoldsTotal is None:
|
|
232
|
+
self.pathFilenameFoldsTotal = pathFilenameFoldsTotal
|
|
233
|
+
|
|
234
|
+
if self.shatteredDataclass is None and self.logicalPathModuleDataclass and self.dataclassIdentifier and self.dataclassInstance:
|
|
235
|
+
self.shatteredDataclass = shatter_dataclassesDOTdataclass(self.logicalPathModuleDataclass, self.dataclassIdentifier, self.dataclassInstance)
|
|
236
|
+
|
|
237
|
+
# ========================================
|
|
238
|
+
# Fields you probably don't need =================================
|
|
239
|
+
# Dispatcher =================================
|
|
240
|
+
sourceDispatcherCallable: ast_Identifier = theNumbaFlow.callableDispatcher
|
|
241
|
+
dispatcherCallable: ast_Identifier = sourceDispatcherCallable
|
|
242
|
+
# Parallel counting =================================
|
|
243
|
+
sourceDataclassInstanceTaskDistribution: ast_Identifier = theNumbaFlow.dataclassInstanceTaskDistribution
|
|
244
|
+
sourceConcurrencyManagerNamespace: ast_Identifier = theNumbaFlow.concurrencyManagerNamespace
|
|
245
|
+
sourceConcurrencyManagerIdentifier: ast_Identifier = theNumbaFlow.concurrencyManagerIdentifier
|
|
246
|
+
dataclassInstanceTaskDistribution: ast_Identifier = sourceDataclassInstanceTaskDistribution
|
|
247
|
+
concurrencyManagerNamespace: ast_Identifier = sourceConcurrencyManagerNamespace
|
|
248
|
+
concurrencyManagerIdentifier: ast_Identifier = sourceConcurrencyManagerIdentifier
|
|
249
|
+
|
|
250
|
+
def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
251
|
+
# TODO a tool to automatically remove unused variables from the ArgumentsSpecification (return, and returns) _might_ be nice.
|
|
252
|
+
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
253
|
+
|
|
254
|
+
listAllIngredientsFunctions = [
|
|
255
|
+
(ingredientsInitialize := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableInitialize)),
|
|
256
|
+
(ingredientsParallel := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableParallel)),
|
|
257
|
+
(ingredientsSequential := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableSequential)),
|
|
258
|
+
(ingredientsDispatcher := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableDispatcher)),
|
|
259
|
+
]
|
|
260
|
+
|
|
261
|
+
# Inline functions ========================================================
|
|
262
|
+
dictionaryReplacementStatements = Z0Z_makeDictionaryReplacementStatements(numbaFlow.source_astModule)
|
|
263
|
+
# NOTE Replacements statements are based on the identifiers in the _source_, so operate on the source identifiers.
|
|
264
|
+
ingredientsInitialize.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsInitialize.astFunctionDef, dictionaryReplacementStatements)
|
|
265
|
+
ingredientsParallel.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsParallel.astFunctionDef, dictionaryReplacementStatements)
|
|
266
|
+
ingredientsSequential.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsSequential.astFunctionDef, dictionaryReplacementStatements)
|
|
267
|
+
|
|
268
|
+
# assignRecipeIdentifiersToCallable. =============================
|
|
269
|
+
# TODO How can I use `RecipeSynthesizeFlow` as the SSOT for the pairs of items that may need to be replaced?
|
|
270
|
+
# NOTE reminder: you are updating these `ast.Name` here (and not in a more general search) because this is a
|
|
271
|
+
# narrow search for `ast.Call` so you won't accidentally replace unrelated `ast.Name`.
|
|
272
|
+
listFindReplace = [(numbaFlow.sourceCallableDispatcher, numbaFlow.callableDispatcher),
|
|
273
|
+
(numbaFlow.sourceCallableInitialize, numbaFlow.callableInitialize),
|
|
274
|
+
(numbaFlow.sourceCallableParallel, numbaFlow.callableParallel),
|
|
275
|
+
(numbaFlow.sourceCallableSequential, numbaFlow.callableSequential),]
|
|
276
|
+
for ingredients in listAllIngredientsFunctions:
|
|
277
|
+
for source_Identifier, recipe_Identifier in listFindReplace:
|
|
278
|
+
updateCallName = NodeChanger(ifThis.isCall_Identifier(source_Identifier), Then.DOTfunc(Then.replaceWith(Make.Name(recipe_Identifier))))
|
|
279
|
+
updateCallName.visit(ingredients.astFunctionDef)
|
|
280
|
+
|
|
281
|
+
ingredientsDispatcher.astFunctionDef.name = numbaFlow.callableDispatcher
|
|
282
|
+
ingredientsInitialize.astFunctionDef.name = numbaFlow.callableInitialize
|
|
283
|
+
ingredientsParallel.astFunctionDef.name = numbaFlow.callableParallel
|
|
284
|
+
ingredientsSequential.astFunctionDef.name = numbaFlow.callableSequential
|
|
285
|
+
|
|
286
|
+
# Assign identifiers per the recipe. ==============================
|
|
287
|
+
listFindReplace = [(numbaFlow.sourceDataclassInstance, numbaFlow.dataclassInstance),
|
|
288
|
+
(numbaFlow.sourceDataclassInstanceTaskDistribution, numbaFlow.dataclassInstanceTaskDistribution),
|
|
289
|
+
(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.concurrencyManagerNamespace),]
|
|
290
|
+
for ingredients in listAllIngredientsFunctions:
|
|
291
|
+
for source_Identifier, recipe_Identifier in listFindReplace:
|
|
292
|
+
updateName = NodeChanger(ifThis.isName_Identifier(source_Identifier), Then.DOTid(Then.replaceWith(recipe_Identifier)))
|
|
293
|
+
update_arg = NodeChanger(ifThis.isArgument_Identifier(source_Identifier), Then.DOTarg(Then.replaceWith(recipe_Identifier)))
|
|
294
|
+
updateName.visit(ingredients.astFunctionDef)
|
|
295
|
+
update_arg.visit(ingredients.astFunctionDef)
|
|
296
|
+
|
|
297
|
+
updateConcurrencyManager = NodeChanger(ifThis.isCallAttributeNamespace_Identifier(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.sourceConcurrencyManagerIdentifier)
|
|
298
|
+
, Then.DOTfunc(Then.replaceWith(Make.Attribute(Make.Name(numbaFlow.concurrencyManagerNamespace), numbaFlow.concurrencyManagerIdentifier))))
|
|
299
|
+
updateConcurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
|
|
300
|
+
|
|
301
|
+
# shatter Dataclass =======================================================
|
|
302
|
+
instance_Identifier = numbaFlow.dataclassInstance
|
|
303
|
+
getTheOtherRecord_damn = numbaFlow.dataclassInstanceTaskDistribution
|
|
304
|
+
shatteredDataclass = shatter_dataclassesDOTdataclass(numbaFlow.logicalPathModuleDataclass, numbaFlow.sourceDataclassIdentifier, instance_Identifier)
|
|
305
|
+
ingredientsDispatcher.imports.update(shatteredDataclass.ledger)
|
|
306
|
+
|
|
307
|
+
# Change callable parameters and Call to the callable at the same time ====
|
|
308
|
+
# 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?
|
|
309
|
+
# Asked differently, how do I integrate separate statements into a "subroutine", and that subroutine is "atomic/indivisible"?
|
|
310
|
+
# sequentialCallable =========================================================
|
|
311
|
+
ingredientsSequential.astFunctionDef.args = Make.argumentsSpecification(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
|
312
|
+
astCallSequentialCallable = Make.Call(Make.Name(numbaFlow.callableSequential), shatteredDataclass.listName4Parameters)
|
|
313
|
+
changeReturnSequentialCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(shatteredDataclass.fragments4AssignmentOrParameters)))
|
|
314
|
+
ingredientsSequential.astFunctionDef.returns = shatteredDataclass.signatureReturnAnnotation
|
|
315
|
+
replaceAssignSequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.replaceWith(Make.Assign(listTargets=[shatteredDataclass.fragments4AssignmentOrParameters], value=astCallSequentialCallable)))
|
|
316
|
+
|
|
317
|
+
unpack4sequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.insertThisAbove(shatteredDataclass.listUnpack))
|
|
318
|
+
repack4sequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.insertThisBelow([shatteredDataclass.repack]))
|
|
319
|
+
|
|
320
|
+
changeReturnSequentialCallable.visit(ingredientsSequential.astFunctionDef)
|
|
321
|
+
replaceAssignSequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
322
|
+
unpack4sequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
323
|
+
repack4sequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
324
|
+
|
|
325
|
+
ingredientsSequential.astFunctionDef = Z0Z_lameFindReplace(ingredientsSequential.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name) # type: ignore
|
|
326
|
+
|
|
327
|
+
# parallelCallable =========================================================
|
|
328
|
+
ingredientsParallel.astFunctionDef.args = Make.argumentsSpecification(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
|
329
|
+
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)))
|
|
330
|
+
|
|
331
|
+
# NOTE I am dissatisfied with this logic for many reasons, including that it requires separate NodeCollector and NodeReplacer instances.
|
|
332
|
+
astCallConcurrencyResult: list[ast.Call] = []
|
|
333
|
+
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]
|
|
334
|
+
get_astCallConcurrencyResult.visit(ingredientsDispatcher.astFunctionDef)
|
|
335
|
+
replaceAssignParallelCallable = NodeChanger(ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(getTheOtherRecord_damn)), Then.DOTvalue(Then.replaceWith(astCallConcurrencyResult[0])))
|
|
336
|
+
replaceAssignParallelCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
337
|
+
changeReturnParallelCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(shatteredDataclass.countingVariableName)))
|
|
338
|
+
ingredientsParallel.astFunctionDef.returns = shatteredDataclass.countingVariableAnnotation
|
|
339
|
+
|
|
340
|
+
unpack4parallelCallable = NodeChanger(ifThis.isAssignAndValueIsCallAttributeNamespace_Identifier(numbaFlow.concurrencyManagerNamespace, numbaFlow.concurrencyManagerIdentifier), Then.insertThisAbove(shatteredDataclass.listUnpack))
|
|
341
|
+
|
|
342
|
+
unpack4parallelCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
343
|
+
replaceCall2concurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
|
|
344
|
+
changeReturnParallelCallable.visit(ingredientsParallel.astFunctionDef)
|
|
345
|
+
|
|
346
|
+
ingredientsParallel.astFunctionDef = Z0Z_lameFindReplace(ingredientsParallel.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name) # type: ignore
|
|
347
|
+
|
|
348
|
+
# numba decorators =========================================
|
|
349
|
+
ingredientsParallel = decorateCallableWithNumba(ingredientsParallel)
|
|
350
|
+
ingredientsSequential = decorateCallableWithNumba(ingredientsSequential)
|
|
351
|
+
|
|
352
|
+
# Module-level transformations ===========================================================
|
|
353
|
+
ingredientsModuleNumbaUnified = IngredientsModule(ingredientsFunction=listAllIngredientsFunctions, imports=LedgerOfImports(numbaFlow.source_astModule))
|
|
354
|
+
|
|
355
|
+
write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.packageIdentifier)
|
|
356
|
+
|
|
357
|
+
if __name__ == '__main__':
|
|
358
|
+
makeNumbaFlow(theNumbaFlow)
|