diff options
author | Jon Dufresne <jon.dufresne@gmail.com> | 2018-11-07 21:36:35 -0800 |
---|---|---|
committer | Jon Dufresne <jon.dufresne@gmail.com> | 2018-11-10 10:50:33 -0800 |
commit | 36cd8f38e1f1725dfc0078b6f42e35855372bb93 (patch) | |
tree | 8ec58e60db64787752dc13fb55b97bddb1956cc6 | |
parent | 1374b6d2de18e11c0ce6e8aab1fcd09cc70a83dd (diff) | |
download | natsort-36cd8f38e1f1725dfc0078b6f42e35855372bb93.tar.gz |
Drop support for EOL Pythons
Support matrix now matches the test matrix from
6233f07bf303d442b39ac677fa6079acc64834a6. By matching these, helps to
ensure all supported Python do indeed work.
Python 2.6 and 3.3 are end of life. They are no longer receiving bug
fixes, including for security issues. Python 2.6 went EOL on 2013-10-29
and on 2017-09-29. For additional details on support Python versions,
see:
Supported: https://devguide.python.org/#status-of-python-branches
EOL: https://devguide.python.org/devcycle/#end-of-life-branches
Removing support for EOL Pythons will reduce testing and maintenance
resources while allowing the library to move towards a modern Python 3
style.
Using pypinfo, we can show the PyPI download statistics, show very low
numbers for EOL Pythons.
| python_version | percent | download_count |
| -------------- | ------: | -------------: |
| 2.7 | 48.94% | 37,036 |
| 3.6 | 26.58% | 20,113 |
| 3.5 | 15.38% | 11,642 |
| 3.4 | 5.93% | 4,488 |
| 3.7 | 3.13% | 2,365 |
| 3.3 | 0.03% | 21 |
| 2.6 | 0.01% | 9 |
| Total | | 75,674 |
-rw-r--r-- | README.rst | 3 | ||||
-rw-r--r-- | docs/examples.rst | 2 | ||||
-rw-r--r-- | docs/howitworks.rst | 5 | ||||
-rw-r--r-- | docs/intro.rst | 3 | ||||
-rw-r--r-- | natsort/__init__.py | 3 | ||||
-rw-r--r-- | natsort/__main__.py | 2 | ||||
-rw-r--r-- | natsort/compat/locale.py | 3 | ||||
-rw-r--r-- | natsort/compat/py23.py | 37 | ||||
-rw-r--r-- | natsort/natsort.py | 4 | ||||
-rw-r--r-- | natsort/ns_enum.py | 27 | ||||
-rw-r--r-- | natsort/unicode_numeric_hex.py | 2 | ||||
-rw-r--r-- | setup.cfg | 2 | ||||
-rw-r--r-- | setup.py | 4 | ||||
-rw-r--r-- | test_natsort/conftest.py | 4 | ||||
-rw-r--r-- | test_natsort/test_ns_enum.py | 50 | ||||
-rw-r--r-- | test_natsort/test_unicode_numbers.py | 2 |
16 files changed, 79 insertions, 74 deletions
@@ -321,8 +321,7 @@ from the command line with ``python -m natsort``. Requirements ------------ -``natsort`` requires Python version 2.6 or greater or Python 3.3 or greater. -It may run on (but is not tested against) Python 3.2. +``natsort`` requires Python version 2.7 or Python 3.4 or greater. Optional Dependencies --------------------- diff --git a/docs/examples.rst b/docs/examples.rst index e30df91..01f78ee 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -221,7 +221,7 @@ sort key so that: ... def __init__(self, bar): ... self.bar = bar ... def __repr__(self): - ... return "Foo('{0}')".format(self.bar) + ... return "Foo('{}')".format(self.bar) >>> b = [Foo('num3'), Foo('num5'), Foo('num2')] >>> natsorted(b, key=attrgetter('bar')) [Foo('num2'), Foo('num3'), Foo('num5')] diff --git a/docs/howitworks.rst b/docs/howitworks.rst index 12bf569..1138c86 100644 --- a/docs/howitworks.rst +++ b/docs/howitworks.rst @@ -895,10 +895,7 @@ It turns out the there is a bug in the legacy Python implementation of input (https://bugs.python.org/issue2481). :func:`locale.strcoll` works, but is intended for use with ``cmp``, which does not exist in current Python implementations. Luckily, the :func:`functools.cmp_to_key` function -makes :func:`locale.strcoll` behave like :func:`locale.strxfrm` (that is, of course, -unless you are on Python 2.6 where :func:`functools.cmp_to_key` doesn't exist, -in which case you simply copy-paste the implementation from Python 2.7 -directly into your code ☹). +makes :func:`locale.strcoll` behave like :func:`locale.strxfrm`. Handling Broken Locale On OSX ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/intro.rst b/docs/intro.rst index 52d31f8..8174e10 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -317,8 +317,7 @@ from the command line with ``python -m natsort``. Requirements ------------ -:mod:`natsort` requires Python version 2.6 or greater or Python 3.3 or greater. -It may run on (but is not tested against) Python 3.2. +:mod:`natsort` requires Python version 2.7 or Python 3.4 or greater. Optional Dependencies --------------------- diff --git a/natsort/__init__.py b/natsort/__init__.py index 679fa90..395bbbf 100644 --- a/natsort/__init__.py +++ b/natsort/__init__.py @@ -48,5 +48,4 @@ __all__ = [ ] # Add the ns keys to this namespace for convenience. -# A dict comprehension is not used for Python 2.6 compatibility. -globals().update(dict((k, getattr(ns, k)) for k in dir(ns) if k.isupper())) +globals().update(ns._asdict()) diff --git a/natsort/__main__.py b/natsort/__main__.py index c06c9b8..70d9572 100644 --- a/natsort/__main__.py +++ b/natsort/__main__.py @@ -24,7 +24,7 @@ def main(*arguments): parser.add_argument( "--version", action="version", - version="%(prog)s {0}".format(natsort.__version__), + version="%(prog)s {}".format(natsort.__version__), ) parser.add_argument( "-p", diff --git a/natsort/compat/locale.py b/natsort/compat/locale.py index 1629ba0..41abea6 100644 --- a/natsort/compat/locale.py +++ b/natsort/compat/locale.py @@ -7,9 +7,10 @@ from __future__ import absolute_import, division, print_function, unicode_litera # Std. lib imports. import sys +from functools import cmp_to_key # Local imports. -from natsort.compat.py23 import PY_VERSION, cmp_to_key, py23_unichr +from natsort.compat.py23 import PY_VERSION, py23_unichr # This string should be sorted after any other byte string because # it contains the max unicode character repeated 20 times. diff --git a/natsort/compat/py23.py b/natsort/compat/py23.py index ba9abd9..58f7487 100644 --- a/natsort/compat/py23.py +++ b/natsort/compat/py23.py @@ -56,43 +56,6 @@ else: py23_map = itertools.imap py23_filter = itertools.ifilter -# cmp_to_key was not created till 2.7, so require this for 2.6 -try: - from functools import cmp_to_key -except ImportError: # pragma: no cover - - def cmp_to_key(mycmp): - """Convert a cmp= function into a key= function""" - - class K(object): - __slots__ = ["obj"] - - def __init__(self, obj): - self.obj = obj - - def __lt__(self, other): - return mycmp(self.obj, other.obj) < 0 - - def __gt__(self, other): - return mycmp(self.obj, other.obj) > 0 - - def __eq__(self, other): - return mycmp(self.obj, other.obj) == 0 - - def __le__(self, other): - return mycmp(self.obj, other.obj) <= 0 - - def __ge__(self, other): - return mycmp(self.obj, other.obj) >= 0 - - def __ne__(self, other): - return mycmp(self.obj, other.obj) != 0 - - def __hash__(self): - raise TypeError("hash not implemented") - - return K - # This function is intended to decorate other functions that will modify # either a string directly, or a function's docstring. diff --git a/natsort/natsort.py b/natsort/natsort.py index 27f532d..c833ab8 100644 --- a/natsort/natsort.py +++ b/natsort/natsort.py @@ -159,7 +159,7 @@ def natsort_keygen(key=None, alg=ns.DEFAULT, **_kwargs): alg = utils.args_to_enum(**_kwargs) | alg except TypeError: msg = "natsort_keygen: 'alg' argument must be from the enum 'ns'" - raise ValueError(msg + ", got {0}".format(py23_str(alg))) + raise ValueError(msg + ", got {}".format(py23_str(alg))) # Add the _DUMB option if the locale library is broken. if alg & ns.LOCALEALPHA and natsort.compat.locale.dumb_sort(): @@ -683,7 +683,7 @@ if float(sys.version[:3]) < 3: alg = utils.args_to_enum(**kwargs) | alg except TypeError: msg = "natsort_keygen: 'alg' argument must be " "from the enum 'ns'" - raise ValueError(msg + ", got {0}".format(py23_str(alg))) + raise ValueError(msg + ", got {}".format(py23_str(alg))) # Add the _DUMB option if the locale library is broken. if alg & ns.LOCALEALPHA and natsort.compat.locale.dumb_sort(): diff --git a/natsort/ns_enum.py b/natsort/ns_enum.py index 0e98ee6..5d15985 100644 --- a/natsort/ns_enum.py +++ b/natsort/ns_enum.py @@ -7,8 +7,6 @@ from __future__ import absolute_import, division, print_function, unicode_litera import collections -# NOTE: OrderedDict is not used below for compatibility with Python 2.6. - # The below are the base ns options. The values will be stored as powers # of two so bitmasks can be used to extract the user's requested options. enum_options = [ @@ -60,26 +58,25 @@ enum_aliases = [ ] # Construct the list of bitwise distinct enums with their fields. -enum_fields = [(name, 1 << i) for i, name in enumerate(enum_options)] -enum_fields.extend((name, 0) for name in enum_do_nothing) +enum_fields = collections.OrderedDict( + (name, 1 << i) for i, name in enumerate(enum_options) +) +enum_fields.update((name, 0) for name in enum_do_nothing) for name, combo in enum_combos: - current_mapping = dict(enum_fields) - combined_value = current_mapping[combo[0]] + combined_value = enum_fields[combo[0]] for combo_name in combo[1:]: - combined_value |= current_mapping[combo_name] - enum_fields.append((name, combined_value)) - -current_mapping = dict(enum_fields) -enum_fields.extend((alias, current_mapping[name]) for alias, name in enum_aliases) + combined_value |= enum_fields[combo_name] + enum_fields[name] = combined_value -# Finally, extract out the enum field names and their values. -enum_field_names, enum_field_values = zip(*enum_fields) +enum_fields.update( + (alias, enum_fields[name]) for alias, name in enum_aliases +) # Subclass the namedtuple to improve the docstring. # noinspection PyUnresolvedReferences -class _NSEnum(collections.namedtuple("_NSEnum", enum_field_names)): +class _NSEnum(collections.namedtuple("_NSEnum", enum_fields.keys())): """ Enum to control the `natsort` algorithm. @@ -205,7 +202,7 @@ class _NSEnum(collections.namedtuple("_NSEnum", enum_field_names)): # Here is where the instance of the ns enum that will be exported is created. # It is a poor-man's singleton. -ns = _NSEnum(*enum_field_values) +ns = _NSEnum(*enum_fields.values()) # The below is private for internal use only. ns_DUMB = 1 << 31 diff --git a/natsort/unicode_numeric_hex.py b/natsort/unicode_numeric_hex.py index 56c69d6..de28f3b 100644 --- a/natsort/unicode_numeric_hex.py +++ b/natsort/unicode_numeric_hex.py @@ -1743,7 +1743,7 @@ if __name__ == "__main__": a = py23_unichr(i) except ValueError: break - if a in set("0123456789"): + if a in "0123456789": continue if unicodedata.numeric(a, None) is not None: hex_chars.append(i) @@ -22,8 +22,8 @@ classifiers = Operating System :: OS Independent License :: OSI Approved :: MIT License Natural Language :: English + Programming Language :: Python Programming Language :: Python :: 2 - Programming Language :: Python :: 2.6 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.4 @@ -5,10 +5,10 @@ setup( name='natsort', version='5.4.1', packages=find_packages(), - install_requires=["argparse; python_version < '2.7'"], entry_points={'console_scripts': ['natsort = natsort.__main__:main']}, + python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", extras_require={ - 'fast': ["fastnumbers >= 2.0.0; python_version > '2.6'"], + 'fast': ["fastnumbers >= 2.0.0"], 'icu': ["PyICU >= 1.0.0"] } ) diff --git a/test_natsort/conftest.py b/test_natsort/conftest.py index 79a8aaa..8a7412b 100644 --- a/test_natsort/conftest.py +++ b/test_natsort/conftest.py @@ -10,9 +10,9 @@ import pytest def load_locale(x): """Convenience to load a locale, trying ISO8859-1 first.""" try: - locale.setlocale(locale.LC_ALL, str("{0}.ISO8859-1".format(x))) + locale.setlocale(locale.LC_ALL, str("{}.ISO8859-1".format(x))) except locale.Error: - locale.setlocale(locale.LC_ALL, str("{0}.UTF-8".format(x))) + locale.setlocale(locale.LC_ALL, str("{}.UTF-8".format(x))) @pytest.fixture() diff --git a/test_natsort/test_ns_enum.py b/test_natsort/test_ns_enum.py new file mode 100644 index 0000000..f8d64df --- /dev/null +++ b/test_natsort/test_ns_enum.py @@ -0,0 +1,50 @@ +from natsort import ns + + +def test_ns_enum(): + enum_name_values = [ + ("FLOAT", 0x0001), + ("SIGNED", 0x0002), + ("NOEXP", 0x0004), + ("PATH", 0x0008), + ("LOCALEALPHA", 0x0010), + ("LOCALENUM", 0x0020), + ("IGNORECASE", 0x0040), + ("LOWERCASEFIRST", 0x0080), + ("GROUPLETTERS", 0x0100), + ("UNGROUPLETTERS", 0x0200), + ("NANLAST", 0x0400), + ("COMPATIBILITYNORMALIZE", 0x0800), + ("NUMAFTER", 0x1000), + ("DEFAULT", 0x0000), + ("TYPESAFE", 0x0000), + ("INT", 0x0000), + ("VERSION", 0x0000), + ("DIGIT", 0x0000), + ("UNSIGNED", 0x0000), + ("REAL", 0x0003), + ("LOCALE", 0x0030), + ("T", 0x0000), + ("I", 0x0000), + ("V", 0x0000), + ("D", 0x0000), + ("U", 0x0000), + ("F", 0x0001), + ("S", 0x0002), + ("R", 0x0003), + ("N", 0x0004), + ("P", 0x0008), + ("LA", 0x0010), + ("LN", 0x0020), + ("L", 0x0030), + ("IC", 0x0040), + ("LF", 0x0080), + ("G", 0x0100), + ("UG", 0x0200), + ("C", 0x0200), + ("CAPITALFIRST", 0x0200), + ("NL", 0x0400), + ("CN", 0x0800), + ("NA", 0x1000), + ] + assert list(ns._asdict().items()) == enum_name_values diff --git a/test_natsort/test_unicode_numbers.py b/test_natsort/test_unicode_numbers.py index 484fbb2..582a8f0 100644 --- a/test_natsort/test_unicode_numbers.py +++ b/test_natsort/test_unicode_numbers.py @@ -45,7 +45,7 @@ def test_numeric_chars_contains_all_valid_unicode_numeric_and_digit_characters() a = py23_unichr(i) except ValueError: break - if a in set("0123456789"): + if a in "0123456789": continue if unicodedata.numeric(a, None) is not None: assert i in set_numeric_hex |