emcd-projects 1.16__tar.gz → 1.17__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.
- {emcd_projects-1.16 → emcd_projects-1.17}/.gitignore +2 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/PKG-INFO +1 -1
- emcd_projects-1.17/data/copier/answers-default.yaml +4 -0
- emcd_projects-1.17/data/copier/answers-maximum.yaml +14 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/pyproject.toml +0 -5
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/__/imports.py +11 -8
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/__init__.py +1 -1
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/cli.py +11 -4
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/interfaces.py +43 -1
- emcd_projects-1.17/sources/emcdproj/template.py +127 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/website.py +13 -10
- {emcd_projects-1.16 → emcd_projects-1.17}/LICENSE.txt +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/data/.gitignore +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/data/templates/coverage.svg.jinja +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/data/templates/website.html.jinja +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/README.rst +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/__/__init__.py +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/__/application.py +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/__/distribution.py +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/__/preparation.py +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/__/state.py +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/__main__.py +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/_typedecls/__builtins__.pyi +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/exceptions.py +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/filesystem.py +0 -0
- {emcd_projects-1.16 → emcd_projects-1.17}/sources/emcdproj/py.typed +0 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
project_name: python-test-maximum
|
2
|
+
distribution_name: emcdproj-maximum
|
3
|
+
package_name: maximum
|
4
|
+
description: 'All configuration options set.'
|
5
|
+
enable_rust_extension: true
|
6
|
+
include_data_resources: true
|
7
|
+
enable_property_tests: true
|
8
|
+
enable_publication: true
|
9
|
+
enable_cli: true
|
10
|
+
enable_executables: true
|
11
|
+
inject_foundations: true
|
12
|
+
inject_exceptions: true
|
13
|
+
inject_immutables: true
|
14
|
+
inject_docstring_utils: true
|
@@ -120,7 +120,6 @@ dependencies = [
|
|
120
120
|
'pytest',
|
121
121
|
'pytest-asyncio',
|
122
122
|
'ruff',
|
123
|
-
'semgrep;platform_system!="Windows"', # https://github.com/returntocorp/semgrep/issues/1330
|
124
123
|
'sphinx',
|
125
124
|
'sphinx-copybutton',
|
126
125
|
'sphinx-inline-tabs',
|
@@ -150,10 +149,6 @@ linters = [
|
|
150
149
|
# --- BEGIN: Injected by Copier ---
|
151
150
|
# --- END: Injected by Copier ---
|
152
151
|
'''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
152
|
]
|
158
153
|
packagers = [
|
159
154
|
'''hatch build''',
|
@@ -25,14 +25,17 @@
|
|
25
25
|
|
26
26
|
from __future__ import annotations
|
27
27
|
|
28
|
-
import
|
29
|
-
import collections.abc as
|
30
|
-
import contextlib as
|
31
|
-
import
|
32
|
-
import
|
33
|
-
import
|
34
|
-
import
|
35
|
-
import
|
28
|
+
import abc
|
29
|
+
import collections.abc as cabc
|
30
|
+
import contextlib as ctxl
|
31
|
+
import enum
|
32
|
+
import io
|
33
|
+
import json
|
34
|
+
import math
|
35
|
+
import os
|
36
|
+
import shutil
|
37
|
+
import sys
|
38
|
+
import types
|
36
39
|
|
37
40
|
from pathlib import Path
|
38
41
|
|
@@ -25,6 +25,7 @@ from __future__ import annotations
|
|
25
25
|
|
26
26
|
from . import __
|
27
27
|
from . import interfaces as _interfaces
|
28
|
+
from . import template as _template
|
28
29
|
from . import website as _website
|
29
30
|
|
30
31
|
|
@@ -34,7 +35,9 @@ class VersionCommand(
|
|
34
35
|
):
|
35
36
|
''' Prints version information. '''
|
36
37
|
|
37
|
-
async def __call__(
|
38
|
+
async def __call__(
|
39
|
+
self, auxdata: __.Globals, display: _interfaces.ConsoleDisplay
|
40
|
+
) -> None:
|
38
41
|
from . import __version__
|
39
42
|
print( f"{__package__} {__version__}" )
|
40
43
|
raise SystemExit( 0 )
|
@@ -48,8 +51,12 @@ class Cli(
|
|
48
51
|
|
49
52
|
application: __.ApplicationInformation
|
50
53
|
# configfile: __.typx.Optional[ str ] = None
|
51
|
-
|
54
|
+
display: _interfaces.ConsoleDisplay
|
52
55
|
command: __.typx.Union[
|
56
|
+
__.typx.Annotated[
|
57
|
+
_template.CommandDispatcher,
|
58
|
+
__.tyro.conf.subcommand( 'template', prefix_name = False ),
|
59
|
+
],
|
53
60
|
__.typx.Annotated[
|
54
61
|
_website.CommandDispatcher,
|
55
62
|
__.tyro.conf.subcommand( 'website', prefix_name = False ),
|
@@ -66,8 +73,8 @@ class Cli(
|
|
66
73
|
async with __.ctxl.AsyncExitStack( ) as exits:
|
67
74
|
auxdata = await _prepare( exits = exits, **nomargs )
|
68
75
|
ictr( 0 )( self.command )
|
69
|
-
await self.command( auxdata = auxdata )
|
70
|
-
|
76
|
+
# await self.command( auxdata = auxdata )
|
77
|
+
await self.command( auxdata = auxdata, display = self.display )
|
71
78
|
|
72
79
|
def prepare_invocation_args(
|
73
80
|
self,
|
@@ -26,6 +26,46 @@ from __future__ import annotations
|
|
26
26
|
from . import __
|
27
27
|
|
28
28
|
|
29
|
+
class DisplayStreams( __.enum.Enum ): # TODO: Python 3.11: StrEnum
|
30
|
+
# TODO: Protected class attributes.
|
31
|
+
''' Stream upon which to place output. '''
|
32
|
+
|
33
|
+
Stderr = 'stderr'
|
34
|
+
Stdout = 'stdout'
|
35
|
+
|
36
|
+
|
37
|
+
class ConsoleDisplay(
|
38
|
+
metaclass = __.ImmutableDataclass,
|
39
|
+
):
|
40
|
+
silence: __.typx.Annotated[
|
41
|
+
bool,
|
42
|
+
__.tyro.conf.arg(
|
43
|
+
aliases = ( '--quiet', '--silent', ), prefix_name = False ),
|
44
|
+
] = False
|
45
|
+
file: __.typx.Annotated[
|
46
|
+
__.typx.Optional[ __.Path ],
|
47
|
+
__.tyro.conf.arg(
|
48
|
+
name = 'console-capture-file', prefix_name = False ),
|
49
|
+
] = None
|
50
|
+
stream: __.typx.Annotated[
|
51
|
+
DisplayStreams,
|
52
|
+
__.tyro.conf.arg( name = 'console-stream', prefix_name = False ),
|
53
|
+
] = DisplayStreams.Stderr
|
54
|
+
|
55
|
+
async def provide_stream( self ) -> __.io.TextIOWrapper:
|
56
|
+
''' Provides output stream for display. '''
|
57
|
+
# TODO: register file stream as a process-lifetime exit
|
58
|
+
if self.file: return open( self.file, 'w' )
|
59
|
+
# TODO: async context manager for async file streams
|
60
|
+
# TODO: return async stream - need async printers
|
61
|
+
# TODO: handle non-TextIOWrapper streams
|
62
|
+
match self.stream:
|
63
|
+
case DisplayStreams.Stdout:
|
64
|
+
return __.sys.stdout # pyright: ignore[reportReturnType]
|
65
|
+
case DisplayStreams.Stderr:
|
66
|
+
return __.sys.stderr # pyright: ignore[reportReturnType]
|
67
|
+
|
68
|
+
|
29
69
|
class CliCommand(
|
30
70
|
__.typx.Protocol,
|
31
71
|
metaclass = __.ImmutableProtocolDataclass,
|
@@ -34,7 +74,9 @@ class CliCommand(
|
|
34
74
|
''' CLI command. '''
|
35
75
|
|
36
76
|
@__.abc.abstractmethod
|
37
|
-
async def __call__(
|
77
|
+
async def __call__(
|
78
|
+
self, auxdata: __.Globals, display: ConsoleDisplay
|
79
|
+
) -> None:
|
38
80
|
''' Executes command with global state. '''
|
39
81
|
raise NotImplementedError
|
40
82
|
|
@@ -0,0 +1,127 @@
|
|
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
|
+
''' Copier template maintenance and validation. '''
|
22
|
+
|
23
|
+
|
24
|
+
from __future__ import annotations
|
25
|
+
|
26
|
+
import subprocess as _subprocess
|
27
|
+
import tempfile as _tempfile
|
28
|
+
|
29
|
+
from . import __
|
30
|
+
from . import interfaces as _interfaces
|
31
|
+
|
32
|
+
|
33
|
+
class CommandDispatcher(
|
34
|
+
_interfaces.CliCommand, decorators = ( __.standard_tyro_class, ),
|
35
|
+
):
|
36
|
+
''' Dispatches commands for static website maintenance. '''
|
37
|
+
|
38
|
+
command: __.typx.Union[
|
39
|
+
__.typx.Annotated[
|
40
|
+
SurveyCommand,
|
41
|
+
__.tyro.conf.subcommand( 'survey', prefix_name = False ),
|
42
|
+
],
|
43
|
+
__.typx.Annotated[
|
44
|
+
ValidateCommand,
|
45
|
+
__.tyro.conf.subcommand( 'validate', prefix_name = False ),
|
46
|
+
],
|
47
|
+
]
|
48
|
+
|
49
|
+
async def __call__(
|
50
|
+
self, auxdata: __.Globals, display: _interfaces.ConsoleDisplay
|
51
|
+
) -> None:
|
52
|
+
ictr( 1 )( self.command )
|
53
|
+
await self.command( auxdata = auxdata, display = display )
|
54
|
+
|
55
|
+
|
56
|
+
class SurveyCommand(
|
57
|
+
_interfaces.CliCommand, decorators = ( __.standard_tyro_class, ),
|
58
|
+
):
|
59
|
+
''' Surveys available configuration variants. '''
|
60
|
+
|
61
|
+
async def __call__(
|
62
|
+
self, auxdata: __.Globals, display: _interfaces.ConsoleDisplay
|
63
|
+
) -> None:
|
64
|
+
stream = await display.provide_stream( )
|
65
|
+
for variant in survey_variants( auxdata ):
|
66
|
+
print( variant, file = stream )
|
67
|
+
|
68
|
+
|
69
|
+
class ValidateCommand(
|
70
|
+
_interfaces.CliCommand, decorators = ( __.standard_tyro_class, ),
|
71
|
+
):
|
72
|
+
''' Validates template against configuration variant. '''
|
73
|
+
|
74
|
+
variant: __.typx.Annotated[
|
75
|
+
str,
|
76
|
+
__.typx.Doc( ''' Configuration variant to validate. ''' ),
|
77
|
+
__.tyro.conf.Positional,
|
78
|
+
]
|
79
|
+
|
80
|
+
async def __call__(
|
81
|
+
self, auxdata: __.Globals, display: _interfaces.ConsoleDisplay
|
82
|
+
) -> None:
|
83
|
+
''' Copies new project from template for configuration variant. '''
|
84
|
+
# TODO: Validate variant argument.
|
85
|
+
validate_variant( auxdata, self.variant )
|
86
|
+
|
87
|
+
|
88
|
+
def copy_template( answers_file: __.Path, projectdir: __.Path ) -> None:
|
89
|
+
''' Copies template to target directory using answers. '''
|
90
|
+
_subprocess.run( # noqa: S603
|
91
|
+
( 'copier', 'copy', '--data-file', str( answers_file ),
|
92
|
+
'--defaults', '--overwrite', '--vcs-ref', 'HEAD',
|
93
|
+
'.', str( projectdir ) ),
|
94
|
+
cwd = __.Path( ), check = True )
|
95
|
+
|
96
|
+
|
97
|
+
def survey_variants( auxdata: __.Globals ) -> __.cabc.Sequence[ str ]:
|
98
|
+
''' Surveys available configuration variants. '''
|
99
|
+
location = auxdata.distribution.provide_data_location( 'copier' )
|
100
|
+
return tuple(
|
101
|
+
fsent.stem.lstrip( 'answers-' )
|
102
|
+
for fsent in location.glob( 'answers-*.yaml' )
|
103
|
+
if fsent.is_file( ) )
|
104
|
+
|
105
|
+
|
106
|
+
def validate_variant( auxdata: __.Globals, variant: str ) -> None:
|
107
|
+
''' Validates configuration variant. '''
|
108
|
+
answers_file = (
|
109
|
+
auxdata.distribution.provide_data_location(
|
110
|
+
'copier', f"answers-{variant}.yaml" ) )
|
111
|
+
if not answers_file.is_file( ):
|
112
|
+
# TODO: Raise error.
|
113
|
+
return
|
114
|
+
with _tempfile.TemporaryDirectory( ) as tmpdir:
|
115
|
+
projectdir = __.Path( tmpdir ) / variant
|
116
|
+
copy_template( answers_file, projectdir )
|
117
|
+
validate_variant_project( projectdir )
|
118
|
+
|
119
|
+
|
120
|
+
def validate_variant_project( projectdir: __.Path ) -> None:
|
121
|
+
''' Validates standard project as generated from template. '''
|
122
|
+
for command in (
|
123
|
+
( 'hatch', '--env', 'develop', 'run',
|
124
|
+
'python', '-m', 'pip', 'install',
|
125
|
+
'--upgrade', 'pip', 'build' ),
|
126
|
+
( 'hatch', '--env', 'develop', 'run', 'make-all' ),
|
127
|
+
): _subprocess.run( command, cwd = str( projectdir ), check = True ) # noqa: S603
|
@@ -33,8 +33,7 @@ from . import interfaces as _interfaces
|
|
33
33
|
|
34
34
|
|
35
35
|
class CommandDispatcher(
|
36
|
-
_interfaces.CliCommand,
|
37
|
-
decorators = ( __.standard_tyro_class, ),
|
36
|
+
_interfaces.CliCommand, decorators = ( __.standard_tyro_class, ),
|
38
37
|
):
|
39
38
|
''' Dispatches commands for static website maintenance. '''
|
40
39
|
|
@@ -49,25 +48,27 @@ class CommandDispatcher(
|
|
49
48
|
],
|
50
49
|
]
|
51
50
|
|
52
|
-
async def __call__(
|
51
|
+
async def __call__(
|
52
|
+
self, auxdata: __.Globals, display: _interfaces.ConsoleDisplay
|
53
|
+
) -> None:
|
53
54
|
ictr( 1 )( self.command )
|
54
|
-
await self.command( auxdata = auxdata )
|
55
|
+
await self.command( auxdata = auxdata, display = display )
|
55
56
|
|
56
57
|
|
57
58
|
class SurveyCommand(
|
58
|
-
_interfaces.CliCommand,
|
59
|
-
decorators = ( __.standard_tyro_class, ),
|
59
|
+
_interfaces.CliCommand, decorators = ( __.standard_tyro_class, ),
|
60
60
|
):
|
61
61
|
''' Surveys release versions published in static website. '''
|
62
62
|
|
63
|
-
async def __call__(
|
63
|
+
async def __call__(
|
64
|
+
self, auxdata: __.Globals, display: _interfaces.ConsoleDisplay
|
65
|
+
) -> None:
|
64
66
|
# TODO: Implement.
|
65
67
|
pass
|
66
68
|
|
67
69
|
|
68
70
|
class UpdateCommand(
|
69
|
-
_interfaces.CliCommand,
|
70
|
-
decorators = ( __.standard_tyro_class, ),
|
71
|
+
_interfaces.CliCommand, decorators = ( __.standard_tyro_class, ),
|
71
72
|
):
|
72
73
|
''' Updates static website for particular release version. '''
|
73
74
|
|
@@ -77,7 +78,9 @@ class UpdateCommand(
|
|
77
78
|
__.tyro.conf.Positional,
|
78
79
|
]
|
79
80
|
|
80
|
-
async def __call__(
|
81
|
+
async def __call__(
|
82
|
+
self, auxdata: __.Globals, display: _interfaces.ConsoleDisplay
|
83
|
+
) -> None:
|
81
84
|
update( auxdata, self.version )
|
82
85
|
|
83
86
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|