create-awesome-python-app 0.2.7__tar.gz → 0.2.8__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 (21) hide show
  1. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/PKG-INFO +1 -1
  2. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/pyproject.toml +1 -1
  3. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/src/create_awesome_python_app/__init__.py +1 -1
  4. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/src/create_awesome_python_app/cli.py +44 -1
  5. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/test_cli.py +102 -0
  6. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/.gitignore +0 -0
  7. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/README.md +0 -0
  8. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/assets/hero.svg +0 -0
  9. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/src/create_awesome_python_app/cache.py +0 -0
  10. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/src/create_awesome_python_app/catalog.py +0 -0
  11. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/src/create_awesome_python_app/prompt_style.py +0 -0
  12. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/conftest.py +0 -0
  13. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/test_cache_cmds.py +0 -0
  14. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/test_cache_env.py +0 -0
  15. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/test_catalog.py +0 -0
  16. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/test_catalog_fetch.py +0 -0
  17. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/test_catalog_resolve.py +0 -0
  18. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/test_cpa_templates_integration.py +0 -0
  19. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/test_flags.py +0 -0
  20. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/test_interactive.py +0 -0
  21. {create_awesome_python_app-0.2.7 → create_awesome_python_app-0.2.8}/tests/test_smoke.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: create-awesome-python-app
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Composable scaffolding CLI for production-ready Python apps
5
5
  Project-URL: Homepage, https://github.com/Create-Python-App/create-python-app
6
6
  Project-URL: Repository, https://github.com/Create-Python-App/create-python-app
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "create-awesome-python-app"
3
- version = "0.2.7"
3
+ version = "0.2.8"
4
4
  description = "Composable scaffolding CLI for production-ready Python apps"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -1,3 +1,3 @@
1
1
  """Create Awesome Python App CLI."""
2
2
 
3
- __version__ = "0.2.7"
3
+ __version__ = "0.2.8"
@@ -71,6 +71,49 @@ def _preprocess_fixture_argv(argv: list[str] | None = None) -> list[str]:
71
71
  return out
72
72
 
73
73
 
74
+ def _expand_variadic_option(argv: list[str], option: str) -> list[str]:
75
+ """Expand ``--addons a b`` into ``--addons a --addons b`` (CNA Commander parity).
76
+
77
+ Typer's ``list[str]`` Option only accepts one value per flag. Commander uses
78
+ ``--addons [extensions...]``, so users naturally write space-separated lists.
79
+ """
80
+ out: list[str] = []
81
+ i = 0
82
+ prefix = option + "="
83
+ while i < len(argv):
84
+ arg = argv[i]
85
+ if arg == option:
86
+ i += 1
87
+ values: list[str] = []
88
+ while i < len(argv) and not argv[i].startswith("-"):
89
+ values.append(argv[i])
90
+ i += 1
91
+ if not values:
92
+ out.append(option)
93
+ else:
94
+ for value in values:
95
+ out.extend([option, value])
96
+ continue
97
+ if arg.startswith(prefix):
98
+ value = arg[len(prefix) :]
99
+ out.extend([option, value] if value else [option])
100
+ i += 1
101
+ continue
102
+ out.append(arg)
103
+ i += 1
104
+ return out
105
+
106
+
107
+ def _preprocess_cli_argv(argv: list[str] | None = None) -> list[str]:
108
+ """Apply argv rewrites needed before Typer parses the CLI."""
109
+ out = _preprocess_fixture_argv(argv)
110
+ out = _expand_variadic_option(out, "--addons")
111
+ out = _expand_variadic_option(out, "--extend")
112
+ if argv is None:
113
+ sys.argv = out
114
+ return out
115
+
116
+
74
117
  def apply_fixture_mode(fixture: str | None) -> None:
75
118
  """Translate ``--fixture`` into ``CPA_CATALOG_FIXTURE`` / ``CPA_FIXTURE_DIR``."""
76
119
  if fixture is None and os.environ.get("CPA_CATALOG_FIXTURE") != "1":
@@ -204,7 +247,7 @@ def main() -> None:
204
247
  treat `cache` as project_directory).
