`_.
+ None will set an infinite timeout.
+
+ :type read: integer, float, or None
+
+ :param total:
+ This combines the connect and read timeouts into one; the read timeout
+ will be set to the time leftover from the connect attempt. In the
+ event that both a connect timeout and a total are specified, or a read
+ timeout and a total are specified, the shorter timeout will be applied.
+
+ Defaults to None.
+
+ :type total: integer, float, or None
+
+ .. note::
+
+ Many factors can affect the total amount of time for urllib3 to return
+ an HTTP response. Specifically, Python's DNS resolver does not obey the
+ timeout specified on the socket. Other factors that can affect total
+ request time include high CPU load, high swap, the program running at a
+ low priority level, or other behaviors. The observed running time for
+ urllib3 to return a response may be greater than the value passed to
+ `total`.
+
+ In addition, the read and total timeouts only measure the time between
+ read operations on the socket connecting the client and the server,
+ not the total amount of time for the request to return a complete
+ response. For most requests, the timeout is raised because the server
+ has not sent the first byte in the specified time. This is not always
+ the case; if a server streams one byte every fifteen seconds, a timeout
+ of 20 seconds will not ever trigger, even though the request will
+ take several minutes to complete.
+
+ If your goal is to cut off any request after a set amount of wall clock
+ time, consider having a second "watcher" thread to cut off a slow
+ request.
+ """
+
+ #: A sentinel object representing the default timeout value
+ DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT
+
+ def __init__(self, total=None, connect=_Default, read=_Default):
+ self._connect = self._validate_timeout(connect, 'connect')
+ self._read = self._validate_timeout(read, 'read')
+ self.total = self._validate_timeout(total, 'total')
+ self._start_connect = None
+
+ def __str__(self):
+ return '%s(connect=%r, read=%r, total=%r)' % (
+ type(self).__name__, self._connect, self._read, self.total)
+
+
+ @classmethod
+ def _validate_timeout(cls, value, name):
+ """ Check that a timeout attribute is valid
+
+ :param value: The timeout value to validate
+ :param name: The name of the timeout attribute to validate. This is used
+ for clear error messages
+ :return: the value
+ :raises ValueError: if the type is not an integer or a float, or if it
+ is a numeric value less than zero
+ """
+ if value is _Default:
+ return cls.DEFAULT_TIMEOUT
+
+ if value is None or value is cls.DEFAULT_TIMEOUT:
+ return value
+
+ try:
+ float(value)
+ except (TypeError, ValueError):
+ raise ValueError("Timeout value %s was %s, but it must be an "
+ "int or float." % (name, value))
+
+ try:
+ if value < 0:
+ raise ValueError("Attempted to set %s timeout to %s, but the "
+ "timeout cannot be set to a value less "
+ "than 0." % (name, value))
+ except TypeError: # Python 3
+ raise ValueError("Timeout value %s was %s, but it must be an "
+ "int or float." % (name, value))
+
+ return value
+
+ @classmethod
+ def from_float(cls, timeout):
+ """ Create a new Timeout from a legacy timeout value.
+
+ The timeout value used by httplib.py sets the same timeout on the
+ connect(), and recv() socket requests. This creates a :class:`Timeout`
+ object that sets the individual timeouts to the ``timeout`` value passed
+ to this function.
+
+ :param timeout: The legacy timeout value
+ :type timeout: integer, float, sentinel default object, or None
+ :return: a Timeout object
+ :rtype: :class:`Timeout`
+ """
+ return Timeout(read=timeout, connect=timeout)
+
+ def clone(self):
+ """ Create a copy of the timeout object
+
+ Timeout properties are stored per-pool but each request needs a fresh
+ Timeout object to ensure each one has its own start/stop configured.
+
+ :return: a copy of the timeout object
+ :rtype: :class:`Timeout`
+ """
+ # We can't use copy.deepcopy because that will also create a new object
+ # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to
+ # detect the user default.
+ return Timeout(connect=self._connect, read=self._read,
+ total=self.total)
+
+ def start_connect(self):
+ """ Start the timeout clock, used during a connect() attempt
+
+ :raises urllib3.exceptions.TimeoutStateError: if you attempt
+ to start a timer that has been started already.
+ """
+ if self._start_connect is not None:
+ raise TimeoutStateError("Timeout timer has already been started.")
+ self._start_connect = current_time()
+ return self._start_connect
+
+ def get_connect_duration(self):
+ """ Gets the time elapsed since the call to :meth:`start_connect`.
+
+ :return: the elapsed time
+ :rtype: float
+ :raises urllib3.exceptions.TimeoutStateError: if you attempt
+ to get duration for a timer that hasn't been started.
+ """
+ if self._start_connect is None:
+ raise TimeoutStateError("Can't get connect duration for timer "
+ "that has not started.")
+ return current_time() - self._start_connect
+
+ @property
+ def connect_timeout(self):
+ """ Get the value to use when setting a connection timeout.
+
+ This will be a positive float or integer, the value None
+ (never timeout), or the default system timeout.
+
+ :return: the connect timeout
+ :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None
+ """
+ if self.total is None:
+ return self._connect
+
+ if self._connect is None or self._connect is self.DEFAULT_TIMEOUT:
+ return self.total
+
+ return min(self._connect, self.total)
+
+ @property
+ def read_timeout(self):
+ """ Get the value for the read timeout.
+
+ This assumes some time has elapsed in the connection timeout and
+ computes the read timeout appropriately.
+
+ If self.total is set, the read timeout is dependent on the amount of
+ time taken by the connect timeout. If the connection time has not been
+ established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be
+ raised.
+
+ :return: the value to use for the read timeout
+ :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None
+ :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect`
+ has not yet been called on this object.
+ """
+ if (self.total is not None and
+ self.total is not self.DEFAULT_TIMEOUT and
+ self._read is not None and
+ self._read is not self.DEFAULT_TIMEOUT):
+ # in case the connect timeout has not yet been established.
+ if self._start_connect is None:
+ return self._read
+ return max(0, min(self.total - self.get_connect_duration(),
+ self._read))
+ elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT:
+ return max(0, self.total - self.get_connect_duration())
+ else:
+ return self._read
diff --git a/PythonHome/Lib/site-packages/requests/packages/urllib3/util/url.py b/PythonHome/Lib/site-packages/requests/packages/urllib3/util/url.py
new file mode 100644
index 000000000..362d21608
--- /dev/null
+++ b/PythonHome/Lib/site-packages/requests/packages/urllib3/util/url.py
@@ -0,0 +1,162 @@
+from collections import namedtuple
+
+from ..exceptions import LocationParseError
+
+
+class Url(namedtuple('Url', ['scheme', 'auth', 'host', 'port', 'path', 'query', 'fragment'])):
+ """
+ Datastructure for representing an HTTP URL. Used as a return value for
+ :func:`parse_url`.
+ """
+ slots = ()
+
+ def __new__(cls, scheme=None, auth=None, host=None, port=None, path=None, query=None, fragment=None):
+ return super(Url, cls).__new__(cls, scheme, auth, host, port, path, query, fragment)
+
+ @property
+ def hostname(self):
+ """For backwards-compatibility with urlparse. We're nice like that."""
+ return self.host
+
+ @property
+ def request_uri(self):
+ """Absolute path including the query string."""
+ uri = self.path or '/'
+
+ if self.query is not None:
+ uri += '?' + self.query
+
+ return uri
+
+ @property
+ def netloc(self):
+ """Network location including host and port"""
+ if self.port:
+ return '%s:%d' % (self.host, self.port)
+ return self.host
+
+
+def split_first(s, delims):
+ """
+ Given a string and an iterable of delimiters, split on the first found
+ delimiter. Return two split parts and the matched delimiter.
+
+ If not found, then the first part is the full input string.
+
+ Example: ::
+
+ >>> split_first('foo/bar?baz', '?/=')
+ ('foo', 'bar?baz', '/')
+ >>> split_first('foo/bar?baz', '123')
+ ('foo/bar?baz', '', None)
+
+ Scales linearly with number of delims. Not ideal for large number of delims.
+ """
+ min_idx = None
+ min_delim = None
+ for d in delims:
+ idx = s.find(d)
+ if idx < 0:
+ continue
+
+ if min_idx is None or idx < min_idx:
+ min_idx = idx
+ min_delim = d
+
+ if min_idx is None or min_idx < 0:
+ return s, '', None
+
+ return s[:min_idx], s[min_idx+1:], min_delim
+
+
+def parse_url(url):
+ """
+ Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is
+ performed to parse incomplete urls. Fields not provided will be None.
+
+ Partly backwards-compatible with :mod:`urlparse`.
+
+ Example: ::
+
+ >>> parse_url('http://google.com/mail/')
+ Url(scheme='http', host='google.com', port=None, path='/', ...)
+ >>> parse_url('google.com:80')
+ Url(scheme=None, host='google.com', port=80, path=None, ...)
+ >>> parse_url('/foo?bar')
+ Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...)
+ """
+
+ # While this code has overlap with stdlib's urlparse, it is much
+ # simplified for our needs and less annoying.
+ # Additionally, this implementations does silly things to be optimal
+ # on CPython.
+
+ scheme = None
+ auth = None
+ host = None
+ port = None
+ path = None
+ fragment = None
+ query = None
+
+ # Scheme
+ if '://' in url:
+ scheme, url = url.split('://', 1)
+
+ # Find the earliest Authority Terminator
+ # (http://tools.ietf.org/html/rfc3986#section-3.2)
+ url, path_, delim = split_first(url, ['/', '?', '#'])
+
+ if delim:
+ # Reassemble the path
+ path = delim + path_
+
+ # Auth
+ if '@' in url:
+ # Last '@' denotes end of auth part
+ auth, url = url.rsplit('@', 1)
+
+ # IPv6
+ if url and url[0] == '[':
+ host, url = url.split(']', 1)
+ host += ']'
+
+ # Port
+ if ':' in url:
+ _host, port = url.split(':', 1)
+
+ if not host:
+ host = _host
+
+ if port:
+ # If given, ports must be integers.
+ if not port.isdigit():
+ raise LocationParseError(url)
+ port = int(port)
+ else:
+ # Blank ports are cool, too. (rfc3986#section-3.2.3)
+ port = None
+
+ elif not host and url:
+ host = url
+
+ if not path:
+ return Url(scheme, auth, host, port, path, query, fragment)
+
+ # Fragment
+ if '#' in path:
+ path, fragment = path.split('#', 1)
+
+ # Query
+ if '?' in path:
+ path, query = path.split('?', 1)
+
+ return Url(scheme, auth, host, port, path, query, fragment)
+
+
+def get_host(url):
+ """
+ Deprecated. Use :func:`.parse_url` instead.
+ """
+ p = parse_url(url)
+ return p.scheme or 'http', p.hostname, p.port
diff --git a/PythonHome/thirdparty/requests/sessions.py b/PythonHome/Lib/site-packages/requests/sessions.py
similarity index 82%
rename from PythonHome/thirdparty/requests/sessions.py
rename to PythonHome/Lib/site-packages/requests/sessions.py
index db227ca37..df85a25c1 100644
--- a/PythonHome/thirdparty/requests/sessions.py
+++ b/PythonHome/Lib/site-packages/requests/sessions.py
@@ -12,27 +12,28 @@ import os
from collections import Mapping
from datetime import datetime
+from .auth import _basic_auth_str
from .compat import cookielib, OrderedDict, urljoin, urlparse, builtin_str
from .cookies import (
cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies)
-from .models import Request, PreparedRequest
+from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT
from .hooks import default_hooks, dispatch_hook
-from .utils import to_key_val_list, default_headers
-from .exceptions import TooManyRedirects, InvalidSchema
+from .utils import to_key_val_list, default_headers, to_native_string
+from .exceptions import (
+ TooManyRedirects, InvalidSchema, ChunkedEncodingError, ContentDecodingError)
from .structures import CaseInsensitiveDict
from .adapters import HTTPAdapter
-from .utils import requote_uri, get_environ_proxies, get_netrc_auth
+from .utils import (
+ requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies,
+ get_auth_from_url
+)
from .status_codes import codes
-REDIRECT_STATI = (
- codes.moved, # 301
- codes.found, # 302
- codes.other, # 303
- codes.temporary_moved, # 307
-)
-DEFAULT_REDIRECT_LIMIT = 30
+
+# formerly defined here, reexposed here for backward compatibility
+from .models import REDIRECT_STATI
def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
@@ -63,6 +64,8 @@ def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
if v is None:
del merged_setting[k]
+ merged_setting = dict((k, v) for (k, v) in merged_setting.items() if v is not None)
+
return merged_setting
@@ -89,11 +92,13 @@ class SessionRedirectMixin(object):
i = 0
- # ((resp.status_code is codes.see_other))
- while ('location' in resp.headers and resp.status_code in REDIRECT_STATI):
+ while resp.is_redirect:
prepared_request = req.copy()
- resp.content # Consume socket so it can be released
+ try:
+ resp.content # Consume socket so it can be released
+ except (ChunkedEncodingError, ContentDecodingError, RuntimeError):
+ resp.raw.read(decode_content=False)
if i >= self.max_redirects:
raise TooManyRedirects('Exceeded %s redirects.' % self.max_redirects)
@@ -121,7 +126,7 @@ class SessionRedirectMixin(object):
else:
url = requote_uri(url)
- prepared_request.url = url
+ prepared_request.url = to_native_string(url)
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4
if (resp.status_code == codes.see_other and
@@ -153,13 +158,19 @@ class SessionRedirectMixin(object):
except KeyError:
pass
- extract_cookies_to_jar(prepared_request._cookies,
- prepared_request, resp.raw)
+ extract_cookies_to_jar(prepared_request._cookies, prepared_request, resp.raw)
prepared_request._cookies.update(self.cookies)
prepared_request.prepare_cookies(prepared_request._cookies)
+ # Rebuild auth and proxy information.
+ proxies = self.rebuild_proxies(prepared_request, proxies)
+ self.rebuild_auth(prepared_request, resp)
+
+ # Override the original request.
+ req = prepared_request
+
resp = self.send(
- prepared_request,
+ req,
stream=stream,
timeout=timeout,
verify=verify,
@@ -173,6 +184,68 @@ class SessionRedirectMixin(object):
i += 1
yield resp
+ def rebuild_auth(self, prepared_request, response):
+ """
+ When being redirected we may want to strip authentication from the
+ request to avoid leaking credentials. This method intelligently removes
+ and reapplies authentication where possible to avoid credential loss.
+ """
+ headers = prepared_request.headers
+ url = prepared_request.url
+
+ if 'Authorization' in headers:
+ # If we get redirected to a new host, we should strip out any
+ # authentication headers.
+ original_parsed = urlparse(response.request.url)
+ redirect_parsed = urlparse(url)
+
+ if (original_parsed.hostname != redirect_parsed.hostname):
+ del headers['Authorization']
+
+ # .netrc might have more auth for us on our new host.
+ new_auth = get_netrc_auth(url) if self.trust_env else None
+ if new_auth is not None:
+ prepared_request.prepare_auth(new_auth)
+
+ return
+
+ def rebuild_proxies(self, prepared_request, proxies):
+ """
+ This method re-evaluates the proxy configuration by considering the
+ environment variables. If we are redirected to a URL covered by
+ NO_PROXY, we strip the proxy configuration. Otherwise, we set missing
+ proxy keys for this URL (in case they were stripped by a previous
+ redirect).
+
+ This method also replaces the Proxy-Authorization header where
+ necessary.
+ """
+ headers = prepared_request.headers
+ url = prepared_request.url
+ scheme = urlparse(url).scheme
+ new_proxies = proxies.copy() if proxies is not None else {}
+
+ if self.trust_env and not should_bypass_proxies(url):
+ environ_proxies = get_environ_proxies(url)
+
+ proxy = environ_proxies.get(scheme)
+
+ if proxy:
+ new_proxies.setdefault(scheme, environ_proxies[scheme])
+
+ if 'Proxy-Authorization' in headers:
+ del headers['Proxy-Authorization']
+
+ try:
+ username, password = get_auth_from_url(new_proxies[scheme])
+ except KeyError:
+ username, password = None, None
+
+ if username and password:
+ headers['Proxy-Authorization'] = _basic_auth_str(username, password)
+
+ return new_proxies
+
class Session(SessionRedirectMixin):
"""A Requests session.
@@ -320,7 +393,7 @@ class Session(SessionRedirectMixin):
:param auth: (optional) Auth tuple or callable to enable
Basic/Digest/Custom HTTP Auth.
:param timeout: (optional) Float describing the timeout of the
- request.
+ request in seconds.
:param allow_redirects: (optional) Boolean. Set to True by default.
:param proxies: (optional) Dictionary mapping protocol to the URL of
the proxy.
@@ -467,8 +540,7 @@ class Session(SessionRedirectMixin):
if not isinstance(request, PreparedRequest):
raise ValueError('You can only send PreparedRequests.')
- # Set up variables needed for resolve_redirects and dispatching of
- # hooks
+ # Set up variables needed for resolve_redirects and dispatching of hooks
allow_redirects = kwargs.pop('allow_redirects', True)
stream = kwargs.get('stream')
timeout = kwargs.get('timeout')
@@ -482,8 +554,10 @@ class Session(SessionRedirectMixin):
# Start time (approximately) of the request
start = datetime.utcnow()
+
# Send the request
r = adapter.send(request, **kwargs)
+
# Total elapsed time of the request (approximately)
r.elapsed = datetime.utcnow() - start
@@ -492,15 +566,20 @@ class Session(SessionRedirectMixin):
# Persist cookies
if r.history:
+
# If the hooks create history then we want those cookies too
for resp in r.history:
extract_cookies_to_jar(self.cookies, resp.request, resp.raw)
+
extract_cookies_to_jar(self.cookies, request, r.raw)
# Redirect resolving generator.
- gen = self.resolve_redirects(r, request, stream=stream,
- timeout=timeout, verify=verify, cert=cert,
- proxies=proxies)
+ gen = self.resolve_redirects(r, request,
+ stream=stream,
+ timeout=timeout,
+ verify=verify,
+ cert=cert,
+ proxies=proxies)
# Resolve redirects if allowed.
history = [resp for resp in gen] if allow_redirects else []
@@ -511,7 +590,10 @@ class Session(SessionRedirectMixin):
history.insert(0, r)
# Get the last request made
r = history.pop()
- r.history = tuple(history)
+ r.history = history
+
+ if not stream:
+ r.content
return r
@@ -534,8 +616,10 @@ class Session(SessionRedirectMixin):
"""Registers a connection adapter to a prefix.
Adapters are sorted in descending order by key length."""
+
self.adapters[prefix] = adapter
keys_to_move = [k for k in self.adapters if len(k) < len(prefix)]
+
for key in keys_to_move:
self.adapters[key] = self.adapters.pop(key)
diff --git a/PythonHome/thirdparty/requests/status_codes.py b/PythonHome/Lib/site-packages/requests/status_codes.py
similarity index 100%
rename from PythonHome/thirdparty/requests/status_codes.py
rename to PythonHome/Lib/site-packages/requests/status_codes.py
diff --git a/PythonHome/thirdparty/requests/structures.py b/PythonHome/Lib/site-packages/requests/structures.py
similarity index 97%
rename from PythonHome/thirdparty/requests/structures.py
rename to PythonHome/Lib/site-packages/requests/structures.py
index a1759137a..9fd78187f 100644
--- a/PythonHome/thirdparty/requests/structures.py
+++ b/PythonHome/Lib/site-packages/requests/structures.py
@@ -106,8 +106,7 @@ class CaseInsensitiveDict(collections.MutableMapping):
return CaseInsensitiveDict(self._store.values())
def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, dict(self.items()))
-
+ return str(dict(self.items()))
class LookupDict(dict):
"""Dictionary lookup object."""
diff --git a/PythonHome/thirdparty/requests/utils.py b/PythonHome/Lib/site-packages/requests/utils.py
similarity index 94%
rename from PythonHome/thirdparty/requests/utils.py
rename to PythonHome/Lib/site-packages/requests/utils.py
index 7b7ff0a7b..68e50cf0a 100644
--- a/PythonHome/thirdparty/requests/utils.py
+++ b/PythonHome/Lib/site-packages/requests/utils.py
@@ -24,10 +24,10 @@ from . import __version__
from . import certs
from .compat import parse_http_list as _parse_list_header
from .compat import (quote, urlparse, bytes, str, OrderedDict, unquote, is_py2,
- builtin_str, getproxies, proxy_bypass)
+ builtin_str, getproxies, proxy_bypass, urlunparse)
from .cookies import RequestsCookieJar, cookiejar_from_dict
from .structures import CaseInsensitiveDict
-from .exceptions import MissingSchema, InvalidURL
+from .exceptions import InvalidURL
_hush_pyflakes = (RequestsCookieJar,)
@@ -61,7 +61,7 @@ def super_len(o):
return os.fstat(fileno).st_size
if hasattr(o, 'getvalue'):
- # e.g. BytesIO, cStringIO.StringI
+ # e.g. BytesIO, cStringIO.StringIO
return len(o.getvalue())
@@ -466,9 +466,10 @@ def is_valid_cidr(string_network):
return True
-def get_environ_proxies(url):
- """Return a dict of environment proxies."""
-
+def should_bypass_proxies(url):
+ """
+ Returns whether we should bypass proxies or not.
+ """
get_proxy = lambda k: os.environ.get(k) or os.environ.get(k.upper())
# First check whether no_proxy is defined. If it is, check that the URL
@@ -486,13 +487,13 @@ def get_environ_proxies(url):
for proxy_ip in no_proxy:
if is_valid_cidr(proxy_ip):
if address_in_network(ip, proxy_ip):
- return {}
+ return True
else:
for host in no_proxy:
if netloc.endswith(host) or netloc.split(':')[0].endswith(host):
# The URL does match something in no_proxy, so we don't want
# to apply the proxies on this URL.
- return {}
+ return True
# If the system proxy settings indicate that this URL should be bypassed,
# don't proxy.
@@ -506,12 +507,16 @@ def get_environ_proxies(url):
bypass = False
if bypass:
- return {}
+ return True
- # If we get here, we either didn't have no_proxy set or we're not going
- # anywhere that no_proxy applies to, and the system settings don't require
- # bypassing the proxy for the current URL.
- return getproxies()
+ return False
+
+def get_environ_proxies(url):
+ """Return a dict of environment proxies."""
+ if should_bypass_proxies(url):
+ return {}
+ else:
+ return getproxies()
def default_user_agent(name="python-requests"):
@@ -548,7 +553,7 @@ def default_user_agent(name="python-requests"):
def default_headers():
return CaseInsensitiveDict({
'User-Agent': default_user_agent(),
- 'Accept-Encoding': ', '.join(('gzip', 'deflate', 'compress')),
+ 'Accept-Encoding': ', '.join(('gzip', 'deflate')),
'Accept': '*/*'
})
@@ -622,13 +627,18 @@ def guess_json_utf(data):
return None
-def except_on_missing_scheme(url):
- """Given a URL, raise a MissingSchema exception if the scheme is missing.
- """
- scheme, netloc, path, params, query, fragment = urlparse(url)
+def prepend_scheme_if_needed(url, new_scheme):
+ '''Given a URL that may or may not have a scheme, prepend the given scheme.
+ Does not replace a present scheme with the one provided as an argument.'''
+ scheme, netloc, path, params, query, fragment = urlparse(url, new_scheme)
- if not scheme:
- raise MissingSchema('Proxy URLs must have explicit schemes.')
+ # urlparse is a finicky beast, and sometimes decides that there isn't a
+ # netloc present. Assume that it's being over-cautious, and switch netloc
+ # and path if urlparse decided there was no netloc.
+ if not netloc:
+ netloc, path = path, netloc
+
+ return urlunparse((scheme, netloc, path, params, query, fragment))
def get_auth_from_url(url):
diff --git a/PythonHome/thirdparty/setuptools-5.4.1.dist-info/DESCRIPTION.rst b/PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/DESCRIPTION.rst
similarity index 100%
rename from PythonHome/thirdparty/setuptools-5.4.1.dist-info/DESCRIPTION.rst
rename to PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/DESCRIPTION.rst
diff --git a/PythonHome/thirdparty/setuptools-5.4.1.dist-info/METADATA b/PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/METADATA
similarity index 100%
rename from PythonHome/thirdparty/setuptools-5.4.1.dist-info/METADATA
rename to PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/METADATA
diff --git a/PythonHome/thirdparty/setuptools-5.4.1.dist-info/RECORD b/PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/RECORD
similarity index 97%
rename from PythonHome/thirdparty/setuptools-5.4.1.dist-info/RECORD
rename to PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/RECORD
index 2cc947a96..4465aaeec 100644
--- a/PythonHome/thirdparty/setuptools-5.4.1.dist-info/RECORD
+++ b/PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/RECORD
@@ -83,8 +83,8 @@ setuptools-5.4.1.dist-info/WHEEL,sha256=2QrAqABq1X2mxKM4JY32oZUIM268GesCrPKhzE9R
setuptools-5.4.1.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
_markerlib/markers.py,sha256=YuFp0-osufFIoqnzG3L0Z2fDCx4Vln3VUDeXJ2DA_1I,3979
_markerlib/__init__.py,sha256=GSmhZqvAitLJHhSgtqqusfq2nJ_ClP3oy3Lm0uZLIsU,552
-e:\github\Wox.JSONRPC\Output\Debug\PythonHome\Scripts\easy_install.exe,sha256=ktvdzicYaXuV9Ps9MmxEZLOo22vx0rRo92IcaGuoOZ8,91530
-e:\github\Wox.JSONRPC\Output\Debug\PythonHome\Scripts\easy_install-2.7.exe,sha256=ktvdzicYaXuV9Ps9MmxEZLOo22vx0rRo92IcaGuoOZ8,91530
+Scripts\easy_install.exe,sha256=j3-cCoCIjUJ_6JofGmdXS0F_g2XnwGbirCTXjSvQCjI,91509
+Scripts\easy_install-2.7.exe,sha256=j3-cCoCIjUJ_6JofGmdXS0F_g2XnwGbirCTXjSvQCjI,91509
setuptools/tests/test_upload_docs.pyc,,
setuptools/ssl_support.pyc,,
setuptools/dist.pyc,,
diff --git a/PythonHome/thirdparty/setuptools-5.4.1.dist-info/WHEEL b/PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/WHEEL
similarity index 100%
rename from PythonHome/thirdparty/setuptools-5.4.1.dist-info/WHEEL
rename to PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/WHEEL
diff --git a/PythonHome/thirdparty/setuptools-5.4.1.dist-info/dependency_links.txt b/PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/dependency_links.txt
similarity index 100%
rename from PythonHome/thirdparty/setuptools-5.4.1.dist-info/dependency_links.txt
rename to PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/dependency_links.txt
diff --git a/PythonHome/thirdparty/setuptools-5.4.1.dist-info/entry_points.txt b/PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/entry_points.txt
similarity index 100%
rename from PythonHome/thirdparty/setuptools-5.4.1.dist-info/entry_points.txt
rename to PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/entry_points.txt
diff --git a/PythonHome/thirdparty/setuptools-5.4.1.dist-info/pydist.json b/PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/pydist.json
similarity index 100%
rename from PythonHome/thirdparty/setuptools-5.4.1.dist-info/pydist.json
rename to PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/pydist.json
diff --git a/PythonHome/thirdparty/setuptools-5.4.1.dist-info/top_level.txt b/PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/top_level.txt
similarity index 100%
rename from PythonHome/thirdparty/setuptools-5.4.1.dist-info/top_level.txt
rename to PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/top_level.txt
diff --git a/PythonHome/thirdparty/setuptools-5.4.1.dist-info/zip-safe b/PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/zip-safe
similarity index 100%
rename from PythonHome/thirdparty/setuptools-5.4.1.dist-info/zip-safe
rename to PythonHome/Lib/site-packages/setuptools-5.4.1.dist-info/zip-safe
diff --git a/PythonHome/thirdparty/setuptools/__init__.py b/PythonHome/Lib/site-packages/setuptools/__init__.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/__init__.py
rename to PythonHome/Lib/site-packages/setuptools/__init__.py
diff --git a/PythonHome/thirdparty/setuptools/archive_util.py b/PythonHome/Lib/site-packages/setuptools/archive_util.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/archive_util.py
rename to PythonHome/Lib/site-packages/setuptools/archive_util.py
diff --git a/PythonHome/thirdparty/setuptools/command/__init__.py b/PythonHome/Lib/site-packages/setuptools/command/__init__.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/__init__.py
rename to PythonHome/Lib/site-packages/setuptools/command/__init__.py
diff --git a/PythonHome/thirdparty/setuptools/command/alias.py b/PythonHome/Lib/site-packages/setuptools/command/alias.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/alias.py
rename to PythonHome/Lib/site-packages/setuptools/command/alias.py
diff --git a/PythonHome/thirdparty/setuptools/command/bdist_egg.py b/PythonHome/Lib/site-packages/setuptools/command/bdist_egg.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/bdist_egg.py
rename to PythonHome/Lib/site-packages/setuptools/command/bdist_egg.py
diff --git a/PythonHome/thirdparty/setuptools/command/bdist_rpm.py b/PythonHome/Lib/site-packages/setuptools/command/bdist_rpm.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/bdist_rpm.py
rename to PythonHome/Lib/site-packages/setuptools/command/bdist_rpm.py
diff --git a/PythonHome/thirdparty/setuptools/command/bdist_wininst.py b/PythonHome/Lib/site-packages/setuptools/command/bdist_wininst.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/bdist_wininst.py
rename to PythonHome/Lib/site-packages/setuptools/command/bdist_wininst.py
diff --git a/PythonHome/thirdparty/setuptools/command/build_ext.py b/PythonHome/Lib/site-packages/setuptools/command/build_ext.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/build_ext.py
rename to PythonHome/Lib/site-packages/setuptools/command/build_ext.py
diff --git a/PythonHome/thirdparty/setuptools/command/build_py.py b/PythonHome/Lib/site-packages/setuptools/command/build_py.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/build_py.py
rename to PythonHome/Lib/site-packages/setuptools/command/build_py.py
diff --git a/PythonHome/thirdparty/setuptools/command/develop.py b/PythonHome/Lib/site-packages/setuptools/command/develop.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/develop.py
rename to PythonHome/Lib/site-packages/setuptools/command/develop.py
diff --git a/PythonHome/thirdparty/setuptools/command/easy_install.py b/PythonHome/Lib/site-packages/setuptools/command/easy_install.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/easy_install.py
rename to PythonHome/Lib/site-packages/setuptools/command/easy_install.py
diff --git a/PythonHome/thirdparty/setuptools/command/egg_info.py b/PythonHome/Lib/site-packages/setuptools/command/egg_info.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/egg_info.py
rename to PythonHome/Lib/site-packages/setuptools/command/egg_info.py
diff --git a/PythonHome/thirdparty/setuptools/command/install.py b/PythonHome/Lib/site-packages/setuptools/command/install.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/install.py
rename to PythonHome/Lib/site-packages/setuptools/command/install.py
diff --git a/PythonHome/thirdparty/setuptools/command/install_egg_info.py b/PythonHome/Lib/site-packages/setuptools/command/install_egg_info.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/install_egg_info.py
rename to PythonHome/Lib/site-packages/setuptools/command/install_egg_info.py
diff --git a/PythonHome/thirdparty/setuptools/command/install_lib.py b/PythonHome/Lib/site-packages/setuptools/command/install_lib.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/install_lib.py
rename to PythonHome/Lib/site-packages/setuptools/command/install_lib.py
diff --git a/PythonHome/thirdparty/setuptools/command/install_scripts.py b/PythonHome/Lib/site-packages/setuptools/command/install_scripts.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/install_scripts.py
rename to PythonHome/Lib/site-packages/setuptools/command/install_scripts.py
diff --git a/PythonHome/thirdparty/setuptools/command/register.py b/PythonHome/Lib/site-packages/setuptools/command/register.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/register.py
rename to PythonHome/Lib/site-packages/setuptools/command/register.py
diff --git a/PythonHome/thirdparty/setuptools/command/rotate.py b/PythonHome/Lib/site-packages/setuptools/command/rotate.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/rotate.py
rename to PythonHome/Lib/site-packages/setuptools/command/rotate.py
diff --git a/PythonHome/thirdparty/setuptools/command/saveopts.py b/PythonHome/Lib/site-packages/setuptools/command/saveopts.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/saveopts.py
rename to PythonHome/Lib/site-packages/setuptools/command/saveopts.py
diff --git a/PythonHome/thirdparty/setuptools/command/sdist.py b/PythonHome/Lib/site-packages/setuptools/command/sdist.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/sdist.py
rename to PythonHome/Lib/site-packages/setuptools/command/sdist.py
diff --git a/PythonHome/thirdparty/setuptools/command/setopt.py b/PythonHome/Lib/site-packages/setuptools/command/setopt.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/setopt.py
rename to PythonHome/Lib/site-packages/setuptools/command/setopt.py
diff --git a/PythonHome/thirdparty/setuptools/command/test.py b/PythonHome/Lib/site-packages/setuptools/command/test.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/test.py
rename to PythonHome/Lib/site-packages/setuptools/command/test.py
diff --git a/PythonHome/thirdparty/setuptools/command/upload_docs.py b/PythonHome/Lib/site-packages/setuptools/command/upload_docs.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/command/upload_docs.py
rename to PythonHome/Lib/site-packages/setuptools/command/upload_docs.py
diff --git a/PythonHome/thirdparty/setuptools/compat.py b/PythonHome/Lib/site-packages/setuptools/compat.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/compat.py
rename to PythonHome/Lib/site-packages/setuptools/compat.py
diff --git a/PythonHome/thirdparty/setuptools/depends.py b/PythonHome/Lib/site-packages/setuptools/depends.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/depends.py
rename to PythonHome/Lib/site-packages/setuptools/depends.py
diff --git a/PythonHome/thirdparty/setuptools/dist.py b/PythonHome/Lib/site-packages/setuptools/dist.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/dist.py
rename to PythonHome/Lib/site-packages/setuptools/dist.py
diff --git a/PythonHome/thirdparty/setuptools/extension.py b/PythonHome/Lib/site-packages/setuptools/extension.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/extension.py
rename to PythonHome/Lib/site-packages/setuptools/extension.py
diff --git a/PythonHome/thirdparty/setuptools/lib2to3_ex.py b/PythonHome/Lib/site-packages/setuptools/lib2to3_ex.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/lib2to3_ex.py
rename to PythonHome/Lib/site-packages/setuptools/lib2to3_ex.py
diff --git a/PythonHome/thirdparty/setuptools/package_index.py b/PythonHome/Lib/site-packages/setuptools/package_index.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/package_index.py
rename to PythonHome/Lib/site-packages/setuptools/package_index.py
diff --git a/PythonHome/thirdparty/setuptools/py26compat.py b/PythonHome/Lib/site-packages/setuptools/py26compat.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/py26compat.py
rename to PythonHome/Lib/site-packages/setuptools/py26compat.py
diff --git a/PythonHome/thirdparty/setuptools/py27compat.py b/PythonHome/Lib/site-packages/setuptools/py27compat.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/py27compat.py
rename to PythonHome/Lib/site-packages/setuptools/py27compat.py
diff --git a/PythonHome/thirdparty/setuptools/py31compat.py b/PythonHome/Lib/site-packages/setuptools/py31compat.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/py31compat.py
rename to PythonHome/Lib/site-packages/setuptools/py31compat.py
diff --git a/PythonHome/thirdparty/setuptools/sandbox.py b/PythonHome/Lib/site-packages/setuptools/sandbox.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/sandbox.py
rename to PythonHome/Lib/site-packages/setuptools/sandbox.py
diff --git a/PythonHome/thirdparty/setuptools/script (dev).tmpl b/PythonHome/Lib/site-packages/setuptools/script (dev).tmpl
similarity index 100%
rename from PythonHome/thirdparty/setuptools/script (dev).tmpl
rename to PythonHome/Lib/site-packages/setuptools/script (dev).tmpl
diff --git a/PythonHome/thirdparty/setuptools/script.tmpl b/PythonHome/Lib/site-packages/setuptools/script.tmpl
similarity index 100%
rename from PythonHome/thirdparty/setuptools/script.tmpl
rename to PythonHome/Lib/site-packages/setuptools/script.tmpl
diff --git a/PythonHome/thirdparty/setuptools/site-patch.py b/PythonHome/Lib/site-packages/setuptools/site-patch.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/site-patch.py
rename to PythonHome/Lib/site-packages/setuptools/site-patch.py
diff --git a/PythonHome/thirdparty/setuptools/ssl_support.py b/PythonHome/Lib/site-packages/setuptools/ssl_support.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/ssl_support.py
rename to PythonHome/Lib/site-packages/setuptools/ssl_support.py
diff --git a/PythonHome/thirdparty/setuptools/svn_utils.py b/PythonHome/Lib/site-packages/setuptools/svn_utils.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/svn_utils.py
rename to PythonHome/Lib/site-packages/setuptools/svn_utils.py
diff --git a/PythonHome/thirdparty/setuptools/unicode_utils.py b/PythonHome/Lib/site-packages/setuptools/unicode_utils.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/unicode_utils.py
rename to PythonHome/Lib/site-packages/setuptools/unicode_utils.py
diff --git a/PythonHome/thirdparty/setuptools/version.py b/PythonHome/Lib/site-packages/setuptools/version.py
similarity index 100%
rename from PythonHome/thirdparty/setuptools/version.py
rename to PythonHome/Lib/site-packages/setuptools/version.py
diff --git a/PythonHome/Lib/site-packages/site.py b/PythonHome/Lib/site-packages/site.py
new file mode 100644
index 000000000..c2168019a
--- /dev/null
+++ b/PythonHome/Lib/site-packages/site.py
@@ -0,0 +1,76 @@
+def __boot():
+ import sys
+ import os
+ PYTHONPATH = os.environ.get('PYTHONPATH')
+ if PYTHONPATH is None or (sys.platform=='win32' and not PYTHONPATH):
+ PYTHONPATH = []
+ else:
+ PYTHONPATH = PYTHONPATH.split(os.pathsep)
+
+ pic = getattr(sys,'path_importer_cache',{})
+ stdpath = sys.path[len(PYTHONPATH):]
+ mydir = os.path.dirname(__file__)
+ #print "searching",stdpath,sys.path
+
+ for item in stdpath:
+ if item==mydir or not item:
+ continue # skip if current dir. on Windows, or my own directory
+ importer = pic.get(item)
+ if importer is not None:
+ loader = importer.find_module('site')
+ if loader is not None:
+ # This should actually reload the current module
+ loader.load_module('site')
+ break
+ else:
+ try:
+ import imp # Avoid import loop in Python >= 3.3
+ stream, path, descr = imp.find_module('site',[item])
+ except ImportError:
+ continue
+ if stream is None:
+ continue
+ try:
+ # This should actually reload the current module
+ imp.load_module('site',stream,path,descr)
+ finally:
+ stream.close()
+ break
+ else:
+ raise ImportError("Couldn't find the real 'site' module")
+
+ #print "loaded", __file__
+
+ known_paths = dict([(makepath(item)[1],1) for item in sys.path]) # 2.2 comp
+
+ oldpos = getattr(sys,'__egginsert',0) # save old insertion position
+ sys.__egginsert = 0 # and reset the current one
+
+ for item in PYTHONPATH:
+ addsitedir(item)
+
+ sys.__egginsert += oldpos # restore effective old position
+
+ d, nd = makepath(stdpath[0])
+ insert_at = None
+ new_path = []
+
+ for item in sys.path:
+ p, np = makepath(item)
+
+ if np==nd and insert_at is None:
+ # We've hit the first 'system' path entry, so added entries go here
+ insert_at = len(new_path)
+
+ if np in known_paths or insert_at is None:
+ new_path.append(item)
+ else:
+ # new path after the insert point, back-insert it
+ new_path.insert(insert_at, item)
+ insert_at += 1
+
+ sys.path[:] = new_path
+
+if __name__=='site':
+ __boot()
+ del __boot
diff --git a/PythonHome/Scripts/easy_install-2.7.exe b/PythonHome/Scripts/easy_install-2.7.exe
index 3d908b457..26964ed1f 100644
Binary files a/PythonHome/Scripts/easy_install-2.7.exe and b/PythonHome/Scripts/easy_install-2.7.exe differ
diff --git a/PythonHome/Scripts/easy_install.exe b/PythonHome/Scripts/easy_install.exe
index 3d908b457..26964ed1f 100644
Binary files a/PythonHome/Scripts/easy_install.exe and b/PythonHome/Scripts/easy_install.exe differ
diff --git a/PythonHome/Scripts/pip.exe b/PythonHome/Scripts/pip.exe
index 896036670..f1a788bc4 100644
Binary files a/PythonHome/Scripts/pip.exe and b/PythonHome/Scripts/pip.exe differ
diff --git a/PythonHome/Scripts/pip2.7.exe b/PythonHome/Scripts/pip2.7.exe
index 896036670..f1a788bc4 100644
Binary files a/PythonHome/Scripts/pip2.7.exe and b/PythonHome/Scripts/pip2.7.exe differ
diff --git a/PythonHome/Scripts/pip2.exe b/PythonHome/Scripts/pip2.exe
index 896036670..f1a788bc4 100644
Binary files a/PythonHome/Scripts/pip2.exe and b/PythonHome/Scripts/pip2.exe differ
diff --git a/PythonHome/pythonx.bat b/PythonHome/pythonx.bat
index ab0d2f4d7..15c1a2eb7 100644
--- a/PythonHome/pythonx.bat
+++ b/PythonHome/pythonx.bat
@@ -1,2 +1,2 @@
-set PYTHONPATH=DLLs;thirdparty
+set PYTHONPATH=DLLs;Lib\site-packages
python.exe -B %*
diff --git a/PythonHome/thirdparty/README.txt b/PythonHome/thirdparty/README.txt
deleted file mode 100644
index 273f6251a..000000000
--- a/PythonHome/thirdparty/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This directory exists so that 3rd party packages can be installed
-here. Read the source for site.py for more details.
diff --git a/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/PKG-INFO b/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/PKG-INFO
deleted file mode 100644
index c9fbab8f8..000000000
--- a/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/PKG-INFO
+++ /dev/null
@@ -1,20 +0,0 @@
-Metadata-Version: 1.1
-Name: beautifulsoup4
-Version: 4.3.2
-Summary: UNKNOWN
-Home-page: http://www.crummy.com/software/BeautifulSoup/bs4/
-Author: Leonard Richardson
-Author-email: leonardr@segfault.org
-License: MIT
-Download-URL: http://www.crummy.com/software/BeautifulSoup/bs4/download/
-Description: Beautiful Soup sits atop an HTML or XML parser, providing Pythonic idioms for iterating, searching, and modifying the parse tree.
-Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Topic :: Text Processing :: Markup :: HTML
-Classifier: Topic :: Text Processing :: Markup :: XML
-Classifier: Topic :: Text Processing :: Markup :: SGML
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff --git a/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/SOURCES.txt b/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/SOURCES.txt
deleted file mode 100644
index d5fbda3bf..000000000
--- a/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-README.txt
-beautifulsoup4.egg-info/PKG-INFO
-beautifulsoup4.egg-info/SOURCES.txt
-beautifulsoup4.egg-info/dependency_links.txt
-beautifulsoup4.egg-info/top_level.txt
-bs4/__init__.py
-bs4/dammit.py
-bs4/diagnose.py
-bs4/element.py
-bs4/testing.py
-bs4/builder/__init__.py
-bs4/builder/_html5lib.py
-bs4/builder/_htmlparser.py
-bs4/builder/_lxml.py
-bs4/tests/__init__.py
-bs4/tests/test_builder_registry.py
-bs4/tests/test_docs.py
-bs4/tests/test_html5lib.py
-bs4/tests/test_htmlparser.py
-bs4/tests/test_lxml.py
-bs4/tests/test_soup.py
-bs4/tests/test_tree.py
\ No newline at end of file
diff --git a/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/dependency_links.txt b/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/dependency_links.txt
deleted file mode 100644
index 8b1378917..000000000
--- a/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/dependency_links.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/installed-files.txt b/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/installed-files.txt
deleted file mode 100644
index 1c4d344b9..000000000
--- a/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/installed-files.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-..\bs4\dammit.py
-..\bs4\diagnose.py
-..\bs4\element.py
-..\bs4\testing.py
-..\bs4\__init__.py
-..\bs4\builder\_html5lib.py
-..\bs4\builder\_htmlparser.py
-..\bs4\builder\_lxml.py
-..\bs4\builder\__init__.py
-..\bs4\tests\test_builder_registry.py
-..\bs4\tests\test_docs.py
-..\bs4\tests\test_html5lib.py
-..\bs4\tests\test_htmlparser.py
-..\bs4\tests\test_lxml.py
-..\bs4\tests\test_soup.py
-..\bs4\tests\test_tree.py
-..\bs4\tests\__init__.py
-..\bs4\dammit.pyc
-..\bs4\diagnose.pyc
-..\bs4\element.pyc
-..\bs4\testing.pyc
-..\bs4\__init__.pyc
-..\bs4\builder\_html5lib.pyc
-..\bs4\builder\_htmlparser.pyc
-..\bs4\builder\_lxml.pyc
-..\bs4\builder\__init__.pyc
-..\bs4\tests\test_builder_registry.pyc
-..\bs4\tests\test_docs.pyc
-..\bs4\tests\test_html5lib.pyc
-..\bs4\tests\test_htmlparser.pyc
-..\bs4\tests\test_lxml.pyc
-..\bs4\tests\test_soup.pyc
-..\bs4\tests\test_tree.pyc
-..\bs4\tests\__init__.pyc
-.\
-dependency_links.txt
-PKG-INFO
-SOURCES.txt
-top_level.txt
diff --git a/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/top_level.txt b/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/top_level.txt
deleted file mode 100644
index 13154420d..000000000
--- a/PythonHome/thirdparty/beautifulsoup4-4.3.2-py2.7.egg-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-bs4
diff --git a/PythonHome/thirdparty/bs4/__init__.py b/PythonHome/thirdparty/bs4/__init__.py
deleted file mode 100644
index 7ba34269a..000000000
--- a/PythonHome/thirdparty/bs4/__init__.py
+++ /dev/null
@@ -1,406 +0,0 @@
-"""Beautiful Soup
-Elixir and Tonic
-"The Screen-Scraper's Friend"
-http://www.crummy.com/software/BeautifulSoup/
-
-Beautiful Soup uses a pluggable XML or HTML parser to parse a
-(possibly invalid) document into a tree representation. Beautiful Soup
-provides provides methods and Pythonic idioms that make it easy to
-navigate, search, and modify the parse tree.
-
-Beautiful Soup works with Python 2.6 and up. It works better if lxml
-and/or html5lib is installed.
-
-For more than you ever wanted to know about Beautiful Soup, see the
-documentation:
-http://www.crummy.com/software/BeautifulSoup/bs4/doc/
-"""
-
-__author__ = "Leonard Richardson (leonardr@segfault.org)"
-__version__ = "4.3.2"
-__copyright__ = "Copyright (c) 2004-2013 Leonard Richardson"
-__license__ = "MIT"
-
-__all__ = ['BeautifulSoup']
-
-import os
-import re
-import warnings
-
-from .builder import builder_registry, ParserRejectedMarkup
-from .dammit import UnicodeDammit
-from .element import (
- CData,
- Comment,
- DEFAULT_OUTPUT_ENCODING,
- Declaration,
- Doctype,
- NavigableString,
- PageElement,
- ProcessingInstruction,
- ResultSet,
- SoupStrainer,
- Tag,
- )
-
-# The very first thing we do is give a useful error if someone is
-# running this code under Python 3 without converting it.
-syntax_error = u'You are trying to run the Python 2 version of Beautiful Soup under Python 3. This will not work. You need to convert the code, either by installing it (`python setup.py install`) or by running 2to3 (`2to3 -w bs4`).'
-
-class BeautifulSoup(Tag):
- """
- This class defines the basic interface called by the tree builders.
-
- These methods will be called by the parser:
- reset()
- feed(markup)
-
- The tree builder may call these methods from its feed() implementation:
- handle_starttag(name, attrs) # See note about return value
- handle_endtag(name)
- handle_data(data) # Appends to the current data node
- endData(containerClass=NavigableString) # Ends the current data node
-
- No matter how complicated the underlying parser is, you should be
- able to build a tree using 'start tag' events, 'end tag' events,
- 'data' events, and "done with data" events.
-
- If you encounter an empty-element tag (aka a self-closing tag,
- like HTML's tag), call handle_starttag and then
- handle_endtag.
- """
- ROOT_TAG_NAME = u'[document]'
-
- # If the end-user gives no indication which tree builder they
- # want, look for one with these features.
- DEFAULT_BUILDER_FEATURES = ['html', 'fast']
-
- ASCII_SPACES = '\x20\x0a\x09\x0c\x0d'
-
- def __init__(self, markup="", features=None, builder=None,
- parse_only=None, from_encoding=None, **kwargs):
- """The Soup object is initialized as the 'root tag', and the
- provided markup (which can be a string or a file-like object)
- is fed into the underlying parser."""
-
- if 'convertEntities' in kwargs:
- warnings.warn(
- "BS4 does not respect the convertEntities argument to the "
- "BeautifulSoup constructor. Entities are always converted "
- "to Unicode characters.")
-
- if 'markupMassage' in kwargs:
- del kwargs['markupMassage']
- warnings.warn(
- "BS4 does not respect the markupMassage argument to the "
- "BeautifulSoup constructor. The tree builder is responsible "
- "for any necessary markup massage.")
-
- if 'smartQuotesTo' in kwargs:
- del kwargs['smartQuotesTo']
- warnings.warn(
- "BS4 does not respect the smartQuotesTo argument to the "
- "BeautifulSoup constructor. Smart quotes are always converted "
- "to Unicode characters.")
-
- if 'selfClosingTags' in kwargs:
- del kwargs['selfClosingTags']
- warnings.warn(
- "BS4 does not respect the selfClosingTags argument to the "
- "BeautifulSoup constructor. The tree builder is responsible "
- "for understanding self-closing tags.")
-
- if 'isHTML' in kwargs:
- del kwargs['isHTML']
- warnings.warn(
- "BS4 does not respect the isHTML argument to the "
- "BeautifulSoup constructor. You can pass in features='html' "
- "or features='xml' to get a builder capable of handling "
- "one or the other.")
-
- def deprecated_argument(old_name, new_name):
- if old_name in kwargs:
- warnings.warn(
- 'The "%s" argument to the BeautifulSoup constructor '
- 'has been renamed to "%s."' % (old_name, new_name))
- value = kwargs[old_name]
- del kwargs[old_name]
- return value
- return None
-
- parse_only = parse_only or deprecated_argument(
- "parseOnlyThese", "parse_only")
-
- from_encoding = from_encoding or deprecated_argument(
- "fromEncoding", "from_encoding")
-
- if len(kwargs) > 0:
- arg = kwargs.keys().pop()
- raise TypeError(
- "__init__() got an unexpected keyword argument '%s'" % arg)
-
- if builder is None:
- if isinstance(features, basestring):
- features = [features]
- if features is None or len(features) == 0:
- features = self.DEFAULT_BUILDER_FEATURES
- builder_class = builder_registry.lookup(*features)
- if builder_class is None:
- raise FeatureNotFound(
- "Couldn't find a tree builder with the features you "
- "requested: %s. Do you need to install a parser library?"
- % ",".join(features))
- builder = builder_class()
- self.builder = builder
- self.is_xml = builder.is_xml
- self.builder.soup = self
-
- self.parse_only = parse_only
-
- if hasattr(markup, 'read'): # It's a file-type object.
- markup = markup.read()
- elif len(markup) <= 256:
- # Print out warnings for a couple beginner problems
- # involving passing non-markup to Beautiful Soup.
- # Beautiful Soup will still parse the input as markup,
- # just in case that's what the user really wants.
- if (isinstance(markup, unicode)
- and not os.path.supports_unicode_filenames):
- possible_filename = markup.encode("utf8")
- else:
- possible_filename = markup
- is_file = False
- try:
- is_file = os.path.exists(possible_filename)
- except Exception, e:
- # This is almost certainly a problem involving
- # characters not valid in filenames on this
- # system. Just let it go.
- pass
- if is_file:
- warnings.warn(
- '"%s" looks like a filename, not markup. You should probably open this file and pass the filehandle into Beautiful Soup.' % markup)
- if markup[:5] == "http:" or markup[:6] == "https:":
- # TODO: This is ugly but I couldn't get it to work in
- # Python 3 otherwise.
- if ((isinstance(markup, bytes) and not b' ' in markup)
- or (isinstance(markup, unicode) and not u' ' in markup)):
- warnings.warn(
- '"%s" looks like a URL. Beautiful Soup is not an HTTP client. You should probably use an HTTP client to get the document behind the URL, and feed that document to Beautiful Soup.' % markup)
-
- for (self.markup, self.original_encoding, self.declared_html_encoding,
- self.contains_replacement_characters) in (
- self.builder.prepare_markup(markup, from_encoding)):
- self.reset()
- try:
- self._feed()
- break
- except ParserRejectedMarkup:
- pass
-
- # Clear out the markup and remove the builder's circular
- # reference to this object.
- self.markup = None
- self.builder.soup = None
-
- def _feed(self):
- # Convert the document to Unicode.
- self.builder.reset()
-
- self.builder.feed(self.markup)
- # Close out any unfinished strings and close all the open tags.
- self.endData()
- while self.currentTag.name != self.ROOT_TAG_NAME:
- self.popTag()
-
- def reset(self):
- Tag.__init__(self, self, self.builder, self.ROOT_TAG_NAME)
- self.hidden = 1
- self.builder.reset()
- self.current_data = []
- self.currentTag = None
- self.tagStack = []
- self.preserve_whitespace_tag_stack = []
- self.pushTag(self)
-
- def new_tag(self, name, namespace=None, nsprefix=None, **attrs):
- """Create a new tag associated with this soup."""
- return Tag(None, self.builder, name, namespace, nsprefix, attrs)
-
- def new_string(self, s, subclass=NavigableString):
- """Create a new NavigableString associated with this soup."""
- navigable = subclass(s)
- navigable.setup()
- return navigable
-
- def insert_before(self, successor):
- raise NotImplementedError("BeautifulSoup objects don't support insert_before().")
-
- def insert_after(self, successor):
- raise NotImplementedError("BeautifulSoup objects don't support insert_after().")
-
- def popTag(self):
- tag = self.tagStack.pop()
- if self.preserve_whitespace_tag_stack and tag == self.preserve_whitespace_tag_stack[-1]:
- self.preserve_whitespace_tag_stack.pop()
- #print "Pop", tag.name
- if self.tagStack:
- self.currentTag = self.tagStack[-1]
- return self.currentTag
-
- def pushTag(self, tag):
- #print "Push", tag.name
- if self.currentTag:
- self.currentTag.contents.append(tag)
- self.tagStack.append(tag)
- self.currentTag = self.tagStack[-1]
- if tag.name in self.builder.preserve_whitespace_tags:
- self.preserve_whitespace_tag_stack.append(tag)
-
- def endData(self, containerClass=NavigableString):
- if self.current_data:
- current_data = u''.join(self.current_data)
- # If whitespace is not preserved, and this string contains
- # nothing but ASCII spaces, replace it with a single space
- # or newline.
- if not self.preserve_whitespace_tag_stack:
- strippable = True
- for i in current_data:
- if i not in self.ASCII_SPACES:
- strippable = False
- break
- if strippable:
- if '\n' in current_data:
- current_data = '\n'
- else:
- current_data = ' '
-
- # Reset the data collector.
- self.current_data = []
-
- # Should we add this string to the tree at all?
- if self.parse_only and len(self.tagStack) <= 1 and \
- (not self.parse_only.text or \
- not self.parse_only.search(current_data)):
- return
-
- o = containerClass(current_data)
- self.object_was_parsed(o)
-
- def object_was_parsed(self, o, parent=None, most_recent_element=None):
- """Add an object to the parse tree."""
- parent = parent or self.currentTag
- most_recent_element = most_recent_element or self._most_recent_element
- o.setup(parent, most_recent_element)
-
- if most_recent_element is not None:
- most_recent_element.next_element = o
- self._most_recent_element = o
- parent.contents.append(o)
-
- def _popToTag(self, name, nsprefix=None, inclusivePop=True):
- """Pops the tag stack up to and including the most recent
- instance of the given tag. If inclusivePop is false, pops the tag
- stack up to but *not* including the most recent instqance of
- the given tag."""
- #print "Popping to %s" % name
- if name == self.ROOT_TAG_NAME:
- # The BeautifulSoup object itself can never be popped.
- return
-
- most_recently_popped = None
-
- stack_size = len(self.tagStack)
- for i in range(stack_size - 1, 0, -1):
- t = self.tagStack[i]
- if (name == t.name and nsprefix == t.prefix):
- if inclusivePop:
- most_recently_popped = self.popTag()
- break
- most_recently_popped = self.popTag()
-
- return most_recently_popped
-
- def handle_starttag(self, name, namespace, nsprefix, attrs):
- """Push a start tag on to the stack.
-
- If this method returns None, the tag was rejected by the
- SoupStrainer. You should proceed as if the tag had not occured
- in the document. For instance, if this was a self-closing tag,
- don't call handle_endtag.
- """
-
- # print "Start tag %s: %s" % (name, attrs)
- self.endData()
-
- if (self.parse_only and len(self.tagStack) <= 1
- and (self.parse_only.text
- or not self.parse_only.search_tag(name, attrs))):
- return None
-
- tag = Tag(self, self.builder, name, namespace, nsprefix, attrs,
- self.currentTag, self._most_recent_element)
- if tag is None:
- return tag
- if self._most_recent_element:
- self._most_recent_element.next_element = tag
- self._most_recent_element = tag
- self.pushTag(tag)
- return tag
-
- def handle_endtag(self, name, nsprefix=None):
- #print "End tag: " + name
- self.endData()
- self._popToTag(name, nsprefix)
-
- def handle_data(self, data):
- self.current_data.append(data)
-
- def decode(self, pretty_print=False,
- eventual_encoding=DEFAULT_OUTPUT_ENCODING,
- formatter="minimal"):
- """Returns a string or Unicode representation of this document.
- To get Unicode, pass None for encoding."""
-
- if self.is_xml:
- # Print the XML declaration
- encoding_part = ''
- if eventual_encoding != None:
- encoding_part = ' encoding="%s"' % eventual_encoding
- prefix = u'\n' % encoding_part
- else:
- prefix = u''
- if not pretty_print:
- indent_level = None
- else:
- indent_level = 0
- return prefix + super(BeautifulSoup, self).decode(
- indent_level, eventual_encoding, formatter)
-
-# Alias to make it easier to type import: 'from bs4 import _soup'
-_s = BeautifulSoup
-_soup = BeautifulSoup
-
-class BeautifulStoneSoup(BeautifulSoup):
- """Deprecated interface to an XML parser."""
-
- def __init__(self, *args, **kwargs):
- kwargs['features'] = 'xml'
- warnings.warn(
- 'The BeautifulStoneSoup class is deprecated. Instead of using '
- 'it, pass features="xml" into the BeautifulSoup constructor.')
- super(BeautifulStoneSoup, self).__init__(*args, **kwargs)
-
-
-class StopParsing(Exception):
- pass
-
-class FeatureNotFound(ValueError):
- pass
-
-
-#By default, act as an HTML pretty-printer.
-if __name__ == '__main__':
- import sys
- soup = BeautifulSoup(sys.stdin)
- print soup.prettify()
diff --git a/PythonHome/thirdparty/bs4/builder/__init__.py b/PythonHome/thirdparty/bs4/builder/__init__.py
deleted file mode 100644
index 740f5f29c..000000000
--- a/PythonHome/thirdparty/bs4/builder/__init__.py
+++ /dev/null
@@ -1,321 +0,0 @@
-from collections import defaultdict
-import itertools
-import sys
-from bs4.element import (
- CharsetMetaAttributeValue,
- ContentMetaAttributeValue,
- whitespace_re
- )
-
-__all__ = [
- 'HTMLTreeBuilder',
- 'SAXTreeBuilder',
- 'TreeBuilder',
- 'TreeBuilderRegistry',
- ]
-
-# Some useful features for a TreeBuilder to have.
-FAST = 'fast'
-PERMISSIVE = 'permissive'
-STRICT = 'strict'
-XML = 'xml'
-HTML = 'html'
-HTML_5 = 'html5'
-
-
-class TreeBuilderRegistry(object):
-
- def __init__(self):
- self.builders_for_feature = defaultdict(list)
- self.builders = []
-
- def register(self, treebuilder_class):
- """Register a treebuilder based on its advertised features."""
- for feature in treebuilder_class.features:
- self.builders_for_feature[feature].insert(0, treebuilder_class)
- self.builders.insert(0, treebuilder_class)
-
- def lookup(self, *features):
- if len(self.builders) == 0:
- # There are no builders at all.
- return None
-
- if len(features) == 0:
- # They didn't ask for any features. Give them the most
- # recently registered builder.
- return self.builders[0]
-
- # Go down the list of features in order, and eliminate any builders
- # that don't match every feature.
- features = list(features)
- features.reverse()
- candidates = None
- candidate_set = None
- while len(features) > 0:
- feature = features.pop()
- we_have_the_feature = self.builders_for_feature.get(feature, [])
- if len(we_have_the_feature) > 0:
- if candidates is None:
- candidates = we_have_the_feature
- candidate_set = set(candidates)
- else:
- # Eliminate any candidates that don't have this feature.
- candidate_set = candidate_set.intersection(
- set(we_have_the_feature))
-
- # The only valid candidates are the ones in candidate_set.
- # Go through the original list of candidates and pick the first one
- # that's in candidate_set.
- if candidate_set is None:
- return None
- for candidate in candidates:
- if candidate in candidate_set:
- return candidate
- return None
-
-# The BeautifulSoup class will take feature lists from developers and use them
-# to look up builders in this registry.
-builder_registry = TreeBuilderRegistry()
-
-class TreeBuilder(object):
- """Turn a document into a Beautiful Soup object tree."""
-
- features = []
-
- is_xml = False
- preserve_whitespace_tags = set()
- empty_element_tags = None # A tag will be considered an empty-element
- # tag when and only when it has no contents.
-
- # A value for these tag/attribute combinations is a space- or
- # comma-separated list of CDATA, rather than a single CDATA.
- cdata_list_attributes = {}
-
-
- def __init__(self):
- self.soup = None
-
- def reset(self):
- pass
-
- def can_be_empty_element(self, tag_name):
- """Might a tag with this name be an empty-element tag?
-
- The final markup may or may not actually present this tag as
- self-closing.
-
- For instance: an HTMLBuilder does not consider a tag to be
- an empty-element tag (it's not in
- HTMLBuilder.empty_element_tags). This means an empty
tag
- will be presented as "
", not "
".
-
- The default implementation has no opinion about which tags are
- empty-element tags, so a tag will be presented as an
- empty-element tag if and only if it has no contents.
- " " will become " ", and "bar " will
- be left alone.
- """
- if self.empty_element_tags is None:
- return True
- return tag_name in self.empty_element_tags
-
- def feed(self, markup):
- raise NotImplementedError()
-
- def prepare_markup(self, markup, user_specified_encoding=None,
- document_declared_encoding=None):
- return markup, None, None, False
-
- def test_fragment_to_document(self, fragment):
- """Wrap an HTML fragment to make it look like a document.
-
- Different parsers do this differently. For instance, lxml
- introduces an empty tag, and html5lib
- doesn't. Abstracting this away lets us write simple tests
- which run HTML fragments through the parser and compare the
- results against other HTML fragments.
-
- This method should not be used outside of tests.
- """
- return fragment
-
- def set_up_substitutions(self, tag):
- return False
-
- def _replace_cdata_list_attribute_values(self, tag_name, attrs):
- """Replaces class="foo bar" with class=["foo", "bar"]
-
- Modifies its input in place.
- """
- if not attrs:
- return attrs
- if self.cdata_list_attributes:
- universal = self.cdata_list_attributes.get('*', [])
- tag_specific = self.cdata_list_attributes.get(
- tag_name.lower(), None)
- for attr in attrs.keys():
- if attr in universal or (tag_specific and attr in tag_specific):
- # We have a "class"-type attribute whose string
- # value is a whitespace-separated list of
- # values. Split it into a list.
- value = attrs[attr]
- if isinstance(value, basestring):
- values = whitespace_re.split(value)
- else:
- # html5lib sometimes calls setAttributes twice
- # for the same tag when rearranging the parse
- # tree. On the second call the attribute value
- # here is already a list. If this happens,
- # leave the value alone rather than trying to
- # split it again.
- values = value
- attrs[attr] = values
- return attrs
-
-class SAXTreeBuilder(TreeBuilder):
- """A Beautiful Soup treebuilder that listens for SAX events."""
-
- def feed(self, markup):
- raise NotImplementedError()
-
- def close(self):
- pass
-
- def startElement(self, name, attrs):
- attrs = dict((key[1], value) for key, value in list(attrs.items()))
- #print "Start %s, %r" % (name, attrs)
- self.soup.handle_starttag(name, attrs)
-
- def endElement(self, name):
- #print "End %s" % name
- self.soup.handle_endtag(name)
-
- def startElementNS(self, nsTuple, nodeName, attrs):
- # Throw away (ns, nodeName) for now.
- self.startElement(nodeName, attrs)
-
- def endElementNS(self, nsTuple, nodeName):
- # Throw away (ns, nodeName) for now.
- self.endElement(nodeName)
- #handler.endElementNS((ns, node.nodeName), node.nodeName)
-
- def startPrefixMapping(self, prefix, nodeValue):
- # Ignore the prefix for now.
- pass
-
- def endPrefixMapping(self, prefix):
- # Ignore the prefix for now.
- # handler.endPrefixMapping(prefix)
- pass
-
- def characters(self, content):
- self.soup.handle_data(content)
-
- def startDocument(self):
- pass
-
- def endDocument(self):
- pass
-
-
-class HTMLTreeBuilder(TreeBuilder):
- """This TreeBuilder knows facts about HTML.
-
- Such as which tags are empty-element tags.
- """
-
- preserve_whitespace_tags = set(['pre', 'textarea'])
- empty_element_tags = set(['br' , 'hr', 'input', 'img', 'meta',
- 'spacer', 'link', 'frame', 'base'])
-
- # The HTML standard defines these attributes as containing a
- # space-separated list of values, not a single value. That is,
- # class="foo bar" means that the 'class' attribute has two values,
- # 'foo' and 'bar', not the single value 'foo bar'. When we
- # encounter one of these attributes, we will parse its value into
- # a list of values if possible. Upon output, the list will be
- # converted back into a string.
- cdata_list_attributes = {
- "*" : ['class', 'accesskey', 'dropzone'],
- "a" : ['rel', 'rev'],
- "link" : ['rel', 'rev'],
- "td" : ["headers"],
- "th" : ["headers"],
- "td" : ["headers"],
- "form" : ["accept-charset"],
- "object" : ["archive"],
-
- # These are HTML5 specific, as are *.accesskey and *.dropzone above.
- "area" : ["rel"],
- "icon" : ["sizes"],
- "iframe" : ["sandbox"],
- "output" : ["for"],
- }
-
- def set_up_substitutions(self, tag):
- # We are only interested in tags
- if tag.name != 'meta':
- return False
-
- http_equiv = tag.get('http-equiv')
- content = tag.get('content')
- charset = tag.get('charset')
-
- # We are interested in tags that say what encoding the
- # document was originally in. This means HTML 5-style
- # tags that provide the "charset" attribute. It also means
- # HTML 4-style tags that provide the "content"
- # attribute and have "http-equiv" set to "content-type".
- #
- # In both cases we will replace the value of the appropriate
- # attribute with a standin object that can take on any
- # encoding.
- meta_encoding = None
- if charset is not None:
- # HTML 5 style:
- #
- meta_encoding = charset
- tag['charset'] = CharsetMetaAttributeValue(charset)
-
- elif (content is not None and http_equiv is not None
- and http_equiv.lower() == 'content-type'):
- # HTML 4 style:
- #
- tag['content'] = ContentMetaAttributeValue(content)
-
- return (meta_encoding is not None)
-
-def register_treebuilders_from(module):
- """Copy TreeBuilders from the given module into this module."""
- # I'm fairly sure this is not the best way to do this.
- this_module = sys.modules['bs4.builder']
- for name in module.__all__:
- obj = getattr(module, name)
-
- if issubclass(obj, TreeBuilder):
- setattr(this_module, name, obj)
- this_module.__all__.append(name)
- # Register the builder while we're at it.
- this_module.builder_registry.register(obj)
-
-class ParserRejectedMarkup(Exception):
- pass
-
-# Builders are registered in reverse order of priority, so that custom
-# builder registrations will take precedence. In general, we want lxml
-# to take precedence over html5lib, because it's faster. And we only
-# want to use HTMLParser as a last result.
-from . import _htmlparser
-register_treebuilders_from(_htmlparser)
-try:
- from . import _html5lib
- register_treebuilders_from(_html5lib)
-except ImportError:
- # They don't have html5lib installed.
- pass
-try:
- from . import _lxml
- register_treebuilders_from(_lxml)
-except ImportError:
- # They don't have lxml installed.
- pass
diff --git a/PythonHome/thirdparty/bs4/builder/_html5lib.py b/PythonHome/thirdparty/bs4/builder/_html5lib.py
deleted file mode 100644
index 7de36ae75..000000000
--- a/PythonHome/thirdparty/bs4/builder/_html5lib.py
+++ /dev/null
@@ -1,285 +0,0 @@
-__all__ = [
- 'HTML5TreeBuilder',
- ]
-
-import warnings
-from bs4.builder import (
- PERMISSIVE,
- HTML,
- HTML_5,
- HTMLTreeBuilder,
- )
-from bs4.element import NamespacedAttribute
-import html5lib
-from html5lib.constants import namespaces
-from bs4.element import (
- Comment,
- Doctype,
- NavigableString,
- Tag,
- )
-
-class HTML5TreeBuilder(HTMLTreeBuilder):
- """Use html5lib to build a tree."""
-
- features = ['html5lib', PERMISSIVE, HTML_5, HTML]
-
- def prepare_markup(self, markup, user_specified_encoding):
- # Store the user-specified encoding for use later on.
- self.user_specified_encoding = user_specified_encoding
- yield (markup, None, None, False)
-
- # These methods are defined by Beautiful Soup.
- def feed(self, markup):
- if self.soup.parse_only is not None:
- warnings.warn("You provided a value for parse_only, but the html5lib tree builder doesn't support parse_only. The entire document will be parsed.")
- parser = html5lib.HTMLParser(tree=self.create_treebuilder)
- doc = parser.parse(markup, encoding=self.user_specified_encoding)
-
- # Set the character encoding detected by the tokenizer.
- if isinstance(markup, unicode):
- # We need to special-case this because html5lib sets
- # charEncoding to UTF-8 if it gets Unicode input.
- doc.original_encoding = None
- else:
- doc.original_encoding = parser.tokenizer.stream.charEncoding[0]
-
- def create_treebuilder(self, namespaceHTMLElements):
- self.underlying_builder = TreeBuilderForHtml5lib(
- self.soup, namespaceHTMLElements)
- return self.underlying_builder
-
- def test_fragment_to_document(self, fragment):
- """See `TreeBuilder`."""
- return u'%s' % fragment
-
-
-class TreeBuilderForHtml5lib(html5lib.treebuilders._base.TreeBuilder):
-
- def __init__(self, soup, namespaceHTMLElements):
- self.soup = soup
- super(TreeBuilderForHtml5lib, self).__init__(namespaceHTMLElements)
-
- def documentClass(self):
- self.soup.reset()
- return Element(self.soup, self.soup, None)
-
- def insertDoctype(self, token):
- name = token["name"]
- publicId = token["publicId"]
- systemId = token["systemId"]
-
- doctype = Doctype.for_name_and_ids(name, publicId, systemId)
- self.soup.object_was_parsed(doctype)
-
- def elementClass(self, name, namespace):
- tag = self.soup.new_tag(name, namespace)
- return Element(tag, self.soup, namespace)
-
- def commentClass(self, data):
- return TextNode(Comment(data), self.soup)
-
- def fragmentClass(self):
- self.soup = BeautifulSoup("")
- self.soup.name = "[document_fragment]"
- return Element(self.soup, self.soup, None)
-
- def appendChild(self, node):
- # XXX This code is not covered by the BS4 tests.
- self.soup.append(node.element)
-
- def getDocument(self):
- return self.soup
-
- def getFragment(self):
- return html5lib.treebuilders._base.TreeBuilder.getFragment(self).element
-
-class AttrList(object):
- def __init__(self, element):
- self.element = element
- self.attrs = dict(self.element.attrs)
- def __iter__(self):
- return list(self.attrs.items()).__iter__()
- def __setitem__(self, name, value):
- "set attr", name, value
- self.element[name] = value
- def items(self):
- return list(self.attrs.items())
- def keys(self):
- return list(self.attrs.keys())
- def __len__(self):
- return len(self.attrs)
- def __getitem__(self, name):
- return self.attrs[name]
- def __contains__(self, name):
- return name in list(self.attrs.keys())
-
-
-class Element(html5lib.treebuilders._base.Node):
- def __init__(self, element, soup, namespace):
- html5lib.treebuilders._base.Node.__init__(self, element.name)
- self.element = element
- self.soup = soup
- self.namespace = namespace
-
- def appendChild(self, node):
- string_child = child = None
- if isinstance(node, basestring):
- # Some other piece of code decided to pass in a string
- # instead of creating a TextElement object to contain the
- # string.
- string_child = child = node
- elif isinstance(node, Tag):
- # Some other piece of code decided to pass in a Tag
- # instead of creating an Element object to contain the
- # Tag.
- child = node
- elif node.element.__class__ == NavigableString:
- string_child = child = node.element
- else:
- child = node.element
-
- if not isinstance(child, basestring) and child.parent is not None:
- node.element.extract()
-
- if (string_child and self.element.contents
- and self.element.contents[-1].__class__ == NavigableString):
- # We are appending a string onto another string.
- # TODO This has O(n^2) performance, for input like
- # "aaa..."
- old_element = self.element.contents[-1]
- new_element = self.soup.new_string(old_element + string_child)
- old_element.replace_with(new_element)
- self.soup._most_recent_element = new_element
- else:
- if isinstance(node, basestring):
- # Create a brand new NavigableString from this string.
- child = self.soup.new_string(node)
-
- # Tell Beautiful Soup to act as if it parsed this element
- # immediately after the parent's last descendant. (Or
- # immediately after the parent, if it has no children.)
- if self.element.contents:
- most_recent_element = self.element._last_descendant(False)
- else:
- most_recent_element = self.element
-
- self.soup.object_was_parsed(
- child, parent=self.element,
- most_recent_element=most_recent_element)
-
- def getAttributes(self):
- return AttrList(self.element)
-
- def setAttributes(self, attributes):
- if attributes is not None and len(attributes) > 0:
-
- converted_attributes = []
- for name, value in list(attributes.items()):
- if isinstance(name, tuple):
- new_name = NamespacedAttribute(*name)
- del attributes[name]
- attributes[new_name] = value
-
- self.soup.builder._replace_cdata_list_attribute_values(
- self.name, attributes)
- for name, value in attributes.items():
- self.element[name] = value
-
- # The attributes may contain variables that need substitution.
- # Call set_up_substitutions manually.
- #
- # The Tag constructor called this method when the Tag was created,
- # but we just set/changed the attributes, so call it again.
- self.soup.builder.set_up_substitutions(self.element)
- attributes = property(getAttributes, setAttributes)
-
- def insertText(self, data, insertBefore=None):
- if insertBefore:
- text = TextNode(self.soup.new_string(data), self.soup)
- self.insertBefore(data, insertBefore)
- else:
- self.appendChild(data)
-
- def insertBefore(self, node, refNode):
- index = self.element.index(refNode.element)
- if (node.element.__class__ == NavigableString and self.element.contents
- and self.element.contents[index-1].__class__ == NavigableString):
- # (See comments in appendChild)
- old_node = self.element.contents[index-1]
- new_str = self.soup.new_string(old_node + node.element)
- old_node.replace_with(new_str)
- else:
- self.element.insert(index, node.element)
- node.parent = self
-
- def removeChild(self, node):
- node.element.extract()
-
- def reparentChildren(self, new_parent):
- """Move all of this tag's children into another tag."""
- element = self.element
- new_parent_element = new_parent.element
- # Determine what this tag's next_element will be once all the children
- # are removed.
- final_next_element = element.next_sibling
-
- new_parents_last_descendant = new_parent_element._last_descendant(False, False)
- if len(new_parent_element.contents) > 0:
- # The new parent already contains children. We will be
- # appending this tag's children to the end.
- new_parents_last_child = new_parent_element.contents[-1]
- new_parents_last_descendant_next_element = new_parents_last_descendant.next_element
- else:
- # The new parent contains no children.
- new_parents_last_child = None
- new_parents_last_descendant_next_element = new_parent_element.next_element
-
- to_append = element.contents
- append_after = new_parent.element.contents
- if len(to_append) > 0:
- # Set the first child's previous_element and previous_sibling
- # to elements within the new parent
- first_child = to_append[0]
- first_child.previous_element = new_parents_last_descendant
- first_child.previous_sibling = new_parents_last_child
-
- # Fix the last child's next_element and next_sibling
- last_child = to_append[-1]
- last_child.next_element = new_parents_last_descendant_next_element
- last_child.next_sibling = None
-
- for child in to_append:
- child.parent = new_parent_element
- new_parent_element.contents.append(child)
-
- # Now that this element has no children, change its .next_element.
- element.contents = []
- element.next_element = final_next_element
-
- def cloneNode(self):
- tag = self.soup.new_tag(self.element.name, self.namespace)
- node = Element(tag, self.soup, self.namespace)
- for key,value in self.attributes:
- node.attributes[key] = value
- return node
-
- def hasContent(self):
- return self.element.contents
-
- def getNameTuple(self):
- if self.namespace == None:
- return namespaces["html"], self.name
- else:
- return self.namespace, self.name
-
- nameTuple = property(getNameTuple)
-
-class TextNode(Element):
- def __init__(self, element, soup):
- html5lib.treebuilders._base.Node.__init__(self, None)
- self.element = element
- self.soup = soup
-
- def cloneNode(self):
- raise NotImplementedError
diff --git a/PythonHome/thirdparty/bs4/builder/_htmlparser.py b/PythonHome/thirdparty/bs4/builder/_htmlparser.py
deleted file mode 100644
index ca8d8b892..000000000
--- a/PythonHome/thirdparty/bs4/builder/_htmlparser.py
+++ /dev/null
@@ -1,258 +0,0 @@
-"""Use the HTMLParser library to parse HTML files that aren't too bad."""
-
-__all__ = [
- 'HTMLParserTreeBuilder',
- ]
-
-from HTMLParser import (
- HTMLParser,
- HTMLParseError,
- )
-import sys
-import warnings
-
-# Starting in Python 3.2, the HTMLParser constructor takes a 'strict'
-# argument, which we'd like to set to False. Unfortunately,
-# http://bugs.python.org/issue13273 makes strict=True a better bet
-# before Python 3.2.3.
-#
-# At the end of this file, we monkeypatch HTMLParser so that
-# strict=True works well on Python 3.2.2.
-major, minor, release = sys.version_info[:3]
-CONSTRUCTOR_TAKES_STRICT = (
- major > 3
- or (major == 3 and minor > 2)
- or (major == 3 and minor == 2 and release >= 3))
-
-from bs4.element import (
- CData,
- Comment,
- Declaration,
- Doctype,
- ProcessingInstruction,
- )
-from bs4.dammit import EntitySubstitution, UnicodeDammit
-
-from bs4.builder import (
- HTML,
- HTMLTreeBuilder,
- STRICT,
- )
-
-
-HTMLPARSER = 'html.parser'
-
-class BeautifulSoupHTMLParser(HTMLParser):
- def handle_starttag(self, name, attrs):
- # XXX namespace
- attr_dict = {}
- for key, value in attrs:
- # Change None attribute values to the empty string
- # for consistency with the other tree builders.
- if value is None:
- value = ''
- attr_dict[key] = value
- attrvalue = '""'
- self.soup.handle_starttag(name, None, None, attr_dict)
-
- def handle_endtag(self, name):
- self.soup.handle_endtag(name)
-
- def handle_data(self, data):
- self.soup.handle_data(data)
-
- def handle_charref(self, name):
- # XXX workaround for a bug in HTMLParser. Remove this once
- # it's fixed.
- if name.startswith('x'):
- real_name = int(name.lstrip('x'), 16)
- elif name.startswith('X'):
- real_name = int(name.lstrip('X'), 16)
- else:
- real_name = int(name)
-
- try:
- data = unichr(real_name)
- except (ValueError, OverflowError), e:
- data = u"\N{REPLACEMENT CHARACTER}"
-
- self.handle_data(data)
-
- def handle_entityref(self, name):
- character = EntitySubstitution.HTML_ENTITY_TO_CHARACTER.get(name)
- if character is not None:
- data = character
- else:
- data = "&%s;" % name
- self.handle_data(data)
-
- def handle_comment(self, data):
- self.soup.endData()
- self.soup.handle_data(data)
- self.soup.endData(Comment)
-
- def handle_decl(self, data):
- self.soup.endData()
- if data.startswith("DOCTYPE "):
- data = data[len("DOCTYPE "):]
- elif data == 'DOCTYPE':
- # i.e. ""
- data = ''
- self.soup.handle_data(data)
- self.soup.endData(Doctype)
-
- def unknown_decl(self, data):
- if data.upper().startswith('CDATA['):
- cls = CData
- data = data[len('CDATA['):]
- else:
- cls = Declaration
- self.soup.endData()
- self.soup.handle_data(data)
- self.soup.endData(cls)
-
- def handle_pi(self, data):
- self.soup.endData()
- if data.endswith("?") and data.lower().startswith("xml"):
- # "An XHTML processing instruction using the trailing '?'
- # will cause the '?' to be included in data." - HTMLParser
- # docs.
- #
- # Strip the question mark so we don't end up with two
- # question marks.
- data = data[:-1]
- self.soup.handle_data(data)
- self.soup.endData(ProcessingInstruction)
-
-
-class HTMLParserTreeBuilder(HTMLTreeBuilder):
-
- is_xml = False
- features = [HTML, STRICT, HTMLPARSER]
-
- def __init__(self, *args, **kwargs):
- if CONSTRUCTOR_TAKES_STRICT:
- kwargs['strict'] = False
- self.parser_args = (args, kwargs)
-
- def prepare_markup(self, markup, user_specified_encoding=None,
- document_declared_encoding=None):
- """
- :return: A 4-tuple (markup, original encoding, encoding
- declared within markup, whether any characters had to be
- replaced with REPLACEMENT CHARACTER).
- """
- if isinstance(markup, unicode):
- yield (markup, None, None, False)
- return
-
- try_encodings = [user_specified_encoding, document_declared_encoding]
- dammit = UnicodeDammit(markup, try_encodings, is_html=True)
- yield (dammit.markup, dammit.original_encoding,
- dammit.declared_html_encoding,
- dammit.contains_replacement_characters)
-
- def feed(self, markup):
- args, kwargs = self.parser_args
- parser = BeautifulSoupHTMLParser(*args, **kwargs)
- parser.soup = self.soup
- try:
- parser.feed(markup)
- except HTMLParseError, e:
- warnings.warn(RuntimeWarning(
- "Python's built-in HTMLParser cannot parse the given document. This is not a bug in Beautiful Soup. The best solution is to install an external parser (lxml or html5lib), and use Beautiful Soup with that parser. See http://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-a-parser for help."))
- raise e
-
-# Patch 3.2 versions of HTMLParser earlier than 3.2.3 to use some
-# 3.2.3 code. This ensures they don't treat markup like
as a
-# string.
-#
-# XXX This code can be removed once most Python 3 users are on 3.2.3.
-if major == 3 and minor == 2 and not CONSTRUCTOR_TAKES_STRICT:
- import re
- attrfind_tolerant = re.compile(
- r'\s*((?<=[\'"\s])[^\s/>][^\s/=>]*)(\s*=+\s*'
- r'(\'[^\']*\'|"[^"]*"|(?![\'"])[^>\s]*))?')
- HTMLParserTreeBuilder.attrfind_tolerant = attrfind_tolerant
-
- locatestarttagend = re.compile(r"""
- <[a-zA-Z][-.a-zA-Z0-9:_]* # tag name
- (?:\s+ # whitespace before attribute name
- (?:[a-zA-Z_][-.:a-zA-Z0-9_]* # attribute name
- (?:\s*=\s* # value indicator
- (?:'[^']*' # LITA-enclosed value
- |\"[^\"]*\" # LIT-enclosed value
- |[^'\">\s]+ # bare value
- )
- )?
- )
- )*
- \s* # trailing whitespace
-""", re.VERBOSE)
- BeautifulSoupHTMLParser.locatestarttagend = locatestarttagend
-
- from html.parser import tagfind, attrfind
-
- def parse_starttag(self, i):
- self.__starttag_text = None
- endpos = self.check_for_whole_start_tag(i)
- if endpos < 0:
- return endpos
- rawdata = self.rawdata
- self.__starttag_text = rawdata[i:endpos]
-
- # Now parse the data between i+1 and j into a tag and attrs
- attrs = []
- match = tagfind.match(rawdata, i+1)
- assert match, 'unexpected call to parse_starttag()'
- k = match.end()
- self.lasttag = tag = rawdata[i+1:k].lower()
- while k < endpos:
- if self.strict:
- m = attrfind.match(rawdata, k)
- else:
- m = attrfind_tolerant.match(rawdata, k)
- if not m:
- break
- attrname, rest, attrvalue = m.group(1, 2, 3)
- if not rest:
- attrvalue = None
- elif attrvalue[:1] == '\'' == attrvalue[-1:] or \
- attrvalue[:1] == '"' == attrvalue[-1:]:
- attrvalue = attrvalue[1:-1]
- if attrvalue:
- attrvalue = self.unescape(attrvalue)
- attrs.append((attrname.lower(), attrvalue))
- k = m.end()
-
- end = rawdata[k:endpos].strip()
- if end not in (">", "/>"):
- lineno, offset = self.getpos()
- if "\n" in self.__starttag_text:
- lineno = lineno + self.__starttag_text.count("\n")
- offset = len(self.__starttag_text) \
- - self.__starttag_text.rfind("\n")
- else:
- offset = offset + len(self.__starttag_text)
- if self.strict:
- self.error("junk characters in start tag: %r"
- % (rawdata[k:endpos][:20],))
- self.handle_data(rawdata[i:endpos])
- return endpos
- if end.endswith('/>'):
- # XHTML-style empty tag:
- self.handle_startendtag(tag, attrs)
- else:
- self.handle_starttag(tag, attrs)
- if tag in self.CDATA_CONTENT_ELEMENTS:
- self.set_cdata_mode(tag)
- return endpos
-
- def set_cdata_mode(self, elem):
- self.cdata_elem = elem.lower()
- self.interesting = re.compile(r'\s*%s\s*>' % self.cdata_elem, re.I)
-
- BeautifulSoupHTMLParser.parse_starttag = parse_starttag
- BeautifulSoupHTMLParser.set_cdata_mode = set_cdata_mode
-
- CONSTRUCTOR_TAKES_STRICT = True
diff --git a/PythonHome/thirdparty/bs4/builder/_lxml.py b/PythonHome/thirdparty/bs4/builder/_lxml.py
deleted file mode 100644
index fa5d49875..000000000
--- a/PythonHome/thirdparty/bs4/builder/_lxml.py
+++ /dev/null
@@ -1,233 +0,0 @@
-__all__ = [
- 'LXMLTreeBuilderForXML',
- 'LXMLTreeBuilder',
- ]
-
-from io import BytesIO
-from StringIO import StringIO
-import collections
-from lxml import etree
-from bs4.element import Comment, Doctype, NamespacedAttribute
-from bs4.builder import (
- FAST,
- HTML,
- HTMLTreeBuilder,
- PERMISSIVE,
- ParserRejectedMarkup,
- TreeBuilder,
- XML)
-from bs4.dammit import EncodingDetector
-
-LXML = 'lxml'
-
-class LXMLTreeBuilderForXML(TreeBuilder):
- DEFAULT_PARSER_CLASS = etree.XMLParser
-
- is_xml = True
-
- # Well, it's permissive by XML parser standards.
- features = [LXML, XML, FAST, PERMISSIVE]
-
- CHUNK_SIZE = 512
-
- # This namespace mapping is specified in the XML Namespace
- # standard.
- DEFAULT_NSMAPS = {'http://www.w3.org/XML/1998/namespace' : "xml"}
-
- def default_parser(self, encoding):
- # This can either return a parser object or a class, which
- # will be instantiated with default arguments.
- if self._default_parser is not None:
- return self._default_parser
- return etree.XMLParser(
- target=self, strip_cdata=False, recover=True, encoding=encoding)
-
- def parser_for(self, encoding):
- # Use the default parser.
- parser = self.default_parser(encoding)
-
- if isinstance(parser, collections.Callable):
- # Instantiate the parser with default arguments
- parser = parser(target=self, strip_cdata=False, encoding=encoding)
- return parser
-
- def __init__(self, parser=None, empty_element_tags=None):
- # TODO: Issue a warning if parser is present but not a
- # callable, since that means there's no way to create new
- # parsers for different encodings.
- self._default_parser = parser
- if empty_element_tags is not None:
- self.empty_element_tags = set(empty_element_tags)
- self.soup = None
- self.nsmaps = [self.DEFAULT_NSMAPS]
-
- def _getNsTag(self, tag):
- # Split the namespace URL out of a fully-qualified lxml tag
- # name. Copied from lxml's src/lxml/sax.py.
- if tag[0] == '{':
- return tuple(tag[1:].split('}', 1))
- else:
- return (None, tag)
-
- def prepare_markup(self, markup, user_specified_encoding=None,
- document_declared_encoding=None):
- """
- :yield: A series of 4-tuples.
- (markup, encoding, declared encoding,
- has undergone character replacement)
-
- Each 4-tuple represents a strategy for parsing the document.
- """
- if isinstance(markup, unicode):
- # We were given Unicode. Maybe lxml can parse Unicode on
- # this system?
- yield markup, None, document_declared_encoding, False
-
- if isinstance(markup, unicode):
- # No, apparently not. Convert the Unicode to UTF-8 and
- # tell lxml to parse it as UTF-8.
- yield (markup.encode("utf8"), "utf8",
- document_declared_encoding, False)
-
- # Instead of using UnicodeDammit to convert the bytestring to
- # Unicode using different encodings, use EncodingDetector to
- # iterate over the encodings, and tell lxml to try to parse
- # the document as each one in turn.
- is_html = not self.is_xml
- try_encodings = [user_specified_encoding, document_declared_encoding]
- detector = EncodingDetector(markup, try_encodings, is_html)
- for encoding in detector.encodings:
- yield (detector.markup, encoding, document_declared_encoding, False)
-
- def feed(self, markup):
- if isinstance(markup, bytes):
- markup = BytesIO(markup)
- elif isinstance(markup, unicode):
- markup = StringIO(markup)
-
- # Call feed() at least once, even if the markup is empty,
- # or the parser won't be initialized.
- data = markup.read(self.CHUNK_SIZE)
- try:
- self.parser = self.parser_for(self.soup.original_encoding)
- self.parser.feed(data)
- while len(data) != 0:
- # Now call feed() on the rest of the data, chunk by chunk.
- data = markup.read(self.CHUNK_SIZE)
- if len(data) != 0:
- self.parser.feed(data)
- self.parser.close()
- except (UnicodeDecodeError, LookupError, etree.ParserError), e:
- raise ParserRejectedMarkup(str(e))
-
- def close(self):
- self.nsmaps = [self.DEFAULT_NSMAPS]
-
- def start(self, name, attrs, nsmap={}):
- # Make sure attrs is a mutable dict--lxml may send an immutable dictproxy.
- attrs = dict(attrs)
- nsprefix = None
- # Invert each namespace map as it comes in.
- if len(self.nsmaps) > 1:
- # There are no new namespaces for this tag, but
- # non-default namespaces are in play, so we need a
- # separate tag stack to know when they end.
- self.nsmaps.append(None)
- elif len(nsmap) > 0:
- # A new namespace mapping has come into play.
- inverted_nsmap = dict((value, key) for key, value in nsmap.items())
- self.nsmaps.append(inverted_nsmap)
- # Also treat the namespace mapping as a set of attributes on the
- # tag, so we can recreate it later.
- attrs = attrs.copy()
- for prefix, namespace in nsmap.items():
- attribute = NamespacedAttribute(
- "xmlns", prefix, "http://www.w3.org/2000/xmlns/")
- attrs[attribute] = namespace
-
- # Namespaces are in play. Find any attributes that came in
- # from lxml with namespaces attached to their names, and
- # turn then into NamespacedAttribute objects.
- new_attrs = {}
- for attr, value in attrs.items():
- namespace, attr = self._getNsTag(attr)
- if namespace is None:
- new_attrs[attr] = value
- else:
- nsprefix = self._prefix_for_namespace(namespace)
- attr = NamespacedAttribute(nsprefix, attr, namespace)
- new_attrs[attr] = value
- attrs = new_attrs
-
- namespace, name = self._getNsTag(name)
- nsprefix = self._prefix_for_namespace(namespace)
- self.soup.handle_starttag(name, namespace, nsprefix, attrs)
-
- def _prefix_for_namespace(self, namespace):
- """Find the currently active prefix for the given namespace."""
- if namespace is None:
- return None
- for inverted_nsmap in reversed(self.nsmaps):
- if inverted_nsmap is not None and namespace in inverted_nsmap:
- return inverted_nsmap[namespace]
- return None
-
- def end(self, name):
- self.soup.endData()
- completed_tag = self.soup.tagStack[-1]
- namespace, name = self._getNsTag(name)
- nsprefix = None
- if namespace is not None:
- for inverted_nsmap in reversed(self.nsmaps):
- if inverted_nsmap is not None and namespace in inverted_nsmap:
- nsprefix = inverted_nsmap[namespace]
- break
- self.soup.handle_endtag(name, nsprefix)
- if len(self.nsmaps) > 1:
- # This tag, or one of its parents, introduced a namespace
- # mapping, so pop it off the stack.
- self.nsmaps.pop()
-
- def pi(self, target, data):
- pass
-
- def data(self, content):
- self.soup.handle_data(content)
-
- def doctype(self, name, pubid, system):
- self.soup.endData()
- doctype = Doctype.for_name_and_ids(name, pubid, system)
- self.soup.object_was_parsed(doctype)
-
- def comment(self, content):
- "Handle comments as Comment objects."
- self.soup.endData()
- self.soup.handle_data(content)
- self.soup.endData(Comment)
-
- def test_fragment_to_document(self, fragment):
- """See `TreeBuilder`."""
- return u'\n%s' % fragment
-
-
-class LXMLTreeBuilder(HTMLTreeBuilder, LXMLTreeBuilderForXML):
-
- features = [LXML, HTML, FAST, PERMISSIVE]
- is_xml = False
-
- def default_parser(self, encoding):
- return etree.HTMLParser
-
- def feed(self, markup):
- encoding = self.soup.original_encoding
- try:
- self.parser = self.parser_for(encoding)
- self.parser.feed(markup)
- self.parser.close()
- except (UnicodeDecodeError, LookupError, etree.ParserError), e:
- raise ParserRejectedMarkup(str(e))
-
-
- def test_fragment_to_document(self, fragment):
- """See `TreeBuilder`."""
- return u'%s' % fragment
diff --git a/PythonHome/thirdparty/bs4/dammit.py b/PythonHome/thirdparty/bs4/dammit.py
deleted file mode 100644
index 59640b7ce..000000000
--- a/PythonHome/thirdparty/bs4/dammit.py
+++ /dev/null
@@ -1,829 +0,0 @@
-# -*- coding: utf-8 -*-
-"""Beautiful Soup bonus library: Unicode, Dammit
-
-This library converts a bytestream to Unicode through any means
-necessary. It is heavily based on code from Mark Pilgrim's Universal
-Feed Parser. It works best on XML and XML, but it does not rewrite the
-XML or HTML to reflect a new encoding; that's the tree builder's job.
-"""
-
-import codecs
-from htmlentitydefs import codepoint2name
-import re
-import logging
-import string
-
-# Import a library to autodetect character encodings.
-chardet_type = None
-try:
- # First try the fast C implementation.
- # PyPI package: cchardet
- import cchardet
- def chardet_dammit(s):
- return cchardet.detect(s)['encoding']
-except ImportError:
- try:
- # Fall back to the pure Python implementation
- # Debian package: python-chardet
- # PyPI package: chardet
- import chardet
- def chardet_dammit(s):
- return chardet.detect(s)['encoding']
- #import chardet.constants
- #chardet.constants._debug = 1
- except ImportError:
- # No chardet available.
- def chardet_dammit(s):
- return None
-
-# Available from http://cjkpython.i18n.org/.
-try:
- import iconv_codec
-except ImportError:
- pass
-
-xml_encoding_re = re.compile(
- '^<\?.*encoding=[\'"](.*?)[\'"].*\?>'.encode(), re.I)
-html_meta_re = re.compile(
- '<\s*meta[^>]+charset\s*=\s*["\']?([^>]*?)[ /;\'">]'.encode(), re.I)
-
-class EntitySubstitution(object):
-
- """Substitute XML or HTML entities for the corresponding characters."""
-
- def _populate_class_variables():
- lookup = {}
- reverse_lookup = {}
- characters_for_re = []
- for codepoint, name in list(codepoint2name.items()):
- character = unichr(codepoint)
- if codepoint != 34:
- # There's no point in turning the quotation mark into
- # ", unless it happens within an attribute value, which
- # is handled elsewhere.
- characters_for_re.append(character)
- lookup[character] = name
- # But we do want to turn " into the quotation mark.
- reverse_lookup[name] = character
- re_definition = "[%s]" % "".join(characters_for_re)
- return lookup, reverse_lookup, re.compile(re_definition)
- (CHARACTER_TO_HTML_ENTITY, HTML_ENTITY_TO_CHARACTER,
- CHARACTER_TO_HTML_ENTITY_RE) = _populate_class_variables()
-
- CHARACTER_TO_XML_ENTITY = {
- "'": "apos",
- '"': "quot",
- "&": "amp",
- "<": "lt",
- ">": "gt",
- }
-
- BARE_AMPERSAND_OR_BRACKET = re.compile("([<>]|"
- "&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)"
- ")")
-
- AMPERSAND_OR_BRACKET = re.compile("([<>&])")
-
- @classmethod
- def _substitute_html_entity(cls, matchobj):
- entity = cls.CHARACTER_TO_HTML_ENTITY.get(matchobj.group(0))
- return "&%s;" % entity
-
- @classmethod
- def _substitute_xml_entity(cls, matchobj):
- """Used with a regular expression to substitute the
- appropriate XML entity for an XML special character."""
- entity = cls.CHARACTER_TO_XML_ENTITY[matchobj.group(0)]
- return "&%s;" % entity
-
- @classmethod
- def quoted_attribute_value(self, value):
- """Make a value into a quoted XML attribute, possibly escaping it.
-
- Most strings will be quoted using double quotes.
-
- Bob's Bar -> "Bob's Bar"
-
- If a string contains double quotes, it will be quoted using
- single quotes.
-
- Welcome to "my bar" -> 'Welcome to "my bar"'
-
- If a string contains both single and double quotes, the
- double quotes will be escaped, and the string will be quoted
- using double quotes.
-
- Welcome to "Bob's Bar" -> "Welcome to "Bob's bar"
- """
- quote_with = '"'
- if '"' in value:
- if "'" in value:
- # The string contains both single and double
- # quotes. Turn the double quotes into
- # entities. We quote the double quotes rather than
- # the single quotes because the entity name is
- # """ whether this is HTML or XML. If we
- # quoted the single quotes, we'd have to decide
- # between ' and &squot;.
- replace_with = """
- value = value.replace('"', replace_with)
- else:
- # There are double quotes but no single quotes.
- # We can use single quotes to quote the attribute.
- quote_with = "'"
- return quote_with + value + quote_with
-
- @classmethod
- def substitute_xml(cls, value, make_quoted_attribute=False):
- """Substitute XML entities for special XML characters.
-
- :param value: A string to be substituted. The less-than sign
- will become <, the greater-than sign will become >,
- and any ampersands will become &. If you want ampersands
- that appear to be part of an entity definition to be left
- alone, use substitute_xml_containing_entities() instead.
-
- :param make_quoted_attribute: If True, then the string will be
- quoted, as befits an attribute value.
- """
- # Escape angle brackets and ampersands.
- value = cls.AMPERSAND_OR_BRACKET.sub(
- cls._substitute_xml_entity, value)
-
- if make_quoted_attribute:
- value = cls.quoted_attribute_value(value)
- return value
-
- @classmethod
- def substitute_xml_containing_entities(
- cls, value, make_quoted_attribute=False):
- """Substitute XML entities for special XML characters.
-
- :param value: A string to be substituted. The less-than sign will
- become <, the greater-than sign will become >, and any
- ampersands that are not part of an entity defition will
- become &.
-
- :param make_quoted_attribute: If True, then the string will be
- quoted, as befits an attribute value.
- """
- # Escape angle brackets, and ampersands that aren't part of
- # entities.
- value = cls.BARE_AMPERSAND_OR_BRACKET.sub(
- cls._substitute_xml_entity, value)
-
- if make_quoted_attribute:
- value = cls.quoted_attribute_value(value)
- return value
-
- @classmethod
- def substitute_html(cls, s):
- """Replace certain Unicode characters with named HTML entities.
-
- This differs from data.encode(encoding, 'xmlcharrefreplace')
- in that the goal is to make the result more readable (to those
- with ASCII displays) rather than to recover from
- errors. There's absolutely nothing wrong with a UTF-8 string
- containg a LATIN SMALL LETTER E WITH ACUTE, but replacing that
- character with "é" will make it more readable to some
- people.
- """
- return cls.CHARACTER_TO_HTML_ENTITY_RE.sub(
- cls._substitute_html_entity, s)
-
-
-class EncodingDetector:
- """Suggests a number of possible encodings for a bytestring.
-
- Order of precedence:
-
- 1. Encodings you specifically tell EncodingDetector to try first
- (the override_encodings argument to the constructor).
-
- 2. An encoding declared within the bytestring itself, either in an
- XML declaration (if the bytestring is to be interpreted as an XML
- document), or in a tag (if the bytestring is to be
- interpreted as an HTML document.)
-
- 3. An encoding detected through textual analysis by chardet,
- cchardet, or a similar external library.
-
- 4. UTF-8.
-
- 5. Windows-1252.
- """
- def __init__(self, markup, override_encodings=None, is_html=False):
- self.override_encodings = override_encodings or []
- self.chardet_encoding = None
- self.is_html = is_html
- self.declared_encoding = None
-
- # First order of business: strip a byte-order mark.
- self.markup, self.sniffed_encoding = self.strip_byte_order_mark(markup)
-
- def _usable(self, encoding, tried):
- if encoding is not None:
- encoding = encoding.lower()
- if encoding not in tried:
- tried.add(encoding)
- return True
- return False
-
- @property
- def encodings(self):
- """Yield a number of encodings that might work for this markup."""
- tried = set()
- for e in self.override_encodings:
- if self._usable(e, tried):
- yield e
-
- # Did the document originally start with a byte-order mark
- # that indicated its encoding?
- if self._usable(self.sniffed_encoding, tried):
- yield self.sniffed_encoding
-
- # Look within the document for an XML or HTML encoding
- # declaration.
- if self.declared_encoding is None:
- self.declared_encoding = self.find_declared_encoding(
- self.markup, self.is_html)
- if self._usable(self.declared_encoding, tried):
- yield self.declared_encoding
-
- # Use third-party character set detection to guess at the
- # encoding.
- if self.chardet_encoding is None:
- self.chardet_encoding = chardet_dammit(self.markup)
- if self._usable(self.chardet_encoding, tried):
- yield self.chardet_encoding
-
- # As a last-ditch effort, try utf-8 and windows-1252.
- for e in ('utf-8', 'windows-1252'):
- if self._usable(e, tried):
- yield e
-
- @classmethod
- def strip_byte_order_mark(cls, data):
- """If a byte-order mark is present, strip it and return the encoding it implies."""
- encoding = None
- if (len(data) >= 4) and (data[:2] == b'\xfe\xff') \
- and (data[2:4] != '\x00\x00'):
- encoding = 'utf-16be'
- data = data[2:]
- elif (len(data) >= 4) and (data[:2] == b'\xff\xfe') \
- and (data[2:4] != '\x00\x00'):
- encoding = 'utf-16le'
- data = data[2:]
- elif data[:3] == b'\xef\xbb\xbf':
- encoding = 'utf-8'
- data = data[3:]
- elif data[:4] == b'\x00\x00\xfe\xff':
- encoding = 'utf-32be'
- data = data[4:]
- elif data[:4] == b'\xff\xfe\x00\x00':
- encoding = 'utf-32le'
- data = data[4:]
- return data, encoding
-
- @classmethod
- def find_declared_encoding(cls, markup, is_html=False, search_entire_document=False):
- """Given a document, tries to find its declared encoding.
-
- An XML encoding is declared at the beginning of the document.
-
- An HTML encoding is declared in a tag, hopefully near the
- beginning of the document.
- """
- if search_entire_document:
- xml_endpos = html_endpos = len(markup)
- else:
- xml_endpos = 1024
- html_endpos = max(2048, int(len(markup) * 0.05))
-
- declared_encoding = None
- declared_encoding_match = xml_encoding_re.search(markup, endpos=xml_endpos)
- if not declared_encoding_match and is_html:
- declared_encoding_match = html_meta_re.search(markup, endpos=html_endpos)
- if declared_encoding_match is not None:
- declared_encoding = declared_encoding_match.groups()[0].decode(
- 'ascii')
- if declared_encoding:
- return declared_encoding.lower()
- return None
-
-class UnicodeDammit:
- """A class for detecting the encoding of a *ML document and
- converting it to a Unicode string. If the source encoding is
- windows-1252, can replace MS smart quotes with their HTML or XML
- equivalents."""
-
- # This dictionary maps commonly seen values for "charset" in HTML
- # meta tags to the corresponding Python codec names. It only covers
- # values that aren't in Python's aliases and can't be determined
- # by the heuristics in find_codec.
- CHARSET_ALIASES = {"macintosh": "mac-roman",
- "x-sjis": "shift-jis"}
-
- ENCODINGS_WITH_SMART_QUOTES = [
- "windows-1252",
- "iso-8859-1",
- "iso-8859-2",
- ]
-
- def __init__(self, markup, override_encodings=[],
- smart_quotes_to=None, is_html=False):
- self.smart_quotes_to = smart_quotes_to
- self.tried_encodings = []
- self.contains_replacement_characters = False
- self.is_html = is_html
-
- self.detector = EncodingDetector(markup, override_encodings, is_html)
-
- # Short-circuit if the data is in Unicode to begin with.
- if isinstance(markup, unicode) or markup == '':
- self.markup = markup
- self.unicode_markup = unicode(markup)
- self.original_encoding = None
- return
-
- # The encoding detector may have stripped a byte-order mark.
- # Use the stripped markup from this point on.
- self.markup = self.detector.markup
-
- u = None
- for encoding in self.detector.encodings:
- markup = self.detector.markup
- u = self._convert_from(encoding)
- if u is not None:
- break
-
- if not u:
- # None of the encodings worked. As an absolute last resort,
- # try them again with character replacement.
-
- for encoding in self.detector.encodings:
- if encoding != "ascii":
- u = self._convert_from(encoding, "replace")
- if u is not None:
- logging.warning(
- "Some characters could not be decoded, and were "
- "replaced with REPLACEMENT CHARACTER.")
- self.contains_replacement_characters = True
- break
-
- # If none of that worked, we could at this point force it to
- # ASCII, but that would destroy so much data that I think
- # giving up is better.
- self.unicode_markup = u
- if not u:
- self.original_encoding = None
-
- def _sub_ms_char(self, match):
- """Changes a MS smart quote character to an XML or HTML
- entity, or an ASCII character."""
- orig = match.group(1)
- if self.smart_quotes_to == 'ascii':
- sub = self.MS_CHARS_TO_ASCII.get(orig).encode()
- else:
- sub = self.MS_CHARS.get(orig)
- if type(sub) == tuple:
- if self.smart_quotes_to == 'xml':
- sub = ''.encode() + sub[1].encode() + ';'.encode()
- else:
- sub = '&'.encode() + sub[0].encode() + ';'.encode()
- else:
- sub = sub.encode()
- return sub
-
- def _convert_from(self, proposed, errors="strict"):
- proposed = self.find_codec(proposed)
- if not proposed or (proposed, errors) in self.tried_encodings:
- return None
- self.tried_encodings.append((proposed, errors))
- markup = self.markup
- # Convert smart quotes to HTML if coming from an encoding
- # that might have them.
- if (self.smart_quotes_to is not None
- and proposed in self.ENCODINGS_WITH_SMART_QUOTES):
- smart_quotes_re = b"([\x80-\x9f])"
- smart_quotes_compiled = re.compile(smart_quotes_re)
- markup = smart_quotes_compiled.sub(self._sub_ms_char, markup)
-
- try:
- #print "Trying to convert document to %s (errors=%s)" % (
- # proposed, errors)
- u = self._to_unicode(markup, proposed, errors)
- self.markup = u
- self.original_encoding = proposed
- except Exception as e:
- #print "That didn't work!"
- #print e
- return None
- #print "Correct encoding: %s" % proposed
- return self.markup
-
- def _to_unicode(self, data, encoding, errors="strict"):
- '''Given a string and its encoding, decodes the string into Unicode.
- %encoding is a string recognized by encodings.aliases'''
- return unicode(data, encoding, errors)
-
- @property
- def declared_html_encoding(self):
- if not self.is_html:
- return None
- return self.detector.declared_encoding
-
- def find_codec(self, charset):
- value = (self._codec(self.CHARSET_ALIASES.get(charset, charset))
- or (charset and self._codec(charset.replace("-", "")))
- or (charset and self._codec(charset.replace("-", "_")))
- or (charset and charset.lower())
- or charset
- )
- if value:
- return value.lower()
- return None
-
- def _codec(self, charset):
- if not charset:
- return charset
- codec = None
- try:
- codecs.lookup(charset)
- codec = charset
- except (LookupError, ValueError):
- pass
- return codec
-
-
- # A partial mapping of ISO-Latin-1 to HTML entities/XML numeric entities.
- MS_CHARS = {b'\x80': ('euro', '20AC'),
- b'\x81': ' ',
- b'\x82': ('sbquo', '201A'),
- b'\x83': ('fnof', '192'),
- b'\x84': ('bdquo', '201E'),
- b'\x85': ('hellip', '2026'),
- b'\x86': ('dagger', '2020'),
- b'\x87': ('Dagger', '2021'),
- b'\x88': ('circ', '2C6'),
- b'\x89': ('permil', '2030'),
- b'\x8A': ('Scaron', '160'),
- b'\x8B': ('lsaquo', '2039'),
- b'\x8C': ('OElig', '152'),
- b'\x8D': '?',
- b'\x8E': ('#x17D', '17D'),
- b'\x8F': '?',
- b'\x90': '?',
- b'\x91': ('lsquo', '2018'),
- b'\x92': ('rsquo', '2019'),
- b'\x93': ('ldquo', '201C'),
- b'\x94': ('rdquo', '201D'),
- b'\x95': ('bull', '2022'),
- b'\x96': ('ndash', '2013'),
- b'\x97': ('mdash', '2014'),
- b'\x98': ('tilde', '2DC'),
- b'\x99': ('trade', '2122'),
- b'\x9a': ('scaron', '161'),
- b'\x9b': ('rsaquo', '203A'),
- b'\x9c': ('oelig', '153'),
- b'\x9d': '?',
- b'\x9e': ('#x17E', '17E'),
- b'\x9f': ('Yuml', ''),}
-
- # A parochial partial mapping of ISO-Latin-1 to ASCII. Contains
- # horrors like stripping diacritical marks to turn á into a, but also
- # contains non-horrors like turning “ into ".
- MS_CHARS_TO_ASCII = {
- b'\x80' : 'EUR',
- b'\x81' : ' ',
- b'\x82' : ',',
- b'\x83' : 'f',
- b'\x84' : ',,',
- b'\x85' : '...',
- b'\x86' : '+',
- b'\x87' : '++',
- b'\x88' : '^',
- b'\x89' : '%',
- b'\x8a' : 'S',
- b'\x8b' : '<',
- b'\x8c' : 'OE',
- b'\x8d' : '?',
- b'\x8e' : 'Z',
- b'\x8f' : '?',
- b'\x90' : '?',
- b'\x91' : "'",
- b'\x92' : "'",
- b'\x93' : '"',
- b'\x94' : '"',
- b'\x95' : '*',
- b'\x96' : '-',
- b'\x97' : '--',
- b'\x98' : '~',
- b'\x99' : '(TM)',
- b'\x9a' : 's',
- b'\x9b' : '>',
- b'\x9c' : 'oe',
- b'\x9d' : '?',
- b'\x9e' : 'z',
- b'\x9f' : 'Y',
- b'\xa0' : ' ',
- b'\xa1' : '!',
- b'\xa2' : 'c',
- b'\xa3' : 'GBP',
- b'\xa4' : '$', #This approximation is especially parochial--this is the
- #generic currency symbol.
- b'\xa5' : 'YEN',
- b'\xa6' : '|',
- b'\xa7' : 'S',
- b'\xa8' : '..',
- b'\xa9' : '',
- b'\xaa' : '(th)',
- b'\xab' : '<<',
- b'\xac' : '!',
- b'\xad' : ' ',
- b'\xae' : '(R)',
- b'\xaf' : '-',
- b'\xb0' : 'o',
- b'\xb1' : '+-',
- b'\xb2' : '2',
- b'\xb3' : '3',
- b'\xb4' : ("'", 'acute'),
- b'\xb5' : 'u',
- b'\xb6' : 'P',
- b'\xb7' : '*',
- b'\xb8' : ',',
- b'\xb9' : '1',
- b'\xba' : '(th)',
- b'\xbb' : '>>',
- b'\xbc' : '1/4',
- b'\xbd' : '1/2',
- b'\xbe' : '3/4',
- b'\xbf' : '?',
- b'\xc0' : 'A',
- b'\xc1' : 'A',
- b'\xc2' : 'A',
- b'\xc3' : 'A',
- b'\xc4' : 'A',
- b'\xc5' : 'A',
- b'\xc6' : 'AE',
- b'\xc7' : 'C',
- b'\xc8' : 'E',
- b'\xc9' : 'E',
- b'\xca' : 'E',
- b'\xcb' : 'E',
- b'\xcc' : 'I',
- b'\xcd' : 'I',
- b'\xce' : 'I',
- b'\xcf' : 'I',
- b'\xd0' : 'D',
- b'\xd1' : 'N',
- b'\xd2' : 'O',
- b'\xd3' : 'O',
- b'\xd4' : 'O',
- b'\xd5' : 'O',
- b'\xd6' : 'O',
- b'\xd7' : '*',
- b'\xd8' : 'O',
- b'\xd9' : 'U',
- b'\xda' : 'U',
- b'\xdb' : 'U',
- b'\xdc' : 'U',
- b'\xdd' : 'Y',
- b'\xde' : 'b',
- b'\xdf' : 'B',
- b'\xe0' : 'a',
- b'\xe1' : 'a',
- b'\xe2' : 'a',
- b'\xe3' : 'a',
- b'\xe4' : 'a',
- b'\xe5' : 'a',
- b'\xe6' : 'ae',
- b'\xe7' : 'c',
- b'\xe8' : 'e',
- b'\xe9' : 'e',
- b'\xea' : 'e',
- b'\xeb' : 'e',
- b'\xec' : 'i',
- b'\xed' : 'i',
- b'\xee' : 'i',
- b'\xef' : 'i',
- b'\xf0' : 'o',
- b'\xf1' : 'n',
- b'\xf2' : 'o',
- b'\xf3' : 'o',
- b'\xf4' : 'o',
- b'\xf5' : 'o',
- b'\xf6' : 'o',
- b'\xf7' : '/',
- b'\xf8' : 'o',
- b'\xf9' : 'u',
- b'\xfa' : 'u',
- b'\xfb' : 'u',
- b'\xfc' : 'u',
- b'\xfd' : 'y',
- b'\xfe' : 'b',
- b'\xff' : 'y',
- }
-
- # A map used when removing rogue Windows-1252/ISO-8859-1
- # characters in otherwise UTF-8 documents.
- #
- # Note that \x81, \x8d, \x8f, \x90, and \x9d are undefined in
- # Windows-1252.
- WINDOWS_1252_TO_UTF8 = {
- 0x80 : b'\xe2\x82\xac', # €
- 0x82 : b'\xe2\x80\x9a', # ‚
- 0x83 : b'\xc6\x92', # ƒ
- 0x84 : b'\xe2\x80\x9e', # „
- 0x85 : b'\xe2\x80\xa6', # …
- 0x86 : b'\xe2\x80\xa0', # †
- 0x87 : b'\xe2\x80\xa1', # ‡
- 0x88 : b'\xcb\x86', # ˆ
- 0x89 : b'\xe2\x80\xb0', # ‰
- 0x8a : b'\xc5\xa0', # Š
- 0x8b : b'\xe2\x80\xb9', # ‹
- 0x8c : b'\xc5\x92', # Œ
- 0x8e : b'\xc5\xbd', # Ž
- 0x91 : b'\xe2\x80\x98', # ‘
- 0x92 : b'\xe2\x80\x99', # ’
- 0x93 : b'\xe2\x80\x9c', # “
- 0x94 : b'\xe2\x80\x9d', # ”
- 0x95 : b'\xe2\x80\xa2', # •
- 0x96 : b'\xe2\x80\x93', # –
- 0x97 : b'\xe2\x80\x94', # —
- 0x98 : b'\xcb\x9c', # ˜
- 0x99 : b'\xe2\x84\xa2', # ™
- 0x9a : b'\xc5\xa1', # š
- 0x9b : b'\xe2\x80\xba', # ›
- 0x9c : b'\xc5\x93', # œ
- 0x9e : b'\xc5\xbe', # ž
- 0x9f : b'\xc5\xb8', # Ÿ
- 0xa0 : b'\xc2\xa0', #
- 0xa1 : b'\xc2\xa1', # ¡
- 0xa2 : b'\xc2\xa2', # ¢
- 0xa3 : b'\xc2\xa3', # £
- 0xa4 : b'\xc2\xa4', # ¤
- 0xa5 : b'\xc2\xa5', # ¥
- 0xa6 : b'\xc2\xa6', # ¦
- 0xa7 : b'\xc2\xa7', # §
- 0xa8 : b'\xc2\xa8', # ¨
- 0xa9 : b'\xc2\xa9', # ©
- 0xaa : b'\xc2\xaa', # ª
- 0xab : b'\xc2\xab', # «
- 0xac : b'\xc2\xac', # ¬
- 0xad : b'\xc2\xad', #
- 0xae : b'\xc2\xae', # ®
- 0xaf : b'\xc2\xaf', # ¯
- 0xb0 : b'\xc2\xb0', # °
- 0xb1 : b'\xc2\xb1', # ±
- 0xb2 : b'\xc2\xb2', # ²
- 0xb3 : b'\xc2\xb3', # ³
- 0xb4 : b'\xc2\xb4', # ´
- 0xb5 : b'\xc2\xb5', # µ
- 0xb6 : b'\xc2\xb6', # ¶
- 0xb7 : b'\xc2\xb7', # ·
- 0xb8 : b'\xc2\xb8', # ¸
- 0xb9 : b'\xc2\xb9', # ¹
- 0xba : b'\xc2\xba', # º
- 0xbb : b'\xc2\xbb', # »
- 0xbc : b'\xc2\xbc', # ¼
- 0xbd : b'\xc2\xbd', # ½
- 0xbe : b'\xc2\xbe', # ¾
- 0xbf : b'\xc2\xbf', # ¿
- 0xc0 : b'\xc3\x80', # À
- 0xc1 : b'\xc3\x81', # Á
- 0xc2 : b'\xc3\x82', # Â
- 0xc3 : b'\xc3\x83', # Ã
- 0xc4 : b'\xc3\x84', # Ä
- 0xc5 : b'\xc3\x85', # Å
- 0xc6 : b'\xc3\x86', # Æ
- 0xc7 : b'\xc3\x87', # Ç
- 0xc8 : b'\xc3\x88', # È
- 0xc9 : b'\xc3\x89', # É
- 0xca : b'\xc3\x8a', # Ê
- 0xcb : b'\xc3\x8b', # Ë
- 0xcc : b'\xc3\x8c', # Ì
- 0xcd : b'\xc3\x8d', # Í
- 0xce : b'\xc3\x8e', # Î
- 0xcf : b'\xc3\x8f', # Ï
- 0xd0 : b'\xc3\x90', # Ð
- 0xd1 : b'\xc3\x91', # Ñ
- 0xd2 : b'\xc3\x92', # Ò
- 0xd3 : b'\xc3\x93', # Ó
- 0xd4 : b'\xc3\x94', # Ô
- 0xd5 : b'\xc3\x95', # Õ
- 0xd6 : b'\xc3\x96', # Ö
- 0xd7 : b'\xc3\x97', # ×
- 0xd8 : b'\xc3\x98', # Ø
- 0xd9 : b'\xc3\x99', # Ù
- 0xda : b'\xc3\x9a', # Ú
- 0xdb : b'\xc3\x9b', # Û
- 0xdc : b'\xc3\x9c', # Ü
- 0xdd : b'\xc3\x9d', # Ý
- 0xde : b'\xc3\x9e', # Þ
- 0xdf : b'\xc3\x9f', # ß
- 0xe0 : b'\xc3\xa0', # à
- 0xe1 : b'\xa1', # á
- 0xe2 : b'\xc3\xa2', # â
- 0xe3 : b'\xc3\xa3', # ã
- 0xe4 : b'\xc3\xa4', # ä
- 0xe5 : b'\xc3\xa5', # å
- 0xe6 : b'\xc3\xa6', # æ
- 0xe7 : b'\xc3\xa7', # ç
- 0xe8 : b'\xc3\xa8', # è
- 0xe9 : b'\xc3\xa9', # é
- 0xea : b'\xc3\xaa', # ê
- 0xeb : b'\xc3\xab', # ë
- 0xec : b'\xc3\xac', # ì
- 0xed : b'\xc3\xad', # í
- 0xee : b'\xc3\xae', # î
- 0xef : b'\xc3\xaf', # ï
- 0xf0 : b'\xc3\xb0', # ð
- 0xf1 : b'\xc3\xb1', # ñ
- 0xf2 : b'\xc3\xb2', # ò
- 0xf3 : b'\xc3\xb3', # ó
- 0xf4 : b'\xc3\xb4', # ô
- 0xf5 : b'\xc3\xb5', # õ
- 0xf6 : b'\xc3\xb6', # ö
- 0xf7 : b'\xc3\xb7', # ÷
- 0xf8 : b'\xc3\xb8', # ø
- 0xf9 : b'\xc3\xb9', # ù
- 0xfa : b'\xc3\xba', # ú
- 0xfb : b'\xc3\xbb', # û
- 0xfc : b'\xc3\xbc', # ü
- 0xfd : b'\xc3\xbd', # ý
- 0xfe : b'\xc3\xbe', # þ
- }
-
- MULTIBYTE_MARKERS_AND_SIZES = [
- (0xc2, 0xdf, 2), # 2-byte characters start with a byte C2-DF
- (0xe0, 0xef, 3), # 3-byte characters start with E0-EF
- (0xf0, 0xf4, 4), # 4-byte characters start with F0-F4
- ]
-
- FIRST_MULTIBYTE_MARKER = MULTIBYTE_MARKERS_AND_SIZES[0][0]
- LAST_MULTIBYTE_MARKER = MULTIBYTE_MARKERS_AND_SIZES[-1][1]
-
- @classmethod
- def detwingle(cls, in_bytes, main_encoding="utf8",
- embedded_encoding="windows-1252"):
- """Fix characters from one encoding embedded in some other encoding.
-
- Currently the only situation supported is Windows-1252 (or its
- subset ISO-8859-1), embedded in UTF-8.
-
- The input must be a bytestring. If you've already converted
- the document to Unicode, you're too late.
-
- The output is a bytestring in which `embedded_encoding`
- characters have been converted to their `main_encoding`
- equivalents.
- """
- if embedded_encoding.replace('_', '-').lower() not in (
- 'windows-1252', 'windows_1252'):
- raise NotImplementedError(
- "Windows-1252 and ISO-8859-1 are the only currently supported "
- "embedded encodings.")
-
- if main_encoding.lower() not in ('utf8', 'utf-8'):
- raise NotImplementedError(
- "UTF-8 is the only currently supported main encoding.")
-
- byte_chunks = []
-
- chunk_start = 0
- pos = 0
- while pos < len(in_bytes):
- byte = in_bytes[pos]
- if not isinstance(byte, int):
- # Python 2.x
- byte = ord(byte)
- if (byte >= cls.FIRST_MULTIBYTE_MARKER
- and byte <= cls.LAST_MULTIBYTE_MARKER):
- # This is the start of a UTF-8 multibyte character. Skip
- # to the end.
- for start, end, size in cls.MULTIBYTE_MARKERS_AND_SIZES:
- if byte >= start and byte <= end:
- pos += size
- break
- elif byte >= 0x80 and byte in cls.WINDOWS_1252_TO_UTF8:
- # We found a Windows-1252 character!
- # Save the string up to this point as a chunk.
- byte_chunks.append(in_bytes[chunk_start:pos])
-
- # Now translate the Windows-1252 character into UTF-8
- # and add it as another, one-byte chunk.
- byte_chunks.append(cls.WINDOWS_1252_TO_UTF8[byte])
- pos += 1
- chunk_start = pos
- else:
- # Go on to the next character.
- pos += 1
- if chunk_start == 0:
- # The string is unchanged.
- return in_bytes
- else:
- # Store the final chunk.
- byte_chunks.append(in_bytes[chunk_start:])
- return b''.join(byte_chunks)
-
diff --git a/PythonHome/thirdparty/bs4/diagnose.py b/PythonHome/thirdparty/bs4/diagnose.py
deleted file mode 100644
index 4d0b00afa..000000000
--- a/PythonHome/thirdparty/bs4/diagnose.py
+++ /dev/null
@@ -1,204 +0,0 @@
-"""Diagnostic functions, mainly for use when doing tech support."""
-import cProfile
-from StringIO import StringIO
-from HTMLParser import HTMLParser
-import bs4
-from bs4 import BeautifulSoup, __version__
-from bs4.builder import builder_registry
-
-import os
-import pstats
-import random
-import tempfile
-import time
-import traceback
-import sys
-import cProfile
-
-def diagnose(data):
- """Diagnostic suite for isolating common problems."""
- print "Diagnostic running on Beautiful Soup %s" % __version__
- print "Python version %s" % sys.version
-
- basic_parsers = ["html.parser", "html5lib", "lxml"]
- for name in basic_parsers:
- for builder in builder_registry.builders:
- if name in builder.features:
- break
- else:
- basic_parsers.remove(name)
- print (
- "I noticed that %s is not installed. Installing it may help." %
- name)
-
- if 'lxml' in basic_parsers:
- basic_parsers.append(["lxml", "xml"])
- from lxml import etree
- print "Found lxml version %s" % ".".join(map(str,etree.LXML_VERSION))
-
- if 'html5lib' in basic_parsers:
- import html5lib
- print "Found html5lib version %s" % html5lib.__version__
-
- if hasattr(data, 'read'):
- data = data.read()
- elif os.path.exists(data):
- print '"%s" looks like a filename. Reading data from the file.' % data
- data = open(data).read()
- elif data.startswith("http:") or data.startswith("https:"):
- print '"%s" looks like a URL. Beautiful Soup is not an HTTP client.' % data
- print "You need to use some other library to get the document behind the URL, and feed that document to Beautiful Soup."
- return
- print
-
- for parser in basic_parsers:
- print "Trying to parse your markup with %s" % parser
- success = False
- try:
- soup = BeautifulSoup(data, parser)
- success = True
- except Exception, e:
- print "%s could not parse the markup." % parser
- traceback.print_exc()
- if success:
- print "Here's what %s did with the markup:" % parser
- print soup.prettify()
-
- print "-" * 80
-
-def lxml_trace(data, html=True, **kwargs):
- """Print out the lxml events that occur during parsing.
-
- This lets you see how lxml parses a document when no Beautiful
- Soup code is running.
- """
- from lxml import etree
- for event, element in etree.iterparse(StringIO(data), html=html, **kwargs):
- print("%s, %4s, %s" % (event, element.tag, element.text))
-
-class AnnouncingParser(HTMLParser):
- """Announces HTMLParser parse events, without doing anything else."""
-
- def _p(self, s):
- print(s)
-
- def handle_starttag(self, name, attrs):
- self._p("%s START" % name)
-
- def handle_endtag(self, name):
- self._p("%s END" % name)
-
- def handle_data(self, data):
- self._p("%s DATA" % data)
-
- def handle_charref(self, name):
- self._p("%s CHARREF" % name)
-
- def handle_entityref(self, name):
- self._p("%s ENTITYREF" % name)
-
- def handle_comment(self, data):
- self._p("%s COMMENT" % data)
-
- def handle_decl(self, data):
- self._p("%s DECL" % data)
-
- def unknown_decl(self, data):
- self._p("%s UNKNOWN-DECL" % data)
-
- def handle_pi(self, data):
- self._p("%s PI" % data)
-
-def htmlparser_trace(data):
- """Print out the HTMLParser events that occur during parsing.
-
- This lets you see how HTMLParser parses a document when no
- Beautiful Soup code is running.
- """
- parser = AnnouncingParser()
- parser.feed(data)
-
-_vowels = "aeiou"
-_consonants = "bcdfghjklmnpqrstvwxyz"
-
-def rword(length=5):
- "Generate a random word-like string."
- s = ''
- for i in range(length):
- if i % 2 == 0:
- t = _consonants
- else:
- t = _vowels
- s += random.choice(t)
- return s
-
-def rsentence(length=4):
- "Generate a random sentence-like string."
- return " ".join(rword(random.randint(4,9)) for i in range(length))
-
-def rdoc(num_elements=1000):
- """Randomly generate an invalid HTML document."""
- tag_names = ['p', 'div', 'span', 'i', 'b', 'script', 'table']
- elements = []
- for i in range(num_elements):
- choice = random.randint(0,3)
- if choice == 0:
- # New tag.
- tag_name = random.choice(tag_names)
- elements.append("<%s>" % tag_name)
- elif choice == 1:
- elements.append(rsentence(random.randint(1,4)))
- elif choice == 2:
- # Close a tag.
- tag_name = random.choice(tag_names)
- elements.append("%s>" % tag_name)
- return "" + "\n".join(elements) + ""
-
-def benchmark_parsers(num_elements=100000):
- """Very basic head-to-head performance benchmark."""
- print "Comparative parser benchmark on Beautiful Soup %s" % __version__
- data = rdoc(num_elements)
- print "Generated a large invalid HTML document (%d bytes)." % len(data)
-
- for parser in ["lxml", ["lxml", "html"], "html5lib", "html.parser"]:
- success = False
- try:
- a = time.time()
- soup = BeautifulSoup(data, parser)
- b = time.time()
- success = True
- except Exception, e:
- print "%s could not parse the markup." % parser
- traceback.print_exc()
- if success:
- print "BS4+%s parsed the markup in %.2fs." % (parser, b-a)
-
- from lxml import etree
- a = time.time()
- etree.HTML(data)
- b = time.time()
- print "Raw lxml parsed the markup in %.2fs." % (b-a)
-
- import html5lib
- parser = html5lib.HTMLParser()
- a = time.time()
- parser.parse(data)
- b = time.time()
- print "Raw html5lib parsed the markup in %.2fs." % (b-a)
-
-def profile(num_elements=100000, parser="lxml"):
-
- filehandle = tempfile.NamedTemporaryFile()
- filename = filehandle.name
-
- data = rdoc(num_elements)
- vars = dict(bs4=bs4, data=data, parser=parser)
- cProfile.runctx('bs4.BeautifulSoup(data, parser)' , vars, vars, filename)
-
- stats = pstats.Stats(filename)
- # stats.strip_dirs()
- stats.sort_stats("cumulative")
- stats.print_stats('_html5lib|bs4', 50)
-
-if __name__ == '__main__':
- diagnose(sys.stdin.read())
diff --git a/PythonHome/thirdparty/bs4/element.py b/PythonHome/thirdparty/bs4/element.py
deleted file mode 100644
index da9afdf48..000000000
--- a/PythonHome/thirdparty/bs4/element.py
+++ /dev/null
@@ -1,1611 +0,0 @@
-import collections
-import re
-import sys
-import warnings
-from bs4.dammit import EntitySubstitution
-
-DEFAULT_OUTPUT_ENCODING = "utf-8"
-PY3K = (sys.version_info[0] > 2)
-
-whitespace_re = re.compile("\s+")
-
-def _alias(attr):
- """Alias one attribute name to another for backward compatibility"""
- @property
- def alias(self):
- return getattr(self, attr)
-
- @alias.setter
- def alias(self):
- return setattr(self, attr)
- return alias
-
-
-class NamespacedAttribute(unicode):
-
- def __new__(cls, prefix, name, namespace=None):
- if name is None:
- obj = unicode.__new__(cls, prefix)
- elif prefix is None:
- # Not really namespaced.
- obj = unicode.__new__(cls, name)
- else:
- obj = unicode.__new__(cls, prefix + ":" + name)
- obj.prefix = prefix
- obj.name = name
- obj.namespace = namespace
- return obj
-
-class AttributeValueWithCharsetSubstitution(unicode):
- """A stand-in object for a character encoding specified in HTML."""
-
-class CharsetMetaAttributeValue(AttributeValueWithCharsetSubstitution):
- """A generic stand-in for the value of a meta tag's 'charset' attribute.
-
- When Beautiful Soup parses the markup ' ', the
- value of the 'charset' attribute will be one of these objects.
- """
-
- def __new__(cls, original_value):
- obj = unicode.__new__(cls, original_value)
- obj.original_value = original_value
- return obj
-
- def encode(self, encoding):
- return encoding
-
-
-class ContentMetaAttributeValue(AttributeValueWithCharsetSubstitution):
- """A generic stand-in for the value of a meta tag's 'content' attribute.
-
- When Beautiful Soup parses the markup:
-
-
- The value of the 'content' attribute will be one of these objects.
- """
-
- CHARSET_RE = re.compile("((^|;)\s*charset=)([^;]*)", re.M)
-
- def __new__(cls, original_value):
- match = cls.CHARSET_RE.search(original_value)
- if match is None:
- # No substitution necessary.
- return unicode.__new__(unicode, original_value)
-
- obj = unicode.__new__(cls, original_value)
- obj.original_value = original_value
- return obj
-
- def encode(self, encoding):
- def rewrite(match):
- return match.group(1) + encoding
- return self.CHARSET_RE.sub(rewrite, self.original_value)
-
-class HTMLAwareEntitySubstitution(EntitySubstitution):
-
- """Entity substitution rules that are aware of some HTML quirks.
-
- Specifically, the contents of
-"""
- soup = BeautifulSoup(doc, "xml")
- # lxml would have stripped this while parsing, but we can add
- # it later.
- soup.script.string = 'console.log("< < hey > > ");'
- encoded = soup.encode()
- self.assertTrue(b"< < hey > >" in encoded)
-
- def test_can_parse_unicode_document(self):
- markup = u'Sacr\N{LATIN SMALL LETTER E WITH ACUTE} bleu! '
- soup = self.soup(markup)
- self.assertEqual(u'Sacr\xe9 bleu!', soup.root.string)
-
- def test_popping_namespaced_tag(self):
- markup = 'b 2012-07-02T20:33:42Z c d '
- soup = self.soup(markup)
- self.assertEqual(
- unicode(soup.rss), markup)
-
- def test_docstring_includes_correct_encoding(self):
- soup = self.soup(" ")
- self.assertEqual(
- soup.encode("latin1"),
- b'\n ')
-
- def test_large_xml_document(self):
- """A large XML document should come out the same as it went in."""
- markup = (b'\n'
- + b'0' * (2**12)
- + b' ')
- soup = self.soup(markup)
- self.assertEqual(soup.encode("utf-8"), markup)
-
-
- def test_tags_are_empty_element_if_and_only_if_they_are_empty(self):
- self.assertSoupEquals("", "
")
- self.assertSoupEquals("foo
")
-
- def test_namespaces_are_preserved(self):
- markup = 'This tag is in the a namespace This tag is in the b namespace '
- soup = self.soup(markup)
- root = soup.root
- self.assertEqual("http://example.com/", root['xmlns:a'])
- self.assertEqual("http://example.net/", root['xmlns:b'])
-
- def test_closing_namespaced_tag(self):
- markup = '20010504
'
- soup = self.soup(markup)
- self.assertEqual(unicode(soup.p), markup)
-
- def test_namespaced_attributes(self):
- markup = ' '
- soup = self.soup(markup)
- self.assertEqual(unicode(soup.foo), markup)
-
- def test_namespaced_attributes_xml_namespace(self):
- markup = 'bar '
- soup = self.soup(markup)
- self.assertEqual(unicode(soup.foo), markup)
-
-class HTML5TreeBuilderSmokeTest(HTMLTreeBuilderSmokeTest):
- """Smoke test for a tree builder that supports HTML5."""
-
- def test_real_xhtml_document(self):
- # Since XHTML is not HTML5, HTML5 parsers are not tested to handle
- # XHTML documents in any particular way.
- pass
-
- def test_html_tags_have_namespace(self):
- markup = ""
- soup = self.soup(markup)
- self.assertEqual("http://www.w3.org/1999/xhtml", soup.a.namespace)
-
- def test_svg_tags_have_namespace(self):
- markup = ' '
- soup = self.soup(markup)
- namespace = "http://www.w3.org/2000/svg"
- self.assertEqual(namespace, soup.svg.namespace)
- self.assertEqual(namespace, soup.circle.namespace)
-
-
- def test_mathml_tags_have_namespace(self):
- markup = '5 '
- soup = self.soup(markup)
- namespace = 'http://www.w3.org/1998/Math/MathML'
- self.assertEqual(namespace, soup.math.namespace)
- self.assertEqual(namespace, soup.msqrt.namespace)
-
- def test_xml_declaration_becomes_comment(self):
- markup = ''
- soup = self.soup(markup)
- self.assertTrue(isinstance(soup.contents[0], Comment))
- self.assertEqual(soup.contents[0], '?xml version="1.0" encoding="utf-8"?')
- self.assertEqual("html", soup.contents[0].next_element.name)
-
-def skipIf(condition, reason):
- def nothing(test, *args, **kwargs):
- return None
-
- def decorator(test_item):
- if condition:
- return nothing
- else:
- return test_item
-
- return decorator
diff --git a/PythonHome/thirdparty/requests-2.2.1.dist-info/DESCRIPTION.rst b/PythonHome/thirdparty/requests-2.2.1.dist-info/DESCRIPTION.rst
deleted file mode 100644
index 2e2360b0e..000000000
--- a/PythonHome/thirdparty/requests-2.2.1.dist-info/DESCRIPTION.rst
+++ /dev/null
@@ -1,887 +0,0 @@
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-Description: Requests: HTTP for Humans
- =========================
-
- .. image:: https://badge.fury.io/py/requests.png
- :target: http://badge.fury.io/py/requests
-
- .. image:: https://pypip.in/d/requests/badge.png
- :target: https://crate.io/packages/requests/
-
-
- Requests is an Apache2 Licensed HTTP library, written in Python, for human
- beings.
-
- Most existing Python modules for sending HTTP requests are extremely
- verbose and cumbersome. Python's builtin urllib2 module provides most of
- the HTTP capabilities you should need, but the api is thoroughly broken.
- It requires an enormous amount of work (even method overrides) to
- perform the simplest of tasks.
-
- Things shouldn't be this way. Not in Python.
-
- .. code-block:: pycon
-
- >>> r = requests.get('https://api.github.com', auth=('user', 'pass'))
- >>> r.status_code
- 204
- >>> r.headers['content-type']
- 'application/json'
- >>> r.text
- ...
-
- See `the same code, without Requests `_.
-
- Requests allow you to send HTTP/1.1 requests. You can add headers, form data,
- multipart files, and parameters with simple Python dictionaries, and access the
- response data in the same way. It's powered by httplib and `urllib3
- `_, but it does all the hard work and crazy
- hacks for you.
-
-
- Features
- --------
-
- - International Domains and URLs
- - Keep-Alive & Connection Pooling
- - Sessions with Cookie Persistence
- - Browser-style SSL Verification
- - Basic/Digest Authentication
- - Elegant Key/Value Cookies
- - Automatic Decompression
- - Unicode Response Bodies
- - Multipart File Uploads
- - Connection Timeouts
- - Thread-safety
- - HTTP(S) proxy support
-
-
- Installation
- ------------
-
- To install Requests, simply:
-
- .. code-block:: bash
-
- $ pip install requests
-
- Or, if you absolutely must:
-
- .. code-block:: bash
-
- $ easy_install requests
-
- But, you really shouldn't do that.
-
-
- Documentation
- -------------
-
- Documentation is available at http://docs.python-requests.org/.
-
-
- Contribute
- ----------
-
- #. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. There is a `Contributor Friendly`_ tag for issues that should be ideal for people who are not very familiar with the codebase yet.
- #. If you feel uncomfortable or uncertain about an issue or your changes, feel free to email @sigmavirus24 and he will happily help you via email, Skype, remote pairing or whatever you are comfortable with.
- #. Fork `the repository`_ on GitHub to start making your changes to the **master** branch (or branch off of it).
- #. Write a test which shows that the bug was fixed or that the feature works as expected.
- #. Send a pull request and bug the maintainer until it gets merged and published. :) Make sure to add yourself to AUTHORS_.
-
- .. _`the repository`: http://github.com/kennethreitz/requests
- .. _AUTHORS: https://github.com/kennethreitz/requests/blob/master/AUTHORS.rst
- .. _Contributor Friendly: https://github.com/kennethreitz/requests/issues?direction=desc&labels=Contributor+Friendly&page=1&sort=updated&state=open
-
-
- .. :changelog:
-
- Release History
- ---------------
-
- 2.2.1 (2014-01-23)
- ++++++++++++++++++
-
- **Bugfixes**
-
- - Fixes incorrect parsing of proxy credentials that contain a literal or encoded '#' character.
- - Assorted urllib3 fixes.
-
- 2.2.0 (2014-01-09)
- ++++++++++++++++++
-
- **API Changes**
-
- - New exception: ``ContentDecodingError``. Raised instead of ``urllib3``
- ``DecodeError`` exceptions.
-
- **Bugfixes**
-
- - Avoid many many exceptions from the buggy implementation of ``proxy_bypass`` on OS X in Python 2.6.
- - Avoid crashing when attempting to get authentication credentials from ~/.netrc when running as a user without a home directory.
- - Use the correct pool size for pools of connections to proxies.
- - Fix iteration of ``CookieJar`` objects.
- - Ensure that cookies are persisted over redirect.
- - Switch back to using chardet, since it has merged with charade.
-
- 2.1.0 (2013-12-05)
- ++++++++++++++++++
-
- - Updated CA Bundle, of course.
- - Cookies set on individual Requests through a ``Session`` (e.g. via ``Session.get()``) are no longer persisted to the ``Session``.
- - Clean up connections when we hit problems during chunked upload, rather than leaking them.
- - Return connections to the pool when a chunked upload is successful, rather than leaking it.
- - Match the HTTPbis recommendation for HTTP 301 redirects.
- - Prevent hanging when using streaming uploads and Digest Auth when a 401 is received.
- - Values of headers set by Requests are now always the native string type.
- - Fix previously broken SNI support.
- - Fix accessing HTTP proxies using proxy authentication.
- - Unencode HTTP Basic usernames and passwords extracted from URLs.
- - Support for IP address ranges for no_proxy environment variable
- - Parse headers correctly when users override the default ``Host:`` header.
- - Avoid munging the URL in case of case-sensitive servers.
- - Looser URL handling for non-HTTP/HTTPS urls.
- - Accept unicode methods in Python 2.6 and 2.7.
- - More resilient cookie handling.
- - Make ``Response`` objects pickleable.
- - Actually added MD5-sess to Digest Auth instead of pretending to like last time.
- - Updated internal urllib3.
- - Fixed @Lukasa's lack of taste.
-
- 2.0.1 (2013-10-24)
- ++++++++++++++++++
-
- - Updated included CA Bundle with new mistrusts and automated process for the future
- - Added MD5-sess to Digest Auth
- - Accept per-file headers in multipart file POST messages.
- - Fixed: Don't send the full URL on CONNECT messages.
- - Fixed: Correctly lowercase a redirect scheme.
- - Fixed: Cookies not persisted when set via functional API.
- - Fixed: Translate urllib3 ProxyError into a requests ProxyError derived from ConnectionError.
- - Updated internal urllib3 and chardet.
-
- 2.0.0 (2013-09-24)
- ++++++++++++++++++
-
- **API Changes:**
-
- - Keys in the Headers dictionary are now native strings on all Python versions,
- i.e. bytestrings on Python 2, unicode on Python 3.
- - Proxy URLs now *must* have an explicit scheme. A ``MissingSchema`` exception
- will be raised if they don't.
- - Timeouts now apply to read time if ``Stream=False``.
- - ``RequestException`` is now a subclass of ``IOError``, not ``RuntimeError``.
- - Added new method to ``PreparedRequest`` objects: ``PreparedRequest.copy()``.
- - Added new method to ``Session`` objects: ``Session.update_request()``. This
- method updates a ``Request`` object with the data (e.g. cookies) stored on
- the ``Session``.
- - Added new method to ``Session`` objects: ``Session.prepare_request()``. This
- method updates and prepares a ``Request`` object, and returns the
- corresponding ``PreparedRequest`` object.
- - Added new method to ``HTTPAdapter`` objects: ``HTTPAdapter.proxy_headers()``.
- This should not be called directly, but improves the subclass interface.
- - ``httplib.IncompleteRead`` exceptions caused by incorrect chunked encoding
- will now raise a Requests ``ChunkedEncodingError`` instead.
- - Invalid percent-escape sequences now cause a Requests ``InvalidURL``
- exception to be raised.
- - HTTP 208 no longer uses reason phrase ``"im_used"``. Correctly uses
- ``"already_reported"``.
- - HTTP 226 reason added (``"im_used"``).
-
- **Bugfixes:**
-
- - Vastly improved proxy support, including the CONNECT verb. Special thanks to
- the many contributors who worked towards this improvement.
- - Cookies are now properly managed when 401 authentication responses are
- received.
- - Chunked encoding fixes.
- - Support for mixed case schemes.
- - Better handling of streaming downloads.
- - Retrieve environment proxies from more locations.
- - Minor cookies fixes.
- - Improved redirect behaviour.
- - Improved streaming behaviour, particularly for compressed data.
- - Miscellaneous small Python 3 text encoding bugs.
- - ``.netrc`` no longer overrides explicit auth.
- - Cookies set by hooks are now correctly persisted on Sessions.
- - Fix problem with cookies that specify port numbers in their host field.
- - ``BytesIO`` can be used to perform streaming uploads.
- - More generous parsing of the ``no_proxy`` environment variable.
- - Non-string objects can be passed in data values alongside files.
-
- 1.2.3 (2013-05-25)
- ++++++++++++++++++
-
- - Simple packaging fix
-
-
- 1.2.2 (2013-05-23)
- ++++++++++++++++++
-
- - Simple packaging fix
-
-
- 1.2.1 (2013-05-20)
- ++++++++++++++++++
-
- - Python 3.3.2 compatibility
- - Always percent-encode location headers
- - Fix connection adapter matching to be most-specific first
- - new argument to the default connection adapter for passing a block argument
- - prevent a KeyError when there's no link headers
-
- 1.2.0 (2013-03-31)
- ++++++++++++++++++
-
- - Fixed cookies on sessions and on requests
- - Significantly change how hooks are dispatched - hooks now receive all the
- arguments specified by the user when making a request so hooks can make a
- secondary request with the same parameters. This is especially necessary for
- authentication handler authors
- - certifi support was removed
- - Fixed bug where using OAuth 1 with body ``signature_type`` sent no data
- - Major proxy work thanks to @Lukasa including parsing of proxy authentication
- from the proxy url
- - Fix DigestAuth handling too many 401s
- - Update vendored urllib3 to include SSL bug fixes
- - Allow keyword arguments to be passed to ``json.loads()`` via the
- ``Response.json()`` method
- - Don't send ``Content-Length`` header by default on ``GET`` or ``HEAD``
- requests
- - Add ``elapsed`` attribute to ``Response`` objects to time how long a request
- took.
- - Fix ``RequestsCookieJar``
- - Sessions and Adapters are now picklable, i.e., can be used with the
- multiprocessing library
- - Update charade to version 1.0.3
-
- The change in how hooks are dispatched will likely cause a great deal of
- issues.
-
- 1.1.0 (2013-01-10)
- ++++++++++++++++++
-
- - CHUNKED REQUESTS
- - Support for iterable response bodies
- - Assume servers persist redirect params
- - Allow explicit content types to be specified for file data
- - Make merge_kwargs case-insensitive when looking up keys
-
- 1.0.3 (2012-12-18)
- ++++++++++++++++++
-
- - Fix file upload encoding bug
- - Fix cookie behavior
-
- 1.0.2 (2012-12-17)
- ++++++++++++++++++
-
- - Proxy fix for HTTPAdapter.
-
- 1.0.1 (2012-12-17)
- ++++++++++++++++++
-
- - Cert verification exception bug.
- - Proxy fix for HTTPAdapter.
-
- 1.0.0 (2012-12-17)
- ++++++++++++++++++
-
- - Massive Refactor and Simplification
- - Switch to Apache 2.0 license
- - Swappable Connection Adapters
- - Mountable Connection Adapters
- - Mutable ProcessedRequest chain
- - /s/prefetch/stream
- - Removal of all configuration
- - Standard library logging
- - Make Response.json() callable, not property.
- - Usage of new charade project, which provides python 2 and 3 simultaneous chardet.
- - Removal of all hooks except 'response'
- - Removal of all authentication helpers (OAuth, Kerberos)
-
- This is not a backwards compatible change.
-
- 0.14.2 (2012-10-27)
- +++++++++++++++++++
-
- - Improved mime-compatible JSON handling
- - Proxy fixes
- - Path hack fixes
- - Case-Insensistive Content-Encoding headers
- - Support for CJK parameters in form posts
-
-
- 0.14.1 (2012-10-01)
- +++++++++++++++++++
-
- - Python 3.3 Compatibility
- - Simply default accept-encoding
- - Bugfixes
-
-
- 0.14.0 (2012-09-02)
- ++++++++++++++++++++
-
- - No more iter_content errors if already downloaded.
-
- 0.13.9 (2012-08-25)
- +++++++++++++++++++
-
- - Fix for OAuth + POSTs
- - Remove exception eating from dispatch_hook
- - General bugfixes
-
- 0.13.8 (2012-08-21)
- +++++++++++++++++++
-
- - Incredible Link header support :)
-
- 0.13.7 (2012-08-19)
- +++++++++++++++++++
-
- - Support for (key, value) lists everywhere.
- - Digest Authentication improvements.
- - Ensure proxy exclusions work properly.
- - Clearer UnicodeError exceptions.
- - Automatic casting of URLs to tsrings (fURL and such)
- - Bugfixes.
-
- 0.13.6 (2012-08-06)
- +++++++++++++++++++
-
- - Long awaited fix for hanging connections!
-
- 0.13.5 (2012-07-27)
- +++++++++++++++++++
-
- - Packaging fix
-
- 0.13.4 (2012-07-27)
- +++++++++++++++++++
-
- - GSSAPI/Kerberos authentication!
- - App Engine 2.7 Fixes!
- - Fix leaking connections (from urllib3 update)
- - OAuthlib path hack fix
- - OAuthlib URL parameters fix.
-
- 0.13.3 (2012-07-12)
- +++++++++++++++++++
-
- - Use simplejson if available.
- - Do not hide SSLErrors behind Timeouts.
- - Fixed param handling with urls containing fragments.
- - Significantly improved information in User Agent.
- - client certificates are ignored when verify=False
-
- 0.13.2 (2012-06-28)
- +++++++++++++++++++
-
- - Zero dependencies (once again)!
- - New: Response.reason
- - Sign querystring parameters in OAuth 1.0
- - Client certificates no longer ignored when verify=False
- - Add openSUSE certificate support
-
- 0.13.1 (2012-06-07)
- +++++++++++++++++++
-
- - Allow passing a file or file-like object as data.
- - Allow hooks to return responses that indicate errors.
- - Fix Response.text and Response.json for body-less responses.
-
- 0.13.0 (2012-05-29)
- +++++++++++++++++++
-
- - Removal of Requests.async in favor of `grequests `_
- - Allow disabling of cookie persistiance.
- - New implimentation of safe_mode
- - cookies.get now supports default argument
- - Session cookies not saved when Session.request is called with return_response=False
- - Env: no_proxy support.
- - RequestsCookieJar improvements.
- - Various bug fixes.
-
- 0.12.1 (2012-05-08)
- +++++++++++++++++++
-
- - New ``Response.json`` property.
- - Ability to add string file uploads.
- - Fix out-of-range issue with iter_lines.
- - Fix iter_content default size.
- - Fix POST redirects containing files.
-
- 0.12.0 (2012-05-02)
- +++++++++++++++++++
-
- - EXPERIMENTAL OAUTH SUPPORT!
- - Proper CookieJar-backed cookies interface with awesome dict-like interface.
- - Speed fix for non-iterated content chunks.
- - Move ``pre_request`` to a more usable place.
- - New ``pre_send`` hook.
- - Lazily encode data, params, files.
- - Load system Certificate Bundle if ``certify`` isn't available.
- - Cleanups, fixes.
-
- 0.11.2 (2012-04-22)
- +++++++++++++++++++
-
- - Attempt to use the OS's certificate bundle if ``certifi`` isn't available.
- - Infinite digest auth redirect fix.
- - Multi-part file upload improvements.
- - Fix decoding of invalid %encodings in URLs.
- - If there is no content in a response don't throw an error the second time that content is attempted to be read.
- - Upload data on redirects.
-
- 0.11.1 (2012-03-30)
- +++++++++++++++++++
-
- * POST redirects now break RFC to do what browsers do: Follow up with a GET.
- * New ``strict_mode`` configuration to disable new redirect behavior.
-
-
- 0.11.0 (2012-03-14)
- +++++++++++++++++++
-
- * Private SSL Certificate support
- * Remove select.poll from Gevent monkeypatching
- * Remove redundant generator for chunked transfer encoding
- * Fix: Response.ok raises Timeout Exception in safe_mode
-
- 0.10.8 (2012-03-09)
- +++++++++++++++++++
-
- * Generate chunked ValueError fix
- * Proxy configuration by environment variables
- * Simplification of iter_lines.
- * New `trust_env` configuration for disabling system/environment hints.
- * Suppress cookie errors.
-
- 0.10.7 (2012-03-07)
- +++++++++++++++++++
-
- * `encode_uri` = False
-
- 0.10.6 (2012-02-25)
- +++++++++++++++++++
-
- * Allow '=' in cookies.
-
- 0.10.5 (2012-02-25)
- +++++++++++++++++++
-
- * Response body with 0 content-length fix.
- * New async.imap.
- * Don't fail on netrc.
-
-
- 0.10.4 (2012-02-20)
- +++++++++++++++++++
-
- * Honor netrc.
-
- 0.10.3 (2012-02-20)
- +++++++++++++++++++
-
- * HEAD requests don't follow redirects anymore.
- * raise_for_status() doesn't raise for 3xx anymore.
- * Make Session objects picklable.
- * ValueError for invalid schema URLs.
-
- 0.10.2 (2012-01-15)
- +++++++++++++++++++
-
- * Vastly improved URL quoting.
- * Additional allowed cookie key values.
- * Attempted fix for "Too many open files" Error
- * Replace unicode errors on first pass, no need for second pass.
- * Append '/' to bare-domain urls before query insertion.
- * Exceptions now inherit from RuntimeError.
- * Binary uploads + auth fix.
- * Bugfixes.
-
-
- 0.10.1 (2012-01-23)
- +++++++++++++++++++
-
- * PYTHON 3 SUPPORT!
- * Dropped 2.5 Support. (*Backwards Incompatible*)
-
- 0.10.0 (2012-01-21)
- +++++++++++++++++++
-
- * ``Response.content`` is now bytes-only. (*Backwards Incompatible*)
- * New ``Response.text`` is unicode-only.
- * If no ``Response.encoding`` is specified and ``chardet`` is available, ``Respoonse.text`` will guess an encoding.
- * Default to ISO-8859-1 (Western) encoding for "text" subtypes.
- * Removal of `decode_unicode`. (*Backwards Incompatible*)
- * New multiple-hooks system.
- * New ``Response.register_hook`` for registering hooks within the pipeline.
- * ``Response.url`` is now Unicode.
-
- 0.9.3 (2012-01-18)
- ++++++++++++++++++
-
- * SSL verify=False bugfix (apparent on windows machines).
-
- 0.9.2 (2012-01-18)
- ++++++++++++++++++
-
- * Asynchronous async.send method.
- * Support for proper chunk streams with boundaries.
- * session argument for Session classes.
- * Print entire hook tracebacks, not just exception instance.
- * Fix response.iter_lines from pending next line.
- * Fix but in HTTP-digest auth w/ URI having query strings.
- * Fix in Event Hooks section.
- * Urllib3 update.
-
-
- 0.9.1 (2012-01-06)
- ++++++++++++++++++
-
- * danger_mode for automatic Response.raise_for_status()
- * Response.iter_lines refactor
-
- 0.9.0 (2011-12-28)
- ++++++++++++++++++
-
- * verify ssl is default.
-
-
- 0.8.9 (2011-12-28)
- ++++++++++++++++++
-
- * Packaging fix.
-
-
- 0.8.8 (2011-12-28)
- ++++++++++++++++++
-
- * SSL CERT VERIFICATION!
- * Release of Cerifi: Mozilla's cert list.
- * New 'verify' argument for SSL requests.
- * Urllib3 update.
-
- 0.8.7 (2011-12-24)
- ++++++++++++++++++
-
- * iter_lines last-line truncation fix
- * Force safe_mode for async requests
- * Handle safe_mode exceptions more consistently
- * Fix iteration on null responses in safe_mode
-
- 0.8.6 (2011-12-18)
- ++++++++++++++++++
-
- * Socket timeout fixes.
- * Proxy Authorization support.
-
- 0.8.5 (2011-12-14)
- ++++++++++++++++++
-
- * Response.iter_lines!
-
- 0.8.4 (2011-12-11)
- ++++++++++++++++++
-
- * Prefetch bugfix.
- * Added license to installed version.
-
- 0.8.3 (2011-11-27)
- ++++++++++++++++++
-
- * Converted auth system to use simpler callable objects.
- * New session parameter to API methods.
- * Display full URL while logging.
-
- 0.8.2 (2011-11-19)
- ++++++++++++++++++
-
- * New Unicode decoding system, based on over-ridable `Response.encoding`.
- * Proper URL slash-quote handling.
- * Cookies with ``[``, ``]``, and ``_`` allowed.
-
- 0.8.1 (2011-11-15)
- ++++++++++++++++++
-
- * URL Request path fix
- * Proxy fix.
- * Timeouts fix.
-
- 0.8.0 (2011-11-13)
- ++++++++++++++++++
-
- * Keep-alive support!
- * Complete removal of Urllib2
- * Complete removal of Poster
- * Complete removal of CookieJars
- * New ConnectionError raising
- * Safe_mode for error catching
- * prefetch parameter for request methods
- * OPTION method
- * Async pool size throttling
- * File uploads send real names
- * Vendored in urllib3
-
- 0.7.6 (2011-11-07)
- ++++++++++++++++++
-
- * Digest authentication bugfix (attach query data to path)
-
- 0.7.5 (2011-11-04)
- ++++++++++++++++++
-
- * Response.content = None if there was an invalid repsonse.
- * Redirection auth handling.
-
- 0.7.4 (2011-10-26)
- ++++++++++++++++++
-
- * Session Hooks fix.
-
- 0.7.3 (2011-10-23)
- ++++++++++++++++++
-
- * Digest Auth fix.
-
-
- 0.7.2 (2011-10-23)
- ++++++++++++++++++
-
- * PATCH Fix.
-
-
- 0.7.1 (2011-10-23)
- ++++++++++++++++++
-
- * Move away from urllib2 authentication handling.
- * Fully Remove AuthManager, AuthObject, &c.
- * New tuple-based auth system with handler callbacks.
-
-
- 0.7.0 (2011-10-22)
- ++++++++++++++++++
-
- * Sessions are now the primary interface.
- * Deprecated InvalidMethodException.
- * PATCH fix.
- * New config system (no more global settings).
-
-
- 0.6.6 (2011-10-19)
- ++++++++++++++++++
-
- * Session parameter bugfix (params merging).
-
-
- 0.6.5 (2011-10-18)
- ++++++++++++++++++
-
- * Offline (fast) test suite.
- * Session dictionary argument merging.
-
-
- 0.6.4 (2011-10-13)
- ++++++++++++++++++
-
- * Automatic decoding of unicode, based on HTTP Headers.
- * New ``decode_unicode`` setting.
- * Removal of ``r.read/close`` methods.
- * New ``r.faw`` interface for advanced response usage.*
- * Automatic expansion of parameterized headers.
-
-
- 0.6.3 (2011-10-13)
- ++++++++++++++++++
-
- * Beautiful ``requests.async`` module, for making async requests w/ gevent.
-
-
- 0.6.2 (2011-10-09)
- ++++++++++++++++++
-
- * GET/HEAD obeys allow_redirects=False.
-
-
- 0.6.1 (2011-08-20)
- ++++++++++++++++++
-
- * Enhanced status codes experience ``\o/``
- * Set a maximum number of redirects (``settings.max_redirects``)
- * Full Unicode URL support
- * Support for protocol-less redirects.
- * Allow for arbitrary request types.
- * Bugfixes
-
-
- 0.6.0 (2011-08-17)
- ++++++++++++++++++
-
- * New callback hook system
- * New persistient sessions object and context manager
- * Transparent Dict-cookie handling
- * Status code reference object
- * Removed Response.cached
- * Added Response.request
- * All args are kwargs
- * Relative redirect support
- * HTTPError handling improvements
- * Improved https testing
- * Bugfixes
-
-
- 0.5.1 (2011-07-23)
- ++++++++++++++++++
-
- * International Domain Name Support!
- * Access headers without fetching entire body (``read()``)
- * Use lists as dicts for parameters
- * Add Forced Basic Authentication
- * Forced Basic is default authentication type
- * ``python-requests.org`` default User-Agent header
- * CaseInsensitiveDict lower-case caching
- * Response.history bugfix
-
-
- 0.5.0 (2011-06-21)
- ++++++++++++++++++
-
- * PATCH Support
- * Support for Proxies
- * HTTPBin Test Suite
- * Redirect Fixes
- * settings.verbose stream writing
- * Querystrings for all methods
- * URLErrors (Connection Refused, Timeout, Invalid URLs) are treated as explicity raised
- ``r.requests.get('hwe://blah'); r.raise_for_status()``
-
-
- 0.4.1 (2011-05-22)
- ++++++++++++++++++
-
- * Improved Redirection Handling
- * New 'allow_redirects' param for following non-GET/HEAD Redirects
- * Settings module refactoring
-
-
- 0.4.0 (2011-05-15)
- ++++++++++++++++++
-
- * Response.history: list of redirected responses
- * Case-Insensitive Header Dictionaries!
- * Unicode URLs
-
-
- 0.3.4 (2011-05-14)
- ++++++++++++++++++
-
- * Urllib2 HTTPAuthentication Recursion fix (Basic/Digest)
- * Internal Refactor
- * Bytes data upload Bugfix
-
-
-
- 0.3.3 (2011-05-12)
- ++++++++++++++++++
-
- * Request timeouts
- * Unicode url-encoded data
- * Settings context manager and module
-
-
- 0.3.2 (2011-04-15)
- ++++++++++++++++++
-
- * Automatic Decompression of GZip Encoded Content
- * AutoAuth Support for Tupled HTTP Auth
-
-
- 0.3.1 (2011-04-01)
- ++++++++++++++++++
-
- * Cookie Changes
- * Response.read()
- * Poster fix
-
-
- 0.3.0 (2011-02-25)
- ++++++++++++++++++
-
- * Automatic Authentication API Change
- * Smarter Query URL Parameterization
- * Allow file uploads and POST data together
- * New Authentication Manager System
- - Simpler Basic HTTP System
- - Supports all build-in urllib2 Auths
- - Allows for custom Auth Handlers
-
-
- 0.2.4 (2011-02-19)
- ++++++++++++++++++
-
- * Python 2.5 Support
- * PyPy-c v1.4 Support
- * Auto-Authentication tests
- * Improved Request object constructor
-
- 0.2.3 (2011-02-15)
- ++++++++++++++++++
-
- * New HTTPHandling Methods
- - Response.__nonzero__ (false if bad HTTP Status)
- - Response.ok (True if expected HTTP Status)
- - Response.error (Logged HTTPError if bad HTTP Status)
- - Response.raise_for_status() (Raises stored HTTPError)
-
-
- 0.2.2 (2011-02-14)
- ++++++++++++++++++
-
- * Still handles request in the event of an HTTPError. (Issue #2)
- * Eventlet and Gevent Monkeypatch support.
- * Cookie Support (Issue #1)
-
-
- 0.2.1 (2011-02-14)
- ++++++++++++++++++
-
- * Added file attribute to POST and PUT requests for multipart-encode file uploads.
- * Added Request.url attribute for context and redirects
-
-
- 0.2.0 (2011-02-14)
- ++++++++++++++++++
-
- * Birth!
-
-
- 0.0.1 (2011-02-13)
- ++++++++++++++++++
-
- * Frustration
- * Conception
-
-
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: Natural Language :: English
-Classifier: License :: OSI Approved :: Apache Software License
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.3
diff --git a/PythonHome/thirdparty/requests-2.2.1.dist-info/METADATA b/PythonHome/thirdparty/requests-2.2.1.dist-info/METADATA
deleted file mode 100644
index 989d4b9d4..000000000
--- a/PythonHome/thirdparty/requests-2.2.1.dist-info/METADATA
+++ /dev/null
@@ -1,896 +0,0 @@
-Metadata-Version: 2.0
-Name: requests
-Version: 2.2.1
-Summary: Python HTTP for Humans.
-Home-page: http://python-requests.org
-Author: Kenneth Reitz
-Author-email: me@kennethreitz.com
-License: Copyright 2014 Kenneth Reitz
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-Description: Requests: HTTP for Humans
- =========================
-
- .. image:: https://badge.fury.io/py/requests.png
- :target: http://badge.fury.io/py/requests
-
- .. image:: https://pypip.in/d/requests/badge.png
- :target: https://crate.io/packages/requests/
-
-
- Requests is an Apache2 Licensed HTTP library, written in Python, for human
- beings.
-
- Most existing Python modules for sending HTTP requests are extremely
- verbose and cumbersome. Python's builtin urllib2 module provides most of
- the HTTP capabilities you should need, but the api is thoroughly broken.
- It requires an enormous amount of work (even method overrides) to
- perform the simplest of tasks.
-
- Things shouldn't be this way. Not in Python.
-
- .. code-block:: pycon
-
- >>> r = requests.get('https://api.github.com', auth=('user', 'pass'))
- >>> r.status_code
- 204
- >>> r.headers['content-type']
- 'application/json'
- >>> r.text
- ...
-
- See `the same code, without Requests `_.
-
- Requests allow you to send HTTP/1.1 requests. You can add headers, form data,
- multipart files, and parameters with simple Python dictionaries, and access the
- response data in the same way. It's powered by httplib and `urllib3
- `_, but it does all the hard work and crazy
- hacks for you.
-
-
- Features
- --------
-
- - International Domains and URLs
- - Keep-Alive & Connection Pooling
- - Sessions with Cookie Persistence
- - Browser-style SSL Verification
- - Basic/Digest Authentication
- - Elegant Key/Value Cookies
- - Automatic Decompression
- - Unicode Response Bodies
- - Multipart File Uploads
- - Connection Timeouts
- - Thread-safety
- - HTTP(S) proxy support
-
-
- Installation
- ------------
-
- To install Requests, simply:
-
- .. code-block:: bash
-
- $ pip install requests
-
- Or, if you absolutely must:
-
- .. code-block:: bash
-
- $ easy_install requests
-
- But, you really shouldn't do that.
-
-
- Documentation
- -------------
-
- Documentation is available at http://docs.python-requests.org/.
-
-
- Contribute
- ----------
-
- #. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. There is a `Contributor Friendly`_ tag for issues that should be ideal for people who are not very familiar with the codebase yet.
- #. If you feel uncomfortable or uncertain about an issue or your changes, feel free to email @sigmavirus24 and he will happily help you via email, Skype, remote pairing or whatever you are comfortable with.
- #. Fork `the repository`_ on GitHub to start making your changes to the **master** branch (or branch off of it).
- #. Write a test which shows that the bug was fixed or that the feature works as expected.
- #. Send a pull request and bug the maintainer until it gets merged and published. :) Make sure to add yourself to AUTHORS_.
-
- .. _`the repository`: http://github.com/kennethreitz/requests
- .. _AUTHORS: https://github.com/kennethreitz/requests/blob/master/AUTHORS.rst
- .. _Contributor Friendly: https://github.com/kennethreitz/requests/issues?direction=desc&labels=Contributor+Friendly&page=1&sort=updated&state=open
-
-
- .. :changelog:
-
- Release History
- ---------------
-
- 2.2.1 (2014-01-23)
- ++++++++++++++++++
-
- **Bugfixes**
-
- - Fixes incorrect parsing of proxy credentials that contain a literal or encoded '#' character.
- - Assorted urllib3 fixes.
-
- 2.2.0 (2014-01-09)
- ++++++++++++++++++
-
- **API Changes**
-
- - New exception: ``ContentDecodingError``. Raised instead of ``urllib3``
- ``DecodeError`` exceptions.
-
- **Bugfixes**
-
- - Avoid many many exceptions from the buggy implementation of ``proxy_bypass`` on OS X in Python 2.6.
- - Avoid crashing when attempting to get authentication credentials from ~/.netrc when running as a user without a home directory.
- - Use the correct pool size for pools of connections to proxies.
- - Fix iteration of ``CookieJar`` objects.
- - Ensure that cookies are persisted over redirect.
- - Switch back to using chardet, since it has merged with charade.
-
- 2.1.0 (2013-12-05)
- ++++++++++++++++++
-
- - Updated CA Bundle, of course.
- - Cookies set on individual Requests through a ``Session`` (e.g. via ``Session.get()``) are no longer persisted to the ``Session``.
- - Clean up connections when we hit problems during chunked upload, rather than leaking them.
- - Return connections to the pool when a chunked upload is successful, rather than leaking it.
- - Match the HTTPbis recommendation for HTTP 301 redirects.
- - Prevent hanging when using streaming uploads and Digest Auth when a 401 is received.
- - Values of headers set by Requests are now always the native string type.
- - Fix previously broken SNI support.
- - Fix accessing HTTP proxies using proxy authentication.
- - Unencode HTTP Basic usernames and passwords extracted from URLs.
- - Support for IP address ranges for no_proxy environment variable
- - Parse headers correctly when users override the default ``Host:`` header.
- - Avoid munging the URL in case of case-sensitive servers.
- - Looser URL handling for non-HTTP/HTTPS urls.
- - Accept unicode methods in Python 2.6 and 2.7.
- - More resilient cookie handling.
- - Make ``Response`` objects pickleable.
- - Actually added MD5-sess to Digest Auth instead of pretending to like last time.
- - Updated internal urllib3.
- - Fixed @Lukasa's lack of taste.
-
- 2.0.1 (2013-10-24)
- ++++++++++++++++++
-
- - Updated included CA Bundle with new mistrusts and automated process for the future
- - Added MD5-sess to Digest Auth
- - Accept per-file headers in multipart file POST messages.
- - Fixed: Don't send the full URL on CONNECT messages.
- - Fixed: Correctly lowercase a redirect scheme.
- - Fixed: Cookies not persisted when set via functional API.
- - Fixed: Translate urllib3 ProxyError into a requests ProxyError derived from ConnectionError.
- - Updated internal urllib3 and chardet.
-
- 2.0.0 (2013-09-24)
- ++++++++++++++++++
-
- **API Changes:**
-
- - Keys in the Headers dictionary are now native strings on all Python versions,
- i.e. bytestrings on Python 2, unicode on Python 3.
- - Proxy URLs now *must* have an explicit scheme. A ``MissingSchema`` exception
- will be raised if they don't.
- - Timeouts now apply to read time if ``Stream=False``.
- - ``RequestException`` is now a subclass of ``IOError``, not ``RuntimeError``.
- - Added new method to ``PreparedRequest`` objects: ``PreparedRequest.copy()``.
- - Added new method to ``Session`` objects: ``Session.update_request()``. This
- method updates a ``Request`` object with the data (e.g. cookies) stored on
- the ``Session``.
- - Added new method to ``Session`` objects: ``Session.prepare_request()``. This
- method updates and prepares a ``Request`` object, and returns the
- corresponding ``PreparedRequest`` object.
- - Added new method to ``HTTPAdapter`` objects: ``HTTPAdapter.proxy_headers()``.
- This should not be called directly, but improves the subclass interface.
- - ``httplib.IncompleteRead`` exceptions caused by incorrect chunked encoding
- will now raise a Requests ``ChunkedEncodingError`` instead.
- - Invalid percent-escape sequences now cause a Requests ``InvalidURL``
- exception to be raised.
- - HTTP 208 no longer uses reason phrase ``"im_used"``. Correctly uses
- ``"already_reported"``.
- - HTTP 226 reason added (``"im_used"``).
-
- **Bugfixes:**
-
- - Vastly improved proxy support, including the CONNECT verb. Special thanks to
- the many contributors who worked towards this improvement.
- - Cookies are now properly managed when 401 authentication responses are
- received.
- - Chunked encoding fixes.
- - Support for mixed case schemes.
- - Better handling of streaming downloads.
- - Retrieve environment proxies from more locations.
- - Minor cookies fixes.
- - Improved redirect behaviour.
- - Improved streaming behaviour, particularly for compressed data.
- - Miscellaneous small Python 3 text encoding bugs.
- - ``.netrc`` no longer overrides explicit auth.
- - Cookies set by hooks are now correctly persisted on Sessions.
- - Fix problem with cookies that specify port numbers in their host field.
- - ``BytesIO`` can be used to perform streaming uploads.
- - More generous parsing of the ``no_proxy`` environment variable.
- - Non-string objects can be passed in data values alongside files.
-
- 1.2.3 (2013-05-25)
- ++++++++++++++++++
-
- - Simple packaging fix
-
-
- 1.2.2 (2013-05-23)
- ++++++++++++++++++
-
- - Simple packaging fix
-
-
- 1.2.1 (2013-05-20)
- ++++++++++++++++++
-
- - Python 3.3.2 compatibility
- - Always percent-encode location headers
- - Fix connection adapter matching to be most-specific first
- - new argument to the default connection adapter for passing a block argument
- - prevent a KeyError when there's no link headers
-
- 1.2.0 (2013-03-31)
- ++++++++++++++++++
-
- - Fixed cookies on sessions and on requests
- - Significantly change how hooks are dispatched - hooks now receive all the
- arguments specified by the user when making a request so hooks can make a
- secondary request with the same parameters. This is especially necessary for
- authentication handler authors
- - certifi support was removed
- - Fixed bug where using OAuth 1 with body ``signature_type`` sent no data
- - Major proxy work thanks to @Lukasa including parsing of proxy authentication
- from the proxy url
- - Fix DigestAuth handling too many 401s
- - Update vendored urllib3 to include SSL bug fixes
- - Allow keyword arguments to be passed to ``json.loads()`` via the
- ``Response.json()`` method
- - Don't send ``Content-Length`` header by default on ``GET`` or ``HEAD``
- requests
- - Add ``elapsed`` attribute to ``Response`` objects to time how long a request
- took.
- - Fix ``RequestsCookieJar``
- - Sessions and Adapters are now picklable, i.e., can be used with the
- multiprocessing library
- - Update charade to version 1.0.3
-
- The change in how hooks are dispatched will likely cause a great deal of
- issues.
-
- 1.1.0 (2013-01-10)
- ++++++++++++++++++
-
- - CHUNKED REQUESTS
- - Support for iterable response bodies
- - Assume servers persist redirect params
- - Allow explicit content types to be specified for file data
- - Make merge_kwargs case-insensitive when looking up keys
-
- 1.0.3 (2012-12-18)
- ++++++++++++++++++
-
- - Fix file upload encoding bug
- - Fix cookie behavior
-
- 1.0.2 (2012-12-17)
- ++++++++++++++++++
-
- - Proxy fix for HTTPAdapter.
-
- 1.0.1 (2012-12-17)
- ++++++++++++++++++
-
- - Cert verification exception bug.
- - Proxy fix for HTTPAdapter.
-
- 1.0.0 (2012-12-17)
- ++++++++++++++++++
-
- - Massive Refactor and Simplification
- - Switch to Apache 2.0 license
- - Swappable Connection Adapters
- - Mountable Connection Adapters
- - Mutable ProcessedRequest chain
- - /s/prefetch/stream
- - Removal of all configuration
- - Standard library logging
- - Make Response.json() callable, not property.
- - Usage of new charade project, which provides python 2 and 3 simultaneous chardet.
- - Removal of all hooks except 'response'
- - Removal of all authentication helpers (OAuth, Kerberos)
-
- This is not a backwards compatible change.
-
- 0.14.2 (2012-10-27)
- +++++++++++++++++++
-
- - Improved mime-compatible JSON handling
- - Proxy fixes
- - Path hack fixes
- - Case-Insensistive Content-Encoding headers
- - Support for CJK parameters in form posts
-
-
- 0.14.1 (2012-10-01)
- +++++++++++++++++++
-
- - Python 3.3 Compatibility
- - Simply default accept-encoding
- - Bugfixes
-
-
- 0.14.0 (2012-09-02)
- ++++++++++++++++++++
-
- - No more iter_content errors if already downloaded.
-
- 0.13.9 (2012-08-25)
- +++++++++++++++++++
-
- - Fix for OAuth + POSTs
- - Remove exception eating from dispatch_hook
- - General bugfixes
-
- 0.13.8 (2012-08-21)
- +++++++++++++++++++
-
- - Incredible Link header support :)
-
- 0.13.7 (2012-08-19)
- +++++++++++++++++++
-
- - Support for (key, value) lists everywhere.
- - Digest Authentication improvements.
- - Ensure proxy exclusions work properly.
- - Clearer UnicodeError exceptions.
- - Automatic casting of URLs to tsrings (fURL and such)
- - Bugfixes.
-
- 0.13.6 (2012-08-06)
- +++++++++++++++++++
-
- - Long awaited fix for hanging connections!
-
- 0.13.5 (2012-07-27)
- +++++++++++++++++++
-
- - Packaging fix
-
- 0.13.4 (2012-07-27)
- +++++++++++++++++++
-
- - GSSAPI/Kerberos authentication!
- - App Engine 2.7 Fixes!
- - Fix leaking connections (from urllib3 update)
- - OAuthlib path hack fix
- - OAuthlib URL parameters fix.
-
- 0.13.3 (2012-07-12)
- +++++++++++++++++++
-
- - Use simplejson if available.
- - Do not hide SSLErrors behind Timeouts.
- - Fixed param handling with urls containing fragments.
- - Significantly improved information in User Agent.
- - client certificates are ignored when verify=False
-
- 0.13.2 (2012-06-28)
- +++++++++++++++++++
-
- - Zero dependencies (once again)!
- - New: Response.reason
- - Sign querystring parameters in OAuth 1.0
- - Client certificates no longer ignored when verify=False
- - Add openSUSE certificate support
-
- 0.13.1 (2012-06-07)
- +++++++++++++++++++
-
- - Allow passing a file or file-like object as data.
- - Allow hooks to return responses that indicate errors.
- - Fix Response.text and Response.json for body-less responses.
-
- 0.13.0 (2012-05-29)
- +++++++++++++++++++
-
- - Removal of Requests.async in favor of `grequests `_
- - Allow disabling of cookie persistiance.
- - New implimentation of safe_mode
- - cookies.get now supports default argument
- - Session cookies not saved when Session.request is called with return_response=False
- - Env: no_proxy support.
- - RequestsCookieJar improvements.
- - Various bug fixes.
-
- 0.12.1 (2012-05-08)
- +++++++++++++++++++
-
- - New ``Response.json`` property.
- - Ability to add string file uploads.
- - Fix out-of-range issue with iter_lines.
- - Fix iter_content default size.
- - Fix POST redirects containing files.
-
- 0.12.0 (2012-05-02)
- +++++++++++++++++++
-
- - EXPERIMENTAL OAUTH SUPPORT!
- - Proper CookieJar-backed cookies interface with awesome dict-like interface.
- - Speed fix for non-iterated content chunks.
- - Move ``pre_request`` to a more usable place.
- - New ``pre_send`` hook.
- - Lazily encode data, params, files.
- - Load system Certificate Bundle if ``certify`` isn't available.
- - Cleanups, fixes.
-
- 0.11.2 (2012-04-22)
- +++++++++++++++++++
-
- - Attempt to use the OS's certificate bundle if ``certifi`` isn't available.
- - Infinite digest auth redirect fix.
- - Multi-part file upload improvements.
- - Fix decoding of invalid %encodings in URLs.
- - If there is no content in a response don't throw an error the second time that content is attempted to be read.
- - Upload data on redirects.
-
- 0.11.1 (2012-03-30)
- +++++++++++++++++++
-
- * POST redirects now break RFC to do what browsers do: Follow up with a GET.
- * New ``strict_mode`` configuration to disable new redirect behavior.
-
-
- 0.11.0 (2012-03-14)
- +++++++++++++++++++
-
- * Private SSL Certificate support
- * Remove select.poll from Gevent monkeypatching
- * Remove redundant generator for chunked transfer encoding
- * Fix: Response.ok raises Timeout Exception in safe_mode
-
- 0.10.8 (2012-03-09)
- +++++++++++++++++++
-
- * Generate chunked ValueError fix
- * Proxy configuration by environment variables
- * Simplification of iter_lines.
- * New `trust_env` configuration for disabling system/environment hints.
- * Suppress cookie errors.
-
- 0.10.7 (2012-03-07)
- +++++++++++++++++++
-
- * `encode_uri` = False
-
- 0.10.6 (2012-02-25)
- +++++++++++++++++++
-
- * Allow '=' in cookies.
-
- 0.10.5 (2012-02-25)
- +++++++++++++++++++
-
- * Response body with 0 content-length fix.
- * New async.imap.
- * Don't fail on netrc.
-
-
- 0.10.4 (2012-02-20)
- +++++++++++++++++++
-
- * Honor netrc.
-
- 0.10.3 (2012-02-20)
- +++++++++++++++++++
-
- * HEAD requests don't follow redirects anymore.
- * raise_for_status() doesn't raise for 3xx anymore.
- * Make Session objects picklable.
- * ValueError for invalid schema URLs.
-
- 0.10.2 (2012-01-15)
- +++++++++++++++++++
-
- * Vastly improved URL quoting.
- * Additional allowed cookie key values.
- * Attempted fix for "Too many open files" Error
- * Replace unicode errors on first pass, no need for second pass.
- * Append '/' to bare-domain urls before query insertion.
- * Exceptions now inherit from RuntimeError.
- * Binary uploads + auth fix.
- * Bugfixes.
-
-
- 0.10.1 (2012-01-23)
- +++++++++++++++++++
-
- * PYTHON 3 SUPPORT!
- * Dropped 2.5 Support. (*Backwards Incompatible*)
-
- 0.10.0 (2012-01-21)
- +++++++++++++++++++
-
- * ``Response.content`` is now bytes-only. (*Backwards Incompatible*)
- * New ``Response.text`` is unicode-only.
- * If no ``Response.encoding`` is specified and ``chardet`` is available, ``Respoonse.text`` will guess an encoding.
- * Default to ISO-8859-1 (Western) encoding for "text" subtypes.
- * Removal of `decode_unicode`. (*Backwards Incompatible*)
- * New multiple-hooks system.
- * New ``Response.register_hook`` for registering hooks within the pipeline.
- * ``Response.url`` is now Unicode.
-
- 0.9.3 (2012-01-18)
- ++++++++++++++++++
-
- * SSL verify=False bugfix (apparent on windows machines).
-
- 0.9.2 (2012-01-18)
- ++++++++++++++++++
-
- * Asynchronous async.send method.
- * Support for proper chunk streams with boundaries.
- * session argument for Session classes.
- * Print entire hook tracebacks, not just exception instance.
- * Fix response.iter_lines from pending next line.
- * Fix but in HTTP-digest auth w/ URI having query strings.
- * Fix in Event Hooks section.
- * Urllib3 update.
-
-
- 0.9.1 (2012-01-06)
- ++++++++++++++++++
-
- * danger_mode for automatic Response.raise_for_status()
- * Response.iter_lines refactor
-
- 0.9.0 (2011-12-28)
- ++++++++++++++++++
-
- * verify ssl is default.
-
-
- 0.8.9 (2011-12-28)
- ++++++++++++++++++
-
- * Packaging fix.
-
-
- 0.8.8 (2011-12-28)
- ++++++++++++++++++
-
- * SSL CERT VERIFICATION!
- * Release of Cerifi: Mozilla's cert list.
- * New 'verify' argument for SSL requests.
- * Urllib3 update.
-
- 0.8.7 (2011-12-24)
- ++++++++++++++++++
-
- * iter_lines last-line truncation fix
- * Force safe_mode for async requests
- * Handle safe_mode exceptions more consistently
- * Fix iteration on null responses in safe_mode
-
- 0.8.6 (2011-12-18)
- ++++++++++++++++++
-
- * Socket timeout fixes.
- * Proxy Authorization support.
-
- 0.8.5 (2011-12-14)
- ++++++++++++++++++
-
- * Response.iter_lines!
-
- 0.8.4 (2011-12-11)
- ++++++++++++++++++
-
- * Prefetch bugfix.
- * Added license to installed version.
-
- 0.8.3 (2011-11-27)
- ++++++++++++++++++
-
- * Converted auth system to use simpler callable objects.
- * New session parameter to API methods.
- * Display full URL while logging.
-
- 0.8.2 (2011-11-19)
- ++++++++++++++++++
-
- * New Unicode decoding system, based on over-ridable `Response.encoding`.
- * Proper URL slash-quote handling.
- * Cookies with ``[``, ``]``, and ``_`` allowed.
-
- 0.8.1 (2011-11-15)
- ++++++++++++++++++
-
- * URL Request path fix
- * Proxy fix.
- * Timeouts fix.
-
- 0.8.0 (2011-11-13)
- ++++++++++++++++++
-
- * Keep-alive support!
- * Complete removal of Urllib2
- * Complete removal of Poster
- * Complete removal of CookieJars
- * New ConnectionError raising
- * Safe_mode for error catching
- * prefetch parameter for request methods
- * OPTION method
- * Async pool size throttling
- * File uploads send real names
- * Vendored in urllib3
-
- 0.7.6 (2011-11-07)
- ++++++++++++++++++
-
- * Digest authentication bugfix (attach query data to path)
-
- 0.7.5 (2011-11-04)
- ++++++++++++++++++
-
- * Response.content = None if there was an invalid repsonse.
- * Redirection auth handling.
-
- 0.7.4 (2011-10-26)
- ++++++++++++++++++
-
- * Session Hooks fix.
-
- 0.7.3 (2011-10-23)
- ++++++++++++++++++
-
- * Digest Auth fix.
-
-
- 0.7.2 (2011-10-23)
- ++++++++++++++++++
-
- * PATCH Fix.
-
-
- 0.7.1 (2011-10-23)
- ++++++++++++++++++
-
- * Move away from urllib2 authentication handling.
- * Fully Remove AuthManager, AuthObject, &c.
- * New tuple-based auth system with handler callbacks.
-
-
- 0.7.0 (2011-10-22)
- ++++++++++++++++++
-
- * Sessions are now the primary interface.
- * Deprecated InvalidMethodException.
- * PATCH fix.
- * New config system (no more global settings).
-
-
- 0.6.6 (2011-10-19)
- ++++++++++++++++++
-
- * Session parameter bugfix (params merging).
-
-
- 0.6.5 (2011-10-18)
- ++++++++++++++++++
-
- * Offline (fast) test suite.
- * Session dictionary argument merging.
-
-
- 0.6.4 (2011-10-13)
- ++++++++++++++++++
-
- * Automatic decoding of unicode, based on HTTP Headers.
- * New ``decode_unicode`` setting.
- * Removal of ``r.read/close`` methods.
- * New ``r.faw`` interface for advanced response usage.*
- * Automatic expansion of parameterized headers.
-
-
- 0.6.3 (2011-10-13)
- ++++++++++++++++++
-
- * Beautiful ``requests.async`` module, for making async requests w/ gevent.
-
-
- 0.6.2 (2011-10-09)
- ++++++++++++++++++
-
- * GET/HEAD obeys allow_redirects=False.
-
-
- 0.6.1 (2011-08-20)
- ++++++++++++++++++
-
- * Enhanced status codes experience ``\o/``
- * Set a maximum number of redirects (``settings.max_redirects``)
- * Full Unicode URL support
- * Support for protocol-less redirects.
- * Allow for arbitrary request types.
- * Bugfixes
-
-
- 0.6.0 (2011-08-17)
- ++++++++++++++++++
-
- * New callback hook system
- * New persistient sessions object and context manager
- * Transparent Dict-cookie handling
- * Status code reference object
- * Removed Response.cached
- * Added Response.request
- * All args are kwargs
- * Relative redirect support
- * HTTPError handling improvements
- * Improved https testing
- * Bugfixes
-
-
- 0.5.1 (2011-07-23)
- ++++++++++++++++++
-
- * International Domain Name Support!
- * Access headers without fetching entire body (``read()``)
- * Use lists as dicts for parameters
- * Add Forced Basic Authentication
- * Forced Basic is default authentication type
- * ``python-requests.org`` default User-Agent header
- * CaseInsensitiveDict lower-case caching
- * Response.history bugfix
-
-
- 0.5.0 (2011-06-21)
- ++++++++++++++++++
-
- * PATCH Support
- * Support for Proxies
- * HTTPBin Test Suite
- * Redirect Fixes
- * settings.verbose stream writing
- * Querystrings for all methods
- * URLErrors (Connection Refused, Timeout, Invalid URLs) are treated as explicity raised
- ``r.requests.get('hwe://blah'); r.raise_for_status()``
-
-
- 0.4.1 (2011-05-22)
- ++++++++++++++++++
-
- * Improved Redirection Handling
- * New 'allow_redirects' param for following non-GET/HEAD Redirects
- * Settings module refactoring
-
-
- 0.4.0 (2011-05-15)
- ++++++++++++++++++
-
- * Response.history: list of redirected responses
- * Case-Insensitive Header Dictionaries!
- * Unicode URLs
-
-
- 0.3.4 (2011-05-14)
- ++++++++++++++++++
-
- * Urllib2 HTTPAuthentication Recursion fix (Basic/Digest)
- * Internal Refactor
- * Bytes data upload Bugfix
-
-
-
- 0.3.3 (2011-05-12)
- ++++++++++++++++++
-
- * Request timeouts
- * Unicode url-encoded data
- * Settings context manager and module
-
-
- 0.3.2 (2011-04-15)
- ++++++++++++++++++
-
- * Automatic Decompression of GZip Encoded Content
- * AutoAuth Support for Tupled HTTP Auth
-
-
- 0.3.1 (2011-04-01)
- ++++++++++++++++++
-
- * Cookie Changes
- * Response.read()
- * Poster fix
-
-
- 0.3.0 (2011-02-25)
- ++++++++++++++++++
-
- * Automatic Authentication API Change
- * Smarter Query URL Parameterization
- * Allow file uploads and POST data together
- * New Authentication Manager System
- - Simpler Basic HTTP System
- - Supports all build-in urllib2 Auths
- - Allows for custom Auth Handlers
-
-
- 0.2.4 (2011-02-19)
- ++++++++++++++++++
-
- * Python 2.5 Support
- * PyPy-c v1.4 Support
- * Auto-Authentication tests
- * Improved Request object constructor
-
- 0.2.3 (2011-02-15)
- ++++++++++++++++++
-
- * New HTTPHandling Methods
- - Response.__nonzero__ (false if bad HTTP Status)
- - Response.ok (True if expected HTTP Status)
- - Response.error (Logged HTTPError if bad HTTP Status)
- - Response.raise_for_status() (Raises stored HTTPError)
-
-
- 0.2.2 (2011-02-14)
- ++++++++++++++++++
-
- * Still handles request in the event of an HTTPError. (Issue #2)
- * Eventlet and Gevent Monkeypatch support.
- * Cookie Support (Issue #1)
-
-
- 0.2.1 (2011-02-14)
- ++++++++++++++++++
-
- * Added file attribute to POST and PUT requests for multipart-encode file uploads.
- * Added Request.url attribute for context and redirects
-
-
- 0.2.0 (2011-02-14)
- ++++++++++++++++++
-
- * Birth!
-
-
- 0.0.1 (2011-02-13)
- ++++++++++++++++++
-
- * Frustration
- * Conception
-
-
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: Natural Language :: English
-Classifier: License :: OSI Approved :: Apache Software License
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.3
diff --git a/PythonHome/thirdparty/requests-2.2.1.dist-info/pydist.json b/PythonHome/thirdparty/requests-2.2.1.dist-info/pydist.json
deleted file mode 100644
index fcb287499..000000000
--- a/PythonHome/thirdparty/requests-2.2.1.dist-info/pydist.json
+++ /dev/null
@@ -1 +0,0 @@
-{"license": "Copyright 2014 Kenneth Reitz", "document_names": {"description": "DESCRIPTION.rst"}, "name": "requests", "metadata_version": "2.0", "contacts": [{"role": "author", "email": "me@kennethreitz.com", "name": "Kenneth Reitz"}], "generator": "bdist_wheel (0.22.0)", "summary": "Python HTTP for Humans.", "project_urls": {"Home": "http://python-requests.org"}, "version": "2.2.1"}
\ No newline at end of file
diff --git a/PythonHome/thirdparty/wox.py b/PythonHome/wox.py
similarity index 95%
rename from PythonHome/thirdparty/wox.py
rename to PythonHome/wox.py
index 503bfa4f1..6cf05527e 100644
--- a/PythonHome/thirdparty/wox.py
+++ b/PythonHome/wox.py
@@ -1,4 +1,5 @@
#encoding=utf8
+
import json
import sys
import inspect
@@ -36,7 +37,7 @@ class Wox(object):
class WoxAPI(object):
@classmethod
- def wox_change_query(cls,query,requery = False):
+ def change_query(cls,query,requery = False):
"""
change wox query
"""
diff --git a/Wox/JsonRPC/JsonPRCModel.cs b/Wox/JsonRPC/JsonPRCModel.cs
index 7c39275ea..84ecc3518 100644
--- a/Wox/JsonRPC/JsonPRCModel.cs
+++ b/Wox/JsonRPC/JsonPRCModel.cs
@@ -45,7 +45,7 @@ namespace Wox.JsonRPC
public new List Result { get; set; }
}
- public abstract class JsonRPCRequestModel : JsonRPCModelBase
+ public class JsonRPCRequestModel : JsonRPCModelBase
{
public string Method { get; set; }
@@ -108,11 +108,17 @@ namespace Wox.JsonRPC
}
///
- /// Json RPC Request that client sent to Wox
+ /// Json RPC Request(in query response) that client sent to Wox
///
public class JsonRPCClientRequestModel : JsonRPCRequestModel
{
public bool DontHideAfterAction { get; set; }
+
+ public override string ToString()
+ {
+ string rpc = base.ToString();
+ return rpc + "}";
+ }
}
///
diff --git a/Wox/PluginLoader/BasePlugin.cs b/Wox/PluginLoader/BasePlugin.cs
index f74cd497e..ce800061c 100644
--- a/Wox/PluginLoader/BasePlugin.cs
+++ b/Wox/PluginLoader/BasePlugin.cs
@@ -35,6 +35,8 @@ namespace Wox.PluginLoader
List results = new List();
JsonRPCQueryResponseModel queryResponseModel = JsonConvert.DeserializeObject(output);
+ if (queryResponseModel.Result == null) return null;
+
foreach (JsonRPCResult result in queryResponseModel.Result)
{
JsonRPCResult result1 = result;
@@ -53,7 +55,7 @@ namespace Wox.PluginLoader
string actionReponse = ExecuteAction(result1.JsonRPCAction);
JsonRPCRequestModel jsonRpcRequestModel = JsonConvert.DeserializeObject(actionReponse);
if (jsonRpcRequestModel != null
- && string.IsNullOrEmpty(jsonRpcRequestModel.Method)
+ && !string.IsNullOrEmpty(jsonRpcRequestModel.Method)
&& jsonRpcRequestModel.Method.StartsWith("Wox."))
{
ExecuteWoxAPI(jsonRpcRequestModel.Method.Substring(4), jsonRpcRequestModel.Parameters);
diff --git a/Wox/PluginLoader/PythonPlugin.cs b/Wox/PluginLoader/PythonPlugin.cs
index eb95f6c40..8a00c7a65 100644
--- a/Wox/PluginLoader/PythonPlugin.cs
+++ b/Wox/PluginLoader/PythonPlugin.cs
@@ -28,7 +28,7 @@ namespace Wox.PluginLoader
};
string additionalPythonPath = string.Format("{0};{1}",
Path.Combine(woxDirectory, "PythonHome\\DLLs"),
- Path.Combine(woxDirectory, "PythonHome\\thirdparty"));
+ Path.Combine(woxDirectory, "PythonHome\\Lib\\site-packages"));
if (!startInfo.EnvironmentVariables.ContainsKey("PYTHONPATH"))
{