hunterMakesPy 0.3.3__py3-none-any.whl → 0.4.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,3 +1,11 @@
1
+ """Tests for data structure utilities.
2
+
3
+ (AI generated docstring)
4
+
5
+ This module validates the behavior of data structure manipulation functions,
6
+ string conversion utilities, and Run-Length Encoding (RLE) tools.
7
+
8
+ """
1
9
  # pyright: standard
2
10
  from collections.abc import Callable, Iterable, Iterator
3
11
  from decimal import Decimal
@@ -12,7 +20,17 @@ import pytest
12
20
  import sys
13
21
 
14
22
  class CustomIterable:
15
- def __init__(self, items: Iterable[Any]) -> None: self.items = items
23
+ """A simple custom iterable for testing purposes.
24
+
25
+ (AI generated docstring)
26
+
27
+ Attributes
28
+ ----------
29
+ items : Iterable[Any]
30
+ The items to iterate over.
31
+
32
+ """
33
+ def __init__(self, items: Iterable[Any]) -> None: self.items: Iterable[Any] = items
16
34
  def __iter__(self) -> Iterator[Any]: return iter(self.items)
17
35
 
18
36
  @pytest.mark.parametrize("description,value_scrapPile,expected", [
@@ -57,7 +75,18 @@ class CustomIterable:
57
75
  ("Raising __str__", type('RaisingStr', (), {'__str__': lambda x: 1/0})(), ZeroDivisionError),
58
76
  ], ids=lambda x: x if isinstance(x, str) else "")
59
77
  def testStringItUp(description: str, value_scrapPile: list[Any], expected: list[str] | type[Exception]) -> None:
60
- """Test stringItUp with various inputs."""
78
+ """Test stringItUp with various inputs.
79
+
80
+ Parameters
81
+ ----------
82
+ description : str
83
+ Description of the test case.
84
+ value_scrapPile : list[Any]
85
+ List of values to convert to strings.
86
+ expected : list[str] | type[Exception]
87
+ Expected list of string representations or an Exception type.
88
+
89
+ """
61
90
  standardizedEqualTo(expected, stringItUp, value_scrapPile)
62
91
 
63
92
  @pytest.mark.parametrize("description,value_dictionaryLists,keywordArguments,expected", [
@@ -72,20 +101,24 @@ def testStringItUp(description: str, value_scrapPile: list[Any], expected: list[
72
101
  ("Non-iterable values", ({'ne': 13, 'sw': 17}, {'ne': 19, 'nw': 23}), {'destroyDuplicates': False, 'reorderLists': False}, TypeError),
73
102
  ("Skip erroneous types", ({'ne': [11, 13], 'sw': [17, 19]}, {'ne': 23, 'nw': 29}), {'killErroneousDataTypes': True}, {'ne': [11, 13], 'sw': [17, 19]}),
74
103
  ], ids=lambda x: x if isinstance(x, str) else "")
75
- def testUpdateExtendPolishDictionaryLists(description: str, value_dictionaryLists: dict[str, Any], keywordArguments: dict[str, Any], expected: dict[str, Any] | type[TypeError]) -> None:
104
+ def testUpdateExtendPolishDictionaryLists(description: str, value_dictionaryLists: tuple[dict[str, Any], ...], keywordArguments: dict[str, Any], expected: dict[str, Any] | type[TypeError]) -> None:
105
+ """Test dictionary list updating and extension logic.
106
+
107
+ (AI generated docstring)
108
+
109
+ Parameters
110
+ ----------
111
+ description : str
112
+ Description of the test case.
113
+ value_dictionaryLists : tuple[dict[str, Any], ...]
114
+ Tuple of dictionaries to merge/update.
115
+ keywordArguments : dict[str, Any]
116
+ Keyword arguments controlling the behavior (e.g., destroyDuplicates).
117
+ expected : dict[str, Any] | type[TypeError]
118
+ The expected result dictionary or an exception type.
119
+
120
+ """
76
121
  standardizedEqualTo(expected, updateExtendPolishDictionaryLists, *value_dictionaryLists, **keywordArguments)
77
- # ruff: noqa: ERA001
78
- # NOTE one line of code with `standardizedEqualTo` replaced the following ten lines of code. Use `standardizedEqualTo`.
79
- # if isinstance(expected, type) and issubclass(expected, Exception):
80
- # with pytest.raises(expected):
81
- # updateExtendPolishDictionaryLists(*value_dictionaryLists, **keywordArguments)
82
- # else:
83
- # result = updateExtendPolishDictionaryLists(*value_dictionaryLists, **keywordArguments)
84
- # if description == "Set values": # Special handling for unordered sets
85
- # for key in result:
86
- # assert sorted(result[key]) == sorted(expected[key])
87
- # else:
88
- # assert result == expected
89
122
 
90
123
  # ruff: noqa: RUF005
91
124
 
@@ -107,12 +140,37 @@ def testUpdateExtendPolishDictionaryLists(description: str, value_dictionaryList
107
140
  ("3D array primes", numpy.array([[[541, 547], [557, 563]], [[569, 571], [577, 587]]]), "[[[541,547],[557,563]],[[569,571],[577,587]]]"),
108
141
  ], ids=lambda x: x if isinstance(x, str) else "")
109
142
  def testAutoDecodingRLE(description: str, value_arrayTarget: NDArray[numpy.integer[Any]], expected: str) -> None:
110
- """Test autoDecodingRLE with various input arrays."""
143
+ """Test autoDecodingRLE with various input arrays.
144
+
145
+ Parameters
146
+ ----------
147
+ description : str
148
+ Description of the test case.
149
+ value_arrayTarget : NDArray[numpy.integer[Any]]
150
+ The input numpy array to encode.
151
+ expected : str
152
+ The expected string representation of the RLE.
153
+
154
+ """
111
155
  standardizedEqualTo(expected, autoDecodingRLE, value_arrayTarget)
112
156
 
113
157
  # Helper functions for generating RLE test data
114
- def generateCartesianMapping(dimensions: tuple[int, int], formula: Callable[[int, int], int]) -> NDArray[Any]:
115
- """Generate a 2D cartesian mapping based on a formula."""
158
+ def generateCartesianMapping(dimensions: tuple[int, int], formula: Callable[[int, int], int]) -> NDArray[numpy.int32]:
159
+ """Generate a 2D cartesian mapping based on a formula.
160
+
161
+ Parameters
162
+ ----------
163
+ dimensions : tuple[int, int]
164
+ The (height, width) of the array to generate.
165
+ formula : Callable[[int, int], int]
166
+ A function taking (x, y) coordinates and returning an integer value.
167
+
168
+ Returns
169
+ -------
170
+ arrayMapping : NDArray[numpy.int32]
171
+ The generated 2D numpy array.
172
+
173
+ """
116
174
  height, width = dimensions
117
175
  arrayMapping = numpy.zeros((height, width), dtype=numpy.int32)
118
176
 
@@ -122,66 +180,139 @@ def generateCartesianMapping(dimensions: tuple[int, int], formula: Callable[[int
122
180
 
123
181
  return arrayMapping
124
182
 
125
- def generateWavePattern(dimensions: tuple[int, int]) -> NDArray[Any]:
126
- """Generate a sine wave pattern that produces many RLE-friendly sequences."""
127
- height, width = dimensions
183
+ def generateWavePattern(dimensions: tuple[int, int]) -> NDArray[numpy.int32]:
184
+ """Generate a sine wave pattern that produces many RLE-friendly sequences.
185
+
186
+ Parameters
187
+ ----------
188
+ dimensions : tuple[int, int]
189
+ The (height, width) of the array.
190
+
191
+ Returns
192
+ -------
193
+ arrayMapping : NDArray[numpy.int32]
194
+ The generated wave pattern array.
195
+
196
+ """
128
197
 
129
198
  def waveFormula(x: int, y: int) -> int:
130
199
  return int(10 * numpy.sin(x / 5) + 10 * numpy.sin(y / 5))
131
200
 
132
201
  return generateCartesianMapping(dimensions, waveFormula)
133
202
 
134
- def generateChessboard(dimensions: tuple[int, int], squareSize: int = 4) -> NDArray[Any]:
135
- """Generate a chessboard pattern with alternating values."""
136
- height, width = dimensions
203
+ def generateChessboard(dimensions: tuple[int, int], squareSize: int = 4) -> NDArray[numpy.int32]:
204
+ """Generate a chessboard pattern with alternating values.
205
+
206
+ Parameters
207
+ ----------
208
+ dimensions : tuple[int, int]
209
+ The (height, width) of the array.
210
+ squareSize : int = 4
211
+ The size of each chessboard square.
137
212
 
213
+ Returns
214
+ -------
215
+ arrayMapping : NDArray[numpy.int32]
216
+ The generated chessboard pattern array.
217
+
218
+ """
138
219
  def chessboardFormula(x: int, y: int) -> int:
139
220
  return 1 if ((x // squareSize) + (y // squareSize)) % 2 == 0 else 0
140
221
 
141
222
  return generateCartesianMapping(dimensions, chessboardFormula)
142
223
 
143
- def generatePrimeModuloMatrix(dimensions: tuple[int, int], modulus: int = 6) -> NDArray[Any]:
144
- """Generate a matrix where each cell is (x*y) % modulus."""
145
- height, width = dimensions
224
+ def generatePrimeModuloMatrix(dimensions: tuple[int, int], modulus: int = 6) -> NDArray[numpy.int32]:
225
+ """Generate a matrix where each cell is (x*y) % modulus.
226
+
227
+ Parameters
228
+ ----------
229
+ dimensions : tuple[int, int]
230
+ The (height, width) of the array.
231
+ modulus : int = 6
232
+ The modulus to apply to the product of coordinates.
233
+
234
+ Returns
235
+ -------
236
+ arrayMapping : NDArray[numpy.int32]
237
+ The generated prime modulo matrix.
146
238
 
239
+ """
147
240
  def primeModuloFormula(x: int, y: int) -> int:
148
241
  return ((x + 1) * (y + 1)) % modulus
149
242
 
150
243
  return generateCartesianMapping(dimensions, primeModuloFormula)
151
244
 
152
- def generateSpiralPattern(dimensions: tuple[int, int], scale: int = 1) -> NDArray[Any]:
153
- """Generate a spiral pattern that creates interesting RLE sequences."""
245
+ def generateSpiralPattern(dimensions: tuple[int, int], scale: int = 1) -> NDArray[numpy.int32]:
246
+ """Generate a spiral pattern that creates interesting RLE sequences.
247
+
248
+ Parameters
249
+ ----------
250
+ dimensions : tuple[int, int]
251
+ The (height, width) of the array.
252
+ scale : int = 1
253
+ Scaling factor for the spiral values.
254
+
255
+ Returns
256
+ -------
257
+ arrayMapping : NDArray[numpy.int32]
258
+ The generated spiral pattern array.
259
+
260
+ """
154
261
  height, width = dimensions
155
262
 
156
263
  def spiralFormula(x: int, y: int) -> int:
157
- xCenter = width // 2
158
- yCenter = height // 2
159
- distanceX = x - xCenter
160
- distanceY = y - yCenter
161
- distance = numpy.sqrt(distanceX**2 + distanceY**2)
162
- angle = numpy.arctan2(distanceY, distanceX)
264
+ xCenter: int = width // 2
265
+ yCenter: int = height // 2
266
+ distanceX: int = x - xCenter
267
+ distanceY: int = y - yCenter
268
+ distance: float = numpy.sqrt(distanceX**2 + distanceY**2)
269
+ angle: float = numpy.arctan2(distanceY, distanceX)
163
270
  return int((distance + 5 * angle) * scale) % 10
164
271
 
165
272
  return generateCartesianMapping(dimensions, spiralFormula)
166
273
 
167
- def generateSignedQuadraticFunction(dimensions: tuple[int, int]) -> NDArray[Any]:
168
- """Generate a matrix with a quadratic function that includes negative values."""
274
+ def generateSignedQuadraticFunction(dimensions: tuple[int, int]) -> NDArray[numpy.int32]:
275
+ """Generate a matrix with a quadratic function that includes negative values.
276
+
277
+ Parameters
278
+ ----------
279
+ dimensions : tuple[int, int]
280
+ The (height, width) of the array.
281
+
282
+ Returns
283
+ -------
284
+ arrayMapping : NDArray[numpy.int32]
285
+ The generated quadratic function array.
286
+
287
+ """
169
288
  height, width = dimensions
170
289
 
171
290
  def quadraticFormula(x: int, y: int) -> int:
172
- xCenter = width // 2
173
- yCenter = height // 2
291
+ xCenter: int = width // 2
292
+ yCenter: int = height // 2
174
293
  return (x - xCenter)**2 - (y - yCenter)**2
175
294
 
176
295
  return generateCartesianMapping(dimensions, quadraticFormula)
177
296
 
178
- def generateTilePattern(dimensions: tuple[int, int], tileSize: int = 10) -> NDArray[Any]:
179
- """Generate a repeating tile pattern."""
180
- height, width = dimensions
297
+ def generateTilePattern(dimensions: tuple[int, int], tileSize: int = 10) -> NDArray[numpy.int32]:
298
+ """Generate a repeating tile pattern.
299
+
300
+ Parameters
301
+ ----------
302
+ dimensions : tuple[int, int]
303
+ The (height, width) of the array.
304
+ tileSize : int = 10
305
+ The size of the repeating tile.
306
+
307
+ Returns
308
+ -------
309
+ arrayMapping : NDArray[numpy.int32]
310
+ The generated tile pattern array.
181
311
 
312
+ """
182
313
  def tileFormula(x: int, y: int) -> int:
183
- patternX = x % tileSize
184
- patternY = y % tileSize
314
+ patternX: int = x % tileSize
315
+ patternY: int = y % tileSize
185
316
  if patternX < patternY:
186
317
  return patternX
187
318
  else:
@@ -189,29 +320,65 @@ def generateTilePattern(dimensions: tuple[int, int], tileSize: int = 10) -> NDAr
189
320
 
190
321
  return generateCartesianMapping(dimensions, tileFormula)
191
322
 
192
- def generateRepeatingZones(dimensions: tuple[int, int], zoneWidth: int = 15) -> NDArray[Any]:
193
- """Generate horizontal zones with repeating values."""
194
- height, width = dimensions
323
+ def generateRepeatingZones(dimensions: tuple[int, int], zoneWidth: int = 15) -> NDArray[numpy.int32]:
324
+ """Generate horizontal zones with repeating values.
325
+
326
+ Parameters
327
+ ----------
328
+ dimensions : tuple[int, int]
329
+ The (height, width) of the array.
330
+ zoneWidth : int = 15
331
+ The width of each zone.
195
332
 
333
+ Returns
334
+ -------
335
+ arrayMapping : NDArray[numpy.int32]
336
+ The generated zonal pattern array.
337
+
338
+ """
196
339
  def zoneFormula(x: int, y: int) -> int:
197
- zone = y // zoneWidth
340
+ zone: int = y // zoneWidth
198
341
  return zone % 5 # 5 different zones
199
342
 
200
343
  return generateCartesianMapping(dimensions, zoneFormula)
201
344
 
202
- def generateStepPattern(dimensions: tuple[int, int], step: int = 5) -> NDArray[Any]:
203
- """Generate a stepping pattern that increases along the x-axis."""
204
- height, width = dimensions
345
+ def generateStepPattern(dimensions: tuple[int, int], step: int = 5) -> NDArray[numpy.int32]:
346
+ """Generate a stepping pattern that increases along the x-axis.
347
+
348
+ Parameters
349
+ ----------
350
+ dimensions : tuple[int, int]
351
+ The (height, width) of the array.
352
+ step : int = 5
353
+ The step size for value increments.
205
354
 
355
+ Returns
356
+ -------
357
+ arrayMapping : NDArray[numpy.int32]
358
+ The generated step pattern array.
359
+
360
+ """
206
361
  def stepFormula(x: int, y: int) -> int:
207
362
  return x // step
208
363
 
209
364
  return generateCartesianMapping(dimensions, stepFormula)
210
365
 
211
- def generateAlternatingColumns(dimensions: tuple[int, int], blockSize: int = 1) -> NDArray[Any]:
212
- """Generate alternating columns with different values."""
213
- height, width = dimensions
366
+ def generateAlternatingColumns(dimensions: tuple[int, int], blockSize: int = 1) -> NDArray[numpy.int32]:
367
+ """Generate alternating columns with different values.
368
+
369
+ Parameters
370
+ ----------
371
+ dimensions : tuple[int, int]
372
+ The (height, width) of the array.
373
+ blockSize : int = 1
374
+ The width of each column block.
214
375
 
376
+ Returns
377
+ -------
378
+ arrayMapping : NDArray[numpy.int32]
379
+ The generated alternating columns array.
380
+
381
+ """
215
382
  def columnFormula(x: int, y: int) -> int:
216
383
  return (x // blockSize) % 2
217
384
 
@@ -249,9 +416,18 @@ def generateAlternatingColumns(dimensions: tuple[int, int], blockSize: int = 1)
249
416
  ("Spiral pattern", generateSpiralPattern((15, 15), 2)),
250
417
  ], ids=lambda x: x if isinstance(x, str) else "")
251
418
  def testAutoDecodingRLEWithRealisticData(description: str, value_arrayTarget: NDArray[numpy.integer[Any]]) -> None:
252
- """Test autoDecodingRLE with more realistic data patterns."""
419
+ """Test autoDecodingRLE with more realistic data patterns.
420
+
421
+ Parameters
422
+ ----------
423
+ description : str
424
+ Description of the test pattern.
425
+ value_arrayTarget : NDArray[numpy.integer[Any]]
426
+ The input array generated by a pattern function.
427
+
428
+ """
253
429
  # Here we test the function behavior rather than expected string output
254
- resultRLE = autoDecodingRLE(value_arrayTarget)
430
+ resultRLE: str = autoDecodingRLE(value_arrayTarget)
255
431
 
256
432
  # Test that the result is a valid string
257
433
  assert isinstance(resultRLE, str)
@@ -261,8 +437,8 @@ def testAutoDecodingRLEWithRealisticData(description: str, value_arrayTarget: ND
261
437
  assert "]" in resultRLE, f"Result should contain list syntax: {resultRLE}"
262
438
 
263
439
  # Check that the result is more compact than the raw string representation
264
- rawStrLength = len(str(value_arrayTarget.tolist()))
265
- encodedLength = len(resultRLE)
440
+ rawStrLength: int = len(str(value_arrayTarget.tolist()))
441
+ encodedLength: int = len(resultRLE)
266
442
  assert encodedLength <= rawStrLength, f"Encoded string ({encodedLength}) should be shorter than raw string ({rawStrLength})"
267
443
 
268
444
  @pytest.mark.parametrize("description,addSpaces", [
@@ -275,32 +451,37 @@ def testAutoDecodingRLEWithSpaces(description: str, addSpaces: bool) -> None:
275
451
  Note: addSpaces doesn't directly change the output format, it just changes
276
452
  the comparison when measuring the length of the string representation.
277
453
  The feature exists because `ast` inserts spaces in its string representation.
454
+
455
+ Parameters
456
+ ----------
457
+ description : str
458
+ Description of the test configuration.
459
+ addSpaces : bool
460
+ Value for the `assumeAddSpaces` parameter.
461
+
278
462
  """
279
463
  # Create a pattern that has repeated sequences to trigger the RLE logic
280
- arrayTarget = generateRepeatingZones((10, 10), 2)
464
+ arrayTarget: NDArray[numpy.int32] = generateRepeatingZones((10, 10), 2)
281
465
 
282
466
  # Test both configurations
283
- resultWithSpacesFlag = autoDecodingRLE(arrayTarget, assumeAddSpaces=addSpaces)
284
- resultNoSpacesFlag = autoDecodingRLE(arrayTarget, assumeAddSpaces=False)
467
+ resultWithSpacesFlag: str = autoDecodingRLE(arrayTarget, assumeAddSpaces=addSpaces)
468
+ resultNoSpacesFlag: str = autoDecodingRLE(arrayTarget, assumeAddSpaces=False)
285
469
 
286
- # When addSpaces=True, the internal length comparisons change
287
- # but the actual output format doesn't necessarily differ
288
- # Just verify the function runs without errors in both cases
289
470
  assert isinstance(resultWithSpacesFlag, str)
290
471
  assert isinstance(resultNoSpacesFlag, str)
291
472
 
292
473
  def testAutoDecodingRLELargeCartesianMapping() -> None:
293
474
  """Test autoDecodingRLE with a large (100x100) cartesian mapping."""
294
- dimensions = (100, 100)
475
+ dimensions: tuple[int, int] = (100, 100)
295
476
 
296
477
  # Generate a large cartesian mapping with a complex pattern
297
478
  def complexFormula(x: int, y: int) -> int:
298
479
  return ((x * 17) % 11 + (y * 13) % 7) % 10
299
480
 
300
- arrayMapping = generateCartesianMapping(dimensions, complexFormula)
481
+ arrayMapping: NDArray[numpy.int32] = generateCartesianMapping(dimensions, complexFormula)
301
482
 
302
483
  # Verify the function works with large arrays
303
- resultRLE = autoDecodingRLE(arrayMapping)
484
+ resultRLE: str = autoDecodingRLE(arrayMapping)
304
485
 
305
486
  # The result should be a valid string representation
306
487
  assert isinstance(resultRLE, str)
@@ -308,6 +489,6 @@ def testAutoDecodingRLELargeCartesianMapping() -> None:
308
489
  assert "]" in resultRLE
309
490
 
310
491
  # The RLE encoding should be more compact than the raw representation
311
- rawStrLength = len(str(arrayMapping.tolist()))
312
- encodedLength = len(resultRLE)
492
+ rawStrLength: int = len(str(arrayMapping.tolist()))
493
+ encodedLength: int = len(resultRLE)
313
494
  assert encodedLength <= rawStrLength, f"RLE encoded string ({encodedLength}) should be shorter than raw string ({rawStrLength})"