fast-dev-cli 0.15.0__tar.gz → 0.15.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 (27) hide show
  1. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/PKG-INFO +2 -2
  2. fast_dev_cli-0.15.2/fast_dev_cli/__init__.py +1 -0
  3. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/fast_dev_cli/cli.py +57 -23
  4. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/pyproject.toml +4 -4
  5. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/conftest.py +8 -3
  6. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_bump.py +135 -0
  7. fast_dev_cli-0.15.0/fast_dev_cli/__init__.py +0 -1
  8. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/LICENSE +0 -0
  9. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/README.md +0 -0
  10. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/fast_dev_cli/__main__.py +0 -0
  11. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/fast_dev_cli/py.typed +0 -0
  12. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/pdm_build.py +0 -0
  13. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/scripts/check.py +0 -0
  14. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/scripts/format.py +0 -0
  15. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/scripts/test.py +0 -0
  16. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/__init__.py +0 -0
  17. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_fast_test.py +0 -0
  18. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_functions.py +0 -0
  19. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_lint.py +0 -0
  20. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_poetry_version_plugin.py +0 -0
  21. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_runserver.py +0 -0
  22. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_sync.py +0 -0
  23. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_tag.py +0 -0
  24. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_upgrade.py +0 -0
  25. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_upload.py +0 -0
  26. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.2}/tests/test_version.py +0 -0
  27. {fast_dev_cli-0.15.0 → fast_dev_cli-0.15.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.15.0
3
+ Version: 0.15.2
4
4
  Summary: Python project development tool.
5
5
  Author-Email: Waket Zheng <waketzheng@gmail.com>>
6
6
  Classifier: Development Status :: 4 - Beta
@@ -23,12 +23,12 @@ Project-URL: Homepage, https://github.com/waketzheng/fast-dev-cli
23
23
  Requires-Python: >=3.9
24
24
  Requires-Dist: typer<1,>=0.12.3
25
25
  Requires-Dist: emoji<3,>=2.12.1
26
+ Requires-Dist: packaging>=20.5
26
27
  Requires-Dist: tomli<3,>=2.0.1; python_version < "3.11"
27
28
  Requires-Dist: coverage<8,>=7.5.1
28
29
  Requires-Dist: mypy<2,>=1.15.0
29
30
  Requires-Dist: bumpversion2<2,>=1.4.3
30
31
  Requires-Dist: pytest<9,>=8.2.0
31
- Requires-Dist: packaging>=20.5
32
32
  Provides-Extra: include-optional-dependencies
33
33
  Requires-Dist: all; extra == "include-optional-dependencies"
34
34
  Description-Content-Type: text/markdown
@@ -0,0 +1 @@
1
+ __version__ = "0.15.2"
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import contextlib
3
4
  import importlib.metadata as importlib_metadata
4
5
  import os
5
6
  import re
@@ -11,7 +12,7 @@ from pathlib import Path
11
12
  from typing import (
12
13
  Any,
13
14
  Literal,
14
- # Optional is required by typers
15
+ # Optional is required by Option generated by typer
15
16
  Optional,
16
17
  cast,
17
18
  get_args,
@@ -121,16 +122,27 @@ def _parse_version(line: str, pattern: re.Pattern[str]) -> str:
121
122
  def read_version_from_file(
122
123
  package_name: str, work_dir: Path | None = None, toml_text: str | None = None
123
124
  ) -> str:
124
- if toml_text is None:
125
- toml_text = Project.load_toml_text()
126
- pattern = re.compile(r"version\s*=")
127
- invalid = ("0", "0.0.0")
128
- for line in toml_text.splitlines():
125
+ if not package_name and toml_text:
126
+ pattern = re.compile(r"version\s*=")
127
+ for line in toml_text.splitlines():
128
+ if pattern.match(line):
129
+ return _parse_version(line, pattern)
130
+ version_file = BumpUp.parse_filename(toml_text, work_dir, package_name)
131
+ if version_file == TOML_FILE:
132
+ if toml_text is None:
133
+ toml_text = Project.load_toml_text()
134
+ context = tomllib.loads(toml_text)
135
+ with contextlib.suppress(KeyError):
136
+ return context["project"]["version"]
137
+ with contextlib.suppress(KeyError): # Poetry V1
138
+ return context["tool"]["poetry"]["version"]
139
+ secho(f"WARNING: can not find 'version' item in {version_file}!")
140
+ return "0.0.0"
141
+ pattern = re.compile(r"__version__\s*=")
142
+ for line in Path(version_file).read_text("utf-8").splitlines():
129
143
  if pattern.match(line):
130
- version = _parse_version(line, pattern)
131
- if version.startswith("{") or version in invalid:
132
- break
133
- return version
144
+ return _parse_version(line, pattern)
145
+ # TODO: remove or refactor the following lines.
134
146
  if work_dir is None:
135
147
  work_dir = Project.get_work_dir()
136
148
  package_dir = work_dir / package_name
@@ -141,6 +153,7 @@ def read_version_from_file(
141
153
  ):
142
154
  secho("WARNING: __init__.py file does not exist!")
143
155
  return "0.0.0"
156
+
144
157
  pattern = re.compile(r"__version__\s*=")
145
158
  for line in init_file.read_text("utf-8").splitlines():
146
159
  if pattern.match(line):
@@ -257,8 +270,13 @@ class BumpUp(DryRun):
257
270
  return emoji.is_emoji(first_char)
258
271
 
259
272
  @staticmethod
260
- def parse_filename() -> str:
261
- toml_text = Project.load_toml_text()
273
+ def parse_filename(
274
+ toml_text: str | None = None,
275
+ work_dir: Path | None = None,
276
+ package_name: str | None = None,
277
+ ) -> str:
278
+ if toml_text is None:
279
+ toml_text = Project.load_toml_text()
262
280
  context = tomllib.loads(toml_text)
263
281
  by_version_plugin = False
264
282
  try:
@@ -276,6 +294,16 @@ class BumpUp(DryRun):
276
294
  version_value = context["tool"]["poetry"]["version"]
277
295
  except KeyError:
278
296
  if not Project.manage_by_poetry():
297
+ if work_dir is None:
298
+ work_dir = Project.get_work_dir()
299
+ for tool in ("pdm", "hatch"):
300
+ with contextlib.suppress(KeyError):
301
+ version_path = context["tool"][tool]["version"]["path"]
302
+ if (
303
+ Path(version_path).exists()
304
+ or work_dir.joinpath(version_path).exists()
305
+ ):
306
+ return version_path
279
307
  # version = { source = "file", path = "fast_dev_cli/__init__.py" }
280
308
  v_key = "version = "
281
309
  p_key = 'path = "'
@@ -284,7 +312,7 @@ class BumpUp(DryRun):
284
312
  continue
285
313
  if p_key in (value := line.split(v_key, 1)[-1].split("#")[0]):
286
314
  filename = value.split(p_key, 1)[-1].split('"')[0]
287
- if Project.get_work_dir().joinpath(filename).exists():
315
+ if work_dir.joinpath(filename).exists():
288
316
  return filename
289
317
  else:
290
318
  by_version_plugin = version_value in ("0", "0.0.0", "init")
@@ -308,6 +336,8 @@ class BumpUp(DryRun):
308
336
  cwd = Path.cwd()
309
337
  pattern = re.compile(r"__version__\s*=\s*['\"]")
310
338
  ds: list[Path] = []
339
+ if package_name is not None:
340
+ packages.insert(0, (package_name, ""))
311
341
  for package_name, source_dir in packages:
312
342
  ds.append(cwd / package_name)
313
343
  ds.append(cwd / "src" / package_name)
@@ -317,7 +347,12 @@ class BumpUp(DryRun):
317
347
  ds.extend([cwd / module_name, cwd / "src" / module_name, cwd])
318
348
  for d in ds:
319
349
  init_file = d / "__init__.py"
320
- if init_file.exists() and pattern.search(init_file.read_text("utf8")):
350
+ if (
351
+ init_file.exists() and pattern.search(init_file.read_text("utf8"))
352
+ ) or (
353
+ (init_file := init_file.with_name("__version__.py")).exists()
354
+ and pattern.search(init_file.read_text("utf8"))
355
+ ):
321
356
  break
322
357
  else:
323
358
  raise ParseError("Version file not found! Where are you now?")
@@ -923,23 +958,22 @@ class Sync(DryRun):
923
958
  raise EnvError("There project is not managed by uv/pdm/poetry!")
924
959
  return f"python -m pip install -r {self.filename}"
925
960
  prefix = "" if is_venv() else f"{tool} run "
926
- ensurepip = " {1}python -m ensurepip && {1}python -m pip install -U pip &&"
927
- if tool == "uv":
928
- export_cmd = "uv export --no-hashes --all-extras --frozen"
929
- if check_call(prefix + "python -m pip --version"):
930
- ensurepip = ""
931
- elif tool in ("poetry", "pdm"):
961
+ ensure_pip = " {1}python -m ensurepip && {1}python -m pip install -U pip &&"
962
+ export_cmd = "uv export --no-hashes --all-extras --frozen"
963
+ if tool in ("poetry", "pdm"):
932
964
  export_cmd = f"{tool} export --without-hashes --with=dev"
933
965
  if tool == "poetry":
934
- ensurepip = ""
966
+ ensure_pip = ""
935
967
  if not UpgradeDependencies.should_with_dev():
936
968
  export_cmd = export_cmd.replace(" --with=dev", "")
937
969
  if extras and isinstance(extras, (str, list)):
938
970
  export_cmd += f" --{extras=}".replace("'", '"')
939
971
  elif check_call(prefix + "python -m pip --version"):
940
- ensurepip = ""
972
+ ensure_pip = ""
973
+ elif check_call(prefix + "python -m pip --version"):
974
+ ensure_pip = ""
941
975
  install_cmd = (
942
- f"{{2}} -o {{0}} &&{ensurepip} {{1}}python -m pip install -r {{0}}"
976
+ f"{{2}} -o {{0}} &&{ensure_pip} {{1}}python -m pip install -r {{0}}"
943
977
  )
944
978
  if should_remove and not save:
945
979
  install_cmd += " && rm -f {0}"
@@ -32,16 +32,16 @@ classifiers = [
32
32
  "License :: OSI Approved :: MIT License",
33
33
  ]
34
34
  dependencies = [
35
- "typer>=0.12.3,<1",
35
+ "typer >=0.12.3,<1",
36
36
  "emoji >=2.12.1,<3",
37
- "tomli>=2.0.1,<3; python_version < '3.11'",
37
+ "packaging >=20.5",
38
+ "tomli >=2.0.1,<3; python_version < '3.11'",
38
39
  "coverage >=7.5.1,<8",
39
40
  "mypy >=1.15.0,<2",
40
41
  "bumpversion2 >=1.4.3,<2",
41
42
  "pytest >=8.2.0,<9",
42
- "packaging>=20.5",
43
43
  ]
44
- version = "0.15.0"
44
+ version = "0.15.2"
45
45
 
46
46
  [project.urls]
47
47
  Homepage = "https://github.com/waketzheng/fast-dev-cli"
@@ -51,7 +51,12 @@ build-backend = "poetry.core.masonry.api"
51
51
 
52
52
 
53
53
  @pytest.fixture
54
- def tmp_poetry_project(tmp_path: Path):
54
+ def tmp_work_dir(tmp_path):
55
55
  with chdir(tmp_path):
56
- tmp_path.joinpath(TOML_FILE).write_text(TOML_CONTENT)
57
- yield
56
+ yield tmp_path
57
+
58
+
59
+ @pytest.fixture
60
+ def tmp_poetry_project(tmp_work_dir: Path):
61
+ Path(TOML_FILE).write_text(TOML_CONTENT)
62
+ yield tmp_work_dir
@@ -230,3 +230,138 @@ version = "0"
230
230
  from_dir.mkdir()
231
231
  shutil.move(another_dir, from_dir)
232
232
  assert BumpUp.parse_filename() == "py/hello/__init__.py"
233
+
234
+
235
+ PDM_DYNAMIC_VERSION = """
236
+ [tool.pdm.version]
237
+ source = "file"
238
+ path = "app/__init__.py"
239
+ """
240
+
241
+
242
+ def test_pdm_project(tmp_work_dir):
243
+ capture_cmd_output("pdm new my-project --non-interactive")
244
+ with chdir("my-project"):
245
+ toml_file = Path("pyproject.toml")
246
+ content = toml_file.read_text().replace(
247
+ 'version = "0.1.0"', 'dynamic = ["version"]'
248
+ )
249
+ toml_file.write_text(content)
250
+ with toml_file.open("a+") as f:
251
+ f.write(PDM_DYNAMIC_VERSION)
252
+ app = Path("app")
253
+ app.mkdir()
254
+ init_file = app.joinpath("__init__.py")
255
+ init_file.write_text('__version__ = "0.2.0"')
256
+ out = capture_cmd_output("fast bump patch")
257
+ assert str(init_file) in out
258
+ assert "0.2.1" in init_file.read_text()
259
+
260
+
261
+ def test_hatch_project(tmp_work_dir):
262
+ project_name = "httpx"
263
+ Path(project_name).mkdir()
264
+ with chdir(project_name):
265
+ toml_file = Path("pyproject.toml")
266
+ toml_file.write_text("""
267
+ [build-system]
268
+ requires = ["hatchling", "hatch-fancy-pypi-readme"]
269
+ build-backend = "hatchling.build"
270
+
271
+ [project]
272
+ name = "httpx"
273
+ description = "The next generation HTTP client."
274
+ license = "BSD-3-Clause"
275
+ requires-python = ">=3.8"
276
+ authors = [
277
+ { name = "Tom Christie", email = "tom@tomchristie.com" },
278
+ ]
279
+ dependencies = [
280
+ "certifi",
281
+ "httpcore==1.*",
282
+ "anyio",
283
+ "idna",
284
+ ]
285
+ dynamic = ["readme", "version"]
286
+
287
+ [tool.hatch.version]
288
+ path = "httpx/__version__.py"
289
+ """)
290
+ Path(project_name).mkdir()
291
+ version_file = Path("httpx/__version__.py")
292
+ version_file.write_text("""
293
+ __title__ = "httpx"
294
+ __description__ = "A next generation HTTP client, for Python 3."
295
+ __version__ = "0.28.1"
296
+ """)
297
+ out = capture_cmd_output("fast bump patch")
298
+ assert str(version_file) in out
299
+ assert "0.28.2" in version_file.read_text()
300
+
301
+
302
+ def test_package_project_diff(tmp_work_dir):
303
+ project_name = "tortoise-database-url"
304
+ package_name = "database_url"
305
+ Path(project_name).mkdir()
306
+ with chdir(project_name):
307
+ Path(package_name).mkdir()
308
+ version_file = Path(package_name, "__init__.py")
309
+ version_file.write_text('__version__ = "0.3.0"')
310
+ toml_file = Path("pyproject.toml")
311
+ toml_file.write_text("""
312
+ [project]
313
+ name = "tortoise-database-url"
314
+ description = "Make it easy to generate database url."
315
+ authors = [{name="Waket Zheng", email="waketzheng@gmail.com"}]
316
+ readme = "README.md"
317
+ dynamic = ["version"]
318
+ keywords = ["database_url", "tortoise-orm"]
319
+ requires-python = ">=3.9"
320
+ dependencies = []
321
+
322
+ [tool.pdm.version]
323
+ source = "file"
324
+ path = "database_url/__init__.py"
325
+
326
+ [build-system]
327
+ requires = ["pdm-backend"]
328
+ build-backend = "pdm.backend"
329
+ """)
330
+ out = capture_cmd_output("fast bump patch")
331
+ assert str(version_file) in out
332
+ assert "0.3.1" in version_file.read_text()
333
+
334
+
335
+ def test_version_file_in_work_dir(tmp_work_dir):
336
+ project_name = package_name = "bigmodels"
337
+ Path(project_name).mkdir()
338
+ with chdir(project_name):
339
+ Path(package_name).mkdir()
340
+ version_file = Path("__version__.py")
341
+ version_file.write_text('__version__ = "0.3.0"')
342
+ toml_file = Path("pyproject.toml")
343
+ toml_file.write_text("""
344
+ [project]
345
+ name = "bigmodels"
346
+ description = ""
347
+ authors = [{name="Waket Zheng", email="waketzheng@gmail.com"}]
348
+ readme = "README.md"
349
+ dynamic = ["version"]
350
+ keywords = []
351
+ requires-python = ">=3.9"
352
+ dependencies = []
353
+
354
+ [tool.pdm]
355
+ distribution = false
356
+
357
+ [tool.pdm.version]
358
+ source = "file"
359
+ path = "__version__.py"
360
+
361
+ [build-system]
362
+ requires = ["pdm-backend"]
363
+ build-backend = "pdm.backend"
364
+ """)
365
+ out = capture_cmd_output("fast bump patch")
366
+ assert str(version_file) in out
367
+ assert "0.3.1" in version_file.read_text()
@@ -1 +0,0 @@
1
- __version__ = "0.15.0"
File without changes
File without changes