fast-dev-cli 0.23.0__tar.gz → 0.23.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 (30) hide show
  1. {fast_dev_cli-0.23.0 → fast_dev_cli-0.23.2}/PKG-INFO +1 -1
  2. fast_dev_cli-0.23.2/fast_dev_cli/__init__.py +1 -0
  3. {fast_dev_cli-0.23.0 → fast_dev_cli-0.23.2}/fast_dev_cli/cli.py +93 -75
  4. {fast_dev_cli-0.23.0 → fast_dev_cli-0.23.2}/pyproject.toml +13 -3
  5. fast_dev_cli-0.23.0/fast_dev_cli/__init__.py +0 -1
  6. fast_dev_cli-0.23.0/tests/__init__.py +0 -0
  7. fast_dev_cli-0.23.0/tests/assets/uv-tx.lock +0 -1476
  8. fast_dev_cli-0.23.0/tests/assets/uv-upload-time.lock +0 -1658
  9. fast_dev_cli-0.23.0/tests/assets/uv.lock +0 -1476
  10. fast_dev_cli-0.23.0/tests/conftest.py +0 -59
  11. fast_dev_cli-0.23.0/tests/test_bump.py +0 -424
  12. fast_dev_cli-0.23.0/tests/test_deps.py +0 -102
  13. fast_dev_cli-0.23.0/tests/test_exec.py +0 -51
  14. fast_dev_cli-0.23.0/tests/test_fast_test.py +0 -115
  15. fast_dev_cli-0.23.0/tests/test_functions.py +0 -119
  16. fast_dev_cli-0.23.0/tests/test_help.py +0 -7
  17. fast_dev_cli-0.23.0/tests/test_lint.py +0 -474
  18. fast_dev_cli-0.23.0/tests/test_poetry_version_plugin.py +0 -102
  19. fast_dev_cli-0.23.0/tests/test_pypi.py +0 -118
  20. fast_dev_cli-0.23.0/tests/test_runserver.py +0 -136
  21. fast_dev_cli-0.23.0/tests/test_sync.py +0 -240
  22. fast_dev_cli-0.23.0/tests/test_tag.py +0 -73
  23. fast_dev_cli-0.23.0/tests/test_upgrade.py +0 -322
  24. fast_dev_cli-0.23.0/tests/test_upload.py +0 -43
  25. fast_dev_cli-0.23.0/tests/test_version.py +0 -78
  26. fast_dev_cli-0.23.0/tests/utils.py +0 -74
  27. {fast_dev_cli-0.23.0 → fast_dev_cli-0.23.2}/LICENSE +0 -0
  28. {fast_dev_cli-0.23.0 → fast_dev_cli-0.23.2}/README.md +0 -0
  29. {fast_dev_cli-0.23.0 → fast_dev_cli-0.23.2}/fast_dev_cli/__main__.py +0 -0
  30. {fast_dev_cli-0.23.0 → fast_dev_cli-0.23.2}/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.23.0
3
+ Version: 0.23.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.23.2"
@@ -148,15 +148,15 @@ class Shell:
148
148
  if isinstance(command, str):
149
149
  cs = shlex.split(command)
150
150
  if "shell" not in self._kw and not (set(self._cmd) & {"|", ">", "&"}):
151
- command = self.extend_user(cs)
151
+ command = self.expand_user(cs)
152
152
  elif any(i.startswith("~") for i in cs):
153
153
  command = re.sub(r" ~", " " + os.path.expanduser("~"), command)
154
154
  else:
155
- command = self.extend_user(command)
155
+ command = self.expand_user(command)
156
156
  return command
157
157
 
158
158
  @staticmethod
159
- def extend_user(cs: list[str]) -> list[str]:
159
+ def expand_user(cs: list[str]) -> list[str]:
160
160
  if cs[0] == "echo":
161
161
  return cs
162
162
  for i, c in enumerate(cs):
@@ -255,28 +255,18 @@ def read_version_from_file(
255
255
  secho(f"WARNING: can not find 'version' item in {version_file}!")
256
256
  return "0.0.0"
257
257
  pattern = re.compile(r"__version__\s*=")
258
- for line in Path(version_file).read_text("utf-8").splitlines():
258
+ all_lines = Path(version_file).read_text("utf-8").strip().splitlines()
259
+ for line in all_lines:
259
260
  if pattern.match(line):
260
261
  return _parse_version(line, pattern)
261
- # TODO: remove or refactor the following lines.
262
- if work_dir is None:
263
- work_dir = Project.get_work_dir()
264
- package_dir = work_dir / package_name
265
- if (
266
- not (init_file := package_dir / "__init__.py").exists()
267
- and not (init_file := work_dir / "src" / package_name / init_file.name).exists()
268
- and not (init_file := work_dir / "app" / init_file.name).exists()
269
- ):
270
- secho("WARNING: __init__.py file does not exist!")
262
+ else:
263
+ pattern = re.compile(r"VERSION\s*=")
264
+ for line in all_lines:
265
+ if pattern.match(line):
266
+ return _parse_version(line, pattern)
267
+ secho(f"WARNING: can not find version pattern in {version_file}!")
271
268
  return "0.0.0"
272
269
 
273
- pattern = re.compile(r"__version__\s*=")
274
- for line in init_file.read_text("utf-8").splitlines():
275
- if pattern.match(line):
276
- return _parse_version(line, pattern)
277
- secho(f"WARNING: can not find '__version__' var in {init_file}!")
278
- return "0.0.0"
279
-
280
270
 
281
271
  def _get_frontend_version() -> tuple[Path, str] | None:
282
272
  try:
@@ -438,7 +428,7 @@ class BumpUp(DryRun):
438
428
 
439
429
  @staticmethod
440
430
  def parse_dynamic_version(
441
- toml_text: str,
431
+ toml_text: str | None,
442
432
  context: dict[str, Any],
443
433
  work_dir: Path | None = None,
444
434
  ) -> str | None:
@@ -455,6 +445,8 @@ class BumpUp(DryRun):
455
445
  # version = { source = "file", path = "fast_dev_cli/__init__.py" }
456
446
  v_key = "version = "
457
447
  p_key = 'path = "'
448
+ if toml_text is None:
449
+ toml_text = Project.load_toml_text()
458
450
  for line in toml_text.splitlines():
459
451
  if not line.startswith(v_key):
460
452
  continue
@@ -470,10 +462,20 @@ class BumpUp(DryRun):
470
462
  toml_text: str | None = None,
471
463
  work_dir: Path | None = None,
472
464
  package_name: str | None = None,
465
+ context: dict | None = None,
473
466
  ) -> str:
474
- if toml_text is None:
475
- toml_text = Project.load_toml_text()
476
- context = tomllib.loads(toml_text)
467
+ if context is None:
468
+ if toml_text is None:
469
+ toml_text = Project.load_toml_text()
470
+ context = tomllib.loads(toml_text)
471
+ is_dynamic_version = False
472
+ with contextlib.suppress(KeyError):
473
+ if "version" in context["project"]["dynamic"]:
474
+ is_dynamic_version = True
475
+ if is_dynamic_version:
476
+ if filename := cls.parse_dynamic_version(toml_text, context, work_dir):
477
+ return filename
478
+ yellow_warn("Failed to find version file for this dynamic version project.")
477
479
  by_version_plugin = False
478
480
  try:
479
481
  ver = context["project"]["version"]
@@ -738,6 +740,12 @@ class Project:
738
740
  if t in backend:
739
741
  cls._tool = t
740
742
  return cls._tool
743
+ return cls._get_manage_tool(text, backend, skip_uv)
744
+
745
+ @classmethod
746
+ def _get_manage_tool(
747
+ cls: type[Self], text: str, backend: str, skip_uv: bool
748
+ ) -> ToolName | None:
741
749
  work_dir: Path | None = None
742
750
  uv_lock_exists: bool | None = None
743
751
  if skip_uv:
@@ -762,6 +770,12 @@ class Project:
762
770
  if uv_lock_exists:
763
771
  cls._tool = "uv"
764
772
  return cls._tool
773
+ return cls._parse_manage_tool(work_dir, text, backend)
774
+
775
+ @classmethod
776
+ def _parse_manage_tool(
777
+ cls: type[Self], work_dir: Path, text: str, backend: str
778
+ ) -> ToolName | None:
765
779
  pdm_lock_exists = Path(work_dir, "pdm.lock").exists()
766
780
  poetry_lock_exists = Path(work_dir, "poetry.lock").exists()
767
781
  match pdm_lock_exists + poetry_lock_exists:
@@ -1576,6 +1590,59 @@ def should_use_just() -> bool:
1576
1590
  return False
1577
1591
 
1578
1592
 
1593
+ def _parse_serve_file(uvicorn, filename: str, cmd: str, args: list) -> str:
1594
+ if m := re.search(r"(.*):(\d+)$", filename):
1595
+ h, p = m.group(1), m.group(2)
1596
+ if h and "--host" not in str(args):
1597
+ if h == "0":
1598
+ args.append("--host=0.0.0.0")
1599
+ else:
1600
+ args.append(f"--host={h}")
1601
+ args.append(f"--port={p}")
1602
+ if uvicorn:
1603
+ p = Path("main.py")
1604
+ if p.exists():
1605
+ cmd += " main:app"
1606
+ elif Path("app", p.name).exists():
1607
+ cmd += " app.main:app"
1608
+ elif Path("app.py").exists():
1609
+ cmd += " app:app"
1610
+ return cmd
1611
+ if uvicorn and ((filepath := Path(filename)).is_file() or filepath.suffix == ".py"):
1612
+ filename = filepath.stem + ":app"
1613
+ parent_names = [j for i in filepath.parents if (j := i.name)]
1614
+ if parent_names:
1615
+ filename = ".".join([*parent_names[::-1], filename])
1616
+ cmd += " " + filename
1617
+ return cmd
1618
+
1619
+
1620
+ def _runserver(uvicorn, host, port, file) -> tuple[str, list[str]]:
1621
+ cmd = "uvicorn" if uvicorn else "fastapi dev"
1622
+ args = []
1623
+ if (host := getattr(host, "default", host)) and host not in (
1624
+ "localhost",
1625
+ "127.0.0.1",
1626
+ ):
1627
+ args.append(f"--host={host}")
1628
+ no_port_yet = True
1629
+ if file is not None:
1630
+ filename = str(file)
1631
+ try:
1632
+ port = int(filename)
1633
+ except ValueError:
1634
+ cmd = _parse_serve_file(uvicorn, filename, cmd, args)
1635
+ else:
1636
+ if port != 8000:
1637
+ args.append(f"--port={port}")
1638
+ no_port_yet = False
1639
+ if no_port_yet and (port := getattr(port, "default", port)) and str(port) != "8000":
1640
+ args.append(f"--port={port}")
1641
+ if shutil.which("pdm") is not None:
1642
+ cmd = "pdm run " + cmd
1643
+ return cmd, args
1644
+
1645
+
1579
1646
  def dev(
1580
1647
  port: int | None | OptionInfo,
1581
1648
  host: str | None | OptionInfo,
@@ -1590,56 +1657,7 @@ def dev(
1590
1657
  args = [i for i in sys.argv[2:] if i != "--dry"]
1591
1658
  cmd = "just dev"
1592
1659
  else:
1593
- cmd = "uvicorn" if uvicorn else "fastapi dev"
1594
- args = []
1595
- if (host := getattr(host, "default", host)) and host not in (
1596
- "localhost",
1597
- "127.0.0.1",
1598
- ):
1599
- args.append(f"--host={host}")
1600
- no_port_yet = True
1601
- if file is not None:
1602
- try:
1603
- port = int(str(file))
1604
- except ValueError:
1605
- if m := re.search(r"(.*):(\d+)$", str(file)):
1606
- h, p = m.group(1), m.group(2)
1607
- if h and "--host" not in str(args):
1608
- if h == "0":
1609
- args.append("--host=0.0.0.0")
1610
- else:
1611
- args.append(f"--host={h}")
1612
- args.append(f"--port={p}")
1613
- if uvicorn:
1614
- p = Path("main.py")
1615
- if p.exists():
1616
- cmd += " main:app"
1617
- elif Path("app", p.name).exists():
1618
- cmd += " app.main:app"
1619
- elif Path("app.py").exists():
1620
- cmd += " app:app"
1621
- else:
1622
- if uvicorn and (
1623
- (filepath := Path(str(file))).is_file()
1624
- or filepath.suffix == ".py"
1625
- ):
1626
- file = filepath.stem + ":app"
1627
- parent_names = [j for i in filepath.parents if (j := i.name)]
1628
- if parent_names:
1629
- file = ".".join([*parent_names[::-1], file])
1630
- cmd += f" {file}"
1631
- else:
1632
- if port != 8000:
1633
- args.append(f"--port={port}")
1634
- no_port_yet = False
1635
- if (
1636
- no_port_yet
1637
- and (port := getattr(port, "default", port))
1638
- and str(port) != "8000"
1639
- ):
1640
- args.append(f"--port={port}")
1641
- if shutil.which("pdm") is not None:
1642
- cmd = "pdm run " + cmd
1660
+ cmd, args = _runserver(uvicorn, host, port, file)
1643
1661
  if args:
1644
1662
  cmd += " " + " ".join(args)
1645
1663
  exit_if_run_failed(cmd, dry=dry)
@@ -29,7 +29,7 @@ dependencies = [
29
29
  "typer>=0.24.0,<1",
30
30
  "tomli >=2.0.1,<3; python_version < '3.11'",
31
31
  ]
32
- version = "0.23.0"
32
+ version = "0.23.2"
33
33
 
34
34
  [project.urls]
35
35
  Homepage = "https://github.com/waketzheng/fast-dev-cli"
@@ -52,7 +52,8 @@ fast = "fast_dev_cli.cli:main"
52
52
 
53
53
  [dependency-groups]
54
54
  dev = [
55
- "asynctor>=0.10.0",
55
+ "asynctor>=0.13.0",
56
+ "httpx2>=2.5.0",
56
57
  ]
57
58
 
58
59
  [build-system]
@@ -65,9 +66,18 @@ build-backend = "pdm.backend"
65
66
  distribution = true
66
67
 
67
68
  [tool.pdm.version]
68
- source = "file"
69
69
  path = "fast_dev_cli/__init__.py"
70
70
 
71
+ [tool.pdm.build]
72
+ excludes = [
73
+ "./**/.git",
74
+ "./**/.*_cache",
75
+ "examples",
76
+ "scripts",
77
+ "tests",
78
+ "fastdevcli-slim",
79
+ ]
80
+
71
81
  [tool.pdm.scripts]
72
82
  up = "just up {args}"
73
83
  tree = "pdm list --tree {args}"
@@ -1 +0,0 @@
1
- __version__ = "0.23.0"
File without changes