hunterMakesPy 0.1.2__tar.gz → 0.2.1__tar.gz
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-0.1.2 → huntermakespy-0.2.1}/PKG-INFO +24 -27
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/README.md +21 -25
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy/__init__.py +7 -2
- huntermakespy-0.2.1/hunterMakesPy/dataStructures.py +268 -0
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy/filesystemToolkit.py +17 -9
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy/parseParameters.py +29 -29
- huntermakespy-0.2.1/hunterMakesPy/pytestForYourUse.py +10 -0
- huntermakespy-0.2.1/hunterMakesPy/tests/__init__.py +5 -0
- {huntermakespy-0.1.2 → huntermakespy-0.2.1/hunterMakesPy}/tests/conftest.py +32 -2
- {huntermakespy-0.1.2 → huntermakespy-0.2.1/hunterMakesPy}/tests/test_coping.py +1 -1
- {huntermakespy-0.1.2 → huntermakespy-0.2.1/hunterMakesPy}/tests/test_dataStructures.py +124 -118
- huntermakespy-0.2.1/hunterMakesPy/tests/test_filesystemToolkit.py +263 -0
- huntermakespy-0.1.2/hunterMakesPy/pytestForYourUse.py → huntermakespy-0.2.1/hunterMakesPy/tests/test_parseParameters.py +17 -5
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy.egg-info/PKG-INFO +24 -27
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy.egg-info/SOURCES.txt +6 -6
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy.egg-info/requires.txt +2 -0
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy.egg-info/top_level.txt +0 -1
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/pyproject.toml +6 -4
- huntermakespy-0.1.2/hunterMakesPy/dataStructures.py +0 -265
- huntermakespy-0.1.2/tests/__init__.py +0 -0
- huntermakespy-0.1.2/tests/test_filesystemToolkit.py +0 -43
- huntermakespy-0.1.2/tests/test_parseParameters.py +0 -21
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/LICENSE +0 -0
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy/_theSSOT.py +0 -0
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy/coping.py +0 -0
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy/py.typed +0 -0
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy/theTypes.py +0 -0
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/hunterMakesPy.egg-info/dependency_links.txt +0 -0
- {huntermakespy-0.1.2 → huntermakespy-0.2.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hunterMakesPy
|
|
3
|
-
Version: 0.1
|
|
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'
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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": ["
|
|
135
|
-
dictionaryBeta = {"servers": ["
|
|
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.
|
|
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(
|
|
161
|
-
|
|
156
|
+
@pytest.mark.parametrize(
|
|
157
|
+
"nameOfTest,callablePytest"
|
|
158
|
+
, PytestFor_intInnit(callableToTest=myFunction))
|
|
162
159
|
def test_myFunction(nameOfTest, callablePytest):
|
|
163
160
|
callablePytest()
|
|
164
161
|
```
|
|
@@ -28,7 +28,7 @@ def findConfiguration(configName: str) -> dict[str, str] | None:
|
|
|
28
28
|
|
|
29
29
|
config = raiseIfNone(
|
|
30
30
|
findConfiguration("database"),
|
|
31
|
-
"Configuration 'database'
|
|
31
|
+
"I could not find Configuration 'database', but I need it to continue."
|
|
32
32
|
)
|
|
33
33
|
```
|
|
34
34
|
|
|
@@ -37,19 +37,19 @@ config = raiseIfNone(
|
|
|
37
37
|
Parameter validation, integer parsing, and concurrency handling.
|
|
38
38
|
|
|
39
39
|
```python
|
|
40
|
-
|
|
40
|
+
import hunterMakesPy as humpy
|
|
41
41
|
|
|
42
42
|
# Smart concurrency limit calculation
|
|
43
|
-
cpuLimit = defineConcurrencyLimit(limit=0.75) # Use 75% of available CPUs
|
|
44
|
-
cpuLimit = defineConcurrencyLimit(limit=True) # Use exactly 1 CPU
|
|
45
|
-
cpuLimit = defineConcurrencyLimit(limit=4) # Use exactly 4 CPUs
|
|
43
|
+
cpuLimit = humpy.defineConcurrencyLimit(limit=0.75) # Use 75% of available CPUs
|
|
44
|
+
cpuLimit = humpy.defineConcurrencyLimit(limit=True) # Use exactly 1 CPU
|
|
45
|
+
cpuLimit = humpy.defineConcurrencyLimit(limit=4) # Use exactly 4 CPUs
|
|
46
46
|
|
|
47
47
|
# Robust integer validation
|
|
48
|
-
validatedIntegers = intInnit([1, "2", 3.0, "4"], "port_numbers")
|
|
48
|
+
validatedIntegers = humpy.intInnit([1, "2", 3.0, "4"], "port_numbers")
|
|
49
49
|
|
|
50
50
|
# String-to-boolean conversion for configuration
|
|
51
51
|
userInput = "True"
|
|
52
|
-
booleanValue = oopsieKwargsie(userInput) # Returns True
|
|
52
|
+
booleanValue = humpy.oopsieKwargsie(userInput) # Returns True
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
## File System Utilities
|
|
@@ -57,20 +57,15 @@ booleanValue = oopsieKwargsie(userInput) # Returns True
|
|
|
57
57
|
Safe file operations and dynamic module importing.
|
|
58
58
|
|
|
59
59
|
```python
|
|
60
|
-
|
|
61
|
-
importLogicalPath2Identifier,
|
|
62
|
-
importPathFilename2Identifier,
|
|
63
|
-
makeDirsSafely,
|
|
64
|
-
writeStringToHere
|
|
65
|
-
)
|
|
60
|
+
import hunterMakesPy as humpy
|
|
66
61
|
|
|
67
62
|
# Dynamic imports
|
|
68
|
-
gcdFunction = importLogicalPath2Identifier("math", "gcd")
|
|
69
|
-
customFunction = importPathFilename2Identifier("path/to/module.py", "functionName")
|
|
63
|
+
gcdFunction = humpy.importLogicalPath2Identifier("math", "gcd")
|
|
64
|
+
customFunction = humpy.importPathFilename2Identifier("path/to/module.py", "functionName")
|
|
70
65
|
|
|
71
66
|
# Safe file operations
|
|
72
67
|
pathFilename = Path("deep/nested/directory/file.txt")
|
|
73
|
-
writeStringToHere("content", pathFilename) # Creates directories automatically
|
|
68
|
+
humpy.writeStringToHere("content", pathFilename) # Creates directories automatically
|
|
74
69
|
```
|
|
75
70
|
|
|
76
71
|
## Data Structure Manipulation
|
|
@@ -78,21 +73,21 @@ writeStringToHere("content", pathFilename) # Creates directories automatically
|
|
|
78
73
|
Utilities for string extraction, data flattening, and array compression.
|
|
79
74
|
|
|
80
75
|
```python
|
|
81
|
-
|
|
76
|
+
import hunterMakesPy as humpy
|
|
82
77
|
import numpy
|
|
83
78
|
|
|
84
79
|
# Extract all strings from nested data structures
|
|
85
80
|
nestedData = {"config": [1, "host", {"port": 8080}], "users": ["alice", "bob"]}
|
|
86
|
-
allStrings = stringItUp(nestedData) # ['config', 'host', 'port', 'users', 'alice', 'bob']
|
|
81
|
+
allStrings = humpy.stringItUp(nestedData) # ['config', 'host', 'port', 'users', 'alice', 'bob']
|
|
87
82
|
|
|
88
83
|
# Merge dictionaries containing lists
|
|
89
|
-
dictionaryAlpha = {"servers": ["
|
|
90
|
-
dictionaryBeta = {"servers": ["
|
|
91
|
-
merged = updateExtendPolishDictionaryLists(dictionaryAlpha, dictionaryBeta, destroyDuplicates=True)
|
|
84
|
+
dictionaryAlpha = {"servers": ["chicago", "tokyo"], "databases": ["elm"]}
|
|
85
|
+
dictionaryBeta = {"servers": ["mumbai"], "databases": ["oak", "cedar"]}
|
|
86
|
+
merged = humpy.updateExtendPolishDictionaryLists(dictionaryAlpha, dictionaryBeta, destroyDuplicates=True)
|
|
92
87
|
|
|
93
88
|
# Compress NumPy arrays with run-length encoding
|
|
94
89
|
arrayData = numpy.array([1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9])
|
|
95
|
-
compressed = autoDecodingRLE(arrayData) # "[1,*range(2,6)]+[5]*2+[*range(6,10)]"
|
|
90
|
+
compressed = humpy.autoDecodingRLE(arrayData) # "[1,*range(2,6)]+[5]*2+[*range(6,10)]"
|
|
96
91
|
```
|
|
97
92
|
|
|
98
93
|
## Testing
|
|
@@ -100,7 +95,7 @@ compressed = autoDecodingRLE(arrayData) # "[1,*range(2,6)]+[5]*2+[*range(6,10)]
|
|
|
100
95
|
The package includes comprehensive test suites that you can import and run:
|
|
101
96
|
|
|
102
97
|
```python
|
|
103
|
-
from hunterMakesPy.
|
|
98
|
+
from hunterMakesPy.tests.test_parseParameters import (
|
|
104
99
|
PytestFor_defineConcurrencyLimit,
|
|
105
100
|
PytestFor_intInnit,
|
|
106
101
|
PytestFor_oopsieKwargsie
|
|
@@ -112,8 +107,9 @@ for nameOfTest, callablePytest in listOfTests:
|
|
|
112
107
|
callablePytest()
|
|
113
108
|
|
|
114
109
|
# Or test your own compatible functions
|
|
115
|
-
@pytest.mark.parametrize(
|
|
116
|
-
|
|
110
|
+
@pytest.mark.parametrize(
|
|
111
|
+
"nameOfTest,callablePytest"
|
|
112
|
+
, PytestFor_intInnit(callableToTest=myFunction))
|
|
117
113
|
def test_myFunction(nameOfTest, callablePytest):
|
|
118
114
|
callablePytest()
|
|
119
115
|
```
|
|
@@ -7,6 +7,7 @@ This package provides:
|
|
|
7
7
|
- Utilities for string extraction from nested data structures and merging dictionaries of lists.
|
|
8
8
|
|
|
9
9
|
"""
|
|
10
|
+
# pyright: reportUnusedImport=false
|
|
10
11
|
from hunterMakesPy.theTypes import identifierDotAttribute as identifierDotAttribute
|
|
11
12
|
|
|
12
13
|
from hunterMakesPy.coping import PackageSettings as PackageSettings, raiseIfNone as raiseIfNone
|
|
@@ -18,7 +19,11 @@ from hunterMakesPy.filesystemToolkit import (importLogicalPath2Identifier as imp
|
|
|
18
19
|
importPathFilename2Identifier as importPathFilename2Identifier, makeDirsSafely as makeDirsSafely,
|
|
19
20
|
writeStringToHere as writeStringToHere)
|
|
20
21
|
|
|
21
|
-
from hunterMakesPy.dataStructures import
|
|
22
|
-
|
|
22
|
+
from hunterMakesPy.dataStructures import stringItUp as stringItUp, updateExtendPolishDictionaryLists as updateExtendPolishDictionaryLists
|
|
23
|
+
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
if sys.version_info < (3, 14):
|
|
27
|
+
from hunterMakesPy.dataStructures import autoDecodingRLE as autoDecodingRLE
|
|
23
28
|
|
|
24
29
|
from hunterMakesPy._theSSOT import settingsPackage
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""Provides utilities for string extraction from nested data structures and merges multiple dictionaries containing lists into one dictionary."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterator, Mapping
|
|
4
|
+
from numpy import integer
|
|
5
|
+
from numpy.typing import NDArray
|
|
6
|
+
from typing import Any
|
|
7
|
+
import more_itertools
|
|
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
|
+
|
|
69
|
+
option1 = ImaRange
|
|
70
|
+
option1AsStr = ImaRangeAsStr
|
|
71
|
+
option2 = ImaSerious
|
|
72
|
+
option2AsStr = None
|
|
73
|
+
|
|
74
|
+
# alpha, potential function
|
|
75
|
+
option1AsStr = option1AsStr or python_minifier.minify(str(option1))
|
|
76
|
+
lengthOption1 = getLengthOption(option1AsStr)
|
|
77
|
+
|
|
78
|
+
option2AsStr = option2AsStr or python_minifier.minify(str(option2))
|
|
79
|
+
lengthOption2 = getLengthOption(option2AsStr)
|
|
80
|
+
|
|
81
|
+
if lengthOption1 < lengthOption2:
|
|
82
|
+
addMe = option1
|
|
83
|
+
else:
|
|
84
|
+
addMe = option2
|
|
85
|
+
|
|
86
|
+
cache_consecutiveGroup_addMe[consecutiveGroup] = addMe
|
|
87
|
+
|
|
88
|
+
arraySliceAsList += addMe
|
|
89
|
+
|
|
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]
|
|
95
|
+
else:
|
|
96
|
+
lengthMalkovich = malkovichGrouped[-1]
|
|
97
|
+
malkovichAsList = list(more_itertools.run_length.decode([malkovichGrouped]))
|
|
98
|
+
malkovichMalkovich = f"[{malkovichGrouped[0]}]*{lengthMalkovich}"
|
|
99
|
+
|
|
100
|
+
option1 = [malkovichGrouped]
|
|
101
|
+
option1AsStr = malkovichMalkovich
|
|
102
|
+
option2 = malkovichAsList
|
|
103
|
+
option2AsStr = None
|
|
104
|
+
|
|
105
|
+
# beta, potential function
|
|
106
|
+
option1AsStr = option1AsStr or python_minifier.minify(str(option1))
|
|
107
|
+
lengthOption1 = getLengthOption(option1AsStr)
|
|
108
|
+
|
|
109
|
+
option2AsStr = option2AsStr or python_minifier.minify(str(option2))
|
|
110
|
+
lengthOption2 = getLengthOption(option2AsStr)
|
|
111
|
+
|
|
112
|
+
if lengthOption1 < lengthOption2:
|
|
113
|
+
addMe = option1
|
|
114
|
+
else:
|
|
115
|
+
addMe = option2
|
|
116
|
+
|
|
117
|
+
cache_malkovichGrouped_addMe[malkovichGrouped] = addMe
|
|
118
|
+
|
|
119
|
+
listRangeAndTuple += addMe
|
|
120
|
+
|
|
121
|
+
return listRangeAndTuple
|
|
122
|
+
return arraySlice
|
|
123
|
+
|
|
124
|
+
arrayAsNestedLists = sliceNDArrayToNestedLists(arrayTarget)
|
|
125
|
+
|
|
126
|
+
arrayAsStr = python_minifier.minify(str(arrayAsNestedLists))
|
|
127
|
+
|
|
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
|
+
)
|
|
140
|
+
|
|
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')
|
|
148
|
+
|
|
149
|
+
replaceAhead = "]+[" if joinAhead == "," else "["
|
|
150
|
+
|
|
151
|
+
replaceBehind = "+[" if joinBehind == "," else ""
|
|
152
|
+
|
|
153
|
+
return f"{replaceAhead}{malkovich}]*{multiply}{replaceBehind}"
|
|
154
|
+
|
|
155
|
+
arrayAsStr = patternRegex.sub(replacementByContext, arrayAsStr)
|
|
156
|
+
arrayAsStr = patternRegex.sub(replacementByContext, arrayAsStr)
|
|
157
|
+
|
|
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')
|
|
161
|
+
|
|
162
|
+
def stringItUp(*scrapPile: Any) -> list[str]: # noqa: C901
|
|
163
|
+
"""Convert, if possible, every element in the input data structure to a string.
|
|
164
|
+
|
|
165
|
+
Order is not preserved or readily predictable.
|
|
166
|
+
|
|
167
|
+
Parameters
|
|
168
|
+
----------
|
|
169
|
+
*scrapPile : Any
|
|
170
|
+
(scrap2pile) One or more data structures to unpack and convert to strings.
|
|
171
|
+
|
|
172
|
+
Returns
|
|
173
|
+
-------
|
|
174
|
+
listStrungUp : list[str]
|
|
175
|
+
(list2strung2up) A `list` of string versions of all convertible elements.
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
scrap = None
|
|
179
|
+
listStrungUp: list[str] = []
|
|
180
|
+
|
|
181
|
+
def drill(KitKat: Any) -> None: # noqa: C901, PLR0912
|
|
182
|
+
match KitKat:
|
|
183
|
+
case str():
|
|
184
|
+
listStrungUp.append(KitKat)
|
|
185
|
+
case bool() | bytearray() | bytes() | complex() | float() | int() | memoryview() | None:
|
|
186
|
+
listStrungUp.append(str(KitKat)) # pyright: ignore [reportUnknownArgumentType]
|
|
187
|
+
case dict():
|
|
188
|
+
for broken, piece in KitKat.items(): # pyright: ignore [reportUnknownVariableType]
|
|
189
|
+
drill(broken)
|
|
190
|
+
drill(piece)
|
|
191
|
+
case list() | tuple() | set() | frozenset() | range():
|
|
192
|
+
for kit in KitKat: # pyright: ignore [reportUnknownVariableType]
|
|
193
|
+
drill(kit)
|
|
194
|
+
case _:
|
|
195
|
+
if hasattr(KitKat, '__iter__'): # Unpack other iterables
|
|
196
|
+
for kat in KitKat:
|
|
197
|
+
drill(kat)
|
|
198
|
+
else:
|
|
199
|
+
try:
|
|
200
|
+
sharingIsCaring = KitKat.__str__()
|
|
201
|
+
listStrungUp.append(sharingIsCaring)
|
|
202
|
+
except AttributeError:
|
|
203
|
+
pass
|
|
204
|
+
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
|
+
pass
|
|
206
|
+
except:
|
|
207
|
+
print(f"\nWoah! I received '{repr(KitKat)}'.\nTheir report card says, 'Plays well with others: Needs improvement.'\n") # noqa: RUF010, T201
|
|
208
|
+
raise
|
|
209
|
+
try:
|
|
210
|
+
for scrap in scrapPile:
|
|
211
|
+
drill(scrap)
|
|
212
|
+
except RecursionError:
|
|
213
|
+
listStrungUp.append(repr(scrap))
|
|
214
|
+
return listStrungUp
|
|
215
|
+
|
|
216
|
+
def updateExtendPolishDictionaryLists(*dictionaryLists: Mapping[str, list[Any] | set[Any] | tuple[Any, ...]], destroyDuplicates: bool = False, reorderLists: bool = False, killErroneousDataTypes: bool = False) -> dict[str, list[Any]]:
|
|
217
|
+
"""Merge multiple dictionaries containing `list` into a single dictionary.
|
|
218
|
+
|
|
219
|
+
With options to handle duplicates, `list` ordering, and erroneous data types.
|
|
220
|
+
|
|
221
|
+
Parameters
|
|
222
|
+
----------
|
|
223
|
+
*dictionaryLists : Mapping[str, list[Any] | set[Any] | tuple[Any, ...]]
|
|
224
|
+
(dictionary2lists) Variable number of dictionaries to be merged. If only one dictionary is passed, it will be processed based on the provided options.
|
|
225
|
+
destroyDuplicates : bool = False
|
|
226
|
+
(destroy2duplicates) If `True`, removes duplicate elements from the `list`. Defaults to `False`.
|
|
227
|
+
reorderLists : bool = False
|
|
228
|
+
(reorder2lists) If `True`, sorts the `list`. Defaults to `False`.
|
|
229
|
+
killErroneousDataTypes : bool = False
|
|
230
|
+
(kill2erroneous2data2types) If `True`, skips dictionary keys or dictionary values that cause a `TypeError` during merging. Defaults to `False`.
|
|
231
|
+
|
|
232
|
+
Returns
|
|
233
|
+
-------
|
|
234
|
+
ePluribusUnum : dict[str, list[Any]]
|
|
235
|
+
(e2pluribus2unum) A single dictionary with merged `list` based on the provided options. If only one dictionary is passed,
|
|
236
|
+
it will be cleaned up based on the options.
|
|
237
|
+
|
|
238
|
+
Notes
|
|
239
|
+
-----
|
|
240
|
+
The returned value, `ePluribusUnum`, is a so-called primitive dictionary (`dict`). Furthermore, every dictionary key is a
|
|
241
|
+
so-called primitive string (cf. `str()`) and every dictionary value is a so-called primitive `list` (`list`). If
|
|
242
|
+
`dictionaryLists` has other data types, the data types will not be preserved. That could have unexpected consequences.
|
|
243
|
+
Conversion from the original data type to a `list`, for example, may not preserve the order even if you want the order to be
|
|
244
|
+
preserved.
|
|
245
|
+
|
|
246
|
+
"""
|
|
247
|
+
ePluribusUnum: dict[str, list[Any]] = {}
|
|
248
|
+
|
|
249
|
+
for dictionaryListTarget in dictionaryLists:
|
|
250
|
+
for keyName, keyValue in dictionaryListTarget.items():
|
|
251
|
+
try:
|
|
252
|
+
ImaStr = str(keyName)
|
|
253
|
+
ImaList = list(keyValue)
|
|
254
|
+
ePluribusUnum.setdefault(ImaStr, []).extend(ImaList)
|
|
255
|
+
except TypeError:
|
|
256
|
+
if killErroneousDataTypes:
|
|
257
|
+
continue
|
|
258
|
+
else:
|
|
259
|
+
raise
|
|
260
|
+
|
|
261
|
+
if destroyDuplicates:
|
|
262
|
+
for ImaStr, ImaList in ePluribusUnum.items():
|
|
263
|
+
ePluribusUnum[ImaStr] = list(dict.fromkeys(ImaList))
|
|
264
|
+
if reorderLists:
|
|
265
|
+
for ImaStr, ImaList in ePluribusUnum.items():
|
|
266
|
+
ePluribusUnum[ImaStr] = sorted(ImaList)
|
|
267
|
+
|
|
268
|
+
return ePluribusUnum
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""File system and module import utilities.
|
|
2
2
|
|
|
3
|
-
This module provides basic file I/O utilities such as importing callables from modules,
|
|
3
|
+
This module provides basic file I/O utilities such as importing callables from modules, safely creating directories, and writing to files or streams (pipes).
|
|
4
4
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
@@ -97,17 +97,25 @@ def makeDirsSafely(pathFilename: Any) -> None:
|
|
|
97
97
|
with contextlib.suppress(OSError):
|
|
98
98
|
Path(pathFilename).parent.mkdir(parents=True, exist_ok=True)
|
|
99
99
|
|
|
100
|
-
def writeStringToHere(this: str, pathFilename: PathLike[Any] | PurePath) -> None:
|
|
101
|
-
"""Write a string to a file
|
|
100
|
+
def writeStringToHere(this: str, pathFilename: PathLike[Any] | PurePath | io.TextIOBase) -> None:
|
|
101
|
+
"""Write a string to a file or text stream.
|
|
102
|
+
|
|
103
|
+
This function writes a string to either a file path or an open text stream. For file paths, it creates parent directories as
|
|
104
|
+
needed and writes with UTF-8 encoding. For text streams, it writes directly to the stream and flushes the buffer.
|
|
102
105
|
|
|
103
106
|
Parameters
|
|
104
107
|
----------
|
|
105
108
|
this : str
|
|
106
|
-
The string content to write
|
|
107
|
-
pathFilename : PathLike[Any] | PurePath
|
|
108
|
-
The
|
|
109
|
+
The string content to write.
|
|
110
|
+
pathFilename : PathLike[Any] | PurePath | io.TextIOBase
|
|
111
|
+
The target destination: either a file path or an open text stream.
|
|
109
112
|
|
|
110
113
|
"""
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
if isinstance(pathFilename, io.TextIOBase):
|
|
115
|
+
pathFilename.write(str(this))
|
|
116
|
+
pathFilename.flush()
|
|
117
|
+
else:
|
|
118
|
+
pathFilename = Path(pathFilename)
|
|
119
|
+
makeDirsSafely(pathFilename)
|
|
120
|
+
pathFilename.write_text(str(this), encoding='utf-8')
|
|
121
|
+
|