Remove dependency on Python2.7 OrderedDict, revise config parser
This commit is contained in:
		
							
								
								
									
										262
									
								
								lib/spack/external/ordereddict.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								lib/spack/external/ordereddict.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | |||||||
|  | # | ||||||
|  | # Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. | ||||||
|  | # Passes Python2.7's test suite and incorporates all the latest updates. | ||||||
|  | # | ||||||
|  | # From http://code.activestate.com/recipes/576693-ordered-dictionary-for-py24/ | ||||||
|  | # This file is in the public domain, and has no particular license. | ||||||
|  | # | ||||||
|  | try: | ||||||
|  |     from thread import get_ident as _get_ident | ||||||
|  | except ImportError: | ||||||
|  |     from dummy_thread import get_ident as _get_ident | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     from _abcoll import KeysView, ValuesView, ItemsView | ||||||
|  | except ImportError: | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class OrderedDict(dict): | ||||||
|  |     'Dictionary that remembers insertion order' | ||||||
|  |     # An inherited dict maps keys to values. | ||||||
|  |     # The inherited dict provides __getitem__, __len__, __contains__, and get. | ||||||
|  |     # The remaining methods are order-aware. | ||||||
|  |     # Big-O running times for all methods are the same as for regular dictionaries. | ||||||
|  |  | ||||||
|  |     # The internal self.__map dictionary maps keys to links in a doubly linked list. | ||||||
|  |     # The circular doubly linked list starts and ends with a sentinel element. | ||||||
|  |     # The sentinel element never gets deleted (this simplifies the algorithm). | ||||||
|  |     # Each link is stored as a list of length three:  [PREV, NEXT, KEY]. | ||||||
|  |  | ||||||
|  |     def __init__(self, *args, **kwds): | ||||||
|  |         '''Initialize an ordered dictionary.  Signature is the same as for | ||||||
|  |         regular dictionaries, but keyword arguments are not recommended | ||||||
|  |         because their insertion order is arbitrary. | ||||||
|  |  | ||||||
|  |         ''' | ||||||
|  |         if len(args) > 1: | ||||||
|  |             raise TypeError('expected at most 1 arguments, got %d' % len(args)) | ||||||
|  |         try: | ||||||
|  |             self.__root | ||||||
|  |         except AttributeError: | ||||||
|  |             self.__root = root = []                     # sentinel node | ||||||
|  |             root[:] = [root, root, None] | ||||||
|  |             self.__map = {} | ||||||
|  |         self.__update(*args, **kwds) | ||||||
|  |  | ||||||
|  |     def __setitem__(self, key, value, dict_setitem=dict.__setitem__): | ||||||
|  |         'od.__setitem__(i, y) <==> od[i]=y' | ||||||
|  |         # Setting a new item creates a new link which goes at the end of the linked | ||||||
|  |         # list, and the inherited dictionary is updated with the new key/value pair. | ||||||
|  |         if key not in self: | ||||||
|  |             root = self.__root | ||||||
|  |             last = root[0] | ||||||
|  |             last[1] = root[0] = self.__map[key] = [last, root, key] | ||||||
|  |         dict_setitem(self, key, value) | ||||||
|  |  | ||||||
|  |     def __delitem__(self, key, dict_delitem=dict.__delitem__): | ||||||
|  |         'od.__delitem__(y) <==> del od[y]' | ||||||
|  |         # Deleting an existing item uses self.__map to find the link which is | ||||||
|  |         # then removed by updating the links in the predecessor and successor nodes. | ||||||
|  |         dict_delitem(self, key) | ||||||
|  |         link_prev, link_next, key = self.__map.pop(key) | ||||||
|  |         link_prev[1] = link_next | ||||||
|  |         link_next[0] = link_prev | ||||||
|  |  | ||||||
|  |     def __iter__(self): | ||||||
|  |         'od.__iter__() <==> iter(od)' | ||||||
|  |         root = self.__root | ||||||
|  |         curr = root[1] | ||||||
|  |         while curr is not root: | ||||||
|  |             yield curr[2] | ||||||
|  |             curr = curr[1] | ||||||
|  |  | ||||||
|  |     def __reversed__(self): | ||||||
|  |         'od.__reversed__() <==> reversed(od)' | ||||||
|  |         root = self.__root | ||||||
|  |         curr = root[0] | ||||||
|  |         while curr is not root: | ||||||
|  |             yield curr[2] | ||||||
|  |             curr = curr[0] | ||||||
|  |  | ||||||
|  |     def clear(self): | ||||||
|  |         'od.clear() -> None.  Remove all items from od.' | ||||||
|  |         try: | ||||||
|  |             for node in self.__map.itervalues(): | ||||||
|  |                 del node[:] | ||||||
|  |             root = self.__root | ||||||
|  |             root[:] = [root, root, None] | ||||||
|  |             self.__map.clear() | ||||||
|  |         except AttributeError: | ||||||
|  |             pass | ||||||
|  |         dict.clear(self) | ||||||
|  |  | ||||||
|  |     def popitem(self, last=True): | ||||||
|  |         '''od.popitem() -> (k, v), return and remove a (key, value) pair. | ||||||
|  |         Pairs are returned in LIFO order if last is true or FIFO order if false. | ||||||
|  |  | ||||||
|  |         ''' | ||||||
|  |         if not self: | ||||||
|  |             raise KeyError('dictionary is empty') | ||||||
|  |         root = self.__root | ||||||
|  |         if last: | ||||||
|  |             link = root[0] | ||||||
|  |             link_prev = link[0] | ||||||
|  |             link_prev[1] = root | ||||||
|  |             root[0] = link_prev | ||||||
|  |         else: | ||||||
|  |             link = root[1] | ||||||
|  |             link_next = link[1] | ||||||
|  |             root[1] = link_next | ||||||
|  |             link_next[0] = root | ||||||
|  |         key = link[2] | ||||||
|  |         del self.__map[key] | ||||||
|  |         value = dict.pop(self, key) | ||||||
|  |         return key, value | ||||||
|  |  | ||||||
|  |     # -- the following methods do not depend on the internal structure -- | ||||||
|  |  | ||||||
|  |     def keys(self): | ||||||
|  |         'od.keys() -> list of keys in od' | ||||||
|  |         return list(self) | ||||||
|  |  | ||||||
|  |     def values(self): | ||||||
|  |         'od.values() -> list of values in od' | ||||||
|  |         return [self[key] for key in self] | ||||||
|  |  | ||||||
|  |     def items(self): | ||||||
|  |         'od.items() -> list of (key, value) pairs in od' | ||||||
|  |         return [(key, self[key]) for key in self] | ||||||
|  |  | ||||||
|  |     def iterkeys(self): | ||||||
|  |         'od.iterkeys() -> an iterator over the keys in od' | ||||||
|  |         return iter(self) | ||||||
|  |  | ||||||
|  |     def itervalues(self): | ||||||
|  |         'od.itervalues -> an iterator over the values in od' | ||||||
|  |         for k in self: | ||||||
|  |             yield self[k] | ||||||
|  |  | ||||||
|  |     def iteritems(self): | ||||||
|  |         'od.iteritems -> an iterator over the (key, value) items in od' | ||||||
|  |         for k in self: | ||||||
|  |             yield (k, self[k]) | ||||||
|  |  | ||||||
|  |     def update(*args, **kwds): | ||||||
|  |         '''od.update(E, **F) -> None.  Update od from dict/iterable E and F. | ||||||
|  |  | ||||||
|  |         If E is a dict instance, does:           for k in E: od[k] = E[k] | ||||||
|  |         If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k] | ||||||
|  |         Or if E is an iterable of items, does:   for k, v in E: od[k] = v | ||||||
|  |         In either case, this is followed by:     for k, v in F.items(): od[k] = v | ||||||
|  |  | ||||||
|  |         ''' | ||||||
|  |         if len(args) > 2: | ||||||
|  |             raise TypeError('update() takes at most 2 positional ' | ||||||
|  |                             'arguments (%d given)' % (len(args),)) | ||||||
|  |         elif not args: | ||||||
|  |             raise TypeError('update() takes at least 1 argument (0 given)') | ||||||
|  |         self = args[0] | ||||||
|  |         # Make progressively weaker assumptions about "other" | ||||||
|  |         other = () | ||||||
|  |         if len(args) == 2: | ||||||
|  |             other = args[1] | ||||||
|  |         if isinstance(other, dict): | ||||||
|  |             for key in other: | ||||||
|  |                 self[key] = other[key] | ||||||
|  |         elif hasattr(other, 'keys'): | ||||||
|  |             for key in other.keys(): | ||||||
|  |                 self[key] = other[key] | ||||||
|  |         else: | ||||||
|  |             for key, value in other: | ||||||
|  |                 self[key] = value | ||||||
|  |         for key, value in kwds.items(): | ||||||
|  |             self[key] = value | ||||||
|  |  | ||||||
|  |     __update = update  # let subclasses override update without breaking __init__ | ||||||
|  |  | ||||||
|  |     __marker = object() | ||||||
|  |  | ||||||
|  |     def pop(self, key, default=__marker): | ||||||
|  |         '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. | ||||||
|  |         If key is not found, d is returned if given, otherwise KeyError is raised. | ||||||
|  |  | ||||||
|  |         ''' | ||||||
|  |         if key in self: | ||||||
|  |             result = self[key] | ||||||
|  |             del self[key] | ||||||
|  |             return result | ||||||
|  |         if default is self.__marker: | ||||||
|  |             raise KeyError(key) | ||||||
|  |         return default | ||||||
|  |  | ||||||
|  |     def setdefault(self, key, default=None): | ||||||
|  |         'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' | ||||||
|  |         if key in self: | ||||||
|  |             return self[key] | ||||||
|  |         self[key] = default | ||||||
|  |         return default | ||||||
|  |  | ||||||
|  |     def __repr__(self, _repr_running={}): | ||||||
|  |         'od.__repr__() <==> repr(od)' | ||||||
|  |         call_key = id(self), _get_ident() | ||||||
|  |         if call_key in _repr_running: | ||||||
|  |             return '...' | ||||||
|  |         _repr_running[call_key] = 1 | ||||||
|  |         try: | ||||||
|  |             if not self: | ||||||
|  |                 return '%s()' % (self.__class__.__name__,) | ||||||
|  |             return '%s(%r)' % (self.__class__.__name__, self.items()) | ||||||
|  |         finally: | ||||||
|  |             del _repr_running[call_key] | ||||||
|  |  | ||||||
|  |     def __reduce__(self): | ||||||
|  |         'Return state information for pickling' | ||||||
|  |         items = [[k, self[k]] for k in self] | ||||||
|  |         inst_dict = vars(self).copy() | ||||||
|  |         for k in vars(OrderedDict()): | ||||||
|  |             inst_dict.pop(k, None) | ||||||
|  |         if inst_dict: | ||||||
|  |             return (self.__class__, (items,), inst_dict) | ||||||
|  |         return self.__class__, (items,) | ||||||
|  |  | ||||||
|  |     def copy(self): | ||||||
|  |         'od.copy() -> a shallow copy of od' | ||||||
|  |         return self.__class__(self) | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def fromkeys(cls, iterable, value=None): | ||||||
|  |         '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S | ||||||
|  |         and values equal to v (which defaults to None). | ||||||
|  |  | ||||||
|  |         ''' | ||||||
|  |         d = cls() | ||||||
|  |         for key in iterable: | ||||||
|  |             d[key] = value | ||||||
|  |         return d | ||||||
|  |  | ||||||
|  |     def __eq__(self, other): | ||||||
|  |         '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive | ||||||
|  |         while comparison to a regular mapping is order-insensitive. | ||||||
|  |  | ||||||
|  |         ''' | ||||||
|  |         if isinstance(other, OrderedDict): | ||||||
|  |             return len(self)==len(other) and self.items() == other.items() | ||||||
|  |         return dict.__eq__(self, other) | ||||||
|  |  | ||||||
|  |     def __ne__(self, other): | ||||||
|  |         return not self == other | ||||||
|  |  | ||||||
|  |     # -- the following methods are only used in Python 2.7 -- | ||||||
|  |  | ||||||
|  |     def viewkeys(self): | ||||||
|  |         "od.viewkeys() -> a set-like object providing a view on od's keys" | ||||||
|  |         return KeysView(self) | ||||||
|  |  | ||||||
|  |     def viewvalues(self): | ||||||
|  |         "od.viewvalues() -> an object providing a view on od's values" | ||||||
|  |         return ValuesView(self) | ||||||
|  |  | ||||||
|  |     def viewitems(self): | ||||||
|  |         "od.viewitems() -> a set-like object providing a view on od's items" | ||||||
|  |         return ItemsView(self) | ||||||
| @@ -84,10 +84,9 @@ | |||||||
| import re | import re | ||||||
| import inspect | import inspect | ||||||
| import ConfigParser as cp | import ConfigParser as cp | ||||||
| from collections import OrderedDict |  | ||||||
|  |  | ||||||
|  | from external.ordereddict import OrderedDict | ||||||
| from llnl.util.lang import memoized | from llnl.util.lang import memoized | ||||||
|  |  | ||||||
| import spack.error | import spack.error | ||||||
|  |  | ||||||
| __all__ = [ | __all__ = [ | ||||||
| @@ -222,7 +221,6 @@ class SpackConfigParser(cp.RawConfigParser): | |||||||
|     """ |     """ | ||||||
|     # Slightly modify Python option expressions to allow leading whitespace |     # Slightly modify Python option expressions to allow leading whitespace | ||||||
|     OPTCRE    = re.compile(r'\s*' + cp.RawConfigParser.OPTCRE.pattern) |     OPTCRE    = re.compile(r'\s*' + cp.RawConfigParser.OPTCRE.pattern) | ||||||
|     OPTCRE_NV = re.compile(r'\s*' + cp.RawConfigParser.OPTCRE_NV.pattern) |  | ||||||
|  |  | ||||||
|     def __init__(self, file_or_files): |     def __init__(self, file_or_files): | ||||||
|         cp.RawConfigParser.__init__(self, dict_type=OrderedDict) |         cp.RawConfigParser.__init__(self, dict_type=OrderedDict) | ||||||
| @@ -341,13 +339,12 @@ def write(self, path_or_fp=None): | |||||||
|  |  | ||||||
|  |  | ||||||
|     def _read(self, fp, fpname): |     def _read(self, fp, fpname): | ||||||
|         """This is a copy of Python 2.7's _read() method, with support for |         """This is a copy of Python 2.6's _read() method, with support for | ||||||
|            continuation lines removed. |            continuation lines removed.""" | ||||||
|         """ |  | ||||||
|         cursect = None                            # None, or a dictionary |         cursect = None                            # None, or a dictionary | ||||||
|         optname = None |         optname = None | ||||||
|         lineno = 0 |  | ||||||
|         comment = 0 |         comment = 0 | ||||||
|  |         lineno = 0 | ||||||
|         e = None                                  # None, or an exception |         e = None                                  # None, or an exception | ||||||
|         while True: |         while True: | ||||||
|             line = fp.readline() |             line = fp.readline() | ||||||
| @@ -359,7 +356,6 @@ def _read(self, fp, fpname): | |||||||
|                 (line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR")): |                 (line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR")): | ||||||
|                 self._sections["comment-%d" % comment] = line |                 self._sections["comment-%d" % comment] = line | ||||||
|                 comment += 1 |                 comment += 1 | ||||||
|                 continue |  | ||||||
|             # a section header or option header? |             # a section header or option header? | ||||||
|             else: |             else: | ||||||
|                 # is it a section header? |                 # is it a section header? | ||||||
| @@ -381,13 +377,9 @@ def _read(self, fp, fpname): | |||||||
|                     raise cp.MissingSectionHeaderError(fpname, lineno, line) |                     raise cp.MissingSectionHeaderError(fpname, lineno, line) | ||||||
|                 # an option line? |                 # an option line? | ||||||
|                 else: |                 else: | ||||||
|                     mo = self._optcre.match(line) |                     mo = self.OPTCRE.match(line) | ||||||
|                     if mo: |                     if mo: | ||||||
|                         optname, vi, optval = mo.group('option', 'vi', 'value') |                         optname, vi, optval = mo.group('option', 'vi', 'value') | ||||||
|                         optname = self.optionxform(optname.rstrip()) |  | ||||||
|                         # This check is fine because the OPTCRE cannot |  | ||||||
|                         # match if it would set optval to None |  | ||||||
|                         if optval is not None: |  | ||||||
|                         if vi in ('=', ':') and ';' in optval: |                         if vi in ('=', ':') and ';' in optval: | ||||||
|                             # ';' is a comment delimiter only if it follows |                             # ';' is a comment delimiter only if it follows | ||||||
|                             # a spacing character |                             # a spacing character | ||||||
| @@ -398,9 +390,7 @@ def _read(self, fp, fpname): | |||||||
|                         # allow empty values |                         # allow empty values | ||||||
|                         if optval == '""': |                         if optval == '""': | ||||||
|                             optval = '' |                             optval = '' | ||||||
|                             cursect[optname] = [optval] |                         optname = self.optionxform(optname.rstrip()) | ||||||
|                         else: |  | ||||||
|                             # valueless option handling |  | ||||||
|                         cursect[optname] = optval |                         cursect[optname] = optval | ||||||
|                     else: |                     else: | ||||||
|                         # a non-fatal parsing error occurred.  set up the |                         # a non-fatal parsing error occurred.  set up the | ||||||
| @@ -414,23 +404,13 @@ def _read(self, fp, fpname): | |||||||
|         if e: |         if e: | ||||||
|             raise e |             raise e | ||||||
|  |  | ||||||
|         # join the multi-line values collected while reading |  | ||||||
|         all_sections = [self._defaults] |  | ||||||
|         all_sections.extend(self._sections.values()) |  | ||||||
|         for options in all_sections: |  | ||||||
|             # skip comments |  | ||||||
|             if isinstance(options, basestring): |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             for name, val in options.items(): |  | ||||||
|                 if isinstance(val, list): |  | ||||||
|                     options[name] = '\n'.join(val) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     def _write(self, fp): |     def _write(self, fp): | ||||||
|         """Write an .ini-format representation of the configuration state. |         """Write an .ini-format representation of the configuration state. | ||||||
|  |  | ||||||
|            This is taken from the default Python 2.7 source.  It writes 4 |            This is taken from the default Python 2.6 source.  It writes 4 | ||||||
|            spaces at the beginning of lines instead of no leading space. |            spaces at the beginning of lines instead of no leading space. | ||||||
|         """ |         """ | ||||||
|         if self._defaults: |         if self._defaults: | ||||||
| @@ -449,11 +429,9 @@ def _write(self, fp): | |||||||
|                 # Allow leading whitespace |                 # Allow leading whitespace | ||||||
|                 fp.write("[%s]\n" % section) |                 fp.write("[%s]\n" % section) | ||||||
|                 for (key, value) in self._sections[section].items(): |                 for (key, value) in self._sections[section].items(): | ||||||
|                     if key == "__name__": |                     if key != "__name__": | ||||||
|                         continue |                         fp.write("    %s = %s\n" % | ||||||
|                     if (value is not None) or (self._optcre == self.OPTCRE): |                                  (key, str(value).replace('\n', '\n\t'))) | ||||||
|                         key = " = ".join((key, str(value).replace('\n', '\n\t'))) |  | ||||||
|                     fp.write("    %s\n" % (key)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class SpackConfigurationError(spack.error.SpackError): | class SpackConfigurationError(spack.error.SpackError): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Todd Gamblin
					Todd Gamblin