mapFolding 0.8.6__py3-none-any.whl → 0.9.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 (31) hide show
  1. mapFolding/__init__.py +60 -13
  2. mapFolding/basecamp.py +32 -17
  3. mapFolding/beDRY.py +3 -3
  4. mapFolding/oeis.py +83 -2
  5. mapFolding/someAssemblyRequired/__init__.py +48 -27
  6. mapFolding/someAssemblyRequired/_theTypes.py +11 -15
  7. mapFolding/someAssemblyRequired/_tool_Make.py +35 -8
  8. mapFolding/someAssemblyRequired/_tool_Then.py +59 -25
  9. mapFolding/someAssemblyRequired/_toolboxAntecedents.py +151 -276
  10. mapFolding/someAssemblyRequired/_toolboxContainers.py +133 -48
  11. mapFolding/someAssemblyRequired/_toolboxPython.py +165 -44
  12. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +101 -18
  13. mapFolding/someAssemblyRequired/toolboxNumba.py +83 -48
  14. mapFolding/someAssemblyRequired/transformationTools.py +220 -138
  15. mapFolding/theSSOT.py +147 -54
  16. mapFolding/toolboxFilesystem.py +1 -1
  17. mapfolding-0.9.0.dist-info/METADATA +177 -0
  18. mapfolding-0.9.0.dist-info/RECORD +46 -0
  19. tests/__init__.py +44 -0
  20. tests/conftest.py +75 -7
  21. tests/test_computations.py +90 -9
  22. tests/test_filesystem.py +32 -33
  23. tests/test_other.py +0 -1
  24. tests/test_tasks.py +1 -1
  25. mapFolding/someAssemblyRequired/newInliner.py +0 -22
  26. mapfolding-0.8.6.dist-info/METADATA +0 -190
  27. mapfolding-0.8.6.dist-info/RECORD +0 -47
  28. {mapfolding-0.8.6.dist-info → mapfolding-0.9.0.dist-info}/WHEEL +0 -0
  29. {mapfolding-0.8.6.dist-info → mapfolding-0.9.0.dist-info}/entry_points.txt +0 -0
  30. {mapfolding-0.8.6.dist-info → mapfolding-0.9.0.dist-info}/licenses/LICENSE +0 -0
  31. {mapfolding-0.8.6.dist-info → mapfolding-0.9.0.dist-info}/top_level.txt +0 -0
mapFolding/__init__.py CHANGED
@@ -11,36 +11,83 @@ Core modules:
11
11
  - basecamp: Public API with simplified interfaces for end users
12
12
  - theDao: Core computational algorithm using a functional state-transformation approach
13
13
  - beDRY: Core utility functions implementing consistent data handling, validation, and
14
- resource management across the package's computational assembly-line
14
+ resource management across the package's computational assembly-line
15
15
  - theSSOT: Single Source of Truth for configuration, types, and state management
16
16
  - toolboxFilesystem: Cross-platform file management services for storing and retrieving
17
- computation results with robust error handling and fallback mechanisms
17
+ computation results with robust error handling and fallback mechanisms
18
18
  - oeis: Interface to the Online Encyclopedia of Integer Sequences for known results
19
19
 
20
20
  Extended functionality:
21
21
  - someAssemblyRequired: Code transformation framework that optimizes the core algorithm
22
- through AST manipulation, dataclass transformation, and compilation techniques
22
+ through AST manipulation, dataclass transformation, and compilation techniques
23
+ - The system converts readable code into high-performance implementations through
24
+ a systematic analysis and transformation pipeline
25
+ - Provides tools to "shatter" complex dataclasses into primitive components,
26
+ enabling compatibility with Numba and other optimization frameworks
27
+ - Creates specialized implementations tailored for specific input parameters
28
+
29
+ Testing and extension:
30
+ - tests: Comprehensive test suite designed for both verification and extension
31
+ - Provides fixtures and utilities that simplify testing of custom implementations
32
+ - Enables users to validate their own recipes and job configurations with minimal code
33
+ - Offers standardized testing patterns that maintain consistency across the codebase
34
+ - See tests/__init__.py for detailed documentation on extending the test suite
23
35
 
24
36
  Special directories:
25
37
  - .cache/: Stores cached data from external sources like OEIS to improve performance
26
38
  - syntheticModules/: Contains dynamically generated, optimized implementations of the
27
- core algorithm created by the code transformation framework
39
+ core algorithm created by the code transformation framework
28
40
  - reference/: Historical implementations and educational resources for algorithm exploration
29
- - reference/jobsCompleted/: Contains successful computations for previously unknown values,
30
- including first-ever calculations for 2x19 and 2x20 maps (OEIS A001415)
41
+ - reference/jobsCompleted/: Contains successful computations for previously unknown values,
42
+ including first-ever calculations for 2x19 and 2x20 maps (OEIS A001415)
31
43
 
32
44
  This package balances algorithm readability and understandability with
33
45
  high-performance computation capabilities, allowing users to compute map folding
34
46
  totals for larger dimensions than previously feasible while also providing
35
47
  a foundation for exploring advanced code transformation techniques.
