fast-dev-cli 0.25.0__tar.gz → 0.25.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fast-dev-cli
3
- Version: 0.25.0
3
+ Version: 0.25.1
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.25.1"
@@ -114,13 +114,19 @@ def yellow_warn(msg: str) -> None:
114
114
  def load_bool(name: str, default: bool = False, *, verbose: bool = True) -> bool:
115
115
  if not (v := os.getenv(name)):
116
116
  return default
117
+ if (b := _convert_bool(v)) is not None:
118
+ return b
119
+ if verbose:
120
+ secho(f"WARNING: can not convert value({v!r}) of {name} to bool!")
121
+ return default
122
+
123
+
124
+ def _convert_bool(v: str) -> bool | None:
117
125
  if (lower := v.lower()) in ("0", "false", "f", "off", "no", "n"):
118
126
  return False
119
127
  elif lower in ("1", "true", "t", "on", "yes", "y"):
120
128
  return True
121
- if verbose:
122
- secho(f"WARNING: can not convert value({v!r}) of {name} to bool!")
123
- return default
129
+ return None
124
130
 
125
131
 
126
132
  def is_venv() -> bool:
@@ -141,7 +147,8 @@ class Shell:
141
147
  ) -> subprocess.CompletedProcess[str]:
142
148
  if isinstance(cmd, str):
143
149
  kw.setdefault("shell", True)
144
- return subprocess.run(cmd, **kw) # nosec:B603
150
+ check = kw.pop("check", False)
151
+ return subprocess.run(cmd, check=check, **kw) # nosec:B603
145
152
 
146
153
  @property
147
154
  def command(self) -> list[str] | str:
@@ -260,13 +267,12 @@ def read_version_from_file(
260
267
  for line in all_lines:
261
268
  if pattern.match(line):
262
269
  return _parse_version(line, pattern)
263
- else:
264
- pattern = re.compile(r"VERSION\s*=")
265
- for line in all_lines:
266
- if pattern.match(line):
267
- return _parse_version(line, pattern)
268
- secho(f"WARNING: can not find version pattern in {version_file}!")
269
- return "0.0.0"
270
+ pattern = re.compile(r"VERSION\s*=")
271
+ for line in all_lines:
272
+ if pattern.match(line):
273
+ return _parse_version(line, pattern)
274
+ secho(f"WARNING: can not find version pattern in {version_file}!")
275
+ return "0.0.0"
270
276
 
271
277
 
272
278
  def _get_frontend_version() -> tuple[Path, str] | None:
@@ -325,9 +331,9 @@ def get_current_version(
325
331
  if package_name is None:
326
332
  try:
327
333
  work_dir = Project.get_work_dir()
328
- except EnvError as e:
334
+ except EnvError:
329
335
  if (res := _get_frontend_version()) is None:
330
- raise e
336
+ raise
331
337
  current_version = res[1]
332
338
  if check_version:
333
339
  return False, current_version
@@ -468,7 +474,7 @@ class BumpUp(DryRun):
468
474
  toml_text: str | None = None,
469
475
  work_dir: Path | None = None,
470
476
  package_name: str | None = None,
471
- context: dict | None = None,
477
+ context: dict[str, Any] | None = None,
472
478
  ) -> str:
473
479
  if context is None:
474
480
  if toml_text is None:
@@ -528,11 +534,11 @@ class BumpUp(DryRun):
528
534
  ds: list[Path] = []
529
535
  if package_name is not None:
530
536
  packages.insert(0, (package_name, ""))
531
- for package_name, source_dir in packages:
532
- ds.append(cwd / package_name)
533
- ds.append(cwd / "src" / package_name)
537
+ for pack_name, source_dir in packages:
538
+ ds.append(cwd / pack_name)
539
+ ds.append(cwd / "src" / pack_name)
534
540
  if source_dir and source_dir != "src":
535
- ds.append(cwd / source_dir / package_name)
541
+ ds.append(cwd / source_dir / pack_name)
536
542
  module_name = poetry_module_name(cwd.name)
537
543
  ds.extend([cwd / module_name, cwd / "src" / module_name, cwd])
538
544
  for d in ds:
@@ -756,7 +762,7 @@ class Project:
756
762
  if skip_uv:
757
763
  for name in ("pdm", "poetry"):
758
764
  if f"[tool.{name}]" in text:
759
- cls._tool = cast(ToolName, name)
765
+ cls._tool = name
760
766
  return cls._tool
761
767
  work_dir = cls.get_work_dir(allow_cwd=True)
762
768
  for name in ("pdm", "poetry"):
@@ -791,11 +797,11 @@ class Project:
791
797
  if backend:
792
798
  for t in ("pdm", "poetry"):
793
799
  if t in backend:
794
- cls._tool = cast(ToolName, t)
800
+ cls._tool = t
795
801
  return cls._tool
796
802
  for name in ("pdm", "poetry"):
797
803
  if f"[tool.{name}]" in text:
798
- cls._tool = cast(ToolName, name)
804
+ cls._tool = name
799
805
  return cls._tool
800
806
  if x == 2:
801
807
  cls._tool = (
@@ -919,7 +925,7 @@ class UpgradeDependencies(Project, DryRun):
919
925
  elif v == "[":
920
926
  echo(f"Skip complex dependence: {line}")
921
927
  return True
922
- elif v.startswith(">") or v.startswith("<") or v[0].isdigit():
928
+ elif v.startswith((">", "<")) or v[0].isdigit():
923
929
  echo(f"Ignore bigger/smaller/equal: {line}")
924
930
  return True
925
931
  return False
@@ -1423,6 +1429,14 @@ def check(
1423
1429
  ).run()
1424
1430
 
1425
1431
 
1432
+ def _should_bandit() -> bool:
1433
+ if v := os.getenv("FASTDEVCLI_BANDIT"):
1434
+ return _convert_bool(v) or True
1435
+ toml_text = Project.load_toml_text()
1436
+ lines = toml_text.splitlines()
1437
+ return any(i.startswith("[tool.bandit") for i in lines)
1438
+
1439
+
1426
1440
  @cli.command(name="lint")
1427
1441
  def make_style(
1428
1442
  files: list[str] | None = typer.Argument(default=None), # noqa:B008
@@ -1444,6 +1458,9 @@ def make_style(
1444
1458
  strict: bool = Option(False, help="Whether run mypy with --strict"),
1445
1459
  ty: bool = Option(False, help="Whether use ty instead of mypy"),
1446
1460
  fix: bool | None = Option(None, help="Whether ruff check with --fix"),
1461
+ auto_bandit: bool | None = Option(
1462
+ None, help="Whether to run bandit if `[tool.bandit]` in pyproject.toml"
1463
+ ),
1447
1464
  ) -> None:
1448
1465
  """Run: ruff check/format to reformat code and then mypy to check"""
1449
1466
  if getattr(files, "default", files) is None:
@@ -1452,7 +1469,9 @@ def make_style(
1452
1469
  files = [files]
1453
1470
  skip = _ensure_bool(skip_mypy)
1454
1471
  dmypy = _ensure_bool(use_dmypy)
1455
- bandit = _ensure_bool(bandit)
1472
+ bandit = _ensure_bool(bandit) or (
1473
+ auto_bandit is not None and _ensure_bool(auto_bandit) and _should_bandit()
1474
+ )
1456
1475
  tool = _ensure_str(tool) or ""
1457
1476
  up = _ensure_bool(up)
1458
1477
  sim = _ensure_bool(sim)
@@ -1585,7 +1604,7 @@ class Publish:
1585
1604
  twine = "python -m build && twine upload"
1586
1605
 
1587
1606
  @classmethod
1588
- def gen(cls, tool: str, verbose: bool) -> str:
1607
+ def gen(cls, tool: str | None, verbose: bool) -> str:
1589
1608
  if tool == "auto":
1590
1609
  tool = Project.get_manage_tool() or ""
1591
1610
  if tool:
@@ -1612,7 +1631,7 @@ def upload(
1612
1631
  dry: bool = DryOption,
1613
1632
  ) -> None:
1614
1633
  """Shortcut for package publish"""
1615
- cmd = Publish.gen(tool, verbose)
1634
+ cmd = Publish.gen(_ensure_str(tool), verbose)
1616
1635
  exit_if_run_failed(cmd, dry=dry)
1617
1636
 
1618
1637
 
@@ -1650,7 +1669,9 @@ def _prefer_just_dev(f: Path) -> bool:
1650
1669
  return False
1651
1670
 
1652
1671
 
1653
- def _parse_serve_file(uvicorn, filename: str, cmd: str, args: list) -> str:
1672
+ def _parse_serve_file(
1673
+ uvicorn: bool | None, filename: str, cmd: str, args: list[str]
1674
+ ) -> str:
1654
1675
  if m := re.search(r"(.*):(\d+)$", filename):
1655
1676
  h, p = m.group(1), m.group(2)
1656
1677
  if h and "--host" not in str(args):
@@ -1677,7 +1698,12 @@ def _parse_serve_file(uvicorn, filename: str, cmd: str, args: list) -> str:
1677
1698
  return cmd
1678
1699
 
1679
1700
 
1680
- def _runserver(uvicorn, host, port, file) -> tuple[str, list[str]]:
1701
+ def _runserver(
1702
+ uvicorn: bool | None,
1703
+ host: OptionInfo | str | None,
1704
+ port: OptionInfo | int | None,
1705
+ file: ArgumentInfo | str | None,
1706
+ ) -> tuple[str, list[str]]:
1681
1707
  cmd = "uvicorn" if uvicorn else "fastapi dev"
1682
1708
  args = []
1683
1709
  if (host := getattr(host, "default", host)) and host not in (
@@ -1710,10 +1736,11 @@ def dev(
1710
1736
  uvicorn: bool | None = None,
1711
1737
  prod: bool | None = None,
1712
1738
  reload: bool | None = None,
1739
+ just: bool | None = None,
1713
1740
  file: str | None | ArgumentInfo = None,
1714
1741
  dry: bool = False,
1715
1742
  ) -> None:
1716
- if should_use_just():
1743
+ if just is not False and should_use_just():
1717
1744
  args = [i for i in sys.argv[2:] if i != "--dry"]
1718
1745
  cmd = "just dev"
1719
1746
  else:
@@ -1732,10 +1759,13 @@ def runserver(
1732
1759
  uvicorn: bool | None = None,
1733
1760
  prod: bool | None = None,
1734
1761
  reload: bool | None = None,
1762
+ just: bool | None = None,
1735
1763
  dry: bool = DryOption,
1736
1764
  ) -> None:
1737
1765
  """Start a fastapi server(only for fastapi>=0.111.0)"""
1738
- f = functools.partial(dev, port, host, fastapi, uvicorn, prod, reload, dry=dry)
1766
+ f = functools.partial(
1767
+ dev, port, host, fastapi, uvicorn, prod, reload, just, dry=dry
1768
+ )
1739
1769
  if getattr(file_or_port, "default", file_or_port):
1740
1770
  f(file=file_or_port)
1741
1771
  else:
@@ -1754,7 +1784,7 @@ def run_by_subprocess(cmd: str, dry: bool = DryOption) -> None:
1754
1784
  ):
1755
1785
  echo(f"Command not found: {command}")
1756
1786
  raise Exit(1) from None
1757
- raise e
1787
+ raise
1758
1788
  else:
1759
1789
  if rc:
1760
1790
  raise Exit(rc)
@@ -1824,15 +1854,17 @@ class MakeDeps(DryRun):
1824
1854
  tool_section = doc["tool"]
1825
1855
  uv_package = tool_section.get("uv", {}).get("package")
1826
1856
  if uv_package is not None:
1827
- return doc["project"]["name"] if uv_package else ""
1828
- match doc["build-system"]["build-backend"]:
1829
- case "pdm.backend":
1830
- if not tool_section.get("pdm", {}).get("distribution", True):
1831
- return ""
1832
- case x if x.startswith("poetry"):
1833
- if not tool_section.get("poetry", {}).get("package-mode", True):
1834
- return ""
1835
- return doc["project"]["name"]
1857
+ if not uv_package:
1858
+ return ""
1859
+ else:
1860
+ match doc["build-system"]["build-backend"]:
1861
+ case "pdm.backend":
1862
+ if not tool_section.get("pdm", {}).get("distribution", True):
1863
+ return ""
1864
+ case x if x.startswith("poetry"):
1865
+ if not tool_section.get("poetry", {}).get("package-mode", True):
1866
+ return ""
1867
+ return cast(str, doc["project"]["name"])
1836
1868
  return ""
1837
1869
 
1838
1870
  def _gen(self) -> str:
@@ -1948,7 +1980,7 @@ class UvPypi(DryRun):
1948
1980
 
1949
1981
  @staticmethod
1950
1982
  def get_target_content(
1951
- text: str, verbose: bool, target_registry, target_host: str
1983
+ text: str, verbose: bool, target_registry: str, target_host: str
1952
1984
  ) -> str | None:
1953
1985
  registry_pattern = r'(registry = ")(.*?)"'
1954
1986
  registry_urls = {i[1] for i in re.findall(registry_pattern, text)}
@@ -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.25.0"
32
+ version = "0.25.1"
33
33
 
34
34
  [project.urls]
35
35
  Homepage = "https://github.com/waketzheng/fast-dev-cli"
@@ -184,10 +184,13 @@ extend-select = [
184
184
  [tool.ruff.lint.per-file-ignores]
185
185
  "test_*.py" = [
186
186
  "E501",
187
+ "BLE001",
188
+ "PLW1510",
187
189
  ]
188
190
  "scripts/*.py" = [
189
191
  "UP009",
190
192
  "UP032",
193
+ "PLW1510",
191
194
  ]
192
195
  "fast_dev_cli/cli.py" = [
193
196
  "UP007",
@@ -1 +0,0 @@
1
- __version__ = "0.25.0"
File without changes
File without changes