emcd-projects 1.15__tar.gz → 1.16__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. {emcd_projects-1.15 → emcd_projects-1.16}/PKG-INFO +1 -1
  2. emcd_projects-1.16/pyproject.toml +334 -0
  3. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/__/imports.py +0 -1
  4. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/__/preparation.py +4 -3
  5. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/__init__.py +1 -1
  6. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/cli.py +2 -3
  7. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/interfaces.py +1 -1
  8. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/website.py +5 -7
  9. emcd_projects-1.15/pyproject.toml +0 -532
  10. {emcd_projects-1.15 → emcd_projects-1.16}/.gitignore +0 -0
  11. {emcd_projects-1.15 → emcd_projects-1.16}/LICENSE.txt +0 -0
  12. {emcd_projects-1.15 → emcd_projects-1.16}/data/.gitignore +0 -0
  13. {emcd_projects-1.15 → emcd_projects-1.16}/data/templates/coverage.svg.jinja +0 -0
  14. {emcd_projects-1.15 → emcd_projects-1.16}/data/templates/website.html.jinja +0 -0
  15. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/README.rst +0 -0
  16. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/__/__init__.py +0 -0
  17. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/__/application.py +0 -0
  18. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/__/distribution.py +0 -0
  19. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/__/state.py +0 -0
  20. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/__main__.py +0 -0
  21. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/_typedecls/__builtins__.pyi +0 -0
  22. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/exceptions.py +0 -0
  23. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/filesystem.py +0 -0
  24. {emcd_projects-1.15 → emcd_projects-1.16}/sources/emcdproj/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: emcd-projects
3
- Version: 1.15
3
+ Version: 1.16
4
4
  Summary: Project management utilities.
5
5
  Project-URL: Homepage, https://github.com/emcd/python-project-common
6
6
  Project-URL: Documentation, https://emcd.github.io/python-project-common
