fast-dev-cli 0.19.0__tar.gz → 0.19.2__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.19.0 → fast_dev_cli-0.19.2}/PKG-INFO +1 -1
  2. fast_dev_cli-0.19.2/fast_dev_cli/__init__.py +1 -0
  3. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/fast_dev_cli/cli.py +152 -98
  4. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/pyproject.toml +2 -2
  5. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_deps.py +28 -0
  6. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_sync.py +26 -8
  7. fast_dev_cli-0.19.0/fast_dev_cli/__init__.py +0 -1
  8. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/LICENSE +0 -0
  9. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/README.md +0 -0
  10. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/fast_dev_cli/__main__.py +0 -0
  11. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/fast_dev_cli/py.typed +0 -0
  12. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/pdm_build.py +0 -0
  13. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/scripts/check.py +0 -0
  14. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/scripts/deps.py +0 -0
  15. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/scripts/format.py +0 -0
  16. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/scripts/test.py +0 -0
  17. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/__init__.py +0 -0
  18. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/assets/uv-tx.lock +0 -0
  19. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/assets/uv.lock +0 -0
  20. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/conftest.py +0 -0
  21. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_bump.py +0 -0
  22. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_exec.py +0 -0
  23. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_fast_test.py +0 -0
  24. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_functions.py +0 -0
  25. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_help.py +0 -0
  26. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_lint.py +0 -0
  27. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_poetry_version_plugin.py +0 -0
  28. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_pypi.py +0 -0
  29. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_runserver.py +0 -0
  30. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_tag.py +0 -0
  31. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_upgrade.py +0 -0
  32. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_upload.py +0 -0
  33. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/test_version.py +0 -0
  34. {fast_dev_cli-0.19.0 → fast_dev_cli-0.19.2}/tests/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fast-dev-cli
3
- Version: 0.19.0
3
+ Version: 0.19.2
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.19.2"
@@ -12,16 +12,7 @@ import subprocess # nosec:B404
12
12
  import sys
13
13
  from functools import cached_property
14
14
  from pathlib import Path
15
- from typing import (
16
- TYPE_CHECKING,
17
- Any,
18
- Literal,
19
- # Optional is required by Option generated by typer
20
- Optional,
21
- cast,
22
- get_args,
23
- overload,
24
- )
15
+ from typing import TYPE_CHECKING, Any, Literal, cast, get_args, overload
25
16
 
26
17
  import typer
27
18
  from click import UsageError
@@ -57,7 +48,7 @@ if TYPE_CHECKING:
57
48
  cli = typer.Typer(no_args_is_help=True)
58
49
  DryOption = Option(False, "--dry", help="Only print, not really run shell command")
59
50
  TOML_FILE = "pyproject.toml"
60
- ToolName = Literal["poetry", "pdm", "uv"]
51
+ ToolName = Literal["uv", "pdm", "poetry"]
61
52
  ToolOption = Option(
62
53
  "auto", "--tool", help="Explicit declare manage tool (default to auto detect)"
63
54
  )
@@ -391,7 +382,36 @@ class BumpUp(DryRun):
391
382
  return is_emoji(first_char)
392
383
 
393
384
  @staticmethod
385
+ def parse_dynamic_version(
386
+ toml_text: str,
387
+ context: dict,
388
+ work_dir: Path | None = None,
389
+ ) -> str | None:
390
+ if work_dir is None:
391
+ work_dir = Project.get_work_dir()
392
+ for tool in ("pdm", "hatch"):
393
+ with contextlib.suppress(KeyError):
394
+ version_path = cast(str, context["tool"][tool]["version"]["path"])
395
+ if (
396
+ Path(version_path).exists()
397
+ or work_dir.joinpath(version_path).exists()
398
+ ):
399
+ return version_path
400
+ # version = { source = "file", path = "fast_dev_cli/__init__.py" }
401
+ v_key = "version = "
402
+ p_key = 'path = "'
403
+ for line in toml_text.splitlines():
404
+ if not line.startswith(v_key):
405
+ continue
406
+ if p_key in (value := line.split(v_key, 1)[-1].split("#")[0]):
407
+ filename = value.split(p_key, 1)[-1].split('"')[0]
408
+ if work_dir.joinpath(filename).exists():
409
+ return filename
410
+ return None
411
+
412
+ @classmethod
394
413
  def parse_filename(
414
+ cls,
395
415
  toml_text: str | None = None,
396
416
  work_dir: Path | None = None,
397
417
  package_name: str | None = None,
@@ -414,74 +434,55 @@ class BumpUp(DryRun):
414
434
  try:
415
435
  version_value = context["tool"]["poetry"]["version"]
416
436
  except KeyError:
417
- if not Project.manage_by_poetry():
418
- if work_dir is None:
419
- work_dir = Project.get_work_dir()
420
- for tool in ("pdm", "hatch"):
421
- with contextlib.suppress(KeyError):
422
- version_path = cast(
423
- str, context["tool"][tool]["version"]["path"]
424
- )
425
- if (
426
- Path(version_path).exists()
427
- or work_dir.joinpath(version_path).exists()
428
- ):
429
- return version_path
430
- # version = { source = "file", path = "fast_dev_cli/__init__.py" }
431
- v_key = "version = "
432
- p_key = 'path = "'
433
- for line in toml_text.splitlines():
434
- if not line.startswith(v_key):
435
- continue
436
- if p_key in (value := line.split(v_key, 1)[-1].split("#")[0]):
437
- filename = value.split(p_key, 1)[-1].split('"')[0]
438
- if work_dir.joinpath(filename).exists():
439
- return filename
437
+ if not Project.manage_by_poetry() and (
438
+ filename := cls.parse_dynamic_version(toml_text, context, work_dir)
439
+ ):
440
+ return filename
440
441
  else:
441
442
  by_version_plugin = version_value in ("0", "0.0.0", "init")
442
443
  if by_version_plugin:
444
+ return cls.parse_plugin_version(context, package_name)
445
+
446
+ return TOML_FILE
447
+
448
+ @staticmethod
449
+ def parse_plugin_version(context: dict, package_name: str | None) -> str:
450
+ try:
451
+ package_item = context["tool"]["poetry"]["packages"]
452
+ except KeyError:
443
453
  try:
444
- package_item = context["tool"]["poetry"]["packages"]
454
+ project_name = context["project"]["name"]
445
455
  except KeyError:
446
- try:
447
- project_name = context["project"]["name"]
448
- except KeyError:
449
- packages = []
450
- else:
451
- packages = [(poetry_module_name(project_name), "")]
456
+ packages = []
452
457
  else:
453
- packages = [
454
- (j, i.get("from", ""))
455
- for i in package_item
456
- if (j := i.get("include"))
457
- ]
458
- # In case of managed by `poetry-plugin-version`
459
- cwd = Path.cwd()
460
- pattern = re.compile(r"__version__\s*=\s*['\"]")
461
- ds: list[Path] = []
462
- if package_name is not None:
463
- packages.insert(0, (package_name, ""))
464
- for package_name, source_dir in packages:
465
- ds.append(cwd / package_name)
466
- ds.append(cwd / "src" / package_name)
467
- if source_dir and source_dir != "src":
468
- ds.append(cwd / source_dir / package_name)
469
- module_name = poetry_module_name(cwd.name)
470
- ds.extend([cwd / module_name, cwd / "src" / module_name, cwd])
471
- for d in ds:
472
- init_file = d / "__init__.py"
473
- if (
474
- init_file.exists() and pattern.search(init_file.read_text("utf8"))
475
- ) or (
476
- (init_file := init_file.with_name("__version__.py")).exists()
477
- and pattern.search(init_file.read_text("utf8"))
478
- ):
479
- break
480
- else:
481
- raise ParseError("Version file not found! Where are you now?")
482
- return os.path.relpath(init_file, cwd)
483
-
484
- return TOML_FILE
458
+ packages = [(poetry_module_name(project_name), "")]
459
+ else:
460
+ packages = [
461
+ (j, i.get("from", "")) for i in package_item if (j := i.get("include"))
462
+ ]
463
+ # In case of managed by `poetry-plugin-version`
464
+ cwd = Path.cwd()
465
+ pattern = re.compile(r"__version__\s*=\s*['\"]")
466
+ ds: list[Path] = []
467
+ if package_name is not None:
468
+ packages.insert(0, (package_name, ""))
469
+ for package_name, source_dir in packages:
470
+ ds.append(cwd / package_name)
471
+ ds.append(cwd / "src" / package_name)
472
+ if source_dir and source_dir != "src":
473
+ ds.append(cwd / source_dir / package_name)
474
+ module_name = poetry_module_name(cwd.name)
475
+ ds.extend([cwd / module_name, cwd / "src" / module_name, cwd])
476
+ for d in ds:
477
+ init_file = d / "__init__.py"
478
+ if (init_file.exists() and pattern.search(init_file.read_text("utf8"))) or (
479
+ (init_file := init_file.with_name("__version__.py")).exists()
480
+ and pattern.search(init_file.read_text("utf8"))
481
+ ):
482
+ break
483
+ else:
484
+ raise ParseError("Version file not found! Where are you now?")
485
+ return os.path.relpath(init_file, cwd)
485
486
 
486
487
  def get_part(self, s: str) -> str:
487
488
  choices: dict[str, str] = {}
@@ -517,7 +518,11 @@ class BumpUp(DryRun):
517
518
  cmd += " && git push && git push --tags && git log -1"
518
519
  else:
519
520
  cmd += " --allow-dirty"
520
- if should_sync and not self._no_sync and (sync := Project.get_sync_command()):
521
+ if (
522
+ should_sync
523
+ and not self._no_sync
524
+ and (sync := Project.get_sync_command(only_me=True))
525
+ ):
521
526
  cmd = f"{sync} && " + cmd
522
527
  return cmd
523
528
 
@@ -561,7 +566,7 @@ def bump_version(
561
566
  commit: bool = Option(
562
567
  False, "--commit", "-c", help="Whether run `git commit` after version changed"
563
568
  ),
564
- emoji: Optional[bool] = Option(
569
+ emoji: bool | None = Option(
565
570
  None, "--emoji", help="Whether add emoji prefix to commit message"
566
571
  ),
567
572
  no_sync: bool = Option(
@@ -658,28 +663,64 @@ class Project:
658
663
  text = cls.load_toml_text()
659
664
  except EnvError:
660
665
  return None
666
+ backend = ""
667
+ skip_uv = load_bool("FASTDEVCLI_SKIP_UV")
661
668
  with contextlib.suppress(KeyError, tomllib.TOMLDecodeError):
662
669
  doc = tomllib.loads(text)
663
670
  backend = doc["build-system"]["build-backend"]
664
- if "poetry" in backend:
665
- cls._tool = "poetry"
666
- return cls._tool
671
+ if skip_uv:
672
+ for t in ("pdm", "poetry"):
673
+ if t in backend:
674
+ cls._tool = t
675
+ return cls._tool
676
+ work_dir: Path | None = None
677
+ uv_lock_exists: bool | None = None
678
+ if skip_uv:
679
+ for name in ("pdm", "poetry"):
680
+ if f"[tool.{name}]" in text:
681
+ cls._tool = cast(ToolName, name)
682
+ return cls._tool
667
683
  work_dir = cls.get_work_dir(allow_cwd=True)
668
- uv_lock_exists = Path(work_dir, "uv.lock").exists()
669
- if "pdm" in backend:
684
+ for name in ("pdm", "poetry"):
685
+ if Path(work_dir, f"{name}.lock").exists():
686
+ cls._tool = cast(ToolName, name)
687
+ return cls._tool
688
+ if uv_lock_exists := Path(work_dir, "uv.lock").exists():
689
+ # Use pdm when uv is not available for uv managed project
670
690
  cls._tool = "pdm"
671
- if not Path(work_dir, "pdm.lock").exists() and (
672
- uv_lock_exists or "[tool.uv]" in text
673
- ):
674
- cls._tool = "uv"
675
- return cls._tool
676
- elif uv_lock_exists:
677
- cls._tool = "uv"
678
691
  return cls._tool
679
- for name in get_args(ToolName):
680
- if f"[tool.{name}]" in text:
681
- cls._tool = cast(ToolName, name)
692
+ return None
693
+ if work_dir is None:
694
+ work_dir = cls.get_work_dir(allow_cwd=True)
695
+ if uv_lock_exists is None:
696
+ uv_lock_exists = Path(work_dir, "uv.lock").exists()
697
+ if uv_lock_exists:
698
+ cls._tool = "uv"
699
+ return cls._tool
700
+ pdm_lock_exists = Path(work_dir, "pdm.lock").exists()
701
+ poetry_lock_exists = Path(work_dir, "poetry.lock").exists()
702
+ match pdm_lock_exists + poetry_lock_exists:
703
+ case 1:
704
+ cls._tool = "pdm" if pdm_lock_exists else "poetry"
682
705
  return cls._tool
706
+ case _ as x:
707
+ if backend:
708
+ for t in ("pdm", "poetry"):
709
+ if t in backend:
710
+ cls._tool = cast(ToolName, t)
711
+ return cls._tool
712
+ for name in ("pdm", "poetry"):
713
+ if f"[tool.{name}]" in text:
714
+ cls._tool = cast(ToolName, name)
715
+ return cls._tool
716
+ if x == 2:
717
+ cls._tool = (
718
+ "poetry" if load_bool("FASTDEVCLI_PREFER_POETRY") else "pdm"
719
+ )
720
+ return cls._tool
721
+ if "[tool.uv]" in text or load_bool("FASTDEVCLI_PREFER_uv"):
722
+ cls._tool = "uv"
723
+ return cls._tool
683
724
  # Poetry 2.0 default to not include the '[tool.poetry]' section
684
725
  if cls.is_poetry_v2(text):
685
726
  cls._tool = "poetry"
@@ -708,9 +749,12 @@ class Project:
708
749
  return True
709
750
 
710
751
  @classmethod
711
- def get_sync_command(cls, prod: bool = True, doc: dict | None = None) -> str:
752
+ def get_sync_command(
753
+ cls, prod: bool = True, doc: dict | None = None, only_me: bool = False
754
+ ) -> str:
755
+ pdm_i = "pdm install --frozen" + " --prod" * prod
712
756
  if cls.is_pdm_project():
713
- return "pdm install --frozen" + " --prod" * prod
757
+ return pdm_i
714
758
  elif cls.manage_by_poetry(cache=True):
715
759
  cmd = "poetry install"
716
760
  if prod:
@@ -725,7 +769,17 @@ class Project:
725
769
  cmd += " --only=main"
726
770
  return cmd
727
771
  elif cls.get_manage_tool(cache=True) == "uv":
728
- return "uv sync --inexact" + " --no-dev" * prod
772
+ install_me = "uv pip install -e ."
773
+ if doc is None:
774
+ doc = tomllib.loads(cls.load_toml_text())
775
+ is_distribution = (
776
+ doc.get("tool", {}).get("pdm", {}).get("distribution") is not False
777
+ )
778
+ if only_me:
779
+ return install_me if is_distribution else pdm_i
780
+ cmd = "uv sync --inexact" + " --no-dev" * prod
781
+ if is_distribution:
782
+ cmd += f" && {install_me}"
729
783
  return ""
730
784
 
731
785
  @classmethod
@@ -1215,7 +1269,7 @@ def check(
1215
1269
 
1216
1270
  @cli.command(name="lint")
1217
1271
  def make_style(
1218
- files: Optional[list[str]] = typer.Argument(default=None), # noqa:B008
1272
+ files: list[str] | None = typer.Argument(default=None), # noqa:B008
1219
1273
  check_only: bool = Option(False, "--check-only", "-c"),
1220
1274
  bandit: bool = Option(False, "--bandit", help="Run `bandit -r <package_dir>`"),
1221
1275
  prefix: bool = Option(
@@ -1398,9 +1452,9 @@ def dev(
1398
1452
 
1399
1453
  @cli.command(name="dev")
1400
1454
  def runserver(
1401
- file_or_port: Optional[str] = typer.Argument(default=None),
1402
- port: Optional[int] = Option(None, "-p", "--port"),
1403
- host: Optional[str] = Option(None, "-h", "--host"),
1455
+ file_or_port: str | None = typer.Argument(default=None),
1456
+ port: int | None = Option(None, "-p", "--port"),
1457
+ host: str | None = Option(None, "-h", "--host"),
1404
1458
  dry: bool = DryOption,
1405
1459
  ) -> None:
1406
1460
  """Start a fastapi server(only for fastapi>=0.111.0)"""
@@ -1588,7 +1642,7 @@ class UvPypi(DryRun):
1588
1642
 
1589
1643
  @cli.command()
1590
1644
  def pypi(
1591
- file: Optional[str] = typer.Argument(default=None),
1645
+ file: str | None = typer.Argument(default=None),
1592
1646
  dry: bool = DryOption,
1593
1647
  verbose: bool = False,
1594
1648
  quiet: bool = False,
@@ -41,7 +41,7 @@ dependencies = [
41
41
  "bumpversion2 >=1.4.3",
42
42
  "pytest >=8.2.0",
43
43
  ]
44
- version = "0.19.0"
44
+ version = "0.19.2"
45
45
 
46
46
  [project.urls]
47
47
  Homepage = "https://github.com/waketzheng/fast-dev-cli"
@@ -57,7 +57,7 @@ fast = "fast_dev_cli:cli.main"
57
57
  [dependency-groups]
58
58
  dev = [
59
59
  "twine>=6.1.0",
60
- "asynctor>=0.8.6",
60
+ "asynctor>=0.10.0",
61
61
  ]
62
62
 
63
63
  [tool.pdm]
@@ -48,3 +48,31 @@ def test_fast_deps():
48
48
  assert out == "--> uv sync --active --all-extras --all-groups"
49
49
  out = capture_cmd_output("fast deps --uv --dry --no-active --no-inexact")
50
50
  assert out == "--> uv sync --all-extras --all-groups"
51
+
52
+
53
+ def test_smart_fast_deps(tmp_work_dir, monkeypatch):
54
+ toml_file = tmp_work_dir.joinpath("pyproject.toml")
55
+ if toml_file.exists():
56
+ toml_file.unlink()
57
+ tmp_work_dir.joinpath("uv.lock").touch()
58
+ out = capture_cmd_output("fast deps --dry")
59
+ assert (
60
+ out
61
+ == "--> python -m ensurepip && python -m pip install --upgrade pip && python -m pip install -e . --group dev"
62
+ )
63
+ toml_file.touch()
64
+ out = capture_cmd_output("fast deps --dry")
65
+ assert out == "--> uv sync --inexact --active --all-extras --all-groups"
66
+ pdm_lock = tmp_work_dir.joinpath("pdm.lock")
67
+ pdm_lock.touch()
68
+ out = capture_cmd_output("fast deps --dry")
69
+ assert out == "--> uv sync --inexact --active --all-extras --all-groups"
70
+ toml_file.write_text("[tool.pdm]\ndistribution=false")
71
+ out = capture_cmd_output("fast deps --dry")
72
+ assert out == "--> uv sync --inexact --active --all-extras --all-groups"
73
+ monkeypatch.setenv("FASTDEVCLI_SKIP_UV", "1")
74
+ out = capture_cmd_output("fast deps --dry")
75
+ assert out == "--> pdm install --frozen -G :all"
76
+ pdm_lock.unlink()
77
+ out = capture_cmd_output("fast deps --dry")
78
+ assert out == "--> pdm install --frozen -G :all"
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import functools
3
4
  from pathlib import Path
4
5
 
5
6
  import pytest
@@ -30,6 +31,16 @@ build-backend = "poetry.core.masonry.api"
30
31
  """
31
32
 
32
33
 
34
+ @functools.cache
35
+ def is_pip_installed() -> bool:
36
+ try:
37
+ import pip # NOQA
38
+ except ImportError:
39
+ return False
40
+ else:
41
+ return True
42
+
43
+
33
44
  def test_sync_not_in_venv(mocker, capsys):
34
45
  mocker.patch("fast_dev_cli.cli.is_venv", return_value=False)
35
46
  test_dir = Path(__file__).parent
@@ -44,10 +55,15 @@ def test_sync_not_in_venv(mocker, capsys):
44
55
  mocker.patch(
45
56
  "fast_dev_cli.cli.UpgradeDependencies.should_with_dev", return_value=True
46
57
  )
47
- assert (
48
- Sync("req.txt", "", True, dry=True).gen()
49
- == "pdm export --without-hashes --with=dev -o req.txt && pdm run python -m pip install -r req.txt"
50
- )
58
+ pdm_export = "pdm export --without-hashes --with=dev -o req.txt"
59
+ installing = "pdm run python -m pip install -r req.txt"
60
+ if not is_pip_installed():
61
+ installing = (
62
+ "pdm run python -m ensurepip && pdm run python -m pip install -U pip && "
63
+ + installing
64
+ )
65
+ expected = f"{pdm_export} && {installing}"
66
+ assert Sync("req.txt", "", True, dry=True).gen() == expected
51
67
 
52
68
 
53
69
  def test_sync(mocker):
@@ -62,10 +78,12 @@ def test_sync(mocker):
62
78
  mocker.patch(
63
79
  "fast_dev_cli.cli.UpgradeDependencies.should_with_dev", return_value=True
64
80
  )
65
- assert (
66
- Sync("req.txt", "", True, dry=True).gen()
67
- == "pdm export --without-hashes --with=dev -o req.txt && python -m pip install -r req.txt"
68
- )
81
+ pdm_export = "pdm export --without-hashes --with=dev -o req.txt"
82
+ if is_pip_installed():
83
+ expected = f"{pdm_export} && python -m pip install -r req.txt"
84
+ else:
85
+ expected = f"{pdm_export} && python -m ensurepip && python -m pip install -U pip && python -m pip install -r req.txt"
86
+ assert Sync("req.txt", "", True, dry=True).gen() == expected
69
87
 
70
88
 
71
89
  UV_TOML_EXAMPLE = """
@@ -1 +0,0 @@
1
- __version__ = "0.19.0"
File without changes
File without changes