mapFolding 0.8.3__tar.gz → 0.8.4__tar.gz

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 (60) hide show
  1. {mapfolding-0.8.3 → mapfolding-0.8.4}/PKG-INFO +2 -1
  2. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/__init__.py +2 -2
  3. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/basecamp.py +11 -5
  4. mapfolding-0.8.4/mapFolding/filesystem.py +154 -0
  5. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/oeis.py +1 -1
  6. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/someAssemblyRequired/__init__.py +37 -18
  7. mapfolding-0.8.4/mapFolding/someAssemblyRequired/_theTypes.py +35 -0
  8. mapfolding-0.8.4/mapFolding/someAssemblyRequired/_tool_Make.py +92 -0
  9. mapfolding-0.8.4/mapFolding/someAssemblyRequired/_tool_Then.py +65 -0
  10. mapfolding-0.8.4/mapFolding/someAssemblyRequired/_toolboxAntecedents.py +326 -0
  11. mapfolding-0.8.4/mapFolding/someAssemblyRequired/_toolboxContainers.py +306 -0
  12. mapfolding-0.8.4/mapFolding/someAssemblyRequired/_toolboxPython.py +76 -0
  13. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/someAssemblyRequired/ingredientsNumba.py +17 -24
  14. mapfolding-0.8.4/mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +156 -0
  15. mapfolding-0.8.4/mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +247 -0
  16. mapfolding-0.8.4/mapFolding/someAssemblyRequired/transformDataStructures.py +235 -0
  17. mapfolding-0.8.4/mapFolding/someAssemblyRequired/transformationTools.py +156 -0
  18. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/syntheticModules/numbaCount_doTheNeedful.py +36 -33
  19. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/theDao.py +13 -11
  20. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/theSSOT.py +69 -112
  21. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding.egg-info/PKG-INFO +2 -1
  22. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding.egg-info/SOURCES.txt +7 -1
  23. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding.egg-info/requires.txt +1 -0
  24. {mapfolding-0.8.3 → mapfolding-0.8.4}/pyproject.toml +3 -2
  25. {mapfolding-0.8.3 → mapfolding-0.8.4}/tests/conftest.py +34 -29
  26. mapfolding-0.8.4/tests/test_computations.py +62 -0
  27. {mapfolding-0.8.3 → mapfolding-0.8.4}/tests/test_filesystem.py +3 -3
  28. mapfolding-0.8.3/mapFolding/filesystem.py +0 -129
  29. mapfolding-0.8.3/mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +0 -211
  30. mapfolding-0.8.3/mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +0 -413
  31. mapfolding-0.8.3/mapFolding/someAssemblyRequired/transformDataStructures.py +0 -168
  32. mapfolding-0.8.3/mapFolding/someAssemblyRequired/transformationTools.py +0 -778
  33. mapfolding-0.8.3/tests/test_computations.py +0 -53
  34. {mapfolding-0.8.3 → mapfolding-0.8.4}/LICENSE +0 -0
  35. {mapfolding-0.8.3 → mapfolding-0.8.4}/README.md +0 -0
  36. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/beDRY.py +0 -0
  37. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/noHomeYet.py +0 -0
  38. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/py.typed +0 -0
  39. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/__init__.py +0 -0
  40. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/flattened.py +0 -0
  41. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/hunterNumba.py +0 -0
  42. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/irvineJavaPort.py +0 -0
  43. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/jaxCount.py +0 -0
  44. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/jobsCompleted/[2x19]/p2x19.py +0 -0
  45. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/jobsCompleted/__init__.py +0 -0
  46. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/jobsCompleted/p2x19/p2x19.py +0 -0
  47. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/lunnanNumpy.py +0 -0
  48. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/lunnanWhile.py +0 -0
  49. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/rotatedEntryPoint.py +0 -0
  50. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/reference/total_countPlus1vsPlusN.py +0 -0
  51. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/someAssemblyRequired/getLLVMforNoReason.py +0 -0
  52. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding/syntheticModules/__init__.py +0 -0
  53. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding.egg-info/dependency_links.txt +0 -0
  54. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding.egg-info/entry_points.txt +0 -0
  55. {mapfolding-0.8.3 → mapfolding-0.8.4}/mapFolding.egg-info/top_level.txt +0 -0
  56. {mapfolding-0.8.3 → mapfolding-0.8.4}/setup.cfg +0 -0
  57. {mapfolding-0.8.3 → mapfolding-0.8.4}/tests/__init__.py +0 -0
  58. {mapfolding-0.8.3 → mapfolding-0.8.4}/tests/test_oeis.py +0 -0
  59. {mapfolding-0.8.3 → mapfolding-0.8.4}/tests/test_other.py +0 -0
  60. {mapfolding-0.8.3 → mapfolding-0.8.4}/tests/test_tasks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapFolding
