frigid 1.0__py3-none-any.whl
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/__.py +395 -0
- frigid/__init__.py +59 -0
- frigid/_annotations.py +42 -0
- frigid/_docstrings.py +72 -0
- frigid/_typedecls/__builtins__.pyi +28 -0
- frigid/classes.py +226 -0
- frigid/dictionaries.py +315 -0
- frigid/exceptions.py +88 -0
- frigid/modules.py +66 -0
- frigid/namespaces.py +86 -0
- frigid/objects.py +129 -0
- frigid/py.typed +0 -0
- frigid/qaliases.py +64 -0
- frigid-1.0.dist-info/METADATA +217 -0
- frigid-1.0.dist-info/RECORD +17 -0
- frigid-1.0.dist-info/WHEEL +4 -0
- frigid-1.0.dist-info/licenses/LICENSE.txt +202 -0
frigid/__.py
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# vim: set filetype=python fileencoding=utf-8:
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
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
|
+
#============================================================================#
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
''' Common constants, imports, and utilities. '''
|
|
22
|
+
|
|
23
|
+
# ruff: noqa: F401
|
|
24
|
+
# pylint: disable=unused-import
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import collections.abc as cabc
|
|
30
|
+
|
|
31
|
+
from abc import (
|
|
32
|
+
ABCMeta as ABCFactory,
|
|
33
|
+
abstractmethod as abstract_member_function,
|
|
34
|
+
)
|
|
35
|
+
from functools import partial as partial_function
|
|
36
|
+
from inspect import cleandoc as clean_docstring
|
|
37
|
+
from sys import modules
|
|
38
|
+
from types import (
|
|
39
|
+
MappingProxyType as DictionaryProxy,
|
|
40
|
+
ModuleType as Module,
|
|
41
|
+
NotImplementedType as TypeofNotImplemented,
|
|
42
|
+
SimpleNamespace,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
from . import _annotations as a
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
C = a.TypeVar( 'C' ) # Class
|
|
49
|
+
H = a.TypeVar( 'H', bound = cabc.Hashable ) # Hash Key
|
|
50
|
+
V = a.TypeVar( 'V' ) # Value
|
|
51
|
+
_H = a.TypeVar( '_H' )
|
|
52
|
+
_V = a.TypeVar( '_V' )
|
|
53
|
+
|
|
54
|
+
ClassDecorators: a.TypeAlias = (
|
|
55
|
+
cabc.Iterable[ cabc.Callable[ [ type ], type ] ] )
|
|
56
|
+
ComparisonResult: a.TypeAlias = bool | TypeofNotImplemented
|
|
57
|
+
DictionaryNominativeArgument: a.TypeAlias = a.Annotation[
|
|
58
|
+
V,
|
|
59
|
+
a.Doc(
|
|
60
|
+
'Zero or more keyword arguments from which to initialize '
|
|
61
|
+
'dictionary data.' ),
|
|
62
|
+
]
|
|
63
|
+
DictionaryPositionalArgument: a.TypeAlias = a.Annotation[
|
|
64
|
+
cabc.Mapping[ H, V ] | cabc.Iterable[ tuple[ H, V ] ],
|
|
65
|
+
a.Doc(
|
|
66
|
+
'Zero or more iterables from which to initialize dictionary data. '
|
|
67
|
+
'Each iterable must be dictionary or sequence of key-value pairs. '
|
|
68
|
+
'Duplicate keys will result in an error.' ),
|
|
69
|
+
]
|
|
70
|
+
DictionaryValidator: a.TypeAlias = a.Annotation[
|
|
71
|
+
cabc.Callable[ [ H, V ], bool ],
|
|
72
|
+
a.Doc( 'Callable which validates entries before addition to dictionary.' ),
|
|
73
|
+
]
|
|
74
|
+
ModuleReclassifier: a.TypeAlias = cabc.Callable[
|
|
75
|
+
[ cabc.Mapping[ str, a.Any ] ], None ]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
behavior_label = 'immutability'
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def repair_class_reproduction( original: type, reproduction: type ) -> None:
|
|
82
|
+
''' Repairs a class reproduction, if necessary. '''
|
|
83
|
+
from platform import python_implementation
|
|
84
|
+
match python_implementation( ):
|
|
85
|
+
case 'CPython': # pragma: no branch
|
|
86
|
+
_repair_cpython_class_closures( original, reproduction )
|
|
87
|
+
case _: pass # pragma: no cover
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _repair_cpython_class_closures( # pylint: disable=too-complex
|
|
91
|
+
original: type, reproduction: type
|
|
92
|
+
) -> None:
|
|
93
|
+
def try_repair_closure( function: cabc.Callable[ ..., a.Any ] ) -> bool:
|
|
94
|
+
try: index = function.__code__.co_freevars.index( '__class__' )
|
|
95
|
+
except ValueError: return False
|
|
96
|
+
if not function.__closure__: return False # pragma: no branch
|
|
97
|
+
closure = function.__closure__[ index ]
|
|
98
|
+
if original is closure.cell_contents: # pragma: no branch
|
|
99
|
+
closure.cell_contents = reproduction
|
|
100
|
+
return True
|
|
101
|
+
return False # pragma: no cover
|
|
102
|
+
|
|
103
|
+
from inspect import isfunction, unwrap
|
|
104
|
+
for attribute in reproduction.__dict__.values( ): # pylint: disable=too-many-nested-blocks
|
|
105
|
+
attribute_ = unwrap( attribute )
|
|
106
|
+
if isfunction( attribute_ ) and try_repair_closure( attribute_ ):
|
|
107
|
+
return
|
|
108
|
+
if isinstance( attribute_, property ):
|
|
109
|
+
for aname in ( 'fget', 'fset', 'fdel' ):
|
|
110
|
+
accessor = getattr( attribute_, aname )
|
|
111
|
+
if None is accessor: continue
|
|
112
|
+
if try_repair_closure( accessor ): return # pragma: no branch
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class InternalClass( type ):
|
|
116
|
+
''' Concealment and immutability on class attributes. '''
|
|
117
|
+
|
|
118
|
+
_class_attribute_visibility_includes_: cabc.Collection[ str ] = (
|
|
119
|
+
frozenset( ) )
|
|
120
|
+
|
|
121
|
+
def __new__(
|
|
122
|
+
factory: type[ type ],
|
|
123
|
+
name: str,
|
|
124
|
+
bases: tuple[ type, ... ],
|
|
125
|
+
namespace: dict[ str, a.Any ], *,
|
|
126
|
+
decorators: ClassDecorators = ( ),
|
|
127
|
+
**args: a.Any
|
|
128
|
+
) -> InternalClass:
|
|
129
|
+
class_ = type.__new__( factory, name, bases, namespace, **args )
|
|
130
|
+
return _immutable_class__new__( class_, decorators = decorators )
|
|
131
|
+
|
|
132
|
+
def __init__( selfclass, *posargs: a.Any, **nomargs: a.Any ):
|
|
133
|
+
super( ).__init__( *posargs, **nomargs )
|
|
134
|
+
_immutable_class__init__( selfclass )
|
|
135
|
+
|
|
136
|
+
def __dir__( selfclass ) -> tuple[ str, ... ]:
|
|
137
|
+
default: frozenset[ str ] = frozenset( )
|
|
138
|
+
includes: frozenset[ str ] = frozenset.union( *( # type: ignore
|
|
139
|
+
getattr( class_, '_class_attribute_visibility_includes_', default )
|
|
140
|
+
for class_ in selfclass.__mro__ ) )
|
|
141
|
+
return tuple( sorted(
|
|
142
|
+
name for name in super( ).__dir__( )
|
|
143
|
+
if not name.startswith( '_' ) or name in includes ) )
|
|
144
|
+
|
|
145
|
+
def __delattr__( selfclass, name: str ) -> None:
|
|
146
|
+
if not _immutable_class__delattr__( selfclass, name ):
|
|
147
|
+
super( ).__delattr__( name )
|
|
148
|
+
|
|
149
|
+
def __setattr__( selfclass, name: str, value: a.Any ) -> None:
|
|
150
|
+
if not _immutable_class__setattr__( selfclass, name ):
|
|
151
|
+
super( ).__setattr__( name, value )
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _immutable_class__new__(
|
|
155
|
+
original: type,
|
|
156
|
+
decorators: ClassDecorators = ( ),
|
|
157
|
+
) -> type:
|
|
158
|
+
# Some decorators create new classes, which invokes this method again.
|
|
159
|
+
# Short-circuit to prevent recursive decoration and other tangles.
|
|
160
|
+
decorators_ = original.__dict__.get( '_class_decorators_', [ ] )
|
|
161
|
+
if decorators_: return original
|
|
162
|
+
setattr( original, '_class_decorators_', decorators_ )
|
|
163
|
+
reproduction = original
|
|
164
|
+
for decorator in decorators:
|
|
165
|
+
decorators_.append( decorator )
|
|
166
|
+
reproduction = decorator( original )
|
|
167
|
+
if original is not reproduction:
|
|
168
|
+
repair_class_reproduction( original, reproduction )
|
|
169
|
+
original = reproduction
|
|
170
|
+
decorators_.clear( ) # Flag '__init__' to enable immutability
|
|
171
|
+
return reproduction
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _immutable_class__init__( class_: type ) -> None:
|
|
175
|
+
# Some metaclasses add class attributes in '__init__' method.
|
|
176
|
+
# So, we wait until last possible moment to set immutability.
|
|
177
|
+
if class_.__dict__.get( '_class_decorators_' ): return
|
|
178
|
+
del class_._class_decorators_
|
|
179
|
+
if ( class_behaviors := class_.__dict__.get( '_class_behaviors_' ) ):
|
|
180
|
+
class_behaviors.add( behavior_label )
|
|
181
|
+
else: setattr( class_, '_class_behaviors_', { behavior_label } )
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _immutable_class__delattr__( class_: type, name: str ) -> bool:
|
|
185
|
+
# Consult class attributes dictionary to ignore immutable base classes.
|
|
186
|
+
if behavior_label not in class_.__dict__.get(
|
|
187
|
+
'_class_behaviors_', ( )
|
|
188
|
+
): return False
|
|
189
|
+
raise AttributeError(
|
|
190
|
+
"Cannot delete attribute {name!r} "
|
|
191
|
+
"on class {class_fqname!r}.".format(
|
|
192
|
+
name = name,
|
|
193
|
+
class_fqname = calculate_class_fqname( class_ ) ) )
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _immutable_class__setattr__( class_: type, name: str ) -> bool:
|
|
197
|
+
# Consult class attributes dictionary to ignore immutable base classes.
|
|
198
|
+
if behavior_label not in class_.__dict__.get(
|
|
199
|
+
'_class_behaviors_', ( )
|
|
200
|
+
): return False
|
|
201
|
+
raise AttributeError(
|
|
202
|
+
"Cannot assign attribute {name!r} "
|
|
203
|
+
"on class {class_fqname!r}.".format(
|
|
204
|
+
name = name,
|
|
205
|
+
class_fqname = calculate_class_fqname( class_ ) ) )
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class ConcealerExtension:
|
|
209
|
+
''' Conceals instance attributes according to some criteria.
|
|
210
|
+
|
|
211
|
+
By default, public attributes are displayed.
|
|
212
|
+
'''
|
|
213
|
+
|
|
214
|
+
_attribute_visibility_includes_: cabc.Collection[ str ] = frozenset( )
|
|
215
|
+
|
|
216
|
+
def __dir__( self ) -> tuple[ str, ... ]:
|
|
217
|
+
return tuple( sorted(
|
|
218
|
+
name for name in super( ).__dir__( )
|
|
219
|
+
if not name.startswith( '_' )
|
|
220
|
+
or name in self._attribute_visibility_includes_ ) )
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class InternalObject( ConcealerExtension, metaclass = InternalClass ):
|
|
224
|
+
''' Concealment and immutability on instance attributes. '''
|
|
225
|
+
|
|
226
|
+
def __delattr__( self, name: str ) -> None:
|
|
227
|
+
raise AttributeError(
|
|
228
|
+
"Cannot delete attribute {name!r} on instance "
|
|
229
|
+
"of class {class_fqname!r}.".format(
|
|
230
|
+
name = name, class_fqname = calculate_fqname( self ) ) )
|
|
231
|
+
|
|
232
|
+
def __setattr__( self, name: str, value: a.Any ) -> None:
|
|
233
|
+
raise AttributeError(
|
|
234
|
+
"Cannot assign attribute {name!r} on instance "
|
|
235
|
+
"of class {class_fqname!r}.".format(
|
|
236
|
+
name = name, class_fqname = calculate_fqname( self ) ) )
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class Falsifier( metaclass = InternalClass ): # pylint: disable=eq-without-hash
|
|
240
|
+
''' Produces falsey objects.
|
|
241
|
+
|
|
242
|
+
Why not something already in Python?
|
|
243
|
+
:py:class:`object` produces truthy objects.
|
|
244
|
+
:py:class:`types.NoneType` "produces" falsey ``None`` singleton.
|
|
245
|
+
:py:class:`typing_extensions.NoDefault` is truthy singleton.
|
|
246
|
+
'''
|
|
247
|
+
|
|
248
|
+
def __bool__( self ) -> bool: return False
|
|
249
|
+
|
|
250
|
+
def __eq__( self, other: a.Any ) -> ComparisonResult:
|
|
251
|
+
return self is other
|
|
252
|
+
|
|
253
|
+
def __ne__( self, other: a.Any ) -> ComparisonResult:
|
|
254
|
+
return self is not other
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class Absent( Falsifier, InternalObject ):
|
|
258
|
+
''' Type of the sentinel for option without default value. '''
|
|
259
|
+
|
|
260
|
+
def __new__( selfclass ) -> a.Self:
|
|
261
|
+
''' Singleton. '''
|
|
262
|
+
absent_ = globals( ).get( 'absent' )
|
|
263
|
+
if isinstance( absent_, selfclass ): return absent_
|
|
264
|
+
return super( ).__new__( selfclass )
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
Optional: a.TypeAlias = V | Absent
|
|
268
|
+
absent: a.Annotation[
|
|
269
|
+
Absent, a.Doc( ''' Sentinel for option with no default value. ''' )
|
|
270
|
+
] = Absent( )
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def is_absent( value: object ) -> a.TypeIs[ Absent ]:
|
|
274
|
+
''' Checks if a value is absent or not. '''
|
|
275
|
+
return absent is value
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class ImmutableDictionary(
|
|
279
|
+
ConcealerExtension,
|
|
280
|
+
dict[ _H, _V ],
|
|
281
|
+
a.Generic[ _H, _V ],
|
|
282
|
+
):
|
|
283
|
+
''' Immutable subclass of :py:class:`dict`.
|
|
284
|
+
|
|
285
|
+
Can be used as an instance dictionary.
|
|
286
|
+
|
|
287
|
+
Prevents attempts to mutate dictionary via inherited interface.
|
|
288
|
+
'''
|
|
289
|
+
|
|
290
|
+
def __init__(
|
|
291
|
+
self,
|
|
292
|
+
*iterables: DictionaryPositionalArgument[ _H, _V ],
|
|
293
|
+
**entries: DictionaryNominativeArgument[ _V ],
|
|
294
|
+
):
|
|
295
|
+
self._behaviors_: set[ str ] = set( )
|
|
296
|
+
super( ).__init__( )
|
|
297
|
+
from itertools import chain
|
|
298
|
+
# Add values in order received, enforcing no alteration.
|
|
299
|
+
for indicator, value in chain.from_iterable( map( # type: ignore
|
|
300
|
+
lambda element: ( # type: ignore
|
|
301
|
+
element.items( )
|
|
302
|
+
if isinstance( element, cabc.Mapping )
|
|
303
|
+
else element
|
|
304
|
+
),
|
|
305
|
+
( *iterables, entries )
|
|
306
|
+
) ): self[ indicator ] = value # type: ignore
|
|
307
|
+
self._behaviors_.add( behavior_label )
|
|
308
|
+
|
|
309
|
+
def __delitem__( self, key: _H ) -> None:
|
|
310
|
+
from .exceptions import EntryImmutabilityError
|
|
311
|
+
raise EntryImmutabilityError( key )
|
|
312
|
+
|
|
313
|
+
def __setitem__( self, key: _H, value: _V ) -> None:
|
|
314
|
+
from .exceptions import EntryImmutabilityError
|
|
315
|
+
default: set[ str ] = set( )
|
|
316
|
+
if behavior_label in getattr( self, '_behaviors_', default ):
|
|
317
|
+
raise EntryImmutabilityError( key )
|
|
318
|
+
if key in self:
|
|
319
|
+
raise EntryImmutabilityError( key )
|
|
320
|
+
super( ).__setitem__( key, value )
|
|
321
|
+
|
|
322
|
+
def clear( self ) -> a.Never:
|
|
323
|
+
''' Raises exception. Cannot clear immutable entries. '''
|
|
324
|
+
from .exceptions import OperationValidityError
|
|
325
|
+
raise OperationValidityError( 'clear' )
|
|
326
|
+
|
|
327
|
+
def copy( self ) -> a.Self:
|
|
328
|
+
''' Provides fresh copy of dictionary. '''
|
|
329
|
+
return type( self )( self )
|
|
330
|
+
|
|
331
|
+
def pop( # pylint: disable=unused-argument
|
|
332
|
+
self, key: _H, default: Optional[ _V ] = absent
|
|
333
|
+
) -> a.Never:
|
|
334
|
+
''' Raises exception. Cannot pop immutable entry. '''
|
|
335
|
+
from .exceptions import OperationValidityError
|
|
336
|
+
raise OperationValidityError( 'pop' )
|
|
337
|
+
|
|
338
|
+
def popitem( self ) -> a.Never:
|
|
339
|
+
''' Raises exception. Cannot pop immutable entry. '''
|
|
340
|
+
from .exceptions import OperationValidityError
|
|
341
|
+
raise OperationValidityError( 'popitem' )
|
|
342
|
+
|
|
343
|
+
def update( # type: ignore
|
|
344
|
+
self, # pylint: disable=unused-argument
|
|
345
|
+
*iterables: DictionaryPositionalArgument[ _H, _V ],
|
|
346
|
+
**entries: DictionaryNominativeArgument[ _V ],
|
|
347
|
+
) -> None:
|
|
348
|
+
''' Raises exception. Cannot perform mass update. '''
|
|
349
|
+
from .exceptions import OperationValidityError
|
|
350
|
+
raise OperationValidityError( 'update' )
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
class Docstring( str ):
|
|
354
|
+
''' Dedicated docstring container. '''
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def calculate_class_fqname( class_: type ) -> str:
|
|
358
|
+
''' Calculates fully-qualified name for class. '''
|
|
359
|
+
return f"{class_.__module__}.{class_.__qualname__}"
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def calculate_fqname( obj: object ) -> str:
|
|
363
|
+
''' Calculates fully-qualified name for class of object. '''
|
|
364
|
+
class_ = type( obj )
|
|
365
|
+
return f"{class_.__module__}.{class_.__qualname__}"
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def discover_public_attributes(
|
|
369
|
+
attributes: cabc.Mapping[ str, a.Any ]
|
|
370
|
+
) -> tuple[ str, ... ]:
|
|
371
|
+
''' Discovers public attributes of certain types from dictionary.
|
|
372
|
+
|
|
373
|
+
By default, callables, including classes, are discovered.
|
|
374
|
+
'''
|
|
375
|
+
return tuple( sorted(
|
|
376
|
+
name for name, attribute in attributes.items( )
|
|
377
|
+
if not name.startswith( '_' ) and callable( attribute ) ) )
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def generate_docstring(
|
|
381
|
+
*fragment_ids: type | Docstring | str
|
|
382
|
+
) -> str:
|
|
383
|
+
''' Sews together docstring fragments into clean docstring. '''
|
|
384
|
+
from inspect import cleandoc, getdoc, isclass
|
|
385
|
+
from ._docstrings import TABLE
|
|
386
|
+
fragments: list[ str ] = [ ]
|
|
387
|
+
for fragment_id in fragment_ids:
|
|
388
|
+
if isclass( fragment_id ): fragment = getdoc( fragment_id ) or ''
|
|
389
|
+
elif isinstance( fragment_id, Docstring ): fragment = fragment_id
|
|
390
|
+
else: fragment = TABLE[ fragment_id ]
|
|
391
|
+
fragments.append( cleandoc( fragment ) )
|
|
392
|
+
return '\n\n'.join( fragments )
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
__all__ = ( )
|
frigid/__init__.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# vim: set filetype=python fileencoding=utf-8:
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
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
|
+
#============================================================================#
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
''' Immutable data structures. '''
|
|
22
|
+
|
|
23
|
+
# ruff: noqa: F401,F403
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
from . import __
|
|
27
|
+
from . import classes
|
|
28
|
+
from . import dictionaries
|
|
29
|
+
from . import exceptions
|
|
30
|
+
from . import modules
|
|
31
|
+
from . import namespaces
|
|
32
|
+
from . import objects
|
|
33
|
+
from . import qaliases
|
|
34
|
+
|
|
35
|
+
from .classes import *
|
|
36
|
+
from .dictionaries import *
|
|
37
|
+
from .modules import *
|
|
38
|
+
from .namespaces import *
|
|
39
|
+
from .objects import *
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
__version__ = '1.0'
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
_attribute_visibility_includes_ = frozenset( ( '__version__', ) )
|
|
46
|
+
|
|
47
|
+
class _InternalModule( __.InternalObject, __.Module ): pass # type: ignore
|
|
48
|
+
def _reclassify_modules(
|
|
49
|
+
attributes: __.cabc.Mapping[ str, __.a.Any ]
|
|
50
|
+
) -> None:
|
|
51
|
+
from inspect import ismodule
|
|
52
|
+
for attribute in attributes.values( ):
|
|
53
|
+
if not ismodule( attribute ): continue
|
|
54
|
+
if isinstance( attribute, _InternalModule ):
|
|
55
|
+
continue # pragma: no coverage
|
|
56
|
+
attribute.__class__ = _InternalModule
|
|
57
|
+
|
|
58
|
+
_reclassify_modules( globals( ) )
|
|
59
|
+
__.modules[ __name__ ].__class__ = _InternalModule
|
frigid/_annotations.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# vim: set filetype=python fileencoding=utf-8:
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
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
|
+
#============================================================================#
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
''' Standard annotations across Python versions. '''
|
|
22
|
+
|
|
23
|
+
# ruff: noqa: F401
|
|
24
|
+
# pylint: disable=unused-import
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
from typing_extensions import (
|
|
28
|
+
Annotated as Annotation,
|
|
29
|
+
Any,
|
|
30
|
+
Doc,
|
|
31
|
+
Generic,
|
|
32
|
+
Never,
|
|
33
|
+
Optional as Nullable,
|
|
34
|
+
Protocol,
|
|
35
|
+
Self,
|
|
36
|
+
TypeAlias,
|
|
37
|
+
TypeIs,
|
|
38
|
+
TypeVar,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
__all__ = ( )
|
frigid/_docstrings.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# vim: set filetype=python fileencoding=utf-8:
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
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
|
+
#============================================================================#
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
''' Docstrings table for reuse across subpackages. '''
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
from types import MappingProxyType as _DictionaryProxy
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
TABLE: _DictionaryProxy[ str, str ] = _DictionaryProxy( {
|
|
28
|
+
|
|
29
|
+
'class attributes immutability': '''
|
|
30
|
+
Prevents assignment or deletion of class attributes after class creation.
|
|
31
|
+
''',
|
|
32
|
+
|
|
33
|
+
'description of class factory class': '''
|
|
34
|
+
Derived from :py:class:`type`, this is a metaclass. A metaclass is a class
|
|
35
|
+
factory class. I.e., it is a class that produces other classes as its
|
|
36
|
+
instances.
|
|
37
|
+
''',
|
|
38
|
+
|
|
39
|
+
'description of module': '''
|
|
40
|
+
Derived from :py:class:`types.ModuleType`, this class is suitable for use as a
|
|
41
|
+
Python module class.
|
|
42
|
+
''',
|
|
43
|
+
|
|
44
|
+
'description of namespace': '''
|
|
45
|
+
A namespace is an object, whose attributes can be determined from iterables and
|
|
46
|
+
keyword arguments, at initialization time. The string representation of the
|
|
47
|
+
namespace object reflects its current instance attributes. Modeled after
|
|
48
|
+
:py:class:`types.SimpleNamespace`.
|
|
49
|
+
''',
|
|
50
|
+
|
|
51
|
+
'dictionary entries immutability': '''
|
|
52
|
+
Prevents addition, alteration, or removal of dictionary entries after creation.
|
|
53
|
+
''',
|
|
54
|
+
|
|
55
|
+
'dictionary entries validation': '''
|
|
56
|
+
When an attempt to create a dictionary with entries, each entry is validated
|
|
57
|
+
against supplied criteria. If validation fails for any entry, then the
|
|
58
|
+
dictionary creation is rejected.
|
|
59
|
+
''',
|
|
60
|
+
|
|
61
|
+
'instance attributes immutability': '''
|
|
62
|
+
Prevents assignment or deletion of instance attributes after instance creation.
|
|
63
|
+
''',
|
|
64
|
+
|
|
65
|
+
'module attributes immutability': '''
|
|
66
|
+
Prevents assignment or deletion of module attributes after module creation.
|
|
67
|
+
|
|
68
|
+
This behavior helps ensure that module-level constants remain constant and that
|
|
69
|
+
module interfaces remain stable during runtime.
|
|
70
|
+
''',
|
|
71
|
+
|
|
72
|
+
} )
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# vim: set filetype=python fileencoding=utf-8:
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
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
|
+
#============================================================================#
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
''' Stubs for additional "builtin" types. '''
|
|
22
|
+
|
|
23
|
+
# https://github.com/microsoft/pyright/blob/main/docs/builtins.md
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
from icecream import IceCreamDebugger # type: ignore
|
|
27
|
+
|
|
28
|
+
ic: IceCreamDebugger
|