mapFolding 0.8.4__py3-none-any.whl → 0.8.5__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 (34) hide show
  1. mapFolding/__init__.py +4 -1
  2. mapFolding/basecamp.py +3 -3
  3. mapFolding/beDRY.py +241 -68
  4. mapFolding/oeis.py +3 -3
  5. mapFolding/reference/hunterNumba.py +1 -1
  6. mapFolding/someAssemblyRequired/__init__.py +16 -15
  7. mapFolding/someAssemblyRequired/_theTypes.py +31 -13
  8. mapFolding/someAssemblyRequired/_tool_Make.py +8 -1
  9. mapFolding/someAssemblyRequired/_tool_Then.py +12 -5
  10. mapFolding/someAssemblyRequired/_toolboxAntecedents.py +131 -99
  11. mapFolding/someAssemblyRequired/_toolboxContainers.py +35 -7
  12. mapFolding/someAssemblyRequired/_toolboxPython.py +17 -31
  13. mapFolding/someAssemblyRequired/getLLVMforNoReason.py +2 -2
  14. mapFolding/someAssemblyRequired/newInliner.py +22 -0
  15. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +24 -113
  16. mapFolding/someAssemblyRequired/toolboxNumba.py +358 -0
  17. mapFolding/someAssemblyRequired/transformationTools.py +253 -40
  18. mapFolding/theSSOT.py +30 -32
  19. mapFolding/{filesystem.py → toolboxFilesystem.py} +90 -25
  20. {mapfolding-0.8.4.dist-info → mapfolding-0.8.5.dist-info}/METADATA +3 -2
  21. mapfolding-0.8.5.dist-info/RECORD +48 -0
  22. tests/conftest.py +30 -31
  23. tests/test_computations.py +7 -6
  24. tests/test_filesystem.py +2 -2
  25. tests/test_other.py +2 -2
  26. tests/test_tasks.py +2 -2
  27. mapFolding/someAssemblyRequired/ingredientsNumba.py +0 -199
  28. mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +0 -156
  29. mapFolding/someAssemblyRequired/transformDataStructures.py +0 -235
  30. mapfolding-0.8.4.dist-info/RECORD +0 -49
  31. {mapfolding-0.8.4.dist-info → mapfolding-0.8.5.dist-info}/WHEEL +0 -0
  32. {mapfolding-0.8.4.dist-info → mapfolding-0.8.5.dist-info}/entry_points.txt +0 -0
  33. {mapfolding-0.8.4.dist-info → mapfolding-0.8.5.dist-info}/licenses/LICENSE +0 -0
  34. {mapfolding-0.8.4.dist-info → mapfolding-0.8.5.dist-info}/top_level.txt +0 -0
@@ -5,20 +5,29 @@ This module provides functions for standardized handling of files related to the
5
5
  package, with a focus on saving, retrieving, and naming computation results. It implements
6
6
  consistent naming conventions and path resolution strategies to ensure that:
7
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.
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 standardized interface between the computational components
14
+ of the package and the filesystem, abstracting away the details of file operations
15
+ and path management. It provides robust fallback mechanisms to preserve computation
16
+ results even in the face of filesystem errors, which is critical for long-running
17
+ computations that may take days to complete.
18
+
19
+ The functions here adhere to a consistent approach to path handling:
20
+ - Cross-platform compatibility through the use of `pathlib`.
21
+ - Default locations determined intelligently based on the runtime environment.
22
+ - Progressive fallback strategies for saving critical computation results.
23
+ - Preemptive filesystem validation to detect issues before computation begins.
15
24
  """
16
25
  from mapFolding.theSSOT import The
17
26
  from os import PathLike
18
27
  from pathlib import Path, PurePath
19
28
  from sys import modules as sysModules
20
- from typing import Any
21
29
  import os
30
+ import platformdirs
22
31
 
23
32
  def getFilenameFoldsTotal(mapShape: tuple[int, ...]) -> str:
24
33
  """
@@ -40,13 +49,13 @@ def getFilenameFoldsTotal(mapShape: tuple[int, ...]) -> str:
40
49
  - Safe filesystem characters
41
50
  - Unique extension (.foldsTotal)
42
51
  - Python-safe strings (no starting with numbers, no reserved words)
43
- - The 'p' prefix preserves compatibility with Lunnan's original code.
52
+ - The 'p' prefix comes from Lunnan's original code.
44
53
  """
45
54
  return 'p' + 'x'.join(str(dimension) for dimension in sorted(mapShape)) + '.foldsTotal'
46
55
 
47
56
  def getPathFilenameFoldsTotal(mapShape: tuple[int, ...], pathLikeWriteFoldsTotal: PathLike[str] | PurePath | None = None) -> Path:
48
57
  """
49
- Get a standardized path and filename for the computed foldsTotal value.
58
+ Get a standardized path and filename for the computed `foldsTotal` value.
50
59
 
51
60
  This function resolves paths for storing computation results, handling different
52
61
  input types including directories, absolute paths, or relative paths. It ensures
@@ -58,7 +67,7 @@ def getPathFilenameFoldsTotal(mapShape: tuple[int, ...], pathLikeWriteFoldsTotal
58
67
  If None, uses default path. If a directory, appends standardized filename.
59
68
 
60
69
  Returns:
61
- pathFilenameFoldsTotal: Absolute path and filename for storing the foldsTotal value.
70
+ pathFilenameFoldsTotal: Absolute path and filename for storing the `foldsTotal` value.
62
71
 
63
72
  Notes:
64
73
  The function creates any necessary directories in the path if they don't exist.
@@ -78,15 +87,40 @@ def getPathFilenameFoldsTotal(mapShape: tuple[int, ...], pathLikeWriteFoldsTotal
78
87
  pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
79
88
  return pathFilenameFoldsTotal
80
89
 
81
- # TODO learn how to see this from the user's perspective
82
90
  def getPathRootJobDEFAULT() -> Path:
83
- pathJobDEFAULT = The.pathPackage / "jobs"
91
+ """
92
+ Get the default root directory for map folding computation jobs.
93
+
94
+ This function determines the appropriate default directory for storing computation
95
+ results based on the current runtime environment. It uses platform-specific
96
+ directories for normal environments and adapts to special environments like
97
+ Google Colab.
98
+
99
+ Returns:
100
+ pathJobDEFAULT: Path to the default directory for storing computation results
101
+
102
+ Notes:
103
+ - For standard environments, uses `platformdirs` to find appropriate user data directory.
104
+ - For Google Colab, uses a specific path in Google Drive.
105
+ - Creates the directory if it doesn't exist.
106
+ """
107
+ pathJobDEFAULT = Path(platformdirs.user_data_dir(appname=The.packageName, appauthor=False, ensure_exists=True))
84
108
  if 'google.colab' in sysModules:
85
- pathJobDEFAULT = Path("/content/drive/MyDrive") / "jobs"
109
+ pathJobDEFAULT = Path("/content/drive/MyDrive") / The.packageName
86
110
  pathJobDEFAULT.mkdir(parents=True, exist_ok=True)
87
111
  return pathJobDEFAULT
88
112
 
89
113
  def _saveFoldsTotal(pathFilename: PathLike[str] | PurePath, foldsTotal: int) -> None:
114
+ """
115
+ Internal helper function to save a `foldsTotal` value to a file.
116
+
117
+ This is a low-level function used by the public `saveFoldsTotal` function.
118
+ It handles the basic file operation without extensive error handling.
119
+
120
+ Parameters:
121
+ pathFilename: Path where the `foldsTotal` value should be saved
122
+ foldsTotal: The integer value to save
123
+ """
90
124
  pathFilenameFoldsTotal = Path(pathFilename)
91
125
  pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
92
126
  pathFilenameFoldsTotal.write_text(str(foldsTotal))
@@ -105,17 +139,17 @@ def saveFoldsTotal(pathFilename: PathLike[str] | PurePath, foldsTotal: int) -> N
105
139
 
106
140
  Notes:
107
141
  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
142
+ 1. Print the value prominently to `stdout`.
143
+ 2. Create a fallback file in the current working directory.
144
+ 3. As a last resort, simply print the value.
111
145
  """
112
146
  try:
113
147
  _saveFoldsTotal(pathFilename, foldsTotal)
114
148
  except Exception as ERRORmessage:
115
149
  try:
116
- print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
150
+ print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal = }\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
117
151
  print(ERRORmessage)
118
- print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
152
+ print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal = }\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
119
153
  randomnessPlanB = (int(str(foldsTotal).strip()[-1]) + 1) * ['YO_']
120
154
  filenameInfixUnique = ''.join(randomnessPlanB)
121
155
  pathFilenamePlanB = os.path.join(os.getcwd(), 'foldsTotal' + filenameInfixUnique + '.txt')
@@ -128,25 +162,56 @@ def saveFoldsTotal(pathFilename: PathLike[str] | PurePath, foldsTotal: int) -> N
128
162
  return None
129
163
 
130
164
  def saveFoldsTotalFAILearly(pathFilename: PathLike[str] | PurePath) -> None:
165
+ """
166
+ Preemptively test file write capabilities before beginning computation.
167
+
168
+ This function performs validation checks on the target file location before
169
+ a potentially long-running computation begins. It tests several critical
170
+ aspects of filesystem functionality to ensure results can be saved:
171
+
172
+ 1. Checks if the file already exists to prevent accidental overwrites.
173
+ 2. Verifies that parent directories exist.
174
+ 3. Tests if the system can write a test value to the file.
175
+ 4. Confirms that the written value can be read back correctly.
176
+
177
+ Parameters:
178
+ pathFilename: The path and filename where computation results will be saved.
179
+
180
+ Raises:
181
+ FileExistsError: If the target file already exists.
182
+ FileNotFoundError: If parent directories don't exist or if write tests fail.
183
+
184
+ Notes:
185
+ This function helps prevent a situation where a computation runs for
186
+ hours or days only to discover at the end that results cannot be saved.
187
+ """
131
188
  if Path(pathFilename).exists():
132
- raise FileExistsError(f"{pathFilename=} exists: a battle of overwriting might cause tears.")
189
+ raise FileExistsError(f"`{pathFilename = }` exists: a battle of overwriting might cause tears.")
133
190
  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.")
191
+ 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
192
  foldsTotal = 149302889205120
136
193
  _saveFoldsTotal(pathFilename, foldsTotal)
137
194
  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.")
195
+ 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
196
  foldsTotalRead = int(Path(pathFilename).read_text())
140
197
  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.")
198
+ 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
199
 
143
200
  def writeStringToHere(this: str, pathFilename: PathLike[str] | PurePath) -> None:
144
201
  """
145
202
  Write a string to a file, creating parent directories if needed.
146
203
 
204
+ This utility function provides a consistent interface for writing string content
205
+ to files across the package. It handles path creation and ensures proper
206
+ string conversion.
207
+
147
208
  Parameters:
148
- this: The string content to write to the file
149
- pathFilename: The target file path where the string should be written
209
+ this: The string content to write to the file.
210
+ pathFilename: The target file path where the string should be written.
211
+
212
+ Notes:
213
+ This function creates all parent directories in the path if they don't exist,
214
+ making it safe to use with newly created directory structures.
150
215
  """
151
216
  pathFilename = Path(pathFilename)
152
217
  pathFilename.parent.mkdir(parents=True, exist_ok=True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapFolding
3
- Version: 0.8.4
3
+ Version: 0.8.5
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
@@ -35,6 +35,7 @@ Requires-Dist: more_itertools
35
35
  Requires-Dist: numba_progress
36
36
  Requires-Dist: numba
37
37
  Requires-Dist: numpy
38
+ Requires-Dist: platformdirs
38
39
  Requires-Dist: python_minifier
39
40
  Requires-Dist: tomli
40
41
  Requires-Dist: Z0Z_tools
@@ -132,7 +133,7 @@ The package provides a sophisticated transformation framework that bridges the g
132
133
  - Study the functional state-transformation approach in `theDao.py` with clear, isolated functions
133
134
  - Explore the semantic decomposition in `reference/flattened.py` to understand algorithm sections
134
135
 
135
- - **Code Transformation Pipeline**:
136
+ - **Code Transformation Assembly-line**:
136
137
  - **AST Manipulation**: Analyzes and transforms the algorithm's abstract syntax tree
137
138
  - **Dataclass "Shattering"**: Decomposes complex state objects into primitive components
138
139
  - **Optimization Applications**: Applies domain-specific optimizations for numerical computation
@@ -0,0 +1,48 @@
1
+ mapFolding/__init__.py,sha256=LBgk-iW95pzqkFGY8PbcnU0oHy0AXwJGo18mM0g8wEw,2227
2
+ mapFolding/basecamp.py,sha256=-__EJ2to84ssS4Fm0CAuQjRnghI9VA4cXZoWGYud1r0,4782
3
+ mapFolding/beDRY.py,sha256=2GPO4A8XcxoEJXB_3sro4ZFQ5gcU7ywc1-c8HLEvEv0,15280
4
+ mapFolding/noHomeYet.py,sha256=UKZeWlyn0SKlF9dhYoud7E6gWXpiSEekZOOoJp88WeI,1362
5
+ mapFolding/oeis.py,sha256=EzEnbRi_4qt8Na2tiMcvL23FXpcJEkXTwuXDYDFH_XI,12631
6
+ mapFolding/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ mapFolding/theDao.py,sha256=MVopt1LzhdIQYA97SEoq9bdzct6hbK0lEyPxBAAlVTc,9934
8
+ mapFolding/theSSOT.py,sha256=i3R_G702U7VQOil61ky60JGGsSEOk_x1555rg8yI0Tc,11978
9
+ mapFolding/toolboxFilesystem.py,sha256=WoqRjXqTXy5GYNmbfzWtzv1uufm7vYcgT4zJ9ffhRYY,9982
10
+ mapFolding/reference/__init__.py,sha256=UIEU8BJR_YDzjFQcLel3XtHzOCJiOUGlGiWzOzbvhik,2206
11
+ mapFolding/reference/flattened.py,sha256=QK1xG9SllqCoi68e86Hyl9d9ATUAAFNpTQI-3zmcp5I,16072
12
+ mapFolding/reference/hunterNumba.py,sha256=iLfyqwGdAh6c5GbapnKsWhAsNsR3O-fyGGHAdohluLw,7258
13
+ mapFolding/reference/irvineJavaPort.py,sha256=UEfIX4QbPLl5jnyfYIyX5YRR3_rYvPUikK8jLehsFko,4076
14
+ mapFolding/reference/jaxCount.py,sha256=TuDNKOnyhQfuixKmIxO9Algv7dvy7KMGhgsV3h96FGE,14853
15
+ mapFolding/reference/lunnanNumpy.py,sha256=mMgrgbrBpe4nmo72ThEI-MGH0OwEHmfMPczSXHp2qKo,4357
16
+ mapFolding/reference/lunnanWhile.py,sha256=ZL8GAQtPs5nJZSgoDl5USrLSS_zs03y98y1Z9E4jOmQ,3799
17
+ mapFolding/reference/rotatedEntryPoint.py,sha256=5ughpKUT2JQhoAKgoDUdYNjgWQYPGV8v-7dWEAdDmfE,10274
18
+ mapFolding/reference/total_countPlus1vsPlusN.py,sha256=yJZAVLVdoXqHag2_N6_6CT-Q6HXBgRro-eny93-Rlpw,9307
19
+ mapFolding/reference/jobsCompleted/__init__.py,sha256=TU93ZGUW1xEkT6d9mQFn_rp5DvRy0ZslEB2Q6MF5ZDc,2596
20
+ mapFolding/reference/jobsCompleted/[2x19]/p2x19.py,sha256=_tvYtfzMWVo2VtUbIAieoscb4N8FFflgTdW4-ljBUuA,19626
21
+ mapFolding/reference/jobsCompleted/p2x19/p2x19.py,sha256=eZEw4Me4ocTt6VXoK2-Sbd5SowZtxRIbN9dZmc7OCVg,6395
22
+ mapFolding/someAssemblyRequired/__init__.py,sha256=c2GFI2HSId2_R_aoJWBID-P9AMF3zoHJzOc10XS6DHc,2669
23
+ mapFolding/someAssemblyRequired/_theTypes.py,sha256=SG82WTtQy83BmInlHZHY8Nh3Kp161NcEFSA6-UU5wuE,4623
24
+ mapFolding/someAssemblyRequired/_tool_Make.py,sha256=8ezrMDAdUY6m1raFp-G8vNXrHEr8IGfnZJ-aMVKzGf0,7092
25
+ mapFolding/someAssemblyRequired/_tool_Then.py,sha256=QxuoBqj4iOeKWITjV3DcV8c25fLx3Q6mhUORD7-mCzc,2758
26
+ mapFolding/someAssemblyRequired/_toolboxAntecedents.py,sha256=GEAuniYRj6yOtrJO_6sGZMzsVARdejts8NXhR_0np_c,21914
27
+ mapFolding/someAssemblyRequired/_toolboxContainers.py,sha256=iPLZbFcGB6dKtX3WkopnM-2OtMcVuxXQT46iFhzpdfY,17815
28
+ mapFolding/someAssemblyRequired/_toolboxPython.py,sha256=za30092eT00tj5ctqUCRrEuq5DGeJZN-vV9T4Dro-1w,3483
29
+ mapFolding/someAssemblyRequired/getLLVMforNoReason.py,sha256=9RPU6vK_eUg64GtVFI_nZnvUryXw8gfHJs9NyDYHIvg,2745
30
+ mapFolding/someAssemblyRequired/newInliner.py,sha256=Tm9PSzt66oIXPVrN9VdQwEYBba2iEOF5X3aEsOOF-FE,946
31
+ mapFolding/someAssemblyRequired/synthesizeNumbaJob.py,sha256=0L5ccqBusof6MzKatKnpUmFUNkAtbapzl_Fxmofi4DE,8684
32
+ mapFolding/someAssemblyRequired/toolboxNumba.py,sha256=rluEmsSJOQCl2L6LlJzIc3AfeRxU6cp-sCf-rQFW-og,22613
33
+ mapFolding/someAssemblyRequired/transformationTools.py,sha256=iIvRxSL45qTyl0d0ztHa9BP1MrOikfXE4HBqLlNMENc,20081
34
+ mapFolding/syntheticModules/__init__.py,sha256=evVFqhCGa-WZKDiLcnQWjs-Bj34eRnfSLqz_d7dFYZY,83
35
+ mapFolding/syntheticModules/numbaCount_doTheNeedful.py,sha256=3thXThbv2Xo0t_cRGzMbHPFXTBmLClmKejR_Ibu_jOo,15697
36
+ mapfolding-0.8.5.dist-info/licenses/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
37
+ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
+ tests/conftest.py,sha256=LfogHLu7PULSECwhLQgGCgqSvDMBc5b9RGWBls3YBrM,11364
39
+ tests/test_computations.py,sha256=XjCej6M6lesfKB_ulWq3O-ryXBsJuuwnJ6_XjKOvgDY,3552
40
+ tests/test_filesystem.py,sha256=YEHNU6tUCTj9C65cKs3ETgt3OZTGVnNjxgu4aH6C9uU,3164
41
+ tests/test_oeis.py,sha256=uxvwmgbnylSDdsVJfuAT0LuYLbIVFwSgdLxHm-xUGBM,5043
42
+ tests/test_other.py,sha256=O05PFAK70Skf-k99Wcg4ASLpMpBH-WkELtk6MnynDx0,4293
43
+ tests/test_tasks.py,sha256=S-6PNfM__Npw0zVojgzn5M-6ODBKDyRH5ccMTqQF9C4,2865
44
+ mapfolding-0.8.5.dist-info/METADATA,sha256=vrusTb9uu8FQ3UksfFkVZ3txtYPNufYa3db-Rk6H1y0,9359
45
+ mapfolding-0.8.5.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
46
+ mapfolding-0.8.5.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
47
+ mapfolding-0.8.5.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
48
+ mapfolding-0.8.5.dist-info/RECORD,,
tests/conftest.py CHANGED
@@ -1,13 +1,11 @@
1
1
  from collections.abc import Callable, Generator, Sequence
2
2
  from mapFolding.beDRY import getLeavesTotal, validateListDimensions, makeDataContainer
3
3
  from mapFolding.oeis import oeisIDsImplemented, settingsOEIS
4
- from mapFolding.someAssemblyRequired import importLogicalPath2Callable
5
- from mapFolding.someAssemblyRequired.synthesizeNumbaFlow import makeNumbaFlow
6
- from mapFolding.someAssemblyRequired._toolboxContainers import RecipeSynthesizeFlow
4
+ from mapFolding.someAssemblyRequired import importLogicalPath2Callable, RecipeSynthesizeFlow
7
5
  from mapFolding.theSSOT import ComputationState, The, getPackageDispatcher
8
6
  from pathlib import Path, PurePosixPath
9
7
  from types import ModuleType
10
- from typing import Any, ContextManager
8
+ from typing import Any
11
9
  import importlib
12
10
  import importlib.util
13
11
  import numpy
@@ -215,34 +213,35 @@ def useAlgorithmSourceDispatcher(useThisDispatcher: Callable[..., Any]) -> Gener
215
213
 
216
214
  @pytest.fixture
217
215
  def syntheticDispatcherFixture(useThisDispatcher: Callable[..., Any], pathTmpTesting: Path) -> Callable[..., Any]:
218
- """Generate synthetic Numba-optimized dispatcher module and patch the dispatcher"""
219
- # Configure synthesis flow to use test directory
220
- TESTINGrecipeFlow = RecipeSynthesizeFlow(
221
- pathPackage=PurePosixPath(pathTmpTesting.absolute()),
222
- logicalPathFlowRoot=None,
223
- moduleDispatcher="test_dispatcher",
216
+ """Generate synthetic Numba-optimized dispatcher module and patch the dispatcher"""
217
+ from mapFolding.someAssemblyRequired.toolboxNumba import makeNumbaFlow
218
+
219
+ TESTINGrecipeFlow = RecipeSynthesizeFlow(
220
+ pathPackage=PurePosixPath(pathTmpTesting.absolute()),
221
+ logicalPathFlowRoot=None,
222
+ moduleDispatcher="test_dispatcher",
224
223
  # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
225
- # dispatcherCallable="dispatcherSynthetic",
226
- )
227
-
228
- # Generate optimized module in test directory
229
- makeNumbaFlow(TESTINGrecipeFlow)
230
-
231
- # Import synthesized dispatcher
232
- importlibSpecificationDispatcher = importlib.util.spec_from_file_location(
233
- TESTINGrecipeFlow.moduleDispatcher,
234
- Path(TESTINGrecipeFlow.pathFilenameDispatcher),
235
- )
236
- if importlibSpecificationDispatcher is None or importlibSpecificationDispatcher.loader is None:
237
- raise ImportError("Failed to load synthetic dispatcher module")
238
-
239
- moduleSpecificationDispatcher = importlib.util.module_from_spec(importlibSpecificationDispatcher)
240
- importlibSpecificationDispatcher.loader.exec_module(moduleSpecificationDispatcher)
241
- callableDispatcherSynthetic = getattr(moduleSpecificationDispatcher, TESTINGrecipeFlow.callableDispatcher)
242
-
243
- # Patch dispatcher and return callable
244
- useThisDispatcher(callableDispatcherSynthetic)
245
- return callableDispatcherSynthetic
224
+ # dispatcherCallable="dispatcherSynthetic",
225
+ )
226
+
227
+ # Generate optimized module in test directory
228
+ makeNumbaFlow(TESTINGrecipeFlow)
229
+
230
+ # Import synthesized dispatcher
231
+ importlibSpecificationDispatcher = importlib.util.spec_from_file_location(
232
+ TESTINGrecipeFlow.moduleDispatcher,
233
+ Path(TESTINGrecipeFlow.pathFilenameDispatcher),
234
+ )
235
+ if importlibSpecificationDispatcher is None or importlibSpecificationDispatcher.loader is None:
236
+ raise ImportError("Failed to load synthetic dispatcher module")
237
+
238
+ moduleSpecificationDispatcher = importlib.util.module_from_spec(importlibSpecificationDispatcher)
239
+ importlibSpecificationDispatcher.loader.exec_module(moduleSpecificationDispatcher)
240
+ callableDispatcherSynthetic = getattr(moduleSpecificationDispatcher, TESTINGrecipeFlow.callableDispatcher)
241
+
242
+ # Patch dispatcher and return callable
243
+ useThisDispatcher(callableDispatcherSynthetic)
244
+ return callableDispatcherSynthetic
246
245
 
247
246
  def uniformTestMessage(expected: Any, actual: Any, functionName: str, *arguments: Any) -> str:
248
247
  """Format assertion message for any test comparison."""
@@ -1,10 +1,9 @@
1
1
  from mapFolding.basecamp import countFolds
2
- from mapFolding.filesystem import getPathFilenameFoldsTotal
2
+ from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal
3
3
  from mapFolding.beDRY import validateListDimensions
4
4
  from mapFolding.noHomeYet import getFoldsTotalKnown
5
5
  from mapFolding.oeis import settingsOEIS, oeisIDfor_n
6
- from mapFolding.someAssemblyRequired.synthesizeNumbaJob import makeJobNumba, Z0Z_RecipeJob
7
- from mapFolding.someAssemblyRequired.transformDataStructures import makeInitializedComputationState
6
+ from mapFolding.someAssemblyRequired.transformationTools import makeInitializedComputationState
8
7
  from pathlib import Path, PurePosixPath
9
8
  from tests.conftest import standardizedEqualToCallableReturn, registrarRecordsTmpObject
10
9
  from types import ModuleType
@@ -35,6 +34,8 @@ def test_syntheticSequential(syntheticDispatcherFixture: None, listDimensionsTes
35
34
 
36
35
  @pytest.mark.parametrize('pathFilenameTmpTesting', ['.py'], indirect=True)
37
36
  def test_writeJobNumba(oneTestCuzTestsOverwritingTests: list[int], pathFilenameTmpTesting: Path) -> None:
37
+ from mapFolding.someAssemblyRequired.toolboxNumba import RecipeJob, SpicesJobNumba
38
+ from mapFolding.someAssemblyRequired.synthesizeNumbaJob import makeJobNumba
38
39
  mapShape = validateListDimensions(oneTestCuzTestsOverwritingTests)
39
40
  state = makeInitializedComputationState(mapShape)
40
41
 
@@ -42,12 +43,12 @@ def test_writeJobNumba(oneTestCuzTestsOverwritingTests: list[int], pathFilenameT
42
43
  pathFilenameFoldsTotal = pathFilenameModule.with_suffix('.foldsTotalTesting')
43
44
  registrarRecordsTmpObject(pathFilenameFoldsTotal)
44
45
 
45
- jobTest = Z0Z_RecipeJob(state
46
+ jobTest = RecipeJob(state
46
47
  , pathModule=PurePosixPath(pathFilenameModule.parent)
47
48
  , moduleIdentifier=pathFilenameModule.stem
48
49
  , pathFilenameFoldsTotal=PurePosixPath(pathFilenameFoldsTotal))
49
-
50
- makeJobNumba(jobTest)
50
+ spices = SpicesJobNumba()
51
+ makeJobNumba(jobTest, spices)
51
52
 
52
53
  Don_Lapre_Road_to_Self_Improvement = importlib.util.spec_from_file_location("__main__", pathFilenameModule)
53
54
  if Don_Lapre_Road_to_Self_Improvement is None:
tests/test_filesystem.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from contextlib import redirect_stdout
2
- from mapFolding.filesystem import getFilenameFoldsTotal, getPathFilenameFoldsTotal, saveFoldsTotal
2
+ from mapFolding.toolboxFilesystem import getFilenameFoldsTotal, getPathFilenameFoldsTotal, saveFoldsTotal
3
3
  from mapFolding.beDRY import validateListDimensions
4
- from mapFolding.filesystem import getPathRootJobDEFAULT
4
+ from mapFolding.toolboxFilesystem import getPathRootJobDEFAULT
5
5
  from pathlib import Path
6
6
  import io
7
7
  import pytest
tests/test_other.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from collections.abc import Callable
2
- from mapFolding.beDRY import getLeavesTotal, setCPUlimit, validateListDimensions
2
+ from mapFolding.beDRY import getLeavesTotal, setProcessorLimit, validateListDimensions
3
3
  from mapFolding.theSSOT import The
4
4
  from tests.conftest import standardizedEqualToCallableReturn
5
5
  from typing import Any, Literal
@@ -81,4 +81,4 @@ def testOopsieKwargsie(nameOfTest: str, callablePytest: Callable[[], None]) -> N
81
81
  ])
82
82
  def test_setCPUlimitNumba(CPUlimit: None | float | bool | Literal[4] | Literal[-2] | Literal[0] | Literal[1], expectedLimit: Any | int) -> None:
83
83
  numba.set_num_threads(multiprocessing.cpu_count())
84
- standardizedEqualToCallableReturn(expectedLimit, setCPUlimit, CPUlimit, 'numba')
84
+ standardizedEqualToCallableReturn(expectedLimit, setProcessorLimit, CPUlimit, 'numba')
tests/test_tasks.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Callable
2
2
  from mapFolding.basecamp import countFolds
3
- from mapFolding.beDRY import getTaskDivisions, setCPUlimit, validateListDimensions, getLeavesTotal
3
+ from mapFolding.beDRY import getTaskDivisions, setProcessorLimit, validateListDimensions, getLeavesTotal
4
4
  from mapFolding.noHomeYet import getFoldsTotalKnown
5
5
  from tests.conftest import standardizedEqualToCallableReturn
6
6
  from typing import Literal
@@ -49,4 +49,4 @@ def test_getTaskDivisions(computationDivisions: None | list[str] | Literal['maxi
49
49
  ])
50
50
  def test_setCPUlimitMalformedParameter(expected: type[ValueError] | Literal[2], parameter: list[int] | tuple[int] | set[int] | dict[str, int] | Literal['2']) -> None:
51
51
  """Test that invalid CPUlimit types are properly handled."""
52
- standardizedEqualToCallableReturn(expected, setCPUlimit, parameter)
52
+ standardizedEqualToCallableReturn(expected, setProcessorLimit, parameter)
@@ -1,199 +0,0 @@
1
- """
2
- Numba-specific ingredients for optimized code generation.
3
-
4
- This module provides specialized tools, constants, and types specifically designed
5
- for transforming Python code into Numba-accelerated implementations. It implements:
6
-
7
- 1. A range of Numba jit decorator configurations for different optimization scenarios
8
- 2. Functions to identify and manipulate Numba decorators in abstract syntax trees
9
- 3. Utilities for applying appropriate Numba typing to transformed code
10
- 4. Parameter management for Numba compilation options
11
-
12
- The configurations range from conservative options that prioritize compatibility and
13
- error detection to aggressive optimizations that maximize performance at the cost of
14
- flexibility. While this module specifically targets Numba, its design follows the pattern
15
- of generic code transformation tools in the package, allowing similar approaches to be
16
- applied to other acceleration technologies.
17
-
18
- This module works in conjunction with transformation tools to convert the general-purpose
19
- algorithm implementation into a highly-optimized Numba version.
20
- """
21
-
22
- from collections.abc import Callable, Sequence
23
- from mapFolding.someAssemblyRequired import Make
24
- from mapFolding.someAssemblyRequired._toolboxContainers import IngredientsFunction
25
- from numba.core.compiler import CompilerBase as numbaCompilerBase
26
- from typing import Any, cast, Final, TYPE_CHECKING
27
- import ast
28
-
29
- try:
30
- from typing import NotRequired
31
- except Exception:
32
- from typing_extensions import NotRequired
33
-
34
- if TYPE_CHECKING:
35
- from typing import TypedDict
36
- else:
37
- TypedDict = dict
38
-
39
- class ParametersNumba(TypedDict):
40
- _dbg_extend_lifetimes: NotRequired[bool]
41
- _dbg_optnone: NotRequired[bool]
42
- _nrt: NotRequired[bool]
43
- boundscheck: NotRequired[bool]
44
- cache: bool
45
- debug: NotRequired[bool]
46
- error_model: str
47
- fastmath: bool
48
- forceinline: bool
49
- forceobj: NotRequired[bool]
50
- inline: str
51
- locals: NotRequired[dict[str, Any]]
52
- looplift: bool
53
- no_cfunc_wrapper: bool
54
- no_cpython_wrapper: bool
55
- no_rewrites: NotRequired[bool]
56
- nogil: NotRequired[bool]
57
- nopython: bool
58
- parallel: bool
59
- pipeline_class: NotRequired[type[numbaCompilerBase]]
60
- signature_or_function: NotRequired[Any | Callable[..., Any] | str | tuple[Any, ...]]
61
- target: NotRequired[str]
62
-
63
- parametersNumbaFailEarly: Final[ParametersNumba] = {
64
- '_nrt': True,
65
- 'boundscheck': True,
66
- 'cache': True,
67
- 'error_model': 'python',
68
- 'fastmath': False,
69
- 'forceinline': True,
70
- 'inline': 'always',
71
- 'looplift': False,
72
- 'no_cfunc_wrapper': False,
73
- 'no_cpython_wrapper': False,
74
- 'nopython': True,
75
- 'parallel': False,
76
- }
77
- """For a production function: speed is irrelevant, error discovery is paramount, must be compatible with anything downstream."""
78
-
79
- parametersNumbaDefault: Final[ParametersNumba] = {
80
- '_nrt': True,
81
- 'boundscheck': False,
82
- 'cache': True,
83
- 'error_model': 'numpy',
84
- 'fastmath': True,
85
- 'forceinline': True,
86
- 'inline': 'always',
87
- 'looplift': False,
88
- 'no_cfunc_wrapper': False,
89
- 'no_cpython_wrapper': False,
90
- 'nopython': True,
91
- 'parallel': False, }
92
- """Middle of the road: fast, lean, but will talk to non-jitted functions."""
93
-
94
- parametersNumbaParallelDEFAULT: Final[ParametersNumba] = {
95
- **parametersNumbaDefault,
96
- '_nrt': True,
97
- 'parallel': True, }
98
- """Middle of the road: fast, lean, but will talk to non-jitted functions."""
99
-
100
- parametersNumbaSuperJit: Final[ParametersNumba] = {
101
- **parametersNumbaDefault,
102
- 'no_cfunc_wrapper': True,
103
- 'no_cpython_wrapper': True, }
104
- """Speed, no helmet, no talking to non-jitted functions."""
105
-
106
- parametersNumbaSuperJitParallel: Final[ParametersNumba] = {
107
- **parametersNumbaSuperJit,
108
- '_nrt': True,
109
- 'parallel': True, }
110
- """Speed, no helmet, concurrency, no talking to non-jitted functions."""
111
-
112
- parametersNumbaMinimum: Final[ParametersNumba] = {
113
- '_nrt': True,
114
- 'boundscheck': True,
115
- 'cache': True,
116
- 'error_model': 'numpy',
117
- 'fastmath': True,
118
- 'forceinline': False,
119
- 'inline': 'always',
120
- 'looplift': False,
121
- 'no_cfunc_wrapper': False,
122
- 'no_cpython_wrapper': False,
123
- 'nopython': False,
124
- 'forceobj': True,
125
- 'parallel': False, }
126
-
127
- Z0Z_numbaDataTypeModule = 'numba'
128
- Z0Z_decoratorCallable = 'jit'
129
-
130
- def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, parametersNumba: ParametersNumba | None = None) -> IngredientsFunction:
131
- def Z0Z_UnhandledDecorators(astCallable: ast.FunctionDef) -> ast.FunctionDef:
132
- # TODO: more explicit handling of decorators. I'm able to ignore this because I know `algorithmSource` doesn't have any decorators.
133
- for decoratorItem in astCallable.decorator_list.copy():
134
- import warnings
135
- astCallable.decorator_list.remove(decoratorItem)
136
- warnings.warn(f"Removed decorator {ast.unparse(decoratorItem)} from {astCallable.name}")
137
- return astCallable
138
-
139
- def makeSpecialSignatureForNumba(signatureElement: ast.arg) -> ast.Subscript | ast.Name | None: # type: ignore
140
- if isinstance(signatureElement.annotation, ast.Subscript) and isinstance(signatureElement.annotation.slice, ast.Tuple):
141
- annotationShape: ast.expr = signatureElement.annotation.slice.elts[0]
142
- if isinstance(annotationShape, ast.Subscript) and isinstance(annotationShape.slice, ast.Tuple):
143
- shapeAsListSlices: list[ast.Slice] = [ast.Slice() for _axis in range(len(annotationShape.slice.elts))]
144
- shapeAsListSlices[-1] = ast.Slice(step=ast.Constant(value=1))
145
- shapeAST: ast.Slice | ast.Tuple = ast.Tuple(elts=list(shapeAsListSlices), ctx=ast.Load())
146
- else:
147
- shapeAST = ast.Slice(step=ast.Constant(value=1))
148
-
149
- annotationDtype: ast.expr = signatureElement.annotation.slice.elts[1]
150
- if (isinstance(annotationDtype, ast.Subscript) and isinstance(annotationDtype.slice, ast.Attribute)):
151
- datatypeAST = annotationDtype.slice.attr
152
- else:
153
- datatypeAST = None
154
-
155
- ndarrayName = signatureElement.arg
156
- Z0Z_hacky_dtype: str = ndarrayName
157
- datatype_attr = datatypeAST or Z0Z_hacky_dtype
158
- ingredientsFunction.imports.addImportFrom_asStr(datatypeModuleDecorator, datatype_attr)
159
- datatypeNumba = ast.Name(id=datatype_attr, ctx=ast.Load())
160
-
161
- return ast.Subscript(value=datatypeNumba, slice=shapeAST, ctx=ast.Load())
162
-
163
- elif isinstance(signatureElement.annotation, ast.Name):
164
- return signatureElement.annotation
165
- return None
166
-
167
- datatypeModuleDecorator: str = Z0Z_numbaDataTypeModule
168
- list_argsDecorator: Sequence[ast.expr] = []
169
-
170
- list_arg4signature_or_function: list[ast.expr] = []
171
- for parameter in ingredientsFunction.astFunctionDef.args.args:
172
- # Efficient translation of Python scalar types to Numba types https://github.com/hunterhogan/mapFolding/issues/8
173
- # For now, let Numba infer them.
174
- continue
175
- # signatureElement: ast.Subscript | ast.Name | None = makeSpecialSignatureForNumba(parameter)
176
- # if signatureElement:
177
- # list_arg4signature_or_function.append(signatureElement)
178
-
179
- if ingredientsFunction.astFunctionDef.returns and isinstance(ingredientsFunction.astFunctionDef.returns, ast.Name):
180
- theReturn: ast.Name = ingredientsFunction.astFunctionDef.returns
181
- list_argsDecorator = [cast(ast.expr, ast.Call(func=ast.Name(id=theReturn.id, ctx=ast.Load())
182
- , args=list_arg4signature_or_function if list_arg4signature_or_function else [], keywords=[] ) )]
183
- elif list_arg4signature_or_function:
184
- list_argsDecorator = [cast(ast.expr, ast.Tuple(elts=list_arg4signature_or_function, ctx=ast.Load()))]
185
-
186
- ingredientsFunction.astFunctionDef = Z0Z_UnhandledDecorators(ingredientsFunction.astFunctionDef)
187
- if parametersNumba is None:
188
- parametersNumba = parametersNumbaDefault
189
- listDecoratorKeywords: list[ast.keyword] = [Make.keyword(parameterName, Make.Constant(parameterValue)) for parameterName, parameterValue in parametersNumba.items()]
190
-
191
- decoratorModule: str = Z0Z_numbaDataTypeModule
192
- decoratorCallable: str = Z0Z_decoratorCallable
193
- ingredientsFunction.imports.addImportFrom_asStr(decoratorModule, decoratorCallable)
194
- # Leave this line in so that global edits will change it.
195
- astDecorator: ast.Call = Make.Call(Make.Name(decoratorCallable), list_argsDecorator, listDecoratorKeywords)
196
- astDecorator: ast.Call = Make.Call(Make.Name(decoratorCallable), list_astKeywords=listDecoratorKeywords)
197
-
198
- ingredientsFunction.astFunctionDef.decorator_list = [astDecorator]
199
- return ingredientsFunction