mapFolding 0.4.2__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. mapFolding/__init__.py +3 -2
  2. mapFolding/basecamp.py +12 -14
  3. mapFolding/beDRY.py +81 -58
  4. mapFolding/oeis.py +35 -33
  5. mapFolding/someAssemblyRequired/makeJob.py +8 -7
  6. mapFolding/someAssemblyRequired/synthesizeModuleJAX.py +1 -3
  7. mapFolding/someAssemblyRequired/synthesizeNumba.py +57 -60
  8. mapFolding/someAssemblyRequired/synthesizeNumbaGeneralized.py +102 -30
  9. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +18 -36
  10. mapFolding/someAssemblyRequired/synthesizeNumbaModules.py +77 -31
  11. mapFolding/syntheticModules/numbaCount.py +158 -0
  12. mapFolding/syntheticModules/numba_doTheNeedful.py +5 -12
  13. mapFolding/theDao.py +105 -105
  14. mapFolding/theSSOT.py +80 -205
  15. mapFolding/theSSOTdatatypes.py +166 -0
  16. {mapFolding-0.4.2.dist-info → mapFolding-0.5.0.dist-info}/METADATA +2 -1
  17. mapFolding-0.5.0.dist-info/RECORD +39 -0
  18. tests/conftest.py +84 -26
  19. tests/test_computations.py +29 -66
  20. tests/test_oeis.py +8 -12
  21. tests/test_other.py +11 -7
  22. tests/test_tasks.py +5 -5
  23. mapFolding/syntheticModules/numba_countInitialize.py +0 -52
  24. mapFolding/syntheticModules/numba_countParallel.py +0 -65
  25. mapFolding/syntheticModules/numba_countSequential.py +0 -67
  26. mapFolding/theSSOTnumba.py +0 -125
  27. mapFolding-0.4.2.dist-info/RECORD +0 -42
  28. tests/test_types.py +0 -5
  29. {mapFolding-0.4.2.dist-info → mapFolding-0.5.0.dist-info}/LICENSE +0 -0
  30. {mapFolding-0.4.2.dist-info → mapFolding-0.5.0.dist-info}/WHEEL +0 -0
  31. {mapFolding-0.4.2.dist-info → mapFolding-0.5.0.dist-info}/entry_points.txt +0 -0
  32. {mapFolding-0.4.2.dist-info → mapFolding-0.5.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,166 @@
1
+ from collections import defaultdict
2
+ from typing import Any, cast, Final, TYPE_CHECKING
3
+ import enum
4
+ import numba
5
+ import numpy
6
+
7
+ try:
8
+ from typing import NotRequired
9
+ except Exception:
10
+ from typing_extensions import NotRequired # type: ignore
11
+
12
+ if TYPE_CHECKING:
13
+ from typing import TypedDict
14
+ else:
15
+ TypedDict = dict
16
+
17
+ class EnumIndices(enum.IntEnum):
18
+ @staticmethod
19
+ def _generate_next_value_(name: str, start: int, count: int, last_values: list[Any]) -> int:
20
+ """0-indexed."""
21
+ return count
22
+
23
+ def __index__(self) -> int:
24
+ """Adapt enum to the ultra-rare event of indexing a NumPy 'ndarray', which is not the
25
+ same as `array.array`. See NumPy.org; I think it will be very popular someday."""
26
+ return self.value
27
+
28
+ class indexMy(EnumIndices):
29
+ """Indices for scalar values."""
30
+ dimensionsTotal = enum.auto()
31
+ dimensionsUnconstrained = enum.auto()
32
+ gap1ndex = enum.auto()
33
+ gap1ndexCeiling = enum.auto()
34
+ indexDimension = enum.auto()
35
+ indexLeaf = enum.auto()
36
+ indexMiniGap = enum.auto()
37
+ leaf1ndex = enum.auto()
38
+ leafConnectee = enum.auto()
39
+ taskDivisions = enum.auto()
40
+ taskIndex = enum.auto()
41
+
42
+ class indexTrack(EnumIndices):
43
+ """Indices for state tracking array."""
44
+ leafAbove = enum.auto()
45
+ leafBelow = enum.auto()
46
+ countDimensionsGapped = enum.auto()
47
+ gapRangeStart = enum.auto()
48
+
49
+ _datatypeDefault: Final[dict[str, str]] = {
50
+ 'elephino': 'uint16',
51
+ 'foldsTotal': 'int64',
52
+ 'leavesTotal': 'uint16',
53
+ }
54
+ _datatypeModule = ''
55
+ _datatypeModuleDEFAULT: Final[str] = 'numpy'
56
+
57
+ _datatype: dict[str, str] = defaultdict(str)
58
+
59
+ def reportDatatypeLimit(identifier: str, datatype: str, sourGrapes: bool | None = False) -> str:
60
+ global _datatype
61
+ if not _datatype[identifier]:
62
+ _datatype[identifier] = datatype
63
+ elif _datatype[identifier] == datatype:
64
+ pass
65
+ elif sourGrapes:
66
+ raise Exception(f"Datatype is '{_datatype[identifier]}' not '{datatype}', so you can take your ball and go home.")
67
+ return _datatype[identifier]
68
+
69
+ def setDatatypeModule(datatypeModule: str, sourGrapes: bool | None = False) -> str:
70
+ global _datatypeModule
71
+ if not _datatypeModule:
72
+ _datatypeModule = datatypeModule
73
+ elif _datatypeModule == datatypeModule:
74
+ pass
75
+ elif sourGrapes:
76
+ raise Exception(f"Datatype module is '{_datatypeModule}' not '{datatypeModule}', so you can take your ball and go home.")
77
+ return _datatypeModule
78
+
79
+ def setDatatypeElephino(datatype: str, sourGrapes: bool | None = False) -> str:
80
+ return reportDatatypeLimit('elephino', datatype, sourGrapes)
81
+
82
+ def setDatatypeFoldsTotal(datatype: str, sourGrapes: bool | None = False) -> str:
83
+ return reportDatatypeLimit('foldsTotal', datatype, sourGrapes)
84
+
85
+ def setDatatypeLeavesTotal(datatype: str, sourGrapes: bool | None = False) -> str:
86
+ return reportDatatypeLimit('leavesTotal', datatype, sourGrapes)
87
+
88
+ def _get_datatype(identifier: str) -> str:
89
+ global _datatype
90
+ if not _datatype[identifier]:
91
+ if identifier in indexMy._member_names_:
92
+ _datatype[identifier] = _datatypeDefault.get(identifier) or _get_datatype('elephino')
93
+ elif identifier in indexTrack._member_names_:
94
+ _datatype[identifier] = _datatypeDefault.get(identifier) or _get_datatype('elephino')
95
+ else:
96
+ _datatype[identifier] = _datatypeDefault.get(identifier) or _get_datatype('foldsTotal')
97
+ return _datatype[identifier]
98
+
99
+ def getDatatypeModule() -> str:
100
+ global _datatypeModule
101
+ if not _datatypeModule:
102
+ _datatypeModule = _datatypeModuleDEFAULT
103
+ return _datatypeModule
104
+
105
+ def setInStone(identifier: str) -> type[Any]:
106
+ datatypeModule = getDatatypeModule()
107
+ datatypeStr = _get_datatype(identifier)
108
+ return cast(type[Any], getattr(eval(datatypeModule), datatypeStr))
109
+
110
+ def hackSSOTdtype(identifier: str) -> type[Any]:
111
+ _hackSSOTdtype={
112
+ 'connectionGraph': 'dtypeLeavesTotal',
113
+ 'dtypeElephino': 'dtypeElephino',
114
+ 'dtypeFoldsTotal': 'dtypeFoldsTotal',
115
+ 'dtypeLeavesTotal': 'dtypeLeavesTotal',
116
+ 'foldGroups': 'dtypeFoldsTotal',
117
+ 'gapsWhere': 'dtypeLeavesTotal',
118
+ 'mapShape': 'dtypeLeavesTotal',
119
+ 'my': 'dtypeElephino',
120
+ 'track': 'dtypeElephino',
121
+ }
122
+ RubeGoldBerg = _hackSSOTdtype[identifier]
123
+ if RubeGoldBerg == 'dtypeElephino':
124
+ return setInStone('elephino')
125
+ elif RubeGoldBerg == 'dtypeFoldsTotal':
126
+ return setInStone('foldsTotal')
127
+ elif RubeGoldBerg == 'dtypeLeavesTotal':
128
+ return setInStone('leavesTotal')
129
+ raise Exception("Dude, you forgot to set a value in `hackSSOTdtype`.")
130
+
131
+ def hackSSOTdatatype(identifier: str) -> str:
132
+ _hackSSOTdatatype={
133
+ 'connectionGraph': 'datatypeLeavesTotal',
134
+ 'countDimensionsGapped': 'datatypeLeavesTotal',
135
+ 'datatypeElephino': 'datatypeElephino',
136
+ 'datatypeFoldsTotal': 'datatypeFoldsTotal',
137
+ 'datatypeLeavesTotal': 'datatypeLeavesTotal',
138
+ 'dimensionsTotal': 'datatypeLeavesTotal',
139
+ 'dimensionsUnconstrained': 'datatypeLeavesTotal',
140
+ 'foldGroups': 'datatypeFoldsTotal',
141
+ 'gap1ndex': 'datatypeLeavesTotal',
142
+ 'gap1ndexCeiling': 'datatypeElephino',
143
+ 'gapRangeStart': 'datatypeElephino',
144
+ 'gapsWhere': 'datatypeLeavesTotal',
145
+ 'groupsOfFolds': 'datatypeFoldsTotal',
146
+ 'indexDimension': 'datatypeLeavesTotal',
147
+ 'indexLeaf': 'datatypeLeavesTotal',
148
+ 'indexMiniGap': 'datatypeElephino',
149
+ 'leaf1ndex': 'datatypeLeavesTotal',
150
+ 'leafAbove': 'datatypeLeavesTotal',
151
+ 'leafBelow': 'datatypeLeavesTotal',
152
+ 'leafConnectee': 'datatypeLeavesTotal',
153
+ 'mapShape': 'datatypeLeavesTotal',
154
+ 'my': 'datatypeElephino',
155
+ 'taskDivisions': 'datatypeLeavesTotal',
156
+ 'taskIndex': 'datatypeLeavesTotal',
157
+ 'track': 'datatypeElephino',
158
+ }
159
+ RubeGoldBerg = _hackSSOTdatatype[identifier]
160
+ if RubeGoldBerg == 'datatypeElephino':
161
+ return _get_datatype('elephino')
162
+ elif RubeGoldBerg == 'datatypeFoldsTotal':
163
+ return _get_datatype('foldsTotal')
164
+ elif RubeGoldBerg == 'datatypeLeavesTotal':
165
+ return _get_datatype('leavesTotal')
166
+ raise Exception("Dude, you forgot to set a value in `hackSSOTdatatype`.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: mapFolding
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: Count distinct ways to fold a map (or a strip of stamps)
5
5
  Author-email: Hunter Hogan <HunterHogan@pm.me>
6
6
  License: CC-BY-NC-4.0
@@ -39,6 +39,7 @@ Requires-Dist: pytest-env; extra == "testing"
39
39
  Requires-Dist: pytest-xdist; extra == "testing"
40
40
  Requires-Dist: pytest; extra == "testing"
41
41
  Requires-Dist: python_minifier; extra == "testing"
42
+ Requires-Dist: pyupgrade; extra == "testing"
42
43
  Requires-Dist: updateCitation; extra == "testing"
43
44
 
44
45
  # mapFolding: Algorithms for enumerating distinct map/stamp folding patterns 🗺️
@@ -0,0 +1,39 @@
1
+ mapFolding/__init__.py,sha256=AQA9ypsiV8cDUCvWdM64kFhO9LaKFvAuSEw03jiI7ao,1358
2
+ mapFolding/basecamp.py,sha256=f6Z_KJ1iGV5a3YBDsxS0m7RojYABYlR4kb-dvKW8CAs,3703
3
+ mapFolding/beDRY.py,sha256=ViKLdomPYXD4o86BZwWgT0qPQNKqdtAZ74YoKC9Kgjg,16793
4
+ mapFolding/oeis.py,sha256=Jak0vOfS_gGTXH6xBI7NTUp4Clluvj792E5HNFDDt6U,11149
5
+ mapFolding/theDao.py,sha256=64dlLhrdtNbZAXMbqcZhGAE0ZwgqYRt8nT1on46J-cc,12611
6
+ mapFolding/theSSOT.py,sha256=tcEbPQLmvRWfIyuR0NpeY0Vm6l6L1dUJFyFZjbDo2Gs,6026
7
+ mapFolding/theSSOTdatatypes.py,sha256=OoB9hVfedQejRPxkP-dgLMHS-vqw_0imBvMLBuyLlg0,5829
8
+ mapFolding/reference/flattened.py,sha256=S6D9wiFTlbeoetEqaMLOcA-R22BHOzjqPRujffNxxUM,14875
9
+ mapFolding/reference/hunterNumba.py,sha256=jDS0ORHkIhcJ1rzA5hT49sZHKf3rgJOoGesUCcbKFFY,6054
10
+ mapFolding/reference/irvineJavaPort.py,sha256=7GvBU0tnS6wpFgkYad3465do9jBQW-2bYvbCYyABPHM,3341
11
+ mapFolding/reference/jax.py,sha256=7ji9YWia6Kof0cjcNdiS1GG1rMbC5SBjcyVr_07AeUk,13845
12
+ mapFolding/reference/lunnan.py,sha256=iAbJELfW6RKNMdPcBY9b6rGQ-z1zoRf-1XCurCRMOo8,3951
13
+ mapFolding/reference/lunnanNumpy.py,sha256=rwVP3WIDXimpAuaxhRIuBYU56nVDTKlfGiclw_FkgUU,3765
14
+ mapFolding/reference/lunnanWhile.py,sha256=uRrMT23jTJvoQDlD_FzeIQe_pfMXJG6_bRvs7uhC8z0,3271
15
+ mapFolding/reference/rotatedEntryPoint.py,sha256=USZY3n3zwhSE68ATscUuN66t1qShuEbMI790Gz9JFTw,9352
16
+ mapFolding/reference/total_countPlus1vsPlusN.py,sha256=wpgay-uqPOBd64Z4Pg6tg40j7-4pzWHGMM6v0bnmjhE,6288
17
+ mapFolding/someAssemblyRequired/__init__.py,sha256=wtec_hIz-AKz0_hGdXsWnCKTcCxdMV9-WK6SiIriAeU,396
18
+ mapFolding/someAssemblyRequired/getLLVMforNoReason.py,sha256=nX8tghZClYt7zJd6RpZBXhE_h-CGRHOS17biqiEdf-o,855
19
+ mapFolding/someAssemblyRequired/makeJob.py,sha256=neb_sFvYMx6dlZxKVmwGjKNrEsK0XaHyE1AJD9S9-nA,2408
20
+ mapFolding/someAssemblyRequired/synthesizeModuleJAX.py,sha256=21Wos8ynlly577EUDqWbbNc9R1qc19r5ysWaz86bCvg,1210
21
+ mapFolding/someAssemblyRequired/synthesizeNumba.py,sha256=6bVbZMnszgz5J81KF-_LQyi6Sw9SwUBD-k8u-mFKADo,16940
22
+ mapFolding/someAssemblyRequired/synthesizeNumbaGeneralized.py,sha256=vu6oYqoZGLNzbd3i8H9B2cEtL9bM1dhmbIpcJeF1NKE,16666
23
+ mapFolding/someAssemblyRequired/synthesizeNumbaJob.py,sha256=YRFLuEWcE7Fz4D7vgEwwof5xsrTRY2tIFl69GrFYke8,9050
24
+ mapFolding/someAssemblyRequired/synthesizeNumbaModules.py,sha256=3oUCPU4nnfynhEqSFqIC8BZ1x0lXK0_0_o-hIx8MCPw,5504
25
+ mapFolding/syntheticModules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
+ mapFolding/syntheticModules/numbaCount.py,sha256=447sbrCINu6wMfpJENguUyAxd6Vej3w98WzyVelz8eg,12900
27
+ mapFolding/syntheticModules/numba_doTheNeedful.py,sha256=8utsCDlcIvOlrjGugaD6DgecoDICIo5_BKhkYtwv-74,1150
28
+ tests/__init__.py,sha256=eg9smg-6VblOr0kisM40CpGnuDtU2JgEEWGDTFVOlW8,57
29
+ tests/conftest.py,sha256=rorOpl3Q1ksGQB-8UyLdUDkYBl9O3M19CvOKrnnzr-4,12296
30
+ tests/test_computations.py,sha256=67dcIj94VM69m912cY1L8HuqnXWl9NFVNhjx3zRNjvA,2831
31
+ tests/test_oeis.py,sha256=4EPJrd359kO019e6whDnERU-gnvMeOeUsHFgor7bA1Y,4686
32
+ tests/test_other.py,sha256=x34TGMWY7YmVtTduC_hlmISMVYemcx_z8_UcMcaNyIk,8375
33
+ tests/test_tasks.py,sha256=J8CET4Z-SYZGdy1-nj-pvVqMl6ujTXJR5ZCYkU4gbUc,2389
34
+ mapFolding-0.5.0.dist-info/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
35
+ mapFolding-0.5.0.dist-info/METADATA,sha256=rLrgAmUzYgyLQV_mh749XXhiD1RLrol0iHXZpA_10DU,7678
36
+ mapFolding-0.5.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
37
+ mapFolding-0.5.0.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
38
+ mapFolding-0.5.0.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
39
+ mapFolding-0.5.0.dist-info/RECORD,,
tests/conftest.py CHANGED
@@ -2,16 +2,45 @@
2
2
 
3
3
  # TODO learn how to run tests and coverage analysis without `env = ["NUMBA_DISABLE_JIT=1"]`
4
4
 
5
- from mapFolding import *
6
- from mapFolding import basecamp, getAlgorithmDispatcher, getDispatcherCallable
7
- from mapFolding.beDRY import *
8
- from mapFolding.someAssemblyRequired import *
9
- from mapFolding.oeis import _getFilenameOEISbFile, _getOEISidInformation, _getOEISidValues
10
- from mapFolding.oeis import *
5
+ from collections.abc import Callable, Generator, Sequence
6
+ from mapFolding import (
7
+ getAlgorithmDispatcher,
8
+ getDispatcherCallable,
9
+ countFolds,
10
+ getPathFilenameFoldsTotal,
11
+ oeisIDfor_n,
12
+ saveFoldsTotal,
13
+ hackSSOTdtype,
14
+ clearOEIScache,
15
+ getOEISids,
16
+ )
17
+ from mapFolding import basecamp
18
+ from mapFolding.beDRY import (
19
+ getLeavesTotal,
20
+ validateListDimensions,
21
+ makeDataContainer,
22
+ parseDimensions,
23
+ setCPUlimit,
24
+ makeConnectionGraph,
25
+ getTaskDivisions,
26
+ )
27
+ from mapFolding.oeis import (
28
+ oeisIDsImplemented,
29
+ settingsOEIS,
30
+ validateOEISid,
31
+ getOEISidValues,
32
+ OEIS_for_n,
33
+ )
34
+ from mapFolding.someAssemblyRequired import (
35
+ makeFlowNumbaOptimized,
36
+ youOughtaKnow,
37
+ writeJobNumba,
38
+ )
39
+ from pathlib import Path
11
40
  from types import ModuleType
12
- from typing import Any, Callable, ContextManager, Dict, Generator, List, Literal, NoReturn, Optional, Sequence, Set, Tuple, Type, Union
41
+ from typing import Any, ContextManager, Literal, NoReturn, Final
13
42
  from Z0Z_tools.pytestForYourUse import PytestFor_defineConcurrencyLimit, PytestFor_intInnit, PytestFor_oopsieKwargsie
14
- import pathlib
43
+ import importlib.util
15
44
  import pytest
16
45
  import random
17
46
  import shutil
@@ -19,14 +48,14 @@ import unittest.mock
19
48
  import uuid
20
49
 
21
50
  # SSOT for test data paths and filenames
22
- pathDataSamples = pathlib.Path("tests/dataSamples")
51
+ pathDataSamples = Path("tests/dataSamples")
23
52
  # NOTE `tmp` is not a diminutive form of temporary: it signals a technical term. And "temp" is strongly disfavored.
24
- pathTmpRoot = pathDataSamples / "tmp"
53
+ pathTmpRoot: Path = pathDataSamples / "tmp"
25
54
 
26
55
  # The registrar maintains the register of temp files
27
- registerOfTemporaryFilesystemObjects: Set[pathlib.Path] = set()
56
+ registerOfTemporaryFilesystemObjects: set[Path] = set()
28
57
 
29
- def registrarRecordsTmpObject(path: pathlib.Path) -> None:
58
+ def registrarRecordsTmpObject(path: Path) -> None:
30
59
  """The registrar adds a tmp file to the register."""
31
60
  registerOfTemporaryFilesystemObjects.add(path)
32
61
 
@@ -51,7 +80,7 @@ def setupTeardownTmpObjects() -> Generator[None, None, None]:
51
80
  registrarDeletesTmpObjects()
52
81
 
53
82
  @pytest.fixture
54
- def pathTmpTesting(request: pytest.FixtureRequest) -> pathlib.Path:
83
+ def pathTmpTesting(request: pytest.FixtureRequest) -> Path:
55
84
  # "Z0Z_" ensures the directory name does not start with a number, which would make it an invalid Python identifier
56
85
  pathTmp = pathTmpRoot / ("Z0Z_" + str(uuid.uuid4().hex))
57
86
  pathTmp.mkdir(parents=True, exist_ok=False)
@@ -60,7 +89,7 @@ def pathTmpTesting(request: pytest.FixtureRequest) -> pathlib.Path:
60
89
  return pathTmp
61
90
 
62
91
  @pytest.fixture
63
- def pathFilenameTmpTesting(request: pytest.FixtureRequest) -> pathlib.Path:
92
+ def pathFilenameTmpTesting(request: pytest.FixtureRequest) -> Path:
64
93
  try:
65
94
  extension = request.param
66
95
  except AttributeError:
@@ -71,14 +100,14 @@ def pathFilenameTmpTesting(request: pytest.FixtureRequest) -> pathlib.Path:
71
100
  subpath = "Z0Z_" + uuidHex[0:-8]
72
101
  filenameStem = "Z0Z_" + uuidHex[-8:None]
73
102
 
74
- pathFilenameTmp = pathlib.Path(pathTmpRoot, subpath, filenameStem + extension)
103
+ pathFilenameTmp = Path(pathTmpRoot, subpath, filenameStem + extension)
75
104
  pathFilenameTmp.parent.mkdir(parents=True, exist_ok=False)
76
105
 
77
106
  registrarRecordsTmpObject(pathFilenameTmp)
78
107
  return pathFilenameTmp
79
108
 
80
109
  @pytest.fixture
81
- def pathCacheTesting(pathTmpTesting: pathlib.Path) -> Generator[pathlib.Path, Any, None]:
110
+ def pathCacheTesting(pathTmpTesting: Path) -> Generator[Path, Any, None]:
82
111
  """Temporarily replace the OEIS cache directory with a test directory."""
83
112
  from mapFolding import oeis as there_must_be_a_better_way
84
113
  pathCacheOriginal = there_must_be_a_better_way._pathCache
@@ -87,12 +116,12 @@ def pathCacheTesting(pathTmpTesting: pathlib.Path) -> Generator[pathlib.Path, An
87
116
  there_must_be_a_better_way._pathCache = pathCacheOriginal
88
117
 
89
118
  @pytest.fixture
90
- def pathFilenameFoldsTotalTesting(pathTmpTesting: pathlib.Path) -> pathlib.Path:
119
+ def pathFilenameFoldsTotalTesting(pathTmpTesting: Path) -> Path:
91
120
  return pathTmpTesting.joinpath("foldsTotalTest.txt")
92
121
 
93
- def makeDictionaryFoldsTotalKnown() -> Dict[Tuple[int,...], int]:
122
+ def makeDictionaryFoldsTotalKnown() -> dict[tuple[int, ...], int]:
94
123
  """Returns a dictionary mapping dimension tuples to their known folding totals."""
95
- dictionaryMapDimensionsToFoldsTotalKnown: Dict[Tuple[int, ...], int] = {}
124
+ dictionaryMapDimensionsToFoldsTotalKnown: dict[tuple[int, ...], int] = {}
96
125
 
97
126
  for settings in settingsOEIS.values():
98
127
  sequence = settings['valuesKnown']
@@ -115,7 +144,7 @@ def setupWarningsAsErrors() -> Generator[None, Any, None]:
115
144
  warnings.resetwarnings()
116
145
 
117
146
  @pytest.fixture
118
- def foldsTotalKnown() -> Dict[Tuple[int,...], int]:
147
+ def foldsTotalKnown() -> dict[tuple[int, ...], int]:
119
148
  """Returns a dictionary mapping dimension tuples to their known folding totals.
120
149
  NOTE I am not convinced this is the best way to do this.
121
150
  Advantage: I call `makeDictionaryFoldsTotalKnown()` from modules other than test modules.
@@ -124,7 +153,7 @@ def foldsTotalKnown() -> Dict[Tuple[int,...], int]:
124
153
  return makeDictionaryFoldsTotalKnown()
125
154
 
126
155
  @pytest.fixture
127
- def listDimensionsTestCountFolds(oeisID: str) -> List[int]:
156
+ def listDimensionsTestCountFolds(oeisID: str) -> list[int]:
128
157
  """For each `oeisID` from the `pytest.fixture`, returns `listDimensions` from `valuesTestValidation`
129
158
  if `validateListDimensions` approves. Each `listDimensions` is suitable for testing counts."""
130
159
  while True:
@@ -139,7 +168,7 @@ def listDimensionsTestCountFolds(oeisID: str) -> List[int]:
139
168
  pass
140
169
 
141
170
  @pytest.fixture
142
- def listDimensionsTestFunctionality(oeisID_1random: str) -> List[int]:
171
+ def listDimensionsTestFunctionality(oeisID_1random: str) -> list[int]:
143
172
  """To test functionality, get one `listDimensions` from `valuesTestValidation` if
144
173
  `validateListDimensions` approves. The algorithm can count the folds of the returned
145
174
  `listDimensions` in a short enough time suitable for testing."""
@@ -155,7 +184,7 @@ def listDimensionsTestFunctionality(oeisID_1random: str) -> List[int]:
155
184
  pass
156
185
 
157
186
  @pytest.fixture
158
- def listDimensionsTestParallelization(oeisID: str) -> List[int]:
187
+ def listDimensionsTestParallelization(oeisID: str) -> list[int]:
159
188
  """For each `oeisID` from the `pytest.fixture`, returns `listDimensions` from `valuesTestParallelization`"""
160
189
  n = random.choice(settingsOEIS[oeisID]['valuesTestParallelization'])
161
190
  return settingsOEIS[oeisID]['getMapShape'](n)
@@ -170,7 +199,7 @@ def mockBenchmarkTimer() -> Generator[unittest.mock.MagicMock | unittest.mock.As
170
199
  @pytest.fixture
171
200
  def mockFoldingFunction() -> Callable[..., Callable[..., None]]:
172
201
  """Creates a mock function that simulates _countFolds behavior."""
173
- def make_mock(foldsValue: int, listDimensions: List[int]) -> Callable[..., None]:
202
+ def make_mock(foldsValue: int, listDimensions: list[int]) -> Callable[..., None]:
174
203
  mock_array = makeDataContainer(2)
175
204
  mock_array[0] = foldsValue
176
205
  mock_array[-1] = getLeavesTotal(listDimensions)
@@ -225,6 +254,35 @@ def useAlgorithmSourceDispatcher(useThisDispatcher: Callable) -> Generator[None,
225
254
  useThisDispatcher(getAlgorithmDispatcher())
226
255
  yield
227
256
 
257
+ @pytest.fixture
258
+ def syntheticDispatcherFixture(useThisDispatcher):
259
+ listCallablesInlineHARDCODED: list[str] = ['countInitialize', 'countParallel', 'countSequential']
260
+ listCallablesInline = listCallablesInlineHARDCODED
261
+ callableDispatcher = True
262
+ algorithmSource = None
263
+ relativePathWrite = None
264
+ filenameModuleWrite = 'pytestCount.py'
265
+ formatFilenameWrite = "pytest_{callableTarget}.py"
266
+ listSynthesizedModules: list[youOughtaKnow] = makeFlowNumbaOptimized(listCallablesInline, callableDispatcher, algorithmSource, relativePathWrite, filenameModuleWrite, formatFilenameWrite)
267
+ dispatcherSynthetic = youOughtaKnow('','','')
268
+ for stuff in listSynthesizedModules:
269
+ registrarRecordsTmpObject(stuff.pathFilenameForMe)
270
+ if stuff.callableSynthesized not in listCallablesInline:
271
+ dispatcherSynthetic: youOughtaKnow = stuff
272
+
273
+ dispatcherSpec = importlib.util.spec_from_file_location(dispatcherSynthetic.callableSynthesized, dispatcherSynthetic.pathFilenameForMe)
274
+ if dispatcherSpec is None:
275
+ raise ImportError(f"{dispatcherSynthetic.pathFilenameForMe=}")
276
+ if dispatcherSpec.loader is None:
277
+ raise ImportError(f"Failed to get loader for module {dispatcherSynthetic.pathFilenameForMe}")
278
+
279
+ dispatcherModule = importlib.util.module_from_spec(dispatcherSpec)
280
+ dispatcherSpec.loader.exec_module(dispatcherModule)
281
+ callableDispatcherSynthetic = getattr(dispatcherModule, dispatcherSynthetic.callableSynthesized)
282
+
283
+ useThisDispatcher(callableDispatcherSynthetic)
284
+ return callableDispatcherSynthetic
285
+
228
286
  def uniformTestMessage(expected: Any, actual: Any, functionName: str, *arguments: Any) -> str:
229
287
  """Format assertion message for any test comparison."""
230
288
  return (f"\nTesting: `{functionName}({', '.join(str(parameter) for parameter in arguments)})`\n"
@@ -233,7 +291,7 @@ def uniformTestMessage(expected: Any, actual: Any, functionName: str, *arguments
233
291
 
234
292
  def standardizedEqualTo(expected: Any, functionTarget: Callable, *arguments: Any) -> None:
235
293
  """Template for tests expecting an error."""
236
- if type(expected) is Type[Exception]:
294
+ if type(expected) is type[Exception]:
237
295
  messageExpected = expected.__name__
238
296
  else:
239
297
  messageExpected = expected
@@ -246,7 +304,7 @@ def standardizedEqualTo(expected: Any, functionTarget: Callable, *arguments: Any
246
304
 
247
305
  assert actual == expected, uniformTestMessage(messageExpected, messageActual, functionTarget.__name__, *arguments)
248
306
 
249
- def standardizedSystemExit(expected: Union[str, int, Sequence[int]], functionTarget: Callable, *arguments: Any) -> None:
307
+ def standardizedSystemExit(expected: str | int | Sequence[int], functionTarget: Callable, *arguments: Any) -> None:
250
308
  """Template for tests expecting SystemExit.
251
309
 
252
310
  Parameters
@@ -1,79 +1,42 @@
1
- from pathlib import Path
2
1
  from tests.conftest import *
3
2
  import importlib.util
4
3
  import pytest
5
4
 
6
- def test_algorithmSourceParallel(listDimensionsTestParallelization: List[int], foldsTotalKnown: Dict[Tuple[int, ...], int], useAlgorithmSourceDispatcher: None) -> None:
5
+ def test_algorithmSourceParallel(listDimensionsTestParallelization: list[int], foldsTotalKnown: dict[tuple[int, ...], int], useAlgorithmSourceDispatcher: None) -> None:
7
6
  standardizedEqualTo(foldsTotalKnown[tuple(listDimensionsTestParallelization)], countFolds, listDimensionsTestParallelization, None, 'maximum')
8
7
 
9
- def test_algorithmSourceSequential(listDimensionsTestCountFolds: List[int], foldsTotalKnown: Dict[Tuple[int, ...], int], useAlgorithmSourceDispatcher: None) -> None:
8
+ def test_algorithmSourceSequential(listDimensionsTestCountFolds: list[int], foldsTotalKnown: dict[tuple[int, ...], int], useAlgorithmSourceDispatcher: None) -> None:
10
9
  standardizedEqualTo(foldsTotalKnown[tuple(listDimensionsTestCountFolds)], countFolds, listDimensionsTestCountFolds)
11
10
 
12
11
  def test_aOFn_calculate_value(oeisID: str) -> None:
13
12
  for n in settingsOEIS[oeisID]['valuesTestValidation']:
14
13
  standardizedEqualTo(settingsOEIS[oeisID]['valuesKnown'][n], oeisIDfor_n, oeisID, n)
15
14
 
16
- # Python doesn't want me to test this
17
- # @pytest.mark.parametrize('pathFilenameTmpTesting', ['.py'], indirect=True)
18
- # def test_writeJobNumba(listDimensionsTestCountFolds: List[int], foldsTotalKnown: Dict[Tuple[int, ...], int], pathFilenameTmpTesting: Path) -> None:
19
- # from mapFolding.syntheticModules import numba_countSequential
20
- # algorithmSourceHARDCODED: ModuleType = numba_countSequential
21
- # algorithmSource = algorithmSourceHARDCODED
22
- # pathFilenameModule = writeJobNumba(listDimensionsTestCountFolds, algorithmSource, pathFilenameWriteJob=pathFilenameTmpTesting.absolute())
23
-
24
- # Don_Lapre_Road_to_Self_Improvement = importlib.util.spec_from_file_location("__main__", pathFilenameModule)
25
- # if Don_Lapre_Road_to_Self_Improvement is None:
26
- # raise ImportError(f"Failed to create module specification from {pathFilenameModule}")
27
- # if Don_Lapre_Road_to_Self_Improvement.loader is None:
28
- # raise ImportError(f"Failed to get loader for module {pathFilenameModule}")
29
- # module = importlib.util.module_from_spec(Don_Lapre_Road_to_Self_Improvement)
30
-
31
- # module.__name__ = "__main__"
32
- # Don_Lapre_Road_to_Self_Improvement.loader.exec_module(module)
33
-
34
- # pathFilenameFoldsTotal = getPathFilenameFoldsTotal(listDimensionsTestCountFolds)
35
- # standardizedEqualTo(str(foldsTotalKnown[tuple(listDimensionsTestCountFolds)]), pathFilenameFoldsTotal.read_text().strip)
36
-
37
- # def test_makeFlowNumbaOptimized(pathTmpTesting: Path, useThisDispatcher):
38
- # def test_makeFlowNumbaOptimized(useThisDispatcher):
39
- # """To get this to work:
40
- # walk_up=True doesn't work on 3.10, so that has to go
41
- # the _logical_ import must be in the logical path of the package
42
- # fuck python
43
- # """
44
- # listCallablesInlineHARDCODED: List[str] = ['countInitialize', 'countParallel', 'countSequential']
45
- # listCallablesInline = listCallablesInlineHARDCODED
46
- # callableDispatcher = True
47
- # algorithmSource = None
48
- # relativePathWrite = None
49
- # # relativePathWrite = pathTmpTesting.absolute().relative_to(getPathPackage(), walk_up=True)
50
- # formatFilenameWrite = "pytest_{callableTarget}"
51
- # listSynthesizedModules: List[youOughtaKnow] = makeFlowNumbaOptimized(listCallablesInline, callableDispatcher, algorithmSource, relativePathWrite, formatFilenameWrite)
52
- # for stuff in listSynthesizedModules:
53
- # registrarRecordsTmpObject(stuff.pathFilenameForMe)
54
- # if stuff.callableSynthesized not in listCallablesInline:
55
- # dispatcherSynthetic: youOughtaKnow = stuff
56
- # if not dispatcherSynthetic: raise FREAKOUT
57
- # # dispatcherSynthetic: youOughtaKnow = next(filter(lambda x: x.callableSynthesized not in listCallablesInline, listSynthesizedModules))
58
-
59
- # # Import the synthetic dispatcher module to get the callable
60
- # dispatcherSpec = importlib.util.spec_from_file_location(
61
- # dispatcherSynthetic.callableSynthesized,
62
- # dispatcherSynthetic.pathFilenameForMe
63
- # )
64
- # if dispatcherSpec is None:
65
- # raise ImportError(f"Failed to create module specification from {dispatcherSynthetic.pathFilenameForMe}")
66
- # if dispatcherSpec.loader is None:
67
- # raise ImportError(f"Failed to get loader for module {dispatcherSynthetic.pathFilenameForMe}")
68
-
69
- # dispatcherModule = importlib.util.module_from_spec(dispatcherSpec)
70
- # dispatcherSpec.loader.exec_module(dispatcherModule)
71
- # callableDispatcherSynthetic = getattr(dispatcherModule, dispatcherSynthetic.callableSynthesized)
72
-
73
- # useThisDispatcher(callableDispatcherSynthetic)
74
-
75
- # def test_syntheticSequential(listDimensionsTestCountFolds: List[int], foldsTotalKnown: Dict[Tuple[int, ...], int]):
76
- # standardizedEqualTo(foldsTotalKnown[tuple(listDimensionsTestCountFolds)], countFolds, listDimensionsTestCountFolds)
15
+ @pytest.mark.parametrize('pathFilenameTmpTesting', ['.py'], indirect=True)
16
+ def test_writeJobNumba(listDimensionsTestCountFolds: list[int], foldsTotalKnown: dict[tuple[int, ...], int], pathFilenameTmpTesting: Path) -> None:
17
+ from mapFolding.syntheticModules import numbaCount
18
+ algorithmSourceHARDCODED: ModuleType = numbaCount
19
+ algorithmSource = algorithmSourceHARDCODED
20
+ callableTargetHARDCODED = 'countSequential'
21
+ callableTarget = callableTargetHARDCODED
22
+ pathFilenameModule = writeJobNumba(listDimensionsTestCountFolds, algorithmSource, callableTarget, pathFilenameWriteJob=pathFilenameTmpTesting.absolute())
23
+
24
+ Don_Lapre_Road_to_Self_Improvement = importlib.util.spec_from_file_location("__main__", pathFilenameModule)
25
+ if Don_Lapre_Road_to_Self_Improvement is None:
26
+ raise ImportError(f"Failed to create module specification from {pathFilenameModule}")
27
+ if Don_Lapre_Road_to_Self_Improvement.loader is None:
28
+ raise ImportError(f"Failed to get loader for module {pathFilenameModule}")
29
+ module = importlib.util.module_from_spec(Don_Lapre_Road_to_Self_Improvement)
30
+
31
+ module.__name__ = "__main__"
32
+ Don_Lapre_Road_to_Self_Improvement.loader.exec_module(module)
33
+
34
+ pathFilenameFoldsTotal = getPathFilenameFoldsTotal(listDimensionsTestCountFolds)
35
+ registrarRecordsTmpObject(pathFilenameFoldsTotal)
36
+ standardizedEqualTo(str(foldsTotalKnown[tuple(listDimensionsTestCountFolds)]), pathFilenameFoldsTotal.read_text().strip)
37
+
38
+ def test_syntheticParallel(syntheticDispatcherFixture, listDimensionsTestParallelization: list[int], foldsTotalKnown: dict[tuple[int, ...], int]):
39
+ standardizedEqualTo(foldsTotalKnown[tuple(listDimensionsTestParallelization)], countFolds, listDimensionsTestParallelization, None, 'maximum')
77
40
 
78
- # def test_syntheticParallel(listDimensionsTestParallelization: List[int], foldsTotalKnown: Dict[Tuple[int, ...], int]):
79
- # standardizedEqualTo(foldsTotalKnown[tuple(listDimensionsTestParallelization)], countFolds, listDimensionsTestParallelization, None, 'maximum')
41
+ def test_syntheticSequential(syntheticDispatcherFixture, listDimensionsTestCountFolds: list[int], foldsTotalKnown: dict[tuple[int, ...], int]):
42
+ standardizedEqualTo(foldsTotalKnown[tuple(listDimensionsTestCountFolds)], countFolds, listDimensionsTestCountFolds)
tests/test_oeis.py CHANGED
@@ -1,10 +1,7 @@
1
1
  from contextlib import redirect_stdout
2
- from datetime import datetime, timedelta
3
- from mapFolding.oeis import _getFilenameOEISbFile, _getOEISidValues, _parseBFileOEIS, _validateOEISid, _getOEISidInformation
4
2
  from tests.conftest import *
5
3
  from urllib.error import URLError
6
4
  import io
7
- import os
8
5
  import pathlib
9
6
  import pytest
10
7
  import random
@@ -16,21 +13,20 @@ import urllib.request
16
13
 
17
14
  @pytest.mark.parametrize("badID", ["A999999", " A999999 ", "A999999extra"])
18
15
  def test__validateOEISid_invalid_id(badID: str) -> None:
19
- standardizedEqualTo(KeyError, _validateOEISid, badID)
16
+ standardizedEqualTo(KeyError, validateOEISid, badID)
20
17
 
21
18
  def test__validateOEISid_partially_valid(oeisID_1random: str) -> None:
22
- standardizedEqualTo(KeyError, _validateOEISid, f"{oeisID_1random}extra")
19
+ standardizedEqualTo(KeyError, validateOEISid, f"{oeisID_1random}extra")
23
20
 
24
21
  def test__validateOEISid_valid_id(oeisID: str) -> None:
25
- standardizedEqualTo(oeisID, _validateOEISid, oeisID)
22
+ standardizedEqualTo(oeisID, validateOEISid, oeisID)
26
23
 
27
24
  def test__validateOEISid_valid_id_case_insensitive(oeisID: str) -> None:
28
- standardizedEqualTo(oeisID.upper(), _validateOEISid, oeisID.lower())
29
- standardizedEqualTo(oeisID.upper(), _validateOEISid, oeisID.upper())
30
- standardizedEqualTo(oeisID.upper(), _validateOEISid, oeisID.swapcase())
25
+ standardizedEqualTo(oeisID.upper(), validateOEISid, oeisID.lower())
26
+ standardizedEqualTo(oeisID.upper(), validateOEISid, oeisID.upper())
27
+ standardizedEqualTo(oeisID.upper(), validateOEISid, oeisID.swapcase())
31
28
 
32
29
  parameters_test_aOFn_invalid_n = [
33
- # (2, "ok"), # test the test template
34
30
  (-random.randint(1, 100), "randomNegative"),
35
31
  ("foo", "string"),
36
32
  (1.5, "float")
@@ -62,13 +58,13 @@ def test_clearOEIScache(mock_unlink: unittest.mock.MagicMock, mock_exists: unitt
62
58
  mock_exists.assert_called_once()
63
59
  mock_unlink.assert_not_called()
64
60
 
65
- def testNetworkError(monkeypatch: pytest.MonkeyPatch, pathCacheTesting: pathlib.Path) -> None:
61
+ def testNetworkError(monkeypatch: pytest.MonkeyPatch, pathCacheTesting: Path) -> None:
66
62
  """Test network error handling."""
67
63
  def mockUrlopen(*args: Any, **kwargs: Any) -> NoReturn:
68
64
  raise URLError("Network error")
69
65
 
70
66
  monkeypatch.setattr(urllib.request, 'urlopen', mockUrlopen)
71
- standardizedEqualTo(URLError, _getOEISidValues, next(iter(settingsOEIS)))
67
+ standardizedEqualTo(URLError, getOEISidValues, next(iter(settingsOEIS)))
72
68
 
73
69
  # ===== Command Line Interface Tests =====
74
70
  def testHelpText() -> None: