create-awesome-python-app 0.2.8__py3-none-any.whl → 0.2.10__py3-none-any.whl

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,3 +1,3 @@
1
1
  """Create Awesome Python App CLI."""
2
2
 
3
- __version__ = "0.2.8"
3
+ __version__ = "0.2.10"
@@ -12,6 +12,8 @@ import typer
12
12
  from create_python_app_core import (
13
13
  ConfigParseError,
14
14
  CpaCustomOption,
15
+ NonEmptyTargetDirectoryError,
16
+ assert_directory_is_empty,
15
17
  check_for_latest_version,
16
18
  check_python_version,
17
19
  create_python_app,
@@ -76,10 +78,15 @@ def _expand_variadic_option(argv: list[str], option: str) -> list[str]:
76
78
 
77
79
  Typer's ``list[str]`` Option only accepts one value per flag. Commander uses
78
80
  ``--addons [extensions...]``, so users naturally write space-separated lists.
81
+
82
+ When ``project_directory`` comes *after* options and no positional was seen
83
+ yet, peel the final trailing token at EOS back as the directory so that
84
+ ``--addons a --addons b /tmp/app`` does not treat ``/tmp/app`` as an addon.
79
85
  """
80
86
  out: list[str] = []
81
87
  i = 0
82
88
  prefix = option + "="
89
+ saw_positional = False
83
90
  while i < len(argv):
84
91
  arg = argv[i]
85
92
  if arg == option:
@@ -88,17 +95,26 @@ def _expand_variadic_option(argv: list[str], option: str) -> list[str]:
88
95
  while i < len(argv) and not argv[i].startswith("-"):
89
96
  values.append(argv[i])
90
97
  i += 1
98
+ ended_at_eos = i >= len(argv)
99
+ trailing: str | None = None
100
+ if ended_at_eos and not saw_positional and len(values) >= 2:
101
+ trailing = values.pop()
91
102
  if not values:
92
103
  out.append(option)
93
104
  else:
94
105
  for value in values:
95
106
  out.extend([option, value])
107
+ if trailing is not None:
108
+ out.append(trailing)
109
+ saw_positional = True
96
110
  continue
97
111
  if arg.startswith(prefix):
98
112
  value = arg[len(prefix) :]
99
113
  out.extend([option, value] if value else [option])
100
114
  i += 1
101
115
  continue
116
+ if i > 0 and not arg.startswith("-"):
117
+ saw_positional = True
102
118
  out.append(arg)
103
119
  i += 1
104
120
  return out
@@ -106,7 +122,9 @@ def _expand_variadic_option(argv: list[str], option: str) -> list[str]:
106
122
 
107
123
  def _preprocess_cli_argv(argv: list[str] | None = None) -> list[str]:
108
124
  """Apply argv rewrites needed before Typer parses the CLI."""
109
- out = _preprocess_fixture_argv(argv)
125
+ raw = list(sys.argv if argv is None else argv)
126
+ # Pass an explicit list so fixture preprocess does not mutate sys.argv early.
127
+ out = _preprocess_fixture_argv(raw)
110
128
  out = _expand_variadic_option(out, "--addons")
111
129
  out = _expand_variadic_option(out, "--extend")
112
130
  if argv is None:
@@ -307,6 +325,18 @@ def scaffold(
307
325
  la(template)
308
326
  raise typer.Exit(0)
309
327
 
328
+ target_directory = project_directory or "my-project"
329
+ # Fail before the interactive wizard so a leftover `my-project/` does not
330
+ # waste a full prompt session (and so we exit cleanly, not with a traceback).
331
+ if not force:
332
+ try:
333
+ assert_directory_is_empty(
334
+ Path(target_directory).expanduser().resolve(), force=False
335
+ )
336
+ except NonEmptyTargetDirectoryError as err:
337
+ console.print(f"[red]{err}[/red]")
338
+ raise typer.Exit(1) from err
339
+
310
340
  effective_refresh = _normalize_refresh(refresh)
311
341
  if refresh and effective_refresh is None:
312
342
  console.print(
@@ -524,25 +554,31 @@ def scaffold(
524
554
  raise typer.Exit(1)
525
555
  console.print(f"[yellow]{msg}[/yellow]")
526
556
 
527
- asyncio.run(
528
- create_python_app(
529
- project_directory or "my-project",
530
- {
531
- "template": template,
532
- "addons": addons or [],
533
- "extend": extend or [],
534
- "install": not no_install,
535
- "force": force,
536
- "verbose": verbose,
537
- "offline": offline,
538
- "refresh": effective_refresh,
539
- "keep_on_failure": keep_on_failure,
540
- "cache_dir": str(cache_dir) if cache_dir else None,
541
- "set": set_map,
542
- },
557
+ try:
558
+ asyncio.run(
559
+ create_python_app(
560
+ target_directory,
561
+ {
562
+ "template": template,
563
+ "addons": addons or [],
564
+ "extend": extend or [],
565
+ "install": not no_install,
566
+ "force": force,
567
+ "verbose": verbose,
568
+ "offline": offline,
569
+ "refresh": effective_refresh,
570
+ "keep_on_failure": keep_on_failure,
571
+ "cache_dir": str(cache_dir) if cache_dir else None,
572
+ "set": set_map,
573
+ },
574
+ )
543
575
  )
544
- )
545
- console.print(f"[green]Created[/green] {project_directory}")
576
+ except NonEmptyTargetDirectoryError as err:
577
+ # Safety net if the target fills up after the early check (e.g. during
578
+ # a long interactive session).
579
+ console.print(f"[red]{err}[/red]")
580
+ raise typer.Exit(1) from err
581
+ console.print(f"[green]Created[/green] {target_directory}")
546
582
 
547
583
 
548
584
  @cache_app.command("dir")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: create-awesome-python-app
3
- Version: 0.2.8
3
+ Version: 0.2.10
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
@@ -8,7 +8,7 @@ Project-URL: Issues, https://github.com/Create-Python-App/create-python-app/issu
8
8
  Project-URL: Changelog, https://github.com/Create-Python-App/create-python-app/blob/main/CHANGELOG.md
9
9
  License-Expression: MIT
10
10
  Requires-Python: >=3.12
11
- Requires-Dist: create-python-app-core>=0.2.6
11
+ Requires-Dist: create-python-app-core>=0.2.10
12
12
  Requires-Dist: questionary>=2.1.1
13
13
  Requires-Dist: rich>=15.0.0
14
14
  Requires-Dist: typer>=0.27.0
@@ -0,0 +1,9 @@
1
+ create_awesome_python_app/__init__.py,sha256=bi_KnqAleIdsMEwUjb0fOKqFtc6xP93QD5OPMGuYTtk,61
2
+ create_awesome_python_app/cache.py,sha256=eHKUlunGexZKYJo0HDNoBoOVq0DjLyRYgEe_wUh4Fk0,11812
3
+ create_awesome_python_app/catalog.py,sha256=ZB-ieyEn_TBqVBbCbFkK9h3VJoYtifvvOxs_BM2tDEw,22754
4
+ create_awesome_python_app/cli.py,sha256=sEGWsw1gz1ayQcv2p0VNl2NKZeZJvU_WdSkv8tVyqaY,29229
5
+ create_awesome_python_app/prompt_style.py,sha256=pERX1qPQSLZXeJvPVFC7z85dvte73ZV4iuENPQduheE,3463
6
+ create_awesome_python_app-0.2.10.dist-info/METADATA,sha256=3FZrfWHw86Qrqb0IdSzoE4tMdaIlTbgzJUm4pi5Ksns,23273
7
+ create_awesome_python_app-0.2.10.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
8
+ create_awesome_python_app-0.2.10.dist-info/entry_points.txt,sha256=rszFbUjY-lvMDZ96zX1lALJwgD1mI3CkUuNyF2qqjYo,81
9
+ create_awesome_python_app-0.2.10.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- create_awesome_python_app/__init__.py,sha256=bpha_GXZNmruh0uP4KvEZzHYZOOzyqluLF2ediJjcdo,60
2
- create_awesome_python_app/cache.py,sha256=eHKUlunGexZKYJo0HDNoBoOVq0DjLyRYgEe_wUh4Fk0,11812
3
- create_awesome_python_app/catalog.py,sha256=ZB-ieyEn_TBqVBbCbFkK9h3VJoYtifvvOxs_BM2tDEw,22754
4
- create_awesome_python_app/cli.py,sha256=bSmivzm4lUOcDtoyNT-t3PL_Xb1O8msAUl_XFczeNkQ,27555
5
- create_awesome_python_app/prompt_style.py,sha256=pERX1qPQSLZXeJvPVFC7z85dvte73ZV4iuENPQduheE,3463
6
- create_awesome_python_app-0.2.8.dist-info/METADATA,sha256=YcMQFDgWXeK0jT77VqBV6LOYNBxfTWOhhYRWpZ1A9W0,23271
7
- create_awesome_python_app-0.2.8.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
8
- create_awesome_python_app-0.2.8.dist-info/entry_points.txt,sha256=rszFbUjY-lvMDZ96zX1lALJwgD1mI3CkUuNyF2qqjYo,81
9
- create_awesome_python_app-0.2.8.dist-info/RECORD,,