36
48
  """
37
- from mapFolding.basecamp import countFolds
38
- from mapFolding.oeis import clearOEIScache, getOEISids, OEIS_for_n, oeisIDfor_n
39
49
 
40
50
  __all__ = [
41
- 'clearOEIScache',
42
- 'countFolds',
43
- 'getOEISids',
44
- 'OEIS_for_n',
45
- 'oeisIDfor_n',
51
+ 'clearOEIScache',
52
+ 'countFolds',
53
+ 'getOEISids',
54
+ 'OEIS_for_n',
55
+ 'oeisIDfor_n',
46
56
  ]
57
+
58
+ from mapFolding.theSSOT import (
59
+ Array1DElephino,
60
+ Array1DFoldsTotal,
61
+ Array1DLeavesTotal,
62
+ Array3D,
63
+ ComputationState,
64
+ DatatypeElephino,
65
+ DatatypeFoldsTotal,
66
+ DatatypeLeavesTotal,
67
+ NumPyElephino,
68
+ NumPyFoldsTotal,
69
+ NumPyIntegerType,
70
+ NumPyLeavesTotal,
71
+ raiseIfNoneGitHubIssueNumber3,
72
+ The,
73
+ )
74
+
75
+ from mapFolding.theDao import countInitialize, doTheNeedful
76
+
77
+ from mapFolding.beDRY import (
78
+ outfitCountFolds,
79
+ setProcessorLimit,
80
+ validateListDimensions,
81
+ )
82
+
83
+ from mapFolding.toolboxFilesystem import (
84
+ getPathFilenameFoldsTotal,
85
+ getPathRootJobDEFAULT,
86
+ saveFoldsTotal,
87
+ saveFoldsTotalFAILearly,
88
+ writeStringToHere,
89
+ )
90
+
91
+ from mapFolding.basecamp import countFolds
92
+
93
+ from mapFolding.oeis import clearOEIScache, getFoldsTotalKnown, getOEISids, OEIS_for_n, oeisIDfor_n
mapFolding/basecamp.py CHANGED
@@ -13,9 +13,16 @@ implementation, and optional persistence of results.
13
13
  """
14
14
 
15
15
  from collections.abc import Sequence
16
- from mapFolding.theSSOT import ComputationState, getPackageDispatcher, The
17
- from mapFolding.beDRY import outfitCountFolds, setProcessorLimit, validateListDimensions
18
- from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal, saveFoldsTotal, saveFoldsTotalFAILearly
16
+ from mapFolding import (
17
+ ComputationState,
18
+ getPathFilenameFoldsTotal,
19
+ outfitCountFolds,
20
+ saveFoldsTotal,
21
+ saveFoldsTotalFAILearly,
22
+ setProcessorLimit,
23
+ The,
24
+ validateListDimensions,
25
+ )
19
26
  from os import PathLike
20
27
  from pathlib import PurePath
21
28
 
@@ -24,18 +31,27 @@ def countFolds(listDimensions: Sequence[int]
24
31
  , computationDivisions: int | str | None = None
25
32
  , CPUlimit: int | float | bool | None = None
26
33
  ) -> int:
27
- """Count the total number of possible foldings for a given map dimensions.
34
+ """
35
+ Count the total number of possible foldings for a given map dimensions.
36
+
37
+ This function serves as the main public interface to the map folding algorithm,
38
+ handling all parameter validation, computation state management, and result
39
+ persistence in a user-friendly way.
28
40
 
29
- Parameters:
30
- listDimensions: List of integers representing the dimensions of the map to be folded.
31
- pathLikeWriteFoldsTotal (None): Path, filename, or pathFilename to write the total fold count to.
32
- If a directory is provided, creates a file with a default name based on map dimensions.
33
- computationDivisions (None):
34
- Whether and how to divide the computational work. See notes for details.
35
- CPUlimit (None): This is only relevant if there are `computationDivisions`: whether and how to limit the CPU usage. See notes for details.
36
- Returns:
37
- foldsTotal: Total number of distinct ways to fold a map of the given dimensions.
41
+ Parameters
42
+ ----------
43
+ listDimensions: List of integers representing the dimensions of the map to be folded.
44
+ pathLikeWriteFoldsTotal (None): Path, filename, or pathFilename to write the total fold count to.
45
+ If a directory is provided, creates a file with a default name based on map dimensions.
46
+ computationDivisions (None):
47
+ Whether and how to divide the computational work. See notes for details.
48
+ CPUlimit (None): This is only relevant if there are `computationDivisions`: whether and how to limit the CPU usage. See notes for details.
49
+ Returns
50
+ -------
51
+ foldsTotal: Total number of distinct ways to fold a map of the given dimensions.
38
52
 
53
+ Notes
54
+ -----
39
55
  Computation divisions:
40
56
  - None: no division of the computation into tasks; sets task divisions to 0
41
57
  - int: direct set the number of task divisions; cannot exceed the map's total leaves
