Skip to content

Commit

Permalink
merge master
Browse files Browse the repository at this point in the history
  • Loading branch information
merwok committed Dec 17, 2018
2 parents 7019745 + 27aac0a commit 0429c2a
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 39 deletions.
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ workflows:
version: 2
configstore:
jobs:
- test-py36
- test-py37
- test-py36
- check

jobs:
Expand All @@ -27,7 +27,7 @@ jobs:
name: Test with Python 3.7
command: venv/bin/tox -e py37 -- --junitxml=~/reports/tox/coverage.xml
- run:
name: Run tests with coverage
name: Check coverage with Python 3.7
command: venv/bin/tox -e coverage
- save_cache:
key: configstore-py37-v2
Expand Down
41 changes: 41 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~
changelog for configstore
~~~~~~~~~~~~~~~~~~~~~~~~~~~


v0.6 (unreleased)
=================



v0.5
====

Package library with flit.


v0.4
====

New backend to get config from AWS SSM Parameter Store.


v0.3
====

Added Store.add_backend method.


v0.2
====

Introducing Store class with configurable backends instead of function.


v0.1
====

First release!

The get_config function finds values in environment variables
or Docker secrets.
8 changes: 6 additions & 2 deletions configstore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
from .store import Store, SettingNotFoundException

__all__ = [
'Store', 'SettingNotFoundException',
'EnvVarBackend', 'DotenvBackend', 'DockerSecretBackend', 'AwsSsmBackend',
'Store',
'SettingNotFoundException',
'EnvVarBackend',
'DotenvBackend',
'DockerSecretBackend',
'AwsSsmBackend',
]

__version__ = '0.6.dev'
6 changes: 5 additions & 1 deletion configstore/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@
from .env_var import EnvVarBackend

__all__ = [
'Backend', 'EnvVarBackend', 'DotenvBackend', 'DockerSecretBackend', 'AwsSsmBackend',
'Backend',
'EnvVarBackend',
'DotenvBackend',
'DockerSecretBackend',
'AwsSsmBackend',
]
3 changes: 1 addition & 2 deletions configstore/backends/awsssm.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ class AwsSsmBackend(Backend):

def __init__(self, name_prefix=''):
if boto3 is None:
raise ImportError('install configstore[awsssm] to use '
'the AWS SSM backend')
raise ImportError('install configstore[awsssm] to use the AWS SSM backend')

self.name_prefix = name_prefix

Expand Down
4 changes: 4 additions & 0 deletions configstore/backends/docker_secret.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@


class DockerSecretBackend(Backend):
"""Backend for docker secrets.
See the documentation for docker services for more info.
"""

def __init__(self, secrets_path=SECRETS_PATH):
self.secrets_path = secrets_path
Expand Down
8 changes: 5 additions & 3 deletions configstore/backends/dotenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@


class DotenvBackend(Backend):
"""Create an instance with a path to the .env file."""
"""Backend that reads settings in a .env file.
Create an instance with a path to the .env file.
"""

def __init__(self, dotenv_path):
if dotenv is None:
raise ImportError('install configstore[dotenv] to use '
'the dotenv backend')
raise ImportError('install configstore[dotenv] to use the dotenv backend')

with open(dotenv_path) as file:
content = file.read()
Expand Down
1 change: 1 addition & 0 deletions configstore/backends/env_var.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@


class EnvVarBackend(Backend):
"""Backend that reads settings in environment variables."""

def get_setting(self, key: str) -> Optional[str]:
return os.environ.get(key)
12 changes: 10 additions & 2 deletions configstore/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@


class SettingNotFoundException(Exception):
pass
"""Error raised for settings not found in any backend and without default value."""


_no_default: str = '~~!!configstore-no-default!!~~'


class Store(object):
"""A collection of backends that let you retrieve settings from them.
Backends can be passed to constructor and/or added with add_backend.
When get_setting is called, backends are searched in addition order
to find the value; if no backend returns a value and the method was
called without a default, SettingNotFoundException is raised.
"""

