Changeset 6da01818c9ea…
Parent c55f3b963ead…
by
Changes to 8 files · Browse files at 6da01818c9ea Showing diff from parent c55f3b963ead Diff from another changeset...
@@ -187,7 +187,7 @@
packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert',
'hgext.highlight', 'hgext.zeroconf', 'hggtk',
- 'hggtk.logview', 'thgutil', 'thgutil.iniparse']
+ 'hggtk.logview', 'thgutil', 'iniparse']
try:
import msvcrt
|
@@ -309,8 +309,9 @@
def userconfig(ui, *pats, **opts):
"""user configuration editor"""
+ # Import thgconfig first, to check for iniparse
+ from hggtk.thgconfig import run
portable_fork()
- from hggtk.thgconfig import run
opts['repomode'] = False
gtkrun(run(ui, *pats, **opts))
|
@@ -7,6 +7,7 @@
import gtk
import os
+import sys
import re
import urlparse
import threading
@@ -14,10 +15,20 @@from mercurial import hg, ui, util, url, filemerge
from thgutil.i18n import _
-from thgutil import hglib, settings, paths, iniparse
+from thgutil import hglib, settings, paths
from hggtk import dialog, gdialog, gtklib, hgcmd
+try:
+ from mercurial import demandimport
+ demandimport.disable()
+ import iniparse
+ demandimport.enable()
+except ImportError:
+ print 'The iniparse python package is required by this tool. Download from'
+ print 'http://code.google.com/p/iniparse/'
+ sys.exit(0)
+
_unspecstr = _('<unspecified>')
_unspeclocalstr = hglib.fromutf(_unspecstr)
|
@@ -58,7 +58,7 @@ # Specific definitios for Windows NT-alike installations
_scripts = []
_data_files = []
- _packages = ['hggtk', 'hggtk.logview', 'thgutil', 'thgutil.iniparse']
+ _packages = ['hggtk', 'hggtk.logview', 'thgutil']
extra = {}
hgextmods = []
@@ -113,7 +113,7 @@ # Specific definitios for Posix installations
_extra = {}
_scripts = ['hgtk']
- _packages = ['hggtk', 'hggtk.logview', 'thgutil', 'thgutil.iniparse']
+ _packages = ['hggtk', 'hggtk.logview', 'thgutil']
_data_files = [(os.path.join('share/pixmaps/tortoisehg', root),
[os.path.join(root, file_) for file_ in files])
for root, dirs, files in os.walk('icons')]
|
|
@@ -1,8 +0,0 @@ - from ini import INIConfig
-from config import BasicConfig, ConfigNamespace
-from compat import RawConfigParser, ConfigParser, SafeConfigParser
-
-__all__ = [
- 'INIConfig', 'BasicConfig', 'ConfigNamespace',
- 'RawConfigParser', 'ConfigParser', 'SafeConfigParser',
-]
|
|
|
@@ -1,329 +0,0 @@ - # Copyright (c) 2001, 2002, 2003 Python Software Foundation
-# Copyright (c) 2004 Paramjit Oberoi <param.cs.wisc.edu>
-# All Rights Reserved. See LICENSE-PSF & LICENSE for details.
-
-"""Compatibility interfaces for ConfigParser
-
-Interfaces of ConfigParser, RawConfigParser and SafeConfigParser
-should be completely identical to the Python standard library
-versions. Tested with the unit tests included with Python-2.3.4
-
-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
-
-# 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):
- self.data = ini.INIConfig(defaults=defaults, optionxformsource=self)
-
- def optionxform(self, optionstr):
- return optionstr.lower()
-
- def defaults(self):
- d = {}
- for name, lineobj in self.data._defaults._options:
- d[name] = lineobj.value
- return d
-
- def sections(self):
- """Return a list of section names, excluding [DEFAULT]"""
- return list(self.data)
-
- def add_section(self, section):
- """Create a new section in the configuration.
-
- Raise DuplicateSectionError if a section by the specified name
- already exists.
- """
- if self.has_section(section):
- raise DuplicateSectionError(section)
- else:
- self.data.new_namespace(section)
-
- def has_section(self, section):
- """Indicate whether the named section is present in the configuration.
-
- The DEFAULT section is not acknowledged.
- """
- try:
- self.data[section]
- return True
- except KeyError:
- return False
-
- def options(self, section):
- """Return a list of option names for the given section name."""
- try:
- return list(self.data[section])
- except KeyError:
- raise NoSectionError(section)
-
- def read(self, filenames):
- """Read and parse a filename or a list of filenames.
-
- Files that cannot be opened are silently ignored; this is
- designed so that you can specify a list of potential
- configuration file locations (e.g. current directory, user's
- home directory, systemwide directory), and all existing
- configuration files in the list will be read. A single
- filename may also be given.
- """
- files_read = []
- if isinstance(filenames, basestring):
- filenames = [filenames]
- for filename in filenames:
- try:
- fp = open(filename)
- except IOError:
- continue
- files_read.append(filename)
- self.data.readfp(fp)
- fp.close()
- return files_read
-
- def readfp(self, fp, filename=None):
- """Like read() but the argument must be a file-like object.
-
- The `fp' argument must have a `readline' method. Optional
- second argument is the `filename', which if not given, is
- taken from fp.name. If fp has no `name' attribute, `<???>' is
- used.
- """
- self.data.readfp(fp)
-
- 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]
- try:
- return self.data[section][option]
- except KeyError:
- raise NoOptionError(option, section)
-
- def items(self, section):
- try:
- ans = []
- for opt in self.data[section]:
- ans.append((opt, self.data[section][opt]))
- return ans
- except KeyError:
- raise NoSectionError(section)
-
- def getint(self, section, option):
- return int(self.get(section, option))
-
- def getfloat(self, section, option):
- return float(self.get(section, option))
-
- _boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
- '0': False, 'no': False, 'false': False, 'off': False}
-
- 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
- return self._boolean_states[v.lower()]
-
- def has_option(self, section, option):
- """Check for the existence of a given option in a given section."""
- try:
- sec = self.data[section]
- except KeyError:
- raise NoSectionError(section)
- try:
- sec[option]
- return True
- except KeyError:
- return False
-
- def set(self, section, option, value):
- """Set an option."""
- try:
- self.data[section][option] = value
- except KeyError:
- raise NoSectionError(section)
-
- def write(self, fp):
- """Write an .ini-format representation of the configuration state."""
- fp.write(str(self.data))
-
- def remove_option(self, section, option):
- """Remove an option."""
- try:
- sec = self.data[section]
- except KeyError:
- raise NoSectionError(section)
- try:
- sec[option]
- del sec[option]
- return 1
- except KeyError:
- return 0
-
- def remove_section(self, section):
- """Remove a file section."""
- if not self.has_section(section):
- return False
- del self.data[section]
- return True
-
-
-class ConfigDict(object):
- """Present a dict interface to a ini section."""
-
- def __init__(self, cfg, section, vars):
- self.cfg = cfg
- self.section = section
- self.vars = vars
-
- def __getitem__(self, key):
- try:
- return RawConfigParser.get(self.cfg, self.section, key, self.vars)
- except (NoOptionError, NoSectionError):
- raise KeyError(key)
-
-
-class ConfigParser(RawConfigParser):
-
- def get(self, section, option, raw=False, vars=None):
- """Get an option value for a given section.
-
- All % interpolations are expanded in the return values, based on the
- defaults passed into the constructor, unless the optional argument
- `raw' is true. Additional substitutions may be provided using the
- `vars' argument, which must be a dictionary whose contents overrides
- any pre-existing defaults.
-
- The section DEFAULT is special.
- """
- if section != DEFAULTSECT and not self.has_section(section):
- raise NoSectionError(section)
-
- option = self.optionxform(option)
- value = RawConfigParser.get(self, section, option, vars)
-
- if raw:
- return value
- else:
- d = ConfigDict(self, section, vars)
- return self._interpolate(section, option, value, d)
-
- def _interpolate(self, section, option, rawval, vars):
- # do the string interpolation
- value = rawval
- depth = MAX_INTERPOLATION_DEPTH
- while depth: # Loop through this until it's done
- depth -= 1
- if "%(" in value:
- try:
- value = value % vars
- except KeyError, e:
- raise InterpolationMissingOptionError(
- option, section, rawval, e[0])
- else:
- break
- if value.find("%(") != -1:
- raise InterpolationDepthError(option, section, rawval)
- return value
-
- def items(self, section, raw=False, vars=None):
- """Return a list of tuples with (name, value) for each option
- in the section.
-
- All % interpolations are expanded in the return values, based on the
- defaults passed into the constructor, unless the optional argument
- `raw' is true. Additional substitutions may be provided using the
- `vars' argument, which must be a dictionary whose contents overrides
- any pre-existing defaults.
-
- The section DEFAULT is special.
- """
- if section != DEFAULTSECT and not self.has_section(section):
- raise NoSectionError(section)
- if vars is None:
- options = list(self.data[section])
- else:
- options = []
- for x in self.data[section]:
- if x not in vars:
- options.append(x)
- options.extend(vars.keys())
-
- if "__name__" in options:
- options.remove("__name__")
-
- d = ConfigDict(self, section, vars)
- if raw:
- return [(option, d[option])
- for option in options]
- else:
- return [(option, self._interpolate(section, option, d[option], d))
- for option in options]
-
-
-class SafeConfigParser(ConfigParser):
- def set(self, section, option, value):
- if not isinstance(value, basestring):
- raise TypeError("option values must be strings")
- ConfigParser.set(self, section, option, value)
-
- def _interpolate(self, section, option, rawval, vars):
- # do the string interpolation
- L = []
- self._interpolate_some(option, L, rawval, section, vars, 1)
- return ''.join(L)
-
- _interpvar_match = re.compile(r"%\(([^)]+)\)s").match
-
- def _interpolate_some(self, option, accum, rest, section, map, depth):
- if depth > MAX_INTERPOLATION_DEPTH:
- raise InterpolationDepthError(option, section, rest)
- while rest:
- p = rest.find("%")
- if p < 0:
- accum.append(rest)
- return
- if p > 0:
- accum.append(rest[:p])
- rest = rest[p:]
- # p is no longer used
- c = rest[1:2]
- if c == "%":
- accum.append("%")
- rest = rest[2:]
- elif c == "(":
- m = self._interpvar_match(rest)
- if m is None:
- raise InterpolationSyntaxError(option, section,
- "bad interpolation variable reference %r" % rest)
- var = m.group(1)
- rest = rest[m.end():]
- try:
- v = map[var]
- except KeyError:
- raise InterpolationMissingOptionError(
- option, section, rest, var)
- if "%" in v:
- self._interpolate_some(option, accum, v,
- section, map, depth + 1)
- else:
- accum.append(v)
- else:
- raise InterpolationSyntaxError(
- option, section,
- "'%' must be followed by '%' or '(', found: " + `rest`)
|
|
|
@@ -1,264 +0,0 @@ - # Copyright (c) 2001, 2002, 2003 Python Software Foundation
-# Copyright (c) 2004 Paramjit Oberoi <param.cs.wisc.edu>
-# All Rights Reserved. See LICENSE-PSF & LICENSE for details.
-
-"""Implements basic mechanisms for managing configuration information
-
-* A NAMESPACE is a collection of values and other namepsaces
-* A VALUE is a basic value, like 3.1415, or 'Hello World!'
-* A NAME identifies a value or namespace within a namespace
-
-The ConfigNamespace class is an abstract class that defines the
-basic interface implemented by all config namespace objects. Two
-concrete implementations are included: BasicConfig and INIConfig.
-
-Each is described in detail elsewhere. However, here's an
-example of the capabilities available:
-
-Create config namespace and populate it:
-
- >>> n = BasicConfig()
- >>> n.playlist.expand_playlist = True
- >>> n.ui.display_clock = True
- >>> n.ui.display_qlength = True
- >>> n.ui.width = 150
-
-Examine data:
-
- >>> print n.playlist.expand_playlist
- True
- >>> print n['ui']['width']
- 150
-
- >>> print n
- playlist.expand_playlist = True
- ui.display_clock = True
- ui.display_qlength = True
- ui.width = 150
-
-Delete items:
-
- >>> del n.playlist
- >>> print n
- ui.display_clock = True
- ui.display_qlength = True
- ui.width = 150
-
-Convert it to ini format:
-
- >>> from iniparse import ini
- >>> i = ini.INIConfig()
- >>> i.import_config(n)
-
- >>> print i
- [ui]
- display_clock = True
- display_qlength = True
- width = 150
-"""
-
-# ---- Abstract classes
-
-
-class ConfigNamespace(object):
- def __getitem__(self, key):
- return NotImplementedError(key)
-
- def __setitem__(self, key, value):
- raise NotImplementedError(key, value)
-
- def __delitem__(self, key):
- raise NotImplementedError(key)
-
- def __iter__(self):
- return NotImplementedError()
-
- def new_namespace(self, name):
- raise NotImplementedError(name)
-
- def __getattr__(self, name):
- try:
- return self.__getitem__(name)
- except KeyError:
- return Undefined(name, self)
-
- def __setattr__(self, name, value):
- try:
- object.__getattribute__(self, name)
- object.__setattr__(self, name, value)
- return
- except AttributeError:
- self.__setitem__(name, value)
-
- def __delattr__(self, name):
- try:
- object.__getattribute__(self, name)
- object.__delattr__(self, name)
- except AttributeError:
- self.__delitem__(name)
-
- def import_config(self, ns):
- for name in ns:
- value = ns[name]
- if isinstance(value, ConfigNamespace):
- try:
- myns = self[name]
- if not isinstance(myns, ConfigNamespace):
- raise TypeError('value-namespace conflict')
- except KeyError:
- myns = self.new_namespace(name)
- myns.import_config(value)
- else:
- self[name] = value
-
-class Undefined(object):
- """Helper class used to hold undefined names until assignment.
-
- This class helps create any undefined subsections when an
- assignment is made to a nested value. For example, if the
- statement is "cfg.a.b.c = 42", but "cfg.a.b" does not exist yet.
- """
-
- def __init__(self, name, namespace):
- object.__setattr__(self, 'name', name)
- object.__setattr__(self, 'namespace', namespace)
-
- def __setattr__(self, name, value):
- obj = self.namespace.new_namespace(self.name)
- obj[name] = value
-
-
-# ---- Basic implementation of namespace
-
-
-class BasicConfig(ConfigNamespace):
- """Represents a collection of named values
-
- Values are added using dotted notation:
-
- >>> n = BasicConfig()
- >>> n.x = 7
- >>> n.name.first = 'paramjit'
- >>> n.name.last = 'oberoi'
-
- ...and accessed the same way, or with [...]:
-
- >>> n.x
- 7
- >>> n.name.first
- 'paramjit'
- >>> n.name.last
- 'oberoi'
- >>> n['x']
- 7
-
- The namespace object is a 'container object'. The default
- iterator returns the names of values (i.e. keys).
-
- >>> l = list(n)
- >>> l.sort()
- >>> l
- ['name', 'x']
-
- Values can be deleted using 'del' and printed using 'print'.
-
- >>> n.aaa = 42
- >>> del n.x
- >>> print n
- aaa = 42
- name.first = paramjit
- name.last = oberoi
-
- Nested namepsaces are also namespaces:
-
- >>> isinstance(n.name, ConfigNamespace)
- True
- >>> print n.name
- first = paramjit
- last = oberoi
-
- Finally, values can be read from a file as follows:
-
- >>> from StringIO import StringIO
- >>> sio = StringIO('''
- ... # comment
- ... ui.height = 100
- ... ui.width = 150
- ... complexity = medium
- ... have_python
- ... data.secret.password = goodness=gracious me
- ... ''')
- >>> n = BasicConfig()
- >>> n.readfp(sio)
- >>> print n
- complexity = medium
- data.secret.password = goodness=gracious me
- have_python
- ui.height = 100
- ui.width = 150
- """
-
- # this makes sure that __setattr__ knows this is not a value key
- _data = None
-
- def __init__(self):
- self._data = {}
-
- def __getitem__(self, key):
- return self._data[key]
-
- def __setitem__(self, key, value):
- self._data[key] = value
-
- def __delitem__(self, key):
- del self._data[key]
-
- def __iter__(self):
- return iter(self._data)
-
- def __str__(self, prefix=''):
- lines = []
- keys = self._data.keys()
- keys.sort()
- for name in keys:
- value = self._data[name]
- if isinstance(value, ConfigNamespace):
- lines.append(value.__str__(prefix='%s%s.' % (prefix,name)))
- else:
- if value is None:
- lines.append('%s%s' % (prefix, name))
- else:
- lines.append('%s%s = %s' % (prefix, name, value))
- return '\n'.join(lines)
-
- def new_namespace(self, name):
- obj = BasicConfig()
- self._data[name] = obj
- return obj
-
- def readfp(self, fp):
- while True:
- line = fp.readline()
- if not line:
- break
-
- line = line.strip()
- if not line: continue
- if line[0] == '#': continue
- data = line.split('=', 1)
- if len(data) == 1:
- name = line
- value = None
- else:
- name = data[0].strip()
- value = data[1].strip()
- name_components = name.split('.')
- ns = self
- for n in name_components[:-1]:
- try:
- ns = ns[n]
- if not isinstance(ns, ConfigNamespace):
- raise TypeError('value-namespace conflict', n)
- except KeyError:
- ns = ns.new_namespace(n)
- ns[name_components[-1]] = value
|
|
|
@@ -1,568 +0,0 @@ - # Copyright (c) 2001, 2002, 2003 Python Software Foundation
-# Copyright (c) 2004 Paramjit Oberoi <param.cs.wisc.edu>
-# All Rights Reserved. See LICENSE-PSF & LICENSE for details.
-
-"""Access and/or modify INI files
-
-* Compatiable with ConfigParser
-* Preserves order of sections & options
-* Preserves comments/blank lines/etc
-* More conveninet access to data
-
-Example:
-
- >>> from StringIO import StringIO
- >>> sio = StringIO('''# configure foo-application
- ... [foo]
- ... bar1 = qualia
- ... bar2 = 1977
- ... [foo-ext]
- ... special = 1''')
-
- >>> cfg = INIConfig(sio)
- >>> print cfg.foo.bar1
- qualia
- >>> print cfg['foo-ext'].special
- 1
- >>> cfg.foo.newopt = 'hi!'
-
- >>> print cfg
- # configure foo-application
- [foo]
- bar1 = qualia
- bar2 = 1977
- newopt = hi!
- [foo-ext]
- special = 1
-
-"""
-
-# An ini parser that supports ordered sections/options
-# Also supports updates, while preserving structure
-# Backward-compatiable with ConfigParser
-
-import re
-import config
-from ConfigParser import DEFAULTSECT, ParsingError, MissingSectionHeaderError
-
-class LineType(object):
- line = None
-
- def __init__(self, line=None):
- if line is not None:
- self.line = line.strip('\n')
-
- # Return the original line for unmodified objects
- # Otherwise construct using the current attribute values
- def __str__(self):
- if self.line is not None:
- return self.line
- else:
- return self.to_string()
-
- # If an attribute is modified after initialization
- # set line to None since it is no longer accurate.
- def __setattr__(self, name, value):
- if hasattr(self,name):
- self.__dict__['line'] = None
- self.__dict__[name] = value
-
- def to_string(self):
- raise Exception('This method must be overridden in derived classes')
-
-
-class SectionLine(LineType):
- 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):
- super(SectionLine, self).__init__(line)
- self.name = name
- self.comment = comment
- self.comment_separator = comment_separator
- self.comment_offset = comment_offset
-
- def to_string(self):
- out = '[' + self.name + ']'
- if self.comment is not None:
- # try to preserve indentation of comments
- out = (out+' ').ljust(self.comment_offset)
- out = out + self.comment_separator + self.comment
- return out
-
- def parse(cls, line):
- m = cls.regex.match(line.rstrip())
- if m is None:
- return None
- return cls(m.group('name'), m.group('comment'),
- m.group('csep'), m.start('csep'),
- line)
- parse = classmethod(parse)
-
-
-class OptionLine(LineType):
- def __init__(self, name, value, separator=' = ', comment=None,
- comment_separator=None, comment_offset=-1, line=None):
- super(OptionLine, self).__init__(line)
- self.name = name
- self.value = value
- self.separator = separator
- self.comment = comment
- self.comment_separator = comment_separator
- self.comment_offset = comment_offset
-
- def to_string(self):
- out = '%s%s%s' % (self.name, self.separator, self.value)
- if self.comment is not None:
- # try to preserve indentation of comments
- out = (out+' ').ljust(self.comment_offset)
- out = out + self.comment_separator + self.comment
- return out
-
- regex = re.compile(r'^(?P<name>[^:=\s[][^:=]*)'
- r'(?P<sep>[:=]\s*)'
- r'(?P<value>.*)$')
-
- def parse(cls, line):
- m = cls.regex.match(line.rstrip())
- if m is None:
- return None
-
- name = m.group('name').rstrip()
- value = m.group('value')
- sep = m.group('name')[len(name):] + m.group('sep')
-
- # comments are not detected in the regex because
- # ensuring total compatibility with ConfigParser
- # requires that:
- # option = value ;comment // value=='value'
- # option = value;1 ;comment // value=='value;1 ;comment'
- #
- # Doing this in a regex would be complicated. I
- # think this is a bug. The whole issue of how to
- # include ';' in the value needs to be addressed.
- # Also, '#' doesn't mark comments in options...
-
- coff = value.find(';')
- if coff != -1 and value[coff-1].isspace():
- comment = value[coff+1:]
- csep = value[coff]
- value = value[:coff].rstrip()
- coff = m.start('value') + coff
- else:
- comment = None
- csep = None
- coff = -1
-
- return cls(name, value, sep, comment, csep, coff, line)
- parse = classmethod(parse)
-
-
-class CommentLine(LineType):
- regex = re.compile(r'^(?P<csep>[;#]|[rR][eE][mM])'
- r'(?P<comment>.*)$')
-
- def __init__(self, comment='', separator='#', line=None):
- super(CommentLine, self).__init__(line)
- self.comment = comment
- self.separator = separator
-
- def to_string(self):
- return self.separator + self.comment
-
- def parse(cls, line):
- m = cls.regex.match(line.rstrip())
- if m is None:
- return None
- return cls(m.group('comment'), m.group('csep'), line)
- parse = classmethod(parse)
-
-
-class EmptyLine(LineType):
- # could make this a singleton
- def to_string(self):
- return ''
-
- def parse(cls, line):
- if line.strip(): return None
- return cls(line)
- parse = classmethod(parse)
-
-
-class ContinuationLine(LineType):
- regex = re.compile(r'^\s+(?P<value>.*)$')
-
- def __init__(self, value, value_offset=8, line=None):
- super(ContinuationLine, self).__init__(line)
- self.value = value
- self.value_offset = value_offset
-
- def to_string(self):
- return ' '*self.value_offset + self.value
-
- def parse(cls, line):
- m = cls.regex.match(line.rstrip())
- if m is None:
- return None
- return cls(m.group('value'), m.start('value'), line)
- parse = classmethod(parse)
-
-
-class LineContainer(object):
- def __init__(self, d=None):
- self.contents = []
- self.orgvalue = None
- if d:
- if isinstance(d, list): self.extend(d)
- else: self.add(d)
-
- def add(self, x):
- self.contents.append(x)
-
- def extend(self, x):
- for i in x: self.add(i)
-
- def get_name(self):
- return self.contents[0].name
-
- def set_name(self, data):
- self.contents[0].name = data
-
- def get_value(self):
- if self.orgvalue is not None:
- return self.orgvalue
- elif len(self.contents) == 1:
- return self.contents[0].value
- else:
- return '\n'.join([str(x.value) for x in self.contents
- if not isinstance(x, (CommentLine, EmptyLine))])
-
- def set_value(self, data):
- self.orgvalue = data
- lines = str(data).split('\n')
- linediff = len(lines) - len(self.contents)
- if linediff > 0:
- for _ in range(linediff):
- self.add(ContinuationLine(''))
- elif linediff < 0:
- self.contents = self.contents[:linediff]
- for i,v in enumerate(lines):
- self.contents[i].value = v
-
- name = property(get_name, set_name)
- value = property(get_value, set_value)
-
- def __str__(self):
- s = [str(x) for x in self.contents]
- return '\n'.join(s)
-
- def finditer(self, key):
- for x in self.contents[::-1]:
- if hasattr(x, 'name') and x.name==key:
- yield x
-
- def find(self, key):
- for x in self.finditer(key):
- return x
- raise KeyError(key)
-
-
-def _make_xform_property(myattrname, srcattrname=None):
- private_attrname = myattrname + 'value'
- private_srcname = myattrname + 'source'
- if srcattrname is None:
- srcattrname = myattrname
-
- def getfn(self):
- srcobj = getattr(self, private_srcname)
- if srcobj is not None:
- return getattr(srcobj, srcattrname)
- else:
- return getattr(self, private_attrname)
-
- def setfn(self, value):
- srcobj = getattr(self, private_srcname)
- if srcobj is not None:
- setattr(srcobj, srcattrname, value)
- else:
- setattr(self, private_attrname, value)
-
- return property(getfn, setfn)
-
-
-class INISection(config.ConfigNamespace):
- _lines = None
- _options = None
- _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
- self._optionxformsource = optionxformsource
- self._options = {}
-
- _optionxform = _make_xform_property('_optionxform')
-
- def __getitem__(self, key):
- if key == '__name__':
- return self._lines[-1].name
- if self._optionxform: key = self._optionxform(key)
- try:
- return self._options[key].value
- except KeyError:
- if self._defaults and key in self._defaults._options:
- return self._defaults._options[key].value
- else:
- raise
-
- def __setitem__(self, key, value):
- if self._optionxform: xkey = self._optionxform(key)
- else: xkey = key
- if xkey not in self._options:
- # create a dummy object - value may have multiple lines
- obj = LineContainer(OptionLine(key, ''))
- self._lines[-1].add(obj)
- self._options[xkey] = obj
- # the set_value() function in LineContainer
- # automatically handles multi-line values
- self._options[xkey].value = value
-
- def __delitem__(self, key):
- if self._optionxform: key = self._optionxform(key)
- for l in self._lines:
- remaining = []
- for o in l.contents:
- if isinstance(o, LineContainer):
- n = o.name
- if self._optionxform: n = self._optionxform(n)
- if key != n: remaining.append(o)
- else:
- remaining.append(o)
- l.contents = remaining
- del self._options[key]
-
- def __iter__(self):
- d = set()
- for l in self._lines:
- for x in l.contents:
- if isinstance(x, LineContainer):
- if self._optionxform:
- ans = self._optionxform(x.name)
- else:
- ans = x.name
- if ans not in d:
- yield ans
- d.add(ans)
- if self._defaults:
- for x in self._defaults:
- if x not in d:
- yield x
- d.add(x)
-
- def new_namespace(self, name):
- raise Exception('No sub-sections allowed', name)
-
-
-def make_comment(line):
- return CommentLine(line.rstrip())
-
-
-def readline_iterator(f):
- """iterate over a file by only using the file object's readline method"""
-
- have_newline = False
- while True:
- line = f.readline()
-
- if not line:
- if have_newline:
- yield ""
- return
-
- if line.endswith('\n'):
- have_newline = True
- else:
- have_newline = False
-
- yield line
-
-
-class INIConfig(config.ConfigNamespace):
- _data = None
- _sections = None
- _defaults = None
- _optionxformvalue = None
- _optionxformsource = None
- _sectionxformvalue = None
- _sectionxformsource = None
- _parse_exc = None
- def __init__(self, fp=None, defaults = None, parse_exc=True,
- optionxformvalue=str.lower, optionxformsource=None,
- sectionxformvalue=None, sectionxformsource=None):
- self._data = LineContainer()
- self._parse_exc = parse_exc
- self._optionxformvalue = optionxformvalue
- self._optionxformsource = optionxformsource
- self._sectionxformvalue = sectionxformvalue
- self._sectionxformsource = sectionxformsource
- self._sections = {}
- if defaults is None: defaults = {}
- self._defaults = INISection(LineContainer(), optionxformsource=self)
- for name, value in defaults.iteritems():
- self._defaults[name] = value
- if fp is not None:
- self.readfp(fp)
-
- _optionxform = _make_xform_property('_optionxform', 'optionxform')
- _sectionxform = _make_xform_property('_sectionxform', 'optionxform')
-
- def __getitem__(self, key):
- if key == DEFAULTSECT:
- return self._defaults
- if self._sectionxform: key = self._sectionxform(key)
- return self._sections[key]
-
- def __setitem__(self, key, value):
- raise Exception('Values must be inside sections', key, value)
-
- def __delitem__(self, key):
- if self._sectionxform: key = self._sectionxform(key)
- for line in self._sections[key]._lines:
- self._data.contents.remove(line)
- del self._sections[key]
-
- def __iter__(self):
- d = set()
- for x in self._data.contents:
- if isinstance(x, LineContainer):
- if x.name not in d:
- yield x.name
- d.add(x.name)
-
- def new_namespace(self, name):
- if self._data.contents:
- self._data.add(EmptyLine())
- obj = LineContainer(SectionLine(name))
- self._data.add(obj)
- if self._sectionxform: name = self._sectionxform(name)
- if name in self._sections:
- ns = self._sections[name]
- ns._lines.append(obj)
- else:
- ns = INISection(obj, defaults=self._defaults,
- optionxformsource=self)
- self._sections[name] = ns
- return ns
-
- def __str__(self):
- return str(self._data)
-
- _line_types = [EmptyLine, CommentLine,
- SectionLine, OptionLine,
- ContinuationLine]
-
- def _parse(self, line):
- for linetype in self._line_types:
- lineobj = linetype.parse(line)
- if lineobj:
- return lineobj
- else:
- # can't parse line
- return None
-
- def readfp(self, fp):
- cur_section = None
- cur_option = None
- cur_section_name = None
- cur_option_name = None
- pending_lines = []
- try:
- fname = fp.name
- except AttributeError:
- fname = '<???>'
- linecount = 0
- exc = None
- line = None
-
- for line in readline_iterator(fp):
- lineobj = self._parse(line)
- linecount += 1
-
- if not cur_section and not isinstance(lineobj,
- (CommentLine, EmptyLine, SectionLine)):
- if self._parse_exc:
- raise MissingSectionHeaderError(fname, linecount, line)
- else:
- lineobj = make_comment(line)
-
- if lineobj is None:
- if self._parse_exc:
- if exc is None: exc = ParsingError(fname)
- exc.append(linecount, line)
- lineobj = make_comment(line)
-
- if isinstance(lineobj, ContinuationLine):
- if cur_option:
- cur_option.extend(pending_lines)
- pending_lines = []
- cur_option.add(lineobj)
- 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 isinstance(lineobj, OptionLine):
- cur_section.extend(pending_lines)
- pending_lines = []
- cur_option = LineContainer(lineobj)
- cur_section.add(cur_option)
- if self._optionxform:
- cur_option_name = self._optionxform(cur_option.name)
- else:
- cur_option_name = cur_option.name
- if cur_section_name == DEFAULTSECT:
- optobj = self._defaults
- else:
- optobj = self._sections[cur_section_name]
- optobj._options[cur_option_name] = cur_option
-
- if isinstance(lineobj, SectionLine):
- self._data.extend(pending_lines)
- pending_lines = []
- cur_section = LineContainer(lineobj)
- self._data.add(cur_section)
- cur_option = None
- cur_option_name = None
- if cur_section.name == DEFAULTSECT:
- self._defaults._lines.append(cur_section)
- cur_section_name = DEFAULTSECT
- else:
- if self._sectionxform:
- cur_section_name = self._sectionxform(cur_section.name)
- else:
- cur_section_name = cur_section.name
- if not self._sections.has_key(cur_section_name):
- self._sections[cur_section_name] = \
- INISection(cur_section, defaults=self._defaults,
- optionxformsource=self)
- else:
- self._sections[cur_section_name]._lines.append(cur_section)
-
- if isinstance(lineobj, (CommentLine, EmptyLine)):
- pending_lines.append(lineobj)
-
- self._data.extend(pending_lines)
- if line and line[-1]=='\n':
- self._data.add(EmptyLine())
-
- if exc:
- raise exc
-
|
Loading...