fast-dev-cli 0.6.4__tar.gz → 0.6.6__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.6.4 → fast_dev_cli-0.6.6}/PKG-INFO +6 -2
- {fast_dev_cli-0.6.4 → fast_dev_cli-0.6.6}/README.md +5 -1
- {fast_dev_cli-0.6.4 → fast_dev_cli-0.6.6}/fast_dev_cli/cli.py +71 -45
- {fast_dev_cli-0.6.4 → fast_dev_cli-0.6.6}/pyproject.toml +1 -1
- {fast_dev_cli-0.6.4 → fast_dev_cli-0.6.6}/LICENSE +0 -0
- {fast_dev_cli-0.6.4 → fast_dev_cli-0.6.6}/fast_dev_cli/__init__.py +0 -0
- {fast_dev_cli-0.6.4 → fast_dev_cli-0.6.6}/fast_dev_cli/__main__.py +0 -0
- {fast_dev_cli-0.6.4 → fast_dev_cli-0.6.6}/fast_dev_cli/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fast-dev-cli
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.6
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Waket Zheng
|
|
6
6
|
Author-email: waketzheng@gmail.com
|
|
@@ -56,7 +56,7 @@ Python 3.11+
|
|
|
56
56
|
```console
|
|
57
57
|
$ pip install "fast-dev-cli[all]"
|
|
58
58
|
---> 100%
|
|
59
|
-
Successfully installed fast-dev-cli
|
|
59
|
+
Successfully installed fast-dev-cli isort black ruff mypy typer bumpversion pytest coverage
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
</div>
|
|
@@ -67,6 +67,10 @@ Successfully installed fast-dev-cli
|
|
|
67
67
|
```bash
|
|
68
68
|
fast lint /path/to/file-or-directory
|
|
69
69
|
```
|
|
70
|
+
- Check only
|
|
71
|
+
```bash
|
|
72
|
+
fast check
|
|
73
|
+
```
|
|
70
74
|
- Bump up version in pyproject.toml
|
|
71
75
|
```bash
|
|
72
76
|
fast bump
|
|
@@ -34,7 +34,7 @@ Python 3.11+
|
|
|
34
34
|
```console
|
|
35
35
|
$ pip install "fast-dev-cli[all]"
|
|
36
36
|
---> 100%
|
|
37
|
-
Successfully installed fast-dev-cli
|
|
37
|
+
Successfully installed fast-dev-cli isort black ruff mypy typer bumpversion pytest coverage
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
</div>
|
|
@@ -45,6 +45,10 @@ Successfully installed fast-dev-cli
|
|
|
45
45
|
```bash
|
|
46
46
|
fast lint /path/to/file-or-directory
|
|
47
47
|
```
|
|
48
|
+
- Check only
|
|
49
|
+
```bash
|
|
50
|
+
fast check
|
|
51
|
+
```
|
|
48
52
|
- Bump up version in pyproject.toml
|
|
49
53
|
```bash
|
|
50
54
|
fast bump
|
|
@@ -7,6 +7,7 @@ from enum import StrEnum
|
|
|
7
7
|
from functools import cached_property
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from subprocess import CompletedProcess
|
|
10
|
+
from typing import Self, Type
|
|
10
11
|
|
|
11
12
|
__version__ = importlib.metadata.version(Path(__file__).parent.name)
|
|
12
13
|
|
|
@@ -129,14 +130,14 @@ def exit_if_run_failed(
|
|
|
129
130
|
|
|
130
131
|
|
|
131
132
|
class DryRun:
|
|
132
|
-
def __init__(self, _exit=False, dry=False):
|
|
133
|
+
def __init__(self: Self, _exit=False, dry=False) -> None:
|
|
133
134
|
self.dry = dry
|
|
134
135
|
self._exit = _exit
|
|
135
136
|
|
|
136
|
-
def gen(self) -> str:
|
|
137
|
+
def gen(self: Self) -> str:
|
|
137
138
|
raise NotImplementedError
|
|
138
139
|
|
|
139
|
-
def run(self) -> None:
|
|
140
|
+
def run(self: Self) -> None:
|
|
140
141
|
exit_if_run_failed(self.gen(), _exit=self._exit, dry=self.dry)
|
|
141
142
|
|
|
142
143
|
|
|
@@ -146,7 +147,9 @@ class BumpUp(DryRun):
|
|
|
146
147
|
minor = "minor"
|
|
147
148
|
major = "major"
|
|
148
149
|
|
|
149
|
-
def __init__(
|
|
150
|
+
def __init__(
|
|
151
|
+
self: Self, commit: bool, part: str, filename=TOML_FILE, dry=False
|
|
152
|
+
) -> None:
|
|
150
153
|
self.commit = commit
|
|
151
154
|
self.part = part
|
|
152
155
|
self.filename = filename
|
|
@@ -163,7 +166,7 @@ class BumpUp(DryRun):
|
|
|
163
166
|
echo(f"Invalid part: {s!r}")
|
|
164
167
|
raise Exit(1) from e
|
|
165
168
|
|
|
166
|
-
def gen(self) -> str:
|
|
169
|
+
def gen(self: Self) -> str:
|
|
167
170
|
_version = get_current_version()
|
|
168
171
|
filename = self.filename
|
|
169
172
|
echo(f"Current version(@{filename}): {_version}")
|
|
@@ -186,7 +189,7 @@ class BumpUp(DryRun):
|
|
|
186
189
|
cmd += " --allow-dirty"
|
|
187
190
|
return cmd
|
|
188
191
|
|
|
189
|
-
def run(self) -> None:
|
|
192
|
+
def run(self: Self) -> None:
|
|
190
193
|
super().run()
|
|
191
194
|
if not self.commit and not self.dry:
|
|
192
195
|
new_version = get_current_version(True)
|
|
@@ -196,7 +199,7 @@ class BumpUp(DryRun):
|
|
|
196
199
|
|
|
197
200
|
|
|
198
201
|
@cli.command()
|
|
199
|
-
def version():
|
|
202
|
+
def version() -> None:
|
|
200
203
|
"""Show the version of this tool"""
|
|
201
204
|
echo(__version__)
|
|
202
205
|
|
|
@@ -208,11 +211,12 @@ def bump_version(
|
|
|
208
211
|
False, "--commit", "-c", help="Whether run `git commit` after version changed"
|
|
209
212
|
),
|
|
210
213
|
dry: bool = Option(False, "--dry", help="Only print, not really run shell command"),
|
|
211
|
-
):
|
|
214
|
+
) -> None:
|
|
215
|
+
"""Bump up version string in pyproject.toml"""
|
|
212
216
|
return BumpUp(commit, part.value, dry=dry).run()
|
|
213
217
|
|
|
214
218
|
|
|
215
|
-
def bump():
|
|
219
|
+
def bump() -> None:
|
|
216
220
|
part, commit = "", False
|
|
217
221
|
if args := sys.argv[2:]:
|
|
218
222
|
if "-c" in args or "--commit" in args:
|
|
@@ -239,13 +243,17 @@ class Project:
|
|
|
239
243
|
return None
|
|
240
244
|
|
|
241
245
|
@classmethod
|
|
242
|
-
def get_work_dir(
|
|
246
|
+
def get_work_dir(
|
|
247
|
+
cls: Type[Self], name=TOML_FILE, cwd: Path | None = None, allow_cwd=False
|
|
248
|
+
) -> Path:
|
|
243
249
|
if d := cls.work_dir(name, cwd or Path.cwd(), cls.path_depth):
|
|
244
250
|
return d
|
|
251
|
+
if allow_cwd:
|
|
252
|
+
return cls.get_root_dir(cwd)
|
|
245
253
|
raise EnvError(f"{name} not found! Make sure this is a poetry project.")
|
|
246
254
|
|
|
247
255
|
@classmethod
|
|
248
|
-
def load_toml_text(cls):
|
|
256
|
+
def load_toml_text(cls: Type[Self]) -> str:
|
|
249
257
|
toml_file = cls.get_work_dir().resolve() / TOML_FILE # to be optimize
|
|
250
258
|
return toml_file.read_text("utf8")
|
|
251
259
|
|
|
@@ -254,7 +262,7 @@ class Project:
|
|
|
254
262
|
return Path(sys.executable).parent
|
|
255
263
|
|
|
256
264
|
@classmethod
|
|
257
|
-
def get_root_dir(cls, cwd: Path | None = None) -> Path:
|
|
265
|
+
def get_root_dir(cls: Type[Self], cwd: Path | None = None) -> Path:
|
|
258
266
|
root = cwd or Path.cwd()
|
|
259
267
|
venv_parent = cls.python_exec_dir().parent.parent
|
|
260
268
|
if root.is_relative_to(venv_parent):
|
|
@@ -313,7 +321,7 @@ class UpgradeDependencies(Project, DryRun):
|
|
|
313
321
|
|
|
314
322
|
@classmethod
|
|
315
323
|
def build_args(
|
|
316
|
-
cls, package_lines: list[str]
|
|
324
|
+
cls: Type[Self], package_lines: list[str]
|
|
317
325
|
) -> tuple[list[str], dict[str, list[str]]]:
|
|
318
326
|
args: list[str] = [] # ['typer[all]', 'fastapi']
|
|
319
327
|
specials: dict[str, list[str]] = {} # {'--platform linux': ['gunicorn']}
|
|
@@ -347,7 +355,7 @@ class UpgradeDependencies(Project, DryRun):
|
|
|
347
355
|
return args, specials
|
|
348
356
|
|
|
349
357
|
@classmethod
|
|
350
|
-
def should_with_dev(cls):
|
|
358
|
+
def should_with_dev(cls: Type[Self]) -> bool:
|
|
351
359
|
text = cls.load_toml_text()
|
|
352
360
|
return cls.DevFlag.new in text or cls.DevFlag.old in text
|
|
353
361
|
|
|
@@ -364,7 +372,7 @@ class UpgradeDependencies(Project, DryRun):
|
|
|
364
372
|
|
|
365
373
|
@classmethod
|
|
366
374
|
def get_args(
|
|
367
|
-
cls, toml_text: str | None = None
|
|
375
|
+
cls: Type[Self], toml_text: str | None = None
|
|
368
376
|
) -> tuple[list[str], list[str], list[list[str]], str]:
|
|
369
377
|
if toml_text is None:
|
|
370
378
|
toml_text = cls.load_toml_text()
|
|
@@ -390,7 +398,7 @@ class UpgradeDependencies(Project, DryRun):
|
|
|
390
398
|
return prod_packs, dev_packs, others, dev_flag
|
|
391
399
|
|
|
392
400
|
@classmethod
|
|
393
|
-
def gen_cmd(cls) -> str:
|
|
401
|
+
def gen_cmd(cls: Type[Self]) -> str:
|
|
394
402
|
main_args, dev_args, others, dev_flags = cls.get_args()
|
|
395
403
|
return cls.to_cmd(main_args, dev_args, others, dev_flags)
|
|
396
404
|
|
|
@@ -413,30 +421,30 @@ class UpgradeDependencies(Project, DryRun):
|
|
|
413
421
|
_upgrade += f" && poetry add {' '.join(single)}"
|
|
414
422
|
return _upgrade
|
|
415
423
|
|
|
416
|
-
def gen(self) -> str:
|
|
417
|
-
return self.gen_cmd()
|
|
424
|
+
def gen(self: Self) -> str:
|
|
425
|
+
return self.gen_cmd() + " && poetry update"
|
|
418
426
|
|
|
419
427
|
|
|
420
428
|
@cli.command()
|
|
421
429
|
def upgrade(
|
|
422
430
|
dry: bool = Option(False, "--dry", help="Only print, not really run shell command"),
|
|
423
|
-
):
|
|
431
|
+
) -> None:
|
|
424
432
|
"""Upgrade dependencies in pyproject.toml to latest versions"""
|
|
425
433
|
UpgradeDependencies(dry=dry).run()
|
|
426
434
|
|
|
427
435
|
|
|
428
436
|
class GitTag(DryRun):
|
|
429
|
-
def __init__(self, message, dry):
|
|
437
|
+
def __init__(self: Self, message: str, dry: bool) -> None:
|
|
430
438
|
self.message = message
|
|
431
439
|
super().__init__(dry=dry)
|
|
432
440
|
|
|
433
|
-
def has_v_prefix(self) -> bool:
|
|
441
|
+
def has_v_prefix(self: Self) -> bool:
|
|
434
442
|
return "v" in capture_cmd_output("git tag")
|
|
435
443
|
|
|
436
|
-
def should_push(self) -> bool:
|
|
444
|
+
def should_push(self: Self) -> bool:
|
|
437
445
|
return "git push" in self.git_status
|
|
438
446
|
|
|
439
|
-
def gen(self):
|
|
447
|
+
def gen(self: Self) -> str:
|
|
440
448
|
_version = get_current_version(verbose=False)
|
|
441
449
|
if self.has_v_prefix():
|
|
442
450
|
# Add `v` at prefix to compare with bumpversion tool
|
|
@@ -447,17 +455,17 @@ class GitTag(DryRun):
|
|
|
447
455
|
return cmd
|
|
448
456
|
|
|
449
457
|
@cached_property
|
|
450
|
-
def git_status(self) -> str:
|
|
458
|
+
def git_status(self: Self) -> str:
|
|
451
459
|
return capture_cmd_output("git status")
|
|
452
460
|
|
|
453
|
-
def mark_tag(self) -> bool:
|
|
461
|
+
def mark_tag(self: Self) -> bool:
|
|
454
462
|
if not re.search(r"working (tree|directory) clean", self.git_status):
|
|
455
463
|
run_and_echo("git status")
|
|
456
464
|
echo("ERROR: Please run git commit to make sure working tree is clean!")
|
|
457
465
|
return False
|
|
458
466
|
return bool(super().run())
|
|
459
467
|
|
|
460
|
-
def run(self):
|
|
468
|
+
def run(self: Self) -> None:
|
|
461
469
|
if self.mark_tag() and not self.dry:
|
|
462
470
|
echo("You may want to publish package:\n poetry publish --build")
|
|
463
471
|
|
|
@@ -466,13 +474,13 @@ class GitTag(DryRun):
|
|
|
466
474
|
def tag(
|
|
467
475
|
message: str = Option("", "-m", "--message"),
|
|
468
476
|
dry: bool = Option(False, "--dry", help="Only print, not really run shell command"),
|
|
469
|
-
):
|
|
477
|
+
) -> None:
|
|
470
478
|
"""Run shell command: git tag -a <current-version-in-pyproject.toml> -m {message}"""
|
|
471
479
|
GitTag(message, dry=dry).run()
|
|
472
480
|
|
|
473
481
|
|
|
474
482
|
class LintCode(DryRun):
|
|
475
|
-
def __init__(self, args, check_only=False, _exit=False, dry=False):
|
|
483
|
+
def __init__(self: Self, args, check_only=False, _exit=False, dry=False) -> None:
|
|
476
484
|
self.args = args
|
|
477
485
|
self.check_only = check_only
|
|
478
486
|
super().__init__(_exit, dry)
|
|
@@ -482,7 +490,7 @@ class LintCode(DryRun):
|
|
|
482
490
|
return check_call("black --version")
|
|
483
491
|
|
|
484
492
|
@classmethod
|
|
485
|
-
def to_cmd(cls, paths=".", check_only=False):
|
|
493
|
+
def to_cmd(cls: Type[Self], paths=".", check_only=False) -> str:
|
|
486
494
|
cmd = ""
|
|
487
495
|
tools = ["isort --profile=black", "black", "ruff check --fix", "mypy"]
|
|
488
496
|
if check_only:
|
|
@@ -495,10 +503,7 @@ class LintCode(DryRun):
|
|
|
495
503
|
tools = tools[:-1]
|
|
496
504
|
lint_them = " && ".join("{0}{%d} {1}" % i for i in range(2, len(tools) + 2))
|
|
497
505
|
current_path = Path.cwd()
|
|
498
|
-
|
|
499
|
-
root = Project.get_work_dir(cwd=current_path)
|
|
500
|
-
except EnvError:
|
|
501
|
-
root = Project.get_root_dir(cwd=current_path)
|
|
506
|
+
root = Project.get_work_dir(cwd=current_path, allow_cwd=True)
|
|
502
507
|
app_name = root.name.replace("-", "_")
|
|
503
508
|
if (app_dir := root / app_name).exists() or (app_dir := root / "app").exists():
|
|
504
509
|
if current_path == app_dir:
|
|
@@ -524,18 +529,18 @@ class LintCode(DryRun):
|
|
|
524
529
|
cmd += lint_them.format(prefix, paths, *tools)
|
|
525
530
|
return cmd
|
|
526
531
|
|
|
527
|
-
def gen(self) -> str:
|
|
532
|
+
def gen(self: Self) -> str:
|
|
528
533
|
paths = " ".join(self.args) if self.args else "."
|
|
529
534
|
return self.to_cmd(paths, self.check_only)
|
|
530
535
|
|
|
531
536
|
|
|
532
|
-
def lint(files=None, dry=False):
|
|
537
|
+
def lint(files=None, dry=False) -> None:
|
|
533
538
|
if files is None:
|
|
534
539
|
files = parse_files(sys.argv[1:])
|
|
535
540
|
LintCode(files, dry=dry).run()
|
|
536
541
|
|
|
537
542
|
|
|
538
|
-
def check(files=None, dry=False):
|
|
543
|
+
def check(files=None, dry=False) -> None:
|
|
539
544
|
LintCode(files, check_only=True, _exit=True, dry=dry).run()
|
|
540
545
|
|
|
541
546
|
|
|
@@ -544,7 +549,7 @@ def make_style(
|
|
|
544
549
|
files: list[str],
|
|
545
550
|
check_only: bool = Option(False, "--check-only", "-c"),
|
|
546
551
|
dry: bool = Option(False, "--dry", help="Only print, not really run shell command"),
|
|
547
|
-
):
|
|
552
|
+
) -> None:
|
|
548
553
|
"""Run: isort+black+ruff to reformat code and then mypy to check"""
|
|
549
554
|
if isinstance(files, str):
|
|
550
555
|
files = [files]
|
|
@@ -557,13 +562,13 @@ def make_style(
|
|
|
557
562
|
@cli.command(name="check")
|
|
558
563
|
def only_check(
|
|
559
564
|
dry: bool = Option(False, "--dry", help="Only print, not really run shell command"),
|
|
560
|
-
):
|
|
565
|
+
) -> None:
|
|
561
566
|
"""Check code style without reformat"""
|
|
562
567
|
check(dry=dry)
|
|
563
568
|
|
|
564
569
|
|
|
565
570
|
class Sync(DryRun):
|
|
566
|
-
def __init__(self, filename: str, extras: str, save: bool, dry=False):
|
|
571
|
+
def __init__(self: Self, filename: str, extras: str, save: bool, dry=False) -> None:
|
|
567
572
|
self.filename = filename
|
|
568
573
|
self.extras = extras
|
|
569
574
|
self._save = save
|
|
@@ -594,20 +599,41 @@ def sync(
|
|
|
594
599
|
False, "--save", "-s", help="Whether save the requirement file"
|
|
595
600
|
),
|
|
596
601
|
dry: bool = Option(False, "--dry", help="Only print, not really run shell command"),
|
|
597
|
-
):
|
|
602
|
+
) -> None:
|
|
598
603
|
"""Export dependencies by poetry to a txt file then install by pip."""
|
|
599
604
|
Sync(filename, extras, save, dry=dry).run()
|
|
600
605
|
|
|
601
606
|
|
|
607
|
+
def _should_run_test_script(path: Path) -> bool:
|
|
608
|
+
return path.exists()
|
|
609
|
+
|
|
610
|
+
|
|
602
611
|
@cli.command()
|
|
603
612
|
def test(
|
|
604
613
|
dry: bool = Option(False, "--dry", help="Only print, not really run shell command"),
|
|
605
|
-
):
|
|
614
|
+
) -> None:
|
|
606
615
|
"""Run unittest by pytest and report coverage"""
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
616
|
+
cwd = Path.cwd()
|
|
617
|
+
root = Project.get_work_dir(cwd=cwd, allow_cwd=True)
|
|
618
|
+
test_script = root / "scripts" / "test.sh"
|
|
619
|
+
if _should_run_test_script(test_script):
|
|
620
|
+
cmd = f"sh {test_script.relative_to(root)}"
|
|
621
|
+
if cwd != root:
|
|
622
|
+
cmd = f"cd {root} && " + cmd
|
|
623
|
+
else:
|
|
624
|
+
cmd = 'coverage run -m pytest -s && coverage report --omit="tests/*" -m'
|
|
625
|
+
if not is_venv() or not check_call("coverage --version"):
|
|
626
|
+
sep = " && "
|
|
627
|
+
cmd = sep.join("poetry run " + i for i in cmd.split(sep))
|
|
628
|
+
exit_if_run_failed(cmd, dry=dry)
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
@cli.command()
|
|
632
|
+
def upload(
|
|
633
|
+
dry: bool = Option(False, "--dry", help="Only print, not really run shell command"),
|
|
634
|
+
) -> None:
|
|
635
|
+
"""Shortcut for package publish"""
|
|
636
|
+
cmd = "poetry publish --build"
|
|
611
637
|
exit_if_run_failed(cmd, dry=dry)
|
|
612
638
|
|
|
613
639
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|