classcore 1.7__tar.gz → 1.9__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 (24) hide show
  1. {classcore-1.7 → classcore-1.9}/.gitignore +4 -0
  2. {classcore-1.7 → classcore-1.9}/PKG-INFO +2 -2
  3. {classcore-1.7 → classcore-1.9}/README.rst +1 -1
  4. {classcore-1.7 → classcore-1.9}/pyproject.toml +53 -12
  5. {classcore-1.7 → classcore-1.9}/sources/classcore/__init__.py +1 -1
  6. {classcore-1.7 → classcore-1.9}/sources/classcore/standard/modules.py +21 -7
  7. {classcore-1.7 → classcore-1.9}/sources/classcore/standard/nomina.py +1 -2
  8. {classcore-1.7 → classcore-1.9}/sources/classcore/utilities.py +1 -1
  9. {classcore-1.7 → classcore-1.9}/LICENSE.txt +0 -0
  10. {classcore-1.7 → classcore-1.9}/sources/classcore/__/__init__.py +0 -0
  11. {classcore-1.7 → classcore-1.9}/sources/classcore/__/doctab.py +0 -0
  12. {classcore-1.7 → classcore-1.9}/sources/classcore/__/imports.py +0 -0
  13. {classcore-1.7 → classcore-1.9}/sources/classcore/__/nomina.py +0 -0
  14. {classcore-1.7 → classcore-1.9}/sources/classcore/decorators.py +0 -0
  15. {classcore-1.7 → classcore-1.9}/sources/classcore/exceptions.py +0 -0
  16. {classcore-1.7 → classcore-1.9}/sources/classcore/factories.py +0 -0
  17. {classcore-1.7 → classcore-1.9}/sources/classcore/nomina.py +0 -0
  18. {classcore-1.7 → classcore-1.9}/sources/classcore/py.typed +0 -0
  19. {classcore-1.7 → classcore-1.9}/sources/classcore/standard/__.py +0 -0
  20. {classcore-1.7 → classcore-1.9}/sources/classcore/standard/__init__.py +0 -0
  21. {classcore-1.7 → classcore-1.9}/sources/classcore/standard/behaviors.py +0 -0
  22. {classcore-1.7 → classcore-1.9}/sources/classcore/standard/classes.py +0 -0
  23. {classcore-1.7 → classcore-1.9}/sources/classcore/standard/decorators.py +0 -0
  24. {classcore-1.7 → classcore-1.9}/sources/classcore/standard/dynadoc.py +0 -0
@@ -2,10 +2,14 @@
2
2
  .claude
3
3
  .gemini
4
4
  .mcp.json
5
+ .opencode
5
6
  .*.swp
6
7
  AGENTS.md
7
8
  CLAUDE.md
8
9
  CONVENTIONS.md
9
10
  GEMINI.md
11
+ opencode.jsonc
10
12
  __pycache__/
11
13
  bugs/
14
+ build/
15
+ dist/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: classcore
3
- Version: 1.7
3
+ Version: 1.9
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
@@ -237,7 +237,7 @@ For development guidance and standards, please see the `development guide
237
237
  <https://emcd.github.io/python-classcore/stable/sphinx-html/contribution.html#development>`_.
238
238
 
239
239
 
240
- `More Flair <https://www.imdb.com/title/tt0151804/characters/nm0431918>`_
240
+ Additional Indicia
241
241
  ===============================================================================
242
242
 
243
243
  .. image:: https://img.shields.io/github/last-commit/emcd/python-classcore
@@ -208,7 +208,7 @@ For development guidance and standards, please see the `development guide
208
208
  <https://emcd.github.io/python-classcore/stable/sphinx-html/contribution.html#development>`_.
209
209
 
210
210
 
211
- `More Flair <https://www.imdb.com/title/tt0151804/characters/nm0431918>`_
211
+ Additional Indicia
212
212
  ===============================================================================
213
213
 
214
214
  .. image:: https://img.shields.io/github/last-commit/emcd/python-classcore
@@ -59,7 +59,7 @@ gha-runners = [
59
59
  ]
