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.
Files changed (30) hide show
  1. mapFolding/__init__.py +2 -2
  2. mapFolding/basecamp.py +11 -5
  3. mapFolding/filesystem.py +134 -109
  4. mapFolding/oeis.py +1 -1
  5. mapFolding/someAssemblyRequired/__init__.py +37 -18
  6. mapFolding/someAssemblyRequired/_theTypes.py +35 -0
  7. mapFolding/someAssemblyRequired/_tool_Make.py +92 -0
  8. mapFolding/someAssemblyRequired/_tool_Then.py +65 -0
  9. mapFolding/someAssemblyRequired/_toolboxAntecedents.py +326 -0
  10. mapFolding/someAssemblyRequired/_toolboxContainers.py +306 -0
  11. mapFolding/someAssemblyRequired/_toolboxPython.py +76 -0
  12. mapFolding/someAssemblyRequired/ingredientsNumba.py +17 -24
  13. mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +114 -169
  14. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +247 -0
  15. mapFolding/someAssemblyRequired/transformDataStructures.py +167 -100
  16. mapFolding/someAssemblyRequired/transformationTools.py +63 -685
  17. mapFolding/syntheticModules/numbaCount_doTheNeedful.py +36 -33
  18. mapFolding/theDao.py +13 -11
  19. mapFolding/theSSOT.py +69 -112
  20. {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/METADATA +2 -1
  21. mapfolding-0.8.4.dist-info/RECORD +49 -0
  22. {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/WHEEL +1 -1
  23. tests/conftest.py +34 -29
  24. tests/test_computations.py +40 -31
  25. tests/test_filesystem.py +3 -3
  26. mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +0 -413
  27. mapfolding-0.8.3.dist-info/RECORD +0 -43
  28. {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/entry_points.txt +0 -0
  29. {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/licenses/LICENSE +0 -0
  30. {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 ifThis, IngredientsFunction, Make
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
- parametersNumbaDEFAULT: Final[ParametersNumba] = {
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
- **parametersNumbaDEFAULT,
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
- **parametersNumbaDEFAULT,
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.addImportFromStr(datatypeModuleDecorator, datatype_attr)
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
- list_arg4signature_or_function.append(signatureElement)
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 = parametersNumbaDEFAULT
196
- listDecoratorKeywords: list[ast.keyword] = [Make.ast_keyword(parameterName, Make.astConstant(parameterValue)) for parameterName, parameterValue in parametersNumba.items()]
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.addImportFromStr(decoratorModule, decoratorCallable)
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.astCall(Make.astName(decoratorCallable), list_argsDecorator, listDecoratorKeywords)
203
- astDecorator: ast.Call = Make.astCall(Make.astName(decoratorCallable), list_astKeywords=listDecoratorKeywords) # type: ignore[no-redef]
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
- ast_Identifier,
26
- extractFunctionDef,
25
+ be,
27
26
  ifThis,
28
- IngredientsFunction,
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.theSSOT import raiseIfNoneGitHubIssueNumber3
44
+ from mapFolding.someAssemblyRequired.transformationTools import write_astModule
44
45
  import ast
45
46
 
46
- def astModuleToIngredientsFunction(astModule: ast.Module, identifierFunctionDef: ast_Identifier) -> IngredientsFunction:
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
- Think about a better organization of this function.
59
-
60
- Currently, transform `Callable` in order:
61
- sourceDispatcherCallable
62
- sourceInitializeCallable
63
- sourceParallelCallable
64
- sourceSequentialCallable
65
-
66
- But, it should be organized around each transformation. So, when the parameters of `sourceSequentialCallable`
67
- are transformed, for example, the statement in `sourceDispatcherCallable` that calls `sourceSequentialCallable` should be
68
- transformed at the same time: literally in the same function-or-NodeReplacer-or-subroutine. That would help
69
- avoid bugs.
70
-
71
- Furthermore, if the above example transformation requires unpacking the dataclass, for example, then the unpacking
72
- would be automatically triggered. I have no idea how that would happen, but the transformations are highly predictable,
73
- so using a programming language to construct if-this-then-that cascades shouldn't be a problem, you know?
74
-
75
- """
76
- ingredientsDispatcher: IngredientsFunction = astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceDispatcherCallable)
77
- ingredientsInitialize: IngredientsFunction = astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceInitializeCallable)
78
- ingredientsParallel: IngredientsFunction = astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceParallelCallable)
79
- ingredientsSequential: IngredientsFunction = astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceSequentialCallable)
80
-
81
- # Inline functions
82
- # NOTE Replacements statements are based on the identifiers in the _source_
83
- dictionaryReplacementStatements = makeDictionaryReplacementStatements(numbaFlow.source_astModule)
84
- ingredientsInitialize.astFunctionDef = inlineThisFunctionWithTheseValues(ingredientsInitialize.astFunctionDef, dictionaryReplacementStatements)
85
- ingredientsParallel.astFunctionDef = inlineThisFunctionWithTheseValues(ingredientsParallel.astFunctionDef, dictionaryReplacementStatements)
86
- ingredientsSequential.astFunctionDef = inlineThisFunctionWithTheseValues(ingredientsSequential.astFunctionDef, dictionaryReplacementStatements)
87
-
88
- # Assign CALLABLE identifiers per the recipe.
89
- # TODO Assign the other identifiers.
90
- listIngredientsFunctions = [ingredientsDispatcher, ingredientsInitialize, ingredientsParallel, ingredientsSequential]
91
- listFindReplace = [(numbaFlow.sourceDispatcherCallable, numbaFlow.dispatcherCallable),
92
- (numbaFlow.sourceInitializeCallable, numbaFlow.initializeCallable),
93
- (numbaFlow.sourceParallelCallable, numbaFlow.parallelCallable),
94
- (numbaFlow.sourceSequentialCallable, numbaFlow.sequentialCallable)]
95
- for ingredients in listIngredientsFunctions:
96
- ImaNode = ingredients.astFunctionDef
97
- for source_Identifier, Z0Z_Identifier in listFindReplace:
98
- findThis = ifThis.isCall_Identifier(source_Identifier)
99
- doThis = Then.replaceDOTfuncWith(Make.astName(Z0Z_Identifier))
100
- NodeReplacer(findThis, doThis).visit(ImaNode)
101
-
102
- ingredientsDispatcher.astFunctionDef.name = numbaFlow.dispatcherCallable
103
- ingredientsInitialize.astFunctionDef.name = numbaFlow.initializeCallable
104
- ingredientsParallel.astFunctionDef.name = numbaFlow.parallelCallable
105
- ingredientsSequential.astFunctionDef.name = numbaFlow.sequentialCallable
106
- # ===========================================================
107
- # Old organization
108
-
109
- # sourceParallelCallable
110
- shatteredDataclass = shatter_dataclassesDOTdataclass(numbaFlow.logicalPathModuleDataclass, numbaFlow.sourceDataclassIdentifier, numbaFlow.sourceDataclassInstanceTaskDistribution)
111
- ingredientsDispatcher.imports.update(shatteredDataclass.ledgerDataclassANDFragments)
112
-
113
- NodeReplacer(
114
- findThis = ifThis.isAssignAndValueIsCallNamespace_Identifier(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.sourceConcurrencyManagerIdentifier)
115
- , doThat = Then.insertThisAbove(shatteredDataclass.listAnnAssign4DataclassUnpack)
116
- ).visit(ingredientsDispatcher.astFunctionDef)
117
- NodeReplacer(
118
- findThis = ifThis.isCallNamespace_Identifier(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.sourceConcurrencyManagerIdentifier)
119
- , doThat = Then.replaceWith(Make.astCall(Make.astAttribute(Make.astName(numbaFlow.sourceConcurrencyManagerNamespace), numbaFlow.sourceConcurrencyManagerIdentifier)
120
- , listArguments=[Make.astName(numbaFlow.parallelCallable)] + shatteredDataclass.listNameDataclassFragments4Parameters))
121
- ).visit(ingredientsDispatcher.astFunctionDef)
122
-
123
- CapturedAssign: list[ast.AST] = []
124
- CapturedCall: list[ast.Call] = []
125
- findThis = ifThis.isCall
126
- doThat = [Then.appendTo(CapturedCall)]
127
- capture = NodeCollector(findThis, doThat)
128
-
129
- NodeCollector(
130
- findThis = ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(numbaFlow.sourceDataclassInstance))
131
- , doThat = [Then.appendTo(CapturedAssign)
132
- , lambda node: capture.visit(node)]
133
- ).visit(ingredientsDispatcher.astFunctionDef)
134
-
135
- newAssign = CapturedAssign[0]
136
- NodeReplacer(
137
- findThis = lambda node: ifThis.isSubscript(node) and ifThis.isAttribute(node.value) and ifThis.isCall(node.value.value)
138
- , doThat = Then.replaceWith(CapturedCall[0])
139
- ).visit(newAssign)
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
- ingredientsSequential.astFunctionDef.args = Make.astArgumentsSpecification(args=shatteredDataclass.list_ast_argAnnotated4ArgumentsSpecification)
183
- NodeReplacer(
184
- findThis = ifThis.isReturn
185
- , doThat = Then.replaceWith(Make.astReturn(shatteredDataclass.astTuple4AssignTargetsToFragments))
186
- ).visit(ingredientsSequential.astFunctionDef)
187
- NodeReplacer(
188
- findThis = ifThis.isReturn
189
- , doThat = Then.replaceWith(Make.astReturn(shatteredDataclass.astTuple4AssignTargetsToFragments))
190
- ).visit(ingredientsSequential.astFunctionDef)
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
- # End function-level transformations
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.packageName)
152
+ write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.packageIdentifier)
209
153
 
154
+ theNumbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()
210
155
  if __name__ == '__main__':
211
- makeNumbaFlow()
156
+ makeNumbaFlow(theNumbaFlow)