hunterMakesPy 0.1.2__py3-none-any.whl → 0.2.1__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.
@@ -0,0 +1,339 @@
1
+ # pyright: standard
2
+ from collections.abc import Callable, Iterable, Iterator
3
+ from hunterMakesPy import defineConcurrencyLimit, intInnit, oopsieKwargsie
4
+ from typing import Any, NoReturn, ParamSpec, TypeVar
5
+ from unittest.mock import Mock, patch
6
+ import pytest
7
+
8
+ parameters = ParamSpec('parameters')
9
+ returnType = TypeVar('returnType')
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
+
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
320
+
321
+ return [
322
+ ('testHandlesTrueVariants', testHandlesTrueVariants),
323
+ ('testHandlesFalseVariants', testHandlesFalseVariants),
324
+ ('testHandlesNoneVariants', testHandlesNoneVariants),
325
+ ('testReturnsOriginalString', testReturnsOriginalString),
326
+ ('testHandlesNonStringObjects', testHandlesNonStringObjects)
327
+ ]
328
+
329
+ @pytest.mark.parametrize("nameOfTest,aPytest", PytestFor_defineConcurrencyLimit())
330
+ def testConcurrencyLimit(nameOfTest: str, aPytest: Callable[parameters, returnType], *arguments: parameters.args, **keywordArguments: parameters.kwargs) -> None:
331
+ aPytest(*arguments, **keywordArguments)
332
+
333
+ @pytest.mark.parametrize("nameOfTest,aPytest", PytestFor_intInnit())
334
+ def testIntInnit(nameOfTest: str, aPytest: Callable[parameters, returnType], *arguments: parameters.args, **keywordArguments: parameters.kwargs) -> None:
335
+ aPytest(*arguments, **keywordArguments)
336
+
337
+ @pytest.mark.parametrize("nameOfTest,aPytest", PytestFor_oopsieKwargsie())
338
+ def testOopsieKwargsie(nameOfTest: str, aPytest: Callable[parameters, returnType], *arguments: parameters.args, **keywordArguments: parameters.kwargs) -> None:
339
+ aPytest(*arguments, **keywordArguments)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hunterMakesPy
3
- Version: 0.1.2
3
+ Version: 0.2.1
4
4
  Summary: Easy Python functions making making functional Python functions easier.
5
5
  Author-email: Hunter Hogan <HunterHogan@pm.me>
6
6
  License: CC-BY-NC-4.0
@@ -22,6 +22,7 @@ Classifier: Programming Language :: Python :: 3
22
22
  Classifier: Programming Language :: Python :: 3.11
23
23
  Classifier: Programming Language :: Python :: 3.12
24
24
  Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
25
26
  Classifier: Programming Language :: Python :: Implementation :: CPython
26
27
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
28
  Classifier: Topic :: Utilities
@@ -32,7 +33,7 @@ License-File: LICENSE
32
33
  Requires-Dist: charset_normalizer
33
34
  Requires-Dist: more_itertools
34
35
  Requires-Dist: numpy
35
- Requires-Dist: python_minifier
36
+ Requires-Dist: python_minifier; python_version < "3.14"
36
37
  Provides-Extra: development
37
38
  Requires-Dist: mypy; extra == "development"
38
39
  Requires-Dist: pyupgrade; extra == "development"
@@ -73,7 +74,7 @@ def findConfiguration(configName: str) -> dict[str, str] | None:
73
74
 
74
75
  config = raiseIfNone(
75
76
  findConfiguration("database"),
76
- "Configuration 'database' is required but not found"
77
+ "I could not find Configuration 'database', but I need it to continue."
77
78
  )
78
79
  ```
79
80
 
@@ -82,19 +83,19 @@ config = raiseIfNone(
82
83
  Parameter validation, integer parsing, and concurrency handling.
83
84
 
84
85
  ```python
85
- from hunterMakesPy import defineConcurrencyLimit, intInnit, oopsieKwargsie
86
+ import hunterMakesPy as humpy
86
87
 
87
88
  # Smart concurrency limit calculation
88
- cpuLimit = defineConcurrencyLimit(limit=0.75) # Use 75% of available CPUs
89
- cpuLimit = defineConcurrencyLimit(limit=True) # Use exactly 1 CPU
90
- cpuLimit = defineConcurrencyLimit(limit=4) # Use exactly 4 CPUs
89
+ cpuLimit = humpy.defineConcurrencyLimit(limit=0.75) # Use 75% of available CPUs
90
+ cpuLimit = humpy.defineConcurrencyLimit(limit=True) # Use exactly 1 CPU
91
+ cpuLimit = humpy.defineConcurrencyLimit(limit=4) # Use exactly 4 CPUs
91
92
 
92
93
  # Robust integer validation
93
- validatedIntegers = intInnit([1, "2", 3.0, "4"], "port_numbers")
94
+ validatedIntegers = humpy.intInnit([1, "2", 3.0, "4"], "port_numbers")
94
95
 
95
96
  # String-to-boolean conversion for configuration
96
97
  userInput = "True"
97
- booleanValue = oopsieKwargsie(userInput) # Returns True
98
+ booleanValue = humpy.oopsieKwargsie(userInput) # Returns True
98
99
  ```
99
100
 
100
101
  ## File System Utilities
@@ -102,20 +103,15 @@ booleanValue = oopsieKwargsie(userInput) # Returns True
102
103
  Safe file operations and dynamic module importing.
103
104
 
104
105
  ```python
105
- from hunterMakesPy import (
106
- importLogicalPath2Identifier,
107
- importPathFilename2Identifier,
108
- makeDirsSafely,
109
- writeStringToHere
110
- )
106
+ import hunterMakesPy as humpy
111
107
 
112
108
  # Dynamic imports
113
- gcdFunction = importLogicalPath2Identifier("math", "gcd")
114
- customFunction = importPathFilename2Identifier("path/to/module.py", "functionName")
109
+ gcdFunction = humpy.importLogicalPath2Identifier("math", "gcd")
110
+ customFunction = humpy.importPathFilename2Identifier("path/to/module.py", "functionName")
115
111
 
116
112
  # Safe file operations
117
113
  pathFilename = Path("deep/nested/directory/file.txt")
118
- writeStringToHere("content", pathFilename) # Creates directories automatically
114
+ humpy.writeStringToHere("content", pathFilename) # Creates directories automatically
119
115
  ```
120
116
 
121
117
  ## Data Structure Manipulation
@@ -123,21 +119,21 @@ writeStringToHere("content", pathFilename) # Creates directories automatically
123
119
  Utilities for string extraction, data flattening, and array compression.
124
120
 
125
121
  ```python
126
- from hunterMakesPy import stringItUp, updateExtendPolishDictionaryLists, autoDecodingRLE
122
+ import hunterMakesPy as humpy
127
123
  import numpy
128
124
 
129
125
  # Extract all strings from nested data structures
130
126
  nestedData = {"config": [1, "host", {"port": 8080}], "users": ["alice", "bob"]}
131
- allStrings = stringItUp(nestedData) # ['config', 'host', 'port', 'users', 'alice', 'bob']
127
+ allStrings = humpy.stringItUp(nestedData) # ['config', 'host', 'port', 'users', 'alice', 'bob']
132
128
 
133
129
  # Merge dictionaries containing lists
134
- dictionaryAlpha = {"servers": ["web1", "web2"], "databases": ["db1"]}
135
- dictionaryBeta = {"servers": ["web3"], "databases": ["db2", "db3"]}
136
- merged = updateExtendPolishDictionaryLists(dictionaryAlpha, dictionaryBeta, destroyDuplicates=True)
130
+ dictionaryAlpha = {"servers": ["chicago", "tokyo"], "databases": ["elm"]}
131
+ dictionaryBeta = {"servers": ["mumbai"], "databases": ["oak", "cedar"]}
132
+ merged = humpy.updateExtendPolishDictionaryLists(dictionaryAlpha, dictionaryBeta, destroyDuplicates=True)
137
133
 
