PostgreSQL database adapter for the Python programming language
Go to file
Jon Dufresne 6df60ad588 Remove support for mxDateTime
The mxDateTime support has a number of issues:

- The mxDateTime is Python 2 only. There is no support for Python 3 nor
  talk of adding it AFAICT.

- Package mxDateTime support is not tested by Travis CI. New changes,
  especially around date/time interactions, could break it.

- Running psycopg2 tests with mxDateTime support results in the failures
  below.

- Installing egenix-mx-base (to install mxDateTime) with pip fails with
  the error:

    gcc: error: mx/DateTime/mxDateTime/mxDateTime.c: No such file or directory

- All of this to say, it looks like the mxDateTime package is
  unmaintained. It hasn't had a release since 2015.

The datetime module has long been a part of the Python stdlib. All
psycopg2 supported Python environments have date/time support, so
mxDateTime may not be as necessary as it was in the past.

Given the above, I recommend removing mxDateTime support. There are a
number of other items being removed with 2.8, so it is a good
opportunity for backwards incompatible changes.

Alternatively, we could look at:

1. Deprecating mxDateTime for a period (perhaps until Python 2 support is
  dropped).

Or

1. Fixing the unit test failures
2. Find a workaround for the pip install failure
3. Running mxDateTime as part of Travis

---

Failures:

