fast-dev-cli 0.17.0__tar.gz → 0.17.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.17.0 → fast_dev_cli-0.17.1}/PKG-INFO +1 -1
- fast_dev_cli-0.17.1/fast_dev_cli/__init__.py +1 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/fast_dev_cli/cli.py +149 -56
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/pyproject.toml +5 -2
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/conftest.py +5 -3
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_bump.py +21 -8
- fast_dev_cli-0.17.1/tests/test_help.py +7 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_lint.py +0 -8
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_poetry_version_plugin.py +21 -36
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_tag.py +14 -6
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_upgrade.py +2 -2
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_version.py +20 -2
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/utils.py +13 -21
- fast_dev_cli-0.17.0/fast_dev_cli/__init__.py +0 -1
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/LICENSE +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/README.md +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/fast_dev_cli/__main__.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/fast_dev_cli/py.typed +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/pdm_build.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/scripts/check.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/scripts/deps.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/scripts/format.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/scripts/test.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/__init__.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_exec.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_fast_test.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_functions.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_runserver.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_sync.py +0 -0
- {fast_dev_cli-0.17.0 → fast_dev_cli-0.17.1}/tests/test_upload.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.17.1"
|
|
@@ -10,6 +10,7 @@ import sys
|
|
|
10
10
|
from functools import cached_property
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
from typing import (
|
|
13
|
+
TYPE_CHECKING,
|
|
13
14
|
Any,
|
|
14
15
|
Literal,
|
|
15
16
|
# Optional is required by Option generated by typer
|
|
@@ -23,17 +24,6 @@ import typer
|
|
|
23
24
|
from typer import Exit, Option, echo, secho
|
|
24
25
|
from typer.models import ArgumentInfo, OptionInfo
|
|
25
26
|
|
|
26
|
-
try:
|
|
27
|
-
from emoji import is_emoji
|
|
28
|
-
except ImportError:
|
|
29
|
-
|
|
30
|
-
def is_emoji(char: str) -> bool: # type:ignore[misc]
|
|
31
|
-
return (
|
|
32
|
-
not re.match(r"[\w\d\s]", char)
|
|
33
|
-
and not "\u4e00" <= char <= "\u9fff" # Chinese
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
27
|
try:
|
|
38
28
|
from . import __version__
|
|
39
29
|
except ImportError: # pragma: no cover
|
|
@@ -43,20 +33,24 @@ except ImportError: # pragma: no cover
|
|
|
43
33
|
|
|
44
34
|
if sys.version_info >= (3, 11): # pragma: no cover
|
|
45
35
|
from enum import StrEnum
|
|
46
|
-
from typing import Self
|
|
47
36
|
|
|
48
37
|
import tomllib
|
|
49
38
|
else: # pragma: no cover
|
|
50
39
|
from enum import Enum
|
|
51
40
|
|
|
52
41
|
import tomli as tomllib
|
|
53
|
-
from typing_extensions import Self
|
|
54
42
|
|
|
55
43
|
class StrEnum(str, Enum):
|
|
56
44
|
__str__ = str.__str__
|
|
57
45
|
|
|
58
46
|
|
|
59
|
-
|
|
47
|
+
if TYPE_CHECKING:
|
|
48
|
+
if sys.version_info >= (3, 11):
|
|
49
|
+
from typing import Self
|
|
50
|
+
else:
|
|
51
|
+
from typing_extensions import Self
|
|
52
|
+
|
|
53
|
+
cli = typer.Typer(no_args_is_help=True)
|
|
60
54
|
DryOption = Option(False, "--dry", help="Only print, not really run shell command")
|
|
61
55
|
TOML_FILE = "pyproject.toml"
|
|
62
56
|
ToolName = Literal["poetry", "pdm", "uv"]
|
|
@@ -83,6 +77,18 @@ def poetry_module_name(name: str) -> str:
|
|
|
83
77
|
return canonicalize_name(name).replace("-", "_").replace(" ", "_")
|
|
84
78
|
|
|
85
79
|
|
|
80
|
+
def is_emoji(char: str) -> bool:
|
|
81
|
+
try:
|
|
82
|
+
import emoji
|
|
83
|
+
except ImportError:
|
|
84
|
+
pass
|
|
85
|
+
else:
|
|
86
|
+
return emoji.is_emoji(char)
|
|
87
|
+
if re.match(r"[\w\d\s]", char):
|
|
88
|
+
return False
|
|
89
|
+
return not "\u4e00" <= char <= "\u9fff" # Chinese character
|
|
90
|
+
|
|
91
|
+
|
|
86
92
|
def load_bool(name: str, default: bool = False) -> bool:
|
|
87
93
|
if not (v := os.getenv(name)):
|
|
88
94
|
return default
|
|
@@ -116,7 +122,7 @@ def run_and_echo(
|
|
|
116
122
|
if dry:
|
|
117
123
|
return 0
|
|
118
124
|
command: list[str] | str = cmd
|
|
119
|
-
if "shell" not in kw and not (set(cmd) & {"|", ">"}):
|
|
125
|
+
if "shell" not in kw and not (set(cmd) & {"|", ">", "&"}):
|
|
120
126
|
command = shlex.split(cmd)
|
|
121
127
|
return _run_shell(command, **kw).returncode
|
|
122
128
|
|
|
@@ -155,9 +161,9 @@ def read_version_from_file(
|
|
|
155
161
|
toml_text = Project.load_toml_text()
|
|
156
162
|
context = tomllib.loads(toml_text)
|
|
157
163
|
with contextlib.suppress(KeyError):
|
|
158
|
-
return context["project"]["version"]
|
|
164
|
+
return cast(str, context["project"]["version"])
|
|
159
165
|
with contextlib.suppress(KeyError): # Poetry V1
|
|
160
|
-
return context["tool"]["poetry"]["version"]
|
|
166
|
+
return cast(str, context["tool"]["poetry"]["version"])
|
|
161
167
|
secho(f"WARNING: can not find 'version' item in {version_file}!")
|
|
162
168
|
return "0.0.0"
|
|
163
169
|
pattern = re.compile(r"__version__\s*=")
|
|
@@ -274,14 +280,14 @@ def exit_if_run_failed(
|
|
|
274
280
|
|
|
275
281
|
|
|
276
282
|
class DryRun:
|
|
277
|
-
def __init__(self
|
|
283
|
+
def __init__(self, _exit: bool = False, dry: bool = False) -> None:
|
|
278
284
|
self.dry = dry
|
|
279
285
|
self._exit = _exit
|
|
280
286
|
|
|
281
|
-
def gen(self
|
|
287
|
+
def gen(self) -> str:
|
|
282
288
|
raise NotImplementedError
|
|
283
289
|
|
|
284
|
-
def run(self
|
|
290
|
+
def run(self) -> None:
|
|
285
291
|
exit_if_run_failed(self.gen(), _exit=self._exit, dry=self.dry)
|
|
286
292
|
|
|
287
293
|
|
|
@@ -292,17 +298,21 @@ class BumpUp(DryRun):
|
|
|
292
298
|
major = "major"
|
|
293
299
|
|
|
294
300
|
def __init__(
|
|
295
|
-
self
|
|
301
|
+
self,
|
|
296
302
|
commit: bool,
|
|
297
303
|
part: str,
|
|
298
304
|
filename: str | None = None,
|
|
299
305
|
dry: bool = False,
|
|
306
|
+
no_sync: bool = False,
|
|
307
|
+
emoji: bool | None = None,
|
|
300
308
|
) -> None:
|
|
301
309
|
self.commit = commit
|
|
302
310
|
self.part = part
|
|
303
311
|
if filename is None:
|
|
304
312
|
filename = self.parse_filename()
|
|
305
313
|
self.filename = filename
|
|
314
|
+
self._no_sync = no_sync
|
|
315
|
+
self._emoji = emoji
|
|
306
316
|
super().__init__(dry=dry)
|
|
307
317
|
|
|
308
318
|
@staticmethod
|
|
@@ -352,7 +362,9 @@ class BumpUp(DryRun):
|
|
|
352
362
|
work_dir = Project.get_work_dir()
|
|
353
363
|
for tool in ("pdm", "hatch"):
|
|
354
364
|
with contextlib.suppress(KeyError):
|
|
355
|
-
version_path =
|
|
365
|
+
version_path = cast(
|
|
366
|
+
str, context["tool"][tool]["version"]["path"]
|
|
367
|
+
)
|
|
356
368
|
if (
|
|
357
369
|
Path(version_path).exists()
|
|
358
370
|
or work_dir.joinpath(version_path).exists()
|
|
@@ -425,10 +437,8 @@ class BumpUp(DryRun):
|
|
|
425
437
|
echo(f"Invalid part: {s!r}")
|
|
426
438
|
raise Exit(1) from e
|
|
427
439
|
|
|
428
|
-
def gen(self
|
|
440
|
+
def gen(self) -> str:
|
|
429
441
|
should_sync, _version = get_current_version(check_version=True)
|
|
430
|
-
if should_sync:
|
|
431
|
-
Project.sync_dependencies()
|
|
432
442
|
filename = self.filename
|
|
433
443
|
echo(f"Current version(@{filename}): {_version}")
|
|
434
444
|
if self.part:
|
|
@@ -444,15 +454,17 @@ class BumpUp(DryRun):
|
|
|
444
454
|
if part != "patch":
|
|
445
455
|
cmd += " --tag"
|
|
446
456
|
cmd += " --commit"
|
|
447
|
-
if self.should_add_emoji():
|
|
457
|
+
if self._emoji or (self._emoji is None and self.should_add_emoji()):
|
|
448
458
|
cmd += " --message-emoji=1"
|
|
449
459
|
if not load_bool("DONT_GIT_PUSH"):
|
|
450
460
|
cmd += " && git push && git push --tags && git log -1"
|
|
451
461
|
else:
|
|
452
462
|
cmd += " --allow-dirty"
|
|
463
|
+
if should_sync and not self._no_sync and (sync := Project.get_sync_command()):
|
|
464
|
+
cmd = f"{sync} && " + cmd
|
|
453
465
|
return cmd
|
|
454
466
|
|
|
455
|
-
def run(self
|
|
467
|
+
def run(self) -> None:
|
|
456
468
|
super().run()
|
|
457
469
|
if not self.commit and not self.dry:
|
|
458
470
|
new_version = get_current_version(True)
|
|
@@ -464,7 +476,19 @@ class BumpUp(DryRun):
|
|
|
464
476
|
@cli.command()
|
|
465
477
|
def version() -> None:
|
|
466
478
|
"""Show the version of this tool"""
|
|
467
|
-
echo(
|
|
479
|
+
echo("Fast Dev Cli Version: " + typer.style(__version__, fg=typer.colors.BLUE))
|
|
480
|
+
with contextlib.suppress(FileNotFoundError, KeyError):
|
|
481
|
+
toml_text = Project.load_toml_text()
|
|
482
|
+
doc = tomllib.loads(toml_text)
|
|
483
|
+
version_file = doc["tool"]["pdm"]["version"]["path"]
|
|
484
|
+
text = Project.get_work_dir().joinpath(version_file).read_text()
|
|
485
|
+
varname = "__version__"
|
|
486
|
+
for line in text.splitlines():
|
|
487
|
+
if line.strip().startswith(varname):
|
|
488
|
+
value = line.split("=", 1)[-1].strip().strip('"').strip("'")
|
|
489
|
+
styled = typer.style(value, bold=True)
|
|
490
|
+
echo(f"Version value in {version_file}: " + styled)
|
|
491
|
+
break
|
|
468
492
|
|
|
469
493
|
|
|
470
494
|
@cli.command(name="bump")
|
|
@@ -473,10 +497,24 @@ def bump_version(
|
|
|
473
497
|
commit: bool = Option(
|
|
474
498
|
False, "--commit", "-c", help="Whether run `git commit` after version changed"
|
|
475
499
|
),
|
|
500
|
+
emoji: Optional[bool] = Option(
|
|
501
|
+
None, "--emoji", help="Whether add emoji prefix to commit message"
|
|
502
|
+
),
|
|
503
|
+
no_sync: bool = Option(
|
|
504
|
+
False, "--no-sync", help="Do not run sync command to update version"
|
|
505
|
+
),
|
|
476
506
|
dry: bool = DryOption,
|
|
477
507
|
) -> None:
|
|
478
508
|
"""Bump up version string in pyproject.toml"""
|
|
479
|
-
|
|
509
|
+
if emoji is not None:
|
|
510
|
+
emoji = _ensure_bool(emoji)
|
|
511
|
+
return BumpUp(
|
|
512
|
+
_ensure_bool(commit),
|
|
513
|
+
getattr(part, "value", part),
|
|
514
|
+
no_sync=_ensure_bool(no_sync),
|
|
515
|
+
emoji=emoji,
|
|
516
|
+
dry=dry,
|
|
517
|
+
).run()
|
|
480
518
|
|
|
481
519
|
|
|
482
520
|
def bump() -> None:
|
|
@@ -488,7 +526,7 @@ def bump() -> None:
|
|
|
488
526
|
if not a.startswith("-"):
|
|
489
527
|
part = a
|
|
490
528
|
break
|
|
491
|
-
return BumpUp(commit, part, dry="--dry" in args).run()
|
|
529
|
+
return BumpUp(commit, part, no_sync="--no-sync" in args, dry="--dry" in args).run()
|
|
492
530
|
|
|
493
531
|
|
|
494
532
|
class EnvError(Exception):
|
|
@@ -594,14 +632,30 @@ class Project:
|
|
|
594
632
|
return True
|
|
595
633
|
|
|
596
634
|
@classmethod
|
|
597
|
-
def
|
|
635
|
+
def get_sync_command(cls, prod: bool = True, doc: dict | None = None) -> str:
|
|
598
636
|
if cls.is_pdm_project():
|
|
599
|
-
|
|
600
|
-
run_and_echo(cmd)
|
|
637
|
+
return "pdm sync" + " --prod" * prod
|
|
601
638
|
elif cls.manage_by_poetry(cache=True):
|
|
602
|
-
|
|
639
|
+
cmd = "poetry install"
|
|
640
|
+
if prod:
|
|
641
|
+
if doc is None:
|
|
642
|
+
doc = tomllib.loads(cls.load_toml_text())
|
|
643
|
+
if doc.get("project", {}).get("dependencies") or any(
|
|
644
|
+
i != "python"
|
|
645
|
+
for i in doc.get("tool", {})
|
|
646
|
+
.get("poetry", {})
|
|
647
|
+
.get("dependencies", [])
|
|
648
|
+
):
|
|
649
|
+
cmd += " --only=main"
|
|
650
|
+
return cmd
|
|
603
651
|
elif cls.get_manage_tool(cache=True) == "uv":
|
|
604
|
-
|
|
652
|
+
return "uv sync --inexact" + " --no-dev" * prod
|
|
653
|
+
return ""
|
|
654
|
+
|
|
655
|
+
@classmethod
|
|
656
|
+
def sync_dependencies(cls, prod: bool = True) -> None:
|
|
657
|
+
if cmd := cls.get_sync_command():
|
|
658
|
+
run_and_echo(cmd)
|
|
605
659
|
|
|
606
660
|
|
|
607
661
|
class ParseError(Exception):
|
|
@@ -612,7 +666,7 @@ class ParseError(Exception):
|
|
|
612
666
|
|
|
613
667
|
class UpgradeDependencies(Project, DryRun):
|
|
614
668
|
def __init__(
|
|
615
|
-
self
|
|
669
|
+
self, _exit: bool = False, dry: bool = False, tool: ToolName = "poetry"
|
|
616
670
|
) -> None:
|
|
617
671
|
super().__init__(_exit, dry)
|
|
618
672
|
self._tool = tool
|
|
@@ -777,11 +831,13 @@ class UpgradeDependencies(Project, DryRun):
|
|
|
777
831
|
_upgrade += f" && poetry add {' '.join(single)}"
|
|
778
832
|
return _upgrade
|
|
779
833
|
|
|
780
|
-
def gen(self
|
|
834
|
+
def gen(self) -> str:
|
|
781
835
|
if self._tool == "uv":
|
|
782
|
-
|
|
836
|
+
up = "uv lock --upgrade --verbose"
|
|
837
|
+
deps = "uv sync --inexact --frozen --all-groups --all-extras"
|
|
838
|
+
return f"{up} && {deps}"
|
|
783
839
|
elif self._tool == "pdm":
|
|
784
|
-
return "pdm update --verbose && pdm sync -G :all"
|
|
840
|
+
return "pdm update --verbose && pdm sync -G :all --frozen"
|
|
785
841
|
return self.gen_cmd() + " && poetry lock && poetry update"
|
|
786
842
|
|
|
787
843
|
|
|
@@ -801,36 +857,35 @@ def upgrade(
|
|
|
801
857
|
|
|
802
858
|
|
|
803
859
|
class GitTag(DryRun):
|
|
804
|
-
def __init__(self
|
|
860
|
+
def __init__(self, message: str, dry: bool, no_sync: bool = False) -> None:
|
|
805
861
|
self.message = message
|
|
862
|
+
self._no_sync = no_sync
|
|
806
863
|
super().__init__(dry=dry)
|
|
807
864
|
|
|
808
865
|
@staticmethod
|
|
809
866
|
def has_v_prefix() -> bool:
|
|
810
867
|
return "v" in capture_cmd_output("git tag")
|
|
811
868
|
|
|
812
|
-
def should_push(self
|
|
869
|
+
def should_push(self) -> bool:
|
|
813
870
|
return "git push" in self.git_status
|
|
814
871
|
|
|
815
|
-
def gen(self
|
|
872
|
+
def gen(self) -> str:
|
|
816
873
|
should_sync, _version = get_current_version(verbose=False, check_version=True)
|
|
817
|
-
if should_sync:
|
|
818
|
-
Project.sync_dependencies()
|
|
819
874
|
if self.has_v_prefix():
|
|
820
875
|
# Add `v` at prefix to compare with bumpversion tool
|
|
821
876
|
_version = "v" + _version
|
|
822
877
|
cmd = f"git tag -a {_version} -m {self.message!r} && git push --tags"
|
|
823
878
|
if self.should_push():
|
|
824
879
|
cmd += " && git push"
|
|
825
|
-
if Project.
|
|
826
|
-
cmd = "
|
|
880
|
+
if should_sync and not self._no_sync and (sync := Project.get_sync_command()):
|
|
881
|
+
cmd = f"{sync} && " + cmd
|
|
827
882
|
return cmd
|
|
828
883
|
|
|
829
884
|
@cached_property
|
|
830
|
-
def git_status(self
|
|
885
|
+
def git_status(self) -> str:
|
|
831
886
|
return capture_cmd_output("git status")
|
|
832
887
|
|
|
833
|
-
def mark_tag(self
|
|
888
|
+
def mark_tag(self) -> bool:
|
|
834
889
|
if not re.search(r"working (tree|directory) clean", self.git_status) and (
|
|
835
890
|
"无文件要提交,干净的工作区" not in self.git_status
|
|
836
891
|
):
|
|
@@ -839,7 +894,7 @@ class GitTag(DryRun):
|
|
|
839
894
|
return False
|
|
840
895
|
return bool(super().run())
|
|
841
896
|
|
|
842
|
-
def run(self
|
|
897
|
+
def run(self) -> None:
|
|
843
898
|
if self.mark_tag() and not self.dry:
|
|
844
899
|
echo("You may want to publish package:\n poetry publish --build")
|
|
845
900
|
|
|
@@ -847,15 +902,18 @@ class GitTag(DryRun):
|
|
|
847
902
|
@cli.command()
|
|
848
903
|
def tag(
|
|
849
904
|
message: str = Option("", "-m", "--message"),
|
|
905
|
+
no_sync: bool = Option(
|
|
906
|
+
False, "--no-sync", help="Do not run sync command to update version"
|
|
907
|
+
),
|
|
850
908
|
dry: bool = DryOption,
|
|
851
909
|
) -> None:
|
|
852
910
|
"""Run shell command: git tag -a <current-version-in-pyproject.toml> -m {message}"""
|
|
853
|
-
GitTag(message, dry=dry).run()
|
|
911
|
+
GitTag(message, dry=dry, no_sync=_ensure_bool(no_sync)).run()
|
|
854
912
|
|
|
855
913
|
|
|
856
914
|
class LintCode(DryRun):
|
|
857
915
|
def __init__(
|
|
858
|
-
self
|
|
916
|
+
self,
|
|
859
917
|
args: list[str] | str | None,
|
|
860
918
|
check_only: bool = False,
|
|
861
919
|
_exit: bool = False,
|
|
@@ -921,10 +979,21 @@ class LintCode(DryRun):
|
|
|
921
979
|
lint_them = " && ".join(
|
|
922
980
|
"{0}{" + str(i) + "} {1}" for i in range(2, len(tools) + 2)
|
|
923
981
|
)
|
|
982
|
+
if ruff_exists := cls.check_lint_tool_installed():
|
|
983
|
+
# `ruff <command>` get the same result with `pdm run ruff <command>`
|
|
984
|
+
# While `mypy .`(installed global and env not activated),
|
|
985
|
+
# does not the same as `pdm run mypy .`
|
|
986
|
+
lint_them = " && ".join(
|
|
987
|
+
("" if tool.startswith("ruff") else "{0}")
|
|
988
|
+
+ (
|
|
989
|
+
"{%d} {1}" % i # noqa: UP031
|
|
990
|
+
)
|
|
991
|
+
for i, tool in enumerate(tools, 2)
|
|
992
|
+
)
|
|
924
993
|
prefix = ""
|
|
925
994
|
should_run_by_tool = False
|
|
926
995
|
if is_venv() and Path(sys.argv[0]).parent != Path.home().joinpath(".local/bin"):
|
|
927
|
-
if not
|
|
996
|
+
if not ruff_exists:
|
|
928
997
|
should_run_by_tool = True
|
|
929
998
|
if check_call('python -c "import fast_dev_cli"'):
|
|
930
999
|
command = 'python -m pip install -U "fast-dev-cli"'
|
|
@@ -936,7 +1005,11 @@ class LintCode(DryRun):
|
|
|
936
1005
|
if tool == ToolOption.default:
|
|
937
1006
|
tool = Project.get_manage_tool() or ""
|
|
938
1007
|
if tool:
|
|
939
|
-
prefix =
|
|
1008
|
+
prefix = (
|
|
1009
|
+
str(bin_dir)
|
|
1010
|
+
if tool == "uv" and (bin_dir := Path(".venv/bin/")).exists()
|
|
1011
|
+
else (tool + " run ")
|
|
1012
|
+
)
|
|
940
1013
|
if cls.prefer_dmypy(paths, tools, use_dmypy=use_dmypy):
|
|
941
1014
|
tools[-1] = "dmypy run"
|
|
942
1015
|
cmd += lint_them.format(prefix, paths, *tools)
|
|
@@ -952,7 +1025,7 @@ class LintCode(DryRun):
|
|
|
952
1025
|
cmd += " && " + command
|
|
953
1026
|
return cmd
|
|
954
1027
|
|
|
955
|
-
def gen(self
|
|
1028
|
+
def gen(self) -> str:
|
|
956
1029
|
if isinstance(args := self.args, str):
|
|
957
1030
|
args = args.split()
|
|
958
1031
|
paths = " ".join(map(str, args)) if args else "."
|
|
@@ -1041,7 +1114,7 @@ def only_check(
|
|
|
1041
1114
|
|
|
1042
1115
|
class Sync(DryRun):
|
|
1043
1116
|
def __init__(
|
|
1044
|
-
self
|
|
1117
|
+
self, filename: str, extras: str, save: bool, dry: bool = False
|
|
1045
1118
|
) -> None:
|
|
1046
1119
|
self.filename = filename
|
|
1047
1120
|
self.extras = extras
|
|
@@ -1192,7 +1265,7 @@ def runserver(
|
|
|
1192
1265
|
|
|
1193
1266
|
@cli.command(name="exec")
|
|
1194
1267
|
def run_by_subprocess(cmd: str, dry: bool = DryOption) -> None:
|
|
1195
|
-
"""Run cmd by subprocess, auto set shell=True when cmd contains '
|
|
1268
|
+
"""Run cmd by subprocess, auto set shell=True when cmd contains '|>'"""
|
|
1196
1269
|
try:
|
|
1197
1270
|
rc = run_and_echo(cmd, verbose=True, dry=_ensure_bool(dry))
|
|
1198
1271
|
except FileNotFoundError as e:
|
|
@@ -1205,6 +1278,26 @@ def run_by_subprocess(cmd: str, dry: bool = DryOption) -> None:
|
|
|
1205
1278
|
raise Exit(rc)
|
|
1206
1279
|
|
|
1207
1280
|
|
|
1281
|
+
def version_callback(value: bool) -> None:
|
|
1282
|
+
if value:
|
|
1283
|
+
echo("Fast Dev Cli Version: " + typer.style(__version__, bold=True))
|
|
1284
|
+
raise Exit()
|
|
1285
|
+
|
|
1286
|
+
|
|
1287
|
+
@cli.callback()
|
|
1288
|
+
def common(
|
|
1289
|
+
version: bool = Option(
|
|
1290
|
+
None,
|
|
1291
|
+
"--version",
|
|
1292
|
+
"-V",
|
|
1293
|
+
callback=version_callback,
|
|
1294
|
+
is_eager=True,
|
|
1295
|
+
help="Show the version of this tool",
|
|
1296
|
+
),
|
|
1297
|
+
) -> None:
|
|
1298
|
+
pass
|
|
1299
|
+
|
|
1300
|
+
|
|
1208
1301
|
def main() -> None:
|
|
1209
1302
|
cli()
|
|
1210
1303
|
|
|
@@ -42,7 +42,7 @@ dependencies = [
|
|
|
42
42
|
"bumpversion2 >=1.4.3,<2",
|
|
43
43
|
"pytest >=8.2.0,<9",
|
|
44
44
|
]
|
|
45
|
-
version = "0.17.
|
|
45
|
+
version = "0.17.1"
|
|
46
46
|
|
|
47
47
|
[project.urls]
|
|
48
48
|
Homepage = "https://github.com/waketzheng/fast-dev-cli"
|
|
@@ -59,6 +59,9 @@ fast = "fast_dev_cli:cli.main"
|
|
|
59
59
|
dev = [
|
|
60
60
|
"twine>=6.1.0",
|
|
61
61
|
]
|
|
62
|
+
test = [
|
|
63
|
+
"asynctor>=0.8.6",
|
|
64
|
+
]
|
|
62
65
|
|
|
63
66
|
[tool.pdm]
|
|
64
67
|
distribution = true
|
|
@@ -150,7 +153,7 @@ omit = [
|
|
|
150
153
|
context = "${CONTEXT}"
|
|
151
154
|
|
|
152
155
|
[tool.coverage.report]
|
|
153
|
-
|
|
156
|
+
exclude_also = [
|
|
154
157
|
"pragma: no cover",
|
|
155
158
|
"@overload",
|
|
156
159
|
"if __name__ == \"__main__\":",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import sys
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
|
|
3
4
|
import pytest
|
|
5
|
+
from asynctor.compat import chdir
|
|
4
6
|
|
|
5
|
-
from fast_dev_cli.cli import TOML_FILE
|
|
6
|
-
|
|
7
|
-
from .utils import chdir
|
|
7
|
+
from fast_dev_cli.cli import TOML_FILE, run_and_echo
|
|
8
8
|
|
|
9
9
|
# toml file content before migrate to pdm
|
|
10
10
|
TOML_CONTENT = """
|
|
@@ -59,4 +59,6 @@ def tmp_work_dir(tmp_path):
|
|
|
59
59
|
@pytest.fixture
|
|
60
60
|
def tmp_poetry_project(tmp_work_dir: Path):
|
|
61
61
|
Path(TOML_FILE).write_text(TOML_CONTENT)
|
|
62
|
+
if sys.version_info >= (3, 10):
|
|
63
|
+
run_and_echo("poetry config --local virtualenvs.in-project true")
|
|
62
64
|
yield tmp_work_dir
|
|
@@ -22,6 +22,7 @@ from fast_dev_cli.cli import (
|
|
|
22
22
|
bump_version,
|
|
23
23
|
capture_cmd_output,
|
|
24
24
|
get_current_version,
|
|
25
|
+
run_and_echo,
|
|
25
26
|
)
|
|
26
27
|
|
|
27
28
|
from .utils import chdir, mock_sys_argv, prepare_poetry_project
|
|
@@ -102,35 +103,38 @@ def test_bump(
|
|
|
102
103
|
|
|
103
104
|
def test_bump_with_poetry(mocker, tmp_poetry_project, tmp_path):
|
|
104
105
|
mocker.patch("builtins.input", return_value=" ")
|
|
105
|
-
version = get_current_version()
|
|
106
|
+
version = get_current_version(check_version=False)
|
|
106
107
|
patch_without_commit, patch_with_commit, minor_with_commit = _bump_commands(
|
|
107
108
|
version, add_sync=False
|
|
108
109
|
)
|
|
109
110
|
stream = StringIO()
|
|
110
111
|
with redirect_stdout(stream):
|
|
111
|
-
BumpUp(part="patch", commit=False).run()
|
|
112
|
+
BumpUp(part="patch", commit=False, no_sync=True).run()
|
|
112
113
|
assert f"Current version(@{TOML_FILE}):" in stream.getvalue()
|
|
113
114
|
stream = StringIO()
|
|
114
115
|
with redirect_stdout(stream):
|
|
115
|
-
BumpUp(part="minor", commit=False).run()
|
|
116
|
+
BumpUp(part="minor", commit=False, no_sync=True).run()
|
|
116
117
|
assert "You may want to pin tag by `fast tag`" in stream.getvalue()
|
|
117
118
|
stream = StringIO()
|
|
118
119
|
new_version = get_current_version()
|
|
119
120
|
with redirect_stdout(stream):
|
|
120
|
-
bump_version(BumpUp.PartChoices.patch, commit=False, dry=True)
|
|
121
|
+
bump_version(BumpUp.PartChoices.patch, commit=False, dry=True, no_sync=True)
|
|
121
122
|
assert patch_without_commit.replace(version, new_version) in stream.getvalue()
|
|
122
123
|
stream = StringIO()
|
|
123
|
-
with redirect_stdout(stream), mock_sys_argv(["patch", "--dry"]):
|
|
124
|
+
with redirect_stdout(stream), mock_sys_argv(["patch", "--dry", "--no-sync"]):
|
|
124
125
|
bump()
|
|
125
126
|
assert patch_without_commit.replace(version, new_version) in stream.getvalue()
|
|
126
127
|
stream = StringIO()
|
|
127
|
-
with
|
|
128
|
+
with (
|
|
129
|
+
redirect_stdout(stream),
|
|
130
|
+
mock_sys_argv(["patch", "--commit", "--dry", "--no-sync"]),
|
|
131
|
+
):
|
|
128
132
|
bump()
|
|
129
133
|
assert patch_with_commit.replace(version, new_version) in stream.getvalue()
|
|
130
134
|
stream = StringIO()
|
|
131
135
|
with (
|
|
132
136
|
redirect_stdout(stream),
|
|
133
|
-
mock_sys_argv(["-c", "minor", "--commit", "--dry"]),
|
|
137
|
+
mock_sys_argv(["-c", "minor", "--commit", "--dry", "--no-sync"]),
|
|
134
138
|
):
|
|
135
139
|
bump()
|
|
136
140
|
assert minor_with_commit.replace(version, new_version) in stream.getvalue()
|
|
@@ -182,7 +186,7 @@ def test_bump_with_emoji_in_poetry_project(mocker, tmp_path, monkeypatch):
|
|
|
182
186
|
assert BumpUp.should_add_emoji() is False
|
|
183
187
|
subprocess.run(["git", "commit", "-m", last_commit])
|
|
184
188
|
monkeypatch.setenv("DONT_GIT_PUSH", "1")
|
|
185
|
-
command = BumpUp(part="patch", commit=True).gen()
|
|
189
|
+
command = BumpUp(part="patch", commit=True, no_sync=True).gen()
|
|
186
190
|
expected = patch_with_commit.split("&&")[0].strip().replace('""', '"0.1.0"')
|
|
187
191
|
assert expected == command
|
|
188
192
|
subprocess.run(["poetry", "run", "pip", "install", "bumpversion2"])
|
|
@@ -267,6 +271,15 @@ def test_pdm_project(dynamic_pdm_project):
|
|
|
267
271
|
out = capture_cmd_output("fast bump patch")
|
|
268
272
|
assert str(init_file) in out
|
|
269
273
|
assert "0.2.1" in init_file.read_text()
|
|
274
|
+
run_and_echo("git init")
|
|
275
|
+
shutil.copy(Path(__file__).parent.parent / ".gitignore", ".")
|
|
276
|
+
run_and_echo("git add .")
|
|
277
|
+
run_and_echo("git config user.name xxx")
|
|
278
|
+
run_and_echo("git config user.email xxx@a.com")
|
|
279
|
+
run_and_echo('git commit -m "xxx"')
|
|
280
|
+
out = capture_cmd_output("fast bump patch --emoji --commit")
|
|
281
|
+
assert "--message-emoji=1" in out
|
|
282
|
+
assert "⬆️ Bump version: 0.2.1 → 0.2.2" in capture_cmd_output("git log")
|
|
270
283
|
|
|
271
284
|
|
|
272
285
|
def test_installed_version_is_0_0_0(dynamic_pdm_project):
|
|
@@ -160,14 +160,6 @@ def test_lint_html():
|
|
|
160
160
|
assert LintCode.to_cmd("index.html flv.html") == "prettier -w index.html flv.html"
|
|
161
161
|
|
|
162
162
|
|
|
163
|
-
def test_lint_by_global_fast():
|
|
164
|
-
run = "pdm run "
|
|
165
|
-
fast = Path.home() / ".local" / "bin" / "fast"
|
|
166
|
-
command = capture_cmd_output(f"{fast} lint --dry")
|
|
167
|
-
for cmd in command.split(SEP):
|
|
168
|
-
assert run in cmd
|
|
169
|
-
|
|
170
|
-
|
|
171
163
|
def test_with_dmypy():
|
|
172
164
|
cmd = "fast lint --dmypy --dry ."
|
|
173
165
|
assert "dmypy run ." in capture_cmd_output(cmd)
|
|
@@ -38,21 +38,20 @@ def _prepare_package(
|
|
|
38
38
|
a, b = 'version = "0.1.0"', f'version = "{mark}"'
|
|
39
39
|
if define_include:
|
|
40
40
|
b += f'\npackages = [{{include = "{package_name}"}}]'
|
|
41
|
+
py_version = "{}.{}".format(*sys.version_info)
|
|
41
42
|
with chdir(package_path.parent):
|
|
42
|
-
run_and_echo(
|
|
43
|
+
run_and_echo(
|
|
44
|
+
f'poetry new --python="^{py_version}" --no-interaction "{package_path.name}"'
|
|
45
|
+
)
|
|
43
46
|
src_dir = package_path / "src"
|
|
44
47
|
if is_src_layout := src_dir.exists():
|
|
45
48
|
# poetry v2 default to use src/<package_name> layout
|
|
46
49
|
init_file = src_dir / package_name / init_file.name
|
|
47
|
-
toml_file.unlink()
|
|
48
|
-
py_version = "{}.{}".format(*sys.version_info)
|
|
49
50
|
with chdir(package_path):
|
|
50
|
-
run_and_echo(
|
|
51
|
+
run_and_echo("poetry config --local virtualenvs.in-project true")
|
|
51
52
|
text = toml_file.read_text().replace(a, b)
|
|
52
53
|
if " " in package_path.name:
|
|
53
|
-
text = text.replace(
|
|
54
|
-
f'name = "{package_path.name}"', f'name = "{package_name}"'
|
|
55
|
-
)
|
|
54
|
+
text = text.replace(f'"{package_path.name}"', f'"{package_name}"')
|
|
56
55
|
toml_file.write_text(text + CONF)
|
|
57
56
|
if package_path.name != package_name:
|
|
58
57
|
if is_src_layout:
|
|
@@ -63,15 +62,21 @@ def _prepare_package(
|
|
|
63
62
|
yield init_file
|
|
64
63
|
|
|
65
64
|
|
|
66
|
-
def _build_bump_cmd(
|
|
65
|
+
def _build_bump_cmd(
|
|
66
|
+
init_file: Path, project_path: Path, should_sync: bool = False
|
|
67
|
+
) -> str:
|
|
67
68
|
relative_path = init_file.relative_to(project_path).as_posix()
|
|
68
|
-
|
|
69
|
+
cmd = rf'bumpversion --parse "(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)" --current-version="0.0.1" patch {relative_path} --allow-dirty'
|
|
70
|
+
if should_sync:
|
|
71
|
+
cmd = "poetry install && " + cmd
|
|
72
|
+
return cmd
|
|
69
73
|
|
|
70
74
|
|
|
71
|
-
|
|
75
|
+
@pytest.mark.parametrize("mark", ["0", "0.0.0"])
|
|
76
|
+
def test_version_plugin(mark, tmp_path: Path) -> None:
|
|
72
77
|
project_path = tmp_path / "helloworld"
|
|
73
|
-
with _prepare_package(project_path) as init_file:
|
|
74
|
-
command = _build_bump_cmd(init_file, project_path)
|
|
78
|
+
with _prepare_package(project_path, mark=mark) as init_file:
|
|
79
|
+
command = _build_bump_cmd(init_file, project_path, should_sync=True)
|
|
75
80
|
assert BumpUp(part="patch", commit=False, dry=True).gen() == command
|
|
76
81
|
run_and_echo("poetry run fast bump patch")
|
|
77
82
|
assert init_file.read_text() == '__version__ = "0.0.2"\n'
|
|
@@ -80,31 +85,11 @@ def test_version_plugin(tmp_path: Path) -> None:
|
|
|
80
85
|
BumpUp(part="patch", commit=False, dry=True).gen()
|
|
81
86
|
|
|
82
87
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
with _prepare_package(project_path, mark="0.0.0") as init_file:
|
|
86
|
-
command = _build_bump_cmd(init_file, project_path)
|
|
87
|
-
assert BumpUp(part="patch", commit=False, dry=True).gen() == command
|
|
88
|
-
run_and_echo("poetry run fast bump patch")
|
|
89
|
-
assert init_file.read_text() == '__version__ = "0.0.2"\n'
|
|
90
|
-
init_file.unlink()
|
|
91
|
-
with pytest.raises(ParseError, match=r"Version file not found!.*"):
|
|
92
|
-
BumpUp(part="patch", commit=False, dry=True).gen()
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def test_version_plugin_include_defined(tmp_path: Path) -> None:
|
|
96
|
-
project_path = tmp_path / "hello world"
|
|
97
|
-
with _prepare_package(project_path, True) as init_file:
|
|
98
|
-
command = _build_bump_cmd(init_file, project_path)
|
|
99
|
-
assert BumpUp(part="patch", commit=False, dry=True).gen() == command
|
|
100
|
-
run_and_echo("poetry run fast bump patch")
|
|
101
|
-
assert init_file.read_text() == '__version__ = "0.0.2"\n'
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def test_version_plugin_include_defined_2(tmp_path: Path) -> None:
|
|
88
|
+
@pytest.mark.parametrize("mark", ["0", "0.0.0"])
|
|
89
|
+
def test_version_plugin_include_defined(mark, tmp_path: Path) -> None:
|
|
105
90
|
project_path = tmp_path / "hello world"
|
|
106
|
-
with _prepare_package(project_path, True, mark=
|
|
107
|
-
command = _build_bump_cmd(init_file, project_path)
|
|
91
|
+
with _prepare_package(project_path, True, mark=mark) as init_file:
|
|
92
|
+
command = _build_bump_cmd(init_file, project_path, should_sync=True)
|
|
108
93
|
assert BumpUp(part="patch", commit=False, dry=True).gen() == command
|
|
109
94
|
run_and_echo("poetry run fast bump patch")
|
|
110
95
|
assert init_file.read_text() == '__version__ = "0.0.2"\n'
|
|
@@ -50,16 +50,24 @@ def _clear_tags():
|
|
|
50
50
|
def test_with_push(mocker):
|
|
51
51
|
git_tag = GitTag("", dry=True)
|
|
52
52
|
mocker.patch.object(git_tag, "git_status", return_value="git push")
|
|
53
|
-
version = get_current_version()
|
|
53
|
+
should_sync, version = get_current_version(check_version=True)
|
|
54
54
|
prefix = "v" if "v" in capture_cmd_output(["git", "tag"]) else ""
|
|
55
55
|
sync = "pdm sync --prod"
|
|
56
56
|
push = "git push --tags"
|
|
57
|
-
|
|
57
|
+
expected = f"git tag -a {prefix}{version} -m '' && {push}"
|
|
58
|
+
if should_sync:
|
|
59
|
+
expected = f"{sync} && " + expected
|
|
60
|
+
assert git_tag.gen() == expected
|
|
58
61
|
with _clear_tags():
|
|
59
62
|
git_tag_cmd = git_tag.gen()
|
|
60
|
-
|
|
63
|
+
expected = f"git tag -a {version} -m '' && {push}"
|
|
64
|
+
if should_sync:
|
|
65
|
+
expected = f"{sync} && " + expected
|
|
66
|
+
assert git_tag_cmd == expected
|
|
61
67
|
mocker.patch.object(git_tag, "has_v_prefix", return_value=True)
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
expected = f"git tag -a v{version} -m '' && {push}"
|
|
69
|
+
if should_sync:
|
|
70
|
+
expected = f"{sync} && " + expected
|
|
71
|
+
assert git_tag.gen() == expected
|
|
64
72
|
mocker.patch.object(git_tag, "should_push", return_value=True)
|
|
65
|
-
assert git_tag.gen() ==
|
|
73
|
+
assert git_tag.gen() == expected + " && git push"
|
|
@@ -292,7 +292,7 @@ fastapi = "^0.112.2"
|
|
|
292
292
|
|
|
293
293
|
def test_upgrade_uv_project():
|
|
294
294
|
cmd = "fast upgrade --tool=uv --dry"
|
|
295
|
-
expected = "uv lock --upgrade --verbose && uv sync --frozen --all-groups"
|
|
295
|
+
expected = "uv lock --upgrade --verbose && uv sync --inexact --frozen --all-groups --all-extras"
|
|
296
296
|
assert expected in capture_cmd_output(cmd)
|
|
297
297
|
assert expected in capture_cmd_output("pdm run " + cmd)
|
|
298
298
|
assert UpgradeDependencies(tool="uv").gen() == expected
|
|
@@ -300,7 +300,7 @@ def test_upgrade_uv_project():
|
|
|
300
300
|
|
|
301
301
|
def test_upgrade_pdm_project():
|
|
302
302
|
cmd = "fast upgrade --tool=pdm --dry"
|
|
303
|
-
expected = "pdm update --verbose && pdm sync -G :all"
|
|
303
|
+
expected = "pdm update --verbose && pdm sync -G :all --frozen"
|
|
304
304
|
assert expected in capture_cmd_output(cmd)
|
|
305
305
|
assert expected in capture_cmd_output("pdm run " + cmd)
|
|
306
306
|
assert UpgradeDependencies(tool="pdm").gen() == expected
|
|
@@ -2,19 +2,21 @@ import re
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
4
|
import pytest
|
|
5
|
+
from asynctor import Shell
|
|
6
|
+
from asynctor.compat import chdir
|
|
5
7
|
|
|
6
8
|
from fast_dev_cli import __version__
|
|
7
9
|
from fast_dev_cli.cli import (
|
|
8
10
|
TOML_FILE,
|
|
11
|
+
Exit,
|
|
9
12
|
ShellCommandError,
|
|
10
13
|
_parse_version,
|
|
11
14
|
get_current_version,
|
|
12
15
|
read_version_from_file,
|
|
13
16
|
version,
|
|
17
|
+
version_callback,
|
|
14
18
|
)
|
|
15
19
|
|
|
16
|
-
from .utils import chdir
|
|
17
|
-
|
|
18
20
|
|
|
19
21
|
def test_version(capsys):
|
|
20
22
|
version()
|
|
@@ -58,3 +60,19 @@ def test_parse_version():
|
|
|
58
60
|
assert _parse_version(line, pattern) == "0.0.1"
|
|
59
61
|
line = '__version__ = "0.0.1" # 0.0.2'
|
|
60
62
|
assert _parse_version(line, pattern) == "0.0.1"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_display_self_version(capsys):
|
|
66
|
+
with pytest.raises(Exit):
|
|
67
|
+
version_callback(True)
|
|
68
|
+
assert __version__ in capsys.readouterr().out
|
|
69
|
+
out = Shell("fast --version").capture_output().strip()
|
|
70
|
+
assert out == "Fast Dev Cli Version: 0.17.0"
|
|
71
|
+
out_v = Shell("fast -V").capture_output().strip()
|
|
72
|
+
assert out_v == out
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_fast_version(capsys):
|
|
76
|
+
out = Shell("fast version").capture_output().strip()
|
|
77
|
+
assert "Fast Dev Cli Version: 0.17.0" in out
|
|
78
|
+
assert "fast_dev_cli/__init__.py: 0.17.0" in out
|
|
@@ -1,29 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import subprocess
|
|
1
|
+
import shutil
|
|
3
2
|
import sys
|
|
4
|
-
from contextlib import
|
|
3
|
+
from contextlib import contextmanager, redirect_stdout
|
|
5
4
|
from io import StringIO
|
|
6
5
|
from pathlib import Path
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class chdir(AbstractContextManager): # Copied from source code of Python3.13
|
|
11
|
-
"""Non thread-safe context manager to change the current working directory."""
|
|
12
|
-
|
|
13
|
-
def __init__(self, path):
|
|
14
|
-
self.path = path
|
|
15
|
-
self._old_cwd = []
|
|
16
|
-
|
|
17
|
-
def __enter__(self):
|
|
18
|
-
self._old_cwd.append(os.getcwd())
|
|
19
|
-
os.chdir(self.path)
|
|
20
|
-
|
|
21
|
-
def __exit__(self, *excinfo):
|
|
22
|
-
os.chdir(self._old_cwd.pop())
|
|
23
|
-
|
|
7
|
+
from asynctor import Shell
|
|
8
|
+
from asynctor.compat import chdir
|
|
24
9
|
|
|
25
10
|
__all__ = (
|
|
26
|
-
"chdir",
|
|
27
11
|
"mock_sys_argv",
|
|
28
12
|
"capture_stdout",
|
|
29
13
|
"temp_file",
|
|
@@ -68,8 +52,16 @@ def temp_file(name: str, text=""):
|
|
|
68
52
|
|
|
69
53
|
@contextmanager
|
|
70
54
|
def prepare_poetry_project(tmp_path: Path):
|
|
55
|
+
py = "{}.{}".format(*sys.version_info)
|
|
56
|
+
poetry = "poetry"
|
|
57
|
+
if shutil.which(poetry) is None:
|
|
58
|
+
poetry = "uvx " + poetry
|
|
71
59
|
with chdir(tmp_path):
|
|
72
60
|
project = "foo"
|
|
73
|
-
|
|
61
|
+
Shell.run_by_subprocess(f"{poetry} new {project} --python=^{py}")
|
|
74
62
|
with chdir(tmp_path / project):
|
|
63
|
+
Shell.run_by_subprocess(
|
|
64
|
+
f"{poetry} config --local virtualenvs.in-project true"
|
|
65
|
+
)
|
|
66
|
+
Shell.run_by_subprocess(f"{poetry} env use {py}")
|
|
75
67
|
yield
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.17.0"
|
|
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
|