hunterMakesPy 0.2.1__py3-none-any.whl → 0.2.4__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.
hunterMakesPy/coping.py CHANGED
@@ -36,14 +36,14 @@ class PackageSettings:
36
36
  package identifiers and installation paths if they are not passed to the `class` constructor. Python `dataclasses` are easy to
37
37
  subtype and extend.
38
38
 
39
- Parameters
39
+ Attributes
40
40
  ----------
41
41
  identifierPackageFALLBACK : str = ''
42
42
  Fallback package identifier used only during initialization when automatic discovery fails.
43
- pathPackage : Path = Path()
44
- Absolute path to the installed package directory. Automatically resolved from `identifierPackage` if not provided.
45
43
  identifierPackage : str = ''
46
- Canonical name of the package. Automatically extracted from `pyproject.toml`.
44
+ Canonical name of the package. Automatically extracted from "pyproject.toml".
45
+ pathPackage : Path = getPathPackageINSTALLING(identifierPackage)
46
+ Absolute path to the installed package directory. Automatically resolved from `identifierPackage` if not provided.
47
47
  fileExtension : str = '.py'
48
48
  Default file extension.
49
49
 
@@ -85,34 +85,39 @@ class PackageSettings:
85
85
  if self.pathPackage == Path() and self.identifierPackage:
86
86
  self.pathPackage = getPathPackageINSTALLING(self.identifierPackage)
87
87
 
88
- def raiseIfNone(returnTarget: TypeSansNone | None, errorMessage: str | None = None) -> TypeSansNone:
89
- """Raise a `ValueError` if the target value is `None`, otherwise return the value: tell the type checker that the return value is not `None`.
90
-
91
- (AI generated docstring)
88
+ def raiseIfNone(expression: TypeSansNone | None, errorMessage: str | None = None) -> TypeSansNone:
89
+ """Convert the `expression` return annotation from '`cerPytainty | None`' to '`cerPytainty`' because `expression` cannot be `None`; `raise` an `Exception` if you're wrong.
92
90
 
93
- This is a defensive programming function that converts unexpected `None` values into explicit errors with context. It is useful for asserting that functions that might return `None` have actually returned a meaningful value.
91
+ The Python interpreter evaluates `expression` to a value: think of a function call or an attribute access. You can use
92
+ `raiseIfNone` for fail early defensive programming. I use it, however, to cure type-checker-nihilism: that's when "or `None`"
93
+ return types cause your type checker to repeatedly say, "You can't do that because the value might be `None`."
94
94
 
95
95
  Parameters
96
96
  ----------
97
- returnTarget : TypeSansNone | None
98
- The value to check for `None`. If not `None`, this value is returned unchanged.
99
- errorMessage : str | None = None
100
- Custom error message to include in the `ValueError`. If `None`, a default message with debugging hints is used.
97
+ expression : TypeSansNone | None
98
+ Python code with a return type that is a `union` of `None` and `TypeSansNone`, which is a stand-in for one or more other types.
99
+ errorMessage : str | None = 'A function unexpectedly returned `None`. Hint: look at the traceback immediately before `raiseIfNone`.'
100
+ Custom error message for the `ValueError` `Exception` if `expression` is `None`.
101
101
 
102
102
  Returns
103
103
  -------
104
- returnTarget : TypeSansNone
105
- The original `returnTarget` value, guaranteed to not be `None`.
104
+ contentment : TypeSansNone
105
+ The value returned by `expression`, but guaranteed to not be `None`.
106
106
 
107
107
  Raises
108
108
  ------
109
109
  ValueError
110
- If `returnTarget` is `None`.
110
+ If the value returned by `expression` is `None`.
111
111
 
112
112
  Examples
113
113
  --------
114
- Ensure a function result is not `None`:
114
+ Basic usage with attribute access:
115
+ ```python
116
+ annotation = raiseIfNone(ast_arg.annotation)
117
+ # Raises ValueError if ast_arg.annotation is None
118
+ ```
115
119
 
120
+ Function return value validation:
116
121
  ```python
117
122
  def findFirstMatch(listItems: list[str], pattern: str) -> str | None:
118
123
  for item in listItems:
@@ -122,28 +127,27 @@ def raiseIfNone(returnTarget: TypeSansNone | None, errorMessage: str | None = No
122
127
 
123
128
  listFiles = ['document.txt', 'image.png', 'data.csv']
124
129
  filename = raiseIfNone(findFirstMatch(listFiles, '.txt'))
125
- # Returns 'document.txt'
130
+ # Returns 'document.txt' when match exists
126
131
  ```
127
132
 
128
- Handle dictionary lookups with custom error messages:
129
-
133
+ Dictionary value retrieval with custom message:
130
134
  ```python
131
135
  configurationMapping = {'host': 'localhost', 'port': 8080}
132
136
  host = raiseIfNone(configurationMapping.get('host'),
133
137
  "Configuration must include 'host' setting")
134
- # Returns 'localhost'
138
+ # Returns 'localhost' when key exists
135
139
 
136
140
  # This would raise ValueError with custom message:
137
141
  # database = raiseIfNone(configurationMapping.get('database'),
138
- # "Configuration must include 'database' setting")
142
+ # "Configuration must include 'database' setting")
139
143
  ```
140
144
 
141
145
  Thanks
142
146
  ------
143
- sobolevn, https://github.com/sobolevn, for the seed of the function. https://github.com/python/typing/discussions/1997#discussioncomment-13108399
147
+ sobolevn, https://github.com/sobolevn, for the seed of this function. https://github.com/python/typing/discussions/1997#discussioncomment-13108399
144
148
 
