From 25d6c405aff4167e801d0a4995083a56160b969e Mon Sep 17 00:00:00 2001 From: Andrew Shadura Date: Thu, 20 Aug 2015 15:58:27 +0200 Subject: Imported Upstream version 0.1.39 --- .travis.yml | 8 +++++ README.rst | 16 ++++++++-- docs/source/conf.py | 6 ++-- docs/source/index.rst | 6 +++- reconfigure/__init__.py | 2 +- reconfigure/builders/__init__.py | 8 ++--- reconfigure/configs/__init__.py | 36 +++++++++++----------- reconfigure/configs/base.py | 18 ++++++----- reconfigure/configs/ctdb.py | 2 +- reconfigure/includers/__init__.py | 10 +++--- reconfigure/includers/auto.py | 6 ++-- reconfigure/items/ajenti.py | 1 + reconfigure/items/bound.py | 19 +++++++----- reconfigure/items/ctdb.py | 2 +- reconfigure/items/fstab.py | 2 +- reconfigure/items/iptables.py | 2 -- reconfigure/items/netatalk.py | 3 +- reconfigure/items/samba.py | 33 +++++++++----------- reconfigure/items/supervisor.py | 3 +- reconfigure/nodes.py | 7 ++++- reconfigure/parsers/__init__.py | 22 +++++++------- reconfigure/parsers/bind9.py | 3 +- reconfigure/parsers/ini.py | 9 ++++-- reconfigure/parsers/iniparse/__init__.py | 28 +++++++++++------ reconfigure/parsers/iniparse/compat.py | 44 ++++++++++++++++++--------- reconfigure/parsers/iniparse/ini.py | 16 ++++++---- reconfigure/parsers/iniparse/utils.py | 4 +-- reconfigure/parsers/jsonparser.py | 3 +- reconfigure/parsers/nginx.py | 4 +-- reconfigure/tests/configs/ajenti_tests.py | 6 ++-- reconfigure/tests/configs/base_test.py | 4 +-- reconfigure/tests/configs/bind9_tests.py | 2 +- reconfigure/tests/configs/crontab_tests.py | 2 +- reconfigure/tests/configs/ctdb_tests.py | 2 +- reconfigure/tests/configs/dhcpd_tests.py | 2 +- reconfigure/tests/configs/exports_tests.py | 2 +- reconfigure/tests/configs/fstab_tests.py | 2 +- reconfigure/tests/configs/group_tests.py | 2 +- reconfigure/tests/configs/hosts_tests.py | 2 +- reconfigure/tests/configs/iptables_tests.py | 2 +- reconfigure/tests/configs/netatalk_tests.py | 3 +- reconfigure/tests/configs/nsd_tests.py | 2 +- reconfigure/tests/configs/passwd_tests.py | 2 +- reconfigure/tests/configs/resolv_tests.py | 2 +- reconfigure/tests/configs/samba_tests.py | 14 +++++++-- reconfigure/tests/configs/squid_tests.py | 2 +- reconfigure/tests/configs/supervisor_tests.py | 2 +- reconfigure/tests/parsers/base_test.py | 4 +-- reconfigure/tests/parsers/jsonparser_tests.py | 7 +++++ reconfigure/tests/parsers/nginx_tests.py | 4 +-- requirements.txt | 2 ++ 51 files changed, 239 insertions(+), 156 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7d91b9e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: python +python: + - "3.3" + - "2.7" + - "2.6" + +install: "pip install -r requirements.txt" +script: nosetests diff --git a/README.rst b/README.rst index b45af01..df387f5 100644 --- a/README.rst +++ b/README.rst @@ -1,6 +1,16 @@ -Reconfigure - Python object mapping for config files. +==================================================== +Reconfigure - Python object mapping for config files +==================================================== -Quickstart:: +.. image:: https://travis-ci.org/Eugeny/reconfigure.png + +`Browse API on SourceGraph `_ + +---------- +Quickstart +---------- + +:: >>> from reconfigure.configs import FSTabConfig >>> from reconfigure.items.fstab import FilesystemData @@ -137,4 +147,4 @@ Included parsers: * squid (``squid``) * nsd (``nsd``) * CSV-like space-separated values (``ssv``) - * JSON (``jsonparser``) \ No newline at end of file + * JSON (``jsonparser``) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1cbb69c..f879568 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -23,16 +23,16 @@ release = '1.0a1' exclude_patterns = [] add_function_parentheses = True -pygments_style = 'sphinx' +#pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- -html_theme = 'air' +#html_theme = 'air' #html_theme_options = {} -html_theme_path = ['../../../sphinx-themes'] +#html_theme_path = ['../../../sphinx-themes'] html_title = 'Reconfigure documentation' html_short_title = 'Reconfigure docs' diff --git a/docs/source/index.rst b/docs/source/index.rst index 940f2bd..eea3a8a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -12,7 +12,11 @@ Links: * `Source at GitHub `_ * Questions? `Email me `_ * `PyPI `_ -* `CI `_ + +`Browse API on SourceGraph `_ + +.. image:: https://sourcegraph.com/api/repos/github.com/Eugeny/reconfigure/badges/funcs.png +.. image:: https://sourcegraph.com/api/repos/github.com/Eugeny/reconfigure/badges/status.png Contents: --------- diff --git a/reconfigure/__init__.py b/reconfigure/__init__.py index a5f3762..31b9658 100644 --- a/reconfigure/__init__.py +++ b/reconfigure/__init__.py @@ -1 +1 @@ -__version__ = "0.1.29" +__version__ = "0.1.39" diff --git a/reconfigure/builders/__init__.py b/reconfigure/builders/__init__.py index d96710d..2057a95 100644 --- a/reconfigure/builders/__init__.py +++ b/reconfigure/builders/__init__.py @@ -2,15 +2,11 @@ Builders are used to convert Node Tree to Data Tree """ -from base import BaseBuilder -from bound import BoundBuilder -#from nginx import NginxBuilder -#from crontab import CrontabBuilder +from reconfigure.builders.base import BaseBuilder +from reconfigure.builders.bound import BoundBuilder __all__ = [ 'BaseBuilder', 'BoundBuilder', - #'NginxBuilder', - #'CrontabBuilder', ] diff --git a/reconfigure/configs/__init__.py b/reconfigure/configs/__init__.py index 6954547..f0a6a26 100644 --- a/reconfigure/configs/__init__.py +++ b/reconfigure/configs/__init__.py @@ -2,24 +2,24 @@ Configs are ready-to-use objects that link together Parsers, Includers and Builders to provide direct conversion between config files and Data tree. """ -from base import Reconfig -from ajenti import AjentiConfig -from bind9 import BIND9Config -from crontab import CrontabConfig -from ctdb import CTDBConfig, CTDBNodesConfig, CTDBPublicAddressesConfig -from dhcpd import DHCPDConfig -from exports import ExportsConfig -from fstab import FSTabConfig -from group import GroupConfig -from hosts import HostsConfig -from iptables import IPTablesConfig -from netatalk import NetatalkConfig -from nsd import NSDConfig -from passwd import PasswdConfig -from resolv import ResolvConfig -from samba import SambaConfig -from squid import SquidConfig -from supervisor import SupervisorConfig +from reconfigure.configs.base import Reconfig +from reconfigure.configs.ajenti import AjentiConfig +from reconfigure.configs.bind9 import BIND9Config +from reconfigure.configs.crontab import CrontabConfig +from reconfigure.configs.ctdb import CTDBConfig, CTDBNodesConfig, CTDBPublicAddressesConfig +from reconfigure.configs.dhcpd import DHCPDConfig +from reconfigure.configs.exports import ExportsConfig +from reconfigure.configs.fstab import FSTabConfig +from reconfigure.configs.group import GroupConfig +from reconfigure.configs.hosts import HostsConfig +from reconfigure.configs.iptables import IPTablesConfig +from reconfigure.configs.netatalk import NetatalkConfig +from reconfigure.configs.nsd import NSDConfig +from reconfigure.configs.passwd import PasswdConfig +from reconfigure.configs.resolv import ResolvConfig +from reconfigure.configs.samba import SambaConfig +from reconfigure.configs.squid import SquidConfig +from reconfigure.configs.supervisor import SupervisorConfig __all__ = [ diff --git a/reconfigure/configs/base.py b/reconfigure/configs/base.py index 0753246..5d0bb61 100644 --- a/reconfigure/configs/base.py +++ b/reconfigure/configs/base.py @@ -35,12 +35,13 @@ class Reconfig (object): if self.origin: self.content = open(self.origin, 'r').read() - try: - self.content = self.content.decode('utf8') - self.encoding = 'utf8' - except UnicodeDecodeError: - self.encoding = chardet.detect(self.content)['encoding'] - self.content = self.content.decode(self.encoding) + self.encoding = 'utf8' + if hasattr(self.content, 'decode'): # str (2) or bytes (3) + try: + self.content = self.content.decode('utf8') + except (UnicodeDecodeError, AttributeError): + self.encoding = chardet.detect(self.content)['encoding'] + self.content = self.content.decode(self.encoding) self.nodetree = self.parser.parse(self.content) if self.includer is not None: @@ -63,7 +64,10 @@ class Reconfig (object): result = {} for k in nodetree: - result[k or self.origin] = self.parser.stringify(nodetree[k]).encode(self.encoding) + v = self.parser.stringify(nodetree[k]) + if self.encoding != 'utf8': + v = v.encode(self.encoding) + result[k or self.origin] = v if self.origin is not None: for k in result: diff --git a/reconfigure/configs/ctdb.py b/reconfigure/configs/ctdb.py index 491ac28..1a74a00 100644 --- a/reconfigure/configs/ctdb.py +++ b/reconfigure/configs/ctdb.py @@ -37,7 +37,7 @@ class CTDBPublicAddressesConfig (Reconfig): """ def __init__(self, **kwargs): k = { - 'parser': SSVParser(), + 'parser': SSVParser(separator=' '), 'builder': BoundBuilder(PublicAddressesData), } k.update(kwargs) diff --git a/reconfigure/includers/__init__.py b/reconfigure/includers/__init__.py index 1128588..8a7e3e8 100644 --- a/reconfigure/includers/__init__.py +++ b/reconfigure/includers/__init__.py @@ -1,8 +1,8 @@ -from base import BaseIncluder -from auto import AutoIncluder -from bind9 import BIND9Includer -from nginx import NginxIncluder -from supervisor import SupervisorIncluder +from reconfigure.includers.base import BaseIncluder +from reconfigure.includers.auto import AutoIncluder +from reconfigure.includers.bind9 import BIND9Includer +from reconfigure.includers.nginx import NginxIncluder +from reconfigure.includers.supervisor import SupervisorIncluder __all__ = [ diff --git a/reconfigure/includers/auto.py b/reconfigure/includers/auto.py index 16844ca..c220d88 100644 --- a/reconfigure/includers/auto.py +++ b/reconfigure/includers/auto.py @@ -1,4 +1,4 @@ -from base import BaseIncluder +from reconfigure.includers.base import BaseIncluder from reconfigure.nodes import * import glob import os @@ -50,7 +50,9 @@ class AutoIncluder (BaseIncluder): if replacement: node.children[node.children.index(child)] = replacement else: - if child.origin != node.origin: + if child.origin is None: + child.origin = node.origin + elif child.origin != node.origin: node.children.remove(child) result.setdefault(child.origin, RootNode()).children.append(self.decompose_rec(child, result)) else: diff --git a/reconfigure/items/ajenti.py b/reconfigure/items/ajenti.py index 3756c5c..ef70501 100644 --- a/reconfigure/items/ajenti.py +++ b/reconfigure/items/ajenti.py @@ -31,6 +31,7 @@ class ConfigData (BoundData): AjentiData.bind_property('authentication', 'authentication') +AjentiData.bind_property('language', 'language') AjentiData.bind_property('installation_id', 'installation_id') AjentiData.bind_property('enable_feedback', 'enable_feedback') AjentiData.bind_child('http_binding', lambda x: x.get('bind'), item_class=HttpData) diff --git a/reconfigure/items/bound.py b/reconfigure/items/bound.py index f096965..fed73f4 100644 --- a/reconfigure/items/bound.py +++ b/reconfigure/items/bound.py @@ -84,7 +84,7 @@ class BoundDictionary (BoundCollection): self.datadict = dict((self.key(x), x) for x in self.data) def to_dict(self): - return dict((k, x.to_dict() if hasattr(x, 'to_dict') else x) for k, x in self.iteritems()) + return dict((k, x.to_dict() if hasattr(x, 'to_dict') else x) for k, x in self.items()) def __getitem__(self, key): self.rebuild_dict() @@ -95,6 +95,7 @@ class BoundDictionary (BoundCollection): if not key in self: self.append(value) self.datadict[key] = value + self.rebuild_dict() def __contains__(self, key): self.rebuild_dict() @@ -105,7 +106,10 @@ class BoundDictionary (BoundCollection): return self.datadict.__iter__() def iteritems(self): - return self.datadict.iteritems() + self.rebuild_dict() + return self.datadict.items() + + items = iteritems def setdefault(self, k, v): if not k in self: @@ -114,10 +118,11 @@ class BoundDictionary (BoundCollection): return self[k] def values(self): + self.rebuild_dict() return self.data def update(self, other): - for k, v in other.iteritems(): + for k, v in other.items(): self[k] = v def pop(self, key): @@ -136,7 +141,7 @@ class BoundData (object): """ def __init__(self, node=None, **kwargs): - if not node: + if node is None: node = self.template(**kwargs) self._node = node @@ -198,7 +203,7 @@ class BoundData (object): """ def pget(self): prop = path(self._node).get(node_property) - if prop: + if prop is not None: return getter(prop.value) else: return default @@ -206,7 +211,7 @@ class BoundData (object): def pset(self, value): if setter(value) in default_remove: node = path(self._node).get(node_property) - if node: + if node is not None: path(self._node).remove(node) else: path(self._node).set_property(node_property, setter(value)) @@ -228,7 +233,7 @@ class BoundData (object): """ def pget(self): prop = getattr(path(self._node), node_attribute) - if prop: + if prop is not None: return getter(prop) else: return getter(default) diff --git a/reconfigure/items/ctdb.py b/reconfigure/items/ctdb.py index f700c03..13fb9e2 100644 --- a/reconfigure/items/ctdb.py +++ b/reconfigure/items/ctdb.py @@ -1,6 +1,6 @@ from reconfigure.nodes import Node, PropertyNode from reconfigure.items.bound import BoundData -from util import yn_getter, yn_setter +from reconfigure.items.util import yn_getter, yn_setter class CTDBData (BoundData): diff --git a/reconfigure/items/fstab.py b/reconfigure/items/fstab.py index 81b8060..30ab030 100644 --- a/reconfigure/items/fstab.py +++ b/reconfigure/items/fstab.py @@ -14,7 +14,7 @@ class FilesystemData (BoundData): Node('token', children=[PropertyNode('value', 'none')]), Node('token', children=[PropertyNode('value', 'none')]), Node('token', children=[PropertyNode('value', 'auto')]), - Node('token', children=[PropertyNode('value', 'none')]), + Node('token', children=[PropertyNode('value', 'defaults,rw')]), Node('token', children=[PropertyNode('value', '0')]), Node('token', children=[PropertyNode('value', '0')]), ]) diff --git a/reconfigure/items/iptables.py b/reconfigure/items/iptables.py index d4656ff..195758b 100644 --- a/reconfigure/items/iptables.py +++ b/reconfigure/items/iptables.py @@ -80,7 +80,6 @@ class OptionData (BoundData): @staticmethod def create(template_id): - print 'new' t = OptionData.templates[template_id] return OptionData(Node( 'option', @@ -93,7 +92,6 @@ class OptionData (BoundData): @staticmethod def create_destination(): - print 'new' return OptionData(Node( 'option', Node('argument', PropertyNode('value', 'ACCEPT')), diff --git a/reconfigure/items/netatalk.py b/reconfigure/items/netatalk.py index e4957cf..b3863d9 100644 --- a/reconfigure/items/netatalk.py +++ b/reconfigure/items/netatalk.py @@ -1,6 +1,6 @@ from reconfigure.nodes import Node, PropertyNode from reconfigure.items.bound import BoundData -from util import yn_getter, yn_setter +from reconfigure.items.util import yn_getter, yn_setter class NetatalkData (BoundData): @@ -28,6 +28,7 @@ NetatalkData.bind_collection('shares', selector=lambda x: x.name != 'Global', it GlobalData.bind_property('afp port', 'afp_port', default='548') GlobalData.bind_property('cnid listen', 'cnid_listen', default='localhost:4700') +GlobalData.bind_property('uam list', 'uam_list', default='uams_dhx.so,uams_dhx2.so') GlobalData.bind_property( 'zeroconf', 'zeroconf', default=True, getter=yn_getter, setter=yn_setter) diff --git a/reconfigure/items/samba.py b/reconfigure/items/samba.py index 079da5e..01b6f6f 100644 --- a/reconfigure/items/samba.py +++ b/reconfigure/items/samba.py @@ -1,6 +1,6 @@ from reconfigure.nodes import Node, PropertyNode from reconfigure.items.bound import BoundData -from util import yn_getter, yn_setter +from reconfigure.items.util import yn_getter, yn_setter class SambaData (BoundData): @@ -14,11 +14,16 @@ class GlobalData (BoundData): class ShareData (BoundData): fields = [ 'comment', 'path', 'guest ok', 'browseable', 'create mask', 'directory mask', 'read only', - 'follow symlinks', 'wide links', + 'follow symlinks', 'wide links', 'fstype', 'write list', 'veto files', + 'force create mode', 'force directory mode', ] defaults = [ '', '', 'no', 'yes', '0744', '0755', 'yes', - 'yes', 'no', + 'yes', 'no', 'NTFS', '', '', '000', '000', + ] + default_values = [ + '', '', False, True, '0744', '0755', True, + True, False, '', '', '', '000', '000', ] def template(self): @@ -42,18 +47,10 @@ GlobalData.bind_property('log file', 'log_file', default='') GlobalData.bind_property('security', 'security', default='user') ShareData.bind_name('name') -ShareData.bind_property('path', 'path', default='') -ShareData.bind_property('comment', 'comment', default='') -ShareData.bind_property('create mask', 'create_mask', default='0744') -ShareData.bind_property('directory mask', 'directory_mask', default='0755') - -for x, y in [ - ('guest ok', False), - ('browseable', True), - ('read only', True), - ('follow symlinks', True), - ('wide links', False), -]: - ShareData.bind_property( - x, x.replace(' ', '_'), default=y, - getter=yn_getter, setter=yn_setter) +for f, d in zip(ShareData.fields, ShareData.default_values): + if d not in [True, False]: + ShareData.bind_property(f, f.replace(' ', '_'), default=d) + else: + ShareData.bind_property( + f, f.replace(' ', '_'), default=d, + getter=yn_getter, setter=yn_setter) diff --git a/reconfigure/items/supervisor.py b/reconfigure/items/supervisor.py index a8e462f..b1d201c 100644 --- a/reconfigure/items/supervisor.py +++ b/reconfigure/items/supervisor.py @@ -12,11 +12,12 @@ class ProgramData (BoundData): def template(self): return Node('program:new', - PropertyNode('command', '127.0.0.1'), + PropertyNode('command', 'false'), ) SupervisorData.bind_collection('programs', item_class=ProgramData, selector=lambda x: x.name.startswith('program:')) ProgramData.bind_name('name', getter=lambda x: x[8:], setter=lambda x: 'program:%s' % x) +ProgramData.bind_attribute('comment', 'comment') for i in range(0, len(ProgramData.fields)): ProgramData.bind_property(ProgramData.fields[i], ProgramData.fields[i], default_remove=[None, '']) diff --git a/reconfigure/nodes.py b/reconfigure/nodes.py index 3335ad5..8c2c2d4 100644 --- a/reconfigure/nodes.py +++ b/reconfigure/nodes.py @@ -25,6 +25,8 @@ class Node (object): s += ' (%s)' % self.comment s += '\n' for child in self.children: + if child.origin != self.origin: + s += '\t@%s\n' % child.origin s += '\n'.join('\t' + x for x in str(child).splitlines()) + '\n' return s @@ -126,7 +128,7 @@ class Node (object): Creates or replaces a child :class:`PropertyNode` by name. """ node = self.get(name) - if not node: + if node is None: node = PropertyNode(name, value) self.append(node) node.value = value @@ -160,6 +162,9 @@ class PropertyNode (Node): Node.__eq__(self, other) and \ self.value == other.value + def __hash__(self): + return Node.__hash__(self) + hash(self.value) + def __str__(self): s = '%s = %s' % (self.name, self.value) if self.comment: diff --git a/reconfigure/parsers/__init__.py b/reconfigure/parsers/__init__.py index 8de7aeb..af88033 100644 --- a/reconfigure/parsers/__init__.py +++ b/reconfigure/parsers/__init__.py @@ -1,14 +1,14 @@ -from base import BaseParser -from bind9 import BIND9Parser -from exports import ExportsParser -from ini import IniFileParser -from iptables import IPTablesParser -from jsonparser import JsonParser -from nginx import NginxParser -from nsd import NSDParser -from ssv import SSVParser -from squid import SquidParser -from crontab import CrontabParser +from reconfigure.parsers.base import BaseParser +from reconfigure.parsers.bind9 import BIND9Parser +from reconfigure.parsers.exports import ExportsParser +from reconfigure.parsers.ini import IniFileParser +from reconfigure.parsers.iptables import IPTablesParser +from reconfigure.parsers.jsonparser import JsonParser +from reconfigure.parsers.nginx import NginxParser +from reconfigure.parsers.nsd import NSDParser +from reconfigure.parsers.ssv import SSVParser +from reconfigure.parsers.squid import SquidParser +from reconfigure.parsers.crontab import CrontabParser __all__ = [ 'BaseParser', diff --git a/reconfigure/parsers/bind9.py b/reconfigure/parsers/bind9.py index d5c8e01..123a799 100644 --- a/reconfigure/parsers/bind9.py +++ b/reconfigure/parsers/bind9.py @@ -9,7 +9,8 @@ class BIND9Parser (NginxParser): tokens = [ (r"[\w_]+\s*?.*?{", lambda s, t: ('section_start', t)), - (r"[\w\d_:]+?.*?;", lambda s, t: ('option', t)), + (r"[\w\d_:.]+?.*?;", lambda s, t: ('option', t)), + (r"\".*?\"\s*;", lambda s, t: ('option', t)), (r"\s", lambda s, t: 'whitespace'), (r"$^", lambda s, t: 'newline'), (r"\#.*?\n", lambda s, t: ('comment', t)), diff --git a/reconfigure/parsers/ini.py b/reconfigure/parsers/ini.py index dbd0c7c..2f3b82e 100644 --- a/reconfigure/parsers/ini.py +++ b/reconfigure/parsers/ini.py @@ -1,7 +1,11 @@ from reconfigure.nodes import * from reconfigure.parsers import BaseParser -from iniparse import INIConfig -from StringIO import StringIO +from reconfigure.parsers.iniparse import INIConfig + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO class IniFileParser (BaseParser): @@ -48,7 +52,6 @@ class IniFileParser (BaseParser): def stringify(self, tree): cp = INIConfig() - for section in tree.children: if self.sectionless and section.name is None: sectionname = self.nullsection diff --git a/reconfigure/parsers/iniparse/__init__.py b/reconfigure/parsers/iniparse/__init__.py index 618bd20..ca5d579 100644 --- a/reconfigure/parsers/iniparse/__init__.py +++ b/reconfigure/parsers/iniparse/__init__.py @@ -3,17 +3,25 @@ # Copyright (c) 2007 Tim Lauridsen # All Rights Reserved. See LICENSE-PSF & LICENSE for details. -from ini import INIConfig, change_comment_syntax -from config import BasicConfig, ConfigNamespace -from compat import RawConfigParser, ConfigParser, SafeConfigParser -from utils import tidy +from reconfigure.parsers.iniparse.ini import INIConfig, change_comment_syntax +from reconfigure.parsers.iniparse.config import BasicConfig, ConfigNamespace +from reconfigure.parsers.iniparse.compat import RawConfigParser, ConfigParser, SafeConfigParser +from reconfigure.parsers.iniparse.utils import tidy -from ConfigParser import DuplicateSectionError, \ - NoSectionError, NoOptionError, \ - InterpolationMissingOptionError, \ - InterpolationDepthError, \ - InterpolationSyntaxError, \ - DEFAULTSECT, MAX_INTERPOLATION_DEPTH +try: + from ConfigParser import DuplicateSectionError, \ + NoSectionError, NoOptionError, \ + InterpolationMissingOptionError, \ + InterpolationDepthError, \ + InterpolationSyntaxError, \ + DEFAULTSECT, MAX_INTERPOLATION_DEPTH +except ImportError: + from configparser import DuplicateSectionError, \ + NoSectionError, NoOptionError, \ + InterpolationMissingOptionError, \ + InterpolationDepthError, \ + InterpolationSyntaxError, \ + DEFAULTSECT, MAX_INTERPOLATION_DEPTH __all__ = [ 'BasicConfig', 'ConfigNamespace', diff --git a/reconfigure/parsers/iniparse/compat.py b/reconfigure/parsers/iniparse/compat.py index 17c4f67..01df27c 100644 --- a/reconfigure/parsers/iniparse/compat.py +++ b/reconfigure/parsers/iniparse/compat.py @@ -12,19 +12,33 @@ The underlying INIConfig object can be accessed as cfg.data """ import re -from ConfigParser import DuplicateSectionError, \ - NoSectionError, NoOptionError, \ - InterpolationMissingOptionError, \ - InterpolationDepthError, \ - InterpolationSyntaxError, \ - DEFAULTSECT, MAX_INTERPOLATION_DEPTH +try: + from ConfigParser import DuplicateSectionError, \ + NoSectionError, NoOptionError, \ + InterpolationMissingOptionError, \ + InterpolationDepthError, \ + InterpolationSyntaxError, \ + DEFAULTSECT, MAX_INTERPOLATION_DEPTH + + # These are imported only for compatiability. + # The code below does not reference them directly. + from ConfigParser import Error, InterpolationError, \ + MissingSectionHeaderError, ParsingError +except ImportError: + from configparser import DuplicateSectionError, \ + NoSectionError, NoOptionError, \ + InterpolationMissingOptionError, \ + InterpolationDepthError, \ + InterpolationSyntaxError, \ + DEFAULTSECT, MAX_INTERPOLATION_DEPTH + + # These are imported only for compatiability. + # The code below does not reference them directly. + from configparser import Error, InterpolationError, \ + MissingSectionHeaderError, ParsingError + +import reconfigure.parsers.iniparse.ini -# These are imported only for compatiability. -# The code below does not reference them directly. -from ConfigParser import Error, InterpolationError, \ - MissingSectionHeaderError, ParsingError - -import ini class RawConfigParser(object): def __init__(self, defaults=None, dict_type=dict): @@ -56,7 +70,7 @@ class RawConfigParser(object): # The default section is the only one that gets the case-insensitive # treatment - so it is special-cased here. if section.lower() == "default": - raise ValueError, 'Invalid section name: %s' % section + raise ValueError('Invalid section name: %s' % section) if self.has_section(section): raise DuplicateSectionError(section) @@ -143,7 +157,7 @@ class RawConfigParser(object): def getboolean(self, section, option): v = self.get(section, option) if v.lower() not in self._boolean_states: - raise ValueError, 'Not a boolean: %s' % v + raise ValueError('Not a boolean: %s' % v) return self._boolean_states[v.lower()] def has_option(self, section, option): @@ -234,7 +248,7 @@ class ConfigParser(RawConfigParser): if "%(" in value: try: value = value % vars - except KeyError, e: + except KeyError as e: raise InterpolationMissingOptionError( option, section, rawval, e.args[0]) else: diff --git a/reconfigure/parsers/iniparse/ini.py b/reconfigure/parsers/iniparse/ini.py index 7881fd2..84611ba 100644 --- a/reconfigure/parsers/iniparse/ini.py +++ b/reconfigure/parsers/iniparse/ini.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals """Access and/or modify INI files * Compatiable with ConfigParser @@ -42,9 +43,12 @@ Example: # Backward-compatiable with ConfigParser import re -from ConfigParser import DEFAULTSECT, ParsingError, MissingSectionHeaderError +try: + from ConfigParser import DEFAULTSECT, ParsingError, MissingSectionHeaderError +except ImportError: + from configparser import DEFAULTSECT, ParsingError, MissingSectionHeaderError -import config +from reconfigure.parsers.iniparse import config class LineType(object): line = None @@ -465,7 +469,7 @@ class INIConfig(config.ConfigNamespace): self._sections = {} if defaults is None: defaults = {} self._defaults = INISection(LineContainer(), optionxformsource=self) - for name, value in defaults.iteritems(): + for name, value in defaults.items(): self._defaults[name] = value if fp is not None: self._readfp(fp) @@ -514,7 +518,7 @@ class INIConfig(config.ConfigNamespace): def __str__(self): if self._bom: - fmt = u'\ufeff%s' + fmt = '\ufeff%s' else: fmt = '%s' return fmt % self._data.__str__() @@ -551,8 +555,8 @@ class INIConfig(config.ConfigNamespace): for line in readline_iterator(fp): # Check for BOM on first line - if linecount == 0 and isinstance(line, unicode): - if line[0] == u'\ufeff': + if linecount == 0: + if line[0] == '\ufeff': line = line[1:] self._bom = True diff --git a/reconfigure/parsers/iniparse/utils.py b/reconfigure/parsers/iniparse/utils.py index 9cb7488..bfd4fd7 100644 --- a/reconfigure/parsers/iniparse/utils.py +++ b/reconfigure/parsers/iniparse/utils.py @@ -1,5 +1,5 @@ -import compat -from ini import LineContainer, EmptyLine +from reconfigure.parsers.iniparse import compat +from reconfigure.parsers.iniparse.ini import LineContainer, EmptyLine def tidy(cfg): """Clean up blank lines. diff --git a/reconfigure/parsers/jsonparser.py b/reconfigure/parsers/jsonparser.py index c1eaee6..1c55e97 100644 --- a/reconfigure/parsers/jsonparser.py +++ b/reconfigure/parsers/jsonparser.py @@ -14,7 +14,8 @@ class JsonParser (BaseParser): return node def load_node_rec(self, node, json): - for k, v in json.iteritems(): + for k in sorted(json.keys()): + v = json[k] if isinstance(v, dict): child = Node(k) node.children.append(child) diff --git a/reconfigure/parsers/nginx.py b/reconfigure/parsers/nginx.py index 661cfcd..f0fe202 100644 --- a/reconfigure/parsers/nginx.py +++ b/reconfigure/parsers/nginx.py @@ -9,11 +9,11 @@ class NginxParser (BaseParser): """ tokens = [ + (r"[\w_]+\s*?.*?{", lambda s, t: ('section_start', t)), (r"[\w_]+?.+?;", lambda s, t: ('option', t)), (r"\s", lambda s, t: 'whitespace'), (r"$^", lambda s, t: 'newline'), (r"\#.*?\n", lambda s, t: ('comment', t)), - (r"[\w_]+\s*?.*?{", lambda s, t: ('section_start', t)), (r"\}", lambda s, t: 'section_end'), ] token_comment = '#' @@ -44,7 +44,7 @@ class NginxParser (BaseParser): next_comment += '\n' next_comment += token[1].strip('#/*').strip() if token[0] == 'option': - if ' ' in token[1]: + if ' ' in token[1] and not token[1][0] in ['"', "'"]: k, v = token[1].split(None, 1) else: v = token[1] diff --git a/reconfigure/tests/configs/ajenti_tests.py b/reconfigure/tests/configs/ajenti_tests.py index 56a1dc1..66a0526 100644 --- a/reconfigure/tests/configs/ajenti_tests.py +++ b/reconfigure/tests/configs/ajenti_tests.py @@ -1,7 +1,7 @@ import json from reconfigure.configs import AjentiConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class AjentiConfigTest (BaseConfigTest): @@ -12,6 +12,7 @@ class AjentiConfigTest (BaseConfigTest): "host": "0.0.0.0", "port": 8000 }, + "language": null, "enable_feedback": true, "installation_id": null, "users": { @@ -34,6 +35,7 @@ class AjentiConfigTest (BaseConfigTest): 'authentication': False, 'enable_feedback': True, 'installation_id': None, + 'language': None, 'http_binding': {'host': '0.0.0.0', 'port': 8000}, 'ssl': {'certificate_path': '', 'enable': False}, 'users': {'test': { @@ -46,7 +48,7 @@ class AjentiConfigTest (BaseConfigTest): config = AjentiConfig - stringify_filter = staticmethod(json.loads) + stringify_filter = staticmethod(lambda x: json.loads(str(x))) del BaseConfigTest diff --git a/reconfigure/tests/configs/base_test.py b/reconfigure/tests/configs/base_test.py index 1824819..aefb13c 100644 --- a/reconfigure/tests/configs/base_test.py +++ b/reconfigure/tests/configs/base_test.py @@ -24,13 +24,13 @@ class BaseConfigTest (unittest.TestCase): #self.assertTrue(self.__class__.result== config.tree.to_dict()) a, b = self.__class__.result, config.tree.to_dict() if a != b: - print 'SOURCE: %s\nGENERATED: %s\n' % (json.dumps(a, indent=4), json.dumps(b, indent=4)) + print('SOURCE: %s\nGENERATED: %s\n' % (json.dumps(a, indent=4), json.dumps(b, indent=4))) self.assertEquals(a, b) result = config.save() s_filter = self.__class__.stringify_filter #print s_filter(result[None]) - for k, v in result.iteritems(): + for k, v in result.items(): self.assertEquals( s_filter(self.__class__.sources[k]), s_filter(v) diff --git a/reconfigure/tests/configs/bind9_tests.py b/reconfigure/tests/configs/bind9_tests.py index ee0c05a..fabbd2f 100644 --- a/reconfigure/tests/configs/bind9_tests.py +++ b/reconfigure/tests/configs/bind9_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import BIND9Config -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class BIND9ConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/crontab_tests.py b/reconfigure/tests/configs/crontab_tests.py index f1b28fe..15d0eff 100644 --- a/reconfigure/tests/configs/crontab_tests.py +++ b/reconfigure/tests/configs/crontab_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import CrontabConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class CrontabConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/ctdb_tests.py b/reconfigure/tests/configs/ctdb_tests.py index 7437ef7..6ef81d9 100644 --- a/reconfigure/tests/configs/ctdb_tests.py +++ b/reconfigure/tests/configs/ctdb_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import CTDBConfig, CTDBNodesConfig, CTDBPublicAddressesConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class CTDBNodesConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/dhcpd_tests.py b/reconfigure/tests/configs/dhcpd_tests.py index 73fbc74..eb98068 100644 --- a/reconfigure/tests/configs/dhcpd_tests.py +++ b/reconfigure/tests/configs/dhcpd_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import DHCPDConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class DHCPDConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/exports_tests.py b/reconfigure/tests/configs/exports_tests.py index be85736..28b53d1 100644 --- a/reconfigure/tests/configs/exports_tests.py +++ b/reconfigure/tests/configs/exports_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import ExportsConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class ExportsConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/fstab_tests.py b/reconfigure/tests/configs/fstab_tests.py index 9ffe19b..1232349 100644 --- a/reconfigure/tests/configs/fstab_tests.py +++ b/reconfigure/tests/configs/fstab_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import FSTabConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class FSTabConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/group_tests.py b/reconfigure/tests/configs/group_tests.py index b53dc5c..d3c31fe 100644 --- a/reconfigure/tests/configs/group_tests.py +++ b/reconfigure/tests/configs/group_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import GroupConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class GroupConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/hosts_tests.py b/reconfigure/tests/configs/hosts_tests.py index e202929..e90ed2a 100644 --- a/reconfigure/tests/configs/hosts_tests.py +++ b/reconfigure/tests/configs/hosts_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import HostsConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class FSTabConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/iptables_tests.py b/reconfigure/tests/configs/iptables_tests.py index 335e081..f69f58f 100644 --- a/reconfigure/tests/configs/iptables_tests.py +++ b/reconfigure/tests/configs/iptables_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import IPTablesConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class IPTablesConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/netatalk_tests.py b/reconfigure/tests/configs/netatalk_tests.py index ab9f693..c3bf1a6 100644 --- a/reconfigure/tests/configs/netatalk_tests.py +++ b/reconfigure/tests/configs/netatalk_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import NetatalkConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class NetatalkConfigTest (BaseConfigTest): @@ -19,6 +19,7 @@ ea=sys "global": { "zeroconf": True, "cnid_listen": "localhost:4700", + "uam_list": 'uams_dhx.so,uams_dhx2.so', "afp_port": "123", }, "shares": [ diff --git a/reconfigure/tests/configs/nsd_tests.py b/reconfigure/tests/configs/nsd_tests.py index d91b0bd..03809e7 100644 --- a/reconfigure/tests/configs/nsd_tests.py +++ b/reconfigure/tests/configs/nsd_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import NSDConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class NSDConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/passwd_tests.py b/reconfigure/tests/configs/passwd_tests.py index 8f9a5de..f0d797a 100644 --- a/reconfigure/tests/configs/passwd_tests.py +++ b/reconfigure/tests/configs/passwd_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import PasswdConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class PasswdConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/resolv_tests.py b/reconfigure/tests/configs/resolv_tests.py index d7bedc8..37854e3 100644 --- a/reconfigure/tests/configs/resolv_tests.py +++ b/reconfigure/tests/configs/resolv_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import ResolvConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class ResolvConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/samba_tests.py b/reconfigure/tests/configs/samba_tests.py index c6ce44c..7a5865c 100644 --- a/reconfigure/tests/configs/samba_tests.py +++ b/reconfigure/tests/configs/samba_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import SambaConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class SambaConfigTest (BaseConfigTest): @@ -48,6 +48,11 @@ directory mask=0700 "guest_ok": False, "path": "", 'wide_links': False, + "fstype": "", + "force_create_mode": "000", + "force_directory_mode": "000", + "veto_files": "", + "write_list": "", }, { "name": "profiles", @@ -59,7 +64,12 @@ directory mask=0700 "read_only": True, "guest_ok": False, "path": "/home/samba/profiles", - 'wide_links': False + 'wide_links': False, + "fstype": "", + "force_create_mode": "000", + "force_directory_mode": "000", + "veto_files": "", + "write_list": "", } ] } diff --git a/reconfigure/tests/configs/squid_tests.py b/reconfigure/tests/configs/squid_tests.py index 011d4bf..81eaf87 100644 --- a/reconfigure/tests/configs/squid_tests.py +++ b/reconfigure/tests/configs/squid_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import SquidConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class SquidConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/configs/supervisor_tests.py b/reconfigure/tests/configs/supervisor_tests.py index 8656128..b304654 100644 --- a/reconfigure/tests/configs/supervisor_tests.py +++ b/reconfigure/tests/configs/supervisor_tests.py @@ -1,5 +1,5 @@ from reconfigure.configs import SupervisorConfig -from base_test import BaseConfigTest +from reconfigure.tests.configs.base_test import BaseConfigTest class SupervisorConfigTest (BaseConfigTest): diff --git a/reconfigure/tests/parsers/base_test.py b/reconfigure/tests/parsers/base_test.py index 74c94b5..58c2cc8 100644 --- a/reconfigure/tests/parsers/base_test.py +++ b/reconfigure/tests/parsers/base_test.py @@ -16,7 +16,7 @@ class BaseParserTest (unittest.TestCase): nodetree = self.parser.parse(self.__class__.source) if self.__class__.parsed != nodetree: - print 'TARGET: %s\n\nPARSED: %s' % (self.__class__.parsed, nodetree) + print('TARGET: %s\n\nPARSED: %s' % (self.__class__.parsed, nodetree)) self.assertEquals(self.__class__.parsed, nodetree) def test_stringify(self): @@ -26,5 +26,5 @@ class BaseParserTest (unittest.TestCase): unparsed = self.parser.stringify(self.__class__.parsed) a, b = self.stringified, unparsed if a.split() != b.split(): - print 'SOURCE: %s\n\nGENERATED: %s' % (a, b) + print('SOURCE: %s\n\nGENERATED: %s' % (a, b)) self.assertEquals(a.split(), b.split()) diff --git a/reconfigure/tests/parsers/jsonparser_tests.py b/reconfigure/tests/parsers/jsonparser_tests.py index 1c1312e..c385763 100644 --- a/reconfigure/tests/parsers/jsonparser_tests.py +++ b/reconfigure/tests/parsers/jsonparser_tests.py @@ -1,3 +1,4 @@ +import json from reconfigure.tests.parsers.base_test import BaseParserTest from reconfigure.parsers import JsonParser from reconfigure.nodes import * @@ -20,5 +21,11 @@ class JsonParserTest (BaseParserTest): ), ) + def test_stringify(self): + unparsed = self.parser.stringify(self.__class__.parsed) + a, b = self.stringified, unparsed + if json.loads(a) != json.loads(b): + print('SOURCE: %s\n\nGENERATED: %s' % (a, b)) + self.assertEquals(a, b) del BaseParserTest diff --git a/reconfigure/tests/parsers/nginx_tests.py b/reconfigure/tests/parsers/nginx_tests.py index 83fe8b2..01b209d 100644 --- a/reconfigure/tests/parsers/nginx_tests.py +++ b/reconfigure/tests/parsers/nginx_tests.py @@ -12,9 +12,7 @@ sec { s1p2 wqe; # test - sec2 test { - s2p1 qwe; - } + sec2 test { s2p1 qwe; } } """ parsed = RootNode( diff --git a/requirements.txt b/requirements.txt index e69de29..983a631 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,2 @@ +chardet +nose \ No newline at end of file -- cgit v1.2.3