python (3.11.7)

(root)/
lib/
python3.11/
site-packages/
pip/
_vendor/
distlib/
compat.py
       1  # -*- coding: utf-8 -*-
       2  #
       3  # Copyright (C) 2013-2017 Vinay Sajip.
       4  # Licensed to the Python Software Foundation under a contributor agreement.
       5  # See LICENSE.txt and CONTRIBUTORS.txt.
       6  #
       7  from __future__ import absolute_import
       8  
       9  import os
      10  import re
      11  import sys
      12  
      13  try:
      14      import ssl
      15  except ImportError:  # pragma: no cover
      16      ssl = None
      17  
      18  if sys.version_info[0] < 3:  # pragma: no cover
      19      from StringIO import StringIO
      20      string_types = basestring,
      21      text_type = unicode
      22      from types import FileType as file_type
      23      import __builtin__ as builtins
      24      import ConfigParser as configparser
      25      from urlparse import urlparse, urlunparse, urljoin, urlsplit, urlunsplit
      26      from urllib import (urlretrieve, quote as _quote, unquote, url2pathname,
      27                          pathname2url, ContentTooShortError, splittype)
      28  
      29      def quote(s):
      30          if isinstance(s, unicode):
      31              s = s.encode('utf-8')
      32          return _quote(s)
      33  
      34      import urllib2
      35      from urllib2 import (Request, urlopen, URLError, HTTPError,
      36                           HTTPBasicAuthHandler, HTTPPasswordMgr,
      37                           HTTPHandler, HTTPRedirectHandler,
      38                           build_opener)
      39      if ssl:
      40          from urllib2 import HTTPSHandler
      41      import httplib
      42      import xmlrpclib
      43      import Queue as queue
      44      from HTMLParser import HTMLParser
      45      import htmlentitydefs
      46      raw_input = raw_input
      47      from itertools import ifilter as filter
      48      from itertools import ifilterfalse as filterfalse
      49  
      50      # Leaving this around for now, in case it needs resurrecting in some way
      51      # _userprog = None
      52      # def splituser(host):
      53          # """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'."""
      54          # global _userprog
      55          # if _userprog is None:
      56              # import re
      57              # _userprog = re.compile('^(.*)@(.*)$')
      58  
      59          # match = _userprog.match(host)
      60          # if match: return match.group(1, 2)
      61          # return None, host
      62  
      63  else:  # pragma: no cover
      64      from io import StringIO
      65      string_types = str,
      66      text_type = str
      67      from io import TextIOWrapper as file_type
      68      import builtins
      69      import configparser
      70      import shutil
      71      from urllib.parse import (urlparse, urlunparse, urljoin, quote,
      72                                unquote, urlsplit, urlunsplit, splittype)
      73      from urllib.request import (urlopen, urlretrieve, Request, url2pathname,
      74                                  pathname2url,
      75                                  HTTPBasicAuthHandler, HTTPPasswordMgr,
      76                                  HTTPHandler, HTTPRedirectHandler,
      77                                  build_opener)
      78      if ssl:
      79          from urllib.request import HTTPSHandler
      80      from urllib.error import HTTPError, URLError, ContentTooShortError
      81      import http.client as httplib
      82      import urllib.request as urllib2
      83      import xmlrpc.client as xmlrpclib
      84      import queue
      85      from html.parser import HTMLParser
      86      import html.entities as htmlentitydefs
      87      raw_input = input
      88      from itertools import filterfalse
      89      filter = filter
      90  
      91  
      92  try:
      93      from ssl import match_hostname, CertificateError
      94  except ImportError: # pragma: no cover
      95      class ESC[4;38;5;81mCertificateError(ESC[4;38;5;149mValueError):
      96          pass
      97  
      98  
      99      def _dnsname_match(dn, hostname, max_wildcards=1):
     100          """Matching according to RFC 6125, section 6.4.3
     101  
     102          http://tools.ietf.org/html/rfc6125#section-6.4.3
     103          """
     104          pats = []
     105          if not dn:
     106              return False
     107  
     108          parts = dn.split('.')
     109          leftmost, remainder = parts[0], parts[1:]
     110  
     111          wildcards = leftmost.count('*')
     112          if wildcards > max_wildcards:
     113              # Issue #17980: avoid denials of service by refusing more
     114              # than one wildcard per fragment.  A survey of established
     115              # policy among SSL implementations showed it to be a
     116              # reasonable choice.
     117              raise CertificateError(
     118                  "too many wildcards in certificate DNS name: " + repr(dn))
     119  
     120          # speed up common case w/o wildcards
     121          if not wildcards:
     122              return dn.lower() == hostname.lower()
     123  
     124          # RFC 6125, section 6.4.3, subitem 1.
     125          # The client SHOULD NOT attempt to match a presented identifier in which
     126          # the wildcard character comprises a label other than the left-most label.
     127          if leftmost == '*':
     128              # When '*' is a fragment by itself, it matches a non-empty dotless
     129              # fragment.
     130              pats.append('[^.]+')
     131          elif leftmost.startswith('xn--') or hostname.startswith('xn--'):
     132              # RFC 6125, section 6.4.3, subitem 3.
     133              # The client SHOULD NOT attempt to match a presented identifier
     134              # where the wildcard character is embedded within an A-label or
     135              # U-label of an internationalized domain name.
     136              pats.append(re.escape(leftmost))
     137          else:
     138              # Otherwise, '*' matches any dotless string, e.g. www*
     139              pats.append(re.escape(leftmost).replace(r'\*', '[^.]*'))
     140  
     141          # add the remaining fragments, ignore any wildcards
     142          for frag in remainder:
     143              pats.append(re.escape(frag))
     144  
     145          pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
     146          return pat.match(hostname)
     147  
     148  
     149      def match_hostname(cert, hostname):
     150          """Verify that *cert* (in decoded format as returned by
     151          SSLSocket.getpeercert()) matches the *hostname*.  RFC 2818 and RFC 6125
     152          rules are followed, but IP addresses are not accepted for *hostname*.
     153  
     154          CertificateError is raised on failure. On success, the function
     155          returns nothing.
     156          """
     157          if not cert:
     158              raise ValueError("empty or no certificate, match_hostname needs a "
     159                               "SSL socket or SSL context with either "
     160                               "CERT_OPTIONAL or CERT_REQUIRED")
     161          dnsnames = []
     162          san = cert.get('subjectAltName', ())
     163          for key, value in san:
     164              if key == 'DNS':
     165                  if _dnsname_match(value, hostname):
     166                      return
     167                  dnsnames.append(value)
     168          if not dnsnames:
     169              # The subject is only checked when there is no dNSName entry
     170              # in subjectAltName
     171              for sub in cert.get('subject', ()):
     172                  for key, value in sub:
     173                      # XXX according to RFC 2818, the most specific Common Name
     174                      # must be used.
     175                      if key == 'commonName':
     176                          if _dnsname_match(value, hostname):
     177                              return
     178                          dnsnames.append(value)
     179          if len(dnsnames) > 1:
     180              raise CertificateError("hostname %r "
     181                  "doesn't match either of %s"
     182                  % (hostname, ', '.join(map(repr, dnsnames))))
     183          elif len(dnsnames) == 1:
     184              raise CertificateError("hostname %r "
     185                  "doesn't match %r"
     186                  % (hostname, dnsnames[0]))
     187          else:
     188              raise CertificateError("no appropriate commonName or "
     189                  "subjectAltName fields were found")
     190  
     191  
     192  try:
     193      from types import SimpleNamespace as Container
     194  except ImportError:  # pragma: no cover
     195      class ESC[4;38;5;81mContainer(ESC[4;38;5;149mobject):
     196          """
     197          A generic container for when multiple values need to be returned
     198          """
     199          def __init__(self, **kwargs):
     200              self.__dict__.update(kwargs)
     201  
     202  
     203  try:
     204      from shutil import which
     205  except ImportError:  # pragma: no cover
     206      # Implementation from Python 3.3
     207      def which(cmd, mode=os.F_OK | os.X_OK, path=None):
     208          """Given a command, mode, and a PATH string, return the path which
     209          conforms to the given mode on the PATH, or None if there is no such
     210          file.
     211  
     212          `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
     213          of os.environ.get("PATH"), or can be overridden with a custom search
     214          path.
     215  
     216          """
     217          # Check that a given file can be accessed with the correct mode.
     218          # Additionally check that `file` is not a directory, as on Windows
     219          # directories pass the os.access check.
     220          def _access_check(fn, mode):
     221              return (os.path.exists(fn) and os.access(fn, mode)
     222                      and not os.path.isdir(fn))
     223  
     224          # If we're given a path with a directory part, look it up directly rather
     225          # than referring to PATH directories. This includes checking relative to the
     226          # current directory, e.g. ./script
     227          if os.path.dirname(cmd):
     228              if _access_check(cmd, mode):
     229                  return cmd
     230              return None
     231  
     232          if path is None:
     233              path = os.environ.get("PATH", os.defpath)
     234          if not path:
     235              return None
     236          path = path.split(os.pathsep)
     237  
     238          if sys.platform == "win32":
     239              # The current directory takes precedence on Windows.
     240              if not os.curdir in path:
     241                  path.insert(0, os.curdir)
     242  
     243              # PATHEXT is necessary to check on Windows.
     244              pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
     245              # See if the given file matches any of the expected path extensions.
     246              # This will allow us to short circuit when given "python.exe".
     247              # If it does match, only test that one, otherwise we have to try
     248              # others.
     249              if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
     250                  files = [cmd]
     251              else:
     252                  files = [cmd + ext for ext in pathext]
     253          else:
     254              # On other platforms you don't have things like PATHEXT to tell you
     255              # what file suffixes are executable, so just pass on cmd as-is.
     256              files = [cmd]
     257  
     258          seen = set()
     259          for dir in path:
     260              normdir = os.path.normcase(dir)
     261              if not normdir in seen:
     262                  seen.add(normdir)
     263                  for thefile in files:
     264                      name = os.path.join(dir, thefile)
     265                      if _access_check(name, mode):
     266                          return name
     267          return None
     268  
     269  
     270  # ZipFile is a context manager in 2.7, but not in 2.6
     271  
     272  from zipfile import ZipFile as BaseZipFile
     273  
     274  if hasattr(BaseZipFile, '__enter__'):  # pragma: no cover
     275      ZipFile = BaseZipFile
     276  else:  # pragma: no cover
     277      from zipfile import ZipExtFile as BaseZipExtFile
     278  
     279      class ESC[4;38;5;81mZipExtFile(ESC[4;38;5;149mBaseZipExtFile):
     280          def __init__(self, base):
     281              self.__dict__.update(base.__dict__)
     282  
     283          def __enter__(self):
     284              return self
     285  
     286          def __exit__(self, *exc_info):
     287              self.close()
     288              # return None, so if an exception occurred, it will propagate
     289  
     290      class ESC[4;38;5;81mZipFile(ESC[4;38;5;149mBaseZipFile):
     291          def __enter__(self):
     292              return self
     293  
     294          def __exit__(self, *exc_info):
     295              self.close()
     296              # return None, so if an exception occurred, it will propagate
     297  
     298          def open(self, *args, **kwargs):
     299              base = BaseZipFile.open(self, *args, **kwargs)
     300              return ZipExtFile(base)
     301  
     302  try:
     303      from platform import python_implementation
     304  except ImportError: # pragma: no cover
     305      def python_implementation():
     306          """Return a string identifying the Python implementation."""
     307          if 'PyPy' in sys.version:
     308              return 'PyPy'
     309          if os.name == 'java':
     310              return 'Jython'
     311          if sys.version.startswith('IronPython'):
     312              return 'IronPython'
     313          return 'CPython'
     314  
     315  import shutil
     316  import sysconfig
     317  
     318  try:
     319      callable = callable
     320  except NameError:   # pragma: no cover
     321      from collections.abc import Callable
     322  
     323      def callable(obj):
     324          return isinstance(obj, Callable)
     325  
     326  
     327  try:
     328      fsencode = os.fsencode
     329      fsdecode = os.fsdecode
     330  except AttributeError:  # pragma: no cover
     331      # Issue #99: on some systems (e.g. containerised),
     332      # sys.getfilesystemencoding() returns None, and we need a real value,
     333      # so fall back to utf-8. From the CPython 2.7 docs relating to Unix and
     334      # sys.getfilesystemencoding(): the return value is "the user’s preference
     335      # according to the result of nl_langinfo(CODESET), or None if the
     336      # nl_langinfo(CODESET) failed."
     337      _fsencoding = sys.getfilesystemencoding() or 'utf-8'
     338      if _fsencoding == 'mbcs':
     339          _fserrors = 'strict'
     340      else:
     341          _fserrors = 'surrogateescape'
     342  
     343      def fsencode(filename):
     344          if isinstance(filename, bytes):
     345              return filename
     346          elif isinstance(filename, text_type):
     347              return filename.encode(_fsencoding, _fserrors)
     348          else:
     349              raise TypeError("expect bytes or str, not %s" %
     350                              type(filename).__name__)
     351  
     352      def fsdecode(filename):
     353          if isinstance(filename, text_type):
     354              return filename
     355          elif isinstance(filename, bytes):
     356              return filename.decode(_fsencoding, _fserrors)
     357          else:
     358              raise TypeError("expect bytes or str, not %s" %
     359                              type(filename).__name__)
     360  
     361  try:
     362      from tokenize import detect_encoding
     363  except ImportError: # pragma: no cover
     364      from codecs import BOM_UTF8, lookup
     365      import re
     366  
     367      cookie_re = re.compile(r"coding[:=]\s*([-\w.]+)")
     368  
     369      def _get_normal_name(orig_enc):
     370          """Imitates get_normal_name in tokenizer.c."""
     371          # Only care about the first 12 characters.
     372          enc = orig_enc[:12].lower().replace("_", "-")
     373          if enc == "utf-8" or enc.startswith("utf-8-"):
     374              return "utf-8"
     375          if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \
     376             enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")):
     377              return "iso-8859-1"
     378          return orig_enc
     379  
     380      def detect_encoding(readline):
     381          """
     382          The detect_encoding() function is used to detect the encoding that should
     383          be used to decode a Python source file.  It requires one argument, readline,
     384          in the same way as the tokenize() generator.
     385  
     386          It will call readline a maximum of twice, and return the encoding used
     387          (as a string) and a list of any lines (left as bytes) it has read in.
     388  
     389          It detects the encoding from the presence of a utf-8 bom or an encoding
     390          cookie as specified in pep-0263.  If both a bom and a cookie are present,
     391          but disagree, a SyntaxError will be raised.  If the encoding cookie is an
     392          invalid charset, raise a SyntaxError.  Note that if a utf-8 bom is found,
     393          'utf-8-sig' is returned.
     394  
     395          If no encoding is specified, then the default of 'utf-8' will be returned.
     396          """
     397          try:
     398              filename = readline.__self__.name
     399          except AttributeError:
     400              filename = None
     401          bom_found = False
     402          encoding = None
     403          default = 'utf-8'
     404          def read_or_stop():
     405              try:
     406                  return readline()
     407              except StopIteration:
     408                  return b''
     409  
     410          def find_cookie(line):
     411              try:
     412                  # Decode as UTF-8. Either the line is an encoding declaration,
     413                  # in which case it should be pure ASCII, or it must be UTF-8
     414                  # per default encoding.
     415                  line_string = line.decode('utf-8')
     416              except UnicodeDecodeError:
     417                  msg = "invalid or missing encoding declaration"
     418                  if filename is not None:
     419                      msg = '{} for {!r}'.format(msg, filename)
     420                  raise SyntaxError(msg)
     421  
     422              matches = cookie_re.findall(line_string)
     423              if not matches:
     424                  return None
     425              encoding = _get_normal_name(matches[0])
     426              try:
     427                  codec = lookup(encoding)
     428              except LookupError:
     429                  # This behaviour mimics the Python interpreter
     430                  if filename is None:
     431                      msg = "unknown encoding: " + encoding
     432                  else:
     433                      msg = "unknown encoding for {!r}: {}".format(filename,
     434                              encoding)
     435                  raise SyntaxError(msg)
     436  
     437              if bom_found:
     438                  if codec.name != 'utf-8':
     439                      # This behaviour mimics the Python interpreter
     440                      if filename is None:
     441                          msg = 'encoding problem: utf-8'
     442                      else:
     443                          msg = 'encoding problem for {!r}: utf-8'.format(filename)
     444                      raise SyntaxError(msg)
     445                  encoding += '-sig'
     446              return encoding
     447  
     448          first = read_or_stop()
     449          if first.startswith(BOM_UTF8):
     450              bom_found = True
     451              first = first[3:]
     452              default = 'utf-8-sig'
     453          if not first:
     454              return default, []
     455  
     456          encoding = find_cookie(first)
     457          if encoding:
     458              return encoding, [first]
     459  
     460          second = read_or_stop()
     461          if not second:
     462              return default, [first]
     463  
     464          encoding = find_cookie(second)
     465          if encoding:
     466              return encoding, [first, second]
     467  
     468          return default, [first, second]
     469  
     470  # For converting & <-> &amp; etc.
     471  try:
     472      from html import escape
     473  except ImportError:
     474      from cgi import escape
     475  if sys.version_info[:2] < (3, 4):
     476      unescape = HTMLParser().unescape
     477  else:
     478      from html import unescape
     479  
     480  try:
     481      from collections import ChainMap
     482  except ImportError: # pragma: no cover
     483      from collections import MutableMapping
     484  
     485      try:
     486          from reprlib import recursive_repr as _recursive_repr
     487      except ImportError:
     488          def _recursive_repr(fillvalue='...'):
     489              '''
     490              Decorator to make a repr function return fillvalue for a recursive
     491              call
     492              '''
     493  
     494              def decorating_function(user_function):
     495                  repr_running = set()
     496  
     497                  def wrapper(self):
     498                      key = id(self), get_ident()
     499                      if key in repr_running:
     500                          return fillvalue
     501                      repr_running.add(key)
     502                      try:
     503                          result = user_function(self)
     504                      finally:
     505                          repr_running.discard(key)
     506                      return result
     507  
     508                  # Can't use functools.wraps() here because of bootstrap issues
     509                  wrapper.__module__ = getattr(user_function, '__module__')
     510                  wrapper.__doc__ = getattr(user_function, '__doc__')
     511                  wrapper.__name__ = getattr(user_function, '__name__')
     512                  wrapper.__annotations__ = getattr(user_function, '__annotations__', {})
     513                  return wrapper
     514  
     515              return decorating_function
     516  
     517      class ESC[4;38;5;81mChainMap(ESC[4;38;5;149mMutableMapping):
     518          ''' A ChainMap groups multiple dicts (or other mappings) together
     519          to create a single, updateable view.
     520  
     521          The underlying mappings are stored in a list.  That list is public and can
     522          accessed or updated using the *maps* attribute.  There is no other state.
     523  
     524          Lookups search the underlying mappings successively until a key is found.
     525          In contrast, writes, updates, and deletions only operate on the first
     526          mapping.
     527  
     528          '''
     529  
     530          def __init__(self, *maps):
     531              '''Initialize a ChainMap by setting *maps* to the given mappings.
     532              If no mappings are provided, a single empty dictionary is used.
     533  
     534              '''
     535              self.maps = list(maps) or [{}]          # always at least one map
     536  
     537          def __missing__(self, key):
     538              raise KeyError(key)
     539  
     540          def __getitem__(self, key):
     541              for mapping in self.maps:
     542                  try:
     543                      return mapping[key]             # can't use 'key in mapping' with defaultdict
     544                  except KeyError:
     545                      pass
     546              return self.__missing__(key)            # support subclasses that define __missing__
     547  
     548          def get(self, key, default=None):
     549              return self[key] if key in self else default
     550  
     551          def __len__(self):
     552              return len(set().union(*self.maps))     # reuses stored hash values if possible
     553  
     554          def __iter__(self):
     555              return iter(set().union(*self.maps))
     556  
     557          def __contains__(self, key):
     558              return any(key in m for m in self.maps)
     559  
     560          def __bool__(self):
     561              return any(self.maps)
     562  
     563          @_recursive_repr()
     564          def __repr__(self):
     565              return '{0.__class__.__name__}({1})'.format(
     566                  self, ', '.join(map(repr, self.maps)))
     567  
     568          @classmethod
     569          def fromkeys(cls, iterable, *args):
     570              'Create a ChainMap with a single dict created from the iterable.'
     571              return cls(dict.fromkeys(iterable, *args))
     572  
     573          def copy(self):
     574              'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]'
     575              return self.__class__(self.maps[0].copy(), *self.maps[1:])
     576  
     577          __copy__ = copy
     578  
     579          def new_child(self):                        # like Django's Context.push()
     580              'New ChainMap with a new dict followed by all previous maps.'
     581              return self.__class__({}, *self.maps)
     582  
     583          @property
     584          def parents(self):                          # like Django's Context.pop()
     585              'New ChainMap from maps[1:].'
     586              return self.__class__(*self.maps[1:])
     587  
     588          def __setitem__(self, key, value):
     589              self.maps[0][key] = value
     590  
     591          def __delitem__(self, key):
     592              try:
     593                  del self.maps[0][key]
     594              except KeyError:
     595                  raise KeyError('Key not found in the first mapping: {!r}'.format(key))
     596  
     597          def popitem(self):
     598              'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.'
     599              try:
     600                  return self.maps[0].popitem()
     601              except KeyError:
     602                  raise KeyError('No keys found in the first mapping.')
     603  
     604          def pop(self, key, *args):
     605              'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].'
     606              try:
     607                  return self.maps[0].pop(key, *args)
     608              except KeyError:
     609                  raise KeyError('Key not found in the first mapping: {!r}'.format(key))
     610  
     611          def clear(self):
     612              'Clear maps[0], leaving maps[1:] intact.'
     613              self.maps[0].clear()
     614  
     615  try:
     616      from importlib.util import cache_from_source  # Python >= 3.4
     617  except ImportError:  # pragma: no cover
     618      def cache_from_source(path, debug_override=None):
     619          assert path.endswith('.py')
     620          if debug_override is None:
     621              debug_override = __debug__
     622          if debug_override:
     623              suffix = 'c'
     624          else:
     625              suffix = 'o'
     626          return path + suffix
     627  
     628  try:
     629      from collections import OrderedDict
     630  except ImportError: # pragma: no cover
     631  ## {{{ http://code.activestate.com/recipes/576693/ (r9)
     632  # Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
     633  # Passes Python2.7's test suite and incorporates all the latest updates.
     634      try:
     635          from thread import get_ident as _get_ident
     636      except ImportError:
     637          from dummy_thread import get_ident as _get_ident
     638  
     639      try:
     640          from _abcoll import KeysView, ValuesView, ItemsView
     641      except ImportError:
     642          pass
     643  
     644  
     645      class ESC[4;38;5;81mOrderedDict(ESC[4;38;5;149mdict):
     646          'Dictionary that remembers insertion order'
     647          # An inherited dict maps keys to values.
     648          # The inherited dict provides __getitem__, __len__, __contains__, and get.
     649          # The remaining methods are order-aware.
     650          # Big-O running times for all methods are the same as for regular dictionaries.
     651  
     652          # The internal self.__map dictionary maps keys to links in a doubly linked list.
     653          # The circular doubly linked list starts and ends with a sentinel element.
     654          # The sentinel element never gets deleted (this simplifies the algorithm).
     655          # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
     656  
     657          def __init__(self, *args, **kwds):
     658              '''Initialize an ordered dictionary.  Signature is the same as for
     659              regular dictionaries, but keyword arguments are not recommended
     660              because their insertion order is arbitrary.
     661  
     662              '''
     663              if len(args) > 1:
     664                  raise TypeError('expected at most 1 arguments, got %d' % len(args))
     665              try:
     666                  self.__root
     667              except AttributeError:
     668                  self.__root = root = []                     # sentinel node
     669                  root[:] = [root, root, None]
     670                  self.__map = {}
     671              self.__update(*args, **kwds)
     672  
     673          def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
     674              'od.__setitem__(i, y) <==> od[i]=y'
     675              # Setting a new item creates a new link which goes at the end of the linked
     676              # list, and the inherited dictionary is updated with the new key/value pair.
     677              if key not in self:
     678                  root = self.__root
     679                  last = root[0]
     680                  last[1] = root[0] = self.__map[key] = [last, root, key]
     681              dict_setitem(self, key, value)
     682  
     683          def __delitem__(self, key, dict_delitem=dict.__delitem__):
     684              'od.__delitem__(y) <==> del od[y]'
     685              # Deleting an existing item uses self.__map to find the link which is
     686              # then removed by updating the links in the predecessor and successor nodes.
     687              dict_delitem(self, key)
     688              link_prev, link_next, key = self.__map.pop(key)
     689              link_prev[1] = link_next
     690              link_next[0] = link_prev
     691  
     692          def __iter__(self):
     693              'od.__iter__() <==> iter(od)'
     694              root = self.__root
     695              curr = root[1]
     696              while curr is not root:
     697                  yield curr[2]
     698                  curr = curr[1]
     699  
     700          def __reversed__(self):
     701              'od.__reversed__() <==> reversed(od)'
     702              root = self.__root
     703              curr = root[0]
     704              while curr is not root:
     705                  yield curr[2]
     706                  curr = curr[0]
     707  
     708          def clear(self):
     709              'od.clear() -> None.  Remove all items from od.'
     710              try:
     711                  for node in self.__map.itervalues():
     712                      del node[:]
     713                  root = self.__root
     714                  root[:] = [root, root, None]
     715                  self.__map.clear()
     716              except AttributeError:
     717                  pass
     718              dict.clear(self)
     719  
     720          def popitem(self, last=True):
     721              '''od.popitem() -> (k, v), return and remove a (key, value) pair.
     722              Pairs are returned in LIFO order if last is true or FIFO order if false.
     723  
     724              '''
     725              if not self:
     726                  raise KeyError('dictionary is empty')
     727              root = self.__root
     728              if last:
     729                  link = root[0]
     730                  link_prev = link[0]
     731                  link_prev[1] = root
     732                  root[0] = link_prev
     733              else:
     734                  link = root[1]
     735                  link_next = link[1]
     736                  root[1] = link_next
     737                  link_next[0] = root
     738              key = link[2]
     739              del self.__map[key]
     740              value = dict.pop(self, key)
     741              return key, value
     742  
     743          # -- the following methods do not depend on the internal structure --
     744  
     745          def keys(self):
     746              'od.keys() -> list of keys in od'
     747              return list(self)
     748  
     749          def values(self):
     750              'od.values() -> list of values in od'
     751              return [self[key] for key in self]
     752  
     753          def items(self):
     754              'od.items() -> list of (key, value) pairs in od'
     755              return [(key, self[key]) for key in self]
     756  
     757          def iterkeys(self):
     758              'od.iterkeys() -> an iterator over the keys in od'
     759              return iter(self)
     760  
     761          def itervalues(self):
     762              'od.itervalues -> an iterator over the values in od'
     763              for k in self:
     764                  yield self[k]
     765  
     766          def iteritems(self):
     767              'od.iteritems -> an iterator over the (key, value) items in od'
     768              for k in self:
     769                  yield (k, self[k])
     770  
     771          def update(*args, **kwds):
     772              '''od.update(E, **F) -> None.  Update od from dict/iterable E and F.
     773  
     774              If E is a dict instance, does:           for k in E: od[k] = E[k]
     775              If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
     776              Or if E is an iterable of items, does:   for k, v in E: od[k] = v
     777              In either case, this is followed by:     for k, v in F.items(): od[k] = v
     778  
     779              '''
     780              if len(args) > 2:
     781                  raise TypeError('update() takes at most 2 positional '
     782                                  'arguments (%d given)' % (len(args),))
     783              elif not args:
     784                  raise TypeError('update() takes at least 1 argument (0 given)')
     785              self = args[0]
     786              # Make progressively weaker assumptions about "other"
     787              other = ()
     788              if len(args) == 2:
     789                  other = args[1]
     790              if isinstance(other, dict):
     791                  for key in other:
     792                      self[key] = other[key]
     793              elif hasattr(other, 'keys'):
     794                  for key in other.keys():
     795                      self[key] = other[key]
     796              else:
     797                  for key, value in other:
     798                      self[key] = value
     799              for key, value in kwds.items():
     800                  self[key] = value
     801  
     802          __update = update  # let subclasses override update without breaking __init__
     803  
     804          __marker = object()
     805  
     806          def pop(self, key, default=__marker):
     807              '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
     808              If key is not found, d is returned if given, otherwise KeyError is raised.
     809  
     810              '''
     811              if key in self:
     812                  result = self[key]
     813                  del self[key]
     814                  return result
     815              if default is self.__marker:
     816                  raise KeyError(key)
     817              return default
     818  
     819          def setdefault(self, key, default=None):
     820              'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
     821              if key in self:
     822                  return self[key]
     823              self[key] = default
     824              return default
     825  
     826          def __repr__(self, _repr_running=None):
     827              'od.__repr__() <==> repr(od)'
     828              if not _repr_running: _repr_running = {}
     829              call_key = id(self), _get_ident()
     830              if call_key in _repr_running:
     831                  return '...'
     832              _repr_running[call_key] = 1
     833              try:
     834                  if not self:
     835                      return '%s()' % (self.__class__.__name__,)
     836                  return '%s(%r)' % (self.__class__.__name__, self.items())
     837              finally:
     838                  del _repr_running[call_key]
     839  
     840          def __reduce__(self):
     841              'Return state information for pickling'
     842              items = [[k, self[k]] for k in self]
     843              inst_dict = vars(self).copy()
     844              for k in vars(OrderedDict()):
     845                  inst_dict.pop(k, None)
     846              if inst_dict:
     847                  return (self.__class__, (items,), inst_dict)
     848              return self.__class__, (items,)
     849  
     850          def copy(self):
     851              'od.copy() -> a shallow copy of od'
     852              return self.__class__(self)
     853  
     854          @classmethod
     855          def fromkeys(cls, iterable, value=None):
     856              '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
     857              and values equal to v (which defaults to None).
     858  
     859              '''
     860              d = cls()
     861              for key in iterable:
     862                  d[key] = value
     863              return d
     864  
     865          def __eq__(self, other):
     866              '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
     867              while comparison to a regular mapping is order-insensitive.
     868  
     869              '''
     870              if isinstance(other, OrderedDict):
     871                  return len(self)==len(other) and self.items() == other.items()
     872              return dict.__eq__(self, other)
     873  
     874          def __ne__(self, other):
     875              return not self == other
     876  
     877          # -- the following methods are only used in Python 2.7 --
     878  
     879          def viewkeys(self):
     880              "od.viewkeys() -> a set-like object providing a view on od's keys"
     881              return KeysView(self)
     882  
     883          def viewvalues(self):
     884              "od.viewvalues() -> an object providing a view on od's values"
     885              return ValuesView(self)
     886  
     887          def viewitems(self):
     888              "od.viewitems() -> a set-like object providing a view on od's items"
     889              return ItemsView(self)
     890  
     891  try:
     892      from logging.config import BaseConfigurator, valid_ident
     893  except ImportError: # pragma: no cover
     894      IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I)
     895  
     896  
     897      def valid_ident(s):
     898          m = IDENTIFIER.match(s)
     899          if not m:
     900              raise ValueError('Not a valid Python identifier: %r' % s)
     901          return True
     902  
     903  
     904      # The ConvertingXXX classes are wrappers around standard Python containers,
     905      # and they serve to convert any suitable values in the container. The
     906      # conversion converts base dicts, lists and tuples to their wrapped
     907      # equivalents, whereas strings which match a conversion format are converted
     908      # appropriately.
     909      #
     910      # Each wrapper should have a configurator attribute holding the actual
     911      # configurator to use for conversion.
     912  
     913      class ESC[4;38;5;81mConvertingDict(ESC[4;38;5;149mdict):
     914          """A converting dictionary wrapper."""
     915  
     916          def __getitem__(self, key):
     917              value = dict.__getitem__(self, key)
     918              result = self.configurator.convert(value)
     919              #If the converted value is different, save for next time
     920              if value is not result:
     921                  self[key] = result
     922                  if type(result) in (ConvertingDict, ConvertingList,
     923                                      ConvertingTuple):
     924                      result.parent = self
     925                      result.key = key
     926              return result
     927  
     928          def get(self, key, default=None):
     929              value = dict.get(self, key, default)
     930              result = self.configurator.convert(value)
     931              #If the converted value is different, save for next time
     932              if value is not result:
     933                  self[key] = result
     934                  if type(result) in (ConvertingDict, ConvertingList,
     935                                      ConvertingTuple):
     936                      result.parent = self
     937                      result.key = key
     938              return result
     939  
     940      def pop(self, key, default=None):
     941          value = dict.pop(self, key, default)
     942          result = self.configurator.convert(value)
     943          if value is not result:
     944              if type(result) in (ConvertingDict, ConvertingList,
     945                                  ConvertingTuple):
     946                  result.parent = self
     947                  result.key = key
     948          return result
     949  
     950      class ESC[4;38;5;81mConvertingList(ESC[4;38;5;149mlist):
     951          """A converting list wrapper."""
     952          def __getitem__(self, key):
     953              value = list.__getitem__(self, key)
     954              result = self.configurator.convert(value)
     955              #If the converted value is different, save for next time
     956              if value is not result:
     957                  self[key] = result
     958                  if type(result) in (ConvertingDict, ConvertingList,
     959                                      ConvertingTuple):
     960                      result.parent = self
     961                      result.key = key
     962              return result
     963  
     964          def pop(self, idx=-1):
     965              value = list.pop(self, idx)
     966              result = self.configurator.convert(value)
     967              if value is not result:
     968                  if type(result) in (ConvertingDict, ConvertingList,
     969                                      ConvertingTuple):
     970                      result.parent = self
     971              return result
     972  
     973      class ESC[4;38;5;81mConvertingTuple(ESC[4;38;5;149mtuple):
     974          """A converting tuple wrapper."""
     975          def __getitem__(self, key):
     976              value = tuple.__getitem__(self, key)
     977              result = self.configurator.convert(value)
     978              if value is not result:
     979                  if type(result) in (ConvertingDict, ConvertingList,
     980                                      ConvertingTuple):
     981                      result.parent = self
     982                      result.key = key
     983              return result
     984  
     985      class ESC[4;38;5;81mBaseConfigurator(ESC[4;38;5;149mobject):
     986          """
     987          The configurator base class which defines some useful defaults.
     988          """
     989  
     990          CONVERT_PATTERN = re.compile(r'^(?P<prefix>[a-z]+)://(?P<suffix>.*)$')
     991  
     992          WORD_PATTERN = re.compile(r'^\s*(\w+)\s*')
     993          DOT_PATTERN = re.compile(r'^\.\s*(\w+)\s*')
     994          INDEX_PATTERN = re.compile(r'^\[\s*(\w+)\s*\]\s*')
     995          DIGIT_PATTERN = re.compile(r'^\d+$')
     996  
     997          value_converters = {
     998              'ext' : 'ext_convert',
     999              'cfg' : 'cfg_convert',
    1000          }
    1001  
    1002          # We might want to use a different one, e.g. importlib
    1003          importer = staticmethod(__import__)
    1004  
    1005          def __init__(self, config):
    1006              self.config = ConvertingDict(config)
    1007              self.config.configurator = self
    1008  
    1009          def resolve(self, s):
    1010              """
    1011              Resolve strings to objects using standard import and attribute
    1012              syntax.
    1013              """
    1014              name = s.split('.')
    1015              used = name.pop(0)
    1016              try:
    1017                  found = self.importer(used)
    1018                  for frag in name:
    1019                      used += '.' + frag
    1020                      try:
    1021                          found = getattr(found, frag)
    1022                      except AttributeError:
    1023                          self.importer(used)
    1024                          found = getattr(found, frag)
    1025                  return found
    1026              except ImportError:
    1027                  e, tb = sys.exc_info()[1:]
    1028                  v = ValueError('Cannot resolve %r: %s' % (s, e))
    1029                  v.__cause__, v.__traceback__ = e, tb
    1030                  raise v
    1031  
    1032          def ext_convert(self, value):
    1033              """Default converter for the ext:// protocol."""
    1034              return self.resolve(value)
    1035  
    1036          def cfg_convert(self, value):
    1037              """Default converter for the cfg:// protocol."""
    1038              rest = value
    1039              m = self.WORD_PATTERN.match(rest)
    1040              if m is None:
    1041                  raise ValueError("Unable to convert %r" % value)
    1042              else:
    1043                  rest = rest[m.end():]
    1044                  d = self.config[m.groups()[0]]
    1045                  #print d, rest
    1046                  while rest:
    1047                      m = self.DOT_PATTERN.match(rest)
    1048                      if m:
    1049                          d = d[m.groups()[0]]
    1050                      else:
    1051                          m = self.INDEX_PATTERN.match(rest)
    1052                          if m:
    1053                              idx = m.groups()[0]
    1054                              if not self.DIGIT_PATTERN.match(idx):
    1055                                  d = d[idx]
    1056                              else:
    1057                                  try:
    1058                                      n = int(idx) # try as number first (most likely)
    1059                                      d = d[n]
    1060                                  except TypeError:
    1061                                      d = d[idx]
    1062                      if m:
    1063                          rest = rest[m.end():]
    1064                      else:
    1065                          raise ValueError('Unable to convert '
    1066                                           '%r at %r' % (value, rest))
    1067              #rest should be empty
    1068              return d
    1069  
    1070          def convert(self, value):
    1071              """
    1072              Convert values to an appropriate type. dicts, lists and tuples are
    1073              replaced by their converting alternatives. Strings are checked to
    1074              see if they have a conversion format and are converted if they do.
    1075              """
    1076              if not isinstance(value, ConvertingDict) and isinstance(value, dict):
    1077                  value = ConvertingDict(value)
    1078                  value.configurator = self
    1079              elif not isinstance(value, ConvertingList) and isinstance(value, list):
    1080                  value = ConvertingList(value)
    1081                  value.configurator = self
    1082              elif not isinstance(value, ConvertingTuple) and\
    1083                       isinstance(value, tuple):
    1084                  value = ConvertingTuple(value)
    1085                  value.configurator = self
    1086              elif isinstance(value, string_types):
    1087                  m = self.CONVERT_PATTERN.match(value)
    1088                  if m:
    1089                      d = m.groupdict()
    1090                      prefix = d['prefix']
    1091                      converter = self.value_converters.get(prefix, None)
    1092                      if converter:
    1093                          suffix = d['suffix']
    1094                          converter = getattr(self, converter)
    1095                          value = converter(suffix)
    1096              return value
    1097  
    1098          def configure_custom(self, config):
    1099              """Configure an object with a user-supplied factory."""
    1100              c = config.pop('()')
    1101              if not callable(c):
    1102                  c = self.resolve(c)
    1103              props = config.pop('.', None)
    1104              # Check for valid identifiers
    1105              kwargs = dict([(k, config[k]) for k in config if valid_ident(k)])
    1106              result = c(**kwargs)
    1107              if props:
    1108                  for name, value in props.items():
    1109                      setattr(result, name, value)
    1110              return result
    1111  
    1112          def as_tuple(self, value):
    1113              """Utility function which converts lists to tuples."""
    1114              if isinstance(value, list):
    1115                  value = tuple(value)
    1116              return value