socx-cli 0.11.2__tar.gz → 0.11.4__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.11.2 → socx_cli-0.11.4}/PKG-INFO +1 -1
- {socx_cli-0.11.2 → socx_cli-0.11.4}/pyproject.toml +2 -1
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/converters.py +22 -13
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/core/encoder.py +4 -2
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/core/serializer.py +4 -2
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/patterns/visitor/protocol.py +8 -5
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/patterns/visitor/traversal.py +7 -3
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/static/settings/regression.yaml +1 -1
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/config/_config.py +1 -6
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/rgr/_rgr.py +23 -32
- socx_cli-0.11.4/socx_plugins/rgr/callbacks.py +28 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/rgr/rgr.py +3 -4
- socx_cli-0.11.2/socx_plugins/rgr/callbacks.py +0 -42
- {socx_cli-0.11.2 → socx_cli-0.11.4}/.gitignore +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/LICENSE +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/README.md +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/__main__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/cli/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/cli/_cli.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/cli/_jinja.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/cli/callbacks.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/cli/cfg.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/cli/cli.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/cli/params.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/_config.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/_settings.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/encoders.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/formatters.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/schema/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/schema/git/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/schema/git/git.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/schema/git/manifest.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/schema/plugin.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/schema/types.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/serializers.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/config/validators.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/core/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/core/_paths.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/core/enums.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/core/funcs.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/core/metadata.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/core/paths.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/core/types.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/git/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/git/_git.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/git/_manifest.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/git/_ssh.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/io/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/io/console.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/io/decorators.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/io/log.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/patterns/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/patterns/mixins/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/patterns/mixins/proxy.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/patterns/mixins/uid.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/patterns/singleton/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/patterns/singleton/singleton.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/patterns/visitor/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/regression/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/regression/regression.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/regression/status.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/regression/test.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/regression/validator.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/static/settings/cli.yaml +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/static/settings/console.yaml +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/static/settings/git.yaml +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/static/settings/plugins.yaml +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/static/settings/rich_click.yaml +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/static/settings/settings.yaml +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/static/sql/socx.sql +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/utils/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx/utils/decorators.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/config/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/config/edit.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/git/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/git/arguments.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/git/callbacks.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/git/cli.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/git/manifest.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/git/renderables.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/git/summary.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/git/utils.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/plugin/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/plugin/example.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/plugin/schema.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/rgr/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/version/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_plugins/version/__main__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/__main__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/app.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/bindings/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/bindings/vim/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/bindings/vim/mode.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/bindings/vim/vim.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/containers.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/mixins/__init__.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/mixins/composable.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/preview.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/screens.py +0 -0
- {socx_cli-0.11.2 → socx_cli-0.11.4}/socx_tui/regression/table.py +0 -0
|
@@ -29,7 +29,7 @@ socx = 'socx.__main__:main'
|
|
|
29
29
|
[project]
|
|
30
30
|
name = "socx-cli"
|
|
31
31
|
readme = "README.md"
|
|
32
|
-
version = "0.11.
|
|
32
|
+
version = "0.11.4"
|
|
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" }]
|
|
@@ -107,6 +107,7 @@ dev = [
|
|
|
107
107
|
"hatch-uvenv",
|
|
108
108
|
"objexplore>=1.6.3",
|
|
109
109
|
"ipython>=8.38.0",
|
|
110
|
+
"ty>=0.0.14",
|
|
110
111
|
]
|
|
111
112
|
docs = [
|
|
112
113
|
"mike",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import os
|
|
5
6
|
import sys
|
|
6
7
|
import abc
|
|
7
8
|
import runpy
|
|
@@ -17,6 +18,7 @@ from typing import (
|
|
|
17
18
|
override,
|
|
18
19
|
TypeVar,
|
|
19
20
|
ClassVar,
|
|
21
|
+
Generic,
|
|
20
22
|
)
|
|
21
23
|
from pathlib import Path
|
|
22
24
|
from importlib import import_module
|
|
@@ -52,8 +54,11 @@ _validate = validate_call(config=ConfigDict(arbitrary_types_allowed=True))
|
|
|
52
54
|
|
|
53
55
|
logger = logging.getLogger(__name__)
|
|
54
56
|
|
|
57
|
+
TI = TypeVar("TI")
|
|
58
|
+
TO = TypeVar("TO")
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
|
|
61
|
+
class Converter(abc.ABC, Generic[TI, TO]):
|
|
57
62
|
"""Base protocol for Dynaconf converters used by SoCX."""
|
|
58
63
|
|
|
59
64
|
@abc.abstractmethod
|
|
@@ -73,8 +78,6 @@ class Converter[TI, TO](abc.ABC):
|
|
|
73
78
|
self, msg: str, *args: Any, exc: Exception | None = None, **kwargs: Any
|
|
74
79
|
) -> None:
|
|
75
80
|
"""Log a recoverable converter error message."""
|
|
76
|
-
if exc is not None:
|
|
77
|
-
exc.add_note(msg)
|
|
78
81
|
self.logger.exception(msg, *args, **kwargs)
|
|
79
82
|
|
|
80
83
|
def convert(self, value: TI, *args: Any, **kwargs: Any) -> TO:
|
|
@@ -417,7 +420,7 @@ class CommandConverter(
|
|
|
417
420
|
return cli
|
|
418
421
|
|
|
419
422
|
@singledispatchmethod
|
|
420
|
-
def _run_shell_script(self, value, *args, **kwargs)
|
|
423
|
+
def _run_shell_script(self, value, *args, **kwargs): ...
|
|
421
424
|
|
|
422
425
|
@_run_shell_script.register
|
|
423
426
|
def _(
|
|
@@ -450,12 +453,15 @@ class CommandConverter(
|
|
|
450
453
|
env = env or {}
|
|
451
454
|
cwd = local.path(cwd)
|
|
452
455
|
|
|
453
|
-
|
|
456
|
+
if not fresh_env:
|
|
457
|
+
env = dict(os.environ, **env)
|
|
458
|
+
|
|
459
|
+
with local.env(env), local.cwd(cwd):
|
|
454
460
|
if fresh_env:
|
|
455
461
|
local.env.clear()
|
|
456
462
|
|
|
457
463
|
local.env.update(env)
|
|
458
|
-
cmd = value.with_cwd(cwd)
|
|
464
|
+
cmd = value.with_cwd(cwd).with_env(**env)
|
|
459
465
|
cmd_str = str(cmd)
|
|
460
466
|
cwd_str = str(cwd)
|
|
461
467
|
env_str = "\n".join(f"\t{k}={v}" for k, v in local.env.items())
|
|
@@ -518,6 +524,7 @@ class CommandConverter(
|
|
|
518
524
|
cwd = cwd or Path.cwd()
|
|
519
525
|
ctx = click.get_current_context(silent=True)
|
|
520
526
|
argv = sys.argv.copy()
|
|
527
|
+
environ = os.environ.copy()
|
|
521
528
|
|
|
522
529
|
path, _, symbol = value.rpartition(":")
|
|
523
530
|
|
|
@@ -550,11 +557,11 @@ class CommandConverter(
|
|
|
550
557
|
if self.is_script_path(path) or self.is_package_path(path):
|
|
551
558
|
path = str(Path(path).resolve())
|
|
552
559
|
|
|
553
|
-
with local.cwd(cwd)
|
|
560
|
+
with local.cwd(cwd):
|
|
554
561
|
if fresh_env:
|
|
555
|
-
|
|
562
|
+
os.environ.clear()
|
|
556
563
|
|
|
557
|
-
|
|
564
|
+
os.environ.update(env)
|
|
558
565
|
|
|
559
566
|
try:
|
|
560
567
|
if self.is_module_path(path) and symbol:
|
|
@@ -591,6 +598,8 @@ class CommandConverter(
|
|
|
591
598
|
self.log_exception(err)
|
|
592
599
|
finally:
|
|
593
600
|
sys.argv = argv
|
|
601
|
+
os.environ.clear()
|
|
602
|
+
os.environ.update(environ)
|
|
594
603
|
|
|
595
604
|
return rv
|
|
596
605
|
|
|
@@ -766,9 +775,9 @@ class ShConverter(
|
|
|
766
775
|
def __call__( # pyright: ignore[reportIncompatibleMethodOverride]
|
|
767
776
|
self,
|
|
768
777
|
value,
|
|
769
|
-
*args
|
|
770
|
-
**kwargs
|
|
771
|
-
)
|
|
778
|
+
*args,
|
|
779
|
+
**kwargs,
|
|
780
|
+
): ...
|
|
772
781
|
|
|
773
782
|
@__call__.register
|
|
774
783
|
def _(self, value: Lazy) -> Lazy:
|
|
@@ -821,7 +830,7 @@ class MarkdownConverter(Converter[str | Lazy | Markdown | None, str | Lazy]):
|
|
|
821
830
|
return value
|
|
822
831
|
|
|
823
832
|
|
|
824
|
-
class GenericConverter
|
|
833
|
+
class GenericConverter(Converter[TI, TO]):
|
|
825
834
|
"""Adapter turning plain callables into ``Converter`` instances."""
|
|
826
835
|
|
|
827
836
|
def __init__(self, name: str, cvt: Callable[..., TO]) -> None:
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, TypeVar, Generic
|
|
5
5
|
|
|
6
|
+
T = TypeVar("T")
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
class Encoder(ABC, Generic[T]):
|
|
8
10
|
"""Generic protocol for converting values into configuration payloads."""
|
|
9
11
|
|
|
10
12
|
@classmethod
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, TypeVar, Generic
|
|
5
5
|
|
|
6
|
+
T = TypeVar("T")
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
class Serializer(ABC, Generic[T]):
|
|
8
10
|
"""Generic protocol for converting values into configuration payloads."""
|
|
9
11
|
|
|
10
12
|
@classmethod
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Protocol
|
|
5
|
+
from typing import Protocol, TypeVar, Generic
|
|
6
6
|
from collections.abc import Iterable
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
NODE = TypeVar("NODE")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Visitor(Protocol, Generic[NODE]):
|
|
10
13
|
"""Protocol describing objects that can visit nodes."""
|
|
11
14
|
|
|
12
15
|
__slots__ = ()
|
|
@@ -16,7 +19,7 @@ class Visitor[NODE](Protocol):
|
|
|
16
19
|
...
|
|
17
20
|
|
|
18
21
|
|
|
19
|
-
class Node[NODE]
|
|
22
|
+
class Node(Protocol, Generic[NODE]):
|
|
20
23
|
"""Protocol for nodes that accept visitors."""
|
|
21
24
|
|
|
22
25
|
__slots__ = ()
|
|
@@ -26,7 +29,7 @@ class Node[NODE](Protocol):
|
|
|
26
29
|
...
|
|
27
30
|
|
|
28
31
|
|
|
29
|
-
class Structure[NODE]
|
|
32
|
+
class Structure(Protocol, Generic[NODE]):
|
|
30
33
|
"""Protocol for structures exposing child relationships."""
|
|
31
34
|
|
|
32
35
|
__slots__ = ()
|
|
@@ -37,7 +40,7 @@ class Structure[NODE](Protocol):
|
|
|
37
40
|
...
|
|
38
41
|
|
|
39
42
|
|
|
40
|
-
class Traversal[NODE]
|
|
43
|
+
class Traversal(Protocol, Generic[NODE]):
|
|
41
44
|
"""Adapter interface that controls how nodes accept visitors."""
|
|
42
45
|
|
|
43
46
|
__slots__ = ()
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
"""Traversal strategies compatible with the visitor protocol."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
|
+
from typing import TypeVar
|
|
4
5
|
|
|
5
6
|
from socx.patterns.visitor.protocol import Visitor
|
|
6
7
|
from socx.patterns.visitor.protocol import Structure
|
|
7
8
|
from socx.patterns.visitor.protocol import Traversal
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
NODE = TypeVar("NODE")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TopDownTraversal(Traversal[NODE]):
|
|
11
15
|
"""Pre-order traversal that visits parents before descendants."""
|
|
12
16
|
|
|
13
17
|
@classmethod
|
|
@@ -19,7 +23,7 @@ class TopDownTraversal[NODE](Traversal[NODE]):
|
|
|
19
23
|
cls.accept(c, v, p)
|
|
20
24
|
|
|
21
25
|
|
|
22
|
-
class BottomUpTraversal
|
|
26
|
+
class BottomUpTraversal(Traversal[NODE]):
|
|
23
27
|
"""Post-order traversal that visits descendants before parents."""
|
|
24
28
|
|
|
25
29
|
@classmethod
|
|
@@ -31,7 +35,7 @@ class BottomUpTraversal[NODE](Traversal[NODE]):
|
|
|
31
35
|
v.visit(n)
|
|
32
36
|
|
|
33
37
|
|
|
34
|
-
class ByLevelTraversal
|
|
38
|
+
class ByLevelTraversal(Traversal[NODE]):
|
|
35
39
|
"""Breadth-first traversal that visits nodes one level at a time."""
|
|
36
40
|
|
|
37
41
|
@classmethod
|
|
@@ -20,12 +20,7 @@ def edit_config():
|
|
|
20
20
|
Path(file).stem: Path(settings.app_settings_dir / file)
|
|
21
21
|
for file in settings.dynaconf_include
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
for name in files:
|
|
25
|
-
try:
|
|
26
|
-
files[name] = files[name].resolve()
|
|
27
|
-
except OSError:
|
|
28
|
-
del files[name]
|
|
23
|
+
files = {k: v.resolve() for k, v in files.items() if v.exists()}
|
|
29
24
|
|
|
30
25
|
file_choice = Prompt.ask(
|
|
31
26
|
console=console,
|
|
@@ -28,17 +28,17 @@ def _input() -> Decorator:
|
|
|
28
28
|
return click.argument(
|
|
29
29
|
"input",
|
|
30
30
|
help="A file containing a list of test commands to be ran.",
|
|
31
|
-
metavar="
|
|
31
|
+
metavar="<file>",
|
|
32
32
|
required=True,
|
|
33
33
|
callback=input_cb,
|
|
34
|
-
expose_value=
|
|
34
|
+
expose_value=False,
|
|
35
35
|
type=click.Path(
|
|
36
36
|
exists=True,
|
|
37
|
-
file_okay=True,
|
|
38
|
-
dir_okay=False,
|
|
39
37
|
readable=True,
|
|
40
|
-
|
|
38
|
+
dir_okay=False,
|
|
39
|
+
file_okay=True,
|
|
41
40
|
path_type=Path,
|
|
41
|
+
resolve_path=True,
|
|
42
42
|
),
|
|
43
43
|
)
|
|
44
44
|
|
|
@@ -51,19 +51,18 @@ def _output() -> Decorator:
|
|
|
51
51
|
"output",
|
|
52
52
|
help="Output directory for writing passed/failed run commands.",
|
|
53
53
|
nargs=1,
|
|
54
|
+
metavar="[<directory>]",
|
|
54
55
|
type=click.Path(
|
|
55
56
|
exists=False,
|
|
56
|
-
file_okay=False,
|
|
57
57
|
dir_okay=True,
|
|
58
|
-
|
|
58
|
+
file_okay=False,
|
|
59
59
|
path_type=Path,
|
|
60
|
+
resolve_path=True,
|
|
60
61
|
),
|
|
61
62
|
default=settings.regression.run.output.directory,
|
|
62
63
|
callback=output_cb,
|
|
63
|
-
required=True,
|
|
64
|
-
show_envvar=True,
|
|
65
64
|
show_default=True,
|
|
66
|
-
expose_value=
|
|
65
|
+
expose_value=False,
|
|
67
66
|
)
|
|
68
67
|
|
|
69
68
|
|
|
@@ -72,28 +71,23 @@ def options() -> Decorator:
|
|
|
72
71
|
return join_decorators(_input(), _output())
|
|
73
72
|
|
|
74
73
|
|
|
75
|
-
def
|
|
74
|
+
def _get_input_path() -> Path:
|
|
76
75
|
"""Resolve the regression input path from CLI value or settings."""
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return input_path.resolve()
|
|
76
|
+
input_cfg = settings.regression.run.input
|
|
77
|
+
directory, filename = input_cfg.directory, input_cfg.filename
|
|
78
|
+
rv = (
|
|
79
|
+
(Path(directory) / filename)
|
|
80
|
+
if isinstance(directory, str)
|
|
81
|
+
else (directory / filename)
|
|
82
|
+
)
|
|
83
|
+
return rv.resolve()
|
|
87
84
|
|
|
88
85
|
|
|
89
|
-
def
|
|
90
|
-
regression: Regression,
|
|
91
|
-
output_path: str | Path | None = None,
|
|
92
|
-
) -> Path:
|
|
86
|
+
def _get_output_path(regression: Regression) -> Path:
|
|
93
87
|
"""Return timestamped output paths for passed and failed results."""
|
|
94
88
|
now = time.strftime("%H-%M")
|
|
95
89
|
today = time.strftime("%d-%m-%Y")
|
|
96
|
-
dir_out =
|
|
90
|
+
dir_out = settings.regression.run.output.directory # pyright: ignore
|
|
97
91
|
if isinstance(dir_out, str):
|
|
98
92
|
dir_out = Path(dir_out)
|
|
99
93
|
dir_out = dir_out / regression.name / today / now
|
|
@@ -166,14 +160,11 @@ def populate_regression(filepath: Path) -> Regression:
|
|
|
166
160
|
)
|
|
167
161
|
|
|
168
162
|
|
|
169
|
-
async def
|
|
170
|
-
input: str | Path | None = None, # noqa: A002
|
|
171
|
-
output: str | Path | None = None,
|
|
172
|
-
) -> Regression:
|
|
163
|
+
async def run_regression() -> Regression:
|
|
173
164
|
"""Run a regression using file inputs and persist the results."""
|
|
174
|
-
path_in =
|
|
165
|
+
path_in = _get_input_path()
|
|
175
166
|
regression = populate_regression(path_in)
|
|
176
|
-
output_dir =
|
|
167
|
+
output_dir = _get_output_path(regression)
|
|
177
168
|
|
|
178
169
|
try:
|
|
179
170
|
async with asyncio.TaskGroup() as tg:
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Rich-Click callbacks for normalising regression CLI arguments."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from socx import settings, log, log_it
|
|
8
|
+
from rich_click import Context, Parameter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
logger = log.get_logger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def input_cb(ctx: Context, param: Parameter, value: str | Path) -> Path:
|
|
15
|
+
"""Normalise the regression input path and update configuration."""
|
|
16
|
+
path = Path(value) if isinstance(value, str) else value
|
|
17
|
+
settings.regression.run.input.update(
|
|
18
|
+
{"filename": path.name, "directory": path.parent}
|
|
19
|
+
)
|
|
20
|
+
return path
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@log_it(logger=logger)
|
|
24
|
+
def output_cb(ctx: Context, param: Parameter, value: str | Path) -> Path:
|
|
25
|
+
"""Normalise the regression output directory and update configuration."""
|
|
26
|
+
path = Path(value) if isinstance(value, str) else value
|
|
27
|
+
settings.regression.run.output.update({param.name: path})
|
|
28
|
+
return path
|
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
|
-
from pathlib import Path
|
|
7
6
|
|
|
8
7
|
from socx import settings, group, command
|
|
9
8
|
|
|
10
|
-
from socx_plugins.rgr._rgr import options,
|
|
9
|
+
from socx_plugins.rgr._rgr import options, run_regression
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
@group()
|
|
@@ -25,7 +24,7 @@ def tui() -> None:
|
|
|
25
24
|
|
|
26
25
|
@command(parent=cli, no_args_is_help=True)
|
|
27
26
|
@options()
|
|
28
|
-
def run(
|
|
27
|
+
def run():
|
|
29
28
|
r"""Run a regression of multiple tests defined in FILE.
|
|
30
29
|
|
|
31
30
|
The FILE argument is a file containing a list of test commands to be ran.
|
|
@@ -48,7 +47,7 @@ def run(input: Path, output: Path): # noqa: A002
|
|
|
48
47
|
"""
|
|
49
48
|
try:
|
|
50
49
|
regression = asyncio.run(
|
|
51
|
-
|
|
50
|
+
run_regression(),
|
|
52
51
|
debug=settings.cli.params.debug,
|
|
53
52
|
)
|
|
54
53
|
except (asyncio.CancelledError, KeyboardInterrupt):
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"""Rich-Click callbacks for normalising regression CLI arguments."""
|
|
2
|
-
|
|
3
|
-
# type: ignore
|
|
4
|
-
from __future__ import annotations
|
|
5
|
-
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
|
|
8
|
-
from socx import settings, log, log_it
|
|
9
|
-
from rich_click import Context, Parameter
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
logger = log.get_logger(__name__)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def input_cb(ctx: Context, param: Parameter, value: str | Path) -> Path:
|
|
16
|
-
"""Normalise the regression input path and update configuration."""
|
|
17
|
-
if value and isinstance(value, str):
|
|
18
|
-
path = Path(value)
|
|
19
|
-
|
|
20
|
-
if path.exists() and path.is_file():
|
|
21
|
-
input_ = {"filename": path.name, "directory": path.parent}
|
|
22
|
-
settings.set("regression.run.input", input_, merge=True)
|
|
23
|
-
|
|
24
|
-
file: str = settings.get("regression.run.input.filename")
|
|
25
|
-
directory: Path = Path(settings.get("regression.run.input.directory"))
|
|
26
|
-
input_path = directory / file
|
|
27
|
-
return input_path
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@log_it(logger=logger)
|
|
31
|
-
def output_cb(ctx: Context, param: Parameter, value: str) -> str:
|
|
32
|
-
"""Normalise the regression output directory and update configuration."""
|
|
33
|
-
if value:
|
|
34
|
-
path = Path(value)
|
|
35
|
-
|
|
36
|
-
if path.exists() and path.is_dir():
|
|
37
|
-
settings.set(
|
|
38
|
-
"regression.run.output", {"directory": path}, merge=True
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
output_path: Path = Path(settings.get("regression.run.output.directory"))
|
|
42
|
-
return output_path
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|