frigid 4.2__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.2
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
 
@@ -282,6 +283,9 @@ Other Projects by This Author 🌟
282
283
  * `python-classcore <https://github.com/emcd/python-classcore>`_ (`classcore <https://pypi.org/project/classcore/>`_ on PyPI)
283
284
 
284
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.
285
289
  * `python-dynadoc <https://github.com/emcd/python-dynadoc>`_ (`dynadoc <https://pypi.org/project/dynadoc/>`_ on PyPI)
286
290
 
287
291
  📝 A Python library package which bridges the gap between **rich annotations** and **automatic documentation generation** with configurable renderers and support for reusable fragments.
@@ -291,6 +295,9 @@ Other Projects by This Author 🌟
291
295
  * `python-icecream-truck <https://github.com/emcd/python-icecream-truck>`_ (`icecream-truck <https://pypi.org/project/icecream-truck/>`_ on PyPI)
292
296
 
293
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.
294
301
  * `python-mimeogram <https://github.com/emcd/python-mimeogram>`_ (`mimeogram <https://pypi.org/project/mimeogram/>`_ on PyPI)
295
302
 
296
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.
@@ -251,6 +251,9 @@ Other Projects by This Author 🌟
251
251
  * `python-classcore <https://github.com/emcd/python-classcore>`_ (`classcore <https://pypi.org/project/classcore/>`_ on PyPI)
252
252
 
253
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.
254
257
  * `python-dynadoc <https://github.com/emcd/python-dynadoc>`_ (`dynadoc <https://pypi.org/project/dynadoc/>`_ on PyPI)
255
258
 
256
259
  📝 A Python library package which bridges the gap between **rich annotations** and **automatic documentation generation** with configurable renderers and support for reusable fragments.
@@ -260,6 +263,9 @@ Other Projects by This Author 🌟
260
263
  * `python-icecream-truck <https://github.com/emcd/python-icecream-truck>`_ (`icecream-truck <https://pypi.org/project/icecream-truck/>`_ on PyPI)
261
264
 
262
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.
263
269
  * `python-mimeogram <https://github.com/emcd/python-mimeogram>`_ (`mimeogram <https://pypi.org/project/mimeogram/>`_ on PyPI)
264
270
 
265
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 ---
@@ -95,12 +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',
103
- 'packaging',
104
+ 'myst-parser',
104
105
  'pre-commit',
105
106
  'pyright',
106
107
  'pytest',
@@ -130,10 +131,10 @@ docsgen = [
130
131
  ]
131
132
  linters = [
132
133
  """ruff check --quiet sources documentation tests""",
134
+ """vibelinter check""",
133
135
  # --- BEGIN: Injected by Copier ---
134
136
  # --- END: Injected by Copier ---
135
137
  """isort --check-only --diff sources tests""",
136
- """vulture""",
137
138
  """pyright sources""",
138
139
  ]
139
140
  packagers = [
@@ -175,7 +176,8 @@ python = [
175
176
  '3.11',
176
177
  '3.12',
177
178
  '3.13',
178
- 'pypy3.10',
179
+ '3.14',
180
+ 'pypy3.11',
179
181
  ]
180
182
  [tool.hatch.version]
181
183
  path = 'sources/frigid/__init__.py'
@@ -348,6 +350,14 @@ directory = 'repair'
348
350
  name = 'Repairs'
349
351
  showcontent = true
350
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
+
351
361
  [tool.vulture]
352
362
  paths = [ '.auxiliary/configuration/vulturefood.py', 'sources' ]
353
363
  min_confidence = 60
@@ -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.
@@ -39,5 +39,6 @@ import typing_extensions as typx
39
39
  # --- BEGIN: Injected by Copier ---
40
40
  # --- END: Injected by Copier ---
41
41
 
42
-
43
42
  from absence import AbsentSingleton, Absential, absent, is_absent
43
+ # --- BEGIN: Injected by Copier ---
44
+ # --- END: Injected by Copier ---
@@ -26,10 +26,15 @@
26
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.2'
43
+ __version__ = '4.3'
44
44
 
45
45
 
46
46
  finalize_module( __name__, dynadoc_table = __.fragments, recursive = True )
@@ -161,7 +161,7 @@ class ProtocolClass( type( __.typx.Protocol ) ):
161
161
 
162
162
  @_class_factory( )
163
163
  @__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
164
- class ProtocolDataclass( type( __.typx.Protocol ) ):
164
+ class ProtocolDataclass( ProtocolClass ):
165
165
  ''' Metaclass for standard protocol dataclasses. '''
166
166
 
167
167
  _dynadoc_fragments_ = (
@@ -182,7 +182,7 @@ class ProtocolDataclass( type( __.typx.Protocol ) ):
182
182
 
183
183
  @_class_factory( )
184
184
  @__.typx.dataclass_transform( kw_only_default = True )
185
- class ProtocolDataclassMutable( type( __.typx.Protocol ) ):
185
+ class ProtocolDataclassMutable( ProtocolDataclass ):
186
186
  ''' Metaclass for protocol dataclasses with mutable instances.
187
187
  '''
188
188
 
@@ -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,
@@ -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.2/.gitignore DELETED
@@ -1,15 +0,0 @@
1
- .env
2
- .claude
3
- .gemini
4
- .mcp.json
5
- .opencode
6
- .*.swp
7
- AGENTS.md
8
- CLAUDE.md
9
- CONVENTIONS.md
10
- GEMINI.md
11
- opencode.jsonc
12
- __pycache__/
13
- bugs/
14
- build/
15
- dist/
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes