Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add+collect tests for tzinfos input types, fix missed case of invalid… #891

Merged
merged 6 commits into from Mar 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog.d/891.bugfix.rst
@@ -0,0 +1,4 @@
``parser.parse`` will now raise ``TypeError`` when ``tzinfos`` is passed a type
that cannot be interpreted as a time zone. Prior to this change, it would raise
an ``UnboundLocalError`` instead.
Patch by @jbrockmendel (gh pr #891)
2 changes: 2 additions & 0 deletions changelog.d/891.misc.rst
@@ -0,0 +1,2 @@
Added tests for tzinfos input types.
Patch by @jbrockmendel (gh pr #891)
3 changes: 3 additions & 0 deletions dateutil/parser/_parser.py
Expand Up @@ -1172,6 +1172,9 @@ def _build_tzinfo(self, tzinfos, tzname, tzoffset):
tzinfo = tz.tzstr(tzdata)
elif isinstance(tzdata, integer_types):
tzinfo = tz.tzoffset(tzname, tzdata)
else:
raise TypeError("Offset must be tzinfo subclass, tz string, "
"or int offset.")
return tzinfo

def _build_tzaware(self, naive, res, tzinfos):
Expand Down
64 changes: 56 additions & 8 deletions dateutil/test/test_parser.py
Expand Up @@ -347,6 +347,62 @@ def test_parse_bytearray(self):
assert res == expected


class TestTzinfoInputTypes(object):
def assert_equal_same_tz(self, dt1, dt2):
assert dt1 == dt2
assert dt1.tzinfo is dt2.tzinfo

def test_tzinfo_dict_could_return_none(self):
dstr = "2017-02-03 12:40 BRST"
result = parse(dstr, tzinfos={"BRST": None})
expected = datetime(2017, 2, 3, 12, 40)
self.assert_equal_same_tz(result, expected)

def test_tzinfos_callable_could_return_none(self):
dstr = "2017-02-03 12:40 BRST"
result = parse(dstr, tzinfos=lambda *args: None)
expected = datetime(2017, 2, 3, 12, 40)
self.assert_equal_same_tz(result, expected)

def test_invalid_tzinfo_input(self):
dstr = "2014 January 19 09:00 UTC"
# Pass an absurd tzinfos object
tzinfos = {"UTC": ValueError}
with pytest.raises(TypeError):
parse(dstr, tzinfos=tzinfos)

def test_valid_tzinfo_tzinfo_input(self):
dstr = "2014 January 19 09:00 UTC"
tzinfos = {"UTC": tz.UTC}
expected = datetime(2014, 1, 19, 9, tzinfo=tz.UTC)
res = parse(dstr, tzinfos=tzinfos)
self.assert_equal_same_tz(res, expected)

def test_valid_tzinfo_unicode_input(self):
dstr = "2014 January 19 09:00 UTC"
tzinfos = {u"UTC": u"UTC+0"}
expected = datetime(2014, 1, 19, 9, tzinfo=tz.tzstr("UTC+0"))
res = parse(dstr, tzinfos=tzinfos)
self.assert_equal_same_tz(res, expected)

def test_valid_tzinfo_callable_input(self):
dstr = "2014 January 19 09:00 UTC"

def tzinfos(*args, **kwargs):
return u"UTC+0"

expected = datetime(2014, 1, 19, 9, tzinfo=tz.tzstr("UTC+0"))
res = parse(dstr, tzinfos=tzinfos)
self.assert_equal_same_tz(res, expected)

def test_valid_tzinfo_int_input(self):
dstr = "2014 January 19 09:00 UTC"
tzinfos = {u"UTC": -28800}
expected = datetime(2014, 1, 19, 9, tzinfo=tz.tzoffset(u"UTC", -28800))
res = parse(dstr, tzinfos=tzinfos)
self.assert_equal_same_tz(res, expected)


class ParserTest(unittest.TestCase):

@classmethod
Expand Down Expand Up @@ -507,14 +563,6 @@ def testUnspecifiedDayFallbackFebLeapYear(self):
self.assertEqual(parse("Feb 2008", default=datetime(2010, 1, 31)),
datetime(2008, 2, 29))

def testTzinfoDictionaryCouldReturnNone(self):
self.assertEqual(parse('2017-02-03 12:40 BRST', tzinfos={"BRST": None}),
datetime(2017, 2, 3, 12, 40))

def testTzinfosCallableCouldReturnNone(self):
self.assertEqual(parse('2017-02-03 12:40 BRST', tzinfos=lambda *args: None),
datetime(2017, 2, 3, 12, 40))

def testErrorType01(self):
with pytest.raises(ValueError):
parse('shouldfail')
Expand Down