mapFolding 0.11.2__py3-none-any.whl → 0.11.3__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.
@@ -18,138 +18,18 @@ The containers work in conjunction with transformation tools that manipulate the
18
18
  specific optimizations and transformations.
19
19
  """
20
20
 
21
+ from astToolkit import ast_Identifier, ClassIsAndAttribute, DOT, LedgerOfImports, Make, NodeTourist, str_nameDOTname, Then
21
22
  from collections.abc import Callable
22
- from astToolkit import ClassIsAndAttribute
23
23
  from copy import deepcopy
24
- from mapFolding.someAssemblyRequired import ast_Identifier, DOT, IfThis, Make, NodeTourist, parseLogicalPath2astModule, str_nameDOTname, Then, LedgerOfImports
25
- from mapFolding import raiseIfNoneGitHubIssueNumber3, The
26
- from pathlib import Path, PurePosixPath
24
+ from mapFolding.someAssemblyRequired import IfThis, raiseIfNoneGitHubIssueNumber3
27
25
  from typing import Any, cast
28
26
  import ast
29
27
  import dataclasses
30
28
 
31
- # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
32
- @dataclasses.dataclass
33
- class RecipeSynthesizeFlow:
34
- """
35
- Configure the generation of new modules, including Numba-accelerated code modules.
36
-
37
- RecipeSynthesizeFlow defines the complete blueprint for transforming an original Python algorithm into an optimized,
38
- accelerated implementation. It specifies:
39
-
40
- 1. Source code locations and identifiers.
41
- 2. Target code locations and identifiers.
42
- 3. Naming conventions for generated modules and functions.
43
- 4. File system paths for output files.
44
- 5. Import relationships between components.
45
-
46
- This configuration class serves as a single source of truth for the code generation process, ensuring consistency
47
- across all generated artifacts while enabling customization of the transformation assembly line.
48
-
49
- The transformation process uses this configuration to extract functions from the source module, transform them
50
- according to optimization rules, and output properly structured optimized modules with all necessary imports.
51
- """
52
- # ========================================
53
- # Source
54
- source_astModule: ast.Module = parseLogicalPath2astModule(The.logicalPathModuleSourceAlgorithm)
55
- """AST of the source algorithm module containing the original implementation."""
56
-
57
- # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
58
- sourceCallableDispatcher: ast_Identifier = The.sourceCallableDispatcher
59
- sourceCallableInitialize: ast_Identifier = The.sourceCallableInitialize
60
- sourceCallableParallel: ast_Identifier = The.sourceCallableParallel
61
- sourceCallableSequential: ast_Identifier = The.sourceCallableSequential
62
-
63
- sourceDataclassIdentifier: ast_Identifier = The.dataclassIdentifier
64
- sourceDataclassInstance: ast_Identifier = The.dataclassInstance
65
- sourceDataclassInstanceTaskDistribution: ast_Identifier = The.dataclassInstanceTaskDistribution
66
- sourceLogicalPathModuleDataclass: str_nameDOTname = The.logicalPathModuleDataclass
67
-
68
- sourceConcurrencyManagerNamespace = The.sourceConcurrencyManagerNamespace
69
- sourceConcurrencyManagerIdentifier = The.sourceConcurrencyManagerIdentifier
70
-
71
- # ========================================
72
- # Logical identifiers (as opposed to physical identifiers)
73
- # ========================================
74
- # Package ================================
75
- packageIdentifier: ast_Identifier | None = The.packageName
76
-
77
- # Qualified logical path ================================
78
- logicalPathModuleDataclass: str_nameDOTname = sourceLogicalPathModuleDataclass
79
- logicalPathFlowRoot: ast_Identifier | None = 'syntheticModules'
80
- """ `logicalPathFlowRoot` likely corresponds to a physical filesystem directory."""
81
-
82
- # Module ================================
83
- moduleDispatcher: ast_Identifier = 'numbaCount'
84
- moduleInitialize: ast_Identifier = moduleDispatcher
85
- moduleParallel: ast_Identifier = moduleDispatcher
86
- moduleSequential: ast_Identifier = moduleDispatcher
87
-
88
- # Function ================================
89
- callableDispatcher: ast_Identifier = sourceCallableDispatcher
90
- callableInitialize: ast_Identifier = sourceCallableInitialize
91
- callableParallel: ast_Identifier = sourceCallableParallel
92
- callableSequential: ast_Identifier = sourceCallableSequential
93
- concurrencyManagerNamespace: ast_Identifier = sourceConcurrencyManagerNamespace
94
- concurrencyManagerIdentifier: ast_Identifier = sourceConcurrencyManagerIdentifier
95
- dataclassIdentifier: ast_Identifier = sourceDataclassIdentifier
96
-
97
- # Variable ================================
98
- dataclassInstance: ast_Identifier = sourceDataclassInstance
99
- dataclassInstanceTaskDistribution: ast_Identifier = sourceDataclassInstanceTaskDistribution
100
-
101
- removeDataclassDispatcher: bool = False
102
- removeDataclassInitialize: bool = False
103
- removeDataclassParallel: bool = True
104
- removeDataclassSequential: bool = True
105
- # ========================================
106
- # Computed
107
- # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
108
- # theFormatStrModuleSynthetic = "{packageFlow}Count"
109
- # theFormatStrModuleForCallableSynthetic = theFormatStrModuleSynthetic + "_{callableTarget}"
110
- # theModuleDispatcherSynthetic: ast_Identifier = theFormatStrModuleForCallableSynthetic.format(packageFlow=packageFlowSynthetic, callableTarget=The.sourceCallableDispatcher)
111
- # theLogicalPathModuleDispatcherSynthetic: str = '.'.join([The.packageName, The.moduleOfSyntheticModules, theModuleDispatcherSynthetic])
112
- # logicalPathModuleDispatcher: str = '.'.join([Z0Z_flowLogicalPathRoot, moduleDispatcher])
113
-
114
- # ========================================
115
- # Filesystem (names of physical objects)
116
- pathPackage: PurePosixPath | None = PurePosixPath(The.pathPackage)
117
- fileExtension: str = The.fileExtension
118
-
119
- def _makePathFilename(self, filenameStem: str,
120
- pathRoot: PurePosixPath | None = None,
121
- logicalPathINFIX: str_nameDOTname | None = None,
122
- fileExtension: str | None = None,
123
- ) -> PurePosixPath:
124
- """filenameStem: (hint: the name of the logical module)"""
125
- if pathRoot is None:
126
- pathRoot = self.pathPackage or PurePosixPath(Path.cwd())
127
- if logicalPathINFIX:
128
- whyIsThisStillAThing: list[str] = logicalPathINFIX.split('.')
129
- pathRoot = pathRoot.joinpath(*whyIsThisStillAThing)
130
- if fileExtension is None:
131
- fileExtension = self.fileExtension
132
- filename: str = filenameStem + fileExtension
133
- return pathRoot.joinpath(filename)
134
-
135
- @property
136
- def pathFilenameDispatcher(self) -> PurePosixPath:
137
- return self._makePathFilename(filenameStem=self.moduleDispatcher, logicalPathINFIX=self.logicalPathFlowRoot)
138
- @property
139
- def pathFilenameInitialize(self) -> PurePosixPath:
140
- return self._makePathFilename(filenameStem=self.moduleInitialize, logicalPathINFIX=self.logicalPathFlowRoot)
141
- @property
142
- def pathFilenameParallel(self) -> PurePosixPath:
143
- return self._makePathFilename(filenameStem=self.moduleParallel, logicalPathINFIX=self.logicalPathFlowRoot)
144
- @property
145
- def pathFilenameSequential(self) -> PurePosixPath:
146
- return self._makePathFilename(filenameStem=self.moduleSequential, logicalPathINFIX=self.logicalPathFlowRoot)
147
-
148
29
  dummyAssign = Make.Assign([Make.Name("dummyTarget")], Make.Constant(None))
149
30
  dummySubscript = Make.Subscript(Make.Name("dummy"), Make.Name("slice"))
150
31
  dummyTuple = Make.Tuple([Make.Name("dummyElement")])
151
32
 
152
- # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
153
33
  @dataclasses.dataclass
154
34
  class ShatteredDataclass:
155
35
  countingVariableAnnotation: ast.expr
@@ -1,27 +1,13 @@
1
- from collections.abc import Callable
2
- from importlib import import_module as importlib_import_module
3
- from mapFolding import ComputationState, PackageSettings
4
- from types import ModuleType
1
+ from mapFolding import PackageSettings
5
2
  import dataclasses
6
3
 
7
4
  @dataclasses.dataclass
8
5
  class PackageInformation(PackageSettings):
9
- """
10
- In _all_ of the root directory and "syntheticModules", the _only_ `PackageInformation` that are used are:
11
- The.concurrencyPackage
12
- The.dispatcher
13
- """
14
-
15
- logicalPathModuleDispatcher: str | None = None
16
- """Logical import path to the module containing the dispatcher function."""
17
-
18
- callableDispatcher: str | None = None
6
+ callableDispatcher: str = 'doTheNeedful'
19
7
  """Name of the function within the dispatcher module that will be called."""
20
8
 
21
- concurrencyPackage: str | None = None
22
- """Package to use for concurrent execution (e.g., 'multiprocessing', 'numba')."""
23
-
24
- # "Evaluate When Packaging" and "Evaluate When Installing" https://github.com/hunterhogan/mapFolding/issues/18
9
+ # "Evaluate When Packaging" and "Evaluate When Installing"
10
+ # https://github.com/hunterhogan/mapFolding/issues/18
25
11
  dataclassIdentifier: str = dataclasses.field(default='ComputationState', metadata={'evaluateWhen': 'packaging'})
26
12
  """Name of the dataclass used to track computation state."""
27
13
 
@@ -70,14 +56,6 @@ class PackageInformation(PackageSettings):
70
56
  logicalPathModuleSourceAlgorithm: str = dataclasses.field(default=None, metadata={'evaluateWhen': 'packaging'}) # pyright: ignore[reportAssignmentType]
71
57
  """Fully qualified import path to the module containing the source algorithm."""
72
58
 
73
- @property
74
- def dispatcher(self) -> Callable[['ComputationState'], 'ComputationState']:
75
- """ _The_ callable that connects `countFolds` to the logic that does the work."""
76
- logicalPath: str = self.logicalPathModuleDispatcher or self.logicalPathModuleSourceAlgorithm
77
- identifier: str = self.callableDispatcher or self.sourceCallableDispatcher
78
- moduleImported: ModuleType = importlib_import_module(logicalPath)
79
- return getattr(moduleImported, identifier)
80
-
81
59
  def __post_init__(self) -> None:
82
60
  if self.dataclassInstanceTaskDistribution is None: # pyright: ignore[reportUnnecessaryComparison]
83
61
  self.dataclassInstanceTaskDistribution = self.dataclassInstance + self.dataclassInstanceTaskDistributionSuffix
@@ -89,8 +67,4 @@ class PackageInformation(PackageSettings):
89
67
 
90
68
  class raiseIfNoneGitHubIssueNumber3(Exception): pass
91
69
 
92
- logicalPathModuleDispatcherHARDCODED: str = 'mapFolding.syntheticModules.numbaCount'
93
- callableDispatcherHARDCODED: str = 'doTheNeedful'
94
- concurrencyPackageHARDCODED = 'multiprocessing'
95
-
96
- The = PackageInformation(logicalPathModuleDispatcher=logicalPathModuleDispatcherHARDCODED, callableDispatcher=callableDispatcherHARDCODED, concurrencyPackage=concurrencyPackageHARDCODED)
70
+ packageInformation = PackageInformation()
@@ -1,10 +1,10 @@
1
- from astToolkit import ClassIsAndAttribute
2
- from mapFolding import getPathFilenameFoldsTotal, raiseIfNoneGitHubIssueNumber3, The, MapFoldingState
3
- from mapFolding.someAssemblyRequired import (
1
+ from mapFolding import getPathFilenameFoldsTotal, MapFoldingState
2
+ from mapFolding.someAssemblyRequired import IfThis, packageInformation, raiseIfNoneGitHubIssueNumber3
3
+ from astToolkit import (
4
4
  ast_Identifier,
5
5
  Be,
6
+ ClassIsAndAttribute,
6
7
  extractFunctionDef,
7
- IfThis,
8
8
  IngredientsFunction,
9
9
  IngredientsModule,
10
10
  LedgerOfImports,
@@ -13,10 +13,10 @@ from mapFolding.someAssemblyRequired import (
13
13
  NodeTourist,
14
14
  str_nameDOTname,
15
15
  Then,
16
- write_astModule,
17
16
  )
17
+ from astToolkit.transformationTools import write_astModule
18
18
  from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2Numba
19
- from mapFolding.someAssemblyRequired.toolkitNumba import parametersNumbaLight, SpicesJobNumba, decorateCallableWithNumba
19
+ from mapFolding.someAssemblyRequired.toolkitNumba import decorateCallableWithNumba, parametersNumbaLight, SpicesJobNumba
20
20
  from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
21
21
  from pathlib import PurePosixPath
22
22
  from typing import cast, NamedTuple
@@ -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 = ClassIsAndAttribute.targetIs(ast.AugAssign, IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id)) # type: ignore
80
+ findThis = ClassIsAndAttribute.targetIs(ast.AugAssign, 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)
@@ -184,7 +184,7 @@ def makeJobNumba(job: RecipeJobTheorem2Numba, spices: SpicesJobNumba) -> None:
184
184
  if __name__ == '__main__':
185
185
  import time
186
186
  timeStart = time.perf_counter()
187
- foldsTotal = {job.countCallable}() * {job.state.leavesTotal}
187
+ foldsTotal = int({job.countCallable}() * {job.state.leavesTotal})
188
188
  print(time.perf_counter() - timeStart)
189
189
  print('\\nmap {job.state.mapShape} =', foldsTotal)
190
190
  writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
@@ -267,7 +267,7 @@ if __name__ == '__main__':
267
267
  # foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal
268
268
  # foldsTotalEstimated = dictionaryEstimates[state.mapShape] // state.leavesTotal
269
269
  foldsTotalEstimated = 0
270
- pathModule = PurePosixPath(The.pathPackage, 'jobs')
270
+ pathModule = PurePosixPath(packageInformation.pathPackage, 'jobs')
271
271
  pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
272
272
  aJob = RecipeJobTheorem2Numba(state, foldsTotalEstimated, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
273
273
  spices = SpicesJobNumba(useNumbaProgressBar=False, parametersNumba=parametersNumbaLight)
@@ -17,16 +17,13 @@ performance improvements while preserving code semantics and correctness.
17
17
 
18
18
  from collections.abc import Callable, Sequence
19
19
  from mapFolding import NotRequired, TypedDict
20
- from mapFolding.someAssemblyRequired import ast_Identifier, IngredientsFunction, Make, RecipeSynthesizeFlow, str_nameDOTname, write_astModule
21
- from mapFolding.someAssemblyRequired.transformationTools import makeNewFlow
20
+ from astToolkit import ast_Identifier, IngredientsFunction, Make, str_nameDOTname
21
+ from astToolkit.transformationTools import write_astModule
22
22
  from numba.core.compiler import CompilerBase as numbaCompilerBase
23
23
  from typing import Any, cast, Final
24
24
  import ast
25
25
  import dataclasses
26
26
 
27
- # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
28
- theNumbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()
29
-
30
27
  class ParametersNumba(TypedDict):
31
28
  _dbg_extend_lifetimes: NotRequired[bool]
32
29
  _dbg_optnone: NotRequired[bool]
@@ -128,47 +125,8 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
128
125
  ingredientsFunction.astFunctionDef.decorator_list = [astDecorator]
129
126
  return ingredientsFunction
130
127
 
131
- # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
132
128
  @dataclasses.dataclass
133
129
  class SpicesJobNumba:
134
130
  useNumbaProgressBar: bool = True
135
131
  numbaProgressBarIdentifier: ast_Identifier = 'ProgressBarGroupsOfFolds'
136
132
  parametersNumba: ParametersNumba = dataclasses.field(default_factory=ParametersNumba) # type: ignore
137
-
138
- # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
139
- def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
140
- """
141
- Transform standard Python algorithm code into optimized Numba implementations.
142
-
143
- This function implements the complete transformation assembly line that converts
144
- a conventional Python implementation into a high-performance Numba-accelerated
145
- version. The process includes:
146
-
147
- 1. Extracting core algorithm functions from the source module
148
- 2. Inlining function calls to create self-contained implementations
149
- 3. Transforming dataclass access patterns for Numba compatibility
150
- 4. Applying appropriate Numba decorators with optimization settings
151
- 5. Generating a unified module with sequential and parallel implementations
152
- 6. Writing the transformed code to the filesystem with properly managed imports
153
-
154
- The transformation preserves the logical structure and semantics of the original
155
- implementation while making it compatible with Numba's constraints and
156
- optimization capabilities. This creates a bridge between the general-purpose
157
- implementation and the highly-optimized version needed for production use.
158
-
159
- Parameters:
160
- numbaFlow: Configuration object that specifies all aspects of the
161
- transformation process, including source and target locations,
162
- function and variable names, and output paths.
163
- """
164
-
165
- ingredientsModuleNumbaUnified = makeNewFlow(numbaFlow)
166
-
167
- # numba decorators =========================================
168
- ingredientsModuleNumbaUnified.listIngredientsFunctions[1] = decorateCallableWithNumba(ingredientsModuleNumbaUnified.listIngredientsFunctions[1])
169
- ingredientsModuleNumbaUnified.listIngredientsFunctions[2] = decorateCallableWithNumba(ingredientsModuleNumbaUnified.listIngredientsFunctions[2])
170
-
171
- write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.packageIdentifier)
172
-
173
- if __name__ == '__main__':
174
- makeNumbaFlow(theNumbaFlow)
@@ -18,78 +18,27 @@ readable, maintainable implementations to highly optimized versions while preser
18
18
  logical structure and correctness.
19
19
  """
20
20
 
21
- from collections.abc import Callable
22
21
  from astToolkit import ClassIsAndAttribute
23
- from mapFolding import outfitCountFolds, ComputationState, The, getPathFilenameFoldsTotal
24
22
  from mapFolding.someAssemblyRequired import (
23
+ DeReConstructField2ast,
24
+ IfThis,
25
+ ShatteredDataclass,
26
+ )
27
+ from astToolkit import(
25
28
  ast_Identifier,
26
- astModuleToIngredientsFunction,
27
29
  Be,
28
- DeReConstructField2ast,
29
30
  extractClassDef,
30
- Grab,
31
- IfThis,
32
- importLogicalPath2Callable,
33
31
  IngredientsFunction,
34
- IngredientsModule,
35
- inlineFunctionDef,
36
- LedgerOfImports,
37
32
  Make,
38
33
  NodeChanger,
39
- NodeTourist,
40
34
  parseLogicalPath2astModule,
41
- RecipeSynthesizeFlow,
42
- removeUnusedParameters,
43
- ShatteredDataclass,
44
35
  str_nameDOTname,
45
36
  Then,
46
- unparseFindReplace,
47
37
  )
48
- from os import PathLike
49
- from pathlib import Path, PurePath
50
- from typing import Any, Literal, overload
38
+ from astToolkit.transformationTools import unparseFindReplace
39
+ from Z0Z_tools import importLogicalPath2Callable
51
40
  import ast
52
41
  import dataclasses
53
- import pickle
54
-
55
- @overload
56
- def makeInitializedComputationState(mapShape: tuple[int, ...], writeJob: Literal[True], *, pathFilename: PathLike[str] | PurePath | None = None, **keywordArguments: Any) -> Path: ...
57
- @overload
58
- def makeInitializedComputationState(mapShape: tuple[int, ...], writeJob: Literal[False] = False, **keywordArguments: Any) -> ComputationState: ...
59
- def makeInitializedComputationState(mapShape: tuple[int, ...], writeJob: bool = False, *, pathFilename: PathLike[str] | PurePath | None = None, **keywordArguments: Any) -> ComputationState | Path:
60
- """
61
- Initializes a computation state and optionally saves it to disk.
62
-
63
- This function initializes a computation state using the source algorithm.
64
-
65
- Hint: If you want an uninitialized state, call `outfitCountFolds` directly.
66
-
67
- Parameters:
68
- mapShape: List of integers representing the dimensions of the map to be folded.
69
- writeJob (False): Whether to save the state to disk.
70
- pathFilename (getPathFilenameFoldsTotal.pkl): The path and filename to save the state. If None, uses a default path.
71
- **keywordArguments: computationDivisions:int|str|None=None,concurrencyLimit:int=1.
72
- Returns:
73
- stateUniversal|pathFilenameJob: The computation state for the map folding calculations, or
74
- the path to the saved state file if writeJob is True.
75
- """
76
- stateUniversal: ComputationState = outfitCountFolds(mapShape, **keywordArguments)
77
-
78
- initializeState = importLogicalPath2Callable(The.logicalPathModuleSourceAlgorithm, The.sourceCallableInitialize)
79
- stateUniversal = initializeState(stateUniversal)
80
-
81
- if not writeJob:
82
- return stateUniversal
83
-
84
- if pathFilename:
85
- pathFilenameJob = Path(pathFilename)
86
- pathFilenameJob.parent.mkdir(parents=True, exist_ok=True)
87
- else:
88
- pathFilenameJob = getPathFilenameFoldsTotal(stateUniversal.mapShape).with_suffix('.pkl')
89
-
90
- # Fix code scanning alert - Consider possible security implications associated with pickle module. #17
91
- pathFilenameJob.write_bytes(pickle.dumps(stateUniversal))
92
- return pathFilenameJob
93
42
 
