~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/util/configobj/configobj.py

  • Committer: Vincent Ladeuil
  • Date: 2009-04-27 16:10:10 UTC
  • mto: (4310.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4311.
  • Revision ID: v.ladeuil+lp@free.fr-20090427161010-7swfzeagf63cpixd
Fix bug #367726 by reverting some default user handling introduced
while fixing bug #256612.

* bzrlib/transport/ssh.py:
(_paramiko_auth): Explicitly use getpass.getuser() as default
user.

* bzrlib/transport/ftp/_gssapi.py:
(GSSAPIFtpTransport._create_connection): Explicitly use
getpass.getuser() as default user.

* bzrlib/transport/ftp/__init__.py:
(FtpTransport._create_connection): Explicitly use
getpass.getuser() as default user.

* bzrlib/tests/test_sftp_transport.py:
(TestUsesAuthConfig.test_sftp_is_none_if_no_config)
(TestUsesAuthConfig.test_sftp_doesnt_prompt_username): Revert to
None as the default user.

* bzrlib/tests/test_remote.py:
(TestRemoteSSHTransportAuthentication): The really offending one:
revert to None as the default user.

* bzrlib/tests/test_config.py:
(TestAuthenticationConfig.test_username_default_no_prompt): Update
test (and some PEP8).

* bzrlib/smtp_connection.py:
(SMTPConnection._authenticate): Revert to None as the default
user.

* bzrlib/plugins/launchpad/account.py:
(_get_auth_user): Revert default value handling.

* bzrlib/config.py:
(AuthenticationConfig.get_user): Fix doc-string. Leave default
value handling to callers.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# configobj.py
2
2
# A config file reader/writer that supports nested sections in config files.
3
 
# Copyright (C) 2005-2009 Michael Foord, Nicola Larosa
 
3
# Copyright (C) 2005-2008 Michael Foord, Nicola Larosa
4
4
# E-mail: fuzzyman AT voidspace DOT org DOT uk
5
5
#         nico AT tekNico DOT net
6
6
 
16
16
# http://lists.sourceforge.net/lists/listinfo/configobj-develop
17
17
# Comments, suggestions and bug reports welcome.
18
18
 
19
 
 
20
19
from __future__ import generators
21
20
 
22
21
import sys
23
 
import os
24
 
import re
 
22
INTP_VER = sys.version_info[:2]
 
23
if INTP_VER < (2, 2):
 
24
    raise RuntimeError("Python v.2.2 or later needed")
25
25
 
 
26
import os, re
26
27
compiler = None
27
28
# Bzr modification: Disabled import of 'compiler' module
28
29
# bzr doesn't use the 'unrepr' feature of configobj, so importing compiler just
33
34
#except ImportError:
34
35
#    # for IronPython
35
36
#    pass
36
 
 
37
 
 
 
37
from types import StringTypes
 
38
from warnings import warn
38
39
try:
39
40
    from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
40
41
except ImportError:
100
101
squot = "'%s'"
101
102
dquot = '"%s"'
102
103
noquot = "%s"
103
 
wspace_plus = ' \r\n\v\t\'"'
 
104
wspace_plus = ' \r\t\n\v\t\'"'
104
105
tsquot = '"""%s"""'
105
106
tdquot = "'''%s'''"
106
107
 
114
115
            i += 1
115
116
            yield i, item
116
117
 
117
 
# Sentinel for use in getattr calls to replace hasattr
118
 
MISSING = object()
119
 
 
120
 
__version__ = '4.6.0'
 
118
try:
 
119
    True, False
 
120
except NameError:
 
121
    True, False = 1, 0
 
122
 
 
123
 
 
124
__version__ = '4.5.2'
121
125
 
122
126
__revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $'
123
127
 
250
254
    This is the base class for all errors that ConfigObj raises.
251
255
    It is a subclass of SyntaxError.
252
256
    """
253
 
    def __init__(self, message='', line_number=None, line=''):
 
257
    def __init__(self, msg='', line_number=None, line=''):
254
258
        self.line = line
255
259
        self.line_number = line_number
256
 
        SyntaxError.__init__(self, message)
 
260
        self.msg = msg
 
261
        SyntaxError.__init__(self, msg)
257
262
 
258
263
 
259
264
class NestingError(ConfigObjError):
353
358
            This is similar to a depth-first-search algorithm.
354
359
            """
355
360
            # Have we been here already?
356
 
            if (key, section.name) in backtrail:
 
361
            if backtrail.has_key((key, section.name)):
357
362
                # Yes - infinite loop detected
358
363
                raise InterpolationLoopError(key)
359
364
            # Place a marker on our backtrail so we won't come back here again
486
491
}
487
492
 
