Merge pull request #801 from pganssle/invalid_tz

Stop trying to add None to the weakref cache
diff --git a/changelog.d/672.bugfix.rst b/changelog.d/672.bugfix.rst
index 8714449..149981c 100644
--- a/changelog.d/672.bugfix.rst
+++ b/changelog.d/672.bugfix.rst
@@ -1 +1 @@
-Switched the ``tzoffset``, ``tzstr`` and ``gettz`` caches over to using weak references, so that the cache expires when no other references to the original ``tzinfo`` objects exist. This cache-expiry behavior is not considered part of the public interface and may change in the future. Requested by @pganssle (gh issue #635), implemented by @cs-cordero (gh pr #672).
+Switched the ``tzoffset``, ``tzstr`` and ``gettz`` caches over to using weak references, so that the cache expires when no other references to the original ``tzinfo`` objects exist. This cache-expiry behavior is not considered part of the public interface and may change in the future. Implemented by @cs-cordero (gh pr #672, #801)
diff --git a/dateutil/test/test_tz.py b/dateutil/test/test_tz.py
index 29c4d82..84416dd 100644
--- a/dateutil/test/test_tz.py
+++ b/dateutil/test/test_tz.py
@@ -8,6 +8,7 @@
 from datetime import datetime, timedelta
 from datetime import time as dt_time
 from datetime import tzinfo
+from six import PY2
 from six import BytesIO, StringIO
 import unittest
 
@@ -1076,6 +1077,26 @@
 
 
 @pytest.mark.gettz
+@pytest.mark.parametrize('badzone', [
+    'Fake.Region/Abcdefghijklmnop',  # Violates several tz project name rules
+])
+def test_gettz_badzone(badzone):
+    # Make sure passing a bad TZ string to gettz returns None (GH #800)
+    tzi = tz.gettz(badzone)
+    assert tzi is None
+
+
+@pytest.mark.gettz
+@pytest.mark.xfail(IS_WIN and PY2,
+                   reason='tzwin fails with non-unicode characters on 2.7')
+def test_gettz_badzone_unicode():
+    # Make sure a unicode string can be passed to TZ (GH #802)
+    # When fixed, combine this with test_gettz_badzone
+    tzi = tz.gettz('🐼')
+    assert tzi is None
+
+
+@pytest.mark.gettz
 @pytest.mark.xfail(IS_WIN, reason='zoneinfo separately cached')
 def test_gettz_cache_clear():
     NYC1 = tz.gettz('America/New_York')
diff --git a/dateutil/tz/tz.py b/dateutil/tz/tz.py
index ba0d8b7..3caac67 100644
--- a/dateutil/tz/tz.py
+++ b/dateutil/tz/tz.py
@@ -1539,10 +1539,15 @@
 
                 if rv is None:
                     rv = self.nocache(name=name)
-                    if not (name is None or isinstance(rv, tzlocal_classes)):
+                    if not (name is None
+                            or isinstance(rv, tzlocal_classes)
+                            or rv is None):
                         # tzlocal is slightly more complicated than the other
                         # time zone providers because it depends on environment
                         # at construction time, so don't cache that.
+                        #
+                        # We also cannot store weak references to None, so we
+                        # will also not store that.
                         self.__instances[name] = rv
 
             return rv