config-cli-gui 0.1.2__tar.gz → 0.1.3__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.
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.idea/runConfigurations/config_generate.xml +1 -1
- config_cli_gui-0.1.3/HISTORY.md +42 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/PKG-INFO +145 -134
- config_cli_gui-0.1.3/README.md +264 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/config.yaml +2 -2
- config_cli_gui-0.1.3/docs/index.md +262 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/src/config_cli_gui/_version.py +2 -2
- config_cli_gui-0.1.2/src/config_cli_gui/cli_generator.py → config_cli_gui-0.1.3/src/config_cli_gui/cli.py +2 -2
- config_cli_gui-0.1.2/src/config_cli_gui/config_framework.py → config_cli_gui-0.1.3/src/config_cli_gui/config.py +6 -8
- config_cli_gui-0.1.2/src/config_cli_gui/docs_generator.py → config_cli_gui-0.1.3/src/config_cli_gui/docs.py +1 -1
- config_cli_gui-0.1.2/src/config_cli_gui/gui_generator.py → config_cli_gui-0.1.3/src/config_cli_gui/gui.py +2 -2
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/src/config_cli_gui.egg-info/PKG-INFO +145 -134
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/src/config_cli_gui.egg-info/SOURCES.txt +7 -8
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/src/config_cli_gui.egg-info/top_level.txt +0 -1
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/example_project/__main__.py +1 -1
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/example_project/cli/__main__.py +1 -1
- config_cli_gui-0.1.3/tests/example_project/cli/cli_example.py +74 -0
- config_cli_gui-0.1.2/tests/example_project/config/config.py → config_cli_gui-0.1.3/tests/example_project/config/config_example.py +13 -13
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/example_project/core/base.py +6 -10
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/example_project/core/logging.py +4 -4
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/example_project/gui/__main__.py +1 -1
- config_cli_gui-0.1.2/tests/example_project/gui/gui.py → config_cli_gui-0.1.3/tests/example_project/gui/gui_example.py +11 -13
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/test_generic_cli.py +7 -7
- config_cli_gui-0.1.2/HISTORY.md +0 -25
- config_cli_gui-0.1.2/README.md +0 -253
- config_cli_gui-0.1.2/docs/index.md +0 -251
- config_cli_gui-0.1.2/src/main.py +0 -153
- config_cli_gui-0.1.2/tests/example_project/cli/cli.py +0 -132
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/FUNDING.yml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/actions/setup-environment/action.yml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/dependabot.yml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/init.sh +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/release_message.sh +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/update_funding.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/workflows/main.yml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/workflows/release.yml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.github/workflows/update_readme.yml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.gitignore +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.pre-commit-config.yaml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/.readthedocs.yaml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/LICENSE +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/Makefile +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/.nav.yml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/_static/img/favicon.png +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/_static/img/logo.png +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/css/custom.css +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/develop/contributing.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/develop/make_windows.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/develop/naming_convention.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/funding/funding.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/getting-started/install.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/getting-started/virtual-environment.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/usage/cli.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/docs/usage/config.md +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/examples/kuhkopfsteig.gpx +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/examples/rother_lilienstein.gpx +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/examples/teneriffa.gpx +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/mkdocs.yml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/pyproject.toml +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/scripts/show_filelist.ps1 +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/scripts/show_tree.ps1 +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/scripts/show_tree.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/scripts/update_readme.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/setup.cfg +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/src/__init__.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/src/config_cli_gui/__init__.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/src/config_cli_gui.egg-info/dependency_links.txt +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/src/config_cli_gui.egg-info/entry_points.txt +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/src/config_cli_gui.egg-info/requires.txt +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/template.yml.url +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/__init__.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/example_project/__init__.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/example_project/cli/__init__.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/example_project/config/__init__.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/example_project/core/__init__.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/tests/example_project/gui/__init__.py +0 -0
- {config_cli_gui-0.1.2 → config_cli_gui-0.1.3}/uv.lock +0 -0
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
14
14
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
15
15
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
|
16
|
-
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/tests/example_project/config/
|
|
16
|
+
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/tests/example_project/config/config_example.py" />
|
|
17
17
|
<option name="PARAMETERS" value="" />
|
|
18
18
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
|
19
19
|
<option name="EMULATE_TERMINAL" value="false" />
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Changelog
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
(unreleased)
|
|
6
|
+
------------
|
|
7
|
+
- Feat #5: improve dialog. [Paul Magister]
|
|
8
|
+
- Feat #5: Bugfig: use specific dialog for path parameters. [Paul
|
|
9
|
+
Magister]
|
|
10
|
+
- Fix #4: fix test. [Paul Magister]
|
|
11
|
+
- Fix #4: write yaml file with nicely with comments. [Paul Magister]
|
|
12
|
+
- Fix #4: add comments to the yaml. [Paul Magister]
|
|
13
|
+
- Fix #4: make new special datatypes work (Color, Path): correct
|
|
14
|
+
load/save lifecycle. [Paul Magister]
|
|
15
|
+
- Feat #3: some advanced parameter types as example. [Paul Magister]
|
|
16
|
+
- Feat #3: delete build workflow since it is not necessary for the lib.
|
|
17
|
+
[Paul Magister]
|
|
18
|
+
- Feat #3: add verbose and quiet doc to auto generated config. [Paul
|
|
19
|
+
Magister]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
0.1.1 (2025-06-22)
|
|
23
|
+
------------------
|
|
24
|
+
- Feat #3: avoid type_ [Paul Magister]
|
|
25
|
+
- Feat #3: Improved paramter types: [Paul Magister]
|
|
26
|
+
- Feat #3: Improved paramter types: * move example project to tests *
|
|
27
|
+
remove type_ * add improved widgets to gui.py * separate
|
|
28
|
+
module for docs.py. [Paul Magister]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
0.1.0 (2025-06-22)
|
|
32
|
+
------------------
|
|
33
|
+
- Remove unnecessary example files and deps. [Paul Magister]
|
|
34
|
+
- Update README.md from docs/index.md. [github-actions]
|
|
35
|
+
- Fix doc: formatting. [Paul Magister]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
0.0.2 (2025-06-22)
|
|
39
|
+
------------------
|
|
40
|
+
- Remove _version.py. [Paul Magister]
|
|
41
|
+
|
|
42
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: config-cli-gui
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Feature-rich Python project template for config-cli-gui.
|
|
5
5
|
Author: pamagister
|
|
6
6
|
Requires-Python: <3.12,>=3.10
|
|
@@ -78,79 +78,74 @@ pip install config-cli-gui
|
|
|
78
78
|
Start by defining your application's configuration parameters in a central `config.py` file within your project. You will inherit from `config-cli-gui`'s `GenericConfigManager` and `BaseConfigCategory`.
|
|
79
79
|
|
|
80
80
|
```python
|
|
81
|
-
# my_project/
|
|
82
|
-
|
|
83
|
-
from
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
# my_project/config_example.py
|
|
82
|
+
|
|
83
|
+
from config_cli_gui.config import (
|
|
84
|
+
ConfigCategory,
|
|
85
|
+
ConfigManager,
|
|
86
|
+
ConfigParameter,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class CliConfig(ConfigCategory):
|
|
91
|
+
"""CLI-specific configuration parameters."""
|
|
92
|
+
|
|
93
|
+
def get_category_name(self) -> str:
|
|
94
|
+
return "cli"
|
|
95
|
+
|
|
96
|
+
# Positional argument
|
|
97
|
+
input: ConfigParameter = ConfigParameter(
|
|
98
|
+
name="input",
|
|
89
99
|
default="",
|
|
90
|
-
|
|
91
|
-
help="Path to the input file or directory",
|
|
100
|
+
help="Path to input (file or folder)",
|
|
92
101
|
required=True,
|
|
93
|
-
|
|
102
|
+
is_cli=True,
|
|
94
103
|
)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
help="
|
|
100
|
-
|
|
104
|
+
|
|
105
|
+
min_dist: ConfigParameter = ConfigParameter(
|
|
106
|
+
name="min_dist",
|
|
107
|
+
default=20,
|
|
108
|
+
help="Maximum distance between two waypoints",
|
|
109
|
+
is_cli=True,
|
|
101
110
|
)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
help="
|
|
107
|
-
|
|
111
|
+
|
|
112
|
+
extract_waypoints: ConfigParameter = ConfigParameter(
|
|
113
|
+
name="extract_waypoints",
|
|
114
|
+
default=True,
|
|
115
|
+
help="Extract starting points of each track as waypoint",
|
|
116
|
+
is_cli=True,
|
|
108
117
|
)
|
|
109
118
|
|
|
110
|
-
|
|
111
|
-
|
|
119
|
+
|
|
120
|
+
class AppConfig(ConfigCategory):
|
|
121
|
+
"""Application-specific configuration parameters."""
|
|
122
|
+
|
|
123
|
+
def get_category_name(self) -> str:
|
|
124
|
+
return "app"
|
|
125
|
+
|
|
112
126
|
log_level: ConfigParameter = ConfigParameter(
|
|
113
127
|
name="log_level",
|
|
114
128
|
default="INFO",
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
help="Logging verbosity level"
|
|
118
|
-
)
|
|
119
|
-
max_threads: ConfigParameter = ConfigParameter(
|
|
120
|
-
name="max_threads",
|
|
121
|
-
default=4,
|
|
122
|
-
type_=int,
|
|
123
|
-
help="Maximum number of processing threads"
|
|
129
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
|
130
|
+
help="Logging level for the application",
|
|
124
131
|
)
|
|
125
132
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
default="dark",
|
|
131
|
-
type_=str,
|
|
132
|
-
choices=["light", "dark", "system"],
|
|
133
|
-
help="GUI theme"
|
|
134
|
-
)
|
|
135
|
-
window_size: ConfigParameter = ConfigParameter(
|
|
136
|
-
name="window_size",
|
|
137
|
-
default="800x600",
|
|
138
|
-
type_=str,
|
|
139
|
-
help="Initial GUI window size"
|
|
133
|
+
log_file_max_size: ConfigParameter = ConfigParameter(
|
|
134
|
+
name="log_file_max_size",
|
|
135
|
+
default=10,
|
|
136
|
+
help="Maximum log file size in MB before rotation",
|
|
140
137
|
)
|
|
141
138
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
139
|
+
|
|
140
|
+
class ProjectConfigManager(ConfigManager): # Inherit from ConfigManager
|
|
141
|
+
"""Main configuration manager that handles all parameter categories."""
|
|
142
|
+
|
|
143
|
+
categories = (CliConfig(), AppConfig())
|
|
147
144
|
|
|
148
145
|
def __init__(self, config_file: str | None = None, **kwargs):
|
|
149
|
-
|
|
150
|
-
self.
|
|
151
|
-
|
|
152
|
-
self.__class__.add_config_category("gui", MyGuiConfig)
|
|
153
|
-
super().__init__(config_file, **kwargs)
|
|
146
|
+
"""Initialize the configuration manager with all parameter categories."""
|
|
147
|
+
super().__init__(self.categories, config_file, **kwargs)
|
|
148
|
+
|
|
154
149
|
|
|
155
150
|
```
|
|
156
151
|
|
|
@@ -159,60 +154,76 @@ class ProjectConfigManager(GenericConfigManager):
|
|
|
159
154
|
Use the generic CLI functions to parse command-line arguments based on your defined `CliConfig`.
|
|
160
155
|
|
|
161
156
|
```python
|
|
162
|
-
# my_project/
|
|
163
|
-
import
|
|
164
|
-
from
|
|
165
|
-
from
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
157
|
+
# my_project/cli_example.py
|
|
158
|
+
from config_cli_gui.cli import CliGenerator
|
|
159
|
+
from config_cli_gui.config import ConfigManager
|
|
160
|
+
from tests.example_project.config.config_example import ProjectConfigManager
|
|
161
|
+
from tests.example_project.core.base import BaseGPXProcessor
|
|
162
|
+
from tests.example_project.core.logging import initialize_logging
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def run_main_processing(_config: ConfigManager) -> int:
|
|
166
|
+
"""Main processing function that gets called by the CLI generator.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
_config: Configuration manager with all settings
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Exit code (0 for success, non-zero for error)
|
|
173
|
+
"""
|
|
174
|
+
# Initialize logging system
|
|
175
|
+
logger_manager = initialize_logging(_config)
|
|
176
|
+
logger = logger_manager.get_logger("config_cli_gui.cli")
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
# Log startup information
|
|
180
|
+
logger.info("Starting config_cli_gui CLI")
|
|
181
|
+
logger_manager.log_config_summary()
|
|
182
|
+
|
|
183
|
+
logger.info(f"Processing input")
|
|
184
|
+
|
|
185
|
+
# Create and run BaseGPXProcessor
|
|
186
|
+
processor = BaseGPXProcessor(
|
|
187
|
+
_config.get_category("cli").input.default,
|
|
188
|
+
_config.get_category("cli").output.default,
|
|
189
|
+
_config.get_category("cli").min_dist.default,
|
|
190
|
+
_config.get_category("app").date_format.default,
|
|
191
|
+
_config.get_category("cli").elevation.default,
|
|
192
|
+
logger=logger,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
logger.info("Starting conversion process")
|
|
196
|
+
|
|
197
|
+
# Run the processing (adjust method name based on your actual implementation)
|
|
198
|
+
result_files = processor.compress_files()
|
|
199
|
+
logger.info(f"Successfully processed {result_files}")
|
|
200
|
+
return 0
|
|
201
|
+
|
|
202
|
+
except Exception as e:
|
|
203
|
+
logger.error(f"Processing failed: {e}")
|
|
204
|
+
logger.debug("Full traceback:", exc_info=True)
|
|
205
|
+
return 1
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def main():
|
|
209
|
+
"""Main entry point for the CLI application."""
|
|
210
|
+
# Create the base configuration manager
|
|
211
|
+
config_manager = ProjectConfigManager()
|
|
212
|
+
|
|
213
|
+
# Create CLI generator
|
|
214
|
+
cli_generator = CliGenerator(config_manager=config_manager, app_name="config_cli_gui")
|
|
215
|
+
|
|
216
|
+
# Run the CLI with our main processing function
|
|
217
|
+
return cli_generator.run_cli(
|
|
218
|
+
main_function=run_main_processing,
|
|
219
|
+
description="Example CLI for config-cli-gui using the generic config framework.",
|
|
200
220
|
)
|
|
201
221
|
|
|
202
|
-
# Initialize your project's configuration
|
|
203
|
-
config = ProjectConfigManager(
|
|
204
|
-
config_file=args.config if hasattr(args, "config") and args.config else None,
|
|
205
|
-
**cli_overrides
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
print(f"Input Path: {config.cli.input_path.default}")
|
|
209
|
-
print(f"Output Directory: {config.cli.output_dir.default}")
|
|
210
|
-
print(f"Dry Run: {config.cli.dry_run.default}")
|
|
211
|
-
print(f"Log Level: {config.app.log_level.default}")
|
|
212
|
-
# ... your application logic using 'config'
|
|
213
222
|
|
|
214
223
|
if __name__ == "__main__":
|
|
215
|
-
|
|
224
|
+
import sys
|
|
225
|
+
|
|
226
|
+
sys.exit(main())
|
|
216
227
|
```
|
|
217
228
|
|
|
218
229
|
### 3\. Integrate GUI Settings Dialog
|
|
@@ -220,27 +231,29 @@ if __name__ == "__main__":
|
|
|
220
231
|
The `SettingsDialog` from `config-cli-gui` (or your project's adapted version) can be used to easily create a settings window.
|
|
221
232
|
|
|
222
233
|
```python
|
|
223
|
-
# my_project/
|
|
234
|
+
# my_project/gui_example.py (Simplified example)
|
|
224
235
|
import tkinter as tk
|
|
225
|
-
from
|
|
226
|
-
from config_cli_gui.
|
|
236
|
+
from tests.example_project.config.config_example import ProjectConfigManager
|
|
237
|
+
from config_cli_gui.gui import GenericSettingsDialog # Assuming gui_settings is part of the generic lib or adapted
|
|
238
|
+
|
|
227
239
|
|
|
228
240
|
def open_settings_window(parent_root, config_manager: ProjectConfigManager):
|
|
229
|
-
dialog =
|
|
241
|
+
dialog = GenericSettingsDialog(parent_root, config_manager)
|
|
230
242
|
parent_root.wait_window(dialog.dialog)
|
|
231
243
|
# After dialog closes, config_manager will have updated values if 'OK' was clicked
|
|
232
244
|
print("Settings updated or cancelled.")
|
|
233
|
-
print(f"New GUI Theme: {config_manager.gui.theme.default}")
|
|
245
|
+
print(f"New GUI Theme: {config_manager.get_category('gui').theme.default}")
|
|
246
|
+
|
|
234
247
|
|
|
235
248
|
if __name__ == "__main__":
|
|
236
249
|
root = tk.Tk()
|
|
237
|
-
root.withdraw()
|
|
238
|
-
|
|
250
|
+
root.withdraw() # Hide main window for this example
|
|
251
|
+
|
|
239
252
|
# Initialize your project's config manager
|
|
240
|
-
project_config = ProjectConfigManager()
|
|
241
|
-
|
|
253
|
+
project_config = ProjectConfigManager()
|
|
254
|
+
|
|
242
255
|
open_settings_window(root, project_config)
|
|
243
|
-
|
|
256
|
+
|
|
244
257
|
root.destroy()
|
|
245
258
|
```
|
|
246
259
|
|
|
@@ -250,29 +263,27 @@ Use the static methods on your `ProjectConfigManager` to generate `config.yaml`,
|
|
|
250
263
|
|
|
251
264
|
```python
|
|
252
265
|
# scripts/generate_docs.py (or similar script in your project)
|
|
253
|
-
from
|
|
266
|
+
from tests.example_project.config.config_example import ProjectConfigManager
|
|
267
|
+
from config_cli_gui.docs import DocumentationGenerator
|
|
254
268
|
import os
|
|
255
269
|
|
|
256
270
|
# Define output paths
|
|
257
271
|
output_dir = "docs/generated"
|
|
258
272
|
os.makedirs(output_dir, exist_ok=True)
|
|
259
273
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
274
|
+
default_config = "config.yaml" # At the project root or similar
|
|
275
|
+
default_cli_doc = os.path.join(output_dir, "cli.md")
|
|
276
|
+
default_config_doc = os.path.join(output_dir, "config.md")
|
|
277
|
+
_config = ProjectConfigManager()
|
|
278
|
+
doc_gen = DocumentationGenerator(_config)
|
|
279
|
+
doc_gen.generate_default_config_file(output_file=default_config)
|
|
280
|
+
print(f"Generated: {default_config}")
|
|
266
281
|
|
|
267
|
-
|
|
268
|
-
|
|
282
|
+
doc_gen.generate_config_markdown_doc(output_file=default_config_doc)
|
|
283
|
+
print(f"Generated: {default_config_doc}")
|
|
269
284
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
output_file=cli_doc_path,
|
|
273
|
-
cli_category_name="cli", # Ensure this matches your CLI config category
|
|
274
|
-
cli_entry_point="python -m my_project.cli" # Your project's actual CLI entry point
|
|
275
|
-
)
|
|
285
|
+
doc_gen.generate_cli_markdown_doc(output_file=default_cli_doc)
|
|
286
|
+
print(f"Generated: {default_cli_doc}")
|
|
276
287
|
|
|
277
288
|
print("Documentation and default config generation complete.")
|
|
278
289
|
```
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
<!-- This README.md is auto-generated from docs/index.md -->
|
|
2
|
+
|
|
3
|
+
# Welcome to config-cli-gui
|
|
4
|
+
|
|
5
|
+
**Unified Configuration and Interface Management**
|
|
6
|
+
|
|
7
|
+
Provides a generic configuration framework that automatically generates both command-line interfaces and GUI settings dialogs from configuration parameters.
|
|
8
|
+
|
|
9
|
+
[](https://github.com/pamagister/config-cli-gui/actions)
|
|
10
|
+
[](https://github.com/pamagister/config-cli-gui/releases)
|
|
11
|
+
[](https://config-cli-gui.readthedocs.io/en/stable/)
|
|
12
|
+
[](https://github.com/pamagister/config-cli-gui/blob/main/LICENSE)
|
|
13
|
+
[](https://github.com/pamagister/config-cli-gui/issues)
|
|
14
|
+
[](https://pypi.org/project/config-cli-gui/)
|
|
15
|
+
[](https://pepy.tech/project/config-cli-gui/)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
`config-cli-gui` is a Python library designed to streamline the management of application configurations,
|
|
19
|
+
generating command-line interfaces (CLIs), and dynamically creating graphical user interface (GUI) settings dialogs
|
|
20
|
+
from a single source of truth. It leverages Pydantic for robust parameter definition and offers
|
|
21
|
+
powerful features for consistent configuration across different application entry points.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 🚀 Installation
|
|
26
|
+
|
|
27
|
+
You can install `config-cli-gui` using pip:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install config-cli-gui
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## ✨ Features
|
|
36
|
+
|
|
37
|
+
* **Single Source of Truth**: Define all your application parameters in one place using simple, dataclass-like structures based on Pydantic's `BaseModel`. This ensures consistency and reduces errors across your application.
|
|
38
|
+
* **Categorized Configuration**: Organize your parameters into logical categories (e.g., `cli`, `app`, `gui`) for better structure and maintainability.
|
|
39
|
+
* **Dynamic CLI Generation**: Automatically generate `argparse`-compatible command-line arguments directly from your defined configuration parameters, including help texts, types, and choices.
|
|
40
|
+
* **Config File Management**: Easily load and save configurations from/to YAML or JSON files, allowing users to customize default settings.
|
|
41
|
+
* **GUI Settings Dialogs**: Dynamically create Tkinter-based settings dialogs for your application, allowing users to intuitively modify configuration parameters via a graphical interface.
|
|
42
|
+
* **Documentation Generation**: Generate detailed Markdown documentation for both your CLI options and all configuration parameters, keeping your user guides always up-to-date with your codebase.
|
|
43
|
+
* **Override System**: Supports robust overriding of configuration values via configuration files and command-line arguments, with clear precedence.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 📚 Usage
|
|
48
|
+
|
|
49
|
+
### 1\. Define Your Configuration
|
|
50
|
+
|
|
51
|
+
Start by defining your application's configuration parameters in a central `config.py` file within your project. You will inherit from `config-cli-gui`'s `GenericConfigManager` and `BaseConfigCategory`.
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
# my_project/config_example.py
|
|
55
|
+
|
|
56
|
+
from config_cli_gui.config import (
|
|
57
|
+
ConfigCategory,
|
|
58
|
+
ConfigManager,
|
|
59
|
+
ConfigParameter,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class CliConfig(ConfigCategory):
|
|
64
|
+
"""CLI-specific configuration parameters."""
|
|
65
|
+
|
|
66
|
+
def get_category_name(self) -> str:
|
|
67
|
+
return "cli"
|
|
68
|
+
|
|
69
|
+
# Positional argument
|
|
70
|
+
input: ConfigParameter = ConfigParameter(
|
|
71
|
+
name="input",
|
|
72
|
+
default="",
|
|
73
|
+
help="Path to input (file or folder)",
|
|
74
|
+
required=True,
|
|
75
|
+
is_cli=True,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
min_dist: ConfigParameter = ConfigParameter(
|
|
79
|
+
name="min_dist",
|
|
80
|
+
default=20,
|
|
81
|
+
help="Maximum distance between two waypoints",
|
|
82
|
+
is_cli=True,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
extract_waypoints: ConfigParameter = ConfigParameter(
|
|
86
|
+
name="extract_waypoints",
|
|
87
|
+
default=True,
|
|
88
|
+
help="Extract starting points of each track as waypoint",
|
|
89
|
+
is_cli=True,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class AppConfig(ConfigCategory):
|
|
94
|
+
"""Application-specific configuration parameters."""
|
|
95
|
+
|
|
96
|
+
def get_category_name(self) -> str:
|
|
97
|
+
return "app"
|
|
98
|
+
|
|
99
|
+
log_level: ConfigParameter = ConfigParameter(
|
|
100
|
+
name="log_level",
|
|
101
|
+
default="INFO",
|
|
102
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
|
103
|
+
help="Logging level for the application",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
log_file_max_size: ConfigParameter = ConfigParameter(
|
|
107
|
+
name="log_file_max_size",
|
|
108
|
+
default=10,
|
|
109
|
+
help="Maximum log file size in MB before rotation",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class ProjectConfigManager(ConfigManager): # Inherit from ConfigManager
|
|
114
|
+
"""Main configuration manager that handles all parameter categories."""
|
|
115
|
+
|
|
116
|
+
categories = (CliConfig(), AppConfig())
|
|
117
|
+
|
|
118
|
+
def __init__(self, config_file: str | None = None, **kwargs):
|
|
119
|
+
"""Initialize the configuration manager with all parameter categories."""
|
|
120
|
+
super().__init__(self.categories, config_file, **kwargs)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 2\. Generate CLI
|
|
126
|
+
|
|
127
|
+
Use the generic CLI functions to parse command-line arguments based on your defined `CliConfig`.
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
# my_project/cli_example.py
|
|
131
|
+
from config_cli_gui.cli import CliGenerator
|
|
132
|
+
from config_cli_gui.config import ConfigManager
|
|
133
|
+
from tests.example_project.config.config_example import ProjectConfigManager
|
|
134
|
+
from tests.example_project.core.base import BaseGPXProcessor
|
|
135
|
+
from tests.example_project.core.logging import initialize_logging
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def run_main_processing(_config: ConfigManager) -> int:
|
|
139
|
+
"""Main processing function that gets called by the CLI generator.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
_config: Configuration manager with all settings
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
Exit code (0 for success, non-zero for error)
|
|
146
|
+
"""
|
|
147
|
+
# Initialize logging system
|
|
148
|
+
logger_manager = initialize_logging(_config)
|
|
149
|
+
logger = logger_manager.get_logger("config_cli_gui.cli")
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
# Log startup information
|
|
153
|
+
logger.info("Starting config_cli_gui CLI")
|
|
154
|
+
logger_manager.log_config_summary()
|
|
155
|
+
|
|
156
|
+
logger.info(f"Processing input")
|
|
157
|
+
|
|
158
|
+
# Create and run BaseGPXProcessor
|
|
159
|
+
processor = BaseGPXProcessor(
|
|
160
|
+
_config.get_category("cli").input.default,
|
|
161
|
+
_config.get_category("cli").output.default,
|
|
162
|
+
_config.get_category("cli").min_dist.default,
|
|
163
|
+
_config.get_category("app").date_format.default,
|
|
164
|
+
_config.get_category("cli").elevation.default,
|
|
165
|
+
logger=logger,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
logger.info("Starting conversion process")
|
|
169
|
+
|
|
170
|
+
# Run the processing (adjust method name based on your actual implementation)
|
|
171
|
+
result_files = processor.compress_files()
|
|
172
|
+
logger.info(f"Successfully processed {result_files}")
|
|
173
|
+
return 0
|
|
174
|
+
|
|
175
|
+
except Exception as e:
|
|
176
|
+
logger.error(f"Processing failed: {e}")
|
|
177
|
+
logger.debug("Full traceback:", exc_info=True)
|
|
178
|
+
return 1
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def main():
|
|
182
|
+
"""Main entry point for the CLI application."""
|
|
183
|
+
# Create the base configuration manager
|
|
184
|
+
config_manager = ProjectConfigManager()
|
|
185
|
+
|
|
186
|
+
# Create CLI generator
|
|
187
|
+
cli_generator = CliGenerator(config_manager=config_manager, app_name="config_cli_gui")
|
|
188
|
+
|
|
189
|
+
# Run the CLI with our main processing function
|
|
190
|
+
return cli_generator.run_cli(
|
|
191
|
+
main_function=run_main_processing,
|
|
192
|
+
description="Example CLI for config-cli-gui using the generic config framework.",
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
if __name__ == "__main__":
|
|
197
|
+
import sys
|
|
198
|
+
|
|
199
|
+
sys.exit(main())
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 3\. Integrate GUI Settings Dialog
|
|
203
|
+
|
|
204
|
+
The `SettingsDialog` from `config-cli-gui` (or your project's adapted version) can be used to easily create a settings window.
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
# my_project/gui_example.py (Simplified example)
|
|
208
|
+
import tkinter as tk
|
|
209
|
+
from tests.example_project.config.config_example import ProjectConfigManager
|
|
210
|
+
from config_cli_gui.gui import GenericSettingsDialog # Assuming gui_settings is part of the generic lib or adapted
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def open_settings_window(parent_root, config_manager: ProjectConfigManager):
|
|
214
|
+
dialog = GenericSettingsDialog(parent_root, config_manager)
|
|
215
|
+
parent_root.wait_window(dialog.dialog)
|
|
216
|
+
# After dialog closes, config_manager will have updated values if 'OK' was clicked
|
|
217
|
+
print("Settings updated or cancelled.")
|
|
218
|
+
print(f"New GUI Theme: {config_manager.get_category('gui').theme.default}")
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
if __name__ == "__main__":
|
|
222
|
+
root = tk.Tk()
|
|
223
|
+
root.withdraw() # Hide main window for this example
|
|
224
|
+
|
|
225
|
+
# Initialize your project's config manager
|
|
226
|
+
project_config = ProjectConfigManager()
|
|
227
|
+
|
|
228
|
+
open_settings_window(root, project_config)
|
|
229
|
+
|
|
230
|
+
root.destroy()
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### 4\. Generate Documentation and Default Config
|
|
234
|
+
|
|
235
|
+
Use the static methods on your `ProjectConfigManager` to generate `config.yaml`, `cli.md`, and `config.md` files.
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
# scripts/generate_docs.py (or similar script in your project)
|
|
239
|
+
from tests.example_project.config.config_example import ProjectConfigManager
|
|
240
|
+
from config_cli_gui.docs import DocumentationGenerator
|
|
241
|
+
import os
|
|
242
|
+
|
|
243
|
+
# Define output paths
|
|
244
|
+
output_dir = "docs/generated"
|
|
245
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
246
|
+
|
|
247
|
+
default_config = "config.yaml" # At the project root or similar
|
|
248
|
+
default_cli_doc = os.path.join(output_dir, "cli.md")
|
|
249
|
+
default_config_doc = os.path.join(output_dir, "config.md")
|
|
250
|
+
_config = ProjectConfigManager()
|
|
251
|
+
doc_gen = DocumentationGenerator(_config)
|
|
252
|
+
doc_gen.generate_default_config_file(output_file=default_config)
|
|
253
|
+
print(f"Generated: {default_config}")
|
|
254
|
+
|
|
255
|
+
doc_gen.generate_config_markdown_doc(output_file=default_config_doc)
|
|
256
|
+
print(f"Generated: {default_config_doc}")
|
|
257
|
+
|
|
258
|
+
doc_gen.generate_cli_markdown_doc(output_file=default_cli_doc)
|
|
259
|
+
print(f"Generated: {default_cli_doc}")
|
|
260
|
+
|
|
261
|
+
print("Documentation and default config generation complete.")
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
By following this structure, `config-cli-gui` provides a robust and maintainable foundation for your application's configuration needs.
|
|
@@ -45,7 +45,7 @@ misc:
|
|
|
45
45
|
- 255
|
|
46
46
|
- 0
|
|
47
47
|
- 0
|
|
48
|
-
# Date setting for the application | type=ConfigParameter, default=2025-06-23 18:58:
|
|
49
|
-
some_date: '2025-06-23T18:58:
|
|
48
|
+
# Date setting for the application | type=ConfigParameter, default=2025-06-23 18:58:00
|
|
49
|
+
some_date: '2025-06-23T18:58:00'
|
|
50
50
|
# Path to the file to use | type=ConfigParameter, default=some_file.txt
|
|
51
51
|
some_file: some_file.txt
|