3
- Version: 0.8.3
3
+ Version: 0.8.4
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
@@ -45,6 +45,7 @@ Requires-Dist: pytest-cov; extra == "testing"
45
45
  Requires-Dist: pytest-env; extra == "testing"
46
46
  Requires-Dist: pytest-xdist; extra == "testing"
47
47
  Requires-Dist: pyupgrade; extra == "testing"
48
+ Requires-Dist: ruff; extra == "testing"
48
49
  Dynamic: license-file
49
50
 
50
51
  # mapFolding: Algorithms for enumerating distinct map/stamp folding patterns 🗺️
@@ -24,13 +24,13 @@ Special directories:
24
24
  core algorithm created by the code transformation framework
25
25
  - reference/: Historical implementations and educational resources for algorithm exploration
26
26
  - reference/jobsCompleted/: Contains successful computations for previously unknown values,
27
- including first-ever calculations for 2×19 and 2×20 maps (OEIS A001415)
27
+ including first-ever calculations for 2x19 and 2x20 maps (OEIS A001415)
28
28
 
29
29
  This package strives to balance algorithm readability and understandability with
30
30
  high-performance computation capabilities, allowing users to compute map folding
31
31
  totals for larger dimensions than previously feasible.
32
32
  """
33
- from mapFolding.basecamp import countFolds as countFolds
33
+ from mapFolding.basecamp import countFolds
34
34
  from mapFolding.oeis import clearOEIScache, getOEISids, OEIS_for_n, oeisIDfor_n
35
35
 
36
36
  __all__ = [
@@ -14,13 +14,13 @@ implementation, and optional persistence of results.
14
14
 
15
15
  from collections.abc import Sequence
16
16
  from mapFolding.beDRY import outfitCountFolds, setCPUlimit, validateListDimensions
17
- from mapFolding.filesystem import getPathFilenameFoldsTotal, saveFoldsTotal
17
+ from mapFolding.filesystem import getPathFilenameFoldsTotal, saveFoldsTotal, saveFoldsTotalFAILearly
18
18
  from mapFolding.theSSOT import ComputationState, getPackageDispatcher, The
19
19
  from os import PathLike
20
- from pathlib import Path
20
+ from pathlib import PurePath
21
21
 
22
22
  def countFolds(listDimensions: Sequence[int]
23
- , pathLikeWriteFoldsTotal: str | PathLike[str] | None = None
23
+ , pathLikeWriteFoldsTotal: PathLike[str] | PurePath | None = None
24
24
  , computationDivisions: int | str | None = None
25
25
  , CPUlimit: int | float | bool | None = None
26
26
  ) -> int:
@@ -57,13 +57,19 @@ def countFolds(listDimensions: Sequence[int]
57
57
  concurrencyLimit: int = setCPUlimit(CPUlimit, The.concurrencyPackage)
58
58
  computationStateInitialized: ComputationState = outfitCountFolds(mapShape, computationDivisions, concurrencyLimit)
59
59
 
60
+ if pathLikeWriteFoldsTotal is not None:
61
+ pathFilenameFoldsTotal = getPathFilenameFoldsTotal(computationStateInitialized.mapShape, pathLikeWriteFoldsTotal)
62
+ saveFoldsTotalFAILearly(pathFilenameFoldsTotal)
63
+ else:
64
+ pathFilenameFoldsTotal = None
65
+
60
66
  dispatcherCallableProxy = getPackageDispatcher()
61
67
  computationStateComplete: ComputationState = dispatcherCallableProxy(computationStateInitialized)
68
+ # computationStateComplete: ComputationState = The.dispatcher(computationStateInitialized)
62
69
 
63
70
  computationStateComplete.getFoldsTotal()
64
71
 
65
- if pathLikeWriteFoldsTotal is not None:
66
- pathFilenameFoldsTotal: Path = getPathFilenameFoldsTotal(computationStateComplete.mapShape, pathLikeWriteFoldsTotal)
72
+ if pathFilenameFoldsTotal is not None:
67
73
  saveFoldsTotal(pathFilenameFoldsTotal, computationStateComplete.foldsTotal)
68
74
 
69
75
  return computationStateComplete.foldsTotal
@@ -0,0 +1,154 @@
1
+ """
2
+ Filesystem utilities for managing map folding computation results.
3
+
4
+ This module provides functions for standardized handling of files related to the mapFolding
5
+ package, with a focus on saving, retrieving, and naming computation results. It implements
6
+ consistent naming conventions and path resolution strategies to ensure that:
7
+
8
+ 1. Computation results are stored in a predictable location
9
+ 2. Filenames follow a consistent pattern based on map dimensions
10
+ 3. Results can be reliably retrieved for future reference
11
+ 4. The system handles file operations safely with appropriate error handling
12
+
13
+ The module serves as the interface between the computational components of the package
14
+ and the filesystem, abstracting away the details of file operations and path management.
15
+ """
16
+ from mapFolding.theSSOT import The
17
+ from os import PathLike
18
+ from pathlib import Path, PurePath
19
+ from sys import modules as sysModules
20
+ from typing import Any
21
+ import os
22
+
23
+ def getFilenameFoldsTotal(mapShape: tuple[int, ...]) -> str:
24
+ """
25
+ Create a standardized filename for a computed `foldsTotal` value.
26
+
27
+ This function generates a consistent, filesystem-safe filename based on map dimensions.
28
+ Standardizing filenames ensures that results can be reliably stored and retrieved,
29
+ avoiding potential filesystem incompatibilities or Python naming restrictions.
30
+
31
+ Parameters:
32
+ mapShape: A sequence of integers representing the dimensions of the map.
33
+
34
+ Returns:
35
+ filenameFoldsTotal: A filename string in format 'pMxN.foldsTotal' where M,N are sorted dimensions.
36
+
37
+ Notes:
38
+ The filename format ensures:
39
+ - No spaces in the filename
40
+ - Safe filesystem characters
41
+ - Unique extension (.foldsTotal)
42
+ - Python-safe strings (no starting with numbers, no reserved words)
43
+ - The 'p' prefix preserves compatibility with Lunnan's original code.
44
+ """
45
+ return 'p' + 'x'.join(str(dimension) for dimension in sorted(mapShape)) + '.foldsTotal'
46
+
47
+ def getPathFilenameFoldsTotal(mapShape: tuple[int, ...], pathLikeWriteFoldsTotal: PathLike[str] | PurePath | None = None) -> Path:
48
+ """
49
+ Get a standardized path and filename for the computed foldsTotal value.
50
+
51
+ This function resolves paths for storing computation results, handling different
52
+ input types including directories, absolute paths, or relative paths. It ensures
53
+ that all parent directories exist in the resulting path.
54
+
55
+ Parameters:
56
+ mapShape: List of dimensions for the map folding problem.
57
+ pathLikeWriteFoldsTotal (getPathJobRootDEFAULT): Path, filename, or relative path and filename.
58
+ If None, uses default path. If a directory, appends standardized filename.
59
+
60
+ Returns:
61
+ pathFilenameFoldsTotal: Absolute path and filename for storing the foldsTotal value.
62
+
63
+ Notes:
64
+ The function creates any necessary directories in the path if they don't exist.
65
+ """
66
+
67
+ if pathLikeWriteFoldsTotal is None:
68
+ pathFilenameFoldsTotal = getPathRootJobDEFAULT() / getFilenameFoldsTotal(mapShape)
69
+ else:
70
+ pathLikeSherpa = Path(pathLikeWriteFoldsTotal)
71
+ if pathLikeSherpa.is_dir():
72
+ pathFilenameFoldsTotal = pathLikeSherpa / getFilenameFoldsTotal(mapShape)
73
+ elif pathLikeSherpa.is_file() and pathLikeSherpa.is_absolute():
74
+ pathFilenameFoldsTotal = pathLikeSherpa
75
+ else:
76
+ pathFilenameFoldsTotal = getPathRootJobDEFAULT() / pathLikeSherpa
77
+
78
+ pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
79
+ return pathFilenameFoldsTotal
80
+
81
+ # TODO learn how to see this from the user's perspective
82
+ def getPathRootJobDEFAULT() -> Path:
83
+ pathJobDEFAULT = The.pathPackage / "jobs"
84
+ if 'google.colab' in sysModules:
85
+ pathJobDEFAULT = Path("/content/drive/MyDrive") / "jobs"
86
+ pathJobDEFAULT.mkdir(parents=True, exist_ok=True)
87
+ return pathJobDEFAULT
88
+
89
+ def _saveFoldsTotal(pathFilename: PathLike[str] | PurePath, foldsTotal: int) -> None:
90
+ pathFilenameFoldsTotal = Path(pathFilename)
91
+ pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
92
+ pathFilenameFoldsTotal.write_text(str(foldsTotal))
93
+
94
+ def saveFoldsTotal(pathFilename: PathLike[str] | PurePath, foldsTotal: int) -> None:
95
+ """
96
+ Save `foldsTotal` value to disk with multiple fallback mechanisms.
97
+
98
+ This function attempts to save the computed `foldsTotal` value to the specified
99
+ location, with backup strategies in case the primary save attempt fails.
100
+ The robustness is critical since these computations may take days to complete.
101
+
102
+ Parameters:
103
+ pathFilename: Target save location for the `foldsTotal` value
104
+ foldsTotal: The computed value to save
105
+
106
+ Notes:
107
+ If the primary save fails, the function will attempt alternative save methods:
108
+ 1. Print the value prominently to stdout
109
+ 2. Create a fallback file in the current working directory
110
+ 3. As a last resort, simply print the value
111
+ """
112
+ try:
113
+ _saveFoldsTotal(pathFilename, foldsTotal)
114
+ except Exception as ERRORmessage:
115
+ try:
116
+ print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
117
+ print(ERRORmessage)
118
+ print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
119
+ randomnessPlanB = (int(str(foldsTotal).strip()[-1]) + 1) * ['YO_']
120
+ filenameInfixUnique = ''.join(randomnessPlanB)
121
+ pathFilenamePlanB = os.path.join(os.getcwd(), 'foldsTotal' + filenameInfixUnique + '.txt')
122
+ writeStreamFallback = open(pathFilenamePlanB, 'w')
123
+ writeStreamFallback.write(str(foldsTotal))
124
+ writeStreamFallback.close()
125
+ print(str(pathFilenamePlanB))
126
+ except Exception:
127
+ print(foldsTotal)
128
+ return None
129
+
130
+ def saveFoldsTotalFAILearly(pathFilename: PathLike[str] | PurePath) -> None:
131
+ if Path(pathFilename).exists():
132
+ raise FileExistsError(f"{pathFilename=} exists: a battle of overwriting might cause tears.")
133
+ if not Path(pathFilename).parent.exists():
134
+ raise FileNotFoundError(f"I received {pathFilename=} 0.000139 seconds ago from a function that promised it created the parent directory, but the parent directory does not exist. Fix that now, so your computation doesn't get deleted later. And be compassionate to others.")
135
+ foldsTotal = 149302889205120
136
+ _saveFoldsTotal(pathFilename, foldsTotal)
137
+ if not Path(pathFilename).exists():
138
+ raise FileNotFoundError(f"I just wrote a test file to {pathFilename=}, but it does not exist. Fix that now, so your computation doesn't get deleted later. And continually improve your empathy skills.")
139
+ foldsTotalRead = int(Path(pathFilename).read_text())
140
+ if foldsTotalRead != foldsTotal:
141
+ raise FileNotFoundError(f"I wrote a test file to {pathFilename=} with contents of {str(foldsTotal)=}, but I read {foldsTotalRead=} from the file. Python says the values are not equal. Fix that now, so your computation doesn't get corrupted later. And be pro-social.")
142
+
143
+ def writeStringToHere(this: str, pathFilename: PathLike[str] | PurePath) -> None:
144
+ """
145
+ Write a string to a file, creating parent directories if needed.
146
+
147
+ Parameters:
148
+ this: The string content to write to the file
149
+ pathFilename: The target file path where the string should be written
150
+ """
151
+ pathFilename = Path(pathFilename)
152
+ pathFilename.parent.mkdir(parents=True, exist_ok=True)
153
+ pathFilename.write_text(str(this))
154
+ return None
@@ -33,7 +33,7 @@ if TYPE_CHECKING:
33
33
  else:
34
34
  TypedDict = dict
35
35
 
36
- cacheDays = 7
36
+ cacheDays = 30
37
37
 
38
38
  """
