mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-04-22 01:11:58 +03:00
Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4f1e4a03d1 | ||
|
8aaa4eabca | ||
|
7e9e11ee27 | ||
|
0442fd924f | ||
|
58c53025d1 | ||
|
8d8cc38590 | ||
|
429ebfc764 | ||
|
865b36e005 | ||
|
09cf64dda4 | ||
|
0e08fbb20b | ||
|
96248d0f09 | ||
|
bf843fc5f0 | ||
|
68d5d070fe | ||
|
9b2f4c7d77 | ||
|
468951de25 | ||
|
889b1d826e | ||
|
9f4b5b37a3 | ||
|
eb36e75b89 | ||
|
8fd228dd28 | ||
|
1e94018473 | ||
|
cc4cabebf0 | ||
|
3a13599a99 | ||
|
c862554fdc | ||
|
5f320e52f4 | ||
|
0fc1e3a8c7 | ||
|
361522cde8 | ||
|
ad5af45ba6 | ||
|
b8fbe599ac | ||
|
9a1dac6125 | ||
|
244a58e5c7 | ||
|
35086c9ef0 | ||
|
e93357ba17 | ||
|
ec4aa95554 | ||
|
29e96179f2 | ||
|
5d3a5c242e | ||
|
979c4fc1a6 |
2
INSTALL
2
INSTALL
|
@ -93,7 +93,7 @@ You can compile psycopg under Windows platform with mingw32
|
|||
Dev-C++ (http://www.bloodshed.net/devcpp.html) and Code::Blocks
|
||||
(http://www.codeblocks.org). gcc binaries should be in your PATH.
|
||||
|
||||
You need a PostgreSQL with include and libary files installed. At least v8.0
|
||||
You need a PostgreSQL with include and library files installed. At least v8.0
|
||||
is required.
|
||||
|
||||
First you need to create a libpython2X.a as described in
|
||||
|
|
14
MANIFEST.in
14
MANIFEST.in
|
@ -1,16 +1,12 @@
|
|||
recursive-include psycopg *.c *.h *.manifest
|
||||
recursive-include lib *.py
|
||||
recursive-include tests *.py
|
||||
recursive-include ZPsycopgDA *.py *.gif *.dtml
|
||||
recursive-include psycopg2da *
|
||||
recursive-include examples *.py somehackers.jpg whereareyou.jpg
|
||||
recursive-include debian *
|
||||
recursive-include doc README HACKING SUCCESS COPYING* ChangeLog-1.x pep-0249.txt
|
||||
recursive-include doc *.txt *.html *.css *.js Makefile
|
||||
recursive-include doc/src *.rst *.py *.css Makefile
|
||||
recursive-include doc/html *
|
||||
prune doc/src/_build
|
||||
include doc/Makefile doc/README doc/HACKING doc/SUCCESS doc/COPYING* doc/*.txt
|
||||
include doc/src/Makefile doc/src/conf.py doc/src/*.rst doc/src/_static/*
|
||||
recursive-include doc/src/tools *.py
|
||||
include doc/html/*.html doc/html/*.js doc/html/_sources/*.txt doc/html/_static/*
|
||||
recursive-include scripts *.py *.sh
|
||||
include scripts/maketypes.sh scripts/buildtypes.py
|
||||
include AUTHORS README INSTALL LICENSE NEWS ChangeLog
|
||||
include AUTHORS README INSTALL LICENSE NEWS
|
||||
include PKG-INFO MANIFEST.in MANIFEST setup.py setup.cfg Makefile
|
||||
|
|
37
NEWS
37
NEWS
|
@ -1,3 +1,28 @@
|
|||
Current release
|
||||
---------------
|
||||
|
||||
What's new in psycopg 2.5.2
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Fixed segfault pickling the exception raised on connection error
|
||||
(:ticket:`#170`).
|
||||
- Meaningful connection errors report a meaningful message, thanks to
|
||||
Alexey Borzenkov (:ticket:`#173`).
|
||||
- Manually creating `lobject` with the wrong parameter doesn't segfault
|
||||
(:ticket:`#187`).
|
||||
|
||||
|
||||
What's new in psycopg 2.5.1
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Fixed build on Solaris 10 and 11 where the round() function is already
|
||||
declared (:ticket:`#146`).
|
||||
- Fixed comparison of `Range` with non-range objects (:ticket:`#164`).
|
||||
Thanks to Chris Withers for the patch.
|
||||
- Fixed double-free on connection dealloc (:ticket:`#166`). Thanks to
|
||||
Gangadharan S.A. for the report and fix suggestion.
|
||||
|
||||
|
||||
What's new in psycopg 2.5
|
||||
-------------------------
|
||||
|
||||
|
@ -181,7 +206,7 @@ New features and changes:
|
|||
ISO885916, LATIN10, SHIFT_JIS_2004.
|
||||
- Dropped repeated dictionary lookups with unicode query/parameters.
|
||||
|
||||
- Improvements to the named cusors:
|
||||
- Improvements to the named cursors:
|
||||
|
||||
- More efficient iteration on named cursors, fetching 'itersize'
|
||||
records at time from the backend.
|
||||
|
@ -244,7 +269,7 @@ Main new features:
|
|||
- `dict` to `hstore` adapter and `hstore` to `dict` typecaster, using both
|
||||
9.0 and pre-9.0 syntax.
|
||||
- Two-phase commit protocol support as per DBAPI specification.
|
||||
- Support for payload in notifications received from the backed.
|
||||
- Support for payload in notifications received from the backend.
|
||||
- `namedtuple`-returning cursor.
|
||||
- Query execution cancel.
|
||||
|
||||
|
@ -284,7 +309,7 @@ Bux fixes:
|
|||
The old register_tstz_w_secs() function is deprecated and will raise a
|
||||
warning if called.
|
||||
- Exceptions raised by the column iterator are propagated.
|
||||
- Exceptions raised by executemany() interators are propagated.
|
||||
- Exceptions raised by executemany() iterators are propagated.
|
||||
|
||||
|
||||
What's new in psycopg 2.2.1
|
||||
|
@ -401,7 +426,7 @@ New features:
|
|||
|
||||
Bug fixes:
|
||||
|
||||
- Fixed exeception in setup.py.
|
||||
- Fixed exception in setup.py.
|
||||
- More robust detection of PostgreSQL development versions.
|
||||
- Fixed exception in RealDictCursor, introduced in 2.0.10.
|
||||
|
||||
|
@ -783,7 +808,7 @@ What's new in psycopg 1.99.11
|
|||
|
||||
* changed 'tuple_factory' cursor attribute name to 'row_factory'.
|
||||
|
||||
* the .cursor attribute is gone and connections and cursors are propely
|
||||
* the .cursor attribute is gone and connections and cursors are properly
|
||||
gc-managed.
|
||||
|
||||
* fixes to the async core.
|
||||
|
@ -832,7 +857,7 @@ What's new in psycopg 1.99.8
|
|||
* now cursors support .fileno() and .isready() methods, to be used in
|
||||
select() calls.
|
||||
* .copy_from() and .copy_in() methods are back in (still using the old
|
||||
protocol, will be updated to use new one in next releasae.)
|
||||
protocol, will be updated to use new one in next release.)
|
||||
* fixed memory corruption bug reported on win32 platform.
|
||||
|
||||
What's new in psycopg 1.99.7
|
||||
|
|
1744
doc/ChangeLog-1.x
1744
doc/ChangeLog-1.x
File diff suppressed because it is too large
Load Diff
|
@ -23,7 +23,7 @@ Date: 23 Oct 2001 09:53:11 +0600
|
|||
|
||||
We use psycopg and psycopg zope adapter since fisrt public
|
||||
release (it seems version 0.4). Now it works on 3 our sites and in intranet
|
||||
applications. We had few problems, but all problems were quckly
|
||||
applications. We had few problems, but all problems were quickly
|
||||
solved. The strong side of psycopg is that it's code is well organized
|
||||
and easy to understand. When I found a problem with non-ISO datestyle in first
|
||||
version of psycopg, it took for me 15 or 20 minutes to learn code and
|
||||
|
|
|
@ -255,7 +255,7 @@ Cursor Objects
|
|||
display_size, internal_size, precision, scale,
|
||||
null_ok). The first two items (name and type_code) are
|
||||
mandatory, the other five are optional and must be set to
|
||||
None if meaningfull values are not provided.
|
||||
None if meaningful values are not provided.
|
||||
|
||||
This attribute will be None for operations that
|
||||
do not return rows or if the cursor has not had an
|
||||
|
|
|
@ -678,7 +678,7 @@ The ``connection`` class
|
|||
|
||||
Return one of the constants defined in :ref:`poll-constants`. If it
|
||||
returns `~psycopg2.extensions.POLL_OK` then the connection has been
|
||||
estabilished or the query results are available on the client.
|
||||
established or the query results are available on the client.
|
||||
Otherwise wait until the file descriptor returned by `fileno()` is
|
||||
ready to read or to write, as explained in :ref:`async-support`.
|
||||
`poll()` should be also used by the function installed by
|
||||
|
|
|
@ -332,10 +332,6 @@ The ``cursor`` class
|
|||
`~psycopg2.ProgrammingError` is raised and the cursor position is
|
||||
not changed.
|
||||
|
||||
The method can be used both for client-side cursors and
|
||||
:ref:`server-side cursors <server-side-cursors>`. Server-side cursors
|
||||
can usually scroll backwards only if declared `~cursor.scrollable`.
|
||||
|
||||
.. note::
|
||||
|
||||
According to the |DBAPI|_, the exception raised for a cursor out
|
||||
|
@ -347,6 +343,13 @@ The ``cursor`` class
|
|||
except (ProgrammingError, IndexError), exc:
|
||||
deal_with_it(exc)
|
||||
|
||||
The method can be used both for client-side cursors and
|
||||
:ref:`server-side cursors <server-side-cursors>`. Server-side cursors
|
||||
can usually scroll backwards only if declared `~cursor.scrollable`.
|
||||
Moving out-of-bound in a server-side cursor doesn't result in an
|
||||
exception, if the backend doesn't raise any (Postgres doesn't tell us
|
||||
in a reliable way if we went out of bound).
|
||||
|
||||
|
||||
.. attribute:: arraysize
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ functionalities defined by the |DBAPI|_.
|
|||
|
||||
.. class:: cursor(conn, name=None)
|
||||
|
||||
It is the class usually returnded by the `connection.cursor()`
|
||||
It is the class usually returned by the `connection.cursor()`
|
||||
method. It is exposed by the `extensions` module in order to allow
|
||||
subclassing to extend its behaviour: the subclass should be passed to the
|
||||
`!cursor()` method using the `cursor_factory` parameter. See
|
||||
|
@ -352,8 +352,8 @@ details.
|
|||
`register_type()` to be used.
|
||||
|
||||
:param oids: tuple of OIDs of the PostgreSQL type to convert. It should
|
||||
probably be the oid of the array type (e.g. the ``typarray`` field in
|
||||
the ``pg_type`` table.
|
||||
probably contain the oid of the array type (e.g. the ``typarray``
|
||||
field in the ``pg_type`` table).
|
||||
:param name: the name of the new type adapter.
|
||||
:param base_caster: a Psycopg typecaster, e.g. created using the
|
||||
`new_type()` function. The caster should be able to parse a single
|
||||
|
@ -366,11 +366,12 @@ details.
|
|||
.. note::
|
||||
|
||||
The function can be used to create a generic array typecaster,
|
||||
returning a list of strings: just use the `~psycopg2.STRING` as base
|
||||
typecaster. For instance, if you want to receive from the database an
|
||||
array of :sql:`macaddr`, each address represented by string, you can
|
||||
use::
|
||||
returning a list of strings: just use `psycopg2.STRING` as base
|
||||
typecaster. For instance, if you want to receive an array of
|
||||
:sql:`macaddr` from the database, each address represented by string,
|
||||
you can use::
|
||||
|
||||
# select typarray from pg_type where typname = 'macaddr' -> 1040
|
||||
psycopg2.extensions.register_type(
|
||||
psycopg2.extensions.new_array_type(
|
||||
(1040,), 'MACADDR[]', psycopg2.STRING))
|
||||
|
@ -427,7 +428,7 @@ The module exports a few exceptions in addition to the :ref:`standard ones
|
|||
|
||||
(subclasses `~psycopg2.OperationalError`)
|
||||
|
||||
Error causing transaction rollback (deadlocks, serialisation failures,
|
||||
Error causing transaction rollback (deadlocks, serialization failures,
|
||||
etc). It can be trapped specifically to detect a deadlock.
|
||||
|
||||
.. versionadded:: 2.0.7
|
||||
|
@ -515,7 +516,7 @@ set to one of the following constants:
|
|||
:sql:`SERIALIZABLE` isolation level. This is the strictest transactions
|
||||
isolation level, equivalent to having the transactions executed serially
|
||||
rather than concurrently. However applications using this level must be
|
||||
prepared to retry reansactions due to serialization failures.
|
||||
prepared to retry transactions due to serialization failures.
|
||||
|
||||
Starting from PostgreSQL 9.1, this mode monitors for conditions which
|
||||
could make execution of a concurrent set of serializable transactions
|
||||
|
|
|
@ -41,7 +41,7 @@ If you want to use a `!connection` subclass you can pass it as the
|
|||
Dictionary-like cursor
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The dict cursors allow to access to the retrieved records using an iterface
|
||||
The dict cursors allow to access to the retrieved records using an interface
|
||||
similar to the Python dictionaries instead of the tuples.
|
||||
|
||||
>>> dict_cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
|
||||
|
@ -453,6 +453,17 @@ automatically casted into instances of these classes.
|
|||
.. autoclass:: DateTimeRange
|
||||
.. autoclass:: DateTimeTZRange
|
||||
|
||||
.. note::
|
||||
|
||||
Python lacks a representation for :sql:`infinity` date so Psycopg converts
|
||||
the value to `date.max` and such. When written into the database these
|
||||
dates will assume their literal value (e.g. :sql:`9999-12-31` instead of
|
||||
:sql:`infinity`). Check :ref:`infinite-dates-handling` for an example of
|
||||
an alternative adapter to map `date.max` to :sql:`infinity`. An
|
||||
alternative dates adapter will be used automatically by the `DateRange`
|
||||
adapter and so on.
|
||||
|
||||
|
||||
Custom |range| types (created with |CREATE TYPE|_ :sql:`... AS RANGE`) can be
|
||||
adapted to a custom `Range` subclass:
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ Psycopg converts :sql:`decimal`\/\ :sql:`numeric` database types into Python `!D
|
|||
psycopg2.extensions.register_type(DEC2FLOAT)
|
||||
|
||||
See :ref:`type-casting-from-sql-to-python` to read the relevant
|
||||
documentation. If you find `!psycopg2.extensions.DECIMAL` not avalable, use
|
||||
documentation. If you find `!psycopg2.extensions.DECIMAL` not available, use
|
||||
`!psycopg2._psycopg.DECIMAL` instead.
|
||||
|
||||
|
||||
|
|
|
@ -15,16 +15,10 @@ Psycopg 2 is mostly implemented in C as a libpq_ wrapper, resulting in being
|
|||
both efficient and secure. It features client-side and :ref:`server-side
|
||||
<server-side-cursors>` cursors, :ref:`asynchronous communication
|
||||
<async-support>` and :ref:`notifications <async-notify>`, |COPY-TO-FROM|__
|
||||
support, and a flexible :ref:`objects adaptation system
|
||||
<python-types-adaptation>`. Many basic Python types are supported
|
||||
out-of-the-box and mapped to matching PostgreSQL data types, such as strings
|
||||
(both byte strings and Unicode), numbers (ints, longs, floats, decimals),
|
||||
booleans and date/time objects (both built-in and `mx.DateTime`_), several
|
||||
types of :ref:`binary objects <adapt-binary>`. Also available are mappings
|
||||
between lists and PostgreSQL arrays of any supported type, between
|
||||
:ref:`dictionaries and PostgreSQL hstore <adapt-hstore>`, between
|
||||
:ref:`tuples/namedtuples and PostgreSQL composite types <adapt-composite>`,
|
||||
and between Python objects and :ref:`JSON <adapt-json>`.
|
||||
support. Many Python types are supported out-of-the-box and :ref:`adapted to
|
||||
matching PostgreSQL data types <python-types-adaptation>`; adaptation can be
|
||||
extended and customized thanks to a flexible :ref:`objects adaptation system
|
||||
<adapting-new-types>`.
|
||||
|
||||
Psycopg 2 is both Unicode and Python 3 friendly.
|
||||
|
||||
|
|
|
@ -100,7 +100,8 @@ many placeholders can use the same values::
|
|||
... {'int': 10, 'str': "O'Reilly", 'date': datetime.date(2005, 11, 18)})
|
||||
|
||||
When parameters are used, in order to include a literal ``%`` in the query you
|
||||
can use the ``%%`` string.
|
||||
can use the ``%%`` string. Using characters ``%``, ``(``, ``)`` in the
|
||||
argument names is not supported.
|
||||
|
||||
While the mechanism resembles regular Python strings manipulation, there are a
|
||||
few subtle differences you should care about when passing parameters to a
|
||||
|
@ -298,8 +299,8 @@ proper SQL literals::
|
|||
Numbers adaptation
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Numeric objects: `int`, `long`, `float`, `~decimal.Decimal` are converted in
|
||||
the PostgreSQL numerical representation::
|
||||
Python numeric objects `int`, `long`, `float`, `~decimal.Decimal` are
|
||||
converted into a PostgreSQL numerical representation::
|
||||
|
||||
>>> cur.mogrify("SELECT %s, %s, %s, %s;", (10, 10L, 10.0, Decimal("10.00")))
|
||||
'SELECT 10, 10, 10.0, 10.00;'
|
||||
|
@ -311,7 +312,7 @@ converted into `!Decimal`.
|
|||
.. note::
|
||||
|
||||
Sometimes you may prefer to receive :sql:`numeric` data as `!float`
|
||||
insted, for performance reason or ease of manipulation: you can configure
|
||||
instead, for performance reason or ease of manipulation: you can configure
|
||||
an adapter to :ref:`cast PostgreSQL numeric to Python float <faq-float>`.
|
||||
This of course may imply a loss of precision.
|
||||
|
||||
|
@ -422,7 +423,7 @@ the connection or globally: see the function
|
|||
Binary adaptation
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Binary types: Python types representing binary objects are converted into
|
||||
Python types representing binary objects are converted into
|
||||
PostgreSQL binary string syntax, suitable for :sql:`bytea` fields. Such
|
||||
types are `buffer` (only available in Python 2), `memoryview` (available
|
||||
from Python 2.7), `bytearray` (available from Python 2.6) and `bytes`
|
||||
|
@ -477,7 +478,7 @@ or `!memoryview` (in Python 3).
|
|||
Date/Time objects adaptation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Date and time objects: builtin `~datetime.datetime`, `~datetime.date`,
|
||||
Python builtin `~datetime.datetime`, `~datetime.date`,
|
||||
`~datetime.time`, `~datetime.timedelta` are converted into PostgreSQL's
|
||||
:sql:`timestamp[tz]`, :sql:`date`, :sql:`time`, :sql:`interval` data types.
|
||||
Time zones are supported too. The Egenix `mx.DateTime`_ objects are adapted
|
||||
|
@ -496,6 +497,7 @@ the same way::
|
|||
.. seealso:: `PostgreSQL date/time types
|
||||
<http://www.postgresql.org/docs/current/static/datatype-datetime.html>`__
|
||||
|
||||
|
||||
.. index::
|
||||
single: Time Zones
|
||||
|
||||
|
@ -530,6 +532,40 @@ rounded to the nearest minute, with an error of up to 30 seconds.
|
|||
versions use `psycopg2.extras.register_tstz_w_secs()`.
|
||||
|
||||
|
||||
.. index::
|
||||
double: Date objects; Infinite
|
||||
|
||||
.. _infinite-dates-handling:
|
||||
|
||||
Infinite dates handling
|
||||
'''''''''''''''''''''''
|
||||
|
||||
PostgreSQL can store the representation of an "infinite" date, timestamp, or
|
||||
interval. Infinite dates are not available to Python, so these objects are
|
||||
mapped to `!date.max`, `!datetime.max`, `!interval.max`. Unfortunately the
|
||||
mapping cannot be bidirectional so these dates will be stored back into the
|
||||
database with their values, such as :sql:`9999-12-31`.
|
||||
|
||||
It is possible to create an alternative adapter for dates and other objects
|
||||
to map `date.max` to :sql:`infinity`, for instance::
|
||||
|
||||
class InfDateAdapter:
|
||||
def __init__(self, wrapped):
|
||||
self.wrapped = wrapped
|
||||
def getquoted(self):
|
||||
if self.wrapped == datetime.date.max:
|
||||
return b"'infinity'::date"
|
||||
elif self.wrapped == datetime.date.min:
|
||||
return b"'-infinity'::date"
|
||||
else:
|
||||
return psycopg2.extensions.DateFromPy(self.wrapped).getquoted()
|
||||
|
||||
psycopg2.extensions.register_adapter(datetime.date, InfDateAdapter)
|
||||
|
||||
Of course it will not be possible to write the value of `date.max` in the
|
||||
database anymore: :sql:`infinity` will be stored instead.
|
||||
|
||||
|
||||
.. _adapt-list:
|
||||
|
||||
Lists adaptation
|
||||
|
@ -560,7 +596,7 @@ Python lists are converted into PostgreSQL :sql:`ARRAY`\ s::
|
|||
.. note::
|
||||
|
||||
Reading back from PostgreSQL, arrays are converted to lists of Python
|
||||
objects as expected, but only if the items are of a known known type.
|
||||
objects as expected, but only if the items are of a known type.
|
||||
Arrays of unknown types are returned as represented by the database (e.g.
|
||||
``{a,b,c}``). If you want to convert the items into Python objects you can
|
||||
easily create a typecaster for :ref:`array of unknown types
|
||||
|
@ -576,7 +612,7 @@ Tuples adaptation
|
|||
double: Tuple; Adaptation
|
||||
single: IN operator
|
||||
|
||||
Python tuples are converted in a syntax suitable for the SQL :sql:`IN`
|
||||
Python tuples are converted into a syntax suitable for the SQL :sql:`IN`
|
||||
operator and to represent a composite type::
|
||||
|
||||
>>> cur.mogrify("SELECT %s IN %s;", (10, (10, 20, 30)))
|
||||
|
|
|
@ -79,7 +79,7 @@ for row in curs.fetchall():
|
|||
print "done"
|
||||
print " python type of image data is", type(row[0])
|
||||
|
||||
# this rollback is required because we can't drop a table with a binary cusor
|
||||
# this rollback is required because we can't drop a table with a binary cursor
|
||||
# declared and still open
|
||||
conn.rollback()
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# encoding.py - show to change client enkoding (and test it works)
|
||||
# encoding.py - show to change client encoding (and test it works)
|
||||
# -*- encoding: utf8 -*-
|
||||
#
|
||||
# Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org>
|
||||
|
|
|
@ -121,6 +121,8 @@ class Range(object):
|
|||
return self._bounds is not None
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Range):
|
||||
return False
|
||||
return (self._lower == other._lower
|
||||
and self._upper == other._upper
|
||||
and self._bounds == other._bounds)
|
||||
|
@ -415,7 +417,7 @@ class NumberRangeAdapter(RangeAdapter):
|
|||
def getquoted(self):
|
||||
r = self.adapted
|
||||
if r.isempty:
|
||||
return "'empty'"
|
||||
return b("'empty'")
|
||||
|
||||
if not r.lower_inf:
|
||||
# not exactly: we are relying that none of these object is really
|
||||
|
@ -431,8 +433,8 @@ class NumberRangeAdapter(RangeAdapter):
|
|||
else:
|
||||
upper = ''
|
||||
|
||||
return b("'%s%s,%s%s'" % (
|
||||
r._bounds[0], lower, upper, r._bounds[1]))
|
||||
return ("'%s%s,%s%s'" % (
|
||||
r._bounds[0], lower, upper, r._bounds[1])).encode('ascii')
|
||||
|
||||
# TODO: probably won't work with infs, nans and other tricky cases.
|
||||
register_adapter(NumericRange, NumberRangeAdapter)
|
||||
|
|
|
@ -82,7 +82,7 @@ STATUS_SYNC = 3 # currently unused
|
|||
STATUS_ASYNC = 4 # currently unused
|
||||
STATUS_PREPARED = 5
|
||||
|
||||
# This is a usefull mnemonic to check if the connection is in a transaction
|
||||
# This is a useful mnemonic to check if the connection is in a transaction
|
||||
STATUS_IN_TRANSACTION = STATUS_BEGIN
|
||||
|
||||
"""psycopg asynchronous connection polling values"""
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Miscellaneous goodies for psycopg2
|
||||
|
||||
This module is a generic place used to hold little helper functions
|
||||
and classes untill a better place in the distribution is found.
|
||||
and classes until a better place in the distribution is found.
|
||||
"""
|
||||
# psycopg/extras.py - miscellaneous extra goodies for psycopg
|
||||
#
|
||||
|
@ -131,7 +131,7 @@ class DictCursor(DictCursorBase):
|
|||
self._query_executed = 0
|
||||
|
||||
class DictRow(list):
|
||||
"""A row object that allow by-colmun-name access to data."""
|
||||
"""A row object that allow by-column-name access to data."""
|
||||
|
||||
__slots__ = ('_index',)
|
||||
|
||||
|
@ -406,7 +406,7 @@ class MinTimeLoggingConnection(LoggingConnection):
|
|||
|
||||
This is just an example of how to sub-class `LoggingConnection` to
|
||||
provide some extra filtering for the logged queries. Both the
|
||||
`inizialize()` and `filter()` methods are overwritten to make sure
|
||||
`initialize()` and `filter()` methods are overwritten to make sure
|
||||
that only queries executing for more than ``mintime`` ms are logged.
|
||||
|
||||
Note that this connection uses the specialized cursor
|
||||
|
@ -449,13 +449,15 @@ class UUID_adapter(object):
|
|||
def __init__(self, uuid):
|
||||
self._uuid = uuid
|
||||
|
||||
def prepare(self, conn):
|
||||
pass
|
||||
def __conform__(self, proto):
|
||||
if proto is _ext.ISQLQuote:
|
||||
return self
|
||||
|
||||
def getquoted(self):
|
||||
return "'"+str(self._uuid)+"'::uuid"
|
||||
return b("'%s'::uuid" % self._uuid)
|
||||
|
||||
__str__ = getquoted
|
||||
def __str__(self):
|
||||
return "'%s'::uuid" % self._uuid
|
||||
|
||||
def register_uuid(oids=None, conn_or_curs=None):
|
||||
"""Create the UUID type and an uuid.UUID adapter.
|
||||
|
@ -514,8 +516,8 @@ class Inet(object):
|
|||
obj.prepare(self._conn)
|
||||
return obj.getquoted() + b("::inet")
|
||||
|
||||
def __conform__(self, foo):
|
||||
if foo is _ext.ISQLQuote:
|
||||
def __conform__(self, proto):
|
||||
if proto is _ext.ISQLQuote:
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -45,7 +45,7 @@ typedef struct {
|
|||
HIDDEN PyObject *psyco_Binary(PyObject *module, PyObject *args);
|
||||
#define psyco_Binary_doc \
|
||||
"Binary(buffer) -> new binary object\n\n" \
|
||||
"Build an object capable to hold a bynary string value."
|
||||
"Build an object capable to hold a binary string value."
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -141,7 +141,10 @@ static int pthread_mutex_init(pthread_mutex_t *mutex, void* fake)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined(__FreeBSD__) && __FreeBSD_version < 503000) || (defined(_WIN32) && !defined(__GNUC__)) || defined(__sun__) || defined(sun)
|
||||
#if (defined(__FreeBSD__) && __FreeBSD_version < 503000) \
|
||||
|| (defined(_WIN32) && !defined(__GNUC__)) \
|
||||
|| (defined(sun) || defined(__sun__)) \
|
||||
&& (defined(__SunOS_5_8) || defined(__SunOS_5_9))
|
||||
/* what's this, we have no round function either? */
|
||||
static double round(double num)
|
||||
{
|
||||
|
|
|
@ -226,7 +226,7 @@ conn_get_standard_conforming_strings(PGconn *pgconn)
|
|||
* The presence of the 'standard_conforming_strings' parameter
|
||||
* means that the server _accepts_ the E'' quote.
|
||||
*
|
||||
* If the paramer is off, the PQescapeByteaConn returns
|
||||
* If the parameter is off, the PQescapeByteaConn returns
|
||||
* backslash escaped strings (e.g. '\001' -> "\\001"),
|
||||
* so the E'' quotes are required to avoid warnings
|
||||
* if 'escape_string_warning' is set.
|
||||
|
@ -642,6 +642,7 @@ static int
|
|||
_conn_poll_connecting(connectionObject *self)
|
||||
{
|
||||
int res = PSYCO_POLL_ERROR;
|
||||
const char *msg;
|
||||
|
||||
Dprintf("conn_poll: poll connecting");
|
||||
switch (PQconnectPoll(self->pgconn)) {
|
||||
|
@ -656,7 +657,11 @@ _conn_poll_connecting(connectionObject *self)
|
|||
break;
|
||||
case PGRES_POLLING_FAILED:
|
||||
case PGRES_POLLING_ACTIVE:
|
||||
PyErr_SetString(OperationalError, "asynchronous connection failed");
|
||||
msg = PQerrorMessage(self->pgconn);
|
||||
if (!(msg && *msg)) {
|
||||
msg = "asynchronous connection failed";
|
||||
}
|
||||
PyErr_SetString(OperationalError, msg);
|
||||
res = PSYCO_POLL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
@ -1177,7 +1182,7 @@ conn_set_client_encoding(connectionObject *self, const char *enc)
|
|||
goto endlock;
|
||||
}
|
||||
|
||||
/* no error, we can proceeed and store the new encoding */
|
||||
/* no error, we can proceed and store the new encoding */
|
||||
{
|
||||
char *tmp = self->encoding;
|
||||
self->encoding = clean_enc;
|
||||
|
|
|
@ -1128,10 +1128,13 @@ connection_dealloc(PyObject* obj)
|
|||
{
|
||||
connectionObject *self = (connectionObject *)obj;
|
||||
|
||||
conn_close(self);
|
||||
|
||||
/* Make sure to untrack the connection before calling conn_close, which may
|
||||
* allow a different thread to try and dealloc the connection again,
|
||||
* resulting in a double-free segfault (ticket #166). */
|
||||
PyObject_GC_UnTrack(self);
|
||||
|
||||
conn_close(self);
|
||||
|
||||
if (self->weakreflist) {
|
||||
PyObject_ClearWeakRefs(obj);
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new)
|
|||
/* if we find '%(' then this is a dictionary, we:
|
||||
1/ find the matching ')' and extract the key name
|
||||
2/ locate the value in the dictionary (or return an error)
|
||||
3/ mogrify the value into something usefull (quoting)...
|
||||
3/ mogrify the value into something useful (quoting)...
|
||||
4/ ...and add it to the new dictionary to be used as argument
|
||||
*/
|
||||
case '(':
|
||||
|
@ -314,7 +314,7 @@ _psyco_curs_merge_query_args(cursorObject *self,
|
|||
"not all arguments converted"
|
||||
|
||||
and return the appropriate ProgrammingError. we do that by grabbing
|
||||
the curren exception (we will later restore it if the type or the
|
||||
the current exception (we will later restore it if the type or the
|
||||
strings do not match.) */
|
||||
|
||||
if (!(fquery = Bytes_Format(query, args))) {
|
||||
|
@ -1822,7 +1822,7 @@ cursor_setup(cursorObject *self, connectionObject *conn, const char *name)
|
|||
}
|
||||
}
|
||||
|
||||
/* FIXME: why does this raise an excpetion on the _next_ line of code?
|
||||
/* FIXME: why does this raise an exception on the _next_ line of code?
|
||||
if (PyObject_IsInstance((PyObject*)conn,
|
||||
(PyObject *)&connectionType) == 0) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
|
|
|
@ -163,8 +163,16 @@ psyco_error_reduce(errorObject *self)
|
|||
if (2 != PyTuple_GET_SIZE(tuple)) { goto exit; }
|
||||
|
||||
if (!(dict = PyDict_New())) { goto error; }
|
||||
if (0 != PyDict_SetItemString(dict, "pgerror", self->pgerror)) { goto error; }
|
||||
if (0 != PyDict_SetItemString(dict, "pgcode", self->pgcode)) { goto error; }
|
||||
if (self->pgerror) {
|
||||
if (0 != PyDict_SetItemString(dict, "pgerror", self->pgerror)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (self->pgcode) {
|
||||
if (0 != PyDict_SetItemString(dict, "pgcode", self->pgcode)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
PyObject *newtuple;
|
||||
|
|
|
@ -355,9 +355,11 @@ lobject_dealloc(PyObject* obj)
|
|||
{
|
||||
lobjectObject *self = (lobjectObject *)obj;
|
||||
|
||||
if (lobject_close(self) < 0)
|
||||
PyErr_Print();
|
||||
Py_XDECREF((PyObject*)self->conn);
|
||||
if (self->conn) { /* if not, init failed */
|
||||
if (lobject_close(self) < 0)
|
||||
PyErr_Print();
|
||||
Py_XDECREF((PyObject*)self->conn);
|
||||
}
|
||||
PyMem_Free(self->smode);
|
||||
|
||||
Dprintf("lobject_dealloc: deleted lobject object at %p, refcnt = "
|
||||
|
@ -372,10 +374,11 @@ lobject_init(PyObject *obj, PyObject *args, PyObject *kwds)
|
|||
int oid = (int)InvalidOid, new_oid = (int)InvalidOid;
|
||||
const char *smode = "";
|
||||
const char *new_file = NULL;
|
||||
PyObject *conn;
|
||||
PyObject *conn = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O|iziz",
|
||||
&conn, &oid, &smode, &new_oid, &new_file))
|
||||
if (!PyArg_ParseTuple(args, "O!|iziz",
|
||||
&connectionType, &conn,
|
||||
&oid, &smode, &new_oid, &new_file))
|
||||
return -1;
|
||||
|
||||
return lobject_setup((lobjectObject *)obj,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* microporotocols_proto.h - definiton for psycopg's protocols
|
||||
/* microporotocols_proto.h - definition for psycopg's protocols
|
||||
*
|
||||
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org>
|
||||
*
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
/* IMPORTANT NOTE: no function in this file do its own connection locking
|
||||
except for pg_execute and pq_fetch (that are somehow high-level). This means
|
||||
that all the othe functions should be called while holding a lock to the
|
||||
that all the other functions should be called while holding a lock to the
|
||||
connection.
|
||||
*/
|
||||
|
||||
|
@ -153,7 +153,7 @@ exception_from_sqlstate(const char *sqlstate)
|
|||
This function should be called while holding the GIL.
|
||||
|
||||
The function passes the ownership of the pgres to the returned exception,
|
||||
wherer the pgres was the explicit argument or taken from the cursor.
|
||||
where the pgres was the explicit argument or taken from the cursor.
|
||||
So, after calling it curs->pgres will be set to null */
|
||||
|
||||
RAISES static void
|
||||
|
@ -781,7 +781,7 @@ exit:
|
|||
means that there is data available to be collected. -1 means an error, the
|
||||
exception will be set accordingly.
|
||||
|
||||
this fucntion locks the connection object
|
||||
this function locks the connection object
|
||||
this function call Py_*_ALLOW_THREADS macros */
|
||||
|
||||
int
|
||||
|
@ -974,7 +974,7 @@ pq_execute(cursorObject *curs, const char *query, int async, int no_result)
|
|||
/* if the execute was sync, we call pq_fetch() immediately,
|
||||
to respect the old DBAPI-2.0 compatible behaviour */
|
||||
if (async == 0) {
|
||||
Dprintf("pq_execute: entering syncronous DBAPI compatibility mode");
|
||||
Dprintf("pq_execute: entering synchronous DBAPI compatibility mode");
|
||||
if (pq_fetch(curs, no_result) < 0) return -1;
|
||||
}
|
||||
else {
|
||||
|
@ -1041,7 +1041,7 @@ pq_get_last_result(connectionObject *conn)
|
|||
|
||||
/* pq_fetch - fetch data after a query
|
||||
|
||||
this fucntion locks the connection object
|
||||
this function locks the connection object
|
||||
this function call Py_*_ALLOW_THREADS macros
|
||||
|
||||
return value:
|
||||
|
@ -1335,7 +1335,7 @@ _pq_copy_in_v3(cursorObject *curs)
|
|||
else if (error == 2)
|
||||
res = PQputCopyEnd(curs->conn->pgconn, "error in PQputCopyData() call");
|
||||
else
|
||||
/* XXX would be nice to propagate the exeption */
|
||||
/* XXX would be nice to propagate the exception */
|
||||
res = PQputCopyEnd(curs->conn->pgconn, "error in .read() call");
|
||||
|
||||
CLEARPGRES(curs->pgres);
|
||||
|
@ -1343,7 +1343,7 @@ _pq_copy_in_v3(cursorObject *curs)
|
|||
Dprintf("_pq_copy_in_v3: copy ended; res = %d", res);
|
||||
|
||||
/* if the result is -1 we should not even try to get a result from the
|
||||
bacause that will lock the current thread forever */
|
||||
because that will lock the current thread forever */
|
||||
if (res == -1) {
|
||||
pq_raise(curs->conn, curs, NULL);
|
||||
/* FIXME: pq_raise check the connection but for some reason even
|
||||
|
|
|
@ -59,7 +59,7 @@ extern "C" {
|
|||
HIDDEN psyco_errors_fill_RETURN psyco_errors_fill psyco_errors_fill_PROTO;
|
||||
HIDDEN psyco_errors_set_RETURN psyco_errors_set psyco_errors_set_PROTO;
|
||||
|
||||
/* global excpetions */
|
||||
/* global exceptions */
|
||||
extern HIDDEN PyObject *Error, *Warning, *InterfaceError, *DatabaseError,
|
||||
*InternalError, *OperationalError, *ProgrammingError,
|
||||
*IntegrityError, *DataError, *NotSupportedError;
|
||||
|
@ -169,7 +169,7 @@ STEALS(1) HIDDEN PyObject * psycopg_ensure_text(PyObject *obj);
|
|||
"Error related to SQL query cancellation."
|
||||
|
||||
#define TransactionRollbackError_doc \
|
||||
"Error causing transaction rollback (deadlocks, serialisation failures, etc)."
|
||||
"Error causing transaction rollback (deadlocks, serialization failures, etc)."
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -437,7 +437,7 @@ static struct {
|
|||
static int
|
||||
psyco_errors_init(void)
|
||||
{
|
||||
/* the names of the exceptions here reflect the oranization of the
|
||||
/* the names of the exceptions here reflect the organization of the
|
||||
psycopg2 module and not the fact the the original error objects
|
||||
live in _psycopg */
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ chunk_getreadbuffer(chunkObject *self, Py_ssize_t segment, void **ptr)
|
|||
if (segment != 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"acessing non-existant buffer segment");
|
||||
"accessing non-existant buffer segment");
|
||||
return -1;
|
||||
}
|
||||
*ptr = self->base;
|
||||
|
@ -160,7 +160,7 @@ typecast_BINARY_cast(const char *s, Py_ssize_t l, PyObject *curs)
|
|||
}
|
||||
else {
|
||||
/* This is a buffer in the classic bytea format. So we can handle it
|
||||
* to the PQunescapeBytea to have it parsed, rignt? ...Wrong. We
|
||||
* to the PQunescapeBytea to have it parsed, right? ...Wrong. We
|
||||
* could, but then we'd have to record whether buffer was allocated by
|
||||
* Python or by the libpq to dispose it properly. Furthermore the
|
||||
* PQunescapeBytea interface is not the most brilliant as it wants a
|
||||
|
|
|
@ -74,7 +74,7 @@ typecastObject_initlist typecast_builtins[] = {
|
|||
FOOTER = """ {NULL, NULL, NULL, NULL}\n};\n"""
|
||||
|
||||
|
||||
# usefull error reporting function
|
||||
# useful error reporting function
|
||||
def error(msg):
|
||||
"""Report an error on stderr."""
|
||||
sys.stderr.write(msg+'\n')
|
||||
|
|
|
@ -28,5 +28,5 @@ have_ssl=0
|
|||
# Statically link against the postgresql client library.
|
||||
#static_libpq=1
|
||||
|
||||
# Add here eventual extra libreries required to link the module.
|
||||
# Add here eventual extra libraries required to link the module.
|
||||
#libraries=
|
||||
|
|
15
setup.py
15
setup.py
|
@ -21,7 +21,7 @@ and stable as a rock.
|
|||
psycopg2 is different from the other database adapter because it was
|
||||
designed for heavily multi-threaded applications that create and destroy
|
||||
lots of cursors and make a conspicuous number of concurrent INSERTs or
|
||||
UPDATEs. psycopg2 also provide full asycronous operations and support
|
||||
UPDATEs. psycopg2 also provide full asynchronous operations and support
|
||||
for coroutine libraries.
|
||||
"""
|
||||
|
||||
|
@ -31,7 +31,13 @@ Intended Audience :: Developers
|
|||
License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
|
||||
License :: OSI Approved :: Zope Public License
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2.5
|
||||
Programming Language :: Python :: 2.6
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.1
|
||||
Programming Language :: Python :: 3.2
|
||||
Programming Language :: Python :: 3.3
|
||||
Programming Language :: C
|
||||
Programming Language :: SQL
|
||||
Topic :: Database
|
||||
|
@ -76,8 +82,7 @@ except ImportError:
|
|||
|
||||
# Take a look at http://www.python.org/dev/peps/pep-0386/
|
||||
# for a consistent versioning pattern.
|
||||
|
||||
PSYCOPG_VERSION = '2.5'
|
||||
PSYCOPG_VERSION = '2.5.2'
|
||||
|
||||
version_flags = ['dt', 'dec']
|
||||
|
||||
|
@ -210,7 +215,7 @@ or with the pg_config option in 'setup.cfg'.
|
|||
class psycopg_build_ext(build_ext):
|
||||
"""Conditionally complement the setup.cfg options file.
|
||||
|
||||
This class configures the include_dirs, libray_dirs, libraries
|
||||
This class configures the include_dirs, library_dirs, libraries
|
||||
options as required by the system. Most of the configuration happens
|
||||
in finalize_options() method.
|
||||
|
||||
|
@ -362,7 +367,7 @@ class psycopg_build_ext(build_ext):
|
|||
finalize_linux3 = finalize_linux
|
||||
|
||||
def finalize_options(self):
|
||||
"""Complete the build system configuation."""
|
||||
"""Complete the build system configuration."""
|
||||
build_ext.finalize_options(self)
|
||||
|
||||
pg_config_helper = PostgresConfig(self)
|
||||
|
|
|
@ -60,7 +60,7 @@ import sys
|
|||
# - Now a subclass of TestCase, to avoid requiring the driver stub
|
||||
# to use multiple inheritance
|
||||
# - Reversed the polarity of buggy test in test_description
|
||||
# - Test exception heirarchy correctly
|
||||
# - Test exception hierarchy correctly
|
||||
# - self.populate is now self._populate(), so if a driver stub
|
||||
# overrides self.ddl1 this change propogates
|
||||
# - VARCHAR columns now have a width, which will hopefully make the
|
||||
|
@ -188,7 +188,7 @@ class DatabaseAPI20Test(unittest.TestCase):
|
|||
|
||||
def test_Exceptions(self):
|
||||
# Make sure required exceptions exist, and are in the
|
||||
# defined heirarchy.
|
||||
# defined hierarchy.
|
||||
if sys.version[0] == '3': #under Python 3 StardardError no longer exists
|
||||
self.failUnless(issubclass(self.driver.Warning,Exception))
|
||||
self.failUnless(issubclass(self.driver.Error,Exception))
|
||||
|
@ -504,7 +504,7 @@ class DatabaseAPI20Test(unittest.TestCase):
|
|||
self.assertRaises(self.driver.Error,cur.fetchone)
|
||||
|
||||
# cursor.fetchone should raise an Error if called after
|
||||
# executing a query that cannnot return rows
|
||||
# executing a query that cannot return rows
|
||||
self.executeDDL1(cur)
|
||||
self.assertRaises(self.driver.Error,cur.fetchone)
|
||||
|
||||
|
@ -516,7 +516,7 @@ class DatabaseAPI20Test(unittest.TestCase):
|
|||
self.failUnless(cur.rowcount in (-1,0))
|
||||
|
||||
# cursor.fetchone should raise an Error if called after
|
||||
# executing a query that cannnot return rows
|
||||
# executing a query that cannot return rows
|
||||
cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
|
||||
self.table_prefix
|
||||
))
|
||||
|
|
|
@ -449,6 +449,16 @@ class AsyncTests(ConnectingTestCase):
|
|||
self.wait(self.conn)
|
||||
self.assertEqual(cur.fetchone(), (42,))
|
||||
|
||||
def test_async_connection_error_message(self):
|
||||
try:
|
||||
cnn = psycopg2.connect('dbname=thisdatabasedoesntexist', async=True)
|
||||
self.wait(cnn)
|
||||
except psycopg2.Error, e:
|
||||
self.assertNotEqual(str(e), "asynchronous connection failed",
|
||||
"connection error reason lost")
|
||||
else:
|
||||
self.fail("no exception raised")
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
|
|
@ -199,6 +199,20 @@ class CopyTests(ConnectingTestCase):
|
|||
f.seek(0)
|
||||
self.assertEqual(f.readline().rstrip(), about)
|
||||
|
||||
# same tests with setting size
|
||||
f = io.StringIO()
|
||||
f.write(about)
|
||||
f.seek(0)
|
||||
exp_size = 123
|
||||
# hack here to leave file as is, only check size when reading
|
||||
real_read = f.read
|
||||
def read(_size, f=f, exp_size=exp_size):
|
||||
self.assertEqual(_size, exp_size)
|
||||
return real_read(_size)
|
||||
f.read = read
|
||||
curs.copy_expert('COPY tcopy (data) FROM STDIN', f, size=exp_size)
|
||||
curs.execute("select data from tcopy;")
|
||||
self.assertEqual(curs.fetchone()[0], abin)
|
||||
|
||||
def _copy_from(self, curs, nrecs, srec, copykw):
|
||||
f = StringIO()
|
||||
|
|
|
@ -27,7 +27,7 @@ import psycopg2
|
|||
import psycopg2.extensions
|
||||
from psycopg2.extensions import b
|
||||
from testutils import unittest, ConnectingTestCase, skip_before_postgres
|
||||
from testutils import skip_if_no_namedtuple
|
||||
from testutils import skip_if_no_namedtuple, skip_if_no_getrefcount
|
||||
|
||||
class CursorTests(ConnectingTestCase):
|
||||
|
||||
|
@ -97,6 +97,7 @@ class CursorTests(ConnectingTestCase):
|
|||
self.assertEqual(b('SELECT 10.3;'),
|
||||
cur.mogrify("SELECT %s;", (Decimal("10.3"),)))
|
||||
|
||||
@skip_if_no_getrefcount
|
||||
def test_mogrify_leak_on_multiple_reference(self):
|
||||
# issue #81: reference leak when a parameter value is referenced
|
||||
# more than once from a dict.
|
||||
|
@ -157,6 +158,7 @@ class CursorTests(ConnectingTestCase):
|
|||
curs = self.conn.cursor()
|
||||
w = ref(curs)
|
||||
del curs
|
||||
import gc; gc.collect()
|
||||
self.assert_(w() is None)
|
||||
|
||||
def test_null_name(self):
|
||||
|
@ -400,7 +402,7 @@ class CursorTests(ConnectingTestCase):
|
|||
|
||||
@skip_before_postgres(8, 0)
|
||||
def test_scroll_named(self):
|
||||
cur = self.conn.cursor()
|
||||
cur = self.conn.cursor('tmp', scrollable=True)
|
||||
cur.execute("select generate_series(0,9)")
|
||||
cur.scroll(2)
|
||||
self.assertEqual(cur.fetchone(), (2,))
|
||||
|
@ -410,8 +412,6 @@ class CursorTests(ConnectingTestCase):
|
|||
self.assertEqual(cur.fetchone(), (8,))
|
||||
cur.scroll(9, mode='absolute')
|
||||
self.assertEqual(cur.fetchone(), (9,))
|
||||
self.assertRaises((IndexError, psycopg2.ProgrammingError),
|
||||
cur.scroll, 10, mode='absolute')
|
||||
|
||||
|
||||
def test_suite():
|
||||
|
|
|
@ -213,6 +213,14 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
|
|||
self.assertEqual(value.seconds, 41103)
|
||||
self.assertEqual(value.microseconds, 876544)
|
||||
|
||||
def test_parse_infinity(self):
|
||||
value = self.DATETIME('-infinity', self.curs)
|
||||
self.assertEqual(str(value), '0001-01-01 00:00:00')
|
||||
value = self.DATETIME('infinity', self.curs)
|
||||
self.assertEqual(str(value), '9999-12-31 23:59:59.999999')
|
||||
value = self.DATE('infinity', self.curs)
|
||||
self.assertEqual(str(value), '9999-12-31')
|
||||
|
||||
def test_adapt_date(self):
|
||||
from datetime import date
|
||||
value = self.execute('select (%s)::date::text',
|
||||
|
@ -240,7 +248,7 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
|
|||
self.assertEqual(seconds, 3674096)
|
||||
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
||||
|
||||
def test_adapt_megative_timedelta(self):
|
||||
def test_adapt_negative_timedelta(self):
|
||||
from datetime import timedelta
|
||||
value = self.execute('select extract(epoch from (%s)::interval)',
|
||||
[timedelta(days=-42, seconds=45296,
|
||||
|
@ -428,7 +436,7 @@ class mxDateTimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
|
|||
self.assertEqual(seconds, 3674096)
|
||||
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
||||
|
||||
def test_adapt_megative_timedelta(self):
|
||||
def test_adapt_negative_timedelta(self):
|
||||
from mx.DateTime import DateTimeDeltaFrom
|
||||
value = self.execute('select extract(epoch from (%s)::interval)',
|
||||
[DateTimeDeltaFrom(days=-42,
|
||||
|
|
|
@ -77,6 +77,10 @@ class LargeObjectTests(LargeObjectTestCase):
|
|||
self.assertNotEqual(lo, None)
|
||||
self.assertEqual(lo.mode[0], "w")
|
||||
|
||||
def test_connection_needed(self):
|
||||
self.assertRaises(TypeError,
|
||||
psycopg2.extensions.lobject, [])
|
||||
|
||||
def test_open_non_existent(self):
|
||||
# By creating then removing a large object, we get an Oid that
|
||||
# should be unused.
|
||||
|
|
|
@ -199,7 +199,7 @@ class ExceptionsTestCase(ConnectingTestCase):
|
|||
self.assertEqual(diag.sqlstate, '42P01')
|
||||
|
||||
del diag
|
||||
gc.collect()
|
||||
gc.collect(); gc.collect()
|
||||
assert(w() is None)
|
||||
|
||||
@skip_copy_if_green
|
||||
|
@ -279,6 +279,21 @@ class ExceptionsTestCase(ConnectingTestCase):
|
|||
self.assertEqual(e.pgcode, e1.pgcode)
|
||||
self.assert_(e1.cursor is None)
|
||||
|
||||
@skip_before_python(2, 5)
|
||||
def test_pickle_connection_error(self):
|
||||
# segfaults on psycopg 2.5.1 - see ticket #170
|
||||
import pickle
|
||||
try:
|
||||
psycopg2.connect('dbname=nosuchdatabasemate')
|
||||
except psycopg2.Error, exc:
|
||||
e = exc
|
||||
|
||||
e1 = pickle.loads(pickle.dumps(e))
|
||||
|
||||
self.assertEqual(e.pgerror, e1.pgerror)
|
||||
self.assertEqual(e.pgcode, e1.pgcode)
|
||||
self.assert_(e1.cursor is None)
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
|
|
@ -1212,6 +1212,19 @@ class RangeTestCase(unittest.TestCase):
|
|||
assert_not_equal(Range(10, 20), Range(11, 20))
|
||||
assert_not_equal(Range(10, 20, '[)'), Range(10, 20, '[]'))
|
||||
|
||||
def test_eq_wrong_type(self):
|
||||
from psycopg2.extras import Range
|
||||
self.assertNotEqual(Range(10, 20), ())
|
||||
|
||||
def test_eq_subclass(self):
|
||||
from psycopg2.extras import Range, NumericRange
|
||||
|
||||
class IntRange(NumericRange): pass
|
||||
class PositiveIntRange(IntRange): pass
|
||||
|
||||
self.assertEqual(Range(10, 20), IntRange(10, 20))
|
||||
self.assertEqual(PositiveIntRange(10, 20), IntRange(10, 20))
|
||||
|
||||
def test_not_ordered(self):
|
||||
from psycopg2.extras import Range
|
||||
self.assertRaises(TypeError, lambda: Range(empty=True) < Range(0,4))
|
||||
|
|
|
@ -293,6 +293,15 @@ def skip_if_green(reason):
|
|||
|
||||
skip_copy_if_green = skip_if_green("copy in async mode currently not supported")
|
||||
|
||||
def skip_if_no_getrefcount(f):
|
||||
@wraps(f)
|
||||
def skip_if_no_getrefcount_(self):
|
||||
if not hasattr(sys, 'getrefcount'):
|
||||
return self.skipTest('skipped, no sys.getrefcount()')
|
||||
else:
|
||||
return f(self)
|
||||
return skip_if_no_getrefcount_
|
||||
|
||||
def script_to_py3(script):
|
||||
"""Convert a script to Python3 syntax if required."""
|
||||
if sys.version_info[0] < 3:
|
||||
|
|
Loading…
Reference in New Issue
Block a user