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))
Rather than deleting, the class, use the skip feature. Provides a more
informative message during test output.
Never skip DatetimeTests as all supported Python environments have the
datetime module builtin.
Previous one didn't refresh by last use. Use the stdlib version for py3
and one of our own for py2.
Max size set to 512, which should be fine for everyone (tweaking is
still possible by monkeypatching, as the tests do, but I don't want to
make an interface of it).
Pass around the module instead of its dict (getting the latter is fast
if needed), mark function raising with negative results, check all errors,
consistent names...