hunterMakesPy 0.1.0__tar.gz → 0.1.2__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/PKG-INFO +180 -0
- huntermakespy-0.1.2/README.md +135 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy/__init__.py +11 -3
- huntermakespy-0.1.2/hunterMakesPy/_theSSOT.py +4 -0
- huntermakespy-0.1.2/hunterMakesPy/coping.py +149 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy/dataStructures.py +12 -12
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy/filesystemToolkit.py +1 -2
- huntermakespy-0.1.2/hunterMakesPy.egg-info/PKG-INFO +180 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy.egg-info/SOURCES.txt +1 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy.egg-info/requires.txt +5 -4
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/pyproject.toml +32 -9
- huntermakespy-0.1.2/tests/test_coping.py +216 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/tests/test_filesystemToolkit.py +1 -1
- huntermakespy-0.1.0/PKG-INFO +0 -38
- huntermakespy-0.1.0/hunterMakesPy/_theSSOT.py +0 -40
- huntermakespy-0.1.0/hunterMakesPy/coping.py +0 -73
- huntermakespy-0.1.0/hunterMakesPy.egg-info/PKG-INFO +0 -38
- huntermakespy-0.1.0/tests/test_coping.py +0 -56
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/LICENSE +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy/parseParameters.py +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy/py.typed +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy/pytestForYourUse.py +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy/theTypes.py +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy.egg-info/dependency_links.txt +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/hunterMakesPy.egg-info/top_level.txt +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/setup.cfg +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/tests/__init__.py +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/tests/conftest.py +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/tests/test_dataStructures.py +0 -0
- {huntermakespy-0.1.0 → huntermakespy-0.1.2}/tests/test_parseParameters.py +0 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hunterMakesPy
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Easy Python functions making making functional Python functions easier.
|
|
5
|
+
Author-email: Hunter Hogan <HunterHogan@pm.me>
|
|
6
|
+
License: CC-BY-NC-4.0
|
|
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/
|
|
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
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Framework :: Pytest
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
17
|
+
Classifier: Intended Audience :: Other Audience
|
|
18
|
+
Classifier: Natural Language :: English
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
|
+
Classifier: Topic :: Utilities
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.11
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Dist: charset_normalizer
|
|
33
|
+
Requires-Dist: more_itertools
|
|
34
|
+
Requires-Dist: numpy
|
|
35
|
+
Requires-Dist: python_minifier
|
|
36
|
+
Provides-Extra: development
|
|
37
|
+
Requires-Dist: mypy; extra == "development"
|
|
38
|
+
Requires-Dist: pyupgrade; extra == "development"
|
|
39
|
+
Requires-Dist: setuptools-scm; extra == "development"
|
|
40
|
+
Provides-Extra: testing
|
|
41
|
+
Requires-Dist: pytest; extra == "testing"
|
|
42
|
+
Requires-Dist: pytest-cov; extra == "testing"
|
|
43
|
+
Requires-Dist: pytest-xdist; extra == "testing"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
# hunterMakesPy
|
|
47
|
+
|
|
48
|
+
A modular Python toolkit for defensive programming, parameter validation, file system utilities, and flexible data structure manipulation.
|
|
49
|
+
|
|
50
|
+
[](https://pypi.org/project/hunterMakesPy/)
|
|
51
|
+
|
|
52
|
+
## Overview
|
|
53
|
+
|
|
54
|
+
hunterMakesPy provides utilities for safe error handling, flexible input validation, dynamic module and attribute importing, and merging or transforming complex data structures. The package emphasizes clear identifiers, robust type handling, and reusable components for building reliable Python applications.
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install hunterMakesPy
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Defensive Programming
|
|
63
|
+
|
|
64
|
+
Utilities for handling `None` values and defensive programming patterns.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from hunterMakesPy import raiseIfNone
|
|
68
|
+
|
|
69
|
+
# Ensure a function result is not None
|
|
70
|
+
def findConfiguration(configName: str) -> dict[str, str] | None:
|
|
71
|
+
# ... search logic ...
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
config = raiseIfNone(
|
|
75
|
+
findConfiguration("database"),
|
|
76
|
+
"Configuration 'database' is required but not found"
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Parameter Validation
|
|
81
|
+
|
|
82
|
+
Parameter validation, integer parsing, and concurrency handling.
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from hunterMakesPy import defineConcurrencyLimit, intInnit, oopsieKwargsie
|
|
86
|
+
|
|
87
|
+
# 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
|
|
91
|
+
|
|
92
|
+
# Robust integer validation
|
|
93
|
+
validatedIntegers = intInnit([1, "2", 3.0, "4"], "port_numbers")
|
|
94
|
+
|
|
95
|
+
# String-to-boolean conversion for configuration
|
|
96
|
+
userInput = "True"
|
|
97
|
+
booleanValue = oopsieKwargsie(userInput) # Returns True
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## File System Utilities
|
|
101
|
+
|
|
102
|
+
Safe file operations and dynamic module importing.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from hunterMakesPy import (
|
|
106
|
+
importLogicalPath2Identifier,
|
|
107
|
+
importPathFilename2Identifier,
|
|
108
|
+
makeDirsSafely,
|
|
109
|
+
writeStringToHere
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Dynamic imports
|
|
113
|
+
gcdFunction = importLogicalPath2Identifier("math", "gcd")
|
|
114
|
+
customFunction = importPathFilename2Identifier("path/to/module.py", "functionName")
|
|
115
|
+
|
|
116
|
+
# Safe file operations
|
|
117
|
+
pathFilename = Path("deep/nested/directory/file.txt")
|
|
118
|
+
writeStringToHere("content", pathFilename) # Creates directories automatically
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Data Structure Manipulation
|
|
122
|
+
|
|
123
|
+
Utilities for string extraction, data flattening, and array compression.
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from hunterMakesPy import stringItUp, updateExtendPolishDictionaryLists, autoDecodingRLE
|
|
127
|
+
import numpy
|
|
128
|
+
|
|
129
|
+
# Extract all strings from nested data structures
|
|
130
|
+
nestedData = {"config": [1, "host", {"port": 8080}], "users": ["alice", "bob"]}
|
|
131
|
+
allStrings = stringItUp(nestedData) # ['config', 'host', 'port', 'users', 'alice', 'bob']
|
|
132
|
+
|
|
133
|
+
# Merge dictionaries containing lists
|
|
134
|
+
dictionaryAlpha = {"servers": ["web1", "web2"], "databases": ["db1"]}
|
|
135
|
+
dictionaryBeta = {"servers": ["web3"], "databases": ["db2", "db3"]}
|
|
136
|
+
merged = updateExtendPolishDictionaryLists(dictionaryAlpha, dictionaryBeta, destroyDuplicates=True)
|
|
137
|
+
|
|
138
|
+
# Compress NumPy arrays with run-length encoding
|
|
139
|
+
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)]"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Testing
|
|
144
|
+
|
|
145
|
+
The package includes comprehensive test suites that you can import and run:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from hunterMakesPy.pytestForYourUse import (
|
|
149
|
+
PytestFor_defineConcurrencyLimit,
|
|
150
|
+
PytestFor_intInnit,
|
|
151
|
+
PytestFor_oopsieKwargsie
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Run tests on the built-in functions
|
|
155
|
+
listOfTests = PytestFor_defineConcurrencyLimit()
|
|
156
|
+
for nameOfTest, callablePytest in listOfTests:
|
|
157
|
+
callablePytest()
|
|
158
|
+
|
|
159
|
+
# Or test your own compatible functions
|
|
160
|
+
@pytest.mark.parametrize("nameOfTest,callablePytest",
|
|
161
|
+
PytestFor_intInnit(callableToTest=myFunction))
|
|
162
|
+
def test_myFunction(nameOfTest, callablePytest):
|
|
163
|
+
callablePytest()
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## My recovery
|
|
167
|
+
|
|
168
|
+
[](https://HunterThinks.com/support)
|
|
169
|
+
[](https://www.youtube.com/@HunterHogan)
|
|
170
|
+
|
|
171
|
+
## How to code
|
|
172
|
+
|
|
173
|
+
Coding One Step at a Time:
|
|
174
|
+
|
|
175
|
+
0. WRITE CODE.
|
|
176
|
+
1. Don't write stupid code that's hard to revise.
|
|
177
|
+
2. Write good code.
|
|
178
|
+
3. When revising, write better code.
|
|
179
|
+
|
|
180
|
+
[](https://creativecommons.org/licenses/by-nc/4.0/)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# hunterMakesPy
|
|
2
|
+
|
|
3
|
+
A modular Python toolkit for defensive programming, parameter validation, file system utilities, and flexible data structure manipulation.
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/hunterMakesPy/)
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
hunterMakesPy provides utilities for safe error handling, flexible input validation, dynamic module and attribute importing, and merging or transforming complex data structures. The package emphasizes clear identifiers, robust type handling, and reusable components for building reliable Python applications.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install hunterMakesPy
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Defensive Programming
|
|
18
|
+
|
|
19
|
+
Utilities for handling `None` values and defensive programming patterns.
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from hunterMakesPy import raiseIfNone
|
|
23
|
+
|
|
24
|
+
# Ensure a function result is not None
|
|
25
|
+
def findConfiguration(configName: str) -> dict[str, str] | None:
|
|
26
|
+
# ... search logic ...
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
config = raiseIfNone(
|
|
30
|
+
findConfiguration("database"),
|
|
31
|
+
"Configuration 'database' is required but not found"
|
|
32
|
+
)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Parameter Validation
|
|
36
|
+
|
|
37
|
+
Parameter validation, integer parsing, and concurrency handling.
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from hunterMakesPy import defineConcurrencyLimit, intInnit, oopsieKwargsie
|
|
41
|
+
|
|
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
|
|
46
|
+
|
|
47
|
+
# Robust integer validation
|
|
48
|
+
validatedIntegers = intInnit([1, "2", 3.0, "4"], "port_numbers")
|
|
49
|
+
|
|
50
|
+
# String-to-boolean conversion for configuration
|
|
51
|
+
userInput = "True"
|
|
52
|
+
booleanValue = oopsieKwargsie(userInput) # Returns True
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## File System Utilities
|
|
56
|
+
|
|
57
|
+
Safe file operations and dynamic module importing.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from hunterMakesPy import (
|
|
61
|
+
importLogicalPath2Identifier,
|
|
62
|
+
importPathFilename2Identifier,
|
|
63
|
+
makeDirsSafely,
|
|
64
|
+
writeStringToHere
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Dynamic imports
|
|
68
|
+
gcdFunction = importLogicalPath2Identifier("math", "gcd")
|
|
69
|
+
customFunction = importPathFilename2Identifier("path/to/module.py", "functionName")
|
|
70
|
+
|
|
71
|
+
# Safe file operations
|
|
72
|
+
pathFilename = Path("deep/nested/directory/file.txt")
|
|
73
|
+
writeStringToHere("content", pathFilename) # Creates directories automatically
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Data Structure Manipulation
|
|
77
|
+
|
|
78
|
+
Utilities for string extraction, data flattening, and array compression.
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from hunterMakesPy import stringItUp, updateExtendPolishDictionaryLists, autoDecodingRLE
|
|
82
|
+
import numpy
|
|
83
|
+
|
|
84
|
+
# Extract all strings from nested data structures
|
|
85
|
+
nestedData = {"config": [1, "host", {"port": 8080}], "users": ["alice", "bob"]}
|
|
86
|
+
allStrings = stringItUp(nestedData) # ['config', 'host', 'port', 'users', 'alice', 'bob']
|
|
87
|
+
|
|
88
|
+
# Merge dictionaries containing lists
|
|
89
|
+
dictionaryAlpha = {"servers": ["web1", "web2"], "databases": ["db1"]}
|
|
90
|
+
dictionaryBeta = {"servers": ["web3"], "databases": ["db2", "db3"]}
|
|
91
|
+
merged = updateExtendPolishDictionaryLists(dictionaryAlpha, dictionaryBeta, destroyDuplicates=True)
|
|
92
|
+
|
|
93
|
+
# Compress NumPy arrays with run-length encoding
|
|
94
|
+
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)]"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Testing
|
|
99
|
+
|
|
100
|
+
The package includes comprehensive test suites that you can import and run:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from hunterMakesPy.pytestForYourUse import (
|
|
104
|
+
PytestFor_defineConcurrencyLimit,
|
|
105
|
+
PytestFor_intInnit,
|
|
106
|
+
PytestFor_oopsieKwargsie
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Run tests on the built-in functions
|
|
110
|
+
listOfTests = PytestFor_defineConcurrencyLimit()
|
|
111
|
+
for nameOfTest, callablePytest in listOfTests:
|
|
112
|
+
callablePytest()
|
|
113
|
+
|
|
114
|
+
# Or test your own compatible functions
|
|
115
|
+
@pytest.mark.parametrize("nameOfTest,callablePytest",
|
|
116
|
+
PytestFor_intInnit(callableToTest=myFunction))
|
|
117
|
+
def test_myFunction(nameOfTest, callablePytest):
|
|
118
|
+
callablePytest()
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## My recovery
|
|
122
|
+
|
|
123
|
+
[](https://HunterThinks.com/support)
|
|
124
|
+
[](https://www.youtube.com/@HunterHogan)
|
|
125
|
+
|
|
126
|
+
## How to code
|
|
127
|
+
|
|
128
|
+
Coding One Step at a Time:
|
|
129
|
+
|
|
130
|
+
0. WRITE CODE.
|
|
131
|
+
1. Don't write stupid code that's hard to revise.
|
|
132
|
+
2. Write good code.
|
|
133
|
+
3. When revising, write better code.
|
|
134
|
+
|
|
135
|
+
[](https://creativecommons.org/licenses/by-nc/4.0/)
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""A modular toolkit for defensive programming, parameter validation, file system utilities, and data structure manipulation.
|
|
2
|
+
|
|
3
|
+
This package provides:
|
|
4
|
+
- Defensive programming helpers for handling `None` values and error propagation.
|
|
5
|
+
- Parameter and input validation, integer parsing, and concurrency limit utilities.
|
|
6
|
+
- File system and import utilities for safe directory creation and dynamic module/attribute loading.
|
|
7
|
+
- Utilities for string extraction from nested data structures and merging dictionaries of lists.
|
|
8
|
+
|
|
9
|
+
"""
|
|
2
10
|
from hunterMakesPy.theTypes import identifierDotAttribute as identifierDotAttribute
|
|
3
11
|
|
|
4
|
-
from hunterMakesPy.coping import raiseIfNone as raiseIfNone
|
|
12
|
+
from hunterMakesPy.coping import PackageSettings as PackageSettings, raiseIfNone as raiseIfNone
|
|
5
13
|
|
|
6
14
|
from hunterMakesPy.parseParameters import (defineConcurrencyLimit as defineConcurrencyLimit, intInnit as intInnit,
|
|
7
15
|
oopsieKwargsie as oopsieKwargsie)
|
|
8
16
|
|
|
9
17
|
from hunterMakesPy.filesystemToolkit import (importLogicalPath2Identifier as importLogicalPath2Identifier,
|
|
10
18
|
importPathFilename2Identifier as importPathFilename2Identifier, makeDirsSafely as makeDirsSafely,
|
|
11
|
-
|
|
19
|
+
writeStringToHere as writeStringToHere)
|
|
12
20
|
|
|
13
21
|
from hunterMakesPy.dataStructures import (autoDecodingRLE as autoDecodingRLE, stringItUp as stringItUp,
|
|
14
22
|
updateExtendPolishDictionaryLists as updateExtendPolishDictionaryLists)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""Package configuration and defensive programming utilities for Python projects."""
|
|
2
|
+
from importlib.util import find_spec
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from tomllib import loads as tomllib_loads
|
|
5
|
+
from typing import TYPE_CHECKING, TypeVar
|
|
6
|
+
import dataclasses
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from importlib.machinery import ModuleSpec
|
|
10
|
+
|
|
11
|
+
TypeSansNone = TypeVar('TypeSansNone')
|
|
12
|
+
|
|
13
|
+
def getIdentifierPackagePACKAGING(identifierPackageFALLBACK: str) -> str:
|
|
14
|
+
"""Get package name from pyproject.toml or fallback to provided value."""
|
|
15
|
+
try:
|
|
16
|
+
return tomllib_loads(Path('pyproject.toml').read_text(encoding='utf-8'))['project']['name']
|
|
17
|
+
except Exception: # noqa: BLE001
|
|
18
|
+
return identifierPackageFALLBACK
|
|
19
|
+
|
|
20
|
+
def getPathPackageINSTALLING(identifierPackage: str) -> Path:
|
|
21
|
+
"""Return the root directory of the installed package."""
|
|
22
|
+
try:
|
|
23
|
+
moduleSpecification: ModuleSpec | None = find_spec(identifierPackage)
|
|
24
|
+
if moduleSpecification and moduleSpecification.origin:
|
|
25
|
+
pathFilename = Path(moduleSpecification.origin)
|
|
26
|
+
return pathFilename.parent if pathFilename.is_file() else pathFilename
|
|
27
|
+
except ModuleNotFoundError:
|
|
28
|
+
pass
|
|
29
|
+
return Path.cwd()
|
|
30
|
+
|
|
31
|
+
@dataclasses.dataclass
|
|
32
|
+
class PackageSettings:
|
|
33
|
+
"""Configuration container for Python package metadata and runtime settings.
|
|
34
|
+
|
|
35
|
+
This `class` provides a simple way to store and access basic information about a Python package, It will automatically resolve
|
|
36
|
+
package identifiers and installation paths if they are not passed to the `class` constructor. Python `dataclasses` are easy to
|
|
37
|
+
subtype and extend.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
identifierPackageFALLBACK : str = ''
|
|
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
|
+
identifierPackage : str = ''
|
|
46
|
+
Canonical name of the package. Automatically extracted from `pyproject.toml`.
|
|
47
|
+
fileExtension : str = '.py'
|
|
48
|
+
Default file extension.
|
|
49
|
+
|
|
50
|
+
Examples
|
|
51
|
+
--------
|
|
52
|
+
Automatic package discovery from development environment:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
settings = PackageSettings(identifierPackageFALLBACK='cobraPy')
|
|
56
|
+
# Automatically discovers package name from pyproject.toml
|
|
57
|
+
# Resolves installation path from package identifier
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Explicit configuration for specific deployment:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
settings = PackageSettings(
|
|
64
|
+
identifierPackage='cobraPy',
|
|
65
|
+
pathPackage=Path('/opt/tenEx/packages/cobraPy'),
|
|
66
|
+
fileExtension='.pyx'
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
identifierPackageFALLBACK: dataclasses.InitVar[str] = ''
|
|
73
|
+
"""Fallback package identifier used during initialization only."""
|
|
74
|
+
pathPackage: Path = dataclasses.field(default_factory=Path, metadata={'evaluateWhen': 'installing'})
|
|
75
|
+
"""Absolute path to the installed package."""
|
|
76
|
+
identifierPackage: str = dataclasses.field(default='', metadata={'evaluateWhen': 'packaging'})
|
|
77
|
+
"""Name of this package."""
|
|
78
|
+
fileExtension: str = dataclasses.field(default='.py', metadata={'evaluateWhen': 'installing'})
|
|
79
|
+
"""Default file extension for files."""
|
|
80
|
+
|
|
81
|
+
def __post_init__(self, identifierPackageFALLBACK: str) -> None:
|
|
82
|
+
"""Initialize computed fields after dataclass initialization."""
|
|
83
|
+
if not self.identifierPackage and identifierPackageFALLBACK:
|
|
84
|
+
self.identifierPackage = getIdentifierPackagePACKAGING(identifierPackageFALLBACK)
|
|
85
|
+
if self.pathPackage == Path() and self.identifierPackage:
|
|
86
|
+
self.pathPackage = getPathPackageINSTALLING(self.identifierPackage)
|
|
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)
|
|
92
|
+
|
|
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.
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
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.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
returnTarget : TypeSansNone
|
|
105
|
+
The original `returnTarget` value, guaranteed to not be `None`.
|
|
106
|
+
|
|
107
|
+
Raises
|
|
108
|
+
------
|
|
109
|
+
ValueError
|
|
110
|
+
If `returnTarget` is `None`.
|
|
111
|
+
|
|
112
|
+
Examples
|
|
113
|
+
--------
|
|
114
|
+
Ensure a function result is not `None`:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
def findFirstMatch(listItems: list[str], pattern: str) -> str | None:
|
|
118
|
+
for item in listItems:
|
|
119
|
+
if pattern in item:
|
|
120
|
+
return item
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
listFiles = ['document.txt', 'image.png', 'data.csv']
|
|
124
|
+
filename = raiseIfNone(findFirstMatch(listFiles, '.txt'))
|
|
125
|
+
# Returns 'document.txt'
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Handle dictionary lookups with custom error messages:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
configurationMapping = {'host': 'localhost', 'port': 8080}
|
|
132
|
+
host = raiseIfNone(configurationMapping.get('host'),
|
|
133
|
+
"Configuration must include 'host' setting")
|
|
134
|
+
# Returns 'localhost'
|
|
135
|
+
|
|
136
|
+
# This would raise ValueError with custom message:
|
|
137
|
+
# database = raiseIfNone(configurationMapping.get('database'),
|
|
138
|
+
# "Configuration must include 'database' setting")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Thanks
|
|
142
|
+
------
|
|
143
|
+
sobolevn, https://github.com/sobolevn, for the seed of the function. https://github.com/python/typing/discussions/1997#discussioncomment-13108399
|
|
144
|
+
|
|
145
|
+
"""
|
|
146
|
+
if returnTarget is None:
|
|
147
|
+
message = errorMessage or 'A function unexpectedly returned `None`. Hint: look at the traceback immediately before `raiseIfNone`.'
|
|
148
|
+
raise ValueError(message)
|
|
149
|
+
return returnTarget
|
|
@@ -46,7 +46,7 @@ def autoDecodingRLE(arrayTarget: NDArray[integer[Any]], *, assumeAddSpaces: bool
|
|
|
46
46
|
"""
|
|
47
47
|
def sliceNDArrayToNestedLists(arraySlice: NDArray[integer[Any]]) -> Any:
|
|
48
48
|
def getLengthOption(optionAsStr: str) -> int:
|
|
49
|
-
|
|
49
|
+
"""`assumeAddSpaces` characters: `,` 1; `]*` 2."""
|
|
50
50
|
return assumeAddSpaces * (optionAsStr.count(',') + optionAsStr.count(']*') * 2) + len(optionAsStr)
|
|
51
51
|
|
|
52
52
|
if arraySlice.ndim > 1:
|
|
@@ -125,29 +125,29 @@ def autoDecodingRLE(arrayTarget: NDArray[integer[Any]], *, assumeAddSpaces: bool
|
|
|
125
125
|
patternRegex = regex.compile(
|
|
126
126
|
"(?<!rang)(?:"
|
|
127
127
|
# Pattern 1: Comma ahead, bracket behind # noqa: ERA001
|
|
128
|
-
"(?P<joinAhead>,)\\((?P<malkovich>\\d+),(?P<
|
|
128
|
+
"(?P<joinAhead>,)\\((?P<malkovich>\\d+),(?P<multiply>\\d+)\\)(?P<bracketBehind>])|"
|
|
129
129
|
# Pattern 2: Bracket or start ahead, comma behind # noqa: ERA001
|
|
130
|
-
"(?P<bracketOrStartAhead>\\[|^.)\\((?P<
|
|
130
|
+
"(?P<bracketOrStartAhead>\\[|^.)\\((?P<malkovichMalkovich>\\d+),(?P<multiplyIDK>\\d+)\\)(?P<joinBehind>,)|"
|
|
131
131
|
# Pattern 3: Bracket ahead, bracket behind # noqa: ERA001
|
|
132
|
-
"(?P<bracketAhead>\\[)\\((?P<
|
|
132
|
+
"(?P<bracketAhead>\\[)\\((?P<malkovichMalkovichMalkovich>\\d+),(?P<multiply_whatever>\\d+)\\)(?P<bracketBehindBracketBehind>])|"
|
|
133
133
|
# Pattern 4: Comma ahead, comma behind # noqa: ERA001
|
|
134
|
-
"(?P<
|
|
134
|
+
"(?P<joinAheadJoinAhead>,)\\((?P<malkovichMalkovichMalkovichMalkovich>\\d+),(?P<multiplyOrSomething>\\d+)\\)(?P<joinBehindJoinBehind>,)"
|
|
135
135
|
")"
|
|
136
136
|
)
|
|
137
137
|
|
|
138
138
|
def replacementByContext(match: regex.Match[str]) -> str:
|
|
139
139
|
"""Generate replacement string based on context patterns."""
|
|
140
|
-
|
|
141
|
-
joinAhead =
|
|
142
|
-
malkovich =
|
|
143
|
-
|
|
144
|
-
joinBehind =
|
|
140
|
+
elephino = match.groupdict()
|
|
141
|
+
joinAhead = elephino.get('joinAhead') or elephino.get('joinAheadJoinAhead')
|
|
142
|
+
malkovich = elephino.get('malkovich') or elephino.get('malkovichMalkovich') or elephino.get('malkovichMalkovichMalkovich') or elephino.get('malkovichMalkovichMalkovichMalkovich')
|
|
143
|
+
multiply = elephino.get('multiply') or elephino.get('multiplyIDK') or elephino.get('multiply_whatever') or elephino.get('multiplyOrSomething')
|
|
144
|
+
joinBehind = elephino.get('joinBehind') or elephino.get('joinBehindJoinBehind')
|
|
145
145
|
|
|
146
146
|
replaceAhead = "]+[" if joinAhead == "," else "["
|
|
147
147
|
|
|
148
148
|
replaceBehind = "+[" if joinBehind == "," else ""
|
|
149
149
|
|
|
150
|
-
return f"{replaceAhead}{malkovich}]*{
|
|
150
|
+
return f"{replaceAhead}{malkovich}]*{multiply}{replaceBehind}"
|
|
151
151
|
|
|
152
152
|
arrayAsStr = patternRegex.sub(replacementByContext, arrayAsStr)
|
|
153
153
|
arrayAsStr = patternRegex.sub(replacementByContext, arrayAsStr)
|
|
@@ -249,7 +249,7 @@ def updateExtendPolishDictionaryLists(*dictionaryLists: Mapping[str, list[Any] |
|
|
|
249
249
|
ImaStr = str(keyName)
|
|
250
250
|
ImaList = list(keyValue)
|
|
251
251
|
ePluribusUnum.setdefault(ImaStr, []).extend(ImaList)
|
|
252
|
-
except TypeError:
|
|
252
|
+
except TypeError:
|
|
253
253
|
if killErroneousDataTypes:
|
|
254
254
|
continue
|
|
255
255
|
else:
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""File system and module import utilities.
|
|
2
2
|
|
|
3
|
-
This module provides basic file I/O utilities such as
|
|
4
|
-
callables from modules, and safely creating directories.
|
|
3
|
+
This module provides basic file I/O utilities such as importing callables from modules, and safely creating directories.
|
|
5
4
|
|
|
6
5
|
"""
|
|
7
6
|
|