pydantic-settings-manager 0.1.2__tar.gz → 0.2.2__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.
- pydantic_settings_manager-0.2.2/.github/workflows/ci.yml +55 -0
- pydantic_settings_manager-0.2.2/.gitignore +14 -0
- pydantic_settings_manager-0.2.2/CHANGELOG.md +65 -0
- pydantic_settings_manager-0.2.2/Makefile +30 -0
- pydantic_settings_manager-0.2.2/PKG-INFO +372 -0
- pydantic_settings_manager-0.2.2/README.md +346 -0
- pydantic_settings_manager-0.2.2/mypy.ini +9 -0
- {pydantic_settings_manager-0.1.2 → pydantic_settings_manager-0.2.2}/pydantic_settings_manager/__init__.py +4 -4
- {pydantic_settings_manager-0.1.2 → pydantic_settings_manager-0.2.2}/pydantic_settings_manager/base.py +3 -3
- {pydantic_settings_manager-0.1.2 → pydantic_settings_manager-0.2.2}/pydantic_settings_manager/mapped.py +10 -10
- {pydantic_settings_manager-0.1.2 → pydantic_settings_manager-0.2.2}/pydantic_settings_manager/single.py +4 -4
- pydantic_settings_manager-0.2.2/pydantic_settings_manager/types.py +7 -0
- {pydantic_settings_manager-0.1.2 → pydantic_settings_manager-0.2.2}/pydantic_settings_manager/utils.py +3 -3
- {pydantic_settings_manager-0.1.2 → pydantic_settings_manager-0.2.2}/pyproject.toml +52 -36
- pydantic_settings_manager-0.2.2/tests/__init__.py +0 -0
- pydantic_settings_manager-0.2.2/tests/test_mapped.py +164 -0
- pydantic_settings_manager-0.2.2/tests/test_single.py +68 -0
- pydantic_settings_manager-0.2.2/tests/test_utils.py +65 -0
- pydantic_settings_manager-0.2.2/uv.lock +522 -0
- pydantic_settings_manager-0.1.2/PKG-INFO +0 -119
- pydantic_settings_manager-0.1.2/README.md +0 -90
- pydantic_settings_manager-0.1.2/pydantic_settings_manager/types.py +0 -6
- {pydantic_settings_manager-0.1.2 → pydantic_settings_manager-0.2.2}/LICENSE +0 -0
- {pydantic_settings_manager-0.1.2 → pydantic_settings_manager-0.2.2}/pydantic_settings_manager/py.typed +0 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ main ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ main ]
|
8
|
+
release:
|
9
|
+
types: [created]
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
test:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
strategy:
|
15
|
+
matrix:
|
16
|
+
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
17
|
+
|
18
|
+
steps:
|
19
|
+
- uses: actions/checkout@v4
|
20
|
+
- name: Install uv
|
21
|
+
uses: astral-sh/setup-uv@v4
|
22
|
+
with:
|
23
|
+
version: "latest"
|
24
|
+
- name: Set up Python ${{ matrix.python-version }}
|
25
|
+
run: uv python install ${{ matrix.python-version }}
|
26
|
+
- name: Install dependencies
|
27
|
+
run: uv sync --dev
|
28
|
+
- name: Run tests
|
29
|
+
run: uv run make test
|
30
|
+
- name: Run format check
|
31
|
+
run: uv run ruff check .
|
32
|
+
- name: Run linters
|
33
|
+
run: uv run make lint
|
34
|
+
|
35
|
+
publish:
|
36
|
+
needs: test
|
37
|
+
runs-on: ubuntu-latest
|
38
|
+
if: github.event_name == 'release' && github.event.action == 'created'
|
39
|
+
|
40
|
+
steps:
|
41
|
+
- uses: actions/checkout@v4
|
42
|
+
- name: Install uv
|
43
|
+
uses: astral-sh/setup-uv@v4
|
44
|
+
with:
|
45
|
+
version: "latest"
|
46
|
+
- name: Set up Python
|
47
|
+
run: uv python install 3.9
|
48
|
+
- name: Install dependencies
|
49
|
+
run: uv sync --dev
|
50
|
+
- name: Build and publish
|
51
|
+
env:
|
52
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
|
53
|
+
run: |
|
54
|
+
uv build
|
55
|
+
uv publish
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
|
7
|
+
## [0.2.2] - 2025-06-28
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- Version bump: 0.2.1 → 0.2.2
|
11
|
+
- Internal version sync in __init__.py
|
12
|
+
- docs: add section on pydantic-config-builder in README
|
13
|
+
|
14
|
+
|
15
|
+
## [0.2.1] - 2025-06-28
|
16
|
+
|
17
|
+
### Changed
|
18
|
+
- Version bump: 0.2.0 → 0.2.1
|
19
|
+
- Internal version sync in __init__.py
|
20
|
+
|
21
|
+
## [0.2.0] - 2025-06-28
|
22
|
+
|
23
|
+
### Changed
|
24
|
+
- **BREAKING**: Migrated from Poetry to uv for dependency management
|
25
|
+
- Modernized development toolchain with unified linting using ruff
|
26
|
+
- Updated to use PEP 621 compliant project metadata format
|
27
|
+
- Introduced PEP 735 dependency groups for flexible development environments
|
28
|
+
- Enhanced CI/CD pipeline to use uv instead of Poetry
|
29
|
+
- Improved type checking configuration with stricter MyPy settings
|
30
|
+
- Updated all development dependencies to latest versions
|
31
|
+
|
32
|
+
### Added
|
33
|
+
- Comprehensive development documentation in README
|
34
|
+
- Support for modular dependency groups (test, lint, dev)
|
35
|
+
- Enhanced linting rules including pyupgrade and flake8-comprehensions
|
36
|
+
- Migration guide for developers updating their local environment
|
37
|
+
|
38
|
+
### Removed
|
39
|
+
- Poetry configuration files (poetry.lock, pyproject.toml Poetry sections)
|
40
|
+
- Separate black, isort, and flake8 configurations (replaced by ruff)
|
41
|
+
|
42
|
+
## [0.1.2] - 2024-03-12
|
43
|
+
|
44
|
+
### Added
|
45
|
+
- Added py.typed file for better type checking support
|
46
|
+
- Improved package configuration and build process
|
47
|
+
|
48
|
+
## [0.1.1] - 2024-03-12
|
49
|
+
|
50
|
+
### Added
|
51
|
+
- Added detailed documentation in README.md
|
52
|
+
- Added example code for both SingleSettingsManager and MappedSettingsManager
|
53
|
+
|
54
|
+
### Fixed
|
55
|
+
- Improved type hints and documentation
|
56
|
+
|
57
|
+
## [0.1.0] - 2024-03-11
|
58
|
+
|
59
|
+
### Added
|
60
|
+
- Initial release
|
61
|
+
- Implemented SingleSettingsManager for managing single settings object
|
62
|
+
- Implemented MappedSettingsManager for managing multiple settings objects
|
63
|
+
- Support for loading settings from multiple sources
|
64
|
+
- Command line argument overrides
|
65
|
+
- Settings validation through Pydantic
|
@@ -0,0 +1,30 @@
|
|
1
|
+
.PHONY: format lint test clean build publish
|
2
|
+
.DEFAULT_GOAL := build
|
3
|
+
|
4
|
+
format:
|
5
|
+
uv run ruff check --fix .
|
6
|
+
|
7
|
+
lint:
|
8
|
+
uv run ruff check .
|
9
|
+
uv run mypy .
|
10
|
+
|
11
|
+
test:
|
12
|
+
uv run pytest --cov=pydantic_settings_manager tests/
|
13
|
+
|
14
|
+
clean:
|
15
|
+
rm -rf dist/
|
16
|
+
rm -rf *.egg-info/
|
17
|
+
find . -type d -name __pycache__ -exec rm -rf {} +
|
18
|
+
find . -type f -name "*.pyc" -delete
|
19
|
+
find . -type f -name "*.pyo" -delete
|
20
|
+
find . -type f -name "*.pyd" -delete
|
21
|
+
find . -type f -name ".coverage" -delete
|
22
|
+
find . -type d -name ".pytest_cache" -exec rm -rf {} +
|
23
|
+
find . -type d -name ".mypy_cache" -exec rm -rf {} +
|
24
|
+
find . -type d -name ".ruff_cache" -exec rm -rf {} +
|
25
|
+
|
26
|
+
build: format lint test clean
|
27
|
+
uv build
|
28
|
+
|
29
|
+
publish: build
|
30
|
+
uv publish
|
@@ -0,0 +1,372 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: pydantic-settings-manager
|
3
|
+
Version: 0.2.2
|
4
|
+
Summary: A library for managing Pydantic settings objects
|
5
|
+
Project-URL: homepage, https://github.com/kiarina/pydantic-settings-manager
|
6
|
+
Project-URL: repository, https://github.com/kiarina/pydantic-settings-manager
|
7
|
+
Project-URL: documentation, https://github.com/kiarina/pydantic-settings-manager
|
8
|
+
Author-email: kiarina <kiarinadawa@gmail.com>
|
9
|
+
License: MIT
|
10
|
+
License-File: LICENSE
|
11
|
+
Keywords: configuration,pydantic,settings
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
13
|
+
Classifier: Intended Audience :: Developers
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
15
|
+
Classifier: Operating System :: OS Independent
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
22
|
+
Requires-Python: >=3.9
|
23
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
25
|
+
Description-Content-Type: text/markdown
|
26
|
+
|
27
|
+
# pydantic-settings-manager
|
28
|
+
|
29
|
+
A library for managing Pydantic settings objects.
|
30
|
+
|
31
|
+
## Features
|
32
|
+
|
33
|
+
- Two types of settings managers:
|
34
|
+
- `SingleSettingsManager`: For managing a single settings object
|
35
|
+
- `MappedSettingsManager`: For managing multiple settings objects mapped to keys
|
36
|
+
- Support for loading settings from multiple sources
|
37
|
+
- Command line argument overrides
|
38
|
+
- Settings validation through Pydantic
|
39
|
+
- Type hints and documentation
|
40
|
+
|
41
|
+
## Installation
|
42
|
+
|
43
|
+
```bash
|
44
|
+
pip install pydantic-settings-manager
|
45
|
+
```
|
46
|
+
|
47
|
+
## Quick Start
|
48
|
+
|
49
|
+
### Basic Usage
|
50
|
+
|
51
|
+
Let's start with a simple example you can try immediately:
|
52
|
+
|
53
|
+
```python
|
54
|
+
from pydantic_settings import BaseSettings
|
55
|
+
from pydantic_settings_manager import SingleSettingsManager
|
56
|
+
|
57
|
+
# 1. Define your settings
|
58
|
+
class AppSettings(BaseSettings):
|
59
|
+
app_name: str = "MyApp"
|
60
|
+
debug: bool = False
|
61
|
+
max_connections: int = 100
|
62
|
+
|
63
|
+
# 2. Create a settings manager
|
64
|
+
settings_manager = SingleSettingsManager(AppSettings)
|
65
|
+
|
66
|
+
# 3. Use your settings
|
67
|
+
settings = settings_manager.settings
|
68
|
+
print(f"App: {settings.app_name}, Debug: {settings.debug}")
|
69
|
+
```
|
70
|
+
|
71
|
+
### Loading from Configuration Files
|
72
|
+
|
73
|
+
You can load settings from external sources:
|
74
|
+
|
75
|
+
```python
|
76
|
+
# Load from a dictionary (could be from JSON, YAML, etc.)
|
77
|
+
settings_manager.user_config = {
|
78
|
+
"app_name": "ProductionApp",
|
79
|
+
"debug": False,
|
80
|
+
"max_connections": 500
|
81
|
+
}
|
82
|
+
|
83
|
+
settings = settings_manager.settings
|
84
|
+
print(f"App: {settings.app_name}") # Output: App: ProductionApp
|
85
|
+
```
|
86
|
+
|
87
|
+
### Command Line Overrides
|
88
|
+
|
89
|
+
Override specific settings at runtime:
|
90
|
+
|
91
|
+
```python
|
92
|
+
# Simulate command line arguments
|
93
|
+
settings_manager.cli_args["debug"] = True
|
94
|
+
settings_manager.cli_args["max_connections"] = 50
|
95
|
+
|
96
|
+
# Clear cache to apply changes
|
97
|
+
settings_manager.clear()
|
98
|
+
|
99
|
+
settings = settings_manager.settings
|
100
|
+
print(f"Debug: {settings.debug}") # Output: Debug: True
|
101
|
+
print(f"Connections: {settings.max_connections}") # Output: Connections: 50
|
102
|
+
```
|
103
|
+
|
104
|
+
### Multiple Configurations (Mapped Settings)
|
105
|
+
|
106
|
+
For managing multiple environments or configurations:
|
107
|
+
|
108
|
+
```python
|
109
|
+
from pydantic_settings_manager import MappedSettingsManager
|
110
|
+
|
111
|
+
# Create a mapped settings manager
|
112
|
+
mapped_manager = MappedSettingsManager(AppSettings)
|
113
|
+
|
114
|
+
# Configure multiple environments
|
115
|
+
mapped_manager.user_config = {
|
116
|
+
"map": {
|
117
|
+
"development": {
|
118
|
+
"app_name": "MyApp-Dev",
|
119
|
+
"debug": True,
|
120
|
+
"max_connections": 10
|
121
|
+
},
|
122
|
+
"production": {
|
123
|
+
"app_name": "MyApp-Prod",
|
124
|
+
"debug": False,
|
125
|
+
"max_connections": 1000
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
# Switch between configurations
|
131
|
+
mapped_manager.set_cli_args("development")
|
132
|
+
dev_settings = mapped_manager.settings
|
133
|
+
print(f"Dev: {dev_settings.app_name}, Debug: {dev_settings.debug}")
|
134
|
+
|
135
|
+
mapped_manager.set_cli_args("production")
|
136
|
+
prod_settings = mapped_manager.settings
|
137
|
+
print(f"Prod: {prod_settings.app_name}, Debug: {prod_settings.debug}")
|
138
|
+
```
|
139
|
+
|
140
|
+
## Advanced Usage
|
141
|
+
|
142
|
+
### Project Structure for Large Applications
|
143
|
+
|
144
|
+
For complex applications with multiple modules, you can organize your settings like this:
|
145
|
+
|
146
|
+
```
|
147
|
+
your_project/
|
148
|
+
├── hoge/
|
149
|
+
│ ├── __init__.py
|
150
|
+
│ ├── settings.py
|
151
|
+
│ ├── client.py
|
152
|
+
│ └── registry.py
|
153
|
+
├── fuga/
|
154
|
+
│ ├── __init__.py
|
155
|
+
│ ├── settings.py
|
156
|
+
│ ├── client.py
|
157
|
+
│ └── registry.py
|
158
|
+
├── bootstrap.py
|
159
|
+
├── __main__.py
|
160
|
+
└── config.yaml
|
161
|
+
```
|
162
|
+
|
163
|
+
### Module-based Settings Management
|
164
|
+
|
165
|
+
```python
|
166
|
+
# fuga/__init__.py
|
167
|
+
from .settings import settings_manager
|
168
|
+
|
169
|
+
__all__ = ["settings_manager"]
|
170
|
+
```
|
171
|
+
|
172
|
+
```python
|
173
|
+
# fuga/settings.py
|
174
|
+
from pydantic_settings import BaseSettings
|
175
|
+
from pydantic_settings_manager import MappedSettingsManager
|
176
|
+
|
177
|
+
class FugaSettings(BaseSettings):
|
178
|
+
name: str = "default"
|
179
|
+
api_key: str = "***"
|
180
|
+
|
181
|
+
settings_manager = MappedSettingsManager(FugaSettings)
|
182
|
+
```
|
183
|
+
|
184
|
+
```python
|
185
|
+
# fuga/client.py
|
186
|
+
from .settings import FugaSettings
|
187
|
+
|
188
|
+
class FugaClient:
|
189
|
+
def __init__(self, settings: FugaSettings):
|
190
|
+
self.settings = settings
|
191
|
+
```
|
192
|
+
|
193
|
+
```python
|
194
|
+
# fuga/registry.py
|
195
|
+
from .settings import settings_manager
|
196
|
+
|
197
|
+
def create_fuga_client(config_key: str = ""):
|
198
|
+
settings = settings_manager.get_settings_by_key(config_key)
|
199
|
+
return FugaClient(settings)
|
200
|
+
```
|
201
|
+
|
202
|
+
### Bootstrap
|
203
|
+
|
204
|
+
The bootstrap process loads configuration from external sources (like YAML files) and applies them to your settings managers. This allows you to centralize configuration management and easily switch between different environments.
|
205
|
+
|
206
|
+
```yaml
|
207
|
+
# config.yaml
|
208
|
+
hoge:
|
209
|
+
name: "star"
|
210
|
+
value: 7
|
211
|
+
fuga:
|
212
|
+
key: first
|
213
|
+
map:
|
214
|
+
first:
|
215
|
+
name: "first"
|
216
|
+
api_key: "***"
|
217
|
+
second:
|
218
|
+
name: "second"
|
219
|
+
api_key: "***"
|
220
|
+
```
|
221
|
+
|
222
|
+
```python
|
223
|
+
# bootstrap.py
|
224
|
+
import importlib
|
225
|
+
import yaml
|
226
|
+
|
227
|
+
from pydantic_settings_manager import BaseSettingsManager
|
228
|
+
|
229
|
+
def bootstrap():
|
230
|
+
config = yaml.safe_load(open("/path/to/config.yaml"))
|
231
|
+
|
232
|
+
for module_name, user_config in config.items():
|
233
|
+
try:
|
234
|
+
module = importlib.import_module(module_name)
|
235
|
+
settings_manager = getattr(module, 'settings_manager', None)
|
236
|
+
|
237
|
+
if isinstance(settings_manager, BaseSettingsManager):
|
238
|
+
settings_manager.user_config = user_config
|
239
|
+
settings_manager.clear()
|
240
|
+
```
|
241
|
+
|
242
|
+
### CLI Integration
|
243
|
+
|
244
|
+
You can integrate command-line arguments to override specific settings at runtime. This is useful for debugging, testing different configurations, or providing runtime flexibility without modifying configuration files.
|
245
|
+
|
246
|
+
```python
|
247
|
+
# __main__.py
|
248
|
+
import click
|
249
|
+
|
250
|
+
from .bootstrap import bootstrap
|
251
|
+
from .hoge import settings_manager as hoge_settings_manager
|
252
|
+
from .fuga import settings_manager as fuga_settings_manager
|
253
|
+
|
254
|
+
@click.command
|
255
|
+
@click.option("--name", type=str, default="", help="Name of the Hoge")
|
256
|
+
@click.option("--key", type=str, default="", help="Key for Fuga settings")
|
257
|
+
def main(name: str, key: str):
|
258
|
+
bootstrap()
|
259
|
+
|
260
|
+
if name:
|
261
|
+
hoge_settings_manager.cli_args["name"] = name
|
262
|
+
hoge_settings_manager.clear()
|
263
|
+
|
264
|
+
if key:
|
265
|
+
fuga_settings_manager.cli_args["key"] = key
|
266
|
+
fuga_settings_manager.clear()
|
267
|
+
|
268
|
+
# ...
|
269
|
+
```
|
270
|
+
|
271
|
+
## Related Tools
|
272
|
+
|
273
|
+
### pydantic-config-builder
|
274
|
+
|
275
|
+
For complex projects with multiple configuration files, you might want to use [`pydantic-config-builder`](https://github.com/kiarina/pydantic-config-builder) to merge and build your YAML configuration files:
|
276
|
+
|
277
|
+
```bash
|
278
|
+
pip install pydantic-config-builder
|
279
|
+
```
|
280
|
+
|
281
|
+
This tool allows you to:
|
282
|
+
- Merge multiple YAML files into a single configuration
|
283
|
+
- Use base configurations with overlay files
|
284
|
+
- Build different configurations for different environments
|
285
|
+
- Support glob patterns and recursive merging
|
286
|
+
|
287
|
+
Example workflow:
|
288
|
+
```yaml
|
289
|
+
# pydantic_config_builder.yml
|
290
|
+
development:
|
291
|
+
input:
|
292
|
+
- base/*.yaml
|
293
|
+
- dev-overrides.yaml
|
294
|
+
output:
|
295
|
+
- config/dev.yaml
|
296
|
+
|
297
|
+
production:
|
298
|
+
input:
|
299
|
+
- base/*.yaml
|
300
|
+
- prod-overrides.yaml
|
301
|
+
output:
|
302
|
+
- config/prod.yaml
|
303
|
+
```
|
304
|
+
|
305
|
+
Then use the generated configurations with your settings manager:
|
306
|
+
```python
|
307
|
+
import yaml
|
308
|
+
from your_app import settings_manager
|
309
|
+
|
310
|
+
# Load the built configuration
|
311
|
+
with open("config/dev.yaml") as f:
|
312
|
+
config = yaml.safe_load(f)
|
313
|
+
|
314
|
+
settings_manager.user_config = config
|
315
|
+
```
|
316
|
+
|
317
|
+
## Development
|
318
|
+
|
319
|
+
This project uses modern Python development tools with flexible dependency groups:
|
320
|
+
|
321
|
+
- **ruff**: Fast linter and formatter (replaces black, isort, and flake8)
|
322
|
+
- **mypy**: Static type checking
|
323
|
+
- **pytest**: Testing framework with coverage reporting
|
324
|
+
- **uv**: Fast Python package manager with PEP 735 dependency groups support
|
325
|
+
|
326
|
+
### Setup
|
327
|
+
|
328
|
+
```bash
|
329
|
+
# Install all development dependencies
|
330
|
+
uv sync --group dev
|
331
|
+
|
332
|
+
# Or install specific dependency groups
|
333
|
+
uv sync --group test # Testing tools only
|
334
|
+
uv sync --group lint # Linting tools only
|
335
|
+
|
336
|
+
# Format code
|
337
|
+
uv run ruff check --fix .
|
338
|
+
|
339
|
+
# Run linting
|
340
|
+
uv run ruff check .
|
341
|
+
uv run mypy .
|
342
|
+
|
343
|
+
# Run tests
|
344
|
+
uv run pytest --cov=pydantic_settings_manager tests/
|
345
|
+
|
346
|
+
# Build and test everything
|
347
|
+
make build
|
348
|
+
```
|
349
|
+
|
350
|
+
### Development Workflow
|
351
|
+
|
352
|
+
```bash
|
353
|
+
# Quick setup for testing
|
354
|
+
uv sync --group test
|
355
|
+
make test
|
356
|
+
|
357
|
+
# Quick setup for linting
|
358
|
+
uv sync --group lint
|
359
|
+
make lint
|
360
|
+
|
361
|
+
# Full development environment
|
362
|
+
uv sync --group dev
|
363
|
+
make build
|
364
|
+
```
|
365
|
+
|
366
|
+
## Documentation
|
367
|
+
|
368
|
+
For more detailed documentation, please see the [GitHub repository](https://github.com/kiarina/pydantic-settings-manager).
|
369
|
+
|
370
|
+
## License
|
371
|
+
|
372
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|