mapFolding 0.10.0__py3-none-any.whl → 0.11.0__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 (26) hide show
  1. mapFolding/__init__.py +29 -27
  2. mapFolding/someAssemblyRequired/Z0Z_makeSomeModules.py +4 -6
  3. mapFolding/someAssemblyRequired/__init__.py +15 -24
  4. mapFolding/someAssemblyRequired/_toolIfThis.py +4 -144
  5. mapFolding/someAssemblyRequired/_toolboxContainers.py +12 -284
  6. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +6 -6
  7. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +5 -5
  8. mapFolding/someAssemblyRequired/transformationTools.py +5 -178
  9. {mapfolding-0.10.0.dist-info → mapfolding-0.11.0.dist-info}/METADATA +2 -1
  10. {mapfolding-0.10.0.dist-info → mapfolding-0.11.0.dist-info}/RECORD +14 -26
  11. {mapfolding-0.10.0.dist-info → mapfolding-0.11.0.dist-info}/WHEEL +1 -1
  12. mapFolding/someAssemblyRequired/_astTypes.py +0 -117
  13. mapFolding/someAssemblyRequired/_theTypes.py +0 -34
  14. mapFolding/someAssemblyRequired/_toolBe.py +0 -524
  15. mapFolding/someAssemblyRequired/_toolDOT.py +0 -493
  16. mapFolding/someAssemblyRequired/_toolGrab.py +0 -653
  17. mapFolding/someAssemblyRequired/_toolMake.py +0 -339
  18. mapFolding/someAssemblyRequired/_toolThen.py +0 -63
  19. mapFolding/someAssemblyRequired/_toolboxAST.py +0 -57
  20. mapFolding/someAssemblyRequired/_toolboxPython.py +0 -188
  21. mapFolding/toolFactory/astFactory.py +0 -493
  22. mapFolding/toolFactory/astFactory_annex.py +0 -63
  23. mapFolding/toolFactory/astFactory_docstrings.py +0 -63
  24. {mapfolding-0.10.0.dist-info → mapfolding-0.11.0.dist-info}/entry_points.txt +0 -0
  25. {mapfolding-0.10.0.dist-info → mapfolding-0.11.0.dist-info}/licenses/LICENSE +0 -0
  26. {mapfolding-0.10.0.dist-info → mapfolding-0.11.0.dist-info}/top_level.txt +0 -0
@@ -18,294 +18,16 @@ The containers work in conjunction with transformation tools that manipulate the
18
18
  specific optimizations and transformations.