@@ -51,7 +67,8 @@ def countFolds(listDimensions: Sequence[int]
51
67
  - Integer `<= -1`: Subtract the absolute value from total CPUs.
52
68
 
53
69
  N.B.: You probably don't want to divide the computation into tasks.
54
- If you want to compute a large `foldsTotal`, dividing the computation into tasks is usually a bad idea. Dividing the algorithm into tasks is inherently inefficient: efficient division into tasks means there would be no overlap in the work performed by each task. When dividing this algorithm, the amount of overlap is between 50% and 90% by all tasks: at least 50% of the work done by every task must be done by _all_ tasks. If you improve the computation time, it will only change by -10 to -50% depending on (at the very least) the ratio of the map dimensions and the number of leaves. If an undivided computation would take 10 hours on your computer, for example, the computation will still take at least 5 hours but you might reduce the time to 9 hours. Most of the time, however, you will increase the computation time. If logicalCores >= leavesTotal, it will probably be faster. If logicalCores <= 2 * leavesTotal, it will almost certainly be slower for all map dimensions.
70
+
71
+ If you want to compute a large `foldsTotal`, dividing the computation into tasks is usually a bad idea. Dividing the algorithm into tasks is inherently inefficient: efficient division into tasks means there would be no overlap in the work performed by each task. When dividing this algorithm, the amount of overlap is between 50% and 90% by all tasks: at least 50% of the work done by every task must be done by _all_ tasks. If you improve the computation time, it will only change by -10 to -50% depending on (at the very least) the ratio of the map dimensions and the number of leaves. If an undivided computation would take 10 hours on your computer, for example, the computation will still take at least 5 hours but you might reduce the time to 9 hours. Most of the time, however, you will increase the computation time. If logicalCores >= leavesTotal, it will probably be faster. If logicalCores <= 2 * leavesTotal, it will almost certainly be slower for all map dimensions.
55
72
  """
56
73
  mapShape: tuple[int, ...] = validateListDimensions(listDimensions)
57
74
  concurrencyLimit: int = setProcessorLimit(CPUlimit, The.concurrencyPackage)
@@ -63,9 +80,7 @@ def countFolds(listDimensions: Sequence[int]
63
80
  else:
64
81
  pathFilenameFoldsTotal = None
65
82
 
66
- dispatcherCallableProxy = getPackageDispatcher()
67
- computationStateComplete: ComputationState = dispatcherCallableProxy(computationStateInitialized)
68
- # computationStateComplete: ComputationState = The.dispatcher(computationStateInitialized)
83
+ computationStateComplete: ComputationState = The.dispatcher(computationStateInitialized)
69
84
 
70
85
  computationStateComplete.getFoldsTotal()
71
86
 
mapFolding/beDRY.py CHANGED
@@ -19,7 +19,7 @@ These utilities form a stable internal API that other modules depend on, particu
19
19
  produce optimized implementations.
20
20
  """
21
21
  from collections.abc import Sequence
22
- from mapFolding.theSSOT import ComputationState, numpyIntegerType
22
+ from mapFolding import ComputationState, NumPyIntegerType
23
23
  from numpy import dtype as numpy_dtype, int64 as numpy_int64, ndarray
24
24
  from sys import maxsize as sysMaxsize
25
25
  from typing import Any
@@ -165,7 +165,7 @@ def _makeConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int) -> ndarray
165
165
  connectionGraph[indexDimension, activeLeaf1ndex, connectee1ndex] = connectee1ndex + cumulativeProduct[indexDimension]
166
166
  return connectionGraph
167
167
 
168
- def getConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int, datatype: type[numpyIntegerType]) -> ndarray[tuple[int, int, int], numpy_dtype[numpyIntegerType]]:
168
+ def getConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int, datatype: type[NumPyIntegerType]) -> ndarray[tuple[int, int, int], numpy_dtype[NumPyIntegerType]]:
169
169
  """
170
170
  Create a properly typed connection graph for the map folding algorithm.
171
171
 
@@ -193,7 +193,7 @@ def getConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int, datatype: ty
193
193
  connectionGraph = connectionGraph.astype(datatype)
194
194
  return connectionGraph
195
195
 
196
- def makeDataContainer(shape: int | tuple[int, ...], datatype: type[numpyIntegerType]) -> ndarray[Any, numpy_dtype[numpyIntegerType]]:
196
+ def makeDataContainer(shape: int | tuple[int, ...], datatype: type[NumPyIntegerType]) -> ndarray[Any, numpy_dtype[NumPyIntegerType]]:
197
197
  """
198
198
  Create a typed NumPy array container with initialized values.
199
199
 
mapFolding/oeis.py CHANGED
@@ -22,8 +22,7 @@ implementation in the package.
22
22
  from collections.abc import Callable
23
23
  from datetime import datetime, timedelta
24
24
  from functools import cache
25
- from mapFolding.theSSOT import The
26
- from mapFolding.toolboxFilesystem import writeStringToHere
25
+ from mapFolding import writeStringToHere, The
27
26
  from pathlib import Path
28
27
  from typing import Any, Final, TYPE_CHECKING
29
28
  import argparse
@@ -162,6 +161,27 @@ def _parseBFileOEIS(OEISbFile: str, oeisID: str) -> dict[int, int]:
162
161
  return OEISsequence
163
162
 
164
163
  def getOEISofficial(pathFilenameCache: Path, url: str) -> None | str:
