socx-cli 0.13.5__tar.gz → 0.13.7__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.
- {socx_cli-0.13.5 → socx_cli-0.13.7}/PKG-INFO +2 -2
- {socx_cli-0.13.5 → socx_cli-0.13.7}/pyproject.toml +2 -2
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/config/_config.py +12 -57
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/config/_settings.py +149 -21
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/_paths.py +1 -1
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/enums.py +7 -3
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/patterns/singleton/singleton.py +1 -1
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/regression/progress.py +52 -53
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/regression/regression.py +191 -237
- socx_cli-0.13.7/socx/regression/test.py +583 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/static/settings/cli.yaml +6 -1
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/static/settings/console.yaml +6 -1
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/static/settings/logging.yaml +1 -1
- socx_cli-0.13.7/socx/static/settings/regression.yaml +113 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/static/settings/rich_click.yaml +7 -8
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/regression/_run.py +13 -16
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/regression/callbacks.py +1 -1
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/regression/tui.py +1 -1
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/app.py +41 -29
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/details.py +44 -24
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/dialog.py +81 -3
- socx_cli-0.13.7/socx_tui/regression/mixins/configurable.py +22 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/widget.py +93 -46
- socx_cli-0.13.7/socx_tui/static/tcss/regression/app.tcss +224 -0
- socx_cli-0.13.5/socx/regression/test.py +0 -351
- socx_cli-0.13.5/socx/static/settings/regression.yaml +0 -40
- socx_cli-0.13.5/socx_tui/static/tcss/regression/app.tcss +0 -107
- {socx_cli-0.13.5 → socx_cli-0.13.7}/.gitignore +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/LICENSE +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/README.md +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/__main__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/cli/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/cli/_cli.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/cli/_jinja.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/cli/callbacks.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/cli/cfg.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/cli/cli.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/cli/params.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/cli/types.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/config/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/config/converters.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/config/encoders.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/config/formatters.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/config/serializers.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/config/validators.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/encoder.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/funcs.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/metadata.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/paths.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/schema/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/schema/git/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/schema/git/git.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/schema/git/manifest.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/schema/plugin.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/schema/types.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/core/serializer.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/git/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/git/_git.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/git/_manifest.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/git/_ssh.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/io/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/io/console.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/io/decorators.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/io/log.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/patterns/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/patterns/mixins/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/patterns/mixins/proxy.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/patterns/mixins/uid.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/patterns/singleton/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/patterns/visitor/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/patterns/visitor/protocol.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/patterns/visitor/traversal.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/regression/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/regression/status.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/regression/validator.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/regression/visitor.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/static/settings/git.yaml +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/static/settings/plugins.yaml +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/static/settings/settings.yaml +1 -1
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/static/sql/socx.sql +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/utils/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx/utils/decorators.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/config/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/config/_config.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/config/edit.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/git/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/git/arguments.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/git/callbacks.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/git/cli.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/git/manifest.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/git/renderables.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/git/summary.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/git/utils.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/plugin/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/plugin/example.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/plugin/schema.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/regression/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/regression/cli.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/regression/run.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/version/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_plugins/version/__main__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/__main__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/bindings/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/bindings/vim/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/bindings/vim/mode.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/bindings/vim/vim.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/containers.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/mixins/__init__.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/mixins/composable.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/preview.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/table.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/regression/tree.py +0 -0
- {socx_cli-0.13.5 → socx_cli-0.13.7}/socx_tui/static/tcss/regression/preview.tcss +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: socx-cli
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.7
|
|
4
4
|
Summary: System on chip verification and tooling infrastructure.
|
|
5
5
|
Project-URL: Issues, https://github.com/sagikimhi/socx-cli/issues
|
|
6
6
|
Project-URL: Homepage, https://sagikimhi.dev/socx-cli
|
|
@@ -28,7 +28,7 @@ Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA
|
|
|
28
28
|
Classifier: Topic :: Software Development
|
|
29
29
|
Classifier: Topic :: Utilities
|
|
30
30
|
Requires-Python: >=3.12
|
|
31
|
-
Requires-Dist: anyio>=4.12.1
|
|
31
|
+
Requires-Dist: anyio[trio]>=4.12.1
|
|
32
32
|
Requires-Dist: click
|
|
33
33
|
Requires-Dist: copier~=9.11
|
|
34
34
|
Requires-Dist: declare
|
|
@@ -29,7 +29,7 @@ socx = 'socx.__main__:main'
|
|
|
29
29
|
[project]
|
|
30
30
|
name = "socx-cli"
|
|
31
31
|
readme = "README.md"
|
|
32
|
-
version = "0.13.
|
|
32
|
+
version = "0.13.7"
|
|
33
33
|
license = "Apache-2.0"
|
|
34
34
|
authors = [{ name = "Sagi Kimhi", email = "sagi.kim5@gmail.com" }]
|
|
35
35
|
maintainers = [{ name = "Sagi Kimhi", email = "sagi.kim5@gmail.com" }]
|
|
@@ -82,7 +82,7 @@ dependencies = [
|
|
|
82
82
|
"pydantic-extra-types>=2.11.0",
|
|
83
83
|
"pydantic-settings>=2.12.0",
|
|
84
84
|
"sqlmodel>=0.0.31",
|
|
85
|
-
"anyio>=4.12.1",
|
|
85
|
+
"anyio[trio]>=4.12.1",
|
|
86
86
|
]
|
|
87
87
|
|
|
88
88
|
[project.urls]
|
|
@@ -8,9 +8,7 @@ import contextvars as ctx
|
|
|
8
8
|
from textwrap import dedent
|
|
9
9
|
from typing import Any
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from collections import ChainMap
|
|
12
11
|
|
|
13
|
-
from dynaconf.utils import ensure_a_list
|
|
14
12
|
from werkzeug.local import LocalProxy
|
|
15
13
|
|
|
16
14
|
from socx.config import converters
|
|
@@ -109,70 +107,27 @@ def get_settings(
|
|
|
109
107
|
path: str | Path | None = None,
|
|
110
108
|
/,
|
|
111
109
|
user_overrides: bool = False,
|
|
112
|
-
|
|
110
|
+
project_overrides: bool = False,
|
|
113
111
|
extra_overrides: list[str | Path] | None = None,
|
|
114
112
|
**kwargs: Any,
|
|
115
113
|
) -> Settings:
|
|
116
114
|
"""Create a configured ``Settings`` instance, including overrides."""
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if isinstance(path, str):
|
|
122
|
-
path = Path(path)
|
|
123
|
-
|
|
124
|
-
includes = []
|
|
125
|
-
settings_file = ensure_a_list(path or paths.APP_CONFIG_FILE)
|
|
126
|
-
|
|
127
|
-
if user_overrides:
|
|
128
|
-
includes.extend(get_user_config_files())
|
|
129
|
-
|
|
130
|
-
if local_overrides:
|
|
131
|
-
includes.extend(get_local_config_files())
|
|
132
|
-
|
|
133
|
-
if extra_overrides:
|
|
134
|
-
includes.extend(
|
|
135
|
-
Path(p) if isinstance(p, str) else p for p in extra_overrides
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
root = includes[-1].parent if includes else Path.cwd()
|
|
139
|
-
settings_kwargs = dict(
|
|
140
|
-
preload=settings_file, root_path=root, settings_file=includes
|
|
141
|
-
)
|
|
142
|
-
kwargs = dict(
|
|
143
|
-
ChainMap(
|
|
144
|
-
kwargs,
|
|
145
|
-
settings_kwargs,
|
|
146
|
-
ModuleSerializer.serialize(paths),
|
|
147
|
-
ModuleSerializer.serialize(metadata),
|
|
148
|
-
),
|
|
115
|
+
return Settings(
|
|
116
|
+
user_overrides=user_overrides,
|
|
117
|
+
project_overrides=project_overrides,
|
|
118
|
+
**kwargs,
|
|
149
119
|
)
|
|
150
|
-
rv = Settings(**kwargs)
|
|
151
|
-
return rv
|
|
152
120
|
|
|
153
121
|
|
|
154
122
|
converters.init()
|
|
155
|
-
|
|
156
123
|
_tokens = []
|
|
157
|
-
|
|
158
124
|
_settings_cv: ctx.ContextVar[Settings] = ctx.ContextVar("settings")
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
_user_settings = _default_settings
|
|
166
|
-
|
|
167
|
-
try:
|
|
168
|
-
_local_settings: Settings = get_settings(
|
|
169
|
-
user_overrides=True, local_overrides=True
|
|
170
|
-
)
|
|
171
|
-
except Exception:
|
|
172
|
-
_local_settings = _default_settings
|
|
173
|
-
_local_settings.update(_user_settings)
|
|
174
|
-
|
|
175
|
-
settings: SettingsProxy = LocalProxy( # type: ignore[assignment]
|
|
125
|
+
_default_settings: Settings = Settings(
|
|
126
|
+
project_overrides=False, user_overrides=False
|
|
127
|
+
)
|
|
128
|
+
_user_settings: Settings = Settings(project_overrides=False)
|
|
129
|
+
_local_settings: Settings = Settings()
|
|
130
|
+
settings: SettingsProxy = LocalProxy(
|
|
176
131
|
_settings_cv,
|
|
177
132
|
unbound_message=dedent("""
|
|
178
133
|
Working outside of application context.
|
|
@@ -180,7 +135,7 @@ settings: SettingsProxy = LocalProxy( # type: ignore[assignment]
|
|
|
180
135
|
Attempted to use functionality that expected a current application to
|
|
181
136
|
be set. To solve this, set up an app context.
|
|
182
137
|
"""),
|
|
183
|
-
)
|
|
138
|
+
) # ty:ignore[invalid-assignment]
|
|
184
139
|
|
|
185
140
|
if "--no-configure" in sys.argv or "-NC" in sys.argv:
|
|
186
141
|
_tokens.append(_settings_cv.set(_default_settings))
|
|
@@ -9,14 +9,16 @@ from collections import ChainMap
|
|
|
9
9
|
from collections.abc import Callable
|
|
10
10
|
|
|
11
11
|
from dynaconf import LazySettings, get_history
|
|
12
|
+
from dynaconf.loaders import env_loader
|
|
12
13
|
from dynaconf.base import SourceMetadata, ensure_a_list
|
|
13
14
|
from dynaconf.utils.boxing import DynaBox
|
|
14
15
|
from dynaconf.utils.inspect import get_debug_info, _get_data_by_key
|
|
15
16
|
from dynaconf.utils.parse_conf import unparse_conf_data
|
|
16
17
|
from pydantic_core import to_jsonable_python
|
|
17
18
|
|
|
18
|
-
from socx.
|
|
19
|
-
|
|
19
|
+
from socx.core import paths, metadata
|
|
20
|
+
from socx.core.enums import SettingsFormat
|
|
21
|
+
from socx.config.serializers import SettingsSerializer, ModuleSerializer
|
|
20
22
|
|
|
21
23
|
logger = logging.getLogger(__name__)
|
|
22
24
|
|
|
@@ -29,8 +31,10 @@ VT = TypeVar("VT")
|
|
|
29
31
|
SETTINGS_DEFAULTS: dict[str, Any] = dict(
|
|
30
32
|
env="default",
|
|
31
33
|
envvar="SOCX_SETTINGS_PATH",
|
|
34
|
+
preload=[paths.APP_CONFIG_FILE],
|
|
32
35
|
encoding="utf-8",
|
|
33
36
|
auto_cast=True,
|
|
37
|
+
root_path=paths.PROJECT_ROOT_DIR,
|
|
34
38
|
load_dotenv=True,
|
|
35
39
|
environments=False,
|
|
36
40
|
dotted_lookup=True,
|
|
@@ -46,15 +50,51 @@ SETTINGS_DEFAULTS: dict[str, Any] = dict(
|
|
|
46
50
|
|
|
47
51
|
|
|
48
52
|
class Settings(LazySettings):
|
|
49
|
-
"""
|
|
53
|
+
"""Application settings class."""
|
|
50
54
|
|
|
51
55
|
def __init__(self, wrapped=None, **kwargs: Any) -> None:
|
|
52
|
-
|
|
56
|
+
default_kwargs = SETTINGS_DEFAULTS
|
|
57
|
+
if kwargs.get("project_overrides", True):
|
|
58
|
+
project_files = self.get_project_config_files()
|
|
59
|
+
if project_files:
|
|
60
|
+
default_kwargs["settings_file"] = [project_files[-1]]
|
|
61
|
+
kwargs = dict(
|
|
62
|
+
ChainMap(
|
|
63
|
+
kwargs,
|
|
64
|
+
default_kwargs,
|
|
65
|
+
ModuleSerializer.serialize(paths),
|
|
66
|
+
ModuleSerializer.serialize(metadata),
|
|
67
|
+
)
|
|
68
|
+
)
|
|
53
69
|
LazySettings.__init__(self, wrapped=wrapped, **kwargs)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
70
|
+
|
|
71
|
+
def _setup(self) -> None:
|
|
72
|
+
super()._setup()
|
|
73
|
+
self._load_overrides()
|
|
74
|
+
|
|
75
|
+
def _load_overrides(self) -> None:
|
|
76
|
+
user_overrides = self.get("user_overrides", True)
|
|
77
|
+
project_overrides = self.get("project_overrides", True)
|
|
78
|
+
includes = self.get_settings_overrides(
|
|
79
|
+
user_overrides=user_overrides, project_overrides=project_overrides
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if includes:
|
|
83
|
+
for file in includes:
|
|
84
|
+
logger.debug("loading settings overrides from: '%s'")
|
|
85
|
+
try:
|
|
86
|
+
self.load_file(file)
|
|
87
|
+
except Exception:
|
|
88
|
+
logger.exception(
|
|
89
|
+
"Failed to load settings file: '%s'" % str(file)
|
|
90
|
+
)
|
|
91
|
+
continue
|
|
92
|
+
else:
|
|
93
|
+
logger.debug("loaded settings overrides from: '%s'")
|
|
94
|
+
|
|
95
|
+
last_loader = self.loaders and self.loaders[-1]
|
|
96
|
+
if last_loader is env_loader:
|
|
97
|
+
env_loader.load(self._store)
|
|
58
98
|
|
|
59
99
|
def __contains__(self, key):
|
|
60
100
|
return self.exists(key) or (
|
|
@@ -77,19 +117,6 @@ class Settings(LazySettings):
|
|
|
77
117
|
"""Get the root path of the current settings instance."""
|
|
78
118
|
return Path(self._root_path)
|
|
79
119
|
|
|
80
|
-
@root.setter
|
|
81
|
-
def root(self, value: str | Path) -> None:
|
|
82
|
-
if isinstance(value, str):
|
|
83
|
-
value = Path(value)
|
|
84
|
-
|
|
85
|
-
if value.is_file() and value.exists():
|
|
86
|
-
self.set(
|
|
87
|
-
"SETTINGS_FILE_FOR_DYNACONF",
|
|
88
|
-
value,
|
|
89
|
-
loader_identifier="init_settings_module",
|
|
90
|
-
)
|
|
91
|
-
self.reload()
|
|
92
|
-
|
|
93
120
|
@property
|
|
94
121
|
def history(self) -> tuple[dict[str, Any], ...]:
|
|
95
122
|
"""Get the history of this instance.
|
|
@@ -274,6 +301,107 @@ class Settings(LazySettings):
|
|
|
274
301
|
rv = cls._transform(rv, fn, skip_values=skip_values)
|
|
275
302
|
return rv
|
|
276
303
|
|
|
304
|
+
@classmethod
|
|
305
|
+
def get_settings_overrides(
|
|
306
|
+
cls, user_overrides: bool = True, project_overrides: bool = True
|
|
307
|
+
) -> list[Path]:
|
|
308
|
+
"""Get a list of project settings file overrides."""
|
|
309
|
+
overrides = []
|
|
310
|
+
if user_overrides:
|
|
311
|
+
overrides.extend(cls.get_user_config_files())
|
|
312
|
+
if project_overrides:
|
|
313
|
+
overrides.extend(cls.get_project_config_files())
|
|
314
|
+
return overrides
|
|
315
|
+
|
|
316
|
+
@classmethod
|
|
317
|
+
def get_project_config_files(cls) -> list[Path]:
|
|
318
|
+
"""Get a list of local settings file paths found in parent folders.
|
|
319
|
+
|
|
320
|
+
Description:
|
|
321
|
+
------------
|
|
322
|
+
After initialization, `socx` searches parent directories for any file
|
|
323
|
+
named '.socx.<ext>' where <ext> is any file extension supported by the
|
|
324
|
+
`socx` configuration system.
|
|
325
|
+
|
|
326
|
+
Local configuration overrides are any files named '.socx.<ext>' which
|
|
327
|
+
found in any of the parent directories of the current working
|
|
328
|
+
directory, where <ext> may be any one of: '.yaml', '.yml', '.json', or
|
|
329
|
+
'.toml'.
|
|
330
|
+
|
|
331
|
+
For reference, it works similar to git:
|
|
332
|
+
|
|
333
|
+
1. first, default app configurations are loaded to initialize to
|
|
334
|
+
app's core functionality.
|
|
335
|
+
|
|
336
|
+
2. second, global user configurations are loaded from the user's
|
|
337
|
+
config directory, determined according to the 'XDG Base Directory
|
|
338
|
+
Specification'
|
|
339
|
+
(https://specifications.freedesktop.org/basedir-spec).
|
|
340
|
+
|
|
341
|
+
3. last, a search for local configuration files is done, matching
|
|
342
|
+
(and loading) any configuration files named '.socx.yaml' found in
|
|
343
|
+
any of the parent directories starting the search at the current
|
|
344
|
+
working
|
|
345
|
+
directory.
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
--------
|
|
349
|
+
An ordered list of `Path` objects pointing at configuration files to
|
|
350
|
+
be loaded in that exact order to preserve the described overrides
|
|
351
|
+
order.
|
|
352
|
+
|
|
353
|
+
"""
|
|
354
|
+
from socx.core.paths import LOCAL_CONFIG_FILE, LOCAL_CONFIG_FILENAME
|
|
355
|
+
|
|
356
|
+
rv = []
|
|
357
|
+
for parent in LOCAL_CONFIG_FILE.parents:
|
|
358
|
+
cfg_file = parent / LOCAL_CONFIG_FILENAME
|
|
359
|
+
for member in SettingsFormat:
|
|
360
|
+
rv.extend(
|
|
361
|
+
cfg_file.with_suffix(ext)
|
|
362
|
+
for ext in member.extensions
|
|
363
|
+
if cfg_file.with_suffix(ext).is_file()
|
|
364
|
+
)
|
|
365
|
+
return rv
|
|
366
|
+
|
|
367
|
+
@classmethod
|
|
368
|
+
def get_user_config_files(cls) -> list[Path]:
|
|
369
|
+
"""Get a list of all local config files found in parent folders.
|
|
370
|
+
|
|
371
|
+
Description:
|
|
372
|
+
------------
|
|
373
|
+
User configuration files are any configuration files who's format is
|
|
374
|
+
supported and are located under the XDG_CONFIG_HOME directory.
|
|
375
|
+
|
|
376
|
+
Local configuration overrides are any files named '.socx.yaml' which
|
|
377
|
+
found in any of the parent directories of the current working
|
|
378
|
+
directory.
|
|
379
|
+
|
|
380
|
+
For reference, it works similar to git:
|
|
381
|
+
|
|
382
|
+
1. first, default app configurations are loaded to initialize to
|
|
383
|
+
app's core functionality.
|
|
384
|
+
|
|
385
|
+
2. second, global user configurations are loaded from the user's
|
|
386
|
+
config directory, determined according to the 'XDG Base Directory
|
|
387
|
+
Specification'
|
|
388
|
+
(https://specifications.freedesktop.org/basedir-spec).
|
|
389
|
+
|
|
390
|
+
3. last, a search for local configuration files is done, matching
|
|
391
|
+
(and loading) any configuration files named '.socx.yaml' found in
|
|
392
|
+
any of the parent directories starting the search at the current
|
|
393
|
+
working directory.
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
--------
|
|
397
|
+
An ordered list of `Path` objects pointing at configuration files to be
|
|
398
|
+
loaded in that exact order to preserve the described overrides order.
|
|
399
|
+
|
|
400
|
+
"""
|
|
401
|
+
from socx.core.paths import USER_CONFIG_FILE
|
|
402
|
+
|
|
403
|
+
return [USER_CONFIG_FILE] if USER_CONFIG_FILE.exists() else []
|
|
404
|
+
|
|
277
405
|
@classmethod
|
|
278
406
|
def _transform(
|
|
279
407
|
cls,
|
|
@@ -18,15 +18,19 @@ class AutoNumber(int, enum.ReprEnum):
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class SettingsFormat(AutoNumber):
|
|
21
|
-
Ini = ".ini"
|
|
22
21
|
Json = ".json"
|
|
23
22
|
Yaml = ".yaml", ".yml"
|
|
24
23
|
Toml = ".toml"
|
|
24
|
+
Ini = ".ini"
|
|
25
25
|
Python = ".python"
|
|
26
26
|
|
|
27
27
|
def __init__(self, extension: str, *extensions: str) -> None:
|
|
28
|
-
self.
|
|
29
|
-
|
|
28
|
+
self.extensions = {extension, *extensions}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
@cache
|
|
32
|
+
def all_extensions(cls) -> set[str]:
|
|
33
|
+
return {extension for member in cls for extension in member.extensions}
|
|
30
34
|
|
|
31
35
|
@classmethod
|
|
32
36
|
@cache
|
|
@@ -18,7 +18,7 @@ class _SingletonMeta(type):
|
|
|
18
18
|
return cls._instances[cls]
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
class Singleton(_SingletonMeta("
|
|
21
|
+
class Singleton(_SingletonMeta("_SingletonMeta", (object,), {})):
|
|
22
22
|
"""Mixin class for creating singleton classes.
|
|
23
23
|
|
|
24
24
|
Extending this class enforces the singleton pattern on the subclass.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import anyio
|
|
4
3
|
import logging
|
|
5
4
|
from typing import Any
|
|
6
|
-
from collections import ChainMap
|
|
7
5
|
|
|
6
|
+
import anyio
|
|
7
|
+
from anyio.abc import TaskStatus
|
|
8
8
|
from rich.progress import (
|
|
9
9
|
Progress as BaseProgress,
|
|
10
10
|
ProgressColumn,
|
|
@@ -27,7 +27,6 @@ logger = logging.getLogger(__name__)
|
|
|
27
27
|
|
|
28
28
|
class PipelineProgress(BaseProgress):
|
|
29
29
|
def __init__(self, **kwargs: Any) -> None:
|
|
30
|
-
kwargs = dict(ChainMap(kwargs, dict(speed_estimate_period=10)))
|
|
31
30
|
super().__init__(*self.get_default_columns(), **kwargs)
|
|
32
31
|
|
|
33
32
|
@classmethod
|
|
@@ -60,23 +59,10 @@ class RegressionProgress:
|
|
|
60
59
|
self,
|
|
61
60
|
include: set[str] | None = None,
|
|
62
61
|
exclude: set[str] | None = None,
|
|
62
|
+
limiter: anyio.CapacityLimiter | None = None,
|
|
63
63
|
) -> None:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if include is None and exclude is None:
|
|
67
|
-
async with anyio.create_task_group() as tg:
|
|
68
|
-
for obj in self.regression.tests:
|
|
69
|
-
tg.start_soon(
|
|
70
|
-
self.track_regression,
|
|
71
|
-
obj,
|
|
72
|
-
name=f"track_{obj.name}_progress",
|
|
73
|
-
)
|
|
74
|
-
tg.start_soon(
|
|
75
|
-
self.regression.start,
|
|
76
|
-
name=f"{self.regression.name}",
|
|
77
|
-
)
|
|
78
|
-
return
|
|
79
|
-
|
|
64
|
+
self.progress.start()
|
|
65
|
+
try:
|
|
80
66
|
async with anyio.create_task_group() as tg:
|
|
81
67
|
for obj in self.regression.tests:
|
|
82
68
|
if exclude is not None and obj.name in exclude:
|
|
@@ -86,54 +72,62 @@ class RegressionProgress:
|
|
|
86
72
|
continue
|
|
87
73
|
|
|
88
74
|
if isinstance(obj, Regression) and not obj.started:
|
|
89
|
-
tg.start_soon(obj.start, name=obj.name)
|
|
90
75
|
tg.start_soon(
|
|
91
76
|
self.track_regression,
|
|
92
77
|
obj,
|
|
93
78
|
name=f"track_{obj.name}_progress",
|
|
94
79
|
)
|
|
80
|
+
finally:
|
|
81
|
+
self.progress.stop()
|
|
95
82
|
|
|
96
|
-
async def track_regression(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
83
|
+
async def track_regression(
|
|
84
|
+
self,
|
|
85
|
+
regression: Regression,
|
|
86
|
+
limiter: anyio.CapacityLimiter | None = None,
|
|
87
|
+
task_status: TaskStatus = anyio.TASK_STATUS_IGNORED,
|
|
88
|
+
) -> None:
|
|
100
89
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
90
|
+
async with anyio.create_task_group() as tg:
|
|
91
|
+
if regression.id not in self.tasks:
|
|
92
|
+
self.tasks[regression.id] = self.progress.add_task(
|
|
93
|
+
total=len(regression),
|
|
94
|
+
description=(
|
|
95
|
+
f"[gray39]{self._get_task_tag(regression)}: "
|
|
96
|
+
f"{regression.status.name}"
|
|
97
|
+
),
|
|
98
|
+
)
|
|
99
|
+
tg.start_soon(self._track_regression, regression)
|
|
100
|
+
await tg.start(regression.start, limiter)
|
|
101
|
+
task_status.started()
|
|
109
102
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
self.update_regression(regression, len(regression))
|
|
113
|
-
break
|
|
103
|
+
async def _track_regression(self, regression: Regression) -> None:
|
|
104
|
+
task = self.progress.tasks[self.tasks[regression.id]]
|
|
114
105
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
status = regression.status
|
|
118
|
-
finished = self._count_statuses(
|
|
106
|
+
while True:
|
|
107
|
+
finished = await self._count_statuses(
|
|
119
108
|
regression,
|
|
120
109
|
TestStatus.Finished,
|
|
121
110
|
TestStatus.Terminated,
|
|
122
111
|
)
|
|
123
112
|
|
|
124
|
-
if
|
|
125
|
-
self.update_regression(regression, finished)
|
|
113
|
+
if finished != task.completed:
|
|
114
|
+
await self.update_regression(regression, finished)
|
|
115
|
+
|
|
116
|
+
if finished == len(regression):
|
|
117
|
+
break
|
|
126
118
|
|
|
127
|
-
await anyio.sleep(0.
|
|
119
|
+
await anyio.sleep(0.05)
|
|
128
120
|
|
|
129
|
-
def advance_regression(
|
|
121
|
+
async def advance_regression(
|
|
122
|
+
self, regression: Regression, n: int = 1
|
|
123
|
+
) -> None:
|
|
130
124
|
progress = self.progress
|
|
131
125
|
tid = self.tasks.get(regression.id)
|
|
132
126
|
if progress is not None and tid is not None:
|
|
133
127
|
task = progress.tasks[tid]
|
|
134
|
-
self.update_regression(regression, task.completed + n)
|
|
128
|
+
await self.update_regression(regression, task.completed + n)
|
|
135
129
|
|
|
136
|
-
def update_regression(self, regression: Regression, n: int) -> None:
|
|
130
|
+
async def update_regression(self, regression: Regression, n: int) -> None:
|
|
137
131
|
progress = self.progress
|
|
138
132
|
tid = self.tasks.get(regression.id)
|
|
139
133
|
if progress is not None and tid is not None:
|
|
@@ -144,32 +138,37 @@ class RegressionProgress:
|
|
|
144
138
|
or regression.is_pending()
|
|
145
139
|
or regression.is_suspended()
|
|
146
140
|
):
|
|
147
|
-
|
|
141
|
+
description = (
|
|
148
142
|
f"[gray39]{self._get_task_tag(regression)}: "
|
|
149
143
|
f"{regression.status.name}"
|
|
150
144
|
)
|
|
151
145
|
elif regression.is_running():
|
|
152
|
-
|
|
146
|
+
description = (
|
|
153
147
|
f"[yellow]{self._get_task_tag(regression)}: "
|
|
154
148
|
f"{regression.status.name}"
|
|
155
149
|
)
|
|
156
150
|
elif regression.finished:
|
|
157
|
-
|
|
151
|
+
description = (
|
|
158
152
|
f"[green]{self._get_task_tag(regression)}: "
|
|
159
153
|
f"{regression.status.name}"
|
|
160
154
|
)
|
|
161
155
|
elif regression.terminated:
|
|
162
|
-
|
|
156
|
+
description = (
|
|
163
157
|
f"[red]{self._get_task_tag(regression)}: "
|
|
164
158
|
f"{regression.status.name}"
|
|
165
159
|
)
|
|
166
160
|
|
|
167
|
-
|
|
161
|
+
completed = min(n, task.total)
|
|
162
|
+
progress.update(
|
|
163
|
+
task.id,
|
|
164
|
+
completed=completed,
|
|
165
|
+
description=description,
|
|
166
|
+
)
|
|
168
167
|
|
|
169
|
-
def _count_statuses(
|
|
168
|
+
async def _count_statuses(
|
|
170
169
|
self, regression: Regression, *statuses: TestStatus
|
|
171
170
|
) -> int:
|
|
172
|
-
with self.regression.
|
|
171
|
+
async with self.regression.mutex:
|
|
173
172
|
return sum(
|
|
174
173
|
1 for test in regression.tests if test.status in statuses
|
|
175
174
|
)
|