@@ -0,0 +1,334 @@
1
+ # vim: set filetype=toml fileencoding=utf-8:
2
+ # -*- mode: toml ; coding: utf-8 -*-
3
+
4
+ [build-system]
5
+ requires = [
6
+ 'hatchling',
7
+ ]
8
+ build-backend = 'hatchling.build'
9
+
10
+ [project]
11
+ name = 'emcd-projects'
12
+ description = 'Project management utilities.'
13
+ dynamic = [ 'version' ]
14
+ license = 'Apache-2.0'
15
+ readme = { 'file' = 'sources/emcdproj/README.rst', 'content-type' = 'text/x-rst' }
16
+ requires-python = '>= 3.10'
17
+ dependencies = [
18
+ 'Jinja2',
19
+ 'absence',
20
+ 'defusedxml',
21
+ 'frigid',
22
+ 'icecream-truck',
23
+ 'importlib-metadata', # TODO: Drop once we have separate appcore package.
24
+ 'importlib-resources', # TODO: Drop once we have separate appcore package.
25
+ 'packaging',
26
+ 'platformdirs', # TODO: Drop once we have separate appcore package.
27
+ 'tomli', # TODO: Drop once we have separate appcore package.
28
+ 'typing-extensions',
29
+ # --- BEGIN: Injected by Copier ---
30
+ 'tyro',
31
+ # --- END: Injected by Copier ---
32
+ ]
33
+ classifiers = [ # https://pypi.org/classifiers
34
+ 'Development Status :: 3 - Alpha',
35
+ 'Intended Audience :: Developers',
36
+ 'License :: OSI Approved :: Apache Software License',
37
+ 'Programming Language :: Python :: 3 :: Only',
38
+ # --- BEGIN: Injected by Copier ---
39
+ 'Programming Language :: Python :: 3.10',
40
+ 'Programming Language :: Python :: 3.11',
41
+ 'Programming Language :: Python :: 3.12',
42
+ 'Programming Language :: Python :: 3.13',
43
+ 'Programming Language :: Python :: Implementation :: CPython',
44
+ 'Programming Language :: Python :: Implementation :: PyPy',
45
+ # --- END: Injected by Copier ---
46
+ 'Topic :: Software Development',
47
+ ]
48
+ keywords = [ 'maintenance', 'project', 'template' ]
49
+ [[project.authors]]
50
+ name = 'Eric McDonald'
51
+ email = 'emcd@users.noreply.github.com'
52
+ [project.scripts]
53
+ emcdproj = 'emcdproj:main'
54
+ [project.urls]
55
+ 'Homepage' = 'https://github.com/emcd/python-project-common'
56
+ 'Documentation' = 'https://emcd.github.io/python-project-common'
57
+ 'Download' = 'https://pypi.org/project/emcd-projects/#files'
58
+ 'Source Code' = 'https://github.com/emcd/python-project-common'
59
+ 'Issue Tracker' = 'https://github.com/emcd/python-project-common/issues'
60
+
61
+ [tool.SELF]
62
+ year-of-origin = 2024
63
+
64
+ # https://coverage.readthedocs.io/en/latest/config.html
65
+ [tool.coverage.paths]
66
+ gha-runners = [
67
+ '/home/runner/work/python-project-common/python-project-common/',
68
+ '/Users/runner/work/python-project-common/python-project-common/',
69
+ 'D:\a\python-project-common\python-project-common\',
70
+ ]
71
+ [tool.coverage.run]
72
+ branch = true
73
+ command_line = '-m pytest' # TODO? '--fail-under'
74
+ data_file = '.auxiliary/caches/pytest/coverage.sqlite3'
75
+ parallel = true
76
+ source = [ 'sources' ]
77
+ [tool.coverage.html]
78
+ directory = '.auxiliary/artifacts/coverage-pytest'
79
+ [tool.coverage.xml]
80
+ output = '.auxiliary/artifacts/coverage-pytest/coverage.xml'
81
+
82
+ # https://hatch.pypa.io/latest/config/metadata/
83
+ [tool.hatch.build]
84
+ directory = '.auxiliary/artifacts/hatch-build'
85
+ [tool.hatch.build.targets.sdist]
86
+ only-include = [
87
+ 'sources/emcdproj',
88
+ # --- BEGIN: Injected by Copier ---
89
+ 'data',
90
+ # --- END: Injected by Copier ---
91
+ ]
92
+ strict-naming = false
93
+ [tool.hatch.build.targets.wheel]
94
+ only-include = [
95
+ 'sources/emcdproj',
96
+ # --- BEGIN: Injected by Copier ---
97
+ 'data',
98
+ # --- END: Injected by Copier ---
99
+ ]
100
+ strict-naming = false
101
+ [tool.hatch.build.targets.wheel.sources]
102
+ 'sources/emcdproj' = 'emcdproj'
103
+ # --- BEGIN: Injected by Copier ---
104
+ 'data' = 'emcdproj/data'
105
+ # --- END: Injected by Copier ---
106
+ [tool.hatch.envs.default]
107
+ python = '3.10'
108
+ [tool.hatch.envs.develop]
109
+ description = ''' Development environment. '''
110
+ dependencies = [
111
+ 'Jinja2',
112
+ 'coverage[toml]',
113
+ 'emcd-projects',
114
+ 'furo',
115
+ 'icecream-truck',
116
+ 'packaging',
117
+ 'pre-commit',
118
+ 'pyfakefs',
119
+ 'pyright',
120
+ 'pytest',
121
+ 'pytest-asyncio',
122
+ 'ruff',
123
+ 'semgrep;platform_system!="Windows"', # https://github.com/returntocorp/semgrep/issues/1330
124
+ 'sphinx',
125
+ 'sphinx-copybutton',
126
+ 'sphinx-inline-tabs',
127
+ 'towncrier',
128
+ # --- BEGIN: Injected by Copier ---
129
+ # --- END: Injected by Copier ---
130
+ ]
131
+ post-install-commands = [
132
+ # --- BEGIN: Injected by Copier ---
133
+ # --- END: Injected by Copier ---
134
+ ]
135
+ [tool.hatch.envs.develop.env-vars]
136
+ PYTHONUNBUFFERED = 'TRUE' # TODO: Only for coverage/pytest.
137
+ # --- BEGIN: Injected by Copier ---
138
+ # --- END: Injected by Copier ---
139
+ [tool.hatch.envs.develop.scripts]
140
+ docsgen = [
141
+ '''sphinx-build -E -b doctest -d .auxiliary/caches/sphinx \
142
+ documentation .auxiliary/artifacts/sphinx-doctest''',
143
+ '''sphinx-build -E -b linkcheck -d .auxiliary/caches/sphinx \
144
+ documentation .auxiliary/artifacts/sphinx-linkcheck''',
145
+ '''sphinx-build -a -d .auxiliary/caches/sphinx \
146
+ documentation .auxiliary/artifacts/sphinx-html''',
147
+ ]
148
+ linters = [
149
+ '''ruff check --quiet sources documentation tests''',
150
+ # --- BEGIN: Injected by Copier ---
151
+ # --- END: Injected by Copier ---
152
+ '''pyright sources''',
153
+ '''semgrep --config p/python --error --quiet --skip-unknown-extensions \
154
+ sources/emcdproj''',
155
+ # --- BEGIN: Injected by Copier ---
156
+ # --- END: Injected by Copier ---
157
+ ]
158
+ packagers = [
159
+ '''hatch build''',
160
+ # --- BEGIN: Injected by Copier ---
161
+ # --- END: Injected by Copier ---
162
+ ]
163
+ testers = [
164
+ 'coverage erase',
165
+ 'coverage run',
166
+ 'coverage combine',
167
+ 'coverage report --skip-covered',
168
+ 'coverage html',
169
+ 'coverage xml',
170
+ ]
171
+ make-all = [
172
+ 'linters',
173
+ 'testers',
174
+ 'packagers',
175
+ 'docsgen',
176
+ ]
177
+ [tool.hatch.envs.qa]
178
+ description = ''' Quality assurance environment. '''
179
+ template = 'develop'
180
+ [[tool.hatch.envs.qa.matrix]]
181
+ python = [
182
+ '3.10',
183
+ '3.11',
184
+ '3.12',
185
+ '3.13',
186
+ 'pypy3.10',
187
+ ]
188
+ [tool.hatch.version]
189
+ path = 'sources/emcdproj/__init__.py'
190
+
191
+ # https://mypy.readthedocs.io/en/stable/config_file.html
192
+ [tool.mypy]
193
+ # Note: Due to repeated painful experiences with Mypy, we use Pyright instead.
194
+ # Pyright properly handles TypeVars, etc...
195
+ cache_dir = '.auxiliary/caches/mypy'
196
+ exclude = [ '.*' ] # Ignore everything
197
+ ignore_errors = true
198
+ follow_imports = 'skip'
199
+ pretty = true
200
+ strict = false
201
+
202
+ # https://microsoft.github.io/pyright/#/configuration
203
+ [tool.pyright]
204
+ ignore = [ 'tests' ] # Stronger hint for language server.
205
+ include = [ 'sources' ]
206
+ reportConstantRedefinition = true
207
+ reportInvalidTypeVarUse = true
208
+ reportMatchNotExhaustive = true
209
+ reportMissingImports = true
210
+ reportMissingTypeStubs = true
211
+ reportMissingTypeArgument = true
212
+ reportPossiblyUnboundVariable = false # Covered by other linters.
213
+ reportPrivateImportUsage = false # Covered by other linters.
214
+ reportPrivateUsage = false # Covered by other linters.
215
+ reportSelfClsParameterName = false # Too opinionated.
216
+ reportUnknownArgumentType = true
217
+ reportUnknownLambdaType = true
218
+ reportUnknownMemberType = true
219
+ reportUnknownParameterType = true
220
+ reportUnknownVariableType = true
221
+ reportUnnecessaryCast = true
222
+ reportUnnecessaryComparison = true
223
+ reportUntypedBaseClass = true
224
+ reportUntypedClassDecorator = true
225
+ reportUntypedFunctionDecorator = true
226
+ reportUntypedNamedTuple = true
227
+ reportUnusedExpression = true
228
+ reportUnusedImport = false # Covered by other linters.
229
+ reportUnusedVariable = false # Covered by other linters.
230
+ #strict = [ 'sources' ]
231
+ stubPath = 'sources/emcdproj/_typedecls'
232
+
233
+ [tool.pytest.ini_options]
234
+ # Note: Cannot run doctests from Pytest, because Pytest tries to update '_'
235
+ # attribute on protected modules. Instead, we use Sphinx to run doctests.
236
+ minversion = '8.1'
237
+ addopts = '--capture=no --exitfirst -rfE'
238
+ testpaths = [ 'tests' ]
239
+ python_files = [ 'test_*.py' ]
240
+ python_functions = [ 'test_[0-9][0-9][0-9]_*' ]
241
+ cache_dir = '.auxiliary/caches/pytest'
242
+
243
+ [tool.ruff]
244
+ builtins = [ 'ictr' ]
245
+ cache-dir = '.auxiliary/caches/ruff'
246
+ indent-width = 4
247
+ line-length = 79
248
+ [tool.ruff.lint]
249
+ dummy-variable-rgx = '^_$'
250
+ ignore = [
251
+ 'E701', # multiple-statements-on-one-line-colon
252
+ 'PLC0415', # import-outside-top-level
253
+ 'SIM300', # yoda-condition: scarred by assignment expressions, I am
254
+ ]
255
+ select = [ # default: E4, E7, E9, F
256
+ 'A', # Flake8 builtins rules
257
+ 'B006', # mutable-argument-default
258
+ 'B008', # function-call-in-default-argument
259
+ 'B011', # assert-false
260
+ 'B023', # function-uses-loop-variable
261
+ 'B904', # raise-without-from-inside-except
262
+ 'B909', # PREVIEW: loop-iterator-mutation
263
+ 'C90', # McCabe complexity rules
264
+ 'E101', # mixed-spaces-and-tabs
265
+ 'E111', # PREVIEW: indentation-with-invalid-multiple
266
+ 'E112', # PREVIEW: no-indented-block
267
+ 'E4', # Pycodestyle import rules
268
+ 'E501', # line-too-long
269
+ 'E7', # Pycodestyle general rules
270
+ 'E9', # Pycodestyle runtime errors
271
+ 'F', # Pyflakes rules
272
+ 'PERF', # Perflint rules
273
+ 'PLC', # Pylint convention rules
274
+ 'PLE', # Pylint error rules
275
+ 'PLR', # Pylint refactor rules
276
+ 'PLW', # Pylint warning rules
277
+ 'RET', # Flake8 return rules
278
+ 'RUF', # Ruff rules
279
+ 'S', # Flake8 Bandit rules
280
+ 'SIM', # Flake8 simplify rules
281
+ 'SLF', # Flake8 self rules
282
+ 'TRY', # Tryceratops rules
283
+ ]
284
+ [tool.ruff.lint.mccabe]
285
+ max-complexity = 12
286
+ [tool.ruff.lint.per-file-ignores]
287
+ '__init__.py' = [
288
+ 'F401', # unused-import
289
+ 'F403', # undefined-local-with-import-star
290
+ 'F405', # undefined-local-with-import-star-usage
291
+ ]
292
+ 'tests/**/*.py' = [
293
+ 'PLR0124', # comparison-with-itself
294
+ 'PLR0913', # too-many-arguments
295
+ 'PLR0915', # too-many-statements
296
+ 'PLR1704', # redefined-argument-from-local
297
+ 'PLR2004', # magic-value-comparison
298
+ 'PLW0129', # assert-on-string-literal
299
+ 'PLW0603', # global-statement
300
+ 'PLW0642', # self-assignment
301
+ 'S101', # assert
302
+ 'SLF001', # private-member-accessed
303
+ 'TRY', # Tryceratops rules
304
+ ]
305
+ [tool.ruff.lint.pylint]
306
+ max-locals = 10
307
+ max-public-methods = 10
308
+ max-statements = 30
309
+
310
+ [tool.towncrier]
311
+ directory = '.auxiliary/data/towncrier'
312
+ filename = 'documentation/changelog.rst'
313
+ package = 'emcdproj'
314
+ package_dir = 'sources'
315
+ [[tool.towncrier.type]]
316
+ # features and other improvements
317
+ directory = 'enhance'
318
+ name = 'Enhancements'
319
+ showcontent = true
320
+ [[tool.towncrier.type]]
321
+ # deprecations and other notices
322
+ directory = 'notify'
323
+ name = 'Notices'
324
+ showcontent = true
325
+ [[tool.towncrier.type]]
326
+ # removals of feature or platform support
327
+ directory = 'remove'
328
+ name = 'Removals'
329
+ showcontent = true
330
+ [[tool.towncrier.type]]
331
+ # bug fixes
332
+ directory = 'repair'
333
+ name = 'Repairs'
334
+ showcontent = true
@@ -20,7 +20,6 @@
20
20
 
21
21
  ''' Common imports and type aliases used throughout the package. '''
22
22
 
23
- # pylint: disable=unused-import
24
23
  # ruff: noqa: F401
25
24
 
26
25
 
@@ -30,9 +30,10 @@ from . import distribution as _distribution
30
30
  from . import state as _state
31
31
 
32
32
 
33
- async def prepare( # pylint: disable=too-many-arguments,too-many-locals
33
+ async def prepare(
34
34
  exits: __.ctxl.AsyncExitStack,
35
- application: _application.Information = _application.Information( ),
35
+ application: _application.Information = (
36
+ _application.Information( ) ), # noqa: B008
36
37
  # configedits: _dictedits.Edits = ( ),
37
38
  # configfile: __.Absential[ __.Path ] = __.absent,
38
39
  # environment: bool = False,
@@ -66,7 +67,7 @@ async def prepare( # pylint: disable=too-many-arguments,too-many-locals
66
67
  exits = exits )
67
68
  # if environment: await _environment.update( auxdata )
68
69
  # _inscribe_preparation_report( auxdata )
69
- return auxdata
70
+ return auxdata # noqa: RET504
70
71
 
71
72
 
72
73
  # def _inscribe_preparation_report( auxdata: _state.Globals ):
@@ -27,7 +27,7 @@ from . import exceptions
27
27
  # --- END: Injected by Copier ---
28
28
 
29
29
 
30
- __version__ = '1.15'
30
+ __version__ = '1.16'
31
31
 
32
32
 
33
33
  def main( ):
@@ -35,7 +35,7 @@ class VersionCommand(
35
35
  ''' Prints version information. '''
36
36
 
37
37
  async def __call__( self, auxdata: __.Globals ) -> None:
38
- from . import __version__ # pylint: disable=cyclic-import
38
+ from . import __version__
39
39
  print( f"{__package__} {__version__}" )
40
40
  raise SystemExit( 0 )
41
41
 
@@ -107,9 +107,8 @@ async def _prepare(
107
107
  import ictruck
108
108
  # TODO: Finetune Icecream truck installation from CLI arguments.
109
109
  ictruck.install( trace_levels = 9 )
110
- auxdata = await __.prepare(
110
+ return await __.prepare(
111
111
  application = application,
112
112
  # configedits = configedits,
113
113
  # environment = environment,
114
114
  exits = exits )
115
- return auxdata
@@ -26,7 +26,7 @@ from __future__ import annotations
26
26
  from . import __
27
27
 
28
28
 
29
- class CliCommand( # pylint: disable=invalid-metaclass
29
+ class CliCommand(
30
30
  __.typx.Protocol,
31
31
  metaclass = __.ImmutableProtocolDataclass,
32
32
  decorators = ( __.typx.runtime_checkable, ),
@@ -146,7 +146,7 @@ def update(
146
146
  locations.website.mkdir( exist_ok = True, parents = True )
147
147
  if locations.archive.is_file( ):
148
148
  with tarfile_open( locations.archive, 'r:xz' ) as archive:
149
- archive.extractall( path = locations.website )
149
+ archive.extractall( path = locations.website ) # noqa: S202
150
150
  available_species = _update_available_species( locations, version )
151
151
  j2context = _jinja2.Environment(
152
152
  loader = _jinja2.FileSystemLoader( locations.templates ),
@@ -157,7 +157,7 @@ def update(
157
157
  _update_coverage_badge( locations, j2context )
158
158
  ( locations.website / '.nojekyll' ).touch( )
159
159
  from .filesystem import chdir
160
- with chdir( locations.website ):
160
+ with chdir( locations.website ): # noqa: SIM117
161
161
  with tarfile_open( locations.archive, 'w:xz' ) as archive:
162
162
  archive.add( '.' )
163
163
 
@@ -195,7 +195,7 @@ def _update_available_species(
195
195
  return tuple( available_species )
196
196
 
197
197
 
198
- def _update_coverage_badge( # pylint: disable=too-many-locals
198
+ def _update_coverage_badge(
199
199
  locations: Locations, j2context: _jinja2.Environment
200
200
  ) -> None:
201
201
  ''' Updates coverage badge SVG.
@@ -207,11 +207,9 @@ def _update_coverage_badge( # pylint: disable=too-many-locals
207
207
  - green: >= 80%
208
208
  '''
209
209
  coverage = _extract_coverage( locations )
210
- # pylint: disable=magic-value-comparison
211
210
  color = (
212
- 'red' if coverage < 50 else (
213
- 'yellow' if coverage < 80 else 'green' ) )
214
- # pylint: enable=magic-value-comparison
211
+ 'red' if coverage < 50 else ( # noqa: PLR2004
212
+ 'yellow' if coverage < 80 else 'green' ) ) # noqa: PLR2004
215
213
  label_text = 'coverage'
216
214
  value_text = f"{coverage}%"
217
215
  label_width = len( label_text ) * 6 + 10
@@ -1,532 +0,0 @@
1
- # vim: set filetype=toml fileencoding=utf-8:
2
- # -*- mode: toml ; coding: utf-8 -*-
3
-
4
- [build-system]
5
- requires = [
6
- 'hatchling',
7
- ]
8
- build-backend = 'hatchling.build'
9
-
10
- [project]
11
- name = 'emcd-projects'
12
- description = 'Project management utilities.'
13
- dynamic = [ 'version' ]
14
- license = 'Apache-2.0'
15
- readme = { 'file' = 'sources/emcdproj/README.rst', 'content-type' = 'text/x-rst' }
16
- requires-python = '>= 3.10'
17
- dependencies = [
18
- 'Jinja2',
19
- 'absence',
20
- 'defusedxml',
21
- 'frigid',
22
- 'icecream-truck',
23
- 'importlib-metadata', # TODO: Drop once we have separate appcore package.
24
- 'importlib-resources', # TODO: Drop once we have separate appcore package.
25
- 'packaging',
26
- 'platformdirs', # TODO: Drop once we have separate appcore package.
27
- 'tomli', # TODO: Drop once we have separate appcore package.
28
- 'typing-extensions',
29
- # --- BEGIN: Injected by Copier ---
30
- 'tyro',
31
- # --- END: Injected by Copier ---
32
- ]
33
- classifiers = [ # https://pypi.org/classifiers
34
- 'Development Status :: 3 - Alpha',
35
- 'Intended Audience :: Developers',
36
- 'License :: OSI Approved :: Apache Software License',
37
- 'Programming Language :: Python :: 3 :: Only',
38
- # --- BEGIN: Injected by Copier ---
39
- 'Programming Language :: Python :: 3.10',
40
- 'Programming Language :: Python :: 3.11',
41
- 'Programming Language :: Python :: 3.12',
42
- 'Programming Language :: Python :: 3.13',
43
- 'Programming Language :: Python :: Implementation :: CPython',
44
- 'Programming Language :: Python :: Implementation :: PyPy',
45
- # --- END: Injected by Copier ---
46
- 'Topic :: Software Development',
47
- ]
48
- keywords = [ 'maintenance', 'project', 'template' ]
49
- [[project.authors]]
50
- name = 'Eric McDonald'
51
- email = 'emcd@users.noreply.github.com'
52
- [project.scripts]
53
- emcdproj = 'emcdproj:main'
54
- [project.urls]
55
- 'Homepage' = 'https://github.com/emcd/python-project-common'
56
- 'Documentation' = 'https://emcd.github.io/python-project-common'
57
- 'Download' = 'https://pypi.org/project/emcd-projects/#files'
58
- 'Source Code' = 'https://github.com/emcd/python-project-common'
59
- 'Issue Tracker' = 'https://github.com/emcd/python-project-common/issues'
60
-
61
- [tool.SELF]
62
- year-of-origin = 2024
63
-
64
- [tool.bandit]
65
- exclude_dirs = [ 'tests' ]
66
-
67
- # https://coverage.readthedocs.io/en/latest/config.html
68
- [tool.coverage.run]
69
- branch = true
70
- command_line = '-m pytest' # TODO? '--fail-under'
71
- data_file = '.auxiliary/caches/pytest/coverage.sqlite3'
72
- parallel = true
73
- source = [ 'sources' ]
74
- [tool.coverage.html]
75
- directory = '.auxiliary/artifacts/coverage-pytest'
76
- [tool.coverage.xml]
77
- output = '.auxiliary/artifacts/coverage-pytest/coverage.xml'
78
-
79
- # https://hatch.pypa.io/latest/config/metadata/
80
- [tool.hatch.build]
81
- directory = '.auxiliary/artifacts/hatch-build'
82
- [tool.hatch.build.targets.sdist]
83
- only-include = [
84
- 'sources/emcdproj',
85
- # --- BEGIN: Injected by Copier ---
86
- 'data',
87
- # --- END: Injected by Copier ---
88
- ]
89
- strict-naming = false
90
- [tool.hatch.build.targets.wheel]
91
- only-include = [
92
- 'sources/emcdproj',
93
- # --- BEGIN: Injected by Copier ---
94
- 'data',
95
- # --- END: Injected by Copier ---
96
- ]
97
- strict-naming = false
98
- [tool.hatch.build.targets.wheel.sources]
99
- 'sources/emcdproj' = 'emcdproj'
100
- # --- BEGIN: Injected by Copier ---
101
- 'data' = 'emcdproj/data'
102
- # --- END: Injected by Copier ---
103
- [tool.hatch.envs.default]
104
- python = '3.10'
105
- [tool.hatch.envs.develop]
106
- description = ''' Development environment. '''
107
- dependencies = [
108
- 'Jinja2',
109
- 'bandit',
110
- 'coverage[toml]',
111
- 'furo',
112
- 'icecream',
113
- 'isort',
114
- 'packaging',
115
- 'pre-commit',
116
- 'pyfakefs',
117
- 'pylint',
118
- 'pylint-per-file-ignores',
119
- 'pyright',
120
- 'pytest',
121
- 'pytest-asyncio',
122
- 'ruff',
123
- 'semgrep;platform_system!="Windows"', # https://github.com/returntocorp/semgrep/issues/1330
124
- 'sphinx',
125
- 'sphinx-copybutton',
126
- 'sphinx-inline-tabs',
127
- 'towncrier',
128
- 'tryceratops',
129
- 'yapf',
130
- # --- BEGIN: Injected by Copier ---
131
- # --- END: Injected by Copier ---
132
- ]
133
- post-install-commands = [
134
- # --- BEGIN: Injected by Copier ---
135
- # --- END: Injected by Copier ---
136
- ]
137
- [tool.hatch.envs.develop.env-vars]
138
- PYTHONUNBUFFERED = 'TRUE' # TODO: Only for coverage/pytest.
139
- # --- BEGIN: Injected by Copier ---
140
- # --- END: Injected by Copier ---
141
- [tool.hatch.envs.develop.scripts]
142
- docsgen = [
143
- '''sphinx-build -E -b doctest -d .auxiliary/caches/sphinx \
144
- documentation .auxiliary/artifacts/sphinx-doctest''',
145
- '''sphinx-build -E -b linkcheck -d .auxiliary/caches/sphinx \
146
- documentation .auxiliary/artifacts/sphinx-linkcheck''',
147
- '''sphinx-build -a -d .auxiliary/caches/sphinx \
148
- documentation .auxiliary/artifacts/sphinx-html''',
149
- ]
150
- linters = [
151
- '''ruff check --quiet sources documentation tests''',
152
- # --- BEGIN: Injected by Copier ---
153
- # --- END: Injected by Copier ---
154
- '''bandit --configfile pyproject.toml --quiet --recursive sources''',
155
- '''tryceratops sources''',
156
- '''pyright sources''',
157
- '''pylint --recursive yes sources documentation tests''',
158
- '''semgrep --config p/python --error --quiet --skip-unknown-extensions \
159
- sources/emcdproj''',
160
- # --- BEGIN: Injected by Copier ---
161
- # --- END: Injected by Copier ---
162
- ]
163
- packagers = [
164
- '''hatch build''',
165
- # --- BEGIN: Injected by Copier ---
166
- # --- END: Injected by Copier ---
167
- ]
168
- testers = [
169
- 'coverage erase',
170
- 'coverage run',
171
- 'coverage combine',
172
- 'coverage report --skip-covered',
173
- 'coverage html',
174
- 'coverage xml',
175
- ]
176
- make-all = [
177
- 'linters',
178
- 'testers',
179
- 'packagers',
180
- 'docsgen',
181
- ]
182
- [tool.hatch.envs.qa]
183
- description = ''' Quality assurance environment. '''
184
- template = 'develop'
185
- [[tool.hatch.envs.qa.matrix]]
186
- python = [
187
- '3.10',
188
- '3.11',
189
- '3.12',
190
- '3.13',
191
- 'pypy3.10',
192
- ]
193
- [tool.hatch.version]
194
- path = 'sources/emcdproj/__init__.py'
195
-
196
- # https://pycqa.github.io/isort/docs/configuration/options.html
197
- # https://pycqa.github.io/isort/docs/configuration/multi_line_output_modes.html
198
- [tool.isort]
199
- atomic = true
200
- #color = false
201
- #combine_as = false
202
- #combine_straight_imports = false
203
- #extra_standard_library = [ ]
204
- follow_links = false
205
- #force_alphabetical_sort_within_sections = false
206
- #float_to_top = false
207
- honor_noqa = true
208
- #ignore_whitespace = false
209
- include_trailing_comma = true
210
- # known_OTHER: substitute OTHER
211
- known_first_party = [ 'emcdproj' ]
212
- #known_third_party = [ ]
213
- #line_length = 79
214
- #lines_after_imports = -1 # automatic
215
- #lines_before_imports = -1 # automatic
216
- multi_line_output = 3 # vertical hanging indent
217
- #quiet = false
218
- #sections = [ 'FUTURE', 'STDLIB', 'THIRDPARTY', 'FIRSTPARTY', 'LOCALFOLDER' ]
219
- skip_gitignore = true
220
- split_on_trailing_comma = true
221
- #src_paths = [ ]
222
- #star_first = false
223
- #supported_extensions = [ 'pxd', 'py', 'pyi', 'pyx' ]
224
- use_parentheses = true
225
-
226
- # https://mypy.readthedocs.io/en/stable/config_file.html
227
- [tool.mypy]
228
- # Note: Due to repeated painful experiences with Mypy, we use Pyright instead.
229
- # Pyright properly handles TypeVars, etc...
230
- cache_dir = '.auxiliary/caches/mypy'
231
- exclude = [ '.*' ] # Ignore everything
232
- ignore_errors = true
233
- follow_imports = 'skip'
234
- pretty = true
235
- strict = false
236
-
237
- # https://pylint.pycqa.org/en/latest/user_guide/configuration/index.html
238
- [tool.pylint.main]
239
- fail-under = 10
240
- # TODO: jobs: Consider parallelization if output interleaving, dependency
241
- # grouping, and similarities detection bugs have been fixed.
242
- load-plugins = [
243
- # 'pylint.extensions.bad_builtin',
244
- 'pylint.extensions.broad_try_clause',
245
- 'pylint.extensions.check_elif',
246
- 'pylint.extensions.code_style',
247
- 'pylint.extensions.confusing_elif',
248
- # 'pylint.extensions.consider_ternary_expression',
249
- 'pylint.extensions.dict_init_mutate',
250
- 'pylint.extensions.dunder',
251
- 'pylint.extensions.eq_without_hash',
252
- 'pylint.extensions.for_any_all',
253
- 'pylint.extensions.magic_value',
254
- 'pylint.extensions.mccabe',
255
- 'pylint.extensions.no_self_use',
256
- 'pylint.extensions.overlapping_exceptions',
257
- 'pylint.extensions.private_import',
258
- 'pylint.extensions.redefined_loop_name',
259
- 'pylint.extensions.redefined_variable_type',
260
- # 'pylint.extensions.set_membership',
261
- # 'pylint.extensions.while_used',
262
- 'pylint_per_file_ignores',
263
- ]
264
- recursive = false
265
- suggestion-mode = true
266
- [tool.pylint.basic]
267
- const-rgx = '([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$'
268
- good-names = [ '_', '__' ]
269
- include-naming-hint = true
270
- [tool.pylint.broad_try_clause]
271
- max-try-statements = 2
272
- [tool.pylint.classes]
273
- defining-attr-methods = [ '__init__', '__new__', '__post_init__' ]
274
- exclude-protected = [ ]
275
- valid-classmethod-first-arg = [ 'selfclass' ]
276
- valid-metaclass-classmethod-first-arg = [ 'clscls' ]
277
- [tool.pylint.design]
278
- # TODO: exclude-too-few-public-methods: Consider exception hierarchies.
279
- ignored-parents = [
280
- 'abc.ABCMeta',
281
- 'builtins.AttributeError',
282
- 'builtins.BaseException',
283
- 'builtins.Exception',
284
- 'builtins.KeyError',
285
- 'builtins.TypeError',
286
- 'builtins.ValueError',
287
- 'builtins.type',
288
- 'typing.Protocol',
289
- 'typing_extensions.Protocol',
290
- # --- BEGIN: Injected by Copier ---
291
- 'emcdproj.exceptions.Omnierror',
292
- 'emcdproj.exceptions.Omniexception',
293
- # --- END: Injected by Copier ---
294
- ]
295
- max-args = 5
296
- max-attributes = 7
297
- max-bool-expr = 3
298
- max-branches = 12
299
- max-locals = 10
300
- max-parents = 3
301
- max-public-methods = 10
302
- max-returns = 6
303
- max-statements = 30
304
- min-public-methods = 1
305
- [tool.pylint.exceptions]
306
- overgeneral-exceptions = [
307
- 'builtins.BaseException',
308
- 'builtins.Exception',
309
- # --- BEGIN: Injected by Copier ---
310
- 'emcdproj.exceptions.Omnierror',
311
- 'emcdproj.exceptions.Omniexception',
312
- # --- END: Injected by Copier ---
313
- ]
314
- [tool.pylint.format]
315
- ignore-long-lines = '''^(\s*<?https?://\S+>?|([^'"]*\s+)?#.*)$'''
316
- max-line-length = 79
317
- max-module-lines = 800
318
- single-line-class-stmt = true
319
- single-line-if-stmt = true
320
- [tool.pylint.imports]
321
- allow-wildcard-with-all = false
322
- # TODO: ext-import-graph
323
- # TODO: int-import-graph
324
- [tool.pylint.logging]
325
- logging-format-style = 'new'
326
- [tool.pylint.'messages control']
327
- disable = [
328
- 'bad-dunder-name',
329
- 'consider-using-assignment-expr',
330
- 'consider-using-f-string',
331
- 'duplicate-code', # TODO: Re-enable after heuristic is fixed.
332
- 'fixme',
333
- 'f-string-without-interpolation',
334
- 'import-outside-toplevel',
335
- 'invalid-name',
336
- 'logging-format-interpolation',
337
- 'logging-fstring-interpolation',
338
- 'multiple-statements',
339
- 'reimported',
340
- 'too-few-public-methods',
341
- 'too-many-positional-arguments', # 'too-many-arguments' is good enough
342
- 'ungrouped-imports',
343
- 'unused-wildcard-import',
344
- 'use-dict-literal',
345
- 'using-exception-groups-in-unsupported-version',
346
- 'wrong-import-order',
347
- 'wrong-import-position',
348
- ]
349
- # TODO: Latest 'per-file-ignores' code may supports dicts and lists in addition to strings.
350
- per-file-ignores = '''
351
- /tests/:attribute-defined-outside-init,comparison-with-itself,magic-value-comparison,missing-class-docstring,missing-function-docstring,protected-access,redefined-outer-name,singleton-comparison,superfluous-parens,too-many-try-statements,unexpected-keyword-arg
352
- __init__\.py:unused-import
353
- ''' # Note: Paths are regexes.
354
- [tool.pylint.refactoring]
355
- max-nested-blocks = 3
356
- never-returning-functions = [ 'sys.exit', 'argparse.parse_error' ]
357
- [tool.pylint.reports]
358
- msg-template = '{path} {line:3d},{column:2d} [{symbol}] {msg}'
359
- output-format = 'colorized'
360
- reports = false
361
- score = true
362
- [tool.pylint.similarities]
363
- ignore-comments = true
364
- ignore-docstrings = true
365
- ignore-imports = true
366
- ignore-signatures = true
367
- min-similarity-lines = 5
368
- [tool.pylint.spelling]
369
- max-spelling-suggestions = 4
370
- # TODO: spelling-dict
371
- [tool.pylint.typecheck]
372
- contextmanager-decorators = [ 'contextlib.contextmanager' ]
373
- ignored-checks-for-mixins = [
374
- 'attribute-defined-outside-init',
375
- 'no-member',
376
- 'not-async-context-manager',
377
- 'not-context-manager',
378
- ]
379
- #ignored-classes = [ 'thread._local', '_thread._local', 'argparse.Namespace' ]
380
- ignore-mixin-members = false
381
- missing-member-hint = true
382
- missing-member-hint-distance = 1
383
- missing-member-max-choices = 2
384
- #mixin-class-rgx = '.*[Mm]ixin'
385
- #signature-mutators = [ ]
386
- [tool.pylint.variables]
387
- additional-builtins = [ 'ictr' ]
388
- callbacks = [ ]
389
- dummy-variables-rgx = '''_$'''
390
- ignored-argument-names = '''_.*'''
391
- redefining-builtins-modules = [ 'builtins', 'io' ]
392
-
393
- # https://microsoft.github.io/pyright/#/configuration
394
- [tool.pyright]
395
- include = [ 'sources' ]
396
- ignore = [ 'tests' ]
397
- reportConstantRedefinition = true
398
- reportInvalidTypeVarUse = true
399
- reportMatchNotExhaustive = true
400
- reportMissingImports = true
401
- reportMissingTypeStubs = true
402
- reportMissingTypeArgument = true
403
- reportPossiblyUnboundVariable = false # Covered by other linters.
404
- reportPrivateImportUsage = false # Covered by other linters.
405
- reportPrivateUsage = false # Covered by other linters.
406
- reportSelfClsParameterName = false # Too opinionated.
407
- reportUnknownArgumentType = true
408
- reportUnknownLambdaType = true
409
- reportUnknownMemberType = true
410
- reportUnknownParameterType = true
411
- reportUnknownVariableType = true
412
- reportUnnecessaryCast = true
413
- reportUnnecessaryComparison = true
414
- reportUntypedBaseClass = true
415
- reportUntypedClassDecorator = true
416
- reportUntypedFunctionDecorator = true
417
- reportUntypedNamedTuple = true
418
- reportUnusedExpression = true
419
- reportUnusedImport = false # Covered by other linters.
420
- reportUnusedVariable = false # Covered by other linters.
421
- #strict = [ 'sources' ]
422
- stubPath = 'sources/emcdproj/_typedecls'
423
-
424
- [tool.pytest.ini_options]
425
- # Note: Cannot run doctests from Pytest, because Pytest tries to update '_'
426
- # attribute on protected modules. Instead, we use Sphinx to run doctests.
427
- minversion = '8.1'
428
- addopts = '--capture=no --exitfirst -rfE'
429
- testpaths = [ 'tests' ]
430
- python_files = [ 'test_*.py' ]
431
- python_functions = [ 'test_[0-9][0-9][0-9]_*' ]
432
- cache_dir = '.auxiliary/caches/pytest'
433
-
434
- [tool.ruff]
435
- builtins = [ 'ictr' ]
436
- cache-dir = '.auxiliary/caches/ruff'
437
- [tool.ruff.lint]
438
- ignore = [
439
- 'E701', # multiple-statements-on-one-line-colon
440
- ]
441
- [tool.ruff.lint.per-file-ignores]
442
- '__init__.py' = [
443
- 'F401', # unused-import
444
- 'F403', # undefined-local-with-import-star
445
- 'F405', # undefined-local-with-import-star-usage
446
- ]
447
-
448
- [tool.towncrier]
449
- directory = '.auxiliary/data/towncrier'
450
- filename = 'documentation/changelog.rst'
451
- package = 'emcdproj'
452
- package_dir = 'sources'
453
- [[tool.towncrier.type]]
454
- directory = 'bugfix'
455
- name = 'Bugfixes'
456
- showcontent = true
457
- [[tool.towncrier.type]]
458
- directory = 'docs'
459
- name = 'Documentation Improvements'
460
- showcontent = true
461
- [[tool.towncrier.type]]
462
- directory = 'feature'
463
- name = 'Features'
464
- showcontent = true
465
- [[tool.towncrier.type]]
466
- directory = 'platform'
467
- name = 'Supported Platforms'
468
- showcontent = true
469
- [[tool.towncrier.type]]
470
- directory = 'removal'
471
- name = 'Deprecations and Removals'
472
- showcontent = true
473
-
474
- [tool.tryceratops]
475
- exclude = [ 'tests' ]
476
-
477
- # https://github.com/google/yapf?tab=readme-ov-file#knobs
478
- # yapf --style-help
479
- [tool.yapf]
480
- align_closing_bracket_with_visual_indent = false
481
- allow_multiline_dictionary_keys = true
482
- allow_multiline_lambdas = true
483
- #allow_split_before_default_or_named_assigns = true
484
- #allow_split_before_dict_value = true
485
- blank_line_before_module_docstring = true
486
- #blank_line_before_nested_class_or_def = true
487
- #blank_lines_around_top_level_definition = 2
488
- blank_lines_between_top_level_imports_and_variables = 2
489
- #coalesce_brackets = false
490
- #column_limit = 79
491
- #continuation_align_style = 'SPACE'
492
- #continuation_indent_width = 4
493
- dedent_closing_brackets = true
494
- #disable_ending_comma_heuristic = false
495
- #disable_split_list_with_comment = false
496
- #each_dict_entry_on_separate_line = true
497
- #force_multiline_dict = false
498
- indent_dictionary_value = true
499
- #indent_width = 4
500
- join_multiple_lines = true
501
- #space_between_ending_comma_and_closing_bracket = true
502
- space_inside_brackets = true
503
- spaces_around_default_or_named_assign = true
504
- spaces_around_dict_delimiters = true
505
- spaces_around_list_delimiters = true
506
- spaces_around_power_operator = true
507
- spaces_around_subscript_colon = true
508
- spaces_around_tuple_delimiters = true
509
- #spaces_before_comment = 2
510
- #split_all_comma_separated_values = false
511
- #split_all_top_level_comma_separated_values = false
512
- split_arguments_when_comma_terminated = true
513
- split_before_arithmetic_operator = true
514
- split_before_bitwise_operator = true
515
- split_before_closing_bracket = false
516
- #split_before_dict_set_generator = true
517
- split_before_dot = true
518
- split_before_expression_after_opening_paren = true
519
- split_before_first_argument = true
520
- split_before_logical_operator = true
521
- #split_before_named_assigns = true
522
- split_complex_comprehension = true
523
- split_penalty_after_opening_bracket = 100 # default: 300
524
- #split_penalty_after_unary_operator = 10000
525
- #split_penalty_arithmetic_operator = 300
526
- #split_penalty_before_if_expr = 0
527
- #split_penalty_bitwise_operator = 300
528
- #split_penalty_comprehension = 80
529
- #split_penalty_excess_character = 7000
530
- #split_penalty_for_added_line_split = 30
531
- #split_penalty_import_names = 0
532
- #split_penalty_logical_operator = 300
File without changes
File without changes