WIP: python3

This commit is contained in:
htouvet
2020-07-24 12:14:48 +02:00
parent 8aa63dbdd4
commit 1a99f9bb9a
11 changed files with 185 additions and 172 deletions
Executable → Regular
+10 -10
View File
@@ -3,17 +3,17 @@
# Copyright (c) 2007 Tim Lauridsen <tla@rasmil.dk>
# 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 .ini import INIConfig, change_comment_syntax
from .config import BasicConfig, ConfigNamespace
from .compat import RawConfigParser, ConfigParser, SafeConfigParser
from .utils import tidy
from ConfigParser import DuplicateSectionError, \
NoSectionError, NoOptionError, \
InterpolationMissingOptionError, \
InterpolationDepthError, \
InterpolationSyntaxError, \
DEFAULTSECT, MAX_INTERPOLATION_DEPTH
from .configparser import DuplicateSectionError, \
NoSectionError, NoOptionError, \
InterpolationMissingOptionError, \
InterpolationDepthError, \
InterpolationSyntaxError, \
DEFAULTSECT, MAX_INTERPOLATION_DEPTH
__all__ = [
'BasicConfig', 'ConfigNamespace',
Executable → Regular
+19 -19
View File
@@ -12,19 +12,22 @@ 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
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
from .configparser import Error, InterpolationError, \
MissingSectionHeaderError, ParsingError
import six
from . import ini
import ini
class RawConfigParser(object):
def __init__(self, defaults=None, dict_type=dict):
@@ -56,7 +59,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)
@@ -68,7 +71,7 @@ class RawConfigParser(object):
The DEFAULT section is not acknowledged.
"""
return (section in self.data)
return section in self.data
def options(self, section):
"""Return a list of option names for the given section name."""
@@ -88,7 +91,7 @@ class RawConfigParser(object):
filename may also be given.
"""
files_read = []
if isinstance(filenames, basestring):
if isinstance(filenames, six.string_types):
filenames = [filenames]
for filename in filenames:
try:
@@ -113,8 +116,6 @@ class RawConfigParser(object):
def get(self, section, option, vars=None):
if not self.has_section(section):
raise NoSectionError(section)
if vars is not None and option in vars:
value = vars[option]
sec = self.data[section]
if option in sec:
@@ -143,7 +144,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 +235,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:
@@ -283,7 +284,7 @@ class SafeConfigParser(ConfigParser):
_badpercent_re = re.compile(r"%[^%]|%$")
def set(self, section, option, value):
if not isinstance(value, basestring):
if not isinstance(value, six.string_types):
raise TypeError("option values must be strings")
# check for bad percent signs:
# first, replace all "good" interpolations
@@ -323,8 +324,7 @@ class SafeConfigParser(ConfigParser):
elif c == "(":
m = self._interpvar_match(rest)
if m is None:
raise InterpolationSyntaxError(option, section,
"bad interpolation variable reference %r" % rest)
raise InterpolationSyntaxError(option, section, "bad interpolation variable reference %r" % rest)
var = m.group(1)
rest = rest[m.end():]
try:
Executable → Regular
+10 -12
View File
@@ -86,6 +86,7 @@ class ConfigNamespace(object):
def __setstate__(self, state):
self.__dict__.update(state)
class Undefined(object):
"""Helper class used to hold undefined names until assignment.
@@ -143,16 +144,16 @@ class BasicConfig(ConfigNamespace):
>>> n.aaa = 42
>>> del n.x
>>> print n
>>> print(n)
aaa = 42
name.first = paramjit
name.last = oberoi
Nested namepsaces are also namespaces:
Nested namespaces are also namespaces:
>>> isinstance(n.name, ConfigNamespace)
True
>>> print n.name
>>> print(n.name)
first = paramjit
last = oberoi
>>> sorted(list(n.name))
@@ -160,7 +161,7 @@ class BasicConfig(ConfigNamespace):
Finally, values can be read from a file as follows:
>>> from StringIO import StringIO
>>> from six import StringIO
>>> sio = StringIO('''
... # comment
... ui.height = 100
@@ -171,7 +172,7 @@ class BasicConfig(ConfigNamespace):
... ''')
>>> n = BasicConfig()
>>> n._readfp(sio)
>>> print n
>>> print(n)
complexity = medium
data.secret.password = goodness=gracious me
have_python
@@ -199,7 +200,7 @@ class BasicConfig(ConfigNamespace):
def __str__(self, prefix=''):
lines = []
keys = self._data.keys()
keys = list(self._data.keys())
keys.sort()
for name in keys:
value = self._data[name]
@@ -258,7 +259,7 @@ def update_config(target, source):
>>> n.ui.display_clock = True
>>> n.ui.display_qlength = True
>>> n.ui.width = 150
>>> print n
>>> print(n)
playlist.expand_playlist = True
ui.display_clock = True
ui.display_qlength = True
@@ -267,7 +268,7 @@ def update_config(target, source):
>>> from iniparse import ini
>>> i = ini.INIConfig()
>>> update_config(i, n)
>>> print i
>>> print(i)
[playlist]
expand_playlist = True
<BLANKLINE>
@@ -277,7 +278,7 @@ def update_config(target, source):
width = 150
"""
for name in source:
for name in sorted(source):
value = source[name]
if isinstance(value, ConfigNamespace):
if name in target:
@@ -289,6 +290,3 @@ def update_config(target, source):
update_config(myns, value)
else:
target[name] = value
+7
View File
@@ -0,0 +1,7 @@
try:
from ConfigParser import *
# not all objects get imported with __all__
from ConfigParser import Error, InterpolationMissingOptionError
except ImportError:
from configparser import *
from configparser import Error, InterpolationMissingOptionError
Executable → Regular
+52 -43
View File
@@ -7,7 +7,7 @@
Example:
>>> from StringIO import StringIO
>>> from six import StringIO
>>> sio = StringIO('''# configure foo-application
... [foo]
... bar1 = qualia
@@ -16,14 +16,14 @@ Example:
... special = 1''')
>>> cfg = INIConfig(sio)
>>> print cfg.foo.bar1
>>> print(cfg.foo.bar1)
qualia
>>> print cfg['foo-ext'].special
>>> print(cfg['foo-ext'].special)
1
>>> cfg.foo.newopt = 'hi!'
>>> cfg.baz.enabled = 0
>>> print cfg
>>> print(cfg)
# configure foo-application
[foo]
bar1 = qualia
@@ -42,9 +42,12 @@ Example:
# Backward-compatiable with ConfigParser
import re
from ConfigParser import DEFAULTSECT, ParsingError, MissingSectionHeaderError
from .configparser import DEFAULTSECT, ParsingError, MissingSectionHeaderError
import six
from . import config
import config
class LineType(object):
line = None
@@ -73,10 +76,10 @@ class LineType(object):
class SectionLine(LineType):
regex = re.compile(r'^\['
r'(?P<name>[^]]+)'
r'\]\s*'
r'((?P<csep>;|#)(?P<comment>.*))?$')
regex = re.compile(r'^\['
r'(?P<name>[^]]+)'
r'\]\s*'
r'((?P<csep>;|#)(?P<comment>.*))?$')
def __init__(self, name, comment=None, comment_separator=None,
comment_offset=-1, line=None):
@@ -170,8 +173,9 @@ def change_comment_syntax(comment_chars='%;#', allow_rem=False):
regex += r')(?P<comment>.*)$'
CommentLine.regex = re.compile(regex)
class CommentLine(LineType):
regex = re.compile(r'^(?P<csep>[;#]|[rR][eE][mM] +)'
regex = re.compile(r'^(?P<csep>[;#]|[rR][eE][mM])'
r'(?P<comment>.*)$')
def __init__(self, comment='', separator='#', line=None):
@@ -187,6 +191,7 @@ class CommentLine(LineType):
if m is None:
return None
return cls(m.group('comment'), m.group('csep'), line)
parse = classmethod(parse)
@@ -195,11 +200,13 @@ class EmptyLine(LineType):
def to_string(self):
return ''
value = property(lambda _: '')
value = property(lambda self: '')
def parse(cls, line):
if line.strip(): return None
if line.strip():
return None
return cls(line)
parse = classmethod(parse)
@@ -221,6 +228,7 @@ class ContinuationLine(LineType):
if m is None:
return None
return cls(m.group('value'), m.start('value'), line)
parse = classmethod(parse)
@@ -275,6 +283,7 @@ class LineContainer(object):
self.add(EmptyLine())
name = property(get_name, set_name)
value = property(get_value, set_value)
def __str__(self):
@@ -322,8 +331,8 @@ class INISection(config.ConfigNamespace):
_optionxformvalue = None
_optionxformsource = None
_compat_skip_empty_lines = set()
def __init__(self, lineobj, defaults = None,
optionxformvalue=None, optionxformsource=None):
def __init__(self, lineobj, defaults=None, optionxformvalue=None, optionxformsource=None):
self._lines = [lineobj]
self._defaults = defaults
self._optionxformvalue = optionxformvalue
@@ -453,6 +462,7 @@ class INIConfig(config.ConfigNamespace):
_sectionxformsource = None
_parse_exc = None
_bom = False
def __init__(self, fp=None, defaults=None, parse_exc=True,
optionxformvalue=lower, optionxformsource=None,
sectionxformvalue=None, sectionxformsource=None):
@@ -465,7 +475,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)
@@ -545,34 +555,34 @@ class INIConfig(config.ConfigNamespace):
fname = fp.name
except AttributeError:
fname = '<???>'
linecount = 0
line_count = 0
exc = None
line = None
for line in readline_iterator(fp):
# Check for BOM on first line
if linecount == 0 and isinstance(line, unicode):
if line_count == 0 and isinstance(line, six.text_type):
if line[0] == u'\ufeff':
line = line[1:]
self._bom = True
lineobj = self._parse(line)
linecount += 1
line_obj = self._parse(line)
line_count += 1
if not cur_section and not isinstance(lineobj,
(CommentLine, EmptyLine, SectionLine)):
if not cur_section and not isinstance(line_obj, (CommentLine, EmptyLine, SectionLine)):
if self._parse_exc:
raise MissingSectionHeaderError(fname, linecount, line)
raise MissingSectionHeaderError(fname, line_count, line)
else:
lineobj = make_comment(line)
line_obj = make_comment(line)
if lineobj is None:
if line_obj is None:
if self._parse_exc:
if exc is None: exc = ParsingError(fname)
exc.append(linecount, line)
lineobj = make_comment(line)
if exc is None:
exc = ParsingError(fname)
exc.append(line_count, line)
line_obj = make_comment(line)
if isinstance(lineobj, ContinuationLine):
if isinstance(line_obj, ContinuationLine):
if cur_option:
if pending_lines:
cur_option.extend(pending_lines)
@@ -580,20 +590,21 @@ class INIConfig(config.ConfigNamespace):
if pending_empty_lines:
optobj._compat_skip_empty_lines.add(cur_option_name)
pending_empty_lines = False
cur_option.add(lineobj)
cur_option.add(line_obj)
else:
# illegal continuation line - convert to comment
if self._parse_exc:
if exc is None: exc = ParsingError(fname)
exc.append(linecount, line)
lineobj = make_comment(line)
if exc is None:
exc = ParsingError(fname)
exc.append(line_count, line)
line_obj = make_comment(line)
if isinstance(lineobj, OptionLine):
if isinstance(line_obj, OptionLine):
if pending_lines:
cur_section.extend(pending_lines)
pending_lines = []
pending_empty_lines = False
cur_option = LineContainer(lineobj)
cur_option = LineContainer(line_obj)
cur_section.add(cur_option)
if self._optionxform:
cur_option_name = self._optionxform(cur_option.name)
@@ -605,11 +616,11 @@ class INIConfig(config.ConfigNamespace):
optobj = self._sections[cur_section_name]
optobj._options[cur_option_name] = cur_option
if isinstance(lineobj, SectionLine):
if isinstance(line_obj, SectionLine):
self._data.extend(pending_lines)
pending_lines = []
pending_empty_lines = False
cur_section = LineContainer(lineobj)
cur_section = LineContainer(line_obj)
self._data.add(cur_section)
cur_option = None
cur_option_name = None
@@ -628,16 +639,14 @@ class INIConfig(config.ConfigNamespace):
else:
self._sections[cur_section_name]._lines.append(cur_section)
if isinstance(lineobj, (CommentLine, EmptyLine)):
pending_lines.append(lineobj)
if isinstance(lineobj, EmptyLine):
if isinstance(line_obj, (CommentLine, EmptyLine)):
pending_lines.append(line_obj)
if isinstance(line_obj, EmptyLine):
pending_empty_lines = True
self._data.extend(pending_lines)
if line and line[-1]=='\n':
if line and line[-1] == '\n':
self._data.add(EmptyLine())
if exc:
raise exc
Executable → Regular
+5 -4
View File
@@ -1,5 +1,6 @@
import compat
from ini import LineContainer, EmptyLine
from . import compat
from .ini import LineContainer, EmptyLine
def tidy(cfg):
"""Clean up blank lines.
@@ -32,12 +33,12 @@ def tidy(cfg):
if cont and not isinstance(cont[-1], EmptyLine):
cont.append(EmptyLine())
def tidy_section(lc):
cont = lc.contents
i = 1
while i < len(cont):
if (isinstance(cont[i-1], EmptyLine) and
isinstance(cont[i], EmptyLine)):
if isinstance(cont[i-1], EmptyLine) and isinstance(cont[i], EmptyLine):
del cont[i]
else:
i += 1