create-awesome-python-app 0.2.2__py3-none-any.whl → 0.2.3__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.
- create_awesome_python_app/__init__.py +1 -1
- create_awesome_python_app/catalog.py +11 -7
- create_awesome_python_app/cli.py +27 -11
- create_awesome_python_app/prompt_style.py +61 -0
- {create_awesome_python_app-0.2.2.dist-info → create_awesome_python_app-0.2.3.dist-info}/METADATA +2 -2
- create_awesome_python_app-0.2.3.dist-info/RECORD +9 -0
- create_awesome_python_app-0.2.2.dist-info/RECORD +0 -8
- {create_awesome_python_app-0.2.2.dist-info → create_awesome_python_app-0.2.3.dist-info}/WHEEL +0 -0
- {create_awesome_python_app-0.2.2.dist-info → create_awesome_python_app-0.2.3.dist-info}/entry_points.txt +0 -0
|
@@ -16,6 +16,7 @@ from rich.console import Console
|
|
|
16
16
|
from rich.table import Table
|
|
17
17
|
|
|
18
18
|
from create_awesome_python_app import __version__
|
|
19
|
+
from create_awesome_python_app.prompt_style import bold, color_category, dim
|
|
19
20
|
|
|
20
21
|
console = Console(stderr=True)
|
|
21
22
|
|
|
@@ -238,14 +239,17 @@ def build_template_choices(data: dict[str, Any]) -> list[TemplateChoice]:
|
|
|
238
239
|
labels = template.get("labels", [])
|
|
239
240
|
label_suffix = ""
|
|
240
241
|
if isinstance(labels, list) and labels:
|
|
241
|
-
label_suffix = " · " + ", ".join(str(label) for label in labels[:3])
|
|
242
|
+
label_suffix = dim(" · " + ", ".join(str(label) for label in labels[:3]))
|
|
242
243
|
description = str(template.get("description", "")).strip()
|
|
243
|
-
|
|
244
|
-
#
|
|
245
|
-
|
|
244
|
+
# Keep slug + short description in the title so select(use_search_filter)
|
|
245
|
+
# can match them (filter scans Choice.title only).
|
|
246
|
+
description_suffix = dim(f" — {description}") if description else ""
|
|
247
|
+
name = str(template.get("name", slug))
|
|
248
|
+
# ANSI is OK here: questionary.select renders titles as terminal text.
|
|
249
|
+
# Do not pass these titles to autocomplete (HTML match highlighting).
|
|
246
250
|
title = (
|
|
247
|
-
f"{badge} "
|
|
248
|
-
f"{
|
|
251
|
+
f"{color_category(category_slug, badge)} "
|
|
252
|
+
f"{bold(name)} ({slug})"
|
|
249
253
|
f"{label_suffix}{description_suffix}"
|
|
250
254
|
)
|
|
251
255
|
choices.append(
|
|
@@ -258,7 +262,7 @@ def build_template_choices(data: dict[str, Any]) -> list[TemplateChoice]:
|
|
|
258
262
|
|
|
259
263
|
choices.append(
|
|
260
264
|
TemplateChoice(
|
|
261
|
-
title=" " * 12 + "Use my own template URL",
|
|
265
|
+
title=" " * 12 + dim("Use my own template URL"),
|
|
262
266
|
value=CUSTOM_TEMPLATE_SENTINEL,
|
|
263
267
|
search="custom own template url github file",
|
|
264
268
|
)
|
create_awesome_python_app/cli.py
CHANGED
|
@@ -104,6 +104,8 @@ def _prompt_custom_options(
|
|
|
104
104
|
) -> dict[str, str]:
|
|
105
105
|
import questionary
|
|
106
106
|
|
|
107
|
+
from create_awesome_python_app.prompt_style import CPA_PROMPT_STYLE
|
|
108
|
+
|
|
107
109
|
source = resolve_source(template, cache_dir=cache_dir)
|
|
108
110
|
root = download_repository(
|
|
109
111
|
source,
|
|
@@ -138,9 +140,12 @@ def _prompt_custom_options(
|
|
|
138
140
|
answer = questionary.confirm(
|
|
139
141
|
message,
|
|
140
142
|
default=initial.lower() in {"1", "true", "yes", "on"},
|
|
143
|
+
style=CPA_PROMPT_STYLE,
|
|
141
144
|
).ask()
|
|
142
145
|
else:
|
|
143
|
-
answer = questionary.text(
|
|
146
|
+
answer = questionary.text(
|
|
147
|
+
message, default=initial, style=CPA_PROMPT_STYLE
|
|
148
|
+
).ask()
|
|
144
149
|
if answer is None:
|
|
145
150
|
raise typer.Exit(1)
|
|
146
151
|
answers[option.key] = _stringify_option_value(answer)
|
|
@@ -230,30 +235,38 @@ def scaffold(
|
|
|
230
235
|
if want_interactive and not template:
|
|
231
236
|
try:
|
|
232
237
|
import questionary
|
|
238
|
+
from questionary import Choice
|
|
233
239
|
|
|
234
240
|
from create_awesome_python_app.catalog import (
|
|
235
241
|
CUSTOM_TEMPLATE_SENTINEL,
|
|
236
242
|
build_template_choices,
|
|
237
243
|
get_catalog_data,
|
|
238
244
|
)
|
|
245
|
+
from create_awesome_python_app.prompt_style import CPA_PROMPT_STYLE
|
|
239
246
|
|
|
240
247
|
interactive_catalog = get_catalog_data()
|
|
241
248
|
template_choices = build_template_choices(interactive_catalog)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
+
# select + type-to-filter: browseable list (CNA-style discovery)
|
|
250
|
+
# instead of autocomplete-only. use_jk_keys must be False with search.
|
|
251
|
+
selected_template = questionary.select(
|
|
252
|
+
"Pick a template",
|
|
253
|
+
choices=[
|
|
254
|
+
Choice(title=choice.title, value=choice.value)
|
|
255
|
+
for choice in template_choices
|
|
256
|
+
],
|
|
249
257
|
qmark="?",
|
|
258
|
+
pointer="❯",
|
|
259
|
+
style=CPA_PROMPT_STYLE,
|
|
260
|
+
use_search_filter=True,
|
|
261
|
+
use_jk_keys=False,
|
|
262
|
+
instruction="(↑↓ browse · type to filter · Enter)",
|
|
250
263
|
).ask()
|
|
251
|
-
selected_template = choice_by_title.get(str(selected_title), selected_title)
|
|
252
264
|
if selected_template == CUSTOM_TEMPLATE_SENTINEL:
|
|
253
265
|
selected_template = questionary.text(
|
|
254
266
|
"Template URL",
|
|
255
267
|
default="file://.",
|
|
256
268
|
validate=lambda value: bool(value) or "Template URL is required",
|
|
269
|
+
style=CPA_PROMPT_STYLE,
|
|
257
270
|
).ask()
|
|
258
271
|
template = selected_template
|
|
259
272
|
if not template:
|
|
@@ -296,6 +309,7 @@ def scaffold(
|
|
|
296
309
|
get_catalog_data,
|
|
297
310
|
group_extension_choices,
|
|
298
311
|
)
|
|
312
|
+
from create_awesome_python_app.prompt_style import CPA_PROMPT_STYLE
|
|
299
313
|
|
|
300
314
|
interactive_catalog = interactive_catalog or get_catalog_data()
|
|
301
315
|
extension_choices = build_extension_choices(interactive_catalog, template)
|
|
@@ -316,7 +330,8 @@ def scaffold(
|
|
|
316
330
|
"Which kinds of extensions do you need?",
|
|
317
331
|
choices=category_choices,
|
|
318
332
|
qmark="?",
|
|
319
|
-
pointer="
|
|
333
|
+
pointer="❯",
|
|
334
|
+
style=CPA_PROMPT_STYLE,
|
|
320
335
|
).ask()
|
|
321
336
|
selected_addons: list[str] = []
|
|
322
337
|
for category_slug in selected_categories or []:
|
|
@@ -330,7 +345,8 @@ def scaffold(
|
|
|
330
345
|
for choice in choices
|
|
331
346
|
],
|
|
332
347
|
qmark="?",
|
|
333
|
-
pointer="
|
|
348
|
+
pointer="❯",
|
|
349
|
+
style=CPA_PROMPT_STYLE,
|
|
334
350
|
).ask()
|
|
335
351
|
selected_addons.extend(str(item) for item in picked or [])
|
|
336
352
|
addons = selected_addons
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""High-contrast questionary styles for CPA interactive prompts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from questionary import Style
|
|
8
|
+
|
|
9
|
+
# Lighter brand blues/greens than docs hex so selected rows stay readable on
|
|
10
|
+
# dark terminals (slate backgrounds common in Arch/Ghostty/Alacritty).
|
|
11
|
+
CPA_PROMPT_STYLE = Style.from_dict(
|
|
12
|
+
{
|
|
13
|
+
"qmark": "fg:#60a5fa bold",
|
|
14
|
+
"question": "bold fg:#f8fafc",
|
|
15
|
+
"answer": "fg:#4ade80 bold",
|
|
16
|
+
"pointer": "fg:#60a5fa bold",
|
|
17
|
+
"highlighted": "fg:#0f172a bg:#60a5fa bold",
|
|
18
|
+
"selected": "fg:#4ade80 bold",
|
|
19
|
+
"separator": "fg:#94a3b8",
|
|
20
|
+
"instruction": "fg:#94a3b8",
|
|
21
|
+
"text": "fg:#e2e8f0",
|
|
22
|
+
"disabled": "fg:#64748b italic",
|
|
23
|
+
"checkbox": "fg:#60a5fa",
|
|
24
|
+
"checkbox-selected": "fg:#4ade80 bold",
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def colors_enabled() -> bool:
|
|
30
|
+
return not os.environ.get("NO_COLOR")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def ansi(code: str, text: str) -> str:
|
|
34
|
+
"""Wrap *text* in an ANSI SGR sequence when colors are enabled."""
|
|
35
|
+
if not colors_enabled():
|
|
36
|
+
return text
|
|
37
|
+
return f"\033[{code}m{text}\033[0m"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# Bold bright ANSI — readable on dark terminals; select() renders these safely
|
|
41
|
+
# (unlike autocomplete, which HTML-parses choice text).
|
|
42
|
+
_CATEGORY_PALETTE = (
|
|
43
|
+
"1;93", # bright yellow
|
|
44
|
+
"1;92", # bright green
|
|
45
|
+
"1;96", # bright cyan
|
|
46
|
+
"1;95", # bright magenta
|
|
47
|
+
"1;94", # bright blue
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def color_category(slug: str, label: str) -> str:
|
|
52
|
+
idx = sum(ord(char) for char in slug) % len(_CATEGORY_PALETTE)
|
|
53
|
+
return ansi(_CATEGORY_PALETTE[idx], label)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def bold(text: str) -> str:
|
|
57
|
+
return ansi("1", text)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def dim(text: str) -> str:
|
|
61
|
+
return ansi("2", text)
|
{create_awesome_python_app-0.2.2.dist-info → create_awesome_python_app-0.2.3.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: create-awesome-python-app
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
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.
|
|
11
|
+
Requires-Dist: create-python-app-core>=0.2.3
|
|
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=DPsQbeW1110h7DEbWLxV7pLEEDAUnc5WkLiBamNsjSU,60
|
|
2
|
+
create_awesome_python_app/cache.py,sha256=eHKUlunGexZKYJo0HDNoBoOVq0DjLyRYgEe_wUh4Fk0,11812
|
|
3
|
+
create_awesome_python_app/catalog.py,sha256=_x6TqYAVlURM1dbNsflB9I4g8ku_anZzuK_ggN_OvKs,16909
|
|
4
|
+
create_awesome_python_app/cli.py,sha256=6og82WI-RZxTqHETqrieA8relgppwCqFntOEmOFrIPk,21195
|
|
5
|
+
create_awesome_python_app/prompt_style.py,sha256=A1RQn2hX7khu21bNL5KfD1ZNAHUJfCzmxXIRMgin658,1670
|
|
6
|
+
create_awesome_python_app-0.2.3.dist-info/METADATA,sha256=Kvw2BT6Ff3YF3ZkH8DVJd5uSFyepcGGlMBqX6fgJAp4,1428
|
|
7
|
+
create_awesome_python_app-0.2.3.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
8
|
+
create_awesome_python_app-0.2.3.dist-info/entry_points.txt,sha256=rszFbUjY-lvMDZ96zX1lALJwgD1mI3CkUuNyF2qqjYo,81
|
|
9
|
+
create_awesome_python_app-0.2.3.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
create_awesome_python_app/__init__.py,sha256=zyHa8jk_E_HCeu1vlupYAWdBZUI34ETHbMgMgjJEcPE,60
|
|
2
|
-
create_awesome_python_app/cache.py,sha256=eHKUlunGexZKYJo0HDNoBoOVq0DjLyRYgEe_wUh4Fk0,11812
|
|
3
|
-
create_awesome_python_app/catalog.py,sha256=ljpyTFhaUo7t43CbQ8y86D_GfLOo7hE7yQwNojRUTG0,16612
|
|
4
|
-
create_awesome_python_app/cli.py,sha256=aNDUiIgRiks6nV72wrAbLit4yxD6VpCCv8Msp9QDXa4,20453
|
|
5
|
-
create_awesome_python_app-0.2.2.dist-info/METADATA,sha256=rlAPeMlrpm37YAgoHeFZd0UPnE9L-4uU8v01VPG1hpM,1428
|
|
6
|
-
create_awesome_python_app-0.2.2.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
7
|
-
create_awesome_python_app-0.2.2.dist-info/entry_points.txt,sha256=rszFbUjY-lvMDZ96zX1lALJwgD1mI3CkUuNyF2qqjYo,81
|
|
8
|
-
create_awesome_python_app-0.2.2.dist-info/RECORD,,
|
{create_awesome_python_app-0.2.2.dist-info → create_awesome_python_app-0.2.3.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|