Merge branch 'stringification-of-ranges'

This commit is contained in:
Daniele Varrazzo 2018-10-04 12:24:27 +01:00
commit 695c757dc3
3 changed files with 61 additions and 0 deletions

2
NEWS
View File

@ -7,6 +7,8 @@ What's new in psycopg 2.8
New features: New features:
- Added `~psycopg2.extensions.encrypt_password()` function (:ticket:`#576`). - Added `~psycopg2.extensions.encrypt_password()` function (:ticket:`#576`).
- `!str()` on `~psycopg2.extras.Range` produces a human-readable representation
(:ticket:`#773`).
- `~psycopg2.extras.DictCursor` and `~psycopg2.extras.RealDictCursor` rows - `~psycopg2.extras.DictCursor` and `~psycopg2.extras.RealDictCursor` rows
maintain columns order (:ticket:`#177`). maintain columns order (:ticket:`#177`).

View File

@ -62,6 +62,19 @@ class Range(object):
return "%s(%r, %r, %r)" % (self.__class__.__name__, return "%s(%r, %r, %r)" % (self.__class__.__name__,
self._lower, self._upper, self._bounds) self._lower, self._upper, self._bounds)
def __str__(self):
if self._bounds is None:
return 'empty'
items = [
self._bounds[0],
str(self._lower),
', ',
str(self._upper),
self._bounds[1]
]
return ''.join(items)
@property @property
def lower(self): def lower(self):
"""The lower bound of the range. `!None` if empty or unbound.""" """The lower bound of the range. `!None` if empty or unbound."""

View File

@ -1386,6 +1386,52 @@ class RangeTestCase(unittest.TestCase):
r = Range(0, 4) r = Range(0, 4)
self.assertEqual(loads(dumps(r)), r) self.assertEqual(loads(dumps(r)), r)
def test_str(self):
'''
Range types should have a short and readable ``str`` implementation.
Using ``repr`` for all string conversions can be very unreadable for
longer types like ``DateTimeTZRange``.
'''
from psycopg2.extras import Range
# Using the "u" prefix to make sure we have the proper return types in
# Python2
expected = [
u'(0, 4)',
u'[0, 4]',
u'(0, 4]',
u'[0, 4)',
u'empty',
]
results = []
converter = unicode if sys.version_info < (3, 0) else str
for bounds in ('()', '[]', '(]', '[)'):
r = Range(0, 4, bounds=bounds)
results.append(converter(r))
r = Range(empty=True)
results.append(converter(r))
self.assertEqual(results, expected)
def test_str_datetime(self):
'''
Date-Time ranges should return a human-readable string as well on
string conversion.
'''
from psycopg2.extras import DateTimeTZRange
from datetime import datetime
from psycopg2.tz import FixedOffsetTimezone
converter = unicode if sys.version_info < (3, 0) else str
tz = FixedOffsetTimezone(-5*60, "EST")
r = DateTimeTZRange(datetime(2010, 1, 1, tzinfo=tz),
datetime(2011, 1, 1, tzinfo=tz))
expected = u'[2010-01-01 00:00:00-05:00, 2011-01-01 00:00:00-05:00)'
result = converter(r)
self.assertEqual(result, expected)
def skip_if_no_range(f): def skip_if_no_range(f):
@wraps(f) @wraps(f)