[Python-modules-commits] [python-setoptconf] 01/02: Imported Upstream version 0.2.0
Daniel Stender
danstender-guest at moszumanska.debian.org
Sun Jun 21 18:08:36 UTC 2015
This is an automated email from the git hooks/post-receive script.
danstender-guest pushed a commit to branch master
in repository python-setoptconf.
commit 5ac9ccba2cbe8d8a5374eead07e2d3e4aa479a45
Author: Daniel Stender <debian at danielstender.com>
Date: Sun Jun 21 20:04:51 2015 +0200
Imported Upstream version 0.2.0
---
LICENSE | 22 +++
MANIFEST.in | 2 +
PKG-INFO | 79 ++++++++++
README.rst | 57 +++++++
setoptconf.egg-info/PKG-INFO | 79 ++++++++++
setoptconf.egg-info/SOURCES.txt | 34 ++++
setoptconf.egg-info/dependency_links.txt | 1 +
setoptconf.egg-info/requires.txt | 4 +
setoptconf.egg-info/top_level.txt | 1 +
setoptconf/__init__.py | 12 ++
setoptconf/config.py | 84 ++++++++++
setoptconf/datatype.py | 135 ++++++++++++++++
setoptconf/exception.py | 28 ++++
setoptconf/manager.py | 44 ++++++
setoptconf/setting.py | 81 ++++++++++
setoptconf/source/__init__.py | 19 +++
setoptconf/source/base.py | 9 ++
setoptconf/source/commandline.py | 167 ++++++++++++++++++++
setoptconf/source/configfile.py | 35 +++++
setoptconf/source/environment.py | 38 +++++
setoptconf/source/filebased.py | 105 +++++++++++++
setoptconf/source/jsonfile.py | 33 ++++
setoptconf/source/mapping.py | 20 +++
setoptconf/source/modobj.py | 59 +++++++
setoptconf/source/yamlfile.py | 34 ++++
setoptconf/util.py | 26 ++++
setup.cfg | 21 +++
setup.py | 70 +++++++++
test/test_configuration.py | 179 +++++++++++++++++++++
test/test_datatypes.py | 158 +++++++++++++++++++
test/test_directory_modifiers.py | 22 +++
test/test_file_sources.py | 260 +++++++++++++++++++++++++++++++
test/test_manager.py | 44 ++++++
test/test_settings.py | 58 +++++++
test/test_sources.py | 182 ++++++++++++++++++++++
35 files changed, 2202 insertions(+)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..37c3132
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License
+
+Copyright (c)2014 Jason Simeone
+
+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:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+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.
+
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..3b8be7d
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,2 @@
+include README.rst LICENSE
+
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..5a43079
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,79 @@
+Metadata-Version: 1.1
+Name: setoptconf
+Version: 0.2.0
+Summary: A module for retrieving program settings from various sources in a consistant method.
+Home-page: https://github.com/jayclassless/setoptconf
+Author: Jason Simeone
+Author-email: jay at classless.net
+License: MIT
+Description: ==========
+ setoptconf
+ ==========
+
+ .. image:: https://travis-ci.org/jayclassless/setoptconf.svg?branch=master
+ :target: https://travis-ci.org/jayclassless/setoptconf
+
+ ``setoptconf`` is a Python library that can be used to retrieve program settings
+ from a variety of common sources:
+
+ * Command Line
+ * Environment Variables
+ * INI Files
+ * JSON Files
+ * YAML Files
+ * Python Objects/Modules
+
+ The goal of this project is to define your desired settings in a simple and
+ consistent way, and then point setoptconf at as many of the sources as you'd
+ like to use, and let it comb them all, looking for your settings.
+
+ This README is admittedly very light on details. Full documentation will come
+ in time. For now, here's an example of its use:
+
+ Import the library::
+
+ import setoptconf as soc
+
+ Instantiate the manager::
+
+ manager = soc.ConfigurationManager('myprogram')
+
+ Define the settings we'd like to collect::
+
+ manager.add(soc.StringSetting('foo'))
+ manager.add(soc.IntegerSetting('bar', required=True))
+ manager.add(soc.BooleanSetting('baz', default=True))
+
+ Retreive the settings from our desired sources, combining the settings and
+ overriding with the priority implied by the order of the sources we pass::
+
+ config = manager.retrieve(
+ # This source pulls from the command line using argparse.
+ soc.CommandLineSource,
+
+ # This source pulls from environment variables that are prefixed
+ # with MYPROGRAM_*
+ soc.EnvironmentVariableSource,
+
+ # This source pulls from the named INI files. It stops at the first
+ # file it finds.
+ soc.ConfigFileSource(('.myprogramrc', '/etc/myprogram.conf')),
+ )
+
+ We now have a Configuration object named ``config`` that has three attributes;
+ ``foo``, ``bar``, and ``baz``.
+
+
+Keywords: settings,options,configuration,config,arguments
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..0f6e401
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,57 @@
+==========
+setoptconf
+==========
+
+.. image:: https://travis-ci.org/jayclassless/setoptconf.svg?branch=master
+ :target: https://travis-ci.org/jayclassless/setoptconf
+
+``setoptconf`` is a Python library that can be used to retrieve program settings
+from a variety of common sources:
+
+* Command Line
+* Environment Variables
+* INI Files
+* JSON Files
+* YAML Files
+* Python Objects/Modules
+
+The goal of this project is to define your desired settings in a simple and
+consistent way, and then point setoptconf at as many of the sources as you'd
+like to use, and let it comb them all, looking for your settings.
+
+This README is admittedly very light on details. Full documentation will come
+in time. For now, here's an example of its use:
+
+Import the library::
+
+ import setoptconf as soc
+
+Instantiate the manager::
+
+ manager = soc.ConfigurationManager('myprogram')
+
+Define the settings we'd like to collect::
+
+ manager.add(soc.StringSetting('foo'))
+ manager.add(soc.IntegerSetting('bar', required=True))
+ manager.add(soc.BooleanSetting('baz', default=True))
+
+Retreive the settings from our desired sources, combining the settings and
+overriding with the priority implied by the order of the sources we pass::
+
+ config = manager.retrieve(
+ # This source pulls from the command line using argparse.
+ soc.CommandLineSource,
+
+ # This source pulls from environment variables that are prefixed
+ # with MYPROGRAM_*
+ soc.EnvironmentVariableSource,
+
+ # This source pulls from the named INI files. It stops at the first
+ # file it finds.
+ soc.ConfigFileSource(('.myprogramrc', '/etc/myprogram.conf')),
+ )
+
+We now have a Configuration object named ``config`` that has three attributes;
+``foo``, ``bar``, and ``baz``.
+
diff --git a/setoptconf.egg-info/PKG-INFO b/setoptconf.egg-info/PKG-INFO
new file mode 100644
index 0000000..5a43079
--- /dev/null
+++ b/setoptconf.egg-info/PKG-INFO
@@ -0,0 +1,79 @@
+Metadata-Version: 1.1
+Name: setoptconf
+Version: 0.2.0
+Summary: A module for retrieving program settings from various sources in a consistant method.
+Home-page: https://github.com/jayclassless/setoptconf
+Author: Jason Simeone
+Author-email: jay at classless.net
+License: MIT
+Description: ==========
+ setoptconf
+ ==========
+
+ .. image:: https://travis-ci.org/jayclassless/setoptconf.svg?branch=master
+ :target: https://travis-ci.org/jayclassless/setoptconf
+
+ ``setoptconf`` is a Python library that can be used to retrieve program settings
+ from a variety of common sources:
+
+ * Command Line
+ * Environment Variables
+ * INI Files
+ * JSON Files
+ * YAML Files
+ * Python Objects/Modules
+
+ The goal of this project is to define your desired settings in a simple and
+ consistent way, and then point setoptconf at as many of the sources as you'd
+ like to use, and let it comb them all, looking for your settings.
+
+ This README is admittedly very light on details. Full documentation will come
+ in time. For now, here's an example of its use:
+
+ Import the library::
+
+ import setoptconf as soc
+
+ Instantiate the manager::
+
+ manager = soc.ConfigurationManager('myprogram')
+
+ Define the settings we'd like to collect::
+
+ manager.add(soc.StringSetting('foo'))
+ manager.add(soc.IntegerSetting('bar', required=True))
+ manager.add(soc.BooleanSetting('baz', default=True))
+
+ Retreive the settings from our desired sources, combining the settings and
+ overriding with the priority implied by the order of the sources we pass::
+
+ config = manager.retrieve(
+ # This source pulls from the command line using argparse.
+ soc.CommandLineSource,
+
+ # This source pulls from environment variables that are prefixed
+ # with MYPROGRAM_*
+ soc.EnvironmentVariableSource,
+
+ # This source pulls from the named INI files. It stops at the first
+ # file it finds.
+ soc.ConfigFileSource(('.myprogramrc', '/etc/myprogram.conf')),
+ )
+
+ We now have a Configuration object named ``config`` that has three attributes;
+ ``foo``, ``bar``, and ``baz``.
+
+
+Keywords: settings,options,configuration,config,arguments
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff --git a/setoptconf.egg-info/SOURCES.txt b/setoptconf.egg-info/SOURCES.txt
new file mode 100644
index 0000000..7315f41
--- /dev/null
+++ b/setoptconf.egg-info/SOURCES.txt
@@ -0,0 +1,34 @@
+LICENSE
+MANIFEST.in
+README.rst
+setup.cfg
+setup.py
+setoptconf/__init__.py
+setoptconf/config.py
+setoptconf/datatype.py
+setoptconf/exception.py
+setoptconf/manager.py
+setoptconf/setting.py
+setoptconf/util.py
+setoptconf.egg-info/PKG-INFO
+setoptconf.egg-info/SOURCES.txt
+setoptconf.egg-info/dependency_links.txt
+setoptconf.egg-info/requires.txt
+setoptconf.egg-info/top_level.txt
+setoptconf/source/__init__.py
+setoptconf/source/base.py
+setoptconf/source/commandline.py
+setoptconf/source/configfile.py
+setoptconf/source/environment.py
+setoptconf/source/filebased.py
+setoptconf/source/jsonfile.py
+setoptconf/source/mapping.py
+setoptconf/source/modobj.py
+setoptconf/source/yamlfile.py
+test/test_configuration.py
+test/test_datatypes.py
+test/test_directory_modifiers.py
+test/test_file_sources.py
+test/test_manager.py
+test/test_settings.py
+test/test_sources.py
\ No newline at end of file
diff --git a/setoptconf.egg-info/dependency_links.txt b/setoptconf.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/setoptconf.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/setoptconf.egg-info/requires.txt b/setoptconf.egg-info/requires.txt
new file mode 100644
index 0000000..bc55498
--- /dev/null
+++ b/setoptconf.egg-info/requires.txt
@@ -0,0 +1,4 @@
+
+
+[YAML]
+pyyaml
\ No newline at end of file
diff --git a/setoptconf.egg-info/top_level.txt b/setoptconf.egg-info/top_level.txt
new file mode 100644
index 0000000..10ce273
--- /dev/null
+++ b/setoptconf.egg-info/top_level.txt
@@ -0,0 +1 @@
+setoptconf
diff --git a/setoptconf/__init__.py b/setoptconf/__init__.py
new file mode 100644
index 0000000..f136a82
--- /dev/null
+++ b/setoptconf/__init__.py
@@ -0,0 +1,12 @@
+
+# pylint: disable=W0401
+
+from .config import *
+from .datatype import *
+from .exception import *
+from .manager import *
+from .setting import *
+from .source import *
+
+
+__version__ = '0.2.0'
diff --git a/setoptconf/config.py b/setoptconf/config.py
new file mode 100644
index 0000000..1906cf6
--- /dev/null
+++ b/setoptconf/config.py
@@ -0,0 +1,84 @@
+from .exception import MissingRequiredError, ReadOnlyError
+from .util import UnicodeMixin
+
+
+__all__ = (
+ 'Configuration',
+)
+
+
+class Configuration(UnicodeMixin):
+ def __init__(self, settings, parent=None):
+ self.__dict__['_parent'] = parent
+
+ self.__dict__['_settings'] = {}
+ for setting in settings:
+ self._settings[setting.name] = setting
+
+ def validate_setting(self, name):
+ if name in self._settings:
+ setting = self._settings[name]
+ if setting.required and not setting.established:
+ if self._parent:
+ self._parent.validate_setting(name)
+ else:
+ raise MissingRequiredError(name)
+ elif self._parent:
+ self._parent.validate_setting(name)
+ else:
+ raise AttributeError('No such setting "%s"' % name)
+
+ def validate(self):
+ for name in self:
+ self.validate_setting(name)
+
+ def __getattr__(self, name):
+ if name in self._settings:
+ if self._settings[name].established:
+ return self._settings[name].value
+ elif self._parent:
+ return getattr(self._parent, name)
+ else:
+ return self._settings[name].default
+ elif self._parent:
+ return getattr(self._parent, name)
+ else:
+ raise AttributeError('No such setting "%s"' % name)
+
+ def __getitem__(self, key):
+ return getattr(self, key)
+
+ def __setattr__(self, name, value):
+ raise ReadOnlyError('Cannot change the value of settings')
+
+ def __setitem__(self, key, value):
+ setattr(self, key, value)
+
+ def __delattr__(self, name):
+ raise ReadOnlyError('Cannot delete settings')
+
+ def __delitem__(self, key):
+ delattr(self, key)
+
+ def __iter__(self):
+ all_names = set(self._settings.keys())
+ if self._parent:
+ all_names.update(iter(self._parent))
+ return iter(all_names)
+
+ def __len__(self):
+ return len(list(iter(self)))
+
+ def __contains__(self, item):
+ return item in list(iter(self))
+
+ def __unicode__(self): # pragma: no cover
+ return u'Configuration(%s)' % (
+ u', '.join([
+ u'%s=%s' % (name, repr(self[name]))
+ for name in self
+ ])
+ )
+
+ def __repr__(self): # pragma: no cover
+ return '<%s>' % str(self)
diff --git a/setoptconf/datatype.py b/setoptconf/datatype.py
new file mode 100644
index 0000000..f89baff
--- /dev/null
+++ b/setoptconf/datatype.py
@@ -0,0 +1,135 @@
+from .exception import DataTypeError
+
+
+__all__ = (
+ 'DataType',
+ 'String',
+ 'Integer',
+ 'Float',
+ 'Boolean',
+ 'List',
+ 'Choice',
+)
+
+
+class DataType(object):
+ def sanitize(self, value):
+ raise NotImplementedError()
+
+ def is_valid(self, value):
+ try:
+ self.sanitize(value)
+ except DataTypeError:
+ return False
+ else:
+ return True
+
+
+class String(DataType):
+ def sanitize(self, value):
+ if value is not None:
+ value = unicode(value)
+ return value
+
+
+class Integer(DataType):
+ def sanitize(self, value):
+ if value is not None:
+ try:
+ value = int(value)
+ except:
+ raise DataTypeError('"%s" is not valid Integer' % value)
+ return value
+
+
+class Float(DataType):
+ def sanitize(self, value):
+ if value is not None:
+ try:
+ value = float(value)
+ except:
+ raise DataTypeError('"%s" is not valid Float' % value)
+ return value
+
+
+class Boolean(DataType):
+ TRUTHY_STRINGS = ('Y', 'YES', 'T', 'TRUE', 'ON', '1')
+ FALSY_STRINGS = ('', 'N', 'NO', 'F', 'FALSE', 'OFF', '0')
+
+ def sanitize(self, value):
+ if value is None or isinstance(value, bool):
+ return value
+
+ if isinstance(value, (int, long)):
+ return True if value else False
+
+ if isinstance(value, basestring) and value:
+ value = value.strip().upper()
+ if value in self.TRUTHY_STRINGS:
+ return True
+ elif value in self.FALSY_STRINGS:
+ return False
+ else:
+ raise DataTypeError(
+ 'Could not coerce "%s" to a Boolean' % (
+ value,
+ )
+ )
+
+ return True if value else False
+
+
+class List(DataType):
+ def __init__(self, subtype):
+ super(List, self).__init__()
+ if isinstance(subtype, DataType):
+ self.subtype = subtype
+ elif isinstance(subtype, type) and issubclass(subtype, DataType):
+ self.subtype = subtype()
+ else:
+ raise TypeError('subtype must be a DataType')
+
+ def sanitize(self, value):
+ if value is None:
+ return value
+
+ if not isinstance(value, (list, tuple)):
+ value = [value]
+
+ value = [
+ self.subtype.sanitize(v)
+ for v in value
+ ]
+
+ return value
+
+
+class Choice(DataType):
+ def __init__(self, choices, subtype=None):
+ super(Choice, self).__init__()
+
+ subtype = subtype or String()
+ if isinstance(subtype, DataType):
+ self.subtype = subtype
+ elif isinstance(subtype, type) and issubclass(subtype, DataType):
+ self.subtype = subtype()
+ else:
+ raise TypeError('subtype must be a DataType')
+
+ self.choices = choices
+
+ def sanitize(self, value):
+ if value is None:
+ return value
+
+ value = self.subtype.sanitize(value)
+
+ if value not in self.choices:
+ raise DataTypeError(
+ '"%s" is not one of (%s)' % (
+ value,
+ ', '.join([repr(c) for c in self.choices]),
+ )
+ )
+
+ return value
diff --git a/setoptconf/exception.py b/setoptconf/exception.py
new file mode 100644
index 0000000..2f02654
--- /dev/null
+++ b/setoptconf/exception.py
@@ -0,0 +1,28 @@
+
+__all__ = (
+ 'SetOptConfError',
+ 'NamingError',
+ 'DataTypeError',
+ 'MissingRequiredError',
+ 'ReadOnlyError',
+)
+
+
+class SetOptConfError(Exception):
+ pass
+
+
+class NamingError(SetOptConfError):
+ pass
+
+
+class DataTypeError(SetOptConfError):
+ pass
+
+
+class MissingRequiredError(SetOptConfError):
+ pass
+
+
+class ReadOnlyError(SetOptConfError):
+ pass
diff --git a/setoptconf/manager.py b/setoptconf/manager.py
new file mode 100644
index 0000000..1b5b791
--- /dev/null
+++ b/setoptconf/manager.py
@@ -0,0 +1,44 @@
+from copy import deepcopy
+
+from .config import Configuration
+from .setting import Setting
+from .source.base import Source
+
+
+__all__ = (
+ 'ConfigurationManager',
+)
+
+
+class ConfigurationManager(object):
+ def __init__(self, name):
+ self.name = name
+ self.settings = []
+
+ def add(self, setting):
+ if isinstance(setting, Setting):
+ self.settings.append(setting)
+ else:
+ raise TypeError('Can only add objects of type Setting')
+
+ def retrieve(self, *sources):
+ to_process = []
+ for source in reversed(sources):
+ if isinstance(source, Source):
+ to_process.append(source)
+ elif isinstance(source, type) and issubclass(source, Source):
+ to_process.append(source())
+ else:
+ raise TypeError('All sources must be a Source')
+
+ config = Configuration(settings=self.settings)
+ for source in to_process:
+ config = source.get_config(
+ deepcopy(self.settings),
+ manager=self,
+ parent=config,
+ )
+
+ config.validate()
+
+ return config
diff --git a/setoptconf/setting.py b/setoptconf/setting.py
new file mode 100644
index 0000000..f8e008b
--- /dev/null
+++ b/setoptconf/setting.py
@@ -0,0 +1,81 @@
+
+# pylint: disable=W0401,W0223
+
+import re
+
+from .datatype import *
+from .exception import NamingError
+from .util import UnicodeMixin
+
+
+__all__ = (
+ 'Setting',
+ 'StringSetting',
+ 'IntegerSetting',
+ 'FloatSetting',
+ 'BooleanSetting',
+ 'ListSetting',
+ 'ChoiceSetting',
+)
+
+
+class Setting(UnicodeMixin, DataType):
+ RE_NAME = re.compile(r'^[a-z](?:[a-z0-9]|[_](?![_]))*[a-z0-9]$')
+
+ def __init__(self, name, default=None, required=False):
+ if Setting.RE_NAME.match(name):
+ self.name = name
+ else:
+ raise NamingError(name)
+
+ self._value = None
+ self.default = self.sanitize(default)
+ self.required = required
+ self.established = False
+
+ @property
+ def value(self):
+ return self._value
+
+ @value.setter
+ def value(self, value):
+ self._value = self.sanitize(value)
+ self.established = True
+
+ def __unicode__(self): # pragma: no cover
+ return unicode(self.name)
+
+ def __repr__(self): # pragma: no cover
+ return '<%s(%s=%s)>' % (
+ self.__class__.__name__,
+ self.name,
+ self.value if self.established else '',
+ )
+
+
+class StringSetting(Setting, String):
+ pass
+
+
+class IntegerSetting(Setting, Integer):
+ pass
+
+
+class FloatSetting(Setting, Float):
+ pass
+
+
+class BooleanSetting(Setting, Boolean):
+ pass
+
+
+class ListSetting(Setting, List):
+ def __init__(self, name, subtype, **kwargs):
+ List.__init__(self, subtype)
+ Setting.__init__(self, name, **kwargs)
+
+
+class ChoiceSetting(Setting, Choice):
+ def __init__(self, name, choices, subtype=None, **kwargs):
+ Choice.__init__(self, choices, subtype=subtype)
+ Setting.__init__(self, name, **kwargs)
diff --git a/setoptconf/source/__init__.py b/setoptconf/source/__init__.py
new file mode 100644
index 0000000..8eea290
--- /dev/null
+++ b/setoptconf/source/__init__.py
@@ -0,0 +1,19 @@
+
+# pylint: disable=W0401
+
+from .base import *
+from .commandline import *
+from .configfile import *
+from .environment import *
+from .filebased import *
+from .jsonfile import *
+from .mapping import *
+from .modobj import *
+
+try:
+ import yaml
+except ImportError: # pragma: no cover
+ pass
+else:
+ del yaml
+ from .yamlfile import *
diff --git a/setoptconf/source/base.py b/setoptconf/source/base.py
new file mode 100644
index 0000000..b41e051
--- /dev/null
+++ b/setoptconf/source/base.py
@@ -0,0 +1,9 @@
+
+__all__ = (
+ 'Source',
+)
+
+
+class Source(object):
+ def get_config(self, settings, manager=None, parent=None):
+ raise NotImplementedError()
diff --git a/setoptconf/source/commandline.py b/setoptconf/source/commandline.py
new file mode 100644
index 0000000..9b6394b
--- /dev/null
+++ b/setoptconf/source/commandline.py
@@ -0,0 +1,167 @@
+import argparse
+import shlex
+import sys
+
+from copy import deepcopy
+
+from ..config import Configuration
+from ..setting import BooleanSetting, ChoiceSetting, ListSetting
+from .base import Source
+
+
+__all__ = (
+ 'CommandLineSource',
+)
+
+
+# pylint: disable=R0201
+
+
+class CommandLineSource(Source):
+ # pylint: disable=R0913
+ def __init__(
+ self,
+ arguments=None,
+ options=None,
+ version=None,
+ parser_options=None,
+ positional=None):
+ super(CommandLineSource, self).__init__()
+
+ if arguments is None:
+ self.arguments = sys.argv[1:]
+ elif isinstance(arguments, basestring):
+ self.arguments = shlex.split(arguments)
+ elif isinstance(arguments, (list, tuple)):
+ self.arguments = arguments
+ else:
+ raise TypeError('arguments must be a string or list of strings')
+
+ self.version = version
+ self.options = options or {}
+ self.parser_options = parser_options or {}
+ self.positional = positional or ()
+
+ def get_flags(self, setting):
+ if setting.name in self.options:
+ if 'flags' in self.options[setting.name]:
+ return self.options[setting.name]['flags']
+
+ flags = []
+ flag = '--%s' % setting.name.lower().replace('_', '-')
+ flags.append(flag)
+ return flags
+
+ def get_action(self, setting):
+ if isinstance(setting, BooleanSetting):
+ return 'store_false' if setting.default else 'store_true'
+ elif isinstance(setting, ListSetting):
+ return 'append'
+ else:
+ return 'store'
+
+ # pylint: disable=W0613
+ def get_default(self, setting):
+ # Caveat: Returning something other than SUPPRESS probably won't
+ # work the way you'd think.
+ return argparse.SUPPRESS
+
+ def get_type(self, setting):
+ if isinstance(setting, (ListSetting, BooleanSetting)):
+ return None
+ elif isinstance(setting, ChoiceSetting):
+ return setting.subtype.sanitize
+ else:
+ return setting.sanitize
+
+ def get_dest(self, setting):
+ return setting.name
+
+ def get_choices(self, setting):
+ if isinstance(setting, ChoiceSetting):
+ return setting.choices
+ else:
+ return None
+
+ def get_help(self, setting):
+ if setting.name in self.options:
+ if 'help' in self.options[setting.name]:
+ return self.options[setting.name]['help']
+ return None
+
+ def get_metavar(self, setting):
+ if setting.name in self.options:
+ if 'metavar' in self.options[setting.name]:
+ return self.options[setting.name]['metavar']
+ return None
+
+ def build_argument(self, setting):
+ flags = self.get_flags(setting)
+ action = self.get_action(setting)
+ default = self.get_default(setting)
+ argtype = self.get_type(setting)
+ dest = self.get_dest(setting)
+ choices = self.get_choices(setting)
+ arghelp = self.get_help(setting)
+ metavar = self.get_metavar(setting)
+
+ argument_kwargs = {
+ 'action': action,
+ 'default': default,
+ 'dest': dest,
+ 'help': arghelp,
+ }
+ if argtype:
+ argument_kwargs['type'] = argtype
+ if choices:
+ argument_kwargs['choices'] = choices
+ if metavar:
+ argument_kwargs['metavar'] = metavar
+
+ return flags, argument_kwargs
+
+ def build_parser(self, settings, manager):
+ parser_options = deepcopy(self.parser_options)
+ if not parser_options.get('prog') and manager:
+ parser_options['prog'] = manager.name
+ parser = argparse.ArgumentParser(**parser_options)
+
+ add_version = (self.version is not None)
+
+ for setting in settings:
+ flags, argument_kwargs = self.build_argument(setting)
+ parser.add_argument(*flags, **argument_kwargs)
+
+ if add_version and setting.name == 'version':
+ # Don't want to conflict with the desired setting
+ add_version = False
+
+ if add_version:
+ parser.add_argument(
+ '--version',
+ action='version',
+ version='%(prog)s ' + self.version,
+ )
+
+ if self.positional:
+ for name, options in self.positional:
+ parser.add_argument(name, **options)
+
+ return parser
+
+ def get_config(self, settings, manager=None, parent=None):
+ parser = self.build_parser(settings, manager)
+ parsed = parser.parse_args(self.arguments)
+
+ for setting in settings:
... 1457 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-setoptconf.git
More information about the Python-modules-commits
mailing list