19
19
  """
20
20
 
21
- from collections import defaultdict
22
- from collections.abc import Callable, Sequence
21
+ from astToolkit import IngredientsFunction as IngredientsFunction, IngredientsModule as IngredientsModule, LedgerOfImports as LedgerOfImports
22
+ from collections.abc import Callable
23
23
  from copy import deepcopy
24
- from typing import Any
25
24
  from mapFolding.someAssemblyRequired import ast_Identifier, DOT, IfThis, Make, NodeTourist, parseLogicalPath2astModule, str_nameDOTname, Then
26
25
  from mapFolding.theSSOT import raiseIfNoneGitHubIssueNumber3, The
27
26
  from pathlib import Path, PurePosixPath
28
- from Z0Z_tools import updateExtendPolishDictionaryLists
27
+ from typing import Any, cast
29
28
  import ast
30
29
  import dataclasses
31
30
 
32
- class LedgerOfImports:
33
- """
34
- Track and manage import statements for programmatically generated code.
35
-
36
- LedgerOfImports acts as a registry for import statements, maintaining a clean separation between the logical
37
- structure of imports and their textual representation. It enables:
38
-
39
- 1. Tracking regular imports and import-from statements.
40
- 2. Adding imports programmatically during code transformation.
41
- 3. Merging imports from multiple sources.
42
- 4. Removing unnecessary or conflicting imports.
43
- 5. Generating optimized AST import nodes for the final code.
44
-
45
- This class forms the foundation of dependency management in generated code, ensuring that all required libraries are
46
- available without duplication or conflict.
47
- """
48
- # TODO When resolving the ledger of imports, remove self-referential imports
49
-
50
- def __init__(self, startWith: ast.AST | None = None, type_ignores: list[ast.TypeIgnore] | None = None) -> None:
51
- self.dictionaryImportFrom: dict[str_nameDOTname, list[tuple[ast_Identifier, ast_Identifier | None]]] = defaultdict(list)
52
- self.listImport: list[str_nameDOTname] = []
53
- self.type_ignores = [] if type_ignores is None else list(type_ignores)
54
- if startWith:
55
- self.walkThis(startWith)
56
-
57
- def addAst(self, astImport____: ast.Import | ast.ImportFrom, type_ignores: list[ast.TypeIgnore] | None = None) -> None:
58
- match astImport____:
59
- case ast.Import():
60
- for alias in astImport____.names:
61
- self.listImport.append(alias.name)
62
- case ast.ImportFrom():
63
- # TODO fix the mess created by `None` means '.'. I need a `str_nameDOTname` to replace '.'
64
- if astImport____.module is None:
65
- astImport____.module = '.'
66
- for alias in astImport____.names:
67
- self.dictionaryImportFrom[astImport____.module].append((alias.name, alias.asname))
68
- case _:
69
- raise ValueError(f"I received {type(astImport____) = }, but I can only accept {ast.Import} and {ast.ImportFrom}.")
70
- if type_ignores:
71
- self.type_ignores.extend(type_ignores)
72
-
73
- def addImport_asStr(self, moduleWithLogicalPath: str_nameDOTname, type_ignores: list[ast.TypeIgnore] | None = None) -> None:
74
- self.listImport.append(moduleWithLogicalPath)
75
- if type_ignores:
76
- self.type_ignores.extend(type_ignores)
77
-
78
- def addImportFrom_asStr(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier, asname: ast_Identifier | None = None, type_ignores: list[ast.TypeIgnore] | None = None) -> None:
79
- self.dictionaryImportFrom[moduleWithLogicalPath].append((name, asname))
80
- if type_ignores:
81
- self.type_ignores.extend(type_ignores)
82
-
83
- def removeImportFromModule(self, moduleWithLogicalPath: str_nameDOTname) -> None:
84
- """Remove all imports from a specific module."""
85
- self.removeImportFrom(moduleWithLogicalPath, None, None)
86
-
87
- def removeImportFrom(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier | None, asname: ast_Identifier | None = None) -> None:
88
- """
89
- name, asname Action
90
- None, None : remove all matches for the module
91
- ast_Identifier, ast_Identifier : remove exact matches
92
- ast_Identifier, None : remove exact matches
93
- None, ast_Identifier : remove all matches for asname and if entry_asname is None remove name == ast_Identifier
94
- """
95
- if moduleWithLogicalPath in self.dictionaryImportFrom:
96
- if name is None and asname is None:
97
- # Remove all entries for the module
98
- self.dictionaryImportFrom.pop(moduleWithLogicalPath)
99
- else:
100
- if name is None:
101
- self.dictionaryImportFrom[moduleWithLogicalPath] = [(entry_name, entry_asname) for entry_name, entry_asname in self.dictionaryImportFrom[moduleWithLogicalPath]
102
- if not (entry_asname == asname) and not (entry_asname is None and entry_name == asname)]
103
- else:
104
- self.dictionaryImportFrom[moduleWithLogicalPath] = [(entry_name, entry_asname) for entry_name, entry_asname in self.dictionaryImportFrom[moduleWithLogicalPath]
105
- if not (entry_name == name and entry_asname == asname)]
106
- if not self.dictionaryImportFrom[moduleWithLogicalPath]:
107
- self.dictionaryImportFrom.pop(moduleWithLogicalPath)
108
-
109
- def exportListModuleIdentifiers(self) -> list[ast_Identifier]:
110
- listModuleIdentifiers: list[ast_Identifier] = list(self.dictionaryImportFrom.keys())
111
- listModuleIdentifiers.extend(self.listImport)
112
- return sorted(set(listModuleIdentifiers))
113
-
114
- def makeList_ast(self) -> list[ast.ImportFrom | ast.Import]:
115
- listImportFrom: list[ast.ImportFrom] = []
116
- for moduleWithLogicalPath, listOfNameTuples in sorted(self.dictionaryImportFrom.items()):
117
- listOfNameTuples = sorted(list(set(listOfNameTuples)), key=lambda nameTuple: nameTuple[0])
118
- list_alias: list[ast.alias] = []
119
- for name, asname in listOfNameTuples:
120
- list_alias.append(Make.alias(name, asname))
121
- if list_alias:
122
- listImportFrom.append(Make.ImportFrom(moduleWithLogicalPath, list_alias))
123
- list_astImport: list[ast.Import] = [Make.Import(moduleWithLogicalPath) for moduleWithLogicalPath in sorted(set(self.listImport))]
124
- return listImportFrom + list_astImport
125
-
126
- def update(self, *fromLedger: 'LedgerOfImports') -> None:
127
- """Update this ledger with imports from one or more other ledgers.
128
- Parameters:
129
- *fromLedger: One or more other `LedgerOfImports` objects from which to merge.
130
- """
131
- updatedDictionary = updateExtendPolishDictionaryLists(self.dictionaryImportFrom, *(ledger.dictionaryImportFrom for ledger in fromLedger), destroyDuplicates=True, reorderLists=True)
132
- self.dictionaryImportFrom = defaultdict(list, updatedDictionary)
133
- for ledger in fromLedger:
134
- self.listImport.extend(ledger.listImport)
135
- self.type_ignores.extend(ledger.type_ignores)
136
-
137
- def walkThis(self, walkThis: ast.AST, type_ignores: list[ast.TypeIgnore] | None = None) -> None:
138
- for nodeBuffalo in ast.walk(walkThis):
139
- if isinstance(nodeBuffalo, (ast.Import, ast.ImportFrom)):
140
- self.addAst(nodeBuffalo)
141
- if type_ignores:
142
- self.type_ignores.extend(type_ignores)
143
-
144
- # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
145
- @dataclasses.dataclass
146
- class IngredientsFunction:
147
- """
148
- Package a function definition with its import dependencies for code generation.
149
-
150
- IngredientsFunction encapsulates an AST function definition along with all the imports required for that function to
151
- operate correctly. This creates a modular, portable unit that can be:
152
-
153
- 1. Transformed independently (e.g., by applying Numba decorators).
154
- 2. Transplanted between modules while maintaining dependencies.
155
- 3. Combined with other functions to form complete modules.
156
- 4. Analyzed for optimization opportunities.
157
-
158
- This class forms the primary unit of function manipulation in the code generation system, enabling targeted
159
- transformations while preserving function dependencies.
160
-
161
- Parameters:
162
- astFunctionDef: The AST representation of the function definition
163
- imports: Import statements needed by the function
164
- type_ignores: Type ignore comments associated with the function
165
- """
166
- astFunctionDef: ast.FunctionDef
167
- imports: LedgerOfImports = dataclasses.field(default_factory=LedgerOfImports)
168
- type_ignores: list[ast.TypeIgnore] = dataclasses.field(default_factory=list)
169
-
170
- # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
171
- @dataclasses.dataclass
172
- class IngredientsModule:
173
- """
174
- Assemble a complete Python module from its constituent AST components.
175
-
176
- IngredientsModule provides a structured container for all elements needed to generate a complete Python module,
177
- including:
178
-
179
- 1. Import statements aggregated from all module components.
180
- 2. Prologue code that runs before function definitions.
181
- 3. Function definitions with their dependencies.
182
- 4. Epilogue code that runs after function definitions.
183
- 5. Entry point code executed when the module runs as a script.
184
- 6. Type ignores and other annotations.
185
-
186
- This class enables programmatic assembly of Python modules with a clear separation between different structural
187
- elements, while maintaining the proper ordering and relationships between components.
188
-
189
- The modular design allows transformations to be applied to specific parts of a module while preserving the overall
190
- structure.
191
-
192
- Parameters:
193
- ingredientsFunction (None): One or more `IngredientsFunction` that will appended to `listIngredientsFunctions`.
194
- """
195
- ingredientsFunction: dataclasses.InitVar[Sequence[IngredientsFunction] | IngredientsFunction | None] = None
196
-
197
- # init var with an existing module? method to deconstruct an existing module?
198
-
199
- # `body` attribute of `ast.Module`
200
- """NOTE
201
- - Bare statements in `prologue` and `epilogue` are not 'protected' by `if __name__ == '__main__':` so they will be executed merely by loading the module.
202
- - The dataclass has methods for modifying `prologue`, `epilogue`, and `launcher`.
203
- - However, `prologue`, `epilogue`, and `launcher` are `ast.Module` (as opposed to `list[ast.stmt]`), so that you may use tools such as `ast.walk` and `ast.NodeVisitor` on the fields.
204
- """
205
- imports: LedgerOfImports = dataclasses.field(default_factory=LedgerOfImports)
206
- """Modify this field using the methods in `LedgerOfImports`."""
207
- prologue: ast.Module = Make.Module([],[])
208
- """Statements after the imports and before the functions in listIngredientsFunctions."""
209
- listIngredientsFunctions: list[IngredientsFunction] = dataclasses.field(default_factory=list)
210
- epilogue: ast.Module = Make.Module([],[])
211
- """Statements after the functions in listIngredientsFunctions and before `launcher`."""
212
- launcher: ast.Module = Make.Module([],[])
213
- """`if __name__ == '__main__':`"""
214
-
215
- # `ast.TypeIgnore` statements to supplement those in other fields; `type_ignores` is a parameter for `ast.Module` constructor
216
- supplemental_type_ignores: list[ast.TypeIgnore] = dataclasses.field(default_factory=list)
217
-
218
- def __post_init__(self, ingredientsFunction: Sequence[IngredientsFunction] | IngredientsFunction | None = None) -> None:
219
- if ingredientsFunction is not None:
220
- if isinstance(ingredientsFunction, IngredientsFunction):
221
- self.appendIngredientsFunction(ingredientsFunction)
222
- else:
223
- self.appendIngredientsFunction(*ingredientsFunction)
224
-
225
- def _append_astModule(self, self_astModule: ast.Module, astModule: ast.Module | None, statement: Sequence[ast.stmt] | ast.stmt | None, type_ignores: list[ast.TypeIgnore] | None) -> None:
226
- """Append one or more statements to `prologue`."""
227
- list_body: list[ast.stmt] = []
228
- listTypeIgnore: list[ast.TypeIgnore] = []
229
- if astModule is not None and isinstance(astModule, ast.Module): # type: ignore
230
- list_body.extend(astModule.body)
231
- listTypeIgnore.extend(astModule.type_ignores)
232
- if type_ignores is not None:
233
- listTypeIgnore.extend(type_ignores)
234
- if statement is not None:
235
- if isinstance(statement, Sequence):
236
- list_body.extend(statement)
237
- else:
238
- list_body.append(statement)
239
- self_astModule.body.extend(list_body)
240
- self_astModule.type_ignores.extend(listTypeIgnore)
241
- ast.fix_missing_locations(self_astModule)
242
-
243
- def appendPrologue(self, astModule: ast.Module | None = None, statement: Sequence[ast.stmt] | ast.stmt | None = None, type_ignores: list[ast.TypeIgnore] | None = None) -> None:
244
- """Append one or more statements to `prologue`."""
245
- self._append_astModule(self.prologue, astModule, statement, type_ignores)
246
-
247
- def appendEpilogue(self, astModule: ast.Module | None = None, statement: Sequence[ast.stmt] | ast.stmt | None = None, type_ignores: list[ast.TypeIgnore] | None = None) -> None:
248
- """Append one or more statements to `epilogue`."""
249
- self._append_astModule(self.epilogue, astModule, statement, type_ignores)
250
-
251
- def appendLauncher(self, astModule: ast.Module | None = None, statement: Sequence[ast.stmt] | ast.stmt | None = None, type_ignores: list[ast.TypeIgnore] | None = None) -> None:
252
- """Append one or more statements to `launcher`."""
253
- self._append_astModule(self.launcher, astModule, statement, type_ignores)
254
-
255
- def appendIngredientsFunction(self, *ingredientsFunction: IngredientsFunction) -> None:
256
- """Append one or more `IngredientsFunction`."""
257
- for allegedIngredientsFunction in ingredientsFunction:
258
- self.listIngredientsFunctions.append(allegedIngredientsFunction)
259
-
260
- def removeImportFromModule(self, moduleWithLogicalPath: str_nameDOTname) -> None:
261
- self.removeImportFrom(moduleWithLogicalPath, None, None)
262
- """Remove all imports from a specific module."""
263
-
264
- def removeImportFrom(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier | None, asname: ast_Identifier | None = None) -> None:
265
- """
266
- This method modifies all `LedgerOfImports` in this `IngredientsModule` and all `IngredientsFunction` in `listIngredientsFunctions`.
267
- It is not a "blacklist", so the `import from` could be added after this modification.
268
- """
269
- self.imports.removeImportFrom(moduleWithLogicalPath, name, asname)
270
- for ingredientsFunction in self.listIngredientsFunctions:
271
- ingredientsFunction.imports.removeImportFrom(moduleWithLogicalPath, name, asname)
272
-
273
- def _consolidatedLedger(self) -> LedgerOfImports:
274
- """Consolidate all ledgers of imports."""
275
- sherpaLedger = LedgerOfImports()
276
- listLedgers: list[LedgerOfImports] = [self.imports]
277
- for ingredientsFunction in self.listIngredientsFunctions:
278
- listLedgers.append(ingredientsFunction.imports)
279
- sherpaLedger.update(*listLedgers)
280
- return sherpaLedger
281
-
282
- @property
283
- def list_astImportImportFrom(self) -> list[ast.Import | ast.ImportFrom]:
284
- return self._consolidatedLedger().makeList_ast()
285
-
286
- @property
287
- def body(self) -> list[ast.stmt]:
288
- list_stmt: list[ast.stmt] = []
289
- list_stmt.extend(self.list_astImportImportFrom)
290
- list_stmt.extend(self.prologue.body)
291
- for ingredientsFunction in self.listIngredientsFunctions:
292
- list_stmt.append(ingredientsFunction.astFunctionDef)
293
- list_stmt.extend(self.epilogue.body)
294
- list_stmt.extend(self.launcher.body)
295
- # TODO `launcher`, if it exists, must start with `if __name__ == '__main__':` and be indented
296
- return list_stmt
297
-
298
- @property
299
- def type_ignores(self) -> list[ast.TypeIgnore]:
300
- listTypeIgnore: list[ast.TypeIgnore] = self.supplemental_type_ignores
301
- listTypeIgnore.extend(self._consolidatedLedger().type_ignores)
302
- listTypeIgnore.extend(self.prologue.type_ignores)
303
- for ingredientsFunction in self.listIngredientsFunctions:
304
- listTypeIgnore.extend(ingredientsFunction.type_ignores)
305
- listTypeIgnore.extend(self.epilogue.type_ignores)
306
- listTypeIgnore.extend(self.launcher.type_ignores)
307
- return listTypeIgnore
308
-
309
31
  # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
310
32
  @dataclasses.dataclass
311
33
  class RecipeSynthesizeFlow:
@@ -531,7 +253,13 @@ class DeReConstructField2ast:
531
253
  self.ast_keyword_field__field = Make.keyword(self.name, self.astName)
532
254
  self.ast_nameDOTname = Make.Attribute(Make.Name(dataclassesDOTdataclassInstance_Identifier), self.name)
533
255
 
534
- sherpa = NodeTourist(IfThis.isAnnAssign_targetIs(IfThis.isName_Identifier(self.name)), Then.extractIt(DOT.annotation)).captureLastMatch(dataclassClassDef)
256
+ findThis = IfThis.isAnnAssign_targetIs(IfThis.isName_Identifier(self.name))
257
+
258
+ sherpa = NodeTourist(
259
+ findThis=findThis
260
+ , doThat=Then.extractIt(DOT.annotation)
261
+ ).captureLastMatch(dataclassClassDef)
262
+
535
263
  if sherpa is None: raise raiseIfNoneGitHubIssueNumber3
536
264
  else: self.astAnnotation = sherpa
537
265
 
@@ -544,7 +272,7 @@ class DeReConstructField2ast:
544
272
  self.ledger.addImportFrom_asStr(moduleWithLogicalPath, annotationType)
545
273
  self.ledger.addImportFrom_asStr(moduleWithLogicalPath, 'dtype')
546
274
  axesSubscript = Make.Subscript(Make.Name('tuple'), Make.Name('uint8'))
547
- dtype_asnameName: ast.Name = self.astAnnotation # type: ignore
275
+ dtype_asnameName: ast.Name = cast(ast.Name, self.astAnnotation)
548
276
  if dtype_asnameName.id == 'Array3D':
549
277
  axesSubscript = Make.Subscript(Make.Name('tuple'), Make.Tuple([Make.Name('uint8'), Make.Name('uint8'), Make.Name('uint8')]))
550
278
  ast_expr = Make.Subscript(Make.Name(annotationType), Make.Tuple([axesSubscript, Make.Subscript(Make.Name('dtype'), dtype_asnameName)]))
@@ -561,7 +289,7 @@ class DeReConstructField2ast:
561
289
  elif isinstance(self.astAnnotation, ast.Subscript):
562
290
  elementConstructor: ast_Identifier = self.metadata['elementConstructor']
563
291
  self.ledger.addImportFrom_asStr(dataclassesDOTdataclassLogicalPathModule, elementConstructor)
564
- takeTheTuple: ast.Tuple = deepcopy(self.astAnnotation.slice) # type: ignore
292
+ takeTheTuple = deepcopy(self.astAnnotation.slice)
565
293
  self.astAnnAssignConstructor = Make.AnnAssign(self.astName, self.astAnnotation, takeTheTuple)
566
294
  self.Z0Z_hack = (self.astAnnAssignConstructor, elementConstructor)
567
295
  if isinstance(self.astAnnotation, ast.Name):
@@ -15,7 +15,7 @@ from mapFolding.someAssemblyRequired import (
15
15
  )
16
16
  from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2Numba
17
17
  from mapFolding.someAssemblyRequired.toolboxNumba import parametersNumbaLight, SpicesJobNumba, decorateCallableWithNumba
18
- from mapFolding.someAssemblyRequired.transformationTools import dictionaryEstimates, write_astModule, makeInitializedComputationState
18
+ from mapFolding.someAssemblyRequired.transformationTools import write_astModule
19
19
  from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
20
20
  from mapFolding.dataBaskets import MapFoldingState
21
21
  from pathlib import PurePosixPath
@@ -77,7 +77,7 @@ if __name__ == '__main__':
77
77
  ast_argNumbaProgress = ast.arg(arg=spices.numbaProgressBarIdentifier, annotation=ast.Name(id=numba_progressPythonClass, ctx=ast.Load()))
78
78
  ingredientsFunction.astFunctionDef.args.args.append(ast_argNumbaProgress)
79
79
 
80
- findThis = IfThis.isAugAssign_targetIs(IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
80
+ findThis = IfThis.isAugAssignAndTargetIs(IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
81
81
  doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(spices.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
82
82
  countWithProgressBar = NodeChanger(findThis, doThat)
83
83
  countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
@@ -131,19 +131,19 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
131
131
  ImaAnnAssign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[ast_arg.arg]
132
132
  match elementConstructor:
133
133
  case 'scalar':
134
- ImaAnnAssign.value.args[0].value = int(job.state.__dict__[ast_arg.arg]) # type: ignore
134
+ cast(ast.Constant, cast(ast.Call, ImaAnnAssign.value).args[0]).value = int(job.state.__dict__[ast_arg.arg])
135
135
  case 'array':
136
136
  dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], True)
137
137
  dataAs_astExpr: ast.expr = cast(ast.Expr, ast.parse(dataAsStrRLE).body[0]).value
138
- ImaAnnAssign.value.args = [dataAs_astExpr] # type: ignore
138
+ cast(ast.Call, ImaAnnAssign.value).args = [dataAs_astExpr]
139
139
  case _:
140
140
  list_exprDOTannotation: list[ast.expr] = []
141
141
  list_exprDOTvalue: list[ast.expr] = []
142
142
  for dimension in job.state.mapShape:
143
143
  list_exprDOTannotation.append(Make.Name(elementConstructor))
144
144
  list_exprDOTvalue.append(Make.Call(Make.Name(elementConstructor), [Make.Constant(dimension)]))
145
- ImaAnnAssign.annotation.slice.elts = list_exprDOTannotation # type: ignore
146
- ImaAnnAssign.value.elts = list_exprDOTvalue # type: ignore
145
+ cast(ast.Tuple, cast(ast.Subscript, cast(ast.AnnAssign, ImaAnnAssign).annotation).slice).elts = list_exprDOTannotation
146
+ cast(ast.Tuple, ImaAnnAssign.value).elts = list_exprDOTvalue
147
147
 
148
148
  ingredientsFunction.astFunctionDef.body.insert(0, ImaAnnAssign)
149
149
 
@@ -95,7 +95,7 @@ if __name__ == '__main__':
95
95
  ast_argNumbaProgress = ast.arg(arg=spices.numbaProgressBarIdentifier, annotation=ast.Name(id=numba_progressPythonClass, ctx=ast.Load()))
96
96
  ingredientsFunction.astFunctionDef.args.args.append(ast_argNumbaProgress)
97
97
 
98
- findThis = IfThis.isAugAssign_targetIs(IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
98
+ findThis = IfThis.isAugAssignAndTargetIs(IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
99
99
  doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(spices.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
100
100
  countWithProgressBar = NodeChanger(findThis, doThat)
101
101
  countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
@@ -149,19 +149,19 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
149
149
  ImaAnnAssign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[ast_arg.arg]
150
150
  match elementConstructor:
151
151
  case 'scalar':
152
- ImaAnnAssign.value.args[0].value = int(job.state.__dict__[ast_arg.arg]) # type: ignore
152
+ cast(ast.Constant, cast(ast.Call, ImaAnnAssign.value).args[0]).value = int(job.state.__dict__[ast_arg.arg])
153
153
  case 'array':
154
154
  dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], True)
155
155
  dataAs_astExpr: ast.expr = cast(ast.Expr, ast.parse(dataAsStrRLE).body[0]).value
156
- ImaAnnAssign.value.args = [dataAs_astExpr] # type: ignore
156
+ cast(ast.Call, ImaAnnAssign.value).args = [dataAs_astExpr]
157
157
  case _:
158
158
  list_exprDOTannotation: list[ast.expr] = []
159
159
  list_exprDOTvalue: list[ast.expr] = []
160
160
  for dimension in job.state.mapShape:
161
161
  list_exprDOTannotation.append(Make.Name(elementConstructor))
162
162
  list_exprDOTvalue.append(Make.Call(Make.Name(elementConstructor), [Make.Constant(dimension)]))
163
- ImaAnnAssign.annotation.slice.elts = list_exprDOTannotation # type: ignore
164
- ImaAnnAssign.value.elts = list_exprDOTvalue # type: ignore
163
+ cast(ast.Tuple, cast(ast.Subscript, cast(ast.AnnAssign, ImaAnnAssign).annotation).slice).elts = list_exprDOTannotation
164
+ cast(ast.Tuple, ImaAnnAssign.value).elts = list_exprDOTvalue
165
165
 
166
166
  ingredientsFunction.astFunctionDef.body.insert(0, ImaAnnAssign)
167
167
 
@@ -18,7 +18,7 @@ readable, maintainable implementations to highly optimized versions while preser
18
18
  logical structure and correctness.
19
19
  """
