mapFolding 0.9.2__py3-none-any.whl → 0.9.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 (36) hide show
  1. mapFolding/Z0Z_flowControl.py +117 -0
  2. mapFolding/__init__.py +28 -26
  3. mapFolding/basecamp.py +1 -1
  4. mapFolding/beDRY.py +1 -2
  5. mapFolding/daoOfMapFolding.py +142 -0
  6. mapFolding/dataBaskets.py +49 -0
  7. mapFolding/datatypes.py +21 -0
  8. mapFolding/oeis.py +1 -2
  9. mapFolding/someAssemblyRequired/Z0Z_makeSomeModules.py +226 -0
  10. mapFolding/someAssemblyRequired/__init__.py +12 -2
  11. mapFolding/someAssemblyRequired/_theTypes.py +11 -5
  12. mapFolding/someAssemblyRequired/_tool_Make.py +8 -0
  13. mapFolding/someAssemblyRequired/_tool_Then.py +44 -1
  14. mapFolding/someAssemblyRequired/_toolboxAST.py +57 -0
  15. mapFolding/someAssemblyRequired/_toolboxAntecedents.py +95 -29
  16. mapFolding/someAssemblyRequired/_toolboxContainers.py +59 -53
  17. mapFolding/someAssemblyRequired/_toolboxPython.py +52 -50
  18. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +10 -9
  19. mapFolding/someAssemblyRequired/toolboxNumba.py +1 -1
  20. mapFolding/someAssemblyRequired/transformationTools.py +40 -58
  21. mapFolding/syntheticModules/dataPacking.py +25 -0
  22. mapFolding/syntheticModules/initializeCount.py +49 -0
  23. mapFolding/syntheticModules/theorem2.py +49 -0
  24. mapFolding/syntheticModules/theorem2Numba.py +51 -0
  25. mapFolding/theSSOT.py +13 -21
  26. {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/METADATA +4 -3
  27. mapfolding-0.9.4.dist-info/RECORD +57 -0
  28. {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/WHEEL +1 -1
  29. tests/__init__.py +2 -2
  30. tests/conftest.py +7 -7
  31. tests/test_computations.py +17 -13
  32. tests/test_tasks.py +2 -2
  33. mapfolding-0.9.2.dist-info/RECORD +0 -47
  34. {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/entry_points.txt +0 -0
  35. {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/licenses/LICENSE +0 -0
  36. {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,226 @@
1
+ from mapFolding import raiseIfNoneGitHubIssueNumber3, The
2
+ from mapFolding.someAssemblyRequired import (
3
+ ast_Identifier,
4
+ astModuleToIngredientsFunction,
5
+ be,
6
+ DOT,
7
+ extractFunctionDef,
8
+ grab,
9
+ ifThis,
10
+ IngredientsFunction,
11
+ IngredientsModule,
12
+ LedgerOfImports,
13
+ Make,
14
+ NodeChanger,
15
+ NodeTourist,
16
+ parseLogicalPath2astModule,
17
+ parsePathFilename2astModule,
18
+ Then,
19
+ str_nameDOTname,
20
+ )
21
+ from mapFolding.someAssemblyRequired.toolboxNumba import decorateCallableWithNumba, parametersNumbaLight
22
+ from mapFolding.someAssemblyRequired.transformationTools import (
23
+ inlineFunctionDef,
24
+ removeDataclassFromFunction,
25
+ removeUnusedParameters,
26
+ shatter_dataclassesDOTdataclass,
27
+ unpackDataclassCallFunctionRepackDataclass,
28
+ write_astModule,
29
+ )
30
+ from pathlib import PurePath
31
+ import ast
32
+
33
+ algorithmSourceModuleHARDCODED = 'daoOfMapFolding'
34
+ sourceCallableIdentifierHARDCODED = 'count'
35
+ logicalPathInfixHARDCODED: ast_Identifier = 'syntheticModules'
36
+ theCountingIdentifierHARDCODED: ast_Identifier = 'groupsOfFolds'
37
+
38
+ def makeInitializeGroupsOfFolds():
39
+ callableIdentifierHARDCODED = 'initializeGroupsOfFolds'
40
+ moduleIdentifierHARDCODED: ast_Identifier = 'initializeCount'
41
+
42
+ algorithmSourceModule = algorithmSourceModuleHARDCODED
43
+ sourceCallableIdentifier = sourceCallableIdentifierHARDCODED
44
+ logicalPathSourceModule = '.'.join([The.packageName, algorithmSourceModule])
45
+
46
+ callableIdentifier = callableIdentifierHARDCODED
47
+ logicalPathInfix = logicalPathInfixHARDCODED
48
+ moduleIdentifier = moduleIdentifierHARDCODED
49
+
50
+ astModule = parseLogicalPath2astModule(logicalPathSourceModule)
51
+ countInitializeIngredients = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule)
52
+ , LedgerOfImports(astModule))
53
+
54
+ countInitializeIngredients.astFunctionDef.name = callableIdentifier
55
+
56
+ dataclassInstanceIdentifier = NodeTourist(be.arg, Then.extractIt(DOT.arg)).captureLastMatch(countInitializeIngredients.astFunctionDef)
57
+ if dataclassInstanceIdentifier is None: raise raiseIfNoneGitHubIssueNumber3
58
+ theCountingIdentifier = theCountingIdentifierHARDCODED
59
+
60
+ findThis = ifThis.isWhileAttributeNamespace_IdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
61
+ doThat = grab.testAttribute(grab.andDoAllOf([
62
+ grab.opsAttribute(Then.replaceWith([ast.Eq()])), # type: ignore
63
+ grab.leftAttribute(grab.attrAttribute(Then.replaceWith(theCountingIdentifier))) # type: ignore
64
+ ]))
65
+ NodeChanger(findThis, doThat).visit(countInitializeIngredients.astFunctionDef.body[0])
66
+
67
+ initializationModule = IngredientsModule(countInitializeIngredients)
68
+
69
+ pathFilename = PurePath(The.pathPackage, logicalPathInfix, moduleIdentifier + The.fileExtension)
70
+
71
+ write_astModule(initializationModule, pathFilename, The.packageName)
72
+
73
+ def makeTheorem2():
74
+ moduleIdentifierHARDCODED: ast_Identifier = 'theorem2'
75
+
76
+ algorithmSourceModule = algorithmSourceModuleHARDCODED
77
+ sourceCallableIdentifier = sourceCallableIdentifierHARDCODED
78
+ logicalPathSourceModule = '.'.join([The.packageName, algorithmSourceModule])
79
+
80
+ logicalPathInfix = logicalPathInfixHARDCODED
81
+ moduleIdentifier = moduleIdentifierHARDCODED
82
+
83
+ astModule = parseLogicalPath2astModule(logicalPathSourceModule)
84
+ countTheorem2 = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule)
85
+ , LedgerOfImports(astModule))
86
+
87
+ dataclassInstanceIdentifier = NodeTourist(be.arg, Then.extractIt(DOT.arg)).captureLastMatch(countTheorem2.astFunctionDef)
88
+ if dataclassInstanceIdentifier is None: raise raiseIfNoneGitHubIssueNumber3
89
+
90
+ findThis = ifThis.isWhileAttributeNamespace_IdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
91
+ doThat = grab.testAttribute(grab.comparatorsAttribute(Then.replaceWith([Make.Constant(4)]))) # type: ignore
92
+ NodeChanger(findThis, doThat).visit(countTheorem2.astFunctionDef)
93
+
94
+ findThis = ifThis.isIfAttributeNamespace_IdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
95
+ doThat = Then.extractIt(DOT.body)
96
+ insertLeaf = NodeTourist(findThis, doThat).captureLastMatch(countTheorem2.astFunctionDef)
97
+ findThis = ifThis.isIfAttributeNamespace_IdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
98
+ doThat = Then.replaceWith(insertLeaf)
99
+ NodeChanger(findThis, doThat).visit(countTheorem2.astFunctionDef)
100
+
101
+ findThis = ifThis.isAttributeNamespace_IdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
102
+ doThat = Then.removeIt
103
+ NodeChanger(findThis, doThat).visit(countTheorem2.astFunctionDef)
104
+
105
+ findThis = ifThis.isAttributeNamespace_IdentifierLessThanOrEqual(dataclassInstanceIdentifier, 'leaf1ndex')
106
+ doThat = Then.removeIt
107
+ NodeChanger(findThis, doThat).visit(countTheorem2.astFunctionDef)
108
+
109
+ theCountingIdentifier = theCountingIdentifierHARDCODED
110
+ doubleTheCount = Make.AugAssign(Make.Attribute(ast.Name(dataclassInstanceIdentifier), theCountingIdentifier), ast.Mult(), Make.Constant(2))
111
+ findThis = be.Return
112
+ doThat = Then.insertThisAbove([doubleTheCount])
113
+ NodeChanger(findThis, doThat).visit(countTheorem2.astFunctionDef)
114
+
115
+ moduleTheorem2 = IngredientsModule(countTheorem2)
116
+
117
+ pathFilename = PurePath(The.pathPackage, logicalPathInfix, moduleIdentifier + The.fileExtension)
118
+
119
+ write_astModule(moduleTheorem2, pathFilename, The.packageName)
120
+
121
+ return pathFilename
122
+
123
+ def numbaOnTheorem2(pathFilenameSource: PurePath):
124
+ logicalPathInfix = logicalPathInfixHARDCODED
125
+ sourceCallableIdentifier = sourceCallableIdentifierHARDCODED
126
+ countNumbaTheorem2 = astModuleToIngredientsFunction(parsePathFilename2astModule(pathFilenameSource), sourceCallableIdentifier)
127
+ dataclassName: ast.expr | None = NodeTourist(be.arg, Then.extractIt(DOT.annotation)).captureLastMatch(countNumbaTheorem2.astFunctionDef)
128
+ if dataclassName is None: raise raiseIfNoneGitHubIssueNumber3
129
+ dataclass_Identifier: ast_Identifier | None = NodeTourist(be.Name, Then.extractIt(DOT.id)).captureLastMatch(dataclassName)
130
+ if dataclass_Identifier is None: raise raiseIfNoneGitHubIssueNumber3
131
+
132
+ dataclassLogicalPathModule = None
133
+ for moduleWithLogicalPath, listNameTuples in countNumbaTheorem2.imports.dictionaryImportFrom.items():
134
+ for nameTuple in listNameTuples:
135
+ if nameTuple[0] == dataclass_Identifier:
136
+ dataclassLogicalPathModule = moduleWithLogicalPath
137
+ break
138
+ if dataclassLogicalPathModule:
139
+ break
140
+ if dataclassLogicalPathModule is None: raise raiseIfNoneGitHubIssueNumber3
141
+ dataclassInstanceIdentifier = NodeTourist(be.arg, Then.extractIt(DOT.arg)).captureLastMatch(countNumbaTheorem2.astFunctionDef)
142
+ if dataclassInstanceIdentifier is None: raise raiseIfNoneGitHubIssueNumber3
143
+ shatteredDataclass = shatter_dataclassesDOTdataclass(dataclassLogicalPathModule, dataclass_Identifier, dataclassInstanceIdentifier)
144
+
145
+ countNumbaTheorem2.imports.update(shatteredDataclass.imports)
146
+ countNumbaTheorem2 = removeDataclassFromFunction(countNumbaTheorem2, shatteredDataclass)
147
+
148
+ countNumbaTheorem2 = removeUnusedParameters(countNumbaTheorem2)
149
+
150
+ countNumbaTheorem2 = decorateCallableWithNumba(countNumbaTheorem2, parametersNumbaLight)
151
+
152
+ moduleNumbaTheorem2 = IngredientsModule(countNumbaTheorem2)
153
+ moduleNumbaTheorem2.removeImportFromModule('numpy')
154
+
155
+ pathFilename = pathFilenameSource.with_stem(pathFilenameSource.stem + 'Numba')
156
+
157
+ write_astModule(moduleNumbaTheorem2, pathFilename, The.packageName)
158
+
159
+ logicalPath: list[str] = []
160
+ if The.packageName:
161
+ logicalPath.append(The.packageName)
162
+ if logicalPathInfix:
163
+ logicalPath.append(logicalPathInfix)
164
+ logicalPath.append(pathFilename.stem)
165
+ moduleWithLogicalPath: str_nameDOTname = '.'.join(logicalPath)
166
+
167
+ astImportFrom: ast.ImportFrom = Make.ImportFrom(moduleWithLogicalPath, list_astAlias=[Make.alias(countNumbaTheorem2.astFunctionDef.name)])
168
+
169
+ return astImportFrom
170
+
171
+ def makeUnRePackDataclass(astImportFrom: ast.ImportFrom):
172
+ moduleIdentifierHARDCODED: ast_Identifier = 'dataPacking'
173
+
174
+ algorithmSourceModule = algorithmSourceModuleHARDCODED
175
+ sourceCallableIdentifier = The.sourceCallableDispatcher
176
+ logicalPathSourceModule = '.'.join([The.packageName, algorithmSourceModule])
177
+
178
+ callableIdentifier = sourceCallableIdentifier
179
+ logicalPathInfix = logicalPathInfixHARDCODED
180
+ moduleIdentifier = moduleIdentifierHARDCODED
181
+
182
+ doTheNeedful: IngredientsFunction = astModuleToIngredientsFunction(parseLogicalPath2astModule(logicalPathSourceModule), sourceCallableIdentifier)
183
+ dataclassName: ast.expr | None = NodeTourist(be.arg, Then.extractIt(DOT.annotation)).captureLastMatch(doTheNeedful.astFunctionDef)
184
+ if dataclassName is None: raise raiseIfNoneGitHubIssueNumber3
185
+ dataclass_Identifier: ast_Identifier | None = NodeTourist(be.Name, Then.extractIt(DOT.id)).captureLastMatch(dataclassName)
186
+ if dataclass_Identifier is None: raise raiseIfNoneGitHubIssueNumber3
187
+
188
+ dataclassLogicalPathModule = None
189
+ for moduleWithLogicalPath, listNameTuples in doTheNeedful.imports.dictionaryImportFrom.items():
190
+ for nameTuple in listNameTuples:
191
+ if nameTuple[0] == dataclass_Identifier:
192
+ dataclassLogicalPathModule = moduleWithLogicalPath
193
+ break
194
+ if dataclassLogicalPathModule:
195
+ break
196
+ if dataclassLogicalPathModule is None: raise raiseIfNoneGitHubIssueNumber3
197
+ dataclassInstanceIdentifier = NodeTourist(be.arg, Then.extractIt(DOT.arg)).captureLastMatch(doTheNeedful.astFunctionDef)
198
+ if dataclassInstanceIdentifier is None: raise raiseIfNoneGitHubIssueNumber3
199
+ shatteredDataclass = shatter_dataclassesDOTdataclass(dataclassLogicalPathModule, dataclass_Identifier, dataclassInstanceIdentifier)
200
+
201
+ doTheNeedful.imports.update(shatteredDataclass.imports)
202
+ doTheNeedful.imports.addAst(astImportFrom)
203
+ targetCallableIdentifier = astImportFrom.names[0].name
204
+ doTheNeedful = unpackDataclassCallFunctionRepackDataclass(doTheNeedful, targetCallableIdentifier, shatteredDataclass)
205
+ targetFunctionDef = extractFunctionDef(parseLogicalPath2astModule(astImportFrom.module), targetCallableIdentifier) # type: ignore
206
+ if targetFunctionDef is None: raise raiseIfNoneGitHubIssueNumber3
207
+ astTuple: ast.Tuple | None = NodeTourist(be.Return, Then.extractIt(DOT.value)).captureLastMatch(targetFunctionDef)
208
+ if astTuple is None: raise raiseIfNoneGitHubIssueNumber3
209
+ astTuple.ctx = ast.Store()
210
+
211
+ findThis = ifThis.isAssignAndValueIs(ifThis.isCall_Identifier(targetCallableIdentifier))
212
+ doThat = Then.replaceWith(Make.Assign(listTargets=[astTuple], value=Make.Call(Make.Name(targetCallableIdentifier), astTuple.elts)))
213
+ NodeChanger(findThis, doThat).visit(doTheNeedful.astFunctionDef)
214
+
215
+ moduleDoTheNeedful = IngredientsModule(doTheNeedful)
216
+ moduleDoTheNeedful.removeImportFromModule('numpy')
217
+
218
+ pathFilename = PurePath(The.pathPackage, logicalPathInfix, moduleIdentifier + The.fileExtension)
219
+
220
+ write_astModule(moduleDoTheNeedful, pathFilename, The.packageName)
221
+
222
+ if __name__ == '__main__':
223
+ makeInitializeGroupsOfFolds()
224
+ pathFilename = makeTheorem2()
225
+ astImportFrom = numbaOnTheorem2(pathFilename)
226
+ makeUnRePackDataclass(astImportFrom)
@@ -22,7 +22,7 @@ functional implementations into highly-optimized variants with verified correctn
22
22
  - Recipe configuration for generating optimized code (RecipeSynthesizeFlow)
23
23
  - Dataclass decomposition for compatibility (ShatteredDataclass)
24
24
 
25
- 3. **Optimization Pipelines**
25
+ 3. **Optimization assembly lines**
26
26
  - General-purpose Numba acceleration (makeNumbaFlow)
27
27
  - Job-specific optimization for concrete parameters (makeJobNumba)
28
28
  - Specialized component transformation (decorateCallableWithNumba)
@@ -50,14 +50,18 @@ to verify correctness at each transformation stage through the integrated test s
50
50
  from mapFolding.someAssemblyRequired._theTypes import (
51
51
  ast_expr_Slice as ast_expr_Slice,
52
52
  ast_Identifier as ast_Identifier,
53
+ astClassHasDOTbody as astClassHasDOTbody,
54
+ astClassHasDOTbody_expr as astClassHasDOTbody_expr,
55
+ astClassHasDOTbodyList_stmt as astClassHasDOTbodyList_stmt,
53
56
  astClassHasDOTnameNotName as astClassHasDOTnameNotName,
57
+ astClassHasDOTnameNotNameAlways as astClassHasDOTnameNotNameAlways,
58
+ astClassHasDOTnameNotNameOptionally as astClassHasDOTnameNotNameOptionally,
54
59
  astClassHasDOTtarget as astClassHasDOTtarget,
55
60
  astClassHasDOTtarget_expr as astClassHasDOTtarget_expr,
56
61
  astClassHasDOTtargetAttributeNameSubscript as astClassHasDOTtargetAttributeNameSubscript,
57
62
  astClassHasDOTvalue as astClassHasDOTvalue,
58
63
  astClassHasDOTvalue_expr as astClassHasDOTvalue_expr,
59
64
  astClassHasDOTvalue_exprNone as astClassHasDOTvalue_exprNone,
60
- astClassOptionallyHasDOTnameNotName as astClassOptionallyHasDOTnameNotName,
61
65
  ImaCallToName as ImaCallToName,
62
66
  intORlist_ast_type_paramORstr_orNone as intORlist_ast_type_paramORstr_orNone,
63
67
  intORstr_orNone as intORstr_orNone,
@@ -87,3 +91,9 @@ from mapFolding.someAssemblyRequired._toolboxContainers import (
87
91
  RecipeSynthesizeFlow as RecipeSynthesizeFlow,
88
92
  ShatteredDataclass as ShatteredDataclass,
89
93
  )
94
+
95
+ from mapFolding.someAssemblyRequired._toolboxAST import (
96
+ astModuleToIngredientsFunction as astModuleToIngredientsFunction,
97
+ extractClassDef as extractClassDef,
98
+ extractFunctionDef as extractFunctionDef,
99
+ )
@@ -6,24 +6,30 @@ stuPyd: typing_TypeAlias = str
6
6
  if TYPE_CHECKING:
7
7
  """ 3.12 new: ast.ParamSpec, ast.type_param, ast.TypeAlias, ast.TypeVar, ast.TypeVarTuple
8
8
  3.11 new: ast.TryStar"""
9
- astClassHasDOTnameNotName: typing_TypeAlias = ast.alias | ast.AsyncFunctionDef | ast.ClassDef | ast.FunctionDef | ast.ParamSpec | ast.TypeVar | ast.TypeVarTuple
9
+ astClassHasDOTbodyList_stmt: typing_TypeAlias = ast.AsyncFor | ast.AsyncWith | ast.ClassDef | ast.ExceptHandler | ast.For | ast.FunctionDef | ast.If | ast.Interactive | ast.match_case | ast.Module | ast.Try | ast.TryStar | ast.While | ast.With
10
+ astClassHasDOTnameNotNameAlways: typing_TypeAlias = ast.alias | ast.AsyncFunctionDef | ast.ClassDef | ast.FunctionDef | ast.ParamSpec | ast.TypeVar | ast.TypeVarTuple
10
11
  astClassHasDOTvalue_expr: typing_TypeAlias = ast.Assign | ast.Attribute | ast.AugAssign | ast.Await | ast.DictComp | ast.Expr | ast.FormattedValue | ast.keyword | ast.MatchValue | ast.NamedExpr | ast.Starred | ast.Subscript | ast.TypeAlias | ast.YieldFrom
11
12
 
12
13
  else:
13
- astClassHasDOTnameNotName = stuPyd
14
+ astClassHasDOTbodyList_stmt = stuPyd
15
+ astClassHasDOTnameNotNameAlways = stuPyd
14
16
  astClassHasDOTvalue_expr = stuPyd
15
17
 
16
18
  class ImaCallToName(ast.Call):
17
19
  func: ast.Name # pyright: ignore[reportIncompatibleVariableOverride]
18
- # assert isinstance(ast.Call.func, ast.Name), "brinksmanship"
20
+ # assert isinstance(ast.Call.func, ast.Name), "brinkmanship"
19
21
  # func: ast.Name
20
22
 
23
+ astClassHasDOTbody_expr: typing_TypeAlias = ast.Expression | ast.IfExp | ast.Lambda
24
+ astClassHasDOTbody: typing_TypeAlias = astClassHasDOTbody_expr | astClassHasDOTbodyList_stmt
25
+
26
+ astClassHasDOTnameNotNameOptionally: typing_TypeAlias = ast.ExceptHandler | ast.MatchAs | ast.MatchStar
27
+ astClassHasDOTnameNotName: typing_TypeAlias = astClassHasDOTnameNotNameAlways | astClassHasDOTnameNotNameOptionally
28
+
21
29
  astClassHasDOTtargetAttributeNameSubscript: typing_TypeAlias = ast.AnnAssign | ast.AugAssign
22
30
  astClassHasDOTtarget_expr: typing_TypeAlias = ast.AsyncFor | ast.comprehension | ast.For
23
31
  astClassHasDOTtarget: typing_TypeAlias = ast.NamedExpr | astClassHasDOTtarget_expr | astClassHasDOTtargetAttributeNameSubscript
24
32
 
25
- astClassOptionallyHasDOTnameNotName: typing_TypeAlias = ast.ExceptHandler | ast.MatchAs | ast.MatchStar
26
-
27
33
  astClassHasDOTvalue_exprNone: typing_TypeAlias = ast.AnnAssign | ast.Return | ast.Yield
28
34
  astClassHasDOTvalue: typing_TypeAlias = ast.Constant | ast.MatchSingleton | astClassHasDOTvalue_expr | astClassHasDOTvalue_exprNone
29
35
 
@@ -73,6 +73,10 @@ class Make:
73
73
  buffaloBuffalo = addDOTattribute(buffaloBuffalo, identifier, context, **keywordArguments)
74
74
  return buffaloBuffalo
75
75
 
76
+ @staticmethod
77
+ def AugAssign(target: ast.Attribute | ast.Name | ast.Subscript, operator: ast.operator, value: ast.expr, **keywordArguments: int) -> ast.AugAssign:
78
+ return ast.AugAssign(target, operator, value, **keywordArguments)
79
+
76
80
  @staticmethod
77
81
  def Call(callee: ast.expr, listArguments: Sequence[ast.expr] | None = None, list_astKeywords: Sequence[ast.keyword] | None = None) -> ast.Call:
78
82
  return ast.Call(func=callee, args=list(listArguments) if listArguments else [], keywords=list(list_astKeywords) if list_astKeywords else [])
@@ -124,3 +128,7 @@ class Make:
124
128
  @staticmethod
125
129
  def Tuple(elements: Sequence[ast.expr] = [], context: ast.expr_context = ast.Load(), **keywordArguments: int) -> ast.Tuple:
126
130
  return ast.Tuple(list(elements), context, **keywordArguments)
131
+
132
+ @staticmethod
133
+ def While(test: ast.expr, doThis: list[ast.stmt], orElse: list[ast.stmt] = [], **keywordArguments: int) -> ast.While:
134
+ return ast.While(test, doThis, orElse, **keywordArguments)
@@ -16,7 +16,7 @@ once they have been identified using predicate functions from ifThis.
16
16
 
17
17
  from collections.abc import Callable, Sequence
18
18
  from mapFolding.someAssemblyRequired import ast_Identifier, astClassHasDOTvalue, ImaCallToName, NodeORattribute
19
- from typing import Any
19
+ from typing import Any, overload
20
20
  import ast
21
21
 
22
22
  class grab:
@@ -32,6 +32,14 @@ class grab:
32
32
  specific attribute of that node, and returns the modified node. This enables fine-grained
33
33
  control when transforming AST structures.
34
34
  """
35
+ @staticmethod
36
+ def andDoAllOf(listOfActions: list[Callable[[NodeORattribute], NodeORattribute]]) -> Callable[[NodeORattribute], NodeORattribute]:
37
+ def workhorse(node: NodeORattribute) -> NodeORattribute:
38
+ for action in listOfActions:
39
+ node = action(node)
40
+ return node
41
+ return workhorse
42
+
35
43
  @staticmethod
36
44
  def argAttribute(action: Callable[[ast_Identifier | None], ast_Identifier]) -> Callable[[ast.arg | ast.keyword], ast.arg | ast.keyword]:
37
45
  def workhorse(node: ast.arg | ast.keyword) -> ast.arg | ast.keyword:
@@ -39,6 +47,20 @@ class grab:
39
47
  return node
40
48
  return workhorse
41
49
 
50
+ @staticmethod
51
+ def attrAttribute(action: Callable[[ast_Identifier], ast_Identifier]) -> Callable[[ast.Attribute], ast.Attribute]:
52
+ def workhorse(node: ast.Attribute) -> ast.Attribute:
53
+ node.attr = action(node.attr)
54
+ return node
55
+ return workhorse
56
+
57
+ @staticmethod
58
+ def comparatorsAttribute(action: Callable[[list[ast.expr]], list[ast.expr]]) -> Callable[[ast.Compare], ast.Compare]:
59
+ def workhorse(node: ast.Compare) -> ast.Compare:
60
+ node.comparators = action(node.comparators)
61
+ return node
62
+ return workhorse
63
+
42
64
  @staticmethod
43
65
  def funcAttribute(action: Callable[[ast.expr], ast.expr]) -> Callable[[ast.Call], ast.Call]:
44
66
  def workhorse(node: ast.Call) -> ast.Call:
@@ -60,6 +82,27 @@ class grab:
60
82
  return node
61
83
  return workhorse
62
84
 
85
+ @staticmethod
86
+ def leftAttribute(action: Callable[[ast.expr], ast.expr]) -> Callable[[ast.BinOp | ast.Compare], ast.BinOp | ast.Compare]:
87
+ def workhorse(node: ast.BinOp | ast.Compare) -> ast.BinOp | ast.Compare:
88
+ node.left = action(node.left)
89
+ return node
90
+ return workhorse
91
+
92
+ @staticmethod
93
+ def opsAttribute(action: Callable[[list[ast.cmpop]], list[ast.cmpop]]) -> Callable[[ast.Compare], ast.Compare]:
94
+ def workhorse(node: ast.Compare) -> ast.Compare:
95
+ node.ops = action(node.ops)
96
+ return node
97
+ return workhorse
98
+
99
+ @staticmethod
100
+ def testAttribute(action: Callable[[ast.expr], ast.expr]) -> Callable[[ast.Assert | ast.If | ast.IfExp | ast.While], ast.Assert | ast.If | ast.IfExp | ast.While]:
101
+ def workhorse(node: ast.Assert | ast.If | ast.IfExp | ast.While) -> ast.Assert | ast.If | ast.IfExp | ast.While:
102
+ node.test = action(node.test)
103
+ return node
104
+ return workhorse
105
+
63
106
  @staticmethod
64
107
  def valueAttribute(action: Callable[[Any], Any]) -> Callable[[astClassHasDOTvalue], astClassHasDOTvalue]:
65
108
  def workhorse(node: astClassHasDOTvalue) -> astClassHasDOTvalue:
@@ -0,0 +1,57 @@
1
+ from mapFolding.someAssemblyRequired import ast_Identifier, ifThis, IngredientsFunction, LedgerOfImports, NodeTourist, Then
2
+ from mapFolding.theSSOT import raiseIfNoneGitHubIssueNumber3
3
+ import ast
4
+
5
+ def astModuleToIngredientsFunction(astModule: ast.AST, identifierFunctionDef: ast_Identifier) -> IngredientsFunction:
6
+ """
7
+ Extract a function definition from an AST module and create an `IngredientsFunction`.
8
+
9
+ This function finds a function definition with the specified identifier in the given AST module, extracts it, and
10
+ stores all module imports in the `LedgerOfImports`.
11
+
12
+ Parameters:
13
+ astModule: The AST module containing the function definition.
14
+ identifierFunctionDef: The name of the function to extract.
15
+
16
+ Returns:
17
+ ingredientsFunction: `IngredientsFunction` object containing the `ast.FunctionDef` and _all_ imports from the
18
+ source module.
19
+
20
+ Raises:
21
+ raiseIfNoneGitHubIssueNumber3: If the function definition is not found.
22
+ """
23
+ astFunctionDef = extractFunctionDef(astModule, identifierFunctionDef)
24
+ if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
25
+ return IngredientsFunction(astFunctionDef, LedgerOfImports(astModule))
26
+
27
+ def extractClassDef(module: ast.AST, identifier: ast_Identifier) -> ast.ClassDef | None:
28
+ """
29
+ Extract a class definition with a specific name from an AST module.
30
+
31
+ This function searches through an AST module for a class definition that matches the provided identifier and returns
32
+ it if found.
33
+
34
+ Parameters:
35
+ module: The AST module to search within.
36
+ identifier: The name of the class to find.
37
+
38
+ Returns:
39
+ astClassDef|None: The matching class definition AST node, or `None` if not found.
40
+ """
41
+ return NodeTourist(ifThis.isClassDef_Identifier(identifier), Then.extractIt).captureLastMatch(module)
42
+
43
+ def extractFunctionDef(module: ast.AST, identifier: ast_Identifier) -> ast.FunctionDef | None:
44
+ """
45
+ Extract a function definition with a specific name from an AST module.
46
+
47
+ This function searches through an AST module for a function definition that matches the provided identifier and
48
+ returns it if found.
49
+
50
+ Parameters:
51
+ module: The AST module to search within.
52
+ identifier: The name of the function to find.
53
+
54
+ Returns:
55
+ astFunctionDef|None: The matching function definition AST node, or `None` if not found.
56
+ """
57
+ return NodeTourist(ifThis.isFunctionDef_Identifier(identifier), Then.extractIt).captureLastMatch(module)
@@ -1,36 +1,39 @@
1
1
  """
2
2
  AST Node Predicate and Access Utilities for Pattern Matching and Traversal
3
3
 
4
- This module provides utilities for accessing and matching AST nodes in a consistent way.
5
- It contains three primary classes:
4
+ This module provides utilities for accessing and matching AST nodes in a consistent way. It contains three primary
5
+ classes:
6
6
 
7
- 1. DOT: Provides consistent accessor methods for AST node attributes across different
8
- node types, simplifying the access to node properties.
7
+ 1. DOT: Provides consistent accessor methods for AST node attributes across different node types, simplifying the access
8
+ to node properties.
9
9
 
10
- 2. be: Offers type-guard functions that verify AST node types, enabling safe type
11
- narrowing for static type checking and improving code safety.
10
+ 2. be: Offers type-guard functions that verify AST node types, enabling safe type narrowing for static type checking and
11
+ improving code safety.
12
12
 
13
- 3. ifThis: Contains predicate functions for matching AST nodes based on various criteria,
14
- enabling precise targeting of nodes for analysis or transformation.
13
+ 3. ifThis: Contains predicate functions for matching AST nodes based on various criteria, enabling precise targeting of
14
+ nodes for analysis or transformation.
15
15
 
16
- These utilities form the foundation of the pattern-matching component in the AST
17
- manipulation framework, working in conjunction with the NodeChanger and NodeTourist
18
- classes to enable precise and targeted code transformations. Together, they implement
19
- a declarative approach to AST manipulation that separates node identification (ifThis),
20
- type verification (be), and data access (DOT).
16
+ These utilities form the foundation of the pattern-matching component in the AST manipulation framework, working in
17
+ conjunction with the NodeChanger and NodeTourist classes to enable precise and targeted code transformations. Together,
18
+ they implement a declarative approach to AST manipulation that separates node identification (ifThis), type verification
19
+ (be), and data access (DOT).
21
20
  """
22
21
 
23
22
  from collections.abc import Callable
24
23
  from mapFolding.someAssemblyRequired import (
25
24
  ast_Identifier,
25
+ astClassHasDOTbody,
26
+ astClassHasDOTbody_expr,
27
+ astClassHasDOTbodyList_stmt,
26
28
  astClassHasDOTnameNotName,
29
+ astClassHasDOTnameNotNameAlways,
30
+ astClassHasDOTnameNotNameOptionally,
31
+ astClassHasDOTtarget_expr,
27
32
  astClassHasDOTtarget,
28
33
  astClassHasDOTtargetAttributeNameSubscript,
29
- astClassHasDOTtarget_expr,
30
- astClassHasDOTvalue,
31
34
  astClassHasDOTvalue_expr,
32
- astClassOptionallyHasDOTnameNotName,
33
35
  astClassHasDOTvalue_exprNone,
36
+ astClassHasDOTvalue,
34
37
  ImaCallToName,
35
38
  )
36
39
  from typing import Any, overload, TypeGuard
@@ -72,6 +75,16 @@ class DOT:
72
75
  def attr(node: ast.Attribute) -> ast_Identifier:
73
76
  return node.attr
74
77
 
78
+ @staticmethod
79
+ @overload
80
+ def body(node: astClassHasDOTbodyList_stmt) -> list[ast.stmt]:...
81
+ @staticmethod
82
+ @overload
83
+ def body(node: astClassHasDOTbody_expr) -> ast.expr:...
84
+ @staticmethod
85
+ def body(node: astClassHasDOTbody) -> ast.expr | list[ast.stmt]:
86
+ return node.body
87
+
75
88
  @staticmethod
76
89
  @overload
77
90
  def func(node: ImaCallToName) -> ast.Name:...
@@ -88,12 +101,12 @@ class DOT:
88
101
 
89
102
  @staticmethod
90
103
  @overload
91
- def name(node: astClassHasDOTnameNotName) -> ast_Identifier:...
104
+ def name(node: astClassHasDOTnameNotNameAlways) -> ast_Identifier:...
92
105
  @staticmethod
93
106
  @overload
94
- def name(node: astClassOptionallyHasDOTnameNotName) -> ast_Identifier | None:...
107
+ def name(node: astClassHasDOTnameNotNameOptionally) -> ast_Identifier | None:...
95
108
  @staticmethod
96
- def name(node: astClassHasDOTnameNotName | astClassOptionallyHasDOTnameNotName) -> ast_Identifier | None:
109
+ def name(node: astClassHasDOTnameNotName) -> ast_Identifier | None:
97
110
  return node.name
98
111
 
99
112
  @staticmethod
@@ -129,18 +142,16 @@ class be:
129
142
  """
130
143
  Provide type-guard functions for safely verifying AST node types during manipulation.
131
144
 
132
- The be class contains static methods that perform runtime type verification of AST nodes,
133
- returning TypeGuard results that enable static type checkers to narrow node types in
134
- conditional branches. These type-guards:
145
+ The be class contains static methods that perform runtime type verification of AST nodes, returning TypeGuard
146
+ results that enable static type checkers to narrow node types in conditional branches. These type-guards:
135
147
 
136
- 1. Improve code safety by preventing operations on incompatible node types
137
- 2. Enable IDE tooling to provide better autocompletion and error detection
138
- 3. Document expected node types in a way that's enforced by the type system
139
- 4. Support pattern-matching workflows where node types must be verified before access
148
+ 1. Improve code safety by preventing operations on incompatible node types.
149
+ 2. Enable IDE tooling to provide better autocompletion and error detection.
150
+ 3. Document expected node types in a way that's enforced by the type system.
151
+ 4. Support pattern-matching workflows where node types must be verified before access.
140
152
 
141
- When used with conditional statements, these type-guards allow for precise,
142
- type-safe manipulation of AST nodes while maintaining full static type checking
143
- capabilities, even in complex transformation scenarios.
153
+ When used with conditional statements, these type-guards allow for precise, type-safe manipulation of AST nodes
154
+ while maintaining full static type checking capabilities, even in complex transformation scenarios.
144
155
  """
145
156
  @staticmethod
146
157
  def AnnAssign(node: ast.AST) -> TypeGuard[ast.AnnAssign]:
@@ -170,6 +181,14 @@ class be:
170
181
  def ClassDef(node: ast.AST) -> TypeGuard[ast.ClassDef]:
171
182
  return isinstance(node, ast.ClassDef)
172
183
 
184
+ @staticmethod
185
+ def Compare(node: ast.AST) -> TypeGuard[ast.Compare]:
186
+ return isinstance(node, ast.Compare)
187
+
188
+ @staticmethod
189
+ def Constant(node: ast.AST) -> TypeGuard[ast.Constant]:
190
+ return isinstance(node, ast.Constant)
191
+
173
192
  @staticmethod
174
193
  def FunctionDef(node: ast.AST) -> TypeGuard[ast.FunctionDef]:
175
194
  return isinstance(node, ast.FunctionDef)
@@ -178,6 +197,18 @@ class be:
178
197
  def keyword(node: ast.AST) -> TypeGuard[ast.keyword]:
179
198
  return isinstance(node, ast.keyword)
180
199
 
200
+ @staticmethod
201
+ def If(node: ast.AST) -> TypeGuard[ast.If]:
202
+ return isinstance(node, ast.If)
203
+
204
+ @staticmethod
205
+ def Gt(node: ast.AST) -> TypeGuard[ast.Gt]:
206
+ return isinstance(node, ast.Gt)
207
+
208
+ @staticmethod
209
+ def LtE(node: ast.AST) -> TypeGuard[ast.LtE]:
210
+ return isinstance(node, ast.LtE)
211
+
181
212
  @staticmethod
182
213
  def Name(node: ast.AST) -> TypeGuard[ast.Name]:
183
214
  return isinstance(node, ast.Name)
@@ -194,6 +225,14 @@ class be:
194
225
  def Subscript(node: ast.AST) -> TypeGuard[ast.Subscript]:
195
226
  return isinstance(node, ast.Subscript)
196
227
 
228
+ @staticmethod
229
+ def Tuple(node: ast.AST) -> TypeGuard[ast.Tuple]:
230
+ return isinstance(node, ast.Tuple)
231
+
232
+ @staticmethod
233
+ def While(node: ast.AST) -> TypeGuard[ast.While]:
234
+ return isinstance(node, ast.While)
235
+
197
236
  class ifThis:
198
237
  """
199
238
  Provide predicate functions for matching and filtering AST nodes based on various criteria.
@@ -257,6 +296,29 @@ class ifThis:
257
296
  def isAttributeNamespace_Identifier(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Attribute] | bool]:
258
297
  return lambda node: ifThis.isAttributeName(node) and ifThis.isName_Identifier(namespace)(DOT.value(node)) and ifThis._Identifier(identifier)(DOT.attr(node))
259
298
 
299
+ @staticmethod
300
+ def isAttributeNamespace_IdentifierGreaterThan0(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Compare] | bool]:
301
+ return lambda node: (be.Compare(node)
302
+ and ifThis.isAttributeNamespace_Identifier(namespace, identifier)(node.left)
303
+ and be.Gt(node.ops[0])
304
+ and ifThis.isConstant_value(0)(node.comparators[0]))
305
+
306
+ @staticmethod
307
+ def isIfAttributeNamespace_IdentifierGreaterThan0(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.While] | bool]:
308
+ return lambda node: (be.If(node)
309
+ and ifThis.isAttributeNamespace_IdentifierGreaterThan0(namespace, identifier)(node.test))
310
+
311
+ @staticmethod
312
+ def isWhileAttributeNamespace_IdentifierGreaterThan0(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.While] | bool]:
313
+ return lambda node: (be.While(node)
314
+ and ifThis.isAttributeNamespace_IdentifierGreaterThan0(namespace, identifier)(node.test))
315
+
316
+ @staticmethod
317
+ def isAttributeNamespace_IdentifierLessThanOrEqual(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Compare] | bool]:
318
+ return lambda node: (be.Compare(node)
319
+ and ifThis.isAttributeNamespace_Identifier(namespace, identifier)(node.left)
320
+ and be.LtE(node.ops[0]))
321
+
260
322
  @staticmethod
261
323
  def isAugAssign_targetIs(targetPredicate: Callable[[ast.expr], TypeGuard[ast.expr] | bool]) -> Callable[[ast.AST], TypeGuard[ast.AugAssign] | bool]:
262
324
  def workhorse(node: ast.AST) -> TypeGuard[ast.AugAssign] | bool:
@@ -282,6 +344,10 @@ class ifThis:
282
344
  def isClassDef_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.ClassDef] | bool]:
283
345
  return lambda node: be.ClassDef(node) and ifThis._Identifier(identifier)(DOT.name(node))
284
346
 
347
+ @staticmethod
348
+ def isConstant_value(value: Any) -> Callable[[ast.AST], TypeGuard[ast.Constant] | bool]:
349
+ return lambda node: be.Constant(node) and DOT.value(node) == value
350
+
285
351
  @staticmethod
286
352
  def isFunctionDef_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.FunctionDef] | bool]:
287
353
  return lambda node: be.FunctionDef(node) and ifThis._Identifier(identifier)(DOT.name(node))