classcore 1.0__tar.gz → 1.1rc0__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.
Files changed (22) hide show
  1. {classcore-1.0 → classcore-1.1rc0}/PKG-INFO +1 -1
  2. {classcore-1.0 → classcore-1.1rc0}/pyproject.toml +13 -10
  3. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/__/imports.py +1 -0
  4. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/__init__.py +1 -1
  5. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/factories.py +7 -5
  6. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/standard/behaviors.py +2 -1
  7. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/standard/decorators.py +6 -4
  8. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/standard/modules.py +2 -1
  9. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/utilities.py +38 -8
  10. {classcore-1.0 → classcore-1.1rc0}/.gitignore +0 -0
  11. {classcore-1.0 → classcore-1.1rc0}/LICENSE.txt +0 -0
  12. {classcore-1.0 → classcore-1.1rc0}/README.rst +0 -0
  13. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/__/__init__.py +0 -0
  14. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/__/nomina.py +0 -0
  15. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/decorators.py +0 -0
  16. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/exceptions.py +0 -0
  17. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/nomina.py +0 -0
  18. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/py.typed +0 -0
  19. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/standard/__.py +0 -0
  20. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/standard/__init__.py +0 -0
  21. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/standard/classes.py +0 -0
  22. {classcore-1.0 → classcore-1.1rc0}/sources/classcore/standard/nomina.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: classcore
3
- Version: 1.0
3
+ Version: 1.1rc0
4
4
  Summary: Foundational class factories and decorators.
5
5
  Project-URL: Homepage, https://github.com/emcd/python-classcore
6
6
  Project-URL: Documentation, https://emcd.github.io/python-classcore
@@ -119,28 +119,31 @@ PYTHONUNBUFFERED = 'TRUE' # TODO: Only for coverage/pytest.
119
119
  # --- END: Injected by Copier ---
120
120
  [tool.hatch.envs.develop.scripts]
121
121
  docsgen = [
122
- '''sphinx-build -E -b linkcheck -d .auxiliary/caches/sphinx \
123
- documentation .auxiliary/artifacts/sphinx-linkcheck''',
124
- '''sphinx-build -a -d .auxiliary/caches/sphinx \
125
- documentation .auxiliary/artifacts/sphinx-html''',
122
+ """sphinx-build -E -b linkcheck -d .auxiliary/caches/sphinx \
123
+ documentation .auxiliary/artifacts/sphinx-linkcheck""",
124
+ """sphinx-build -a -d .auxiliary/caches/sphinx \
125
+ documentation .auxiliary/artifacts/sphinx-html""",
126
126
  ]
127
127
  linters = [
128
- '''ruff check --quiet sources documentation tests''',
128
+ """ruff check --quiet sources documentation tests""",
129
129
  # --- BEGIN: Injected by Copier ---
130
130
  # --- END: Injected by Copier ---
131
- '''pyright sources''',
131
+ """pyright sources""",
132
132
  ]
133
133
  packagers = [
134
- '''hatch build''',
134
+ """hatch build""",
135
135
  # --- BEGIN: Injected by Copier ---
136
136
  # --- END: Injected by Copier ---
137
137
  ]