488
493
 
489
 
def __newobj__(cls, *args):
490
 
    # Hack for pickle
491
 
    return cls.__new__(cls, *args)
492
494
 
493
495
class Section(dict):
494
496
    """
508
510
    Iteration follows the order: scalars, then sections.
509
511
    """
510
512
 
511
 
 
512
 
    def __setstate__(self, state):
513
 
        dict.update(self, state[0])
514
 
        self.__dict__.update(state[1])
515
 
 
516
 
    def __reduce__(self):
517
 
        state = (dict(self), self.__dict__)
518
 
        return (__newobj__, (self.__class__,), state)
519
 
 
520
 
 
521
513
    def __init__(self, parent, depth, main, indict=None, name=None):
522
514
        """
523
515
        * parent is the section above
552
544
        # for comments :-)
553
545
        self.comments = {}
554
546
        self.inline_comments = {}
555
 
        # the configspec
556
 
        self.configspec = None
 
547
        # for the configspec
 
548
        self.configspec = {}
 
549
        self._order = []
 
550
        self._configspec_comments = {}
 
551
        self._configspec_inline_comments = {}
 
552
        self._cs_section_comments = {}
 
553
        self._cs_section_inline_comments = {}
557
554
        # for defaults
558
555
        self.defaults = []
559
556
        self.default_values = {}
585
582
    def __getitem__(self, key):
586
583
        """Fetch the item and do string interpolation."""
587
584
        val = dict.__getitem__(self, key)
588
 
        if self.main.interpolation and isinstance(val, basestring):
 
585
        if self.main.interpolation and isinstance(val, StringTypes):
589
586
            return self._interpolate(key, val)
590
587
        return val
591
588
 
601
598
        Values need only be strings (or lists of strings) if
602
599
        ``main.stringify`` is set.
603
600
 
604
 
        ``unrepr`` must be set when setting a value to a dictionary, without
 
601
        `unrepr`` must be set when setting a value to a dictionary, without
605
602
        creating a new sub-section.
606
603
        """
607
 
        if not isinstance(key, basestring):
 
604
        if not isinstance(key, StringTypes):
608
605
            raise ValueError('The key "%s" is not a string.' % key)
609
606
 
610
607
        # add the comment
611
 
        if key not in self.comments:
 
608
        if not self.comments.has_key(key):
612
609
            self.comments[key] = []
613
610
            self.inline_comments[key] = ''
614
611
        # remove the entry from defaults
616
613
            self.defaults.remove(key)
617
614
        #
618
615
        if isinstance(value, Section):
619
 
            if key not in self:
 
616
            if not self.has_key(key):
620
617
                self.sections.append(key)
621
618
            dict.__setitem__(self, key, value)
622
619
        elif isinstance(value, dict) and not unrepr:
623
620
            # First create the new depth level,
624
621
            # then create the section
625
 
            if key not in self:
 
622
            if not self.has_key(key):
626
623
                self.sections.append(key)
627
624
            new_depth = self.depth + 1
628
625
            dict.__setitem__(
635
632
                    indict=value,
636
633
                    name=key))
637
634
        else:
638
 
            if key not in self:
 
635
            if not self.has_key(key):
639
636
                self.scalars.append(key)
640
637
            if not self.main.stringify:
641
 
                if isinstance(value, basestring):
 
638
                if isinstance(value, StringTypes):
642
639
                    pass
643
640
                elif isinstance(value, (list, tuple)):
644
641
                    for entry in value:
645
 
                        if not isinstance(entry, basestring):
 
642
                        if not isinstance(entry, StringTypes):
646
643
                            raise TypeError('Value is not a string "%s".' % entry)
647
644
                else:
648
645
                    raise TypeError('Value is not a string "%s".' % value)
690
687
            del self.comments[key]
691
688
            del self.inline_comments[key]
692
689
            self.sections.remove(key)
693
 
        if self.main.interpolation and isinstance(val, basestring):
 
690
        if self.main.interpolation and isinstance(val, StringTypes):
694
691
            return self._interpolate(key, val)
695
692
        return val
696
693
 
719
716
        self.sections = []
720
717
        self.comments = {}
721
718
        self.inline_comments = {}
722
 
        self.configspec = None
 
719
        self.configspec = {}
723
720
 
724
721
 
725
722
    def setdefault(self, key, default=None):
819
816
        >>> c2 = ConfigObj(a)
820
817
        >>> c2.merge(c1)
821
818
        >>> c2
822
 
        ConfigObj({'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}})
 
819
        {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}}
823
820
        """
824
821
        for key, val in indict.items():
825
822
            if (key in self and isinstance(self[key], dict) and
882
879
 
883
880
        See  the encode and decode methods for examples, including functions.
884
881
 
885
 
        .. admonition:: caution
 
882
        .. caution::
886
883
 
887
884
            You can use ``walk`` to transform the names of members of a section
888
885
            but you mustn't add or delete members.
891
888
        ... XXXXkey = XXXXvalue'''.splitlines()
892
889
        >>> cfg = ConfigObj(config)
893
890
        >>> cfg
894
 
        ConfigObj({'XXXXsection': {'XXXXkey': 'XXXXvalue'}})
 
891
        {'XXXXsection': {'XXXXkey': 'XXXXvalue'}}
895
892
        >>> def transform(section, key):
896
893
        ...     val = section[key]
897
894
        ...     newkey = key.replace('XXXX', 'CLIENT1')
904
901
        >>> cfg.walk(transform, call_on_sections=True)
905
902
        {'CLIENT1section': {'CLIENT1key': None}}
906
903
        >>> cfg
907
 
        ConfigObj({'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}})
 
904
        {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}}
908
905
        """
909
906
        out = {}
910
907
        # scalars first
944
941
        return out
945
942
 
946
943
 
 
944
    def decode(self, encoding):
 
945
        """
 
946
        Decode all strings and values to unicode, using the specified encoding.
 
947
 
 
948
        Works with subsections and list values.
 
949
 
 
950
        Uses the ``walk`` method.
 
951
 
 
952
        Testing ``encode`` and ``decode``.
 
953
        >>> m = ConfigObj(a)
 
954
        >>> m.decode('ascii')
 
955
        >>> def testuni(val):
 
956
        ...     for entry in val:
 
957
        ...         if not isinstance(entry, unicode):
 
958
        ...             print >> sys.stderr, type(entry)
 
959
        ...             raise AssertionError, 'decode failed.'
 
960
        ...         if isinstance(val[entry], dict):
 
961
        ...             testuni(val[entry])
 
962
        ...         elif not isinstance(val[entry], unicode):
 
963
        ...             raise AssertionError, 'decode failed.'
 
964
        >>> testuni(m)
 
965
        >>> m.encode('ascii')
 
966
        >>> a == m
 
967
        1
 
968
        """
 
969
        warn('use of ``decode`` is deprecated.', DeprecationWarning)
 
970
        def decode(section, key, encoding=encoding, warn=True):
 
971
            """ """
 
972
            val = section[key]
 
973
            if isinstance(val, (list, tuple)):
 
974
                newval = []
 
975
                for entry in val:
 
976
                    newval.append(entry.decode(encoding))
 
977
            elif isinstance(val, dict):
 
978
                newval = val
 
979
            else:
 
980
                newval = val.decode(encoding)
 
981
            newkey = key.decode(encoding)
 
982
            section.rename(key, newkey)
 
983
            section[newkey] = newval
 
984
        # using ``call_on_sections`` allows us to modify section names
 
985
        self.walk(decode, call_on_sections=True)
 
986
 
 
987
 
 
988
    def encode(self, encoding):
 
989
        """
 
990
        Encode all strings and values from unicode,
 
991
        using the specified encoding.
 
992
 
 
993
        Works with subsections and list values.
 
994
        Uses the ``walk`` method.
 
995
        """
 
996
        warn('use of ``encode`` is deprecated.', DeprecationWarning)
 
997
        def encode(section, key, encoding=encoding):
 
998
            """ """
 
999
            val = section[key]
 
1000
            if isinstance(val, (list, tuple)):
 
1001
                newval = []
 
1002
                for entry in val:
 
1003
                    newval.append(entry.encode(encoding))
 
1004
            elif isinstance(val, dict):
 
1005
                newval = val
 
1006
            else:
 
1007
                newval = val.encode(encoding)
 
1008
            newkey = key.encode(encoding)
 
1009
            section.rename(key, newkey)
 
1010
            section[newkey] = newval
 
1011
        self.walk(encode, call_on_sections=True)
 
1012
 
 
1013
 
 
1014
    def istrue(self, key):
 
1015
        """A deprecated version of ``as_bool``."""
 
1016
        warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
 
1017
                'instead.', DeprecationWarning)
 