20
20
 
21
- from autoflake import fix_code as autoflake_fix_code
21
+ from astToolkit.transformationTools import ( inlineFunctionDef as inlineFunctionDef, removeUnusedParameters as removeUnusedParameters, write_astModule as write_astModule, )
22
22
  from collections.abc import Callable, Mapping
23
23
  from copy import deepcopy
24
24
  from mapFolding.beDRY import outfitCountFolds
@@ -27,7 +27,6 @@ from mapFolding.someAssemblyRequired import (
27
27
  astModuleToIngredientsFunction,
28
28
  Be,
29
29
  DeReConstructField2ast,
30
- DOT,
31
30
  extractClassDef,
32
31
  Grab,
33
32
  IfThis,
@@ -45,102 +44,14 @@ from mapFolding.someAssemblyRequired import (
45
44
  Then,
46
45
  个,
47
46
  )
48
- from mapFolding.theSSOT import ComputationState, raiseIfNoneGitHubIssueNumber3, The
49
- from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal, writeStringToHere
47
+ from mapFolding.theSSOT import ComputationState, The
48
+ from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal
50
49
  from os import PathLike
51
50
  from pathlib import Path, PurePath
52
51
  from typing import Any, Literal, overload
53
52
  import ast
54
53
  import dataclasses
55
54
  import pickle
56
- import python_minifier
57
-
58
- def makeDictionaryFunctionDef(module: ast.Module) -> dict[ast_Identifier, ast.FunctionDef]:
59
- """
60
- Create a dictionary mapping function names to their AST definitions.
61
-
62
- This function creates a dictionary that maps function names to their AST function
63
- definition nodes for all functions defined in the given module.
64
-
65
- Parameters:
66
- module: The AST module to extract function definitions from.
67
-
68
- Returns:
69
- A dictionary mapping function identifiers to their AST function definition nodes.
70
- """
71
- dictionaryIdentifier2FunctionDef: dict[ast_Identifier, ast.FunctionDef] = {}
72
- NodeTourist(Be.FunctionDef, Then.updateKeyValueIn(DOT.name, Then.extractIt, dictionaryIdentifier2FunctionDef)).visit(module)
73
- return dictionaryIdentifier2FunctionDef
74
-
75
- def inlineFunctionDef(identifierToInline: ast_Identifier, module: ast.Module) -> ast.FunctionDef:
76
- """
77
- Inline function calls within a function definition to create a self-contained function.
78
-
79
- This function takes a function identifier and a module, finds the function definition,
80
- and then recursively inlines all function calls within that function with their
81
- implementation bodies. This produces a fully inlined function that doesn't depend
82
- on other function definitions from the module.
83
-
84
- Parameters:
85
- identifierToInline: The name of the function to inline.
86
- module: The AST module containing the function and its dependencies.
87
-
88
- Returns:
89
- A modified function definition with all function calls inlined.
90
-
91
- Raises:
92
- ValueError: If the function to inline is not found in the module.
93
- """
94
- dictionaryFunctionDef: dict[ast_Identifier, ast.FunctionDef] = makeDictionaryFunctionDef(module)
95
- try:
96
- FunctionDefToInline = dictionaryFunctionDef[identifierToInline]
97
- except KeyError as ERRORmessage:
98
- raise ValueError(f"FunctionDefToInline not found in dictionaryIdentifier2FunctionDef: {identifierToInline = }") from ERRORmessage
99
-
100
- listIdentifiersCalledFunctions: list[ast_Identifier] = []
101
- findIdentifiersToInline = NodeTourist(findThis = IfThis.isCallToName, doThat = Grab.funcDOTidAttribute(Then.appendTo(listIdentifiersCalledFunctions)))
102
- findIdentifiersToInline.visit(FunctionDefToInline)
103
-
104
- dictionary4Inlining: dict[ast_Identifier, ast.FunctionDef] = {}
105
- for identifier in sorted(set(listIdentifiersCalledFunctions).intersection(dictionaryFunctionDef.keys())):
106
- if NodeTourist(IfThis.matchesMeButNotAnyDescendant(IfThis.isCall_Identifier(identifier)), Then.extractIt).captureLastMatch(module) is not None:
107
- dictionary4Inlining[identifier] = dictionaryFunctionDef[identifier]
108
-
109
- keepGoing = True
110
- while keepGoing:
111
- keepGoing = False
112
- listIdentifiersCalledFunctions.clear()
113
- findIdentifiersToInline.visit(Make.Module(list(dictionary4Inlining.values())))
114
-
115
- listIdentifiersCalledFunctions = sorted((set(listIdentifiersCalledFunctions).difference(dictionary4Inlining.keys())).intersection(dictionaryFunctionDef.keys()))
116
- if len(listIdentifiersCalledFunctions) > 0:
117
- keepGoing = True
118
- for identifier in listIdentifiersCalledFunctions:
119
- if NodeTourist(IfThis.matchesMeButNotAnyDescendant(IfThis.isCall_Identifier(identifier)), Then.extractIt).captureLastMatch(module) is not None:
120
- FunctionDefTarget = dictionaryFunctionDef[identifier]
121
- if len(FunctionDefTarget.body) == 1:
122
- replacement = NodeTourist(Be.Return, Then.extractIt(DOT.value)).captureLastMatch(FunctionDefTarget)
123
-
124
- findThis = IfThis.isCall_Identifier(identifier)
125
- doThat = Then.replaceWith(replacement)
126
- inliner = NodeChanger(findThis, doThat)
127
- for astFunctionDef in dictionary4Inlining.values():
128
- inliner.visit(astFunctionDef)
129
- else:
130
- inliner = NodeChanger(IfThis.isAssignAndValueIs(IfThis.isCall_Identifier(identifier)),Then.replaceWith(FunctionDefTarget.body[0:-1]))
131
- for astFunctionDef in dictionary4Inlining.values():
132
- inliner.visit(astFunctionDef)
133
-
134
- for identifier, FunctionDefTarget in dictionary4Inlining.items():
135
- if len(FunctionDefTarget.body) == 1:
136
- replacement = NodeTourist(Be.Return, Then.extractIt(DOT.value)).captureLastMatch(FunctionDefTarget)
137
- inliner = NodeChanger(IfThis.isCall_Identifier(identifier), Then.replaceWith(replacement))
138
- inliner.visit(FunctionDefToInline)
139
- else:
140
- inliner = NodeChanger(IfThis.isAssignAndValueIs(IfThis.isCall_Identifier(identifier)),Then.replaceWith(FunctionDefTarget.body[0:-1]))
141
- inliner.visit(FunctionDefToInline)
142
- ast.fix_missing_locations(FunctionDefToInline)
143
- return FunctionDefToInline
144
55
 
145
56
  @overload
146
57
  def makeInitializedComputationState(mapShape: tuple[int, ...], writeJob: Literal[True], *, pathFilename: PathLike[str] | PurePath | None = None, **keywordArguments: Any) -> Path: ...
@@ -248,91 +159,7 @@ def shatter_dataclassesDOTdataclass(logicalPathModule: str_nameDOTname, dataclas
248
159
 
249
160
  return shatteredDataclass
250
161
 
251
- def write_astModule(ingredients: IngredientsModule, pathFilename: PathLike[Any] | PurePath, packageName: ast_Identifier | None = None) -> None:
252
- """
253
- Convert an IngredientsModule to Python source code and write it to a file.
254
-
255
- This function renders an IngredientsModule into executable Python code,
256
- applies code quality improvements like import organization via autoflake,
257
- and writes the result to the specified file path.
258
-
259
- The function performs several key steps:
260
- 1. Converts the AST module structure to a valid Python AST
261
- 2. Fixes location attributes in the AST for proper formatting
262
- 3. Converts the AST to Python source code
263
- 4. Optimizes imports using autoflake
264
- 5. Writes the final source code to the specified file location
265
-
266
- This is typically the final step in the code generation assembly line,
267
- producing optimized Python modules ready for execution.
268
-
269
- Parameters:
270
- ingredients: The IngredientsModule containing the module definition.
271
- pathFilename: The file path where the module should be written.
272
- packageName: Optional package name to preserve in import optimization.
273
-
274
- Raises:
275
- raiseIfNoneGitHubIssueNumber3: If the generated source code is empty.
276
- """
277
- astModule = Make.Module(ingredients.body, ingredients.type_ignores)
278
- ast.fix_missing_locations(astModule)
279
- pythonSource: str = ast.unparse(astModule)
280
- if not pythonSource: raise raiseIfNoneGitHubIssueNumber3
281
- autoflake_additional_imports: list[str] = ingredients.imports.exportListModuleIdentifiers()
282
- if packageName:
283
- autoflake_additional_imports.append(packageName)
284
- pythonSource = autoflake_fix_code(pythonSource, autoflake_additional_imports, expand_star_imports=False, remove_all_unused_imports=True, remove_duplicate_keys = False, remove_unused_variables = False)
285
- # pythonSource = python_minifier.minify(pythonSource, remove_annotations=False, hoist_literals=False)
286
- writeStringToHere(pythonSource, pathFilename)
287
-
288
162
  # END of acceptable classes and functions ======================================================
289
- def removeUnusedParameters(ingredientsFunction: IngredientsFunction) -> IngredientsFunction:
290
- """
291
- Removes unused parameters from a function's AST definition, return statement, and annotation.
292
-
293
- This function analyzes the Abstract Syntax Tree (AST) of a given function and removes
294
- any parameters that are not referenced within the function body. It updates the
295
- function signature, the return statement (if it's a tuple containing unused variables),
296
- and the return type annotation accordingly.
297
-
298
- Parameters
299
- ----------
300
- ingredientsFunction : IngredientsFunction
301
- An object containing the AST representation of a function to be processed.
302
-
303
- Returns
304
- -------
305
- IngredientsFunction
306
- The modified IngredientsFunction object with unused parameters and corresponding
307
- return elements/annotations removed from its AST.
308
-
309
- The modification is done in-place on the original AST nodes within the IngredientsFunction object.
310
- """
311
- list_argCuzMyBrainRefusesToThink = ingredientsFunction.astFunctionDef.args.args + ingredientsFunction.astFunctionDef.args.posonlyargs + ingredientsFunction.astFunctionDef.args.kwonlyargs
312
- list_arg_arg: list[ast_Identifier] = [ast_arg.arg for ast_arg in list_argCuzMyBrainRefusesToThink]
313
- listName: list[ast.Name] = []
314
- fauxFunctionDef = deepcopy(ingredientsFunction.astFunctionDef)
315
- NodeChanger(Be.Return, Then.removeIt).visit(fauxFunctionDef)
316
- NodeTourist(Be.Name, Then.appendTo(listName)).visit(fauxFunctionDef)
317
- list_Identifiers: list[ast_Identifier] = [astName.id for astName in listName]
318
- list_IdentifiersNotUsed: list[ast_Identifier] = list(set(list_arg_arg) - set(list_Identifiers))
319
- for arg_Identifier in list_IdentifiersNotUsed:
320
- remove_arg = NodeChanger(IfThis.is_arg_Identifier(arg_Identifier), Then.removeIt)
321
- remove_arg.visit(ingredientsFunction.astFunctionDef)
322
-
323
- list_argCuzMyBrainRefusesToThink = ingredientsFunction.astFunctionDef.args.args + ingredientsFunction.astFunctionDef.args.posonlyargs + ingredientsFunction.astFunctionDef.args.kwonlyargs
324
-
325
- listName: list[ast.Name] = [Make.Name(ast_arg.arg) for ast_arg in list_argCuzMyBrainRefusesToThink]
326
- replaceReturn = NodeChanger(Be.Return, Then.replaceWith(Make.Return(Make.Tuple(listName))))
327
- replaceReturn.visit(ingredientsFunction.astFunctionDef)
328
-
329
- list_annotation: list[ast.expr] = [ast_arg.annotation for ast_arg in list_argCuzMyBrainRefusesToThink if ast_arg.annotation is not None]
330
- ingredientsFunction.astFunctionDef.returns = Make.Subscript(Make.Name('tuple'), Make.Tuple(list_annotation))
331
-
332
- ast.fix_missing_locations(ingredientsFunction.astFunctionDef)
333
-
334
- return ingredientsFunction
335
-
336
163
  def makeNewFlow(recipeFlow: RecipeSynthesizeFlow) -> IngredientsModule:
337
164
  # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
338
165
  listAllIngredientsFunctions = [
@@ -374,7 +201,7 @@ def makeNewFlow(recipeFlow: RecipeSynthesizeFlow) -> IngredientsModule:
374
201
  for ingredients in listAllIngredientsFunctions:
375
202
  for source_Identifier, recipe_Identifier in listFindReplace:
376
203
  updateName = NodeChanger(IfThis.isName_Identifier(source_Identifier) , Grab.idAttribute(Then.replaceWith(recipe_Identifier)))
377
- update_arg = NodeChanger(IfThis.isArgument_Identifier(source_Identifier), Grab.argAttribute(Then.replaceWith(recipe_Identifier))) # type: ignore
204
+ update_arg = NodeChanger(IfThis.isArgument_Identifier(source_Identifier), Grab.argAttribute(Then.replaceWith(recipe_Identifier)))
378
205
  updateName.visit(ingredients.astFunctionDef)
379
206
  update_arg.visit(ingredients.astFunctionDef)
380
207
 
@@ -494,7 +321,7 @@ def Z0Z_lameFindReplace(astTree: 个, mappingFindReplaceNodes: Mapping[ast.AST,
494
321
 
495
322
  while keepGoing:
496
323
  for nodeFind, nodeReplace in mappingFindReplaceNodes.items():
497
- NodeChanger(IfThis.Z0Z_unparseIs(nodeFind), Then.replaceWith(nodeReplace)).visit(newTree)
324
+ NodeChanger(IfThis.unparseIs(nodeFind), Then.replaceWith(nodeReplace)).visit(newTree)
498
325
 
499
326
  if ast.unparse(newTree) == ast.unparse(astTree):
500
327
  keepGoing = False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapFolding
3
- Version: 0.10.0
3
+ Version: 0.11.0
4
4
  Summary: Map folding algorithm with code transformation framework for optimizing numerical computations
5
5
  Author-email: Hunter Hogan <HunterHogan@pm.me>
6
6
  License: CC-BY-NC-4.0
@@ -31,6 +31,7 @@ Classifier: Typing :: Typed
31
31
  Requires-Python: >=3.10
32
32
  Description-Content-Type: text/markdown
33
33
  License-File: LICENSE
34
+ Requires-Dist: astToolkit
34
35
  Requires-Dist: autoflake
35
36
  Requires-Dist: cytoolz
36
37
  Requires-Dist: more_itertools