summaryrefslogtreecommitdiff
path: root/git/config.py
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2015-01-05 15:53:46 +0100
committerSebastian Thiel <byronimo@gmail.com>2015-01-05 15:53:46 +0100
commit04357d0d46fee938a618b64daed1716606e05ca5 (patch)
treeab7f0a4ecc047f4710b7e5cf7182cc3e22e477fc /git/config.py
parentbc8c91200a7fb2140aadd283c66b5ab82f9ad61e (diff)
downloadgitpython-04357d0d46fee938a618b64daed1716606e05ca5.tar.gz
Intermediate commit: test_config and test_actor works
Kind of tackling the tasks step by step, picking low-hanging fruit first, or the ones that everyone depends on
Diffstat (limited to 'git/config.py')
-rw-r--r--git/config.py42
1 files changed, 22 insertions, 20 deletions
diff --git a/git/config.py b/git/config.py
index 34fe290b..988547a0 100644
--- a/git/config.py
+++ b/git/config.py
@@ -14,12 +14,15 @@ except ImportError:
import configparser as cp
import inspect
import logging
+import abc
from git.odict import OrderedDict
from git.util import LockFile
from git.compat import (
string_types,
- FileType
+ FileType,
+ defenc,
+ with_metaclass
)
__all__ = ('GitConfigParser', 'SectionConstraint')
@@ -28,7 +31,7 @@ __all__ = ('GitConfigParser', 'SectionConstraint')
log = logging.getLogger('git.config')
-class MetaParserBuilder(type):
+class MetaParserBuilder(abc.ABCMeta):
"""Utlity class wrapping base-class methods into decorators that assure read-only properties"""
def __new__(metacls, name, bases, clsdict):
@@ -39,7 +42,7 @@ class MetaParserBuilder(type):
if kmm in clsdict:
mutating_methods = clsdict[kmm]
for base in bases:
- methods = (t for t in inspect.getmembers(base, inspect.ismethod) if not t[0].startswith("_"))
+ methods = (t for t in inspect.getmembers(base, inspect.isroutine) if not t[0].startswith("_"))
for name, method in methods:
if name in clsdict:
continue
@@ -112,7 +115,7 @@ class SectionConstraint(object):
return self._config
-class GitConfigParser(cp.RawConfigParser, object):
+class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, object)):
"""Implements specifics required to read git style configuration files.
@@ -128,7 +131,6 @@ class GitConfigParser(cp.RawConfigParser, object):
:note:
The config is case-sensitive even when queried, hence section and option names
must match perfectly."""
- __metaclass__ = MetaParserBuilder
#{ Configuration
# The lock type determines the type of lock to use in new configuration readers.
@@ -150,7 +152,6 @@ class GitConfigParser(cp.RawConfigParser, object):
# list of RawConfigParser methods able to change the instance
_mutating_methods_ = ("add_section", "remove_section", "remove_option", "set")
- __slots__ = ("_sections", "_defaults", "_file_or_files", "_read_only", "_is_initialized", '_lock')
def __init__(self, file_or_files, read_only=True):
"""Initialize a configuration reader to read the given file_or_files and to
@@ -162,12 +163,12 @@ class GitConfigParser(cp.RawConfigParser, object):
:param read_only:
If True, the ConfigParser may only read the data , but not change it.
If False, only a single file path or file object may be given."""
- super(GitConfigParser, self).__init__()
- # initialize base with ordered dictionaries to be sure we write the same
- # file back
- self._sections = OrderedDict()
- self._defaults = OrderedDict()
+ cp.RawConfigParser.__init__(self, dict_type=OrderedDict)
+ # Used in python 3, needs to stay in sync with sections for underlying implementation to work
+ if not hasattr(self, '_proxies'):
+ self._proxies = self._dict()
+
self._file_or_files = file_or_files
self._read_only = read_only
self._is_initialized = False
@@ -222,7 +223,8 @@ class GitConfigParser(cp.RawConfigParser, object):
lineno = 0
e = None # None, or an exception
while True:
- line = fp.readline()
+ # we assume to read binary !
+ line = fp.readline().decode(defenc)
if not line:
break
lineno = lineno + 1
@@ -242,9 +244,9 @@ class GitConfigParser(cp.RawConfigParser, object):
elif sectname == cp.DEFAULTSECT:
cursect = self._defaults
else:
- # THE ONLY LINE WE CHANGED !
- cursect = OrderedDict((('__name__', sectname),))
+ cursect = self._dict((('__name__', sectname),))
self._sections[sectname] = cursect
+ self._proxies[sectname] = None
# So sections can't start with a continuation line
optname = None
# no section header in the file?
@@ -295,7 +297,7 @@ class GitConfigParser(cp.RawConfigParser, object):
# assume a path if it is not a file-object
if not hasattr(file_object, "seek"):
try:
- fp = open(file_object)
+ fp = open(file_object, 'rb')
close_fp = True
except IOError:
continue
@@ -314,16 +316,17 @@ class GitConfigParser(cp.RawConfigParser, object):
"""Write an .ini-format representation of the configuration state in
git compatible format"""
def write_section(name, section_dict):
- fp.write("[%s]\n" % name)
+ fp.write(("[%s]\n" % name).encode(defenc))
for (key, value) in section_dict.items():
if key != "__name__":
- fp.write("\t%s = %s\n" % (key, str(value).replace('\n', '\n\t')))
+ fp.write(("\t%s = %s\n" % (key, str(value).replace('\n', '\n\t'))).encode(defenc))
# END if key is not __name__
# END section writing
if self._defaults:
write_section(cp.DEFAULTSECT, self._defaults)
- map(lambda t: write_section(t[0], t[1]), self._sections.items())
+ for name, value in self._sections.items():
+ write_section(name, value)
@needs_values
def write(self):
@@ -371,8 +374,7 @@ class GitConfigParser(cp.RawConfigParser, object):
@set_dirty_and_flush_changes
def add_section(self, section):
"""Assures added options will stay in order"""
- super(GitConfigParser, self).add_section(section)
- self._sections[section] = OrderedDict()
+ return super(GitConfigParser, self).add_section(section)
@property
def read_only(self):