1018
        return self.as_bool(key)
 
1019
 
 
1020
 
947
1021
    def as_bool(self, key):
948
1022
        """
949
1023
        Accepts a key as input. The corresponding value must be a string or
979
1053
            return False
980
1054
        else:
981
1055
            try:
982
 
                if not isinstance(val, basestring):
 
1056
                if not isinstance(val, StringTypes):
983
1057
                    # TODO: Why do we raise a KeyError here?
984
1058
                    raise KeyError()
985
1059
                else:
999
1073
        >>> a['a'] = 'fish'
1000
1074
        >>> a.as_int('a')
1001
1075
        Traceback (most recent call last):
1002
 
        ValueError: invalid literal for int() with base 10: 'fish'
 
1076
        ValueError: invalid literal for int(): fish
1003
1077
        >>> a['b'] = '1'
1004
1078
        >>> a.as_int('b')
1005
1079
        1
1006
1080
        >>> a['b'] = '3.2'
1007
1081
        >>> a.as_int('b')
1008
1082
        Traceback (most recent call last):
1009
 
        ValueError: invalid literal for int() with base 10: '3.2'
 
1083
        ValueError: invalid literal for int(): 3.2
1010
1084
        """
1011
1085
        return int(self[key])
1012
1086
 
1033
1107
        return float(self[key])
1034
1108
 
1035
1109
 
1036
 
    def as_list(self, key):
1037
 
        """
1038
 
        A convenience method which fetches the specified value, guaranteeing
1039
 
        that it is a list.
1040
 
 
1041
 
        >>> a = ConfigObj()
1042
 
        >>> a['a'] = 1
1043
 
        >>> a.as_list('a')
1044
 
        [1]
1045
 
        >>> a['a'] = (1,)
1046
 
        >>> a.as_list('a')
1047
 
        [1]
1048
 
        >>> a['a'] = [1]
1049
 
        >>> a.as_list('a')
1050
 
        [1]
1051
 
        """
1052
 
        result = self[key]
1053
 
        if isinstance(result, (tuple, list)):
1054
 
            return list(result)
1055
 
        return [result]
1056
 
 
1057
 
 
1058
1110
    def restore_default(self, key):
1059
1111
        """
1060
1112
        Restore (and return) default value for the specified key.
1191
1243
        }
1192
1244
 
1193
1245
 
1194
 
    def __init__(self, infile=None, options=None, _inspec=False, **kwargs):
 
1246
    def __init__(self, infile=None, options=None, **kwargs):
1195
1247
        """
1196
1248
        Parse a config file or create a config file object.
1197
1249
 
1198
1250
        ``ConfigObj(infile=None, options=None, **kwargs)``
1199
1251
        """
1200
 
        self._inspec = _inspec
1201
1252
        # init the superclass
1202
1253
        Section.__init__(self, self, 0, self)
1203
1254
 
1204
 
        infile = infile or []
1205
 
        options = dict(options or {})
 
1255
        if infile is None:
 
1256
            infile = []
 
1257
        if options is None:
 
1258
            options = {}
 
1259
        else:
 
1260
            options = dict(options)
1206
1261
 
1207
1262
        # keyword arguments take precedence over an options dictionary
1208
1263
        options.update(kwargs)
1209
 
        if _inspec:
1210
 
            options['list_values'] = False
1211
1264
 
1212
1265
        defaults = OPTION_DEFAULTS.copy()
1213
1266
        # TODO: check the values too.
1224
1277
 
1225
1278
 
1226
1279
    def _load(self, infile, configspec):
1227
 
        if isinstance(infile, basestring):
 
1280
        if isinstance(infile, StringTypes):
1228
1281
            self.filename = infile
1229
1282
            if os.path.isfile(infile):
1230
1283
                h = open(infile, 'rb')
1263
1316
                self.configspec = None
1264
1317
            return
1265
1318
 
1266
 
        elif getattr(infile, 'read', MISSING) is not MISSING:
 
1319
        elif getattr(infile, 'read', None) is not None:
1267
1320
            # This supports file like objects
1268
1321
            infile = infile.read() or []
1269
1322
            # needs splitting into lines - but needs doing *after* decoding
1336
1389
 
1337
1390
        self.initial_comment = []
1338
1391
        self.final_comment = []
1339
 
        self.configspec = None
1340
 
 
1341
 
        if self._inspec:
1342
 
            self.list_values = False
 
1392
        self.configspec = {}
1343
1393
 
1344
1394
        # Clear section attributes as well
1345
1395
        Section._initialise(self)
1438
1488
                    else:
1439
1489
                        infile = newline
1440
1490
                    # UTF8 - don't decode
1441
 
                    if isinstance(infile, basestring):
 
1491
                    if isinstance(infile, StringTypes):
1442
1492
                        return infile.splitlines(True)
1443
1493
                    else:
1444
1494
                        return infile
1446
1496
                return self._decode(infile, encoding)
1447
1497
 
1448
1498
        # No BOM discovered and no encoding specified, just return
1449
 
        if isinstance(infile, basestring):
 
1499
        if isinstance(infile, StringTypes):
1450
1500
            # infile read from a file will be a single string
1451
1501
            return infile.splitlines(True)
1452
1502
        return infile
1466
1516
 
1467
1517
        if is a string, it also needs converting to a list.
1468
1518
        """
1469
 
        if isinstance(infile, basestring):
 
1519
        if isinstance(infile, StringTypes):
1470
1520
            # can't be unicode
1471
1521
            # NOTE: Could raise a ``UnicodeDecodeError``
1472
1522
            return infile.decode(encoding).splitlines(True)
1493
1543
        Used by ``stringify`` within validate, to turn non-string values
1494
1544
        into strings.
1495
1545
        """
1496
 
        if not isinstance(value, basestring):
 
1546
        if not isinstance(value, StringTypes):
1497
1547
            return str(value)
1498
1548
        else:
1499
1549
            return value
1564
1614
                                       NestingError, infile, cur_index)
1565
1615
 
1566
1616
                sect_name = self._unquote(sect_name)
1567
 
                if sect_name in parent:
 
1617
                if parent.has_key(sect_name):
1568
1618
                    self._handle_error('Duplicate section name at line %s.',
1569
1619
                                       DuplicateError, infile, cur_index)
1570
1620
                    continue
1642
1692
                            continue
1643
1693
                #
1644
1694
                key = self._unquote(key)
1645
 
                if key in this_section:
 
1695
                if this_section.has_key(key):
1646
1696
                    self._handle_error(
1647
1697
                        'Duplicate keyword name at line %s.',
1648
1698
                        DuplicateError, infile, cur_index)
1720
1770
        If multiline is ``True`` (default) then use triple quotes
1721
1771
        if necessary.
1722
1772
 
1723
 
        * Don't quote values that don't need it.
1724
 
        * Recursively quote members of a list and return a comma joined list.
1725
 
        * Multiline is ``False`` for lists.
1726
 
        * Obey list syntax for empty and single member lists.
 
1773
        Don't quote values that don't need it.
 
1774
        Recursively quote members of a list and return a comma joined list.
 
1775
        Multiline is ``False`` for lists.
 
1776
        Obey list syntax for empty and single member lists.
1727
1777
 
1728
1778
        If ``list_values=False`` then the value is only quoted if it contains
1729
 
        a ``\\n`` (is multiline) or '#'.
 
1779
        a ``\n`` (is multiline) or '#'.
1730
1780
 
1731
1781
        If ``write_empty_values`` is set, and the value is an empty string, it
1732
1782
        won't be quoted.
1743
1793
                return self._quote(value[0], multiline=False) + ','
1744
1794
            return ', '.join([self._quote(val, multiline=False)
1745
1795
                for val in value])
1746
 
        if not isinstance(value, basestring):
 
1796
        if not isinstance(value, StringTypes):
1747
1797
            if self.stringify:
1748
1798
                value = str(value)
1749
1799
            else:
1806
1856
        Given a value string, unquote, remove comment,
1807
1857
        handle lists. (including empty and single member lists)
1808
1858
        """
1809
 
        if self._inspec:
1810
 
            # Parsing a configspec so don't handle comments
1811
 
            return (value, '')
1812
1859
        # do we look for lists in values ?
1813
1860
        if not self.list_values:
1814
1861
            mat = self._nolistvalue.match(value)
1894
1941
                configspec = ConfigObj(configspec,
1895
1942
                                       raise_errors=True,
1896
1943
                                       file_error=True,
1897
 
                                       _inspec=True)
 
1944
                                       list_values=False)
1898
1945
            except ConfigObjError, e:
1899
1946
                # FIXME: Should these errors have a reference
1900
1947
                #        to the already parsed ConfigObj ?
1902
1949
            except IOError, e:
1903
1950
                raise IOError('Reading configspec failed: %s' % e)
1904
1951
 
