1st trial
This commit is contained in:
19
.travis.yml
19
.travis.yml
@@ -2,9 +2,7 @@ language: python
|
||||
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.pip-cache/
|
||||
cache: pip
|
||||
|
||||
python:
|
||||
- '2.7'
|
||||
@@ -12,20 +10,7 @@ python:
|
||||
- '3.5'
|
||||
|
||||
install:
|
||||
- |
|
||||
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 pycrypto; fi;
|
||||
- if [[ $TRAVIS_PYTHON_VERSION != '3.5' ]]; then pip install -e .; fi;
|
||||
|
||||
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
|
||||
# All rights reserved.
|
||||
#
|
||||
@@ -28,258 +39,9 @@
|
||||
__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(
|
||||
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.
|
||||
|
||||
This function is part of the `DBAPI 2.0 specification
|
||||
@@ -287,9 +49,7 @@ def connect(
|
||||
function are not defined by the specification.
|
||||
|
||||
:param user:
|
||||
The username to connect to the PostgreSQL server with. If this is not
|
||||
provided, pg8000 looks first for the PGUSER then the USER environment
|
||||
variables.
|
||||
The username to connect to the PostgreSQL server with.
|
||||
|
||||
If your server character encoding is not ``ascii`` or ``utf8``, then
|
||||
you need to provide ``user`` as bytes, eg.
|
||||
@@ -325,15 +85,24 @@ def connect(
|
||||
authentication, the connection will fail to open. If this parameter
|
||||
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:
|
||||
Use SSL encryption for TCP/IP sockets if ``True``. Defaults to
|
||||
``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:
|
||||
A :class:`Connection` object.
|
||||
"""
|
||||
return Connection(
|
||||
user, host, unix_sock, port, database, password, ssl)
|
||||
user, host, unix_sock, port, database, password, ssl, timeout)
|
||||
|
||||
apilevel = "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 type oid."""
|
||||
|
||||
if PY2:
|
||||
BINARY = Bytea
|
||||
else:
|
||||
BINARY = bytes
|
||||
|
||||
NUMBER = 1700
|
||||
"""Numeric type oid"""
|
||||
@@ -396,104 +161,15 @@ DATETIME = 1114
|
||||
ROWID = 26
|
||||
"""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__ = [
|
||||
Warning, Bytea, DataError, DatabaseError, connect, InterfaceError,
|
||||
ProgrammingError, Error, OperationalError, IntegrityError, InternalError,
|
||||
NotSupportedError, ArrayContentNotHomogenousError, ArrayContentEmptyError,
|
||||
ArrayDimensionsNotConsistentError, ArrayContentNotSupportedError, utc,
|
||||
Connection, Cursor]
|
||||
Connection, Cursor, Binary, Date, DateFromTicks, Time, TimeFromTicks,
|
||||
Timestamp, TimestampFromTicks, BINARY, Interval]
|
||||
|
||||
"""Version string for pg8000.
|
||||
|
||||
.. 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.
|
||||
|
||||
# This file is released into the public domain. Generated by
|
||||
# versioneer-0.12 (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"
|
||||
# versioneer-0.15 (https://github.com/warner/python-versioneer)
|
||||
|
||||
import errno
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
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):
|
||||
@@ -29,6 +65,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
|
||||
p = None
|
||||
for c in commands:
|
||||
try:
|
||||
dispcmd = str([c] + args)
|
||||
# remember shell=False, so use git.cmd on windows, not just git
|
||||
p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
|
||||
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:
|
||||
continue
|
||||
if verbose:
|
||||
print("unable to run %s" % args[0])
|
||||
print("unable to run %s" % dispcmd)
|
||||
print(e)
|
||||
return None
|
||||
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,))
|
||||
return None
|
||||
stdout = p.communicate()[0].strip()
|
||||
if sys.version >= '3':
|
||||
if sys.version_info[0] >= 3:
|
||||
stdout = stdout.decode()
|
||||
if p.returncode != 0:
|
||||
if verbose:
|
||||
print("unable to run %s (error)" % args[0])
|
||||
print("unable to run %s (error)" % dispcmd)
|
||||
return None
|
||||
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
|
||||
# both the project name and a version string.
|
||||
dirname = os.path.basename(root)
|
||||
if not dirname.startswith(parentdir_prefix):
|
||||
if verbose:
|
||||
print(
|
||||
"guessing rootdir is '%s', but '%s' doesn't start with "
|
||||
"prefix '%s'" % (root, dirname, parentdir_prefix))
|
||||
return None
|
||||
return {"version": dirname[len(parentdir_prefix):], "full": ""}
|
||||
print("guessing rootdir is '%s', but '%s' doesn't start with "
|
||||
"prefix '%s'" % (root, dirname, parentdir_prefix))
|
||||
raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
|
||||
return {"version": dirname[len(parentdir_prefix):],
|
||||
"full-revisionid": None,
|
||||
"dirty": False, "error": None}
|
||||
|
||||
|
||||
@register_vcs_handler("git", "get_keywords")
|
||||
def git_get_keywords(versionfile_abs):
|
||||
# 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,
|
||||
@@ -92,14 +131,15 @@ def git_get_keywords(versionfile_abs):
|
||||
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:
|
||||
return {} # keyword-finding function failed to find keywords
|
||||
raise NotThisMethod("no keywords at all, weird")
|
||||
refnames = keywords["refnames"].strip()
|
||||
if refnames.startswith("$Format"):
|
||||
if verbose:
|
||||
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(",")])
|
||||
# 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.
|
||||
@@ -124,18 +164,20 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose=False):
|
||||
r = ref[len(tag_prefix):]
|
||||
if verbose:
|
||||
print("picking %s" % r)
|
||||
return {
|
||||
"version": r,
|
||||
"full": keywords["full"].strip()}
|
||||
# no suitable tags, so we use the full revision id
|
||||
return {"version": r,
|
||||
"full-revisionid": keywords["full"].strip(),
|
||||
"dirty": False, "error": None
|
||||
}
|
||||
# no suitable tags, so version is "0+unknown", but full hex is still there
|
||||
if verbose:
|
||||
print("no suitable tags, using full revision id")
|
||||
return {
|
||||
"version": keywords["full"].strip(),
|
||||
"full": keywords["full"].strip()}
|
||||
print("no suitable tags, using unknown + full revision id")
|
||||
return {"version": "0+unknown",
|
||||
"full-revisionid": 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
|
||||
# if the git-archive 'subst' keywords were *not* expanded, and
|
||||
# _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 verbose:
|
||||
print("no .git in %s" % root)
|
||||
return {}
|
||||
raise NotThisMethod("no .git directory")
|
||||
|
||||
GITS = ["git"]
|
||||
if sys.platform == "win32":
|
||||
GITS = ["git.cmd", "git.exe"]
|
||||
stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"],
|
||||
cwd=root)
|
||||
if stdout is None:
|
||||
return {}
|
||||
if not stdout.startswith(tag_prefix):
|
||||
if verbose:
|
||||
print(
|
||||
"tag '%s' doesn't start with prefix '%s'" %
|
||||
(stdout, tag_prefix))
|
||||
return {}
|
||||
tag = stdout[len(tag_prefix):]
|
||||
stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
|
||||
if stdout is None:
|
||||
return {}
|
||||
full = stdout.strip()
|
||||
if tag.endswith("-dirty"):
|
||||
full += "-dirty"
|
||||
return {"version": tag, "full": full}
|
||||
# if there is a tag, this yields TAG-NUM-gHEX[-dirty]
|
||||
# if there are no tags, this yields HEX[-dirty] (no NUM)
|
||||
describe_out = run_command(GITS, ["describe", "--tags", "--dirty",
|
||||
"--always", "--long"],
|
||||
cwd=root)
|
||||
# --long was added in git-1.5.5
|
||||
if describe_out is None:
|
||||
raise NotThisMethod("'git describe' failed")
|
||||
describe_out = describe_out.strip()
|
||||
full_out = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
|
||||
if full_out is None:
|
||||
raise NotThisMethod("'git rev-parse' failed")
|
||||
full_out = full_out.strip()
|
||||
|
||||
pieces = {}
|
||||
pieces["long"] = full_out
|
||||
pieces["short"] = full_out[:7] # maybe improved later
|
||||
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
|
||||
# __file__, we can work backwards from there to the root. Some
|
||||
# py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
|
||||
# case we can only use expanded keywords.
|
||||
|
||||
keywords = {"refnames": git_refnames, "full": git_full}
|
||||
ver = git_versions_from_keywords(keywords, tag_prefix, verbose)
|
||||
if ver:
|
||||
return ver
|
||||
cfg = get_config()
|
||||
verbose = cfg.verbose
|
||||
|
||||
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
|
||||
# tree (where the .git directory might live) to this file. Invert
|
||||
# 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)
|
||||
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)
|
||||
or versions_from_parentdir(parentdir_prefix, root, verbose)
|
||||
or default)
|
||||
try:
|
||||
pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
|
||||
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"}
|
||||
|
||||
@@ -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
|
||||
# All rights reserved.
|
||||
#
|
||||
@@ -27,34 +47,6 @@
|
||||
|
||||
__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:
|
||||
from json import loads
|
||||
@@ -78,9 +70,350 @@ class UTC(datetime.tzinfo):
|
||||
|
||||
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_BINARY = 1
|
||||
@@ -271,13 +604,13 @@ def timestamp_recv_integer(data, offset, length):
|
||||
micros = q_unpack(data, offset)[0]
|
||||
try:
|
||||
return EPOCH + timedelta(microseconds=micros)
|
||||
except OverflowError:
|
||||
except OverflowError as e:
|
||||
if micros == INFINITY_MICROSECONDS:
|
||||
return datetime.datetime.max
|
||||
elif micros == MINUS_INFINITY_MICROSECONDS:
|
||||
return datetime.datetime.min
|
||||
else:
|
||||
raise exc_info()[1]
|
||||
raise e
|
||||
|
||||
|
||||
# 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
|
||||
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):
|
||||
@@ -325,13 +658,13 @@ def timestamptz_recv_integer(data, offset, length):
|
||||
micros = q_unpack(data, offset)[0]
|
||||
try:
|
||||
return EPOCH_TZ + timedelta(microseconds=micros)
|
||||
except OverflowError:
|
||||
except OverflowError as e:
|
||||
if micros == INFINITY_MICROSECONDS:
|
||||
return DATETIME_MAX_TZ
|
||||
elif micros == MINUS_INFINITY_MICROSECONDS:
|
||||
return DATETIME_MIN_TZ
|
||||
else:
|
||||
raise exc_info()[1]
|
||||
raise e
|
||||
|
||||
|
||||
def timestamptz_recv_float(data, offset, length):
|
||||
@@ -565,21 +898,19 @@ class Cursor():
|
||||
.. versionadded:: 1.9.11
|
||||
"""
|
||||
try:
|
||||
self._c._lock.acquire()
|
||||
self.stream = stream
|
||||
with self._c._lock:
|
||||
self.stream = stream
|
||||
|
||||
if not self._c.in_transaction and not self._c.autocommit:
|
||||
self._c.execute(self, "begin transaction", None)
|
||||
self._c.execute(self, operation, args)
|
||||
except AttributeError:
|
||||
if not self._c.in_transaction and not self._c.autocommit:
|
||||
self._c.execute(self, "begin transaction", None)
|
||||
self._c.execute(self, operation, args)
|
||||
except AttributeError as e:
|
||||
if self._c is None:
|
||||
raise InterfaceError("Cursor closed")
|
||||
elif self._c._sock is None:
|
||||
raise InterfaceError("connection is closed")
|
||||
else:
|
||||
raise exc_info()[1]
|
||||
finally:
|
||||
self._c._lock.release()
|
||||
raise e
|
||||
|
||||
def executemany(self, operation, param_sets):
|
||||
"""Prepare a database operation, and then execute it against all
|
||||
@@ -690,28 +1021,26 @@ class Cursor():
|
||||
pass
|
||||
|
||||
def __next__(self):
|
||||
try:
|
||||
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)
|
||||
with self._c._lock:
|
||||
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()
|
||||
finally:
|
||||
self._c._lock.release()
|
||||
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:
|
||||
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:
|
||||
Cursor.next = Cursor.__next__
|
||||
@@ -737,6 +1066,7 @@ COPY_DONE = b("c")
|
||||
COPY_DATA = b("d")
|
||||
COPY_IN_RESPONSE = b("G")
|
||||
COPY_OUT_RESPONSE = b("H")
|
||||
EMPTY_QUERY_RESPONSE = b("I")
|
||||
|
||||
BIND = b("B")
|
||||
PARSE = b("P")
|
||||
@@ -776,14 +1106,6 @@ IDLE_IN_TRANSACTION = b("T")
|
||||
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))
|
||||
|
||||
|
||||
@@ -895,7 +1217,9 @@ class Connection(object):
|
||||
error.__name__, stacklevel=3)
|
||||
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._commands_with_count = (
|
||||
b("INSERT"), b("DELETE"), b("UPDATE"), b("MOVE"),
|
||||
@@ -903,23 +1227,19 @@ class Connection(object):
|
||||
self._lock = threading.Lock()
|
||||
|
||||
if user is None:
|
||||
try:
|
||||
self.user = os.environ['PGUSER']
|
||||
except KeyError:
|
||||
try:
|
||||
self.user = os.environ['USER']
|
||||
except KeyError:
|
||||
raise InterfaceError(
|
||||
"The 'user' connection parameter was omitted, and "
|
||||
"neither the PGUSER or USER environment variables "
|
||||
"were set.")
|
||||
raise InterfaceError(
|
||||
"The 'user' connection parameter cannot be None")
|
||||
|
||||
if isinstance(user, text_type):
|
||||
self.user = user.encode('utf8')
|
||||
else:
|
||||
self.user = user
|
||||
|
||||
if isinstance(self.user, text_type):
|
||||
self.user = self.user.encode('utf8')
|
||||
if isinstance(password, text_type):
|
||||
self.password = password.encode('utf8')
|
||||
else:
|
||||
self.password = password
|
||||
|
||||
self.password = password
|
||||
self.autocommit = False
|
||||
self._xid = None
|
||||
|
||||
@@ -939,41 +1259,38 @@ class Connection(object):
|
||||
else:
|
||||
raise ProgrammingError(
|
||||
"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:
|
||||
self._usock.connect((host, port))
|
||||
elif unix_sock is not None:
|
||||
self._usock.connect(unix_sock)
|
||||
|
||||
if ssl:
|
||||
try:
|
||||
self._lock.acquire()
|
||||
import ssl as sslmodule
|
||||
# Int32(8) - Message length, including self.
|
||||
# Int32(80877103) - The SSL request code.
|
||||
self._usock.sendall(ii_pack(8, 80877103))
|
||||
resp = self._usock.recv(1)
|
||||
if resp == b('S'):
|
||||
self._usock = sslmodule.wrap_socket(self._usock)
|
||||
else:
|
||||
raise InterfaceError("Server refuses SSL")
|
||||
except ImportError:
|
||||
raise InterfaceError(
|
||||
"SSL required but ssl module not available in "
|
||||
"this python installation")
|
||||
finally:
|
||||
self._lock.release()
|
||||
with self._lock:
|
||||
try:
|
||||
import ssl as sslmodule
|
||||
# Int32(8) - Message length, including self.
|
||||
# Int32(80877103) - The SSL request code.
|
||||
self._usock.sendall(ii_pack(8, 80877103))
|
||||
resp = self._usock.recv(1)
|
||||
if resp == b('S'):
|
||||
self._usock = sslmodule.wrap_socket(self._usock)
|
||||
else:
|
||||
raise InterfaceError("Server refuses SSL")
|
||||
except ImportError:
|
||||
raise InterfaceError(
|
||||
"SSL required but ssl module not available in "
|
||||
"this python installation")
|
||||
|
||||
self._sock = self._usock.makefile(mode="rwb")
|
||||
except socket.error:
|
||||
except socket.error as e:
|
||||
self._usock.close()
|
||||
raise InterfaceError("communication error", exc_info()[1])
|
||||
raise InterfaceError("communication error", e)
|
||||
self._flush = self._sock.flush
|
||||
self._read = self._sock.read
|
||||
|
||||
if PRE_26:
|
||||
self._write = self._sock.writelines
|
||||
else:
|
||||
self._write = self._sock.write
|
||||
self._write = self._sock.write
|
||||
self._backend_key_data = None
|
||||
|
||||
##
|
||||
@@ -1182,7 +1499,6 @@ class Connection(object):
|
||||
bool: (16, FC_BINARY, bool_send),
|
||||
int: (705, FC_TEXT, unknown_out),
|
||||
float: (701, FC_BINARY, d_pack), # float8
|
||||
str: (705, FC_TEXT, text_out), # unknown
|
||||
datetime.date: (1082, FC_TEXT, date_out), # date
|
||||
datetime.time: (1083, FC_TEXT, time_out), # time
|
||||
1114: (1114, FC_BINARY, timestamp_send_integer), # timestamp
|
||||
@@ -1203,10 +1519,12 @@ class Connection(object):
|
||||
if PY2:
|
||||
self.py_types[Bytea] = (17, FC_BINARY, bytea_send) # bytea
|
||||
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
|
||||
else:
|
||||
self.py_types[bytes] = (17, FC_BINARY, bytea_send) # bytea
|
||||
self.py_types[str] = (705, FC_TEXT, text_out) # unknown
|
||||
|
||||
try:
|
||||
from ipaddress import (
|
||||
@@ -1240,6 +1558,7 @@ class Connection(object):
|
||||
READY_FOR_QUERY: self.handle_READY_FOR_QUERY,
|
||||
ROW_DESCRIPTION: self.handle_ROW_DESCRIPTION,
|
||||
ERROR_RESPONSE: self.handle_ERROR_RESPONSE,
|
||||
EMPTY_QUERY_RESPONSE: self.handle_EMPTY_QUERY_RESPONSE,
|
||||
DATA_ROW: self.handle_DATA_ROW,
|
||||
COMMAND_COMPLETE: self.handle_COMMAND_COMPLETE,
|
||||
PARSE_COMPLETE: self.handle_PARSE_COMPLETE,
|
||||
@@ -1272,32 +1591,37 @@ class Connection(object):
|
||||
self._flush()
|
||||
|
||||
self._cursor = self.cursor()
|
||||
try:
|
||||
self._lock.acquire()
|
||||
code = self.error = None
|
||||
while code not in (READY_FOR_QUERY, ERROR_RESPONSE):
|
||||
code, data_len = ci_unpack(self._read(5))
|
||||
self.message_types[code](self._read(data_len - 4), None)
|
||||
if self.error is not None:
|
||||
raise self.error
|
||||
except:
|
||||
self._close()
|
||||
raise
|
||||
finally:
|
||||
self._lock.release()
|
||||
with self._lock:
|
||||
try:
|
||||
code = self.error = None
|
||||
while code not in (READY_FOR_QUERY, ERROR_RESPONSE):
|
||||
code, data_len = ci_unpack(self._read(5))
|
||||
self.message_types[code](self._read(data_len - 4), None)
|
||||
if self.error is not None:
|
||||
raise self.error
|
||||
except Exception as e:
|
||||
try:
|
||||
self._close()
|
||||
except Exception:
|
||||
pass
|
||||
raise e
|
||||
|
||||
self.in_transaction = False
|
||||
self.notifies = []
|
||||
self.notifies_lock = threading.Lock()
|
||||
|
||||
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":
|
||||
self.error = InterfaceError("md5 password authentication failed")
|
||||
else:
|
||||
self.error = ProgrammingError(
|
||||
msg_dict[RESPONSE_SEVERITY], msg_dict[RESPONSE_CODE],
|
||||
msg_dict[RESPONSE_MSG])
|
||||
self.error = ProgrammingError(*tuple(v for k, v in responses))
|
||||
|
||||
def handle_EMPTY_QUERY_RESPONSE(self, data, ps):
|
||||
self.error = ProgrammingError("query was empty")
|
||||
|
||||
def handle_CLOSE_COMPLETE(self, data, ps):
|
||||
pass
|
||||
@@ -1391,11 +1715,8 @@ class Connection(object):
|
||||
# additional_info = data[idx:idx + null]
|
||||
|
||||
# psycopg2 compatible notification interface
|
||||
try:
|
||||
self.notifies_lock.acquire()
|
||||
with self.notifies_lock:
|
||||
self.notifies.append((backend_pid, condition))
|
||||
finally:
|
||||
self.notifies_lock.release()
|
||||
|
||||
def cursor(self):
|
||||
"""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
|
||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||
"""
|
||||
try:
|
||||
self._lock.acquire()
|
||||
with self._lock:
|
||||
self.execute(self._cursor, "commit", None)
|
||||
finally:
|
||||
self._lock.release()
|
||||
|
||||
def rollback(self):
|
||||
"""Rolls back the current database transaction.
|
||||
@@ -1424,11 +1742,8 @@ class Connection(object):
|
||||
This function is part of the `DBAPI 2.0 specification
|
||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||
"""
|
||||
try:
|
||||
self._lock.acquire()
|
||||
with self._lock:
|
||||
self.execute(self._cursor, "rollback", None)
|
||||
finally:
|
||||
self._lock.release()
|
||||
|
||||
def _close(self):
|
||||
try:
|
||||
@@ -1437,12 +1752,15 @@ class Connection(object):
|
||||
self._write(TERMINATE_MSG)
|
||||
self._flush()
|
||||
self._sock.close()
|
||||
self._usock.close()
|
||||
self._sock = None
|
||||
except AttributeError:
|
||||
raise InterfaceError("connection is closed")
|
||||
except ValueError:
|
||||
raise InterfaceError("connection is closed")
|
||||
except socket.error as e:
|
||||
raise OperationalError(str(e))
|
||||
finally:
|
||||
self._usock.close()
|
||||
self._sock = None
|
||||
|
||||
def close(self):
|
||||
"""Closes the database connection.
|
||||
@@ -1450,11 +1768,8 @@ class Connection(object):
|
||||
This function is part of the `DBAPI 2.0 specification
|
||||
<http://www.python.org/dev/peps/pep-0249/>`_.
|
||||
"""
|
||||
try:
|
||||
self._lock.acquire()
|
||||
with self._lock:
|
||||
self._close()
|
||||
finally:
|
||||
self._lock.release()
|
||||
|
||||
def handle_AUTHENTICATION_REQUEST(self, data, cursor):
|
||||
assert self._lock.locked()
|
||||
@@ -1463,7 +1778,7 @@ class Connection(object):
|
||||
# 0 = AuthenticationOk
|
||||
# 5 = MD5 pwd
|
||||
# 2 = Kerberos v5 (not supported by pg8000)
|
||||
# 3 = Cleartext pwd (not supported by pg8000)
|
||||
# 3 = Cleartext pwd
|
||||
# 4 = crypt() pwd (not supported by pg8000)
|
||||
# 6 = SCM credential (not supported by pg8000)
|
||||
# 7 = GSSAPI (not supported by pg8000)
|
||||
@@ -1480,8 +1795,7 @@ class Connection(object):
|
||||
raise InterfaceError(
|
||||
"server requesting password authentication, but no "
|
||||
"password was provided")
|
||||
self._send_message(
|
||||
PASSWORD, self.password.encode("ascii") + NULL_BYTE)
|
||||
self._send_message(PASSWORD, self.password + NULL_BYTE)
|
||||
self._flush()
|
||||
elif auth_code == 5:
|
||||
##
|
||||
@@ -1497,8 +1811,8 @@ class Connection(object):
|
||||
"server requesting MD5 password authentication, but no "
|
||||
"password was provided")
|
||||
pwd = b("md5") + md5(
|
||||
md5(self.password.encode("ascii") + self.user).
|
||||
hexdigest().encode("ascii") + salt).hexdigest().encode("ascii")
|
||||
md5(self.password + self.user).hexdigest().encode("ascii") +
|
||||
salt).hexdigest().encode("ascii")
|
||||
# Byte1('p') - Identifies the message as a password message.
|
||||
# Int32 - Message length including self.
|
||||
# String - The password. Password may be encrypted.
|
||||
@@ -1536,11 +1850,10 @@ class Connection(object):
|
||||
except KeyError:
|
||||
try:
|
||||
params.append(self.inspect_funcs[typ](value))
|
||||
except KeyError:
|
||||
except KeyError as e:
|
||||
raise NotSupportedError(
|
||||
"type " + str(exc_info()[1]) +
|
||||
"not mapped to pg type")
|
||||
return params
|
||||
"type " + str(e) + "not mapped to pg type")
|
||||
return tuple(params)
|
||||
|
||||
def handle_ROW_DESCRIPTION(self, data, cursor):
|
||||
count = h_unpack(data)[0]
|
||||
@@ -1572,8 +1885,7 @@ class Connection(object):
|
||||
|
||||
args = make_args(vals)
|
||||
params = self.make_params(args)
|
||||
|
||||
key = tuple(oid for oid, x, y in params), operation
|
||||
key = operation, params
|
||||
|
||||
try:
|
||||
ps = cache['ps'][key]
|
||||
@@ -1617,11 +1929,13 @@ class Connection(object):
|
||||
|
||||
try:
|
||||
self._flush()
|
||||
except AttributeError:
|
||||
except AttributeError as e:
|
||||
if self._sock is None:
|
||||
raise InterfaceError("connection is closed")
|
||||
else:
|
||||
raise exc_info()[1]
|
||||
raise e
|
||||
except socket.error as e:
|
||||
raise OperationalError(str(e))
|
||||
|
||||
self.handle_messages(cursor)
|
||||
|
||||
@@ -1711,11 +2025,11 @@ class Connection(object):
|
||||
self._write(i_pack(len(data) + 4))
|
||||
self._write(data)
|
||||
self._write(FLUSH_MSG)
|
||||
except ValueError:
|
||||
if str(exc_info()[1]) == "write to closed file":
|
||||
except ValueError as e:
|
||||
if str(e) == "write to closed file":
|
||||
raise InterfaceError("connection is closed")
|
||||
else:
|
||||
raise exc_info()[1]
|
||||
raise e
|
||||
except AttributeError:
|
||||
raise InterfaceError("connection is closed")
|
||||
|
||||
@@ -1783,8 +2097,13 @@ class Connection(object):
|
||||
self._flush()
|
||||
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):
|
||||
resp = data_into_dict(data)
|
||||
resp = dict((s[0:1], s[1:]) for s in data.split(NULL_BYTE))
|
||||
self.NoticeReceived(resp)
|
||||
|
||||
def handle_PARAMETER_STATUS(self, data, ps):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""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
|
||||
# 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
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
@@ -21,22 +21,21 @@
|
||||
# SOFTWARE.
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import functools
|
||||
import itertools
|
||||
import operator
|
||||
import sys
|
||||
import types
|
||||
|
||||
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
||||
__version__ = "1.4.1"
|
||||
__version__ = "1.10.0"
|
||||
|
||||
|
||||
# Useful for very coarse version differentiation.
|
||||
PY2 = sys.version_info[0] == 2
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
PRE_26 = PY2 and sys.version_info[1] < 6
|
||||
|
||||
IS_JYTHON = sys.platform.lower().count('java') > 0
|
||||
|
||||
PY34 = sys.version_info[0:2] >= (3, 4)
|
||||
|
||||
if PY3:
|
||||
string_types = str,
|
||||
@@ -47,10 +46,10 @@ if PY3:
|
||||
|
||||
MAXSIZE = sys.maxsize
|
||||
else:
|
||||
string_types = basestring, # noqa
|
||||
integer_types = (int, long) # noqa
|
||||
string_types = basestring,
|
||||
integer_types = (int, long)
|
||||
class_types = (type, types.ClassType)
|
||||
text_type = unicode # noqa
|
||||
text_type = unicode
|
||||
binary_type = str
|
||||
|
||||
if sys.platform.startswith("java"):
|
||||
@@ -59,6 +58,7 @@ else:
|
||||
else:
|
||||
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
||||
class X(object):
|
||||
|
||||
def __len__(self):
|
||||
return 1 << 31
|
||||
try:
|
||||
@@ -90,9 +90,13 @@ class _LazyDescr(object):
|
||||
|
||||
def __get__(self, obj, tp):
|
||||
result = self._resolve()
|
||||
setattr(obj, self.name, result)
|
||||
# This is a bit ugly, but it avoids running this again.
|
||||
delattr(tp, self.name)
|
||||
setattr(obj, self.name, result) # Invokes __set__.
|
||||
try:
|
||||
# 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
|
||||
|
||||
|
||||
@@ -110,6 +114,27 @@ class MovedModule(_LazyDescr):
|
||||
def _resolve(self):
|
||||
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):
|
||||
|
||||
@@ -136,38 +161,109 @@ class MovedAttribute(_LazyDescr):
|
||||
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"""
|
||||
__path__ = [] # mark as package
|
||||
|
||||
|
||||
_moved_attributes = [
|
||||
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
|
||||
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
|
||||
MovedAttribute(
|
||||
"filterfalse", "itertools", "itertools", "ifilterfalse",
|
||||
"filterfalse"),
|
||||
MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
|
||||
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
|
||||
MovedAttribute("intern", "__builtin__", "sys"),
|
||||
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("reload_module", "__builtin__", "imp", "reload"),
|
||||
MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
|
||||
MovedAttribute("reduce", "__builtin__", "functools"),
|
||||
MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
|
||||
MovedAttribute("StringIO", "StringIO", "io"),
|
||||
MovedAttribute("UserDict", "UserDict", "collections"),
|
||||
MovedAttribute("UserList", "UserList", "collections"),
|
||||
MovedAttribute("UserString", "UserString", "collections"),
|
||||
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
|
||||
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
|
||||
MovedAttribute(
|
||||
"zip_longest", "itertools", "itertools", "izip_longest",
|
||||
"zip_longest"),
|
||||
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
|
||||
MovedModule("builtins", "__builtin__"),
|
||||
MovedModule("configparser", "ConfigParser"),
|
||||
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_cookies", "Cookie", "http.cookies"),
|
||||
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
||||
MovedModule("html_parser", "HTMLParser", "html.parser"),
|
||||
MovedModule("http_client", "httplib", "http.client"),
|
||||
MovedModule(
|
||||
"email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
|
||||
MovedModule("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_base", "email.MIMEBase", "email.mime.base"),
|
||||
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
|
||||
@@ -177,14 +273,14 @@ _moved_attributes = [
|
||||
MovedModule("queue", "Queue"),
|
||||
MovedModule("reprlib", "repr"),
|
||||
MovedModule("socketserver", "SocketServer"),
|
||||
MovedModule("_thread", "thread", "_thread"),
|
||||
MovedModule("tkinter", "Tkinter"),
|
||||
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
|
||||
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
|
||||
MovedModule(
|
||||
"tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
|
||||
MovedModule(
|
||||
"tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
|
||||
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
|
||||
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
|
||||
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
|
||||
MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
|
||||
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
|
||||
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
|
||||
MovedModule("tkinter_colorchooser", "tkColorChooser",
|
||||
@@ -194,30 +290,41 @@ _moved_attributes = [
|
||||
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
|
||||
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
|
||||
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
|
||||
MovedModule(
|
||||
"tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"),
|
||||
MovedModule(
|
||||
"urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
|
||||
MovedModule(
|
||||
"urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
|
||||
MovedModule(
|
||||
"urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
|
||||
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
|
||||
"tkinter.simpledialog"),
|
||||
MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
|
||||
MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
|
||||
MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
|
||||
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:
|
||||
setattr(_MovedItems, attr.name, attr)
|
||||
if isinstance(attr, MovedModule):
|
||||
_importer._add_module(attr, "moves." + attr.name)
|
||||
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"""
|
||||
|
||||
|
||||
_urllib_parse_moved_attributes = [
|
||||
MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
|
||||
MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
|
||||
@@ -231,18 +338,27 @@ _urllib_parse_moved_attributes = [
|
||||
MovedAttribute("unquote", "urllib", "urllib.parse"),
|
||||
MovedAttribute("unquote_plus", "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:
|
||||
setattr(Module_six_moves_urllib_parse, attr.name, attr)
|
||||
del attr
|
||||
|
||||
sys.modules[__name__ + ".moves.urllib_parse"] = Module_six_moves_urllib_parse(
|
||||
__name__ + ".moves.urllib_parse")
|
||||
sys.modules[__name__ + ".moves.urllib.parse"] = Module_six_moves_urllib_parse(
|
||||
__name__ + ".moves.urllib.parse")
|
||||
Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_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"""
|
||||
|
||||
|
||||
@@ -255,13 +371,14 @@ for attr in _urllib_error_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_error, attr.name, attr)
|
||||
del attr
|
||||
|
||||
sys.modules[__name__ + ".moves.urllib_error"] = Module_six_moves_urllib_error(
|
||||
__name__ + ".moves.urllib_error")
|
||||
sys.modules[__name__ + ".moves.urllib.error"] = Module_six_moves_urllib_error(
|
||||
__name__ + ".moves.urllib.error")
|
||||
Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_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"""
|
||||
|
||||
|
||||
@@ -280,8 +397,7 @@ _urllib_request_moved_attributes = [
|
||||
MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
|
||||
MovedAttribute(
|
||||
"HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
|
||||
MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
|
||||
MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
|
||||
@@ -299,18 +415,20 @@ _urllib_request_moved_attributes = [
|
||||
MovedAttribute("urlcleanup", "urllib", "urllib.request"),
|
||||
MovedAttribute("URLopener", "urllib", "urllib.request"),
|
||||
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
|
||||
MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
|
||||
]
|
||||
for attr in _urllib_request_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_request, attr.name, attr)
|
||||
del attr
|
||||
|
||||
sys.modules[__name__ + ".moves.urllib_request"] = \
|
||||
Module_six_moves_urllib_request(__name__ + ".moves.urllib_request")
|
||||
sys.modules[__name__ + ".moves.urllib.request"] = \
|
||||
Module_six_moves_urllib_request(__name__ + ".moves.urllib.request")
|
||||
Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
|
||||
|
||||
_importer._add_module(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"""
|
||||
|
||||
|
||||
@@ -324,13 +442,14 @@ for attr in _urllib_response_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_response, attr.name, attr)
|
||||
del attr
|
||||
|
||||
sys.modules[__name__ + ".moves.urllib_response"] = \
|
||||
Module_six_moves_urllib_response(__name__ + ".moves.urllib_response")
|
||||
sys.modules[__name__ + ".moves.urllib.response"] = \
|
||||
Module_six_moves_urllib_response(__name__ + ".moves.urllib.response")
|
||||
Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
|
||||
|
||||
_importer._add_module(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"""
|
||||
|
||||
|
||||
@@ -341,25 +460,27 @@ for attr in _urllib_robotparser_moved_attributes:
|
||||
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
|
||||
del attr
|
||||
|
||||
sys.modules[__name__ + ".moves.urllib_robotparser"] = \
|
||||
Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib_robotparser")
|
||||
sys.modules[__name__ + ".moves.urllib.robotparser"] = \
|
||||
Module_six_moves_urllib_robotparser(
|
||||
__name__ + ".moves.urllib.robotparser")
|
||||
Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
|
||||
"moves.urllib_robotparser", "moves.urllib.robotparser")
|
||||
|
||||
|
||||
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(
|
||||
__name__ + ".moves.urllib")
|
||||
def __dir__(self):
|
||||
return ['parse', 'error', 'request', 'response', 'robotparser']
|
||||
|
||||
_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
|
||||
"moves.urllib")
|
||||
|
||||
|
||||
def add_move(move):
|
||||
@@ -386,11 +507,6 @@ if PY3:
|
||||
_func_code = "__code__"
|
||||
_func_defaults = "__defaults__"
|
||||
_func_globals = "__globals__"
|
||||
|
||||
_iterkeys = "keys"
|
||||
_itervalues = "values"
|
||||
_iteritems = "items"
|
||||
_iterlists = "lists"
|
||||
else:
|
||||
_meth_func = "im_func"
|
||||
_meth_self = "im_self"
|
||||
@@ -400,11 +516,6 @@ else:
|
||||
_func_defaults = "func_defaults"
|
||||
_func_globals = "func_globals"
|
||||
|
||||
_iterkeys = "iterkeys"
|
||||
_itervalues = "itervalues"
|
||||
_iteritems = "iteritems"
|
||||
_iterlists = "iterlists"
|
||||
|
||||
|
||||
try:
|
||||
advance_iterator = next
|
||||
@@ -427,6 +538,9 @@ if PY3:
|
||||
|
||||
create_bound_method = types.MethodType
|
||||
|
||||
def create_unbound_method(func, cls):
|
||||
return func
|
||||
|
||||
Iterator = object
|
||||
else:
|
||||
def get_unbound_function(unbound):
|
||||
@@ -435,6 +549,9 @@ else:
|
||||
def create_bound_method(func, obj):
|
||||
return types.MethodType(func, obj, obj.__class__)
|
||||
|
||||
def create_unbound_method(func, cls):
|
||||
return types.MethodType(func, None, cls)
|
||||
|
||||
class Iterator(object):
|
||||
|
||||
def next(self):
|
||||
@@ -453,24 +570,49 @@ get_function_defaults = operator.attrgetter(_func_defaults)
|
||||
get_function_globals = operator.attrgetter(_func_globals)
|
||||
|
||||
|
||||
def iterkeys(d, **kw):
|
||||
"""Return an iterator over the keys of a dictionary."""
|
||||
return iter(getattr(d, _iterkeys)(**kw))
|
||||
if PY3:
|
||||
def iterkeys(d, **kw):
|
||||
return iter(d.keys(**kw))
|
||||
|
||||
def itervalues(d, **kw):
|
||||
return iter(d.values(**kw))
|
||||
|
||||
def itervalues(d, **kw):
|
||||
"""Return an iterator over the values of a dictionary."""
|
||||
return iter(getattr(d, _itervalues)(**kw))
|
||||
def iteritems(d, **kw):
|
||||
return iter(d.items(**kw))
|
||||
|
||||
def iterlists(d, **kw):
|
||||
return iter(d.lists(**kw))
|
||||
|
||||
def iteritems(d, **kw):
|
||||
"""Return an iterator over the (key, value) pairs of a dictionary."""
|
||||
return iter(getattr(d, _iteritems)(**kw))
|
||||
viewkeys = operator.methodcaller("keys")
|
||||
|
||||
viewvalues = operator.methodcaller("values")
|
||||
|
||||
def iterlists(d, **kw):
|
||||
"""Return an iterator over the (key, [values]) pairs of a dictionary."""
|
||||
return iter(getattr(d, _iterlists)(**kw))
|
||||
viewitems = operator.methodcaller("items")
|
||||
else:
|
||||
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:
|
||||
@@ -480,24 +622,29 @@ if PY3:
|
||||
def u(s):
|
||||
return s
|
||||
unichr = chr
|
||||
if sys.version_info[1] <= 1:
|
||||
def int2byte(i):
|
||||
return bytes((i,))
|
||||
else:
|
||||
# This is about 2x faster than the implementation above on 3.2+
|
||||
int2byte = operator.methodcaller("to_bytes", 1, "big")
|
||||
import struct
|
||||
int2byte = struct.Struct(">B").pack
|
||||
del struct
|
||||
byte2int = operator.itemgetter(0)
|
||||
indexbytes = operator.getitem
|
||||
iterbytes = iter
|
||||
import io
|
||||
StringIO = io.StringIO
|
||||
BytesIO = io.BytesIO
|
||||
_assertCountEqual = "assertCountEqual"
|
||||
if sys.version_info[1] <= 1:
|
||||
_assertRaisesRegex = "assertRaisesRegexp"
|
||||
_assertRegex = "assertRegexpMatches"
|
||||
else:
|
||||
_assertRaisesRegex = "assertRaisesRegex"
|
||||
_assertRegex = "assertRegex"
|
||||
else:
|
||||
def b(s):
|
||||
return s
|
||||
# Workaround for standalone backslash
|
||||
|
||||
def u(s):
|
||||
return unicode(s, "unicode_escape") # noqa
|
||||
return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
|
||||
unichr = unichr
|
||||
int2byte = chr
|
||||
|
||||
@@ -506,27 +653,38 @@ else:
|
||||
|
||||
def indexbytes(buf, i):
|
||||
return ord(buf[i])
|
||||
|
||||
def iterbytes(buf):
|
||||
return (ord(byte) for byte in buf)
|
||||
iterbytes = functools.partial(itertools.imap, ord)
|
||||
import StringIO
|
||||
StringIO = BytesIO = StringIO.StringIO
|
||||
_assertCountEqual = "assertItemsEqual"
|
||||
_assertRaisesRegex = "assertRaisesRegexp"
|
||||
_assertRegex = "assertRegexpMatches"
|
||||
_add_doc(b, """Byte 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:
|
||||
import builtins
|
||||
exec_ = getattr(builtins, "exec")
|
||||
exec_ = getattr(moves.builtins, "exec")
|
||||
|
||||
def reraise(tp, value, tb=None):
|
||||
if value is None:
|
||||
value = tp()
|
||||
if value.__traceback__ is not tb:
|
||||
raise value.with_traceback(tb)
|
||||
raise value
|
||||
|
||||
print_ = getattr(builtins, "print")
|
||||
del builtins
|
||||
|
||||
else:
|
||||
def exec_(_code_, _globs_=None, _locs_=None):
|
||||
"""Execute code in a namespace."""
|
||||
@@ -544,26 +702,52 @@ else:
|
||||
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):
|
||||
"""The new-style print function."""
|
||||
"""The new-style print function for Python 2.4 and 2.5."""
|
||||
fp = kwargs.pop("file", sys.stdout)
|
||||
if fp is None:
|
||||
return
|
||||
|
||||
def write(data):
|
||||
if not isinstance(data, basestring): # noqa
|
||||
if not isinstance(data, basestring):
|
||||
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)
|
||||
want_unicode = False
|
||||
sep = kwargs.pop("sep", None)
|
||||
if sep is not None:
|
||||
if isinstance(sep, unicode): # noqa
|
||||
if isinstance(sep, unicode):
|
||||
want_unicode = True
|
||||
elif not isinstance(sep, str):
|
||||
raise TypeError("sep must be None or a string")
|
||||
end = kwargs.pop("end", None)
|
||||
if end is not None:
|
||||
if isinstance(end, unicode): # noqa
|
||||
if isinstance(end, unicode):
|
||||
want_unicode = True
|
||||
elif not isinstance(end, str):
|
||||
raise TypeError("end must be None or a string")
|
||||
@@ -571,12 +755,12 @@ else:
|
||||
raise TypeError("invalid keyword arguments to print()")
|
||||
if not want_unicode:
|
||||
for arg in args:
|
||||
if isinstance(arg, unicode): # noqa
|
||||
if isinstance(arg, unicode):
|
||||
want_unicode = True
|
||||
break
|
||||
if want_unicode:
|
||||
newline = unicode("\n") # noqa
|
||||
space = unicode(" ") # noqa
|
||||
newline = unicode("\n")
|
||||
space = unicode(" ")
|
||||
else:
|
||||
newline = "\n"
|
||||
space = " "
|
||||
@@ -589,22 +773,96 @@ else:
|
||||
write(sep)
|
||||
write(arg)
|
||||
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.""")
|
||||
|
||||
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):
|
||||
"""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):
|
||||
"""Class decorator for creating a class with a metaclass."""
|
||||
def wrapper(cls):
|
||||
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('__weakref__', None)
|
||||
for slots_var in orig_vars.get('__slots__', ()):
|
||||
orig_vars.pop(slots_var)
|
||||
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
||||
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