mapFolding 0.12.2__py3-none-any.whl → 0.13.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.
- mapFolding/__init__.py +4 -2
- mapFolding/_theSSOT.py +32 -88
- mapFolding/{datatypes.py → _theTypes.py} +25 -3
- mapFolding/basecamp.py +38 -33
- mapFolding/beDRY.py +79 -54
- mapFolding/dataBaskets.py +123 -93
- mapFolding/filesystemToolkit.py +140 -91
- mapFolding/oeis.py +243 -145
- mapFolding/reference/flattened.py +1 -1
- mapFolding/someAssemblyRequired/RecipeJob.py +116 -100
- mapFolding/someAssemblyRequired/__init__.py +40 -15
- mapFolding/someAssemblyRequired/_toolIfThis.py +82 -54
- mapFolding/someAssemblyRequired/_toolkitContainers.py +19 -16
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py +35 -26
- mapFolding/someAssemblyRequired/makeAllModules.py +353 -283
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +83 -84
- mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +256 -0
- mapFolding/someAssemblyRequired/toolkitNumba.py +80 -50
- mapFolding/someAssemblyRequired/transformationTools.py +63 -40
- {tests → mapFolding/tests}/__init__.py +2 -2
- {tests → mapFolding/tests}/conftest.py +232 -63
- {tests → mapFolding/tests}/test_computations.py +58 -18
- {tests → mapFolding/tests}/test_filesystem.py +10 -13
- {tests → mapFolding/tests}/test_oeis.py +5 -18
- {tests → mapFolding/tests}/test_other.py +9 -9
- {tests → mapFolding/tests}/test_tasks.py +7 -9
- {mapfolding-0.12.2.dist-info → mapfolding-0.13.0.dist-info}/METADATA +24 -37
- mapfolding-0.13.0.dist-info/RECORD +54 -0
- {mapfolding-0.12.2.dist-info → mapfolding-0.13.0.dist-info}/top_level.txt +0 -1
- mapfolding-0.12.2.dist-info/RECORD +0 -53
- {mapfolding-0.12.2.dist-info → mapfolding-0.13.0.dist-info}/WHEEL +0 -0
- {mapfolding-0.12.2.dist-info → mapfolding-0.13.0.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.12.2.dist-info → mapfolding-0.13.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -24,7 +24,7 @@ research domain.
|
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
26
|
from collections.abc import Callable, Generator, Sequence
|
|
27
|
-
from mapFolding import getLeavesTotal, makeDataContainer, validateListDimensions
|
|
27
|
+
from mapFolding import getLeavesTotal, makeDataContainer, oeis, packageSettings, validateListDimensions
|
|
28
28
|
from mapFolding.oeis import oeisIDsImplemented, settingsOEIS
|
|
29
29
|
from pathlib import Path
|
|
30
30
|
from typing import Any
|
|
@@ -34,50 +34,90 @@ import random
|
|
|
34
34
|
import shutil
|
|
35
35
|
import unittest.mock
|
|
36
36
|
import uuid
|
|
37
|
+
import warnings
|
|
38
|
+
|
|
39
|
+
# ruff: noqa: S311
|
|
37
40
|
|
|
38
41
|
# SSOT for test data paths and filenames
|
|
39
|
-
pathDataSamples: Path = Path("tests/dataSamples").absolute()
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
pathDataSamples: Path = Path(packageSettings.pathPackage, "tests/dataSamples").absolute()
|
|
43
|
+
path_tmpRoot: Path = pathDataSamples / "tmp"
|
|
44
|
+
path_tmpRoot.mkdir(parents=True, exist_ok=True)
|
|
42
45
|
|
|
43
46
|
# The registrar maintains the register of temp files
|
|
44
47
|
registerOfTemporaryFilesystemObjects: set[Path] = set()
|
|
45
48
|
|
|
46
|
-
def
|
|
47
|
-
"""The registrar adds a tmp file to the register.
|
|
49
|
+
def registrarRecordsTemporaryFilesystemObject(path: Path) -> None:
|
|
50
|
+
"""The registrar adds a tmp file to the register.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
path : Path
|
|
55
|
+
The filesystem path to register for cleanup.
|
|
56
|
+
|
|
57
|
+
"""
|
|
48
58
|
registerOfTemporaryFilesystemObjects.add(path)
|
|
49
59
|
|
|
50
|
-
def
|
|
60
|
+
def registrarDeletesTemporaryFilesystemObjects() -> None:
|
|
51
61
|
"""The registrar cleans up tmp files in the register."""
|
|
52
|
-
for
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
shutil.rmtree(pathTmp, ignore_errors=True)
|
|
58
|
-
except Exception as ERRORmessage:
|
|
59
|
-
print(f"Warning: Failed to clean up {pathTmp}: {ERRORmessage}")
|
|
62
|
+
for path_tmp in sorted(registerOfTemporaryFilesystemObjects, reverse=True):
|
|
63
|
+
if path_tmp.is_file():
|
|
64
|
+
path_tmp.unlink(missing_ok=True)
|
|
65
|
+
elif path_tmp.is_dir():
|
|
66
|
+
shutil.rmtree(path_tmp, ignore_errors=True)
|
|
60
67
|
registerOfTemporaryFilesystemObjects.clear()
|
|
61
68
|
|
|
62
69
|
@pytest.fixture(scope="session", autouse=True)
|
|
63
|
-
def
|
|
64
|
-
"""Auto-fixture to setup test data directories and cleanup after.
|
|
70
|
+
def setupTeardownTemporaryFilesystemObjects() -> Generator[None, None, None]:
|
|
71
|
+
"""Auto-fixture to setup test data directories and cleanup after.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
contextManager : Generator[None, None, None]
|
|
76
|
+
Context manager that sets up test directories and ensures cleanup.
|
|
77
|
+
|
|
78
|
+
"""
|
|
65
79
|
pathDataSamples.mkdir(exist_ok=True)
|
|
66
|
-
|
|
80
|
+
path_tmpRoot.mkdir(exist_ok=True)
|
|
67
81
|
yield
|
|
68
|
-
|
|
82
|
+
registrarDeletesTemporaryFilesystemObjects()
|
|
69
83
|
|
|
70
84
|
@pytest.fixture
|
|
71
|
-
def
|
|
85
|
+
def path_tmpTesting(request: pytest.FixtureRequest) -> Path:
|
|
86
|
+
"""Creates a unique temporary directory for testing.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
request : pytest.FixtureRequest
|
|
91
|
+
The pytest request object providing test context.
|
|
92
|
+
|
|
93
|
+
Returns
|
|
94
|
+
-------
|
|
95
|
+
temporaryPath : Path
|
|
96
|
+
Path to a unique temporary directory that will be cleaned up automatically.
|
|
97
|
+
|
|
98
|
+
"""
|
|
72
99
|
# "Z0Z_" ensures the directory name does not start with a number, which would make it an invalid Python identifier
|
|
73
|
-
|
|
74
|
-
|
|
100
|
+
path_tmp: Path = path_tmpRoot / ("Z0Z_" + str(uuid.uuid4().hex))
|
|
101
|
+
path_tmp.mkdir(parents=True, exist_ok=False)
|
|
75
102
|
|
|
76
|
-
|
|
77
|
-
return
|
|
103
|
+
registrarRecordsTemporaryFilesystemObject(path_tmp)
|
|
104
|
+
return path_tmp
|
|
78
105
|
|
|
79
106
|
@pytest.fixture
|
|
80
|
-
def
|
|
107
|
+
def pathFilename_tmpTesting(request: pytest.FixtureRequest) -> Path:
|
|
108
|
+
"""Creates a unique temporary file path for testing.
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
request : pytest.FixtureRequest
|
|
113
|
+
The pytest request object, optionally containing `param` for file extension.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
temporaryFilePath : Path
|
|
118
|
+
Path to a unique temporary file that will be cleaned up automatically.
|
|
119
|
+
|
|
120
|
+
"""
|
|
81
121
|
try:
|
|
82
122
|
extension = request.param
|
|
83
123
|
except AttributeError:
|
|
@@ -88,32 +128,62 @@ def pathFilenameTmpTesting(request: pytest.FixtureRequest) -> Path:
|
|
|
88
128
|
subpath = "Z0Z_" + uuidHex[0:-8]
|
|
89
129
|
filenameStem = "Z0Z_" + uuidHex[-8:None]
|
|
90
130
|
|
|
91
|
-
|
|
92
|
-
|
|
131
|
+
pathFilename_tmp = Path(path_tmpRoot, subpath, filenameStem + extension)
|
|
132
|
+
pathFilename_tmp.parent.mkdir(parents=True, exist_ok=False)
|
|
93
133
|
|
|
94
|
-
|
|
95
|
-
return
|
|
134
|
+
registrarRecordsTemporaryFilesystemObject(pathFilename_tmp.parent)
|
|
135
|
+
return pathFilename_tmp
|
|
96
136
|
|
|
97
137
|
@pytest.fixture
|
|
98
|
-
def pathCacheTesting(
|
|
99
|
-
"""Temporarily replace the OEIS cache directory with a test directory.
|
|
100
|
-
|
|
138
|
+
def pathCacheTesting(path_tmpTesting: Path) -> Generator[Path, Any, None]:
|
|
139
|
+
"""Temporarily replace the OEIS cache directory with a test directory.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
pathTmpTesting : Path
|
|
144
|
+
Temporary directory path from the `pathTmpTesting` fixture.
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
temporaryCachePath : Generator[Path, Any, None]
|
|
149
|
+
Context manager that provides the temporary cache path and restores original.
|
|
150
|
+
|
|
151
|
+
"""
|
|
101
152
|
pathCacheOriginal = oeis.pathCache
|
|
102
|
-
oeis.pathCache =
|
|
103
|
-
yield
|
|
153
|
+
oeis.pathCache = path_tmpTesting
|
|
154
|
+
yield path_tmpTesting
|
|
104
155
|
oeis.pathCache = pathCacheOriginal
|
|
105
156
|
|
|
106
157
|
@pytest.fixture
|
|
107
|
-
def pathFilenameFoldsTotalTesting(
|
|
108
|
-
|
|
158
|
+
def pathFilenameFoldsTotalTesting(path_tmpTesting: Path) -> Path:
|
|
159
|
+
"""Creates a temporary file path for folds total testing.
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
pathTmpTesting : Path
|
|
164
|
+
Temporary directory path from the `pathTmpTesting` fixture.
|
|
165
|
+
|
|
166
|
+
Returns
|
|
167
|
+
-------
|
|
168
|
+
foldsTotalFilePath : Path
|
|
169
|
+
Path to a temporary file for testing folds total functionality.
|
|
170
|
+
|
|
171
|
+
"""
|
|
172
|
+
return path_tmpTesting.joinpath("foldsTotalTest.txt")
|
|
109
173
|
|
|
110
174
|
"""
|
|
111
175
|
Section: Fixtures"""
|
|
112
176
|
|
|
113
177
|
@pytest.fixture(autouse=True)
|
|
114
178
|
def setupWarningsAsErrors() -> Generator[None, Any, None]:
|
|
115
|
-
"""Convert all warnings to errors for all tests.
|
|
116
|
-
|
|
179
|
+
"""Convert all warnings to errors for all tests.
|
|
180
|
+
|
|
181
|
+
Returns
|
|
182
|
+
-------
|
|
183
|
+
contextManager : Generator[None, Any, None]
|
|
184
|
+
Context manager that configures warnings as errors and restores settings.
|
|
185
|
+
|
|
186
|
+
"""
|
|
117
187
|
warnings.filterwarnings("error")
|
|
118
188
|
yield
|
|
119
189
|
warnings.resetwarnings()
|
|
@@ -129,6 +199,17 @@ def oneTestCuzTestsOverwritingTests(oeisID_1random: str) -> tuple[int, ...]:
|
|
|
129
199
|
|
|
130
200
|
The returned map shape is guaranteed to be computationally feasible for testing purposes,
|
|
131
201
|
avoiding cases that would take excessive time to complete during test runs.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
oeisID_1random : str
|
|
206
|
+
Random OEIS sequence identifier from the `oeisID_1random` fixture.
|
|
207
|
+
|
|
208
|
+
Returns
|
|
209
|
+
-------
|
|
210
|
+
mapDimensions : tuple[int, ...]
|
|
211
|
+
Valid map dimensions suitable for testing fold counting operations.
|
|
212
|
+
|
|
132
213
|
"""
|
|
133
214
|
while True:
|
|
134
215
|
n = random.choice(settingsOEIS[oeisID_1random]['valuesTestValidation'])
|
|
@@ -143,8 +224,19 @@ def oneTestCuzTestsOverwritingTests(oeisID_1random: str) -> tuple[int, ...]:
|
|
|
143
224
|
|
|
144
225
|
@pytest.fixture
|
|
145
226
|
def mapShapeTestCountFolds(oeisID: str) -> tuple[int, ...]:
|
|
146
|
-
"""For each `oeisID` from the `pytest.fixture`, returns `listDimensions` from `valuesTestValidation`
|
|
147
|
-
|
|
227
|
+
"""For each `oeisID` from the `pytest.fixture`, returns `listDimensions` from `valuesTestValidation` if `validateListDimensions` approves. Each `listDimensions` is suitable for testing counts.
|
|
228
|
+
|
|
229
|
+
Parameters
|
|
230
|
+
----------
|
|
231
|
+
oeisID : str
|
|
232
|
+
OEIS sequence identifier from the `oeisID` fixture.
|
|
233
|
+
|
|
234
|
+
Returns
|
|
235
|
+
-------
|
|
236
|
+
mapDimensions : tuple[int, ...]
|
|
237
|
+
Valid map dimensions suitable for testing fold counting operations.
|
|
238
|
+
|
|
239
|
+
"""
|
|
148
240
|
while True:
|
|
149
241
|
n = random.choice(settingsOEIS[oeisID]['valuesTestValidation'])
|
|
150
242
|
if n < 2:
|
|
@@ -158,9 +250,21 @@ def mapShapeTestCountFolds(oeisID: str) -> tuple[int, ...]:
|
|
|
158
250
|
|
|
159
251
|
@pytest.fixture
|
|
160
252
|
def mapShapeTestFunctionality(oeisID_1random: str) -> tuple[int, ...]:
|
|
161
|
-
"""To test functionality, get one `listDimensions` from `valuesTestValidation` if
|
|
162
|
-
|
|
163
|
-
`listDimensions` in a short enough time suitable for testing.
|
|
253
|
+
"""To test functionality, get one `listDimensions` from `valuesTestValidation` if `validateListDimensions` approves.
|
|
254
|
+
|
|
255
|
+
The algorithm can count the folds of the returned `listDimensions` in a short enough time suitable for testing.
|
|
256
|
+
|
|
257
|
+
Parameters
|
|
258
|
+
----------
|
|
259
|
+
oeisID_1random : str
|
|
260
|
+
Random OEIS sequence identifier from the `oeisID_1random` fixture.
|
|
261
|
+
|
|
262
|
+
Returns
|
|
263
|
+
-------
|
|
264
|
+
mapDimensions : tuple[int, ...]
|
|
265
|
+
Valid map dimensions that can be processed quickly for functional testing.
|
|
266
|
+
|
|
267
|
+
"""
|
|
164
268
|
while True:
|
|
165
269
|
n = random.choice(settingsOEIS[oeisID_1random]['valuesTestValidation'])
|
|
166
270
|
if n < 2:
|
|
@@ -174,20 +278,46 @@ def mapShapeTestFunctionality(oeisID_1random: str) -> tuple[int, ...]:
|
|
|
174
278
|
|
|
175
279
|
@pytest.fixture
|
|
176
280
|
def mapShapeTestParallelization(oeisID: str) -> tuple[int, ...]:
|
|
177
|
-
"""For each `oeisID` from the `pytest.fixture`, returns `listDimensions` from `valuesTestParallelization
|
|
281
|
+
"""For each `oeisID` from the `pytest.fixture`, returns `listDimensions` from `valuesTestParallelization`.
|
|
282
|
+
|
|
283
|
+
Parameters
|
|
284
|
+
----------
|
|
285
|
+
oeisID : str
|
|
286
|
+
OEIS sequence identifier from the `oeisID` fixture.
|
|
287
|
+
|
|
288
|
+
Returns
|
|
289
|
+
-------
|
|
290
|
+
mapDimensions : tuple[int, ...]
|
|
291
|
+
Map dimensions suitable for testing parallelization features.
|
|
292
|
+
|
|
293
|
+
"""
|
|
178
294
|
n = random.choice(settingsOEIS[oeisID]['valuesTestParallelization'])
|
|
179
295
|
return settingsOEIS[oeisID]['getMapShape'](n)
|
|
180
296
|
|
|
181
297
|
@pytest.fixture
|
|
182
298
|
def mockBenchmarkTimer() -> Generator[unittest.mock.MagicMock | unittest.mock.AsyncMock, Any, None]:
|
|
183
|
-
"""Mock time.perf_counter_ns for consistent benchmark timing.
|
|
299
|
+
"""Mock time.perf_counter_ns for consistent benchmark timing.
|
|
300
|
+
|
|
301
|
+
Returns
|
|
302
|
+
-------
|
|
303
|
+
mockTimer : Generator[unittest.mock.MagicMock | unittest.mock.AsyncMock, Any, None]
|
|
304
|
+
Mock timer that returns predictable timing values for testing benchmarks.
|
|
305
|
+
|
|
306
|
+
"""
|
|
184
307
|
with unittest.mock.patch('time.perf_counter_ns') as mockTimer:
|
|
185
308
|
mockTimer.side_effect = [0, 1e9] # Start and end times for 1 second
|
|
186
309
|
yield mockTimer
|
|
187
310
|
|
|
188
311
|
@pytest.fixture
|
|
189
312
|
def mockFoldingFunction() -> Callable[..., Callable[..., None]]:
|
|
190
|
-
"""Creates a mock function that simulates _countFolds behavior.
|
|
313
|
+
"""Creates a mock function that simulates _countFolds behavior.
|
|
314
|
+
|
|
315
|
+
Returns
|
|
316
|
+
-------
|
|
317
|
+
mockFactory : Callable[..., Callable[..., None]]
|
|
318
|
+
Factory function that creates mock folding functions with specified behavior.
|
|
319
|
+
|
|
320
|
+
"""
|
|
191
321
|
def make_mock(foldsValue: int, listDimensions: list[int]) -> Callable[..., None]:
|
|
192
322
|
mock_array = makeDataContainer(2, numpy.int32)
|
|
193
323
|
mock_array[0] = foldsValue
|
|
@@ -196,18 +326,39 @@ def mockFoldingFunction() -> Callable[..., Callable[..., None]]:
|
|
|
196
326
|
|
|
197
327
|
def mock_countFolds(**keywordArguments: Any) -> None:
|
|
198
328
|
keywordArguments['foldGroups'][:] = mock_array
|
|
199
|
-
return None
|
|
200
329
|
|
|
201
330
|
return mock_countFolds
|
|
202
331
|
return make_mock
|
|
203
332
|
|
|
204
333
|
@pytest.fixture(params=oeisIDsImplemented)
|
|
205
334
|
def oeisID(request: pytest.FixtureRequest) -> Any:
|
|
335
|
+
"""Parametrized fixture providing all implemented OEIS sequence identifiers.
|
|
336
|
+
|
|
337
|
+
(AI generated docstring)
|
|
338
|
+
|
|
339
|
+
Parameters
|
|
340
|
+
----------
|
|
341
|
+
request : pytest.FixtureRequest
|
|
342
|
+
The pytest request object containing the current parameter value.
|
|
343
|
+
|
|
344
|
+
Returns
|
|
345
|
+
-------
|
|
346
|
+
sequenceIdentifier : Any
|
|
347
|
+
OEIS sequence identifier for testing across all implemented sequences.
|
|
348
|
+
|
|
349
|
+
"""
|
|
206
350
|
return request.param
|
|
207
351
|
|
|
208
352
|
@pytest.fixture
|
|
209
353
|
def oeisID_1random() -> str:
|
|
210
|
-
"""Return one random valid OEIS ID.
|
|
354
|
+
"""Return one random valid OEIS ID.
|
|
355
|
+
|
|
356
|
+
Returns
|
|
357
|
+
-------
|
|
358
|
+
randomSequenceIdentifier : str
|
|
359
|
+
Randomly selected OEIS sequence identifier from implemented sequences.
|
|
360
|
+
|
|
361
|
+
"""
|
|
211
362
|
return random.choice(oeisIDsImplemented)
|
|
212
363
|
|
|
213
364
|
def uniformTestMessage(expected: Any, actual: Any, functionName: str, *arguments: Any) -> str:
|
|
@@ -219,13 +370,21 @@ def uniformTestMessage(expected: Any, actual: Any, functionName: str, *arguments
|
|
|
219
370
|
test suite.
|
|
220
371
|
|
|
221
372
|
Parameters
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
373
|
+
----------
|
|
374
|
+
expected : Any
|
|
375
|
+
The value or exception type that was expected.
|
|
376
|
+
actual : Any
|
|
377
|
+
The value or exception type that was actually received.
|
|
378
|
+
functionName : str
|
|
379
|
+
Name of the function being tested.
|
|
380
|
+
arguments : Any
|
|
381
|
+
Arguments that were passed to the function.
|
|
226
382
|
|
|
227
383
|
Returns
|
|
228
|
-
|
|
384
|
+
-------
|
|
385
|
+
formattedMessage : str
|
|
386
|
+
A formatted string showing the test context and comparison.
|
|
387
|
+
|
|
229
388
|
"""
|
|
230
389
|
return (f"\nTesting: `{functionName}({', '.join(str(parameter) for parameter in arguments)})`\n"
|
|
231
390
|
f"Expected: {expected}\n"
|
|
@@ -243,9 +402,14 @@ def standardizedEqualToCallableReturn(expected: Any, functionTarget: Callable[..
|
|
|
243
402
|
return value.
|
|
244
403
|
|
|
245
404
|
Parameters
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
405
|
+
----------
|
|
406
|
+
expected : Any
|
|
407
|
+
Expected return value or exception type.
|
|
408
|
+
functionTarget : Callable[..., Any]
|
|
409
|
+
The function to test.
|
|
410
|
+
arguments : Any
|
|
411
|
+
Arguments to pass to the function.
|
|
412
|
+
|
|
249
413
|
"""
|
|
250
414
|
if type(expected) is type[Exception]:
|
|
251
415
|
messageExpected = expected.__name__
|
|
@@ -264,13 +428,18 @@ def standardizedSystemExit(expected: str | int | Sequence[int], functionTarget:
|
|
|
264
428
|
"""Template for tests expecting SystemExit.
|
|
265
429
|
|
|
266
430
|
Parameters
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
431
|
+
----------
|
|
432
|
+
expected : str | int | Sequence[int]
|
|
433
|
+
Exit code expectation:
|
|
434
|
+
- "error": any non-zero exit code
|
|
435
|
+
- "nonError": specifically zero exit code
|
|
436
|
+
- int: exact exit code match
|
|
437
|
+
- Sequence[int]: exit code must be one of these values
|
|
438
|
+
functionTarget : Callable[..., Any]
|
|
439
|
+
The function to test.
|
|
440
|
+
arguments : Any
|
|
441
|
+
Arguments to pass to the function.
|
|
442
|
+
|
|
274
443
|
"""
|
|
275
444
|
with pytest.raises(SystemExit) as exitInfo:
|
|
276
445
|
functionTarget(*arguments)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Core computational verification and algorithm validation tests.
|
|
2
2
|
|
|
3
|
+
(AI generated docstring)
|
|
4
|
+
|
|
3
5
|
This module validates the mathematical correctness of map folding computations and
|
|
4
6
|
serves as the primary testing ground for new computational approaches. It's the most
|
|
5
7
|
important module for users who create custom folding algorithms or modify existing ones.
|
|
@@ -26,10 +28,11 @@ which is useful if you're working with the code synthesis features of the packag
|
|
|
26
28
|
from mapFolding import countFolds, getFoldsTotalKnown, oeisIDfor_n
|
|
27
29
|
from mapFolding.dataBaskets import MapFoldingState
|
|
28
30
|
from mapFolding.oeis import settingsOEIS
|
|
29
|
-
from mapFolding.someAssemblyRequired.RecipeJob import
|
|
31
|
+
from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2
|
|
32
|
+
from mapFolding.someAssemblyRequired.makeAllModules import parametersNumbaLight
|
|
30
33
|
from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
|
|
34
|
+
from mapFolding.tests.conftest import registrarRecordsTemporaryFilesystemObject, standardizedEqualToCallableReturn
|
|
31
35
|
from pathlib import Path, PurePosixPath
|
|
32
|
-
from tests.conftest import registrarRecordsTmpObject, standardizedEqualToCallableReturn
|
|
33
36
|
from typing import Literal
|
|
34
37
|
import importlib.util
|
|
35
38
|
import multiprocessing
|
|
@@ -38,29 +41,57 @@ import pytest
|
|
|
38
41
|
if __name__ == '__main__':
|
|
39
42
|
multiprocessing.set_start_method('spawn')
|
|
40
43
|
|
|
41
|
-
# TODO test synthesis
|
|
42
|
-
|
|
43
44
|
@pytest.mark.parametrize('flow', ['daoOfMapFolding', 'theorem2', 'theorem2Trimmed', 'theorem2numba'])
|
|
44
|
-
def test_flowControl(mapShapeTestCountFolds: tuple[int, ...], flow: Literal['daoOfMapFolding'
|
|
45
|
+
def test_flowControl(mapShapeTestCountFolds: tuple[int, ...], flow: Literal['daoOfMapFolding', 'theorem2', 'theorem2numba']) -> None:
|
|
45
46
|
"""Validate that different computational flows produce identical results.
|
|
46
47
|
|
|
48
|
+
(AI generated docstring)
|
|
49
|
+
|
|
47
50
|
This is the primary test for ensuring mathematical consistency across different
|
|
48
51
|
algorithmic implementations. When adding a new computational approach, include
|
|
49
52
|
it in the parametrized flow list to verify it produces correct results.
|
|
50
53
|
|
|
51
54
|
The test compares the output of each flow against known correct values from
|
|
52
55
|
OEIS sequences, ensuring that optimization techniques don't compromise accuracy.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
mapShapeTestCountFolds : tuple[int, ...]
|
|
60
|
+
The map shape dimensions to test fold counting for.
|
|
61
|
+
flow : Literal['daoOfMapFolding', 'theorem2', 'theorem2numba']
|
|
62
|
+
The computational flow algorithm to validate.
|
|
63
|
+
|
|
53
64
|
"""
|
|
54
65
|
standardizedEqualToCallableReturn(getFoldsTotalKnown(mapShapeTestCountFolds), countFolds, None, None, None, None, mapShapeTestCountFolds, None, None, flow)
|
|
55
66
|
|
|
56
67
|
def test_aOFn_calculate_value(oeisID: str) -> None:
|
|
68
|
+
"""Verify OEIS sequence value calculations against known reference values.
|
|
69
|
+
|
|
70
|
+
(AI generated docstring)
|
|
71
|
+
|
|
72
|
+
Tests the `oeisIDfor_n` function by comparing its calculated output against
|
|
73
|
+
known correct values from the OEIS database. This ensures that sequence
|
|
74
|
+
value computations remain mathematically accurate across code changes.
|
|
75
|
+
|
|
76
|
+
The test iterates through validation test cases defined in `settingsOEIS`
|
|
77
|
+
for the given OEIS sequence identifier, verifying that each computed value
|
|
78
|
+
matches its corresponding known reference value.
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
oeisID : str
|
|
83
|
+
The OEIS sequence identifier to test calculations for.
|
|
84
|
+
|
|
85
|
+
"""
|
|
57
86
|
for n in settingsOEIS[oeisID]['valuesTestValidation']:
|
|
58
87
|
standardizedEqualToCallableReturn(settingsOEIS[oeisID]['valuesKnown'][n], oeisIDfor_n, oeisID, n)
|
|
59
88
|
|
|
60
|
-
@pytest.mark.parametrize('
|
|
61
|
-
def test_writeJobNumba(oneTestCuzTestsOverwritingTests: tuple[int, ...],
|
|
89
|
+
@pytest.mark.parametrize('pathFilename_tmpTesting', ['.py'], indirect=True)
|
|
90
|
+
def test_writeJobNumba(oneTestCuzTestsOverwritingTests: tuple[int, ...], pathFilename_tmpTesting: Path) -> None:
|
|
62
91
|
"""Test dynamic code generation and execution for computational modules.
|
|
63
92
|
|
|
93
|
+
(AI generated docstring)
|
|
94
|
+
|
|
64
95
|
This test validates the package's ability to generate, compile, and execute
|
|
65
96
|
optimized computational code at runtime. It's essential for users working with
|
|
66
97
|
the code synthesis features or implementing custom optimization strategies.
|
|
@@ -68,32 +99,41 @@ def test_writeJobNumba(oneTestCuzTestsOverwritingTests: tuple[int, ...], pathFil
|
|
|
68
99
|
The test creates a complete computational module, executes it, and verifies
|
|
69
100
|
that the generated code produces mathematically correct results. This pattern
|
|
70
101
|
can be adapted for testing other dynamically generated computational approaches.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
oneTestCuzTestsOverwritingTests : tuple[int, ...]
|
|
106
|
+
The map shape dimensions for testing code generation.
|
|
107
|
+
pathFilename_tmpTesting : Path
|
|
108
|
+
The temporary file path for generated module testing.
|
|
109
|
+
|
|
71
110
|
"""
|
|
72
|
-
from mapFolding.someAssemblyRequired.makeJobTheorem2Numba import makeJobNumba
|
|
73
|
-
from mapFolding.someAssemblyRequired.toolkitNumba import SpicesJobNumba
|
|
111
|
+
from mapFolding.someAssemblyRequired.makeJobTheorem2Numba import makeJobNumba # noqa: PLC0415
|
|
112
|
+
from mapFolding.someAssemblyRequired.toolkitNumba import SpicesJobNumba # noqa: PLC0415
|
|
74
113
|
mapShape = oneTestCuzTestsOverwritingTests
|
|
75
|
-
state = MapFoldingState(mapShape)
|
|
76
|
-
state = initializeGroupsOfFolds(state)
|
|
114
|
+
state = initializeGroupsOfFolds(MapFoldingState(mapShape))
|
|
77
115
|
|
|
78
|
-
pathFilenameModule =
|
|
116
|
+
pathFilenameModule = pathFilename_tmpTesting.absolute()
|
|
79
117
|
pathFilenameFoldsTotal = pathFilenameModule.with_suffix('.foldsTotalTesting')
|
|
80
|
-
|
|
118
|
+
registrarRecordsTemporaryFilesystemObject(pathFilenameFoldsTotal)
|
|
81
119
|
|
|
82
|
-
jobTest =
|
|
120
|
+
jobTest = RecipeJobTheorem2(state
|
|
83
121
|
, pathModule=PurePosixPath(pathFilenameModule.parent)
|
|
84
122
|
, moduleIdentifier=pathFilenameModule.stem
|
|
85
123
|
, pathFilenameFoldsTotal=PurePosixPath(pathFilenameFoldsTotal))
|
|
86
|
-
spices = SpicesJobNumba(useNumbaProgressBar=False)
|
|
124
|
+
spices = SpicesJobNumba(useNumbaProgressBar=False, parametersNumba=parametersNumbaLight)
|
|
87
125
|
makeJobNumba(jobTest, spices)
|
|
88
126
|
|
|
89
127
|
Don_Lapre_Road_to_Self_Improvement = importlib.util.spec_from_file_location("__main__", pathFilenameModule)
|
|
90
128
|
if Don_Lapre_Road_to_Self_Improvement is None:
|
|
91
|
-
|
|
129
|
+
message = f"Failed to create module specification from {pathFilenameModule}"
|
|
130
|
+
raise ImportError(message)
|
|
92
131
|
if Don_Lapre_Road_to_Self_Improvement.loader is None:
|
|
93
|
-
|
|
132
|
+
message = f"Failed to get loader for module {pathFilenameModule}"
|
|
133
|
+
raise ImportError(message)
|
|
94
134
|
module = importlib.util.module_from_spec(Don_Lapre_Road_to_Self_Improvement)
|
|
95
135
|
|
|
96
136
|
module.__name__ = "__main__"
|
|
97
137
|
Don_Lapre_Road_to_Self_Improvement.loader.exec_module(module)
|
|
98
138
|
|
|
99
|
-
standardizedEqualToCallableReturn(str(getFoldsTotalKnown(oneTestCuzTestsOverwritingTests)), pathFilenameFoldsTotal.read_text().strip)
|
|
139
|
+
standardizedEqualToCallableReturn(str(getFoldsTotalKnown(oneTestCuzTestsOverwritingTests)), pathFilenameFoldsTotal.read_text(encoding="utf-8").strip)
|
|
@@ -21,23 +21,20 @@ stores computational results or adding new file formats.
|
|
|
21
21
|
|
|
22
22
|
from contextlib import redirect_stdout
|
|
23
23
|
from mapFolding import (
|
|
24
|
-
getFilenameFoldsTotal, getPathFilenameFoldsTotal, getPathRootJobDEFAULT, saveFoldsTotal,
|
|
25
|
-
validateListDimensions,
|
|
26
|
-
)
|
|
24
|
+
getFilenameFoldsTotal, getPathFilenameFoldsTotal, getPathRootJobDEFAULT, saveFoldsTotal, validateListDimensions)
|
|
27
25
|
from pathlib import Path
|
|
28
26
|
import io
|
|
29
27
|
import pytest
|
|
30
28
|
import unittest.mock
|
|
31
29
|
|
|
32
|
-
def test_saveFoldsTotal_fallback(
|
|
30
|
+
def test_saveFoldsTotal_fallback(path_tmpTesting: Path) -> None:
|
|
33
31
|
foldsTotal = 123
|
|
34
|
-
pathFilename =
|
|
35
|
-
with unittest.mock.patch("pathlib.Path.write_text", side_effect=OSError("Simulated write failure")):
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
fallbackFiles = list(pathTmpTesting.glob("foldsTotalYO_*.txt"))
|
|
32
|
+
pathFilename = path_tmpTesting / "foldsTotal.txt"
|
|
33
|
+
with unittest.mock.patch("pathlib.Path.write_text", side_effect=OSError("Simulated write failure")), unittest.mock.patch("os.getcwd", return_value=str(path_tmpTesting)):
|
|
34
|
+
capturedOutput = io.StringIO()
|
|
35
|
+
with redirect_stdout(capturedOutput):
|
|
36
|
+
saveFoldsTotal(pathFilename, foldsTotal)
|
|
37
|
+
fallbackFiles = list(path_tmpTesting.glob("foldsTotalYO_*.txt"))
|
|
41
38
|
assert len(fallbackFiles) == 1, "Fallback file was not created upon write failure."
|
|
42
39
|
|
|
43
40
|
@pytest.mark.parametrize("listDimensions, expectedFilename", [
|
|
@@ -64,9 +61,9 @@ def test_getPathFilenameFoldsTotal_relativeFilename(mapShapeTestFunctionality: t
|
|
|
64
61
|
assert pathFilenameFoldsTotal.is_absolute(), "Path should be absolute"
|
|
65
62
|
assert pathFilenameFoldsTotal == getPathRootJobDEFAULT() / relativeFilename, "Relative path should be appended to default job root"
|
|
66
63
|
|
|
67
|
-
def test_getPathFilenameFoldsTotal_createsDirs(
|
|
64
|
+
def test_getPathFilenameFoldsTotal_createsDirs(path_tmpTesting: Path, mapShapeTestFunctionality: tuple[int, ...]) -> None:
|
|
68
65
|
"""Test that getPathFilenameFoldsTotal creates necessary directories."""
|
|
69
|
-
nestedPath =
|
|
66
|
+
nestedPath = path_tmpTesting / "deep/nested/structure"
|
|
70
67
|
pathFilenameFoldsTotal = getPathFilenameFoldsTotal(mapShapeTestFunctionality, nestedPath)
|
|
71
68
|
assert pathFilenameFoldsTotal.parent.exists(), "Parent directories should be created"
|
|
72
69
|
assert pathFilenameFoldsTotal.parent.is_dir(), "Created path should be a directory"
|
|
@@ -26,19 +26,14 @@ which is crucial for maintaining package reliability in production environments.
|
|
|
26
26
|
|
|
27
27
|
from contextlib import redirect_stdout
|
|
28
28
|
from mapFolding.oeis import (
|
|
29
|
-
clearOEIScache, getOEISids,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
from pathlib import Path
|
|
33
|
-
from tests.conftest import standardizedEqualToCallableReturn, standardizedSystemExit
|
|
34
|
-
from typing import Any, NoReturn
|
|
35
|
-
from urllib.error import URLError
|
|
29
|
+
clearOEIScache, getOEISids, OEIS_for_n, oeisIDfor_n, oeisIDsImplemented, settingsOEIS, validateOEISid)
|
|
30
|
+
from mapFolding.tests.conftest import standardizedEqualToCallableReturn, standardizedSystemExit
|
|
31
|
+
from typing import Any
|
|
36
32
|
import io
|
|
37
33
|
import pytest
|
|
38
34
|
import random
|
|
39
35
|
import re as regex
|
|
40
36
|
import unittest.mock
|
|
41
|
-
import urllib.request
|
|
42
37
|
|
|
43
38
|
@pytest.mark.parametrize("badID", ["A999999", " A999999 ", "A999999extra"])
|
|
44
39
|
def test__validateOEISid_invalid_id(badID: str) -> None:
|
|
@@ -56,11 +51,11 @@ def test__validateOEISid_valid_id_case_insensitive(oeisID: str) -> None:
|
|
|
56
51
|
standardizedEqualToCallableReturn(oeisID.upper(), validateOEISid, oeisID.swapcase())
|
|
57
52
|
|
|
58
53
|
parameters_test_aOFn_invalid_n = [
|
|
59
|
-
(-random.randint(1, 100), "randomNegative"),
|
|
54
|
+
(-random.randint(1, 100), "randomNegative"), # noqa: S311
|
|
60
55
|
("foo", "string"),
|
|
61
56
|
(1.5, "float")
|
|
62
57
|
]
|
|
63
|
-
badValues, badValuesIDs = zip(*parameters_test_aOFn_invalid_n)
|
|
58
|
+
badValues, badValuesIDs = zip(*parameters_test_aOFn_invalid_n, strict=True)
|
|
64
59
|
@pytest.mark.parametrize("badN", badValues, ids=badValuesIDs)
|
|
65
60
|
def test_aOFn_invalid_n(oeisID_1random: str, badN: Any) -> None:
|
|
66
61
|
"""Check that negative or non-integer n raises ValueError."""
|
|
@@ -87,14 +82,6 @@ def test_clearOEIScache(mock_unlink: unittest.mock.MagicMock, mock_exists: unitt
|
|
|
87
82
|
mock_exists.assert_called_once()
|
|
88
83
|
mock_unlink.assert_not_called()
|
|
89
84
|
|
|
90
|
-
def testNetworkError(monkeypatch: pytest.MonkeyPatch, pathCacheTesting: Path) -> None:
|
|
91
|
-
"""Test network error handling."""
|
|
92
|
-
def mockUrlopen(*args: Any, **kwargs: Any) -> NoReturn:
|
|
93
|
-
raise URLError("Network error")
|
|
94
|
-
|
|
95
|
-
monkeypatch.setattr(urllib.request, 'urlopen', mockUrlopen)
|
|
96
|
-
standardizedEqualToCallableReturn(URLError, getOEISidValues, next(iter(settingsOEIS)))
|
|
97
|
-
|
|
98
85
|
# ===== Command Line Interface Tests =====
|
|
99
86
|
def testHelpText() -> None:
|
|
100
87
|
"""Test that help text is complete and examples are valid."""
|