145
149
  """
146
- if returnTarget is None:
150
+ if expression is None:
147
151
  message = errorMessage or 'A function unexpectedly returned `None`. Hint: look at the traceback immediately before `raiseIfNone`.'
148
152
  raise ValueError(message)
149
- return returnTarget
153
+ return expression
@@ -6,160 +6,170 @@ from numpy.typing import NDArray
6
6
  from typing import Any
7
7
  import more_itertools
8
8
  import re as regex
9
- import sys
10
-
11
- if sys.version_info < (3, 14):
12
- import python_minifier
13
-
14
- def autoDecodingRLE(arrayTarget: NDArray[integer[Any]], *, assumeAddSpaces: bool = False) -> str: # noqa: C901, PLR0915
15
- """Transform a NumPy array into a compact, self-decoding run-length encoded string representation.
16
-
17
- This function converts a NumPy array into a string that, when evaluated as Python code,
18
- recreates the original array structure. The function employs two compression strategies:
19
- 1. Python's `range` syntax for consecutive integer sequences
20
- 2. Multiplication syntax for repeated elements
21
-
22
- The resulting string representation is designed to be both human-readable and space-efficient,
23
- especially for large cartesian mappings with repetitive patterns. When this string is used
24
- as a data source, Python will automatically decode it into Python `list`, which if used as an
25
- argument to `numpy.array()`, will recreate the original array structure.
26
-
27
- Parameters
28
- ----------
29
- arrayTarget : NDArray[integer[Any]]
30
- (array2target) The NumPy array to be encoded.
31
- assumeAddSpaces : bool = False
32
- (assume2add2spaces) Affects internal length comparison during compression decisions.
33
- This parameter doesn't directly change output format but influences whether
34
- `range` or multiplication syntax is preferred in certain cases. The parameter
35
- exists because the Abstract Syntax Tree (AST) inserts spaces in its string
36
- representation.
37
-
38
- Returns
39
- -------
40
- rleString : str
41
- (rle2string) A string representation of the array using run-length encoding that,
42
- when evaluated as Python code, reproduces the original array structure.
43
-
44
- Notes
45
- -----
46
- The "autoDecoding" feature means that the string representation evaluates directly
47
- to the desired data structure without explicit decompression steps.
48
-
49
- """
50
- def sliceNDArrayToNestedLists(arraySlice: NDArray[integer[Any]]) -> Any:
51
- def getLengthOption(optionAsStr: str) -> int:
52
- """`assumeAddSpaces` characters: `,` 1; `]*` 2."""
53
- return assumeAddSpaces * (optionAsStr.count(',') + optionAsStr.count(']*') * 2) + len(optionAsStr)
54
-
55
- if arraySlice.ndim > 1:
56
- axisOfOperation = 0
57
- return [sliceNDArrayToNestedLists(arraySlice[index]) for index in range(arraySlice.shape[axisOfOperation])]
58
- if arraySlice.ndim == 1:
59
- arraySliceAsList: list[int | range] = []
60
- cache_consecutiveGroup_addMe: dict[Iterator[Any], list[int] | list[range]] = {}
61
- for consecutiveGroup in more_itertools.consecutive_groups(arraySlice.tolist()):
62
- if consecutiveGroup in cache_consecutiveGroup_addMe:
63
- addMe = cache_consecutiveGroup_addMe[consecutiveGroup]
64
- else:
65
- ImaSerious: list[int] = list(consecutiveGroup)
66
- ImaRange = [range(ImaSerious[0], ImaSerious[-1] + 1)]
67
- ImaRangeAsStr = python_minifier.minify(str(ImaRange)).replace('range(0,', 'range(').replace('range', '*range')
68
9
 
69
- option1 = ImaRange
70
- option1AsStr = ImaRangeAsStr
71
- option2 = ImaSerious
72
- option2AsStr = None
10
+ def removeExtraWhitespace(text: str) -> str:
11
+ """Remove extra whitespace from string representation of Python data structures.
12
+
13
+ This function replaces python_minifier.minify() for the specific use case of
14
+ minimizing string representations of lists, tuples, ranges, etc. It removes
15
+ spaces after commas, around brackets and parentheses.
16
+ """
17
+ # Remove spaces after commas
18
+ text = regex.sub(r',\s+', ',', text)
19
+ # Remove spaces after opening brackets/parens
20
+ text = regex.sub(r'([\[\(])\s+', r'\1', text)
21
+ # Remove spaces before closing brackets/parens
22
+ return regex.sub(r'\s+([\]\)])', r'\1', text)
23
+
24
+ def autoDecodingRLE(arrayTarget: NDArray[integer[Any]], *, assumeAddSpaces: bool = False) -> str:
25
+ """Transform a NumPy array into a compact, self-decoding run-length encoded string representation.
26
+
27
+ This function converts a NumPy array into a string that, when evaluated as Python code,
28
+ recreates the original array structure. The function employs two compression strategies:
29
+ 1. Python's `range` syntax for consecutive integer sequences
30
+ 2. Multiplication syntax for repeated elements
31
+
32
+ The resulting string representation is designed to be both human-readable and space-efficient,
33
+ especially for large cartesian mappings with repetitive patterns. When this string is used
34
+ as a data source, Python will automatically decode it into Python `list`, which if used as an
35
+ argument to `numpy.array()`, will recreate the original array structure.
36
+
37
+ Parameters
38
+ ----------
39
+ arrayTarget : NDArray[integer[Any]]
40
+ (array2target) The NumPy array to be encoded.
41
+ assumeAddSpaces : bool = False
42
+ (assume2add2spaces) Affects internal length comparison during compression decisions.
43
+ This parameter doesn't directly change output format but influences whether
44
+ `range` or multiplication syntax is preferred in certain cases. The parameter
45
+ exists because the Abstract Syntax Tree (AST) inserts spaces in its string
46
+ representation.
47
+
48
+ Returns
49
+ -------
50
+ rleString : str
51
+ (rle2string) A string representation of the array using run-length encoding that,
52
+ when evaluated as Python code, reproduces the original array structure.
73
53
 