def __init__(self, backends: Tuple[Type[Backend]]) -> None:
self._backends = tuple(backends)
Expand All @@ -30,4 +37,5 @@ def get_setting(self, key: str, default: str=_no_default) -> str:
return default
else:
raise SettingNotFoundException(
"Couldn't find setting {} in any backend".format(key))
"Couldn't find setting {} in any backend".format(key)
)
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ author-email = "[email protected]"
home-page = "https://github.com/caravancoop/configstore"
description-file = "README.rst"
classifiers = [
"Development Status :: 3 - Alpha",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Topic :: Software Development",
"Topic :: System :: Installation/Setup",
"Topic :: System :: Systems Administration",
]
requires = [
]
Expand Down
63 changes: 63 additions & 0 deletions tests/test_z_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import pytest
import configstore

DOTENV_CONTENTS = u'''
SECRET_KEY=1234dot
ENVIRONMENT=PRODUCTION
'''

DOTENV_EMPTY = u'''
'''


def test_configstore_envvars_override_dotenv(monkeypatch, tmp_path):
monkeypatch.setenv('ENVIRONMENT', 'STAGING')
path = tmp_path / 'config.env'
path.write_text(DOTENV_CONTENTS)

store = configstore.Store([
configstore.EnvVarBackend(),
configstore.DotenvBackend(str(path)),
])

secret_key = store.get_setting('SECRET_KEY')
environment = store.get_setting('ENVIRONMENT')

assert secret_key == '1234dot'
assert environment == 'STAGING'


def test_configstore_dotenv_overrides_envvars(monkeypatch, tmp_path):
monkeypatch.setenv('ENVIRONMENT', 'STAGING')
path = tmp_path / 'config.env'
path.write_text(DOTENV_CONTENTS)

store = configstore.Store([
configstore.DotenvBackend(str(path)),
configstore.EnvVarBackend(),
])

secret_key = store.get_setting('SECRET_KEY')
environment = store.get_setting('ENVIRONMENT')

assert secret_key == '1234dot'
assert environment == 'PRODUCTION'


def test_dotenv_empty_file(monkeypatch, tmp_path):
monkeypatch.setenv('ENVIRONMENT', 'STAGING')
path = tmp_path / 'config.env'
path.write_text(DOTENV_EMPTY)

store = configstore.Store([
configstore.DotenvBackend(str(path)),
configstore.EnvVarBackend(),
])

with pytest.raises(Exception) as excinfo:
store.get_setting('DEBUG')
environment = store.get_setting('ENVIRONMENT')

assert "Couldn't find setting" in str(excinfo.value)
assert environment == 'STAGING'
52 changes: 26 additions & 26 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,11 @@ envlist = py36,py37
minversion = 3.4.0
isolated_build = True

[flake8]
max-line-length = 89
exclude = .git,.tox,__pycache__,dist
ignore = E731,N806
show-source = True

[pytest]
addopts = -svv
testpaths = tests
norecursedirs =
.tox
__pycache__

[coverage:run]
source = configstore
branch = 1

[coverage:report]
skip_covered = 1
show_missing = 1
fail_under = 100
exclude_lines =
pragma: no cover


[testenv]
deps =
flake8
pretend
pytest
pytest >= 3.9
extras =
dotenv
awsssm
Expand Down Expand Up @@ -67,3 +42,28 @@ commands =
# FIXME check all dists when flit fixes #216
twine check dist/*.whl
safety check


[flake8]
max-line-length = 89
exclude = .git,.tox,__pycache__,dist
ignore = E731,N806
show-source = True

[pytest]
addopts = -svv
testpaths = tests
norecursedirs =
.tox
__pycache__

[coverage:run]
source = configstore
branch = 1

[coverage:report]
skip_covered = 1
show_missing = 1
fail_under = 100
exclude_lines =
pragma: no cover

0 comments on commit 0429c2a

Please sign in to comment.