Skip to content

Commit 2789851

Browse files
committed
Sync README quick-start recipes
1 parent 0f09aee commit 2789851

7 files changed

Lines changed: 271 additions & 27 deletions

File tree

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,21 @@ for the generated summary of runner scripts, tox environments, CI jobs, expected
260260

261261
## 🍳 Common Recipes
262262

263+
<!-- BEGIN AUTO-GENERATED CLI RECIPE QUICK STARTS -->
264+
### CLI option quick starts
265+
266+
Use these starting points when combining options; each option links to the generated CLI reference for details and examples.
267+
268+
- **Generate a local schema file:** Pin the input type and destination when the source extension is ambiguous or generated output needs a stable path. Options: [`--input`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/base-options/#input), [`--input-file-type`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/base-options/#input-file-type), [`--output`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/base-options/#output).
269+
- **Target Pydantic v2 on modern Python:** Set the output model family and Python/Pydantic compatibility targets together. Options: [`--output-model-type`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/model-customization/#output-model-type), [`--target-python-version`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/model-customization/#target-python-version), [`--target-pydantic-version`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/model-customization/#target-pydantic-version).
270+
- **Use modern Python annotations:** Target a recent Python version and prefer built-in collection and union syntax in generated types. Options: [`--target-python-version`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/model-customization/#target-python-version), [`--use-union-operator`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/typing-customization/#use-union-operator), [`--use-standard-collections`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/typing-customization/#use-standard-collections).
271+
- **Normalize incoming field names:** Convert source names to Python identifiers while preserving explicit alias data for runtime IO. Options: [`--snake-case-field`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/field-customization/#snake-case-field), [`--original-field-name-delimiter`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/field-customization/#original-field-name-delimiter), [`--aliases`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/field-customization/#aliases).
272+
- **Generate operation-focused models:** Limit OpenAPI output to operation shapes and name models from operation IDs and status codes. Options: [`--openapi-scopes`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/openapi-only-options/#openapi-scopes), [`--use-operation-id-as-name`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/openapi-only-options/#use-operation-id-as-name), [`--use-status-code-in-response-name`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/openapi-only-options/#use-status-code-in-response-name).
273+
- **Resolve remote references deliberately:** Enable remote `$ref` loading and configure request metadata, timeouts, or local ref roots. Options: [`--allow-remote-refs`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/general-options/#allow-remote-refs), [`--http-headers`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/general-options/#http-headers), [`--http-timeout`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/general-options/#http-timeout), [`--http-local-ref-path`](https://datamodel-code-generator.koxudaxi.dev/cli-reference/general-options/#http-local-ref-path).
274+
275+
See the [CLI Reference](https://datamodel-code-generator.koxudaxi.dev/cli-reference/) for the full option list and category-specific recipes.
276+
<!-- END AUTO-GENERATED CLI RECIPE QUICK STARTS -->
277+
263278
### 🤖 Get CLI Help from LLMs
264279

265280
Generate a prompt to ask LLMs about CLI options:

docs/index.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,21 @@ See [Supported Data Types](supported-data-types.md) for the full list.
253253

254254
## 🍳 Common Recipes
255255

256+
<!-- BEGIN AUTO-GENERATED CLI RECIPE QUICK STARTS -->
257+
### CLI option quick starts
258+
259+
Use these starting points when combining options; each option links to the generated CLI reference for details and examples.
260+
261+
- **Generate a local schema file:** Pin the input type and destination when the source extension is ambiguous or generated output needs a stable path. Options: [`--input`](cli-reference/base-options.md#input), [`--input-file-type`](cli-reference/base-options.md#input-file-type), [`--output`](cli-reference/base-options.md#output).
262+
- **Target Pydantic v2 on modern Python:** Set the output model family and Python/Pydantic compatibility targets together. Options: [`--output-model-type`](cli-reference/model-customization.md#output-model-type), [`--target-python-version`](cli-reference/model-customization.md#target-python-version), [`--target-pydantic-version`](cli-reference/model-customization.md#target-pydantic-version).
263+
- **Use modern Python annotations:** Target a recent Python version and prefer built-in collection and union syntax in generated types. Options: [`--target-python-version`](cli-reference/model-customization.md#target-python-version), [`--use-union-operator`](cli-reference/typing-customization.md#use-union-operator), [`--use-standard-collections`](cli-reference/typing-customization.md#use-standard-collections).
264+
- **Normalize incoming field names:** Convert source names to Python identifiers while preserving explicit alias data for runtime IO. Options: [`--snake-case-field`](cli-reference/field-customization.md#snake-case-field), [`--original-field-name-delimiter`](cli-reference/field-customization.md#original-field-name-delimiter), [`--aliases`](cli-reference/field-customization.md#aliases).
265+
- **Generate operation-focused models:** Limit OpenAPI output to operation shapes and name models from operation IDs and status codes. Options: [`--openapi-scopes`](cli-reference/openapi-only-options.md#openapi-scopes), [`--use-operation-id-as-name`](cli-reference/openapi-only-options.md#use-operation-id-as-name), [`--use-status-code-in-response-name`](cli-reference/openapi-only-options.md#use-status-code-in-response-name).
266+
- **Resolve remote references deliberately:** Enable remote `$ref` loading and configure request metadata, timeouts, or local ref roots. Options: [`--allow-remote-refs`](cli-reference/general-options.md#allow-remote-refs), [`--http-headers`](cli-reference/general-options.md#http-headers), [`--http-timeout`](cli-reference/general-options.md#http-timeout), [`--http-local-ref-path`](cli-reference/general-options.md#http-local-ref-path).
267+
268+
See the [CLI Reference](cli-reference/index.md) for the full option list and category-specific recipes.
269+
<!-- END AUTO-GENERATED CLI RECIPE QUICK STARTS -->
270+
256271
### 🤖 Get CLI Help from LLMs
257272

258273
Generate a prompt to ask LLMs about CLI options:

docs/llms-full.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,21 @@ See [Supported Data Types](supported-data-types.md) for the full list.
255255

256256
## 🍳 Common Recipes
257257

258+
<!-- BEGIN AUTO-GENERATED CLI RECIPE QUICK STARTS -->
259+
### CLI option quick starts
260+
261+
Use these starting points when combining options; each option links to the generated CLI reference for details and examples.
262+
263+
- **Generate a local schema file:** Pin the input type and destination when the source extension is ambiguous or generated output needs a stable path. Options: [`--input`](cli-reference/base-options.md#input), [`--input-file-type`](cli-reference/base-options.md#input-file-type), [`--output`](cli-reference/base-options.md#output).
264+
- **Target Pydantic v2 on modern Python:** Set the output model family and Python/Pydantic compatibility targets together. Options: [`--output-model-type`](cli-reference/model-customization.md#output-model-type), [`--target-python-version`](cli-reference/model-customization.md#target-python-version), [`--target-pydantic-version`](cli-reference/model-customization.md#target-pydantic-version).
265+
- **Use modern Python annotations:** Target a recent Python version and prefer built-in collection and union syntax in generated types. Options: [`--target-python-version`](cli-reference/model-customization.md#target-python-version), [`--use-union-operator`](cli-reference/typing-customization.md#use-union-operator), [`--use-standard-collections`](cli-reference/typing-customization.md#use-standard-collections).
266+
- **Normalize incoming field names:** Convert source names to Python identifiers while preserving explicit alias data for runtime IO. Options: [`--snake-case-field`](cli-reference/field-customization.md#snake-case-field), [`--original-field-name-delimiter`](cli-reference/field-customization.md#original-field-name-delimiter), [`--aliases`](cli-reference/field-customization.md#aliases).
267+
- **Generate operation-focused models:** Limit OpenAPI output to operation shapes and name models from operation IDs and status codes. Options: [`--openapi-scopes`](cli-reference/openapi-only-options.md#openapi-scopes), [`--use-operation-id-as-name`](cli-reference/openapi-only-options.md#use-operation-id-as-name), [`--use-status-code-in-response-name`](cli-reference/openapi-only-options.md#use-status-code-in-response-name).
268+
- **Resolve remote references deliberately:** Enable remote `$ref` loading and configure request metadata, timeouts, or local ref roots. Options: [`--allow-remote-refs`](cli-reference/general-options.md#allow-remote-refs), [`--http-headers`](cli-reference/general-options.md#http-headers), [`--http-timeout`](cli-reference/general-options.md#http-timeout), [`--http-local-ref-path`](cli-reference/general-options.md#http-local-ref-path).
269+
270+
See the [CLI Reference](cli-reference/index.md) for the full option list and category-specific recipes.
271+
<!-- END AUTO-GENERATED CLI RECIPE QUICK STARTS -->
272+
258273
### 🤖 Get CLI Help from LLMs
259274

260275
Generate a prompt to ask LLMs about CLI options:

scripts/build_cli_docs.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,15 @@ class CategoryRecipe:
289289
),
290290
}
291291

292+
HOMEPAGE_RECIPE_CATEGORIES: tuple[OptionCategory, ...] = (
293+
OptionCategory.BASE,
294+
OptionCategory.MODEL,
295+
OptionCategory.TYPING,
296+
OptionCategory.FIELD,
297+
OptionCategory.OPENAPI,
298+
OptionCategory.GENERAL,
299+
)
300+
292301
# Manual option descriptions for utility options
293302
MANUAL_OPTION_DESCRIPTIONS = {
294303
"--help": "Show help message and exit",
@@ -862,6 +871,8 @@ def _format_option_link(
862871
documented_options: frozenset[str],
863872
*,
864873
current_category: OptionCategory | None = None,
874+
root: str = "",
875+
extension: str = ".md",
865876
) -> str:
866877
"""Return a Markdown link to a generated option section when metadata is available."""
867878
documented_option = _documented_related_option(option, documented_options)
@@ -870,13 +881,54 @@ def _format_option_link(
870881

871882
if current_category == meta.category:
872883
target = f"#{get_cli_doc_slug(get_cli_option_doc_name(documented_option))}"
873-
elif doc_path := get_cli_option_doc_path(documented_option):
884+
elif doc_path := get_cli_option_doc_path(documented_option, root=root, extension=extension):
874885
target = doc_path
875886
else:
876887
return f"`{documented_option}`"
877888
return f"[`{documented_option}`]({target})"
878889

879890

891+
def _recipe_option_names(recipes: tuple[CategoryRecipe, ...]) -> frozenset[str]:
892+
"""Return recipe option names for preserving generated documentation aliases."""
893+
return frozenset(option for recipe in recipes for option in recipe.options)
894+
895+
896+
def _homepage_recipes() -> tuple[CategoryRecipe, ...]:
897+
"""Return a bounded recipe set for README and docs-home quick-start sections."""
898+
return tuple(recipes[0] for category in HOMEPAGE_RECIPE_CATEGORIES if (recipes := CATEGORY_RECIPES.get(category)))
899+
900+
901+
def generate_homepage_recipe_quick_starts(
902+
*,
903+
cli_reference_root: str,
904+
cli_reference_extension: str,
905+
cli_reference_index: str,
906+
) -> str:
907+
"""Generate concise CLI recipe quick-starts for README and docs home."""
908+
if not (recipes := _homepage_recipes()):
909+
return ""
910+
911+
documented_options = _recipe_option_names(recipes)
912+
md = "### CLI option quick starts\n\n"
913+
md += (
914+
"Use these starting points when combining options; each option links to the generated CLI reference for "
915+
"details and examples.\n\n"
916+
)
917+
for recipe in recipes:
918+
option_links = ", ".join(
919+
_format_option_link(
920+
option,
921+
documented_options,
922+
root=cli_reference_root,
923+
extension=cli_reference_extension,
924+
)
925+
for option in recipe.options
926+
)
927+
md += f"- **{recipe.title}:** {recipe.description} Options: {option_links}.\n"
928+
md += f"\nSee the [CLI Reference]({cli_reference_index}) for the full option list and category-specific recipes.\n"
929+
return md
930+
931+
880932
def generate_category_recipes(
881933
category: OptionCategory,
882934
documented_options: frozenset[str],

scripts/update_command_help_on_markdown.py

Lines changed: 111 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Update command help text in markdown documentation files."""
1+
"""Update generated sections in markdown documentation files."""
22

33
from __future__ import annotations
44

@@ -7,21 +7,33 @@
77
import os
88
import re
99
import sys
10+
from dataclasses import dataclass
1011
from pathlib import Path
1112

12-
from datamodel_code_generator.__main__ import Exit, arg_parser
13-
14-
os.environ["COLUMNS"] = "94"
15-
os.environ["LINES"] = "24"
16-
1713
START_MARK: str = "<!-- start command help -->"
1814
END_MARK: str = "<!-- end command help -->"
15+
RECIPE_START_MARK: str = "<!-- BEGIN AUTO-GENERATED CLI RECIPE QUICK STARTS -->"
16+
RECIPE_END_MARK: str = "<!-- END AUTO-GENERATED CLI RECIPE QUICK STARTS -->"
1917
BASH_CODE_BLOCK: str = "```bash"
2018
CODE_BLOCK_END: str = "```"
2119

2220
CURRENT_DIR = Path(__file__).parent
2321
PROJECT_DIR = CURRENT_DIR.parent
2422
DOC_DIR = PROJECT_DIR / "docs"
23+
SRC_DIR = PROJECT_DIR / "src"
24+
README_FILE = PROJECT_DIR / "README.md"
25+
DOCS_INDEX_FILE = DOC_DIR / "index.md"
26+
README_CLI_REFERENCE_ROOT = "https://datamodel-code-generator.koxudaxi.dev/cli-reference"
27+
README_CLI_REFERENCE_INDEX = "https://datamodel-code-generator.koxudaxi.dev/cli-reference/"
28+
DOCS_CLI_REFERENCE_ROOT = "cli-reference"
29+
DOCS_CLI_REFERENCE_INDEX = "cli-reference/index.md"
30+
31+
for import_path in (PROJECT_DIR, SRC_DIR):
32+
if str(import_path) not in sys.path:
33+
sys.path.insert(0, str(import_path))
34+
35+
from datamodel_code_generator.arguments import arg_parser # noqa: E402
36+
from scripts.build_cli_docs import generate_homepage_recipe_quick_starts # noqa: E402
2537

2638
# CLI help is now auto-generated in docs/cli-reference/ by build_cli_docs.py
2739
# These files no longer contain command help markers
@@ -30,8 +42,36 @@
3042
REPLACE_MAP = {"(default: UTF-8)": "(default: utf-8)", "'": r"''"}
3143

3244

45+
@dataclass(frozen=True, slots=True)
46+
class RecipeMarkdownTarget:
47+
"""Markdown file and link style for generated CLI recipe quick-starts."""
48+
49+
path: Path
50+
cli_reference_root: str
51+
cli_reference_extension: str
52+
cli_reference_index: str
53+
54+
55+
RECIPE_MARKDOWN_TARGETS: tuple[RecipeMarkdownTarget, ...] = (
56+
RecipeMarkdownTarget(
57+
path=README_FILE,
58+
cli_reference_root=README_CLI_REFERENCE_ROOT,
59+
cli_reference_extension="/",
60+
cli_reference_index=README_CLI_REFERENCE_INDEX,
61+
),
62+
RecipeMarkdownTarget(
63+
path=DOCS_INDEX_FILE,
64+
cli_reference_root=DOCS_CLI_REFERENCE_ROOT,
65+
cli_reference_extension=".md",
66+
cli_reference_index=DOCS_CLI_REFERENCE_INDEX,
67+
),
68+
)
69+
70+
3371
def get_help() -> str:
3472
"""Get formatted help text from argument parser."""
73+
os.environ["COLUMNS"] = "94"
74+
os.environ["LINES"] = "24"
3575
with io.StringIO() as f:
3676
arg_parser.print_help(file=f)
3777
output = f.getvalue()
@@ -41,29 +81,52 @@ def get_help() -> str:
4181
return re.sub(r"\x1b\[[0-?]*[ -/]*[@-~]", "", output)
4282

4383

84+
def replace_marked_section(markdown_text: str, start_mark: str, end_mark: str, replacement: str) -> str:
85+
"""Replace generated markdown content between ordered markers."""
86+
start_pos = markdown_text.find(start_mark)
87+
if start_pos == -1:
88+
msg = f"Could not find {start_mark} in markdown_text"
89+
raise ValueError(msg)
90+
end_pos = markdown_text.find(end_mark, start_pos + len(start_mark))
91+
if end_pos == -1:
92+
msg = f"Could not find {end_mark} after {start_mark} in markdown_text"
93+
raise ValueError(msg)
94+
return markdown_text[: start_pos + len(start_mark)] + "\n" + replacement.rstrip() + "\n" + markdown_text[end_pos:]
95+
96+
4497
def inject_help(markdown_text: str, help_text: str) -> str:
4598
"""Inject help text into markdown between start and end markers."""
46-
start_pos = markdown_text.find(START_MARK)
47-
end_pos = markdown_text.find(END_MARK)
48-
if start_pos == -1 or end_pos == -1:
49-
msg = f"Could not find {START_MARK} or {END_MARK} in markdown_text"
50-
raise ValueError(msg)
51-
return (
52-
markdown_text[: start_pos + len(START_MARK)]
53-
+ "\n"
54-
+ BASH_CODE_BLOCK
55-
+ "\n"
56-
+ help_text
57-
+ CODE_BLOCK_END
58-
+ "\n"
59-
+ markdown_text[end_pos:]
99+
return replace_marked_section(
100+
markdown_text,
101+
START_MARK,
102+
END_MARK,
103+
f"{BASH_CODE_BLOCK}\n{help_text}{CODE_BLOCK_END}",
104+
)
105+
106+
107+
def inject_recipe_quick_starts(
108+
markdown_text: str,
109+
*,
110+
cli_reference_root: str,
111+
cli_reference_extension: str,
112+
cli_reference_index: str,
113+
) -> str:
114+
"""Inject generated CLI recipe quick-starts into markdown."""
115+
return replace_marked_section(
116+
markdown_text,
117+
RECIPE_START_MARK,
118+
RECIPE_END_MARK,
119+
generate_homepage_recipe_quick_starts(
120+
cli_reference_root=cli_reference_root,
121+
cli_reference_extension=cli_reference_extension,
122+
cli_reference_index=cli_reference_index,
123+
),
60124
)
61125

62126

63-
def main() -> Exit:
64-
"""Update or validate command help in target markdown files."""
65-
help_text = get_help()
66-
script_parser = argparse.ArgumentParser(description="Update command help in markdown files")
127+
def main() -> int:
128+
"""Update or validate generated sections in target markdown files."""
129+
script_parser = argparse.ArgumentParser(description="Update generated sections in markdown files")
67130
script_parser.add_argument(
68131
"--check",
69132
action="store_true",
@@ -72,16 +135,38 @@ def main() -> Exit:
72135
args = script_parser.parse_args()
73136
check: bool = args.check
74137

138+
out_of_date: list[Path] = []
139+
help_text = get_help() if TARGET_MARKDOWN_FILES else ""
75140
for file_path in TARGET_MARKDOWN_FILES:
76141
with file_path.open("r") as f:
77142
markdown_text = f.read()
78143
new_markdown_text = inject_help(markdown_text, help_text)
79144
if new_markdown_text != markdown_text:
80145
if check:
81-
return Exit.ERROR
146+
out_of_date.append(file_path)
147+
continue
82148
with file_path.open("w") as f:
83149
f.write(new_markdown_text)
84-
return Exit.OK
150+
151+
for target in RECIPE_MARKDOWN_TARGETS:
152+
markdown_text = target.path.read_text(encoding="utf-8")
153+
new_markdown_text = inject_recipe_quick_starts(
154+
markdown_text,
155+
cli_reference_root=target.cli_reference_root,
156+
cli_reference_extension=target.cli_reference_extension,
157+
cli_reference_index=target.cli_reference_index,
158+
)
159+
if new_markdown_text != markdown_text:
160+
if check:
161+
out_of_date.append(target.path)
162+
continue
163+
target.path.write_text(new_markdown_text, encoding="utf-8")
164+
165+
if out_of_date:
166+
for path in out_of_date:
167+
print(f"Markdown generated sections are out of date: {path.relative_to(PROJECT_DIR)}", file=sys.stderr)
168+
return 1
169+
return 0
85170

86171

87172
if __name__ == "__main__":

0 commit comments

Comments
 (0)