138
134
  # Compress NumPy arrays with run-length encoding
139
135
  arrayData = numpy.array([1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9])
140
- compressed = autoDecodingRLE(arrayData) # "[1,*range(2,6)]+[5]*2+[*range(6,10)]"
136
+ compressed = humpy.autoDecodingRLE(arrayData) # "[1,*range(2,6)]+[5]*2+[*range(6,10)]"
141
137
  ```
142
138
 
143
139
  ## Testing
@@ -145,7 +141,7 @@ compressed = autoDecodingRLE(arrayData) # "[1,*range(2,6)]+[5]*2+[*range(6,10)]
145
141
  The package includes comprehensive test suites that you can import and run:
146
142
 
147
143
  ```python
148
- from hunterMakesPy.pytestForYourUse import (
144
+ from hunterMakesPy.tests.test_parseParameters import (
149
145
  PytestFor_defineConcurrencyLimit,
150
146
  PytestFor_intInnit,
151
147
  PytestFor_oopsieKwargsie
@@ -157,8 +153,9 @@ for nameOfTest, callablePytest in listOfTests:
157
153
  callablePytest()
158
154
 
159
155
  # Or test your own compatible functions
160
- @pytest.mark.parametrize("nameOfTest,callablePytest",
161
- PytestFor_intInnit(callableToTest=myFunction))
156
+ @pytest.mark.parametrize(
157
+ "nameOfTest,callablePytest"
158
+ , PytestFor_intInnit(callableToTest=myFunction))
162
159
  def test_myFunction(nameOfTest, callablePytest):
163
160
  callablePytest()
164
161
  ```
@@ -0,0 +1,20 @@
1
+ hunterMakesPy/__init__.py,sha256=bVF1F2Mdo5AOiioEfxKvNrnsa3vCFI16eMK7Oy5O5TU,1450
2
+ hunterMakesPy/_theSSOT.py,sha256=lkLOG3oTIWNKD_ULX55chlUGNqCHgqVIrBvolvK1vbQ,153
3
+ hunterMakesPy/coping.py,sha256=covqNFAwkF9gjafrlAvMdtCO8haFsESQBhO-7s68qSg,5581
4
+ hunterMakesPy/dataStructures.py,sha256=CFyGjmAOoN2MoEPwWwWdwKNXmOXX8kCS3ttMOa2Rsx0,11379
5
+ hunterMakesPy/filesystemToolkit.py,sha256=jd7H5UtrIrPiCYWcvNBNa6DAy-2Ewcf21-jbGXg_IVI,4702
6
+ hunterMakesPy/parseParameters.py,sha256=DXpyATx7trGBg_8jlO5dXGfLcG8vg_lU3R1sq1rRFOQ,11644
7
+ hunterMakesPy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ hunterMakesPy/pytestForYourUse.py,sha256=GiN1C1gTTM0ZunRPEMnrKlLQLMdH0wF_ZGr_RPgRjjA,500
9
+ hunterMakesPy/theTypes.py,sha256=C2d0uLn1VIx6_2CK41it3IP7iplSQqe51tzWc-RT320,306
10
+ hunterMakesPy/tests/__init__.py,sha256=C_FzfKDi_VrGVxlenWHyOYtKShAKlt3KW14jeRx1mQI,224
11
+ hunterMakesPy/tests/conftest.py,sha256=NZQPRiwvGhP16hJ6WGGm9eKLxfQArYV8E9X12YzSpP0,2827
12
+ hunterMakesPy/tests/test_coping.py,sha256=mH89TUAL6fJanBLlhdVlCNNQqm5OpdcQMP_p5W2JJwo,9860
13
+ hunterMakesPy/tests/test_dataStructures.py,sha256=O4aqzSKg7KfWWVhIewOH0Y8Zj28PbFCb4XX3xhwuFQA,16605
14
+ hunterMakesPy/tests/test_filesystemToolkit.py,sha256=q2voXjCbQPIT8l8VF9iuWX1Bs2ZieABItWoVkITj_fo,8841
15
+ hunterMakesPy/tests/test_parseParameters.py,sha256=80npsoWcCackjxvoW2dMXMpHeale7fuRXyXp78MibLs,14037
16
+ huntermakespy-0.2.1.dist-info/licenses/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
17
+ huntermakespy-0.2.1.dist-info/METADATA,sha256=U7mdPv2TiV-JgdBigReM9zxA1N9uZ0Nb93fmASS1-bk,6501
18
+ huntermakespy-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
+ huntermakespy-0.2.1.dist-info/top_level.txt,sha256=Uh4bj8EDTdsRpqY1VlK_his_B4HDfZ6Tqrwhoj75P_w,14
20
+ huntermakespy-0.2.1.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- hunterMakesPy/__init__.py,sha256=4gIm--UJmlQEhbLCqpiVFM_JVbyfVpvFFAJyMNFHekk,1329
2
- hunterMakesPy/_theSSOT.py,sha256=lkLOG3oTIWNKD_ULX55chlUGNqCHgqVIrBvolvK1vbQ,153
3
- hunterMakesPy/coping.py,sha256=covqNFAwkF9gjafrlAvMdtCO8haFsESQBhO-7s68qSg,5581
4
- hunterMakesPy/dataStructures.py,sha256=znMEnboo2iNXZtQKdmruRrJDEoeTfqoH4-coUDM75g4,11218
5
- hunterMakesPy/filesystemToolkit.py,sha256=vDYS0Rc1aP7ETLXHKoO3TfOpuwJQFQW2ybwtJNiIIo4,4305
6
- hunterMakesPy/parseParameters.py,sha256=plrJ4xR1FQnQR9j-oeMAwB2H9r_8QD8OALnw0OH8Kt0,11947
7
- hunterMakesPy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- hunterMakesPy/pytestForYourUse.py,sha256=21BI8TXyinf8rMmS6dTsuRMBOOFTcyoG_gD__Gz_e7Q,13288
9
- hunterMakesPy/theTypes.py,sha256=C2d0uLn1VIx6_2CK41it3IP7iplSQqe51tzWc-RT320,306
10
- huntermakespy-0.1.2.dist-info/licenses/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
11
- tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- tests/conftest.py,sha256=MkNc4Ar6yYrnAok4t1NWsgyOYFDiGo1qwXHyp8ChJf4,1672
13
- tests/test_coping.py,sha256=MQl0fhdWX2YSFzzjWMThSm_ZSnglE3anSJO2b33typU,9846
14
- tests/test_dataStructures.py,sha256=VhM3VzG1l8l3Iz1q9sQjpNBQTWSrl4zWbnefsGTccos,16406
15
- tests/test_filesystemToolkit.py,sha256=jk6Ke0fW6dlHIVyvA1lh7o7_I7DVZr6uMO3s_i43isQ,2445
16
- tests/test_parseParameters.py,sha256=bHD-O-OyWWwPOx3zvS53pSNPDm3LbFS05N5JcfNCLG4,1137
17
- huntermakespy-0.1.2.dist-info/METADATA,sha256=b1Xr8jhpu8t-H3BTVQUcCww_gG8q5fcb1REz-8AQbY8,6555
18
- huntermakespy-0.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
- huntermakespy-0.1.2.dist-info/top_level.txt,sha256=dUy7z3LNO6aqNjPD81tZjE5N9HO70a14Y9lAWjWC2gA,20
20
- huntermakespy-0.1.2.dist-info/RECORD,,
tests/__init__.py DELETED
File without changes
@@ -1,43 +0,0 @@
1
- # pyright: standard
2
- from hunterMakesPy import importLogicalPath2Identifier, importPathFilename2Identifier, makeDirsSafely, writeStringToHere
3
- from tests.conftest import uniformTestFailureMessage
4
- import io
5
- import math
6
- import os
7
- import pathlib
8
- import pytest
9
-
10
- def testMakeDirsSafelyCreatesParentDirectories(pathTmpTesting: pathlib.Path) -> None:
11
- nestedDirectory = pathTmpTesting / "sub1" / "sub2"
12
- filePath = nestedDirectory / "dummy.txt"
13
- makeDirsSafely(filePath)
14
- assert nestedDirectory.exists() and nestedDirectory.is_dir(), uniformTestFailureMessage(True, nestedDirectory.exists() and nestedDirectory.is_dir(), "testMakeDirsSafelyCreatesParentDirectories", filePath)
15
-
16
- def testMakeDirsSafelyWithIOBaseDoesNotRaise() -> None:
17
- memoryStream = io.StringIO()
18
- makeDirsSafely(memoryStream)
19
-
20
- def testWriteStringToHereCreatesFileAndWritesContent(pathTmpTesting: pathlib.Path) -> None:
21
- nestedDirectory = pathTmpTesting / "a" / "b"
22
- filePath = nestedDirectory / "test.txt"
23
- writeStringToHere("hello world", filePath)
24
- assert filePath.exists(), uniformTestFailureMessage(True, filePath.exists(), "testWriteStringToHereCreatesFileAndWritesContent", filePath)
25
- assert filePath.read_text(encoding="utf-8") == "hello world", uniformTestFailureMessage("hello world", filePath.read_text(encoding="utf-8"), "testWriteStringToHereCreatesFileAndWritesContent", filePath)
26
-
27
- @pytest.mark.parametrize(
28
- "moduleName, identifier, expectedType",
29
- [("math", "gcd", type(math.gcd)),("os.path", "join", type(os.path.join))])
30
- def testImportLogicalPath2Identifier(moduleName: str, identifier: str, expectedType: type) -> None:
31
- imported = importLogicalPath2Identifier(moduleName, identifier)
32
- assert isinstance(imported, expectedType), uniformTestFailureMessage(expectedType, type(imported), "testImportLogicalPath2Identifier", (moduleName, identifier))
33
-
34
- @pytest.mark.parametrize( "source, identifier, expected", [ ("def fibonacciNumber():\n return 13\n", "fibonacciNumber", 13), ("prime = 17\n", "prime", 17), ] )
35
- def testImportPathFilename2Identifier(tmp_path: pathlib.Path, source: str, identifier: str, expected: object) -> None:
36
- filePath = tmp_path / "moduleTest.py"
37
- filePath.write_text(source)
38
- imported = importPathFilename2Identifier(filePath, identifier)
39
- if callable(imported):
40
- actual = imported()
41
- else:
42
- actual = imported
43
- assert actual == expected, uniformTestFailureMessage(expected, actual, "testImportPathFilename2Identifier", (filePath, identifier))
@@ -1,21 +0,0 @@
1
- # pyright: standard
2
- from collections.abc import Callable
3
- from hunterMakesPy.pytestForYourUse import (
4
- PytestFor_defineConcurrencyLimit, PytestFor_intInnit, PytestFor_oopsieKwargsie)
5
- from typing import ParamSpec, TypeVar
6
- import pytest
7
-
8
- parameters = ParamSpec('parameters')
9
- returnType = TypeVar('returnType')
10
-
11
- @pytest.mark.parametrize("nameOfTest,aPytest", PytestFor_defineConcurrencyLimit())
12
- def testConcurrencyLimit(nameOfTest: str, aPytest: Callable[parameters, returnType], *arguments: parameters.args, **keywordArguments: parameters.kwargs) -> None:
13
- aPytest(*arguments, **keywordArguments)
14
-
15
- @pytest.mark.parametrize("nameOfTest,aPytest", PytestFor_intInnit())
16
- def testIntInnit(nameOfTest: str, aPytest: Callable[parameters, returnType], *arguments: parameters.args, **keywordArguments: parameters.kwargs) -> None:
17
- aPytest(*arguments, **keywordArguments)
18
-
19
- @pytest.mark.parametrize("nameOfTest,aPytest", PytestFor_oopsieKwargsie())
20
- def testOopsieKwargsie(nameOfTest: str, aPytest: Callable[parameters, returnType], *arguments: parameters.args, **keywordArguments: parameters.kwargs) -> None:
21
- aPytest(*arguments, **keywordArguments)