Skip to content

Commit

Permalink
Fix on Logging configuration (avoid double echo) and added loader for…
Browse files Browse the repository at this point in the history
… toml files
  • Loading branch information
phenobarbital committed Mar 11, 2022
1 parent 183306f commit 1e50656
Show file tree
Hide file tree
Showing 13 changed files with 206 additions and 66 deletions.
9 changes: 9 additions & 0 deletions .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[bumpversion]
current_version = 0.7.6
commit = False
tag = True
tag_name = {new_version}

[bumpversion:file:pyproject.toml]

[bumpversion:file:navconfig/version.py]
39 changes: 16 additions & 23 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
BSD License
The MIT License (MIT)

Copyright (c) 2018-present, Jesus Lara
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
66 changes: 64 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,79 @@ APP_NAME = config.get('APP_NAME')

```

but also you can use config as a object:

```python
from navconfig import config

APP_NAME = config.APP_NAME
# the result is "My App".

```

## Working with Environments ##

NavConfig can load all environment variables (and the .ini files associated with .env file) from different directories,
every directory works as a new Environment and you can split your configuration for different environments, like this:

```
env/
.
├── dev
├── prod
├── staging
└── experimental
```

Then, you can load your application using the "ENV" environment variable:

```bash
ENV=dev python app.py
```


## Configure Logging ##

NavConfig has owns logging facility, if you load logging_config from Navconfig, you will get
a logging configuration using the Python dictConfig format.

also, if you put an environment variable called "logstash_enabled = True", there is a ready to use Logging facility using Logstash.

```python
import logging
from navconfig.logging import (
logdir,
loglevel,
logging_config
)
from logging.config import dictConfig
dictConfig(logging_config)
```

To use just the logger as expected with logging.getLogger(), e.g.

```python
logger = logging.getLogger('MY_APP_NAME')
logger.info('Hello World')
```
By default, the current logging configuration make echo to the standard output:

```bash
[INFO] 2022-03-11 19:31:39,408 navigator: Hello World
```

## Dependencies ##

* ConfigParser
* Python-Dotenv
* redis
* pylibmc


### Requirements ###

* Python >= 3.8
* asyncio (https://pypi.python.org/pypi/asyncio/)
* asyncdb
* python-dotenv

### Contribution guidelines ###
Expand All @@ -77,4 +139,4 @@ Please have a look at the Contribution Guide

### License ###

Navigator is dual-licensed under BSD and Apache 2.0 licenses.
NavConfig is released under MIT license.
10 changes: 1 addition & 9 deletions navconfig/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from .version import (
__title__, __description__, __version__, __author__, __author_email__
)
from .config import navigatorConfig
from .config import navigatorConfig # noqa

def is_virtualenv():
return (
Expand Down Expand Up @@ -57,11 +57,3 @@ def is_virtualenv():
# Add Path Navigator to Sys path
sys.path.append(str(BASE_DIR))
sys.path.append(str(SETTINGS_DIR))

# """
# Config-Settings.
# """
# try:
# from .conf import *
# except (ImportError, ModuleNotFoundError) as err:
# print(err)
60 changes: 41 additions & 19 deletions navconfig/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import sys
import types
import logging
from configparser import RawConfigParser, ConfigParser
from configparser import ConfigParser
from pathlib import Path
from dotenv import load_dotenv, dotenv_values
from dotenv import load_dotenv
import redis
from redis.exceptions import (
ConnectionError,
Expand All @@ -19,7 +19,9 @@
import pylibmc
from typing import (
Dict,
Any
Any,
Union,
List
)


Expand Down Expand Up @@ -189,18 +191,7 @@ class navigatorConfig(metaclass=Singleton):
_conffile: str = 'etc/config.ini'
__initialized = False

def __del__(self):
try:
self._mem.close()
self._redis.close()
finally:
pass

@property
def debug(self):
return self._debug

def __init__(self, site_root: str = None):
def __init__(self, site_root: str = None, env: str = None):
if self.__initialized is True:
return
self.__initialized = True
Expand All @@ -210,8 +201,11 @@ def __init__(self, site_root: str = None):
else:
self._site_path = Path(site_root).resolve()
# Environment Configuration:
environment = os.getenv('ENV', '')
self.ENV = environment
if env is not None:
self.ENV = env
else:
environment = os.getenv('ENV', '')
self.ENV = environment
# getting type of enviroment consumer:
env_type = os.getenv('NAVCONFIG_ENV', 'file') # file by default
# get the environment
Expand Down Expand Up @@ -256,6 +250,17 @@ def __init__(self, site_root: str = None):
# memcache not working
self._mem = None

def __del__(self):
try:
self._mem.close()
self._redis.close()
finally:
pass

@property
def debug(self):
return self._debug

def save_environment(self, env_type: str = 'drive'):
"""
Save remote Environment into a local File.
Expand All @@ -270,7 +275,7 @@ def save_environment(self, env_type: str = 'drive'):
except Exception as err:
print('Error Saving Environment', err)

def load_enviroment(self, env_type: str = 'file'):
def load_enviroment(self, env_type: str = 'file', file: Union[str, Path] = None):
"""
Load an environment from a File or any pluggable Origin.
"""
Expand Down Expand Up @@ -303,6 +308,22 @@ def load_enviroment(self, env_type: str = 'file'):
logging.exception(
f'Error Reading from Google Drive {err}', exc_info=True
)
elif env_type == 'yaml':
from navconfig.loaders import YamlLoader
try:
d = YamlLoader().load_environment(file)
except Exception as err:
logging.exception(
f'Error Reading from YAML File {file}: {err}', exc_info=True
)
elif env_type == 'toml':
from navconfig.loaders import TomlLoader
try:
d = TomlLoader().load_environment(file)
except Exception as err:
logging.exception(
f'Error Reading from TOML File {file}: {err}', exc_info=True
)

@property
def site_root(self):
Expand Down Expand Up @@ -508,7 +529,8 @@ def __getattr__(self, key: str) -> Any:
def set(self, key: str, value: Any) -> None:
"""
set.
Set an enviroment variable on REDIS
Set an enviroment variable on REDIS or Memcached, based on Strategy
TODO: add cloudpickle to serialize and unserialize data.
"""
return self._redis.set(key, value)

Expand Down
6 changes: 5 additions & 1 deletion navconfig/loaders/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
from .drive import driveLoader
__all__ = ('driveLoader')
from .yaml import YamlLoader
from .toml import TomlLoader


__all__ = ('driveLoader', 'YamlLoader', 'TomlLoader')
7 changes: 4 additions & 3 deletions navconfig/loaders/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def save_enviroment(self):
pass

def load_from_string(self, content: str):
filelike = StringIO(content)
filelike.seek(0)
dotenv_values(stream=filelike)
if content:
filelike = StringIO(content)
filelike.seek(0)
dotenv_values(stream=filelike)
3 changes: 1 addition & 2 deletions navconfig/loaders/drive.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ def load_enviroment(self):
try:
env = self.drive.CreateFile({'id': self.file_id})
content = env.GetContentString()
if content:
self.load_from_string(content)
self.load_from_string(content)
except Exception as err:
raise Exception('Error loading Environment: {}'.format(err))

Expand Down
24 changes: 24 additions & 0 deletions navconfig/loaders/toml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import codecs
import toml
from pathlib import Path
from .base import BaseLoader
from typing import (
Union
)

class TomlLoader(BaseLoader):
"""TomlLoader.
Used to read configuration settings from TOML files.
Args:
BaseLoader (_type_): _description_
"""

def load_enviroment(self, file: Union[str, Path]):
with codecs.open(file, 'r') as f:
content = toml.loads(f.read())
self.load_from_string(content)

def save_enviroment(self):
pass
24 changes: 24 additions & 0 deletions navconfig/loaders/yaml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import codecs
import yaml
from pathlib import Path
from .base import BaseLoader
from typing import (
Union
)

class YamlLoader(BaseLoader):
"""YamlLoader.
Used to read configuration settings from YAML files.
Args:
BaseLoader (_type_): _description_
"""

def load_enviroment(self, file: Union[str, Path]):
with codecs.open(file, 'r') as f:
content = yaml.safe_load(f)
self.load_from_string(content)

def save_enviroment(self):
pass
Loading

0 comments on commit 1e50656

Please sign in to comment.