164
+ """
165
+ Retrieve OEIS sequence data from cache or online source.
166
+
167
+ This function implements a caching strategy for OEIS sequence data, first checking
168
+ if a local cached copy exists and is not expired. If a valid cache exists, it returns
169
+ the cached content; otherwise, it fetches the data from the OEIS website and
170
+ writes it to the cache for future use.
171
+
172
+ Parameters:
173
+ pathFilenameCache: Path to the local cache file.
174
+ url: URL to retrieve the OEIS sequence data from if cache is invalid or missing.
175
+
176
+ Returns:
177
+ oeisInformation: The retrieved OEIS sequence information as a string, or None if
178
+ the information could not be retrieved.
179
+
180
+ Notes:
181
+ The cache expiration period is controlled by the global `cacheDays` variable.
182
+ If the function fails to retrieve data from both cache and online source,
183
+ it will return None and issue a warning.
184
+ """
165
185
  tryCache: bool = False
166
186
  if pathFilenameCache.exists():
167
187
  fileAge: timedelta = datetime.now() - datetime.fromtimestamp(pathFilenameCache.stat().st_mtime)
@@ -175,6 +195,7 @@ def getOEISofficial(pathFilenameCache: Path, url: str) -> None | str:
175
195
  tryCache = False
176
196
 
177
197
  if not tryCache:
198
+ # Change http handling #13
178
199
  httpResponse: urllib.response.addinfourl = urllib.request.urlopen(url)
179
200
  oeisInformation = httpResponse.read().decode('utf-8')
180
201
  writeStringToHere(oeisInformation, pathFilenameCache)
@@ -214,6 +235,27 @@ def getOEISidValues(oeisID: str) -> dict[int, int]:
214
235
  return {-1: -1}
215
236
 
216
237
  def getOEISidInformation(oeisID: str) -> tuple[str, int]:
238
+ """
239
+ Retrieve the description and offset for an OEIS sequence.
240
+
241
+ This function fetches the metadata for a given OEIS sequence ID, including
242
+ its textual description and index offset value. It uses a caching mechanism
243
+ to avoid redundant network requests while ensuring data freshness.
244
+
245
+ Parameters:
246
+ oeisID: The OEIS sequence identifier to retrieve information for.
247
+
248
+ Returns:
249
+ A tuple containing:
250
+ - description: A string describing the sequence's mathematical meaning.
251
+ - offset: An integer representing the starting index of the sequence.
252
+ Usually 0 or 1, depending on the mathematical context.
253
+
254
+ Notes:
255
+ Sequence descriptions are parsed from the machine-readable format of OEIS.
256
+ If information cannot be retrieved, warning messages are issued and
257
+ fallback values are returned.
258
+ """
217
259
  oeisID = validateOEISid(oeisID)
218
260
  pathFilenameCache: Path = pathCache / f"{oeisID}.txt"
219
261
  url: str = f"https://oeis.org/search?q=id:{oeisID}&fmt=text"
@@ -243,6 +285,26 @@ def getOEISidInformation(oeisID: str) -> tuple[str, int]:
243
285
  return description, offset
244
286
 
245
287
  def makeSettingsOEIS() -> dict[str, SettingsOEIS]:
288
+ """
289
+ Construct the comprehensive settings dictionary for all implemented OEIS sequences.
290
+
291
+ This function builds a complete configuration dictionary for all supported OEIS
292
+ sequences by retrieving and combining:
293
+ 1. Sequence values from OEIS b-files
294
+ 2. Sequence metadata (descriptions and offsets)
295
+ 3. Hardcoded mapping functions and test values
296
+
297
+ The resulting dictionary provides a single authoritative source for all OEIS-related
298
+ configurations used throughout the package, including:
299
+ - Mathematical descriptions of each sequence
300
+ - Functions to convert between sequence indices and map dimensions
301
+ - Known sequence values retrieved from OEIS
302
+ - Testing and benchmarking reference values
303
+
304
+ Returns:
305
+ A dictionary mapping OEIS sequence IDs to their complete settings objects,
306
+ containing all metadata and known values needed for computation and validation.
307
+ """
246
308
  settingsTarget: dict[str, SettingsOEIS] = {}
247
309
  for oeisID in oeisIDsImplemented:
248
310
  valuesKnownSherpa: dict[int, int] = getOEISidValues(oeisID)
@@ -277,6 +339,25 @@ def makeDictionaryFoldsTotalKnown() -> dict[tuple[int, ...], int]:
277
339
  return dictionaryMapDimensionsToFoldsTotalKnown
278
340
 
279
341
  def getFoldsTotalKnown(mapShape: tuple[int, ...]) -> int:
