fast-dev-cli 0.21.1__tar.gz → 0.23.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.1 → fast_dev_cli-0.23.0}/PKG-INFO +15 -10
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/README.md +5 -5
- fast_dev_cli-0.23.0/fast_dev_cli/__init__.py +1 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/fast_dev_cli/cli.py +128 -51
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/pyproject.toml +23 -47
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_deps.py +26 -2
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_fast_test.py +1 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_functions.py +5 -4
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_lint.py +87 -38
- fast_dev_cli-0.23.0/tests/test_runserver.py +136 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_sync.py +14 -8
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_tag.py +1 -1
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_upgrade.py +4 -3
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_upload.py +1 -1
- fast_dev_cli-0.21.1/fast_dev_cli/__init__.py +0 -1
- fast_dev_cli-0.21.1/pdm_build.py +0 -39
- fast_dev_cli-0.21.1/scripts/check.py +0 -30
- fast_dev_cli-0.21.1/scripts/deps.py +0 -156
- fast_dev_cli-0.21.1/scripts/format.py +0 -13
- fast_dev_cli-0.21.1/scripts/test.py +0 -48
- fast_dev_cli-0.21.1/tests/test_runserver.py +0 -97
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/LICENSE +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/fast_dev_cli/__main__.py +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/fast_dev_cli/py.typed +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/__init__.py +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/assets/uv-tx.lock +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/assets/uv-upload-time.lock +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/assets/uv.lock +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/conftest.py +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_bump.py +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_exec.py +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_help.py +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_poetry_version_plugin.py +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_pypi.py +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.0}/tests/test_version.py +0 -0
- {fast_dev_cli-0.21.1 → fast_dev_cli-0.23.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.23.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">
|
|
@@ -90,8 +95,8 @@ Python 3.10+
|
|
|
90
95
|
<div class="termy">
|
|
91
96
|
|
|
92
97
|
```bash
|
|
93
|
-
uv tool install
|
|
94
|
-
# Or: pipx install
|
|
98
|
+
uv tool install fast-dev-cli
|
|
99
|
+
# Or: pipx install fast-dev-cli
|
|
95
100
|
```
|
|
96
101
|
*Will create a `fast` command in ~/.local/bin
|
|
97
102
|
|
|
@@ -102,7 +107,7 @@ uv tool install --python 3.14 fastdevcli-slim
|
|
|
102
107
|
<div class="termy">
|
|
103
108
|
|
|
104
109
|
```bash
|
|
105
|
-
pip install fast-dev-cli
|
|
110
|
+
pip install "fast-dev-cli[standard]"
|
|
106
111
|
```
|
|
107
112
|
*Will install: fast-dev-cli emoji typer packaging pytest coverage*
|
|
108
113
|
|
|
@@ -118,7 +123,7 @@ fast lint [/path/to/file-or-directory]
|
|
|
118
123
|
```bash
|
|
119
124
|
fast check
|
|
120
125
|
```
|
|
121
|
-
- Bump up version in pyproject.toml
|
|
126
|
+
- Bump up version in pyproject.toml(or package.json)
|
|
122
127
|
```bash
|
|
123
128
|
fast bump patch # 0.1.0 -> 0.1.1
|
|
124
129
|
fast bump minor # 0.1.0 -> 0.2.0
|
|
@@ -146,7 +151,7 @@ fast pypi
|
|
|
146
151
|
## Use it without installed
|
|
147
152
|
|
|
148
153
|
```bash
|
|
149
|
-
uvx --from
|
|
154
|
+
uvx --from fast-dev-cli fast
|
|
150
155
|
```
|
|
151
156
|
|
|
152
157
|
## Lint/Check by ty instead of mypy
|
|
@@ -59,8 +59,8 @@ Python 3.10+
|
|
|
59
59
|
<div class="termy">
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
uv tool install
|
|
63
|
-
# Or: pipx install
|
|
62
|
+
uv tool install fast-dev-cli
|
|
63
|
+
# Or: pipx install fast-dev-cli
|
|
64
64
|
```
|
|
65
65
|
*Will create a `fast` command in ~/.local/bin
|
|
66
66
|
|
|
@@ -71,7 +71,7 @@ uv tool install --python 3.14 fastdevcli-slim
|
|
|
71
71
|
<div class="termy">
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
|
-
pip install fast-dev-cli
|
|
74
|
+
pip install "fast-dev-cli[standard]"
|
|
75
75
|
```
|
|
76
76
|
*Will install: fast-dev-cli emoji typer packaging pytest coverage*
|
|
77
77
|
|
|
@@ -87,7 +87,7 @@ fast lint [/path/to/file-or-directory]
|
|
|
87
87
|
```bash
|
|
88
88
|
fast check
|
|
89
89
|
```
|
|
90
|
-
- Bump up version in pyproject.toml
|
|
90
|
+
- Bump up version in pyproject.toml(or package.json)
|
|
91
91
|
```bash
|
|
92
92
|
fast bump patch # 0.1.0 -> 0.1.1
|
|
93
93
|
fast bump minor # 0.1.0 -> 0.2.0
|
|
@@ -115,7 +115,7 @@ fast pypi
|
|
|
115
115
|
## Use it without installed
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
|
-
uvx --from
|
|
118
|
+
uvx --from fast-dev-cli fast
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
## Lint/Check by ty instead of mypy
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.23.0"
|
|
@@ -15,7 +15,6 @@ from pathlib import Path
|
|
|
15
15
|
from typing import TYPE_CHECKING, Any, Literal, cast, get_args, overload
|
|
16
16
|
|
|
17
17
|
import typer
|
|
18
|
-
from click import UsageError
|
|
19
18
|
from typer import Exit, Option, echo, secho
|
|
20
19
|
from typer.models import ArgumentInfo, OptionInfo
|
|
21
20
|
|
|
@@ -98,6 +97,14 @@ def is_windows() -> bool:
|
|
|
98
97
|
return platform.system() == "Windows"
|
|
99
98
|
|
|
100
99
|
|
|
100
|
+
@functools.cache
|
|
101
|
+
def prefer_uv_tool() -> bool:
|
|
102
|
+
if shutil.which("uv") is None:
|
|
103
|
+
return False
|
|
104
|
+
cmd = "uv tool list"
|
|
105
|
+
return Shell(cmd).capture_output() != "No tools installed"
|
|
106
|
+
|
|
107
|
+
|
|
101
108
|
def yellow_warn(msg: str) -> None:
|
|
102
109
|
if is_windows() and (encoding := sys.stdout.encoding) != "utf-8":
|
|
103
110
|
msg = msg.encode(encoding, errors="ignore").decode(encoding)
|
|
@@ -281,7 +288,7 @@ def _get_frontend_version() -> tuple[Path, str] | None:
|
|
|
281
288
|
except ImportError:
|
|
282
289
|
from json import loads as json_loads # type:ignore[assignment]
|
|
283
290
|
content = frontend_version_file.read_bytes()
|
|
284
|
-
metadata: dict[str, str] = json_loads(content) # type:ignore
|
|
291
|
+
metadata: dict[str, str] = json_loads(content) # type:ignore
|
|
285
292
|
try:
|
|
286
293
|
current_version = metadata["version"]
|
|
287
294
|
except (KeyError, TypeError):
|
|
@@ -1078,7 +1085,7 @@ class GitTag(DryRun):
|
|
|
1078
1085
|
|
|
1079
1086
|
def run(self) -> None:
|
|
1080
1087
|
if self.mark_tag() and not self.dry:
|
|
1081
|
-
echo("You may want to publish package:\n
|
|
1088
|
+
echo("You may want to publish package:\n pdm publish")
|
|
1082
1089
|
|
|
1083
1090
|
|
|
1084
1091
|
@cli.command()
|
|
@@ -1173,17 +1180,21 @@ class LintCode(DryRun):
|
|
|
1173
1180
|
) -> str:
|
|
1174
1181
|
if paths != "." and all(i.endswith(".html") for i in paths.split()):
|
|
1175
1182
|
return f"prettier -w {paths}"
|
|
1176
|
-
|
|
1177
|
-
|
|
1183
|
+
ruff_rules = ["I", "B"]
|
|
1184
|
+
if ruff_check_sim and not load_bool("FASTDEVCLI_NO_SIM"):
|
|
1185
|
+
ruff_rules.append("SIM")
|
|
1186
|
+
if ruff_check_up or load_bool("FASTDEVCLI_UP"):
|
|
1187
|
+
ruff_rules.append("UP")
|
|
1188
|
+
ruff_check = "ruff check --extend-select=" + ",".join(ruff_rules)
|
|
1189
|
+
if (
|
|
1190
|
+
ruff_check_fix
|
|
1191
|
+
and not check_only
|
|
1192
|
+
and (not load_bool("NO_FIX") and not load_bool("FASTDEVCLI_NO_FIX"))
|
|
1193
|
+
):
|
|
1194
|
+
ruff_check += " --fix"
|
|
1178
1195
|
tools = ["ruff format", ruff_check, "mypy"]
|
|
1179
1196
|
if check_only:
|
|
1180
1197
|
tools[0] += " --check"
|
|
1181
|
-
if check_only or load_bool("NO_FIX"):
|
|
1182
|
-
tools[1] = tools[1].replace(" --fix", "")
|
|
1183
|
-
if ruff_check_up or load_bool("FASTDEVCLI_UP"):
|
|
1184
|
-
tools[1] = tools[1].replace(",SIM", ",SIM,UP")
|
|
1185
|
-
if not ruff_check_sim or load_bool("FASTDEVCLI_NO_SIM"):
|
|
1186
|
-
tools[1] = tools[1].replace(",SIM", "")
|
|
1187
1198
|
if skip_mypy or load_bool("SKIP_MYPY") or load_bool("FASTDEVCLI_NO_MYPY"):
|
|
1188
1199
|
# Sometimes mypy is too slow
|
|
1189
1200
|
tools = tools[:-1]
|
|
@@ -1195,23 +1206,11 @@ class LintCode(DryRun):
|
|
|
1195
1206
|
tools[-1] += " --ignore-missing-imports"
|
|
1196
1207
|
if mypy_strict or load_bool("FASTDEVCLI_STRICT"):
|
|
1197
1208
|
tools[-1] += " --strict"
|
|
1198
|
-
|
|
1199
|
-
"{0}{" + str(i) + "} {1}" for i in range(2, len(tools) + 2)
|
|
1200
|
-
)
|
|
1201
|
-
if ruff_exists := cls.check_lint_tool_installed():
|
|
1202
|
-
# `ruff <command>` get the same result with `pdm run ruff <command>`
|
|
1203
|
-
# While `mypy .`(installed global and env not activated),
|
|
1204
|
-
# does not the same as `pdm run mypy .`
|
|
1205
|
-
lint_them = " && ".join(
|
|
1206
|
-
("" if tool.startswith("ruff") else "{0}")
|
|
1207
|
-
+ (
|
|
1208
|
-
"{%d} {1}" % i # noqa: UP031
|
|
1209
|
-
)
|
|
1210
|
-
for i, tool in enumerate(tools, 2)
|
|
1211
|
-
)
|
|
1209
|
+
ruff_exists = cls.check_lint_tool_installed()
|
|
1212
1210
|
prefix = ""
|
|
1213
1211
|
should_run_by_tool = with_prefix
|
|
1214
|
-
|
|
1212
|
+
requires_mypy = any(tool.startswith("mypy") for tool in tools)
|
|
1213
|
+
if requires_mypy and not should_run_by_tool:
|
|
1215
1214
|
if is_venv() and Path(sys.argv[0]).parent != Path.home().joinpath(
|
|
1216
1215
|
".local/bin"
|
|
1217
1216
|
): # Virtual environment activated and fast-dev-cli is installed in it
|
|
@@ -1221,6 +1220,8 @@ class LintCode(DryRun):
|
|
|
1221
1220
|
if shutil.which("pipx") is None:
|
|
1222
1221
|
ensure_pipx = "pip install --user pipx\n pipx ensurepath\n "
|
|
1223
1222
|
command = ensure_pipx + command
|
|
1223
|
+
elif prefer_uv_tool():
|
|
1224
|
+
command = "uv tool install ruff"
|
|
1224
1225
|
yellow_warn(
|
|
1225
1226
|
"You may need to run the following command"
|
|
1226
1227
|
f" to install ruff:\n\n {command}\n"
|
|
@@ -1228,7 +1229,7 @@ class LintCode(DryRun):
|
|
|
1228
1229
|
elif cls.missing_mypy_exec():
|
|
1229
1230
|
should_run_by_tool = True
|
|
1230
1231
|
if check_call('python -c "import fast_dev_cli"'):
|
|
1231
|
-
command =
|
|
1232
|
+
command = "python -m pip install -U mypy"
|
|
1232
1233
|
yellow_warn(
|
|
1233
1234
|
"You may need to run the following command"
|
|
1234
1235
|
f" to install lint tools:\n\n {command}\n"
|
|
@@ -1255,7 +1256,17 @@ class LintCode(DryRun):
|
|
|
1255
1256
|
prefix = bin_dir
|
|
1256
1257
|
if cls.prefer_dmypy(paths, tools, use_dmypy=use_dmypy):
|
|
1257
1258
|
tools[-1] = "dmypy run"
|
|
1258
|
-
cmd
|
|
1259
|
+
cmd = " && ".join(
|
|
1260
|
+
(
|
|
1261
|
+
tool
|
|
1262
|
+
# `ruff <command>` get the same result with `pdm run ruff <command>`.
|
|
1263
|
+
# Other tools should run inside the selected environment.
|
|
1264
|
+
if ruff_exists and tool.startswith("ruff")
|
|
1265
|
+
else prefix + tool
|
|
1266
|
+
)
|
|
1267
|
+
+ f" {paths}"
|
|
1268
|
+
for tool in tools
|
|
1269
|
+
)
|
|
1259
1270
|
if bandit or load_bool("FASTDEVCLI_BANDIT"):
|
|
1260
1271
|
command = prefix + "bandit"
|
|
1261
1272
|
if Path("pyproject.toml").exists():
|
|
@@ -1453,7 +1464,9 @@ class Sync(DryRun):
|
|
|
1453
1464
|
if should_remove or not is_venv():
|
|
1454
1465
|
raise EnvError("There project is not managed by uv/pdm/poetry!")
|
|
1455
1466
|
return f"python -m pip install -r {self.filename}"
|
|
1456
|
-
prefix = ""
|
|
1467
|
+
prefix = ""
|
|
1468
|
+
if not is_venv():
|
|
1469
|
+
prefix = f"{tool} run " + "--no-sync " * (tool == "uv")
|
|
1457
1470
|
ensure_pip = " {1}python -m ensurepip && {1}python -m pip install -U pip &&"
|
|
1458
1471
|
export_cmd = "uv export --no-hashes --all-extras --all-groups --frozen"
|
|
1459
1472
|
if tool in ("poetry", "pdm"):
|
|
@@ -1549,30 +1562,86 @@ def upload(
|
|
|
1549
1562
|
exit_if_run_failed(cmd, dry=dry)
|
|
1550
1563
|
|
|
1551
1564
|
|
|
1565
|
+
def should_use_just() -> bool:
|
|
1566
|
+
if shutil.which("just") is None:
|
|
1567
|
+
return False
|
|
1568
|
+
d = Path.cwd()
|
|
1569
|
+
for _ in range(5):
|
|
1570
|
+
f = d / "justfile"
|
|
1571
|
+
if f.exists():
|
|
1572
|
+
text = f.read_text(encoding="utf-8")
|
|
1573
|
+
return any(i.startswith("dev *args:") for i in text.splitlines())
|
|
1574
|
+
if d.joinpath("pyproject.toml").exists():
|
|
1575
|
+
break
|
|
1576
|
+
return False
|
|
1577
|
+
|
|
1578
|
+
|
|
1552
1579
|
def dev(
|
|
1553
1580
|
port: int | None | OptionInfo,
|
|
1554
1581
|
host: str | None | OptionInfo,
|
|
1582
|
+
fastapi: bool | None = None,
|
|
1583
|
+
uvicorn: bool | None = None,
|
|
1584
|
+
prod: bool | None = None,
|
|
1585
|
+
reload: bool | None = None,
|
|
1555
1586
|
file: str | None | ArgumentInfo = None,
|
|
1556
1587
|
dry: bool = False,
|
|
1557
1588
|
) -> None:
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1589
|
+
if should_use_just():
|
|
1590
|
+
args = [i for i in sys.argv[2:] if i != "--dry"]
|
|
1591
|
+
cmd = "just dev"
|
|
1592
|
+
else:
|
|
1593
|
+
cmd = "uvicorn" if uvicorn else "fastapi dev"
|
|
1594
|
+
args = []
|
|
1595
|
+
if (host := getattr(host, "default", host)) and host not in (
|
|
1596
|
+
"localhost",
|
|
1597
|
+
"127.0.0.1",
|
|
1598
|
+
):
|
|
1599
|
+
args.append(f"--host={host}")
|
|
1600
|
+
no_port_yet = True
|
|
1601
|
+
if file is not None:
|
|
1602
|
+
try:
|
|
1603
|
+
port = int(str(file))
|
|
1604
|
+
except ValueError:
|
|
1605
|
+
if m := re.search(r"(.*):(\d+)$", str(file)):
|
|
1606
|
+
h, p = m.group(1), m.group(2)
|
|
1607
|
+
if h and "--host" not in str(args):
|
|
1608
|
+
if h == "0":
|
|
1609
|
+
args.append("--host=0.0.0.0")
|
|
1610
|
+
else:
|
|
1611
|
+
args.append(f"--host={h}")
|
|
1612
|
+
args.append(f"--port={p}")
|
|
1613
|
+
if uvicorn:
|
|
1614
|
+
p = Path("main.py")
|
|
1615
|
+
if p.exists():
|
|
1616
|
+
cmd += " main:app"
|
|
1617
|
+
elif Path("app", p.name).exists():
|
|
1618
|
+
cmd += " app.main:app"
|
|
1619
|
+
elif Path("app.py").exists():
|
|
1620
|
+
cmd += " app:app"
|
|
1621
|
+
else:
|
|
1622
|
+
if uvicorn and (
|
|
1623
|
+
(filepath := Path(str(file))).is_file()
|
|
1624
|
+
or filepath.suffix == ".py"
|
|
1625
|
+
):
|
|
1626
|
+
file = filepath.stem + ":app"
|
|
1627
|
+
parent_names = [j for i in filepath.parents if (j := i.name)]
|
|
1628
|
+
if parent_names:
|
|
1629
|
+
file = ".".join([*parent_names[::-1], file])
|
|
1630
|
+
cmd += f" {file}"
|
|
1631
|
+
else:
|
|
1632
|
+
if port != 8000:
|
|
1633
|
+
args.append(f"--port={port}")
|
|
1634
|
+
no_port_yet = False
|
|
1635
|
+
if (
|
|
1636
|
+
no_port_yet
|
|
1637
|
+
and (port := getattr(port, "default", port))
|
|
1638
|
+
and str(port) != "8000"
|
|
1639
|
+
):
|
|
1640
|
+
args.append(f"--port={port}")
|
|
1641
|
+
if shutil.which("pdm") is not None:
|
|
1642
|
+
cmd = "pdm run " + cmd
|
|
1643
|
+
if args:
|
|
1644
|
+
cmd += " " + " ".join(args)
|
|
1576
1645
|
exit_if_run_failed(cmd, dry=dry)
|
|
1577
1646
|
|
|
1578
1647
|
|
|
@@ -1581,13 +1650,18 @@ def runserver(
|
|
|
1581
1650
|
file_or_port: str | None = typer.Argument(default=None),
|
|
1582
1651
|
port: int | None = Option(None, "-p", "--port"),
|
|
1583
1652
|
host: str | None = Option(None, "-h", "--host"),
|
|
1653
|
+
fastapi: bool | None = None,
|
|
1654
|
+
uvicorn: bool | None = None,
|
|
1655
|
+
prod: bool | None = None,
|
|
1656
|
+
reload: bool | None = None,
|
|
1584
1657
|
dry: bool = DryOption,
|
|
1585
1658
|
) -> None:
|
|
1586
1659
|
"""Start a fastapi server(only for fastapi>=0.111.0)"""
|
|
1660
|
+
f = functools.partial(dev, port, host, fastapi, uvicorn, prod, reload, dry=dry)
|
|
1587
1661
|
if getattr(file_or_port, "default", file_or_port):
|
|
1588
|
-
|
|
1662
|
+
f(file=file_or_port)
|
|
1589
1663
|
else:
|
|
1590
|
-
|
|
1664
|
+
f()
|
|
1591
1665
|
|
|
1592
1666
|
|
|
1593
1667
|
@cli.command(name="exec")
|
|
@@ -1654,7 +1728,7 @@ class MakeDeps(DryRun):
|
|
|
1654
1728
|
if self.should_ensure_pip():
|
|
1655
1729
|
cmd = f"python -m ensurepip && {upgrade} && {cmd}"
|
|
1656
1730
|
elif self.should_upgrade_pip():
|
|
1657
|
-
cmd = "{upgrade} && {cmd}"
|
|
1731
|
+
cmd = f"{upgrade} && {cmd}"
|
|
1658
1732
|
return cmd
|
|
1659
1733
|
|
|
1660
1734
|
|
|
@@ -1680,7 +1754,10 @@ def make_deps(
|
|
|
1680
1754
|
) -> None:
|
|
1681
1755
|
"""Run: ruff check/format to reformat code and then mypy to check"""
|
|
1682
1756
|
if use_uv + use_pdm + use_pip + use_poetry > 1:
|
|
1683
|
-
raise
|
|
1757
|
+
raise typer.BadParameter(
|
|
1758
|
+
"can only choose one",
|
|
1759
|
+
param_hint=("--uv", "--pdm", "--pip", "--poetry"),
|
|
1760
|
+
)
|
|
1684
1761
|
if use_uv:
|
|
1685
1762
|
tool = "uv"
|
|
1686
1763
|
elif use_pdm:
|
|
@@ -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,39 @@ 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.23.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
|
-
"twine>=6.1.0",
|
|
56
55
|
"asynctor>=0.10.0",
|
|
57
56
|
]
|
|
58
57
|
|
|
58
|
+
[build-system]
|
|
59
|
+
requires = [
|
|
60
|
+
"pdm-backend",
|
|
61
|
+
]
|
|
62
|
+
build-backend = "pdm.backend"
|
|
63
|
+
|
|
59
64
|
[tool.pdm]
|
|
60
65
|
distribution = true
|
|
61
66
|
|
|
@@ -63,24 +68,14 @@ distribution = true
|
|
|
63
68
|
source = "file"
|
|
64
69
|
path = "fast_dev_cli/__init__.py"
|
|
65
70
|
|
|
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
71
|
[tool.pdm.scripts]
|
|
77
|
-
up = "
|
|
72
|
+
up = "just up {args}"
|
|
78
73
|
tree = "pdm list --tree {args}"
|
|
79
|
-
deps = "
|
|
74
|
+
deps = "just deps {args}"
|
|
80
75
|
prod = "pdm install --prod --frozen {args}"
|
|
81
76
|
test = "pdm run fast test {args}"
|
|
82
|
-
lint = "
|
|
83
|
-
check = "
|
|
77
|
+
lint = "just lint {args}"
|
|
78
|
+
check = "just check {args}"
|
|
84
79
|
tag = "pdm run fast tag {args}"
|
|
85
80
|
bump = "pdm run fast bump patch --commit {args}"
|
|
86
81
|
|
|
@@ -99,7 +94,7 @@ composite = [
|
|
|
99
94
|
|
|
100
95
|
[tool.pdm.scripts.start]
|
|
101
96
|
composite = [
|
|
102
|
-
"
|
|
97
|
+
"prek install",
|
|
103
98
|
"deps",
|
|
104
99
|
]
|
|
105
100
|
|
|
@@ -109,25 +104,6 @@ composite = [
|
|
|
109
104
|
"ruff check --fix --unsafe-fixes {args}",
|
|
110
105
|
]
|
|
111
106
|
|
|
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
107
|
[tool.pytest.ini_options]
|
|
132
108
|
testpaths = [
|
|
133
109
|
"tests",
|
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from fast_dev_cli.cli import MakeDeps, capture_cmd_output, run_and_echo
|
|
4
|
+
|
|
5
|
+
ANSI_RE = re.compile(r"\x1b\[[0-9;]*m")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def strip_ansi(text: str) -> str:
|
|
9
|
+
return ANSI_RE.sub("", text)
|
|
2
10
|
|
|
3
11
|
|
|
4
12
|
def test_make_deps_class():
|
|
13
|
+
class PipDepsWithoutEnsure(MakeDeps):
|
|
14
|
+
def should_ensure_pip(self) -> bool:
|
|
15
|
+
return False
|
|
16
|
+
|
|
5
17
|
assert (
|
|
6
18
|
MakeDeps("uv", prod=False).gen()
|
|
7
19
|
== "uv sync --inexact --active --all-extras --all-groups"
|
|
@@ -27,10 +39,14 @@ def test_make_deps_class():
|
|
|
27
39
|
MakeDeps("pip", prod=True).gen()
|
|
28
40
|
== "python -m ensurepip && python -m pip install --upgrade pip && python -m pip install -e ."
|
|
29
41
|
)
|
|
42
|
+
assert (
|
|
43
|
+
PipDepsWithoutEnsure("pip", prod=False).gen()
|
|
44
|
+
== "python -m pip install --upgrade pip && python -m pip install -e . --group dev"
|
|
45
|
+
)
|
|
30
46
|
|
|
31
47
|
|
|
32
48
|
def test_fast_deps():
|
|
33
|
-
out = capture_cmd_output("fast deps --dry")
|
|
49
|
+
out = capture_cmd_output("fast deps --pdm --dry")
|
|
34
50
|
assert out == "--> pdm install --frozen -G :all"
|
|
35
51
|
out = capture_cmd_output("fast deps --uv --prod --dry")
|
|
36
52
|
assert out == "--> uv sync --inexact --active"
|
|
@@ -50,6 +66,14 @@ def test_fast_deps():
|
|
|
50
66
|
assert out == "--> uv sync --all-extras --all-groups"
|
|
51
67
|
|
|
52
68
|
|
|
69
|
+
def test_fast_deps_mutually_exclusive_options():
|
|
70
|
+
cmd = "fast deps --uv --pdm --dry"
|
|
71
|
+
assert run_and_echo(cmd, verbose=False) == 2
|
|
72
|
+
out = strip_ansi(capture_cmd_output(cmd))
|
|
73
|
+
assert "Invalid value for '--uv' / '--pdm' / '--pip' / '--poetry'" in out
|
|
74
|
+
assert "can only choose" in out
|
|
75
|
+
|
|
76
|
+
|
|
53
77
|
def test_smart_fast_deps(tmp_work_dir, monkeypatch):
|
|
54
78
|
toml_file = tmp_work_dir.joinpath("pyproject.toml")
|
|
55
79
|
if toml_file.exists():
|
|
@@ -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'
|
|
@@ -4,7 +4,8 @@ from io import StringIO
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
6
|
import pytest
|
|
7
|
-
import
|
|
7
|
+
from typer import Exit as TyperExit
|
|
8
|
+
from typer import Option
|
|
8
9
|
|
|
9
10
|
from fast_dev_cli.cli import (
|
|
10
11
|
DryRun,
|
|
@@ -85,7 +86,7 @@ def test_run_shell():
|
|
|
85
86
|
)
|
|
86
87
|
with pytest.raises(FileNotFoundError):
|
|
87
88
|
exit_if_run_failed("in_valid_command", _exit=True, capture_output=True)
|
|
88
|
-
with pytest.raises(
|
|
89
|
+
with pytest.raises(TyperExit):
|
|
89
90
|
exit_if_run_failed(
|
|
90
91
|
"in_valid_command", _exit=False, capture_output=True, shell=True
|
|
91
92
|
)
|
|
@@ -111,8 +112,8 @@ def test_get_version_in_poetry_project(tmp_path: Path):
|
|
|
111
112
|
def test_ensure_bool():
|
|
112
113
|
assert _ensure_bool(True) is True
|
|
113
114
|
assert _ensure_bool(False) is False
|
|
114
|
-
opt =
|
|
115
|
+
opt = Option(False, "--check-only", "-c")
|
|
115
116
|
assert opt
|
|
116
117
|
assert _ensure_bool(opt) is False
|
|
117
|
-
opt =
|
|
118
|
+
opt = Option(True, "--check-only", "-c")
|
|
118
119
|
assert _ensure_bool(opt) is True
|