Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
news
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Sartika Aritonang
news
Commits
a63a7c8a
Commit
a63a7c8a
authored
May 29, 2020
by
Sartika Aritonang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Upload New File
parent
1bb1d2eb
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1120 additions
and
0 deletions
+1120
-0
compat.py
stbi/Lib/site-packages/pip/_vendor/distlib/compat.py
+1120
-0
No files found.
stbi/Lib/site-packages/pip/_vendor/distlib/compat.py
0 → 100644
View file @
a63a7c8a
# -*- coding: utf-8 -*-
#
# Copyright (C) 2013-2017 Vinay Sajip.
# Licensed to the Python Software Foundation under a contributor agreement.
# See LICENSE.txt and CONTRIBUTORS.txt.
#
from
__future__
import
absolute_import
import
os
import
re
import
sys
try
:
import
ssl
except
ImportError
:
# pragma: no cover
ssl
=
None
if
sys
.
version_info
[
0
]
<
3
:
# pragma: no cover
from
StringIO
import
StringIO
string_types
=
basestring
,
text_type
=
unicode
from
types
import
FileType
as
file_type
import
__builtin__
as
builtins
import
ConfigParser
as
configparser
from
._backport
import
shutil
from
urlparse
import
urlparse
,
urlunparse
,
urljoin
,
urlsplit
,
urlunsplit
from
urllib
import
(
urlretrieve
,
quote
as
_quote
,
unquote
,
url2pathname
,
pathname2url
,
ContentTooShortError
,
splittype
)
def
quote
(
s
):
if
isinstance
(
s
,
unicode
):
s
=
s
.
encode
(
'utf-8'
)
return
_quote
(
s
)
import
urllib2
from
urllib2
import
(
Request
,
urlopen
,
URLError
,
HTTPError
,
HTTPBasicAuthHandler
,
HTTPPasswordMgr
,
HTTPHandler
,
HTTPRedirectHandler
,
build_opener
)
if
ssl
:
from
urllib2
import
HTTPSHandler
import
httplib
import
xmlrpclib
import
Queue
as
queue
from
HTMLParser
import
HTMLParser
import
htmlentitydefs
raw_input
=
raw_input
from
itertools
import
ifilter
as
filter
from
itertools
import
ifilterfalse
as
filterfalse
_userprog
=
None
def
splituser
(
host
):
"""splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'."""
global
_userprog
if
_userprog
is
None
:
import
re
_userprog
=
re
.
compile
(
'^(.*)@(.*)$'
)
match
=
_userprog
.
match
(
host
)
if
match
:
return
match
.
group
(
1
,
2
)
return
None
,
host
else
:
# pragma: no cover
from
io
import
StringIO
string_types
=
str
,
text_type
=
str
from
io
import
TextIOWrapper
as
file_type
import
builtins
import
configparser
import
shutil
from
urllib.parse
import
(
urlparse
,
urlunparse
,
urljoin
,
splituser
,
quote
,
unquote
,
urlsplit
,
urlunsplit
,
splittype
)
from
urllib.request
import
(
urlopen
,
urlretrieve
,
Request
,
url2pathname
,
pathname2url
,
HTTPBasicAuthHandler
,
HTTPPasswordMgr
,
HTTPHandler
,
HTTPRedirectHandler
,
build_opener
)
if
ssl
:
from
urllib.request
import
HTTPSHandler
from
urllib.error
import
HTTPError
,
URLError
,
ContentTooShortError
import
http.client
as
httplib
import
urllib.request
as
urllib2
import
xmlrpc.client
as
xmlrpclib
import
queue
from
html.parser
import
HTMLParser
import
html.entities
as
htmlentitydefs
raw_input
=
input
from
itertools
import
filterfalse
filter
=
filter
try
:
from
ssl
import
match_hostname
,
CertificateError
except
ImportError
:
# pragma: no cover
class
CertificateError
(
ValueError
):
pass
def
_dnsname_match
(
dn
,
hostname
,
max_wildcards
=
1
):
"""Matching according to RFC 6125, section 6.4.3
http://tools.ietf.org/html/rfc6125#section-6.4.3
"""
pats
=
[]
if
not
dn
:
return
False
parts
=
dn
.
split
(
'.'
)
leftmost
,
remainder
=
parts
[
0
],
parts
[
1
:]
wildcards
=
leftmost
.
count
(
'*'
)
if
wildcards
>
max_wildcards
:
# Issue #17980: avoid denials of service by refusing more
# than one wildcard per fragment. A survey of established
# policy among SSL implementations showed it to be a
# reasonable choice.
raise
CertificateError
(
"too many wildcards in certificate DNS name: "
+
repr
(
dn
))
# speed up common case w/o wildcards
if
not
wildcards
:
return
dn
.
lower
()
==
hostname
.
lower
()
# RFC 6125, section 6.4.3, subitem 1.
# The client SHOULD NOT attempt to match a presented identifier in which
# the wildcard character comprises a label other than the left-most label.
if
leftmost
==
'*'
:
# When '*' is a fragment by itself, it matches a non-empty dotless
# fragment.
pats
.
append
(
'[^.]+'
)
elif
leftmost
.
startswith
(
'xn--'
)
or
hostname
.
startswith
(
'xn--'
):
# RFC 6125, section 6.4.3, subitem 3.
# The client SHOULD NOT attempt to match a presented identifier
# where the wildcard character is embedded within an A-label or
# U-label of an internationalized domain name.
pats
.
append
(
re
.
escape
(
leftmost
))
else
:
# Otherwise, '*' matches any dotless string, e.g. www*
pats
.
append
(
re
.
escape
(
leftmost
)
.
replace
(
r'\*'
,
'[^.]*'
))
# add the remaining fragments, ignore any wildcards
for
frag
in
remainder
:
pats
.
append
(
re
.
escape
(
frag
))
pat
=
re
.
compile
(
r'\A'
+
r'\.'
.
join
(
pats
)
+
r'\Z'
,
re
.
IGNORECASE
)
return
pat
.
match
(
hostname
)
def
match_hostname
(
cert
,
hostname
):
"""Verify that *cert* (in decoded format as returned by
SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125
rules are followed, but IP addresses are not accepted for *hostname*.
CertificateError is raised on failure. On success, the function
returns nothing.
"""
if
not
cert
:
raise
ValueError
(
"empty or no certificate, match_hostname needs a "
"SSL socket or SSL context with either "
"CERT_OPTIONAL or CERT_REQUIRED"
)
dnsnames
=
[]
san
=
cert
.
get
(
'subjectAltName'
,
())
for
key
,
value
in
san
:
if
key
==
'DNS'
:
if
_dnsname_match
(
value
,
hostname
):
return
dnsnames
.
append
(
value
)
if
not
dnsnames
:
# The subject is only checked when there is no dNSName entry
# in subjectAltName
for
sub
in
cert
.
get
(
'subject'
,
()):
for
key
,
value
in
sub
:
# XXX according to RFC 2818, the most specific Common Name
# must be used.
if
key
==
'commonName'
:
if
_dnsname_match
(
value
,
hostname
):
return
dnsnames
.
append
(
value
)
if
len
(
dnsnames
)
>
1
:
raise
CertificateError
(
"hostname
%
r "
"doesn't match either of
%
s"
%
(
hostname
,
', '
.
join
(
map
(
repr
,
dnsnames
))))
elif
len
(
dnsnames
)
==
1
:
raise
CertificateError
(
"hostname
%
r "
"doesn't match
%
r"
%
(
hostname
,
dnsnames
[
0
]))
else
:
raise
CertificateError
(
"no appropriate commonName or "
"subjectAltName fields were found"
)
try
:
from
types
import
SimpleNamespace
as
Container
except
ImportError
:
# pragma: no cover
class
Container
(
object
):
"""
A generic container for when multiple values need to be returned
"""
def
__init__
(
self
,
**
kwargs
):
self
.
__dict__
.
update
(
kwargs
)
try
:
from
shutil
import
which
except
ImportError
:
# pragma: no cover
# Implementation from Python 3.3
def
which
(
cmd
,
mode
=
os
.
F_OK
|
os
.
X_OK
,
path
=
None
):
"""Given a command, mode, and a PATH string, return the path which
conforms to the given mode on the PATH, or None if there is no such
file.
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
of os.environ.get("PATH"), or can be overridden with a custom search
path.
"""
# Check that a given file can be accessed with the correct mode.
# Additionally check that `file` is not a directory, as on Windows
# directories pass the os.access check.
def
_access_check
(
fn
,
mode
):
return
(
os
.
path
.
exists
(
fn
)
and
os
.
access
(
fn
,
mode
)
and
not
os
.
path
.
isdir
(
fn
))
# If we're given a path with a directory part, look it up directly rather
# than referring to PATH directories. This includes checking relative to the
# current directory, e.g. ./script
if
os
.
path
.
dirname
(
cmd
):
if
_access_check
(
cmd
,
mode
):
return
cmd
return
None
if
path
is
None
:
path
=
os
.
environ
.
get
(
"PATH"
,
os
.
defpath
)
if
not
path
:
return
None
path
=
path
.
split
(
os
.
pathsep
)
if
sys
.
platform
==
"win32"
:
# The current directory takes precedence on Windows.
if
not
os
.
curdir
in
path
:
path
.
insert
(
0
,
os
.
curdir
)
# PATHEXT is necessary to check on Windows.
pathext
=
os
.
environ
.
get
(
"PATHEXT"
,
""
)
.
split
(
os
.
pathsep
)
# See if the given file matches any of the expected path extensions.
# This will allow us to short circuit when given "python.exe".
# If it does match, only test that one, otherwise we have to try
# others.
if
any
(
cmd
.
lower
()
.
endswith
(
ext
.
lower
())
for
ext
in
pathext
):
files
=
[
cmd
]
else
:
files
=
[
cmd
+
ext
for
ext
in
pathext
]
else
:
# On other platforms you don't have things like PATHEXT to tell you
# what file suffixes are executable, so just pass on cmd as-is.
files
=
[
cmd
]
seen
=
set
()
for
dir
in
path
:
normdir
=
os
.
path
.
normcase
(
dir
)
if
not
normdir
in
seen
:
seen
.
add
(
normdir
)
for
thefile
in
files
:
name
=
os
.
path
.
join
(
dir
,
thefile
)
if
_access_check
(
name
,
mode
):
return
name
return
None
# ZipFile is a context manager in 2.7, but not in 2.6
from
zipfile
import
ZipFile
as
BaseZipFile
if
hasattr
(
BaseZipFile
,
'__enter__'
):
# pragma: no cover
ZipFile
=
BaseZipFile
else
:
# pragma: no cover
from
zipfile
import
ZipExtFile
as
BaseZipExtFile
class
ZipExtFile
(
BaseZipExtFile
):
def
__init__
(
self
,
base
):
self
.
__dict__
.
update
(
base
.
__dict__
)
def
__enter__
(
self
):
return
self
def
__exit__
(
self
,
*
exc_info
):
self
.
close
()
# return None, so if an exception occurred, it will propagate
class
ZipFile
(
BaseZipFile
):
def
__enter__
(
self
):
return
self
def
__exit__
(
self
,
*
exc_info
):
self
.
close
()
# return None, so if an exception occurred, it will propagate
def
open
(
self
,
*
args
,
**
kwargs
):
base
=
BaseZipFile
.
open
(
self
,
*
args
,
**
kwargs
)
return
ZipExtFile
(
base
)
try
:
from
platform
import
python_implementation
except
ImportError
:
# pragma: no cover
def
python_implementation
():
"""Return a string identifying the Python implementation."""
if
'PyPy'
in
sys
.
version
:
return
'PyPy'
if
os
.
name
==
'java'
:
return
'Jython'
if
sys
.
version
.
startswith
(
'IronPython'
):
return
'IronPython'
return
'CPython'
try
:
import
sysconfig
except
ImportError
:
# pragma: no cover
from
._backport
import
sysconfig
try
:
callable
=
callable
except
NameError
:
# pragma: no cover
from
collections
import
Callable
def
callable
(
obj
):
return
isinstance
(
obj
,
Callable
)
try
:
fsencode
=
os
.
fsencode
fsdecode
=
os
.
fsdecode
except
AttributeError
:
# pragma: no cover
# Issue #99: on some systems (e.g. containerised),
# sys.getfilesystemencoding() returns None, and we need a real value,
# so fall back to utf-8. From the CPython 2.7 docs relating to Unix and
# sys.getfilesystemencoding(): the return value is "the user’s preference
# according to the result of nl_langinfo(CODESET), or None if the
# nl_langinfo(CODESET) failed."
_fsencoding
=
sys
.
getfilesystemencoding
()
or
'utf-8'
if
_fsencoding
==
'mbcs'
:
_fserrors
=
'strict'
else
:
_fserrors
=
'surrogateescape'
def
fsencode
(
filename
):
if
isinstance
(
filename
,
bytes
):
return
filename
elif
isinstance
(
filename
,
text_type
):
return
filename
.
encode
(
_fsencoding
,
_fserrors
)
else
:
raise
TypeError
(
"expect bytes or str, not
%
s"
%
type
(
filename
)
.
__name__
)
def
fsdecode
(
filename
):
if
isinstance
(
filename
,
text_type
):
return
filename
elif
isinstance
(
filename
,
bytes
):
return
filename
.
decode
(
_fsencoding
,
_fserrors
)
else
:
raise
TypeError
(
"expect bytes or str, not
%
s"
%
type
(
filename
)
.
__name__
)
try
:
from
tokenize
import
detect_encoding
except
ImportError
:
# pragma: no cover
from
codecs
import
BOM_UTF8
,
lookup
import
re
cookie_re
=
re
.
compile
(
r"coding[:=]\s*([-\w.]+)"
)
def
_get_normal_name
(
orig_enc
):
"""Imitates get_normal_name in tokenizer.c."""
# Only care about the first 12 characters.
enc
=
orig_enc
[:
12
]
.
lower
()
.
replace
(
"_"
,
"-"
)
if
enc
==
"utf-8"
or
enc
.
startswith
(
"utf-8-"
):
return
"utf-8"
if
enc
in
(
"latin-1"
,
"iso-8859-1"
,
"iso-latin-1"
)
or
\
enc
.
startswith
((
"latin-1-"
,
"iso-8859-1-"
,
"iso-latin-1-"
)):
return
"iso-8859-1"
return
orig_enc
def
detect_encoding
(
readline
):
"""
The detect_encoding() function is used to detect the encoding that should
be used to decode a Python source file. It requires one argument, readline,
in the same way as the tokenize() generator.
It will call readline a maximum of twice, and return the encoding used
(as a string) and a list of any lines (left as bytes) it has read in.
It detects the encoding from the presence of a utf-8 bom or an encoding
cookie as specified in pep-0263. If both a bom and a cookie are present,
but disagree, a SyntaxError will be raised. If the encoding cookie is an
invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found,
'utf-8-sig' is returned.
If no encoding is specified, then the default of 'utf-8' will be returned.
"""
try
:
filename
=
readline
.
__self__
.
name
except
AttributeError
:
filename
=
None
bom_found
=
False
encoding
=
None
default
=
'utf-8'
def
read_or_stop
():
try
:
return
readline
()
except
StopIteration
:
return
b
''
def
find_cookie
(
line
):
try
:
# Decode as UTF-8. Either the line is an encoding declaration,
# in which case it should be pure ASCII, or it must be UTF-8
# per default encoding.
line_string
=
line
.
decode
(
'utf-8'
)
except
UnicodeDecodeError
:
msg
=
"invalid or missing encoding declaration"
if
filename
is
not
None
:
msg
=
'{} for {!r}'
.
format
(
msg
,
filename
)
raise
SyntaxError
(
msg
)
matches
=
cookie_re
.
findall
(
line_string
)
if
not
matches
:
return
None
encoding
=
_get_normal_name
(
matches
[
0
])
try
:
codec
=
lookup
(
encoding
)
except
LookupError
:
# This behaviour mimics the Python interpreter
if
filename
is
None
:
msg
=
"unknown encoding: "
+
encoding
else
:
msg
=
"unknown encoding for {!r}: {}"
.
format
(
filename
,
encoding
)
raise
SyntaxError
(
msg
)
if
bom_found
:
if
codec
.
name
!=
'utf-8'
:
# This behaviour mimics the Python interpreter
if
filename
is
None
:
msg
=
'encoding problem: utf-8'
else
:
msg
=
'encoding problem for {!r}: utf-8'
.
format
(
filename
)
raise
SyntaxError
(
msg
)
encoding
+=
'-sig'
return
encoding
first
=
read_or_stop
()
if
first
.
startswith
(
BOM_UTF8
):
bom_found
=
True
first
=
first
[
3
:]
default
=
'utf-8-sig'
if
not
first
:
return
default
,
[]
encoding
=
find_cookie
(
first
)
if
encoding
:
return
encoding
,
[
first
]
second
=
read_or_stop
()
if
not
second
:
return
default
,
[
first
]
encoding
=
find_cookie
(
second
)
if
encoding
:
return
encoding
,
[
first
,
second
]
return
default
,
[
first
,
second
]
# For converting & <-> & etc.
try
:
from
html
import
escape
except
ImportError
:
from
cgi
import
escape
if
sys
.
version_info
[:
2
]
<
(
3
,
4
):
unescape
=
HTMLParser
()
.
unescape
else
:
from
html
import
unescape
try
:
from
collections
import
ChainMap
except
ImportError
:
# pragma: no cover
from
collections
import
MutableMapping
try
:
from
reprlib
import
recursive_repr
as
_recursive_repr
except
ImportError
:
def
_recursive_repr
(
fillvalue
=
'...'
):
'''
Decorator to make a repr function return fillvalue for a recursive
call
'''
def
decorating_function
(
user_function
):
repr_running
=
set
()
def
wrapper
(
self
):
key
=
id
(
self
),
get_ident
()
if
key
in
repr_running
:
return
fillvalue
repr_running
.
add
(
key
)
try
:
result
=
user_function
(
self
)
finally
:
repr_running
.
discard
(
key
)
return
result
# Can't use functools.wraps() here because of bootstrap issues
wrapper
.
__module__
=
getattr
(
user_function
,
'__module__'
)
wrapper
.
__doc__
=
getattr
(
user_function
,
'__doc__'
)
wrapper
.
__name__
=
getattr
(
user_function
,
'__name__'
)
wrapper
.
__annotations__
=
getattr
(
user_function
,
'__annotations__'
,
{})
return
wrapper
return
decorating_function
class
ChainMap
(
MutableMapping
):
''' A ChainMap groups multiple dicts (or other mappings) together
to create a single, updateable view.
The underlying mappings are stored in a list. That list is public and can
accessed or updated using the *maps* attribute. There is no other state.
Lookups search the underlying mappings successively until a key is found.
In contrast, writes, updates, and deletions only operate on the first
mapping.
'''
def
__init__
(
self
,
*
maps
):
'''Initialize a ChainMap by setting *maps* to the given mappings.
If no mappings are provided, a single empty dictionary is used.
'''
self
.
maps
=
list
(
maps
)
or
[{}]
# always at least one map
def
__missing__
(
self
,
key
):
raise
KeyError
(
key
)
def
__getitem__
(
self
,
key
):
for
mapping
in
self
.
maps
:
try
:
return
mapping
[
key
]
# can't use 'key in mapping' with defaultdict
except
KeyError
:
pass
return
self
.
__missing__
(
key
)
# support subclasses that define __missing__
def
get
(
self
,
key
,
default
=
None
):
return
self
[
key
]
if
key
in
self
else
default
def
__len__
(
self
):
return
len
(
set
()
.
union
(
*
self
.
maps
))
# reuses stored hash values if possible
def
__iter__
(
self
):
return
iter
(
set
()
.
union
(
*
self
.
maps
))
def
__contains__
(
self
,
key
):
return
any
(
key
in
m
for
m
in
self
.
maps
)
def
__bool__
(
self
):
return
any
(
self
.
maps
)
@_recursive_repr
()
def
__repr__
(
self
):
return
'{0.__class__.__name__}({1})'
.
format
(
self
,
', '
.
join
(
map
(
repr
,
self
.
maps
)))
@classmethod
def
fromkeys
(
cls
,
iterable
,
*
args
):
'Create a ChainMap with a single dict created from the iterable.'
return
cls
(
dict
.
fromkeys
(
iterable
,
*
args
))
def
copy
(
self
):
'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]'
return
self
.
__class__
(
self
.
maps
[
0
]
.
copy
(),
*
self
.
maps
[
1
:])
__copy__
=
copy
def
new_child
(
self
):
# like Django's Context.push()
'New ChainMap with a new dict followed by all previous maps.'
return
self
.
__class__
({},
*
self
.
maps
)
@property
def
parents
(
self
):
# like Django's Context.pop()
'New ChainMap from maps[1:].'
return
self
.
__class__
(
*
self
.
maps
[
1
:])
def
__setitem__
(
self
,
key
,
value
):
self
.
maps
[
0
][
key
]
=
value
def
__delitem__
(
self
,
key
):
try
:
del
self
.
maps
[
0
][
key
]
except
KeyError
:
raise
KeyError
(
'Key not found in the first mapping: {!r}'
.
format
(
key
))
def
popitem
(
self
):
'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.'
try
:
return
self
.
maps
[
0
]
.
popitem
()
except
KeyError
:
raise
KeyError
(
'No keys found in the first mapping.'
)
def
pop
(
self
,
key
,
*
args
):
'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].'
try
:
return
self
.
maps
[
0
]
.
pop
(
key
,
*
args
)
except
KeyError
:
raise
KeyError
(
'Key not found in the first mapping: {!r}'
.
format
(
key
))
def
clear
(
self
):
'Clear maps[0], leaving maps[1:] intact.'
self
.
maps
[
0
]
.
clear
()
try
:
from
importlib.util
import
cache_from_source
# Python >= 3.4
except
ImportError
:
# pragma: no cover
try
:
from
imp
import
cache_from_source
except
ImportError
:
# pragma: no cover
def
cache_from_source
(
path
,
debug_override
=
None
):
assert
path
.
endswith
(
'.py'
)
if
debug_override
is
None
:
debug_override
=
__debug__
if
debug_override
:
suffix
=
'c'
else
:
suffix
=
'o'
return
path
+
suffix
try
:
from
collections
import
OrderedDict
except
ImportError
:
# pragma: no cover
## {{{ http://code.activestate.com/recipes/576693/ (r9)
# 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.
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
=
None
):
'od.__repr__() <==> repr(od)'
if
not
_repr_running
:
_repr_running
=
{}
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
)
try
:
from
logging.config
import
BaseConfigurator
,
valid_ident
except
ImportError
:
# pragma: no cover
IDENTIFIER
=
re
.
compile
(
'^[a-z_][a-z0-9_]*$'
,
re
.
I
)
def
valid_ident
(
s
):
m
=
IDENTIFIER
.
match
(
s
)
if
not
m
:
raise
ValueError
(
'Not a valid Python identifier:
%
r'
%
s
)
return
True
# The ConvertingXXX classes are wrappers around standard Python containers,
# and they serve to convert any suitable values in the container. The
# conversion converts base dicts, lists and tuples to their wrapped
# equivalents, whereas strings which match a conversion format are converted
# appropriately.
#
# Each wrapper should have a configurator attribute holding the actual
# configurator to use for conversion.
class
ConvertingDict
(
dict
):
"""A converting dictionary wrapper."""
def
__getitem__
(
self
,
key
):
value
=
dict
.
__getitem__
(
self
,
key
)
result
=
self
.
configurator
.
convert
(
value
)
#If the converted value is different, save for next time
if
value
is
not
result
:
self
[
key
]
=
result
if
type
(
result
)
in
(
ConvertingDict
,
ConvertingList
,
ConvertingTuple
):
result
.
parent
=
self
result
.
key
=
key
return
result
def
get
(
self
,
key
,
default
=
None
):
value
=
dict
.
get
(
self
,
key
,
default
)
result
=
self
.
configurator
.
convert
(
value
)
#If the converted value is different, save for next time
if
value
is
not
result
:
self
[
key
]
=
result
if
type
(
result
)
in
(
ConvertingDict
,
ConvertingList
,
ConvertingTuple
):
result
.
parent
=
self
result
.
key
=
key
return
result
def
pop
(
self
,
key
,
default
=
None
):
value
=
dict
.
pop
(
self
,
key
,
default
)
result
=
self
.
configurator
.
convert
(
value
)
if
value
is
not
result
:
if
type
(
result
)
in
(
ConvertingDict
,
ConvertingList
,
ConvertingTuple
):
result
.
parent
=
self
result
.
key
=
key
return
result
class
ConvertingList
(
list
):
"""A converting list wrapper."""
def
__getitem__
(
self
,
key
):
value
=
list
.
__getitem__
(
self
,
key
)
result
=
self
.
configurator
.
convert
(
value
)
#If the converted value is different, save for next time
if
value
is
not
result
:
self
[
key
]
=
result
if
type
(
result
)
in
(
ConvertingDict
,
ConvertingList
,
ConvertingTuple
):
result
.
parent
=
self
result
.
key
=
key
return
result
def
pop
(
self
,
idx
=-
1
):
value
=
list
.
pop
(
self
,
idx
)
result
=
self
.
configurator
.
convert
(
value
)
if
value
is
not
result
:
if
type
(
result
)
in
(
ConvertingDict
,
ConvertingList
,
ConvertingTuple
):
result
.
parent
=
self
return
result
class
ConvertingTuple
(
tuple
):
"""A converting tuple wrapper."""
def
__getitem__
(
self
,
key
):
value
=
tuple
.
__getitem__
(
self
,
key
)
result
=
self
.
configurator
.
convert
(
value
)
if
value
is
not
result
:
if
type
(
result
)
in
(
ConvertingDict
,
ConvertingList
,
ConvertingTuple
):
result
.
parent
=
self
result
.
key
=
key
return
result
class
BaseConfigurator
(
object
):
"""
The configurator base class which defines some useful defaults.
"""
CONVERT_PATTERN
=
re
.
compile
(
r'^(?P<prefix>[a-z]+)://(?P<suffix>.*)$'
)
WORD_PATTERN
=
re
.
compile
(
r'^\s*(\w+)\s*'
)
DOT_PATTERN
=
re
.
compile
(
r'^\.\s*(\w+)\s*'
)
INDEX_PATTERN
=
re
.
compile
(
r'^\[\s*(\w+)\s*\]\s*'
)
DIGIT_PATTERN
=
re
.
compile
(
r'^\d+$'
)
value_converters
=
{
'ext'
:
'ext_convert'
,
'cfg'
:
'cfg_convert'
,
}
# We might want to use a different one, e.g. importlib
importer
=
staticmethod
(
__import__
)
def
__init__
(
self
,
config
):
self
.
config
=
ConvertingDict
(
config
)
self
.
config
.
configurator
=
self
def
resolve
(
self
,
s
):
"""
Resolve strings to objects using standard import and attribute
syntax.
"""
name
=
s
.
split
(
'.'
)
used
=
name
.
pop
(
0
)
try
:
found
=
self
.
importer
(
used
)
for
frag
in
name
:
used
+=
'.'
+
frag
try
:
found
=
getattr
(
found
,
frag
)
except
AttributeError
:
self
.
importer
(
used
)
found
=
getattr
(
found
,
frag
)
return
found
except
ImportError
:
e
,
tb
=
sys
.
exc_info
()[
1
:]
v
=
ValueError
(
'Cannot resolve
%
r:
%
s'
%
(
s
,
e
))
v
.
__cause__
,
v
.
__traceback__
=
e
,
tb
raise
v
def
ext_convert
(
self
,
value
):
"""Default converter for the ext:// protocol."""
return
self
.
resolve
(
value
)
def
cfg_convert
(
self
,
value
):
"""Default converter for the cfg:// protocol."""
rest
=
value
m
=
self
.
WORD_PATTERN
.
match
(
rest
)
if
m
is
None
:
raise
ValueError
(
"Unable to convert
%
r"
%
value
)
else
:
rest
=
rest
[
m
.
end
():]
d
=
self
.
config
[
m
.
groups
()[
0
]]
#print d, rest
while
rest
:
m
=
self
.
DOT_PATTERN
.
match
(
rest
)
if
m
:
d
=
d
[
m
.
groups
()[
0
]]
else
:
m
=
self
.
INDEX_PATTERN
.
match
(
rest
)
if
m
:
idx
=
m
.
groups
()[
0
]
if
not
self
.
DIGIT_PATTERN
.
match
(
idx
):
d
=
d
[
idx
]
else
:
try
:
n
=
int
(
idx
)
# try as number first (most likely)
d
=
d
[
n
]
except
TypeError
:
d
=
d
[
idx
]
if
m
:
rest
=
rest
[
m
.
end
():]
else
:
raise
ValueError
(
'Unable to convert '
'
%
r at
%
r'
%
(
value
,
rest
))
#rest should be empty
return
d
def
convert
(
self
,
value
):
"""
Convert values to an appropriate type. dicts, lists and tuples are
replaced by their converting alternatives. Strings are checked to
see if they have a conversion format and are converted if they do.
"""
if
not
isinstance
(
value
,
ConvertingDict
)
and
isinstance
(
value
,
dict
):
value
=
ConvertingDict
(
value
)
value
.
configurator
=
self
elif
not
isinstance
(
value
,
ConvertingList
)
and
isinstance
(
value
,
list
):
value
=
ConvertingList
(
value
)
value
.
configurator
=
self
elif
not
isinstance
(
value
,
ConvertingTuple
)
and
\
isinstance
(
value
,
tuple
):
value
=
ConvertingTuple
(
value
)
value
.
configurator
=
self
elif
isinstance
(
value
,
string_types
):
m
=
self
.
CONVERT_PATTERN
.
match
(
value
)
if
m
:
d
=
m
.
groupdict
()
prefix
=
d
[
'prefix'
]
converter
=
self
.
value_converters
.
get
(
prefix
,
None
)
if
converter
:
suffix
=
d
[
'suffix'
]
converter
=
getattr
(
self
,
converter
)
value
=
converter
(
suffix
)
return
value
def
configure_custom
(
self
,
config
):
"""Configure an object with a user-supplied factory."""
c
=
config
.
pop
(
'()'
)
if
not
callable
(
c
):
c
=
self
.
resolve
(
c
)
props
=
config
.
pop
(
'.'
,
None
)
# Check for valid identifiers
kwargs
=
dict
([(
k
,
config
[
k
])
for
k
in
config
if
valid_ident
(
k
)])
result
=
c
(
**
kwargs
)
if
props
:
for
name
,
value
in
props
.
items
():
setattr
(
result
,
name
,
value
)
return
result
def
as_tuple
(
self
,
value
):
"""Utility function which converts lists to tuples."""
if
isinstance
(
value
,
list
):
value
=
tuple
(
value
)
return
value
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment