emcd-projects 1.14rc0__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.
- emcd_projects-1.14rc0.dist-info/METADATA +132 -0
- emcd_projects-1.14rc0.dist-info/RECORD +24 -0
- emcd_projects-1.14rc0.dist-info/WHEEL +4 -0
- emcd_projects-1.14rc0.dist-info/entry_points.txt +2 -0
- emcd_projects-1.14rc0.dist-info/licenses/LICENSE.txt +202 -0
- emcdproj/README.rst +93 -0
- emcdproj/__/__init__.py +33 -0
- emcdproj/__/application.py +50 -0
- emcdproj/__/distribution.py +90 -0
- emcdproj/__/imports.py +60 -0
- emcdproj/__/preparation.py +83 -0
- emcdproj/__/state.py +80 -0
- emcdproj/__init__.py +39 -0
- emcdproj/__main__.py +28 -0
- emcdproj/_typedecls/__builtins__.pyi +7 -0
- emcdproj/cli.py +115 -0
- emcdproj/data/.gitignore +0 -0
- emcdproj/data/templates/coverage.svg.jinja +35 -0
- emcdproj/data/templates/website.html.jinja +58 -0
- emcdproj/exceptions.py +69 -0
- emcdproj/filesystem.py +39 -0
- emcdproj/interfaces.py +41 -0
- emcdproj/py.typed +0 -0
- emcdproj/website.py +279 -0
emcdproj/__/imports.py
ADDED
@@ -0,0 +1,60 @@
|
|
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 imports and type aliases used throughout the package. '''
|
22
|
+
|
23
|
+
# pylint: disable=unused-import
|
24
|
+
# ruff: noqa: F401
|
25
|
+
|
26
|
+
|
27
|
+
from __future__ import annotations
|
28
|
+
|
29
|
+
import abc
|
30
|
+
import collections.abc as cabc
|
31
|
+
import contextlib as ctxl
|
32
|
+
import json
|
33
|
+
import math
|
34
|
+
import os
|
35
|
+
import shutil
|
36
|
+
import types
|
37
|
+
|
38
|
+
from pathlib import Path
|
39
|
+
|
40
|
+
import typing_extensions as typx
|
41
|
+
# --- BEGIN: Injected by Copier ---
|
42
|
+
import tyro
|
43
|
+
# --- END: Injected by Copier ---
|
44
|
+
|
45
|
+
from absence import Absential, absent, is_absent
|
46
|
+
from frigid.qaliases import (
|
47
|
+
ImmutableClass,
|
48
|
+
ImmutableDataclass,
|
49
|
+
ImmutableProtocolDataclass,
|
50
|
+
immutable,
|
51
|
+
)
|
52
|
+
from platformdirs import PlatformDirs
|
53
|
+
|
54
|
+
|
55
|
+
ComparisonResult: typx.TypeAlias = bool | types.NotImplementedType
|
56
|
+
|
57
|
+
|
58
|
+
package_name = __name__.split( '.', maxsplit = 1 )[ 0 ]
|
59
|
+
simple_tyro_class = tyro.conf.configure( )
|
60
|
+
standard_tyro_class = tyro.conf.configure( tyro.conf.OmitArgPrefixes )
|
@@ -0,0 +1,83 @@
|
|
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
|
+
''' Preparation of the library core. '''
|
22
|
+
|
23
|
+
|
24
|
+
from . import imports as __
|
25
|
+
from . import application as _application
|
26
|
+
# from . import configuration as _configuration
|
27
|
+
# from . import dictedits as _dictedits
|
28
|
+
from . import distribution as _distribution
|
29
|
+
# from . import environment as _environment
|
30
|
+
from . import state as _state
|
31
|
+
|
32
|
+
|
33
|
+
async def prepare( # pylint: disable=too-many-arguments,too-many-locals
|
34
|
+
exits: __.ctxl.AsyncExitStack,
|
35
|
+
application: _application.Information = _application.Information( ),
|
36
|
+
# configedits: _dictedits.Edits = ( ),
|
37
|
+
# configfile: __.Absential[ __.Path ] = __.absent,
|
38
|
+
# environment: bool = False,
|
39
|
+
) -> _state.Globals:
|
40
|
+
''' Prepares globals DTO for use with library functions.
|
41
|
+
|
42
|
+
Also:
|
43
|
+
* Configures logging for library package (not application).
|
44
|
+
* Optionally, loads process environment from files.
|
45
|
+
|
46
|
+
Note that asynchronous preparation allows for applications to
|
47
|
+
concurrently initialize other entities outside of the library, even
|
48
|
+
though the library initialization, itself, is inherently sequential.
|
49
|
+
'''
|
50
|
+
directories = application.produce_platform_directories( )
|
51
|
+
distribution = (
|
52
|
+
await _distribution.Information.prepare(
|
53
|
+
package = __.package_name, exits = exits ) )
|
54
|
+
# configuration = (
|
55
|
+
# await _configuration.acquire(
|
56
|
+
# application_name = application.name,
|
57
|
+
# directories = directories,
|
58
|
+
# distribution = distribution,
|
59
|
+
# edits = configedits,
|
60
|
+
# file = configfile ) )
|
61
|
+
auxdata = _state.Globals(
|
62
|
+
application = application,
|
63
|
+
# configuration = configuration,
|
64
|
+
directories = directories,
|
65
|
+
distribution = distribution,
|
66
|
+
exits = exits )
|
67
|
+
# if environment: await _environment.update( auxdata )
|
68
|
+
# _inscribe_preparation_report( auxdata )
|
69
|
+
return auxdata
|
70
|
+
|
71
|
+
|
72
|
+
# def _inscribe_preparation_report( auxdata: _state.Globals ):
|
73
|
+
# scribe = __.produce_scribe( __.package_name )
|
74
|
+
# scribe.debug( f"Application Name: {auxdata.application.name}" )
|
75
|
+
# # scribe.debug( f"Execution ID: {auxdata.application.execution_id}" )
|
76
|
+
# scribe.debug( "Application Cache Location: {}".format(
|
77
|
+
# auxdata.provide_cache_location( ) ) )
|
78
|
+
# scribe.debug( "Application Data Location: {}".format(
|
79
|
+
# auxdata.provide_data_location( ) ) )
|
80
|
+
# scribe.debug( "Application State Location: {}".format(
|
81
|
+
# auxdata.provide_state_location( ) ) )
|
82
|
+
# scribe.debug( "Package Data Location: {}".format(
|
83
|
+
# auxdata.distribution.provide_data_location( ) ) )
|
emcdproj/__/state.py
ADDED
@@ -0,0 +1,80 @@
|
|
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 global state. '''
|
22
|
+
|
23
|
+
|
24
|
+
from . import imports as __
|
25
|
+
from . import application as _application
|
26
|
+
from . import distribution as _distribution
|
27
|
+
|
28
|
+
|
29
|
+
# class DirectorySpecies( __.enum.Enum ): # TODO: Python 3.11: StrEnum
|
30
|
+
# ''' Possible species for locations. '''
|
31
|
+
#
|
32
|
+
# Cache = 'cache'
|
33
|
+
# Data = 'data'
|
34
|
+
# State = 'state'
|
35
|
+
|
36
|
+
|
37
|
+
class Globals( metaclass = __.ImmutableDataclass ):
|
38
|
+
''' Immutable global data. Required by some library functions. '''
|
39
|
+
|
40
|
+
application: _application.Information
|
41
|
+
# configuration: __.AccretiveDictionary[ str, __.typx.Any ]
|
42
|
+
directories: __.PlatformDirs
|
43
|
+
distribution: _distribution.Information
|
44
|
+
exits: __.ctxl.AsyncExitStack
|
45
|
+
|
46
|
+
def as_dictionary( self ) -> __.cabc.Mapping[ str, __.typx.Any ]:
|
47
|
+
''' Returns shallow copy of state. '''
|
48
|
+
from dataclasses import fields
|
49
|
+
return {
|
50
|
+
field.name: getattr( self, field.name )
|
51
|
+
for field in fields( self ) }
|
52
|
+
|
53
|
+
# def provide_cache_location( self, *appendages: str ) -> __.Path:
|
54
|
+
# ''' Provides cache location from configuration. '''
|
55
|
+
# return self.provide_location( DirectorySpecies.Cache, *appendages )
|
56
|
+
|
57
|
+
# def provide_data_location( self, *appendages: str ) -> __.Path:
|
58
|
+
# ''' Provides data location from configuration. '''
|
59
|
+
# return self.provide_location( DirectorySpecies.Data, *appendages )
|
60
|
+
|
61
|
+
# def provide_state_location( self, *appendages: str ) -> __.Path:
|
62
|
+
# ''' Provides state location from configuration. '''
|
63
|
+
# return self.provide_location( DirectorySpecies.State, *appendages )
|
64
|
+
|
65
|
+
# def provide_location(
|
66
|
+
# self, species: DirectorySpecies, *appendages: str
|
67
|
+
# ) -> __.Path:
|
68
|
+
# ''' Provides particular species of location from configuration. '''
|
69
|
+
# species_name = species.value
|
70
|
+
# base = getattr( self.directories, f"user_{species_name}_path" )
|
71
|
+
# spec = self.configuration.get( 'locations', { } ).get( species_name )
|
72
|
+
# if spec:
|
73
|
+
# args: dict[ str, str | __.Path ] = {
|
74
|
+
# f"user_{species_name}": base,
|
75
|
+
# 'user_home': __.Path.home( ),
|
76
|
+
# 'application_name': self.application.name,
|
77
|
+
# }
|
78
|
+
# base = __.Path( spec.format( **args ) )
|
79
|
+
# if appendages: return base.joinpath( *appendages )
|
80
|
+
# return base
|
emcdproj/__init__.py
ADDED
@@ -0,0 +1,39 @@
|
|
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
|
+
''' Project management utilities. '''
|
22
|
+
|
23
|
+
|
24
|
+
from . import __
|
25
|
+
# --- BEGIN: Injected by Copier ---
|
26
|
+
from . import exceptions
|
27
|
+
# --- END: Injected by Copier ---
|
28
|
+
|
29
|
+
|
30
|
+
__version__ = '1.14rc0'
|
31
|
+
|
32
|
+
|
33
|
+
def main( ):
|
34
|
+
''' Entrypoint. '''
|
35
|
+
from .cli import execute
|
36
|
+
execute( )
|
37
|
+
|
38
|
+
|
39
|
+
# TODO: Reclassify package modules as immutable and concealed.
|
emcdproj/__main__.py
ADDED
@@ -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
|
+
''' Entrypoint. '''
|
22
|
+
|
23
|
+
|
24
|
+
# Note: Use absolute import for PyInstaller happiness.
|
25
|
+
from emcdproj.cli import execute
|
26
|
+
|
27
|
+
|
28
|
+
if '__main__' == __name__: execute( )
|
emcdproj/cli.py
ADDED
@@ -0,0 +1,115 @@
|
|
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
|
+
''' Command-line interface. '''
|
22
|
+
|
23
|
+
|
24
|
+
from __future__ import annotations
|
25
|
+
|
26
|
+
from . import __
|
27
|
+
from . import interfaces as _interfaces
|
28
|
+
from . import website as _website
|
29
|
+
|
30
|
+
|
31
|
+
class VersionCommand(
|
32
|
+
_interfaces.CliCommand,
|
33
|
+
decorators = ( __.standard_tyro_class, ),
|
34
|
+
):
|
35
|
+
''' Prints version information. '''
|
36
|
+
|
37
|
+
async def __call__( self, auxdata: __.Globals ) -> None:
|
38
|
+
from . import __version__ # pylint: disable=cyclic-import
|
39
|
+
print( f"{__package__} {__version__}" )
|
40
|
+
raise SystemExit( 0 )
|
41
|
+
|
42
|
+
|
43
|
+
class Cli(
|
44
|
+
metaclass = __.ImmutableDataclass,
|
45
|
+
decorators = ( __.simple_tyro_class, ),
|
46
|
+
):
|
47
|
+
''' Various utilities for projects by Github user '@emcd'. '''
|
48
|
+
|
49
|
+
application: __.ApplicationInformation
|
50
|
+
# configfile: __.typx.Optional[ str ] = None
|
51
|
+
# display: ConsoleDisplay
|
52
|
+
command: __.typx.Union[
|
53
|
+
__.typx.Annotated[
|
54
|
+
_website.CommandDispatcher,
|
55
|
+
__.tyro.conf.subcommand( 'website', prefix_name = False ),
|
56
|
+
],
|
57
|
+
__.typx.Annotated[
|
58
|
+
VersionCommand,
|
59
|
+
__.tyro.conf.subcommand( 'version', prefix_name = False ),
|
60
|
+
],
|
61
|
+
]
|
62
|
+
|
63
|
+
async def __call__( self ):
|
64
|
+
''' Invokes command after library preparation. '''
|
65
|
+
nomargs = self.prepare_invocation_args( )
|
66
|
+
async with __.ctxl.AsyncExitStack( ) as exits:
|
67
|
+
auxdata = await _prepare( exits = exits, **nomargs )
|
68
|
+
ictr( 0 )( self.command )
|
69
|
+
await self.command( auxdata = auxdata )
|
70
|
+
# await self.command( auxdata = auxdata, display = self.display )
|
71
|
+
|
72
|
+
def prepare_invocation_args(
|
73
|
+
self,
|
74
|
+
) -> __.cabc.Mapping[ str, __.typx.Any ]:
|
75
|
+
''' Prepares arguments for initial configuration. '''
|
76
|
+
# configedits: __.DictionaryEdits = (
|
77
|
+
# self.command.provide_configuration_edits( ) )
|
78
|
+
args: dict[ str, __.typx.Any ] = dict(
|
79
|
+
application = self.application,
|
80
|
+
# configedits = configedits,
|
81
|
+
# environment = True,
|
82
|
+
)
|
83
|
+
# if self.configfile: args[ 'configfile' ] = self.configfile
|
84
|
+
return args
|
85
|
+
|
86
|
+
|
87
|
+
def execute( ) -> None:
|
88
|
+
''' Entrypoint for CLI execution. '''
|
89
|
+
from asyncio import run
|
90
|
+
config = (
|
91
|
+
__.tyro.conf.HelptextFromCommentsOff,
|
92
|
+
)
|
93
|
+
try: run( __.tyro.cli( Cli, config = config )( ) )
|
94
|
+
except SystemExit: raise
|
95
|
+
except BaseException:
|
96
|
+
# TODO: Log exception.
|
97
|
+
raise SystemExit( 1 ) from None
|
98
|
+
|
99
|
+
|
100
|
+
async def _prepare(
|
101
|
+
application: __.ApplicationInformation,
|
102
|
+
# configedits: __.DictionaryEdits,
|
103
|
+
# environment: bool,
|
104
|
+
exits: __.ctxl.AsyncExitStack,
|
105
|
+
) -> __.Globals:
|
106
|
+
''' Configures logging based on verbosity. '''
|
107
|
+
import ictruck
|
108
|
+
# TODO: Finetune Icecream truck installation from CLI arguments.
|
109
|
+
ictruck.install( trace_levels = 9 )
|
110
|
+
auxdata = await __.prepare(
|
111
|
+
application = application,
|
112
|
+
# configedits = configedits,
|
113
|
+
# environment = environment,
|
114
|
+
exits = exits )
|
115
|
+
return auxdata
|
emcdproj/data/.gitignore
ADDED
File without changes
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg"
|
2
|
+
width="{{ total_width }}" height="20"
|
3
|
+
role="img" aria-label="{{ label_text }}: {{ value_text }}"
|
4
|
+
>
|
5
|
+
<title>{{ label_text }}: {{ value_text }}</title>
|
6
|
+
<linearGradient id="s" x2="0" y2="100%">
|
7
|
+
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
8
|
+
<stop offset="1" stop-opacity=".1"/>
|
9
|
+
</linearGradient>
|
10
|
+
<clipPath id="r">
|
11
|
+
<rect width="{{ total_width }}" height="20" rx="3" fill="#fff"/>
|
12
|
+
</clipPath>
|
13
|
+
<g clip-path="url(#r)">
|
14
|
+
<rect width="{{ label_width }}" height="20" fill="#555"/>
|
15
|
+
<rect x="{{ label_width }}" width="{{ value_width }}" height="20" fill="{{ color }}"/>
|
16
|
+
<rect width="{{ total_width }}" height="20" fill="url(#s)"/>
|
17
|
+
</g>
|
18
|
+
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110">
|
19
|
+
<text aria-hidden="true"
|
20
|
+
x="{{ label_width / 2 * 10 }}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)"
|
21
|
+
>
|
22
|
+
{{ label_text }}
|
23
|
+
</text>
|
24
|
+
<text x="{{ label_width / 2 * 10 }}" y="140" transform="scale(.1)" fill="#fff">{{ label_text }}</text>
|
25
|
+
<text aria-hidden="true"
|
26
|
+
x="{{ label_width * 10 + value_width / 2 * 10 }}" y="150"
|
27
|
+
fill="#010101" fill-opacity=".3" transform="scale(.1)"
|
28
|
+
>
|
29
|
+
{{ value_text }}
|
30
|
+
</text>
|
31
|
+
<text x="{{ label_width * 10 + value_width / 2 * 10 }}" y="140" transform="scale(.1)" fill="#fff">
|
32
|
+
{{ value_text }}
|
33
|
+
</text>
|
34
|
+
</g>
|
35
|
+
</svg>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>Available Releases</title>
|
7
|
+
<style>
|
8
|
+
table {
|
9
|
+
width: 100%;
|
10
|
+
border-collapse: collapse;
|
11
|
+
}
|
12
|
+
th, td {
|
13
|
+
padding: 8px;
|
14
|
+
text-align: left;
|
15
|
+
border-bottom: 1px solid #ddd;
|
16
|
+
}
|
17
|
+
th {
|
18
|
+
background-color: #f2f2f2;
|
19
|
+
}
|
20
|
+
tr:hover {
|
21
|
+
background-color: #f5f5f5;
|
22
|
+
}
|
23
|
+
</style>
|
24
|
+
</head>
|
25
|
+
<body>
|
26
|
+
<h1>Available Releases</h1>
|
27
|
+
<table>
|
28
|
+
<thead>
|
29
|
+
<tr>
|
30
|
+
<th>Version</th>
|
31
|
+
<th>Documentation</th>
|
32
|
+
<th>Coverage</th>
|
33
|
+
</tr>
|
34
|
+
</thead>
|
35
|
+
<tbody>
|
36
|
+
{% for version, attributes in versions.items() %}
|
37
|
+
<tr>
|
38
|
+
<td>{{ version }}</td>
|
39
|
+
<td>
|
40
|
+
{% if 'sphinx-html' in attributes %}
|
41
|
+
<a href="{{ version }}/sphinx-html/index.html">Docs</a>
|
42
|
+
{% else %}
|
43
|
+
N/A
|
44
|
+
{% endif %}
|
45
|
+
</td>
|
46
|
+
<td>
|
47
|
+
{% if 'coverage-pytest' in attributes %}
|
48
|
+
<a href="{{ version }}/coverage-pytest/index.html">Coverage</a>
|
49
|
+
{% else %}
|
50
|
+
N/A
|
51
|
+
{% endif %}
|
52
|
+
</td>
|
53
|
+
</tr>
|
54
|
+
{% endfor %}
|
55
|
+
</tbody>
|
56
|
+
</table>
|
57
|
+
</body>
|
58
|
+
</html>
|
emcdproj/exceptions.py
ADDED
@@ -0,0 +1,69 @@
|
|
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
|
+
''' Family of exceptions for package API. '''
|
22
|
+
|
23
|
+
|
24
|
+
from . import __
|
25
|
+
|
26
|
+
|
27
|
+
class Omniexception(
|
28
|
+
BaseException,
|
29
|
+
metaclass = __.ImmutableClass,
|
30
|
+
decorators = ( __.immutable, ),
|
31
|
+
):
|
32
|
+
''' Base for all exceptions raised by package API. '''
|
33
|
+
# TODO: Class and instance attribute concealment.
|
34
|
+
|
35
|
+
_attribute_visibility_includes_: __.cabc.Collection[ str ] = (
|
36
|
+
frozenset( ( '__cause__', '__context__', ) ) )
|
37
|
+
|
38
|
+
|
39
|
+
class Omnierror( Omniexception, Exception ):
|
40
|
+
''' Base for error exceptions raised by package API. '''
|
41
|
+
|
42
|
+
|
43
|
+
class DataAwol( Omnierror, AssertionError ):
|
44
|
+
''' Unexpected data absence. '''
|
45
|
+
|
46
|
+
def __init__( self, source: str, label: str ):
|
47
|
+
super( ).__init__(
|
48
|
+
f"Necessary data with label '{label}' is missing from {source}." )
|
49
|
+
|
50
|
+
|
51
|
+
class FileDataAwol( DataAwol ):
|
52
|
+
''' Unexpected data absence from file. '''
|
53
|
+
|
54
|
+
def __init__( self, file: str | __.Path, label: str ):
|
55
|
+
super( ).__init__( source = f"file '{file}'", label = label )
|
56
|
+
|
57
|
+
|
58
|
+
class FileAwol( Omnierror, AssertionError ):
|
59
|
+
''' Unexpected file absence. '''
|
60
|
+
|
61
|
+
def __init__( self, file: str | __.Path ):
|
62
|
+
super( ).__init__( f"Necessary file is missing at '{file}'." )
|
63
|
+
|
64
|
+
|
65
|
+
class FileEmpty( Omnierror, AssertionError ):
|
66
|
+
''' Unexpectedly empty file. '''
|
67
|
+
|
68
|
+
def __init__( self, file: str| __.Path ):
|
69
|
+
super( ).__init__( f"Unexpectedly empty file at '{file}'." )
|
emcdproj/filesystem.py
ADDED
@@ -0,0 +1,39 @@
|
|
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
|
+
''' Filesystem operations and utilities. '''
|
22
|
+
|
23
|
+
|
24
|
+
from __future__ import annotations
|
25
|
+
|
26
|
+
from . import __
|
27
|
+
|
28
|
+
|
29
|
+
@__.ctxl.contextmanager
|
30
|
+
def chdir( directory: __.Path ) -> __.cabc.Iterator[ __.Path ]:
|
31
|
+
''' Temporarily changes working directory.
|
32
|
+
|
33
|
+
Not thread-safe or async-safe.
|
34
|
+
'''
|
35
|
+
# TODO: Python 3.11: contextlib.chdir
|
36
|
+
original = __.os.getcwd( )
|
37
|
+
__.os.chdir( directory )
|
38
|
+
try: yield directory
|
39
|
+
finally: __.os.chdir( original )
|
emcdproj/interfaces.py
ADDED
@@ -0,0 +1,41 @@
|
|
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
|
+
''' Abstract bases and interfaces. '''
|
22
|
+
|
23
|
+
|
24
|
+
from __future__ import annotations
|
25
|
+
|
26
|
+
from . import __
|
27
|
+
|
28
|
+
|
29
|
+
class CliCommand( # pylint: disable=invalid-metaclass
|
30
|
+
__.typx.Protocol,
|
31
|
+
metaclass = __.ImmutableProtocolDataclass,
|
32
|
+
decorators = ( __.typx.runtime_checkable, ),
|
33
|
+
):
|
34
|
+
''' CLI command. '''
|
35
|
+
|
36
|
+
@__.abc.abstractmethod
|
37
|
+
async def __call__( self, auxdata: __.Globals ) -> None:
|
38
|
+
''' Executes command with global state. '''
|
39
|
+
raise NotImplementedError
|
40
|
+
|
41
|
+
# TODO: provide_configuration_edits
|
emcdproj/py.typed
ADDED
File without changes
|