diff options
| author | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2018-10-04 12:24:27 +0100 |
|---|---|---|
| committer | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2018-10-04 12:24:27 +0100 |
| commit | 695c757dc3ea352e9f92e0ebc8d9d88d1a1ce97d (patch) | |
| tree | 4ccbec296d24e34381bf6acffaaa10f49598023b | |
| parent | 6b6b1a6e8d5d831fe17b168b4bf33d2c22bb2cc0 (diff) | |
| parent | 81d6f7a7caabf7662f3acaedf91b77b913952762 (diff) | |
| download | psycopg2-695c757dc3ea352e9f92e0ebc8d9d88d1a1ce97d.tar.gz | |
Merge branch 'stringification-of-ranges'
| -rw-r--r-- | NEWS | 2 | ||||
| -rw-r--r-- | lib/_range.py | 13 | ||||
| -rwxr-xr-x | tests/test_types_extras.py | 46 |
3 files changed, 61 insertions, 0 deletions
@@ -7,6 +7,8 @@ What's new in psycopg 2.8 New features: - 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 maintain columns order (:ticket:`#177`). diff --git a/lib/_range.py b/lib/_range.py index fd15a76..e72c878 100644 --- a/lib/_range.py +++ b/lib/_range.py @@ -62,6 +62,19 @@ class Range(object): return "%s(%r, %r, %r)" % (self.__class__.__name__, 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 def lower(self): """The lower bound of the range. `!None` if empty or unbound.""" diff --git a/tests/test_types_extras.py b/tests/test_types_extras.py index cda163b..ca31c05 100755 --- a/tests/test_types_extras.py +++ b/tests/test_types_extras.py @@ -1386,6 +1386,52 @@ class RangeTestCase(unittest.TestCase): r = Range(0, 4) 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): @wraps(f) |