1905
 
        self.configspec = configspec
1906
 
 
1907
 
 
1908
 
 
1909
 
    def _set_configspec(self, section, copy):
1910
 
        """
1911
 
        Called by validate. Handles setting the configspec on subsections
1912
 
        including sections to be validated by __many__
1913
 
        """
1914
 
        configspec = section.configspec
1915
 
        many = configspec.get('__many__')
1916
 
        if isinstance(many, dict):
1917
 
            for entry in section.sections:
1918
 
                if entry not in configspec:
1919
 
                    section[entry].configspec = many
 
1952
        self._set_configspec_value(configspec, self)
 
1953
 
 
1954
 
 
1955
    def _set_configspec_value(self, configspec, section):
 
1956
        """Used to recursively set configspec values."""
 
1957
        if '__many__' in configspec.sections:
 
1958
            section.configspec['__many__'] = configspec['__many__']
 
1959
            if len(configspec.sections) > 1:
 
1960
                # FIXME: can we supply any useful information here ?
 
1961
                raise RepeatSectionError()
 
1962
 
 
1963
        if getattr(configspec, 'initial_comment', None) is not None:
 
1964
            section._configspec_initial_comment = configspec.initial_comment
 
1965
            section._configspec_final_comment = configspec.final_comment
 
1966
            section._configspec_encoding = configspec.encoding
 
1967
            section._configspec_BOM = configspec.BOM
 
1968
            section._configspec_newlines = configspec.newlines
 
1969
            section._configspec_indent_type = configspec.indent_type
 
1970
 
 
1971
        for entry in configspec.scalars:
 
1972
            section._configspec_comments[entry] = configspec.comments[entry]
 
1973
            section._configspec_inline_comments[entry] = configspec.inline_comments[entry]
 
1974
            section.configspec[entry] = configspec[entry]
 
1975
            section._order.append(entry)
1920
1976
 
1921
1977
        for entry in configspec.sections:
1922
1978
            if entry == '__many__':
1923
1979
                continue
1924
 
            if entry not in section:
1925
 
                section[entry] = {}
1926
 
                if copy:
1927
 
                    # copy comments
1928
 
                    section.comments[entry] = configspec.comments.get(entry, [])
1929
 
                    section.inline_comments[entry] = configspec.inline_comments.get(entry, '')
1930
 
 
1931
 
            # Could be a scalar when we expect a section
1932
 
            if isinstance(section[entry], Section):
1933
 
                section[entry].configspec = configspec[entry]
 
1980
 
 
1981
            section._cs_section_comments[entry] = configspec.comments[entry]
 
1982
            section._cs_section_inline_comments[entry] = configspec.inline_comments[entry]
 
1983
            if not section.has_key(entry):
 
1984
                section[entry] = {}
 
1985
            self._set_configspec_value(configspec[entry], section[entry])
 
1986
 
 
1987
 
 
1988
    def _handle_repeat(self, section, configspec):
 
1989
        """Dynamically assign configspec for repeated section."""
 
1990
        try:
 
1991
            section_keys = configspec.sections
 
1992
            scalar_keys = configspec.scalars
 
1993
        except AttributeError:
 
1994
            section_keys = [entry for entry in configspec
 
1995
                                if isinstance(configspec[entry], dict)]
 
1996
            scalar_keys = [entry for entry in configspec
 
1997
                                if not isinstance(configspec[entry], dict)]
 
1998
 
 
1999
        if '__many__' in section_keys and len(section_keys) > 1:
 
2000
            # FIXME: can we supply any useful information here ?
 
2001
            raise RepeatSectionError()
 
2002
 
 
2003
        scalars = {}
 
2004
        sections = {}
 
2005
        for entry in scalar_keys:
 
2006
            val = configspec[entry]
 
2007
            scalars[entry] = val
 
2008
        for entry in section_keys:
 
2009
            val = configspec[entry]
 
2010
            if entry == '__many__':
 
2011
                scalars[entry] = val
 
2012
                continue
 
2013
            sections[entry] = val
 
2014
 
 
2015
        section.configspec = scalars
 
2016
        for entry in sections:
 
2017
            if not section.has_key(entry):
 
2018
                section[entry] = {}
 
2019
            self._handle_repeat(section[entry], sections[entry])
1934
2020
 
1935
2021
 
1936
2022
    def _write_line(self, indent_string, entry, this_entry, comment):
2116
2202
                # Which makes importing configobj faster
2117
2203
                from validate import VdtMissingValue