74
- # alpha, potential function
75
- option1AsStr = option1AsStr or python_minifier.minify(str(option1))
76
- lengthOption1 = getLengthOption(option1AsStr)
54
+ Notes
55
+ -----
56
+ The "autoDecoding" feature means that the string representation evaluates directly
57
+ to the desired data structure without explicit decompression steps.
77
58
 
78
- option2AsStr = option2AsStr or python_minifier.minify(str(option2))
79
- lengthOption2 = getLengthOption(option2AsStr)
59
+ """
60
+ def sliceNDArrayToNestedLists(arraySlice: NDArray[integer[Any]]) -> Any:
61
+ def getLengthOption(optionAsStr: str) -> int:
62
+ """`assumeAddSpaces` characters: `,` 1; `]*` 2."""
63
+ return assumeAddSpaces * (optionAsStr.count(',') + optionAsStr.count(']*') * 2) + len(optionAsStr)
64
+
65
+ if arraySlice.ndim > 1:
66
+ axisOfOperation = 0
67
+ return [sliceNDArrayToNestedLists(arraySlice[index]) for index in range(arraySlice.shape[axisOfOperation])]
68
+ if arraySlice.ndim == 1:
69
+ arraySliceAsList: list[int | range] = []
70
+ cache_consecutiveGroup_addMe: dict[Iterator[Any], list[int] | list[range]] = {}
71
+ for consecutiveGroup in more_itertools.consecutive_groups(arraySlice.tolist()):
72
+ if consecutiveGroup in cache_consecutiveGroup_addMe:
73
+ addMe = cache_consecutiveGroup_addMe[consecutiveGroup]
74
+ else:
75
+ ImaSerious: list[int] = list(consecutiveGroup)
76
+ ImaRange = [range(ImaSerious[0], ImaSerious[-1] + 1)]
77
+ ImaRangeAsStr = removeExtraWhitespace(str(ImaRange)).replace('range(0,', 'range(').replace('range', '*range')
80
78
 
81
- if lengthOption1 < lengthOption2:
82
- addMe = option1
83
- else:
84
- addMe = option2
79
+ option1 = ImaRange
80
+ option1AsStr = ImaRangeAsStr
81
+ option2 = ImaSerious
82
+ option2AsStr = None
85
83
 
86
- cache_consecutiveGroup_addMe[consecutiveGroup] = addMe
84
+ # alpha, potential function
85
+ option1AsStr = option1AsStr or removeExtraWhitespace(str(option1))
86
+ lengthOption1 = getLengthOption(option1AsStr)
87
87
 
88
- arraySliceAsList += addMe
88
+ option2AsStr = option2AsStr or removeExtraWhitespace(str(option2))
89
+ lengthOption2 = getLengthOption(option2AsStr)
89
90
 
90
- listRangeAndTuple: list[int | range | tuple[int | range, int]] = []
91
- cache_malkovichGrouped_addMe: dict[tuple[int | range, int], list[tuple[int | range, int]] | list[int | range]] = {}
92
- for malkovichGrouped in more_itertools.run_length.encode(arraySliceAsList):
93
- if malkovichGrouped in cache_malkovichGrouped_addMe:
94
- addMe = cache_malkovichGrouped_addMe[malkovichGrouped]
91
+ if lengthOption1 < lengthOption2:
92
+ addMe = option1
95
93
  else:
96
- lengthMalkovich = malkovichGrouped[-1]
97
- malkovichAsList = list(more_itertools.run_length.decode([malkovichGrouped]))
98
- malkovichMalkovich = f"[{malkovichGrouped[0]}]*{lengthMalkovich}"
94
+ addMe = option2
99
95
 
100
- option1 = [malkovichGrouped]
101
- option1AsStr = malkovichMalkovich
102
- option2 = malkovichAsList
103
- option2AsStr = None
96
+ cache_consecutiveGroup_addMe[consecutiveGroup] = addMe
104
97
 
105
- # beta, potential function
106
- option1AsStr = option1AsStr or python_minifier.minify(str(option1))
107
- lengthOption1 = getLengthOption(option1AsStr)
98
+ arraySliceAsList += addMe
108
99
 
109
- option2AsStr = option2AsStr or python_minifier.minify(str(option2))
110
- lengthOption2 = getLengthOption(option2AsStr)
100
+ listRangeAndTuple: list[int | range | tuple[int | range, int]] = []
101
+ cache_malkovichGrouped_addMe: dict[tuple[int | range, int], list[tuple[int | range, int]] | list[int | range]] = {}
102
+ for malkovichGrouped in more_itertools.run_length.encode(arraySliceAsList):
103
+ if malkovichGrouped in cache_malkovichGrouped_addMe:
104
+ addMe = cache_malkovichGrouped_addMe[malkovichGrouped]
105
+ else:
106
+ lengthMalkovich = malkovichGrouped[-1]
107
+ malkovichAsList = list(more_itertools.run_length.decode([malkovichGrouped]))
108
+ malkovichMalkovich = f"[{malkovichGrouped[0]}]*{lengthMalkovich}"
111
109
 
112
- if lengthOption1 < lengthOption2:
113
- addMe = option1
114
- else:
115
- addMe = option2
110
+ option1 = [malkovichGrouped]
111
+ option1AsStr = malkovichMalkovich
112
+ option2 = malkovichAsList
113
+ option2AsStr = None
114
+
115
+ # beta, potential function
116
+ option1AsStr = option1AsStr or removeExtraWhitespace(str(option1))
117
+ lengthOption1 = getLengthOption(option1AsStr)
118
+
119
+ option2AsStr = option2AsStr or removeExtraWhitespace(str(option2))
120
+ lengthOption2 = getLengthOption(option2AsStr)
121
+
122
+ if lengthOption1 < lengthOption2:
123
+ addMe = option1
124
+ else:
125
+ addMe = option2
116
126
 
117
- cache_malkovichGrouped_addMe[malkovichGrouped] = addMe
127
+ cache_malkovichGrouped_addMe[malkovichGrouped] = addMe
118
128
 
119
- listRangeAndTuple += addMe
129
+ listRangeAndTuple += addMe
120
130
 
121
- return listRangeAndTuple
122
- return arraySlice
131
+ return listRangeAndTuple
132
+ return arraySlice
123
133
 
124
- arrayAsNestedLists = sliceNDArrayToNestedLists(arrayTarget)
134
+ arrayAsNestedLists = sliceNDArrayToNestedLists(arrayTarget)
125
135
 
126
- arrayAsStr = python_minifier.minify(str(arrayAsNestedLists))
136
+ arrayAsStr = removeExtraWhitespace(str(arrayAsNestedLists))
127
137
 
128
- patternRegex = regex.compile(
129
- "(?<!rang)(?:"
130
- # Pattern 1: Comma ahead, bracket behind # noqa: ERA001
131
- "(?P<joinAhead>,)\\((?P<malkovich>\\d+),(?P<multiply>\\d+)\\)(?P<bracketBehind>])|"
132
- # Pattern 2: Bracket or start ahead, comma behind # noqa: ERA001
133
- "(?P<bracketOrStartAhead>\\[|^.)\\((?P<malkovichMalkovich>\\d+),(?P<multiplyIDK>\\d+)\\)(?P<joinBehind>,)|"
134
- # Pattern 3: Bracket ahead, bracket behind # noqa: ERA001
135
- "(?P<bracketAhead>\\[)\\((?P<malkovichMalkovichMalkovich>\\d+),(?P<multiply_whatever>\\d+)\\)(?P<bracketBehindBracketBehind>])|"
136
- # Pattern 4: Comma ahead, comma behind # noqa: ERA001
137
- "(?P<joinAheadJoinAhead>,)\\((?P<malkovichMalkovichMalkovichMalkovich>\\d+),(?P<multiplyOrSomething>\\d+)\\)(?P<joinBehindJoinBehind>,)"
138
- ")"
139
- )
138
+ patternRegex = regex.compile(
139
+ "(?<!rang)(?:"
140
+ # Pattern 1: Comma ahead, bracket behind # noqa: ERA001
141
+ "(?P<joinAhead>,)\\((?P<malkovich>\\d+),(?P<multiply>\\d+)\\)(?P<bracketBehind>])|"
142
+ # Pattern 2: Bracket or start ahead, comma behind # noqa: ERA001
143
+ "(?P<bracketOrStartAhead>\\[|^.)\\((?P<malkovichMalkovich>\\d+),(?P<multiplyIDK>\\d+)\\)(?P<joinBehind>,)|"
144
+ # Pattern 3: Bracket ahead, bracket behind # noqa: ERA001
145
+ "(?P<bracketAhead>\\[)\\((?P<malkovichMalkovichMalkovich>\\d+),(?P<multiply_whatever>\\d+)\\)(?P<bracketBehindBracketBehind>])|"
146
+ # Pattern 4: Comma ahead, comma behind # noqa: ERA001
147
+ "(?P<joinAheadJoinAhead>,)\\((?P<malkovichMalkovichMalkovichMalkovich>\\d+),(?P<multiplyOrSomething>\\d+)\\)(?P<joinBehindJoinBehind>,)"
148
+ ")"
149
+ )
140
150
 
141
- def replacementByContext(match: regex.Match[str]) -> str:
142
- """Generate replacement string based on context patterns."""
143
- elephino = match.groupdict()
144
- joinAhead = elephino.get('joinAhead') or elephino.get('joinAheadJoinAhead')
145
- malkovich = elephino.get('malkovich') or elephino.get('malkovichMalkovich') or elephino.get('malkovichMalkovichMalkovich') or elephino.get('malkovichMalkovichMalkovichMalkovich')
146
- multiply = elephino.get('multiply') or elephino.get('multiplyIDK') or elephino.get('multiply_whatever') or elephino.get('multiplyOrSomething')
147
- joinBehind = elephino.get('joinBehind') or elephino.get('joinBehindJoinBehind')
151
+ def replacementByContext(match: regex.Match[str]) -> str:
152
+ """Generate replacement string based on context patterns."""
153
+ elephino = match.groupdict()
154
+ joinAhead = elephino.get('joinAhead') or elephino.get('joinAheadJoinAhead')
155
+ malkovich = elephino.get('malkovich') or elephino.get('malkovichMalkovich') or elephino.get('malkovichMalkovichMalkovich') or elephino.get('malkovichMalkovichMalkovichMalkovich')
156
+ multiply = elephino.get('multiply') or elephino.get('multiplyIDK') or elephino.get('multiply_whatever') or elephino.get('multiplyOrSomething')
157
+ joinBehind = elephino.get('joinBehind') or elephino.get('joinBehindJoinBehind')
148
158
 
149
- replaceAhead = "]+[" if joinAhead == "," else "["
159
+ replaceAhead = "]+[" if joinAhead == "," else "["
150
160
 
151
- replaceBehind = "+[" if joinBehind == "," else ""
161
+ replaceBehind = "+[" if joinBehind == "," else ""
152
162
 
153
- return f"{replaceAhead}{malkovich}]*{multiply}{replaceBehind}"
163
+ return f"{replaceAhead}{malkovich}]*{multiply}{replaceBehind}"
154
164
 
155
- arrayAsStr = patternRegex.sub(replacementByContext, arrayAsStr)
156
- arrayAsStr = patternRegex.sub(replacementByContext, arrayAsStr)
165
+ arrayAsStr = patternRegex.sub(replacementByContext, arrayAsStr)
166
+ arrayAsStr = patternRegex.sub(replacementByContext, arrayAsStr)
157
167
 
158
- # Replace `range(0,stop)` syntax with `range(stop)` syntax. # noqa: ERA001
159
- # Add unpack operator `*` for automatic decoding when evaluated.
160
- return arrayAsStr.replace('range(0,', 'range(').replace('range', '*range')
168
+ # Replace `range(0,stop)` syntax with `range(stop)` syntax. # noqa: ERA001
169
+ # Add unpack operator `*` for automatic decoding when evaluated.
170
+ return arrayAsStr.replace('range(0,', 'range(').replace('range', '*range')
161
171
 
162
- def stringItUp(*scrapPile: Any) -> list[str]: # noqa: C901
172
+ def stringItUp(*scrapPile: Any) -> list[str]:
163
173
  """Convert, if possible, every element in the input data structure to a string.
