frigid 4.1__tar.gz → 4.3__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.
- frigid-4.3/.gitignore +7 -0
- {frigid-4.1 → frigid-4.3}/PKG-INFO +41 -5
- {frigid-4.1 → frigid-4.3}/README.rst +36 -1
- {frigid-4.1 → frigid-4.3}/pyproject.toml +68 -18
- frigid-4.3/sources/frigid/README.md +119 -0
- {frigid-4.1 → frigid-4.3}/sources/frigid/__/__init__.py +0 -8
- {frigid-4.1 → frigid-4.3}/sources/frigid/__/imports.py +3 -1
- {frigid-4.1 → frigid-4.3}/sources/frigid/__/nomina.py +6 -17
- {frigid-4.1 → frigid-4.3}/sources/frigid/__init__.py +2 -2
- {frigid-4.1 → frigid-4.3}/sources/frigid/classes.py +24 -9
- {frigid-4.1 → frigid-4.3}/sources/frigid/dictionaries.py +8 -1
- {frigid-4.1 → frigid-4.3}/sources/frigid/exceptions.py +2 -2
- {frigid-4.1 → frigid-4.3}/sources/frigid/modules.py +1 -0
- {frigid-4.1 → frigid-4.3}/sources/frigid/namespaces.py +2 -2
- frigid-4.1/.gitignore +0 -10
- {frigid-4.1 → frigid-4.3}/LICENSE.txt +0 -0
- {frigid-4.1 → frigid-4.3}/sources/frigid/__/dictionaries.py +0 -0
- {frigid-4.1 → frigid-4.3}/sources/frigid/__/doctab.py +0 -0
- {frigid-4.1 → frigid-4.3}/sources/frigid/__/exceptions.py +0 -0
- {frigid-4.1 → frigid-4.3}/sources/frigid/_typedecls/__builtins__.pyi +0 -0
- {frigid-4.1 → frigid-4.3}/sources/frigid/installers.py +0 -0
- {frigid-4.1 → frigid-4.3}/sources/frigid/py.typed +0 -0
- {frigid-4.1 → frigid-4.3}/sources/frigid/sequences.py +0 -0
frigid-4.3/.gitignore
ADDED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: frigid
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3
|
|
4
4
|
Summary: Immutable data structures.
|
|
5
5
|
Project-URL: Homepage, https://github.com/emcd/python-frigid
|
|
6
6
|
Project-URL: Documentation, https://emcd.github.io/python-frigid
|
|
@@ -19,13 +19,14 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
23
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
23
24
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
24
25
|
Classifier: Topic :: Software Development
|
|
25
26
|
Requires-Python: >=3.10
|
|
26
27
|
Requires-Dist: absence~=1.1
|
|
27
|
-
Requires-Dist: classcore~=1.
|
|
28
|
-
Requires-Dist: dynadoc~=1.
|
|
28
|
+
Requires-Dist: classcore~=1.12
|
|
29
|
+
Requires-Dist: dynadoc~=1.4
|
|
29
30
|
Requires-Dist: typing-extensions
|
|
30
31
|
Description-Content-Type: text/x-rst
|
|
31
32
|
|
|
@@ -106,6 +107,18 @@ Key Features ⭐
|
|
|
106
107
|
Installation 📦
|
|
107
108
|
===============================================================================
|
|
108
109
|
|
|
110
|
+
Method: Install Python Package
|
|
111
|
+
-------------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
Install via `uv <https://github.com/astral-sh/uv/blob/main/README.md>`_ ``pip``
|
|
114
|
+
command:
|
|
115
|
+
|
|
116
|
+
::
|
|
117
|
+
|
|
118
|
+
uv pip install frigid
|
|
119
|
+
|
|
120
|
+
Or, install via ``pip``:
|
|
121
|
+
|
|
109
122
|
::
|
|
110
123
|
|
|
111
124
|
pip install frigid
|
|
@@ -204,7 +217,24 @@ Use Cases 🎯
|
|
|
204
217
|
complete immutability guarantees.
|
|
205
218
|
|
|
206
219
|
|
|
207
|
-
|
|
220
|
+
Contribution 🤝
|
|
221
|
+
===============================================================================
|
|
222
|
+
|
|
223
|
+
Contribution to this project is welcome! However, it must follow the `code of
|
|
224
|
+
conduct
|
|
225
|
+
<https://emcd.github.io/python-project-common/stable/sphinx-html/common/conduct.html>`_
|
|
226
|
+
for the project.
|
|
227
|
+
|
|
228
|
+
Please file bug reports and feature requests in the `issue tracker
|
|
229
|
+
<https://github.com/emcd/python-frigid/issues>`_ or submit `pull
|
|
230
|
+
requests <https://github.com/emcd/python-frigid/pulls>`_ to
|
|
231
|
+
improve the source code or documentation.
|
|
232
|
+
|
|
233
|
+
For development guidance and standards, please see the `development guide
|
|
234
|
+
<https://emcd.github.io/python-frigid/stable/sphinx-html/contribution.html#development>`_.
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
Additional Indicia
|
|
208
238
|
===============================================================================
|
|
209
239
|
|
|
210
240
|
.. image:: https://img.shields.io/github/last-commit/emcd/python-frigid
|
|
@@ -253,6 +283,9 @@ Other Projects by This Author 🌟
|
|
|
253
283
|
* `python-classcore <https://github.com/emcd/python-classcore>`_ (`classcore <https://pypi.org/project/classcore/>`_ on PyPI)
|
|
254
284
|
|
|
255
285
|
🏭 A Python library package which provides **foundational class factories and decorators** for providing classes with attributes immutability and concealment and other custom behaviors.
|
|
286
|
+
* `python-detextive <https://github.com/emcd/python-detextive>`_ (`detextive <https://pypi.org/project/detextive/>`_ on PyPI)
|
|
287
|
+
|
|
288
|
+
🕵️ A Python library which provides consolidated text detection capabilities for reliable content analysis. Offers MIME type detection, character set detection, and line separator processing.
|
|
256
289
|
* `python-dynadoc <https://github.com/emcd/python-dynadoc>`_ (`dynadoc <https://pypi.org/project/dynadoc/>`_ on PyPI)
|
|
257
290
|
|
|
258
291
|
📝 A Python library package which bridges the gap between **rich annotations** and **automatic documentation generation** with configurable renderers and support for reusable fragments.
|
|
@@ -262,6 +295,9 @@ Other Projects by This Author 🌟
|
|
|
262
295
|
* `python-icecream-truck <https://github.com/emcd/python-icecream-truck>`_ (`icecream-truck <https://pypi.org/project/icecream-truck/>`_ on PyPI)
|
|
263
296
|
|
|
264
297
|
🍦 **Flavorful Debugging** - A Python library which enhances the powerful and well-known ``icecream`` package with flavored traces, configuration hierarchies, customized outputs, ready-made recipes, and more.
|
|
298
|
+
* `python-librovore <https://github.com/emcd/python-librovore>`_ (`librovore <https://pypi.org/project/librovore/>`_ on PyPI)
|
|
299
|
+
|
|
300
|
+
🐲 **Documentation Search Engine** - An intelligent documentation search and extraction tool that provides both a command-line interface for humans and an MCP (Model Context Protocol) server for AI agents. Search across Sphinx and MkDocs sites with fuzzy matching, extract clean markdown content, and integrate seamlessly with AI development workflows.
|
|
265
301
|
* `python-mimeogram <https://github.com/emcd/python-mimeogram>`_ (`mimeogram <https://pypi.org/project/mimeogram/>`_ on PyPI)
|
|
266
302
|
|
|
267
303
|
📨 A command-line tool for **exchanging collections of files with Large Language Models** - bundle multiple files into a single clipboard-ready document while preserving directory structure and metadata... good for code reviews, project sharing, and LLM interactions.
|
|
@@ -75,6 +75,18 @@ Key Features ⭐
|
|
|
75
75
|
Installation 📦
|
|
76
76
|
===============================================================================
|
|
77
77
|
|
|
78
|
+
Method: Install Python Package
|
|
79
|
+
-------------------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
Install via `uv <https://github.com/astral-sh/uv/blob/main/README.md>`_ ``pip``
|
|
82
|
+
command:
|
|
83
|
+
|
|
84
|
+
::
|
|
85
|
+
|
|
86
|
+
uv pip install frigid
|
|
87
|
+
|
|
88
|
+
Or, install via ``pip``:
|
|
89
|
+
|
|
78
90
|
::
|
|
79
91
|
|
|
80
92
|
pip install frigid
|
|
@@ -173,7 +185,24 @@ Use Cases 🎯
|
|
|
173
185
|
complete immutability guarantees.
|
|
174
186
|
|
|
175
187
|
|
|
176
|
-
|
|
188
|
+
Contribution 🤝
|
|
189
|
+
===============================================================================
|
|
190
|
+
|
|
191
|
+
Contribution to this project is welcome! However, it must follow the `code of
|
|
192
|
+
conduct
|
|
193
|
+
<https://emcd.github.io/python-project-common/stable/sphinx-html/common/conduct.html>`_
|
|
194
|
+
for the project.
|
|
195
|
+
|
|
196
|
+
Please file bug reports and feature requests in the `issue tracker
|
|
197
|
+
<https://github.com/emcd/python-frigid/issues>`_ or submit `pull
|
|
198
|
+
requests <https://github.com/emcd/python-frigid/pulls>`_ to
|
|
199
|
+
improve the source code or documentation.
|
|
200
|
+
|
|
201
|
+
For development guidance and standards, please see the `development guide
|
|
202
|
+
<https://emcd.github.io/python-frigid/stable/sphinx-html/contribution.html#development>`_.
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
Additional Indicia
|
|
177
206
|
===============================================================================
|
|
178
207
|
|
|
179
208
|
.. image:: https://img.shields.io/github/last-commit/emcd/python-frigid
|
|
@@ -222,6 +251,9 @@ Other Projects by This Author 🌟
|
|
|
222
251
|
* `python-classcore <https://github.com/emcd/python-classcore>`_ (`classcore <https://pypi.org/project/classcore/>`_ on PyPI)
|
|
223
252
|
|
|
224
253
|
🏭 A Python library package which provides **foundational class factories and decorators** for providing classes with attributes immutability and concealment and other custom behaviors.
|
|
254
|
+
* `python-detextive <https://github.com/emcd/python-detextive>`_ (`detextive <https://pypi.org/project/detextive/>`_ on PyPI)
|
|
255
|
+
|
|
256
|
+
🕵️ A Python library which provides consolidated text detection capabilities for reliable content analysis. Offers MIME type detection, character set detection, and line separator processing.
|
|
225
257
|
* `python-dynadoc <https://github.com/emcd/python-dynadoc>`_ (`dynadoc <https://pypi.org/project/dynadoc/>`_ on PyPI)
|
|
226
258
|
|
|
227
259
|
📝 A Python library package which bridges the gap between **rich annotations** and **automatic documentation generation** with configurable renderers and support for reusable fragments.
|
|
@@ -231,6 +263,9 @@ Other Projects by This Author 🌟
|
|
|
231
263
|
* `python-icecream-truck <https://github.com/emcd/python-icecream-truck>`_ (`icecream-truck <https://pypi.org/project/icecream-truck/>`_ on PyPI)
|
|
232
264
|
|
|
233
265
|
🍦 **Flavorful Debugging** - A Python library which enhances the powerful and well-known ``icecream`` package with flavored traces, configuration hierarchies, customized outputs, ready-made recipes, and more.
|
|
266
|
+
* `python-librovore <https://github.com/emcd/python-librovore>`_ (`librovore <https://pypi.org/project/librovore/>`_ on PyPI)
|
|
267
|
+
|
|
268
|
+
🐲 **Documentation Search Engine** - An intelligent documentation search and extraction tool that provides both a command-line interface for humans and an MCP (Model Context Protocol) server for AI agents. Search across Sphinx and MkDocs sites with fuzzy matching, extract clean markdown content, and integrate seamlessly with AI development workflows.
|
|
234
269
|
* `python-mimeogram <https://github.com/emcd/python-mimeogram>`_ (`mimeogram <https://pypi.org/project/mimeogram/>`_ on PyPI)
|
|
235
270
|
|
|
236
271
|
📨 A command-line tool for **exchanging collections of files with Large Language Models** - bundle multiple files into a single clipboard-ready document while preserving directory structure and metadata... good for code reviews, project sharing, and LLM interactions.
|
|
@@ -16,8 +16,8 @@ readme = { 'file' = 'README.rst', 'content-type' = 'text/x-rst' }
|
|
|
16
16
|
requires-python = '>= 3.10'
|
|
17
17
|
dependencies = [
|
|
18
18
|
'absence~=1.1',
|
|
19
|
-
'classcore~=1.
|
|
20
|
-
'dynadoc~=1.
|
|
19
|
+
'classcore~=1.12',
|
|
20
|
+
'dynadoc~=1.4',
|
|
21
21
|
'typing-extensions',
|
|
22
22
|
# --- BEGIN: Injected by Copier ---
|
|
23
23
|
# --- END: Injected by Copier ---
|
|
@@ -32,6 +32,7 @@ classifiers = [ # https://pypi.org/classifiers
|
|
|
32
32
|
'Programming Language :: Python :: 3.11',
|
|
33
33
|
'Programming Language :: Python :: 3.12',
|
|
34
34
|
'Programming Language :: Python :: 3.13',
|
|
35
|
+
'Programming Language :: Python :: 3.14',
|
|
35
36
|
'Programming Language :: Python :: Implementation :: CPython',
|
|
36
37
|
'Programming Language :: Python :: Implementation :: PyPy',
|
|
37
38
|
# --- END: Injected by Copier ---
|
|
@@ -61,7 +62,7 @@ gha-runners = [
|
|
|
61
62
|
]
|
|
62
63
|
[tool.coverage.run]
|
|
63
64
|
branch = true
|
|
64
|
-
command_line = '-m pytest'
|
|
65
|
+
command_line = '-m pytest'
|
|
65
66
|
data_file = '.auxiliary/caches/pytest/coverage.sqlite3'
|
|
66
67
|
parallel = true
|
|
67
68
|
source = [ 'sources' ]
|
|
@@ -95,11 +96,12 @@ strict-naming = false
|
|
|
95
96
|
python = '3.10'
|
|
96
97
|
[tool.hatch.envs.develop]
|
|
97
98
|
description = ''' Development environment. '''
|
|
99
|
+
builder = true
|
|
98
100
|
dependencies = [
|
|
99
|
-
'Jinja2',
|
|
100
101
|
'coverage[toml]',
|
|
101
102
|
'furo',
|
|
102
|
-
'
|
|
103
|
+
'isort',
|
|
104
|
+
'myst-parser',
|
|
103
105
|
'pre-commit',
|
|
104
106
|
'pyright',
|
|
105
107
|
'pytest',
|
|
@@ -108,6 +110,7 @@ dependencies = [
|
|
|
108
110
|
'sphinx-copybutton',
|
|
109
111
|
'sphinx-inline-tabs',
|
|
110
112
|
'towncrier',
|
|
113
|
+
'vulture',
|
|
111
114
|
# --- BEGIN: Injected by Copier ---
|
|
112
115
|
# --- END: Injected by Copier ---
|
|
113
116
|
]
|
|
@@ -121,15 +124,17 @@ PYTHONUNBUFFERED = 'TRUE' # TODO: Only for coverage/pytest.
|
|
|
121
124
|
# --- END: Injected by Copier ---
|
|
122
125
|
[tool.hatch.envs.develop.scripts]
|
|
123
126
|
docsgen = [
|
|
124
|
-
"""sphinx-build -E -b linkcheck -d .auxiliary/caches/sphinx \
|
|
125
|
-
|
|
126
|
-
"""sphinx-build -a -d .auxiliary/caches/sphinx \
|
|
127
|
-
|
|
127
|
+
"""sphinx-build -E -b linkcheck -d .auxiliary/caches/sphinx --quiet \
|
|
128
|
+
documentation .auxiliary/artifacts/sphinx-linkcheck""",
|
|
129
|
+
"""sphinx-build -a -d .auxiliary/caches/sphinx --quiet \
|
|
130
|
+
documentation .auxiliary/artifacts/sphinx-html""",
|
|
128
131
|
]
|
|
129
132
|
linters = [
|
|
130
133
|
"""ruff check --quiet sources documentation tests""",
|
|
134
|
+
"""vibelinter check""",
|
|
131
135
|
# --- BEGIN: Injected by Copier ---
|
|
132
136
|
# --- END: Injected by Copier ---
|
|
137
|
+
"""isort --check-only --diff sources tests""",
|
|
133
138
|
"""pyright sources""",
|
|
134
139
|
]
|
|
135
140
|
packagers = [
|
|
@@ -137,14 +142,19 @@ packagers = [
|
|
|
137
142
|
# --- BEGIN: Injected by Copier ---
|
|
138
143
|
# --- END: Injected by Copier ---
|
|
139
144
|
]
|
|
145
|
+
testers-documentation = [
|
|
146
|
+
"""coverage run -m sphinx.cmd.build \
|
|
147
|
+
-E -b doctest -d .auxiliary/caches/sphinx --quiet \
|
|
148
|
+
documentation .auxiliary/artifacts/sphinx-doctest""",
|
|
149
|
+
]
|
|
150
|
+
testers-serotine = [ """coverage run -m pytest -m slow""" ]
|
|
140
151
|
testers-no-reports = [
|
|
141
|
-
'coverage erase',
|
|
142
152
|
'coverage run',
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
documentation .auxiliary/artifacts/sphinx-doctest""",
|
|
153
|
+
'testers-documentation',
|
|
154
|
+
'testers-serotine',
|
|
146
155
|
]
|
|
147
156
|
testers = [
|
|
157
|
+
'coverage erase',
|
|
148
158
|
'testers-no-reports',
|
|
149
159
|
'coverage combine',
|
|
150
160
|
'coverage report --skip-covered',
|
|
@@ -166,11 +176,31 @@ python = [
|
|
|
166
176
|
'3.11',
|
|
167
177
|
'3.12',
|
|
168
178
|
'3.13',
|
|
169
|
-
'
|
|
179
|
+
'3.14',
|
|
180
|
+
'pypy3.11',
|
|
170
181
|
]
|
|
171
182
|
[tool.hatch.version]
|
|
172
183
|
path = 'sources/frigid/__init__.py'
|
|
173
184
|
|
|
185
|
+
# https://pycqa.github.io/isort/docs/configuration/config_files.html
|
|
186
|
+
[tool.isort]
|
|
187
|
+
# profile = 'black'
|
|
188
|
+
src_paths = [ 'sources', 'tests' ]
|
|
189
|
+
case_sensitive = true
|
|
190
|
+
# ensure_newline_before_comments = true
|
|
191
|
+
# force_sort_within_sections = true
|
|
192
|
+
ignore_whitespace = true
|
|
193
|
+
include_trailing_comma = true
|
|
194
|
+
known_first_party = [ 'frigid' ]
|
|
195
|
+
lines_between_types = 1
|
|
196
|
+
line_length = 79
|
|
197
|
+
multi_line_output = 3
|
|
198
|
+
quiet = true
|
|
199
|
+
# skip_gitignore = true
|
|
200
|
+
skip_glob = [ '*/__/imports.py', '*/__init__.py' ]
|
|
201
|
+
split_on_trailing_comma = true
|
|
202
|
+
use_parentheses = true
|
|
203
|
+
|
|
174
204
|
# https://mypy.readthedocs.io/en/stable/config_file.html
|
|
175
205
|
[tool.mypy]
|
|
176
206
|
# Note: Due to repeated painful experiences with Mypy, we use Pyright instead.
|
|
@@ -184,8 +214,8 @@ strict = false
|
|
|
184
214
|
|
|
185
215
|
# https://microsoft.github.io/pyright/#/configuration
|
|
186
216
|
[tool.pyright]
|
|
187
|
-
ignore = [ 'documentation', 'tests' ] #
|
|
188
|
-
include = [ 'sources' ]
|
|
217
|
+
ignore = [ '.auxiliary', 'documentation', 'tests' ] # Ignore diagnostics.
|
|
218
|
+
include = [ 'sources', 'tests' ] # Consider for operations.
|
|
189
219
|
reportConstantRedefinition = true
|
|
190
220
|
reportInvalidTypeVarUse = true
|
|
191
221
|
reportMatchNotExhaustive = true
|
|
@@ -217,16 +247,19 @@ stubPath = 'sources/frigid/_typedecls'
|
|
|
217
247
|
# Note: Cannot run doctests from Pytest, because Pytest tries to update '_'
|
|
218
248
|
# attribute on protected modules. Instead, we use Sphinx to run doctests.
|
|
219
249
|
minversion = '8.1'
|
|
220
|
-
addopts =
|
|
250
|
+
addopts = """--capture=no --exitfirst --quiet -rfE -m 'not slow'""" # TODO? '--fail-under'
|
|
221
251
|
testpaths = [ 'tests' ]
|
|
222
252
|
python_files = [ 'test_*.py' ]
|
|
223
253
|
python_functions = [ 'test_[0-9][0-9][0-9]_*' ]
|
|
224
254
|
cache_dir = '.auxiliary/caches/pytest'
|
|
225
|
-
|
|
255
|
+
markers = [
|
|
256
|
+
"slow: long-running tests",
|
|
257
|
+
]
|
|
226
258
|
|
|
227
259
|
[tool.ruff]
|
|
228
260
|
#builtins = [ 'ic' ]
|
|
229
261
|
cache-dir = '.auxiliary/caches/ruff'
|
|
262
|
+
extend-exclude = [ 'vulturefood.py' ]
|
|
230
263
|
indent-width = 4
|
|
231
264
|
line-length = 79
|
|
232
265
|
[tool.ruff.lint]
|
|
@@ -316,3 +349,20 @@ showcontent = true
|
|
|
316
349
|
directory = 'repair'
|
|
317
350
|
name = 'Repairs'
|
|
318
351
|
showcontent = true
|
|
352
|
+
|
|
353
|
+
[tool.vibelinter]
|
|
354
|
+
context = 3
|
|
355
|
+
exclude_paths = [ '.auxiliary/**', '.venv/**', 'tests/**', ]
|
|
356
|
+
[tool.vibelinter.rules.VBL201]
|
|
357
|
+
hub_patterns = [
|
|
358
|
+
'__init__.py', '__main__.py', '__.py', '__/imports.py', '__/nomina.py',
|
|
359
|
+
]
|
|
360
|
+
|
|
361
|
+
[tool.vulture]
|
|
362
|
+
paths = [ '.auxiliary/configuration/vulturefood.py', 'sources' ]
|
|
363
|
+
min_confidence = 60
|
|
364
|
+
exclude = [
|
|
365
|
+
'*/imports.py',
|
|
366
|
+
]
|
|
367
|
+
ignore_decorators = [ '@__.abc.abstractmethod', '@__.typx.overload' ]
|
|
368
|
+
ignore_names = [ 'main' ]
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frigid
|
|
2
|
+
|
|
3
|
+
Immutable data structures for Python. Provides collections and class behaviors
|
|
4
|
+
that cannot be modified after creation.
|
|
5
|
+
|
|
6
|
+
## Architecture
|
|
7
|
+
|
|
8
|
+
Layered architecture with three tiers:
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
┌─────────────────────────────────────────────────┐
|
|
12
|
+
│ Public API │
|
|
13
|
+
│ (Dictionary, Namespace, Object, decorators) │
|
|
14
|
+
└─────────────────────────────────────────────────┘
|
|
15
|
+
↓
|
|
16
|
+
┌─────────────────────────────────────────────────┐
|
|
17
|
+
│ Core Implementation (*/) │
|
|
18
|
+
│ (ImmutableDictionary, type aliases, doc frags) │
|
|
19
|
+
└─────────────────────────────────────────────────┘
|
|
20
|
+
↓
|
|
21
|
+
┌─────────────────────────────────────────────────┐
|
|
22
|
+
│ Foundation Libraries │
|
|
23
|
+
│ (classcore, dynadoc, absence) │
|
|
24
|
+
└─────────────────────────────────────────────────┘
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
All modules follow the `__` import pattern: public modules import from
|
|
28
|
+
`. import __`, which provides centralized access to external dependencies.
|
|
29
|
+
|
|
30
|
+
## Modules
|
|
31
|
+
|
|
32
|
+
### Public API (`sources/frigid/`)
|
|
33
|
+
|
|
34
|
+
| Module | Purpose |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `__init__.py` | Package entry point; re-exports public API |
|
|
37
|
+
| `classes.py` | Metaclasses (`Class`, `Dataclass`, `AbstractBaseClass`, `Protocol*`) and decorators (`with_standard_behaviors`, `dataclass_with_standard_behaviors`) |
|
|
38
|
+
| `dictionaries.py` | `Dictionary`, `ValidatorDictionary` with set operations (`\|`, `&`) |
|
|
39
|
+
| `namespaces.py` | `Namespace` — like `SimpleNamespace`, but immutable |
|
|
40
|
+
| `modules.py` | `Module` type and `finalize_module()` utility |
|
|
41
|
+
| `sequences.py` | `one()` — single-item tuple factory |
|
|
42
|
+
| `exceptions.py` | `Omniexception` → `Omnierror` → `AttributeImmutability`, `EntryImmutability`, `EntryInvalidity` |
|
|
43
|
+
| `installers.py` | Utilities for installing into builtins |
|
|
44
|
+
|
|
45
|
+
### Internal (`sources/frigid/__/`)
|
|
46
|
+
|
|
47
|
+
| Module | Purpose |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `imports.py` | Centralized external library imports |
|
|
50
|
+
| `nomina.py` | Type aliases, type variables, `calculate_attrname()` |
|
|
51
|
+
| `dictionaries.py` | `ImmutableDictionary` — core dict subclass with immutability enforcement |
|
|
52
|
+
| `doctab.py` | Documentation fragments table for dynadoc |
|
|
53
|
+
| `exceptions.py` | Internal exception classes |
|
|
54
|
+
|
|
55
|
+
## Key Patterns
|
|
56
|
+
|
|
57
|
+
**Wrapper Pattern**: `Dictionary` wraps `ImmutableDictionary` in `_data_`.
|
|
58
|
+
`Namespace` uses `ImmutableDictionary` for `__dict__`.
|
|
59
|
+
|
|
60
|
+
**Delegation Pattern**: Core immutability enforcement delegated to
|
|
61
|
+
`classcore.standard.class_factory`. Frigid provides configuration (attribute
|
|
62
|
+
naming, dynadoc, error classes) via `functools.partial`.
|
|
63
|
+
|
|
64
|
+
**Behavioral Flags**: `ImmutableDictionary` uses `_behaviors_` set to track
|
|
65
|
+
state. During `__init__`, immutability is not active. After `__init__`,
|
|
66
|
+
`'immutability'` is added to the set and all mutations are blocked.
|
|
67
|
+
|
|
68
|
+
**Template Method**: `Dictionary.with_data()` creates new instances with
|
|
69
|
+
same type and validator but different data. Subclasses override to maintain
|
|
70
|
+
behavior.
|
|
71
|
+
|
|
72
|
+
## Data Flow
|
|
73
|
+
|
|
74
|
+
### Initialization Flow
|
|
75
|
+
|
|
76
|
+
Immutable objects follow a consistent initialization pattern:
|
|
77
|
+
|
|
78
|
+
1. Object creation begins with `__new__`
|
|
79
|
+
2. During `__init__`, attributes/entries can be freely set
|
|
80
|
+
3. After `__init__` completes, protection activates via `__setattr__`/`__delattr__` overrides
|
|
81
|
+
4. Subsequent modification or deletion attempts raise immutability exceptions
|
|
82
|
+
|
|
83
|
+
For `ImmutableDictionary`, the `_behaviors_` set controls this: `'immutability'`
|
|
84
|
+
is absent during `__init__` (mutations allowed) and added after initialization.
|
|
85
|
+
|
|
86
|
+
### Dictionary Operation Flow
|
|
87
|
+
|
|
88
|
+
Set operations (union, intersection) maintain immutability guarantees:
|
|
89
|
+
|
|
90
|
+
1. User invokes operation: `dict1 | dict2`
|
|
91
|
+
2. Operation method computes new data (checks for key conflicts on union)
|
|
92
|
+
3. Method calls `with_data()` to create a new instance
|
|
93
|
+
4. New instance has the same type and validator (if applicable)
|
|
94
|
+
5. Returns a new immutable dictionary — originals are unchanged
|
|
95
|
+
|
|
96
|
+
## Dependencies
|
|
97
|
+
|
|
98
|
+
- **classcore** `~=1.11`: Class factory mechanism and attribute protection
|
|
99
|
+
- **dynadoc** `~=1.4`: Dynamic documentation generation with reusable fragments
|
|
100
|
+
- **absence** `~=1.1`: Sentinel for absent values (distinguishes missing from `None`)
|
|
101
|
+
- **typing-extensions**: Backported typing features
|
|
102
|
+
|
|
103
|
+
## Exception Hierarchy
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
Omniexception (BaseException)
|
|
107
|
+
└── Omnierror (Exception)
|
|
108
|
+
├── AttributeImmutability (+ AttributeError)
|
|
109
|
+
├── EntryImmutability (+ TypeError)
|
|
110
|
+
├── EntryInvalidity (+ ValueError)
|
|
111
|
+
└── ErrorProvideFailure (+ RuntimeError)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Dual inheritance allows catching via frigid's hierarchy or Python built-ins.
|
|
115
|
+
|
|
116
|
+
## Sister Projects
|
|
117
|
+
|
|
118
|
+
- **[classcore](https://github.com/emcd/python-classcore)** — Foundational class factory and behavior system. Provides the metaclass machinery, attribute protection, and concealment that frigid delegates to.
|
|
119
|
+
- **[accretive](https://github.com/emcd/python-accretive)** — Grow-only data structures. Like frigid, but values can be added (never modified or removed) after creation. Useful for registries, plugin systems, and sticky-state configurations.
|
|
@@ -25,11 +25,3 @@ from .dictionaries import *
|
|
|
25
25
|
from .doctab import *
|
|
26
26
|
from .imports import *
|
|
27
27
|
from .nomina import *
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
dynadoc_introspection_limiter = (
|
|
31
|
-
ccstd.dynadoc.produce_dynadoc_introspection_limiter(
|
|
32
|
-
attributes_namer = calculate_attrname ) )
|
|
33
|
-
dynadoc_introspection_control_on_class = (
|
|
34
|
-
ccstd.dynadoc.produce_dynadoc_introspection_control(
|
|
35
|
-
limiters = ( dynadoc_introspection_limiter, ) ) )
|
|
@@ -31,6 +31,7 @@ import inspect
|
|
|
31
31
|
import sys
|
|
32
32
|
import types
|
|
33
33
|
|
|
34
|
+
import classcore.exceptions as ccexc
|
|
34
35
|
import classcore.standard as ccstd
|
|
35
36
|
import classcore.utilities as ccutils
|
|
36
37
|
import dynadoc as ddoc
|
|
@@ -38,5 +39,6 @@ import typing_extensions as typx
|
|
|
38
39
|
# --- BEGIN: Injected by Copier ---
|
|
39
40
|
# --- END: Injected by Copier ---
|
|
40
41
|
|
|
41
|
-
|
|
42
42
|
from absence import AbsentSingleton, Absential, absent, is_absent
|
|
43
|
+
# --- BEGIN: Injected by Copier ---
|
|
44
|
+
# --- END: Injected by Copier ---
|
|
@@ -23,13 +23,18 @@
|
|
|
23
23
|
# ruff: noqa: F401
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
from classcore.standard.nomina import (
|
|
26
|
+
from classcore.standard.nomina import ( # isort: skip
|
|
27
27
|
AttributesNamer,
|
|
28
28
|
BehaviorExclusionVerifiersOmni,
|
|
29
|
+
ClassDecorator,
|
|
30
|
+
ClassDecorators,
|
|
31
|
+
ClassDecoratorFactory,
|
|
29
32
|
DecorationPreparers as ClassDecorationPreparers,
|
|
30
33
|
DynadocConfiguration,
|
|
34
|
+
ModuleReclassifier,
|
|
31
35
|
concealment_label,
|
|
32
36
|
immutability_label,
|
|
37
|
+
is_public_identifier,
|
|
33
38
|
)
|
|
34
39
|
|
|
35
40
|
from . import imports as __
|
|
@@ -45,16 +50,6 @@ ComparisonResult: __.typx.TypeAlias = bool | __.types.NotImplementedType
|
|
|
45
50
|
NominativeArguments: __.typx.TypeAlias = __.cabc.Mapping[ str, __.typx.Any ]
|
|
46
51
|
PositionalArguments: __.typx.TypeAlias = __.cabc.Sequence[ __.typx.Any ]
|
|
47
52
|
|
|
48
|
-
# TODO: Import ClassDecorator aliases from 'classcore' once documentation
|
|
49
|
-
# fragments have been removed from them.
|
|
50
|
-
ClassDecorator: __.typx.TypeAlias = (
|
|
51
|
-
__.cabc.Callable[ [ type[ U ] ], type[ U ] ] )
|
|
52
|
-
ClassDecorators: __.typx.TypeAlias = (
|
|
53
|
-
__.cabc.Sequence[ ClassDecorator[ U ] ] )
|
|
54
|
-
ClassDecoratorFactory: __.typx.TypeAlias = (
|
|
55
|
-
__.cabc.Callable[ ..., ClassDecorator[ U ] ] )
|
|
56
|
-
ModuleReclassifier: __.typx.TypeAlias = __.cabc.Callable[
|
|
57
|
-
[ __.cabc.Mapping[ str, __.typx.Any ] ], None ]
|
|
58
53
|
|
|
59
54
|
DictionaryNominativeArgument: __.typx.TypeAlias = __.typx.Annotated[
|
|
60
55
|
V,
|
|
@@ -81,9 +76,3 @@ package_name = __name__.split( '.', maxsplit = 1 )[ 0 ]
|
|
|
81
76
|
|
|
82
77
|
def calculate_attrname( level: str, core: str ) -> str:
|
|
83
78
|
return f"_{package_name}_{level}_{core}_"
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
# TODO: Import 'is_public_identifier' from 'classcore'.
|
|
87
|
-
def is_public_identifier( name: str ) -> bool:
|
|
88
|
-
''' Is Python identifier public? '''
|
|
89
|
-
return not name.startswith( '_' )
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
from . import __
|
|
30
|
-
# --- BEGIN: Injected by Copier ---
|
|
31
30
|
from . import exceptions
|
|
31
|
+
# --- BEGIN: Injected by Copier ---
|
|
32
32
|
# --- END: Injected by Copier ---
|
|
33
33
|
|
|
34
34
|
from .classes import *
|
|
@@ -40,7 +40,7 @@ from .sequences import *
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
__version__: __.typx.Annotated[ str, __.ddoc.Visibilities.Reveal ]
|
|
43
|
-
__version__ = '4.
|
|
43
|
+
__version__ = '4.3'
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
finalize_module( __name__, dynadoc_table = __.fragments, recursive = True )
|
|
@@ -26,6 +26,12 @@
|
|
|
26
26
|
from . import __
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
abc_class_mutables = (
|
|
30
|
+
'_abc_cache',
|
|
31
|
+
'_abc_negative_cache',
|
|
32
|
+
'_abc_negative_cache_version',
|
|
33
|
+
'_abc_registry',
|
|
34
|
+
)
|
|
29
35
|
is_public_identifier = __.is_public_identifier
|
|
30
36
|
mutables_default = ( )
|
|
31
37
|
visibles_default = ( is_public_identifier, )
|
|
@@ -44,9 +50,7 @@ def _provide_error_class( name: str ) -> type[ Exception ]:
|
|
|
44
50
|
|
|
45
51
|
_dataclass_core = __.dcls.dataclass( kw_only = True, slots = True )
|
|
46
52
|
_dynadoc_configuration = (
|
|
47
|
-
__.ccstd.dynadoc.produce_dynadoc_configuration(
|
|
48
|
-
introspection = __.dynadoc_introspection_control_on_class,
|
|
49
|
-
table = __.fragments ) )
|
|
53
|
+
__.ccstd.dynadoc.produce_dynadoc_configuration( table = __.fragments ) )
|
|
50
54
|
_class_factory = __.funct.partial(
|
|
51
55
|
__.ccstd.class_factory,
|
|
52
56
|
attributes_namer = __.calculate_attrname,
|
|
@@ -157,7 +161,7 @@ class ProtocolClass( type( __.typx.Protocol ) ):
|
|
|
157
161
|
|
|
158
162
|
@_class_factory( )
|
|
159
163
|
@__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
|
|
160
|
-
class ProtocolDataclass(
|
|
164
|
+
class ProtocolDataclass( ProtocolClass ):
|
|
161
165
|
''' Metaclass for standard protocol dataclasses. '''
|
|
162
166
|
|
|
163
167
|
_dynadoc_fragments_ = (
|
|
@@ -178,7 +182,7 @@ class ProtocolDataclass( type( __.typx.Protocol ) ):
|
|
|
178
182
|
|
|
179
183
|
@_class_factory( )
|
|
180
184
|
@__.typx.dataclass_transform( kw_only_default = True )
|
|
181
|
-
class ProtocolDataclassMutable(
|
|
185
|
+
class ProtocolDataclassMutable( ProtocolDataclass ):
|
|
182
186
|
''' Metaclass for protocol dataclasses with mutable instances.
|
|
183
187
|
'''
|
|
184
188
|
|
|
@@ -232,7 +236,11 @@ class DataclassObjectMutable( metaclass = DataclassMutable ):
|
|
|
232
236
|
'class instance conceal' )
|
|
233
237
|
|
|
234
238
|
|
|
235
|
-
class Protocol(
|
|
239
|
+
class Protocol(
|
|
240
|
+
__.typx.Protocol,
|
|
241
|
+
metaclass = ProtocolClass,
|
|
242
|
+
class_mutables = abc_class_mutables,
|
|
243
|
+
):
|
|
236
244
|
''' Standard base protocol class. '''
|
|
237
245
|
|
|
238
246
|
_dynadoc_fragments_ = (
|
|
@@ -242,7 +250,10 @@ class Protocol( __.typx.Protocol, metaclass = ProtocolClass ):
|
|
|
242
250
|
|
|
243
251
|
|
|
244
252
|
class ProtocolMutable(
|
|
245
|
-
__.typx.Protocol,
|
|
253
|
+
__.typx.Protocol,
|
|
254
|
+
metaclass = ProtocolClass,
|
|
255
|
+
class_mutables = abc_class_mutables,
|
|
256
|
+
instances_mutables = '*',
|
|
246
257
|
):
|
|
247
258
|
''' Base protocol class with mutable instance attributes. '''
|
|
248
259
|
|
|
@@ -253,7 +264,9 @@ class ProtocolMutable(
|
|
|
253
264
|
|
|
254
265
|
|
|
255
266
|
class DataclassProtocol(
|
|
256
|
-
__.typx.Protocol,
|
|
267
|
+
__.typx.Protocol,
|
|
268
|
+
metaclass = ProtocolDataclass,
|
|
269
|
+
class_mutables = abc_class_mutables,
|
|
257
270
|
):
|
|
258
271
|
''' Standard base protocol dataclass. '''
|
|
259
272
|
|
|
@@ -264,7 +277,9 @@ class DataclassProtocol(
|
|
|
264
277
|
|
|
265
278
|
|
|
266
279
|
class DataclassProtocolMutable(
|
|
267
|
-
__.typx.Protocol,
|
|
280
|
+
__.typx.Protocol,
|
|
281
|
+
metaclass = ProtocolDataclassMutable,
|
|
282
|
+
class_mutables = abc_class_mutables,
|
|
268
283
|
):
|
|
269
284
|
''' Base protocol dataclass with mutable instance attributes. '''
|
|
270
285
|
|
|
@@ -120,7 +120,13 @@ class _DictionaryOperations( AbstractDictionary[ __.H, __.V ] ):
|
|
|
120
120
|
|
|
121
121
|
def __ror__( self, other: __.cabc.Mapping[ __.H, __.V ] ) -> __.typx.Self:
|
|
122
122
|
if not isinstance( other, __.cabc.Mapping ): return NotImplemented
|
|
123
|
-
|
|
123
|
+
conflicts = set( self.keys( ) ) & set( other.keys( ) )
|
|
124
|
+
if conflicts:
|
|
125
|
+
from .exceptions import EntryImmutability
|
|
126
|
+
raise EntryImmutability( next( iter( conflicts ) ) )
|
|
127
|
+
data = dict( other )
|
|
128
|
+
data.update( self )
|
|
129
|
+
return self.with_data( data )
|
|
124
130
|
|
|
125
131
|
def __and__(
|
|
126
132
|
self,
|
|
@@ -162,6 +168,7 @@ class _DictionaryOperations( AbstractDictionary[ __.H, __.V ] ):
|
|
|
162
168
|
class Dictionary( # noqa: PLW1641
|
|
163
169
|
_DictionaryOperations[ __.H, __.V ],
|
|
164
170
|
metaclass = _classes.AbstractBaseClass,
|
|
171
|
+
class_mutables = _classes.abc_class_mutables,
|
|
165
172
|
):
|
|
166
173
|
''' Immutable dictionary. '''
|
|
167
174
|
|
|
@@ -32,8 +32,8 @@ from . import classes as _classes
|
|
|
32
32
|
|
|
33
33
|
class Omniexception(
|
|
34
34
|
_classes.Object, BaseException,
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
instances_mutables = __.ccexc.exception_mutables_default,
|
|
36
|
+
instances_visibles = __.ccexc.exception_visibles_default,
|
|
37
37
|
):
|
|
38
38
|
''' Base exceptions for package. '''
|
|
39
39
|
|
|
@@ -59,9 +59,9 @@ class Namespace( metaclass = _classes.Class ): # noqa: PLW1641
|
|
|
59
59
|
*iterables: __.DictionaryPositionalArgument[ __.H, __.V ],
|
|
60
60
|
**attributes: __.DictionaryNominativeArgument[ __.V ],
|
|
61
61
|
) -> None:
|
|
62
|
-
self.__dict__.update(
|
|
62
|
+
self.__dict__.update( # pyright: ignore
|
|
63
63
|
__.ImmutableDictionary(
|
|
64
|
-
*iterables, **attributes ) )
|
|
64
|
+
*iterables, **attributes ) )
|
|
65
65
|
super( ).__init__( )
|
|
66
66
|
|
|
67
67
|
def __repr__( self ) -> str:
|
frigid-4.1/.gitignore
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|