fast-dev-cli 0.18.4__tar.gz → 0.18.5__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.
Files changed (34) hide show
  1. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/PKG-INFO +1 -1
  2. fast_dev_cli-0.18.5/fast_dev_cli/__init__.py +1 -0
  3. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/fast_dev_cli/cli.py +114 -52
  4. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/pyproject.toml +1 -1
  5. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_bump.py +8 -8
  6. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_deps.py +3 -3
  7. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_fast_test.py +1 -1
  8. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_functions.py +8 -0
  9. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_poetry_version_plugin.py +7 -0
  10. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_upgrade.py +14 -19
  11. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/utils.py +5 -3
  12. fast_dev_cli-0.18.4/fast_dev_cli/__init__.py +0 -1
  13. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/LICENSE +0 -0
  14. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/README.md +0 -0
  15. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/fast_dev_cli/__main__.py +0 -0
  16. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/fast_dev_cli/py.typed +0 -0
  17. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/pdm_build.py +0 -0
  18. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/scripts/check.py +0 -0
  19. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/scripts/deps.py +0 -0
  20. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/scripts/format.py +0 -0
  21. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/scripts/test.py +0 -0
  22. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/__init__.py +0 -0
  23. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/assets/uv-tx.lock +0 -0
  24. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/assets/uv.lock +0 -0
  25. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/conftest.py +0 -0
  26. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_exec.py +0 -0
  27. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_help.py +0 -0
  28. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_lint.py +0 -0
  29. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_pypi.py +0 -0
  30. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_runserver.py +0 -0
  31. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_sync.py +0 -0
  32. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_tag.py +0 -0
  33. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_upload.py +0 -0
  34. {fast_dev_cli-0.18.4 → fast_dev_cli-0.18.5}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fast-dev-cli
3
- Version: 0.18.4
3
+ Version: 0.18.5
4
4
  Summary: Python project development tool.
5
5
  Author-Email: Waket Zheng <waketzheng@gmail.com>>
6
6
  Classifier: Development Status :: 4 - Beta
@@ -0,0 +1 @@
1
+ __version__ = "0.18.5"
@@ -4,6 +4,7 @@ import contextlib
4
4
  import functools
5
5
  import importlib.metadata as importlib_metadata
6
6
  import os
7
+ import platform
7
8
  import re
8
9
  import shlex
9
10
  import shutil
@@ -102,6 +103,11 @@ def is_emoji(char: str) -> bool:
102
103
  return not "\u4e00" <= char <= "\u9fff" # Chinese character
103
104
 
104
105
 
106
+ @functools.cache
107
+ def is_windows() -> bool:
108
+ return platform.system() == "Windows"
109
+
110
+
105
111
  def yellow_warn(msg: str) -> None:
106
112
  secho(msg, fg="yellow")
107
113
 
@@ -124,40 +130,92 @@ def is_venv() -> bool:
124
130
  )
125
131
 
126
132
 
127
- def _run_shell(cmd: list[str] | str, **kw: Any) -> subprocess.CompletedProcess[str]:
128
- if isinstance(cmd, str):
129
- kw.setdefault("shell", True)
130
- return subprocess.run(cmd, **kw) # nosec:B603
133
+ class Shell:
134
+ def __init__(self, cmd: list[str] | str, **kw: Any) -> None:
135
+ self._cmd = cmd
136
+ self._kw = kw
137
+
138
+ @staticmethod
139
+ def run_by_subprocess(
140
+ cmd: list[str] | str, **kw: Any
141
+ ) -> subprocess.CompletedProcess[str]:
142
+ if isinstance(cmd, str):
143
+ kw.setdefault("shell", True)
144
+ return subprocess.run(cmd, **kw) # nosec:B603
145
+
146
+ @property
147
+ def command(self) -> list[str] | str:
148
+ command: list[str] | str = self._cmd
149
+ if (
150
+ isinstance(command, str)
151
+ and "shell" not in self._kw
152
+ and not (set(self._cmd) & {"|", ">", "&"})
153
+ ):
154
+ command = shlex.split(command)
155
+ return command
156
+
157
+ def _run(self) -> subprocess.CompletedProcess[str]:
158
+ return self.run_by_subprocess(self.command, **self._kw)
159
+
160
+ def run(self, verbose: bool = False, dry: bool = False) -> int:
161
+ if verbose:
162
+ echo(f"--> {self._cmd}")
163
+ if dry:
164
+ return 0
165
+ return self._run().returncode
166
+
167
+ def check_call(self) -> bool:
168
+ self._kw.update(stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
169
+ return self.run() == 0
170
+
171
+ def capture_output(self, raises: bool = False) -> str:
172
+ self._kw.update(capture_output=True, encoding="utf-8")
173
+ r = self._run()
174
+ if raises and r.returncode != 0:
175
+ raise ShellCommandError(r.stderr)
176
+ return (r.stdout or r.stderr or "").strip()
177
+
178
+ def finish(
179
+ self, env: dict[str, str] | None = None, _exit: bool = False, dry=False
180
+ ) -> subprocess.CompletedProcess[str]:
181
+ self.run(verbose=True, dry=True)
182
+ if _ensure_bool(dry):
183
+ return subprocess.CompletedProcess("", 0)
184
+ if env is not None:
185
+ self._kw["env"] = {**os.environ, **env}
186
+ r = self._run()
187
+ if rc := r.returncode:
188
+ if _exit:
189
+ sys.exit(rc)
190
+ raise Exit(rc)
191
+ return r
131
192
 
132
193
 
133
194
  def run_and_echo(
134
195
  cmd: str, *, dry: bool = False, verbose: bool = True, **kw: Any
135
196
  ) -> int:
136
197
  """Run shell command with subprocess and print it"""
137
- if verbose:
138
- echo(f"--> {cmd}")
139
- if dry:
140
- return 0
141
- command: list[str] | str = cmd
142
- if "shell" not in kw and not (set(cmd) & {"|", ">", "&"}):
143
- command = shlex.split(cmd)
144
- return _run_shell(command, **kw).returncode
198
+ return Shell(cmd, **kw).run(verbose=verbose, dry=dry)
145
199
 
146
200
 
147
201
  def check_call(cmd: str) -> bool:
148
- r = _run_shell(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
149
- return r.returncode == 0
202
+ return Shell(cmd).check_call()
150
203
 
151
204
 
152
205
  def capture_cmd_output(
153
206
  command: list[str] | str, *, raises: bool = False, **kw: Any
154
207
  ) -> str:
155
- if isinstance(command, str) and not kw.get("shell"):
156
- command = shlex.split(command)
157
- r = _run_shell(command, capture_output=True, encoding="utf-8", **kw)
158
- if raises and r.returncode != 0:
159
- raise ShellCommandError(r.stderr)
160
- return r.stdout.strip() or r.stderr
208
+ return Shell(command, **kw).capture_output(raises=raises)
209
+
210
+
211
+ def exit_if_run_failed(
212
+ cmd: str,
213
+ env: dict[str, str] | None = None,
214
+ _exit: bool = False,
215
+ dry: bool = False,
216
+ **kw: Any,
217
+ ) -> subprocess.CompletedProcess[str]:
218
+ return Shell(cmd, **kw).finish(env=env, _exit=_exit, dry=dry)
161
219
 
162
220
 
163
221
  def _parse_version(line: str, pattern: re.Pattern[str]) -> str:
@@ -276,26 +334,6 @@ def _ensure_str(value: str | OptionInfo | None) -> str:
276
334
  return value
277
335
 
278
336
 
279
- def exit_if_run_failed(
280
- cmd: str,
281
- env: dict[str, str] | None = None,
282
- _exit: bool = False,
283
- dry: bool = False,
284
- **kw: Any,
285
- ) -> subprocess.CompletedProcess[str]:
286
- run_and_echo(cmd, dry=True)
287
- if _ensure_bool(dry):
288
- return subprocess.CompletedProcess("", 0)
289
- if env is not None:
290
- env = {**os.environ, **env}
291
- r = _run_shell(cmd, env=env, **kw)
292
- if rc := r.returncode:
293
- if _exit:
294
- sys.exit(rc)
295
- raise Exit(rc)
296
- return r
297
-
298
-
299
337
  class DryRun:
300
338
  def __init__(self, _exit: bool = False, dry: bool = False) -> None:
301
339
  self.dry = _ensure_bool(dry)
@@ -561,6 +599,19 @@ class Project:
561
599
  def is_poetry_v2(text: str) -> bool:
562
600
  return 'build-backend = "poetry' in text
563
601
 
602
+ @staticmethod
603
+ def get_poetry_version(command: str = "poetry") -> str:
604
+ pattern = r"(\d+\.\d+\.\d+)"
605
+ text = capture_cmd_output(f"{command} --version")
606
+ for expr in (
607
+ rf"Poetry \(version {pattern}\)",
608
+ rf"Poetry.*version.*{pattern}.*\)",
609
+ rf"{pattern}",
610
+ ):
611
+ if m := re.search(expr, text):
612
+ return m.group(1)
613
+ return ""
614
+
564
615
  @staticmethod
565
616
  def work_dir(
566
617
  name: str, parent: Path, depth: int, be_file: bool = False
@@ -657,7 +708,7 @@ class Project:
657
708
  @classmethod
658
709
  def get_sync_command(cls, prod: bool = True, doc: dict | None = None) -> str:
659
710
  if cls.is_pdm_project():
660
- return "pdm sync" + " --prod" * prod
711
+ return "pdm install --frozen" + " --prod" * prod
661
712
  elif cls.manage_by_poetry(cache=True):
662
713
  cmd = "poetry install"
663
714
  if prod:
@@ -854,7 +905,7 @@ class UpgradeDependencies(Project, DryRun):
854
905
  deps = "uv sync --inexact --frozen --all-groups --all-extras"
855
906
  return f"{up} && {deps}"
856
907
  elif self._tool == "pdm":
857
- return "pdm update --verbose && pdm sync -G :all --frozen"
908
+ return "pdm update --verbose && pdm install -G :all --frozen"
858
909
  return self.gen_cmd() + " && poetry lock && poetry update"
859
910
 
860
911
 
@@ -1044,11 +1095,12 @@ class LintCode(DryRun):
1044
1095
  if tool == ToolOption.default:
1045
1096
  tool = Project.get_manage_tool() or ""
1046
1097
  if tool:
1047
- prefix = (
1048
- bin_dir
1049
- if tool == "uv" and Path(bin_dir := ".venv/bin/").exists()
1050
- else (tool + " run ")
1051
- )
1098
+ prefix = tool + " run "
1099
+ if tool == "uv":
1100
+ if is_windows():
1101
+ prefix += "--no-sync "
1102
+ elif Path(bin_dir := ".venv/bin/").exists():
1103
+ prefix = bin_dir
1052
1104
  if cls.prefer_dmypy(paths, tools, use_dmypy=use_dmypy):
1053
1105
  tools[-1] = "dmypy run"
1054
1106
  cmd += lint_them.format(prefix, paths, *tools)
@@ -1070,7 +1122,12 @@ class LintCode(DryRun):
1070
1122
  ps = args.split() if isinstance(args, str) else [str(i) for i in args]
1071
1123
  if len(ps) == 1:
1072
1124
  paths = ps[0]
1073
- if paths != "." and not (p := Path(paths)).suffix and not p.exists():
1125
+ if (
1126
+ paths != "."
1127
+ # `Path("a.").suffix` got "." in py3.14 and got "" with py<3.14
1128
+ and (p := Path(paths)).suffix in ("", ".")
1129
+ and not p.exists()
1130
+ ):
1074
1131
  # e.g.:
1075
1132
  # stem -> stem.py
1076
1133
  # me. -> me.py
@@ -1252,7 +1309,9 @@ def test(dry: bool, ignore_script: bool = False) -> None:
1252
1309
  if not _ensure_bool(ignore_script) and (
1253
1310
  test_script := _should_run_test_script(script_dir)
1254
1311
  ):
1255
- cmd = f"{os.path.relpath(test_script, root)}"
1312
+ cmd = test_script.relative_to(root).as_posix()
1313
+ if test_script.suffix == ".py":
1314
+ cmd = "python " + cmd
1256
1315
  if cwd != root:
1257
1316
  cmd = f"cd {root} && " + cmd
1258
1317
  else:
@@ -1343,8 +1402,11 @@ def run_by_subprocess(cmd: str, dry: bool = DryOption) -> None:
1343
1402
  try:
1344
1403
  rc = run_and_echo(cmd, verbose=True, dry=_ensure_bool(dry))
1345
1404
  except FileNotFoundError as e:
1346
- if e.filename == cmd.split()[0]:
1347
- echo(f"Command not found: {e.filename}")
1405
+ command = cmd.split()[0]
1406
+ if e.filename == command or (
1407
+ e.filename is None and "系统找不到指定的文件" in str(e)
1408
+ ):
1409
+ echo(f"Command not found: {command}")
1348
1410
  raise Exit(1) from None
1349
1411
  raise e
1350
1412
  else:
@@ -1380,7 +1442,7 @@ class MakeDeps(DryRun):
1380
1442
 
1381
1443
  def gen(self) -> str:
1382
1444
  if self._tool == "pdm":
1383
- return "pdm sync " + ("--prod" if self._prod else "-G :all")
1445
+ return "pdm install --frozen " + ("--prod" if self._prod else "-G :all")
1384
1446
  elif self._tool == "uv":
1385
1447
  uv_sync = "uv sync" + " --inexact" * self._inexact
1386
1448
  if self._active:
@@ -42,7 +42,7 @@ dependencies = [
42
42
  "bumpversion2 >=1.4.3",
43
43
  "pytest >=8.2.0",
44
44
  ]
45
- version = "0.18.4"
45
+ version = "0.18.5"
46
46
 
47
47
  [project.urls]
48
48
  Homepage = "https://github.com/waketzheng/fast-dev-cli"
@@ -230,16 +230,16 @@ version = "0"
230
230
  another_dir = project_dir / "hello"
231
231
  another_dir.mkdir()
232
232
  shutil.copy(init_file, another_dir / init_file.name)
233
- assert BumpUp.parse_filename() == "helloworld/__init__.py"
233
+ assert BumpUp.parse_filename() == os.path.join("helloworld", "__init__.py")
234
234
  toml_file.write_text(pyproject.strip() + '\npackages=[{include="hello"}]')
235
- assert BumpUp.parse_filename() == "hello/__init__.py"
235
+ assert BumpUp.parse_filename() == os.path.join("hello", "__init__.py")
236
236
  toml_file.write_text(
237
237
  pyproject.strip() + '\npackages=[{include="hello",from="py"}]'
238
238
  )
239
239
  from_dir = project_dir / "py"
240
240
  from_dir.mkdir()
241
241
  shutil.move(another_dir, from_dir)
242
- assert BumpUp.parse_filename() == "py/hello/__init__.py"
242
+ assert BumpUp.parse_filename() == os.path.join("py", "hello", "__init__.py")
243
243
 
244
244
 
245
245
  PDM_DYNAMIC_VERSION = """
@@ -269,7 +269,7 @@ def test_pdm_project(dynamic_pdm_project):
269
269
  init_file = dynamic_pdm_project / "__init__.py"
270
270
  init_file.write_text('__version__ = "0.2.0"')
271
271
  out = capture_cmd_output("fast bump patch")
272
- assert str(init_file) in out
272
+ assert init_file.as_posix() in out
273
273
  assert "0.2.1" in init_file.read_text()
274
274
  run_and_echo("git init")
275
275
  shutil.copy(Path(__file__).parent.parent / ".gitignore", ".")
@@ -291,7 +291,7 @@ def test_installed_version_is_0_0_0(dynamic_pdm_project):
291
291
  capture_cmd_output("pdm install")
292
292
  version_file.write_text('__version__ = "0.3.0"')
293
293
  out = capture_cmd_output("fast bump patch")
294
- assert str(version_file) in out
294
+ assert version_file.as_posix() in out
295
295
  assert "0.3.1" in version_file.read_text()
296
296
 
297
297
 
@@ -332,7 +332,7 @@ __description__ = "A next generation HTTP client, for Python 3."
332
332
  __version__ = "0.28.1"
333
333
  """)
334
334
  out = capture_cmd_output("fast bump patch")
335
- assert str(version_file) in out
335
+ assert version_file.as_posix() in out
336
336
  assert "0.28.2" in version_file.read_text()
337
337
 
338
338
 
@@ -365,7 +365,7 @@ requires = ["pdm-backend"]
365
365
  build-backend = "pdm.backend"
366
366
  """)
367
367
  out = capture_cmd_output("fast bump patch")
368
- assert str(version_file) in out
368
+ assert version_file.as_posix() in out
369
369
  assert "0.3.1" in version_file.read_text()
370
370
 
371
371
 
@@ -400,5 +400,5 @@ requires = ["pdm-backend"]
400
400
  build-backend = "pdm.backend"
401
401
  """)
402
402
  out = capture_cmd_output("fast bump patch")
403
- assert str(version_file) in out
403
+ assert version_file.as_posix() in out
404
404
  assert "0.3.1" in version_file.read_text()
@@ -12,8 +12,8 @@ def test_make_deps_class():
12
12
  )
13
13
  assert MakeDeps("uv", prod=True).gen() == "uv sync --inexact --active"
14
14
  assert MakeDeps("uv", prod=True, active=False).gen() == "uv sync --inexact"
15
- assert MakeDeps("pdm", prod=False).gen() == "pdm sync -G :all"
16
- assert MakeDeps("pdm", prod=True).gen() == "pdm sync --prod"
15
+ assert MakeDeps("pdm", prod=False).gen() == "pdm install --frozen -G :all"
16
+ assert MakeDeps("pdm", prod=True).gen() == "pdm install --frozen --prod"
17
17
  assert (
18
18
  MakeDeps("poetry", prod=False).gen()
19
19
  == "poetry install --all-extras --all-groups"
@@ -31,7 +31,7 @@ def test_make_deps_class():
31
31
 
32
32
  def test_fast_deps():
33
33
  out = capture_cmd_output("fast deps --dry")
34
- assert out == "--> pdm sync -G :all"
34
+ assert out == "--> pdm install --frozen -G :all"
35
35
  out = capture_cmd_output("fast deps --uv --prod --dry")
36
36
  assert out == "--> uv sync --inexact --active"
37
37
  out = capture_cmd_output("fast deps --uv --prod --dry --no-active")
@@ -95,7 +95,7 @@ def test_run_script_in_sub_directory(mocker: MockerFixture, capsys, script_path)
95
95
  mocker.patch("pathlib.Path.cwd", return_value=script_path.parent)
96
96
  unitcase(dry=True)
97
97
  out = capsys.readouterr().out
98
- assert f"cd {script_path.parent.parent} && {TEST_SCRIPT}" in out
98
+ assert f"cd {script_path.parent.parent} && python {TEST_SCRIPT}" in out
99
99
 
100
100
 
101
101
  def test_fast_test(mocker, capsys):
@@ -80,8 +80,16 @@ def test_run_shell():
80
80
  assert run_and_echo("echo foo", capture_output=True) == 0
81
81
 
82
82
  with pytest.raises(SystemExit):
83
+ exit_if_run_failed(
84
+ "in_valid_command", _exit=True, capture_output=True, shell=True
85
+ )
86
+ with pytest.raises(FileNotFoundError):
83
87
  exit_if_run_failed("in_valid_command", _exit=True, capture_output=True)
84
88
  with pytest.raises(typer.Exit):
89
+ exit_if_run_failed(
90
+ "in_valid_command", _exit=False, capture_output=True, shell=True
91
+ )
92
+ with pytest.raises(FileNotFoundError):
85
93
  exit_if_run_failed("in_valid_command", _exit=False, capture_output=True)
86
94
  with pytest.raises(NotImplementedError):
87
95
 
@@ -10,6 +10,7 @@ from fast_dev_cli.cli import (
10
10
  TOML_FILE,
11
11
  BumpUp,
12
12
  ParseError,
13
+ Project,
13
14
  poetry_module_name,
14
15
  run_and_echo,
15
16
  )
@@ -93,3 +94,9 @@ def test_version_plugin_include_defined(mark, tmp_path: Path) -> None:
93
94
  assert BumpUp(part="patch", commit=False, dry=True).gen() == command
94
95
  run_and_echo("poetry run fast bump patch")
95
96
  assert init_file.read_text() == '__version__ = "0.0.2"\n'
97
+
98
+
99
+ @pytest.mark.parametrize("command", ["poetry", "uvx poetry"])
100
+ def test_poetry_version(command) -> None:
101
+ v = Project.get_poetry_version(command)
102
+ assert v >= "2.2.0"
@@ -1,7 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import re
4
- import sys
5
3
  from contextlib import redirect_stdout
6
4
  from io import StringIO
7
5
  from pathlib import Path
@@ -12,13 +10,14 @@ import typer
12
10
  import fast_dev_cli
13
11
  from fast_dev_cli.cli import (
14
12
  TOML_FILE,
13
+ Project,
15
14
  UpgradeDependencies,
16
15
  capture_cmd_output,
17
16
  run_and_echo,
18
17
  upgrade,
19
18
  )
20
19
 
21
- from .utils import chdir
20
+ from .utils import chdir, prepare_poetry_project
22
21
 
23
22
 
24
23
  def test_parse_value():
@@ -85,28 +84,24 @@ uvicorn = {version = "^0.23.2", platform = "linux", optional = true}
85
84
 
86
85
  def test_dev_flag(tmp_path: Path):
87
86
  assert UpgradeDependencies.should_with_dev() is False
88
- with chdir(tmp_path):
89
- project = tmp_path / "project"
90
- run_and_echo(f"poetry new {project.name}")
91
- with chdir(project):
92
- if sys.version_info < (3, 13):
93
- p = Path("pyproject.toml")
94
- content = p.read_text()
95
- pattern = r'(python = "\^3)\.\d+"'
96
- new_content = re.sub(pattern, r'\1.9"', content)
97
- p.write_text(new_content)
98
- assert not UpgradeDependencies.should_with_dev()
99
- run_and_echo("poetry add pytest")
87
+ with prepare_poetry_project(tmp_path) as poetry:
88
+ is_newer_poetry = Project.get_poetry_version(poetry) >= "2.2.0"
89
+ assert not UpgradeDependencies.should_with_dev()
90
+ run_and_echo(f"{poetry} add pytest")
91
+ assert not UpgradeDependencies.should_with_dev()
92
+ run_and_echo(f"{poetry} add --group=dev typer")
93
+ if is_newer_poetry:
100
94
  assert not UpgradeDependencies.should_with_dev()
101
- run_and_echo("poetry add --group=dev typer")
95
+ else:
96
+ toml_file = Path(TOML_FILE)
102
97
  assert UpgradeDependencies.should_with_dev()
103
- text = project.joinpath(TOML_FILE).read_text()
98
+ text = toml_file.read_text()
104
99
  DevFlag = UpgradeDependencies.DevFlag
105
100
  if DevFlag.new in text:
106
101
  new_text = text.replace(DevFlag.new, DevFlag.old)
107
102
  else:
108
103
  new_text = text.replace(DevFlag.old, DevFlag.new)
109
- project.joinpath(TOML_FILE).write_text(new_text)
104
+ toml_file.write_text(new_text)
110
105
  assert UpgradeDependencies.should_with_dev()
111
106
 
112
107
 
@@ -300,7 +295,7 @@ def test_upgrade_uv_project():
300
295
 
301
296
  def test_upgrade_pdm_project():
302
297
  cmd = "fast upgrade --tool=pdm --dry"
303
- expected = "pdm update --verbose && pdm sync -G :all --frozen"
298
+ expected = "pdm update --verbose && pdm install -G :all --frozen"
304
299
  assert expected in capture_cmd_output(cmd)
305
300
  assert expected in capture_cmd_output("pdm run " + cmd)
306
301
  assert UpgradeDependencies(tool="pdm").gen() == expected
@@ -1,5 +1,6 @@
1
1
  import shutil
2
2
  import sys
3
+ from collections.abc import Generator
3
4
  from contextlib import contextmanager, redirect_stdout
4
5
  from io import StringIO
5
6
  from pathlib import Path
@@ -8,8 +9,9 @@ from asynctor import Shell
8
9
  from asynctor.compat import chdir
9
10
 
10
11
  __all__ = (
11
- "mock_sys_argv",
12
12
  "capture_stdout",
13
+ "mock_sys_argv",
14
+ "prepare_poetry_project",
13
15
  "temp_file",
14
16
  )
15
17
 
@@ -51,7 +53,7 @@ def temp_file(name: str, text=""):
51
53
 
52
54
 
53
55
  @contextmanager
54
- def prepare_poetry_project(tmp_path: Path):
56
+ def prepare_poetry_project(tmp_path: Path) -> Generator[str]:
55
57
  py = "{}.{}".format(*sys.version_info)
56
58
  poetry = "poetry"
57
59
  if shutil.which(poetry) is None:
@@ -64,4 +66,4 @@ def prepare_poetry_project(tmp_path: Path):
64
66
  f"{poetry} config --local virtualenvs.in-project true"
65
67
  )
66
68
  Shell.run_by_subprocess(f"{poetry} env use {py}")
67
- yield
69
+ yield poetry
@@ -1 +0,0 @@
1
- __version__ = "0.18.4"
File without changes
File without changes