1st trial
This commit is contained in:
+2
-17
@@ -2,9 +2,7 @@ language: python
|
|||||||
|
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
cache:
|
cache: pip
|
||||||
directories:
|
|
||||||
- $HOME/.pip-cache/
|
|
||||||
|
|
||||||
python:
|
python:
|
||||||
- '2.7'
|
- '2.7'
|
||||||
@@ -12,20 +10,7 @@ python:
|
|||||||
- '3.5'
|
- '3.5'
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- |
|
- if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then pip install pycrypto; fi;
|
||||||
if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then
|
|
||||||
export PYENV_ROOT="$HOME/.pyenv"
|
|
||||||
if [ -f "$PYENV_ROOT/bin/pyenv" ]; then
|
|
||||||
pushd "$PYENV_ROOT" && git pull && popd
|
|
||||||
else
|
|
||||||
rm -rf "$PYENV_ROOT" && git clone --depth 1 https://github.com/yyuu/pyenv.git "$PYENV_ROOT"
|
|
||||||
fi
|
|
||||||
export PYPY_VERSION="5.0.1"
|
|
||||||
"$PYENV_ROOT/bin/pyenv" install --skip-existing "pypy-$PYPY_VERSION"
|
|
||||||
virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION"
|
|
||||||
source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate"
|
|
||||||
fi
|
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then pip install pycrypto pg8000; fi;
|
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION != '3.5' ]]; then pip install -e .; fi;
|
- if [[ $TRAVIS_PYTHON_VERSION != '3.5' ]]; then pip install -e .; fi;
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
from .core import (
|
||||||
|
Warning, Bytea, DataError, DatabaseError, InterfaceError, ProgrammingError,
|
||||||
|
Error, OperationalError, IntegrityError, InternalError, NotSupportedError,
|
||||||
|
ArrayContentNotHomogenousError, ArrayContentEmptyError,
|
||||||
|
ArrayDimensionsNotConsistentError, ArrayContentNotSupportedError, utc,
|
||||||
|
Connection, Cursor, Binary, Date, DateFromTicks, Time, TimeFromTicks,
|
||||||
|
Timestamp, TimestampFromTicks, BINARY, Interval)
|
||||||
|
from ._version import get_versions
|
||||||
|
__version__ = get_versions()['version']
|
||||||
|
del get_versions
|
||||||
|
|
||||||
# Copyright (c) 2007-2009, Mathieu Fenniak
|
# Copyright (c) 2007-2009, Mathieu Fenniak
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
@@ -28,258 +39,9 @@
|
|||||||
__author__ = "Mathieu Fenniak"
|
__author__ = "Mathieu Fenniak"
|
||||||
|
|
||||||
|
|
||||||
exec("from struct import Struct")
|
|
||||||
for fmt in (
|
|
||||||
"i", "h", "q", "d", "f", "iii", "ii", "qii", "dii", "ihihih", "ci",
|
|
||||||
"bh", "cccc"):
|
|
||||||
exec(fmt + "_struct = Struct('!" + fmt + "')")
|
|
||||||
exec(fmt + "_unpack = " + fmt + "_struct.unpack_from")
|
|
||||||
exec(fmt + "_pack = " + fmt + "_struct.pack")
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import time
|
|
||||||
from .six import binary_type, integer_types, PY2
|
|
||||||
|
|
||||||
min_int2, max_int2 = -2 ** 15, 2 ** 15
|
|
||||||
min_int4, max_int4 = -2 ** 31, 2 ** 31
|
|
||||||
min_int8, max_int8 = -2 ** 63, 2 ** 63
|
|
||||||
|
|
||||||
|
|
||||||
class Warning(Exception):
|
|
||||||
"""Generic exception raised for important database warnings like data
|
|
||||||
truncations. This exception is not currently used by pg8000.
|
|
||||||
|
|
||||||
This exception is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Error(Exception):
|
|
||||||
"""Generic exception that is the base exception of all other error
|
|
||||||
exceptions.
|
|
||||||
|
|
||||||
This exception is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceError(Error):
|
|
||||||
"""Generic exception raised for errors that are related to the database
|
|
||||||
interface rather than the database itself. For example, if the interface
|
|
||||||
attempts to use an SSL connection but the server refuses, an InterfaceError
|
|
||||||
will be raised.
|
|
||||||
|
|
||||||
This exception is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseError(Error):
|
|
||||||
"""Generic exception raised for errors that are related to the database.
|
|
||||||
This exception is currently never raised by pg8000.
|
|
||||||
|
|
||||||
This exception is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class DataError(DatabaseError):
|
|
||||||
"""Generic exception raised for errors that are due to problems with the
|
|
||||||
processed data. This exception is not currently raised by pg8000.
|
|
||||||
|
|
||||||
This exception is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class OperationalError(DatabaseError):
|
|
||||||
"""
|
|
||||||
Generic exception raised for errors that are related to the database's
|
|
||||||
operation and not necessarily under the control of the programmer. This
|
|
||||||
exception is currently never raised by pg8000.
|
|
||||||
|
|
||||||
This exception is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class IntegrityError(DatabaseError):
|
|
||||||
"""
|
|
||||||
Generic exception raised when the relational integrity of the database is
|
|
||||||
affected. This exception is not currently raised by pg8000.
|
|
||||||
|
|
||||||
This exception is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class InternalError(DatabaseError):
|
|
||||||
"""Generic exception raised when the database encounters an internal error.
|
|
||||||
This is currently only raised when unexpected state occurs in the pg8000
|
|
||||||
interface itself, and is typically the result of a interface bug.
|
|
||||||
|
|
||||||
This exception is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ProgrammingError(DatabaseError):
|
|
||||||
"""Generic exception raised for programming errors. For example, this
|
|
||||||
exception is raised if more parameter fields are in a query string than
|
|
||||||
there are available parameters.
|
|
||||||
|
|
||||||
This exception is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class NotSupportedError(DatabaseError):
|
|
||||||
"""Generic exception raised in case a method or database API was used which
|
|
||||||
is not supported by the database.
|
|
||||||
|
|
||||||
This exception is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ArrayContentNotSupportedError(NotSupportedError):
|
|
||||||
"""
|
|
||||||
Raised when attempting to transmit an array where the base type is not
|
|
||||||
supported for binary data transfer by the interface.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ArrayContentNotHomogenousError(ProgrammingError):
|
|
||||||
"""
|
|
||||||
Raised when attempting to transmit an array that doesn't contain only a
|
|
||||||
single type of object.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ArrayContentEmptyError(ProgrammingError):
|
|
||||||
"""Raised when attempting to transmit an empty array. The type oid of an
|
|
||||||
empty array cannot be determined, and so sending them is not permitted.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class ArrayDimensionsNotConsistentError(ProgrammingError):
|
|
||||||
"""
|
|
||||||
Raised when attempting to transmit an array that has inconsistent
|
|
||||||
multi-dimension sizes.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Bytea(binary_type):
|
|
||||||
"""Bytea is a str-derived class that is mapped to a PostgreSQL byte array.
|
|
||||||
This class is only used in Python 2, the built-in ``bytes`` type is used in
|
|
||||||
Python 3.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Interval(object):
|
|
||||||
"""An Interval represents a measurement of time. In PostgreSQL, an interval
|
|
||||||
is defined in the measure of months, days, and microseconds; as such, the
|
|
||||||
pg8000 interval type represents the same information.
|
|
||||||
|
|
||||||
Note that values of the :attr:`microseconds`, :attr:`days` and
|
|
||||||
:attr:`months` properties are independently measured and cannot be
|
|
||||||
converted to each other. A month may be 28, 29, 30, or 31 days, and a day
|
|
||||||
may occasionally be lengthened slightly by a leap second.
|
|
||||||
|
|
||||||
.. attribute:: microseconds
|
|
||||||
|
|
||||||
Measure of microseconds in the interval.
|
|
||||||
|
|
||||||
The microseconds value is constrained to fit into a signed 64-bit
|
|
||||||
integer. Any attempt to set a value too large or too small will result
|
|
||||||
in an OverflowError being raised.
|
|
||||||
|
|
||||||
.. attribute:: days
|
|
||||||
|
|
||||||
Measure of days in the interval.
|
|
||||||
|
|
||||||
The days value is constrained to fit into a signed 32-bit integer.
|
|
||||||
Any attempt to set a value too large or too small will result in an
|
|
||||||
OverflowError being raised.
|
|
||||||
|
|
||||||
.. attribute:: months
|
|
||||||
|
|
||||||
Measure of months in the interval.
|
|
||||||
|
|
||||||
The months value is constrained to fit into a signed 32-bit integer.
|
|
||||||
Any attempt to set a value too large or too small will result in an
|
|
||||||
OverflowError being raised.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, microseconds=0, days=0, months=0):
|
|
||||||
self.microseconds = microseconds
|
|
||||||
self.days = days
|
|
||||||
self.months = months
|
|
||||||
|
|
||||||
def _setMicroseconds(self, value):
|
|
||||||
if not isinstance(value, integer_types):
|
|
||||||
raise TypeError("microseconds must be an integer type")
|
|
||||||
elif not (min_int8 < value < max_int8):
|
|
||||||
raise OverflowError(
|
|
||||||
"microseconds must be representable as a 64-bit integer")
|
|
||||||
else:
|
|
||||||
self._microseconds = value
|
|
||||||
|
|
||||||
def _setDays(self, value):
|
|
||||||
if not isinstance(value, integer_types):
|
|
||||||
raise TypeError("days must be an integer type")
|
|
||||||
elif not (min_int4 < value < max_int4):
|
|
||||||
raise OverflowError(
|
|
||||||
"days must be representable as a 32-bit integer")
|
|
||||||
else:
|
|
||||||
self._days = value
|
|
||||||
|
|
||||||
def _setMonths(self, value):
|
|
||||||
if not isinstance(value, integer_types):
|
|
||||||
raise TypeError("months must be an integer type")
|
|
||||||
elif not (min_int4 < value < max_int4):
|
|
||||||
raise OverflowError(
|
|
||||||
"months must be representable as a 32-bit integer")
|
|
||||||
else:
|
|
||||||
self._months = value
|
|
||||||
|
|
||||||
microseconds = property(lambda self: self._microseconds, _setMicroseconds)
|
|
||||||
days = property(lambda self: self._days, _setDays)
|
|
||||||
months = property(lambda self: self._months, _setMonths)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<Interval %s months %s days %s microseconds>" % (
|
|
||||||
self.months, self.days, self.microseconds)
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return other is not None and isinstance(other, Interval) and \
|
|
||||||
self.months == other.months and self.days == other.days and \
|
|
||||||
self.microseconds == other.microseconds
|
|
||||||
|
|
||||||
def __neq__(self, other):
|
|
||||||
return not self.__eq__(other)
|
|
||||||
|
|
||||||
from .core import Connection
|
|
||||||
|
|
||||||
|
|
||||||
def connect(
|
def connect(
|
||||||
user=None, host='localhost', unix_sock=None, port=5432, database=None,
|
user=None, host='localhost', unix_sock=None, port=5432, database=None,
|
||||||
password=None, ssl=False, **kwargs):
|
password=None, ssl=False, timeout=None, **kwargs):
|
||||||
"""Creates a connection to a PostgreSQL database.
|
"""Creates a connection to a PostgreSQL database.
|
||||||
|
|
||||||
This function is part of the `DBAPI 2.0 specification
|
This function is part of the `DBAPI 2.0 specification
|
||||||
@@ -287,9 +49,7 @@ def connect(
|
|||||||
function are not defined by the specification.
|
function are not defined by the specification.
|
||||||
|
|
||||||
:param user:
|
:param user:
|
||||||
The username to connect to the PostgreSQL server with. If this is not
|
The username to connect to the PostgreSQL server with.
|
||||||
provided, pg8000 looks first for the PGUSER then the USER environment
|
|
||||||
variables.
|
|
||||||
|
|
||||||
If your server character encoding is not ``ascii`` or ``utf8``, then
|
If your server character encoding is not ``ascii`` or ``utf8``, then
|
||||||
you need to provide ``user`` as bytes, eg.
|
you need to provide ``user`` as bytes, eg.
|
||||||
@@ -325,15 +85,24 @@ def connect(
|
|||||||
authentication, the connection will fail to open. If this parameter
|
authentication, the connection will fail to open. If this parameter
|
||||||
is provided but not requested by the server, no error will occur.
|
is provided but not requested by the server, no error will occur.
|
||||||
|
|
||||||
|
If your server character encoding is not ``ascii`` or ``utf8``, then
|
||||||
|
you need to provide ``user`` as bytes, eg.
|
||||||
|
``"my_password".encode('EUC-JP')``.
|
||||||
|
|
||||||
:keyword ssl:
|
:keyword ssl:
|
||||||
Use SSL encryption for TCP/IP sockets if ``True``. Defaults to
|
Use SSL encryption for TCP/IP sockets if ``True``. Defaults to
|
||||||
``False``.
|
``False``.
|
||||||
|
|
||||||
|
:keyword timeout:
|
||||||
|
Only used with Python 3, this is the time in seconds before the
|
||||||
|
connection to the database will time out. The default is ``None`` which
|
||||||
|
means no timeout.
|
||||||
|
|
||||||
:rtype:
|
:rtype:
|
||||||
A :class:`Connection` object.
|
A :class:`Connection` object.
|
||||||
"""
|
"""
|
||||||
return Connection(
|
return Connection(
|
||||||
user, host, unix_sock, port, database, password, ssl)
|
user, host, unix_sock, port, database, password, ssl, timeout)
|
||||||
|
|
||||||
apilevel = "2.0"
|
apilevel = "2.0"
|
||||||
"""The DBAPI level supported, currently "2.0".
|
"""The DBAPI level supported, currently "2.0".
|
||||||
@@ -382,10 +151,6 @@ can be changed to any of the following values:
|
|||||||
STRING = 1043
|
STRING = 1043
|
||||||
"""String type oid."""
|
"""String type oid."""
|
||||||
|
|
||||||
if PY2:
|
|
||||||
BINARY = Bytea
|
|
||||||
else:
|
|
||||||
BINARY = bytes
|
|
||||||
|
|
||||||
NUMBER = 1700
|
NUMBER = 1700
|
||||||
"""Numeric type oid"""
|
"""Numeric type oid"""
|
||||||
@@ -396,104 +161,15 @@ DATETIME = 1114
|
|||||||
ROWID = 26
|
ROWID = 26
|
||||||
"""ROWID type oid"""
|
"""ROWID type oid"""
|
||||||
|
|
||||||
|
|
||||||
def Date(year, month, day):
|
|
||||||
"""Constuct an object holding a date value.
|
|
||||||
|
|
||||||
This function is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
|
|
||||||
:rtype: :class:`datetime.date`
|
|
||||||
"""
|
|
||||||
return datetime.date(year, month, day)
|
|
||||||
|
|
||||||
|
|
||||||
def Time(hour, minute, second):
|
|
||||||
"""Construct an object holding a time value.
|
|
||||||
|
|
||||||
This function is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
|
|
||||||
:rtype: :class:`datetime.time`
|
|
||||||
"""
|
|
||||||
return datetime.time(hour, minute, second)
|
|
||||||
|
|
||||||
|
|
||||||
def Timestamp(year, month, day, hour, minute, second):
|
|
||||||
"""Construct an object holding a timestamp value.
|
|
||||||
|
|
||||||
This function is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
|
|
||||||
:rtype: :class:`datetime.datetime`
|
|
||||||
"""
|
|
||||||
return datetime.datetime(year, month, day, hour, minute, second)
|
|
||||||
|
|
||||||
|
|
||||||
def DateFromTicks(ticks):
|
|
||||||
"""Construct an object holding a date value from the given ticks value
|
|
||||||
(number of seconds since the epoch).
|
|
||||||
|
|
||||||
This function is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
|
|
||||||
:rtype: :class:`datetime.date`
|
|
||||||
"""
|
|
||||||
return Date(*time.localtime(ticks)[:3])
|
|
||||||
|
|
||||||
|
|
||||||
def TimeFromTicks(ticks):
|
|
||||||
"""Construct an objet holding a time value from the given ticks value
|
|
||||||
(number of seconds since the epoch).
|
|
||||||
|
|
||||||
This function is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
|
|
||||||
:rtype: :class:`datetime.time`
|
|
||||||
"""
|
|
||||||
return Time(*time.localtime(ticks)[3:6])
|
|
||||||
|
|
||||||
|
|
||||||
def TimestampFromTicks(ticks):
|
|
||||||
"""Construct an object holding a timestamp value from the given ticks value
|
|
||||||
(number of seconds since the epoch).
|
|
||||||
|
|
||||||
This function is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
|
|
||||||
:rtype: :class:`datetime.datetime`
|
|
||||||
"""
|
|
||||||
return Timestamp(*time.localtime(ticks)[:6])
|
|
||||||
|
|
||||||
|
|
||||||
def Binary(value):
|
|
||||||
"""Construct an object holding binary data.
|
|
||||||
|
|
||||||
This function is part of the `DBAPI 2.0 specification
|
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
|
||||||
|
|
||||||
:rtype: :class:`pg8000.types.Bytea` for Python 2, otherwise :class:`bytes`
|
|
||||||
"""
|
|
||||||
if PY2:
|
|
||||||
return Bytea(value)
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
from .core import utc, Cursor
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
Warning, Bytea, DataError, DatabaseError, connect, InterfaceError,
|
Warning, Bytea, DataError, DatabaseError, connect, InterfaceError,
|
||||||
ProgrammingError, Error, OperationalError, IntegrityError, InternalError,
|
ProgrammingError, Error, OperationalError, IntegrityError, InternalError,
|
||||||
NotSupportedError, ArrayContentNotHomogenousError, ArrayContentEmptyError,
|
NotSupportedError, ArrayContentNotHomogenousError, ArrayContentEmptyError,
|
||||||
ArrayDimensionsNotConsistentError, ArrayContentNotSupportedError, utc,
|
ArrayDimensionsNotConsistentError, ArrayContentNotSupportedError, utc,
|
||||||
Connection, Cursor]
|
Connection, Cursor, Binary, Date, DateFromTicks, Time, TimeFromTicks,
|
||||||
|
Timestamp, TimestampFromTicks, BINARY, Interval]
|
||||||
|
|
||||||
"""Version string for pg8000.
|
"""Version string for pg8000.
|
||||||
|
|
||||||
.. versionadded:: 1.9.11
|
.. versionadded:: 1.9.11
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from ._version import get_versions
|
|
||||||
__version__ = get_versions()['version']
|
|
||||||
del get_versions
|
|
||||||
|
|||||||
@@ -6,22 +6,58 @@
|
|||||||
# that just contains the computed version number.
|
# that just contains the computed version number.
|
||||||
|
|
||||||
# This file is released into the public domain. Generated by
|
# This file is released into the public domain. Generated by
|
||||||
# versioneer-0.12 (https://github.com/warner/python-versioneer)
|
# versioneer-0.15 (https://github.com/warner/python-versioneer)
|
||||||
|
|
||||||
# these strings will be replaced by git during git-archive
|
|
||||||
git_refnames = "$Format:%d$"
|
|
||||||
git_full = "$Format:%H$"
|
|
||||||
|
|
||||||
# these strings are filled in when 'setup.py versioneer' creates _version.py
|
|
||||||
tag_prefix = ""
|
|
||||||
parentdir_prefix = "pg8000-"
|
|
||||||
versionfile_source = "pg8000/_version.py"
|
|
||||||
|
|
||||||
|
import errno
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import errno
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def get_keywords():
|
||||||
|
# these strings will be replaced by git during git-archive.
|
||||||
|
# setup.py/versioneer.py will grep for the variable names, so they must
|
||||||
|
# each be defined on a line of their own. _version.py will just call
|
||||||
|
# get_keywords().
|
||||||
|
git_refnames = " (tag: 1.10.6)"
|
||||||
|
git_full = "4098abf6be90683ab10b7b080983ed6f08476485"
|
||||||
|
keywords = {"refnames": git_refnames, "full": git_full}
|
||||||
|
return keywords
|
||||||
|
|
||||||
|
|
||||||
|
class VersioneerConfig:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_config():
|
||||||
|
# these strings are filled in when 'setup.py versioneer' creates
|
||||||
|
# _version.py
|
||||||
|
cfg = VersioneerConfig()
|
||||||
|
cfg.VCS = "git"
|
||||||
|
cfg.style = "pep440"
|
||||||
|
cfg.tag_prefix = ""
|
||||||
|
cfg.parentdir_prefix = "pg8000-"
|
||||||
|
cfg.versionfile_source = "pg8000/_version.py"
|
||||||
|
cfg.verbose = False
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
class NotThisMethod(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
LONG_VERSION_PY = {}
|
||||||
|
HANDLERS = {}
|
||||||
|
|
||||||
|
|
||||||
|
def register_vcs_handler(vcs, method): # decorator
|
||||||
|
def decorate(f):
|
||||||
|
if vcs not in HANDLERS:
|
||||||
|
HANDLERS[vcs] = {}
|
||||||
|
HANDLERS[vcs][method] = f
|
||||||
|
return f
|
||||||
|
return decorate
|
||||||
|
|
||||||
|
|
||||||
def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
|
def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
|
||||||
@@ -29,6 +65,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
|
|||||||
p = None
|
p = None
|
||||||
for c in commands:
|
for c in commands:
|
||||||
try:
|
try:
|
||||||
|
dispcmd = str([c] + args)
|
||||||
# remember shell=False, so use git.cmd on windows, not just git
|
# remember shell=False, so use git.cmd on windows, not just git
|
||||||
p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
|
p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
|
||||||
stderr=(subprocess.PIPE if hide_stderr
|
stderr=(subprocess.PIPE if hide_stderr
|
||||||
@@ -39,7 +76,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
|
|||||||
if e.errno == errno.ENOENT:
|
if e.errno == errno.ENOENT:
|
||||||
continue
|
continue
|
||||||
if verbose:
|
if verbose:
|
||||||
print("unable to run %s" % args[0])
|
print("unable to run %s" % dispcmd)
|
||||||
print(e)
|
print(e)
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
@@ -47,28 +84,30 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
|
|||||||
print("unable to find command, tried %s" % (commands,))
|
print("unable to find command, tried %s" % (commands,))
|
||||||
return None
|
return None
|
||||||
stdout = p.communicate()[0].strip()
|
stdout = p.communicate()[0].strip()
|
||||||
if sys.version >= '3':
|
if sys.version_info[0] >= 3:
|
||||||
stdout = stdout.decode()
|
stdout = stdout.decode()
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
if verbose:
|
if verbose:
|
||||||
print("unable to run %s (error)" % args[0])
|
print("unable to run %s (error)" % dispcmd)
|
||||||
return None
|
return None
|
||||||
return stdout
|
return stdout
|
||||||
|
|
||||||
|
|
||||||
def versions_from_parentdir(parentdir_prefix, root, verbose=False):
|
def versions_from_parentdir(parentdir_prefix, root, verbose):
|
||||||
# Source tarballs conventionally unpack into a directory that includes
|
# Source tarballs conventionally unpack into a directory that includes
|
||||||
# both the project name and a version string.
|
# both the project name and a version string.
|
||||||
dirname = os.path.basename(root)
|
dirname = os.path.basename(root)
|
||||||
if not dirname.startswith(parentdir_prefix):
|
if not dirname.startswith(parentdir_prefix):
|
||||||
if verbose:
|
if verbose:
|
||||||
print(
|
print("guessing rootdir is '%s', but '%s' doesn't start with "
|
||||||
"guessing rootdir is '%s', but '%s' doesn't start with "
|
"prefix '%s'" % (root, dirname, parentdir_prefix))
|
||||||
"prefix '%s'" % (root, dirname, parentdir_prefix))
|
raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
|
||||||
return None
|
return {"version": dirname[len(parentdir_prefix):],
|
||||||
return {"version": dirname[len(parentdir_prefix):], "full": ""}
|
"full-revisionid": None,
|
||||||
|
"dirty": False, "error": None}
|
||||||
|
|
||||||
|
|
||||||
|
@register_vcs_handler("git", "get_keywords")
|
||||||
def git_get_keywords(versionfile_abs):
|
def git_get_keywords(versionfile_abs):
|
||||||
# the code embedded in _version.py can just fetch the value of these
|
# the code embedded in _version.py can just fetch the value of these
|
||||||
# keywords. When used from setup.py, we don't want to import _version.py,
|
# keywords. When used from setup.py, we don't want to import _version.py,
|
||||||
@@ -92,14 +131,15 @@ def git_get_keywords(versionfile_abs):
|
|||||||
return keywords
|
return keywords
|
||||||
|
|
||||||
|
|
||||||
def git_versions_from_keywords(keywords, tag_prefix, verbose=False):
|
@register_vcs_handler("git", "keywords")
|
||||||
|
def git_versions_from_keywords(keywords, tag_prefix, verbose):
|
||||||
if not keywords:
|
if not keywords:
|
||||||
return {} # keyword-finding function failed to find keywords
|
raise NotThisMethod("no keywords at all, weird")
|
||||||
refnames = keywords["refnames"].strip()
|
refnames = keywords["refnames"].strip()
|
||||||
if refnames.startswith("$Format"):
|
if refnames.startswith("$Format"):
|
||||||
if verbose:
|
if verbose:
|
||||||
print("keywords are unexpanded, not using")
|
print("keywords are unexpanded, not using")
|
||||||
return {} # unexpanded, so not in an unpacked git-archive tarball
|
raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
|
||||||
refs = set([r.strip() for r in refnames.strip("()").split(",")])
|
refs = set([r.strip() for r in refnames.strip("()").split(",")])
|
||||||
# starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
|
# starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
|
||||||
# just "foo-1.0". If we see a "tag: " prefix, prefer those.
|
# just "foo-1.0". If we see a "tag: " prefix, prefer those.
|
||||||
@@ -124,18 +164,20 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose=False):
|
|||||||
r = ref[len(tag_prefix):]
|
r = ref[len(tag_prefix):]
|
||||||
if verbose:
|
if verbose:
|
||||||
print("picking %s" % r)
|
print("picking %s" % r)
|
||||||
return {
|
return {"version": r,
|
||||||
"version": r,
|
"full-revisionid": keywords["full"].strip(),
|
||||||
"full": keywords["full"].strip()}
|
"dirty": False, "error": None
|
||||||
# no suitable tags, so we use the full revision id
|
}
|
||||||
|
# no suitable tags, so version is "0+unknown", but full hex is still there
|
||||||
if verbose:
|
if verbose:
|
||||||
print("no suitable tags, using full revision id")
|
print("no suitable tags, using unknown + full revision id")
|
||||||
return {
|
return {"version": "0+unknown",
|
||||||
"version": keywords["full"].strip(),
|
"full-revisionid": keywords["full"].strip(),
|
||||||
"full": keywords["full"].strip()}
|
"dirty": False, "error": "no suitable tags"}
|
||||||
|
|
||||||
|
|
||||||
def git_versions_from_vcs(tag_prefix, root, verbose=False):
|
@register_vcs_handler("git", "pieces_from_vcs")
|
||||||
|
def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
|
||||||
# this runs 'git' from the root of the source tree. This only gets called
|
# this runs 'git' from the root of the source tree. This only gets called
|
||||||
# if the git-archive 'subst' keywords were *not* expanded, and
|
# if the git-archive 'subst' keywords were *not* expanded, and
|
||||||
# _version.py hasn't already been rewritten with a short version string,
|
# _version.py hasn't already been rewritten with a short version string,
|
||||||
@@ -144,52 +186,275 @@ def git_versions_from_vcs(tag_prefix, root, verbose=False):
|
|||||||
if not os.path.exists(os.path.join(root, ".git")):
|
if not os.path.exists(os.path.join(root, ".git")):
|
||||||
if verbose:
|
if verbose:
|
||||||
print("no .git in %s" % root)
|
print("no .git in %s" % root)
|
||||||
return {}
|
raise NotThisMethod("no .git directory")
|
||||||
|
|
||||||
GITS = ["git"]
|
GITS = ["git"]
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
GITS = ["git.cmd", "git.exe"]
|
GITS = ["git.cmd", "git.exe"]
|
||||||
stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"],
|
# if there is a tag, this yields TAG-NUM-gHEX[-dirty]
|
||||||
cwd=root)
|
# if there are no tags, this yields HEX[-dirty] (no NUM)
|
||||||
if stdout is None:
|
describe_out = run_command(GITS, ["describe", "--tags", "--dirty",
|
||||||
return {}
|
"--always", "--long"],
|
||||||
if not stdout.startswith(tag_prefix):
|
cwd=root)
|
||||||
if verbose:
|
# --long was added in git-1.5.5
|
||||||
print(
|
if describe_out is None:
|
||||||
"tag '%s' doesn't start with prefix '%s'" %
|
raise NotThisMethod("'git describe' failed")
|
||||||
(stdout, tag_prefix))
|
describe_out = describe_out.strip()
|
||||||
return {}
|
full_out = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
|
||||||
tag = stdout[len(tag_prefix):]
|
if full_out is None:
|
||||||
stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
|
raise NotThisMethod("'git rev-parse' failed")
|
||||||
if stdout is None:
|
full_out = full_out.strip()
|
||||||
return {}
|
|
||||||
full = stdout.strip()
|
pieces = {}
|
||||||
if tag.endswith("-dirty"):
|
pieces["long"] = full_out
|
||||||
full += "-dirty"
|
pieces["short"] = full_out[:7] # maybe improved later
|
||||||
return {"version": tag, "full": full}
|
pieces["error"] = None
|
||||||
|
|
||||||
|
# parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
|
||||||
|
# TAG might have hyphens.
|
||||||
|
git_describe = describe_out
|
||||||
|
|
||||||
|
# look for -dirty suffix
|
||||||
|
dirty = git_describe.endswith("-dirty")
|
||||||
|
pieces["dirty"] = dirty
|
||||||
|
if dirty:
|
||||||
|
git_describe = git_describe[:git_describe.rindex("-dirty")]
|
||||||
|
|
||||||
|
# now we have TAG-NUM-gHEX or HEX
|
||||||
|
|
||||||
|
if "-" in git_describe:
|
||||||
|
# TAG-NUM-gHEX
|
||||||
|
mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
|
||||||
|
if not mo:
|
||||||
|
# unparseable. Maybe git-describe is misbehaving?
|
||||||
|
pieces["error"] = ("unable to parse git-describe output: '%s'"
|
||||||
|
% describe_out)
|
||||||
|
return pieces
|
||||||
|
|
||||||
|
# tag
|
||||||
|
full_tag = mo.group(1)
|
||||||
|
if not full_tag.startswith(tag_prefix):
|
||||||
|
if verbose:
|
||||||
|
fmt = "tag '%s' doesn't start with prefix '%s'"
|
||||||
|
print(fmt % (full_tag, tag_prefix))
|
||||||
|
pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
|
||||||
|
% (full_tag, tag_prefix))
|
||||||
|
return pieces
|
||||||
|
pieces["closest-tag"] = full_tag[len(tag_prefix):]
|
||||||
|
|
||||||
|
# distance: number of commits since tag
|
||||||
|
pieces["distance"] = int(mo.group(2))
|
||||||
|
|
||||||
|
# commit: short hex revision ID
|
||||||
|
pieces["short"] = mo.group(3)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# HEX: no tags
|
||||||
|
pieces["closest-tag"] = None
|
||||||
|
count_out = run_command(GITS, ["rev-list", "HEAD", "--count"],
|
||||||
|
cwd=root)
|
||||||
|
pieces["distance"] = int(count_out) # total number of commits
|
||||||
|
|
||||||
|
return pieces
|
||||||
|
|
||||||
|
|
||||||
def get_versions(default={"version": "unknown", "full": ""}, verbose=False):
|
def plus_or_dot(pieces):
|
||||||
|
if "+" in pieces.get("closest-tag", ""):
|
||||||
|
return "."
|
||||||
|
return "+"
|
||||||
|
|
||||||
|
|
||||||
|
def render_pep440(pieces):
|
||||||
|
# now build up version string, with post-release "local version
|
||||||
|
# identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
|
||||||
|
# get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
|
||||||
|
|
||||||
|
# exceptions:
|
||||||
|
# 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
|
||||||
|
|
||||||
|
if pieces["closest-tag"]:
|
||||||
|
rendered = pieces["closest-tag"]
|
||||||
|
if pieces["distance"] or pieces["dirty"]:
|
||||||
|
rendered += plus_or_dot(pieces)
|
||||||
|
rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
|
||||||
|
if pieces["dirty"]:
|
||||||
|
rendered += ".dirty"
|
||||||
|
else:
|
||||||
|
# exception #1
|
||||||
|
rendered = "0+untagged.%d.g%s" % (pieces["distance"],
|
||||||
|
pieces["short"])
|
||||||
|
if pieces["dirty"]:
|
||||||
|
rendered += ".dirty"
|
||||||
|
return rendered
|
||||||
|
|
||||||
|
|
||||||
|
def render_pep440_pre(pieces):
|
||||||
|
# TAG[.post.devDISTANCE] . No -dirty
|
||||||
|
|
||||||
|
# exceptions:
|
||||||
|
# 1: no tags. 0.post.devDISTANCE
|
||||||
|
|
||||||
|
if pieces["closest-tag"]:
|
||||||
|
rendered = pieces["closest-tag"]
|
||||||
|
if pieces["distance"]:
|
||||||
|
rendered += ".post.dev%d" % pieces["distance"]
|
||||||
|
else:
|
||||||
|
# exception #1
|
||||||
|
rendered = "0.post.dev%d" % pieces["distance"]
|
||||||
|
return rendered
|
||||||
|
|
||||||
|
|
||||||
|
def render_pep440_post(pieces):
|
||||||
|
# TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that
|
||||||
|
# .dev0 sorts backwards (a dirty tree will appear "older" than the
|
||||||
|
# corresponding clean one), but you shouldn't be releasing software with
|
||||||
|
# -dirty anyways.
|
||||||
|
|
||||||
|
# exceptions:
|
||||||
|
# 1: no tags. 0.postDISTANCE[.dev0]
|
||||||
|
|
||||||
|
if pieces["closest-tag"]:
|
||||||
|
rendered = pieces["closest-tag"]
|
||||||
|
if pieces["distance"] or pieces["dirty"]:
|
||||||
|
rendered += ".post%d" % pieces["distance"]
|
||||||
|
if pieces["dirty"]:
|
||||||
|
rendered += ".dev0"
|
||||||
|
rendered += plus_or_dot(pieces)
|
||||||
|
rendered += "g%s" % pieces["short"]
|
||||||
|
else:
|
||||||
|
# exception #1
|
||||||
|
rendered = "0.post%d" % pieces["distance"]
|
||||||
|
if pieces["dirty"]:
|
||||||
|
rendered += ".dev0"
|
||||||
|
rendered += "+g%s" % pieces["short"]
|
||||||
|
return rendered
|
||||||
|
|
||||||
|
|
||||||
|
def render_pep440_old(pieces):
|
||||||
|
# TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty.
|
||||||
|
|
||||||
|
# exceptions:
|
||||||
|
# 1: no tags. 0.postDISTANCE[.dev0]
|
||||||
|
|
||||||
|
if pieces["closest-tag"]:
|
||||||
|
rendered = pieces["closest-tag"]
|
||||||
|
if pieces["distance"] or pieces["dirty"]:
|
||||||
|
rendered += ".post%d" % pieces["distance"]
|
||||||
|
if pieces["dirty"]:
|
||||||
|
rendered += ".dev0"
|
||||||
|
else:
|
||||||
|
# exception #1
|
||||||
|
rendered = "0.post%d" % pieces["distance"]
|
||||||
|
if pieces["dirty"]:
|
||||||
|
rendered += ".dev0"
|
||||||
|
return rendered
|
||||||
|
|
||||||
|
|
||||||
|
def render_git_describe(pieces):
|
||||||
|
# TAG[-DISTANCE-gHEX][-dirty], like 'git describe --tags --dirty
|
||||||
|
# --always'
|
||||||
|
|
||||||
|
# exceptions:
|
||||||
|
# 1: no tags. HEX[-dirty] (note: no 'g' prefix)
|
||||||
|
|
||||||
|
if pieces["closest-tag"]:
|
||||||
|
rendered = pieces["closest-tag"]
|
||||||
|
if pieces["distance"]:
|
||||||
|
rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
|
||||||
|
else:
|
||||||
|
# exception #1
|
||||||
|
rendered = pieces["short"]
|
||||||
|
if pieces["dirty"]:
|
||||||
|
rendered += "-dirty"
|
||||||
|
return rendered
|
||||||
|
|
||||||
|
|
||||||
|
def render_git_describe_long(pieces):
|
||||||
|
# TAG-DISTANCE-gHEX[-dirty], like 'git describe --tags --dirty
|
||||||
|
# --always -long'. The distance/hash is unconditional.
|
||||||
|
|
||||||
|
# exceptions:
|
||||||
|
# 1: no tags. HEX[-dirty] (note: no 'g' prefix)
|
||||||
|
|
||||||
|
if pieces["closest-tag"]:
|
||||||
|
rendered = pieces["closest-tag"]
|
||||||
|
rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
|
||||||
|
else:
|
||||||
|
# exception #1
|
||||||
|
rendered = pieces["short"]
|
||||||
|
if pieces["dirty"]:
|
||||||
|
rendered += "-dirty"
|
||||||
|
return rendered
|
||||||
|
|
||||||
|
|
||||||
|
def render(pieces, style):
|
||||||
|
if pieces["error"]:
|
||||||
|
return {"version": "unknown",
|
||||||
|
"full-revisionid": pieces.get("long"),
|
||||||
|
"dirty": None,
|
||||||
|
"error": pieces["error"]}
|
||||||
|
|
||||||
|
if not style or style == "default":
|
||||||
|
style = "pep440" # the default
|
||||||
|
|
||||||
|
if style == "pep440":
|
||||||
|
rendered = render_pep440(pieces)
|
||||||
|
elif style == "pep440-pre":
|
||||||
|
rendered = render_pep440_pre(pieces)
|
||||||
|
elif style == "pep440-post":
|
||||||
|
rendered = render_pep440_post(pieces)
|
||||||
|
elif style == "pep440-old":
|
||||||
|
rendered = render_pep440_old(pieces)
|
||||||
|
elif style == "git-describe":
|
||||||
|
rendered = render_git_describe(pieces)
|
||||||
|
elif style == "git-describe-long":
|
||||||
|
rendered = render_git_describe_long(pieces)
|
||||||
|
else:
|
||||||
|
raise ValueError("unknown style '%s'" % style)
|
||||||
|
|
||||||
|
return {"version": rendered, "full-revisionid": pieces["long"],
|
||||||
|
"dirty": pieces["dirty"], "error": None}
|
||||||
|
|
||||||
|
|
||||||
|
def get_versions():
|
||||||
# I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
|
# I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
|
||||||
# __file__, we can work backwards from there to the root. Some
|
# __file__, we can work backwards from there to the root. Some
|
||||||
# py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
|
# py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
|
||||||
# case we can only use expanded keywords.
|
# case we can only use expanded keywords.
|
||||||
|
|
||||||
keywords = {"refnames": git_refnames, "full": git_full}
|
cfg = get_config()
|
||||||
ver = git_versions_from_keywords(keywords, tag_prefix, verbose)
|
verbose = cfg.verbose
|
||||||
if ver:
|
|
||||||
return ver
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
root = os.path.abspath(__file__)
|
return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
|
||||||
|
verbose)
|
||||||
|
except NotThisMethod:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
root = os.path.realpath(__file__)
|
||||||
# versionfile_source is the relative path from the top of the source
|
# versionfile_source is the relative path from the top of the source
|
||||||
# tree (where the .git directory might live) to this file. Invert
|
# tree (where the .git directory might live) to this file. Invert
|
||||||
# this to find the root from __file__.
|
# this to find the root from __file__.
|
||||||
for i in range(len(versionfile_source.split(os.sep))):
|
for i in cfg.versionfile_source.split('/'):
|
||||||
root = os.path.dirname(root)
|
root = os.path.dirname(root)
|
||||||
except NameError:
|
except NameError:
|
||||||
return default
|
return {"version": "0+unknown", "full-revisionid": None,
|
||||||
|
"dirty": None,
|
||||||
|
"error": "unable to find root of source tree"}
|
||||||
|
|
||||||
return (git_versions_from_vcs(tag_prefix, root, verbose)
|
try:
|
||||||
or versions_from_parentdir(parentdir_prefix, root, verbose)
|
pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
|
||||||
or default)
|
return render(pieces, cfg.style)
|
||||||
|
except NotThisMethod:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
if cfg.parentdir_prefix:
|
||||||
|
return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
|
||||||
|
except NotThisMethod:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return {"version": "0+unknown", "full-revisionid": None,
|
||||||
|
"dirty": None,
|
||||||
|
"error": "unable to compute version"}
|
||||||
|
|||||||
+481
-162
@@ -1,3 +1,23 @@
|
|||||||
|
import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
from warnings import warn
|
||||||
|
import socket
|
||||||
|
import threading
|
||||||
|
from struct import pack
|
||||||
|
from hashlib import md5
|
||||||
|
from decimal import Decimal
|
||||||
|
from collections import deque, defaultdict
|
||||||
|
from itertools import count, islice
|
||||||
|
from .six.moves import map
|
||||||
|
from .six import b, PY2, integer_types, next, text_type, u, binary_type
|
||||||
|
from uuid import UUID
|
||||||
|
from copy import deepcopy
|
||||||
|
from calendar import timegm
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
from struct import Struct
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
# Copyright (c) 2007-2009, Mathieu Fenniak
|
# Copyright (c) 2007-2009, Mathieu Fenniak
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
@@ -27,34 +47,6 @@
|
|||||||
|
|
||||||
__author__ = "Mathieu Fenniak"
|
__author__ = "Mathieu Fenniak"
|
||||||
|
|
||||||
import datetime
|
|
||||||
from datetime import timedelta
|
|
||||||
from . import (
|
|
||||||
Interval, min_int2, max_int2, min_int4, max_int4, min_int8, max_int8,
|
|
||||||
Bytea, NotSupportedError, ProgrammingError, InternalError, IntegrityError,
|
|
||||||
OperationalError, DatabaseError, InterfaceError, Error,
|
|
||||||
ArrayContentNotHomogenousError, ArrayContentEmptyError,
|
|
||||||
ArrayDimensionsNotConsistentError, ArrayContentNotSupportedError, Warning,
|
|
||||||
i_unpack, ii_unpack, iii_unpack, h_pack, d_unpack, q_unpack, d_pack,
|
|
||||||
f_unpack, q_pack, i_pack, h_unpack, dii_unpack, qii_unpack, ci_unpack,
|
|
||||||
bh_unpack, ihihih_unpack, cccc_unpack, ii_pack, iii_pack, dii_pack,
|
|
||||||
qii_pack)
|
|
||||||
from warnings import warn
|
|
||||||
import socket
|
|
||||||
import threading
|
|
||||||
from struct import pack
|
|
||||||
from hashlib import md5
|
|
||||||
from decimal import Decimal
|
|
||||||
from collections import deque, defaultdict
|
|
||||||
from itertools import count, islice
|
|
||||||
from .six.moves import map
|
|
||||||
from .six import b, PY2, integer_types, next, PRE_26, text_type, u
|
|
||||||
from sys import exc_info
|
|
||||||
from uuid import UUID
|
|
||||||
from copy import deepcopy
|
|
||||||
from calendar import timegm
|
|
||||||
import os
|
|
||||||
from distutils.version import LooseVersion
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from json import loads
|
from json import loads
|
||||||
@@ -78,9 +70,350 @@ class UTC(datetime.tzinfo):
|
|||||||
|
|
||||||
utc = UTC()
|
utc = UTC()
|
||||||
|
|
||||||
if PRE_26:
|
|
||||||
bytearray = list
|
|
||||||
|
|
||||||
|
class Interval(object):
|
||||||
|
"""An Interval represents a measurement of time. In PostgreSQL, an
|
||||||
|
interval is defined in the measure of months, days, and microseconds; as
|
||||||
|
such, the pg8000 interval type represents the same information.
|
||||||
|
|
||||||
|
Note that values of the :attr:`microseconds`, :attr:`days` and
|
||||||
|
:attr:`months` properties are independently measured and cannot be
|
||||||
|
converted to each other. A month may be 28, 29, 30, or 31 days, and a day
|
||||||
|
may occasionally be lengthened slightly by a leap second.
|
||||||
|
|
||||||
|
.. attribute:: microseconds
|
||||||
|
|
||||||
|
Measure of microseconds in the interval.
|
||||||
|
|
||||||
|
The microseconds value is constrained to fit into a signed 64-bit
|
||||||
|
integer. Any attempt to set a value too large or too small will result
|
||||||
|
in an OverflowError being raised.
|
||||||
|
|
||||||
|
.. attribute:: days
|
||||||
|
|
||||||
|
Measure of days in the interval.
|
||||||
|
|
||||||
|
The days value is constrained to fit into a signed 32-bit integer.
|
||||||
|
Any attempt to set a value too large or too small will result in an
|
||||||
|
OverflowError being raised.
|
||||||
|
|
||||||
|
.. attribute:: months
|
||||||
|
|
||||||
|
Measure of months in the interval.
|
||||||
|
|
||||||
|
The months value is constrained to fit into a signed 32-bit integer.
|
||||||
|
Any attempt to set a value too large or too small will result in an
|
||||||
|
OverflowError being raised.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, microseconds=0, days=0, months=0):
|
||||||
|
self.microseconds = microseconds
|
||||||
|
self.days = days
|
||||||
|
self.months = months
|
||||||
|
|
||||||
|
def _setMicroseconds(self, value):
|
||||||
|
if not isinstance(value, integer_types):
|
||||||
|
raise TypeError("microseconds must be an integer type")
|
||||||
|
elif not (min_int8 < value < max_int8):
|
||||||
|
raise OverflowError(
|
||||||
|
"microseconds must be representable as a 64-bit integer")
|
||||||
|
else:
|
||||||
|
self._microseconds = value
|
||||||
|
|
||||||
|
def _setDays(self, value):
|
||||||
|
if not isinstance(value, integer_types):
|
||||||
|
raise TypeError("days must be an integer type")
|
||||||
|
elif not (min_int4 < value < max_int4):
|
||||||
|
raise OverflowError(
|
||||||
|
"days must be representable as a 32-bit integer")
|
||||||
|
else:
|
||||||
|
self._days = value
|
||||||
|
|
||||||
|
def _setMonths(self, value):
|
||||||
|
if not isinstance(value, integer_types):
|
||||||
|
raise TypeError("months must be an integer type")
|
||||||
|
elif not (min_int4 < value < max_int4):
|
||||||
|
raise OverflowError(
|
||||||
|
"months must be representable as a 32-bit integer")
|
||||||
|
else:
|
||||||
|
self._months = value
|
||||||
|
|
||||||
|
microseconds = property(lambda self: self._microseconds, _setMicroseconds)
|
||||||
|
days = property(lambda self: self._days, _setDays)
|
||||||
|
months = property(lambda self: self._months, _setMonths)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Interval %s months %s days %s microseconds>" % (
|
||||||
|
self.months, self.days, self.microseconds)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return other is not None and isinstance(other, Interval) and \
|
||||||
|
self.months == other.months and self.days == other.days and \
|
||||||
|
self.microseconds == other.microseconds
|
||||||
|
|
||||||
|
def __neq__(self, other):
|
||||||
|
return not self.__eq__(other)
|
||||||
|
|
||||||
|
|
||||||
|
def pack_funcs(fmt):
|
||||||
|
struc = Struct('!' + fmt)
|
||||||
|
return struc.pack, struc.unpack_from
|
||||||
|
|
||||||
|
i_pack, i_unpack = pack_funcs('i')
|
||||||
|
h_pack, h_unpack = pack_funcs('h')
|
||||||
|
q_pack, q_unpack = pack_funcs('q')
|
||||||
|
d_pack, d_unpack = pack_funcs('d')
|
||||||
|
f_pack, f_unpack = pack_funcs('f')
|
||||||
|
iii_pack, iii_unpack = pack_funcs('iii')
|
||||||
|
ii_pack, ii_unpack = pack_funcs('ii')
|
||||||
|
qii_pack, qii_unpack = pack_funcs('qii')
|
||||||
|
dii_pack, dii_unpack = pack_funcs('dii')
|
||||||
|
ihihih_pack, ihihih_unpack = pack_funcs('ihihih')
|
||||||
|
ci_pack, ci_unpack = pack_funcs('ci')
|
||||||
|
bh_pack, bh_unpack = pack_funcs('bh')
|
||||||
|
cccc_pack, cccc_unpack = pack_funcs('cccc')
|
||||||
|
|
||||||
|
|
||||||
|
Struct('!i')
|
||||||
|
|
||||||
|
|
||||||
|
min_int2, max_int2 = -2 ** 15, 2 ** 15
|
||||||
|
min_int4, max_int4 = -2 ** 31, 2 ** 31
|
||||||
|
min_int8, max_int8 = -2 ** 63, 2 ** 63
|
||||||
|
|
||||||
|
|
||||||
|
class Warning(Exception):
|
||||||
|
"""Generic exception raised for important database warnings like data
|
||||||
|
truncations. This exception is not currently used by pg8000.
|
||||||
|
|
||||||
|
This exception is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Error(Exception):
|
||||||
|
"""Generic exception that is the base exception of all other error
|
||||||
|
exceptions.
|
||||||
|
|
||||||
|
This exception is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InterfaceError(Error):
|
||||||
|
"""Generic exception raised for errors that are related to the database
|
||||||
|
interface rather than the database itself. For example, if the interface
|
||||||
|
attempts to use an SSL connection but the server refuses, an InterfaceError
|
||||||
|
will be raised.
|
||||||
|
|
||||||
|
This exception is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseError(Error):
|
||||||
|
"""Generic exception raised for errors that are related to the database.
|
||||||
|
This exception is currently never raised by pg8000.
|
||||||
|
|
||||||
|
This exception is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DataError(DatabaseError):
|
||||||
|
"""Generic exception raised for errors that are due to problems with the
|
||||||
|
processed data. This exception is not currently raised by pg8000.
|
||||||
|
|
||||||
|
This exception is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class OperationalError(DatabaseError):
|
||||||
|
"""
|
||||||
|
Generic exception raised for errors that are related to the database's
|
||||||
|
operation and not necessarily under the control of the programmer. This
|
||||||
|
exception is currently never raised by pg8000.
|
||||||
|
|
||||||
|
This exception is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IntegrityError(DatabaseError):
|
||||||
|
"""
|
||||||
|
Generic exception raised when the relational integrity of the database is
|
||||||
|
affected. This exception is not currently raised by pg8000.
|
||||||
|
|
||||||
|
This exception is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InternalError(DatabaseError):
|
||||||
|
"""Generic exception raised when the database encounters an internal error.
|
||||||
|
This is currently only raised when unexpected state occurs in the pg8000
|
||||||
|
interface itself, and is typically the result of a interface bug.
|
||||||
|
|
||||||
|
This exception is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ProgrammingError(DatabaseError):
|
||||||
|
"""Generic exception raised for programming errors. For example, this
|
||||||
|
exception is raised if more parameter fields are in a query string than
|
||||||
|
there are available parameters.
|
||||||
|
|
||||||
|
This exception is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NotSupportedError(DatabaseError):
|
||||||
|
"""Generic exception raised in case a method or database API was used which
|
||||||
|
is not supported by the database.
|
||||||
|
|
||||||
|
This exception is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayContentNotSupportedError(NotSupportedError):
|
||||||
|
"""
|
||||||
|
Raised when attempting to transmit an array where the base type is not
|
||||||
|
supported for binary data transfer by the interface.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayContentNotHomogenousError(ProgrammingError):
|
||||||
|
"""
|
||||||
|
Raised when attempting to transmit an array that doesn't contain only a
|
||||||
|
single type of object.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayContentEmptyError(ProgrammingError):
|
||||||
|
"""Raised when attempting to transmit an empty array. The type oid of an
|
||||||
|
empty array cannot be determined, and so sending them is not permitted.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayDimensionsNotConsistentError(ProgrammingError):
|
||||||
|
"""
|
||||||
|
Raised when attempting to transmit an array that has inconsistent
|
||||||
|
multi-dimension sizes.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Bytea(binary_type):
|
||||||
|
"""Bytea is a str-derived class that is mapped to a PostgreSQL byte array.
|
||||||
|
This class is only used in Python 2, the built-in ``bytes`` type is used in
|
||||||
|
Python 3.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def Date(year, month, day):
|
||||||
|
"""Constuct an object holding a date value.
|
||||||
|
|
||||||
|
This function is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
|
||||||
|
:rtype: :class:`datetime.date`
|
||||||
|
"""
|
||||||
|
return datetime.date(year, month, day)
|
||||||
|
|
||||||
|
|
||||||
|
def Time(hour, minute, second):
|
||||||
|
"""Construct an object holding a time value.
|
||||||
|
|
||||||
|
This function is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
|
||||||
|
:rtype: :class:`datetime.time`
|
||||||
|
"""
|
||||||
|
return datetime.time(hour, minute, second)
|
||||||
|
|
||||||
|
|
||||||
|
def Timestamp(year, month, day, hour, minute, second):
|
||||||
|
"""Construct an object holding a timestamp value.
|
||||||
|
|
||||||
|
This function is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
|
||||||
|
:rtype: :class:`datetime.datetime`
|
||||||
|
"""
|
||||||
|
return datetime.datetime(year, month, day, hour, minute, second)
|
||||||
|
|
||||||
|
|
||||||
|
def DateFromTicks(ticks):
|
||||||
|
"""Construct an object holding a date value from the given ticks value
|
||||||
|
(number of seconds since the epoch).
|
||||||
|
|
||||||
|
This function is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
|
||||||
|
:rtype: :class:`datetime.date`
|
||||||
|
"""
|
||||||
|
return Date(*time.localtime(ticks)[:3])
|
||||||
|
|
||||||
|
|
||||||
|
def TimeFromTicks(ticks):
|
||||||
|
"""Construct an objet holding a time value from the given ticks value
|
||||||
|
(number of seconds since the epoch).
|
||||||
|
|
||||||
|
This function is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
|
||||||
|
:rtype: :class:`datetime.time`
|
||||||
|
"""
|
||||||
|
return Time(*time.localtime(ticks)[3:6])
|
||||||
|
|
||||||
|
|
||||||
|
def TimestampFromTicks(ticks):
|
||||||
|
"""Construct an object holding a timestamp value from the given ticks value
|
||||||
|
(number of seconds since the epoch).
|
||||||
|
|
||||||
|
This function is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
|
||||||
|
:rtype: :class:`datetime.datetime`
|
||||||
|
"""
|
||||||
|
return Timestamp(*time.localtime(ticks)[:6])
|
||||||
|
|
||||||
|
|
||||||
|
def Binary(value):
|
||||||
|
"""Construct an object holding binary data.
|
||||||
|
|
||||||
|
This function is part of the `DBAPI 2.0 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
|
|
||||||
|
:rtype: :class:`pg8000.types.Bytea` for Python 2, otherwise :class:`bytes`
|
||||||
|
"""
|
||||||
|
if PY2:
|
||||||
|
return Bytea(value)
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
|
if PY2:
|
||||||
|
BINARY = Bytea
|
||||||
|
else:
|
||||||
|
BINARY = bytes
|
||||||
|
|
||||||
FC_TEXT = 0
|
FC_TEXT = 0
|
||||||
FC_BINARY = 1
|
FC_BINARY = 1
|
||||||
@@ -271,13 +604,13 @@ def timestamp_recv_integer(data, offset, length):
|
|||||||
micros = q_unpack(data, offset)[0]
|
micros = q_unpack(data, offset)[0]
|
||||||
try:
|
try:
|
||||||
return EPOCH + timedelta(microseconds=micros)
|
return EPOCH + timedelta(microseconds=micros)
|
||||||
except OverflowError:
|
except OverflowError as e:
|
||||||
if micros == INFINITY_MICROSECONDS:
|
if micros == INFINITY_MICROSECONDS:
|
||||||
return datetime.datetime.max
|
return datetime.datetime.max
|
||||||
elif micros == MINUS_INFINITY_MICROSECONDS:
|
elif micros == MINUS_INFINITY_MICROSECONDS:
|
||||||
return datetime.datetime.min
|
return datetime.datetime.min
|
||||||
else:
|
else:
|
||||||
raise exc_info()[1]
|
raise e
|
||||||
|
|
||||||
|
|
||||||
# data is double-precision float representing seconds since 2000-01-01
|
# data is double-precision float representing seconds since 2000-01-01
|
||||||
@@ -299,7 +632,7 @@ def timestamp_send_integer(v):
|
|||||||
|
|
||||||
# data is double-precision float representing seconds since 2000-01-01
|
# data is double-precision float representing seconds since 2000-01-01
|
||||||
def timestamp_send_float(v):
|
def timestamp_send_float(v):
|
||||||
return d_pack(timegm(v.timetuple) + v.microsecond / 1e6 - EPOCH_SECONDS)
|
return d_pack(timegm(v.timetuple()) + v.microsecond / 1e6 - EPOCH_SECONDS)
|
||||||
|
|
||||||
|
|
||||||
def timestamptz_send_integer(v):
|
def timestamptz_send_integer(v):
|
||||||
@@ -325,13 +658,13 @@ def timestamptz_recv_integer(data, offset, length):
|
|||||||
micros = q_unpack(data, offset)[0]
|
micros = q_unpack(data, offset)[0]
|
||||||
try:
|
try:
|
||||||
return EPOCH_TZ + timedelta(microseconds=micros)
|
return EPOCH_TZ + timedelta(microseconds=micros)
|
||||||
except OverflowError:
|
except OverflowError as e:
|
||||||
if micros == INFINITY_MICROSECONDS:
|
if micros == INFINITY_MICROSECONDS:
|
||||||
return DATETIME_MAX_TZ
|
return DATETIME_MAX_TZ
|
||||||
elif micros == MINUS_INFINITY_MICROSECONDS:
|
elif micros == MINUS_INFINITY_MICROSECONDS:
|
||||||
return DATETIME_MIN_TZ
|
return DATETIME_MIN_TZ
|
||||||
else:
|
else:
|
||||||
raise exc_info()[1]
|
raise e
|
||||||
|
|
||||||
|
|
||||||
def timestamptz_recv_float(data, offset, length):
|
def timestamptz_recv_float(data, offset, length):
|
||||||
@@ -565,21 +898,19 @@ class Cursor():
|
|||||||
.. versionadded:: 1.9.11
|
.. versionadded:: 1.9.11
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self._c._lock.acquire()
|
with self._c._lock:
|
||||||
self.stream = stream
|
self.stream = stream
|
||||||
|
|
||||||
if not self._c.in_transaction and not self._c.autocommit:
|
if not self._c.in_transaction and not self._c.autocommit:
|
||||||
self._c.execute(self, "begin transaction", None)
|
self._c.execute(self, "begin transaction", None)
|
||||||
self._c.execute(self, operation, args)
|
self._c.execute(self, operation, args)
|
||||||
except AttributeError:
|
except AttributeError as e:
|
||||||
if self._c is None:
|
if self._c is None:
|
||||||
raise InterfaceError("Cursor closed")
|
raise InterfaceError("Cursor closed")
|
||||||
elif self._c._sock is None:
|
elif self._c._sock is None:
|
||||||
raise InterfaceError("connection is closed")
|
raise InterfaceError("connection is closed")
|
||||||
else:
|
else:
|
||||||
raise exc_info()[1]
|
raise e
|
||||||
finally:
|
|
||||||
self._c._lock.release()
|
|
||||||
|
|
||||||
def executemany(self, operation, param_sets):
|
def executemany(self, operation, param_sets):
|
||||||
"""Prepare a database operation, and then execute it against all
|
"""Prepare a database operation, and then execute it against all
|
||||||
@@ -690,28 +1021,26 @@ class Cursor():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def __next__(self):
|
def __next__(self):
|
||||||
try:
|
with self._c._lock:
|
||||||
self._c._lock.acquire()
|
|
||||||
return self._cached_rows.popleft()
|
|
||||||
except IndexError:
|
|
||||||
if self.portal_suspended:
|
|
||||||
self._c.send_EXECUTE(self)
|
|
||||||
self._c._write(SYNC_MSG)
|
|
||||||
self._c._flush()
|
|
||||||
self._c.handle_messages(self)
|
|
||||||
if not self.portal_suspended:
|
|
||||||
self._c.close_portal(self)
|
|
||||||
try:
|
try:
|
||||||
return self._cached_rows.popleft()
|
return self._cached_rows.popleft()
|
||||||
except IndexError:
|
except IndexError:
|
||||||
if self.ps is None:
|
if self.portal_suspended:
|
||||||
raise ProgrammingError("A query hasn't been issued.")
|
self._c.send_EXECUTE(self)
|
||||||
elif len(self.ps['row_desc']) == 0:
|
self._c._write(SYNC_MSG)
|
||||||
raise ProgrammingError("no result set")
|
self._c._flush()
|
||||||
else:
|
self._c.handle_messages(self)
|
||||||
raise StopIteration()
|
if not self.portal_suspended:
|
||||||
finally:
|
self._c.close_portal(self)
|
||||||
self._c._lock.release()
|
try:
|
||||||
|
return self._cached_rows.popleft()
|
||||||
|
except IndexError:
|
||||||
|
if self.ps is None:
|
||||||
|
raise ProgrammingError("A query hasn't been issued.")
|
||||||
|
elif len(self.ps['row_desc']) == 0:
|
||||||
|
raise ProgrammingError("no result set")
|
||||||
|
else:
|
||||||
|
raise StopIteration()
|
||||||
|
|
||||||
if PY2:
|
if PY2:
|
||||||
Cursor.next = Cursor.__next__
|
Cursor.next = Cursor.__next__
|
||||||
@@ -737,6 +1066,7 @@ COPY_DONE = b("c")
|
|||||||
COPY_DATA = b("d")
|
COPY_DATA = b("d")
|
||||||
COPY_IN_RESPONSE = b("G")
|
COPY_IN_RESPONSE = b("G")
|
||||||
COPY_OUT_RESPONSE = b("H")
|
COPY_OUT_RESPONSE = b("H")
|
||||||
|
EMPTY_QUERY_RESPONSE = b("I")
|
||||||
|
|
||||||
BIND = b("B")
|
BIND = b("B")
|
||||||
PARSE = b("P")
|
PARSE = b("P")
|
||||||
@@ -776,14 +1106,6 @@ IDLE_IN_TRANSACTION = b("T")
|
|||||||
IDLE_IN_FAILED_TRANSACTION = b("E")
|
IDLE_IN_FAILED_TRANSACTION = b("E")
|
||||||
|
|
||||||
|
|
||||||
# Byte1('N') - Identifier
|
|
||||||
# Int32 - Message length
|
|
||||||
# Any number of these, followed by a zero byte:
|
|
||||||
# Byte1 - code identifying the field type (see responseKeys)
|
|
||||||
# String - field value
|
|
||||||
def data_into_dict(data):
|
|
||||||
return dict((s[0:1], s[1:]) for s in data.split(NULL_BYTE))
|
|
||||||
|
|
||||||
arr_trans = dict(zip(map(ord, u("[] 'u")), list(u('{}')) + [None] * 3))
|
arr_trans = dict(zip(map(ord, u("[] 'u")), list(u('{}')) + [None] * 3))
|
||||||
|
|
||||||
|
|
||||||
@@ -895,7 +1217,9 @@ class Connection(object):
|
|||||||
error.__name__, stacklevel=3)
|
error.__name__, stacklevel=3)
|
||||||
return error
|
return error
|
||||||
|
|
||||||
def __init__(self, user, host, unix_sock, port, database, password, ssl):
|
def __init__(
|
||||||
|
self, user, host, unix_sock, port, database, password, ssl,
|
||||||
|
timeout):
|
||||||
self._client_encoding = "utf8"
|
self._client_encoding = "utf8"
|
||||||
self._commands_with_count = (
|
self._commands_with_count = (
|
||||||
b("INSERT"), b("DELETE"), b("UPDATE"), b("MOVE"),
|
b("INSERT"), b("DELETE"), b("UPDATE"), b("MOVE"),
|
||||||
@@ -903,23 +1227,19 @@ class Connection(object):
|
|||||||
self._lock = threading.Lock()
|
self._lock = threading.Lock()
|
||||||
|
|
||||||
if user is None:
|
if user is None:
|
||||||
try:
|
raise InterfaceError(
|
||||||
self.user = os.environ['PGUSER']
|
"The 'user' connection parameter cannot be None")
|
||||||
except KeyError:
|
|
||||||
try:
|
if isinstance(user, text_type):
|
||||||
self.user = os.environ['USER']
|
self.user = user.encode('utf8')
|
||||||
except KeyError:
|
|
||||||
raise InterfaceError(
|
|
||||||
"The 'user' connection parameter was omitted, and "
|
|
||||||
"neither the PGUSER or USER environment variables "
|
|
||||||
"were set.")
|
|
||||||
else:
|
else:
|
||||||
self.user = user
|
self.user = user
|
||||||
|
|
||||||
if isinstance(self.user, text_type):
|
if isinstance(password, text_type):
|
||||||
self.user = self.user.encode('utf8')
|
self.password = password.encode('utf8')
|
||||||
|
else:
|
||||||
|
self.password = password
|
||||||
|
|
||||||
self.password = password
|
|
||||||
self.autocommit = False
|
self.autocommit = False
|
||||||
self._xid = None
|
self._xid = None
|
||||||
|
|
||||||
@@ -939,41 +1259,38 @@ class Connection(object):
|
|||||||
else:
|
else:
|
||||||
raise ProgrammingError(
|
raise ProgrammingError(
|
||||||
"one of host or unix_sock must be provided")
|
"one of host or unix_sock must be provided")
|
||||||
|
if not PY2 and timeout is not None:
|
||||||
|
self._usock.settimeout(timeout)
|
||||||
|
|
||||||
if unix_sock is None and host is not None:
|
if unix_sock is None and host is not None:
|
||||||
self._usock.connect((host, port))
|
self._usock.connect((host, port))
|
||||||
elif unix_sock is not None:
|
elif unix_sock is not None:
|
||||||
self._usock.connect(unix_sock)
|
self._usock.connect(unix_sock)
|
||||||
|
|
||||||
if ssl:
|
if ssl:
|
||||||
try:
|
with self._lock:
|
||||||
self._lock.acquire()
|
try:
|
||||||
import ssl as sslmodule
|
import ssl as sslmodule
|
||||||
# Int32(8) - Message length, including self.
|
# Int32(8) - Message length, including self.
|
||||||
# Int32(80877103) - The SSL request code.
|
# Int32(80877103) - The SSL request code.
|
||||||
self._usock.sendall(ii_pack(8, 80877103))
|
self._usock.sendall(ii_pack(8, 80877103))
|
||||||
resp = self._usock.recv(1)
|
resp = self._usock.recv(1)
|
||||||
if resp == b('S'):
|
if resp == b('S'):
|
||||||
self._usock = sslmodule.wrap_socket(self._usock)
|
self._usock = sslmodule.wrap_socket(self._usock)
|
||||||
else:
|
else:
|
||||||
raise InterfaceError("Server refuses SSL")
|
raise InterfaceError("Server refuses SSL")
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise InterfaceError(
|
raise InterfaceError(
|
||||||
"SSL required but ssl module not available in "
|
"SSL required but ssl module not available in "
|
||||||
"this python installation")
|
"this python installation")
|
||||||
finally:
|
|
||||||
self._lock.release()
|
|
||||||
|
|
||||||
self._sock = self._usock.makefile(mode="rwb")
|
self._sock = self._usock.makefile(mode="rwb")
|
||||||
except socket.error:
|
except socket.error as e:
|
||||||
self._usock.close()
|
self._usock.close()
|
||||||
raise InterfaceError("communication error", exc_info()[1])
|
raise InterfaceError("communication error", e)
|
||||||
self._flush = self._sock.flush
|
self._flush = self._sock.flush
|
||||||
self._read = self._sock.read
|
self._read = self._sock.read
|
||||||
|
self._write = self._sock.write
|
||||||
if PRE_26:
|
|
||||||
self._write = self._sock.writelines
|
|
||||||
else:
|
|
||||||
self._write = self._sock.write
|
|
||||||
self._backend_key_data = None
|
self._backend_key_data = None
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -1182,7 +1499,6 @@ class Connection(object):
|
|||||||
bool: (16, FC_BINARY, bool_send),
|
bool: (16, FC_BINARY, bool_send),
|
||||||
int: (705, FC_TEXT, unknown_out),
|
int: (705, FC_TEXT, unknown_out),
|
||||||
float: (701, FC_BINARY, d_pack), # float8
|
float: (701, FC_BINARY, d_pack), # float8
|
||||||
str: (705, FC_TEXT, text_out), # unknown
|
|
||||||
datetime.date: (1082, FC_TEXT, date_out), # date
|
datetime.date: (1082, FC_TEXT, date_out), # date
|
||||||
datetime.time: (1083, FC_TEXT, time_out), # time
|
datetime.time: (1083, FC_TEXT, time_out), # time
|
||||||
1114: (1114, FC_BINARY, timestamp_send_integer), # timestamp
|
1114: (1114, FC_BINARY, timestamp_send_integer), # timestamp
|
||||||
@@ -1203,10 +1519,12 @@ class Connection(object):
|
|||||||
if PY2:
|
if PY2:
|
||||||
self.py_types[Bytea] = (17, FC_BINARY, bytea_send) # bytea
|
self.py_types[Bytea] = (17, FC_BINARY, bytea_send) # bytea
|
||||||
self.py_types[text_type] = (705, FC_TEXT, text_out) # unknown
|
self.py_types[text_type] = (705, FC_TEXT, text_out) # unknown
|
||||||
|
self.py_types[str] = (705, FC_TEXT, bytea_send) # unknown
|
||||||
|
|
||||||
self.py_types[long] = (705, FC_TEXT, unknown_out) # noqa
|
self.py_types[long] = (705, FC_TEXT, unknown_out) # noqa
|
||||||
else:
|
else:
|
||||||
self.py_types[bytes] = (17, FC_BINARY, bytea_send) # bytea
|
self.py_types[bytes] = (17, FC_BINARY, bytea_send) # bytea
|
||||||
|
self.py_types[str] = (705, FC_TEXT, text_out) # unknown
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from ipaddress import (
|
from ipaddress import (
|
||||||
@@ -1240,6 +1558,7 @@ class Connection(object):
|
|||||||
READY_FOR_QUERY: self.handle_READY_FOR_QUERY,
|
READY_FOR_QUERY: self.handle_READY_FOR_QUERY,
|
||||||
ROW_DESCRIPTION: self.handle_ROW_DESCRIPTION,
|
ROW_DESCRIPTION: self.handle_ROW_DESCRIPTION,
|
||||||
ERROR_RESPONSE: self.handle_ERROR_RESPONSE,
|
ERROR_RESPONSE: self.handle_ERROR_RESPONSE,
|
||||||
|
EMPTY_QUERY_RESPONSE: self.handle_EMPTY_QUERY_RESPONSE,
|
||||||
DATA_ROW: self.handle_DATA_ROW,
|
DATA_ROW: self.handle_DATA_ROW,
|
||||||
COMMAND_COMPLETE: self.handle_COMMAND_COMPLETE,
|
COMMAND_COMPLETE: self.handle_COMMAND_COMPLETE,
|
||||||
PARSE_COMPLETE: self.handle_PARSE_COMPLETE,
|
PARSE_COMPLETE: self.handle_PARSE_COMPLETE,
|
||||||
@@ -1272,32 +1591,37 @@ class Connection(object):
|
|||||||
self._flush()
|
self._flush()
|
||||||
|
|
||||||
self._cursor = self.cursor()
|
self._cursor = self.cursor()
|
||||||
try:
|
with self._lock:
|
||||||
self._lock.acquire()
|
try:
|
||||||
code = self.error = None
|
code = self.error = None
|
||||||
while code not in (READY_FOR_QUERY, ERROR_RESPONSE):
|
while code not in (READY_FOR_QUERY, ERROR_RESPONSE):
|
||||||
code, data_len = ci_unpack(self._read(5))
|
code, data_len = ci_unpack(self._read(5))
|
||||||
self.message_types[code](self._read(data_len - 4), None)
|
self.message_types[code](self._read(data_len - 4), None)
|
||||||
if self.error is not None:
|
if self.error is not None:
|
||||||
raise self.error
|
raise self.error
|
||||||
except:
|
except Exception as e:
|
||||||
self._close()
|
try:
|
||||||
raise
|
self._close()
|
||||||
finally:
|
except Exception:
|
||||||
self._lock.release()
|
pass
|
||||||
|
raise e
|
||||||
|
|
||||||
self.in_transaction = False
|
self.in_transaction = False
|
||||||
self.notifies = []
|
self.notifies = []
|
||||||
self.notifies_lock = threading.Lock()
|
self.notifies_lock = threading.Lock()
|
||||||
|
|
||||||
def handle_ERROR_RESPONSE(self, data, ps):
|
def handle_ERROR_RESPONSE(self, data, ps):
|
||||||
msg_dict = data_into_dict(data)
|
responses = tuple(
|
||||||
|
(s[0:1], s[1:].decode(self._client_encoding)) for s in
|
||||||
|
data.split(NULL_BYTE))
|
||||||
|
msg_dict = dict(responses)
|
||||||
if msg_dict[RESPONSE_CODE] == "28000":
|
if msg_dict[RESPONSE_CODE] == "28000":
|
||||||
self.error = InterfaceError("md5 password authentication failed")
|
self.error = InterfaceError("md5 password authentication failed")
|
||||||
else:
|
else:
|
||||||
self.error = ProgrammingError(
|
self.error = ProgrammingError(*tuple(v for k, v in responses))
|
||||||
msg_dict[RESPONSE_SEVERITY], msg_dict[RESPONSE_CODE],
|
|
||||||
msg_dict[RESPONSE_MSG])
|
def handle_EMPTY_QUERY_RESPONSE(self, data, ps):
|
||||||
|
self.error = ProgrammingError("query was empty")
|
||||||
|
|
||||||
def handle_CLOSE_COMPLETE(self, data, ps):
|
def handle_CLOSE_COMPLETE(self, data, ps):
|
||||||
pass
|
pass
|
||||||
@@ -1391,11 +1715,8 @@ class Connection(object):
|
|||||||
# additional_info = data[idx:idx + null]
|
# additional_info = data[idx:idx + null]
|
||||||
|
|
||||||
# psycopg2 compatible notification interface
|
# psycopg2 compatible notification interface
|
||||||
try:
|
with self.notifies_lock:
|
||||||
self.notifies_lock.acquire()
|
|
||||||
self.notifies.append((backend_pid, condition))
|
self.notifies.append((backend_pid, condition))
|
||||||
finally:
|
|
||||||
self.notifies_lock.release()
|
|
||||||
|
|
||||||
def cursor(self):
|
def cursor(self):
|
||||||
"""Creates a :class:`Cursor` object bound to this
|
"""Creates a :class:`Cursor` object bound to this
|
||||||
@@ -1412,11 +1733,8 @@ class Connection(object):
|
|||||||
This function is part of the `DBAPI 2.0 specification
|
This function is part of the `DBAPI 2.0 specification
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
"""
|
"""
|
||||||
try:
|
with self._lock:
|
||||||
self._lock.acquire()
|
|
||||||
self.execute(self._cursor, "commit", None)
|
self.execute(self._cursor, "commit", None)
|
||||||
finally:
|
|
||||||
self._lock.release()
|
|
||||||
|
|
||||||
def rollback(self):
|
def rollback(self):
|
||||||
"""Rolls back the current database transaction.
|
"""Rolls back the current database transaction.
|
||||||
@@ -1424,11 +1742,8 @@ class Connection(object):
|
|||||||
This function is part of the `DBAPI 2.0 specification
|
This function is part of the `DBAPI 2.0 specification
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
"""
|
"""
|
||||||
try:
|
with self._lock:
|
||||||
self._lock.acquire()
|
|
||||||
self.execute(self._cursor, "rollback", None)
|
self.execute(self._cursor, "rollback", None)
|
||||||
finally:
|
|
||||||
self._lock.release()
|
|
||||||
|
|
||||||
def _close(self):
|
def _close(self):
|
||||||
try:
|
try:
|
||||||
@@ -1437,12 +1752,15 @@ class Connection(object):
|
|||||||
self._write(TERMINATE_MSG)
|
self._write(TERMINATE_MSG)
|
||||||
self._flush()
|
self._flush()
|
||||||
self._sock.close()
|
self._sock.close()
|
||||||
self._usock.close()
|
|
||||||
self._sock = None
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise InterfaceError("connection is closed")
|
raise InterfaceError("connection is closed")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise InterfaceError("connection is closed")
|
raise InterfaceError("connection is closed")
|
||||||
|
except socket.error as e:
|
||||||
|
raise OperationalError(str(e))
|
||||||
|
finally:
|
||||||
|
self._usock.close()
|
||||||
|
self._sock = None
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Closes the database connection.
|
"""Closes the database connection.
|
||||||
@@ -1450,11 +1768,8 @@ class Connection(object):
|
|||||||
This function is part of the `DBAPI 2.0 specification
|
This function is part of the `DBAPI 2.0 specification
|
||||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||||
"""
|
"""
|
||||||
try:
|
with self._lock:
|
||||||
self._lock.acquire()
|
|
||||||
self._close()
|
self._close()
|
||||||
finally:
|
|
||||||
self._lock.release()
|
|
||||||
|
|
||||||
def handle_AUTHENTICATION_REQUEST(self, data, cursor):
|
def handle_AUTHENTICATION_REQUEST(self, data, cursor):
|
||||||
assert self._lock.locked()
|
assert self._lock.locked()
|
||||||
@@ -1463,7 +1778,7 @@ class Connection(object):
|
|||||||
# 0 = AuthenticationOk
|
# 0 = AuthenticationOk
|
||||||
# 5 = MD5 pwd
|
# 5 = MD5 pwd
|
||||||
# 2 = Kerberos v5 (not supported by pg8000)
|
# 2 = Kerberos v5 (not supported by pg8000)
|
||||||
# 3 = Cleartext pwd (not supported by pg8000)
|
# 3 = Cleartext pwd
|
||||||
# 4 = crypt() pwd (not supported by pg8000)
|
# 4 = crypt() pwd (not supported by pg8000)
|
||||||
# 6 = SCM credential (not supported by pg8000)
|
# 6 = SCM credential (not supported by pg8000)
|
||||||
# 7 = GSSAPI (not supported by pg8000)
|
# 7 = GSSAPI (not supported by pg8000)
|
||||||
@@ -1480,8 +1795,7 @@ class Connection(object):
|
|||||||
raise InterfaceError(
|
raise InterfaceError(
|
||||||
"server requesting password authentication, but no "
|
"server requesting password authentication, but no "
|
||||||
"password was provided")
|
"password was provided")
|
||||||
self._send_message(
|
self._send_message(PASSWORD, self.password + NULL_BYTE)
|
||||||
PASSWORD, self.password.encode("ascii") + NULL_BYTE)
|
|
||||||
self._flush()
|
self._flush()
|
||||||
elif auth_code == 5:
|
elif auth_code == 5:
|
||||||
##
|
##
|
||||||
@@ -1497,8 +1811,8 @@ class Connection(object):
|
|||||||
"server requesting MD5 password authentication, but no "
|
"server requesting MD5 password authentication, but no "
|
||||||
"password was provided")
|
"password was provided")
|
||||||
pwd = b("md5") + md5(
|
pwd = b("md5") + md5(
|
||||||
md5(self.password.encode("ascii") + self.user).
|
md5(self.password + self.user).hexdigest().encode("ascii") +
|
||||||
hexdigest().encode("ascii") + salt).hexdigest().encode("ascii")
|
salt).hexdigest().encode("ascii")
|
||||||
# Byte1('p') - Identifies the message as a password message.
|
# Byte1('p') - Identifies the message as a password message.
|
||||||
# Int32 - Message length including self.
|
# Int32 - Message length including self.
|
||||||
# String - The password. Password may be encrypted.
|
# String - The password. Password may be encrypted.
|
||||||
@@ -1536,11 +1850,10 @@ class Connection(object):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
try:
|
try:
|
||||||
params.append(self.inspect_funcs[typ](value))
|
params.append(self.inspect_funcs[typ](value))
|
||||||
except KeyError:
|
except KeyError as e:
|
||||||
raise NotSupportedError(
|
raise NotSupportedError(
|
||||||
"type " + str(exc_info()[1]) +
|
"type " + str(e) + "not mapped to pg type")
|
||||||
"not mapped to pg type")
|
return tuple(params)
|
||||||
return params
|
|
||||||
|
|
||||||
def handle_ROW_DESCRIPTION(self, data, cursor):
|
def handle_ROW_DESCRIPTION(self, data, cursor):
|
||||||
count = h_unpack(data)[0]
|
count = h_unpack(data)[0]
|
||||||
@@ -1572,8 +1885,7 @@ class Connection(object):
|
|||||||
|
|
||||||
args = make_args(vals)
|
args = make_args(vals)
|
||||||
params = self.make_params(args)
|
params = self.make_params(args)
|
||||||
|
key = operation, params
|
||||||
key = tuple(oid for oid, x, y in params), operation
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ps = cache['ps'][key]
|
ps = cache['ps'][key]
|
||||||
@@ -1617,11 +1929,13 @@ class Connection(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
self._flush()
|
self._flush()
|
||||||
except AttributeError:
|
except AttributeError as e:
|
||||||
if self._sock is None:
|
if self._sock is None:
|
||||||
raise InterfaceError("connection is closed")
|
raise InterfaceError("connection is closed")
|
||||||
else:
|
else:
|
||||||
raise exc_info()[1]
|
raise e
|
||||||
|
except socket.error as e:
|
||||||
|
raise OperationalError(str(e))
|
||||||
|
|
||||||
self.handle_messages(cursor)
|
self.handle_messages(cursor)
|
||||||
|
|
||||||
@@ -1711,11 +2025,11 @@ class Connection(object):
|
|||||||
self._write(i_pack(len(data) + 4))
|
self._write(i_pack(len(data) + 4))
|
||||||
self._write(data)
|
self._write(data)
|
||||||
self._write(FLUSH_MSG)
|
self._write(FLUSH_MSG)
|
||||||
except ValueError:
|
except ValueError as e:
|
||||||
if str(exc_info()[1]) == "write to closed file":
|
if str(e) == "write to closed file":
|
||||||
raise InterfaceError("connection is closed")
|
raise InterfaceError("connection is closed")
|
||||||
else:
|
else:
|
||||||
raise exc_info()[1]
|
raise e
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise InterfaceError("connection is closed")
|
raise InterfaceError("connection is closed")
|
||||||
|
|
||||||
@@ -1783,8 +2097,13 @@ class Connection(object):
|
|||||||
self._flush()
|
self._flush()
|
||||||
self.handle_messages(cursor)
|
self.handle_messages(cursor)
|
||||||
|
|
||||||
|
# Byte1('N') - Identifier
|
||||||
|
# Int32 - Message length
|
||||||
|
# Any number of these, followed by a zero byte:
|
||||||
|
# Byte1 - code identifying the field type (see responseKeys)
|
||||||
|
# String - field value
|
||||||
def handle_NOTICE_RESPONSE(self, data, ps):
|
def handle_NOTICE_RESPONSE(self, data, ps):
|
||||||
resp = data_into_dict(data)
|
resp = dict((s[0:1], s[1:]) for s in data.split(NULL_BYTE))
|
||||||
self.NoticeReceived(resp)
|
self.NoticeReceived(resp)
|
||||||
|
|
||||||
def handle_PARAMETER_STATUS(self, data, ps):
|
def handle_PARAMETER_STATUS(self, data, ps):
|
||||||
|
|||||||
+381
-123
@@ -1,6 +1,6 @@
|
|||||||
"""Utilities for writing code that runs on Python 2 and 3"""
|
"""Utilities for writing code that runs on Python 2 and 3"""
|
||||||
|
|
||||||
# Copyright (c) 2010-2013 Benjamin Peterson
|
# Copyright (c) 2010-2015 Benjamin Peterson
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
# copies of the Software, and to permit persons to whom the Software is
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
# furnished to do so, subject to the following conditions:
|
# furnished to do so, subject to the following conditions:
|
||||||
#
|
#
|
||||||
# The above copyright notice and this permission notice shall be included in
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
# all copies or substantial portions of the Software.
|
# copies or substantial portions of the Software.
|
||||||
#
|
#
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
@@ -21,22 +21,21 @@
|
|||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import itertools
|
||||||
import operator
|
import operator
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
||||||
__version__ = "1.4.1"
|
__version__ = "1.10.0"
|
||||||
|
|
||||||
|
|
||||||
# Useful for very coarse version differentiation.
|
# Useful for very coarse version differentiation.
|
||||||
PY2 = sys.version_info[0] == 2
|
PY2 = sys.version_info[0] == 2
|
||||||
PY3 = sys.version_info[0] == 3
|
PY3 = sys.version_info[0] == 3
|
||||||
|
PY34 = sys.version_info[0:2] >= (3, 4)
|
||||||
PRE_26 = PY2 and sys.version_info[1] < 6
|
|
||||||
|
|
||||||
IS_JYTHON = sys.platform.lower().count('java') > 0
|
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
if PY3:
|
||||||
string_types = str,
|
string_types = str,
|
||||||
@@ -47,10 +46,10 @@ if PY3:
|
|||||||
|
|
||||||
MAXSIZE = sys.maxsize
|
MAXSIZE = sys.maxsize
|
||||||
else:
|
else:
|
||||||
string_types = basestring, # noqa
|
string_types = basestring,
|
||||||
integer_types = (int, long) # noqa
|
integer_types = (int, long)
|
||||||
class_types = (type, types.ClassType)
|
class_types = (type, types.ClassType)
|
||||||
text_type = unicode # noqa
|
text_type = unicode
|
||||||
binary_type = str
|
binary_type = str
|
||||||
|
|
||||||
if sys.platform.startswith("java"):
|
if sys.platform.startswith("java"):
|
||||||
@@ -59,6 +58,7 @@ else:
|
|||||||
else:
|
else:
|
||||||
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
||||||
class X(object):
|
class X(object):
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return 1 << 31
|
return 1 << 31
|
||||||
try:
|
try:
|
||||||
@@ -90,9 +90,13 @@ class _LazyDescr(object):
|
|||||||
|
|
||||||
def __get__(self, obj, tp):
|
def __get__(self, obj, tp):
|
||||||
result = self._resolve()
|
result = self._resolve()
|
||||||
setattr(obj, self.name, result)
|
setattr(obj, self.name, result) # Invokes __set__.
|
||||||
# This is a bit ugly, but it avoids running this again.
|
try:
|
||||||
delattr(tp, self.name)
|
# This is a bit ugly, but it avoids running this again by
|
||||||
|
# removing this descriptor.
|
||||||
|
delattr(obj.__class__, self.name)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -110,6 +114,27 @@ class MovedModule(_LazyDescr):
|
|||||||
def _resolve(self):
|
def _resolve(self):
|
||||||
return _import_module(self.mod)
|
return _import_module(self.mod)
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
_module = self._resolve()
|
||||||
|
value = getattr(_module, attr)
|
||||||
|
setattr(self, attr, value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class _LazyModule(types.ModuleType):
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
super(_LazyModule, self).__init__(name)
|
||||||
|
self.__doc__ = self.__class__.__doc__
|
||||||
|
|
||||||
|
def __dir__(self):
|
||||||
|
attrs = ["__doc__", "__name__"]
|
||||||
|
attrs += [attr.name for attr in self._moved_attributes]
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
# Subclasses should override this
|
||||||
|
_moved_attributes = []
|
||||||
|
|
||||||
|
|
||||||
class MovedAttribute(_LazyDescr):
|
class MovedAttribute(_LazyDescr):
|
||||||
|
|
||||||
@@ -136,38 +161,109 @@ class MovedAttribute(_LazyDescr):
|
|||||||
return getattr(module, self.attr)
|
return getattr(module, self.attr)
|
||||||
|
|
||||||
|
|
||||||
class _MovedItems(types.ModuleType):
|
class _SixMetaPathImporter(object):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A meta path importer to import six.moves and its submodules.
|
||||||
|
|
||||||
|
This class implements a PEP302 finder and loader. It should be compatible
|
||||||
|
with Python 2.5 and all existing versions of Python3
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, six_module_name):
|
||||||
|
self.name = six_module_name
|
||||||
|
self.known_modules = {}
|
||||||
|
|
||||||
|
def _add_module(self, mod, *fullnames):
|
||||||
|
for fullname in fullnames:
|
||||||
|
self.known_modules[self.name + "." + fullname] = mod
|
||||||
|
|
||||||
|
def _get_module(self, fullname):
|
||||||
|
return self.known_modules[self.name + "." + fullname]
|
||||||
|
|
||||||
|
def find_module(self, fullname, path=None):
|
||||||
|
if fullname in self.known_modules:
|
||||||
|
return self
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __get_module(self, fullname):
|
||||||
|
try:
|
||||||
|
return self.known_modules[fullname]
|
||||||
|
except KeyError:
|
||||||
|
raise ImportError("This loader does not know module " + fullname)
|
||||||
|
|
||||||
|
def load_module(self, fullname):
|
||||||
|
try:
|
||||||
|
# in case of a reload
|
||||||
|
return sys.modules[fullname]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
mod = self.__get_module(fullname)
|
||||||
|
if isinstance(mod, MovedModule):
|
||||||
|
mod = mod._resolve()
|
||||||
|
else:
|
||||||
|
mod.__loader__ = self
|
||||||
|
sys.modules[fullname] = mod
|
||||||
|
return mod
|
||||||
|
|
||||||
|
def is_package(self, fullname):
|
||||||
|
"""
|
||||||
|
Return true, if the named module is a package.
|
||||||
|
|
||||||
|
We need this method to get correct spec objects with
|
||||||
|
Python 3.4 (see PEP451)
|
||||||
|
"""
|
||||||
|
return hasattr(self.__get_module(fullname), "__path__")
|
||||||
|
|
||||||
|
def get_code(self, fullname):
|
||||||
|
"""Return None
|
||||||
|
|
||||||
|
Required, if is_package is implemented"""
|
||||||
|
self.__get_module(fullname) # eventually raises ImportError
|
||||||
|
return None
|
||||||
|
get_source = get_code # same as get_code
|
||||||
|
|
||||||
|
_importer = _SixMetaPathImporter(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class _MovedItems(_LazyModule):
|
||||||
|
|
||||||
"""Lazy loading of moved objects"""
|
"""Lazy loading of moved objects"""
|
||||||
|
__path__ = [] # mark as package
|
||||||
|
|
||||||
|
|
||||||
_moved_attributes = [
|
_moved_attributes = [
|
||||||
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
|
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
|
||||||
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
|
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
|
||||||
MovedAttribute(
|
MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
|
||||||
"filterfalse", "itertools", "itertools", "ifilterfalse",
|
|
||||||
"filterfalse"),
|
|
||||||
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
|
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
|
||||||
|
MovedAttribute("intern", "__builtin__", "sys"),
|
||||||
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
|
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
|
||||||
|
MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
|
||||||
|
MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
|
||||||
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
|
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
|
||||||
MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
|
MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
|
||||||
MovedAttribute("reduce", "__builtin__", "functools"),
|
MovedAttribute("reduce", "__builtin__", "functools"),
|
||||||
|
MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
|
||||||
MovedAttribute("StringIO", "StringIO", "io"),
|
MovedAttribute("StringIO", "StringIO", "io"),
|
||||||
|
MovedAttribute("UserDict", "UserDict", "collections"),
|
||||||
|
MovedAttribute("UserList", "UserList", "collections"),
|
||||||
MovedAttribute("UserString", "UserString", "collections"),
|
MovedAttribute("UserString", "UserString", "collections"),
|
||||||
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
|
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
|
||||||
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
|
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
|
||||||
MovedAttribute(
|
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
|
||||||
"zip_longest", "itertools", "itertools", "izip_longest",
|
|
||||||
"zip_longest"),
|
|
||||||
MovedModule("builtins", "__builtin__"),
|
MovedModule("builtins", "__builtin__"),
|
||||||
MovedModule("configparser", "ConfigParser"),
|
MovedModule("configparser", "ConfigParser"),
|
||||||
MovedModule("copyreg", "copy_reg"),
|
MovedModule("copyreg", "copy_reg"),
|
||||||
|
MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
|
||||||
|
MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
|
||||||
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
|
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
|
||||||
MovedModule("http_cookies", "Cookie", "http.cookies"),
|
MovedModule("http_cookies", "Cookie", "http.cookies"),
|
||||||
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
||||||
MovedModule("html_parser", "HTMLParser", "html.parser"),
|
MovedModule("html_parser", "HTMLParser", "html.parser"),
|
||||||
MovedModule("http_client", "httplib", "http.client"),
|
MovedModule("http_client", "httplib", "http.client"),
|
||||||
MovedModule(
|
MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
|
||||||
"email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
|
MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
|
||||||
MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
|
MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
|
||||||
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
|
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
|
||||||
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
|
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
|
||||||
@@ -177,14 +273,14 @@ _moved_attributes = [
|
|||||||
MovedModule("queue", "Queue"),
|
MovedModule("queue", "Queue"),
|
||||||
MovedModule("reprlib", "repr"),
|
MovedModule("reprlib", "repr"),
|
||||||
MovedModule("socketserver", "SocketServer"),
|
MovedModule("socketserver", "SocketServer"),
|
||||||
|
MovedModule("_thread", "thread", "_thread"),
|
||||||
MovedModule("tkinter", "Tkinter"),
|
MovedModule("tkinter", "Tkinter"),
|
||||||
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
|
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
|
||||||
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
|
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
|
||||||
MovedModule(
|
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
|
||||||
"tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
|
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
|
||||||
MovedModule(
|
|
||||||
"tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
|
|
||||||
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
|
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
|
||||||
|
MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
|
||||||
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
|
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
|
||||||
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
|
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
|
||||||
MovedModule("tkinter_colorchooser", "tkColorChooser",
|
MovedModule("tkinter_colorchooser", "tkColorChooser",
|
||||||
@@ -194,30 +290,41 @@ _moved_attributes = [
|
|||||||
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
|
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
|
||||||
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
|
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
|
||||||
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
|
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
|
||||||
MovedModule(
|
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
|
||||||
"tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"),
|
"tkinter.simpledialog"),
|
||||||
MovedModule(
|
MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
|
||||||
"urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
|
MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
|
||||||
MovedModule(
|
MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
|
||||||
"urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
|
|
||||||
MovedModule(
|
|
||||||
"urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
|
|
||||||
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
|
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
|
||||||
MovedModule("winreg", "_winreg"),
|
MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
|
||||||
|
MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
|
||||||
]
|
]
|
||||||
|
# Add windows specific modules.
|
||||||
|
if sys.platform == "win32":
|
||||||
|
_moved_attributes += [
|
||||||
|
MovedModule("winreg", "_winreg"),
|
||||||
|
]
|
||||||
|
|
||||||
for attr in _moved_attributes:
|
for attr in _moved_attributes:
|
||||||
setattr(_MovedItems, attr.name, attr)
|
setattr(_MovedItems, attr.name, attr)
|
||||||
|
if isinstance(attr, MovedModule):
|
||||||
|
_importer._add_module(attr, "moves." + attr.name)
|
||||||
del attr
|
del attr
|
||||||
|
|
||||||
moves = sys.modules[__name__ + ".moves"] = _MovedItems(__name__ + ".moves")
|
_MovedItems._moved_attributes = _moved_attributes
|
||||||
|
|
||||||
|
moves = _MovedItems(__name__ + ".moves")
|
||||||
|
_importer._add_module(moves, "moves")
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_parse(types.ModuleType):
|
class Module_six_moves_urllib_parse(_LazyModule):
|
||||||
|
|
||||||
"""Lazy loading of moved objects in six.moves.urllib_parse"""
|
"""Lazy loading of moved objects in six.moves.urllib_parse"""
|
||||||
|
|
||||||
|
|
||||||
_urllib_parse_moved_attributes = [
|
_urllib_parse_moved_attributes = [
|
||||||
MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
|
MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
|
||||||
MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
|
MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
|
||||||
MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
|
MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
|
||||||
MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
|
MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
|
||||||
@@ -231,18 +338,27 @@ _urllib_parse_moved_attributes = [
|
|||||||
MovedAttribute("unquote", "urllib", "urllib.parse"),
|
MovedAttribute("unquote", "urllib", "urllib.parse"),
|
||||||
MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
|
MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
|
||||||
MovedAttribute("urlencode", "urllib", "urllib.parse"),
|
MovedAttribute("urlencode", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("splitquery", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("splittag", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("splituser", "urllib", "urllib.parse"),
|
||||||
|
MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("uses_params", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("uses_query", "urlparse", "urllib.parse"),
|
||||||
|
MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
|
||||||
]
|
]
|
||||||
for attr in _urllib_parse_moved_attributes:
|
for attr in _urllib_parse_moved_attributes:
|
||||||
setattr(Module_six_moves_urllib_parse, attr.name, attr)
|
setattr(Module_six_moves_urllib_parse, attr.name, attr)
|
||||||
del attr
|
del attr
|
||||||
|
|
||||||
sys.modules[__name__ + ".moves.urllib_parse"] = Module_six_moves_urllib_parse(
|
Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
|
||||||
__name__ + ".moves.urllib_parse")
|
|
||||||
sys.modules[__name__ + ".moves.urllib.parse"] = Module_six_moves_urllib_parse(
|
_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
|
||||||
__name__ + ".moves.urllib.parse")
|
"moves.urllib_parse", "moves.urllib.parse")
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_error(types.ModuleType):
|
class Module_six_moves_urllib_error(_LazyModule):
|
||||||
|
|
||||||
"""Lazy loading of moved objects in six.moves.urllib_error"""
|
"""Lazy loading of moved objects in six.moves.urllib_error"""
|
||||||
|
|
||||||
|
|
||||||
@@ -255,13 +371,14 @@ for attr in _urllib_error_moved_attributes:
|
|||||||
setattr(Module_six_moves_urllib_error, attr.name, attr)
|
setattr(Module_six_moves_urllib_error, attr.name, attr)
|
||||||
del attr
|
del attr
|
||||||
|
|
||||||
sys.modules[__name__ + ".moves.urllib_error"] = Module_six_moves_urllib_error(
|
Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
|
||||||
__name__ + ".moves.urllib_error")
|
|
||||||
sys.modules[__name__ + ".moves.urllib.error"] = Module_six_moves_urllib_error(
|
_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
|
||||||
__name__ + ".moves.urllib.error")
|
"moves.urllib_error", "moves.urllib.error")
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_request(types.ModuleType):
|
class Module_six_moves_urllib_request(_LazyModule):
|
||||||
|
|
||||||
"""Lazy loading of moved objects in six.moves.urllib_request"""
|
"""Lazy loading of moved objects in six.moves.urllib_request"""
|
||||||
|
|
||||||
|
|
||||||
@@ -280,8 +397,7 @@ _urllib_request_moved_attributes = [
|
|||||||
MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
|
MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
|
||||||
MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
|
MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
|
||||||
MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
|
MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
|
||||||
MovedAttribute(
|
MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
|
||||||
"HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
|
MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
|
||||||
MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
|
MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
|
||||||
MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
|
MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
|
||||||
@@ -299,18 +415,20 @@ _urllib_request_moved_attributes = [
|
|||||||
MovedAttribute("urlcleanup", "urllib", "urllib.request"),
|
MovedAttribute("urlcleanup", "urllib", "urllib.request"),
|
||||||
MovedAttribute("URLopener", "urllib", "urllib.request"),
|
MovedAttribute("URLopener", "urllib", "urllib.request"),
|
||||||
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
|
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
|
||||||
|
MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
|
||||||
]
|
]
|
||||||
for attr in _urllib_request_moved_attributes:
|
for attr in _urllib_request_moved_attributes:
|
||||||
setattr(Module_six_moves_urllib_request, attr.name, attr)
|
setattr(Module_six_moves_urllib_request, attr.name, attr)
|
||||||
del attr
|
del attr
|
||||||
|
|
||||||
sys.modules[__name__ + ".moves.urllib_request"] = \
|
Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
|
||||||
Module_six_moves_urllib_request(__name__ + ".moves.urllib_request")
|
|
||||||
sys.modules[__name__ + ".moves.urllib.request"] = \
|
_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
|
||||||
Module_six_moves_urllib_request(__name__ + ".moves.urllib.request")
|
"moves.urllib_request", "moves.urllib.request")
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_response(types.ModuleType):
|
class Module_six_moves_urllib_response(_LazyModule):
|
||||||
|
|
||||||
"""Lazy loading of moved objects in six.moves.urllib_response"""
|
"""Lazy loading of moved objects in six.moves.urllib_response"""
|
||||||
|
|
||||||
|
|
||||||
@@ -324,13 +442,14 @@ for attr in _urllib_response_moved_attributes:
|
|||||||
setattr(Module_six_moves_urllib_response, attr.name, attr)
|
setattr(Module_six_moves_urllib_response, attr.name, attr)
|
||||||
del attr
|
del attr
|
||||||
|
|
||||||
sys.modules[__name__ + ".moves.urllib_response"] = \
|
Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
|
||||||
Module_six_moves_urllib_response(__name__ + ".moves.urllib_response")
|
|
||||||
sys.modules[__name__ + ".moves.urllib.response"] = \
|
_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
|
||||||
Module_six_moves_urllib_response(__name__ + ".moves.urllib.response")
|
"moves.urllib_response", "moves.urllib.response")
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_robotparser(types.ModuleType):
|
class Module_six_moves_urllib_robotparser(_LazyModule):
|
||||||
|
|
||||||
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
|
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
|
||||||
|
|
||||||
|
|
||||||
@@ -341,25 +460,27 @@ for attr in _urllib_robotparser_moved_attributes:
|
|||||||
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
|
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
|
||||||
del attr
|
del attr
|
||||||
|
|
||||||
sys.modules[__name__ + ".moves.urllib_robotparser"] = \
|
Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
|
||||||
Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib_robotparser")
|
|
||||||
sys.modules[__name__ + ".moves.urllib.robotparser"] = \
|
_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
|
||||||
Module_six_moves_urllib_robotparser(
|
"moves.urllib_robotparser", "moves.urllib.robotparser")
|
||||||
__name__ + ".moves.urllib.robotparser")
|
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib(types.ModuleType):
|
class Module_six_moves_urllib(types.ModuleType):
|
||||||
"""Create a six.moves.urllib namespace that resembles the Python 3
|
|
||||||
namespace"""
|
|
||||||
parse = sys.modules[__name__ + ".moves.urllib_parse"]
|
|
||||||
error = sys.modules[__name__ + ".moves.urllib_error"]
|
|
||||||
request = sys.modules[__name__ + ".moves.urllib_request"]
|
|
||||||
response = sys.modules[__name__ + ".moves.urllib_response"]
|
|
||||||
robotparser = sys.modules[__name__ + ".moves.urllib_robotparser"]
|
|
||||||
|
|
||||||
|
"""Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
|
||||||
|
__path__ = [] # mark as package
|
||||||
|
parse = _importer._get_module("moves.urllib_parse")
|
||||||
|
error = _importer._get_module("moves.urllib_error")
|
||||||
|
request = _importer._get_module("moves.urllib_request")
|
||||||
|
response = _importer._get_module("moves.urllib_response")
|
||||||
|
robotparser = _importer._get_module("moves.urllib_robotparser")
|
||||||
|
|
||||||
sys.modules[__name__ + ".moves.urllib"] = Module_six_moves_urllib(
|
def __dir__(self):
|
||||||
__name__ + ".moves.urllib")
|
return ['parse', 'error', 'request', 'response', 'robotparser']
|
||||||
|
|
||||||
|
_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
|
||||||
|
"moves.urllib")
|
||||||
|
|
||||||
|
|
||||||
def add_move(move):
|
def add_move(move):
|
||||||
@@ -386,11 +507,6 @@ if PY3:
|
|||||||
_func_code = "__code__"
|
_func_code = "__code__"
|
||||||
_func_defaults = "__defaults__"
|
_func_defaults = "__defaults__"
|
||||||
_func_globals = "__globals__"
|
_func_globals = "__globals__"
|
||||||
|
|
||||||
_iterkeys = "keys"
|
|
||||||
_itervalues = "values"
|
|
||||||
_iteritems = "items"
|
|
||||||
_iterlists = "lists"
|
|
||||||
else:
|
else:
|
||||||
_meth_func = "im_func"
|
_meth_func = "im_func"
|
||||||
_meth_self = "im_self"
|
_meth_self = "im_self"
|
||||||
@@ -400,11 +516,6 @@ else:
|
|||||||
_func_defaults = "func_defaults"
|
_func_defaults = "func_defaults"
|
||||||
_func_globals = "func_globals"
|
_func_globals = "func_globals"
|
||||||
|
|
||||||
_iterkeys = "iterkeys"
|
|
||||||
_itervalues = "itervalues"
|
|
||||||
_iteritems = "iteritems"
|
|
||||||
_iterlists = "iterlists"
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
advance_iterator = next
|
advance_iterator = next
|
||||||
@@ -427,6 +538,9 @@ if PY3:
|
|||||||
|
|
||||||
create_bound_method = types.MethodType
|
create_bound_method = types.MethodType
|
||||||
|
|
||||||
|
def create_unbound_method(func, cls):
|
||||||
|
return func
|
||||||
|
|
||||||
Iterator = object
|
Iterator = object
|
||||||
else:
|
else:
|
||||||
def get_unbound_function(unbound):
|
def get_unbound_function(unbound):
|
||||||
@@ -435,6 +549,9 @@ else:
|
|||||||
def create_bound_method(func, obj):
|
def create_bound_method(func, obj):
|
||||||
return types.MethodType(func, obj, obj.__class__)
|
return types.MethodType(func, obj, obj.__class__)
|
||||||
|
|
||||||
|
def create_unbound_method(func, cls):
|
||||||
|
return types.MethodType(func, None, cls)
|
||||||
|
|
||||||
class Iterator(object):
|
class Iterator(object):
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
@@ -453,24 +570,49 @@ get_function_defaults = operator.attrgetter(_func_defaults)
|
|||||||
get_function_globals = operator.attrgetter(_func_globals)
|
get_function_globals = operator.attrgetter(_func_globals)
|
||||||
|
|
||||||
|
|
||||||
def iterkeys(d, **kw):
|
if PY3:
|
||||||
"""Return an iterator over the keys of a dictionary."""
|
def iterkeys(d, **kw):
|
||||||
return iter(getattr(d, _iterkeys)(**kw))
|
return iter(d.keys(**kw))
|
||||||
|
|
||||||
|
def itervalues(d, **kw):
|
||||||
|
return iter(d.values(**kw))
|
||||||
|
|
||||||
def itervalues(d, **kw):
|
def iteritems(d, **kw):
|
||||||
"""Return an iterator over the values of a dictionary."""
|
return iter(d.items(**kw))
|
||||||
return iter(getattr(d, _itervalues)(**kw))
|
|
||||||
|
|
||||||
|
def iterlists(d, **kw):
|
||||||
|
return iter(d.lists(**kw))
|
||||||
|
|
||||||
def iteritems(d, **kw):
|
viewkeys = operator.methodcaller("keys")
|
||||||
"""Return an iterator over the (key, value) pairs of a dictionary."""
|
|
||||||
return iter(getattr(d, _iteritems)(**kw))
|
|
||||||
|
|
||||||
|
viewvalues = operator.methodcaller("values")
|
||||||
|
|
||||||
def iterlists(d, **kw):
|
viewitems = operator.methodcaller("items")
|
||||||
"""Return an iterator over the (key, [values]) pairs of a dictionary."""
|
else:
|
||||||
return iter(getattr(d, _iterlists)(**kw))
|
def iterkeys(d, **kw):
|
||||||
|
return d.iterkeys(**kw)
|
||||||
|
|
||||||
|
def itervalues(d, **kw):
|
||||||
|
return d.itervalues(**kw)
|
||||||
|
|
||||||
|
def iteritems(d, **kw):
|
||||||
|
return d.iteritems(**kw)
|
||||||
|
|
||||||
|
def iterlists(d, **kw):
|
||||||
|
return d.iterlists(**kw)
|
||||||
|
|
||||||
|
viewkeys = operator.methodcaller("viewkeys")
|
||||||
|
|
||||||
|
viewvalues = operator.methodcaller("viewvalues")
|
||||||
|
|
||||||
|
viewitems = operator.methodcaller("viewitems")
|
||||||
|
|
||||||
|
_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
|
||||||
|
_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
|
||||||
|
_add_doc(iteritems,
|
||||||
|
"Return an iterator over the (key, value) pairs of a dictionary.")
|
||||||
|
_add_doc(iterlists,
|
||||||
|
"Return an iterator over the (key, [values]) pairs of a dictionary.")
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
if PY3:
|
||||||
@@ -480,24 +622,29 @@ if PY3:
|
|||||||
def u(s):
|
def u(s):
|
||||||
return s
|
return s
|
||||||
unichr = chr
|
unichr = chr
|
||||||
if sys.version_info[1] <= 1:
|
import struct
|
||||||
def int2byte(i):
|
int2byte = struct.Struct(">B").pack
|
||||||
return bytes((i,))
|
del struct
|
||||||
else:
|
|
||||||
# This is about 2x faster than the implementation above on 3.2+
|
|
||||||
int2byte = operator.methodcaller("to_bytes", 1, "big")
|
|
||||||
byte2int = operator.itemgetter(0)
|
byte2int = operator.itemgetter(0)
|
||||||
indexbytes = operator.getitem
|
indexbytes = operator.getitem
|
||||||
iterbytes = iter
|
iterbytes = iter
|
||||||
import io
|
import io
|
||||||
StringIO = io.StringIO
|
StringIO = io.StringIO
|
||||||
BytesIO = io.BytesIO
|
BytesIO = io.BytesIO
|
||||||
|
_assertCountEqual = "assertCountEqual"
|
||||||
|
if sys.version_info[1] <= 1:
|
||||||
|
_assertRaisesRegex = "assertRaisesRegexp"
|
||||||
|
_assertRegex = "assertRegexpMatches"
|
||||||
|
else:
|
||||||
|
_assertRaisesRegex = "assertRaisesRegex"
|
||||||
|
_assertRegex = "assertRegex"
|
||||||
else:
|
else:
|
||||||
def b(s):
|
def b(s):
|
||||||
return s
|
return s
|
||||||
|
# Workaround for standalone backslash
|
||||||
|
|
||||||
def u(s):
|
def u(s):
|
||||||
return unicode(s, "unicode_escape") # noqa
|
return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
|
||||||
unichr = unichr
|
unichr = unichr
|
||||||
int2byte = chr
|
int2byte = chr
|
||||||
|
|
||||||
@@ -506,27 +653,38 @@ else:
|
|||||||
|
|
||||||
def indexbytes(buf, i):
|
def indexbytes(buf, i):
|
||||||
return ord(buf[i])
|
return ord(buf[i])
|
||||||
|
iterbytes = functools.partial(itertools.imap, ord)
|
||||||
def iterbytes(buf):
|
|
||||||
return (ord(byte) for byte in buf)
|
|
||||||
import StringIO
|
import StringIO
|
||||||
StringIO = BytesIO = StringIO.StringIO
|
StringIO = BytesIO = StringIO.StringIO
|
||||||
|
_assertCountEqual = "assertItemsEqual"
|
||||||
|
_assertRaisesRegex = "assertRaisesRegexp"
|
||||||
|
_assertRegex = "assertRegexpMatches"
|
||||||
_add_doc(b, """Byte literal""")
|
_add_doc(b, """Byte literal""")
|
||||||
_add_doc(u, """Text literal""")
|
_add_doc(u, """Text literal""")
|
||||||
|
|
||||||
|
|
||||||
|
def assertCountEqual(self, *args, **kwargs):
|
||||||
|
return getattr(self, _assertCountEqual)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def assertRaisesRegex(self, *args, **kwargs):
|
||||||
|
return getattr(self, _assertRaisesRegex)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def assertRegex(self, *args, **kwargs):
|
||||||
|
return getattr(self, _assertRegex)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
if PY3:
|
||||||
import builtins
|
exec_ = getattr(moves.builtins, "exec")
|
||||||
exec_ = getattr(builtins, "exec")
|
|
||||||
|
|
||||||
def reraise(tp, value, tb=None):
|
def reraise(tp, value, tb=None):
|
||||||
|
if value is None:
|
||||||
|
value = tp()
|
||||||
if value.__traceback__ is not tb:
|
if value.__traceback__ is not tb:
|
||||||
raise value.with_traceback(tb)
|
raise value.with_traceback(tb)
|
||||||
raise value
|
raise value
|
||||||
|
|
||||||
print_ = getattr(builtins, "print")
|
|
||||||
del builtins
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
def exec_(_code_, _globs_=None, _locs_=None):
|
def exec_(_code_, _globs_=None, _locs_=None):
|
||||||
"""Execute code in a namespace."""
|
"""Execute code in a namespace."""
|
||||||
@@ -544,26 +702,52 @@ else:
|
|||||||
raise tp, value, tb
|
raise tp, value, tb
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info[:2] == (3, 2):
|
||||||
|
exec_("""def raise_from(value, from_value):
|
||||||
|
if from_value is None:
|
||||||
|
raise value
|
||||||
|
raise value from from_value
|
||||||
|
""")
|
||||||
|
elif sys.version_info[:2] > (3, 2):
|
||||||
|
exec_("""def raise_from(value, from_value):
|
||||||
|
raise value from from_value
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
def raise_from(value, from_value):
|
||||||
|
raise value
|
||||||
|
|
||||||
|
|
||||||
|
print_ = getattr(moves.builtins, "print", None)
|
||||||
|
if print_ is None:
|
||||||
def print_(*args, **kwargs):
|
def print_(*args, **kwargs):
|
||||||
"""The new-style print function."""
|
"""The new-style print function for Python 2.4 and 2.5."""
|
||||||
fp = kwargs.pop("file", sys.stdout)
|
fp = kwargs.pop("file", sys.stdout)
|
||||||
if fp is None:
|
if fp is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
def write(data):
|
def write(data):
|
||||||
if not isinstance(data, basestring): # noqa
|
if not isinstance(data, basestring):
|
||||||
data = str(data)
|
data = str(data)
|
||||||
|
# If the file has an encoding, encode unicode with it.
|
||||||
|
if (isinstance(fp, file) and
|
||||||
|
isinstance(data, unicode) and
|
||||||
|
fp.encoding is not None):
|
||||||
|
errors = getattr(fp, "errors", None)
|
||||||
|
if errors is None:
|
||||||
|
errors = "strict"
|
||||||
|
data = data.encode(fp.encoding, errors)
|
||||||
fp.write(data)
|
fp.write(data)
|
||||||
want_unicode = False
|
want_unicode = False
|
||||||
sep = kwargs.pop("sep", None)
|
sep = kwargs.pop("sep", None)
|
||||||
if sep is not None:
|
if sep is not None:
|
||||||
if isinstance(sep, unicode): # noqa
|
if isinstance(sep, unicode):
|
||||||
want_unicode = True
|
want_unicode = True
|
||||||
elif not isinstance(sep, str):
|
elif not isinstance(sep, str):
|
||||||
raise TypeError("sep must be None or a string")
|
raise TypeError("sep must be None or a string")
|
||||||
end = kwargs.pop("end", None)
|
end = kwargs.pop("end", None)
|
||||||
if end is not None:
|
if end is not None:
|
||||||
if isinstance(end, unicode): # noqa
|
if isinstance(end, unicode):
|
||||||
want_unicode = True
|
want_unicode = True
|
||||||
elif not isinstance(end, str):
|
elif not isinstance(end, str):
|
||||||
raise TypeError("end must be None or a string")
|
raise TypeError("end must be None or a string")
|
||||||
@@ -571,12 +755,12 @@ else:
|
|||||||
raise TypeError("invalid keyword arguments to print()")
|
raise TypeError("invalid keyword arguments to print()")
|
||||||
if not want_unicode:
|
if not want_unicode:
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if isinstance(arg, unicode): # noqa
|
if isinstance(arg, unicode):
|
||||||
want_unicode = True
|
want_unicode = True
|
||||||
break
|
break
|
||||||
if want_unicode:
|
if want_unicode:
|
||||||
newline = unicode("\n") # noqa
|
newline = unicode("\n")
|
||||||
space = unicode(" ") # noqa
|
space = unicode(" ")
|
||||||
else:
|
else:
|
||||||
newline = "\n"
|
newline = "\n"
|
||||||
space = " "
|
space = " "
|
||||||
@@ -589,22 +773,96 @@ else:
|
|||||||
write(sep)
|
write(sep)
|
||||||
write(arg)
|
write(arg)
|
||||||
write(end)
|
write(end)
|
||||||
|
if sys.version_info[:2] < (3, 3):
|
||||||
|
_print = print_
|
||||||
|
|
||||||
|
def print_(*args, **kwargs):
|
||||||
|
fp = kwargs.get("file", sys.stdout)
|
||||||
|
flush = kwargs.pop("flush", False)
|
||||||
|
_print(*args, **kwargs)
|
||||||
|
if flush and fp is not None:
|
||||||
|
fp.flush()
|
||||||
|
|
||||||
_add_doc(reraise, """Reraise an exception.""")
|
_add_doc(reraise, """Reraise an exception.""")
|
||||||
|
|
||||||
|
if sys.version_info[0:2] < (3, 4):
|
||||||
|
def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
|
||||||
|
updated=functools.WRAPPER_UPDATES):
|
||||||
|
def wrapper(f):
|
||||||
|
f = functools.wraps(wrapped, assigned, updated)(f)
|
||||||
|
f.__wrapped__ = wrapped
|
||||||
|
return f
|
||||||
|
return wrapper
|
||||||
|
else:
|
||||||
|
wraps = functools.wraps
|
||||||
|
|
||||||
|
|
||||||
def with_metaclass(meta, *bases):
|
def with_metaclass(meta, *bases):
|
||||||
"""Create a base class with a metaclass."""
|
"""Create a base class with a metaclass."""
|
||||||
return meta("NewBase", bases, {})
|
# This requires a bit of explanation: the basic idea is to make a dummy
|
||||||
|
# metaclass for one level of class instantiation that replaces itself with
|
||||||
|
# the actual metaclass.
|
||||||
|
class metaclass(meta):
|
||||||
|
|
||||||
|
def __new__(cls, name, this_bases, d):
|
||||||
|
return meta(name, bases, d)
|
||||||
|
return type.__new__(metaclass, 'temporary_class', (), {})
|
||||||
|
|
||||||
|
|
||||||
def add_metaclass(metaclass):
|
def add_metaclass(metaclass):
|
||||||
"""Class decorator for creating a class with a metaclass."""
|
"""Class decorator for creating a class with a metaclass."""
|
||||||
def wrapper(cls):
|
def wrapper(cls):
|
||||||
orig_vars = cls.__dict__.copy()
|
orig_vars = cls.__dict__.copy()
|
||||||
|
slots = orig_vars.get('__slots__')
|
||||||
|
if slots is not None:
|
||||||
|
if isinstance(slots, str):
|
||||||
|
slots = [slots]
|
||||||
|
for slots_var in slots:
|
||||||
|
orig_vars.pop(slots_var)
|
||||||
orig_vars.pop('__dict__', None)
|
orig_vars.pop('__dict__', None)
|
||||||
orig_vars.pop('__weakref__', None)
|
orig_vars.pop('__weakref__', None)
|
||||||
for slots_var in orig_vars.get('__slots__', ()):
|
|
||||||
orig_vars.pop(slots_var)
|
|
||||||
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def python_2_unicode_compatible(klass):
|
||||||
|
"""
|
||||||
|
A decorator that defines __unicode__ and __str__ methods under Python 2.
|
||||||
|
Under Python 3 it does nothing.
|
||||||
|
|
||||||
|
To support Python 2 and 3 with a single code base, define a __str__ method
|
||||||
|
returning text and apply this decorator to the class.
|
||||||
|
"""
|
||||||
|
if PY2:
|
||||||
|
if '__str__' not in klass.__dict__:
|
||||||
|
raise ValueError("@python_2_unicode_compatible cannot be applied "
|
||||||
|
"to %s because it doesn't define __str__()." %
|
||||||
|
klass.__name__)
|
||||||
|
klass.__unicode__ = klass.__str__
|
||||||
|
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
|
||||||
|
return klass
|
||||||
|
|
||||||
|
|
||||||
|
# Complete the moves implementation.
|
||||||
|
# This code is at the end of this module to speed up module loading.
|
||||||
|
# Turn this module into a package.
|
||||||
|
__path__ = [] # required for PEP 302 and PEP 451
|
||||||
|
__package__ = __name__ # see PEP 366 @ReservedAssignment
|
||||||
|
if globals().get("__spec__") is not None:
|
||||||
|
__spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
|
||||||
|
# Remove other six meta path importers, since they cause problems. This can
|
||||||
|
# happen if six is removed from sys.modules and then reloaded. (Setuptools does
|
||||||
|
# this for some reason.)
|
||||||
|
if sys.meta_path:
|
||||||
|
for i, importer in enumerate(sys.meta_path):
|
||||||
|
# Here's some real nastiness: Another "instance" of the six module might
|
||||||
|
# be floating around. Therefore, we can't use isinstance() to check for
|
||||||
|
# the six meta path importer, since the other six instance will have
|
||||||
|
# inserted an importer with different class.
|
||||||
|
if (type(importer).__name__ == "_SixMetaPathImporter" and
|
||||||
|
importer.name == __name__):
|
||||||
|
del sys.meta_path[i]
|
||||||
|
break
|
||||||
|
del i, importer
|
||||||
|
# Finally, add the importer to the meta path import hook.
|
||||||
|
sys.meta_path.append(_importer)
|
||||||
|
|||||||
Reference in New Issue
Block a user