fast-dev-cli 0.17.1__tar.gz → 0.17.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.
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/PKG-INFO +6 -6
- fast_dev_cli-0.17.3/fast_dev_cli/__init__.py +1 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/fast_dev_cli/cli.py +213 -15
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/pyproject.toml +6 -8
- fast_dev_cli-0.17.3/tests/test_deps.py +33 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_help.py +1 -1
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_lint.py +11 -3
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_version.py +4 -4
- fast_dev_cli-0.17.1/fast_dev_cli/__init__.py +0 -1
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/LICENSE +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/README.md +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/fast_dev_cli/__main__.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/fast_dev_cli/py.typed +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/pdm_build.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/scripts/check.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/scripts/deps.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/scripts/format.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/scripts/test.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/__init__.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/conftest.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_bump.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_exec.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_fast_test.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_functions.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_poetry_version_plugin.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_runserver.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_sync.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_tag.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_upgrade.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/test_upload.py +0 -0
- {fast_dev_cli-0.17.1 → fast_dev_cli-0.17.3}/tests/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fast-dev-cli
|
|
3
|
-
Version: 0.17.
|
|
3
|
+
Version: 0.17.3
|
|
4
4
|
Summary: Python project development tool.
|
|
5
5
|
Author-Email: Waket Zheng <waketzheng@gmail.com>>
|
|
6
6
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -24,12 +24,12 @@ Project-URL: Homepage, https://github.com/waketzheng/fast-dev-cli
|
|
|
24
24
|
Requires-Python: >=3.9
|
|
25
25
|
Requires-Dist: typer<1,>=0.12.3
|
|
26
26
|
Requires-Dist: tomli<3,>=2.0.1; python_version < "3.11"
|
|
27
|
-
Requires-Dist: emoji
|
|
27
|
+
Requires-Dist: emoji>=2.12.1
|
|
28
28
|
Requires-Dist: packaging>=20.5
|
|
29
|
-
Requires-Dist: coverage
|
|
30
|
-
Requires-Dist: mypy
|
|
31
|
-
Requires-Dist: bumpversion2
|
|
32
|
-
Requires-Dist: pytest
|
|
29
|
+
Requires-Dist: coverage>=7.5.1
|
|
30
|
+
Requires-Dist: mypy>=1.15.0
|
|
31
|
+
Requires-Dist: bumpversion2>=1.4.3
|
|
32
|
+
Requires-Dist: pytest>=8.2.0
|
|
33
33
|
Provides-Extra: include-optional-dependencies
|
|
34
34
|
Requires-Dist: all; extra == "include-optional-dependencies"
|
|
35
35
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.17.3"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import contextlib
|
|
4
|
+
import functools
|
|
4
5
|
import importlib.metadata as importlib_metadata
|
|
5
6
|
import os
|
|
6
7
|
import re
|
|
@@ -21,6 +22,7 @@ from typing import (
|
|
|
21
22
|
)
|
|
22
23
|
|
|
23
24
|
import typer
|
|
25
|
+
from click import UsageError
|
|
24
26
|
from typer import Exit, Option, echo, secho
|
|
25
27
|
from typer.models import ArgumentInfo, OptionInfo
|
|
26
28
|
|
|
@@ -89,6 +91,10 @@ def is_emoji(char: str) -> bool:
|
|
|
89
91
|
return not "\u4e00" <= char <= "\u9fff" # Chinese character
|
|
90
92
|
|
|
91
93
|
|
|
94
|
+
def yellow_warn(msg: str) -> None:
|
|
95
|
+
secho(msg, fg="yellow")
|
|
96
|
+
|
|
97
|
+
|
|
92
98
|
def load_bool(name: str, default: bool = False) -> bool:
|
|
93
99
|
if not (v := os.getenv(name)):
|
|
94
100
|
return default
|
|
@@ -281,7 +287,7 @@ def exit_if_run_failed(
|
|
|
281
287
|
|
|
282
288
|
class DryRun:
|
|
283
289
|
def __init__(self, _exit: bool = False, dry: bool = False) -> None:
|
|
284
|
-
self.dry = dry
|
|
290
|
+
self.dry = _ensure_bool(dry)
|
|
285
291
|
self._exit = _exit
|
|
286
292
|
|
|
287
293
|
def gen(self) -> str:
|
|
@@ -922,6 +928,7 @@ class LintCode(DryRun):
|
|
|
922
928
|
skip_mypy: bool = False,
|
|
923
929
|
dmypy: bool = False,
|
|
924
930
|
tool: str = ToolOption.default,
|
|
931
|
+
prefix: bool = False,
|
|
925
932
|
) -> None:
|
|
926
933
|
self.args = args
|
|
927
934
|
self.check_only = check_only
|
|
@@ -929,6 +936,7 @@ class LintCode(DryRun):
|
|
|
929
936
|
self._skip_mypy = skip_mypy
|
|
930
937
|
self._use_dmypy = dmypy
|
|
931
938
|
self._tool = tool
|
|
939
|
+
self._prefix = prefix
|
|
932
940
|
super().__init__(_exit, dry)
|
|
933
941
|
|
|
934
942
|
@staticmethod
|
|
@@ -962,6 +970,7 @@ class LintCode(DryRun):
|
|
|
962
970
|
skip_mypy: bool = False,
|
|
963
971
|
use_dmypy: bool = False,
|
|
964
972
|
tool: str = ToolOption.default,
|
|
973
|
+
with_prefix: bool = False,
|
|
965
974
|
) -> str:
|
|
966
975
|
if paths != "." and all(i.endswith(".html") for i in paths.split()):
|
|
967
976
|
return f"prettier -w {paths}"
|
|
@@ -991,23 +1000,28 @@ class LintCode(DryRun):
|
|
|
991
1000
|
for i, tool in enumerate(tools, 2)
|
|
992
1001
|
)
|
|
993
1002
|
prefix = ""
|
|
994
|
-
should_run_by_tool =
|
|
995
|
-
if
|
|
996
|
-
if
|
|
1003
|
+
should_run_by_tool = with_prefix
|
|
1004
|
+
if not should_run_by_tool:
|
|
1005
|
+
if is_venv() and Path(sys.argv[0]).parent != Path.home().joinpath(
|
|
1006
|
+
".local/bin"
|
|
1007
|
+
):
|
|
1008
|
+
if not ruff_exists:
|
|
1009
|
+
should_run_by_tool = True
|
|
1010
|
+
if check_call('python -c "import fast_dev_cli"'):
|
|
1011
|
+
command = 'python -m pip install -U "fast-dev-cli"'
|
|
1012
|
+
yellow_warn(
|
|
1013
|
+
"You may need to run the following command"
|
|
1014
|
+
f" to install lint tools:\n\n {command}\n"
|
|
1015
|
+
)
|
|
1016
|
+
else:
|
|
997
1017
|
should_run_by_tool = True
|
|
998
|
-
if check_call('python -c "import fast_dev_cli"'):
|
|
999
|
-
command = 'python -m pip install -U "fast-dev-cli"'
|
|
1000
|
-
tip = "You may need to run following command to install lint tools:"
|
|
1001
|
-
secho(f"{tip}\n\n {command}\n", fg="yellow")
|
|
1002
|
-
else:
|
|
1003
|
-
should_run_by_tool = True
|
|
1004
1018
|
if should_run_by_tool and tool:
|
|
1005
1019
|
if tool == ToolOption.default:
|
|
1006
1020
|
tool = Project.get_manage_tool() or ""
|
|
1007
1021
|
if tool:
|
|
1008
1022
|
prefix = (
|
|
1009
|
-
|
|
1010
|
-
if tool == "uv" and (bin_dir :=
|
|
1023
|
+
bin_dir
|
|
1024
|
+
if tool == "uv" and Path(bin_dir := ".venv/bin/").exists()
|
|
1011
1025
|
else (tool + " run ")
|
|
1012
1026
|
)
|
|
1013
1027
|
if cls.prefer_dmypy(paths, tools, use_dmypy=use_dmypy):
|
|
@@ -1030,7 +1044,13 @@ class LintCode(DryRun):
|
|
|
1030
1044
|
args = args.split()
|
|
1031
1045
|
paths = " ".join(map(str, args)) if args else "."
|
|
1032
1046
|
return self.to_cmd(
|
|
1033
|
-
paths,
|
|
1047
|
+
paths,
|
|
1048
|
+
self.check_only,
|
|
1049
|
+
self._bandit,
|
|
1050
|
+
self._skip_mypy,
|
|
1051
|
+
self._use_dmypy,
|
|
1052
|
+
tool=self._tool,
|
|
1053
|
+
with_prefix=self._prefix,
|
|
1034
1054
|
)
|
|
1035
1055
|
|
|
1036
1056
|
|
|
@@ -1045,13 +1065,20 @@ def lint(
|
|
|
1045
1065
|
skip_mypy: bool = False,
|
|
1046
1066
|
dmypy: bool = False,
|
|
1047
1067
|
tool: str = ToolOption.default,
|
|
1068
|
+
prefix: bool = False,
|
|
1048
1069
|
) -> None:
|
|
1049
1070
|
if files is None:
|
|
1050
1071
|
files = parse_files(sys.argv[1:])
|
|
1051
1072
|
if files and files[0] == "lint":
|
|
1052
1073
|
files = files[1:]
|
|
1053
1074
|
LintCode(
|
|
1054
|
-
files,
|
|
1075
|
+
files,
|
|
1076
|
+
dry=dry,
|
|
1077
|
+
skip_mypy=skip_mypy,
|
|
1078
|
+
bandit=bandit,
|
|
1079
|
+
dmypy=dmypy,
|
|
1080
|
+
tool=tool,
|
|
1081
|
+
prefix=prefix,
|
|
1055
1082
|
).run()
|
|
1056
1083
|
|
|
1057
1084
|
|
|
@@ -1080,6 +1107,11 @@ def make_style(
|
|
|
1080
1107
|
files: Optional[list[str]] = typer.Argument(default=None), # noqa:B008
|
|
1081
1108
|
check_only: bool = Option(False, "--check-only", "-c"),
|
|
1082
1109
|
bandit: bool = Option(False, "--bandit", help="Run `bandit -r <package_dir>`"),
|
|
1110
|
+
prefix: bool = Option(
|
|
1111
|
+
False,
|
|
1112
|
+
"--prefix",
|
|
1113
|
+
help="Run lint command with tool prefix, e.g.: pdm run ruff ...",
|
|
1114
|
+
),
|
|
1083
1115
|
skip_mypy: bool = Option(False, "--skip-mypy"),
|
|
1084
1116
|
use_dmypy: bool = Option(
|
|
1085
1117
|
False, "--dmypy", help="Use `dmypy run` instead of `mypy`"
|
|
@@ -1095,11 +1127,20 @@ def make_style(
|
|
|
1095
1127
|
skip = _ensure_bool(skip_mypy)
|
|
1096
1128
|
dmypy = _ensure_bool(use_dmypy)
|
|
1097
1129
|
bandit = _ensure_bool(bandit)
|
|
1130
|
+
prefix = _ensure_bool(prefix)
|
|
1098
1131
|
tool = _ensure_str(tool)
|
|
1099
1132
|
if _ensure_bool(check_only):
|
|
1100
1133
|
check(files, dry=dry, skip_mypy=skip, dmypy=dmypy, bandit=bandit, tool=tool)
|
|
1101
1134
|
else:
|
|
1102
|
-
lint(
|
|
1135
|
+
lint(
|
|
1136
|
+
files,
|
|
1137
|
+
dry=dry,
|
|
1138
|
+
skip_mypy=skip,
|
|
1139
|
+
dmypy=dmypy,
|
|
1140
|
+
bandit=bandit,
|
|
1141
|
+
tool=tool,
|
|
1142
|
+
prefix=prefix,
|
|
1143
|
+
)
|
|
1103
1144
|
|
|
1104
1145
|
|
|
1105
1146
|
@cli.command(name="check")
|
|
@@ -1278,6 +1319,163 @@ def run_by_subprocess(cmd: str, dry: bool = DryOption) -> None:
|
|
|
1278
1319
|
raise Exit(rc)
|
|
1279
1320
|
|
|
1280
1321
|
|
|
1322
|
+
class MakeDeps(DryRun):
|
|
1323
|
+
def __init__(self, tool: str, prod: bool = False, dry: bool = False) -> None:
|
|
1324
|
+
self._tool = tool
|
|
1325
|
+
self._prod = prod
|
|
1326
|
+
super().__init__(dry=dry)
|
|
1327
|
+
|
|
1328
|
+
def should_ensure_pip(self) -> bool:
|
|
1329
|
+
return True
|
|
1330
|
+
|
|
1331
|
+
def should_upgrade_pip(self) -> bool:
|
|
1332
|
+
return True
|
|
1333
|
+
|
|
1334
|
+
def get_groups(self) -> list[str]:
|
|
1335
|
+
if self._prod:
|
|
1336
|
+
return []
|
|
1337
|
+
return ["dev"]
|
|
1338
|
+
|
|
1339
|
+
def gen(self) -> str:
|
|
1340
|
+
if self._tool == "pdm":
|
|
1341
|
+
return "pdm sync " + ("--prod" if self._prod else "-G :all")
|
|
1342
|
+
elif self._tool == "uv":
|
|
1343
|
+
return "uv sync --inexact --active" + (
|
|
1344
|
+
"" if self._prod else " --all-extras --all-groups"
|
|
1345
|
+
)
|
|
1346
|
+
elif self._tool == "poetry":
|
|
1347
|
+
return "poetry install " + (
|
|
1348
|
+
"--only=main" if self._prod else "--all-extras --all-groups"
|
|
1349
|
+
)
|
|
1350
|
+
else:
|
|
1351
|
+
cmd = "python -m pip install -e ."
|
|
1352
|
+
if gs := self.get_groups():
|
|
1353
|
+
cmd += " " + " ".join(f"--group {g}" for g in gs)
|
|
1354
|
+
upgrade = "python -m pip install --upgrade pip"
|
|
1355
|
+
if self.should_ensure_pip():
|
|
1356
|
+
cmd = f"python -m ensurepip && {upgrade} && {cmd}"
|
|
1357
|
+
elif self.should_upgrade_pip():
|
|
1358
|
+
cmd = "{upgrade} && {cmd}"
|
|
1359
|
+
return cmd
|
|
1360
|
+
|
|
1361
|
+
|
|
1362
|
+
@cli.command(name="deps")
|
|
1363
|
+
def make_deps(
|
|
1364
|
+
prod: bool = Option(
|
|
1365
|
+
False,
|
|
1366
|
+
"--prod",
|
|
1367
|
+
help="Only instead production dependencies.",
|
|
1368
|
+
),
|
|
1369
|
+
tool: str = ToolOption,
|
|
1370
|
+
use_uv: bool = Option(False, "--uv", help="Use `uv` to install deps"),
|
|
1371
|
+
use_pdm: bool = Option(False, "--pdm", help="Use `pdm` to install deps"),
|
|
1372
|
+
use_pip: bool = Option(False, "--pip", help="Use `pip` to install deps"),
|
|
1373
|
+
use_poetry: bool = Option(False, "--poetry", help="Use `poetry` to install deps"),
|
|
1374
|
+
dry: bool = DryOption,
|
|
1375
|
+
) -> None:
|
|
1376
|
+
"""Run: ruff check/format to reformat code and then mypy to check"""
|
|
1377
|
+
if use_uv + use_pdm + use_pip + use_poetry > 1:
|
|
1378
|
+
raise UsageError("`--uv/--pdm/--pip/--poetry` can only choose one!")
|
|
1379
|
+
if use_uv:
|
|
1380
|
+
tool = "uv"
|
|
1381
|
+
elif use_pdm:
|
|
1382
|
+
tool = "pdm"
|
|
1383
|
+
elif use_pip:
|
|
1384
|
+
tool = "pip"
|
|
1385
|
+
elif use_poetry:
|
|
1386
|
+
tool = "poetry"
|
|
1387
|
+
elif tool == ToolOption.default:
|
|
1388
|
+
tool = Project.get_manage_tool(cache=True) or "pip"
|
|
1389
|
+
MakeDeps(tool, prod, dry=dry).run()
|
|
1390
|
+
|
|
1391
|
+
|
|
1392
|
+
class UvPypi(DryRun):
|
|
1393
|
+
PYPI = "https://pypi.org/simple"
|
|
1394
|
+
HOST = "https://files.pythonhosted.org"
|
|
1395
|
+
|
|
1396
|
+
def __init__(self, lock_file: Path, dry: bool, verbose: bool, quiet: bool) -> None:
|
|
1397
|
+
super().__init__(dry=dry)
|
|
1398
|
+
self.lock_file = lock_file
|
|
1399
|
+
self._verbose = _ensure_bool(verbose)
|
|
1400
|
+
self._quiet = _ensure_bool(quiet)
|
|
1401
|
+
|
|
1402
|
+
def run(self) -> None:
|
|
1403
|
+
try:
|
|
1404
|
+
rc = self.update_lock(self.lock_file, self._verbose, self._quiet)
|
|
1405
|
+
except ValueError as e:
|
|
1406
|
+
secho(str(e), fg=typer.colors.RED)
|
|
1407
|
+
raise Exit(1) from e
|
|
1408
|
+
else:
|
|
1409
|
+
if rc != 0:
|
|
1410
|
+
raise Exit(rc)
|
|
1411
|
+
|
|
1412
|
+
@classmethod
|
|
1413
|
+
def update_lock(cls, p: Path, verbose: bool, quiet: bool) -> int:
|
|
1414
|
+
text = p.read_text("utf-8")
|
|
1415
|
+
registry_pattern = r'(registry = ")(.*?)"'
|
|
1416
|
+
replace_registry = functools.partial(
|
|
1417
|
+
re.sub, registry_pattern, rf'\1{cls.PYPI}"'
|
|
1418
|
+
)
|
|
1419
|
+
registry_urls = {i[1] for i in re.findall(registry_pattern, text)}
|
|
1420
|
+
download_pattern = r'(url = ")(https?://.*?)(/packages/.*?\.)(gz|whl)"'
|
|
1421
|
+
replace_host = functools.partial(
|
|
1422
|
+
re.sub, download_pattern, rf'\1{cls.HOST}\3\4"'
|
|
1423
|
+
)
|
|
1424
|
+
download_hosts = {i[1] for i in re.findall(download_pattern, text)}
|
|
1425
|
+
if not registry_urls:
|
|
1426
|
+
raise ValueError(f"Failed to find pattern {registry_pattern!r} in {p}")
|
|
1427
|
+
if len(registry_urls) == 1:
|
|
1428
|
+
current_registry = registry_urls.pop()
|
|
1429
|
+
if current_registry == cls.PYPI:
|
|
1430
|
+
if download_hosts == {cls.HOST}:
|
|
1431
|
+
if verbose:
|
|
1432
|
+
echo(f"Registry of {p} is {cls.PYPI}, no need to change.")
|
|
1433
|
+
return 0
|
|
1434
|
+
else:
|
|
1435
|
+
text = replace_registry(text)
|
|
1436
|
+
if verbose:
|
|
1437
|
+
echo(f"{current_registry} --> {cls.PYPI}")
|
|
1438
|
+
else:
|
|
1439
|
+
# TODO: ask each one to confirm replace
|
|
1440
|
+
text = replace_registry(text)
|
|
1441
|
+
if verbose:
|
|
1442
|
+
for current_registry in sorted(registry_urls):
|
|
1443
|
+
echo(f"{current_registry} --> {cls.PYPI}")
|
|
1444
|
+
if len(download_hosts) == 1:
|
|
1445
|
+
current_host = download_hosts.pop()
|
|
1446
|
+
if current_host != cls.HOST:
|
|
1447
|
+
text = replace_host(text)
|
|
1448
|
+
if verbose:
|
|
1449
|
+
print(current_host, "-->", cls.HOST)
|
|
1450
|
+
elif download_hosts:
|
|
1451
|
+
# TODO: ask each one to confirm replace
|
|
1452
|
+
text = replace_host(text)
|
|
1453
|
+
if verbose:
|
|
1454
|
+
for current_host in sorted(download_hosts):
|
|
1455
|
+
echo(f"{current_host} --> {cls.HOST}")
|
|
1456
|
+
size = p.write_text(text, encoding="utf-8")
|
|
1457
|
+
if verbose:
|
|
1458
|
+
echo(f"Updated {p} with {size} bytes.")
|
|
1459
|
+
if quiet:
|
|
1460
|
+
return 0
|
|
1461
|
+
return 1
|
|
1462
|
+
|
|
1463
|
+
|
|
1464
|
+
@cli.command()
|
|
1465
|
+
def pypi(
|
|
1466
|
+
dry: bool = DryOption,
|
|
1467
|
+
verbose: bool = False,
|
|
1468
|
+
quiet: bool = False,
|
|
1469
|
+
) -> None:
|
|
1470
|
+
"""Change registry of uv.lock to be pypi.org"""
|
|
1471
|
+
if not (p := Path("uv.lock")).exists() and not (
|
|
1472
|
+
(p := Project.get_work_dir() / p.name).exists()
|
|
1473
|
+
):
|
|
1474
|
+
yellow_warn(f"{p.name!r} not found!")
|
|
1475
|
+
return
|
|
1476
|
+
UvPypi(p, dry, verbose, quiet).run()
|
|
1477
|
+
|
|
1478
|
+
|
|
1281
1479
|
def version_callback(value: bool) -> None:
|
|
1282
1480
|
if value:
|
|
1283
1481
|
echo("Fast Dev Cli Version: " + typer.style(__version__, bold=True))
|
|
@@ -35,14 +35,14 @@ classifiers = [
|
|
|
35
35
|
dependencies = [
|
|
36
36
|
"typer >=0.12.3,<1",
|
|
37
37
|
"tomli >=2.0.1,<3; python_version < '3.11'",
|
|
38
|
-
"emoji >=2.12.1
|
|
38
|
+
"emoji >=2.12.1",
|
|
39
39
|
"packaging >=20.5",
|
|
40
|
-
"coverage >=7.5.1
|
|
41
|
-
"mypy >=1.15.0
|
|
42
|
-
"bumpversion2 >=1.4.3
|
|
43
|
-
"pytest >=8.2.0
|
|
40
|
+
"coverage >=7.5.1",
|
|
41
|
+
"mypy >=1.15.0",
|
|
42
|
+
"bumpversion2 >=1.4.3",
|
|
43
|
+
"pytest >=8.2.0",
|
|
44
44
|
]
|
|
45
|
-
version = "0.17.
|
|
45
|
+
version = "0.17.3"
|
|
46
46
|
|
|
47
47
|
[project.urls]
|
|
48
48
|
Homepage = "https://github.com/waketzheng/fast-dev-cli"
|
|
@@ -58,8 +58,6 @@ fast = "fast_dev_cli:cli.main"
|
|
|
58
58
|
[dependency-groups]
|
|
59
59
|
dev = [
|
|
60
60
|
"twine>=6.1.0",
|
|
61
|
-
]
|
|
62
|
-
test = [
|
|
63
61
|
"asynctor>=0.8.6",
|
|
64
62
|
]
|
|
65
63
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from fast_dev_cli.cli import MakeDeps, capture_cmd_output
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_make_deps_class():
|
|
5
|
+
assert (
|
|
6
|
+
MakeDeps("uv", prod=False).gen()
|
|
7
|
+
== "uv sync --inexact --active --all-extras --all-groups"
|
|
8
|
+
)
|
|
9
|
+
assert MakeDeps("uv", prod=True).gen() == "uv sync --inexact --active"
|
|
10
|
+
assert MakeDeps("pdm", prod=False).gen() == "pdm sync -G :all"
|
|
11
|
+
assert MakeDeps("pdm", prod=True).gen() == "pdm sync --prod"
|
|
12
|
+
assert (
|
|
13
|
+
MakeDeps("poetry", prod=False).gen()
|
|
14
|
+
== "poetry install --all-extras --all-groups"
|
|
15
|
+
)
|
|
16
|
+
assert MakeDeps("poetry", prod=True).gen() == "poetry install --only=main"
|
|
17
|
+
assert (
|
|
18
|
+
MakeDeps("pip", prod=False).gen()
|
|
19
|
+
== "python -m ensurepip && python -m pip install --upgrade pip && python -m pip install -e . --group dev"
|
|
20
|
+
)
|
|
21
|
+
assert (
|
|
22
|
+
MakeDeps("pip", prod=True).gen()
|
|
23
|
+
== "python -m ensurepip && python -m pip install --upgrade pip && python -m pip install -e ."
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_fast_deps():
|
|
28
|
+
out = capture_cmd_output("fast deps --dry")
|
|
29
|
+
assert out == "--> pdm sync -G :all"
|
|
30
|
+
out = capture_cmd_output("fast deps --uv --prod --dry")
|
|
31
|
+
assert out == "--> uv sync --inexact --active"
|
|
32
|
+
out = capture_cmd_output("fast deps --uv --dry")
|
|
33
|
+
assert out == "--> uv sync --inexact --active --all-extras --all-groups"
|
|
@@ -99,7 +99,7 @@ def test_check_bandit(tmp_path):
|
|
|
99
99
|
assert "bandit -r ." in command
|
|
100
100
|
|
|
101
101
|
|
|
102
|
-
def test_check_skip_mypy(mock_skip_mypy_0, mocker
|
|
102
|
+
def test_check_skip_mypy(mock_skip_mypy_0, mocker):
|
|
103
103
|
cmd = "fast check --skip-mypy --dry"
|
|
104
104
|
cmd2 = "fast lint --check-only --skip-mypy --dry"
|
|
105
105
|
mocker.patch("fast_dev_cli.cli.is_venv", return_value=True)
|
|
@@ -187,6 +187,14 @@ def test_lint_with_prefix(mocker):
|
|
|
187
187
|
assert "pdm run" in stream.getvalue()
|
|
188
188
|
|
|
189
189
|
|
|
190
|
+
def test_fast_lint_with_uv():
|
|
191
|
+
command = capture_cmd_output("fast lint --tool=uv --prefix --dry")
|
|
192
|
+
assert (
|
|
193
|
+
command
|
|
194
|
+
== "--> ruff format . && ruff check --extend-select=I,B,SIM --fix . && .venv/bin/mypy ."
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
190
198
|
def test_make_style(mock_skip_mypy_0, mocker, mock_no_dmypy):
|
|
191
199
|
mocker.patch("fast_dev_cli.cli.is_venv", return_value=True)
|
|
192
200
|
with capture_stdout() as stream:
|
|
@@ -239,7 +247,7 @@ def test_lint_without_ruff_installed(mocker, mock_no_dmypy):
|
|
|
239
247
|
output = stream.getvalue()
|
|
240
248
|
cmd = 'python -m pip install -U "fast-dev-cli"'
|
|
241
249
|
assert cmd in output
|
|
242
|
-
tip = "You may need to run following command to install lint tools"
|
|
250
|
+
tip = "You may need to run the following command to install lint tools"
|
|
243
251
|
assert tip in output
|
|
244
252
|
assert f"{tip}:\n\n {cmd}" in output
|
|
245
253
|
|
|
@@ -263,7 +271,7 @@ def test_skip_mypy_option(mock_skip_mypy_0, mocker):
|
|
|
263
271
|
)
|
|
264
272
|
|
|
265
273
|
|
|
266
|
-
def test_skip_mypy_fast_lint(mock_skip_mypy_0, mocker
|
|
274
|
+
def test_skip_mypy_fast_lint(mock_skip_mypy_0, mocker):
|
|
267
275
|
mocker.patch("fast_dev_cli.cli.is_venv", return_value=True)
|
|
268
276
|
command = capture_cmd_output("fast lint --skip-mypy --dry")
|
|
269
277
|
cmds = LINT_CMD.split(SEP)
|
|
@@ -67,12 +67,12 @@ def test_display_self_version(capsys):
|
|
|
67
67
|
version_callback(True)
|
|
68
68
|
assert __version__ in capsys.readouterr().out
|
|
69
69
|
out = Shell("fast --version").capture_output().strip()
|
|
70
|
-
assert out == "Fast Dev Cli Version:
|
|
70
|
+
assert out == f"Fast Dev Cli Version: {__version__}"
|
|
71
71
|
out_v = Shell("fast -V").capture_output().strip()
|
|
72
72
|
assert out_v == out
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def test_fast_version(
|
|
75
|
+
def test_fast_version():
|
|
76
76
|
out = Shell("fast version").capture_output().strip()
|
|
77
|
-
assert "Fast Dev Cli Version:
|
|
78
|
-
assert "fast_dev_cli/__init__.py:
|
|
77
|
+
assert f"Fast Dev Cli Version: {__version__}" in out
|
|
78
|
+
assert f"fast_dev_cli/__init__.py: {__version__}" in out
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.17.1"
|
|
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
|