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 ADDED
@@ -0,0 +1,7 @@
1
+ .env
2
+ *.so
3
+ .*.swp
4
+ __pycache__/
5
+ bugs/
6
+ build/
7
+ dist/
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: frigid
3
- Version: 4.1
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.4
28
- Requires-Dist: dynadoc~=1.2
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
- `More Flair <https://www.imdb.com/title/tt0151804/characters/nm0431918>`_
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
- `More Flair <https://www.imdb.com/title/tt0151804/characters/nm0431918>`_
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.4',
20
- 'dynadoc~=1.2',
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' # TODO? '--fail-under'
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
- 'packaging',
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
- documentation .auxiliary/artifacts/sphinx-linkcheck""",
126
- """sphinx-build -a -d .auxiliary/caches/sphinx \
127
- documentation .auxiliary/artifacts/sphinx-html""",
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
- """coverage run -m sphinx.cmd.build \
144
- -E -b doctest -d .auxiliary/caches/sphinx \
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
- 'pypy3.10',
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' ] # Stronger hint for language server.
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 = '--capture=no --exitfirst -rfE'
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
- filterwarnings = [ 'ignore::DeprecationWarning' ]
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.1'
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( type( __.typx.Protocol ) ):
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( type( __.typx.Protocol ) ):
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( __.typx.Protocol, metaclass = ProtocolClass ):
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, metaclass = ProtocolClass, instances_mutables = '*'
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, metaclass = ProtocolDataclass,
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, metaclass = ProtocolDataclassMutable,
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
- return self | other
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
- instances_visibles = (
36
- '__cause__', '__context__', _classes.is_public_identifier ),
35
+ instances_mutables = __.ccexc.exception_mutables_default,
36
+ instances_visibles = __.ccexc.exception_visibles_default,
37
37
  ):
38
38
  ''' Base exceptions for package. '''
39
39
 
@@ -130,4 +130,5 @@ def reclassify_modules(
130
130
  __.ccstd.reclassify_modules(
131
131
  module,
132
132
  attributes_namer = __.calculate_attrname,
133
+ recursive = recursive,
133
134
  replacement_class = Module )
@@ -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 ) ) # pyright: ignore
64
+ *iterables, **attributes ) )
65
65
  super( ).__init__( )
66
66
 
67
67
  def __repr__( self ) -> str:
frigid-4.1/.gitignore DELETED
@@ -1,10 +0,0 @@
1
- .env
2
- .gemini
3
- .mcp.json
4
- .*.swp
5
- AGENTS.md
6
- CLAUDE.md
7
- CONVENTIONS.md
8
- GEMINI.md
9
- __pycache__/
10
- bugs/
File without changes
File without changes
File without changes
File without changes
File without changes