Coverage for sources/frigid/__/dictionaries.py: 100%
35 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-07-02 16:24 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-07-02 16:24 +0000
1# vim: set filetype=python fileencoding=utf-8:
2# -*- coding: utf-8 -*-
4#============================================================================#
5# #
6# Licensed under the Apache License, Version 2.0 (the "License"); #
7# you may not use this file except in compliance with the License. #
8# You may obtain a copy of the License at #
9# #
10# http://www.apache.org/licenses/LICENSE-2.0 #
11# #
12# Unless required by applicable law or agreed to in writing, software #
13# distributed under the License is distributed on an "AS IS" BASIS, #
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15# See the License for the specific language governing permissions and #
16# limitations under the License. #
17# #
18#============================================================================#
21''' Internal dictionary. '''
24# TODO: Consider a dictionary factory to allow 'mutables' closure
25# to be referenced in the '__setitem__' and '__delitem__' methods.
28from . import imports as __
29from . import nomina as _nomina
32_H = __.typx.TypeVar( '_H' )
33_V = __.typx.TypeVar( '_V' )
36_immutability_label = 'immutability'
39class ImmutableDictionary(
40 dict[ _H, _V ],
41 __.ccstd.Object,
42 __.typx.Generic[ _H, _V ],
43):
44 ''' Immutable subclass of :py:class:`dict`.
46 Can be used as an instance dictionary.
48 Prevents attempts to mutate dictionary via inherited interface.
49 '''
51 def __init__(
52 self,
53 *iterables: _nomina.DictionaryPositionalArgument[ _H, _V ],
54 **entries: _nomina.DictionaryNominativeArgument[ _V ],
55 ):
56 self._behaviors_: set[ str ] = set( )
57 super( ).__init__( )
58 from itertools import chain
59 # Add values in order received, enforcing no alteration.
60 for indicator, value in chain.from_iterable( map( # pyright: ignore
61 lambda element: ( # pyright: ignore
62 element.items( )
63 if isinstance( element, __.cabc.Mapping )
64 else element
65 ),
66 ( *iterables, entries )
67 ) ): self[ indicator ] = value # pyright: ignore
68 self._behaviors_.add( _immutability_label )
70 def __delitem__( self, key: _H ) -> None:
71 from .exceptions import EntryImmutability
72 raise EntryImmutability( key )
74 def __setitem__( self, key: _H, value: _V ) -> None:
75 from .exceptions import EntryImmutability
76 default: set[ str ] = set( )
77 if _immutability_label in getattr(
78 self, '_behaviors_', default
79 ): raise EntryImmutability( key )
80 if key in self: raise EntryImmutability( key )
81 super( ).__setitem__( key, value )
83 def clear( self ) -> __.typx.Never:
84 ''' Raises exception. Cannot clear immutable entries. '''
85 from .exceptions import OperationInvalidity
86 raise OperationInvalidity( 'clear' )
88 def copy( self ) -> __.typx.Self:
89 ''' Provides fresh copy of dictionary. '''
90 return type( self )( self )
92 def pop( # pyright: ignore
93 self, key: _H, default: __.Absential[ _V ] = __.absent
94 ) -> __.typx.Never:
95 ''' Raises exception. Cannot pop immutable entry. '''
96 from .exceptions import OperationInvalidity
97 raise OperationInvalidity( 'pop' )
99 def popitem( self ) -> __.typx.Never:
100 ''' Raises exception. Cannot pop immutable entry. '''
101 from .exceptions import OperationInvalidity
102 raise OperationInvalidity( 'popitem' )
104 def update( # pyright: ignore
105 self,
106 *iterables: _nomina.DictionaryPositionalArgument[ _H, _V ],
107 **entries: _nomina.DictionaryNominativeArgument[ _V ],
108 ) -> None:
109 ''' Raises exception. Cannot perform mass update. '''
110 from .exceptions import OperationInvalidity
111 raise OperationInvalidity( 'update' )