39
39
  Section: make `settingsOEIS`"""
@@ -24,23 +24,42 @@ These tools were developed for map folding computation optimization but are desi
24
24
  general-purpose utilities applicable to a wide range of code transformation scenarios,
25
25
  particularly for numerically-intensive algorithms that benefit from just-in-time compilation.
26
26
  """
27
+ from mapFolding.someAssemblyRequired._theTypes import (
28
+ ast_expr_Slice,
29
+ ast_Identifier,
30
+ ImaAnnotationType,
31
+ astClassHasDOTnameNotName,
32
+ astClassHasDOTnameNotNameOptional,
33
+ astClassHasDOTtarget,
34
+ astClassHasDOTvalue,
35
+ astMosDef,
36
+ intORlist_ast_type_paramORstr_orNone,
37
+ intORstr_orNone,
38
+ list_ast_type_paramORstr_orNone,
39
+ str_nameDOTname,
40
+ typeCertified,
41
+ )
42
+
43
+ from mapFolding.someAssemblyRequired._toolboxPython import (
44
+ importLogicalPath2Callable,
45
+ importPathFilename2Callable,
46
+ NodeChanger,
47
+ NodeTourist,
48
+ parseLogicalPath2astModule,
49
+ parsePathFilename2astModule,
50
+ )
51
+
52
+ from mapFolding.someAssemblyRequired._toolboxAntecedents import be, ifThis, 又
53
+ from mapFolding.someAssemblyRequired._tool_Make import Make
54
+ from mapFolding.someAssemblyRequired._tool_Then import Then
55
+
27
56
  from mapFolding.someAssemblyRequired.transformationTools import (
28
- ast_Identifier as ast_Identifier,
29
- extractClassDef as extractClassDef,
30
- extractFunctionDef as extractFunctionDef,
31
- ifThis as ifThis,
32
- IngredientsFunction as IngredientsFunction,
33
- IngredientsModule as IngredientsModule,
34
- inlineThisFunctionWithTheseValues as inlineThisFunctionWithTheseValues,
35
- LedgerOfImports as LedgerOfImports,
36
- Make as Make,
37
- makeDictionaryReplacementStatements as makeDictionaryReplacementStatements,
38
- NodeCollector as NodeCollector,
39
- NodeReplacer as NodeReplacer,
40
- RecipeSynthesizeFlow as RecipeSynthesizeFlow,
41
- strDotStrCuzPyStoopid as strDotStrCuzPyStoopid,
42
- Then as Then,
43
- write_astModule as write_astModule,
44
- Z0Z_executeActionUnlessDescendantMatches as Z0Z_executeActionUnlessDescendantMatches,
45
- Z0Z_replaceMatchingASTnodes as Z0Z_replaceMatchingASTnodes,
57
+ dictionaryEstimates,
58
+ extractClassDef,
59
+ extractFunctionDef,
60
+ write_astModule,
61
+ Z0Z_executeActionUnlessDescendantMatches,
62
+ Z0Z_inlineThisFunctionWithTheseValues,
63
+ Z0Z_lameFindReplace,
64
+ Z0Z_makeDictionaryReplacementStatements,
46
65
  )
@@ -0,0 +1,35 @@
1
+ """
2
+ Type definitions used across the AST transformation modules.
3
+
4
+ This module provides type aliases and variables used in AST manipulation,
5
+ centralizing type definitions to prevent circular imports.
6
+ """
7
+ from typing import Any, TYPE_CHECKING, TypeAlias as typing_TypeAlias, TypeVar as typing_TypeVar
8
+ import ast
9
+
10
+ stuPyd: typing_TypeAlias = str
11
+
12
+ if TYPE_CHECKING:
13
+ astClassHasDOTnameNotName: typing_TypeAlias = ast.alias | ast.AsyncFunctionDef | ast.ClassDef | ast.FunctionDef | ast.ParamSpec | ast.TypeVar | ast.TypeVarTuple
14
+ astClassHasDOTnameNotNameOptional: typing_TypeAlias = astClassHasDOTnameNotName | ast.ExceptHandler | ast.MatchAs | ast.MatchStar | None
15
+ astClassHasDOTtarget: typing_TypeAlias = ast.AnnAssign | ast.AsyncFor | ast.AugAssign | ast.comprehension | ast.For | ast.NamedExpr
16
+ 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
17
+ else:
18
+ astClassHasDOTnameNotName = stuPyd
19
+ astClassHasDOTnameNotNameOptional = stuPyd
20
+ astClassHasDOTtarget = stuPyd
21
+ astClassHasDOTvalue = stuPyd
22
+
23
+ ast_expr_Slice: typing_TypeAlias = ast.expr
24
+ ast_Identifier: typing_TypeAlias = str
25
+ intORlist_ast_type_paramORstr_orNone: typing_TypeAlias = Any
26
+ intORstr_orNone: typing_TypeAlias = Any
27
+ list_ast_type_paramORstr_orNone: typing_TypeAlias = Any
28
+ # TODO I am using the moniker `nameDOTname` in two very different ways: differentiate them.
29
+ str_nameDOTname: typing_TypeAlias = stuPyd
30
+ ImaAnnotationType: typing_TypeAlias = ast.Attribute | ast.Constant | ast.Name | ast.Subscript
31
+
32
+ # TODO understand whatever the fuck `typing.TypeVar` is _supposed_ to fucking do.
33
+ typeCertified = typing_TypeVar('typeCertified')
34
+
35
+ astMosDef = typing_TypeVar('astMosDef', bound=astClassHasDOTnameNotName)
@@ -0,0 +1,92 @@
1
+ from collections.abc import Sequence
2
+ from mapFolding.someAssemblyRequired import ast_expr_Slice, ast_Identifier, ImaAnnotationType, intORlist_ast_type_paramORstr_orNone, intORstr_orNone, list_ast_type_paramORstr_orNone
3
+ from typing import Any
4
+ import ast
5
+
6
+ class Make:
7
+ """Almost all parameters described here are only accessible through a method's `**keywordArguments` parameter.
8
+
9
+ Parameters:
10
+ context (ast.Load()): Are you loading from, storing to, or deleting the identifier? The `context` (also, `ctx`) value is `ast.Load()`, `ast.Store()`, or `ast.Del()`.
11
+ col_offset (0): int Position information specifying the column where an AST node begins.
12
+ end_col_offset (None): int|None Position information specifying the column where an AST node ends.
13
+ end_lineno (None): int|None Position information specifying the line number where an AST node ends.
14
+ level (0): int Module import depth level that controls relative vs absolute imports. Default 0 indicates absolute import.
15
+ lineno: int Position information manually specifying the line number where an AST node begins.
16
+ kind (None): str|None Used for type annotations in limited cases.
17
+ type_comment (None): str|None "type_comment is an optional string with the type annotation as a comment." or `# type: ignore`.
18
+ type_params: list[ast.type_param] Type parameters for generic type definitions.
19
+
20
+ The `ast._Attributes`, lineno, col_offset, end_lineno, and end_col_offset, hold position information; however, they are, importantly, _not_ `ast._fields`.
21
+ """
22
+ @staticmethod
23
+ def alias(name: ast_Identifier, asname: ast_Identifier | None = None) -> ast.alias:
24
+ return ast.alias(name, asname)
25
+ @staticmethod
26
+ 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.
27
+ return ast.AnnAssign(target, annotation, value, simple=int(isinstance(target, ast.Name)), **keywordArguments)
28
+ @staticmethod
29
+ def arg(identifier: ast_Identifier, annotation: ast.expr | None = None, **keywordArguments: intORstr_orNone) -> ast.arg:
30
+ return ast.arg(identifier, annotation, **keywordArguments)
31
+ @staticmethod
32
+ 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:
33
+ return ast.arguments(posonlyargs, args, vararg, kwonlyargs, kw_defaults, kwarg, defaults)
34
+ @staticmethod
35
+ def Assign(listTargets: Any, value: ast.expr, **keywordArguments: intORstr_orNone) -> ast.Assign:
36
+ return ast.Assign(listTargets, value, **keywordArguments)
37
+ @staticmethod
38
+ def Attribute(value: ast.expr, *attribute: ast_Identifier, context: ast.expr_context = ast.Load(), **keywordArguments: int) -> ast.Attribute:
39
+ """ If two `ast_Identifier` are joined by a dot `.`, they are _usually_ an `ast.Attribute`, but see `ast.ImportFrom`.
40
+ Parameters:
41
+ value: the part before the dot (Often `ast.Name`, but also `ast.Attribute`, `ast.Starred`, and `ast.Subscript`.)
42
+ attribute: an `ast_Identifier` after a dot `.`; you can pass multiple `attribute` and they will be chained together.
43
+ """
44
+ # TODO confirm the precision of the docstring.
45
+ def addDOTattribute(chain, identifier: ast_Identifier, context: ast.expr_context, **keywordArguments: int) -> ast.Attribute:
46
+ return ast.Attribute(value=chain, attr=identifier, ctx=context, **keywordArguments)
47
+ buffaloBuffalo = addDOTattribute(value, attribute[0], context, **keywordArguments)
48
+ for identifier in attribute[1:None]:
49
+ buffaloBuffalo = addDOTattribute(buffaloBuffalo, identifier, context, **keywordArguments)
50
+ return buffaloBuffalo
51
+ @staticmethod
52
+ # TODO are the types for `callee` comprehensive?
53
+ # 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.
54
+ def Call(callee: ast.Attribute | ast.Name | ast.Subscript, listArguments: Sequence[ast.expr] | None = None, list_astKeywords: Sequence[ast.keyword] | None = None) -> ast.Call:
55
+ return ast.Call(func=callee, args=list(listArguments) if listArguments else [], keywords=list(list_astKeywords) if list_astKeywords else [])
56
+ @staticmethod
57
+ 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:
58
+ return ast.ClassDef(name, listBases, list_keyword, body, decorator_list, **keywordArguments)
59
+ @staticmethod
60
+ def Constant(value: Any, **keywordArguments: intORstr_orNone) -> ast.Constant:
61
+ """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."""
62
+ return ast.Constant(value, **keywordArguments)
63
+ @staticmethod
64
+ def Expr(value: ast.expr, **keywordArguments: int) -> ast.Expr:
65
+ return ast.Expr(value, **keywordArguments)
66
+ @staticmethod
67
+ 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:
68
+ return ast.FunctionDef(name, argumentsSpecification, body, decorator_list, returns, **keywordArguments)
69
+ @staticmethod
70
+ def Import(moduleIdentifier: ast_Identifier, asname: ast_Identifier | None = None, **keywordArguments: int) -> ast.Import:
71
+ return ast.Import(names=[Make.alias(moduleIdentifier, asname)], **keywordArguments)
72
+ @staticmethod
73
+ def ImportFrom(moduleIdentifier: ast_Identifier, list_astAlias: list[ast.alias], **keywordArguments: int) -> ast.ImportFrom:
74
+ return ast.ImportFrom(moduleIdentifier, list_astAlias, **keywordArguments)
75
+ @staticmethod
76
+ def keyword(keywordArgument: ast_Identifier, value: ast.expr, **keywordArguments: int) -> ast.keyword:
77
+ return ast.keyword(arg=keywordArgument, value=value, **keywordArguments)
78
+ @staticmethod
79
+ def Module(body: list[ast.stmt] = [], type_ignores: list[ast.TypeIgnore] = []) -> ast.Module:
80
+ return ast.Module(body, type_ignores)
81
+ @staticmethod
82
+ def Name(identifier: ast_Identifier, context: ast.expr_context = ast.Load(), **keywordArguments: int) -> ast.Name:
83
+ return ast.Name(identifier, context, **keywordArguments)
84
+ @staticmethod
85
+ def Return(value: ast.expr | None = None, **keywordArguments: int) -> ast.Return:
86
+ return ast.Return(value, **keywordArguments)
87
+ @staticmethod
88
+ def Subscript(value: ast.expr, slice: ast_expr_Slice, context: ast.expr_context = ast.Load(), **keywordArguments: int) -> ast.Subscript:
89
+ return ast.Subscript(value, slice, context, **keywordArguments)
90
+ @staticmethod
91
+ def Tuple(elements: Sequence[ast.expr] = [], context: ast.expr_context = ast.Load(), **keywordArguments: int) -> ast.Tuple:
92
+ return ast.Tuple(list(elements), context, **keywordArguments)
@@ -0,0 +1,65 @@
1
+ from collections.abc import Callable, Sequence
2
+ from mapFolding.someAssemblyRequired import ast_Identifier, astClassHasDOTvalue, astMosDef
3
+ from typing import Any
4
+ import ast
5
+
6
+ class Then:
7
+ @staticmethod
8
+ def allOf(listActions: Sequence[Callable[[ast.AST], Any]]) -> Callable[[ast.AST], ast.AST]:
9
+ def workhorse(node: ast.AST) -> ast.AST:
10
+ for action in listActions: action(node)
11
+ return node
12
+ return workhorse
13
+
14
+ @staticmethod
15
+ def appendTo(listOfAny: list[Any]) -> Callable[[ast.AST], None]:
16
+ return lambda node: listOfAny.append(node)
17
+
18
+ @staticmethod
19
+ def DOTarg(action: Callable[[Any], Any]) -> Callable[[ast.arg | ast.keyword], ast.arg | ast.keyword]:
20
+ def workhorse(node: ast.arg | ast.keyword) -> ast.arg | ast.keyword:
21
+ node.arg = action(node.arg)
22
+ return node
23
+ return workhorse
24
+ @staticmethod
25
+ def DOTfunc(action: Callable[[Any], Any]) -> Callable[[ast.Call], ast.Call]:
26
+ def workhorse(node: ast.Call) -> ast.Call:
27
+ node.func = action(node.func)
28
+ return node
29
+ return workhorse
30
+ @staticmethod
31
+ def DOTid(action: Callable[[Any], Any]) -> Callable[[ast.Name], ast.Name]:
32
+ def workhorse(node: ast.Name) -> ast.Name:
33
+ node.id = action(node.id)
34
+ return node
35
+ return workhorse
36
+ @staticmethod
37
+ def DOTtarget(action: Callable[[Any], Any]) -> Callable[[ast.AnnAssign | ast.AugAssign], ast.AnnAssign | ast.AugAssign]:
38
+ def workhorse(node: ast.AnnAssign | ast.AugAssign) -> ast.AnnAssign | ast.AugAssign:
39
+ node.target = action(node.target)
40
+ return node
41
+ return workhorse
42
+ @staticmethod
43
+ def DOTvalue(action: Callable[[Any], Any]) -> Callable[[astClassHasDOTvalue], astClassHasDOTvalue]:
44
+ def workhorse(node: astClassHasDOTvalue) -> astClassHasDOTvalue:
45
+ node.value = action(node.value)
46
+ return node
47
+ return workhorse
48
+
49
+ @staticmethod
50
+ def getIt(node: ast.AST) -> ast.AST | ast_Identifier:
51
+ return node
52
+ @staticmethod
53
+ def insertThisAbove(list_astAST: Sequence[ast.AST]) -> Callable[[ast.AST], Sequence[ast.AST]]:
54
+ return lambda aboveMe: [*list_astAST, aboveMe]
55
+ @staticmethod
56
+ def insertThisBelow(list_astAST: Sequence[ast.AST]) -> Callable[[ast.AST], Sequence[ast.AST]]:
57
+ return lambda belowMe: [belowMe, *list_astAST]
58
+ @staticmethod
59
+ def removeIt(_node: ast.AST) -> None: return None
60
+ @staticmethod
61
+ def replaceWith(astAST: ast.AST | ast_Identifier) -> Callable[[ast.AST], ast.AST | ast_Identifier]:
62
+ return lambda _replaceMe: astAST
63
+ @staticmethod
64
+ def updateThis(dictionaryOf_astMosDef: dict[ast_Identifier, astMosDef]) -> Callable[[astMosDef], astMosDef]:
65
+ return lambda node: dictionaryOf_astMosDef.setdefault(node.name, node)