hunterMakesPy 0.1.2__py3-none-any.whl → 0.2.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.
@@ -1,327 +1,10 @@
1
1
  """Pytest tests you can use in your package to test some hunterMakesPy functions.
2
2
 
3
3
  Each function in this module returns a list of test functions that can be used with `pytest.parametrize`.
4
- """
5
- from collections.abc import Callable, Iterable, Iterator
6
- from hunterMakesPy import defineConcurrencyLimit, intInnit, oopsieKwargsie
7
- from typing import Any, NoReturn
8
- from unittest.mock import Mock, patch
9
- import pytest
10
-
11
- def PytestFor_defineConcurrencyLimit(callableToTest: Callable[..., int] = defineConcurrencyLimit, cpuCount: int = 8) -> list[tuple[str, Callable[[], None]]]: # noqa: C901
12
- """Return a list of test functions to validate concurrency limit behavior.
13
-
14
- This function provides a comprehensive test suite for validating concurrency limit parsing
15
- and computation, checking both valid and invalid input scenarios.
16
-
17
- Parameters
18
- ----------
19
- callableToTest : Callable[[bool | float | int | None, int], int] = defineConcurrencyLimit
20
- The function to test, which should accept various input types and return an integer
21
- representing the concurrency limit.
22
- cpuCount : int = 8
23
- The number of CPUs to simulate in the test environment.
24
-
25
- Returns
26
- -------
27
- listOfTestFunctions : list[tuple[str, Callable[[], None]]]
28
- A list of tuples, each containing a string describing the test case and a callable
29
- test function that implements the test case.
30
-
31
- Examples
32
- --------
33
- Run each test on `hunterMakesPy.defineConcurrencyLimit`:
34
- ```python
35
- from hunterMakesPy.pytestForYourUse import PytestFor_defineConcurrencyLimit
36
-
37
- listOfTests = PytestFor_defineConcurrencyLimit()
38
- for nameOfTest, callablePytest in listOfTests:
39
- callablePytest()
40
- ```
41
-
42
- Or, run each test on your function that has a compatible signature:
43
- ```python
44
- from hunterMakesPy.pytestForYourUse import PytestFor_defineConcurrencyLimit
45
- from packageLocal import functionLocal
46
-
47
- @pytest.mark.parametrize("nameOfTest,callablePytest", PytestFor_defineConcurrencyLimit(callableToTest=functionLocal))
48
- def test_functionLocal(nameOfTest, callablePytest):
49
- callablePytest()
50
- ```
51
-
52
- """
53
- @patch('multiprocessing.cpu_count', return_value=cpuCount)
54
- def testDefaults(_mockCpu: Mock) -> None:
55
- listOfParameters: list[bool | int | None] = [None, False, 0]
56
- for limitParameter in listOfParameters:
57
- assert callableToTest(limit=limitParameter, cpuTotal=cpuCount) == cpuCount
58
-
59
- @patch('multiprocessing.cpu_count', return_value=cpuCount)
60
- def testDirectIntegers(_mockCpu: Mock) -> None:
61
- for limitParameter in [1, 4, 16]:
62
- assert callableToTest(limit=limitParameter, cpuTotal=cpuCount) == limitParameter
63
-
64
- @patch('multiprocessing.cpu_count', return_value=cpuCount)
65
- def testFractionalFloats(_mockCpu: Mock) -> None:
66
- testCases: dict[float, int] = {
67
- 0.5: cpuCount // 2,
68
- 0.25: cpuCount // 4,
69
- 0.75: int(cpuCount * 0.75)
70
- }
71
- for limit, expected in testCases.items():
72
- assert callableToTest(limit=limit, cpuTotal=cpuCount) == expected
73
-
74
- @patch('multiprocessing.cpu_count', return_value=cpuCount)
75
- def testMinimumOne(_mockCpu: Mock) -> None:
76
- listOfParameters: list[float | int] = [-10, -0.99, 0.1]
77
- for limitParameter in listOfParameters:
78
- assert callableToTest(limit=limitParameter, cpuTotal=cpuCount) >= 1
79
-
80
- @patch('multiprocessing.cpu_count', return_value=cpuCount)
81
- def testBooleanTrue(_mockCpu: Mock) -> None:
82
- assert callableToTest(limit=True, cpuTotal=cpuCount) == 1
83
- assert callableToTest(limit='True', cpuTotal=cpuCount) == 1 # pyright: ignore[reportArgumentType]
84
- assert callableToTest(limit='TRUE', cpuTotal=cpuCount) == 1 # pyright: ignore[reportArgumentType]
85
- assert callableToTest(limit=' true ', cpuTotal=cpuCount) == 1 # pyright: ignore[reportArgumentType]
86
-
87
- @patch('multiprocessing.cpu_count', return_value=cpuCount)
88
- def testInvalidStrings(_mockCpu: Mock) -> None:
89
- for stringInput in ["invalid", "True but not quite", "None of the above"]:
90
- with pytest.raises(ValueError, match="must be a number, `True`, `False`, or `None`"):
91
- callableToTest(limit=stringInput, cpuTotal=cpuCount) # pyright: ignore[reportArgumentType]
92
-
93
- @patch('multiprocessing.cpu_count', return_value=cpuCount)
94
- def testStringNumbers(_mockCpu: Mock) -> None:
95
- testCases: list[tuple[str, int]] = [
96
- ("1.51", 2),
97
- ("-2.51", 5),
98
- ("4", 4),
99
- ("0.5", 4),
100
- ("-0.25", 6),
101
- ]
102
- for stringNumber, expectedLimit in testCases:
103
- assert callableToTest(limit=stringNumber, cpuTotal=cpuCount) == expectedLimit # pyright: ignore[reportArgumentType]
104
-
105
- return [
106
- ('testDefaults', testDefaults),
107
- ('testDirectIntegers', testDirectIntegers),
108
- ('testFractionalFloats', testFractionalFloats),
109
- ('testMinimumOne', testMinimumOne),
110
- ('testBooleanTrue', testBooleanTrue),
111
- ('testInvalidStrings', testInvalidStrings),
112
- ('testStringNumbers', testStringNumbers)
113
- ]
114
-
115
- def PytestFor_intInnit(callableToTest: Callable[[Iterable[int], str | None, type[Any] | None], list[int]] = intInnit) -> list[tuple[str, Callable[[], None]]]: # noqa: C901
116
- """Return a list of test functions to validate integer initialization behavior.
117
-
118
- This function provides a comprehensive test suite for validating integer parsing
119
- and initialization, checking both valid and invalid input scenarios.
120
-
121
- Parameters
122
- ----------
123
- callableToTest : Callable[[Iterable[int], str | None, type[Any] | None], list[int]] = intInnit
124
- The function to test. Should accept a sequence of integer-compatible values,
125
- an optional parameter name string, and an optional parameter type.
126
- Returns a list of validated integers.
127
-
128
- Returns
129
- -------
130
- listOfTestFunctions : list[tuple[str, Callable[[], None]]]
131
- A list of tuples containing a string describing the test case and a callable
132
- test function implementing the test case.
133
-
134
- Examples
135
- --------
136
- Run tests on `hunterMakesPy.intInnit`:
137
- ```python
138
- from hunterMakesPy.pytestForYourUse import PytestFor_intInnit
139
-
140
- listOfTests = PytestFor_intInnit()
141
- for nameOfTest, callablePytest in listOfTests:
142
- callablePytest()
143
- ```
144
-
145
- Run tests on your compatible function:
146
- ```python
147
- from hunterMakesPy.pytestForYourUse import PytestFor_intInnit
148
- from packageLocal import functionLocal
149
-
150
- @pytest.mark.parametrize("nameOfTest,callablePytest",
151
- PytestFor_intInnit(callableToTest=functionLocal))
152
- def test_functionLocal(nameOfTest, callablePytest):
153
- callablePytest()
154
- ```
155
-
156
- """
157
- def testHandlesValidIntegers() -> None:
158
- assert callableToTest([2, 3, 5, 8], 'test', None) == [2, 3, 5, 8]
159
- assert callableToTest([13.0, 21.0, 34.0], 'test', None) == [13, 21, 34] # pyright: ignore[reportArgumentType]
160
- assert callableToTest(['55', '89', '144'], 'test', None) == [55, 89, 144] # pyright: ignore[reportArgumentType]
161
- assert callableToTest([' 233 ', '377', '-610'], 'test', None) == [233, 377, -610] # pyright: ignore[reportArgumentType]
162
-
163
- def testRejectsNonWholeNumbers() -> None:
164
- listInvalidNumbers: list[float] = [13.7, 21.5, 34.8, -55.9]
165
- for invalidNumber in listInvalidNumbers:
166
- with pytest.raises(ValueError):
167
- callableToTest([invalidNumber], 'test', None) # pyright: ignore[reportArgumentType]
168
-
169
- def testRejectsBooleans() -> None:
170
- with pytest.raises(TypeError):
171
- callableToTest([True, False], 'test', None)
172
4
 
