mapFolding 0.2.0__py3-none-any.whl → 0.2.2__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.
tests/test_oeis.py CHANGED
@@ -1,6 +1,7 @@
1
- from .conftest import *
1
+ from tests.conftest import *
2
2
  from contextlib import redirect_stdout
3
3
  from datetime import datetime, timedelta
4
+ from typing import Optional, Tuple, Union
4
5
  import io
5
6
  import os
6
7
  import pathlib
@@ -62,29 +63,27 @@ def test_clearOEIScache(mock_unlink: unittest.mock.MagicMock, mock_exists: unitt
62
63
  mock_exists.assert_called_once()
63
64
  mock_unlink.assert_not_called()
64
65
 
65
- def testCacheMiss(pathCacheTesting: pathlib.Path, oeisID_1random: str):
66
- """Test cache miss scenario - cache file doesn't exist."""
67
- # No setup function needed - we want to test missing cache
68
- standardCacheTest(settingsOEIS[oeisID_1random]['valuesKnown'], None, oeisID_1random, pathCacheTesting)
66
+ @pytest.mark.parametrize("scenarioCache", ["miss", "expired", "invalid"])
67
+ def testCacheScenarios(pathCacheTesting: pathlib.Path, oeisID_1random: str, scenarioCache: str) -> None:
68
+ """Test cache scenarios: missing file, expired file, and invalid file."""
69
69
 
70
- def testCacheExpired(pathCacheTesting: pathlib.Path, oeisID_1random: str):
71
- """Test expired cache scenario."""
72
- def setupExpiredCache(pathCache: pathlib.Path, oeisID: str) -> None:
70
+ def setupCacheExpired(pathCache: pathlib.Path, oeisID: str) -> None:
73
71
  pathCache.write_text("# Old cache content")
74
72
  oldModificationTime = datetime.now() - timedelta(days=30)
75
73
  os.utime(pathCache, times=(oldModificationTime.timestamp(), oldModificationTime.timestamp()))
76
74
 
77
- standardCacheTest(settingsOEIS[oeisID_1random]['valuesKnown'], setupExpiredCache, oeisID_1random, pathCacheTesting)
78
-
79
- def testInvalidCache(pathCacheTesting: pathlib.Path, oeisID_1random: str):
80
- """Test invalid cache content scenario."""
81
- def setupInvalidCache(pathCache: pathlib.Path, oeisID: str) -> None:
75
+ def setupCacheInvalid(pathCache: pathlib.Path, oeisID: str) -> None:
82
76
  pathCache.write_text("Invalid content")
83
77
 
84
- standardCacheTest(settingsOEIS[oeisID_1random]['valuesKnown'], setupInvalidCache, oeisID_1random, pathCacheTesting)
78
+ if scenarioCache == "miss":
79
+ standardCacheTest(settingsOEIS[oeisID_1random]['valuesKnown'], None, oeisID_1random, pathCacheTesting)
80
+ elif scenarioCache == "expired":
81
+ standardCacheTest(settingsOEIS[oeisID_1random]['valuesKnown'], setupCacheExpired, oeisID_1random, pathCacheTesting)
82
+ else:
83
+ standardCacheTest(settingsOEIS[oeisID_1random]['valuesKnown'], setupCacheInvalid, oeisID_1random, pathCacheTesting)
85
84
 
86
85
  def testInvalidFileContent(pathCacheTesting: pathlib.Path, oeisID_1random: str):
87
- pathFilenameCache = pathCacheTesting / _formatFilenameCache.format(oeisID=oeisID_1random)
86
+ pathFilenameCache = pathCacheTesting / _getFilenameOEISbFile(oeisID=oeisID_1random)
88
87
 
89
88
  # Write invalid content to cache
90
89
  pathFilenameCache.write_text("# A999999\n1 1\n2 2\n")
@@ -100,25 +99,17 @@ def testInvalidFileContent(pathCacheTesting: pathlib.Path, oeisID_1random: str):
100
99
  # Verify cache now contains correct sequence ID
101
100
  assert f"# {oeisID_1random}" in pathFilenameCache.read_text()
102
101
 
103
- def testNetworkError(monkeypatch: pytest.MonkeyPatch, pathCacheTesting: pathlib.Path):
104
- def mockUrlopen(*args, **kwargs):
105
- raise urllib.error.URLError("Network error")
106
-
107
- monkeypatch.setattr(urllib.request, 'urlopen', mockUrlopen)
108
- with pytest.raises(urllib.error.URLError):
109
- _getOEISidValues(next(iter(settingsOEIS)))
110
-
111
102
  def testParseContentErrors():
112
103
  """Test invalid content parsing."""
113
104
  standardComparison(ValueError, _parseBFileOEIS, "Invalid content\n1 2\n", 'A001415')
114
105
 
115
106
  def testExtraComments(pathCacheTesting: pathlib.Path, oeisID_1random: str):
116
- pathFilenameCache = pathCacheTesting / _formatFilenameCache.format(oeisID=oeisID_1random)
107
+ pathFilenameCache = pathCacheTesting / _getFilenameOEISbFile(oeisID=oeisID_1random)
117
108
 
118
109
  # Write content with extra comment lines
119
110
  contentWithExtraComments = f"""# {oeisID_1random}
120
- # Extra comment line 1
121
- # Extra comment line 2
111
+ # Normal place for comment line 1
112
+ # Abnormal comment line
122
113
  1 2
123
114
  2 4
124
115
  3 6
@@ -133,6 +124,14 @@ def testExtraComments(pathCacheTesting: pathlib.Path, oeisID_1random: str):
133
124
  standardComparison(8, lambda d: d[4], OEISsequence) # Value after mid-sequence comment
134
125
  standardComparison(10, lambda d: d[5], OEISsequence) # Last value
135
126
 
127
+ def testNetworkError(monkeypatch: pytest.MonkeyPatch, pathCacheTesting: pathlib.Path):
128
+ """Test network error handling."""
129
+ def mockUrlopen(*args, **kwargs):
130
+ raise urllib.error.URLError("Network error")
131
+
132
+ monkeypatch.setattr(urllib.request, 'urlopen', mockUrlopen)
133
+ standardComparison(urllib.error.URLError, _getOEISidValues, next(iter(settingsOEIS)))
134
+
136
135
  # ===== Command Line Interface Tests =====
137
136
  def testHelpText():
138
137
  """Test that help text is complete and examples are valid."""
tests/test_other.py CHANGED
@@ -1,7 +1,13 @@
1
+ from pathlib import Path
2
+ from typing import List
1
3
  from .conftest import *
2
4
  import pytest
3
5
  import sys
4
- # TODO test `outfitFoldings`, especially that `listDimensions` is sorted.
6
+ import unittest.mock
7
+ import numpy
8
+ import numba
9
+
10
+ # TODO test `outfitFoldings`; no negative values in arrays; compare datatypes to the typeddict; commpare the connection graph to making a graPH
5
11
 
6
12
  @pytest.mark.parametrize("listDimensions,expected_intInnit,expected_parseListDimensions,expected_validateListDimensions,expected_getLeavesTotal", [
7
13
  (None, ValueError, ValueError, ValueError, ValueError), # None instead of list
@@ -21,7 +27,7 @@ import sys
21
27
  ([2, 3, 4], [2, 3, 4], [2, 3, 4], [2, 3, 4], 24),
22
28
  ([2, 3], [2, 3], [2, 3], [2, 3], 6),
23
29
  ([2] * 11, [2] * 11, [2] * 11, [2] * 11, 2048), # power of 2
24
- ([3, 2], [3, 2], [3, 2], [3, 2], 6), # return value is the input when valid
30
+ ([3, 2], [3, 2], [3, 2], [2, 3], 6), # return value is the input when valid
25
31
  ([3] * 5, [3] * 5, [3] * 5, [3, 3, 3, 3, 3], 243), # power of 3
26
32
  ([None], TypeError, TypeError, TypeError, TypeError), # None
27
33
  ([True], TypeError, TypeError, TypeError, TypeError), # bool
@@ -30,8 +36,8 @@ import sys
30
36
  ([complex(1,1)], ValueError, ValueError, ValueError, ValueError), # complex number
31
37
  ([float('inf')], ValueError, ValueError, ValueError, ValueError), # infinity
32
38
  ([float('nan')], ValueError, ValueError, ValueError, ValueError), # NaN
33
- ([sys.maxsize - 1, 1], [sys.maxsize - 1, 1], [sys.maxsize - 1, 1], [sys.maxsize - 1, 1], sys.maxsize - 1), # near maxint
34
- ([sys.maxsize // 2, sys.maxsize // 2, 2], [sys.maxsize // 2, sys.maxsize // 2, 2], [sys.maxsize // 2, sys.maxsize // 2, 2], [sys.maxsize // 2, sys.maxsize // 2, 2], OverflowError), # overflow protection
39
+ ([sys.maxsize - 1, 1], [sys.maxsize - 1, 1], [sys.maxsize - 1, 1], [1, sys.maxsize - 1], sys.maxsize - 1), # near maxint
40
+ ([sys.maxsize // 2, sys.maxsize // 2, 2], [sys.maxsize // 2, sys.maxsize // 2, 2], [sys.maxsize // 2, sys.maxsize // 2, 2], [2, sys.maxsize // 2, sys.maxsize // 2], OverflowError), # overflow protection
35
41
  ([sys.maxsize, sys.maxsize], [sys.maxsize, sys.maxsize], [sys.maxsize, sys.maxsize], [sys.maxsize, sys.maxsize], OverflowError), # overflow protection
36
42
  (range(3, 7), [3, 4, 5, 6], [3, 4, 5, 6], [3, 4, 5, 6], 360), # range sequence type
37
43
  (tuple([3, 5, 7]), [3, 5, 7], [3, 5, 7], [3, 5, 7], 105), # tuple sequence type
@@ -53,7 +59,19 @@ def test_getLeavesTotal_edge_cases() -> None:
53
59
  standardComparison(6, getLeavesTotal, listOriginal)
54
60
  standardComparison([2, 3], lambda x: x, listOriginal) # Check that the list wasn't modified
55
61
 
56
- # ===== Parse Integers Tests =====
62
+ def test_countFolds_writeFoldsTotal_file(listDimensionsTestFunctionality: List[int], pathFilenameFoldsTotalTesting: Path) -> None:
63
+ with unittest.mock.patch("mapFolding.babbage._countFolds", return_value=12345):
64
+ standardComparison(12345, countFolds, listDimensionsTestFunctionality, pathFilenameFoldsTotalTesting)
65
+ standardComparison("12345", lambda: pathFilenameFoldsTotalTesting.read_text())
66
+
67
+ def test_countFolds_writeFoldsTotal_directory(listDimensionsTestFunctionality: List[int], pathTempTesting: Path) -> None:
68
+ with unittest.mock.patch("mapFolding.babbage._countFolds", return_value=67890):
69
+ returned = countFolds(listDimensionsTestFunctionality, writeFoldsTotal=pathTempTesting)
70
+ standardComparison(67890, lambda: returned)
71
+ # Construct expected filename from sorted dimensions
72
+ expectedName = str(sorted(listDimensionsTestFunctionality)).replace(' ', '') + '.foldsTotal'
73
+ standardComparison("67890", lambda: (pathTempTesting / expectedName).read_text())
74
+
57
75
  def test_intInnit() -> None:
58
76
  """Test integer parsing using the test suite generator."""
59
77
  for testName, testFunction in makeTestSuiteIntInnit(intInnit).items():
@@ -64,8 +82,24 @@ def test_oopsieKwargsie() -> None:
64
82
  for testName, testFunction in makeTestSuiteOopsieKwargsie(oopsieKwargsie).items():
65
83
  testFunction()
66
84
 
67
- def test_countFolds_invalid_computationDivisions() -> None:
68
- standardComparison(ValueError, countFolds, [2, 2], {"wrong": "value"})
85
+ # TODO mock CPU counts?
86
+ # @pytest.mark.parametrize("CPUlimit, expectedLimit", [
87
+ # (None, numba.config.NUMBA_DEFAULT_NUM_THREADS),
88
+ # (False, numba.config.NUMBA_DEFAULT_NUM_THREADS),
89
+ # (True, 1),
90
+ # (4, 4),
91
+ # (0.5, max(1, numba.config.NUMBA_DEFAULT_NUM_THREADS // 2)),
92
+ # (-0.5, max(1, numba.config.NUMBA_DEFAULT_NUM_THREADS // 2)),
93
+ # (-2, max(1, numba.config.NUMBA_DEFAULT_NUM_THREADS - 2)),
94
+ # ])
95
+ # def test_setCPUlimit(CPUlimit, expectedLimit) -> None:
96
+ # standardComparison(expectedLimit, setCPUlimit, CPUlimit)
97
+
98
+ def test_makeConnectionGraph_nonNegative(listDimensionsTestFunctionality: List[int]) -> None:
99
+ connectionGraph = makeConnectionGraph(listDimensionsTestFunctionality)
100
+ assert numpy.all(connectionGraph >= 0), "All values in the connection graph should be non-negative."
69
101
 
70
- def test_parseListDimensions_noDimensions() -> None:
71
- standardComparison(ValueError, parseDimensions, [])
102
+ @pytest.mark.parametrize("datatype", [numpy.int16, numpy.uint64])
103
+ def test_makeConnectionGraph_datatype(listDimensionsTestFunctionality: List[int], datatype) -> None:
104
+ connectionGraph = makeConnectionGraph(listDimensionsTestFunctionality, datatype=datatype)
105
+ assert connectionGraph.dtype == datatype, f"Expected datatype {datatype}, but got {connectionGraph.dtype}."
tests/test_tasks.py CHANGED
@@ -3,16 +3,29 @@ import pytest
3
3
  from typing import List, Dict, Tuple
4
4
 
5
5
  # TODO add a test. `C` = number of logical cores available. `n = C + 1`. Ensure that `[2,n]` is computed correctly.
6
+ # Or, probably smarter: limit the number of cores, then run a test with C+1.
6
7
 
7
- def test_foldings_computationDivisions(listDimensionsTest_countFolds: List[int], foldsTotalKnown: Dict[Tuple[int, ...], int]) -> None:
8
- standardComparison(foldsTotalKnown[tuple(listDimensionsTest_countFolds)], countFolds, listDimensionsTest_countFolds, True)
8
+ def test_countFolds_computationDivisions(listDimensionsTest_countFolds: List[int], foldsTotalKnown: Dict[Tuple[int, ...], int]) -> None:
9
+ standardComparison(foldsTotalKnown[tuple(listDimensionsTest_countFolds)], countFolds, listDimensionsTest_countFolds, None, 'maximum')
9
10
 
10
11
  def test_defineConcurrencyLimit() -> None:
11
12
  testSuite = makeTestSuiteConcurrencyLimit(defineConcurrencyLimit)
12
13
  for testName, testFunction in testSuite.items():
13
14
  testFunction()
14
15
 
15
- @pytest.mark.parametrize("cpuLimitValue", [{"invalid": True}, ["weird"]])
16
- def test_countFolds_cpuLimitOopsie(cpuLimitValue: Dict[str, bool] | List[str]) -> None:
17
- # This forces CPUlimit = oopsieKwargsie(cpuLimitValue).
18
- standardComparison(ValueError, countFolds, [2, 2], True, cpuLimitValue)
16
+ @pytest.mark.parametrize("CPUlimitParameter", [{"invalid": True}, ["weird"]])
17
+ def test_countFolds_cpuLimitOopsie(listDimensionsTestFunctionality: List[int], CPUlimitParameter: Dict[str, bool] | List[str]) -> None:
18
+ standardComparison(ValueError, countFolds, listDimensionsTestFunctionality, None, 'cpu', CPUlimitParameter)
19
+
20
+ def test_countFolds_invalid_computationDivisions(listDimensionsTestFunctionality: List[int]) -> None:
21
+ standardComparison(ValueError, countFolds, listDimensionsTestFunctionality, None, {"wrong": "value"})
22
+
23
+ @pytest.mark.parametrize("computationDivisions, concurrencyLimit, listDimensions, expectedTaskDivisions", [
24
+ (None, 4, [9, 11], 0),
25
+ ("maximum", 4, [7, 11], 77),
26
+ ("cpu", 4, [3, 7], 4),
27
+ (["invalid"], 4, [19, 23], ValueError),
28
+ (20, 4, [3,5], ValueError)
29
+ ])
30
+ def test_getTaskDivisions(computationDivisions, concurrencyLimit, listDimensions, expectedTaskDivisions) -> None:
31
+ standardComparison(expectedTaskDivisions, getTaskDivisions, computationDivisions, concurrencyLimit, None, listDimensions)
@@ -1,5 +0,0 @@
1
- """Experiment"""
2
- from Z0Z_tools import defineConcurrencyLimit, intInnit, oopsieKwargsie
3
- from Z0Z_tools.pytest_parseParameters import makeTestSuiteConcurrencyLimit
4
- from Z0Z_tools.pytest_parseParameters import makeTestSuiteIntInnit
5
- from Z0Z_tools.pytest_parseParameters import makeTestSuiteOopsieKwargsie
@@ -1,28 +0,0 @@
1
- mapFolding/__init__.py,sha256=fQGYxmjMofT1id_svln0L3htMBVUbMVj1UWIP74QhAQ,974
2
- mapFolding/babbage.py,sha256=tmz4ZEvMds1nPK7kb_oyl89AsGyuU0MB5udC8AAIL-I,633
3
- mapFolding/beDRY.py,sha256=JUGAuLpQYD-B_mSrgpw4E-JNM_N3gJ2VfY-FkrBP3yA,11135
4
- mapFolding/importPackages.py,sha256=Pno5VXaNiyJKG2Jtj4sB_h6EG50IJ7tQKyivVoKFMxo,303
5
- mapFolding/lovelace.py,sha256=NdQDPYpe7yU8GS9WIv_Rb4nOE9cPt0-XPKOiLfyE_Z4,9369
6
- mapFolding/oeis.py,sha256=pI08RrA39AVAU7U6h_1IowadxXC4K6n2OQd7vgTbTTI,11096
7
- mapFolding/startHere.py,sha256=37wU-VmM92bOZkFw4Wpiz3u0_1TiLsob94HZUPBwFQg,2433
8
- mapFolding/theSSOT.py,sha256=-t23-gPLPNWWBEeSi1mKkNCeeQA4y1AA_oPKC7tZwe4,1970
9
- mapFolding/JAX/lunnanJAX.py,sha256=xMZloN47q-MVfjdYOM1hi9qR4OnLq7qALmGLMraevQs,14819
10
- mapFolding/JAX/taskJAX.py,sha256=yJNeH0rL6EhJ6ppnATHF0Zf81CDMC10bnPnimVxE1hc,20037
11
- mapFolding/benchmarks/benchmarking.py,sha256=kv85F6V9pGhZvTOImArOuxyg5rywA_T6JLH_qFXM8BM,3018
12
- mapFolding/benchmarks/test_benchmarks.py,sha256=c4ANeR3jgqpKXFoxDeZkmAHxSuenMwsjmrhKJ1_XPqY,3659
13
- mapFolding/reference/hunterNumba.py,sha256=jV0dBjhLcnJjUHWRxLV_xvPIUP_GRLRKVeDhOtM9Wp4,7475
14
- mapFolding/reference/irvineJavaPort.py,sha256=Sj-63Z-OsGuDoEBXuxyjRrNmmyl0d7Yz_XuY7I47Oyg,4250
15
- mapFolding/reference/lunnan.py,sha256=SwjpOr1ROg-yZaZuiL7XjXhuvBxu_K4gQoPAWKUjJk4,5037
16
- mapFolding/reference/lunnanNumpy.py,sha256=bDQsBZUQcqJ9bTdnMF7HgtPcgpIodctujkm_lpq9NZ4,4653
17
- mapFolding/reference/lunnanWhile.py,sha256=p8_zLdMc6ujTYIu_yn-hbzOuLTQHvo0ENciIDmKayDU,4067
18
- mapFolding/reference/rotatedEntryPoint.py,sha256=6WVvEcGwDgRPa7dDs7ODAHUJjHDZDIDN6CXH8fFVFmA,12105
19
- tests/__init__.py,sha256=PGYVr7r23gATgcvZ3Sfph9D_g1MVvhgzMNWXBs_9tmY,52
20
- tests/conftest.py,sha256=ur6l5nDnWju7zOEMXqoNGYHY-Hf9GApOm4VT9pXtMtY,10594
21
- tests/test_oeis.py,sha256=h-NhWRoarl3v6qoB0RpnaUPuMGrQpWyfmsL0FXsGauU,7972
22
- tests/test_other.py,sha256=AZYRvZYL-wdDiKcbAFEBTV4a22CANmbl8mj8yVGBQ6g,4852
23
- tests/test_tasks.py,sha256=bBXsMfxb6WXz15eFjUxoS67wzRqusX_9XhetXaY-RnQ,944
24
- mapFolding-0.2.0.dist-info/METADATA,sha256=EC2InFN5XJ1LqKGptTerqGvuJQntDQdyMFG4WIvR6WU,6602
25
- mapFolding-0.2.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
26
- mapFolding-0.2.0.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
27
- mapFolding-0.2.0.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
28
- mapFolding-0.2.0.dist-info/RECORD,,