Repository: pandas-dev/pandas

Issue:
DEPS: drop python 3.4



Discussion:
@jreback : Besides, removing it from the Travis YAML, is it possible to also drop support for library versions that were needed to be compatible with Python 3.4 (e.g. `numpy`)?  I imagine that the code that is "Python 3.4" compatible is actually just code compatible with older library versions.
@gfyoung not sure what you mean. numpy 1.7 is compat with 3.4 (in theory), so nothing really to drop here (except the actual version support / travis). I think code changes are minimal as well.
I was referring to the fact that direct code "hacks" to be compatible with Python 3.4 are likely minimal as you said.  Sounds good.
Is this already necessary? If it would not give much code clean-up, it is not much effort to keep compatibility a bit longer? 
For 0.19.2, still 10% of all conda-forge downloads were for 3.4 packages (I know conda-forge stops with 3.4, but this percentage can be indicative for other downloads (main conda channel, pypi)).
well that's the point. As the rest of the community drops support, then we should as well.
conda-forge alone is not "the rest of the community" (and I suspect the main reason for dropping is that otherwise their build matrix becomes too large). I don't know of any other core packages already dropping support? Not that we can't be the first, but still wondering the necessity of this.
well the reason I put this on here is:

1) conda-forge dropping, so that means NO conda packages (not sure if defaults will have this for 3.4 or not, though I think it would have to be a request).
2) OUR build matrix is encumbered by this. So to be honest we could still support it w/o explicity testing it.
To be fair, breaking the 3.4 builds is not disastrous since they are allowed to fail.  One other thing, have we given users any notice of dropping support for this version?

If we haven't, I would be inclined to agree with @jorisvandenbossche that we should wait.  Perhaps we could warn in the next major release of the impending loss of support and then remove support for it in the next major version.
@gfyoung just want to clarify. just because something is ``allowed to fail``, doesn't mean it actually is!

These builds are there because we want to exhaustively test things, but give quick feedback that for-the-most-part things work (hence the 5 main builds). And travis allows 5 concurrent builds so generally this fits well.

Yes, they can occasionally fail, but we *do* fix them!

If we eliminate the 3.4 builds then we won't *know* that they are failing. Though I will admit 3.4 is highly compat with 3.5 so I suspect that it would be unlikely for a 3.4 build to fail while a 3.5 one works (though possible).
if anyone wants to do this :>

Resolving patch:
diff --git a/pandas/compat/__init__.py b/pandas/compat/__init__.py
--- a/pandas/compat/__init__.py
+++ b/pandas/compat/__init__.py
@@ -7,7 +7,7 @@
 Key items to import for 2/3 compatible code:
 * iterators: range(), map(), zip(), filter(), reduce()
 * lists: lrange(), lmap(), lzip(), lfilter()
-* unicode: u() [u"" is a syntax error in Python 3.0-3.2]
+* unicode: u() [no unicode builtin in Python 3]
 * longs: long (int in Python 3)
 * callable
 * iterable method compatibility: iteritems, iterkeys, itervalues
@@ -110,7 +110,7 @@ def signature(f):
     unichr = chr
 
     # This was introduced in Python 3.3, but we don't support
-    # Python 3.x < 3.4, so checking PY3 is safe.
+    # Python 3.x < 3.5, so checking PY3 is safe.
     FileNotFoundError = FileNotFoundError
 
     # list-producing versions of the major Python iterating functions
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -246,7 +246,6 @@ def build_extensions(self):
     'Programming Language :: Python :: 2',
     'Programming Language :: Python :: 3',
     'Programming Language :: Python :: 2.7',
-    'Programming Language :: Python :: 3.4',
     'Programming Language :: Python :: 3.5',
     'Programming Language :: Python :: 3.6',
     'Programming Language :: Cython',


Test patch:
diff --git a/pandas/tests/util/test_util.py b/pandas/tests/util/test_util.py
--- a/pandas/tests/util/test_util.py
+++ b/pandas/tests/util/test_util.py
@@ -16,9 +16,6 @@
 
 import pandas.util.testing as tm
 
-CURRENT_LOCALE = locale.getlocale()
-LOCALE_OVERRIDE = os.environ.get('LOCALE_OVERRIDE', None)
-
 
 class TestDecorators(object):
 
@@ -412,6 +409,7 @@ class TestLocaleUtils(object):
     @classmethod
     def setup_class(cls):
         cls.locales = tm.get_locales()
+        cls.current_locale = locale.getlocale()
 
         if not cls.locales:
             pytest.skip("No locales found")
@@ -421,6 +419,7 @@ def setup_class(cls):
     @classmethod
     def teardown_class(cls):
         del cls.locales
+        del cls.current_locale
 
     def test_get_locales(self):
         # all systems should have at least a single locale
@@ -438,17 +437,19 @@ def test_set_locale(self):
             pytest.skip("Only a single locale found, no point in "
                         "trying to test setting another locale")
 
-        if all(x is None for x in CURRENT_LOCALE):
+        if all(x is None for x in self.current_locale):
             # Not sure why, but on some travis runs with pytest,
             # getlocale() returned (None, None).
-            pytest.skip("CURRENT_LOCALE is not set.")
+            pytest.skip("Current locale is not set.")
+
+        locale_override = os.environ.get('LOCALE_OVERRIDE', None)
 
-        if LOCALE_OVERRIDE is None:
+        if locale_override is None:
             lang, enc = 'it_CH', 'UTF-8'
-        elif LOCALE_OVERRIDE == 'C':
+        elif locale_override == 'C':
             lang, enc = 'en_US', 'ascii'
         else:
-            lang, enc = LOCALE_OVERRIDE.split('.')
+            lang, enc = locale_override.split('.')
 
         enc = codecs.lookup(enc).name
         new_locale = lang, enc
@@ -465,4 +466,4 @@ def test_set_locale(self):
                 assert normalized_locale == new_locale
 
         current_locale = locale.getlocale()
-        assert current_locale == CURRENT_LOCALE
+        assert current_locale == self.current_locale