164
174
 
165
175
  Order is not preserved or readily predictable.
@@ -178,7 +188,7 @@ def stringItUp(*scrapPile: Any) -> list[str]: # noqa: C901
178
188
  scrap = None
179
189
  listStrungUp: list[str] = []
180
190
 
181
- def drill(KitKat: Any) -> None: # noqa: C901, PLR0912
191
+ def drill(KitKat: Any) -> None:
182
192
  match KitKat:
183
193
  case str():
184
194
  listStrungUp.append(KitKat)
@@ -204,7 +214,7 @@ def stringItUp(*scrapPile: Any) -> list[str]: # noqa: C901
204
214
  except TypeError: # "The error traceback provided indicates that there is an issue when calling the __str__ method on an object that does not have this method properly defined, leading to a TypeError."
205
215
  pass
206
216
  except:
207
- print(f"\nWoah! I received '{repr(KitKat)}'.\nTheir report card says, 'Plays well with others: Needs improvement.'\n") # noqa: RUF010, T201
217
+ print(f"\nWoah! I received '{repr(KitKat)}'.\nTheir report card says, 'Plays well with others: Needs improvement.'\n") # noqa: T201
208
218
  raise
209
219
  try:
210
220
  for scrap in scrapPile:
@@ -75,7 +75,7 @@ def _constructErrorMessage(context: ErrorMessageContext, parameterName: str, par
75
75
 
76
76
  return "".join(messageParts)
77
77
 
78
- def defineConcurrencyLimit(*, limit: bool | float | int | None, cpuTotal: int = multiprocessing.cpu_count()) -> int: # noqa: C901, PYI041
78
+ def defineConcurrencyLimit(*, limit: bool | float | int | None, cpuTotal: int = multiprocessing.cpu_count()) -> int:
79
79
  """Determine the concurrency limit based on the provided parameter.
80
80
 
81
81
  Tests for this function can be run with:
@@ -84,8 +84,7 @@ def defineConcurrencyLimit(*, limit: bool | float | int | None, cpuTotal: int =
84
84
  Parameters
85
85
  ----------
86
86
  limit : bool | float | int | None
87
- Whether and how to limit CPU usage. Accepts `True`/`False`, an integer count, or a fraction of total CPUs. Positive and
88
- negative values have different behaviors, see code for details.
87
+ Whether and how to limit CPU usage. See notes and examples for details how to describe the options to your users.
89
88
  cpuTotal : int = multiprocessing.cpu_count()
90
89
  The total number of CPUs available in the system. Default is `multiprocessing.cpu_count()`.
91
90
 
@@ -96,35 +95,40 @@ def defineConcurrencyLimit(*, limit: bool | float | int | None, cpuTotal: int =
96
95
 
97
96
  Notes
98
97
  -----
99
- If you want to be extra nice to your users, consider using `hunterMakesPy.oopsieKwargsie()` to handle malformed inputs. For
100
- example:
98
+ Consider using `hunterMakesPy.oopsieKwargsie()` to handle malformed inputs. For example:
101
99
 
102
100
  ```
103
101
  if not (CPUlimit is None or isinstance(CPUlimit, (bool, int, float))):
104
102
  CPUlimit = oopsieKwargsie(CPUlimit)
105
103
  ```
106
104
 
107
- Examples
108
- --------
109
- Example parameters:
110
- CPUlimit: bool | float | int | None
111
- CPUlimit: bool | float | int | None = None
105
+ Example parameters
106
+ ------------------
107
+ ```python
108
+ CPUlimit: bool | float | int | None
109
+ CPUlimit: bool | float | int | None = None
110
+ ```
112
111
 
113
- Example docstring:
114
- ```python
112
+ Example docstring
113
+ -----------------
114
+ ```python
115
115
 
116
- Arguments:
117
- CPUlimit: bool | float | int | None
118
- whether and how to limit the CPU usage. See notes for details.
116
+ Arguments
117
+ ---------
118
+ CPUlimit: bool | float | int | None
119
+ Whether and how to limit the the number of available processors used by the function. See notes for details.
119
120
 
120
- Limits on CPU usage `CPUlimit`:
121
- - `False`, `None`, or `0`: No limits on CPU usage; uses all available CPUs. All other values will potentially limit CPU usage.
122
- - `True`: Yes, limit the CPU usage; limits to 1 CPU.
123
- - Integer `>= 1`: Limits usage to the specified number of CPUs.
124
- - Decimal value (`float`) between 0 and 1: Fraction of total CPUs to use.
125
- - Decimal value (`float`) between -1 and 0: Fraction of CPUs to *not* use.
126
- - Integer `<= -1`: Subtract the absolute value from total CPUs.
127
- ```
121
+ Notes
122
+ -----
123
+ Limits on CPU usage, `CPUlimit`:
124
+ - `False`, `None`, or `0`: No limits on processor usage; uses all available processors. All other values will potentially limit processor usage.
125
+ - `True`: Yes, limit the processor usage; limits to 1 processor.
126
+ - `int >= 1`: The maximum number of available processors to use.
127
+ - `0 < float < 1`: The maximum number of processors to use expressed as a fraction of available processors.
128
+ - `-1 < float < 0`: The number of processors to *not* use expressed as a fraction of available processors.
129
+ - `int <= -1`: The number of available processors to *not* use.
130
+ - If the value of `CPUlimit` is a `float` greater than 1 or less than -1, the function truncates the value to an `int` with the same sign as the `float`.
131
+ ```
128
132
 
129
133
  """
130
134
  concurrencyLimit = cpuTotal
@@ -160,7 +164,7 @@ def defineConcurrencyLimit(*, limit: bool | float | int | None, cpuTotal: int =
160
164
  return max(int(concurrencyLimit), 1)
161
165
 
162
166
  # ruff: noqa: TRY301
163
- def intInnit(listInt_Allegedly: Iterable[Any], parameterName: str | None = None, parameterType: type[Any] | None = None) -> list[int]: # noqa: C901, PLR0912, PLR0915
167
+ def intInnit(listInt_Allegedly: Iterable[Any], parameterName: str | None = None, parameterType: type[Any] | None = None) -> list[int]:
164
168
  """Validate and convert input values to a `list` of integers.
165
169
 
166
170
  Accepts various numeric types and attempts to convert them into integers while providing descriptive error messages. This
@@ -2,7 +2,7 @@
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 stringItUp, updateExtendPolishDictionaryLists
5
+ from hunterMakesPy import autoDecodingRLE, stringItUp, updateExtendPolishDictionaryLists
6
6
  from hunterMakesPy.tests.conftest import standardizedEqualTo
7
7
  from numpy.typing import NDArray
8
8
  from typing import Any, Literal
@@ -11,9 +11,6 @@ import numpy
11
11
  import pytest
12
12
  import sys
13
13
 
14
- if sys.version_info < (3, 14):
15
- from hunterMakesPy import autoDecodingRLE
16
-
17
14
  class CustomIterable:
18
15
  def __init__(self, items: Iterable[Any]) -> None: self.items = items
19
16
  def __iter__(self) -> Iterator[Any]: return iter(self.items)
@@ -99,27 +96,26 @@ def testUpdateExtendPolishDictionaryLists(description: str, value_dictionaryList
99
96
 
100
97
  # ruff: noqa: RUF005
101
98
 
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)
99
+ @pytest.mark.parametrize("description,value_arrayTarget,expected", [
100
+ ("One range", numpy.array(list(range(50,60))), "[*range(50,60)]"),
101
+ ("Value, range", numpy.array([123]+list(range(71,81))), "[123,*range(71,81)]"),
102
+ ("range, value", numpy.array(list(range(91,97))+[101]), "[*range(91,97),101]"),
103
+ ("Value, range, value", numpy.array([151]+list(range(163,171))+[181]), "[151,*range(163,171),181]"),
104
+ ("Repeat values", numpy.array([191, 191, 191]), "[191]*3"),
105
+ ("Value with repeat", numpy.array([211, 223, 223, 223]), "[211]+[223]*3"),
106
+ ("Range with repeat", numpy.array(list(range(251,257))+[271, 271, 271]), "[*range(251,257)]+[271]*3"),
107
+ ("Value, range, repeat", numpy.array([281]+list(range(291,297))+[307, 307]), "[281,*range(291,297)]+[307]*2"),
108
+ ("repeat, value", numpy.array([313, 313, 313, 331, 331, 349]), "[313]*3+[331]*2+[349]"),
109
+ ("repeat, range", numpy.array([373, 373, 373]+list(range(383,389))), "[373]*3+[*range(383,389)]"),
110
+ ("repeat, range, value", numpy.array(7*[401]+list(range(409,415))+[421]), "[401]*7+[*range(409,415),421]"),
111
+ ("Repeated primes", numpy.array([431, 431, 431, 443, 443, 457]), "[431]*3+[443]*2+[457]"),
112
+ ("Two Ranges", numpy.array(list(range(461,471))+list(range(479,487))), "[*range(461,471),*range(479,487)]"),
113
+ ("2D array primes", numpy.array([[491, 499, 503], [509, 521, 523]]), "[[491,499,503],[509,521,523]]"),
114
+ ("3D array primes", numpy.array([[[541, 547], [557, 563]], [[569, 571], [577, 587]]]), "[[[541,547],[557,563]],[[569,571],[577,587]]]"),
115
+ ], ids=lambda x: x if isinstance(x, str) else "")
116
+ def testAutoDecodingRLE(description: str, value_arrayTarget: NDArray[numpy.integer[Any]], expected: str) -> None:
117
+ """Test autoDecodingRLE with various input arrays."""
118
+ standardizedEqualTo(expected, autoDecodingRLE, value_arrayTarget)
123
119
 
124
120
  # Helper functions for generating RLE test data
125
121
  def generateCartesianMapping(dimensions: tuple[int, int], formula: Callable[[int, int], int]) -> NDArray[Any]:
@@ -228,98 +224,97 @@ def generateAlternatingColumns(dimensions: tuple[int, int], blockSize: int = 1)
228
224
 
229
225
  return generateCartesianMapping(dimensions, columnFormula)
230
226
 
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})"
227
+ @pytest.mark.parametrize("description,value_arrayTarget", [
228
+ # Basic test cases with simple patterns
229
+ ("Simple range", numpy.array(list(range(50,60)))),
230
+
231
+ # Chessboard patterns
232
+ ("Small chessboard", generateChessboard((8, 8))),
233
+
234
+ # Alternating columns - creates patterns with good RLE opportunities
235
+ ("Alternating columns", generateAlternatingColumns((5, 20), 2)),
236
+
237
+ # Step pattern - creates horizontal runs
238
+ ("Step pattern", generateStepPattern((6, 30), 3)),
239
+
240
+ # Repeating zones - creates horizontal bands
241
+ ("Repeating zones", generateRepeatingZones((40, 40), 8)),
242
+
243
+ # Tile pattern - creates complex repeating regions
244
+ ("Tile pattern", generateTilePattern((15, 15), 5)),
245
+
246
+ # Signed quadratic function - includes negative values
247
+ ("Signed quadratic", generateSignedQuadraticFunction((10, 10))),
248
+
249
+ # Prime modulo matrix - periodic patterns
250
+ ("Prime modulo", generatePrimeModuloMatrix((12, 12), 7)),
251
+
252
+ # Wave pattern - smooth gradients
253
+ ("Wave pattern", generateWavePattern((20, 20))),
254
+
255
+ # Spiral pattern - complex pattern with good RLE potential
256
+ ("Spiral pattern", generateSpiralPattern((15, 15), 2)),
257
+ ], ids=lambda x: x if isinstance(x, str) else "")
258
+ def testAutoDecodingRLEWithRealisticData(description: str, value_arrayTarget: NDArray[numpy.integer[Any]]) -> None:
259
+ """Test autoDecodingRLE with more realistic data patterns."""
260
+ # Here we test the function behavior rather than expected string output
261
+ resultRLE = autoDecodingRLE(value_arrayTarget)
262
+
263
+ # Test that the result is a valid string
264
+ assert isinstance(resultRLE, str)
265
+
266
+ # Test that the result contains the expected syntax elements
267
+ assert "[" in resultRLE, f"Result should contain list syntax: {resultRLE}"
268
+ assert "]" in resultRLE, f"Result should contain list syntax: {resultRLE}"
269
+
270
+ # Check that the result is more compact than the raw string representation
271
+ rawStrLength = len(str(value_arrayTarget.tolist()))
272
+ encodedLength = len(resultRLE)
273
+ assert encodedLength <= rawStrLength, f"Encoded string ({encodedLength}) should be shorter than raw string ({rawStrLength})"
274
+
275
+ @pytest.mark.parametrize("description,addSpaces", [
276
+ ("With spaces", True),
277
+ ("Without spaces", False),
278
+ ], ids=lambda x: x if isinstance(x, str) else "")
279
+ def testAutoDecodingRLEWithSpaces(description: str, addSpaces: bool) -> None:
280
+ """Test that the addSpaces parameter affects the internal comparison logic.
281
+
282
+ Note: addSpaces doesn't directly change the output format, it just changes
283
+ the comparison when measuring the length of the string representation.
284
+ The feature exists because `ast` inserts spaces in its string representation.
285
+ """
286
+ # Create a pattern that has repeated sequences to trigger the RLE logic
287
+ arrayTarget = generateRepeatingZones((10, 10), 2)
288
+
289
+ # Test both configurations
290
+ resultWithSpacesFlag = autoDecodingRLE(arrayTarget, assumeAddSpaces=addSpaces)
291
+ resultNoSpacesFlag = autoDecodingRLE(arrayTarget, assumeAddSpaces=False)
292
+
293
+ # When addSpaces=True, the internal length comparisons change
294
+ # but the actual output format doesn't necessarily differ
295
+ # Just verify the function runs without errors in both cases
296
+ assert isinstance(resultWithSpacesFlag, str)
297
+ assert isinstance(resultNoSpacesFlag, str)
298
+
299
+ def testAutoDecodingRLELargeCartesianMapping() -> None:
300
+ """Test autoDecodingRLE with a large (100x100) cartesian mapping."""
301
+ dimensions = (100, 100)
302
+
303
+ # Generate a large cartesian mapping with a complex pattern
304
+ def complexFormula(x: int, y: int) -> int:
305
+ return ((x * 17) % 11 + (y * 13) % 7) % 10
306
+
307
+ arrayMapping = generateCartesianMapping(dimensions, complexFormula)
308
+
309
+ # Verify the function works with large arrays
310
+ resultRLE = autoDecodingRLE(arrayMapping)
311
+
312
+ # The result should be a valid string representation
313
+ assert isinstance(resultRLE, str)
314
+ assert "[" in resultRLE
315
+ assert "]" in resultRLE
316
+
317
+ # The RLE encoding should be more compact than the raw representation
318
+ rawStrLength = len(str(arrayMapping.tolist()))
319
+ encodedLength = len(resultRLE)
320
+ assert encodedLength <= rawStrLength, f"RLE encoded string ({encodedLength}) should be shorter than raw string ({rawStrLength})"
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hunterMakesPy
3
- Version: 0.2.1
3
+ Version: 0.2.4
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
7
7
  Project-URL: Donate, https://www.patreon.com/integrated
8
- Project-URL: Homepage, https://github.com/hunterhogan/
9
- Project-URL: Issues, https://github.com/hunterhogan/
10
- Project-URL: Repository, https://github.com/hunterhogan/
8
+ Project-URL: Homepage, https://github.com/hunterhogan/hunterMakesPy
9
+ Project-URL: Issues, https://github.com/hunterhogan/hunterMakesPy/issues
10
+ Project-URL: Repository, https://github.com/hunterhogan/hunterMakesPy
11
11
  Keywords: attribute loading,concurrency limit,configuration,defensive programming,dictionary merging,directory creation,dynamic import,error propagation,file system utilities,input validation,integer parsing,module loading,nested data structures,package settings,parameter validation,pytest,string extraction,test utilities
12
12
  Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Environment :: Console
@@ -33,7 +33,6 @@ License-File: LICENSE
33
33
  Requires-Dist: charset_normalizer
34
34
  Requires-Dist: more_itertools
35
35
  Requires-Dist: numpy
36
- Requires-Dist: python_minifier; python_version < "3.14"
37
36
  Provides-Extra: development
38
37
  Requires-Dist: mypy; extra == "development"
39
38
  Requires-Dist: pyupgrade; extra == "development"
@@ -174,4 +173,4 @@ Coding One Step at a Time:
174
173
  2. Write good code.
175
174
  3. When revising, write better code.
176
175
 
177
- [![CC-BY-NC-4.0](https://github.com/hunterhogan/hunterMakesPy/blob/main/CC-BY-NC-4.0.svg)](https://creativecommons.org/licenses/by-nc/4.0/)
176
+ [![CC-BY-NC-4.0](https://github.com/hunterhogan/hunterMakesPy/blob/main/CC-BY-NC-4.0.png)](https://creativecommons.org/licenses/by-nc/4.0/)
@@ -1,20 +1,20 @@
1
1
  hunterMakesPy/__init__.py,sha256=bVF1F2Mdo5AOiioEfxKvNrnsa3vCFI16eMK7Oy5O5TU,1450
2
2
  hunterMakesPy/_theSSOT.py,sha256=lkLOG3oTIWNKD_ULX55chlUGNqCHgqVIrBvolvK1vbQ,153
3
- hunterMakesPy/coping.py,sha256=covqNFAwkF9gjafrlAvMdtCO8haFsESQBhO-7s68qSg,5581
4
- hunterMakesPy/dataStructures.py,sha256=CFyGjmAOoN2MoEPwWwWdwKNXmOXX8kCS3ttMOa2Rsx0,11379
3
+ hunterMakesPy/coping.py,sha256=7NBwaGutEr6Q-2mIz65M69NkrbpG24u1I5HXx6VaAWI,6057
4
+ hunterMakesPy/dataStructures.py,sha256=7CxCBpQmHJzGxTq_AfkAeh2QdJDkzBr5lfSpPaA1GkE,11722
5
5
  hunterMakesPy/filesystemToolkit.py,sha256=jd7H5UtrIrPiCYWcvNBNa6DAy-2Ewcf21-jbGXg_IVI,4702
6
- hunterMakesPy/parseParameters.py,sha256=DXpyATx7trGBg_8jlO5dXGfLcG8vg_lU3R1sq1rRFOQ,11644
6
+ hunterMakesPy/parseParameters.py,sha256=1mwGNVIZ1x23k_di3lhOhQb8QMXMUCHgt7xw3NRzDXs,11814
7
7
  hunterMakesPy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  hunterMakesPy/pytestForYourUse.py,sha256=GiN1C1gTTM0ZunRPEMnrKlLQLMdH0wF_ZGr_RPgRjjA,500
9
9
  hunterMakesPy/theTypes.py,sha256=C2d0uLn1VIx6_2CK41it3IP7iplSQqe51tzWc-RT320,306
10
10
  hunterMakesPy/tests/__init__.py,sha256=C_FzfKDi_VrGVxlenWHyOYtKShAKlt3KW14jeRx1mQI,224
11
11
  hunterMakesPy/tests/conftest.py,sha256=NZQPRiwvGhP16hJ6WGGm9eKLxfQArYV8E9X12YzSpP0,2827
12
12
  hunterMakesPy/tests/test_coping.py,sha256=mH89TUAL6fJanBLlhdVlCNNQqm5OpdcQMP_p5W2JJwo,9860
13
- hunterMakesPy/tests/test_dataStructures.py,sha256=O4aqzSKg7KfWWVhIewOH0Y8Zj28PbFCb4XX3xhwuFQA,16605
13
+ hunterMakesPy/tests/test_dataStructures.py,sha256=OouddHjN-Km26U92jYwnjYeP6_Y2DrJLgq3qD_8GvGw,16393
14
14
  hunterMakesPy/tests/test_filesystemToolkit.py,sha256=q2voXjCbQPIT8l8VF9iuWX1Bs2ZieABItWoVkITj_fo,8841
15
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,,
16
+ huntermakespy-0.2.4.dist-info/licenses/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
17
+ huntermakespy-0.2.4.dist-info/METADATA,sha256=UeGvfHoO_DMo_K5yy8daea6K7Ska8X6hHbC7MuCh7p8,6491
18
+ huntermakespy-0.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
+ huntermakespy-0.2.4.dist-info/top_level.txt,sha256=Uh4bj8EDTdsRpqY1VlK_his_B4HDfZ6Tqrwhoj75P_w,14
20
+ huntermakespy-0.2.4.dist-info/RECORD,,