fast-dev-cli 0.21.0__tar.gz → 0.22.0__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.
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/PKG-INFO +21 -10
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/README.md +11 -5
- fast_dev_cli-0.22.0/fast_dev_cli/__init__.py +1 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/fast_dev_cli/cli.py +169 -49
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/pyproject.toml +24 -46
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_bump.py +20 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_deps.py +1 -1
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_fast_test.py +1 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_lint.py +72 -33
- fast_dev_cli-0.22.0/tests/test_runserver.py +136 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_sync.py +14 -8
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_upgrade.py +1 -1
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_upload.py +1 -1
- fast_dev_cli-0.21.0/fast_dev_cli/__init__.py +0 -1
- fast_dev_cli-0.21.0/pdm_build.py +0 -39
- fast_dev_cli-0.21.0/scripts/check.py +0 -30
- fast_dev_cli-0.21.0/scripts/deps.py +0 -156
- fast_dev_cli-0.21.0/scripts/format.py +0 -13
- fast_dev_cli-0.21.0/scripts/test.py +0 -48
- fast_dev_cli-0.21.0/tests/test_runserver.py +0 -97
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/LICENSE +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/fast_dev_cli/__main__.py +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/fast_dev_cli/py.typed +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/__init__.py +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/assets/uv-tx.lock +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/assets/uv-upload-time.lock +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/assets/uv.lock +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/conftest.py +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_exec.py +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_functions.py +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_help.py +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_poetry_version_plugin.py +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_pypi.py +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_tag.py +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/test_version.py +0 -0
- {fast_dev_cli-0.21.0 → fast_dev_cli-0.22.0}/tests/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fast-dev-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.22.0
|
|
4
4
|
Summary: Python project development tool.
|
|
5
5
|
Author-Email: Waket Zheng <waketzheng@gmail.com>>
|
|
6
6
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -23,10 +23,15 @@ Project-URL: Homepage, https://github.com/waketzheng/fast-dev-cli
|
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
24
|
Requires-Dist: typer<1,>=0.24.0
|
|
25
25
|
Requires-Dist: tomli<3,>=2.0.1; python_version < "3.11"
|
|
26
|
-
|
|
27
|
-
Requires-Dist:
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
Provides-Extra: standard
|
|
27
|
+
Requires-Dist: coverage>=7.5.1; extra == "standard"
|
|
28
|
+
Requires-Dist: pytest>=8.2.0; extra == "standard"
|
|
29
|
+
Provides-Extra: all
|
|
30
|
+
Requires-Dist: emoji>=2.12.1; extra == "all"
|
|
31
|
+
Requires-Dist: packaging>=20.5; extra == "all"
|
|
32
|
+
Requires-Dist: bandit>=1.7.9; extra == "all"
|
|
33
|
+
Requires-Dist: pytest-mock>=3.14.0; extra == "all"
|
|
34
|
+
Requires-Dist: fast-dev-cli[standard]; extra == "all"
|
|
30
35
|
Description-Content-Type: text/markdown
|
|
31
36
|
|
|
32
37
|
<p align="center">
|
|
@@ -51,6 +56,12 @@ Description-Content-Type: text/markdown
|
|
|
51
56
|
<a href="https://github.com/python/mypy" target="_blank">
|
|
52
57
|
<img src="https://img.shields.io/badge/mypy-100%25-brightgreen.svg" alt="Mypy Coverage">
|
|
53
58
|
</a>
|
|
59
|
+
<a href="https://github.com/microsoft/pyright" target="_blank">
|
|
60
|
+
<img src="https://img.shields.io/badge/pyright-checked-brightgreen.svg" alt="Pyright Checked">
|
|
61
|
+
</a>
|
|
62
|
+
<a href="https://github.com/astral-sh/ty" target="_blank">
|
|
63
|
+
<img src="https://img.shields.io/badge/ty-checked-brightgreen.svg" alt="ty Checked">
|
|
64
|
+
</a>
|
|
54
65
|
<a href="https://github.com/astral-sh/ruff" target="_blank">
|
|
55
66
|
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
|
|
56
67
|
</a>
|
|
@@ -84,8 +95,8 @@ Python 3.10+
|
|
|
84
95
|
<div class="termy">
|
|
85
96
|
|
|
86
97
|
```bash
|
|
87
|
-
uv tool install
|
|
88
|
-
# Or: pipx install
|
|
98
|
+
uv tool install fast-dev-cli
|
|
99
|
+
# Or: pipx install fast-dev-cli
|
|
89
100
|
```
|
|
90
101
|
*Will create a `fast` command in ~/.local/bin
|
|
91
102
|
|
|
@@ -96,7 +107,7 @@ uv tool install --python 3.14 fastdevcli-slim
|
|
|
96
107
|
<div class="termy">
|
|
97
108
|
|
|
98
109
|
```bash
|
|
99
|
-
pip install fast-dev-cli
|
|
110
|
+
pip install "fast-dev-cli[standard]"
|
|
100
111
|
```
|
|
101
112
|
*Will install: fast-dev-cli emoji typer packaging pytest coverage*
|
|
102
113
|
|
|
@@ -112,7 +123,7 @@ fast lint [/path/to/file-or-directory]
|
|
|
112
123
|
```bash
|
|
113
124
|
fast check
|
|
114
125
|
```
|
|
115
|
-
- Bump up version in pyproject.toml
|
|
126
|
+
- Bump up version in pyproject.toml(or package.json)
|
|
116
127
|
```bash
|
|
117
128
|
fast bump patch # 0.1.0 -> 0.1.1
|
|
118
129
|
fast bump minor # 0.1.0 -> 0.2.0
|
|
@@ -140,7 +151,7 @@ fast pypi
|
|
|
140
151
|
## Use it without installed
|
|
141
152
|
|
|
142
153
|
```bash
|
|
143
|
-
uvx --from
|
|
154
|
+
uvx --from fast-dev-cli fast
|
|
144
155
|
```
|
|
145
156
|
|
|
146
157
|
## Lint/Check by ty instead of mypy
|
|
@@ -20,6 +20,12 @@
|
|
|
20
20
|
<a href="https://github.com/python/mypy" target="_blank">
|
|
21
21
|
<img src="https://img.shields.io/badge/mypy-100%25-brightgreen.svg" alt="Mypy Coverage">
|
|
22
22
|
</a>
|
|
23
|
+
<a href="https://github.com/microsoft/pyright" target="_blank">
|
|
24
|
+
<img src="https://img.shields.io/badge/pyright-checked-brightgreen.svg" alt="Pyright Checked">
|
|
25
|
+
</a>
|
|
26
|
+
<a href="https://github.com/astral-sh/ty" target="_blank">
|
|
27
|
+
<img src="https://img.shields.io/badge/ty-checked-brightgreen.svg" alt="ty Checked">
|
|
28
|
+
</a>
|
|
23
29
|
<a href="https://github.com/astral-sh/ruff" target="_blank">
|
|
24
30
|
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
|
|
25
31
|
</a>
|
|
@@ -53,8 +59,8 @@ Python 3.10+
|
|
|
53
59
|
<div class="termy">
|
|
54
60
|
|
|
55
61
|
```bash
|
|
56
|
-
uv tool install
|
|
57
|
-
# Or: pipx install
|
|
62
|
+
uv tool install fast-dev-cli
|
|
63
|
+
# Or: pipx install fast-dev-cli
|
|
58
64
|
```
|
|
59
65
|
*Will create a `fast` command in ~/.local/bin
|
|
60
66
|
|
|
@@ -65,7 +71,7 @@ uv tool install --python 3.14 fastdevcli-slim
|
|
|
65
71
|
<div class="termy">
|
|
66
72
|
|
|
67
73
|
```bash
|
|
68
|
-
pip install fast-dev-cli
|
|
74
|
+
pip install "fast-dev-cli[standard]"
|
|
69
75
|
```
|
|
70
76
|
*Will install: fast-dev-cli emoji typer packaging pytest coverage*
|
|
71
77
|
|
|
@@ -81,7 +87,7 @@ fast lint [/path/to/file-or-directory]
|
|
|
81
87
|
```bash
|
|
82
88
|
fast check
|
|
83
89
|
```
|
|
84
|
-
- Bump up version in pyproject.toml
|
|
90
|
+
- Bump up version in pyproject.toml(or package.json)
|
|
85
91
|
```bash
|
|
86
92
|
fast bump patch # 0.1.0 -> 0.1.1
|
|
87
93
|
fast bump minor # 0.1.0 -> 0.2.0
|
|
@@ -109,7 +115,7 @@ fast pypi
|
|
|
109
115
|
## Use it without installed
|
|
110
116
|
|
|
111
117
|
```bash
|
|
112
|
-
uvx --from
|
|
118
|
+
uvx --from fast-dev-cli fast
|
|
113
119
|
```
|
|
114
120
|
|
|
115
121
|
## Lint/Check by ty instead of mypy
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.22.0"
|
|
@@ -75,11 +75,10 @@ def poetry_module_name(name: str) -> str:
|
|
|
75
75
|
try:
|
|
76
76
|
from packaging.utils import canonicalize_name
|
|
77
77
|
except ImportError:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return canonicalize_name(name).replace("-", "_").replace(" ", "_")
|
|
78
|
+
module_name = re.sub(r"[-_.]+", "-", name)
|
|
79
|
+
else:
|
|
80
|
+
module_name = canonicalize_name(name)
|
|
81
|
+
return module_name.replace("-", "_").replace(" ", "_")
|
|
83
82
|
|
|
84
83
|
|
|
85
84
|
def is_emoji(char: str) -> bool:
|
|
@@ -272,6 +271,26 @@ def read_version_from_file(
|
|
|
272
271
|
return "0.0.0"
|
|
273
272
|
|
|
274
273
|
|
|
274
|
+
def _get_frontend_version() -> tuple[Path, str] | None:
|
|
275
|
+
try:
|
|
276
|
+
frontend_version_file = Project.get_work_dir("package.json", be_file=True)
|
|
277
|
+
except EnvError:
|
|
278
|
+
return None
|
|
279
|
+
try:
|
|
280
|
+
from asynctor.jsons import json_loads
|
|
281
|
+
except ImportError:
|
|
282
|
+
from json import loads as json_loads # type:ignore[assignment]
|
|
283
|
+
content = frontend_version_file.read_bytes()
|
|
284
|
+
metadata: dict[str, str] = json_loads(content) # type:ignore[assignment]
|
|
285
|
+
try:
|
|
286
|
+
current_version = metadata["version"]
|
|
287
|
+
except (KeyError, TypeError):
|
|
288
|
+
return None
|
|
289
|
+
with contextlib.suppress(ValueError):
|
|
290
|
+
frontend_version_file = frontend_version_file.relative_to(Path.cwd())
|
|
291
|
+
return frontend_version_file, current_version
|
|
292
|
+
|
|
293
|
+
|
|
275
294
|
@overload
|
|
276
295
|
def get_current_version(
|
|
277
296
|
verbose: bool = False,
|
|
@@ -288,7 +307,7 @@ def get_current_version(
|
|
|
288
307
|
is_poetry: bool | None = None,
|
|
289
308
|
package_name: str | None = None,
|
|
290
309
|
*,
|
|
291
|
-
check_version: Literal[True]
|
|
310
|
+
check_version: Literal[True],
|
|
292
311
|
) -> tuple[bool, str]: ...
|
|
293
312
|
|
|
294
313
|
|
|
@@ -310,11 +329,20 @@ def get_current_version(
|
|
|
310
329
|
return out
|
|
311
330
|
toml_text = work_dir = None
|
|
312
331
|
if package_name is None:
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
332
|
+
try:
|
|
333
|
+
work_dir = Project.get_work_dir()
|
|
334
|
+
except EnvError as e:
|
|
335
|
+
if (res := _get_frontend_version()) is None:
|
|
336
|
+
raise e
|
|
337
|
+
current_version = res[1]
|
|
338
|
+
if check_version:
|
|
339
|
+
return False, current_version
|
|
340
|
+
return current_version
|
|
341
|
+
else:
|
|
342
|
+
toml_text = Project.load_toml_text()
|
|
343
|
+
doc = tomllib.loads(toml_text)
|
|
344
|
+
project_name = doc.get("project", {}).get("name", work_dir.name)
|
|
345
|
+
package_name = re.sub(r"[- ]", "_", project_name)
|
|
318
346
|
local_version = read_version_from_file(package_name, work_dir, toml_text)
|
|
319
347
|
try:
|
|
320
348
|
installed_version = importlib_metadata.version(package_name)
|
|
@@ -330,15 +358,15 @@ def get_current_version(
|
|
|
330
358
|
|
|
331
359
|
|
|
332
360
|
def _ensure_bool(value: bool | OptionInfo) -> bool:
|
|
333
|
-
if
|
|
334
|
-
|
|
335
|
-
return value
|
|
361
|
+
if isinstance(value, bool):
|
|
362
|
+
return value
|
|
363
|
+
return bool(getattr(value, "default", False))
|
|
336
364
|
|
|
337
365
|
|
|
338
|
-
def _ensure_str(value: str | OptionInfo | None) -> str:
|
|
339
|
-
if
|
|
340
|
-
|
|
341
|
-
return value
|
|
366
|
+
def _ensure_str(value: str | OptionInfo | None) -> str | None:
|
|
367
|
+
if isinstance(value, str) or value is None:
|
|
368
|
+
return value
|
|
369
|
+
return getattr(value, "default", "")
|
|
342
370
|
|
|
343
371
|
|
|
344
372
|
class DryRun:
|
|
@@ -371,7 +399,13 @@ class BumpUp(DryRun):
|
|
|
371
399
|
self.commit = commit
|
|
372
400
|
self.part = part
|
|
373
401
|
if filename is None:
|
|
374
|
-
|
|
402
|
+
try:
|
|
403
|
+
filename = self.parse_filename()
|
|
404
|
+
except EnvError:
|
|
405
|
+
if (res := _get_frontend_version()) is not None:
|
|
406
|
+
filename = res[0].name
|
|
407
|
+
else:
|
|
408
|
+
raise
|
|
375
409
|
self.filename = filename
|
|
376
410
|
self._no_sync = no_sync
|
|
377
411
|
self._emoji = emoji
|
|
@@ -467,7 +501,7 @@ class BumpUp(DryRun):
|
|
|
467
501
|
try:
|
|
468
502
|
project_name = context["project"]["name"]
|
|
469
503
|
except KeyError:
|
|
470
|
-
packages = []
|
|
504
|
+
packages: list[tuple[str, str]] = []
|
|
471
505
|
else:
|
|
472
506
|
packages = [(poetry_module_name(project_name), "")]
|
|
473
507
|
else:
|
|
@@ -549,12 +583,23 @@ class BumpUp(DryRun):
|
|
|
549
583
|
echo("You may want to pin tag by `fast tag`")
|
|
550
584
|
|
|
551
585
|
|
|
586
|
+
def _echo_version(version_file: Any, value: str) -> None:
|
|
587
|
+
styled = typer.style(value, bold=True)
|
|
588
|
+
echo(f"Version value in {version_file}: " + styled)
|
|
589
|
+
|
|
590
|
+
|
|
552
591
|
@cli.command()
|
|
553
592
|
def version() -> None:
|
|
554
593
|
"""Show the version of this tool"""
|
|
555
594
|
echo("Fast Dev Cli Version: " + typer.style(__version__, fg=typer.colors.BLUE))
|
|
556
595
|
with contextlib.suppress(FileNotFoundError, KeyError):
|
|
557
|
-
|
|
596
|
+
try:
|
|
597
|
+
toml_text = Project.load_toml_text()
|
|
598
|
+
except EnvError:
|
|
599
|
+
if (res := _get_frontend_version()) is not None:
|
|
600
|
+
_echo_version(*res)
|
|
601
|
+
return
|
|
602
|
+
raise
|
|
558
603
|
doc = tomllib.loads(toml_text)
|
|
559
604
|
if value := doc.get("project", {}).get("version", ""):
|
|
560
605
|
styled = typer.style(value, bold=True, fg=typer.colors.CYAN)
|
|
@@ -569,8 +614,7 @@ def version() -> None:
|
|
|
569
614
|
for line in text.splitlines():
|
|
570
615
|
if line.strip().startswith(varname):
|
|
571
616
|
value = line.split("=", 1)[-1].strip().strip('"').strip("'")
|
|
572
|
-
|
|
573
|
-
echo(f"Version value in {version_file}: " + styled)
|
|
617
|
+
_echo_version(version_file, value)
|
|
574
618
|
break
|
|
575
619
|
|
|
576
620
|
|
|
@@ -985,7 +1029,7 @@ def upgrade(
|
|
|
985
1029
|
dry: bool = DryOption,
|
|
986
1030
|
) -> None:
|
|
987
1031
|
"""Upgrade dependencies in pyproject.toml to latest versions"""
|
|
988
|
-
if not (tool := _ensure_str(tool)) or tool == ToolOption.default:
|
|
1032
|
+
if not (tool := _ensure_str(tool) or "") or tool == ToolOption.default:
|
|
989
1033
|
tool = Project.get_manage_tool() or "uv"
|
|
990
1034
|
if tool in get_args(ToolName):
|
|
991
1035
|
UpgradeDependencies(dry=dry, tool=cast(ToolName, tool)).run()
|
|
@@ -1065,6 +1109,7 @@ class LintCode(DryRun):
|
|
|
1065
1109
|
sim: bool = True,
|
|
1066
1110
|
strict: bool = False,
|
|
1067
1111
|
ty: bool = False,
|
|
1112
|
+
fix: bool = True,
|
|
1068
1113
|
) -> None:
|
|
1069
1114
|
self.args = args
|
|
1070
1115
|
self.check_only = check_only
|
|
@@ -1077,6 +1122,7 @@ class LintCode(DryRun):
|
|
|
1077
1122
|
self._sim = sim
|
|
1078
1123
|
self._strict = strict
|
|
1079
1124
|
self._ty = _ensure_bool(ty)
|
|
1125
|
+
self._fix = _ensure_bool(fix)
|
|
1080
1126
|
super().__init__(_exit, dry)
|
|
1081
1127
|
|
|
1082
1128
|
@staticmethod
|
|
@@ -1123,11 +1169,13 @@ class LintCode(DryRun):
|
|
|
1123
1169
|
ruff_check_sim: bool = True,
|
|
1124
1170
|
mypy_strict: bool = False,
|
|
1125
1171
|
prefer_ty: bool = False,
|
|
1172
|
+
ruff_check_fix: bool = True,
|
|
1126
1173
|
) -> str:
|
|
1127
1174
|
if paths != "." and all(i.endswith(".html") for i in paths.split()):
|
|
1128
1175
|
return f"prettier -w {paths}"
|
|
1129
1176
|
cmd = ""
|
|
1130
|
-
|
|
1177
|
+
ruff_check = "ruff check --extend-select=I,B,SIM" + " --fix" * ruff_check_fix
|
|
1178
|
+
tools = ["ruff format", ruff_check, "mypy"]
|
|
1131
1179
|
if check_only:
|
|
1132
1180
|
tools[0] += " --check"
|
|
1133
1181
|
if check_only or load_bool("NO_FIX"):
|
|
@@ -1256,6 +1304,7 @@ class LintCode(DryRun):
|
|
|
1256
1304
|
ruff_check_sim=self._sim,
|
|
1257
1305
|
mypy_strict=self._strict,
|
|
1258
1306
|
prefer_ty=self._ty,
|
|
1307
|
+
ruff_check_fix=self._fix,
|
|
1259
1308
|
)
|
|
1260
1309
|
|
|
1261
1310
|
|
|
@@ -1275,6 +1324,7 @@ def lint(
|
|
|
1275
1324
|
sim: bool = True,
|
|
1276
1325
|
strict: bool = False,
|
|
1277
1326
|
ty: bool = False,
|
|
1327
|
+
fix: bool = True,
|
|
1278
1328
|
) -> None:
|
|
1279
1329
|
if files is None:
|
|
1280
1330
|
files = parse_files(sys.argv[1:])
|
|
@@ -1292,6 +1342,7 @@ def lint(
|
|
|
1292
1342
|
sim=sim,
|
|
1293
1343
|
strict=strict,
|
|
1294
1344
|
ty=ty,
|
|
1345
|
+
fix=fix,
|
|
1295
1346
|
).run()
|
|
1296
1347
|
|
|
1297
1348
|
|
|
@@ -1343,6 +1394,7 @@ def make_style(
|
|
|
1343
1394
|
sim: bool = Option(True, help="Whether ruff check with --extend-select=SIM"),
|
|
1344
1395
|
strict: bool = Option(False, help="Whether run mypy with --strict"),
|
|
1345
1396
|
ty: bool = Option(False, help="Whether use ty instead of mypy"),
|
|
1397
|
+
fix: bool | None = Option(None, help="Whether ruff check with --fix"),
|
|
1346
1398
|
) -> None:
|
|
1347
1399
|
"""Run: ruff check/format to reformat code and then mypy to check"""
|
|
1348
1400
|
if getattr(files, "default", files) is None:
|
|
@@ -1352,13 +1404,18 @@ def make_style(
|
|
|
1352
1404
|
skip = _ensure_bool(skip_mypy)
|
|
1353
1405
|
dmypy = _ensure_bool(use_dmypy)
|
|
1354
1406
|
bandit = _ensure_bool(bandit)
|
|
1355
|
-
|
|
1356
|
-
tool = _ensure_str(tool)
|
|
1407
|
+
tool = _ensure_str(tool) or ""
|
|
1357
1408
|
up = _ensure_bool(up)
|
|
1358
1409
|
sim = _ensure_bool(sim)
|
|
1359
1410
|
strict = _ensure_bool(strict)
|
|
1360
1411
|
kwargs = {"dry": dry, "skip_mypy": skip, "dmypy": dmypy, "bandit": bandit}
|
|
1361
|
-
|
|
1412
|
+
if _ensure_bool(check_only):
|
|
1413
|
+
run = check
|
|
1414
|
+
else:
|
|
1415
|
+
prefix = _ensure_bool(prefix)
|
|
1416
|
+
if fix is None or not isinstance(fix, bool):
|
|
1417
|
+
fix = load_bool("FASTDEVCLI_FIX", True)
|
|
1418
|
+
run = functools.partial(lint, prefix=prefix, fix=fix)
|
|
1362
1419
|
run(files, tool=tool, up=up, sim=sim, strict=strict, ty=ty, **kwargs)
|
|
1363
1420
|
|
|
1364
1421
|
|
|
@@ -1396,7 +1453,9 @@ class Sync(DryRun):
|
|
|
1396
1453
|
if should_remove or not is_venv():
|
|
1397
1454
|
raise EnvError("There project is not managed by uv/pdm/poetry!")
|
|
1398
1455
|
return f"python -m pip install -r {self.filename}"
|
|
1399
|
-
prefix = ""
|
|
1456
|
+
prefix = ""
|
|
1457
|
+
if not is_venv():
|
|
1458
|
+
prefix = f"{tool} run " + "--no-sync " * (tool == "uv")
|
|
1400
1459
|
ensure_pip = " {1}python -m ensurepip && {1}python -m pip install -U pip &&"
|
|
1401
1460
|
export_cmd = "uv export --no-hashes --all-extras --all-groups --frozen"
|
|
1402
1461
|
if tool in ("poetry", "pdm"):
|
|
@@ -1492,30 +1551,86 @@ def upload(
|
|
|
1492
1551
|
exit_if_run_failed(cmd, dry=dry)
|
|
1493
1552
|
|
|
1494
1553
|
|
|
1554
|
+
def should_use_just() -> bool:
|
|
1555
|
+
if shutil.which("just") is None:
|
|
1556
|
+
return False
|
|
1557
|
+
d = Path.cwd()
|
|
1558
|
+
for _ in range(5):
|
|
1559
|
+
f = d / "justfile"
|
|
1560
|
+
if f.exists():
|
|
1561
|
+
text = f.read_text(encoding="utf-8")
|
|
1562
|
+
return any(i.startswith("dev *args:") for i in text.splitlines())
|
|
1563
|
+
if d.joinpath("pyproject.toml").exists():
|
|
1564
|
+
break
|
|
1565
|
+
return False
|
|
1566
|
+
|
|
1567
|
+
|
|
1495
1568
|
def dev(
|
|
1496
1569
|
port: int | None | OptionInfo,
|
|
1497
1570
|
host: str | None | OptionInfo,
|
|
1571
|
+
fastapi: bool | None = None,
|
|
1572
|
+
uvicorn: bool | None = None,
|
|
1573
|
+
prod: bool | None = None,
|
|
1574
|
+
reload: bool | None = None,
|
|
1498
1575
|
file: str | None | ArgumentInfo = None,
|
|
1499
1576
|
dry: bool = False,
|
|
1500
1577
|
) -> None:
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1578
|
+
if should_use_just():
|
|
1579
|
+
args = [i for i in sys.argv[2:] if i != "--dry"]
|
|
1580
|
+
cmd = "just dev"
|
|
1581
|
+
else:
|
|
1582
|
+
cmd = "uvicorn" if uvicorn else "fastapi dev"
|
|
1583
|
+
args = []
|
|
1584
|
+
if (host := getattr(host, "default", host)) and host not in (
|
|
1585
|
+
"localhost",
|
|
1586
|
+
"127.0.0.1",
|
|
1587
|
+
):
|
|
1588
|
+
args.append(f"--host={host}")
|
|
1589
|
+
no_port_yet = True
|
|
1590
|
+
if file is not None:
|
|
1591
|
+
try:
|
|
1592
|
+
port = int(str(file))
|
|
1593
|
+
except ValueError:
|
|
1594
|
+
if m := re.search(r"(.*):(\d+)$", str(file)):
|
|
1595
|
+
h, p = m.group(1), m.group(2)
|
|
1596
|
+
if h and "--host" not in str(args):
|
|
1597
|
+
if h == "0":
|
|
1598
|
+
args.append("--host=0.0.0.0")
|
|
1599
|
+
else:
|
|
1600
|
+
args.append(f"--host={h}")
|
|
1601
|
+
args.append(f"--port={p}")
|
|
1602
|
+
if uvicorn:
|
|
1603
|
+
p = Path("main.py")
|
|
1604
|
+
if p.exists():
|
|
1605
|
+
cmd += " main:app"
|
|
1606
|
+
elif Path("app", p.name).exists():
|
|
1607
|
+
cmd += " app.main:app"
|
|
1608
|
+
elif Path("app.py").exists():
|
|
1609
|
+
cmd += " app:app"
|
|
1610
|
+
else:
|
|
1611
|
+
if uvicorn and (
|
|
1612
|
+
(filepath := Path(str(file))).is_file()
|
|
1613
|
+
or filepath.suffix == ".py"
|
|
1614
|
+
):
|
|
1615
|
+
file = filepath.stem + ":app"
|
|
1616
|
+
parent_names = [j for i in filepath.parents if (j := i.name)]
|
|
1617
|
+
if parent_names:
|
|
1618
|
+
file = ".".join([*parent_names[::-1], file])
|
|
1619
|
+
cmd += f" {file}"
|
|
1620
|
+
else:
|
|
1621
|
+
if port != 8000:
|
|
1622
|
+
args.append(f"--port={port}")
|
|
1623
|
+
no_port_yet = False
|
|
1624
|
+
if (
|
|
1625
|
+
no_port_yet
|
|
1626
|
+
and (port := getattr(port, "default", port))
|
|
1627
|
+
and str(port) != "8000"
|
|
1628
|
+
):
|
|
1629
|
+
args.append(f"--port={port}")
|
|
1630
|
+
if shutil.which("pdm") is not None:
|
|
1631
|
+
cmd = "pdm run " + cmd
|
|
1632
|
+
if args:
|
|
1633
|
+
cmd += " " + " ".join(args)
|
|
1519
1634
|
exit_if_run_failed(cmd, dry=dry)
|
|
1520
1635
|
|
|
1521
1636
|
|
|
@@ -1524,13 +1639,18 @@ def runserver(
|
|
|
1524
1639
|
file_or_port: str | None = typer.Argument(default=None),
|
|
1525
1640
|
port: int | None = Option(None, "-p", "--port"),
|
|
1526
1641
|
host: str | None = Option(None, "-h", "--host"),
|
|
1642
|
+
fastapi: bool | None = None,
|
|
1643
|
+
uvicorn: bool | None = None,
|
|
1644
|
+
prod: bool | None = None,
|
|
1645
|
+
reload: bool | None = None,
|
|
1527
1646
|
dry: bool = DryOption,
|
|
1528
1647
|
) -> None:
|
|
1529
1648
|
"""Start a fastapi server(only for fastapi>=0.111.0)"""
|
|
1649
|
+
f = functools.partial(dev, port, host, fastapi, uvicorn, prod, reload, dry=dry)
|
|
1530
1650
|
if getattr(file_or_port, "default", file_or_port):
|
|
1531
|
-
|
|
1651
|
+
f(file=file_or_port)
|
|
1532
1652
|
else:
|
|
1533
|
-
|
|
1653
|
+
f()
|
|
1534
1654
|
|
|
1535
1655
|
|
|
1536
1656
|
@cli.command(name="exec")
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = [
|
|
3
|
-
"pdm-backend",
|
|
4
|
-
]
|
|
5
|
-
build-backend = "pdm.backend"
|
|
6
|
-
|
|
7
1
|
[project]
|
|
8
2
|
name = "fast-dev-cli"
|
|
9
3
|
dynamic = []
|
|
@@ -34,28 +28,41 @@ classifiers = [
|
|
|
34
28
|
dependencies = [
|
|
35
29
|
"typer>=0.24.0,<1",
|
|
36
30
|
"tomli >=2.0.1,<3; python_version < '3.11'",
|
|
37
|
-
"coverage >=7.5.1",
|
|
38
|
-
"pytest >=8.2.0",
|
|
39
31
|
]
|
|
40
|
-
version = "0.
|
|
32
|
+
version = "0.22.0"
|
|
41
33
|
|
|
42
34
|
[project.urls]
|
|
43
35
|
Homepage = "https://github.com/waketzheng/fast-dev-cli"
|
|
44
36
|
|
|
45
37
|
[project.optional-dependencies]
|
|
46
|
-
|
|
47
|
-
"
|
|
38
|
+
standard = [
|
|
39
|
+
"coverage >=7.5.1",
|
|
40
|
+
"pytest >=8.2.0",
|
|
41
|
+
]
|
|
42
|
+
all = [
|
|
43
|
+
"emoji >=2.12.1",
|
|
44
|
+
"packaging >=20.5",
|
|
45
|
+
"bandit>=1.7.9",
|
|
46
|
+
"pytest-mock >=3.14.0",
|
|
47
|
+
"fast-dev-cli[standard]",
|
|
48
48
|
]
|
|
49
49
|
|
|
50
50
|
[project.scripts]
|
|
51
|
-
fast = "fast_dev_cli:
|
|
51
|
+
fast = "fast_dev_cli.cli:main"
|
|
52
52
|
|
|
53
53
|
[dependency-groups]
|
|
54
54
|
dev = [
|
|
55
55
|
"twine>=6.1.0",
|
|
56
56
|
"asynctor>=0.10.0",
|
|
57
|
+
"mypy>=1.19.1",
|
|
57
58
|
]
|
|
58
59
|
|
|
60
|
+
[build-system]
|
|
61
|
+
requires = [
|
|
62
|
+
"pdm-backend",
|
|
63
|
+
]
|
|
64
|
+
build-backend = "pdm.backend"
|
|
65
|
+
|
|
59
66
|
[tool.pdm]
|
|
60
67
|
distribution = true
|
|
61
68
|
|
|
@@ -63,24 +70,14 @@ distribution = true
|
|
|
63
70
|
source = "file"
|
|
64
71
|
path = "fast_dev_cli/__init__.py"
|
|
65
72
|
|
|
66
|
-
[tool.pdm.build]
|
|
67
|
-
source-includes = [
|
|
68
|
-
"scripts/",
|
|
69
|
-
]
|
|
70
|
-
|
|
71
|
-
[tool.pdm.dev-dependencies]
|
|
72
|
-
dev = [
|
|
73
|
-
"-e file:///${PROJECT_ROOT}/#egg=fast-dev-cli[all]",
|
|
74
|
-
]
|
|
75
|
-
|
|
76
73
|
[tool.pdm.scripts]
|
|
77
|
-
up = "
|
|
74
|
+
up = "just up {args}"
|
|
78
75
|
tree = "pdm list --tree {args}"
|
|
79
|
-
deps = "
|
|
76
|
+
deps = "just deps {args}"
|
|
80
77
|
prod = "pdm install --prod --frozen {args}"
|
|
81
78
|
test = "pdm run fast test {args}"
|
|
82
|
-
lint = "
|
|
83
|
-
check = "
|
|
79
|
+
lint = "just lint {args}"
|
|
80
|
+
check = "just check {args}"
|
|
84
81
|
tag = "pdm run fast tag {args}"
|
|
85
82
|
bump = "pdm run fast bump patch --commit {args}"
|
|
86
83
|
|
|
@@ -99,7 +96,7 @@ composite = [
|
|
|
99
96
|
|
|
100
97
|
[tool.pdm.scripts.start]
|
|
101
98
|
composite = [
|
|
102
|
-
"
|
|
99
|
+
"prek install",
|
|
103
100
|
"deps",
|
|
104
101
|
]
|
|
105
102
|
|
|
@@ -109,25 +106,6 @@ composite = [
|
|
|
109
106
|
"ruff check --fix --unsafe-fixes {args}",
|
|
110
107
|
]
|
|
111
108
|
|
|
112
|
-
[tool.waketzheng._internal-slim-build.packages.fastdevcli-slim.project]
|
|
113
|
-
name = "fastdevcli-slim"
|
|
114
|
-
|
|
115
|
-
[tool.waketzheng._internal-slim-build.packages.fastdevcli-slim.project.scripts]
|
|
116
|
-
fast = "fast_dev_cli:cli.main"
|
|
117
|
-
|
|
118
|
-
[tool.waketzheng._internal-slim-build.packages.fast-dev-cli]
|
|
119
|
-
include-optional-dependencies = [
|
|
120
|
-
"standard",
|
|
121
|
-
]
|
|
122
|
-
|
|
123
|
-
[tool.waketzheng._internal-slim-build.packages.fast-dev-cli.project.optional-dependencies]
|
|
124
|
-
include-optional-dependencies = [
|
|
125
|
-
"all",
|
|
126
|
-
]
|
|
127
|
-
|
|
128
|
-
[tool.waketzheng._internal-slim-build.packages.fast-dev-cli.project.scripts]
|
|
129
|
-
fast = "fast_dev_cli:cli.main"
|
|
130
|
-
|
|
131
109
|
[tool.pytest.ini_options]
|
|
132
110
|
testpaths = [
|
|
133
111
|
"tests",
|
|
@@ -402,3 +402,23 @@ build-backend = "pdm.backend"
|
|
|
402
402
|
out = capture_cmd_output("fast bump patch")
|
|
403
403
|
assert version_file.as_posix() in out
|
|
404
404
|
assert "0.3.1" in version_file.read_text()
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def test_package_dot_json(tmp_work_dir):
|
|
408
|
+
p = Path("package.json")
|
|
409
|
+
p.write_text('{"version":"0.1.0"}', encoding="utf-8")
|
|
410
|
+
out = capture_cmd_output("fast bump patch")
|
|
411
|
+
assert p.name in out
|
|
412
|
+
assert "0.1.1" in p.read_text()
|
|
413
|
+
out = capture_cmd_output("fast bump patch --commit --dry")
|
|
414
|
+
assert (
|
|
415
|
+
'bumpversion --parse "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)" --current-version="0.1.1" patch package.json --commit'
|
|
416
|
+
in out
|
|
417
|
+
)
|
|
418
|
+
run_and_echo("git init")
|
|
419
|
+
run_and_echo("git add .")
|
|
420
|
+
run_and_echo("git config user.name xxx")
|
|
421
|
+
run_and_echo("git config user.email xxx@a.com")
|
|
422
|
+
run_and_echo('git commit -m "xxx"')
|
|
423
|
+
out = capture_cmd_output("fast tag --dry")
|
|
424
|
+
assert "git tag -a 0.1.1 -m '' && git push --tags" in out
|
|
@@ -30,7 +30,7 @@ def test_make_deps_class():
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def test_fast_deps():
|
|
33
|
-
out = capture_cmd_output("fast deps --dry")
|
|
33
|
+
out = capture_cmd_output("fast deps --pdm --dry")
|
|
34
34
|
assert out == "--> pdm install --frozen -G :all"
|
|
35
35
|
out = capture_cmd_output("fast deps --uv --prod --dry")
|
|
36
36
|
assert out == "--> uv sync --inexact --active"
|
|
@@ -42,6 +42,7 @@ def test_cli_test(mocker, capsys):
|
|
|
42
42
|
def test_test_with_pdm_run(mocker: MockerFixture, capsys):
|
|
43
43
|
mocker.patch("fast_dev_cli.cli.check_call", return_value=False)
|
|
44
44
|
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=None)
|
|
45
|
+
mocker.patch("fast_dev_cli.cli.Project.get_manage_tool", return_value="pdm")
|
|
45
46
|
unitcase(dry=True)
|
|
46
47
|
assert (
|
|
47
48
|
'--> pdm run coverage run -m pytest -s && pdm run coverage report --omit="tests/*" -m'
|