fast-dev-cli 0.9.10__tar.gz → 0.10.1__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.9.10 → fast_dev_cli-0.10.1}/PKG-INFO +5 -5
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/README.md +2 -2
- fast_dev_cli-0.10.1/fast_dev_cli/__init__.py +1 -0
- fast_dev_cli-0.10.1/fast_dev_cli/__main__.py +3 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/fast_dev_cli/cli.py +44 -14
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/pyproject.toml +2 -2
- fast_dev_cli-0.10.1/scripts/check.py +19 -0
- fast_dev_cli-0.10.1/scripts/format.py +14 -0
- fast_dev_cli-0.10.1/scripts/test.py +47 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/test_fast_test.py +35 -17
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/test_functions.py +6 -1
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/test_lint.py +31 -1
- fast_dev_cli-0.10.1/tests/test_poetry_version_plugin.py +70 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/test_runserver.py +14 -1
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/test_tag.py +7 -1
- fast_dev_cli-0.9.10/fast_dev_cli/__init__.py +0 -1
- fast_dev_cli-0.9.10/fast_dev_cli/__main__.py +0 -3
- fast_dev_cli-0.9.10/scripts/check.sh +0 -11
- fast_dev_cli-0.9.10/scripts/format.sh +0 -6
- fast_dev_cli-0.9.10/scripts/test.sh +0 -6
- fast_dev_cli-0.9.10/tests/test_poetry_version_plugin.py +0 -62
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/LICENSE +0 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/fast_dev_cli/py.typed +0 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/pdm_build.py +0 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/__init__.py +0 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/conftest.py +0 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/test_bump.py +0 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/test_sync.py +0 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/test_upgrade.py +0 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/test_upload.py +0 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/tests/test_version.py +0 -0
- {fast_dev_cli-0.9.10 → fast_dev_cli-0.10.1}/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.10.1
|
|
4
4
|
Summary: Python project development tool.
|
|
5
5
|
Author-Email: Waket Zheng <waketzheng@gmail.com>>
|
|
6
6
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -24,13 +24,13 @@ Requires-Dist: typer<0.13,>=0.12.3
|
|
|
24
24
|
Requires-Dist: emoji<3,>=2.12.1
|
|
25
25
|
Requires-Dist: tomli<3,>=2.0.1; python_version < "3.11"
|
|
26
26
|
Requires-Dist: coverage<8,>=7.5.1
|
|
27
|
-
Requires-Dist: ruff<0.
|
|
27
|
+
Requires-Dist: ruff<0.8,>=0.4.4
|
|
28
28
|
Requires-Dist: mypy<2,>=1.10.0
|
|
29
29
|
Requires-Dist: bumpversion2<2,>=1.4.2
|
|
30
30
|
Requires-Dist: pytest<9,>=8.2.0
|
|
31
|
+
Provides-Extra: all
|
|
31
32
|
Requires-Dist: ipython<9,>=8.24.0; extra == "all"
|
|
32
33
|
Requires-Dist: pytest-mock<4,>=3.14.0; extra == "all"
|
|
33
|
-
Provides-Extra: all
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
|
|
36
36
|
<p align="center">
|
|
@@ -78,9 +78,9 @@ Python 3.10+
|
|
|
78
78
|
<div class="termy">
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
pip install
|
|
81
|
+
pip install fast-dev-cli
|
|
82
82
|
```
|
|
83
|
-
*Will install: fast-dev-cli typer ruff mypy
|
|
83
|
+
*Will install: fast-dev-cli emoji typer ruff mypy bumpversion2 pytest coverage*
|
|
84
84
|
|
|
85
85
|
</div>
|
|
86
86
|
|
|
@@ -43,9 +43,9 @@ Python 3.10+
|
|
|
43
43
|
<div class="termy">
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
pip install
|
|
46
|
+
pip install fast-dev-cli
|
|
47
47
|
```
|
|
48
|
-
*Will install: fast-dev-cli typer ruff mypy
|
|
48
|
+
*Will install: fast-dev-cli emoji typer ruff mypy bumpversion2 pytest coverage*
|
|
49
49
|
|
|
50
50
|
</div>
|
|
51
51
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.10.1"
|
|
@@ -44,7 +44,12 @@ cli = typer.Typer()
|
|
|
44
44
|
def load_bool(name: str, default=False) -> bool:
|
|
45
45
|
if not (v := os.getenv(name)):
|
|
46
46
|
return default
|
|
47
|
-
|
|
47
|
+
if (lower := v.lower()) in ("0", "false", "f", "off", "no", "n"):
|
|
48
|
+
return False
|
|
49
|
+
elif lower in ("1", "true", "t", "on", "yes", "y"):
|
|
50
|
+
return True
|
|
51
|
+
secho(f"WARNING: can not convert value({v!r}) of {name} to bool!")
|
|
52
|
+
return default
|
|
48
53
|
|
|
49
54
|
|
|
50
55
|
def is_venv() -> bool:
|
|
@@ -567,9 +572,12 @@ def tag(
|
|
|
567
572
|
|
|
568
573
|
|
|
569
574
|
class LintCode(DryRun):
|
|
570
|
-
def __init__(
|
|
575
|
+
def __init__(
|
|
576
|
+
self: Self, args, check_only=False, _exit=False, dry=False, bandit=False
|
|
577
|
+
) -> None:
|
|
571
578
|
self.args = args
|
|
572
579
|
self.check_only = check_only
|
|
580
|
+
self._bandit = bandit
|
|
573
581
|
super().__init__(_exit, dry)
|
|
574
582
|
|
|
575
583
|
@staticmethod
|
|
@@ -579,11 +587,22 @@ class LintCode(DryRun):
|
|
|
579
587
|
@staticmethod
|
|
580
588
|
def prefer_dmypy(paths: str, tools: list[str]) -> bool:
|
|
581
589
|
return (
|
|
582
|
-
paths == "."
|
|
590
|
+
paths == "."
|
|
591
|
+
and any(t.startswith("mypy") for t in tools)
|
|
592
|
+
and not load_bool("NO_DMYPY")
|
|
583
593
|
)
|
|
584
594
|
|
|
595
|
+
@staticmethod
|
|
596
|
+
def get_package_name() -> str:
|
|
597
|
+
root = Project.get_work_dir(allow_cwd=True)
|
|
598
|
+
package_maybe = (root.name.replace("-", "_"), "src")
|
|
599
|
+
for name in package_maybe:
|
|
600
|
+
if root.joinpath(name).is_dir():
|
|
601
|
+
return name
|
|
602
|
+
return "."
|
|
603
|
+
|
|
585
604
|
@classmethod
|
|
586
|
-
def to_cmd(cls: Type[Self], paths=".", check_only=False) -> str:
|
|
605
|
+
def to_cmd(cls: Type[Self], paths=".", check_only=False, bandit=False) -> str:
|
|
587
606
|
cmd = ""
|
|
588
607
|
tools = ["ruff format", "ruff check --extend-select=I,B,SIM --fix", "mypy"]
|
|
589
608
|
if check_only:
|
|
@@ -601,7 +620,7 @@ class LintCode(DryRun):
|
|
|
601
620
|
if is_venv():
|
|
602
621
|
if not cls.check_lint_tool_installed():
|
|
603
622
|
should_run_by_tool = True
|
|
604
|
-
if check_call(
|
|
623
|
+
if check_call('python -c "import fast_dev_cli"'):
|
|
605
624
|
command = 'python -m pip install -U "fast_dev_cli"'
|
|
606
625
|
tip = "You may need to run following command to install lint tools:"
|
|
607
626
|
secho(f"{tip}\n\n {command}\n", fg="yellow")
|
|
@@ -612,11 +631,16 @@ class LintCode(DryRun):
|
|
|
612
631
|
if cls.prefer_dmypy(paths, tools):
|
|
613
632
|
tools[-1] = "dmypy run"
|
|
614
633
|
cmd += lint_them.format(prefix, paths, *tools)
|
|
634
|
+
if bandit or load_bool("FASTDEVCLI_BANDIT"):
|
|
635
|
+
command = prefix + "bandit"
|
|
636
|
+
if paths == ".": # fast check --bandit
|
|
637
|
+
command += " -r " + cls.get_package_name()
|
|
638
|
+
cmd += " && " + command
|
|
615
639
|
return cmd
|
|
616
640
|
|
|
617
641
|
def gen(self: Self) -> str:
|
|
618
642
|
paths = " ".join(map(str, self.args)) if self.args else "."
|
|
619
|
-
return self.to_cmd(paths, self.check_only)
|
|
643
|
+
return self.to_cmd(paths, self.check_only, self._bandit)
|
|
620
644
|
|
|
621
645
|
|
|
622
646
|
def parse_files(args: list[str] | tuple[str, ...]) -> list[str]:
|
|
@@ -631,8 +655,8 @@ def lint(files=None, dry=False) -> None:
|
|
|
631
655
|
LintCode(files, dry=dry).run()
|
|
632
656
|
|
|
633
657
|
|
|
634
|
-
def check(files=None, dry=False) -> None:
|
|
635
|
-
LintCode(files, check_only=True, _exit=True, dry=dry).run()
|
|
658
|
+
def check(files=None, dry=False, bandit=False) -> None:
|
|
659
|
+
LintCode(files, check_only=True, _exit=True, dry=dry, bandit=bandit).run()
|
|
636
660
|
|
|
637
661
|
|
|
638
662
|
@cli.command(name="lint")
|
|
@@ -654,10 +678,11 @@ def make_style(
|
|
|
654
678
|
|
|
655
679
|
@cli.command(name="check")
|
|
656
680
|
def only_check(
|
|
681
|
+
bandit: bool = Option(False, "--bandit", help="Run `bandit -r <package_dir>`"),
|
|
657
682
|
dry: bool = Option(False, "--dry", help="Only print, not really run shell command"),
|
|
658
683
|
) -> None:
|
|
659
684
|
"""Check code style without reformat"""
|
|
660
|
-
check(dry=dry)
|
|
685
|
+
check(dry=dry, bandit=bandit)
|
|
661
686
|
|
|
662
687
|
|
|
663
688
|
class Sync(DryRun):
|
|
@@ -697,16 +722,21 @@ def sync(
|
|
|
697
722
|
Sync(filename, extras, save, dry=dry).run()
|
|
698
723
|
|
|
699
724
|
|
|
700
|
-
def _should_run_test_script(path: Path) ->
|
|
701
|
-
|
|
725
|
+
def _should_run_test_script(path: Path = Path("scripts")) -> Path | None:
|
|
726
|
+
for name in ("test.sh", "test.py"):
|
|
727
|
+
if (file := path / name).exists():
|
|
728
|
+
return file
|
|
729
|
+
return None
|
|
702
730
|
|
|
703
731
|
|
|
704
732
|
def test(dry: bool, ignore_script=False) -> None:
|
|
705
733
|
cwd = Path.cwd()
|
|
706
734
|
root = Project.get_work_dir(cwd=cwd, allow_cwd=True)
|
|
707
|
-
|
|
708
|
-
if not _ensure_bool(ignore_script) and
|
|
709
|
-
|
|
735
|
+
script_dir = root / "scripts"
|
|
736
|
+
if not _ensure_bool(ignore_script) and (
|
|
737
|
+
test_script := _should_run_test_script(script_dir)
|
|
738
|
+
):
|
|
739
|
+
cmd = f"{os.path.relpath(test_script, root)}"
|
|
710
740
|
if cwd != root:
|
|
711
741
|
cmd = f"cd {root} && " + cmd
|
|
712
742
|
else:
|
|
@@ -35,12 +35,12 @@ dependencies = [
|
|
|
35
35
|
"emoji >=2.12.1,<3",
|
|
36
36
|
"tomli>=2.0.1,<3; python_version < '3.11'",
|
|
37
37
|
"coverage >=7.5.1,<8",
|
|
38
|
-
"ruff >=0.4.4,<0.
|
|
38
|
+
"ruff >=0.4.4,<0.8",
|
|
39
39
|
"mypy >=1.10.0,<2",
|
|
40
40
|
"bumpversion2 >=1.4.2,<2",
|
|
41
41
|
"pytest >=8.2.0,<9",
|
|
42
42
|
]
|
|
43
|
-
version = "0.
|
|
43
|
+
version = "0.10.1"
|
|
44
44
|
|
|
45
45
|
[project.urls]
|
|
46
46
|
Homepage = "https://github.com/waketzheng/fast-dev-cli"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
parent = os.path.abspath(os.path.dirname(__file__))
|
|
6
|
+
work_dir = os.path.dirname(parent)
|
|
7
|
+
if os.getcwd() != work_dir:
|
|
8
|
+
os.chdir(work_dir)
|
|
9
|
+
|
|
10
|
+
if os.system("pdm run fast check") != 0:
|
|
11
|
+
print("\033[1m Please run './scripts/format.py' to auto-fix style issues \033[0m")
|
|
12
|
+
sys.exit(1)
|
|
13
|
+
|
|
14
|
+
package_name = os.path.basename(work_dir).replace("-", "_")
|
|
15
|
+
cmd = "pdm run bandit -r {}".format(package_name)
|
|
16
|
+
print("-->", cmd)
|
|
17
|
+
if os.system(cmd) != 0:
|
|
18
|
+
sys.exit(1)
|
|
19
|
+
print("Done.")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
import os
|
|
3
|
+
import shlex
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
work_dir = Path(__file__).parent.resolve().parent
|
|
9
|
+
if Path.cwd() != work_dir:
|
|
10
|
+
os.chdir(str(work_dir))
|
|
11
|
+
|
|
12
|
+
cmd = "pdm run fast lint"
|
|
13
|
+
r = subprocess.run(shlex.split(cmd), env=dict(os.environ, SKIP_MYPY="1"))
|
|
14
|
+
sys.exit(None if r.returncode == 0 else 1)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
import os
|
|
3
|
+
import shlex
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
work_dir = Path(__file__).parent.resolve().parent
|
|
10
|
+
if Path.cwd() != work_dir:
|
|
11
|
+
os.chdir(str(work_dir))
|
|
12
|
+
|
|
13
|
+
CMD = "pdm run coverage run -m pytest"
|
|
14
|
+
COMBINE = "pdm run coverage combine .coverage*"
|
|
15
|
+
REPORT = "pdm run coverage report -m"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def remove_outdate_files(start_time: float) -> None:
|
|
19
|
+
for file in work_dir.glob(".coverage*"):
|
|
20
|
+
if file.stat().st_mtime < start_time:
|
|
21
|
+
file.unlink()
|
|
22
|
+
print(f"Removed outdate file: {file}")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def run_command(cmd: str, shell=False) -> None:
|
|
26
|
+
print("-->", cmd, flush=True)
|
|
27
|
+
r = subprocess.run(cmd if shell else shlex.split(cmd), shell=shell)
|
|
28
|
+
r.returncode and sys.exit(1)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def combine_result_files(shell=COMBINE) -> None:
|
|
32
|
+
to_be_combine = [i.name for i in work_dir.glob(".coverage.*")]
|
|
33
|
+
if to_be_combine:
|
|
34
|
+
if sys.platform == "win32":
|
|
35
|
+
if work_dir.joinpath(".coverage").exists():
|
|
36
|
+
shell = shell.replace("*", " ")
|
|
37
|
+
else:
|
|
38
|
+
shell = shell.replace(".coverage*", "")
|
|
39
|
+
shell += " ".join(to_be_combine)
|
|
40
|
+
run_command(shell, True)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
started_at = time.time()
|
|
44
|
+
run_command(CMD)
|
|
45
|
+
remove_outdate_files(started_at)
|
|
46
|
+
combine_result_files()
|
|
47
|
+
run_command(REPORT)
|
|
@@ -1,10 +1,27 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import pathlib
|
|
3
|
+
from typing import Generator
|
|
2
4
|
|
|
5
|
+
import pytest
|
|
3
6
|
from pytest_mock import MockerFixture
|
|
4
7
|
|
|
5
|
-
from fast_dev_cli.cli import
|
|
8
|
+
from fast_dev_cli.cli import (
|
|
9
|
+
Project,
|
|
10
|
+
_should_run_test_script,
|
|
11
|
+
capture_cmd_output,
|
|
12
|
+
coverage_test,
|
|
13
|
+
)
|
|
6
14
|
from fast_dev_cli.cli import test as unitcase
|
|
7
15
|
|
|
16
|
+
TEST_SCRIPT = os.path.join("scripts", "test.py")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@pytest.fixture
|
|
20
|
+
def script_path() -> Generator[pathlib.Path, None, None]:
|
|
21
|
+
parent = pathlib.Path(__file__).parent
|
|
22
|
+
test_script = parent.resolve().parent / "scripts" / "test.py"
|
|
23
|
+
yield test_script
|
|
24
|
+
|
|
8
25
|
|
|
9
26
|
def test_cli_test(mocker, capsys):
|
|
10
27
|
output = capture_cmd_output("python fast_dev_cli/cli.py test --dry --ignore-script")
|
|
@@ -14,7 +31,7 @@ def test_cli_test(mocker, capsys):
|
|
|
14
31
|
)
|
|
15
32
|
|
|
16
33
|
mocker.patch("fast_dev_cli.cli.is_venv", return_value=True)
|
|
17
|
-
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=
|
|
34
|
+
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=None)
|
|
18
35
|
unitcase(dry=True)
|
|
19
36
|
assert (
|
|
20
37
|
'coverage run -m pytest -s && coverage report --omit="tests/*" -m'
|
|
@@ -24,7 +41,7 @@ def test_cli_test(mocker, capsys):
|
|
|
24
41
|
|
|
25
42
|
def test_test_with_pdm_run(mocker: MockerFixture, capsys):
|
|
26
43
|
mocker.patch("fast_dev_cli.cli.check_call", return_value=False)
|
|
27
|
-
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=
|
|
44
|
+
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=None)
|
|
28
45
|
unitcase(dry=True)
|
|
29
46
|
assert (
|
|
30
47
|
'--> pdm run coverage run -m pytest -s && pdm run coverage report --omit="tests/*" -m'
|
|
@@ -34,7 +51,7 @@ def test_test_with_pdm_run(mocker: MockerFixture, capsys):
|
|
|
34
51
|
|
|
35
52
|
def test_test_with_poetry_or_pdm_run(mocker: MockerFixture, capsys):
|
|
36
53
|
mocker.patch("fast_dev_cli.cli.check_call", return_value=False)
|
|
37
|
-
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=
|
|
54
|
+
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=None)
|
|
38
55
|
mocker.patch("fast_dev_cli.cli.Project.manage_by_poetry", return_value=True)
|
|
39
56
|
unitcase(dry=True)
|
|
40
57
|
command = "coverage"
|
|
@@ -47,7 +64,7 @@ def test_test_with_poetry_or_pdm_run(mocker: MockerFixture, capsys):
|
|
|
47
64
|
|
|
48
65
|
|
|
49
66
|
def test_test_not_in_venv(mocker: MockerFixture, capsys):
|
|
50
|
-
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=
|
|
67
|
+
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=None)
|
|
51
68
|
mocker.patch("fast_dev_cli.cli.is_venv", return_value=False)
|
|
52
69
|
unitcase(dry=True)
|
|
53
70
|
command = "coverage"
|
|
@@ -59,25 +76,26 @@ def test_test_not_in_venv(mocker: MockerFixture, capsys):
|
|
|
59
76
|
)
|
|
60
77
|
|
|
61
78
|
|
|
62
|
-
def test_run_script(mocker: MockerFixture, capsys):
|
|
63
|
-
|
|
79
|
+
def test_run_script(mocker: MockerFixture, capsys, script_path):
|
|
80
|
+
assert _should_run_test_script()
|
|
81
|
+
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=script_path)
|
|
64
82
|
unitcase(dry=True)
|
|
65
|
-
assert
|
|
83
|
+
assert TEST_SCRIPT in capsys.readouterr().out
|
|
84
|
+
assert _should_run_test_script(pathlib.Path("not-exist")) is None
|
|
66
85
|
|
|
67
86
|
|
|
68
|
-
def test_ignore_script(mocker: MockerFixture, capsys):
|
|
69
|
-
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=
|
|
87
|
+
def test_ignore_script(mocker: MockerFixture, capsys, script_path):
|
|
88
|
+
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=script_path)
|
|
70
89
|
unitcase(dry=True, ignore_script=True)
|
|
71
|
-
assert
|
|
90
|
+
assert TEST_SCRIPT not in capsys.readouterr().out
|
|
72
91
|
|
|
73
92
|
|
|
74
|
-
def test_run_script_in_sub_directory(mocker: MockerFixture, capsys):
|
|
75
|
-
|
|
76
|
-
mocker.patch("
|
|
77
|
-
mocker.patch("pathlib.Path.cwd", return_value=parent)
|
|
93
|
+
def test_run_script_in_sub_directory(mocker: MockerFixture, capsys, script_path):
|
|
94
|
+
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=script_path)
|
|
95
|
+
mocker.patch("pathlib.Path.cwd", return_value=script_path.parent)
|
|
78
96
|
unitcase(dry=True)
|
|
79
97
|
out = capsys.readouterr().out
|
|
80
|
-
assert f"cd {parent.parent} &&
|
|
98
|
+
assert f"cd {script_path.parent.parent} && {TEST_SCRIPT}" in out
|
|
81
99
|
|
|
82
100
|
|
|
83
101
|
def test_fast_test(mocker, capsys):
|
|
@@ -88,7 +106,7 @@ def test_fast_test(mocker, capsys):
|
|
|
88
106
|
)
|
|
89
107
|
|
|
90
108
|
mocker.patch("fast_dev_cli.cli.is_venv", return_value=True)
|
|
91
|
-
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=
|
|
109
|
+
mocker.patch("fast_dev_cli.cli._should_run_test_script", return_value=None)
|
|
92
110
|
coverage_test(dry=True)
|
|
93
111
|
assert (
|
|
94
112
|
'coverage run -m pytest -s && coverage report --omit="tests/*" -m'
|
|
@@ -16,7 +16,7 @@ from fast_dev_cli.cli import (
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def test_utils():
|
|
19
|
+
def test_utils(capsys):
|
|
20
20
|
# parse files
|
|
21
21
|
assert parse_files([]) == []
|
|
22
22
|
assert parse_files(["-a", "--a"]) == []
|
|
@@ -52,6 +52,11 @@ def test_utils():
|
|
|
52
52
|
assert load_bool(name) is True
|
|
53
53
|
os.environ.pop(name)
|
|
54
54
|
assert load_bool(name) is False
|
|
55
|
+
os.environ[name] = "yeah"
|
|
56
|
+
assert load_bool(name) is False
|
|
57
|
+
assert load_bool(name, True) is True
|
|
58
|
+
out = capsys.readouterr().out.strip()
|
|
59
|
+
assert "WARNING" in out
|
|
55
60
|
|
|
56
61
|
|
|
57
62
|
def test_run_shell():
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import shutil
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
|
|
3
4
|
import pytest
|
|
@@ -10,6 +11,7 @@ from fast_dev_cli.cli import (
|
|
|
10
11
|
lint,
|
|
11
12
|
make_style,
|
|
12
13
|
only_check,
|
|
14
|
+
run_and_echo,
|
|
13
15
|
)
|
|
14
16
|
|
|
15
17
|
from .utils import capture_stdout, chdir, mock_sys_argv
|
|
@@ -56,10 +58,28 @@ LINT_CMD = _CMD.format("", " --fix")
|
|
|
56
58
|
CHECK_CMD = _CMD.format(" --check", "")
|
|
57
59
|
|
|
58
60
|
|
|
59
|
-
def test_check(mock_no_dmypy):
|
|
61
|
+
def test_check(mock_no_dmypy, monkeypatch, mocker):
|
|
60
62
|
command = capture_cmd_output("fast check --dry")
|
|
61
63
|
for cmd in CHECK_CMD.split(SEP):
|
|
62
64
|
assert cmd in command
|
|
65
|
+
command2 = capture_cmd_output("fast check --bandit --dry")
|
|
66
|
+
assert command2 == command + " && bandit -r fast_dev_cli"
|
|
67
|
+
monkeypatch.setenv("FASTDEVCLI_BANDIT", "1")
|
|
68
|
+
command3 = capture_cmd_output("fast check --dry")
|
|
69
|
+
assert command3 == command2
|
|
70
|
+
monkeypatch.setenv("FASTDEVCLI_BANDIT", "0")
|
|
71
|
+
command4 = capture_cmd_output("fast check --dry")
|
|
72
|
+
assert command4 == command
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_check_bandit(tmp_path):
|
|
76
|
+
package_path = tmp_path / "foo"
|
|
77
|
+
with chdir(tmp_path):
|
|
78
|
+
run_and_echo(f"poetry new {package_path.name}")
|
|
79
|
+
shutil.rmtree(package_path / package_path.name)
|
|
80
|
+
with chdir(package_path):
|
|
81
|
+
command = capture_cmd_output("fast check --bandit --dry")
|
|
82
|
+
assert "bandit -r ." in command
|
|
63
83
|
|
|
64
84
|
|
|
65
85
|
def test_fast_check():
|
|
@@ -110,9 +130,15 @@ def test_lint_with_prefix(mocker):
|
|
|
110
130
|
|
|
111
131
|
def test_make_style(mocker, mock_no_dmypy):
|
|
112
132
|
mocker.patch("fast_dev_cli.cli.is_venv", return_value=True)
|
|
133
|
+
with capture_stdout() as stream:
|
|
134
|
+
make_style(check_only=False, dry=True)
|
|
135
|
+
assert LINT_CMD in stream.getvalue()
|
|
113
136
|
with capture_stdout() as stream:
|
|
114
137
|
make_style([Path(".")], check_only=False, dry=True)
|
|
115
138
|
assert LINT_CMD in stream.getvalue()
|
|
139
|
+
with capture_stdout() as stream:
|
|
140
|
+
make_style(".", check_only=False, dry=True) # type:ignore[arg-type]
|
|
141
|
+
assert LINT_CMD in stream.getvalue()
|
|
116
142
|
with capture_stdout() as stream:
|
|
117
143
|
make_style([Path(".")], check_only=True, dry=True)
|
|
118
144
|
assert CHECK_CMD in stream.getvalue()
|
|
@@ -138,6 +164,10 @@ def test_lint_func(mocker, mock_no_dmypy):
|
|
|
138
164
|
with mock_sys_argv(["tests"]), capture_stdout() as stream:
|
|
139
165
|
lint(dry=True)
|
|
140
166
|
assert LINT_CMD.replace(" .", " tests") in stream.getvalue()
|
|
167
|
+
with capture_stdout() as stream:
|
|
168
|
+
lint(["lint"], dry=True)
|
|
169
|
+
assert LINT_CMD in stream.getvalue()
|
|
170
|
+
assert LINT_CMD in capture_cmd_output("pdm run python -m fast_dev_cli lint --dry")
|
|
141
171
|
|
|
142
172
|
|
|
143
173
|
def test_lint_without_ruff_installed(mocker, mock_no_dmypy):
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
import sys
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Generator
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from fast_dev_cli.cli import (
|
|
11
|
+
TOML_FILE,
|
|
12
|
+
BumpUp,
|
|
13
|
+
ParseError,
|
|
14
|
+
run_and_echo,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
from .utils import chdir
|
|
18
|
+
|
|
19
|
+
CONF = """
|
|
20
|
+
|
|
21
|
+
[tool.poetry-version-plugin]
|
|
22
|
+
source = "init"
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@contextmanager
|
|
27
|
+
def _prepare_package(
|
|
28
|
+
package_path: Path, define_include=False
|
|
29
|
+
) -> Generator[Path, None, None]:
|
|
30
|
+
toml_file = package_path / TOML_FILE
|
|
31
|
+
package_name = package_path.name.replace(" ", "_")
|
|
32
|
+
init_file = package_path / package_name / "__init__.py"
|
|
33
|
+
a, b = 'version = "0.1.0"', 'version = "0"'
|
|
34
|
+
if define_include:
|
|
35
|
+
b += '\npackages = [{include = "%s"}]' % package_name
|
|
36
|
+
with chdir(package_path.parent):
|
|
37
|
+
run_and_echo(f'poetry new "{package_path.name}"')
|
|
38
|
+
toml_file.unlink()
|
|
39
|
+
py_version = "{0}.{1}".format(*sys.version_info)
|
|
40
|
+
with chdir(package_path):
|
|
41
|
+
run_and_echo(f'poetry init --python="^{py_version}" --no-interaction')
|
|
42
|
+
text = toml_file.read_text().replace(a, b)
|
|
43
|
+
toml_file.write_text(text + CONF)
|
|
44
|
+
shutil.move(package_path.name, package_name)
|
|
45
|
+
init_file.write_text('__version__ = "0.0.1"\n')
|
|
46
|
+
yield init_file
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _build_bump_cmd(init_file: Path) -> str:
|
|
50
|
+
relative_path = os.path.join(init_file.parent.name, init_file.name)
|
|
51
|
+
return rf'bumpversion --parse "(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)" --current-version="0.0.1" patch {relative_path} --allow-dirty'
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_version_plugin(tmp_path: Path) -> None:
|
|
55
|
+
with _prepare_package(tmp_path / "helloworld") as init_file:
|
|
56
|
+
command = _build_bump_cmd(init_file)
|
|
57
|
+
assert BumpUp(part="patch", commit=False, dry=True).gen() == command
|
|
58
|
+
run_and_echo("poetry run fast bump patch")
|
|
59
|
+
assert init_file.read_text() == '__version__ = "0.0.2"\n'
|
|
60
|
+
init_file.unlink()
|
|
61
|
+
with pytest.raises(ParseError, match=r"Version file not found!.*"):
|
|
62
|
+
BumpUp(part="patch", commit=False, dry=True).gen()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_version_plugin_include_defined(tmp_path: Path) -> None:
|
|
66
|
+
with _prepare_package(tmp_path / "hello world", True) as init_file:
|
|
67
|
+
command = _build_bump_cmd(init_file)
|
|
68
|
+
assert BumpUp(part="patch", commit=False, dry=True).gen() == command
|
|
69
|
+
run_and_echo("poetry run fast bump patch")
|
|
70
|
+
assert init_file.read_text() == '__version__ = "0.0.2"\n'
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import fast_dev_cli
|
|
2
|
+
from fast_dev_cli.cli import dev, main, run_and_echo, runserver
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
def test_runserver(capsys):
|
|
@@ -17,6 +18,12 @@ def test_runserver(capsys):
|
|
|
17
18
|
runserver(port=9000, host="0.0.0.0", dry=True)
|
|
18
19
|
out = capsys.readouterr().out.strip()
|
|
19
20
|
assert out.replace("--> ", "") == "fastapi dev --port=9000 --host=0.0.0.0"
|
|
21
|
+
runserver("9000", host="0.0.0.0", dry=True)
|
|
22
|
+
out = capsys.readouterr().out.strip()
|
|
23
|
+
assert out.replace("--> ", "") == "fastapi dev --port=9000 --host=0.0.0.0"
|
|
24
|
+
runserver("app.py", host="0.0.0.0", dry=True)
|
|
25
|
+
out = capsys.readouterr().out.strip()
|
|
26
|
+
assert out.replace("--> ", "") == "fastapi dev app.py --host=0.0.0.0"
|
|
20
27
|
|
|
21
28
|
|
|
22
29
|
def test_dev(capsys):
|
|
@@ -80,3 +87,9 @@ def test_run_by_module(tmp_path):
|
|
|
80
87
|
assert "fastapi dev main.py --port=9000 --host=0.0.0.0" in out.read_text()
|
|
81
88
|
run_and_echo(f"{fast} dev 9000 --host=0.0.0.0 --dry > {out}", verbose=False)
|
|
82
89
|
assert "fastapi dev --port=9000 --host=0.0.0.0" in out.read_text()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_main(mocker):
|
|
93
|
+
mocker.patch("fast_dev_cli.cli.cli")
|
|
94
|
+
main()
|
|
95
|
+
fast_dev_cli.cli.cli.assert_called_once() # type:ignore[attr-defined]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import sys
|
|
1
2
|
from contextlib import contextmanager
|
|
2
3
|
|
|
3
4
|
from fast_dev_cli.cli import (
|
|
@@ -36,7 +37,12 @@ def test_echo_when_not_dry(mocker, capsys):
|
|
|
36
37
|
|
|
37
38
|
@contextmanager
|
|
38
39
|
def _clear_tags():
|
|
39
|
-
|
|
40
|
+
if sys.platform == "win32":
|
|
41
|
+
for t in capture_cmd_output("git tag").splitlines():
|
|
42
|
+
if "v" in (tag := t.strip()):
|
|
43
|
+
run_and_echo(f"git tag -d {tag}")
|
|
44
|
+
else:
|
|
45
|
+
run_and_echo("git tag | xargs git tag -d")
|
|
40
46
|
yield
|
|
41
47
|
run_and_echo("git pull --tags")
|
|
42
48
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.9.10"
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
|
|
3
|
-
import pytest
|
|
4
|
-
|
|
5
|
-
from fast_dev_cli.cli import (
|
|
6
|
-
TOML_FILE,
|
|
7
|
-
BumpUp,
|
|
8
|
-
ParseError,
|
|
9
|
-
run_and_echo,
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
from .utils import chdir
|
|
13
|
-
|
|
14
|
-
CONF = """
|
|
15
|
-
|
|
16
|
-
[tool.poetry-version-plugin]
|
|
17
|
-
source = "init"
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def test_version_plugin(tmp_path: Path) -> None:
|
|
22
|
-
package_path = tmp_path / "helloworld"
|
|
23
|
-
toml_file = package_path / TOML_FILE
|
|
24
|
-
init_file = package_path / package_path.name / "__init__.py"
|
|
25
|
-
a, b = 'version = "0.1.0"', 'version = "0"'
|
|
26
|
-
with chdir(tmp_path):
|
|
27
|
-
run_and_echo(f"poetry new {package_path.name}")
|
|
28
|
-
with chdir(package_path):
|
|
29
|
-
text = toml_file.read_text().replace(a, b)
|
|
30
|
-
toml_file.write_text(text + CONF)
|
|
31
|
-
init_file.write_text('__version__ = "0.0.1"\n')
|
|
32
|
-
assert (
|
|
33
|
-
BumpUp(part="patch", commit=False, dry=True).gen()
|
|
34
|
-
== 'bumpversion --parse "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)" --current-version="0.0.1" patch helloworld/__init__.py --allow-dirty'
|
|
35
|
-
)
|
|
36
|
-
run_and_echo("poetry run fast bump patch")
|
|
37
|
-
assert init_file.read_text() == '__version__ = "0.0.2"\n'
|
|
38
|
-
init_file.unlink()
|
|
39
|
-
with pytest.raises(ParseError, match=r"Version file not found!.*"):
|
|
40
|
-
BumpUp(part="patch", commit=False, dry=True).gen()
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def test_version_plugin_include_defined(tmp_path: Path) -> None:
|
|
44
|
-
package_path = tmp_path / "hello world"
|
|
45
|
-
toml_file = package_path / TOML_FILE
|
|
46
|
-
package_name = package_path.name.replace(" ", "_")
|
|
47
|
-
init_file = package_path / package_name / "__init__.py"
|
|
48
|
-
a, b = 'version = "0.1.0"', 'version = "0"'
|
|
49
|
-
b += '\npackages = [{include = "%s"}]' % package_name
|
|
50
|
-
with chdir(tmp_path):
|
|
51
|
-
run_and_echo(f"poetry new '{package_path.name}'")
|
|
52
|
-
with chdir(package_path):
|
|
53
|
-
text = toml_file.read_text().replace(a, b)
|
|
54
|
-
toml_file.write_text(text + CONF)
|
|
55
|
-
run_and_echo(f"mv '{package_path.name}' {package_name}")
|
|
56
|
-
init_file.write_text('__version__ = "0.0.1"\n')
|
|
57
|
-
assert (
|
|
58
|
-
BumpUp(part="patch", commit=False, dry=True).gen()
|
|
59
|
-
== f'bumpversion --parse "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)" --current-version="0.0.1" patch {package_name}/__init__.py --allow-dirty'
|
|
60
|
-
)
|
|
61
|
-
run_and_echo("poetry run fast bump patch")
|
|
62
|
-
assert init_file.read_text() == '__version__ = "0.0.2"\n'
|
|
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
|