342
+ """
343
+ Retrieve the known total number of foldings for a given map shape.
344
+
345
+ This function looks up precalculated folding totals for specific map dimensions
346
+ from OEIS sequences. It serves as a rapid reference for known values without
347
+ requiring computation, and can be used to validate algorithm results.
348
+
349
+ Parameters:
350
+ mapShape: A tuple of integers representing the dimensions of the map.
351
+
352
+ Returns:
353
+ foldingsTotal: The known total number of foldings for the given map shape,
354
+ or -1 if the map shape doesn't match any known values in the OEIS sequences.
355
+
356
+ Notes:
357
+ The function uses a cached dictionary (via makeDictionaryFoldsTotalKnown) to
358
+ efficiently retrieve values without repeatedly parsing OEIS data. Map shape
359
+ tuples are sorted internally to ensure consistent lookup regardless of dimension order.
360
+ """
280
361
  lookupFoldsTotal = makeDictionaryFoldsTotalKnown()
281
362
  return lookupFoldsTotal.get(tuple(mapShape), -1)
282
363
 
@@ -1,46 +1,67 @@
1
1
  """
2
- Code transformation framework for algorithmic optimization.
2
+ Code Transformation Framework for Algorithm Optimization and Testing
3
3
 
4
4
  This package implements a comprehensive framework for programmatically analyzing,
5
- transforming, and generating Python code. It enables sophisticated algorithm optimization
6
- through abstract syntax tree (AST) manipulation, allowing algorithms to be transformed
7
- from a readable, functional implementation into highly-optimized variants tailored for
8
- different execution environments or specific computational tasks.
5
+ transforming, and generating optimized Python code. It serves as the algorithmic
6
+ optimization engine for the mapFolding package, enabling the conversion of readable,
7
+ functional implementations into highly-optimized variants with verified correctness.
9
8
 
10
- Core capabilities:
11
- 1. AST Pattern Recognition - Precisely identify and match code patterns using composable predicates
12
- 2. Algorithm Transformation - Convert functional state-based implementations to primitive operations
13
- 3. Dataclass "Shattering" - Decompose complex state objects into primitive components
14
- 4. Performance Optimization - Apply domain-specific optimizations for numerical computation
15
- 5. Code Generation - Generate specialized implementations with appropriate imports and syntax
9
+ ## Core Architecture Components
16
10
 
17
- The transformation assembly-line supports multiple optimization targets, from general-purpose
18
- acceleration to generating highly-specialized variants optimized for specific input parameters.
19
- This multi-level transformation approach allows for both development flexibility and
20
- runtime performance, preserving algorithm readability in the source while enabling
21
- maximum execution speed in production.
11
+ 1. **AST Manipulation Tools**
12
+ - Pattern recognition with composable predicates (ifThis)
13
+ - Node access with consistent interfaces (DOT)
14
+ - AST traversal and transformation (NodeChanger, NodeTourist)
15
+ - AST construction with sane defaults (Make)
16
+ - Node transformation operations (grab, Then)
22
17
 
23
- These tools were developed for map folding computation optimization but are designed as
24
- general-purpose utilities applicable to a wide range of code transformation scenarios,
25
- particularly for numerically-intensive algorithms that benefit from just-in-time compilation.
18
+ 2. **Container and Organization**
19
+ - Import tracking and management (LedgerOfImports)
20
+ - Function packaging with dependencies (IngredientsFunction)
21
+ - Module assembly with structured components (IngredientsModule)
22
+ - Recipe configuration for generating optimized code (RecipeSynthesizeFlow)
23
+ - Dataclass decomposition for compatibility (ShatteredDataclass)
24
+
25
+ 3. **Optimization Pipelines**
26
+ - General-purpose Numba acceleration (makeNumbaFlow)
27
+ - Job-specific optimization for concrete parameters (makeJobNumba)
28
+ - Specialized component transformation (decorateCallableWithNumba)
29
+
30
+ ## Integration with Testing Framework
31
+
32
+ The transformation components are extensively tested through the package's test suite,
33
+ which provides specialized fixtures and utilities for validating both the transformation
34
+ process and the resulting optimized code:
35
+
36
+ - **syntheticDispatcherFixture**: Creates and tests a complete Numba-optimized module
37
+ using RecipeSynthesizeFlow configuration
38
+
39
+ - **test_writeJobNumba**: Tests the job-specific optimization process with RecipeJob
40
+
41
+ These fixtures enable users to test their own custom recipes and job configurations
42
+ with minimal effort. See the documentation in tests/__init__.py for details on
43
+ extending the test suite for custom implementations.
44
+
45
+ The framework balances multiple optimization levels - from general algorithmic
46
+ improvements to parameter-specific optimizations - while maintaining the ability
47
+ to verify correctness at each transformation stage through the integrated test suite.
26
48
  """
49
+
27
50
  from mapFolding.someAssemblyRequired._theTypes import (
28
51
  ast_expr_Slice,
29
52
  ast_Identifier,
30
53
  astClassHasDOTnameNotName,
31
54
  astClassHasDOTtarget,
55
+ astClassHasDOTvalue_expr,
56
+ astClassHasDOTvalue_exprNone,
57
+ astClassHasDOTtargetAttributeNameSubscript,
58
+ astClassHasDOTtarget_expr,
32
59
  astClassHasDOTvalue,
33
60
  astClassOptionallyHasDOTnameNotName,
34
- astMosDef,
35
- Ima_funcTypeUNEDITED,
36
- Ima_targetTypeUNEDITED,
37
- ImaAnnotationType,
38
- ImaAnnotationTypeVar,
39
61
  intORlist_ast_type_paramORstr_orNone,
40
62
  intORstr_orNone,
41
63
  list_ast_type_paramORstr_orNone,
42
64
  str_nameDOTname,
43
- TypeCertified,
44
65
  个,
45
66
  )