2118
2204
                self._vdtMissingValue = VdtMissingValue
2119
 
 
2120
2205
            section = self
2121
 
 
2122
 
            if copy:
2123
 
                section.initial_comment = section.configspec.initial_comment
2124
 
                section.final_comment = section.configspec.final_comment
2125
 
                section.encoding = section.configspec.encoding
2126
 
                section.BOM = section.configspec.BOM
2127
 
                section.newlines = section.configspec.newlines
2128
 
                section.indent_type = section.configspec.indent_type
2129
 
 
2130
 
        #
2131
 
        configspec = section.configspec
2132
 
        self._set_configspec(section, copy)
2133
 
 
2134
 
        def validate_entry(entry, spec, val, missing, ret_true, ret_false):
 
2206
        #
 
2207
        spec_section = section.configspec
 
2208
        if copy and getattr(section, '_configspec_initial_comment', None) is not None:
 
2209
            section.initial_comment = section._configspec_initial_comment
 
2210
            section.final_comment = section._configspec_final_comment
 
2211
            section.encoding = section._configspec_encoding
 
2212
            section.BOM = section._configspec_BOM
 
2213
            section.newlines = section._configspec_newlines
 
2214
            section.indent_type = section._configspec_indent_type
 
2215
 
 
2216
        if '__many__' in section.configspec:
 
2217
            many = spec_section['__many__']
 
2218
            # dynamically assign the configspecs
 
2219
            # for the sections below
 
2220
            for entry in section.sections:
 
2221
                self._handle_repeat(section[entry], many)
 
2222
        #
 
2223
        out = {}
 
2224
        ret_true = True
 
2225
        ret_false = True
 
2226
        order = [k for k in section._order if k in spec_section]
 
2227
        order += [k for k in spec_section if k not in order]
 
2228
        for entry in order:
 
2229
            if entry == '__many__':
 
2230
                continue
 
2231
            if (not entry in section.scalars) or (entry in section.defaults):
 
2232
                # missing entries
 
2233
                # or entries from defaults
 
2234
                missing = True
 
2235
                val = None
 
2236
                if copy and not entry in section.scalars:
 
2237
                    # copy comments
 
2238
                    section.comments[entry] = (
 
2239
                        section._configspec_comments.get(entry, []))
 
2240
                    section.inline_comments[entry] = (
 
2241
                        section._configspec_inline_comments.get(entry, ''))
 
2242
                #
 
2243
            else:
 
2244
                missing = False
 
2245
                val = section[entry]
2135
2246
            try:
2136
 
                check = validator.check(spec,
 
2247
                check = validator.check(spec_section[entry],
2137
2248
                                        val,
2138
2249
                                        missing=missing
2139
2250
                                        )
2155
2266
                    except KeyError:
2156
2267
                        pass
2157
2268
 
2158
 
                try:
2159
 
                    section.default_values[entry] = validator.get_default_value(configspec[entry])
2160
 
                except (KeyError, AttributeError):
2161
 
                    # No default or validator has no 'get_default_value' (e.g. SimpleVal)
2162
 
                    pass
 
2269
                if getattr(validator, 'get_default_value', None) is not None:
 
2270
                    try:
 
2271
                        section.default_values[entry] = validator.get_default_value(spec_section[entry])
 
2272
                    except KeyError:
 
2273
                        # No default
 
2274
                        pass
2163
2275
 
2164
2276
                ret_false = False
2165
2277
                out[entry] = True
2179
2291
                        section[entry] = check
2180
2292
                if not copy and missing and entry not in section.defaults:
2181
2293
                    section.defaults.append(entry)
2182
 
            return ret_true, ret_false
2183
 
 
2184
 
        #
2185
 
        out = {}
2186
 
        ret_true = True
2187
 
        ret_false = True
2188
 
 
2189
 
        unvalidated = [k for k in section.scalars if k not in configspec]
2190
 
        incorrect_sections = [k for k in configspec.sections if k in section.scalars]
2191
 
        incorrect_scalars = [k for k in configspec.scalars if k in section.sections]
2192
 
 
2193
 
        for entry in configspec.scalars:
2194
 
            if entry in ('__many__', '___many___'):
2195
 
                # reserved names
2196
 
                continue
2197
 
 
2198
 
            if (not entry in section.scalars) or (entry in section.defaults):
2199
 
                # missing entries
2200
 
                # or entries from defaults
2201
 
                missing = True
2202
 
                val = None
2203
 
                if copy and not entry in section.scalars:
2204
 
                    # copy comments
2205
 
                    section.comments[entry] = (
2206
 
                        configspec.comments.get(entry, []))
2207
 
                    section.inline_comments[entry] = (
2208
 
                        configspec.inline_comments.get(entry, ''))
2209
 
                #
2210
 
            else:
2211
 
                missing = False
2212
 
                val = section[entry]
2213
 
 
2214
 
            ret_true, ret_false = validate_entry(entry, configspec[entry], val,
2215
 
                                                 missing, ret_true, ret_false)
2216
 
 
2217
 
        many = None
2218
 
        if '__many__' in configspec.scalars:
2219
 
            many = configspec['__many__']
2220
 
        elif '___many___' in configspec.scalars:
2221
 
            many = configspec['___many___']
2222
 
 
2223
 
        if many is not None:
2224
 
            for entry in unvalidated:
2225
 
                val = section[entry]
2226
 
                ret_true, ret_false = validate_entry(entry, many, val, False,
2227
 
                                                     ret_true, ret_false)
2228
 
 
2229
 
        for entry in incorrect_scalars:
2230
 
            ret_true = False
2231
 
            if not preserve_errors:
2232
 
                out[entry] = False
2233
 
            else:
2234
 
                ret_false = False
2235
 
                msg = 'Value %r was provided as a section' % entry
2236
 
                out[entry] = validator.baseErrorClass(msg)
2237
 
        for entry in incorrect_sections:
2238
 
            ret_true = False
2239
 
            if not preserve_errors:
2240
 
                out[entry] = False
2241
 
            else:
2242
 
                ret_false = False
2243
 
                msg = 'Section %r was provided as a single value' % entry
2244
 
                out[entry] = validator.baseErrorClass(msg)
2245
 
 
2246
2294
        # Missing sections will have been created as empty ones when the
2247
2295
        # configspec was read.
2248
2296
        for entry in section.sections:
2249
2297
            # FIXME: this means DEFAULT is not copied in copy mode
2250
2298
            if section is self and entry == 'DEFAULT':
2251
2299
                continue
2252
 
            if section[entry].configspec is None:
2253
 
                continue
2254
2300
            if copy:
2255
 
                section.comments[entry] = configspec.comments.get(entry, [])
2256
 
                section.inline_comments[entry] = configspec.inline_comments.get(entry, '')
2257
 
            check = self.validate(validator, preserve_errors=preserve_errors, copy=copy, section=section[entry])
 
2301
                section.comments[entry] = section._cs_section_comments[entry]
 
2302
                section.inline_comments[entry] = (
 
2303
                    section._cs_section_inline_comments[entry])
 
2304
            check = self.validate(validator, preserve_errors=preserve_errors,
 
2305
                copy=copy, section=section[entry])
2258
2306
            out[entry] = check
2259
2307
            if check == False:
2260
2308
                ret_true = False
2289
2337
        This method raises a ``ReloadError`` if the ConfigObj doesn't have
2290
2338
        a filename attribute pointing to a file.
2291
2339
        """
2292
 
        if not isinstance(self.filename, basestring):
 
2340
        if not isinstance(self.filename, StringTypes):
2293
2341
            raise ReloadError()
2294
2342
 
2295
2343
        filename = self.filename
2340
2388
    dictionary returned by ``validate``.
2341
2389
 
2342
2390
    (This is a recursive function, so you shouldn't use the ``levels`` or
2343
 
    ``results`` arguments - they are used by the function.)
 
2391
    ``results`` arguments - they are used by the function.
2344
2392
 
2345
2393
    Returns a list of keys that failed. Each member of the list is a tuple :
2346
 
 
2347
2394
    ::
2348
2395
 
2349
2396
        ([list of sections...], key, result)
2354
2401
    *list of sections* is a flattened list of sections that the key was found
2355
2402
    in.
2356
2403
 
2357
 
    If the section was missing (or a section was expected and a scalar provided
2358
 
    - or vice-versa) then key will be ``None``.
 
2404
    If the section was missing then key will be ``None``.
2359
2405
 
2360
2406
    If the value (or section) was missing then ``result`` will be ``False``.
2361
2407
 
2434
2480
        results = []
2435
2481
    if res is True:
2436
2482
        return results
2437
 
    if res is False or isinstance(res, Exception):
2438
 
        results.append((levels[:], None, res))
 
2483
    if res is False:
 
2484
        results.append((levels[:], None, False))
2439
2485
        if levels:
2440
2486
            levels.pop()
2441
2487
        return results