dotenvmodel 0.1.1__tar.gz → 0.2.0__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.
- dotenvmodel-0.2.0/.release-please-manifest.json +3 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/CHANGELOG.md +7 -0
- dotenvmodel-0.2.0/CONTRIBUTING.md +381 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/PKG-INFO +294 -1
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/README.md +293 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/dotenvmodel/__init__.py +4 -1
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/dotenvmodel/config.py +127 -1
- dotenvmodel-0.2.0/dotenvmodel/describe.py +985 -0
- dotenvmodel-0.2.0/examples/describe_documentation.py +176 -0
- dotenvmodel-0.2.0/examples/generate_env_example.py +75 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/pyproject.toml +1 -1
- dotenvmodel-0.2.0/tests/test_describe.py +1696 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/uv.lock +1 -1
- dotenvmodel-0.1.1/.release-please-manifest.json +0 -3
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/.github/workflows/ci.yml +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/.github/workflows/publish.yml +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/.github/workflows/release-please.yml +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/.gitignore +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/.python-version +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/.vscode/settings.json +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/LICENSE +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/Makefile +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/dotenvmodel/coercion.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/dotenvmodel/exceptions.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/dotenvmodel/fields.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/dotenvmodel/loading.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/dotenvmodel/logging_config.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/dotenvmodel/py.typed +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/dotenvmodel/types.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/dotenvmodel/validation.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/examples/advanced_types.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/examples/basic_usage.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/examples/logging_example.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/release-please-config.json +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/__init__.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/conftest.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_basic.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_coercion.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_collection_validators.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_empty_collection_items.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_empty_strings.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_errors.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_field_constraints.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_inheritance.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_json.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_json_and_optional.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_loading.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_logging_config.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_prefix.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_reload.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_secretstr_security.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_types.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_union_types.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_url_dsn.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_url_password_decoding.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_url_unquote.py +0 -0
- {dotenvmodel-0.1.1 → dotenvmodel-0.2.0}/tests/test_urls.py +0 -0
|
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.0](https://github.com/AZX-PBC/dotenvmodel/compare/v0.1.1...v0.2.0) (2025-12-05)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add describe functionality for configuration classes and related tests ([#6](https://github.com/AZX-PBC/dotenvmodel/issues/6)) ([49767ea](https://github.com/AZX-PBC/dotenvmodel/commit/49767ea34e8216706a0071072cb92452890451f3))
|
|
14
|
+
|
|
8
15
|
## [0.1.1](https://github.com/AZX-PBC/dotenvmodel/compare/v0.1.0...v0.1.1) (2025-12-05)
|
|
9
16
|
|
|
10
17
|
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
# Contributing to dotenvmodel
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to dotenvmodel! We appreciate your time and effort in making this library better for everyone.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
### Prerequisites
|
|
8
|
+
|
|
9
|
+
- Python 3.12 or higher
|
|
10
|
+
- [uv](https://docs.astral.sh/uv/) - Fast Python package installer and resolver
|
|
11
|
+
|
|
12
|
+
### Getting Started
|
|
13
|
+
|
|
14
|
+
1. **Clone the repository:**
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/azxio/dotenvmodel.git
|
|
17
|
+
cd dotenvmodel
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
2. **Install dependencies:**
|
|
21
|
+
|
|
22
|
+
This project uses `uv` for dependency management. Install development dependencies with:
|
|
23
|
+
```bash
|
|
24
|
+
uv sync --dev
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This will create a virtual environment and install all necessary dependencies including pytest, mypy, ruff, and other development tools.
|
|
28
|
+
|
|
29
|
+
## Running Tests
|
|
30
|
+
|
|
31
|
+
**IMPORTANT: Always use `uv run` to execute pytest and other development commands.**
|
|
32
|
+
|
|
33
|
+
Using `uv run` ensures that:
|
|
34
|
+
- Commands run in the correct virtual environment
|
|
35
|
+
- All dependencies are properly resolved
|
|
36
|
+
- You're using the exact versions specified in the project
|
|
37
|
+
- No conflicts with globally installed packages
|
|
38
|
+
|
|
39
|
+
### Test Commands
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Run all tests
|
|
43
|
+
uv run pytest
|
|
44
|
+
|
|
45
|
+
# Run specific test file
|
|
46
|
+
uv run pytest tests/test_describe.py
|
|
47
|
+
|
|
48
|
+
# Run specific test class
|
|
49
|
+
uv run pytest tests/test_describe.py::TestLineEndings
|
|
50
|
+
|
|
51
|
+
# Run specific test function
|
|
52
|
+
uv run pytest tests/test_core.py::TestDotEnvConfig::test_load_from_dict
|
|
53
|
+
|
|
54
|
+
# Run with verbose output
|
|
55
|
+
uv run pytest -v
|
|
56
|
+
|
|
57
|
+
# Run with coverage report
|
|
58
|
+
uv run pytest --cov=dotenvmodel --cov-report=html
|
|
59
|
+
|
|
60
|
+
# Run tests matching a pattern
|
|
61
|
+
uv run pytest -k "test_validation"
|
|
62
|
+
|
|
63
|
+
# Run tests with output from print statements
|
|
64
|
+
uv run pytest -s
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Understanding Test Output
|
|
68
|
+
|
|
69
|
+
The project is configured with the following pytest settings (in `pyproject.toml`):
|
|
70
|
+
- Coverage is automatically collected for the `dotenvmodel` package
|
|
71
|
+
- HTML coverage reports are generated in `htmlcov/`
|
|
72
|
+
- Tests must maintain at least 95% code coverage
|
|
73
|
+
- Coverage reports exclude test files and implementation details
|
|
74
|
+
|
|
75
|
+
## Code Quality
|
|
76
|
+
|
|
77
|
+
### Type Checking
|
|
78
|
+
|
|
79
|
+
The project uses `ty` (a wrapper around pyright) for type checking:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Run type checking
|
|
83
|
+
uv run ty check
|
|
84
|
+
|
|
85
|
+
# Type check specific file
|
|
86
|
+
uv run ty check dotenvmodel/core.py
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Linting and Formatting
|
|
90
|
+
|
|
91
|
+
The project uses `ruff` for both linting and formatting:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Check for linting issues
|
|
95
|
+
uv run ruff check dotenvmodel
|
|
96
|
+
|
|
97
|
+
# Auto-fix linting issues
|
|
98
|
+
uv run ruff check --fix dotenvmodel
|
|
99
|
+
|
|
100
|
+
# Format code
|
|
101
|
+
uv run ruff format dotenvmodel
|
|
102
|
+
|
|
103
|
+
# Check formatting without making changes
|
|
104
|
+
uv run ruff format --check dotenvmodel
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Running All Quality Checks
|
|
108
|
+
|
|
109
|
+
Before submitting a PR, run all quality checks:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Run tests with coverage
|
|
113
|
+
uv run pytest
|
|
114
|
+
|
|
115
|
+
# Run type checking
|
|
116
|
+
uv run ty check
|
|
117
|
+
|
|
118
|
+
# Run linting
|
|
119
|
+
uv run ruff check dotenvmodel
|
|
120
|
+
|
|
121
|
+
# Check formatting
|
|
122
|
+
uv run ruff format --check dotenvmodel
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Making Changes
|
|
126
|
+
|
|
127
|
+
### Workflow
|
|
128
|
+
|
|
129
|
+
1. **Create a feature branch:**
|
|
130
|
+
```bash
|
|
131
|
+
git checkout -b feat/your-feature-name
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Or for bug fixes:
|
|
135
|
+
```bash
|
|
136
|
+
git checkout -b fix/bug-description
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
2. **Make your changes:**
|
|
140
|
+
- Write clear, readable code
|
|
141
|
+
- Follow existing code patterns and conventions
|
|
142
|
+
- Add type hints to all functions and methods
|
|
143
|
+
- Keep functions focused and modular
|
|
144
|
+
|
|
145
|
+
3. **Write tests:**
|
|
146
|
+
- Add tests for all new functionality
|
|
147
|
+
- Update existing tests if modifying behavior
|
|
148
|
+
- Ensure tests are clear and well-documented
|
|
149
|
+
- Test edge cases and error conditions
|
|
150
|
+
- Run tests with `uv run pytest`
|
|
151
|
+
|
|
152
|
+
4. **Update documentation:**
|
|
153
|
+
- Update README.md if adding new features
|
|
154
|
+
- Add docstrings to new functions and classes
|
|
155
|
+
- Update type hints and examples
|
|
156
|
+
|
|
157
|
+
5. **Verify your changes:**
|
|
158
|
+
```bash
|
|
159
|
+
# Run all tests
|
|
160
|
+
uv run pytest
|
|
161
|
+
|
|
162
|
+
# Check types
|
|
163
|
+
uv run ty check
|
|
164
|
+
|
|
165
|
+
# Check linting
|
|
166
|
+
uv run ruff check dotenvmodel
|
|
167
|
+
|
|
168
|
+
# Check formatting
|
|
169
|
+
uv run ruff format --check dotenvmodel
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Pull Request Process
|
|
173
|
+
|
|
174
|
+
### Before Submitting
|
|
175
|
+
|
|
176
|
+
1. **Ensure all tests pass:**
|
|
177
|
+
```bash
|
|
178
|
+
uv run pytest
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
2. **Ensure type checking passes:**
|
|
182
|
+
```bash
|
|
183
|
+
uv run ty check
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
3. **Ensure code is properly formatted:**
|
|
187
|
+
```bash
|
|
188
|
+
uv run ruff format dotenvmodel
|
|
189
|
+
uv run ruff check --fix dotenvmodel
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
4. **Verify coverage hasn't decreased:**
|
|
193
|
+
```bash
|
|
194
|
+
uv run pytest --cov=dotenvmodel --cov-report=term-missing
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Coverage should remain at or above 95%.
|
|
198
|
+
|
|
199
|
+
### Submitting Your PR
|
|
200
|
+
|
|
201
|
+
1. **Push your branch:**
|
|
202
|
+
```bash
|
|
203
|
+
git push origin feat/your-feature-name
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
2. **Create a pull request on GitHub**
|
|
207
|
+
|
|
208
|
+
3. **In your PR description:**
|
|
209
|
+
- Clearly describe what changes you made
|
|
210
|
+
- Explain why the changes are needed
|
|
211
|
+
- Reference any related issues
|
|
212
|
+
- Include examples of new functionality (if applicable)
|
|
213
|
+
- List any breaking changes
|
|
214
|
+
|
|
215
|
+
### PR Description Template
|
|
216
|
+
|
|
217
|
+
```markdown
|
|
218
|
+
## Summary
|
|
219
|
+
Brief description of what this PR does
|
|
220
|
+
|
|
221
|
+
## Changes
|
|
222
|
+
- Change 1
|
|
223
|
+
- Change 2
|
|
224
|
+
- Change 3
|
|
225
|
+
|
|
226
|
+
## Testing
|
|
227
|
+
Describe how you tested these changes
|
|
228
|
+
|
|
229
|
+
## Related Issues
|
|
230
|
+
Fixes #123
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Code Review
|
|
234
|
+
|
|
235
|
+
### What to Expect
|
|
236
|
+
|
|
237
|
+
- All changes must pass automated tests and type checking
|
|
238
|
+
- Code reviewers will check for:
|
|
239
|
+
- Implementation correctness
|
|
240
|
+
- Code clarity and maintainability
|
|
241
|
+
- Adequate test coverage
|
|
242
|
+
- Documentation completeness
|
|
243
|
+
- Adherence to project conventions
|
|
244
|
+
|
|
245
|
+
- You may be asked to make revisions
|
|
246
|
+
- Reviews are constructive - they help improve code quality
|
|
247
|
+
|
|
248
|
+
### Addressing Feedback
|
|
249
|
+
|
|
250
|
+
When reviewers request changes:
|
|
251
|
+
|
|
252
|
+
1. Make the requested changes in your branch
|
|
253
|
+
2. Run tests again: `uv run pytest`
|
|
254
|
+
3. Push the updates: `git push origin feat/your-feature-name`
|
|
255
|
+
4. Respond to reviewer comments
|
|
256
|
+
|
|
257
|
+
## Development Tips
|
|
258
|
+
|
|
259
|
+
### Virtual Environment
|
|
260
|
+
|
|
261
|
+
The `uv run` command automatically manages the virtual environment. You don't need to manually activate it.
|
|
262
|
+
|
|
263
|
+
If you prefer to activate the environment manually:
|
|
264
|
+
```bash
|
|
265
|
+
# uv creates a .venv directory
|
|
266
|
+
source .venv/bin/activate # Linux/macOS
|
|
267
|
+
# or
|
|
268
|
+
.venv\Scripts\activate # Windows
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
However, we recommend using `uv run` for consistency.
|
|
272
|
+
|
|
273
|
+
### Interactive Testing
|
|
274
|
+
|
|
275
|
+
You can use `uv run python` to start a Python interpreter with the correct environment:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
uv run python
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Then test your changes interactively:
|
|
282
|
+
```python
|
|
283
|
+
from dotenvmodel import DotEnvConfig, Field
|
|
284
|
+
|
|
285
|
+
class TestConfig(DotEnvConfig):
|
|
286
|
+
value: str = Field()
|
|
287
|
+
|
|
288
|
+
config = TestConfig.load_from_dict({"value": "test"})
|
|
289
|
+
print(config.value)
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Debugging Tests
|
|
293
|
+
|
|
294
|
+
To debug a specific test with pdb:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
# Add breakpoint() in your test or code
|
|
298
|
+
# Then run with -s to see output
|
|
299
|
+
uv run pytest -s tests/test_describe.py::test_specific_function
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Coverage Reports
|
|
303
|
+
|
|
304
|
+
After running tests with coverage, view the HTML report:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
uv run pytest --cov=dotenvmodel --cov-report=html
|
|
308
|
+
# Open htmlcov/index.html in your browser
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Code Style Guidelines
|
|
312
|
+
|
|
313
|
+
### General Principles
|
|
314
|
+
|
|
315
|
+
- Write clear, self-documenting code
|
|
316
|
+
- Use meaningful variable and function names
|
|
317
|
+
- Keep functions short and focused (ideally under 50 lines)
|
|
318
|
+
- Avoid deep nesting (max 3-4 levels)
|
|
319
|
+
- Comments should explain "why", not "what"
|
|
320
|
+
|
|
321
|
+
### Type Hints
|
|
322
|
+
|
|
323
|
+
Always use type hints:
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
# Good
|
|
327
|
+
def process_value(value: str, default: int = 0) -> int:
|
|
328
|
+
return int(value) if value else default
|
|
329
|
+
|
|
330
|
+
# Bad
|
|
331
|
+
def process_value(value, default=0):
|
|
332
|
+
return int(value) if value else default
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Docstrings
|
|
336
|
+
|
|
337
|
+
Use clear docstrings for public APIs:
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
def describe(cls, format: str = "table") -> str:
|
|
341
|
+
"""Generate documentation for the configuration class.
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
format: Output format - "table", "markdown", "json", "html", or "dotenv"
|
|
345
|
+
|
|
346
|
+
Returns:
|
|
347
|
+
Formatted documentation string
|
|
348
|
+
|
|
349
|
+
Raises:
|
|
350
|
+
ValueError: If format is not supported
|
|
351
|
+
"""
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Error Messages
|
|
355
|
+
|
|
356
|
+
Write helpful error messages:
|
|
357
|
+
|
|
358
|
+
```python
|
|
359
|
+
# Good
|
|
360
|
+
raise ValueError(
|
|
361
|
+
f"Invalid format '{format}'. "
|
|
362
|
+
f"Supported formats: table, markdown, json, html, dotenv"
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
# Bad
|
|
366
|
+
raise ValueError("Invalid format")
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Getting Help
|
|
370
|
+
|
|
371
|
+
- **Questions?** Open a [GitHub Discussion](https://github.com/azxio/dotenvmodel/discussions)
|
|
372
|
+
- **Bug Reports?** Open an [Issue](https://github.com/azxio/dotenvmodel/issues)
|
|
373
|
+
- **Feature Requests?** Open an [Issue](https://github.com/azxio/dotenvmodel/issues) with the `enhancement` label
|
|
374
|
+
|
|
375
|
+
## License
|
|
376
|
+
|
|
377
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
|
378
|
+
|
|
379
|
+
## Thank You!
|
|
380
|
+
|
|
381
|
+
Your contributions help make dotenvmodel better for everyone. We appreciate your time and effort!
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dotenvmodel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Type-safe environment configuration with automatic .env file loading
|
|
5
5
|
Project-URL: Homepage, https://github.com/AZX-PBC/dotenvmodel
|
|
6
6
|
Project-URL: Repository, https://github.com/AZX-PBC/dotenvmodel
|
|
@@ -42,6 +42,9 @@ Description-Content-Type: text/markdown
|
|
|
42
42
|
- **Developer Experience**: Intuitive Pydantic-style API
|
|
43
43
|
- **Smart .env Loading**: Automatic cascading of `.env`, `.env.{env}`, `.env.{env}.local` files
|
|
44
44
|
- **Configuration Reload**: Reload configuration at runtime without creating new instances
|
|
45
|
+
- **Configuration Documentation**: Generate docs in multiple formats (table, markdown, JSON, HTML, dotenv) with `describe()`
|
|
46
|
+
- **.env.example Generation**: Automatically generate `.env.example` files with type hints, constraints, and examples
|
|
47
|
+
- **File Export**: Save documentation directly to files for integration with build tools and wikis
|
|
45
48
|
- **Environment Prefixes**: Class-level `env_prefix` to namespace environment variables
|
|
46
49
|
- **Validation**: Numeric constraints (ge, le, gt, lt), string constraints (min_length, max_length, regex), choice validation, and collection size constraints (min_items, max_items)
|
|
47
50
|
- **Clear Error Messages**: Helpful validation errors that guide you to fixes
|
|
@@ -85,6 +88,9 @@ config = AppConfig.load(env="dev")
|
|
|
85
88
|
print(f"Connecting to {config.database_url}") # config.database_url: str
|
|
86
89
|
print(f"Running on port {config.port}") # config.port: int
|
|
87
90
|
print(f"Debug mode: {config.debug}") # config.debug: bool
|
|
91
|
+
|
|
92
|
+
# Generate documentation for your configuration
|
|
93
|
+
print(AppConfig.describe())
|
|
88
94
|
```
|
|
89
95
|
|
|
90
96
|
## Type Safety and IntelliSense
|
|
@@ -650,6 +656,293 @@ The `reload()` method:
|
|
|
650
656
|
- Validates all fields and raises errors if validation fails
|
|
651
657
|
- Returns the same instance (useful for method chaining)
|
|
652
658
|
|
|
659
|
+
## Configuration Documentation
|
|
660
|
+
|
|
661
|
+
Generate human-readable documentation for your configuration classes using the `describe()` method. This is useful for:
|
|
662
|
+
|
|
663
|
+
- **Creating documentation** for your team
|
|
664
|
+
- **Generating `.env.example` files** automatically
|
|
665
|
+
- **Validating configuration** in CI pipelines
|
|
666
|
+
- **Onboarding new developers** quickly
|
|
667
|
+
|
|
668
|
+
### Generate Documentation for a Single Config
|
|
669
|
+
|
|
670
|
+
```python
|
|
671
|
+
from dotenvmodel import DotEnvConfig, Field
|
|
672
|
+
|
|
673
|
+
class AppConfig(DotEnvConfig):
|
|
674
|
+
database_url: str = Field(description="PostgreSQL connection string")
|
|
675
|
+
port: int = Field(default=8000, ge=1, le=65535, description="Server port")
|
|
676
|
+
debug: bool = Field(default=False, description="Enable debug mode")
|
|
677
|
+
workers: int = Field(default=4, ge=1, le=16, description="Number of worker processes")
|
|
678
|
+
|
|
679
|
+
# Generate ASCII table (default)
|
|
680
|
+
print(AppConfig.describe())
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
Output:
|
|
684
|
+
|
|
685
|
+
```
|
|
686
|
+
AppConfig
|
|
687
|
+
=========
|
|
688
|
+
+--------------+------+----------+---------+---------------------------+----------------+
|
|
689
|
+
| ENV Variable | Type | Required | Default | Description | Constraints |
|
|
690
|
+
+--------------+------+----------+---------+---------------------------+----------------+
|
|
691
|
+
| DATABASE_URL | str | Yes | - | PostgreSQL connection ... | - |
|
|
692
|
+
| PORT | int | No | 8000 | Server port | ge=1, le=65535 |
|
|
693
|
+
| DEBUG | bool | No | False | Enable debug mode | - |
|
|
694
|
+
| WORKERS | int | No | 4 | Number of worker proces...| ge=1, le=16 |
|
|
695
|
+
+--------------+------+----------+---------+---------------------------+----------------+
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
### Output Formats
|
|
699
|
+
|
|
700
|
+
**ASCII Table (default)** - Best for terminal output and logging:
|
|
701
|
+
|
|
702
|
+
```python
|
|
703
|
+
print(AppConfig.describe(output_format="table"))
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
**Markdown** - Perfect for README files and documentation:
|
|
707
|
+
|
|
708
|
+
```python
|
|
709
|
+
# Generate markdown documentation
|
|
710
|
+
docs = AppConfig.describe(output_format="markdown")
|
|
711
|
+
|
|
712
|
+
# Save to file
|
|
713
|
+
with open("CONFIG.md", "w") as f:
|
|
714
|
+
f.write(docs)
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
**JSON** - Ideal for CI validation and programmatic processing:
|
|
718
|
+
|
|
719
|
+
```python
|
|
720
|
+
import json
|
|
721
|
+
|
|
722
|
+
# Get configuration schema as JSON
|
|
723
|
+
config_spec = AppConfig.describe(output_format="json")
|
|
724
|
+
data = json.loads(config_spec)
|
|
725
|
+
|
|
726
|
+
# Use for validation, code generation, etc.
|
|
727
|
+
print(data["class_name"]) # "AppConfig"
|
|
728
|
+
print(data["fields"][0]["env_var"]) # "DATABASE_URL"
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
**HTML** - Styled output for web documentation:
|
|
732
|
+
|
|
733
|
+
```python
|
|
734
|
+
# Generate HTML with styled tables
|
|
735
|
+
html_docs = AppConfig.describe(output_format="html")
|
|
736
|
+
|
|
737
|
+
# Save to file
|
|
738
|
+
with open("config.html", "w") as f:
|
|
739
|
+
f.write(html_docs)
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
**Dotenv Format** - For generating `.env.example` files:
|
|
743
|
+
|
|
744
|
+
```python
|
|
745
|
+
# Generate .env.example format
|
|
746
|
+
dotenv_docs = AppConfig.describe(output_format="dotenv")
|
|
747
|
+
print(dotenv_docs)
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
### File Export
|
|
751
|
+
|
|
752
|
+
Save documentation directly to files using the `output` parameter:
|
|
753
|
+
|
|
754
|
+
```python
|
|
755
|
+
# Save as markdown
|
|
756
|
+
AppConfig.describe(output_format="markdown", output="docs/config.md")
|
|
757
|
+
|
|
758
|
+
# Save as HTML
|
|
759
|
+
AppConfig.describe(output_format="html", output="docs/config.html")
|
|
760
|
+
|
|
761
|
+
# Save as JSON
|
|
762
|
+
AppConfig.describe(output_format="json", output="config-schema.json")
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
### Generate `.env.example` Files
|
|
766
|
+
|
|
767
|
+
Automatically generate `.env.example` files for onboarding new developers:
|
|
768
|
+
|
|
769
|
+
```python
|
|
770
|
+
from dotenvmodel import DotEnvConfig, Field, SecretStr
|
|
771
|
+
|
|
772
|
+
class AppConfig(DotEnvConfig):
|
|
773
|
+
env_prefix = "APP_"
|
|
774
|
+
|
|
775
|
+
api_key: str = Field(
|
|
776
|
+
min_length=32,
|
|
777
|
+
max_length=64,
|
|
778
|
+
description="API key for external service"
|
|
779
|
+
)
|
|
780
|
+
port: int = Field(
|
|
781
|
+
default=8000,
|
|
782
|
+
ge=1,
|
|
783
|
+
le=65535,
|
|
784
|
+
description="Server port number"
|
|
785
|
+
)
|
|
786
|
+
database_password: SecretStr = Field(
|
|
787
|
+
default=SecretStr("change_me_in_production"),
|
|
788
|
+
min_length=8,
|
|
789
|
+
description="Database connection password"
|
|
790
|
+
)
|
|
791
|
+
allowed_hosts: list[str] = Field(
|
|
792
|
+
default_factory=list,
|
|
793
|
+
separator=";",
|
|
794
|
+
min_items=1,
|
|
795
|
+
max_items=10,
|
|
796
|
+
description="Allowed hostnames for CORS"
|
|
797
|
+
)
|
|
798
|
+
|
|
799
|
+
# Generate and print .env.example
|
|
800
|
+
print(AppConfig.generate_env_example())
|
|
801
|
+
|
|
802
|
+
# Or save directly to file
|
|
803
|
+
AppConfig.generate_env_example(output=".env.example")
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
Output in `.env.example`:
|
|
807
|
+
|
|
808
|
+
```bash
|
|
809
|
+
# Configuration for AppConfig
|
|
810
|
+
# All variables prefixed with: APP_
|
|
811
|
+
|
|
812
|
+
# API key for external service
|
|
813
|
+
# Type: str | Constraints: min_length=32, max_length=64
|
|
814
|
+
# Example: APP_API_KEY=your_value_here
|
|
815
|
+
APP_API_KEY=
|
|
816
|
+
|
|
817
|
+
# Server port number
|
|
818
|
+
# Type: int | Constraints: ge=1, le=65535
|
|
819
|
+
# Example: APP_PORT=8000
|
|
820
|
+
# APP_PORT=8000
|
|
821
|
+
|
|
822
|
+
# Database connection password
|
|
823
|
+
# Type: SecretStr | Constraints: min_length=8
|
|
824
|
+
# APP_DATABASE_PASSWORD=your_secret_here
|
|
825
|
+
|
|
826
|
+
# Allowed hostnames for CORS
|
|
827
|
+
# Type: list[str] | Constraints: min_items=1, max_items=10, separator=';'
|
|
828
|
+
# Example: APP_ALLOWED_HOSTS=[]
|
|
829
|
+
# APP_ALLOWED_HOSTS=[]
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
The `.env.example` file includes:
|
|
833
|
+
|
|
834
|
+
- **Type information** - Shows the expected Python type
|
|
835
|
+
- **Parsing hints** - Explains how to format complex types (e.g., "comma-separated values" for lists)
|
|
836
|
+
- **Constraints** - Documents validation rules (min/max length, numeric ranges, etc.)
|
|
837
|
+
- **Examples** - Shows example values for required fields
|
|
838
|
+
- **Commented defaults** - Optional fields are commented out with their default values
|
|
839
|
+
- **Secret handling** - SecretStr fields are masked appropriately
|
|
840
|
+
|
|
841
|
+
### Document Multiple Configurations
|
|
842
|
+
|
|
843
|
+
Use `describe_configs()` to document multiple related configuration classes:
|
|
844
|
+
|
|
845
|
+
```python
|
|
846
|
+
from dotenvmodel import DotEnvConfig, Field, describe_configs
|
|
847
|
+
|
|
848
|
+
class DatabaseConfig(DotEnvConfig):
|
|
849
|
+
env_prefix = "DB_"
|
|
850
|
+
host: str = Field(description="Database host")
|
|
851
|
+
port: int = Field(default=5432, description="Database port")
|
|
852
|
+
|
|
853
|
+
class RedisConfig(DotEnvConfig):
|
|
854
|
+
env_prefix = "REDIS_"
|
|
855
|
+
host: str = Field(description="Redis host")
|
|
856
|
+
port: int = Field(default=6379, description="Redis port")
|
|
857
|
+
|
|
858
|
+
# Generate documentation for all configs
|
|
859
|
+
all_docs = describe_configs([DatabaseConfig, RedisConfig], output_format="markdown")
|
|
860
|
+
print(all_docs)
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
### Practical Use Cases
|
|
864
|
+
|
|
865
|
+
**1. Generate `.env.example` files for onboarding:**
|
|
866
|
+
|
|
867
|
+
```python
|
|
868
|
+
# Generate .env.example with helpful comments and type information
|
|
869
|
+
AppConfig.generate_env_example(output=".env.example")
|
|
870
|
+
|
|
871
|
+
# Or combine multiple configs
|
|
872
|
+
from dotenvmodel import describe_configs
|
|
873
|
+
|
|
874
|
+
with open(".env.example", "w") as f:
|
|
875
|
+
f.write("# Application Configuration\n\n")
|
|
876
|
+
f.write("# Copy this file to .env and fill in the values\n\n")
|
|
877
|
+
for config_cls in [AppConfig, DatabaseConfig, RedisConfig]:
|
|
878
|
+
f.write(config_cls.generate_env_example())
|
|
879
|
+
f.write("\n\n")
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
**2. CI Configuration Validation:**
|
|
883
|
+
|
|
884
|
+
```python
|
|
885
|
+
import json
|
|
886
|
+
import os
|
|
887
|
+
|
|
888
|
+
# Get required environment variables from config schema
|
|
889
|
+
spec = json.loads(AppConfig.describe(output_format="json"))
|
|
890
|
+
required_vars = [f["env_var"] for f in spec["fields"] if f["required"]]
|
|
891
|
+
|
|
892
|
+
# Validate all required vars are set
|
|
893
|
+
missing = [var for var in required_vars if var not in os.environ]
|
|
894
|
+
if missing:
|
|
895
|
+
print(f"ERROR: Missing required environment variables: {', '.join(missing)}")
|
|
896
|
+
exit(1)
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
**3. Developer Onboarding:**
|
|
900
|
+
|
|
901
|
+
```python
|
|
902
|
+
import os
|
|
903
|
+
|
|
904
|
+
# Display configuration reference in development mode
|
|
905
|
+
if os.getenv("ENV") == "dev":
|
|
906
|
+
print("\n" + "=" * 80)
|
|
907
|
+
print("CONFIGURATION REFERENCE")
|
|
908
|
+
print("=" * 80)
|
|
909
|
+
print(AppConfig.describe())
|
|
910
|
+
print("=" * 80 + "\n")
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
**4. Generate Documentation Website:**
|
|
914
|
+
|
|
915
|
+
```python
|
|
916
|
+
from dotenvmodel import describe_configs
|
|
917
|
+
|
|
918
|
+
# Generate markdown docs for all config classes
|
|
919
|
+
configs = [AppConfig, DatabaseConfig, RedisConfig, CacheConfig]
|
|
920
|
+
|
|
921
|
+
# Save as markdown
|
|
922
|
+
describe_configs(configs, output_format="markdown", output="docs/configuration.md")
|
|
923
|
+
|
|
924
|
+
# Or generate HTML version with styling
|
|
925
|
+
describe_configs(configs, output_format="html", output="docs/configuration.html")
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
**5. Build Tool Integration:**
|
|
929
|
+
|
|
930
|
+
```python
|
|
931
|
+
# build_docs.py - Run during build process
|
|
932
|
+
from your_app.config import AppConfig, DatabaseConfig
|
|
933
|
+
|
|
934
|
+
# Generate .env.example for repository
|
|
935
|
+
AppConfig.generate_env_example(output=".env.example")
|
|
936
|
+
|
|
937
|
+
# Generate markdown docs
|
|
938
|
+
AppConfig.describe(output_format="markdown", output="docs/CONFIG.md")
|
|
939
|
+
|
|
940
|
+
# Generate HTML for internal wiki
|
|
941
|
+
AppConfig.describe(output_format="html", output="docs/config.html")
|
|
942
|
+
|
|
943
|
+
print("✓ Configuration documentation generated")
|
|
944
|
+
```
|
|
945
|
+
|
|
653
946
|
## Environment Variable Prefixes
|
|
654
947
|
|
|
655
948
|
Use class-level prefixes to namespace environment variables:
|