kaptan-0.5.12/0000777000175000017500000000000013457501045011625 5ustar xx00000000000000kaptan-0.5.12/AUTHORS0000777000175000017500000000044213457476313012711 0ustar xx00000000000000Kaptan is written and maintained by various authors and contributors: - Emre Yılmaz - Tony Narlock - Berker Peksag Patches and suggestions: - @cenkalti - @marksteve - @Wessie - @pradyunsg For an up to date list of contributors, see: https://github.com/emre/kaptan/graphs/contributors kaptan-0.5.12/LICENSE0000777000175000017500000000305513457476313012651 0ustar xx00000000000000Copyright (c) 2013- by Emre Yılmaz and contributors. See AUTHORS for more details. Some rights reserved. Redistribution and use in source and binary forms of the software as well as documentation, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE AND DOCUMENTATION 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 OWNER 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. kaptan-0.5.12/MANIFEST.in0000777000175000017500000000031213457477116013375 0ustar xx00000000000000include LICENSE AUTHORS README.md include tests.py recursive-include requirements * recursive-include kaptan * recursive-exclude kaptan *.pyc recursive-exclude kaptan *.pyo recursive-include tests *.py kaptan-0.5.12/PKG-INFO0000777000175000017500000002065713457501045012737 0ustar xx00000000000000Metadata-Version: 1.1 Name: kaptan Version: 0.5.12 Summary: Configuration manager Home-page: https://github.com/emre/kaptan Author: Emre Yilmaz Author-email: mail@emreyilmaz.me License: BSD Description: kaptan ====== |pypi| |docs| |build-status| |coverage| |license| configuration parser. installation ------------ .. code-block:: console $ pip install kaptan Also available as a package on FreeBSD, Debian, Arch Linux and Slackware. usage ----- **supported handlers** - dict - json - yaml - .ini - python file **default (dict) handler** .. code-block:: python config = kaptan.Kaptan() config.import_config({ 'environment': 'DEV', 'redis_uri': 'redis://localhost:6379/0', 'debug': False, 'pagination': { 'per_page': 10, 'limit': 20, } }) print config.get("pagination.limit") # output: 20 **json handler** .. code-block:: python config = kaptan.Kaptan(handler="json") config.import_config('{"everything": 42}') print config.get("everything") # output: 42 **yaml handler** .. code-block:: python config = kaptan.Kaptan(handler="yaml") config.import_config(""" product: price: value: 12.65 currency_list: 1. TL 2. EURO """) print config.get("product.price.currency_list.0") # output: TL or you can get from directly from the filename: ``config.import_config("configuration.yaml")`` **.ini handler** config.ini .. code-block:: ini [development] database_uri = mysql://root:123456@localhost/posts [production] database_uri = mysql://poor_user:poor_password@localhost/poor_posts .. code-block:: python config = kaptan.Kaptan(handler="ini") config.import_config('config.ini') print config.get("production.database_uri") # output: mysql://poor_user:poor_password@localhost/poor_posts **file handler** config.py .. code-block:: python DATABASE = 'mysql://root:123456@localhost/posts' DEBUG = False PAGINATION = { 'per_page': 10, 'limit': 20, } .. code-block:: python config = kaptan.Kaptan(handler="file") config.import_config('config') print config.get("DEBUG") # output: False exporting configuration ----------------------- .. code-block:: python config = kaptan.Kaptan(handler="file") config.import_config({ 'environment': 'DEV', 'redis_uri': 'redis://localhost:6379/0', 'debug': False, 'pagination': { 'per_page': 10, 'limit': 20, } }) print config.export("yaml") **output**: .. code-block:: yaml debug: false environment: DEV pagination: {limit: 20, per_page: 10} redis_uri: redis://localhost:6379/0 ``print config.export("json")`` outputs unindented json. ``.export`` accepts kwargs which pass into `json.dumps`. .. _json.dumps: http://docs.python.org/2/library/json.html#json.dump .. code-block:: python print config.export("json", indent=4) **output**: .. code-block:: json { "environment": "DEV", "debug": false, "pagination": { "per_page": 10, "limit": 20 }, "redis_uri": "redis://localhost:6379/0" } ``config.export('yaml')`` also supports the `kwargs for pyyaml`_. .. _kwargs for pyyaml: http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper New in Version 0.5.7: ``config.export('yaml', safe=True)`` will use ``.safe_dump``. cli --- exporting (defaults to json) .. code-block:: console $ echo "environment: DEV" > config.yaml $ kaptan config.yaml --export json > config.json $ cat config.json {"environment": "DEV"} getting a value .. code-block:: console $ kaptan config.yaml --key environment DEV specifying the handler .. code-block:: console $ mv config.yaml config.settings $ kaptan config.settings:yaml --export json {"environment": "DEV"} config from stdin .. code-block:: console $ echo '{"source": "stdin"}' | kaptan - {"source": "stdin"} $ echo 'source: stdin' | kaptan -:yaml {"source": "stdin"} merging configs .. code-block:: console $ echo "environment: PROD" > config.settings $ echo '{"source": "stdin"}' | kaptan - config.json config.settings:yaml {"environment": "PROD", "source": "stdin"} setting default handler .. code-block:: console $ echo "source: stdin" | kaptan --handler yaml - config.settings {"environment": "PROD", "source": "stdin"} writing json with yaml .. code-block:: console $ kaptan -:yaml -e json running tests ------------- with ``py.test``: .. code-block:: console $ py.test contributors ------------ - `Cenk Altı `_ - `Wesley Bitter `_ - `Mark Steve `_ - `Tony Narlock `_ - `Berker Peksag `_ - `Pradyun S. Gedam `_ see more at https://github.com/emre/kaptan/graphs/contributors. .. |pypi| image:: https://img.shields.io/pypi/v/kaptan.svg :alt: Python Package :target: http://badge.fury.io/py/kaptan .. |build-status| image:: https://img.shields.io/travis/emre/kaptan.svg :alt: Build Status :target: https://travis-ci.org/emre/kaptan .. |coverage| image:: https://codecov.io/gh/emre/kaptan/branch/master/graph/badge.svg :alt: Code Coverage :target: https://codecov.io/gh/emre/kaptan .. |license| image:: https://img.shields.io/github/license/emre/kaptan.svg :alt: License .. |docs| image:: https://readthedocs.org/projects/kaptan/badge/?version=latest :alt: Documentation Status :scale: 100% :target: https://readthedocs.org/projects/kaptan/ Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Operating System :: POSIX Classifier: Operating System :: MacOS :: MacOS X Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 kaptan-0.5.12/README.rst0000777000175000017500000001277113457476313013340 0ustar xx00000000000000kaptan ====== |pypi| |docs| |build-status| |coverage| |license| configuration parser. installation ------------ .. code-block:: console $ pip install kaptan Also available as a package on FreeBSD, Debian, Arch Linux and Slackware. usage ----- **supported handlers** - dict - json - yaml - .ini - python file **default (dict) handler** .. code-block:: python config = kaptan.Kaptan() config.import_config({ 'environment': 'DEV', 'redis_uri': 'redis://localhost:6379/0', 'debug': False, 'pagination': { 'per_page': 10, 'limit': 20, } }) print config.get("pagination.limit") # output: 20 **json handler** .. code-block:: python config = kaptan.Kaptan(handler="json") config.import_config('{"everything": 42}') print config.get("everything") # output: 42 **yaml handler** .. code-block:: python config = kaptan.Kaptan(handler="yaml") config.import_config(""" product: price: value: 12.65 currency_list: 1. TL 2. EURO """) print config.get("product.price.currency_list.0") # output: TL or you can get from directly from the filename: ``config.import_config("configuration.yaml")`` **.ini handler** config.ini .. code-block:: ini [development] database_uri = mysql://root:123456@localhost/posts [production] database_uri = mysql://poor_user:poor_password@localhost/poor_posts .. code-block:: python config = kaptan.Kaptan(handler="ini") config.import_config('config.ini') print config.get("production.database_uri") # output: mysql://poor_user:poor_password@localhost/poor_posts **file handler** config.py .. code-block:: python DATABASE = 'mysql://root:123456@localhost/posts' DEBUG = False PAGINATION = { 'per_page': 10, 'limit': 20, } .. code-block:: python config = kaptan.Kaptan(handler="file") config.import_config('config') print config.get("DEBUG") # output: False exporting configuration ----------------------- .. code-block:: python config = kaptan.Kaptan(handler="file") config.import_config({ 'environment': 'DEV', 'redis_uri': 'redis://localhost:6379/0', 'debug': False, 'pagination': { 'per_page': 10, 'limit': 20, } }) print config.export("yaml") **output**: .. code-block:: yaml debug: false environment: DEV pagination: {limit: 20, per_page: 10} redis_uri: redis://localhost:6379/0 ``print config.export("json")`` outputs unindented json. ``.export`` accepts kwargs which pass into `json.dumps`. .. _json.dumps: http://docs.python.org/2/library/json.html#json.dump .. code-block:: python print config.export("json", indent=4) **output**: .. code-block:: json { "environment": "DEV", "debug": false, "pagination": { "per_page": 10, "limit": 20 }, "redis_uri": "redis://localhost:6379/0" } ``config.export('yaml')`` also supports the `kwargs for pyyaml`_. .. _kwargs for pyyaml: http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper New in Version 0.5.7: ``config.export('yaml', safe=True)`` will use ``.safe_dump``. cli --- exporting (defaults to json) .. code-block:: console $ echo "environment: DEV" > config.yaml $ kaptan config.yaml --export json > config.json $ cat config.json {"environment": "DEV"} getting a value .. code-block:: console $ kaptan config.yaml --key environment DEV specifying the handler .. code-block:: console $ mv config.yaml config.settings $ kaptan config.settings:yaml --export json {"environment": "DEV"} config from stdin .. code-block:: console $ echo '{"source": "stdin"}' | kaptan - {"source": "stdin"} $ echo 'source: stdin' | kaptan -:yaml {"source": "stdin"} merging configs .. code-block:: console $ echo "environment: PROD" > config.settings $ echo '{"source": "stdin"}' | kaptan - config.json config.settings:yaml {"environment": "PROD", "source": "stdin"} setting default handler .. code-block:: console $ echo "source: stdin" | kaptan --handler yaml - config.settings {"environment": "PROD", "source": "stdin"} writing json with yaml .. code-block:: console $ kaptan -:yaml -e json running tests ------------- with ``py.test``: .. code-block:: console $ py.test contributors ------------ - `Cenk Altı `_ - `Wesley Bitter `_ - `Mark Steve `_ - `Tony Narlock `_ - `Berker Peksag `_ - `Pradyun S. Gedam `_ see more at https://github.com/emre/kaptan/graphs/contributors. .. |pypi| image:: https://img.shields.io/pypi/v/kaptan.svg :alt: Python Package :target: http://badge.fury.io/py/kaptan .. |build-status| image:: https://img.shields.io/travis/emre/kaptan.svg :alt: Build Status :target: https://travis-ci.org/emre/kaptan .. |coverage| image:: https://codecov.io/gh/emre/kaptan/branch/master/graph/badge.svg :alt: Code Coverage :target: https://codecov.io/gh/emre/kaptan .. |license| image:: https://img.shields.io/github/license/emre/kaptan.svg :alt: License .. |docs| image:: https://readthedocs.org/projects/kaptan/badge/?version=latest :alt: Documentation Status :scale: 100% :target: https://readthedocs.org/projects/kaptan/ kaptan-0.5.12/kaptan/0000777000175000017500000000000013457501045013103 5ustar xx00000000000000kaptan-0.5.12/kaptan/__about__.py0000777000175000017500000000043713457500752015376 0ustar xx00000000000000__title__ = 'kaptan' __package_name__ = 'kaptan' __version__ = '0.5.12' __description__ = 'Configuration manager' __email__ = 'mail@emreyilmaz.me' __url__ = 'https://github.com/emre/kaptan' __author__ = 'Emre Yilmaz' __license__ = 'BSD' __copyright__ = 'Copyright 2013-2019 Emre Yilmaz' kaptan-0.5.12/kaptan/__init__.py0000777000175000017500000001416613457476313015240 0ustar xx00000000000000# -*- coding: utf8 -*- """ kaptan ~~~~~~ configuration parser. :copyright: (c) 2013 by the authors and contributors (See AUTHORS file). :license: BSD, see LICENSE for more details. """ from __future__ import print_function, unicode_literals import argparse import os from ._compat import collections_abc from .handlers.dict_handler import DictHandler from .handlers.pyfile_handler import PyFileHandler from .handlers.ini_handler import IniHandler from .handlers.json_handler import JsonHandler from .handlers.yaml_handler import YamlHandler SENTINEL = object() HANDLER_EXT = { 'ini': 'ini', 'conf': 'ini', 'yaml': 'yaml', 'yml': 'yaml', 'json': 'json', 'py': 'file', } class Kaptan(object): HANDLER_MAP = { 'json': JsonHandler, 'dict': DictHandler, 'yaml': YamlHandler, 'file': PyFileHandler, 'ini': IniHandler, } def __init__(self, handler=None): self.configuration_data = dict() self.handler = None if handler: self.handler = self.HANDLER_MAP[handler]() def upsert(self, key, value): self.configuration_data.update({key: value}) return self def _is_python_file(self, value): """ Return True if the `value` is the path to an existing file with a `.py` extension. False otherwise """ ext = os.path.splitext(value)[1][1:] if ext == 'py' or os.path.isfile(value + '.py'): return True return False def import_config(self, value): if isinstance(value, dict): # load python dict self.handler = self.HANDLER_MAP['dict']() data = value elif os.path.isfile(value) and not self._is_python_file(value): if not self.handler: try: key = HANDLER_EXT.get(os.path.splitext(value)[1][1:], None) self.handler = self.HANDLER_MAP[key]() except: raise RuntimeError("Unable to determine handler") with open(value) as f: data = f.read() elif self._is_python_file(value): # is a python file self.handler = self.HANDLER_MAP[HANDLER_EXT['py']]() if not value.endswith('.py'): value += '.py' # in case someone is referring to a module data = os.path.abspath(os.path.expanduser(value)) if not os.path.isfile(data): raise IOError('File {0} not found.'.format(data)) else: if not self.handler: raise RuntimeError("Unable to determine handler") data = value self.configuration_data = self.handler.load(data) return self def _get(self, key): current_data = self.configuration_data for chunk in key.split('.'): if isinstance(current_data, collections_abc.Mapping): current_data = current_data[chunk] elif isinstance(current_data, collections_abc.Sequence): chunk = int(chunk) current_data = current_data[chunk] else: # A scalar type has been found return current_data return current_data def get(self, key=None, default=SENTINEL): if not key: # .get() or .get(''), return full config return self.export('dict') try: try: return self._get(key) except KeyError: raise KeyError(key) except ValueError: raise ValueError("Sequence index not an integer") except IndexError: raise IndexError("Sequence index out of range") except (KeyError, ValueError, IndexError): if default is not SENTINEL: return default raise def export(self, handler=None, **kwargs): if not handler: handler_class = self.handler else: handler_class = self.HANDLER_MAP[handler]() return handler_class.dump(self.configuration_data, **kwargs) def __handle_default_value(self, key, default): if default == SENTINEL: raise KeyError(key) return default def get_parser(): """Create and return argument parser. :rtype: :class:`argparse.ArgumentParser` :return: CLI Parser """ parser = argparse.ArgumentParser( prog=__package__, description='Configuration manager in your pocket' ) parser.add_argument('config_file', action='store', nargs='*', help="file/s to load config from") parser.add_argument('--handler', action='store', default='json', help="set default handler") parser.add_argument('-e', '--export', action='store', default='json', help="set format to export to") parser.add_argument('-k', '--key', action='store', help="set config key to get value of") return parser def main(): from sys import stdin parser = get_parser() args, ukargs = parser.parse_known_args() config = Kaptan() config_files = args.config_file + ukargs if not config_files: parser.print_help() parser.exit(1) def get_handlers(): for f in config_files: s = f.split(':') if len(s) != 2: s += [None] yield tuple(s) config_handlers = collections_abc.OrderedDict(list(get_handlers())) for config_file, handler in config_handlers.items(): is_stdin = config_file == '-' if is_stdin: handler = handler or args.handler else: ext = handler or os.path.splitext(config_file)[1][1:] handler = HANDLER_EXT.get(ext, args.handler) _config = Kaptan(handler=handler) if is_stdin: _config.import_config(stdin.read()) else: with open(config_file) as f: _config.import_config(f.read()) config.configuration_data.update(_config.configuration_data) if args.key: print(config.get(args.key)) else: print(config.export(args.export)) parser.exit(0) kaptan-0.5.12/kaptan/__main__.py0000777000175000017500000000007713457476313015215 0ustar xx00000000000000from kaptan import main if __name__ == '__main__': main() kaptan-0.5.12/kaptan/_compat.py0000777000175000017500000000027613457476313015120 0ustar xx00000000000000# -*- coding: utf8 -*- # flake8: NOQA: F40 import sys PY2 = sys.version_info[0] == 2 if PY2: import collections as collections_abc else: import collections.abc as collections_abc kaptan-0.5.12/kaptan/handlers/0000777000175000017500000000000013457501045014703 5ustar xx00000000000000kaptan-0.5.12/kaptan/handlers/__init__.py0000777000175000017500000000067613457476313017041 0ustar xx00000000000000# -*- coding: utf8 -*- """ kaptan.handlers ~~~~~~~~~~~~~~~ :copyright: (c) 2013 by the authors and contributors (See AUTHORS file). :license: BSD, see LICENSE for more details. """ from __future__ import print_function, unicode_literals class BaseHandler(object): """Base class for data handlers.""" def load(self, data): raise NotImplementedError def dump(self, data): raise NotImplementedError kaptan-0.5.12/kaptan/handlers/dict_handler.py0000777000175000017500000000066413457476313017717 0ustar xx00000000000000# -*- coding: utf8 -*- """ kaptan.handlers.dict_handler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :copyright: (c) 2013 by the authors and contributors (See AUTHORS file). :license: BSD, see LICENSE for more details. """ from __future__ import print_function, unicode_literals from . import BaseHandler class DictHandler(BaseHandler): def load(self, data): return data def dump(self, data): return data kaptan-0.5.12/kaptan/handlers/ini_handler.py0000777000175000017500000000216313457476313017547 0ustar xx00000000000000# -*- coding: utf8 -*- """ kaptan.handlers.ini_handler ~~~~~~~~~~~~~~~~~~~~~~~~~~~ :copyright: (c) 2013 by the authors and contributors (See AUTHORS file). :license: BSD, see LICENSE for more details. """ from __future__ import print_function, unicode_literals try: import ConfigParser as configparser from StringIO import StringIO configparser.RawConfigParser.read_file = configparser.RawConfigParser.readfp # NOQA except ImportError: # Python 3 import configparser from io import StringIO from . import BaseHandler class KaptanIniParser(configparser.RawConfigParser): def as_dict(self): d = dict(self._sections) for k in d: d[k] = dict(self._defaults, **d[k]) d[k].pop('__name__', None) return d class IniHandler(BaseHandler): def load(self, value): config = KaptanIniParser() # ConfigParser.ConfigParser wants to read value as file / IO config.read_file(StringIO(value)) return config.as_dict() def dump(self, file_): raise NotImplementedError("Exporting .ini files is not supported.") kaptan-0.5.12/kaptan/handlers/json_handler.py0000777000175000017500000000075513457476313017746 0ustar xx00000000000000# -*- coding: utf8 -*- """ kaptan.handlers.json_handler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :copyright: (c) 2013 by the authors and contributors (See AUTHORS file). :license: BSD, see LICENSE for more details. """ from __future__ import print_function, unicode_literals import json from . import BaseHandler class JsonHandler(BaseHandler): def load(self, data): return json.loads(data) def dump(self, data, **kwargs): return json.dumps(data, **kwargs) kaptan-0.5.12/kaptan/handlers/pyfile_handler.py0000777000175000017500000000305513457476313020261 0ustar xx00000000000000# -*- coding: utf8 -*- """ kaptan.handlers.pyfile_handler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :copyright: (c) 2013 by the authors and contributors (See AUTHORS file). :license: BSD, see LICENSE for more details. """ from __future__ import print_function, unicode_literals import os import sys from . import BaseHandler def import_pyfile(pathname, mod_name=''): """Import the contents of filepath as a Python module. Parameters ---------- pathname: str Path to the .py file to be imported as a module mod_name: str Name of the module when imported Returns ------- mod The imported module Raises ------ IOError If file is not found """ if not os.path.isfile(pathname): raise IOError('File {0} not found.'.format(pathname)) if sys.version_info[0] == 3 and sys.version_info[1] > 2: # Python >= 3.3 import importlib.machinery loader = importlib.machinery.SourceFileLoader('', pathname) mod = loader.load_module(mod_name) else: # 2.6 >= Python <= 3.2 import imp mod = imp.load_source(mod_name, pathname) return mod class PyFileHandler(BaseHandler): def load(self, file_): module = import_pyfile(file_) data = dict() for key in dir(module): value = getattr(module, key) if not key.startswith("__"): data.update({key: value}) return data def dump(self, file_): raise NotImplementedError("Exporting python files is not supported.") kaptan-0.5.12/kaptan/handlers/yaml_handler.py0000777000175000017500000000126313457476313017732 0ustar xx00000000000000# -*- coding: utf8 -*- """ kaptan.handlers.yaml_handler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :copyright: (c) 2013 by the authors and contributors (See AUTHORS file). :license: BSD, see LICENSE for more details. """ from __future__ import print_function, unicode_literals import yaml from . import BaseHandler class YamlHandler(BaseHandler): def load(self, data, safe=True): if safe: func = yaml.safe_load else: func = yaml.load return func(data) def dump(self, data, safe=True, **kwargs): if safe: func = yaml.safe_dump else: func = yaml.dump return func(data, **kwargs) kaptan-0.5.12/kaptan.egg-info/0000777000175000017500000000000013457501045014575 5ustar xx00000000000000kaptan-0.5.12/kaptan.egg-info/PKG-INFO0000777000175000017500000002065713457501045015707 0ustar xx00000000000000Metadata-Version: 1.1 Name: kaptan Version: 0.5.12 Summary: Configuration manager Home-page: https://github.com/emre/kaptan Author: Emre Yilmaz Author-email: mail@emreyilmaz.me License: BSD Description: kaptan ====== |pypi| |docs| |build-status| |coverage| |license| configuration parser. installation ------------ .. code-block:: console $ pip install kaptan Also available as a package on FreeBSD, Debian, Arch Linux and Slackware. usage ----- **supported handlers** - dict - json - yaml - .ini - python file **default (dict) handler** .. code-block:: python config = kaptan.Kaptan() config.import_config({ 'environment': 'DEV', 'redis_uri': 'redis://localhost:6379/0', 'debug': False, 'pagination': { 'per_page': 10, 'limit': 20, } }) print config.get("pagination.limit") # output: 20 **json handler** .. code-block:: python config = kaptan.Kaptan(handler="json") config.import_config('{"everything": 42}') print config.get("everything") # output: 42 **yaml handler** .. code-block:: python config = kaptan.Kaptan(handler="yaml") config.import_config(""" product: price: value: 12.65 currency_list: 1. TL 2. EURO """) print config.get("product.price.currency_list.0") # output: TL or you can get from directly from the filename: ``config.import_config("configuration.yaml")`` **.ini handler** config.ini .. code-block:: ini [development] database_uri = mysql://root:123456@localhost/posts [production] database_uri = mysql://poor_user:poor_password@localhost/poor_posts .. code-block:: python config = kaptan.Kaptan(handler="ini") config.import_config('config.ini') print config.get("production.database_uri") # output: mysql://poor_user:poor_password@localhost/poor_posts **file handler** config.py .. code-block:: python DATABASE = 'mysql://root:123456@localhost/posts' DEBUG = False PAGINATION = { 'per_page': 10, 'limit': 20, } .. code-block:: python config = kaptan.Kaptan(handler="file") config.import_config('config') print config.get("DEBUG") # output: False exporting configuration ----------------------- .. code-block:: python config = kaptan.Kaptan(handler="file") config.import_config({ 'environment': 'DEV', 'redis_uri': 'redis://localhost:6379/0', 'debug': False, 'pagination': { 'per_page': 10, 'limit': 20, } }) print config.export("yaml") **output**: .. code-block:: yaml debug: false environment: DEV pagination: {limit: 20, per_page: 10} redis_uri: redis://localhost:6379/0 ``print config.export("json")`` outputs unindented json. ``.export`` accepts kwargs which pass into `json.dumps`. .. _json.dumps: http://docs.python.org/2/library/json.html#json.dump .. code-block:: python print config.export("json", indent=4) **output**: .. code-block:: json { "environment": "DEV", "debug": false, "pagination": { "per_page": 10, "limit": 20 }, "redis_uri": "redis://localhost:6379/0" } ``config.export('yaml')`` also supports the `kwargs for pyyaml`_. .. _kwargs for pyyaml: http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper New in Version 0.5.7: ``config.export('yaml', safe=True)`` will use ``.safe_dump``. cli --- exporting (defaults to json) .. code-block:: console $ echo "environment: DEV" > config.yaml $ kaptan config.yaml --export json > config.json $ cat config.json {"environment": "DEV"} getting a value .. code-block:: console $ kaptan config.yaml --key environment DEV specifying the handler .. code-block:: console $ mv config.yaml config.settings $ kaptan config.settings:yaml --export json {"environment": "DEV"} config from stdin .. code-block:: console $ echo '{"source": "stdin"}' | kaptan - {"source": "stdin"} $ echo 'source: stdin' | kaptan -:yaml {"source": "stdin"} merging configs .. code-block:: console $ echo "environment: PROD" > config.settings $ echo '{"source": "stdin"}' | kaptan - config.json config.settings:yaml {"environment": "PROD", "source": "stdin"} setting default handler .. code-block:: console $ echo "source: stdin" | kaptan --handler yaml - config.settings {"environment": "PROD", "source": "stdin"} writing json with yaml .. code-block:: console $ kaptan -:yaml -e json running tests ------------- with ``py.test``: .. code-block:: console $ py.test contributors ------------ - `Cenk Altı `_ - `Wesley Bitter `_ - `Mark Steve `_ - `Tony Narlock `_ - `Berker Peksag `_ - `Pradyun S. Gedam `_ see more at https://github.com/emre/kaptan/graphs/contributors. .. |pypi| image:: https://img.shields.io/pypi/v/kaptan.svg :alt: Python Package :target: http://badge.fury.io/py/kaptan .. |build-status| image:: https://img.shields.io/travis/emre/kaptan.svg :alt: Build Status :target: https://travis-ci.org/emre/kaptan .. |coverage| image:: https://codecov.io/gh/emre/kaptan/branch/master/graph/badge.svg :alt: Code Coverage :target: https://codecov.io/gh/emre/kaptan .. |license| image:: https://img.shields.io/github/license/emre/kaptan.svg :alt: License .. |docs| image:: https://readthedocs.org/projects/kaptan/badge/?version=latest :alt: Documentation Status :scale: 100% :target: https://readthedocs.org/projects/kaptan/ Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Operating System :: POSIX Classifier: Operating System :: MacOS :: MacOS X Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 kaptan-0.5.12/kaptan.egg-info/SOURCES.txt0000777000175000017500000000113113457501045016460 0ustar xx00000000000000AUTHORS LICENSE MANIFEST.in README.rst setup.py kaptan/__about__.py kaptan/__init__.py kaptan/__main__.py kaptan/_compat.py kaptan.egg-info/PKG-INFO kaptan.egg-info/SOURCES.txt kaptan.egg-info/dependency_links.txt kaptan.egg-info/entry_points.txt kaptan.egg-info/requires.txt kaptan.egg-info/top_level.txt kaptan/handlers/__init__.py kaptan/handlers/dict_handler.py kaptan/handlers/ini_handler.py kaptan/handlers/json_handler.py kaptan/handlers/pyfile_handler.py kaptan/handlers/yaml_handler.py requirements/base.txt requirements/dev.txt requirements/doc.txt requirements/test.txt tests/test_kaptan.pykaptan-0.5.12/kaptan.egg-info/dependency_links.txt0000777000175000017500000000000113457501045020646 0ustar xx00000000000000 kaptan-0.5.12/kaptan.egg-info/entry_points.txt0000777000175000017500000000005013457501045020071 0ustar xx00000000000000[console_scripts] kaptan = kaptan:main kaptan-0.5.12/kaptan.egg-info/requires.txt0000777000175000017500000000002013457501045017170 0ustar xx00000000000000PyYAML<6,>=3.13 kaptan-0.5.12/kaptan.egg-info/top_level.txt0000777000175000017500000000000713457501045017327 0ustar xx00000000000000kaptan kaptan-0.5.12/requirements/0000777000175000017500000000000013457501045014350 5ustar xx00000000000000kaptan-0.5.12/requirements/base.txt0000777000175000017500000000002013457500751016021 0ustar xx00000000000000PyYAML>=3.13,<6 kaptan-0.5.12/requirements/dev.txt0000777000175000017500000000003413457476313015700 0ustar xx00000000000000isort==4.3.15 flake8==3.7.5 kaptan-0.5.12/requirements/doc.txt0000777000175000017500000000007413457477437015703 0ustar xx00000000000000sphinx==2.0.1 sphinx-rtd-theme==0.4.3 sphinx-argparse==0.2.5kaptan-0.5.12/requirements/test.txt0000777000175000017500000000001613457476313016101 0ustar xx00000000000000pytest==4.3.1 kaptan-0.5.12/setup.cfg0000777000175000017500000000004613457501045013451 0ustar xx00000000000000[egg_info] tag_build = tag_date = 0 kaptan-0.5.12/setup.py0000777000175000017500000000406213457476313013355 0ustar xx00000000000000""" kaptan ====== :copyright: (c) 2013- authors and contributors (See AUTHORS file). :license: BSD, see LICENSE for more details. """ import sys from setuptools import find_packages, setup from setuptools.command.test import test as TestCommand about = {} with open("kaptan/__about__.py") as fp: exec(fp.read(), about) with open('requirements/base.txt') as f: install_reqs = [line for line in f.read().split('\n') if line] with open('requirements/test.txt') as f: tests_reqs = [line for line in f.read().split('\n') if line] if sys.version_info[0] > 2: readme = open('README.rst', encoding='utf-8').read() else: readme = open('README.rst').read() class PyTest(TestCommand): user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")] def initialize_options(self): TestCommand.initialize_options(self) self.pytest_args = [] def run_tests(self): import pytest errno = pytest.main(self.pytest_args) sys.exit(errno) setup( name=about['__title__'], version=about['__version__'], packages=find_packages(), url=about['__url__'], license=about['__license__'], author=about['__author__'], author_email=about['__email__'], description=about['__description__'], long_description=readme, install_requires=install_reqs, tests_require=tests_reqs, cmdclass={'test': PyTest}, entry_points=dict( console_scripts=[ 'kaptan = kaptan:main', ], ), classifiers=( 'Development Status :: 5 - Production/Stable', "Operating System :: POSIX", "Operating System :: MacOS :: MacOS X", 'Intended Audience :: Developers', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', ), ) kaptan-0.5.12/tests/0000777000175000017500000000000013457501045012767 5ustar xx00000000000000kaptan-0.5.12/tests/test_kaptan.py0000777000175000017500000001624713457476313015704 0ustar xx00000000000000# -*- coding: utf8 -*- """ kaptan ~~~~~~ :copyright: (c) 2013 by the authors and contributors (See AUTHORS file). :license: BSD, see LICENSE for more details. """ from __future__ import print_function, unicode_literals import json import os import os.path import sys import tempfile import pytest import kaptan try: import yaml except ImportError: yaml = None # python 2/3 compat try: unicode = unicode except NameError: # py changes unicode => str unicode = str PY2 = sys.version_info[0] == 2 sentinel = object() @pytest.fixture def testconfig(): return { 'debug': False, } def test_configuration_data(testconfig): config = kaptan.Kaptan() config.import_config(testconfig) assert 'debug' in config.configuration_data def test_main_get(): config = kaptan.Kaptan() config.import_config({ 'show_comments': True, 'entry_count': 10, }) assert config.get("entry_count", 25) == 10 assert config.get("entry_count") == 10 assert config.get("show_comments", None) assert config.get("show_comments", False) def test_nested_configuration(): config = kaptan.Kaptan() config.import_config({ 'pagination': { 'per_page': 20, 'limit': 5, } }) assert config.get("pagination.limit") == 5 def test_lists_on_configuration(): config = kaptan.Kaptan() config.import_config({ 'servers': ['redis1', 'redis2', 'redis3'], }) assert config.get('servers.0') == 'redis1' def test_upsert(testconfig): config = kaptan.Kaptan() config.import_config(testconfig) assert not config.get('debug') config.upsert('debug', True) assert config.get('debug') def test_default_dict_handler(testconfig): config = kaptan.Kaptan() config.import_config(testconfig) assert not config.configuration_data['debug'] def test_json_handler(testconfig): config = kaptan.Kaptan(handler='json') config.import_config(json.dumps(testconfig)) assert not config.get('debug') def test_json_file_handler(tmpdir): json_file = tmpdir.join('config.json') json_file.write("""{"development": { "DATABASE_URI": "mysql://root:123456@localhost/posts" }, "production": { "DATABASE_URI": "mysql://poor_user:poor_password@localhost/poor_posts" } } """) config = kaptan.Kaptan(handler='json') config.import_config(str(json_file)) assert config.get( 'production.DATABASE_URI' ) == 'mysql://poor_user:poor_password@localhost/poor_posts' @pytest.mark.skipif(yaml is None or not PY2, reason='needs yaml') def test_yaml_safedump(testconfig): testdict = { unicode("development"): { "DATABASE_URI": "mysql://root:123456@localhost/posts" }, "production": { "DATABASE_URI": "mysql://poor_user:poor_password@localhost/poor_posts" # NOQA } } config = kaptan.Kaptan() config.import_config(testdict) yamlconfig = kaptan.Kaptan() yamlconfig.import_config(config.get()) assert '!!python/unicode' not in yamlconfig.export('yaml') assert '!!python/unicode' not in yamlconfig.export('yaml', safe=True) assert '!!python/unicode' in yamlconfig.export('yaml', safe=False) @pytest.mark.skipif(yaml is None, reason='needs yaml') def test_yaml_handler(testconfig): config = kaptan.Kaptan(handler='yaml') config.import_config(yaml.safe_dump(testconfig)) assert not config.get("debug") @pytest.mark.skipif(yaml is None, reason='needs yaml') def test_yaml_file_handler(tmpdir, testconfig): yaml_file = tmpdir.join('config.yaml') yaml_file.write(""" development: DATABASE_URI: mysql://root:123456@localhost/posts production: DATABASE_URI: mysql://poor_user:poor_password@localhost/poor_posts """) config = kaptan.Kaptan(handler='yaml') config.import_config(str(yaml_file)) assert config.get('production.DATABASE_URI') == \ 'mysql://poor_user:poor_password@localhost/poor_posts' @pytest.mark.skipif(yaml is None, reason='needs yaml') def test_yml_file_handler(tmpdir): yml_file = tmpdir.join('config.yml') yml_file.write(""" development: DATABASE_URI: mysql://root:123456@localhost/posts production: DATABASE_URI: mysql://poor_user:poor_password@localhost/poor_posts """) config = kaptan.Kaptan() config.import_config(str(yml_file)) assert config.get('production.DATABASE_URI') == \ 'mysql://poor_user:poor_password@localhost/poor_posts' def test_ini_handler(testconfig): value = """[development] DATABASE_URI = mysql://root:123456@localhost/posts [production] DATABASE_URI = mysql://poor_user:poor_password@localhost/poor_posts """ config = kaptan.Kaptan(handler='ini') config.import_config(value) assert config.get( 'production.database_uri' ) == 'mysql://poor_user:poor_password@localhost/poor_posts' def test_ini_file_handler(tmpdir, testconfig): ini_file = tmpdir.join('config.ini') ini_file.write("""[development] DATABASE_URI = mysql://root:123456@localhost/posts [production] DATABASE_URI = mysql://poor_user:poor_password@localhost/poor_posts """) config = kaptan.Kaptan(handler='ini') config.import_config(str(ini_file)) assert config.get( 'production.database_uri' ) == 'mysql://poor_user:poor_password@localhost/poor_posts' def test_py_file_handler(testconfig, tmpdir, monkeypatch): py_file = tmpdir.join('config.py') py_file.write("""DATABASE = 'mysql://root:123456@localhost/girlz' DEBUG = False PAGINATION = { 'per_page': 10, 'limit': 20, } """) monkeypatch.syspath_prepend(str(tmpdir)) normalize_name = str(py_file).rpartition('.')[0] config = kaptan.Kaptan(handler='file') config.import_config(normalize_name) assert config.get("PAGINATION.limit") == 20 def test_py_file_away_handler(tmpdir, testconfig): py_file = tmpdir.join('config2.py') py_file.write("""DATABASE = 'mysql://root:123456@localhost/girlz' DEBUG = False PAGINATION = { 'per_page': 10, 'limit': 20, } """) config = kaptan.Kaptan() config.import_config(str(py_file)) assert config.get("PAGINATION.limit") == 20 def test_py_file_away_noexist_raises(tmpdir, testconfig): py_file = tmpdir.join('config3.py') config = kaptan.Kaptan() with pytest.raises(IOError): config.import_config(str(py_file)) def test_invalid_key(testconfig): config = kaptan.Kaptan() config.import_config(testconfig) with pytest.raises(KeyError): config.get('invalidkey') with pytest.raises(KeyError): config.get('invaliddict.invalidkey') def test_invalid_key_with_default(testconfig): config = kaptan.Kaptan() config.import_config(testconfig) assert config.get('invalid_key', 'default_value') == 'default_value' assert config.get('invalid_key.bar.baz', 'default_value') == 'default_value' def test_default_value_none(testconfig): config = kaptan.Kaptan() config.import_config(testconfig) assert config.get("invalid_key", None) is None assert config.get("invalid_key.bar.baz", None) is None def test_get_all_config(testconfig): config = kaptan.Kaptan() config.import_config(testconfig) assert isinstance(config.get(), dict) assert isinstance(config.get(''), dict)