138
- testers = [
138
+ testers-no-reports = [
139
139
  'coverage erase',
140
140
  'coverage run',
141
- '''coverage run -m sphinx.cmd.build \
141
+ """coverage run -m sphinx.cmd.build \
142
142
  -E -b doctest -d .auxiliary/caches/sphinx \
143
- documentation .auxiliary/artifacts/sphinx-doctest''',
143
+ documentation .auxiliary/artifacts/sphinx-doctest""",
144
+ ]
145
+ testers = [
146
+ 'testers-no-reports',
144
147
  'coverage combine',
145
148
  'coverage report --skip-covered',
146
149
  'coverage html',
@@ -28,6 +28,7 @@ from __future__ import annotations
28
28
  import collections.abc as cabc
29
29
  import dataclasses as dcls
30
30
  import functools as funct
31
+ import hashlib
31
32
  import inspect
32
33
  import platform
33
34
  import re
@@ -32,7 +32,7 @@ from .decorators import *
32
32
  from .factories import *
33
33
 
34
34
 
35
- __version__ = '1.0'
35
+ __version__ = '1.1rc0'
36
36
 
37
37
 
38
38
  standard.reclassify_modules( __name__, recursive = True )
@@ -58,12 +58,13 @@ def produce_class_constructor(
58
58
  # Some decorators create new classes, which invokes this method again.
59
59
  # Short-circuit to prevent recursive decoration and other tangles.
60
60
  progress_name = attributes_namer( 'class', 'in_progress' )
61
- in_progress = _utilities.getattr0( cls, progress_name, False )
61
+ progress_name_m = _utilities.mangle_name( cls, progress_name )
62
+ in_progress = getattr( cls, progress_name_m, False )
62
63
  if in_progress: return cls
63
- setattr( cls, progress_name, True )
64
+ setattr( cls, progress_name_m, True )
64
65
  for postp in postprocessors: postp( cls, decorators_ )
65
66
  cls = _decorators.apply_decorators( cls, decorators_ )
66
- setattr( cls, progress_name, False )
67
+ setattr( cls, progress_name_m, False )
67
68
  return cls
68
69
 
69
70
  return construct
@@ -84,9 +85,10 @@ def produce_class_initializer(
84
85
  ''' Initializes class, applying hooks. '''
85
86
  superf( *posargs, **nomargs )
86
87
  progress_name = attributes_namer( 'class', 'in_progress' )
87
- in_progress = _utilities.getattr0( cls, progress_name, False )
88
+ progress_name_m = _utilities.mangle_name( cls, progress_name )
89
+ in_progress = getattr( cls, progress_name_m, False )
88
90
  if in_progress: return # If non-empty, then not top-level.
89
- delattr( cls, progress_name )
91
+ delattr( cls, progress_name_m )
90
92
  for completer in completers: completer( cls )
91
93
 
92
94
  return initialize
@@ -251,7 +251,8 @@ def produce_class_initialization_completer(
251
251
  label = concealment_label, behaviors = behaviors,
252
252
  verifiers = visibles )
253
253
  # Set behaviors attribute last since it enables enforcement.
254
- setattr( cls, attributes_namer( 'class', 'behaviors' ), behaviors )
254
+ behaviors_name = attributes_namer( 'class', 'behaviors' )
255
+ _utilities.setattr0( cls, behaviors_name, frozenset( behaviors ) )
255
256
 
256
257
  return complete
257
258
 
@@ -77,9 +77,10 @@ def prepare_dataclass_for_instances(
77
77
  ''' Annotates dataclass in support of instantiation machinery. '''
78
78
  annotations = __.inspect.get_annotations( cls )
79
79
  behaviors_name = attributes_namer( 'instance', 'behaviors' )
80
- annotations[ behaviors_name ] = set[ str ]
80
+ behaviors_name_m = _utilities.mangle_name( cls, behaviors_name )
81
+ annotations[ behaviors_name_m ] = set[ str ]
81
82
  setattr( cls, '__annotations__', annotations ) # in case of absence
82
- setattr( cls, behaviors_name, __.dcls.field( init = False ) )
83
+ setattr( cls, behaviors_name_m, __.dcls.field( init = False ) )
83
84
 
84
85
 
85
86
  def produce_class_factory_decorators(
@@ -137,6 +138,7 @@ def produce_instances_initialization_decorator(
137
138
  if extant is original: return cls
138
139
  behaviors: set[ str ] = set( )
139
140
  behaviors_name = attributes_namer( 'instance', 'behaviors' )
141
+ behaviors_name_m = _utilities.mangle_name( cls, behaviors_name )
140
142
  _behaviors.record_behavior(
141
143
  cls, attributes_namer = attributes_namer,
142
144
  level = 'instances', basename = 'mutables',
@@ -153,9 +155,9 @@ def produce_instances_initialization_decorator(
153
155
  self: object, *posargs: __.typx.Any, **nomargs: __.typx.Any
154
156
  ) -> None:
155
157
  original( self, *posargs, **nomargs )
156
- behaviors_ = _utilities.getattr0( self, behaviors_name, set( ) )
157
- if not behaviors_: setattr( self, behaviors_name, behaviors_ )
158
+ behaviors_: set[ str ] = getattr( self, behaviors_name_m, set( ) )
158
159
  behaviors_.update( behaviors )
160
+ setattr( self, behaviors_name_m, frozenset( behaviors_ ) )
159
161
 
160
162
  setattr( cls, initializer_name, initialize )
161
163
  cls.__init__ = initialize
@@ -23,6 +23,7 @@
23
23
 
24
24
  from __future__ import annotations
25
25
 
26
+ from .. import utilities as _utilities
26
27
  from . import __
27
28
  from . import behaviors as _behaviors
28
29
  from . import classes as _classes
@@ -85,5 +86,5 @@ def _seal_module(
85
86
  ) -> None:
86
87
  behaviors = { _behaviors.concealment_label, _behaviors.immutability_label }
87
88
  behaviors_name = attributes_namer( 'instance', 'behaviors' )
88
- setattr( module, behaviors_name, behaviors )
89
+ _utilities.setattr0( module, behaviors_name, behaviors )
89
90
  module.__class__ = Module
@@ -34,14 +34,44 @@ def describe_object( obj: object ) -> str:
34
34
 
35
35
 
36
36
  def getattr0( obj: object, name: str, default: __.typx.Any ) -> __.typx.Any:
37
- ''' Returns attribute from object without inheritance. '''
38
- # Inspect object dictionary directly to suppress getattr inheritance.
39
- attrsdict = getattr( obj, '__dict__', { } )
40
- if name in attrsdict: return attrsdict[ name ]
41
- slots = getattr( obj, '__slots__', ( ) )
42
- # Name may be in slots but not yet assigned.
43
- if name in slots: return getattr( obj, name, default )
44
- return default
37
+ ''' Returns private attribute from object.
38
+
39
+ Uses mangled attribute which is unique to the class.
40
+ '''
41
+ name_m = mangle_name( obj, name )
42
+ return getattr( obj, name_m, default )
43
+
44
+
45
+ def delattr0( obj: object, name: str ) -> None:
46
+ ''' Deletes private attribute on object.
47
+
48
+ Uses mangled attribute which is unique to the class.
49
+ '''
50
+ name_m = mangle_name( obj, name )
51
+ delattr( obj, name_m )
52
+
53
+
54
+ def setattr0( obj: object, name: str, value: __.typx.Any ) -> None:
55
+ ''' Assigns private attribute to object.
56
+
57
+ Uses mangled attribute which is unique to the class.
58
+ '''
59
+ name_m = mangle_name( obj, name )
60
+ setattr( obj, name_m, value )
61
+
62
+
63
+ def mangle_name( obj: object, name: str ) -> str:
64
+ ''' Mangles attribute name so that it is unique.
65
+
66
+ Effectively provides name of private member attribute,
67
+ which is unique across class inheritance.
68
+ '''
69
+ if not __.inspect.isclass( obj ):
70
+ return mangle_name( type( obj ), name )
71
+ namehash = __.hashlib.sha256( )
72
+ namehash.update( qualify_class_name( obj ).encode( ) )
73
+ namehash_hex = namehash.hexdigest( )
74
+ return f"{name}_{namehash_hex}"
45
75
 
46
76
 
47
77
  def qualify_class_name( cls: type ) -> str:
File without changes
File without changes
File without changes