initial commit
This commit is contained in:
commit
38d8880b7b
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
.idea/
|
||||
venv/
|
||||
__pycache__/
|
||||
*.py[cod]
|
1
MANIFEST.in
Normal file
1
MANIFEST.in
Normal file
@ -0,0 +1 @@
|
||||
include README.md
|
148
README.md
Normal file
148
README.md
Normal file
@ -0,0 +1,148 @@
|
||||
# Configurator
|
||||
|
||||
`Configurator` is a Python package designed for efficient and standardized configuration management in your
|
||||
applications. It uses a singleton pattern to ensure that configuration is loaded once and accessible throughout your
|
||||
application. It supports merging custom configurations, validation of required configurations, and ease of access
|
||||
through getter methods.
|
||||
|
||||
## Features
|
||||
|
||||
- Singleton pattern for configuration management
|
||||
- Support for loading and merging custom configurations
|
||||
- Simple validation for required configuration variables
|
||||
- Easily extendable for additional configuration sources
|
||||
|
||||
## Installation
|
||||
|
||||
You can install the package via pip:
|
||||
|
||||
```bash
|
||||
pip install configurator
|
||||
```
|
||||
|
||||
Or by cloning this repository and installing with:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/yourusername/configurator.git
|
||||
cd configurator
|
||||
pip install .
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Initial Setup
|
||||
|
||||
To use `Configurator` in your application, you first need to load the configuration. This should typically be done once
|
||||
at the start of your application, for instance, in the main entry point or the initial setup script.
|
||||
|
||||
```python
|
||||
from configurator import load_config, get_config, ConfigurationError
|
||||
|
||||
# Define custom configuration for the application
|
||||
custom_config = {
|
||||
'DATABASE_URL': 'sqlite:///default.db',
|
||||
'SECRET_KEY': 'defaultsecretkey',
|
||||
}
|
||||
|
||||
def main():
|
||||
try:
|
||||
# Load configuration with custom settings
|
||||
load_config(custom_config=custom_config)
|
||||
|
||||
# Example usage of get_config
|
||||
database_url = get_config('DATABASE_URL')
|
||||
print(f"Database URL: {database_url}")
|
||||
|
||||
# Example usage of another config variable
|
||||
secret_key = get_config('SECRET_KEY')
|
||||
print(f"Secret Key: {secret_key}")
|
||||
except ConfigurationError as e:
|
||||
print(f"Failed to load configuration: {e}")
|
||||
exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
```
|
||||
|
||||
### Accessing Configuration Values
|
||||
|
||||
You can access configuration values using the `get_config` function. If the key does not exist, you can provide a
|
||||
default value.
|
||||
|
||||
```python
|
||||
from configurator import get_config
|
||||
|
||||
log_level = get_config('LOG_LEVEL', 'INFO')
|
||||
print(f"Log Level: {log_level}")
|
||||
|
||||
debug_mode = get_config('DEBUG', False)
|
||||
print(f"Debug Mode: {debug_mode}")
|
||||
```
|
||||
|
||||
### Configuration Validation
|
||||
|
||||
The package includes basic validation to ensure that all required configurations are provided. If a required variable is
|
||||
missing, a `ConfigurationError` will be raised.
|
||||
|
||||
You can customize validation requirements in the `validators` module if needed.
|
||||
|
||||
## Custom Configuration
|
||||
|
||||
Custom configurations can be passed to the `load_config` function. These will be merged with the default configurations
|
||||
provided in the environment or settings files.
|
||||
|
||||
Example:
|
||||
|
||||
```python
|
||||
custom_config = {
|
||||
'API_ENDPOINT': 'https://api.example.com',
|
||||
'TIMEOUT': 30,
|
||||
}
|
||||
load_config(custom_config)
|
||||
api_endpoint = get_config('API_ENDPOINT')
|
||||
print(f"API Endpoint: {api_endpoint}")
|
||||
```
|
||||
|
||||
## Extending Configurator
|
||||
|
||||
You can extend the `Configurator` to support additional configuration sources like JSON files, remote configuration
|
||||
services, etc. This would typically involve modifying the `load_config` function.
|
||||
|
||||
```python
|
||||
def load_config(custom_config=None, json_file=None) -> dict:
|
||||
global _config_values
|
||||
if _config_values is None:
|
||||
default_config = {
|
||||
'LOG_LEVEL': config('LOG_LEVEL', default='INFO'),
|
||||
'DEBUG': config('DEBUG', default='false', cast=bool),
|
||||
'ENV': config('ENV', default='DEV')
|
||||
}
|
||||
|
||||
if json_file:
|
||||
with open(json_file, 'r') as jf:
|
||||
json_config = json.load(jf)
|
||||
default_config.update(json_config)
|
||||
|
||||
# Merge custom config if present
|
||||
if custom_config:
|
||||
default_config.update(custom_config)
|
||||
|
||||
config_values = {key: config(key, default=value) for key, value in default_config.items()}
|
||||
|
||||
required_vars = [key for key, value in default_config.items() if value is None]
|
||||
validate_config(config_values, required_vars)
|
||||
|
||||
_config_values = config_values
|
||||
|
||||
return _config_values
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please fork the repository and submit a pull request with your changes. For major changes,
|
||||
please open an issue first to discuss what you would like to change.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
5
configurator/__init__.py
Normal file
5
configurator/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
from .core import load_config, get_config
|
||||
from .validators import validate_config
|
||||
from .exceptions import ConfigurationError
|
||||
|
||||
__all__ = ['load_config', 'get_config', 'validate_config', 'ConfigurationError']
|
36
configurator/core.py
Normal file
36
configurator/core.py
Normal file
@ -0,0 +1,36 @@
|
||||
from decouple import config
|
||||
from .validators import validate_config
|
||||
|
||||
# Global state to hold loaded configuration (Singleton pattern)
|
||||
_config_values = None
|
||||
|
||||
|
||||
def load_config(custom_config=None) -> dict:
|
||||
"""Load all configuration variables and validate them."""
|
||||
global _config_values
|
||||
|
||||
if _config_values is None:
|
||||
default_config = {
|
||||
'LOG_LEVEL': config('LOG_LEVEL', default='INFO'),
|
||||
'DEBUG': config('DEBUG', default='false', cast=bool),
|
||||
'ENV': config('ENV', default='DEV')
|
||||
}
|
||||
|
||||
# Merge custom configurator if present
|
||||
if custom_config:
|
||||
default_config.update(custom_config)
|
||||
|
||||
config_values = {key: config(key, default=value) for key, value in default_config.items()}
|
||||
|
||||
required_vars = [key for key, value in default_config.items() if value is None]
|
||||
validate_config(config_values, required_vars)
|
||||
|
||||
_config_values = config_values
|
||||
|
||||
return _config_values
|
||||
|
||||
|
||||
def get_config(key: str, default=None):
|
||||
"""Get a configuration value by key."""
|
||||
config_values = load_config()
|
||||
return config_values.get(key, default)
|
3
configurator/exceptions.py
Normal file
3
configurator/exceptions.py
Normal file
@ -0,0 +1,3 @@
|
||||
class ConfigurationError(Exception):
|
||||
"""Custom Exception for configuration errors."""
|
||||
pass
|
0
configurator/utils.py
Normal file
0
configurator/utils.py
Normal file
8
configurator/validators.py
Normal file
8
configurator/validators.py
Normal file
@ -0,0 +1,8 @@
|
||||
from .exceptions import ConfigurationError
|
||||
|
||||
|
||||
def validate_config(config_values, required_vars):
|
||||
"""Validate the presence and format of required configuration variables."""
|
||||
for key in required_vars:
|
||||
if key not in config_values or config_values[key] is None:
|
||||
raise ConfigurationError(f'Missing required configuration: {key}')
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
python-decouple
|
26
setup.py
Normal file
26
setup.py
Normal file
@ -0,0 +1,26 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
with open("README.md", "r") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
with open("requirements.txt", "r") as fh:
|
||||
required = fh.read().splitlines()
|
||||
|
||||
setup(
|
||||
name="configurator",
|
||||
version="0.1.0",
|
||||
author="agathanonymous",
|
||||
author_email="agatha@juggalol.com",
|
||||
description="A configuration management package",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
url="https://git.juggalol.com/agatha/configurator",
|
||||
packages=find_packages(),
|
||||
classifiers=[
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
],
|
||||
python_requires='>=3.6',
|
||||
install_requires=required,
|
||||
)
|
Loading…
Reference in New Issue
Block a user