======================================================================
ERROR: test_iter_named_cursor_efficient (tests.test_cursor.CursorTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/testutils.py", line 433, in slow_
    return f(self)
  File "tests/testutils.py", line 282, in skip_before_postgres__
    return f(self)
  File "tests/test_cursor.py", line 349, in test_iter_named_cursor_efficient
    self.assert_((t2 - t1).microseconds * 1e-6 < 0.1,
AttributeError: microseconds

======================================================================
ERROR: test_adapt_infinity_tz (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 405, in test_adapt_infinity_tz
    self.assert_(t.tzinfo is None)
AttributeError: tzinfo

======================================================================
ERROR: test_interval_overflow (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 396, in test_interval_overflow
    self.assertRaises(OverflowError, f, '100000000000000000:00:00')
  File "/usr/lib64/python2.7/unittest/case.py", line 511, in assertRaises
    callableObj(*args, **kwargs)
  File "tests/test_dates.py", line 394, in f
    return cur.fetchone()[0]
RangeError: DateTimeDelta value out of range

======================================================================
ERROR: test_large_interval (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/testutils.py", line 282, in skip_before_postgres__
    return f(self)
  File "tests/test_dates.py", line 350, in test_large_interval
    self.assertEqual(total_seconds(t), 999999 * 60 * 60)
  File "tests/test_dates.py", line 34, in total_seconds
    return d.days * 24 * 60 * 60 + d.seconds + d.microseconds / 1000000.0
AttributeError: microseconds

======================================================================
ERROR: test_micros_rounding (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 369, in test_micros_rounding
    self.assertEqual(total_seconds(t), 0.1)
  File "tests/test_dates.py", line 34, in total_seconds
    return d.days * 24 * 60 * 60 + d.seconds + d.microseconds / 1000000.0
AttributeError: microseconds

======================================================================
ERROR: test_time_value_error_sec_59_99 (tests.test_dates.FromTicksTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 647, in test_time_value_error_sec_59_99
    self.assertEqual(s.adapted.replace(hour=0),
AttributeError: replace

======================================================================
FAIL: test_interval_iso_8601_not_supported (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/testutils.py", line 282, in skip_before_postgres__
    return f(self)
  File "tests/test_dates.py", line 447, in test_interval_iso_8601_not_supported
    self.assertRaises(psycopg2.NotSupportedError, cur.fetchone)
AssertionError: NotSupportedError not raised

======================================================================
FAIL: test_redshift_day (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 439, in test_redshift_day
    self.assertEqual(r, v, "%s -> %s != %s" % (s, r, v))
AssertionError: 1 -> 00:00:00.00 != 0:00:00.000001

======================================================================
FAIL: test_type_roundtrip_date (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 279, in test_type_roundtrip_date
    self._test_type_roundtrip(date(2010, 5, 3))
  File "tests/test_dates.py", line 269, in _test_type_roundtrip
    self.assertEqual(type(o1), type(o2))
AssertionError: <type 'datetime.date'> != <type 'mx.DateTime.DateTime'>

======================================================================
FAIL: test_type_roundtrip_date_array (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 315, in test_type_roundtrip_date_array
    self._test_type_roundtrip_array(date(2010, 5, 3))
  File "tests/test_dates.py", line 275, in _test_type_roundtrip_array
    self.assertEqual(type(o1[0]), type(o2[0]))
AssertionError: <type 'datetime.date'> != <type 'mx.DateTime.DateTime'>

======================================================================
FAIL: test_type_roundtrip_datetime (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 283, in test_type_roundtrip_datetime
    dt = self._test_type_roundtrip(datetime(2010, 5, 3, 10, 20, 30))
  File "tests/test_dates.py", line 269, in _test_type_roundtrip
    self.assertEqual(type(o1), type(o2))
AssertionError: <type 'datetime.datetime'> != <type 'mx.DateTime.DateTime'>

======================================================================
FAIL: test_type_roundtrip_datetime_array (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 319, in test_type_roundtrip_datetime_array
    self._test_type_roundtrip_array(datetime(2010, 5, 3, 10, 20, 30))
  File "tests/test_dates.py", line 275, in _test_type_roundtrip_array
    self.assertEqual(type(o1[0]), type(o2[0]))
AssertionError: <type 'datetime.datetime'> != <type 'mx.DateTime.DateTime'>

======================================================================
FAIL: test_type_roundtrip_datetimetz (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 291, in test_type_roundtrip_datetimetz
    dt2 = self._test_type_roundtrip(dt1)
  File "tests/test_dates.py", line 269, in _test_type_roundtrip
    self.assertEqual(type(o1), type(o2))
AssertionError: <type 'datetime.datetime'> != <type 'mx.DateTime.DateTime'>

======================================================================
FAIL: test_type_roundtrip_datetimetz_array (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 324, in test_type_roundtrip_datetimetz_array
    datetime(2010, 5, 3, 10, 20, 30, tzinfo=FixedOffsetTimezone(0)))
  File "tests/test_dates.py", line 275, in _test_type_roundtrip_array
    self.assertEqual(type(o1[0]), type(o2[0]))
AssertionError: <type 'datetime.datetime'> != <type 'mx.DateTime.DateTime'>

======================================================================
FAIL: test_type_roundtrip_interval (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 311, in test_type_roundtrip_interval
    self._test_type_roundtrip(timedelta(seconds=30))
  File "tests/test_dates.py", line 269, in _test_type_roundtrip
    self.assertEqual(type(o1), type(o2))
AssertionError: <type 'datetime.timedelta'> != <type 'mx.DateTime.DateTimeDelta'>

======================================================================
FAIL: test_type_roundtrip_interval_array (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 332, in test_type_roundtrip_interval_array
    self._test_type_roundtrip_array(timedelta(seconds=30))
  File "tests/test_dates.py", line 275, in _test_type_roundtrip_array
    self.assertEqual(type(o1[0]), type(o2[0]))
AssertionError: <type 'datetime.timedelta'> != <type 'mx.DateTime.DateTimeDelta'>

======================================================================
FAIL: test_type_roundtrip_time (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 297, in test_type_roundtrip_time
    tm = self._test_type_roundtrip(time(10, 20, 30))
  File "tests/test_dates.py", line 269, in _test_type_roundtrip
    self.assertEqual(type(o1), type(o2))
AssertionError: <type 'datetime.time'> != <type 'mx.DateTime.DateTimeDelta'>

======================================================================
FAIL: test_type_roundtrip_time_array (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 328, in test_type_roundtrip_time_array
    self._test_type_roundtrip_array(time(10, 20, 30))
  File "tests/test_dates.py", line 275, in _test_type_roundtrip_array
    self.assertEqual(type(o1[0]), type(o2[0]))
AssertionError: <type 'datetime.time'> != <type 'mx.DateTime.DateTimeDelta'>

======================================================================
FAIL: test_type_roundtrip_timetz (tests.test_dates.DatetimeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 305, in test_type_roundtrip_timetz
    tm2 = self._test_type_roundtrip(tm1)
  File "tests/test_dates.py", line 269, in _test_type_roundtrip
    self.assertEqual(type(o1), type(o2))
AssertionError: <type 'datetime.time'> != <type 'mx.DateTime.DateTimeDelta'>

======================================================================
FAIL: test_date_value_error_sec_59_99 (tests.test_dates.FromTicksTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 642, in test_date_value_error_sec_59_99
    self.assert_(s.adapted in [date(2010, 5, 6), date(2010, 5, 7)])
AssertionError: False is not true

======================================================================
FAIL: test_timestamp_value_error_sec_59_99 (tests.test_dates.FromTicksTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_dates.py", line 636, in test_timestamp_value_error_sec_59_99
    tzinfo=FixedOffsetTimezone(-5 * 60)))
AssertionError: <mx.DateTime.DateTime object for '2010-05-06 12:11:59.99' at 7fcbb03cc348> != datetime.datetime(2010, 5, 6, 14, 11, 59, 999920, tzinfo=psycopg2.tz.FixedOffsetTimezone(offset=-300, name=None))

======================================================================
FAIL: test_adapt_date_range (tests.test_types_extras.RangeCasterTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/testutils.py", line 282, in skip_before_postgres__
    return f(self)
  File "tests/test_types_extras.py", line 1627, in test_adapt_date_range
    self.assertEqual(r1.lower, ts1)
AssertionError: <mx.DateTime.DateTime object for '1999-12-31 06:00:00.00' at 7fcbb03cc300> != datetime.datetime(2000, 1, 1, 0, 0, tzinfo=psycopg2.tz.FixedOffsetTimezone(offset=600, name=None))

======================================================================
FAIL: test_cast_timestamptz (tests.test_types_extras.RangeCasterTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/testutils.py", line 282, in skip_before_postgres__
    return f(self)
  File "tests/test_types_extras.py", line 1535, in test_cast_timestamptz
    self.assertEqual(r.lower, ts1)
AssertionError: <mx.DateTime.DateTime object for '1999-12-31 06:00:00.00' at 7fcbb03cc348> != datetime.datetime(2000, 1, 1, 0, 0, tzinfo=psycopg2.tz.FixedOffsetTimezone(offset=600, name=None))
2019-03-13 20:51:17 -07:00
doc Remove support for mxDateTime 2019-03-13 20:51:17 -07:00
lib Remove support for mxDateTime 2019-03-13 20:51:17 -07:00
psycopg Remove support for mxDateTime 2019-03-13 20:51:17 -07:00
scripts Copyright year updated 2019-02-17 01:36:36 +00:00
tests Remove support for mxDateTime 2019-03-13 20:51:17 -07:00
.appveyor.yml Remove Python 3.3 references from appveyor.yml 2018-12-01 09:11:35 -08:00
.gitignore Added table of sqlstate exceptions in the docs 2019-02-17 01:55:14 +01:00
.travis.yml Add testing and document support for Python 3.7 2018-07-12 18:07:25 -07:00
AUTHORS Trim trailing whitespace from all files throughout project 2017-12-01 21:42:14 -08:00
INSTALL Dropped content from the INSTALL file 2014-08-24 02:06:09 +01:00
LICENSE Prefer https:// URLs when available 2018-09-22 19:02:33 -07:00
Makefile Dropped text docs generation 2019-02-17 00:58:27 +00:00
MANIFEST.in Dropped examples dir (and some leftover reference to the sandbox dir) 2018-11-16 17:06:06 +00:00
NEWS Remove support for mxDateTime 2019-03-13 20:51:17 -07:00
psycopg2.cproj Remove support for mxDateTime 2019-03-13 20:51:17 -07:00
README.rst Update all pypi.python.org URLs to pypi.org 2018-05-20 17:22:37 +01:00
setup.cfg Remove support for mxDateTime 2019-03-13 20:51:17 -07:00
setup.py Remove support for mxDateTime 2019-03-13 20:51:17 -07:00
tox.ini Dropped examples dir (and some leftover reference to the sandbox dir) 2018-11-16 17:06:06 +00:00

psycopg2 - Python-PostgreSQL Database Adapter
=============================================

Psycopg is the most popular PostgreSQL database adapter for the Python
programming language.  Its main features are the complete implementation of
the Python DB API 2.0 specification and the thread safety (several threads can
share the same connection).  It was designed for heavily multi-threaded
applications that create and destroy lots of cursors and make a large number
of concurrent "INSERT"s or "UPDATE"s.

Psycopg 2 is mostly implemented in C as a libpq wrapper, resulting in being
both efficient and secure.  It features client-side and server-side cursors,
asynchronous communication and notifications, "COPY TO/COPY FROM" support.
Many Python types are supported out-of-the-box and adapted to matching
PostgreSQL data types; adaptation can be extended and customized thanks to a
flexible objects adaptation system.

Psycopg 2 is both Unicode and Python 3 friendly.


Documentation
-------------

Documentation is included in the ``doc`` directory and is `available online`__.

.. __: http://initd.org/psycopg/docs/

For any other resource (source code repository, bug tracker, mailing list)
please check the `project homepage`__.


Installation
------------

Building Psycopg requires a few prerequisites (a C compiler, some development
packages): please check the install_ and the faq_ documents in the ``doc`` dir
or online for the details.

If prerequisites are met, you can install psycopg like any other Python
package, using ``pip`` to download it from PyPI_::

    $ pip install psycopg2

or using ``setup.py`` if you have downloaded the source package locally::

    $ python setup.py build
    $ sudo python setup.py install

You can also obtain a stand-alone package, not requiring a compiler or
external libraries, by installing the `psycopg2-binary`_ package from PyPI::

    $ pip install psycopg2-binary

The binary package is a practical choice for development and testing but in
production it is advised to use the package built from sources.

.. _PyPI: https://pypi.org/project/psycopg2/
.. _psycopg2-binary: https://pypi.org/project/psycopg2-binary/
.. _install: http://initd.org/psycopg/docs/install.html#install-from-source
.. _faq: http://initd.org/psycopg/docs/faq.html#faq-compile

.. __: http://initd.org/psycopg/


:Linux/OSX: |travis|
:Windows: |appveyor|

.. |travis| image:: https://travis-ci.org/psycopg/psycopg2.svg?branch=master
    :target: https://travis-ci.org/psycopg/psycopg2
    :alt: Linux and OSX build status

.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/psycopg/psycopg2?branch=master&svg=true
    :target: https://ci.appveyor.com/project/psycopg/psycopg2/branch/master
    :alt: Windows build status