46
67
 
@@ -53,9 +74,9 @@ from mapFolding.someAssemblyRequired._toolboxPython import (
53
74
  parsePathFilename2astModule,
54
75
  )
55
76
 
56
- from mapFolding.someAssemblyRequired._toolboxAntecedents import be, DOT, ifThis, 又
77
+ from mapFolding.someAssemblyRequired._toolboxAntecedents import DOT, ifThis
57
78
  from mapFolding.someAssemblyRequired._tool_Make import Make
58
- from mapFolding.someAssemblyRequired._tool_Then import Then
79
+ from mapFolding.someAssemblyRequired._tool_Then import grab, Then
59
80
 
60
81
  from mapFolding.someAssemblyRequired._toolboxContainers import (
61
82
  IngredientsFunction,
@@ -1,20 +1,24 @@
1
- """It's still wrong, but typing information is being transmitted between functions, methods, and modules."""
2
1
  from typing import Any, TYPE_CHECKING, TypeAlias as typing_TypeAlias, TypeVar as typing_TypeVar
3
2
  import ast
3
+ # TODO understand typing.
4
4
 
5
5
  stuPyd: typing_TypeAlias = str
6
-
7
6
  if TYPE_CHECKING:
8
7
  """ 3.12 new: ast.ParamSpec, ast.type_param, ast.TypeAlias, ast.TypeVar, ast.TypeVarTuple
9
8
  3.11 new: ast.TryStar"""
10
9
  astClassHasDOTnameNotName: typing_TypeAlias = ast.alias | ast.AsyncFunctionDef | ast.ClassDef | ast.FunctionDef | ast.ParamSpec | ast.TypeVar | ast.TypeVarTuple
11
- astClassHasDOTvalue: typing_TypeAlias = ast.AnnAssign | ast.Assign | ast.Attribute | ast.AugAssign | ast.Await | ast.Constant | ast.DictComp | ast.Expr | ast.FormattedValue | ast.keyword | ast.MatchValue | ast.NamedExpr | ast.Return | ast.Starred | ast.Subscript | ast.TypeAlias | ast.Yield | ast.YieldFrom
10
+ 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
  else:
13
13
  astClassHasDOTnameNotName = stuPyd
14
- astClassHasDOTvalue = stuPyd
14
+ astClassHasDOTvalue_expr = stuPyd
15
15
 
16
+ astClassHasDOTtargetAttributeNameSubscript: typing_TypeAlias = ast.AnnAssign | ast.AugAssign
17
+ astClassHasDOTtarget_expr: typing_TypeAlias = ast.AsyncFor | ast.comprehension | ast.For
18
+ astClassHasDOTtarget: typing_TypeAlias = ast.NamedExpr | astClassHasDOTtarget_expr | astClassHasDOTtargetAttributeNameSubscript
16
19
  astClassOptionallyHasDOTnameNotName: typing_TypeAlias = ast.ExceptHandler | ast.MatchAs | ast.MatchStar
17
- astClassHasDOTtarget: typing_TypeAlias = ast.AnnAssign | ast.AsyncFor | ast.AugAssign | ast.comprehension | ast.For | ast.NamedExpr
20
+ astClassHasDOTvalue_exprNone: typing_TypeAlias = ast.AnnAssign | ast.Return | ast.Yield
21
+ astClassHasDOTvalue: typing_TypeAlias = ast.Constant | ast.MatchSingleton | astClassHasDOTvalue_expr | astClassHasDOTvalue_exprNone
18
22
 
19
23
  ast_expr_Slice: typing_TypeAlias = ast.expr
20
24
  ast_Identifier: typing_TypeAlias = str
@@ -22,18 +26,10 @@ intORlist_ast_type_paramORstr_orNone: typing_TypeAlias = Any
22
26
  intORstr_orNone: typing_TypeAlias = Any
23
27
  list_ast_type_paramORstr_orNone: typing_TypeAlias = Any
24
28
  str_nameDOTname: typing_TypeAlias = stuPyd
25
- ImaAnnotationType: typing_TypeAlias = ast.Attribute | ast.Constant | ast.Name | ast.Subscript
26
- ImaAnnotationTypeVar = typing_TypeVar('ImaAnnotationTypeVar', ast.Attribute, ast.Constant, ast.Name, ast.Subscript)
27
-
28
- Ima_funcTypeUNEDITED: typing_TypeAlias = ast.Attribute | ast.Await | ast.BinOp | ast.BoolOp | ast.Call | ast.Compare | ast.Constant | ast.Dict | ast.DictComp | ast.FormattedValue | ast.GeneratorExp | ast.IfExp | ast.JoinedStr | ast.Lambda | ast.List | ast.ListComp | ast.Name | ast.NamedExpr | ast.Set | ast.SetComp | ast.Slice | ast.Starred | ast.Subscript | ast.Tuple | ast.UnaryOp | ast.Yield | ast.YieldFrom
29
- Ima_targetTypeUNEDITED: typing_TypeAlias = ast.AST
30
-
31
- # TODO understand whatever the fuck `typing.TypeVar` is _supposed_ to fucking do.
32
- TypeCertified = typing_TypeVar('TypeCertified', bound = ast.AST, covariant=True)
33
- astMosDef = typing_TypeVar('astMosDef', bound=astClassHasDOTnameNotName)
34
29
 
35
- 个 = typing_TypeVar('个', bound= ast.AST | ast_Identifier, covariant=True)
30
+ 个 = typing_TypeVar('个', bound= ast.AST, covariant=True)
36
31
 
32
+ # All ast classes by subgroup:
37
33
  Ima_ast_boolop: typing_TypeAlias = ast.boolop | ast.And | ast.Or
38
34
  Ima_ast_cmpop: typing_TypeAlias = ast.cmpop | ast.Eq | ast.NotEq | ast.Lt | ast.LtE | ast.Gt | ast.GtE | ast.Is | ast.IsNot | ast.In | ast.NotIn
39
35
  Ima_ast_excepthandler: typing_TypeAlias = ast.excepthandler | ast.ExceptHandler
@@ -1,8 +1,20 @@
1
+ """
2
+ AST Node Construction Utilities for Python Code Generation
3
+
4
+ This module provides the Make class with static methods for creating AST nodes
5
+ with sane defaults. It abstracts away the complexity of constructing AST nodes
6
+ directly, making programmatic code generation more intuitive and less error-prone.
7
+
8
+ The Make class serves as a factory for creating various types of AST nodes needed
9
+ in code generation, transformation, and analysis workflows. Each method follows
10
+ a consistent pattern that maps cleanly to Python's syntax while handling the
11
+ details of AST node construction.
12
+ """
13
+
1
14
  from collections.abc import Sequence
2
15
  from mapFolding.someAssemblyRequired import (
3
16
  ast_expr_Slice,
4
17
  ast_Identifier,
5
- ImaAnnotationType,
6
18
  intORlist_ast_type_paramORstr_orNone,
7
19
  intORstr_orNone,
8
20
  list_ast_type_paramORstr_orNone,
@@ -30,71 +42,86 @@ class Make:
30
42
  @staticmethod
31
43
  def alias(name: ast_Identifier, asname: ast_Identifier | None = None) -> ast.alias:
32
44
  return ast.alias(name, asname)
45
+
33
46
  @staticmethod
34
- def AnnAssign(target: ast.Attribute | ast.Name | ast.Subscript, annotation: ImaAnnotationType, value: ast.expr | None = None, **keywordArguments: int) -> ast.AnnAssign: # `simple: int`: uses a clever int-from-boolean to assign the correct value to the `simple` attribute. So, don't make it a method parameter.
47
+ def AnnAssign(target: ast.Attribute | ast.Name | ast.Subscript, annotation: ast.expr, value: ast.expr | None = None, **keywordArguments: int) -> ast.AnnAssign: # `simple: int`: uses a clever int-from-boolean to assign the correct value to the `simple` attribute. So, don't make it a method parameter.
35
48
  return ast.AnnAssign(target, annotation, value, simple=int(isinstance(target, ast.Name)), **keywordArguments)
49
+
36
50
  @staticmethod
37
51
  def arg(identifier: ast_Identifier, annotation: ast.expr | None = None, **keywordArguments: intORstr_orNone) -> ast.arg:
38
52
  return ast.arg(identifier, annotation, **keywordArguments)
53
+
39
54
  @staticmethod
40
55
  def argumentsSpecification(posonlyargs:list[ast.arg]=[], args:list[ast.arg]=[], vararg:ast.arg|None=None, kwonlyargs:list[ast.arg]=[], kw_defaults:list[ast.expr|None]=[None], kwarg:ast.arg|None=None, defaults:list[ast.expr]=[]) -> ast.arguments:
41
56
  return ast.arguments(posonlyargs, args, vararg, kwonlyargs, kw_defaults, kwarg, defaults)
57
+
42
58
  @staticmethod
43
59
  def Assign(listTargets: Any, value: ast.expr, **keywordArguments: intORstr_orNone) -> ast.Assign:
44
60
  return ast.Assign(listTargets, value, **keywordArguments)
61
+
45
62
  @staticmethod
46
63
  def Attribute(value: ast.expr, *attribute: ast_Identifier, context: ast.expr_context = ast.Load(), **keywordArguments: int) -> ast.Attribute:
47
64
  """ If two `ast_Identifier` are joined by a dot `.`, they are _usually_ an `ast.Attribute`, but see `ast.ImportFrom`.
48
65
  Parameters:
49
- value: the part before the dot (Often `ast.Name`, but also `ast.Attribute`, `ast.Starred`, and `ast.Subscript`.)
66
+ value: the part before the dot (e.g., `ast.Name`.)
50
67
  attribute: an `ast_Identifier` after a dot `.`; you can pass multiple `attribute` and they will be chained together.
51
68
  """
52
- # TODO confirm the precision of the docstring.
53
- def addDOTattribute(chain, identifier: ast_Identifier, context: ast.expr_context, **keywordArguments: int) -> ast.Attribute:
69
+ def addDOTattribute(chain: ast.expr, identifier: ast_Identifier, context: ast.expr_context, **keywordArguments: int) -> ast.Attribute:
54
70
  return ast.Attribute(value=chain, attr=identifier, ctx=context, **keywordArguments)
55
71
  buffaloBuffalo = addDOTattribute(value, attribute[0], context, **keywordArguments)
56
72
  for identifier in attribute[1:None]:
57
73
  buffaloBuffalo = addDOTattribute(buffaloBuffalo, identifier, context, **keywordArguments)
58
74
  return buffaloBuffalo
75
+
59
76
  @staticmethod
60
- # TODO are the types for `callee` comprehensive?
61
- # TODO is there an easier way to create precise typings for `ast`? I mean, it's a fucking closed system: there should be a lot of mystery involved.
62
- def Call(callee: ast.Attribute | ast.Name | ast.Subscript, listArguments: Sequence[ast.expr] | None = None, list_astKeywords: Sequence[ast.keyword] | None = None) -> ast.Call:
77
+ def Call(callee: ast.expr, listArguments: Sequence[ast.expr] | None = None, list_astKeywords: Sequence[ast.keyword] | None = None) -> ast.Call:
63
78
  return ast.Call(func=callee, args=list(listArguments) if listArguments else [], keywords=list(list_astKeywords) if list_astKeywords else [])
79
+
64
80
  @staticmethod
65
81
  def ClassDef(name: ast_Identifier, listBases: list[ast.expr]=[], list_keyword: list[ast.keyword]=[], body: list[ast.stmt]=[], decorator_list: list[ast.expr]=[], **keywordArguments: list_ast_type_paramORstr_orNone) -> ast.ClassDef:
66
82
  return ast.ClassDef(name, listBases, list_keyword, body, decorator_list, **keywordArguments)
83
+
67
84
  @staticmethod
68
85
  def Constant(value: Any, **keywordArguments: intORstr_orNone) -> ast.Constant:
69
86
  """value: str|int|float|bool|None|bytes|bytearray|memoryview|complex|list|tuple|dict|set, or any other type that can be represented as a constant in Python."""
70
87
  return ast.Constant(value, **keywordArguments)
88
+
71
89
  @staticmethod
72
90
  def Expr(value: ast.expr, **keywordArguments: int) -> ast.Expr:
73
91
  return ast.Expr(value, **keywordArguments)
92
+
74
93
  @staticmethod
75
94
  def FunctionDef(name: ast_Identifier, argumentsSpecification:ast.arguments=ast.arguments(), body:list[ast.stmt]=[], decorator_list:list[ast.expr]=[], returns:ast.expr|None=None, **keywordArguments: intORlist_ast_type_paramORstr_orNone) -> ast.FunctionDef:
76
95
  return ast.FunctionDef(name, argumentsSpecification, body, decorator_list, returns, **keywordArguments)
96
+
77
97
  @staticmethod
78
98
  def Import(moduleWithLogicalPath: str_nameDOTname, asname: ast_Identifier | None = None, **keywordArguments: int) -> ast.Import:
79
99
  return ast.Import(names=[Make.alias(moduleWithLogicalPath, asname)], **keywordArguments)
100
+
80
101
  @staticmethod
81
102
  def ImportFrom(moduleWithLogicalPath: str_nameDOTname, list_astAlias: list[ast.alias], **keywordArguments: int) -> ast.ImportFrom:
82
103
  return ast.ImportFrom(moduleWithLogicalPath, list_astAlias, **keywordArguments)
104
+
83
105
  @staticmethod
84
106
  def keyword(keywordArgument: ast_Identifier, value: ast.expr, **keywordArguments: int) -> ast.keyword:
85
107
  return ast.keyword(arg=keywordArgument, value=value, **keywordArguments)
108
+
86
109
  @staticmethod
87
110
  def Module(body: list[ast.stmt] = [], type_ignores: list[ast.TypeIgnore] = []) -> ast.Module:
88
111
  return ast.Module(body, type_ignores)
112
+
89
113
  @staticmethod
90
114
  def Name(identifier: ast_Identifier, context: ast.expr_context = ast.Load(), **keywordArguments: int) -> ast.Name:
91
115
  return ast.Name(identifier, context, **keywordArguments)
116
+
92
117
  @staticmethod
93
118
  def Return(value: ast.expr | None = None, **keywordArguments: int) -> ast.Return:
94
119
  return ast.Return(value, **keywordArguments)
120
+
95
121
  @staticmethod
96
122
  def Subscript(value: ast.expr, slice: ast_expr_Slice, context: ast.expr_context = ast.Load(), **keywordArguments: int) -> ast.Subscript:
97
123
  return ast.Subscript(value, slice, context, **keywordArguments)
124
+
98
125
  @staticmethod
99
126
  def Tuple(elements: Sequence[ast.expr] = [], context: ast.expr_context = ast.Load(), **keywordArguments: int) -> ast.Tuple:
100
127
  return ast.Tuple(list(elements), context, **keywordArguments)