apexdevkit 1.27.1__tar.gz → 1.27.3__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.
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/PKG-INFO +3 -1
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/pyproject.toml +6 -13
- apexdevkit-1.27.1/pycodex/__init__.py +0 -0
- apexdevkit-1.27.1/pycodex/cli.py +0 -120
- apexdevkit-1.27.1/pycodex/reporters.py +0 -85
- apexdevkit-1.27.1/pycodex/service.py +0 -27
- apexdevkit-1.27.1/pycodex/tasks/__init__.py +0 -10
- apexdevkit-1.27.1/pycodex/tasks/result.py +0 -31
- apexdevkit-1.27.1/pycodex/tasks/shell.py +0 -58
- apexdevkit-1.27.1/pycodex/tasks/update.py +0 -117
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/LICENSE +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/README.md +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/__init__.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/annotation/__init__.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/annotation/deprecate.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/date.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/environment.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/error.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fastapi/__init__.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fastapi/builder.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fastapi/dependable.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fastapi/docs.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fastapi/name.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fastapi/resource.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fastapi/response.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fastapi/router.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fastapi/schema.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fastapi/service.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/fluent.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/formatter.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/http/__init__.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/http/fake.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/http/fluent.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/http/httpx/__init__.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/http/httpx/client.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/http/httpx/hooks.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/http/json.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/http/url.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/id.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/key_fn.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/py.typed +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/query/__init__.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/query/generator.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/query/query.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/__init__.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/base.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/connector.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/database.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/decorator.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/in_memory.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/interface.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/mssql.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/repository.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/sql.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/repository/sqlite.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/server.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/synchronization.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/testing/__init__.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/testing/database.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/testing/fake.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/testing/rest.py +0 -0
- {apexdevkit-1.27.1 → apexdevkit-1.27.3}/apexdevkit/value.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apexdevkit
|
|
3
|
-
Version: 1.27.
|
|
3
|
+
Version: 1.27.3
|
|
4
4
|
Summary: Apex Development Tools for python.
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Author: Apex Dev
|
|
@@ -16,6 +16,8 @@ Requires-Dist: httpx
|
|
|
16
16
|
Requires-Dist: pymssql (==2.3.2)
|
|
17
17
|
Requires-Dist: python-dotenv
|
|
18
18
|
Requires-Dist: sentry-sdk[fastapi]
|
|
19
|
+
Requires-Dist: tomlkit
|
|
20
|
+
Requires-Dist: typer
|
|
19
21
|
Requires-Dist: uvicorn
|
|
20
22
|
Description-Content-Type: text/markdown
|
|
21
23
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "apexdevkit"
|
|
3
|
-
version = "1.27.
|
|
3
|
+
version = "1.27.3"
|
|
4
4
|
description = "Apex Development Tools for python."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -9,15 +9,6 @@ authors = [
|
|
|
9
9
|
dynamic = ["dependencies"]
|
|
10
10
|
requires-python = ">=3.11"
|
|
11
11
|
|
|
12
|
-
[project.scripts]
|
|
13
|
-
pycodex = "pycodex.cli:cli"
|
|
14
|
-
|
|
15
|
-
[tool.poetry]
|
|
16
|
-
packages = [
|
|
17
|
-
{ include = "apexdevkit" },
|
|
18
|
-
{ include = "pycodex" }
|
|
19
|
-
]
|
|
20
|
-
|
|
21
12
|
[tool.poetry.dependencies]
|
|
22
13
|
httpx = "*"
|
|
23
14
|
fastapi = "*"
|
|
@@ -25,9 +16,11 @@ uvicorn = "*"
|
|
|
25
16
|
sentry-sdk = { extras = ["fastapi"], version = "*" }
|
|
26
17
|
python-dotenv = "*"
|
|
27
18
|
pymssql = "2.3.2"
|
|
19
|
+
typer = "*"
|
|
20
|
+
tomlkit = "*"
|
|
28
21
|
|
|
29
22
|
[tool.poetry.group.dev.dependencies]
|
|
30
|
-
approvaltests = "
|
|
23
|
+
approvaltests = "*"
|
|
31
24
|
pytest = "*"
|
|
32
25
|
pytest-approvaltests = "*"
|
|
33
26
|
pytest-cov = "*"
|
|
@@ -35,9 +28,9 @@ pytest-recording = "*"
|
|
|
35
28
|
coverage = "*"
|
|
36
29
|
faker = "*"
|
|
37
30
|
|
|
31
|
+
|
|
38
32
|
[tool.poetry.group.lint.dependencies]
|
|
39
|
-
|
|
40
|
-
ruff = "*"
|
|
33
|
+
apexcodexpy = "*"
|
|
41
34
|
|
|
42
35
|
[tool.mypy]
|
|
43
36
|
ignore_missing_imports = true
|
|
File without changes
|
apexdevkit-1.27.1/pycodex/cli.py
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
import typer
|
|
7
|
-
|
|
8
|
-
from pycodex.reporters import DefaultReporter
|
|
9
|
-
from pycodex.service import PyCodex
|
|
10
|
-
|
|
11
|
-
cli = typer.Typer(add_completion=False)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@cli.command(
|
|
15
|
-
name="lint",
|
|
16
|
-
help="Run linting (Ruff) and type checking (MyPy).",
|
|
17
|
-
)
|
|
18
|
-
def _(
|
|
19
|
-
path: str = typer.Option(
|
|
20
|
-
".",
|
|
21
|
-
"--path",
|
|
22
|
-
"-p",
|
|
23
|
-
help="Target directory.",
|
|
24
|
-
),
|
|
25
|
-
silent: bool = typer.Option(
|
|
26
|
-
False,
|
|
27
|
-
"--silent",
|
|
28
|
-
"-s",
|
|
29
|
-
help="Suppress output.",
|
|
30
|
-
),
|
|
31
|
-
) -> None:
|
|
32
|
-
raise typer.Exit(
|
|
33
|
-
PyCodex(
|
|
34
|
-
target=Path(path),
|
|
35
|
-
reporter=DefaultReporter.using(TyperDevice()).silenced().when(silent),
|
|
36
|
-
).lint()
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@cli.command(
|
|
41
|
-
name="fix",
|
|
42
|
-
help="Automatically fix Ruff linting errors.",
|
|
43
|
-
)
|
|
44
|
-
def _(
|
|
45
|
-
path: str = typer.Option(
|
|
46
|
-
".",
|
|
47
|
-
"--path",
|
|
48
|
-
"-p",
|
|
49
|
-
help="Target directory.",
|
|
50
|
-
),
|
|
51
|
-
silent: bool = typer.Option(
|
|
52
|
-
False,
|
|
53
|
-
"--silent",
|
|
54
|
-
"-s",
|
|
55
|
-
help="Suppress output.",
|
|
56
|
-
),
|
|
57
|
-
unsafe: bool = typer.Option(
|
|
58
|
-
False,
|
|
59
|
-
"--unsafe",
|
|
60
|
-
help="Run unsafe Ruff fixes.",
|
|
61
|
-
),
|
|
62
|
-
) -> None:
|
|
63
|
-
raise typer.Exit(
|
|
64
|
-
PyCodex(
|
|
65
|
-
target=Path(path),
|
|
66
|
-
reporter=DefaultReporter.using(TyperDevice()).silenced().when(silent),
|
|
67
|
-
).fix(unsafe=unsafe)
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@cli.command(
|
|
72
|
-
name="sync",
|
|
73
|
-
help="Inject pycodex standards into pyproject TOML file.",
|
|
74
|
-
)
|
|
75
|
-
def _(
|
|
76
|
-
path: str = typer.Option(
|
|
77
|
-
".",
|
|
78
|
-
"--path",
|
|
79
|
-
"-p",
|
|
80
|
-
help="Target directory.",
|
|
81
|
-
),
|
|
82
|
-
dry_run: bool = typer.Option(
|
|
83
|
-
False,
|
|
84
|
-
"--dry-run",
|
|
85
|
-
help="Show changes without applying them.",
|
|
86
|
-
),
|
|
87
|
-
) -> None:
|
|
88
|
-
raise typer.Exit(
|
|
89
|
-
PyCodex(
|
|
90
|
-
target=Path(path),
|
|
91
|
-
reporter=DefaultReporter.using(TyperDevice()),
|
|
92
|
-
).sync(dry_run=dry_run)
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
@dataclass(frozen=True)
|
|
97
|
-
class TyperDevice:
|
|
98
|
-
color: str = typer.colors.RESET
|
|
99
|
-
|
|
100
|
-
def with_green(self) -> TyperDevice:
|
|
101
|
-
return TyperDevice(typer.colors.GREEN)
|
|
102
|
-
|
|
103
|
-
def with_red(self) -> TyperDevice:
|
|
104
|
-
return TyperDevice(typer.colors.RED)
|
|
105
|
-
|
|
106
|
-
def with_white(self) -> TyperDevice:
|
|
107
|
-
return TyperDevice(typer.colors.WHITE)
|
|
108
|
-
|
|
109
|
-
def with_yellow(self) -> TyperDevice:
|
|
110
|
-
return TyperDevice(typer.colors.YELLOW)
|
|
111
|
-
|
|
112
|
-
def echo(self, message: str) -> TyperDevice:
|
|
113
|
-
if message.strip():
|
|
114
|
-
typer.secho(message, fg=self.color)
|
|
115
|
-
|
|
116
|
-
return self
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if __name__ == "__main__":
|
|
120
|
-
cli()
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from typing import Protocol
|
|
5
|
-
|
|
6
|
-
from pycodex.tasks import TaskResult
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Reporter(Protocol):
|
|
10
|
-
def report(self, **results: TaskResult) -> int:
|
|
11
|
-
pass
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass(frozen=True)
|
|
15
|
-
class DefaultReporter:
|
|
16
|
-
device: _Device
|
|
17
|
-
|
|
18
|
-
@classmethod
|
|
19
|
-
def using(cls, device: _Device) -> DefaultReporter:
|
|
20
|
-
return cls(device)
|
|
21
|
-
|
|
22
|
-
def silenced(self) -> _Silenced:
|
|
23
|
-
return _Silenced(self)
|
|
24
|
-
|
|
25
|
-
def report(self, **results: TaskResult) -> int:
|
|
26
|
-
return sum(
|
|
27
|
-
self.report_one(name.capitalize(), result)
|
|
28
|
-
for name, result in results.items()
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
def report_one(self, name: str, result: TaskResult) -> int:
|
|
32
|
-
if result:
|
|
33
|
-
self.device.with_green().echo(f"✅ {name} passed!")
|
|
34
|
-
else:
|
|
35
|
-
self.device.with_red().echo(f"❌ {name} failed!")
|
|
36
|
-
|
|
37
|
-
self.device.with_white().echo(result.stdout)
|
|
38
|
-
self.device.with_yellow().echo(result.stderr)
|
|
39
|
-
|
|
40
|
-
return result.exit_code
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class _Device(Protocol):
|
|
44
|
-
def with_green(self) -> _Device:
|
|
45
|
-
pass
|
|
46
|
-
|
|
47
|
-
def with_red(self) -> _Device:
|
|
48
|
-
pass
|
|
49
|
-
|
|
50
|
-
def with_white(self) -> _Device:
|
|
51
|
-
pass
|
|
52
|
-
|
|
53
|
-
def with_yellow(self) -> _Device:
|
|
54
|
-
pass
|
|
55
|
-
|
|
56
|
-
def echo(self, message: str) -> _Device:
|
|
57
|
-
pass
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@dataclass(frozen=True)
|
|
61
|
-
class _Silenced:
|
|
62
|
-
reporter: Reporter
|
|
63
|
-
|
|
64
|
-
def when(self, silenced: bool) -> Reporter:
|
|
65
|
-
return self.reporter if not silenced else DefaultReporter.using(_NoDevice())
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
@dataclass(frozen=True)
|
|
69
|
-
class _NoDevice:
|
|
70
|
-
def with_green(self) -> _Device:
|
|
71
|
-
return self
|
|
72
|
-
|
|
73
|
-
def with_red(self) -> _Device:
|
|
74
|
-
return self
|
|
75
|
-
|
|
76
|
-
def with_white(self) -> _Device:
|
|
77
|
-
return self
|
|
78
|
-
|
|
79
|
-
def with_yellow(self) -> _Device:
|
|
80
|
-
return self
|
|
81
|
-
|
|
82
|
-
def echo(self, message: str) -> _Device:
|
|
83
|
-
_ = message # suppresses IDE warning for unused argument
|
|
84
|
-
|
|
85
|
-
return self
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
|
|
4
|
-
from pycodex.reporters import Reporter
|
|
5
|
-
from pycodex.tasks import RunMypy, RunRuff, SyncToml
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@dataclass(frozen=True)
|
|
9
|
-
class PyCodex:
|
|
10
|
-
target: Path
|
|
11
|
-
reporter: Reporter
|
|
12
|
-
|
|
13
|
-
def sync(self, dry_run: bool = False) -> int:
|
|
14
|
-
return self.reporter.report(
|
|
15
|
-
sync=SyncToml(of=self.target, dry_run=dry_run).run()
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
def lint(self) -> int:
|
|
19
|
-
return self.reporter.report(
|
|
20
|
-
ruff=RunRuff(on=self.target).run(),
|
|
21
|
-
mypy=RunMypy(on=self.target).run(),
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
def fix(self, unsafe: bool = False) -> int:
|
|
25
|
-
return self.reporter.report(
|
|
26
|
-
ruff=RunRuff(on=self.target, fix=True, unsafe=unsafe).run()
|
|
27
|
-
)
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from subprocess import CompletedProcess
|
|
5
|
-
from typing import Any
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@dataclass(frozen=True, kw_only=True)
|
|
9
|
-
class TaskResult:
|
|
10
|
-
stdout: str
|
|
11
|
-
stderr: str
|
|
12
|
-
exit_code: int
|
|
13
|
-
|
|
14
|
-
def __bool__(self) -> bool:
|
|
15
|
-
return self.exit_code == 0
|
|
16
|
-
|
|
17
|
-
@classmethod
|
|
18
|
-
def parse(cls, result: CompletedProcess[Any]) -> TaskResult:
|
|
19
|
-
return cls(
|
|
20
|
-
stdout=result.stdout,
|
|
21
|
-
stderr=result.stderr,
|
|
22
|
-
exit_code=result.returncode,
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
@classmethod
|
|
26
|
-
def success(cls, *, stdout: str = "", stderr: str = "") -> TaskResult:
|
|
27
|
-
return cls(stdout=stdout, stderr=stderr, exit_code=0)
|
|
28
|
-
|
|
29
|
-
@classmethod
|
|
30
|
-
def fail(cls, *, stdout: str = "", stderr: str = "") -> TaskResult:
|
|
31
|
-
return cls(stdout=stdout, stderr=stderr, exit_code=1)
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import subprocess
|
|
4
|
-
from abc import ABC, abstractmethod
|
|
5
|
-
from collections.abc import Iterable
|
|
6
|
-
from dataclasses import dataclass
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from subprocess import CompletedProcess
|
|
9
|
-
|
|
10
|
-
from pycodex.tasks.result import TaskResult
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class ShellTask(ABC):
|
|
14
|
-
def run(self) -> TaskResult:
|
|
15
|
-
return TaskResult.parse(self._execute())
|
|
16
|
-
|
|
17
|
-
def _execute(self) -> CompletedProcess[str]:
|
|
18
|
-
return subprocess.run(
|
|
19
|
-
list(self._command),
|
|
20
|
-
text=True,
|
|
21
|
-
encoding="utf-8",
|
|
22
|
-
capture_output=True,
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
@property
|
|
26
|
-
@abstractmethod
|
|
27
|
-
def _command(self) -> Iterable[str]:
|
|
28
|
-
pass
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@dataclass(frozen=True)
|
|
32
|
-
class RunRuff(ShellTask):
|
|
33
|
-
on: Path
|
|
34
|
-
|
|
35
|
-
fix: bool = False
|
|
36
|
-
unsafe: bool = False
|
|
37
|
-
|
|
38
|
-
@property
|
|
39
|
-
def _command(self) -> Iterable[str]:
|
|
40
|
-
yield "ruff"
|
|
41
|
-
yield "check"
|
|
42
|
-
yield str(self.on)
|
|
43
|
-
|
|
44
|
-
if self.fix:
|
|
45
|
-
yield "--fix"
|
|
46
|
-
|
|
47
|
-
if self.unsafe:
|
|
48
|
-
yield "--unsafe-fixes"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@dataclass(frozen=True)
|
|
52
|
-
class RunMypy(ShellTask):
|
|
53
|
-
on: Path
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def _command(self) -> Iterable[str]:
|
|
57
|
-
yield "mypy"
|
|
58
|
-
yield str(self.on)
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from functools import cached_property
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
import tomlkit
|
|
9
|
-
|
|
10
|
-
from pycodex.tasks.result import TaskResult
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def _mypy_config() -> dict[str, Any]:
|
|
14
|
-
return {
|
|
15
|
-
"strict": True,
|
|
16
|
-
"ignore_missing_imports": True,
|
|
17
|
-
"show_error_codes": True,
|
|
18
|
-
"pretty": True,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def _ruff_config() -> dict[str, Any]:
|
|
23
|
-
return {
|
|
24
|
-
"lint": {
|
|
25
|
-
"select": [
|
|
26
|
-
"A",
|
|
27
|
-
"ARG",
|
|
28
|
-
"B",
|
|
29
|
-
"C4",
|
|
30
|
-
"PT",
|
|
31
|
-
"RSE",
|
|
32
|
-
"RET",
|
|
33
|
-
"SIM",
|
|
34
|
-
"T20",
|
|
35
|
-
"E",
|
|
36
|
-
"W",
|
|
37
|
-
"F",
|
|
38
|
-
"I",
|
|
39
|
-
"N",
|
|
40
|
-
"UP",
|
|
41
|
-
],
|
|
42
|
-
"mccabe": {"max-complexity": 10},
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def _coverage_config() -> dict[str, Any]:
|
|
48
|
-
return {
|
|
49
|
-
"run": {
|
|
50
|
-
"branch": True,
|
|
51
|
-
},
|
|
52
|
-
"report": {
|
|
53
|
-
"skip_empty": True,
|
|
54
|
-
"skip_covered": True,
|
|
55
|
-
"show_missing": True,
|
|
56
|
-
},
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
STANDARDS = {
|
|
61
|
-
"tool": {
|
|
62
|
-
"mypy": _mypy_config(),
|
|
63
|
-
"ruff": _ruff_config(),
|
|
64
|
-
"coverage": _coverage_config(),
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
@dataclass(frozen=True)
|
|
70
|
-
class SyncToml:
|
|
71
|
-
of: Path
|
|
72
|
-
|
|
73
|
-
dry_run: bool = False
|
|
74
|
-
|
|
75
|
-
@cached_property
|
|
76
|
-
def _toml(self) -> Path:
|
|
77
|
-
return self.of / "pyproject.toml"
|
|
78
|
-
|
|
79
|
-
def run(self) -> TaskResult:
|
|
80
|
-
if not self._toml.exists():
|
|
81
|
-
return TaskResult.fail(stderr=f"{self._toml.name} not found.")
|
|
82
|
-
|
|
83
|
-
document = tomlkit.parse(self._toml.read_text(encoding="utf-8"))
|
|
84
|
-
|
|
85
|
-
# Create a copy for comparison if dry-run
|
|
86
|
-
original = tomlkit.dumps(document)
|
|
87
|
-
deep_merge(STANDARDS, document)
|
|
88
|
-
modified = tomlkit.dumps(document)
|
|
89
|
-
|
|
90
|
-
if original == modified:
|
|
91
|
-
return TaskResult.success(stdout="Configuration is already up to date.")
|
|
92
|
-
|
|
93
|
-
if self.dry_run:
|
|
94
|
-
return TaskResult.success(stdout=f"Changes would be applied:\n{modified}")
|
|
95
|
-
|
|
96
|
-
self._toml.write_text(modified, encoding="utf-8", newline="\n")
|
|
97
|
-
|
|
98
|
-
return TaskResult.success(stdout="Configuration synchronized successfully.")
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def deep_merge(source: dict[str, Any], destination: dict[str, Any]) -> None:
|
|
102
|
-
"""Recursively merges the source into destination with TOML formatting."""
|
|
103
|
-
for key, value in source.items():
|
|
104
|
-
if isinstance(value, dict):
|
|
105
|
-
# Create a table if the key doesn't exist
|
|
106
|
-
if key not in destination:
|
|
107
|
-
destination[key] = tomlkit.table()
|
|
108
|
-
deep_merge(value, destination[key])
|
|
109
|
-
elif isinstance(value, list):
|
|
110
|
-
# Create a multiline array
|
|
111
|
-
new_array = tomlkit.array()
|
|
112
|
-
for item in value:
|
|
113
|
-
new_array.append(item)
|
|
114
|
-
new_array.multiline(True)
|
|
115
|
-
destination[key] = new_array
|
|
116
|
-
else:
|
|
117
|
-
destination[key] = value
|
|
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
|