94
43
  def shatter_dataclassesDOTdataclass(logicalPathModule: str_nameDOTname, dataclass_Identifier: ast_Identifier, instance_Identifier: ast_Identifier) -> ShatteredDataclass:
95
44
  """
@@ -161,114 +110,6 @@ def shatter_dataclassesDOTdataclass(logicalPathModule: str_nameDOTname, dataclas
161
110
  return shatteredDataclass
162
111
 
163
112
  # END of acceptable classes and functions ======================================================
164
- def makeNewFlow(recipeFlow: RecipeSynthesizeFlow) -> IngredientsModule:
165
- # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
166
- listAllIngredientsFunctions = [
167
- (ingredientsInitialize := astModuleToIngredientsFunction(recipeFlow.source_astModule, recipeFlow.sourceCallableInitialize)),
168
- (ingredientsParallel := astModuleToIngredientsFunction(recipeFlow.source_astModule, recipeFlow.sourceCallableParallel)),
169
- (ingredientsSequential := astModuleToIngredientsFunction(recipeFlow.source_astModule, recipeFlow.sourceCallableSequential)),
170
- (ingredientsDispatcher := astModuleToIngredientsFunction(recipeFlow.source_astModule, recipeFlow.sourceCallableDispatcher)),
171
- ]
172
-
173
- # Inline functions ========================================================
174
- # NOTE Replacements statements are based on the identifiers in the _source_, so operate on the source identifiers.
175
- ingredientsInitialize.astFunctionDef = inlineFunctionDef(recipeFlow.sourceCallableInitialize, recipeFlow.source_astModule)
176
- ingredientsParallel.astFunctionDef = inlineFunctionDef(recipeFlow.sourceCallableParallel, recipeFlow.source_astModule)
177
- ingredientsSequential.astFunctionDef = inlineFunctionDef(recipeFlow.sourceCallableSequential, recipeFlow.source_astModule)
178
-
179
- # assignRecipeIdentifiersToCallable. =============================
180
- # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
181
- # How can I use dataclass settings as the SSOT for specific actions? https://github.com/hunterhogan/mapFolding/issues/16
182
- # NOTE reminder: you are updating these `ast.Name` here (and not in a more general search) because this is a
183
- # narrow search for `ast.Call` so you won't accidentally replace unrelated `ast.Name`.
184
- listFindReplace = [(recipeFlow.sourceCallableDispatcher, recipeFlow.callableDispatcher),
185
- (recipeFlow.sourceCallableInitialize, recipeFlow.callableInitialize),
186
- (recipeFlow.sourceCallableParallel, recipeFlow.callableParallel),
187
- (recipeFlow.sourceCallableSequential, recipeFlow.callableSequential),]
188
- for ingredients in listAllIngredientsFunctions:
189
- for source_Identifier, recipe_Identifier in listFindReplace:
190
- updateCallName = NodeChanger(IfThis.isCall_Identifier(source_Identifier), Grab.funcAttribute(Then.replaceWith(Make.Name(recipe_Identifier))))
191
- updateCallName.visit(ingredients.astFunctionDef)
192
-
193
- ingredientsDispatcher.astFunctionDef.name = recipeFlow.callableDispatcher
194
- ingredientsInitialize.astFunctionDef.name = recipeFlow.callableInitialize
195
- ingredientsParallel.astFunctionDef.name = recipeFlow.callableParallel
196
- ingredientsSequential.astFunctionDef.name = recipeFlow.callableSequential
197
-
198
- # Assign identifiers per the recipe. ==============================
199
- listFindReplace = [(recipeFlow.sourceDataclassInstance, recipeFlow.dataclassInstance),
200
- (recipeFlow.sourceDataclassInstanceTaskDistribution, recipeFlow.dataclassInstanceTaskDistribution),
201
- (recipeFlow.sourceConcurrencyManagerNamespace, recipeFlow.concurrencyManagerNamespace),]
202
- for ingredients in listAllIngredientsFunctions:
203
- for source_Identifier, recipe_Identifier in listFindReplace:
204
- updateName = NodeChanger(IfThis.isName_Identifier(source_Identifier) , Grab.idAttribute(Then.replaceWith(recipe_Identifier)))
205
- update_arg = NodeChanger(IfThis.isArgument_Identifier(source_Identifier), Grab.argAttribute(Then.replaceWith(recipe_Identifier)))
206
- updateName.visit(ingredients.astFunctionDef)
207
- update_arg.visit(ingredients.astFunctionDef)
208
-
209
- updateConcurrencyManager = NodeChanger(IfThis.isCallAttributeNamespace_Identifier(recipeFlow.sourceConcurrencyManagerNamespace, recipeFlow.sourceConcurrencyManagerIdentifier)
210
- , Grab.funcAttribute(Then.replaceWith(Make.Attribute(Make.Name(recipeFlow.concurrencyManagerNamespace), recipeFlow.concurrencyManagerIdentifier))))
211
- updateConcurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
212
-
213
- # shatter Dataclass =======================================================
214
- instance_Identifier = recipeFlow.dataclassInstance
215
- getTheOtherRecord_damn = recipeFlow.dataclassInstanceTaskDistribution
216
- shatteredDataclass = shatter_dataclassesDOTdataclass(recipeFlow.logicalPathModuleDataclass, recipeFlow.sourceDataclassIdentifier, instance_Identifier)
217
- ingredientsDispatcher.imports.update(shatteredDataclass.imports)
218
-
219
- # How can I use dataclass settings as the SSOT for specific actions? https://github.com/hunterhogan/mapFolding/issues/16
220
- # Change callable parameters and Call to the callable at the same time ====
221
- # sequentialCallable =========================================================
222
- if recipeFlow.removeDataclassSequential:
223
- ingredientsSequential = removeDataclassFromFunction(ingredientsSequential, shatteredDataclass)
224
- ingredientsDispatcher = unpackDataclassCallFunctionRepackDataclass(ingredientsDispatcher, recipeFlow.callableSequential, shatteredDataclass)
225
-
226
- if recipeFlow.removeDataclassInitialize:
227
- ingredientsInitialize = removeDataclassFromFunction(ingredientsInitialize, shatteredDataclass)
228
- ingredientsDispatcher = unpackDataclassCallFunctionRepackDataclass(ingredientsDispatcher, recipeFlow.callableInitialize, shatteredDataclass)
229
-
230
- # parallelCallable =========================================================
231
- if recipeFlow.removeDataclassParallel:
232
- ingredientsParallel.astFunctionDef.args = Make.arguments(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
233
-
234
- ingredientsParallel.astFunctionDef = unparseFindReplace(ingredientsParallel.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
235
-
236
- ingredientsParallel = removeUnusedParameters(ingredientsParallel)
237
-
238
- list_argCuzMyBrainRefusesToThink = ingredientsParallel.astFunctionDef.args.args + ingredientsParallel.astFunctionDef.args.posonlyargs + ingredientsParallel.astFunctionDef.args.kwonlyargs
239
- list_arg_arg: list[ast_Identifier] = [ast_arg.arg for ast_arg in list_argCuzMyBrainRefusesToThink]
240
-
241
- listParameters = [parameter for parameter in shatteredDataclass.listName4Parameters if parameter.id in list_arg_arg]
242
-
243
- replaceCall2concurrencyManager = NodeChanger(IfThis.isCallAttributeNamespace_Identifier(recipeFlow.concurrencyManagerNamespace, recipeFlow.concurrencyManagerIdentifier), Then.replaceWith(Make.Call(Make.Attribute(Make.Name(recipeFlow.concurrencyManagerNamespace), recipeFlow.concurrencyManagerIdentifier), [Make.Name(recipeFlow.callableParallel)] + listParameters)))
244
-
245
- def getIt(astCallConcurrencyResult: list[ast.Call]) -> Callable[[ast.AST], ast.AST]:
246
- # TODO I cannot remember why I made this function. It doesn't fit with how I normally do things.
247
- def workhorse(node: ast.AST) -> ast.AST:
248
- NodeTourist(Be.Call, Then.appendTo(astCallConcurrencyResult)).visit(node)
249
- return node
250
- return workhorse
251
-
252
- # NOTE I am dissatisfied with this logic for many reasons, including that it requires separate NodeCollector and NodeReplacer instances.
253
- astCallConcurrencyResult: list[ast.Call] = []
254
- get_astCallConcurrencyResult = NodeTourist(IfThis.isAssignAndTargets0Is(IfThis.isSubscript_Identifier(getTheOtherRecord_damn)), getIt(astCallConcurrencyResult))
255
- get_astCallConcurrencyResult.visit(ingredientsDispatcher.astFunctionDef)
256
- replaceAssignParallelCallable = NodeChanger(IfThis.isAssignAndTargets0Is(IfThis.isSubscript_Identifier(getTheOtherRecord_damn)), Grab.valueAttribute(Then.replaceWith(astCallConcurrencyResult[0])))
257
- replaceAssignParallelCallable.visit(ingredientsDispatcher.astFunctionDef)
258
- changeReturnParallelCallable = NodeChanger(Be.Return, Then.replaceWith(Make.Return(shatteredDataclass.countingVariableName)))
259
- ingredientsParallel.astFunctionDef.returns = shatteredDataclass.countingVariableAnnotation
260
-
261
- unpack4parallelCallable = NodeChanger(ClassIsAndAttribute.valueIs(ast.Assign, IfThis.isCallAttributeNamespace_Identifier(recipeFlow.concurrencyManagerNamespace, recipeFlow.concurrencyManagerIdentifier)), Then.insertThisAbove(shatteredDataclass.listUnpack))
262
-
263
- unpack4parallelCallable.visit(ingredientsDispatcher.astFunctionDef)
264
- replaceCall2concurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
265
- changeReturnParallelCallable.visit(ingredientsParallel.astFunctionDef)
266
-
267
- # Module-level transformations ===========================================================
268
- ingredientsModuleNumbaUnified = IngredientsModule(ingredientsFunction=listAllIngredientsFunctions, imports=LedgerOfImports(recipeFlow.source_astModule))
269
- ingredientsModuleNumbaUnified.removeImportFromModule('numpy')
270
-
271
- return ingredientsModuleNumbaUnified
272
113
 
273
114
  def removeDataclassFromFunction(ingredientsTarget: IngredientsFunction, shatteredDataclass: ShatteredDataclass) -> IngredientsFunction:
274
115
  ingredientsTarget.astFunctionDef.args = Make.arguments(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
mapFolding/theSSOT.py CHANGED
@@ -5,25 +5,30 @@ from tomli import load as tomli_load
5
5
  import dataclasses
6
6
 
7
7
  packageNamePACKAGING_HARDCODED = "mapFolding"
8
+ concurrencyPackageHARDCODED = 'multiprocessing'
8
9
 
9
- # Evaluate When Packaging https://github.com/hunterhogan/mapFolding/issues/18
10
+ # Evaluate When Packaging
11
+ # https://github.com/hunterhogan/mapFolding/issues/18
10
12
  try:
11
13
  packageNamePACKAGING: str = tomli_load(Path("../pyproject.toml").open('rb'))["project"]["name"]
12
14
  except Exception:
13
15
  packageNamePACKAGING = packageNamePACKAGING_HARDCODED
14
16
 
15
- # Evaluate When Installing https://github.com/hunterhogan/mapFolding/issues/18
17
+ # Evaluate When Installing
18
+ # https://github.com/hunterhogan/mapFolding/issues/18
16
19
  def getPathPackageINSTALLING() -> Path:
17
20
  pathPackage: Path = Path(inspect_getfile(importlib_import_module(packageNamePACKAGING)))
18
21
  if pathPackage.is_file():
19
22
  pathPackage = pathPackage.parent
20
23
  return pathPackage
21
24
 
22
- # PackageSettings in theSSOT.py and immutability https://github.com/hunterhogan/mapFolding/issues/11
23
25
  @dataclasses.dataclass
24
26
  class PackageSettings:
25
27
  fileExtension: str = dataclasses.field(default='.py', metadata={'evaluateWhen': 'installing'})
26
28
  packageName: str = dataclasses.field(default = packageNamePACKAGING, metadata={'evaluateWhen': 'packaging'})
27
29
  pathPackage: Path = dataclasses.field(default_factory=getPathPackageINSTALLING, metadata={'evaluateWhen': 'installing'})
30
+ concurrencyPackage: str | None = None
31
+ """Package to use for concurrent execution (e.g., 'multiprocessing', 'numba')."""
28
32
 
29
- packageSettings = PackageSettings()
33
+ concurrencyPackage = concurrencyPackageHARDCODED
34
+ packageSettings = PackageSettings(concurrencyPackage=concurrencyPackage)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapFolding
3
- Version: 0.11.2
3
+ Version: 0.11.3
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
@@ -33,8 +33,6 @@ Description-Content-Type: text/markdown
33
33
  License-File: LICENSE
34
34
  Requires-Dist: astToolkit
35
35
  Requires-Dist: autoflake
36
- Requires-Dist: cytoolz
37
- Requires-Dist: more_itertools
38
36
  Requires-Dist: numba_progress
39
37
  Requires-Dist: numba
40
38
  Requires-Dist: numpy
@@ -42,7 +40,6 @@ Requires-Dist: platformdirs
42
40
  Requires-Dist: python_minifier
43
41
  Requires-Dist: sympy
44
42
  Requires-Dist: tomli
45
- Requires-Dist: typeshed_client
46
43
  Requires-Dist: Z0Z_tools
47
44
  Provides-Extra: testing
48
45
  Requires-Dist: mypy; extra == "testing"