python-template-project 0.1.0__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.
- python_template_project/__init__.py +0 -0
- python_template_project/__main__.py +8 -0
- python_template_project/cli/__init__.py +0 -0
- python_template_project/cli/__main__.py +8 -0
- python_template_project/cli/cli.py +217 -0
- python_template_project/config/__init__.py +0 -0
- python_template_project/config/config.py +557 -0
- python_template_project/core/__init__.py +0 -0
- python_template_project/core/base.py +397 -0
- python_template_project/core/logging.py +219 -0
- python_template_project/gui/__init__.py +0 -0
- python_template_project/gui/__main__.py +8 -0
- python_template_project/gui/gui.py +615 -0
- python_template_project-0.1.0.dist-info/METADATA +92 -0
- python_template_project-0.1.0.dist-info/RECORD +18 -0
- python_template_project-0.1.0.dist-info/WHEEL +4 -0
- python_template_project-0.1.0.dist-info/entry_points.txt +3 -0
- python_template_project-0.1.0.dist-info/licenses/LICENSE +24 -0
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
"""Central configuration management for python_template_project project.
|
|
2
|
+
|
|
3
|
+
This module provides a single source of truth for all configuration parameters
|
|
4
|
+
organized in categories (CLI, App, GUI). It can generate config files, CLI modules,
|
|
5
|
+
and documentation from the parameter definitions.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from textwrap import dedent
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
import yaml # type: ignore
|
|
15
|
+
from pydantic import BaseModel # type: ignore
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class ConfigParameter:
|
|
20
|
+
"""Represents a single configuration parameter with all its metadata."""
|
|
21
|
+
|
|
22
|
+
name: str
|
|
23
|
+
default: Any
|
|
24
|
+
type_: type
|
|
25
|
+
choices: list[str | bool | int] | None = None
|
|
26
|
+
help: str = ""
|
|
27
|
+
cli_arg: str | None = None
|
|
28
|
+
required: bool = False
|
|
29
|
+
|
|
30
|
+
def __post_init__(self):
|
|
31
|
+
if self.cli_arg is None and not self.required:
|
|
32
|
+
self.cli_arg = f"--{self.name}"
|
|
33
|
+
if self.type_ is bool:
|
|
34
|
+
self.choices = [True, False]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class CliConfig(BaseModel):
|
|
38
|
+
"""CLI-specific configuration parameters."""
|
|
39
|
+
|
|
40
|
+
# Positional argument
|
|
41
|
+
input: ConfigParameter = ConfigParameter(
|
|
42
|
+
name="input",
|
|
43
|
+
default="",
|
|
44
|
+
type_=str,
|
|
45
|
+
help="Path to input (file or folder)",
|
|
46
|
+
required=True,
|
|
47
|
+
cli_arg=None, # Positional argument
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Optional CLI arguments
|
|
51
|
+
output: ConfigParameter = ConfigParameter(
|
|
52
|
+
name="output",
|
|
53
|
+
default="",
|
|
54
|
+
type_=str,
|
|
55
|
+
help="Path to output destination",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
min_dist: ConfigParameter = ConfigParameter(
|
|
59
|
+
name="min_dist",
|
|
60
|
+
default=20,
|
|
61
|
+
type_=int,
|
|
62
|
+
help="Maximum distance between two waypoints",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
extract_waypoints: ConfigParameter = ConfigParameter(
|
|
66
|
+
name="extract_waypoints",
|
|
67
|
+
default=True,
|
|
68
|
+
type_=bool,
|
|
69
|
+
help="Extract starting points of each track as waypoint",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
elevation: ConfigParameter = ConfigParameter(
|
|
73
|
+
name="elevation",
|
|
74
|
+
default=True,
|
|
75
|
+
type_=bool,
|
|
76
|
+
help="Include elevation data in waypoints",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class AppConfig(BaseModel):
|
|
81
|
+
"""Application-specific configuration parameters."""
|
|
82
|
+
|
|
83
|
+
date_format: ConfigParameter = ConfigParameter(
|
|
84
|
+
name="date_format",
|
|
85
|
+
default="%Y-%m-%d",
|
|
86
|
+
type_=str,
|
|
87
|
+
help="Date format to use",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
log_level: ConfigParameter = ConfigParameter(
|
|
91
|
+
name="log_level",
|
|
92
|
+
default="INFO",
|
|
93
|
+
type_=str,
|
|
94
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
|
95
|
+
help="Logging level for the application",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
log_file_max_size: ConfigParameter = ConfigParameter(
|
|
99
|
+
name="log_file_max_size",
|
|
100
|
+
default=10,
|
|
101
|
+
type_=int,
|
|
102
|
+
help="Maximum log file size in MB before rotation",
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
log_backup_count: ConfigParameter = ConfigParameter(
|
|
106
|
+
name="log_backup_count",
|
|
107
|
+
default=5,
|
|
108
|
+
type_=int,
|
|
109
|
+
help="Number of backup log files to keep",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
log_format: ConfigParameter = ConfigParameter(
|
|
113
|
+
name="log_format",
|
|
114
|
+
default="detailed",
|
|
115
|
+
type_=str,
|
|
116
|
+
choices=["simple", "detailed", "json"],
|
|
117
|
+
help="Log message format style",
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
max_workers: ConfigParameter = ConfigParameter(
|
|
121
|
+
name="max_workers",
|
|
122
|
+
default=4,
|
|
123
|
+
type_=int,
|
|
124
|
+
help="Maximum number of worker threads",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
enable_file_logging: ConfigParameter = ConfigParameter(
|
|
128
|
+
name="enable_file_logging",
|
|
129
|
+
default=True,
|
|
130
|
+
type_=bool,
|
|
131
|
+
help="Enable logging to file",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
enable_console_logging: ConfigParameter = ConfigParameter(
|
|
135
|
+
name="enable_console_logging",
|
|
136
|
+
default=True,
|
|
137
|
+
type_=bool,
|
|
138
|
+
help="Enable logging to console",
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class GuiConfig(BaseModel):
|
|
143
|
+
"""GUI-specific configuration parameters."""
|
|
144
|
+
|
|
145
|
+
theme: ConfigParameter = ConfigParameter(
|
|
146
|
+
name="theme",
|
|
147
|
+
default="light",
|
|
148
|
+
type_=str,
|
|
149
|
+
choices=["light", "dark", "auto"],
|
|
150
|
+
help="GUI theme setting",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
window_width: ConfigParameter = ConfigParameter(
|
|
154
|
+
name="window_width",
|
|
155
|
+
default=800,
|
|
156
|
+
type_=int,
|
|
157
|
+
help="Default window width",
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
window_height: ConfigParameter = ConfigParameter(
|
|
161
|
+
name="window_height",
|
|
162
|
+
default=600,
|
|
163
|
+
type_=int,
|
|
164
|
+
help="Default window height",
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
log_window_height: ConfigParameter = ConfigParameter(
|
|
168
|
+
name="log_window_height",
|
|
169
|
+
default=200,
|
|
170
|
+
type_=int,
|
|
171
|
+
help="Height of the log window in pixels",
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
auto_scroll_log: ConfigParameter = ConfigParameter(
|
|
175
|
+
name="auto_scroll_log",
|
|
176
|
+
default=True,
|
|
177
|
+
type_=bool,
|
|
178
|
+
help="Automatically scroll to newest log entries",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
max_log_lines: ConfigParameter = ConfigParameter(
|
|
182
|
+
name="max_log_lines",
|
|
183
|
+
default=1000,
|
|
184
|
+
type_=int,
|
|
185
|
+
help="Maximum number of log lines to keep in GUI",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class ConfigParameterManager(BaseModel):
|
|
190
|
+
"""Main configuration manager that handles all parameter categories."""
|
|
191
|
+
|
|
192
|
+
cli: CliConfig = CliConfig()
|
|
193
|
+
app: AppConfig = AppConfig()
|
|
194
|
+
gui: GuiConfig = GuiConfig()
|
|
195
|
+
|
|
196
|
+
def __init__(self, config_file: str | None = None, **kwargs):
|
|
197
|
+
"""Initialize configuration from file and/or keyword arguments.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
config_file: Path to configuration file (JSON or YAML)
|
|
201
|
+
**kwargs: Override parameters in format category__parameter (e.g., cli__output)
|
|
202
|
+
"""
|
|
203
|
+
super().__init__()
|
|
204
|
+
|
|
205
|
+
# Load from file if provided
|
|
206
|
+
if config_file:
|
|
207
|
+
self.load_from_file(config_file)
|
|
208
|
+
|
|
209
|
+
# Override with provided kwargs
|
|
210
|
+
self._apply_kwargs(kwargs)
|
|
211
|
+
|
|
212
|
+
def _apply_kwargs(self, kwargs: dict[str, Any]):
|
|
213
|
+
"""Apply keyword arguments to override configuration values.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
kwargs: Dictionary with keys in format 'category__parameter'
|
|
217
|
+
"""
|
|
218
|
+
for key, value in kwargs.items():
|
|
219
|
+
if "__" in key:
|
|
220
|
+
category, param_name = key.split("__", 1)
|
|
221
|
+
if hasattr(self, category):
|
|
222
|
+
category_obj = getattr(self, category)
|
|
223
|
+
if hasattr(category_obj, param_name):
|
|
224
|
+
param = getattr(category_obj, param_name)
|
|
225
|
+
param.default = value
|
|
226
|
+
|
|
227
|
+
def load_from_file(self, config_file: str):
|
|
228
|
+
"""Load configuration from JSON or YAML file."""
|
|
229
|
+
config_path = Path(config_file)
|
|
230
|
+
if not config_path.exists():
|
|
231
|
+
raise FileNotFoundError(f"Configuration file not found: {config_file}")
|
|
232
|
+
|
|
233
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
234
|
+
if config_path.suffix.lower() in [".yml", ".yaml"]:
|
|
235
|
+
config_data = yaml.safe_load(f)
|
|
236
|
+
else:
|
|
237
|
+
config_data = json.load(f)
|
|
238
|
+
|
|
239
|
+
# Apply loaded configuration
|
|
240
|
+
for category_name, category_data in config_data.items():
|
|
241
|
+
if hasattr(self, category_name):
|
|
242
|
+
category_obj = getattr(self, category_name)
|
|
243
|
+
for param_name, param_value in category_data.items():
|
|
244
|
+
if hasattr(category_obj, param_name):
|
|
245
|
+
param = getattr(category_obj, param_name)
|
|
246
|
+
param.default = param_value
|
|
247
|
+
|
|
248
|
+
def save_to_file(self, config_file: str, format_: str = "auto"):
|
|
249
|
+
"""Save current configuration to file.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
config_file: Path to save configuration
|
|
253
|
+
format_: Format to use ('json', 'yaml', or 'auto' to detect from extension)
|
|
254
|
+
"""
|
|
255
|
+
config_path = Path(config_file)
|
|
256
|
+
config_data = self.to_dict()
|
|
257
|
+
|
|
258
|
+
# Determine format
|
|
259
|
+
if format_ == "auto":
|
|
260
|
+
format_ = "yaml" if config_path.suffix.lower() in [".yml", ".yaml"] else "json"
|
|
261
|
+
|
|
262
|
+
# Ensure directory exists
|
|
263
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
264
|
+
|
|
265
|
+
with open(config_path, "w", encoding="utf-8") as f:
|
|
266
|
+
if format_ == "yaml":
|
|
267
|
+
yaml.dump(config_data, f, default_flow_style=False, indent=2)
|
|
268
|
+
else:
|
|
269
|
+
json.dump(config_data, f, indent=2)
|
|
270
|
+
|
|
271
|
+
def to_dict(self) -> dict[str, Any]:
|
|
272
|
+
"""Convert configuration to dictionary."""
|
|
273
|
+
result = {}
|
|
274
|
+
for category_name in self.model_fields.keys():
|
|
275
|
+
category_obj = getattr(self, category_name)
|
|
276
|
+
category_dict = {}
|
|
277
|
+
for field_name in category_obj.model_fields:
|
|
278
|
+
param = getattr(category_obj, field_name)
|
|
279
|
+
category_dict[param.name] = param.default
|
|
280
|
+
result[category_name] = category_dict
|
|
281
|
+
return result
|
|
282
|
+
|
|
283
|
+
def get_all_parameters(self) -> list[ConfigParameter]:
|
|
284
|
+
"""Get all parameters from all categories."""
|
|
285
|
+
parameters = []
|
|
286
|
+
for category_name in self.model_fields.keys():
|
|
287
|
+
category_obj = getattr(self, category_name)
|
|
288
|
+
for field_name in category_obj.model_fields:
|
|
289
|
+
param = getattr(category_obj, field_name)
|
|
290
|
+
parameters.append(param)
|
|
291
|
+
return parameters
|
|
292
|
+
|
|
293
|
+
def get_cli_parameters(self) -> list[ConfigParameter]:
|
|
294
|
+
"""Get only CLI parameters."""
|
|
295
|
+
cli_params = []
|
|
296
|
+
for field_name in type(self.cli).model_fields.keys():
|
|
297
|
+
param = getattr(self.cli, field_name)
|
|
298
|
+
cli_params.append(param)
|
|
299
|
+
return cli_params
|
|
300
|
+
|
|
301
|
+
def get_logging_config(self) -> dict[str, Any]:
|
|
302
|
+
"""Get logging-specific configuration as dictionary.
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
Dictionary with logging configuration parameters
|
|
306
|
+
"""
|
|
307
|
+
return {
|
|
308
|
+
"log_level": self.app.log_level.default,
|
|
309
|
+
"log_file_max_size": self.app.log_file_max_size.default
|
|
310
|
+
* 1024
|
|
311
|
+
* 1024, # Convert MB to bytes
|
|
312
|
+
"log_backup_count": self.app.log_backup_count.default,
|
|
313
|
+
"log_format": self.app.log_format.default,
|
|
314
|
+
"enable_file_logging": self.app.enable_file_logging.default,
|
|
315
|
+
"enable_console_logging": self.app.enable_console_logging.default,
|
|
316
|
+
"max_log_lines": self.gui.max_log_lines.default,
|
|
317
|
+
"auto_scroll_log": self.gui.auto_scroll_log.default,
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
@classmethod
|
|
321
|
+
def generate_config_markdown_doc(cls, output_file: str):
|
|
322
|
+
"""Generate a Markdown documentation for all
|
|
323
|
+
configuration parameters organized by category."""
|
|
324
|
+
|
|
325
|
+
manager = cls()
|
|
326
|
+
|
|
327
|
+
def pad(s, width):
|
|
328
|
+
return s + " " * (width - len(s))
|
|
329
|
+
|
|
330
|
+
markdown_content = dedent(
|
|
331
|
+
"""
|
|
332
|
+
# Config parameters
|
|
333
|
+
|
|
334
|
+
These parameters are available to configure the behavior of your application.
|
|
335
|
+
The parameters in the cli category can be accessed via the command line interface.
|
|
336
|
+
|
|
337
|
+
"""
|
|
338
|
+
).lstrip()
|
|
339
|
+
|
|
340
|
+
for category_name in cls.model_fields.keys():
|
|
341
|
+
category_obj = getattr(manager, category_name)
|
|
342
|
+
markdown_content += f'## Category "{category_name}"\n\n'
|
|
343
|
+
|
|
344
|
+
# Collect all parameters for this category
|
|
345
|
+
rows = []
|
|
346
|
+
header = ["Name", "Type", "Description", "Default", "Choices"]
|
|
347
|
+
|
|
348
|
+
for field_name in type(category_obj).model_fields.keys():
|
|
349
|
+
param = getattr(category_obj, field_name)
|
|
350
|
+
name = param.name
|
|
351
|
+
typ = param.type_.__name__
|
|
352
|
+
desc = param.help
|
|
353
|
+
default = repr(param.default)
|
|
354
|
+
choices = str(param.choices) if param.choices else "-"
|
|
355
|
+
|
|
356
|
+
rows.append((name, typ, desc, default, choices))
|
|
357
|
+
|
|
358
|
+
# Calculate column widths
|
|
359
|
+
all_rows = [header] + rows
|
|
360
|
+
widths = [max(len(str(col)) for col in column) for column in zip(*all_rows)]
|
|
361
|
+
|
|
362
|
+
# Create Markdown table
|
|
363
|
+
table = (
|
|
364
|
+
"| "
|
|
365
|
+
+ " | ".join(pad(h, w) for h, w in zip(header, widths))
|
|
366
|
+
+ " |\n"
|
|
367
|
+
+ "|-"
|
|
368
|
+
+ "-|-".join("-" * w for w in widths)
|
|
369
|
+
+ "-|\n"
|
|
370
|
+
)
|
|
371
|
+
for row in rows:
|
|
372
|
+
table += "| " + " | ".join(pad(str(col), w) for col, w in zip(row, widths)) + " |\n"
|
|
373
|
+
|
|
374
|
+
markdown_content += table + "\n"
|
|
375
|
+
|
|
376
|
+
# Write to file
|
|
377
|
+
Path(output_file).parent.mkdir(parents=True, exist_ok=True)
|
|
378
|
+
with open(output_file, "w", encoding="utf-8") as f:
|
|
379
|
+
f.write(markdown_content)
|
|
380
|
+
|
|
381
|
+
@classmethod
|
|
382
|
+
def generate_default_config_file(cls, output_file: str):
|
|
383
|
+
"""Generate a default configuration file with all parameters and their descriptions."""
|
|
384
|
+
manager = cls()
|
|
385
|
+
output_path = Path(output_file)
|
|
386
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
387
|
+
|
|
388
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
389
|
+
f.write("# Configuration File\n")
|
|
390
|
+
f.write("# This file was auto-generated. Modify as needed.\n\n")
|
|
391
|
+
|
|
392
|
+
for category_name in cls.model_fields.keys():
|
|
393
|
+
category_obj = getattr(manager, category_name)
|
|
394
|
+
f.write(f"# {category_name.upper()} Configuration\n")
|
|
395
|
+
f.write(f"{category_name}:\n")
|
|
396
|
+
|
|
397
|
+
for field_name in type(category_obj).model_fields.keys():
|
|
398
|
+
param = getattr(category_obj, field_name)
|
|
399
|
+
f.write(f" # {param.help}\n")
|
|
400
|
+
if param.choices:
|
|
401
|
+
f.write(f" # Choices: {param.choices}\n")
|
|
402
|
+
f.write(f" # Type: {param.type_.__name__}\n")
|
|
403
|
+
f.write(f" {param.name}: {repr(param.default)}\n\n")
|
|
404
|
+
|
|
405
|
+
f.write("\n")
|
|
406
|
+
|
|
407
|
+
@classmethod
|
|
408
|
+
def generate_cli_markdown_doc(cls, output_file: str):
|
|
409
|
+
"""Generate a Markdown CLI documentation with a formatted table and examples."""
|
|
410
|
+
manager = cls()
|
|
411
|
+
cli_params = manager.get_cli_parameters()
|
|
412
|
+
|
|
413
|
+
rows = []
|
|
414
|
+
required_params = []
|
|
415
|
+
optional_params = []
|
|
416
|
+
|
|
417
|
+
for param in cli_params:
|
|
418
|
+
cli_arg = f"`--{param.name}`" if param.name != "input" else "`path/to/file`"
|
|
419
|
+
typ = param.type_.__name__
|
|
420
|
+
desc = param.help
|
|
421
|
+
default = (
|
|
422
|
+
"*required*"
|
|
423
|
+
if param.required or param.default in (None, "")
|
|
424
|
+
else repr(param.default)
|
|
425
|
+
)
|
|
426
|
+
choices = str(param.choices) if param.choices else "-"
|
|
427
|
+
|
|
428
|
+
rows.append((cli_arg, typ, desc, default, choices))
|
|
429
|
+
if default == "*required*":
|
|
430
|
+
required_params.append(param)
|
|
431
|
+
else:
|
|
432
|
+
optional_params.append(param)
|
|
433
|
+
|
|
434
|
+
# Dynamically determine column width
|
|
435
|
+
def pad(s, width):
|
|
436
|
+
return s + " " * (width - len(s))
|
|
437
|
+
|
|
438
|
+
widths = [max(len(str(col)) for col in column) for column in zip(*rows)]
|
|
439
|
+
header = ["Option", "Type", "Description", "Default", "Choices"]
|
|
440
|
+
|
|
441
|
+
# Create Markdown table
|
|
442
|
+
table = (
|
|
443
|
+
"| "
|
|
444
|
+
+ " | ".join(pad(h, w) for h, w in zip(header, widths))
|
|
445
|
+
+ " |\n"
|
|
446
|
+
+ "|-"
|
|
447
|
+
+ "-|-".join("-" * w for w in widths)
|
|
448
|
+
+ "-|\n"
|
|
449
|
+
)
|
|
450
|
+
for row in rows:
|
|
451
|
+
table += "| " + " | ".join(pad(str(col), w) for col, w in zip(row, widths)) + " |\n"
|
|
452
|
+
|
|
453
|
+
# Generate example commands
|
|
454
|
+
examples = []
|
|
455
|
+
required_arg = required_params[0].name if required_params else "example.input"
|
|
456
|
+
examples.append(
|
|
457
|
+
dedent(
|
|
458
|
+
f"""
|
|
459
|
+
### 1. Standard version (only required parameter)
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
python -m python_template_project.cli {required_arg}
|
|
463
|
+
```
|
|
464
|
+
"""
|
|
465
|
+
)
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
# Add logging examples
|
|
469
|
+
examples.append(
|
|
470
|
+
dedent(
|
|
471
|
+
f"""
|
|
472
|
+
### 2. With verbose logging
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
python -m python_template_project.cli --verbose {required_arg}
|
|
476
|
+
```
|
|
477
|
+
"""
|
|
478
|
+
)
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
examples.append(
|
|
482
|
+
dedent(
|
|
483
|
+
f"""
|
|
484
|
+
### 3. With quiet mode
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
python -m python_template_project.cli --quiet {required_arg}
|
|
488
|
+
```
|
|
489
|
+
"""
|
|
490
|
+
)
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
for i in range(1, min(3, len(optional_params) + 1)):
|
|
494
|
+
selected = [p for p in optional_params if p.name not in ["verbose", "quiet"]][:i]
|
|
495
|
+
if selected:
|
|
496
|
+
cli_part = " ".join(
|
|
497
|
+
f"--{p.name} {p.choices[0] if p.choices else p.default}" for p in selected
|
|
498
|
+
)
|
|
499
|
+
examples.append(
|
|
500
|
+
dedent(
|
|
501
|
+
f"""
|
|
502
|
+
### {i + 3}. Example with {i} Parameter(s)
|
|
503
|
+
|
|
504
|
+
```bash
|
|
505
|
+
python -m python_template_project.cli {cli_part} {required_arg}
|
|
506
|
+
```
|
|
507
|
+
"""
|
|
508
|
+
)
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
markdown = dedent(
|
|
512
|
+
"""
|
|
513
|
+
# Command line interface
|
|
514
|
+
|
|
515
|
+
Command line options
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
python -m python_template_project.cli [OPTIONS] path/to/file
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## ⚙️ CLI-Options
|
|
524
|
+
|
|
525
|
+
{}
|
|
526
|
+
|
|
527
|
+
## 💡 Examples
|
|
528
|
+
|
|
529
|
+
In the example, the following is assumed: `example.input` in the current directory
|
|
530
|
+
|
|
531
|
+
{}
|
|
532
|
+
"""
|
|
533
|
+
).format(table, "".join(examples))
|
|
534
|
+
|
|
535
|
+
Path(output_file).parent.mkdir(parents=True, exist_ok=True)
|
|
536
|
+
with open(output_file, "w", encoding="utf-8") as f:
|
|
537
|
+
f.write(markdown.strip())
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def main():
|
|
541
|
+
"""Main function to generate config file and documentation."""
|
|
542
|
+
default_config: str = "../../config.yaml"
|
|
543
|
+
default_cli_doc: str = "../../docs/usage/cli.md"
|
|
544
|
+
default_config_doc: str = "../../docs/usage/config.md"
|
|
545
|
+
|
|
546
|
+
ConfigParameterManager.generate_default_config_file(default_config)
|
|
547
|
+
print(f"Generated: {default_config}")
|
|
548
|
+
|
|
549
|
+
ConfigParameterManager.generate_config_markdown_doc(default_config_doc)
|
|
550
|
+
print(f"Generated: {default_config_doc}")
|
|
551
|
+
|
|
552
|
+
ConfigParameterManager.generate_cli_markdown_doc(default_cli_doc)
|
|
553
|
+
print(f"Generated: {default_cli_doc}")
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
if __name__ == "__main__":
|
|
557
|
+
main()
|
|
File without changes
|