173
- def testRejectsInvalidStrings() -> None:
174
- for invalidString in ['NW', '', ' ', 'SE.SW']:
175
- with pytest.raises(ValueError):
176
- callableToTest([invalidString], 'test', None) # pyright: ignore[reportArgumentType]
177
-
178
- def testRejectsEmptyList() -> None:
179
- with pytest.raises(ValueError):
180
- callableToTest([], 'test', None)
181
-
182
- def testHandlesMixedValidTypes() -> None:
183
- assert callableToTest([13, '21', 34.0], 'test', None) == [13, 21, 34] # pyright: ignore[reportArgumentType]
184
-
185
- def testHandlesBytes() -> None:
186
- validCases: list[tuple[list[bytes], str, list[int]]] = [
187
- ([b'123'], '123', [123]),
188
- ]
189
- for inputData, testName, expected in validCases:
190
- assert callableToTest(inputData, testName, None) == expected # pyright: ignore[reportArgumentType]
191
-
192
- extendedCases: list[tuple[list[bytes], str, list[int]]] = [
193
- ([b'123456789'], '123456789', [123456789]),
194
- ]
195
- for inputData, testName, expected in extendedCases:
196
- assert callableToTest(inputData, testName, None) == expected # pyright: ignore[reportArgumentType]
197
-
198
- invalidCases: list[list[bytes]] = [[b'\x00']]
199
- for inputData in invalidCases:
200
- with pytest.raises(ValueError):
201
- callableToTest(inputData, 'test', None) # pyright: ignore[reportArgumentType]
202
-
203
- def testHandlesMemoryview() -> None:
204
- validCases: list[tuple[list[memoryview], str, list[int]]] = [
205
- ([memoryview(b'123')], '123', [123]),
206
- ]
207
- for inputData, testName, expected in validCases:
208
- assert callableToTest(inputData, testName, None) == expected # pyright: ignore[reportArgumentType]
209
-
210
- largeMemoryviewCase: list[memoryview] = [memoryview(b'9999999999')]
211
- assert callableToTest(largeMemoryviewCase, 'test', None) == [9999999999] # pyright: ignore[reportArgumentType]
212
-
213
- invalidMemoryviewCases: list[list[memoryview]] = [[memoryview(b'\x00')]]
214
- for inputData in invalidMemoryviewCases:
215
- with pytest.raises(ValueError):
216
- callableToTest(inputData, 'test', None) # pyright: ignore[reportArgumentType]
217
-
218
- def testRejectsMutableSequence() -> None:
219
- class MutableList(list[int]):
220
- def __iter__(self) -> Iterator[int]:
221
- self.append(89)
222
- return super().__iter__()
223
- with pytest.raises(RuntimeError, match=".*modified during iteration.*"):
224
- callableToTest(MutableList([13, 21, 34]), 'test', None)
225
-
226
- def testHandlesComplexIntegers() -> None:
227
- testCases: list[tuple[list[complex], list[int]]] = [
228
- ([13+0j], [13]),
229
- ([21+0j, 34+0j], [21, 34])
230
- ]
231
- for inputData, expected in testCases:
232
- assert callableToTest(inputData, 'test', None) == expected # pyright: ignore[reportArgumentType]
233
-
234
- def testRejectsInvalidComplex() -> None:
235
- for invalidComplex in [13+1j, 21+0.5j, 34.5+0j]:
236
- with pytest.raises(ValueError):
237
- callableToTest([invalidComplex], 'test', None) # pyright: ignore[reportArgumentType]
238
-
239
- return [
240
- ('testHandlesValidIntegers', testHandlesValidIntegers),
241
- ('testRejectsNonWholeNumbers', testRejectsNonWholeNumbers),
242
- ('testRejectsBooleans', testRejectsBooleans),
243
- ('testRejectsInvalidStrings', testRejectsInvalidStrings),
244
- ('testRejectsEmptyList', testRejectsEmptyList),
245
- ('testHandlesMixedValidTypes', testHandlesMixedValidTypes),
246
- ('testHandlesBytes', testHandlesBytes),
247
- ('testHandlesMemoryview', testHandlesMemoryview),
248
- ('testRejectsMutableSequence', testRejectsMutableSequence),
249
- ('testHandlesComplexIntegers', testHandlesComplexIntegers),
250
- ('testRejectsInvalidComplex', testRejectsInvalidComplex)
251
- ]
252
-
253
- def PytestFor_oopsieKwargsie(callableToTest: Callable[[str], bool | None | str] = oopsieKwargsie) -> list[tuple[str, Callable[[], None]]]: # noqa: C901
254
- """Return a list of test functions to validate string-to-boolean/None conversion behavior.
255
-
256
- This function provides a comprehensive test suite for validating string parsing and conversion
257
- to boolean or None values, with fallback to the original string when appropriate.
258
-
259
- Parameters
260
- ----------
261
- callableToTest : Callable[[str], bool | None | str] = oopsieKwargsie
262
- The function to test, which should accept a string and return either a boolean, None,
263
- or the original input.
264
-
265
- Returns
266
- -------
267
- listOfTestFunctions : list[tuple[str, Callable[[], None]]]
268
- A list of tuples, each containing a string describing the test case and a callable
269
- test function that implements the test case.
270
-
271
- Examples
272
- --------
273
- Run each test on `hunterMakesPy.oopsieKwargsie`:
274
- ```python
275
- from hunterMakesPy.pytestForYourUse import PytestFor_oopsieKwargsie
276
-
277
- listOfTests = PytestFor_oopsieKwargsie()
278
- for nameOfTest, callablePytest in listOfTests:
279
- callablePytest()
280
- ```
281
-
282
- Or, run each test on your function that has a compatible signature:
283
- ```python
284
- from hunterMakesPy.pytestForYourUse import PytestFor_oopsieKwargsie
285
- from packageLocal import functionLocal
286
-
287
- @pytest.mark.parametrize("nameOfTest,callablePytest", PytestFor_oopsieKwargsie(callableToTest=functionLocal))
288
- def test_functionLocal(nameOfTest, callablePytest):
289
- callablePytest()
290
- ```
291
-
292
- """
293
- def testHandlesTrueVariants() -> None:
294
- for variantTrue in ['True', 'TRUE', ' true ', 'TrUe']:
295
- assert callableToTest(variantTrue) is True
296
-
297
- def testHandlesFalseVariants() -> None:
298
- for variantFalse in ['False', 'FALSE', ' false ', 'FaLsE']:
299
- assert callableToTest(variantFalse) is False
300
-
301
- def testHandlesNoneVariants() -> None:
302
- for variantNone in ['None', 'NONE', ' none ', 'NoNe']:
303
- assert callableToTest(variantNone) is None
304
-
305
- def testReturnsOriginalString() -> None:
306
- for stringInput in ['hello', '123', 'True story', 'False alarm']:
307
- assert callableToTest(stringInput) == stringInput
308
-
309
- def testHandlesNonStringObjects() -> None:
310
- class NeverGonnaStringIt:
311
- def __str__(self) -> NoReturn:
312
- message = "Cannot be stringified"
313
- raise TypeError(message)
314
-
315
- assert callableToTest(123) == "123" # pyright: ignore[reportArgumentType]
316
-
317
- neverGonnaStringIt = NeverGonnaStringIt()
318
- result = callableToTest(neverGonnaStringIt) # pyright: ignore[reportArgumentType]
319
- assert result is neverGonnaStringIt
5
+ Note: These test functions are now in `hunterMakesPy.tests` with all other tests.
6
+ """
320
7
 
321
- return [
322
- ('testHandlesTrueVariants', testHandlesTrueVariants),
323
- ('testHandlesFalseVariants', testHandlesFalseVariants),
324
- ('testHandlesNoneVariants', testHandlesNoneVariants),
325
- ('testReturnsOriginalString', testReturnsOriginalString),
326
- ('testHandlesNonStringObjects', testHandlesNonStringObjects)
327
- ]
8
+ from hunterMakesPy.tests.test_parseParameters import (
9
+ PytestFor_defineConcurrencyLimit as PytestFor_defineConcurrencyLimit, PytestFor_intInnit as PytestFor_intInnit,
10
+ PytestFor_oopsieKwargsie as PytestFor_oopsieKwargsie)
@@ -0,0 +1,5 @@
1
+ """Test modules for hunterMakesPy package.
2
+
3
+ This module contains comprehensive test suites for all major functions and features in the hunterMakesPy package. Tests can be run
4
+ independently or imported into your project.
5
+ """
@@ -5,8 +5,7 @@ import pathlib
5
5
  import pytest
6
6
 
7
7
  # SSOT for test data paths and filenames
8
- # SSOT for test data paths and filenames
9
- pathDataSamples = pathlib.Path("tests/dataSamples")
8
+ pathDataSamples = pathlib.Path("hunterMakesPy/tests/dataSamples")
10
9
 
11
10
  # Fixture to provide a temporary directory for filesystem tests
12
11
  @pytest.fixture
@@ -1,7 +1,7 @@
1
1
  from hunterMakesPy import PackageSettings, raiseIfNone
2
2
  from hunterMakesPy.coping import getIdentifierPackagePACKAGING, getPathPackageINSTALLING
3
+ from hunterMakesPy.tests.conftest import uniformTestFailureMessage
3
4
  from pathlib import Path
4
- from tests.conftest import uniformTestFailureMessage
5
5
  import pytest
6
6
 
7
7
  @pytest.mark.parametrize(
@@ -2,13 +2,17 @@
2
2
  from collections.abc import Callable, Iterable, Iterator
3
3
  from decimal import Decimal
4
4
  from fractions import Fraction
5
- from hunterMakesPy import autoDecodingRLE, stringItUp, updateExtendPolishDictionaryLists
5
+ from hunterMakesPy import stringItUp, updateExtendPolishDictionaryLists
6
+ from hunterMakesPy.tests.conftest import standardizedEqualTo
6
7
  from numpy.typing import NDArray
7
- from tests.conftest import standardizedEqualTo
8
8
  from typing import Any, Literal
9
9
  import datetime
10
10
  import numpy
11
11
  import pytest
12
+ import sys
13
+
14
+ if sys.version_info < (3, 14):
15
+ from hunterMakesPy import autoDecodingRLE
12
16
 
13
17
  class CustomIterable:
14
18
  def __init__(self, items: Iterable[Any]) -> None: self.items = items
@@ -81,7 +85,7 @@ def testStringItUpErrorCases(description: Literal['Memory view'], value_scrapPil
81
85
  def testUpdateExtendPolishDictionaryLists(description: str, value_dictionaryLists: dict[str, Any], keywordArguments: dict[str, Any], expected: dict[str, Any] | type[TypeError]) -> None:
82
86
  standardizedEqualTo(expected, updateExtendPolishDictionaryLists, *value_dictionaryLists, **keywordArguments)
83
87
  # ruff: noqa: ERA001
84
- # NOTE one line of code with `standardizedEqualTo` replaced the following ten lines of code.
88
+ # NOTE one line of code with `standardizedEqualTo` replaced the following ten lines of code. Use `standardizedEqualTo`.
85
89
  # if isinstance(expected, type) and issubclass(expected, Exception):
86
90
  # with pytest.raises(expected):
87
91
  # updateExtendPolishDictionaryLists(*value_dictionaryLists, **keywordArguments)
@@ -94,26 +98,28 @@ def testUpdateExtendPolishDictionaryLists(description: str, value_dictionaryList
94
98
  # assert result == expected
95
99
 
96
100
  # ruff: noqa: RUF005
97
- @pytest.mark.parametrize("description,value_arrayTarget,expected", [
98
- ("One range", numpy.array(list(range(50,60))), "[*range(50,60)]"),
99
- ("Value, range", numpy.array([123]+list(range(71,81))), "[123,*range(71,81)]"),
100
- ("range, value", numpy.array(list(range(91,97))+[101]), "[*range(91,97),101]"),
101
- ("Value, range, value", numpy.array([151]+list(range(163,171))+[181]), "[151,*range(163,171),181]"),
102
- ("Repeat values", numpy.array([191, 191, 191]), "[191]*3"),
103
- ("Value with repeat", numpy.array([211, 223, 223, 223]), "[211]+[223]*3"),
104
- ("Range with repeat", numpy.array(list(range(251,257))+[271, 271, 271]), "[*range(251,257)]+[271]*3"),
105
- ("Value, range, repeat", numpy.array([281]+list(range(291,297))+[307, 307]), "[281,*range(291,297)]+[307]*2"),
106
- ("repeat, value", numpy.array([313, 313, 313, 331, 331, 349]), "[313]*3+[331]*2+[349]"),
107
- ("repeat, range", numpy.array([373, 373, 373]+list(range(383,389))), "[373]*3+[*range(383,389)]"),
108
- ("repeat, range, value", numpy.array(7*[401]+list(range(409,415))+[421]), "[401]*7+[*range(409,415),421]"),
109
- ("Repeated primes", numpy.array([431, 431, 431, 443, 443, 457]), "[431]*3+[443]*2+[457]"),
110
- ("Two Ranges", numpy.array(list(range(461,471))+list(range(479,487))), "[*range(461,471),*range(479,487)]"),
111
- ("2D array primes", numpy.array([[491, 499, 503], [509, 521, 523]]), "[[491,499,503],[509,521,523]]"),
112
- ("3D array primes", numpy.array([[[541, 547], [557, 563]], [[569, 571], [577, 587]]]), "[[[541,547],[557,563]],[[569,571],[577,587]]]"),
113
- ], ids=lambda x: x if isinstance(x, str) else "")
114
- def testAutoDecodingRLE(description: str, value_arrayTarget: NDArray[numpy.integer[Any]], expected: str) -> None:
115
- """Test autoDecodingRLE with various input arrays."""
116
- standardizedEqualTo(expected, autoDecodingRLE, value_arrayTarget)
101
+
102
+ if sys.version_info < (3, 14):
103
+ @pytest.mark.parametrize("description,value_arrayTarget,expected", [
104
+ ("One range", numpy.array(list(range(50,60))), "[*range(50,60)]"),
105
+ ("Value, range", numpy.array([123]+list(range(71,81))), "[123,*range(71,81)]"),
106
+ ("range, value", numpy.array(list(range(91,97))+[101]), "[*range(91,97),101]"),
107
+ ("Value, range, value", numpy.array([151]+list(range(163,171))+[181]), "[151,*range(163,171),181]"),
108
+ ("Repeat values", numpy.array([191, 191, 191]), "[191]*3"),
109
+ ("Value with repeat", numpy.array([211, 223, 223, 223]), "[211]+[223]*3"),
110
+ ("Range with repeat", numpy.array(list(range(251,257))+[271, 271, 271]), "[*range(251,257)]+[271]*3"),
111
+ ("Value, range, repeat", numpy.array([281]+list(range(291,297))+[307, 307]), "[281,*range(291,297)]+[307]*2"),
112
+ ("repeat, value", numpy.array([313, 313, 313, 331, 331, 349]), "[313]*3+[331]*2+[349]"),
113
+ ("repeat, range", numpy.array([373, 373, 373]+list(range(383,389))), "[373]*3+[*range(383,389)]"),
114
+ ("repeat, range, value", numpy.array(7*[401]+list(range(409,415))+[421]), "[401]*7+[*range(409,415),421]"),
115
+ ("Repeated primes", numpy.array([431, 431, 431, 443, 443, 457]), "[431]*3+[443]*2+[457]"),
116
+ ("Two Ranges", numpy.array(list(range(461,471))+list(range(479,487))), "[*range(461,471),*range(479,487)]"),
117
+ ("2D array primes", numpy.array([[491, 499, 503], [509, 521, 523]]), "[[491,499,503],[509,521,523]]"),
118
+ ("3D array primes", numpy.array([[[541, 547], [557, 563]], [[569, 571], [577, 587]]]), "[[[541,547],[557,563]],[[569,571],[577,587]]]"),
119
+ ], ids=lambda x: x if isinstance(x, str) else "")
120
+ def testAutoDecodingRLE(description: str, value_arrayTarget: NDArray[numpy.integer[Any]], expected: str) -> None:
121
+ """Test autoDecodingRLE with various input arrays."""
122
+ standardizedEqualTo(expected, autoDecodingRLE, value_arrayTarget)
117
123
 
118
124
  # Helper functions for generating RLE test data
119
125
  def generateCartesianMapping(dimensions: tuple[int, int], formula: Callable[[int, int], int]) -> NDArray[Any]:
@@ -222,98 +228,98 @@ def generateAlternatingColumns(dimensions: tuple[int, int], blockSize: int = 1)
222
228
 
223
229
  return generateCartesianMapping(dimensions, columnFormula)
224
230
 
225
- # Updated test cases for autoDecodingRLE with more realistic data
226
- @pytest.mark.parametrize("description,value_arrayTarget", [
227
- # Basic test cases with simple patterns
228
- ("Simple range", numpy.array(list(range(50,60)))),
229
-
230
- # Chessboard patterns
231
- ("Small chessboard", generateChessboard((8, 8))),
232
-
233
- # Alternating columns - creates patterns with good RLE opportunities
234
- ("Alternating columns", generateAlternatingColumns((5, 20), 2)),
235
-
236
- # Step pattern - creates horizontal runs
237
- ("Step pattern", generateStepPattern((6, 30), 3)),
238
-
239
- # Repeating zones - creates horizontal bands
240
- ("Repeating zones", generateRepeatingZones((40, 40), 8)),
241
-
242
- # Tile pattern - creates complex repeating regions
243
- ("Tile pattern", generateTilePattern((15, 15), 5)),
244
-
245
- # Signed quadratic function - includes negative values
246
- ("Signed quadratic", generateSignedQuadraticFunction((10, 10))),
247
-
248
- # Prime modulo matrix - periodic patterns
249
- ("Prime modulo", generatePrimeModuloMatrix((12, 12), 7)),
250
-
251
- # Wave pattern - smooth gradients
252
- ("Wave pattern", generateWavePattern((20, 20))),
253
-
254
- # Spiral pattern - complex pattern with good RLE potential
255
- ("Spiral pattern", generateSpiralPattern((15, 15), 2)),
256
- ], ids=lambda x: x if isinstance(x, str) else "")
257
- def testAutoDecodingRLEWithRealisticData(description: str, value_arrayTarget: NDArray[numpy.integer[Any]]) -> None:
258
- """Test autoDecodingRLE with more realistic data patterns."""
259
- # Here we test the function behavior rather than expected string output
260
- resultRLE = autoDecodingRLE(value_arrayTarget)
261
-
262
- # Test that the result is a valid string
263
- assert isinstance(resultRLE, str)
264
-
265
- # Test that the result contains the expected syntax elements
266
- assert "[" in resultRLE, f"Result should contain list syntax: {resultRLE}"
267
- assert "]" in resultRLE, f"Result should contain list syntax: {resultRLE}"
268
-
269
- # Check that the result is more compact than the raw string representation
270
- rawStrLength = len(str(value_arrayTarget.tolist()))
271
- encodedLength = len(resultRLE)
272
- assert encodedLength <= rawStrLength, f"Encoded string ({encodedLength}) should be shorter than raw string ({rawStrLength})"
273
-
274
- @pytest.mark.parametrize("description,addSpaces", [
275
- ("With spaces", True),
276
- ("Without spaces", False),
277
- ], ids=lambda x: x if isinstance(x, str) else "")
278
- def testAutoDecodingRLEWithSpaces(description: str, addSpaces: bool) -> None:
279
- """Test that the addSpaces parameter affects the internal comparison logic.
280
-
281
- Note: addSpaces doesn't directly change the output format, it just changes
282
- the comparison when measuring the length of the string representation.
283
- The feature exists because `ast` inserts spaces in its string representation.
284
- """
285
- # Create a pattern that has repeated sequences to trigger the RLE logic
286
- arrayTarget = generateRepeatingZones((10, 10), 2)
287
-
288
- # Test both configurations
289
- resultWithSpacesFlag = autoDecodingRLE(arrayTarget, assumeAddSpaces=addSpaces)
290
- resultNoSpacesFlag = autoDecodingRLE(arrayTarget, assumeAddSpaces=False)
291
-
292
- # When addSpaces=True, the internal length comparisons change
293
- # but the actual output format doesn't necessarily differ
294
- # Just verify the function runs without errors in both cases
295
- assert isinstance(resultWithSpacesFlag, str)
296
- assert isinstance(resultNoSpacesFlag, str)
297
-
298
- def testAutoDecodingRLELargeCartesianMapping() -> None:
299
- """Test autoDecodingRLE with a large (100x100) cartesian mapping."""
300
- dimensions = (100, 100)
301
-
302
- # Generate a large cartesian mapping with a complex pattern
303
- def complexFormula(x: int, y: int) -> int:
304
- return ((x * 17) % 11 + (y * 13) % 7) % 10
305
-
306
- arrayMapping = generateCartesianMapping(dimensions, complexFormula)
307
-
308
- # Verify the function works with large arrays
309
- resultRLE = autoDecodingRLE(arrayMapping)
310
-
311
- # The result should be a valid string representation
312
- assert isinstance(resultRLE, str)
313
- assert "[" in resultRLE
314
- assert "]" in resultRLE
315
-
316
- # The RLE encoding should be more compact than the raw representation
317
- rawStrLength = len(str(arrayMapping.tolist()))
318
- encodedLength = len(resultRLE)
319
- assert encodedLength <= rawStrLength, f"RLE encoded string ({encodedLength}) should be shorter than raw string ({rawStrLength})"
231
+ if sys.version_info < (3, 14):
232
+ @pytest.mark.parametrize("description,value_arrayTarget", [
233
+ # Basic test cases with simple patterns
234
+ ("Simple range", numpy.array(list(range(50,60)))),
235
+
236
+ # Chessboard patterns
237
+ ("Small chessboard", generateChessboard((8, 8))),
238
+
239
+ # Alternating columns - creates patterns with good RLE opportunities
240
+ ("Alternating columns", generateAlternatingColumns((5, 20), 2)),
241
+
242
+ # Step pattern - creates horizontal runs
243
+ ("Step pattern", generateStepPattern((6, 30), 3)),
244
+
245
+ # Repeating zones - creates horizontal bands
246
+ ("Repeating zones", generateRepeatingZones((40, 40), 8)),
247
+
248
+ # Tile pattern - creates complex repeating regions
249
+ ("Tile pattern", generateTilePattern((15, 15), 5)),
250
+
251
+ # Signed quadratic function - includes negative values
252
+ ("Signed quadratic", generateSignedQuadraticFunction((10, 10))),
253
+
254
+ # Prime modulo matrix - periodic patterns
255
+ ("Prime modulo", generatePrimeModuloMatrix((12, 12), 7)),
256
+
257
+ # Wave pattern - smooth gradients
258
+ ("Wave pattern", generateWavePattern((20, 20))),
259
+
260
+ # Spiral pattern - complex pattern with good RLE potential
261
+ ("Spiral pattern", generateSpiralPattern((15, 15), 2)),
262
+ ], ids=lambda x: x if isinstance(x, str) else "")
263
+ def testAutoDecodingRLEWithRealisticData(description: str, value_arrayTarget: NDArray[numpy.integer[Any]]) -> None:
264
+ """Test autoDecodingRLE with more realistic data patterns."""
265
+ # Here we test the function behavior rather than expected string output
266
+ resultRLE = autoDecodingRLE(value_arrayTarget)
267
+
268
+ # Test that the result is a valid string
269
+ assert isinstance(resultRLE, str)
270
+
271
+ # Test that the result contains the expected syntax elements
272
+ assert "[" in resultRLE, f"Result should contain list syntax: {resultRLE}"
273
+ assert "]" in resultRLE, f"Result should contain list syntax: {resultRLE}"
274
+
275
+ # Check that the result is more compact than the raw string representation
276
+ rawStrLength = len(str(value_arrayTarget.tolist()))
277
+ encodedLength = len(resultRLE)
278
+ assert encodedLength <= rawStrLength, f"Encoded string ({encodedLength}) should be shorter than raw string ({rawStrLength})"
279
+
280
+ @pytest.mark.parametrize("description,addSpaces", [
281
+ ("With spaces", True),
282
+ ("Without spaces", False),
283
+ ], ids=lambda x: x if isinstance(x, str) else "")
284
+ def testAutoDecodingRLEWithSpaces(description: str, addSpaces: bool) -> None:
285
+ """Test that the addSpaces parameter affects the internal comparison logic.
286
+
287
+ Note: addSpaces doesn't directly change the output format, it just changes
288
+ the comparison when measuring the length of the string representation.
289
+ The feature exists because `ast` inserts spaces in its string representation.
290
+ """
291
+ # Create a pattern that has repeated sequences to trigger the RLE logic
292
+ arrayTarget = generateRepeatingZones((10, 10), 2)
293
+
294
+ # Test both configurations
295
+ resultWithSpacesFlag = autoDecodingRLE(arrayTarget, assumeAddSpaces=addSpaces)
296
+ resultNoSpacesFlag = autoDecodingRLE(arrayTarget, assumeAddSpaces=False)
297
+
298
+ # When addSpaces=True, the internal length comparisons change
299
+ # but the actual output format doesn't necessarily differ
300
+ # Just verify the function runs without errors in both cases
301
+ assert isinstance(resultWithSpacesFlag, str)
302
+ assert isinstance(resultNoSpacesFlag, str)
303
+
304
+ def testAutoDecodingRLELargeCartesianMapping() -> None:
305
+ """Test autoDecodingRLE with a large (100x100) cartesian mapping."""
306
+ dimensions = (100, 100)
307
+
308
+ # Generate a large cartesian mapping with a complex pattern
309
+ def complexFormula(x: int, y: int) -> int:
310
+ return ((x * 17) % 11 + (y * 13) % 7) % 10
311
+
312
+ arrayMapping = generateCartesianMapping(dimensions, complexFormula)
313
+
314
+ # Verify the function works with large arrays
315
+ resultRLE = autoDecodingRLE(arrayMapping)
316
+
317
+ # The result should be a valid string representation
318
+ assert isinstance(resultRLE, str)
319
+ assert "[" in resultRLE
320
+ assert "]" in resultRLE
321
+
322
+ # The RLE encoding should be more compact than the raw representation
323
+ rawStrLength = len(str(arrayMapping.tolist()))
324
+ encodedLength = len(resultRLE)
325
+ assert encodedLength <= rawStrLength, f"RLE encoded string ({encodedLength}) should be shorter than raw string ({rawStrLength})"
@@ -1,6 +1,6 @@
1
1
  # pyright: standard
2
2
  from hunterMakesPy import importLogicalPath2Identifier, importPathFilename2Identifier, makeDirsSafely, writeStringToHere
3
- from tests.conftest import uniformTestFailureMessage
3
+ from hunterMakesPy.tests.conftest import uniformTestFailureMessage
4
4
  import io
5
5
  import math
6
6
  import os
@@ -31,7 +31,10 @@ def testImportLogicalPath2Identifier(moduleName: str, identifier: str, expectedT
31
31
  imported = importLogicalPath2Identifier(moduleName, identifier)
32
32
  assert isinstance(imported, expectedType), uniformTestFailureMessage(expectedType, type(imported), "testImportLogicalPath2Identifier", (moduleName, identifier))
33
33
 
34
- @pytest.mark.parametrize( "source, identifier, expected", [ ("def fibonacciNumber():\n return 13\n", "fibonacciNumber", 13), ("prime = 17\n", "prime", 17), ] )
34
+ @pytest.mark.parametrize(
35
+ "source, identifier, expected"
36
+ , [("def fibonacciNumber():\n return 13\n", "fibonacciNumber", 13)
37
+ , ("prime = 17\n", "prime", 17)])
35
38
  def testImportPathFilename2Identifier(tmp_path: pathlib.Path, source: str, identifier: str, expected: object) -> None:
36
39
  filePath = tmp_path / "moduleTest.py"
37
40
  filePath.write_text(source)