205
248
  """
206
249
  check_python_version(">=3.12", "create-awesome-python-app")
207
- _preprocess_fixture_argv()
250
+ _preprocess_cli_argv()
208
251
  if len(sys.argv) > 1 and sys.argv[1] == "cache":
209
252
  sys.argv = [sys.argv[0], *sys.argv[2:]]
210
253
  cache_app(prog_name="create-awesome-python-app cache")
@@ -271,6 +271,108 @@ def test_options_after_project_directory(tmp_path: Path, monkeypatch) -> None:
271
271
  assert options["template"] == f"file://{tpl}"
272
272
 
273
273
 
274
+ def test_expand_variadic_addons_and_extend() -> None:
275
+ from create_awesome_python_app.cli import (
276
+ _expand_variadic_option,
277
+ _preprocess_cli_argv,
278
+ )
279
+
280
+ assert _expand_variadic_option(
281
+ ["cpa", "my-api", "--addons", "fastapi-docker", "github-setup", "--no-install"],
282
+ "--addons",
283
+ ) == [
284
+ "cpa",
285
+ "my-api",
286
+ "--addons",
287
+ "fastapi-docker",
288
+ "--addons",
289
+ "github-setup",
290
+ "--no-install",
291
+ ]
292
+ assert _preprocess_cli_argv(
293
+ [
294
+ "cpa",
295
+ "my-api",
296
+ "--template",
297
+ "fastapi-starter",
298
+ "--addons",
299
+ "fastapi-docker",
300
+ "github-setup",
301
+ "--extend",
302
+ "a",
303
+ "b",
304
+ "--no-interactive",
305
+ ]
306
+ ) == [
307
+ "cpa",
308
+ "my-api",
309
+ "--template",
310
+ "fastapi-starter",
311
+ "--addons",
312
+ "fastapi-docker",
313
+ "--addons",
314
+ "github-setup",
315
+ "--extend",
316
+ "a",
317
+ "--extend",
318
+ "b",
319
+ "--no-interactive",
320
+ ]
321
+
322
+
323
+ def test_space_separated_addons_after_project_directory(
324
+ tmp_path: Path, monkeypatch
325
+ ) -> None:
326
+ """CNA parity: ``--addons fastapi-docker github-setup`` (one flag, many values)."""
327
+ from create_awesome_python_app.cli import _preprocess_cli_argv
328
+
329
+ tpl = tmp_path / "tpl"
330
+ tpl.mkdir()
331
+ captured: dict[str, object] = {}
332
+
333
+ async def fake_check_for_latest_version(_package_name):
334
+ return None
335
+
336
+ async def fake_create_python_app(project_directory, options, *_args, **_kwargs):
337
+ captured["project_directory"] = project_directory
338
+ captured["options"] = options
339
+
340
+ monkeypatch.setattr(
341
+ "create_awesome_python_app.cli.check_for_latest_version",
342
+ fake_check_for_latest_version,
343
+ )
344
+ monkeypatch.setattr(
345
+ "create_awesome_python_app.cli.create_python_app",
346
+ fake_create_python_app,
347
+ )
348
+
349
+ argv = _preprocess_cli_argv(
350
+ [
351
+ "cpa",
352
+ "my-api",
353
+ "--template",
354
+ f"file://{tpl}",
355
+ "--addons",
356
+ "fastapi-docker",
357
+ "github-setup",
358
+ "--no-install",
359
+ "--no-interactive",
360
+ ]
361
+ )
362
+ result = runner.invoke(app, argv[1:])
363
+
364
+ text = (result.stdout or "") + (result.stderr or "")
365
+ assert result.exit_code == 0, text
366
+ assert "unexpected extra argument" not in text.lower()
367
+ options = captured["options"]
368
+ assert isinstance(options, dict)
369
+ addons = options["addons"]
370
+ assert isinstance(addons, list)
371
+ assert len(addons) == 2
372
+ assert any("fastapi-docker" in a for a in addons)
373
+ assert any("github-setup" in a for a in addons)
374
+
375
+
274
376
  def test_preprocess_fixture_argv_bare_and_with_dir() -> None:
275
377
  from create_awesome_python_app.cli import _FIXTURE_AUTO, _preprocess_fixture_argv
276
378