60
60
  [tool.coverage.run]
61
61
  branch = true
62
- command_line = '-m pytest' # TODO? '--fail-under'
62
+ command_line = '-m pytest'
63
63
  data_file = '.auxiliary/caches/pytest/coverage.sqlite3'
64
64
  parallel = true
65
65
  source = [ 'sources' ]
@@ -97,6 +97,7 @@ dependencies = [
97
97
  'Jinja2',
98
98
  'coverage[toml]',
99
99
  'furo',
100
+ 'isort',
100
101
  'packaging',
101
102
  'pre-commit',
102
103
  'pyright',
@@ -106,6 +107,7 @@ dependencies = [
106
107
  'sphinx-copybutton',
107
108
  'sphinx-inline-tabs',
108
109
  'towncrier',
110
+ 'vulture',
109
111
  # --- BEGIN: Injected by Copier ---
110
112
  # --- END: Injected by Copier ---
111
113
  ]
@@ -119,15 +121,17 @@ PYTHONUNBUFFERED = 'TRUE' # TODO: Only for coverage/pytest.
119
121
  # --- END: Injected by Copier ---
120
122
  [tool.hatch.envs.develop.scripts]
121
123
  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""",
124
+ """sphinx-build -E -b linkcheck -d .auxiliary/caches/sphinx --quiet \
125
+ documentation .auxiliary/artifacts/sphinx-linkcheck""",
126
+ """sphinx-build -a -d .auxiliary/caches/sphinx --quiet \
127
+ documentation .auxiliary/artifacts/sphinx-html""",
126
128
  ]
127
129
  linters = [
128
130
  """ruff check --quiet sources documentation tests""",
129
131
  # --- BEGIN: Injected by Copier ---
130
132
  # --- END: Injected by Copier ---
133
+ """isort --check-only --diff sources tests""",
134
+ """vulture""",
131
135
  """pyright sources""",
132
136
  ]
133
137
  packagers = [
@@ -135,14 +139,19 @@ packagers = [
135
139
  # --- BEGIN: Injected by Copier ---
136
140
  # --- END: Injected by Copier ---
137
141
  ]
142
+ testers-documentation = [
143
+ """coverage run -m sphinx.cmd.build \
144
+ -E -b doctest -d .auxiliary/caches/sphinx --quiet \
145
+ documentation .auxiliary/artifacts/sphinx-doctest""",
146
+ ]
147
+ testers-serotine = [ """coverage run -m pytest -m slow""" ]
138
148
  testers-no-reports = [
139
- 'coverage erase',
140
149
  'coverage run',
141
- """coverage run -m sphinx.cmd.build \
142
- -E -b doctest -d .auxiliary/caches/sphinx \
143
- documentation .auxiliary/artifacts/sphinx-doctest""",
150
+ 'testers-documentation',
151
+ 'testers-serotine',
144
152
  ]
145
153
  testers = [
154
+ 'coverage erase',
146
155
  'testers-no-reports',
147
156
  'coverage combine',
148
157
  'coverage report --skip-covered',
@@ -171,6 +180,25 @@ python = [
171
180
  [tool.hatch.version]
172
181
  path = 'sources/classcore/__init__.py'
173
182
 
183
+ # https://pycqa.github.io/isort/docs/configuration/config_files.html
184
+ [tool.isort]
185
+ # profile = 'black'
186
+ src_paths = [ 'sources', 'tests' ]
187
+ case_sensitive = true
188
+ # ensure_newline_before_comments = true
189
+ # force_sort_within_sections = true
190
+ ignore_whitespace = true
191
+ include_trailing_comma = true
192
+ known_first_party = [ 'classcore' ]
193
+ lines_between_types = 1
194
+ line_length = 79
195
+ multi_line_output = 3
196
+ quiet = true
197
+ # skip_gitignore = true
198
+ skip_glob = [ '*/__/imports.py', '*/__init__.py' ]
199
+ split_on_trailing_comma = true
200
+ use_parentheses = true
201
+
174
202
  # https://mypy.readthedocs.io/en/stable/config_file.html
175
203
  [tool.mypy]
176
204
  # Note: Due to repeated painful experiences with Mypy, we use Pyright instead.
@@ -184,8 +212,8 @@ strict = false
184
212
 
185
213
  # https://microsoft.github.io/pyright/#/configuration
186
214
  [tool.pyright]
187
- ignore = [ 'documentation', 'tests' ] # Stronger hint for language server.
188
- include = [ 'sources' ]
215
+ ignore = [ '.auxiliary', 'documentation', 'tests' ] # Ignore diagnostics.
216
+ include = [ 'sources', 'tests' ] # Consider for operations.
189
217
  reportConstantRedefinition = true
190
218
  reportInvalidTypeVarUse = true
191
219
  reportMatchNotExhaustive = true
@@ -217,15 +245,19 @@ stubPath = 'sources/classcore/_typedecls'
217
245
  # Note: Cannot run doctests from Pytest, because Pytest tries to update '_'
218
246
  # attribute on protected modules. Instead, we use Sphinx to run doctests.
219
247
  minversion = '8.1'
220
- addopts = '--capture=no --exitfirst -rfE'
248
+ addopts = """--capture=no --exitfirst --quiet -rfE -m 'not slow'""" # TODO? '--fail-under'
221
249
  testpaths = [ 'tests' ]
222
250
  python_files = [ 'test_*.py' ]
223
251
  python_functions = [ 'test_[0-9][0-9][0-9]_*' ]
224
252
  cache_dir = '.auxiliary/caches/pytest'
253
+ markers = [
254
+ "slow: long-running tests",
255
+ ]
225
256
 
226
257
  [tool.ruff]
227
258
  #builtins = [ 'ic' ]
228
259
  cache-dir = '.auxiliary/caches/ruff'
260
+ extend-exclude = [ 'vulturefood.py' ]
229
261
  indent-width = 4
230
262
  line-length = 79
231
263
  [tool.ruff.lint]
@@ -315,3 +347,12 @@ showcontent = true
315
347
  directory = 'repair'
316
348
  name = 'Repairs'
317
349
  showcontent = true
350
+
351
+ [tool.vulture]
352
+ paths = [ '.auxiliary/configuration/vulturefood.py', 'sources' ]
353
+ min_confidence = 60
354
+ exclude = [
355
+ '*/imports.py',
356
+ ]
357
+ ignore_decorators = [ '@__.abc.abstractmethod', '@__.typx.overload' ]
358
+ ignore_names = [ 'main' ]
@@ -62,7 +62,7 @@ from .factories import *
62
62
 
63
63
 
64
64
  __version__: __.typx.Annotated[ str, __.ddoc.Visibilities.Reveal ]
65
- __version__ = '1.7'
65
+ __version__ = '1.9'
66
66
 
67
67
 
68
68
  standard.finalize_module(
@@ -42,6 +42,10 @@ def finalize_module( # noqa: PLR0913
42
42
  dynadoc_introspection: _nomina.DynadocIntrospectionArgument = (
43
43
  _dynadoc.dynadoc_introspection_on_package ),
44
44
  dynadoc_table: _nomina.DynadocTableArgument = __.dictproxy_empty,
45
+ excludes: __.typx.Annotated[
46
+ __.typx.Optional[ __.cabc.MutableSet[ __.types.ModuleType ] ],
47
+ __.ddoc.Doc( ''' Modules to exclude from reclassification. ''' ),
48
+ ] = None,
45
49
  recursive: __.typx.Annotated[
46
50
  bool, __.ddoc.Doc( ''' Recursively reclassify package modules? ''' )
47
51
  ] = False,
@@ -84,7 +88,7 @@ def finalize_module( # noqa: PLR0913
84
88
  _reclassify_module(
85
89
  module,
86
90
  attributes_namer = attributes_namer,
87
- recursive = recursive,
91
+ excludes = excludes, recursive = recursive,
88
92
  replacement_class = replacement_class )
89
93
 
90
94
 
@@ -100,6 +104,10 @@ def reclassify_modules(
100
104
  __.ddoc.Doc(
101
105
  ''' Attributes namer function with which to seal class. ''' ),
102
106
  ] = __.calculate_attrname,
107
+ excludes: __.typx.Annotated[
108
+ __.typx.Optional[ __.cabc.MutableSet[ __.types.ModuleType ] ],
109
+ __.ddoc.Doc( ''' Modules to exclude from reclassification. ''' ),
110
+ ] = None,
103
111
  recursive: __.typx.Annotated[
104
112
  bool, __.ddoc.Doc( ''' Recursively reclassify package modules? ''' )
105
113
  ] = False,
@@ -123,11 +131,11 @@ def reclassify_modules(
123
131
  _reclassify_module(
124
132
  attributes,
125
133
  attributes_namer = attributes_namer,
126
- recursive = recursive,
134
+ excludes = excludes, recursive = recursive,
127
135
  replacement_class = replacement_class )
128
136
 
129
137
 
130
- def _reclassify_module(
138
+ def _reclassify_module( # noqa: C901,PLR0912
131
139
  attributes: __.typx.Annotated[
132
140
  __.cabc.Mapping[ str, __.typx.Any ] | __.types.ModuleType | str,
133
141
  __.ddoc.Doc(
@@ -138,6 +146,10 @@ def _reclassify_module(
138
146
  __.ddoc.Doc(
139
147
  ''' Attributes namer function with which to seal class. ''' ),
140
148
  ] = __.calculate_attrname,
149
+ excludes: __.typx.Annotated[
150
+ __.typx.Optional[ __.cabc.MutableSet[ __.types.ModuleType ] ],
151
+ __.ddoc.Doc( ''' Modules to exclude from reclassification. ''' ),
152
+ ] = None,
141
153
  recursive: __.typx.Annotated[
142
154
  bool, __.ddoc.Doc( ''' Recursively reclassify package modules? ''' )
143
155
  ] = False,
@@ -164,22 +176,24 @@ def _reclassify_module(
164
176
  attributes = __.sys.modules[ attributes ]
165
177
  if isinstance( attributes, __.types.ModuleType ):
166
178
  module = attributes
167
- attributes = attributes.__dict__
179
+ if excludes and module in excludes: return
180
+ attributes = module.__dict__
168
181
  else: module = None
182
+ if excludes is None: excludes = set( )
183
+ if module: excludes.add( module )
169
184
  package_name = (
170
185
  attributes.get( '__package__' ) or attributes.get( '__name__' ) )
171
186
  if not package_name: return
172
187
  for value in attributes.values( ):
173
188
  if not __.inspect.ismodule( value ): continue
174
189
  if not value.__name__.startswith( f"{package_name}." ): continue
190
+ if isinstance( value, replacement_class ): continue
175
191
  if recursive:
176
192
  _reclassify_module(
177
193
  value,
178
194
  attributes_namer = attributes_namer,
179
- recursive = True,
195
+ excludes = excludes, recursive = True,
180
196
  replacement_class = replacement_class )
181
- if isinstance( value, replacement_class ): continue
182
- _seal_module( value, attributes_namer, replacement_class )
183
197
  if module and not isinstance( module, replacement_class ):
184
198
  _seal_module( module, attributes_namer, replacement_class )
185
199
 
@@ -22,9 +22,8 @@
22
22
  # ruff: noqa: F403,F405
23
23
 
24
24
 
25
- from . import __
26
25
  from ..nomina import *
27
-
26
+ from . import __
28
27
 
29
28
  concealment_label = 'concealment'
30
29
  immutability_label = 'immutability'
@@ -114,7 +114,7 @@ def qualify_class_name( cls: type ) -> str:
114
114
  def repair_class_reproduction( original: type, reproduction: type ) -> None:
115
115
  ''' Repairs a class reproduction, if necessary. '''
116
116
  match __.platform.python_implementation( ):
117
- case 'CPython': # pragma: no branch
117
+ case 'CPython' | 'PyPy': # pragma: no branch
118
118
  _repair_cpython_class_closures( original, reproduction )
119
119
  case _: pass # pragma: no cover
120
120
 
File without changes