Code Monkey home page Code Monkey logo

natsort's People

Contributors

altendky avatar chrysos349 avatar cpburnz avatar dobatymo avatar domdfcoding avatar gilthans avatar graingert avatar hholzgra avatar hugovk avatar jdufresne avatar kianmeng avatar kuraga avatar madphysicist avatar minchinweb avatar msabramo avatar rdpate avatar rinslow avatar robert-scheck avatar sethmmorton avatar swt2c avatar thethiny avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

natsort's Issues

DeprecationWarning: generator '_sep_inserter' raised StopIteration - PEP 479

In Python 3.6.1, I'm experiencing an issue with a DeprecationWarning as shown below:

lib/python3.6/site-packages/natsort/utils.py:366: DeprecationWarning: generator '_sep_inserter' raised StopIteration
  return lambda split_val, val: tuple(split_val)

Code functions and proceeds, however it pops the above DeprecationWarning for every sort.

Appears to be PEP 479 related. As of Python 3.5, StopIteration handling has changed inside generators.

From PEP 479 section on the Transition Plan, it seems like the correct timing as 3.6 is when the non-silent warning was instituted:

Python 3.5: Enable new semantics under __future__ import; silent deprecation warning if StopIteration bubbles out of a generator not under __future__ import.
Python 3.6: Non-silent deprecation warning.
Python 3.7: Enable new semantics everywhere.

The Natsort code itself shows a comment about StopIteration inside of the referenced _sep_inserter method:
https://github.com/SethMMorton/natsort/blob/master/natsort/utils.py#L233

# Get the first element. If StopIteration is raised, that's OK.

Seems like we may just need to handle the raised StopIteration exception as outlined in PEP 479 and execute inside a try...except block to catch StopIteration.

Add MacOS and Windows to Travis-CI

Describe the feature or enhancement
Update the Travis-CI configuration to support running MacOS and Windows as well as Linux.

Provide a concrete example of how the feature or enhancement will improve natsort
I used to develop on MacOS, but now develop on Linux. There are definite differences in the two in how the locale library behaves, so it is important that both are tested. The best long-term solution is to run all three OSs through CI.

Would you be willing to submit a Pull Request for this feature?
Yes

Support unicode objects

natsort silently fails to do anything useful with unicode strings:

>>> natsort.natsort_key('AAAS 5A')
('AAAS ', 5.0, 'A')
>>> natsort.natsort_key(u'AAAS 5A')
(u'AAAS 5A',)
# should be (u'AAAS ', 5.0, u'A')

Unexpected TypeError when using natsorted on a custom class

Minimum, Complete, Verifiable Example

Using my custom class with python builtin sorted() works 100%. But with natsorted, Python throws this insane type error. This happens when one of my classes on the list has an iterator and the other don't.

from natsort import natsorted

class Production(object):
    def __init__(self, arg):
        self.arg = arg

    def __str__(self):
        return self.arg

    def __lt__(self, other):
        return str( self ) < str( other )

    def __hash__(self):
        return hash( str( self ) )

    def __iter__(self):
        self.index = True
        return self

    def __next__(self):

        if self.index:
            self.index = False
            return self.arg

        raise StopIteration


class Terminal(object):
    def __init__(self, arg):
        self.arg = arg

    def __str__(self):
        return self.arg

    def __lt__(self, other):
        return str( self ) < str( other )

    def __hash__(self):
        return hash( str( self ) )


terminal = Terminal('B')
production = Production('A')

trouble_set = [terminal, production]

print( 'Python sorted:' )
print( sorted( trouble_set ) )
print(  )
print( 'natsorted sorted:' )
print( natsorted( trouble_set ) )

Error message, Traceback

Python sorted:
[<__main__.Production object at 0x00...>, <__main__.Terminal object at 0x00...>]

natsorted sorted:
Traceback (most recent call last):
  File "D:\User\Downloads\test.py", line 54, in <module>
    print( natsorted( trouble_set ) )
  File "F:\Python\lib\site-packages\natsort\natsort.py", line 299, in natsorted
    return sorted(seq, reverse=reverse, key=natsort_key)
TypeError: '<' not supported between instances of 'tuple' and 'str'

This error also comes up if you replace the iterator by the __getitem__:

from natsort import natsorted

class Production(object):
    def __init__(self, arg):
        self.arg = arg

    def __str__(self):
        return self.arg

    def __lt__(self, other):
        return str( self ) < str( other )

    def __hash__(self):
        return hash( str( self ) )

    def __getitem__(self, key):
        return self.arg[key]


class Terminal(object):
    def __init__(self, arg):
        self.arg = arg

    def __str__(self):
        return self.arg

    def __lt__(self, other):
        return str( self ) < str( other )

    def __hash__(self):
        return hash( str( self ) )


terminal = Terminal('B')
production = Production('A')

trouble_set = [terminal, production]

print( 'Python sorted:' )
print( sorted( trouble_set ) )
print(  )
print( 'natsorted sorted:' )
print( natsorted( trouble_set ) )


Handle NaN in input when sorting

Currently, natsort does not detect NaN in input when sorting, and as a result the output can be unexpected (see SethMMorton/fastnumbers#2). _natsort_key should be updated to detect NaN, and then either raise a ValueError, or do something like replace it with -INF or +INF depending on a user's choice.

Refactor natural sorting key in a more functional manner.

As new features were added to natsort, the _natsort_key function was becoming a bit hacky and patched together. It was becoming difficult to add new functionality, and definitely difficult to follow the code. Further, the testing was becoming difficult.

I will be refactoring this function into several smaller functions and factory functions which will make future enhancements/bugfixes/testing more straightforward.

Consider units of measurement

Hi Seth,
I just stumbled over natsort and think it's great! Would it be feasible to consider units of measurement to sort something like ['1 ft', '5 in', '10 ft', '2 in']? I would really appreciate it, if you could point me in the right direction.

Cheers,
Gunnar

'extras_require' must be a dictionary whose values are strings or lists

Minimum, Complete, Verifiable Example

  • CentOS Linux 7.5
  • Python 2.7.5
  • Centos 7 package: python-setuptools 0.9.8 (latest from Redhat 7, added Apr 12, 2017)

Create a setup.py with natsort required:

# -*- coding: utf-8 -*-
# !/usr/bin/python

import sys

from setuptools import setup

sys.path.insert(0, '.')

if __name__ == "__main__":
    package = "test_bug"
    setup(
        name=package,
        version="0.0.1",
        author="Nobody",
        author_email="[email protected]",
        url="https://github.com/SethMMorton",
        license="ASLv2",
        packages=[package],
        package_dir={package: package},
        description=(
            'test'
        ),
        long_description=(
            'test'
        ),
        classifiers=[
            'Intended Audience :: System Administrators',
        ],
        data_files=[],
        install_requires=[
            'natsort'
        ]
    )

Run command

/usr/bin/python2.7 setup.py install

Error message, Traceback, Desired behavior, Suggestion, Request, or Question

Processing dependencies for test_bug==0.0.1
Searching for natsort
Reading https://pypi.python.org/simple/natsort/
Best match: natsort 5.3.3
Downloading https://files.pythonhosted.org/packages/9b/04/f397de5d77942e37cf31f2d37ba7cc2b6f46a440e5dd41e3ab3474f51a0e/natsort-5.3.3.tar.gz#sha256=da930bfddce941526955dea8d35a44243c96adf919ceb758ba7bbd1ba5b0a39a
Processing natsort-5.3.3.tar.gz
Writing /tmp/easy_install-QQ9Rgf/natsort-5.3.3/setup.cfg
Running natsort-5.3.3/setup.py -q bdist_egg --dist-dir /tmp/easy_install-QQ9Rgf/natsort-5.3.3/egg-dist-tmp-mM234_
error: Setup script exited with error in natsort setup command: 'extras_require' must be a dictionary whose values are strings or lists of strings containing valid project/version requirement specifiers.

natsort with ns.LOCALE error: ValueError: character U+110000 is not in range [U+0000; U+10ffff]

This isn't really a bug in natsort, but rather with the UTF-8 implementation on BSD systems (like OSX). Below are some references:

I am creating this issue and leaving it open so that users that see this problem know that they need to use PyICU to solve this problem if they see it, and have easy access to all the relevant documentation.

Feature request natsorted(): Sort by letters, then numbers

I'd like to submit a feature request to add an option that would allow natsorted() to sort by letters first, then numbers instead of numbers first, then letters. Here is an example of the list that I am looking to sort - I am sorting by index 2 ('ABCDE', 'BCDEF' and '10001'):

from natsort import natsorted
a = [
	['192.168.1.1', 'generic_description_1', 'ABCDE', 'apples', '172.16.1.1', u'\nCircuit is up\n'],
	['192.168.1.1', 'generic_description_2', 'BCDEF', 'oranges', '172.16.2.1', u'\nCircuit is up\n'],
	['192.168.2.1', 'generic_description_3', '10001', 'bananas', '172.16.3.1', u'\nCircuit is up\n']
]
print(natsorted(a, key = lambda x: x[2]))

Here are the results that are printed:

[['192.168.2.1', 'generic_description_3', '10001', 'bananas', '172.16.3.1', u'\nCircuit is up\n'],
 ['192.168.1.1', 'generic_description_1', 'ABCDE', 'apples', '172.16.1.1', u'\nCircuit is up\n'],
 ['192.168.1.1', 'generic_description_2', 'BCDEF', 'oranges', '172.16.2.1', u'\nCircuit is up\n']]

And as you can see, it sorts by index 2 by numbers first, then letters:

10001
ABCDE
BCDEF

The option I am requesting would allow the sorting by letters first, then numbers - like this:

ABCDE
BCDEF
10001

Thanks for the consideration!

-Matt

How to get accented chars to group with their unaccented versions?

I am writing a PyQt app and am unhappy with the performance of their table sorting. However it does do "locale-aware" sorting in what I believe to be the correct way. Given this word list:

words = ['apple', 'åpple', 'Apple', 'Äpple', 'Epple', 'Èpple', 'épple', 'epple']

and not ignoring case, Qt sorts in the order: apple, Apple, åpple, Äpple, epple, Epple, épple, Èpple

That is, all forms of A are grouped, then all forms of E. When I do the same sort in native Python using natsort:

if locale.setlocale(locale.LC_ALL) == 'C' :
    locale.setlocale(locale.LC_ALL,'en_US.UTF-8')
key_func_L = natsort.natsort_keygen( alg = natsort.ns.LOCALE )
print( sorted( words, key=key_func_L )  )

The resulting order is 'Apple', 'Epple', 'apple', 'epple', 'Äpple', 'Èpple', 'åpple', 'épple'

That is, all accented forms sort higher than un-accented forms. I am not so concerned that in the one, lowercase is first and the other, uppercase is first. I am concerned that in a long table, words starting with é may be hundreds of rows removed from words starting with e.

I am working in Python 3.4, PyQt5.4, Mac OS 10.10. Changing the locale to fr_FR and de_DE didn't make any difference.

Make sorting by unsigned integers the natsorted default?

I am making the proposal to change the default sorting algorithm for natsorted starting with version 4.0.0. Currently, natsorted looks for any string of numbers that are valid input to the float function in a greedy way (for example, "number-1.402e10hello" would be split into ['number', -14020000000.0, 'hello']).

I have observed that this does not pass the "rule of least astonishment" for most users because it is easy to not recognize that '-' and '.' are actually valid parts of a number or that the algorithm would be accounting for signs and decimals, and thus users are surprised to see natsorted return results where "version2.10" < "version2.2" or "version-2.0" < "version-1.0". I have observed this in this Stack Overflow Question, this issue reported to natsort, and this python module that was created because natsorted did not meet their expectations and instead of filing a bug report attacked natsort in its documentation (the documentation was toned down in the 3rd commit).

My proposal would be to make the behavior of the current function versorted be the default behavior for natsorted, and make the current natsorted behavior belong to a new function (possibly called realnatsorted but I am open to suggestions). versorted would remain for backwards compatibility. A SIGNED attribute to the ns algorithm chooser class would have to be added. This would mean that natsorted would by default return results where "version2.2" < "version2.10" and "version-1.0" < "version-2.0" which I believe would meet most user's expectations.

I am polling the community to find out if I am correct in my assumption that people would expect natsorted to only look for digits and not '-' and '.' from a string, and if it would be worth it to modify the natsorted default behavior to provide less astonishment without breaking existing code too severely.

'NoneType' object has no attribute 'format'

If you use uwsgi with parameter optimize=2 you can get error with using it:

AttributeError at /mymodule/api/
'NoneType' object has no attribute 'format'

interpreter info:

Python Executable: /home/httpd/app/bin/uwsgi
Python Version: 2.7.5

additional:

-O Turn on basic optimizations. This changes the filename extension for compiled (bytecode) files from .pyc to .pyo. See also PYTHONOPTIMIZE.
-OO Discard docstrings in addition to the -O optimizations.

As possible solution add for py23compat.py

return s.format(u='u') if s else s

Any ideas?

Thnx!

detect Path objects in argument iterable and auto-use ns.P

It'd be nice if natsort autodetects whether its arguments are all Path objects (from the new stdlib's pathlib), converted them to strs, and turned on ns.P automatically (and possibly ns.IC on Windows too). I don't have a strong opinion of what to do if some arguments are Paths and others are not (I guess this should fail with TypeError since they are not technically comparable).

Migrate doctests to unit tests (pyest)

Currently, all of the testing for natsort is implemented as doctests. This was fine when natsort was just a single file with two functions, but since it has grown with new functionality things have gotten out of hand. I have also noticed that some doctests fail on python 2.6 because of the way it prints floating point numbers.

The doctests will be migrated to unit tests to use the pytest unit testing framework. This will help make the documentation and the code more clear, as well as allow for more thorough testing.

Sorting arabic, farsi or hebrew numbers is not "natural"

Minimum, Complete, Verifiable Example

import locale
from natsort import natsorted,natsort_keygen, ns

locale.setlocale(locale.LC_ALL, 'fa_IR.UTF-8')

streets = [ 
        "1st street",
        "10th street",
        "2nd street",
        "2 street", 	
        "1 street",
        "1street",
        "12street",
        "11 street",
        "street 23",
        "street 2",
        "street 1",
        "Street 11",
        "۲ street",
        "۱ street",
        "۱street",
        "۱۲street",
        "۱۱ street",
        "street ۲",
        "street ۱",
        "street ۱",
        "street ۱۲",
        "street ۱۱",
]

sl = natsorted(streets, alg= ns.LOCALE | ns.IGNORECASE) 

for name in sl:
    print(name)

Error message, Traceback, Desired behavior, Suggestion, Request, or Question

Expected result:

1 street
۱ street
1st street
1street
۱street
2 street
۲ street
2nd street
10th street
11 street
۱۱ street
12street
۱۲street
street 1
street ۱
street ۱
street 2
street ۲
Street 11
street ۱۱
street ۱۲
street 23

Actual result:

۱۱ street
۱۲street
1street
۱street
1 street
۱ street
1st street
2nd street
2 street
۲ street
10th street
11 street
12street
street 1
street ۱
street ۱
street ۱۱
street ۱۲
street 2
street ۲
Street 11
street 23

Randomly fails to install from wheels on pypi

Exception information:
Traceback (most recent call last):
  File "/home/travis/virtualenv/python2.6.9/lib/python2.6/site-packages/pip/basecommand.py", line 122, in main
    status = self.run(options, args)
  File "/home/travis/virtualenv/python2.6.9/lib/python2.6/site-packages/pip/commands/install.py", line 283, in run
    requirement_set.install(install_options, global_options, root=options.root_path)
  File "/home/travis/virtualenv/python2.6.9/lib/python2.6/site-packages/pip/req.py", line 1435, in install
    requirement.install(install_options, global_options, *args, **kwargs)
  File "/home/travis/virtualenv/python2.6.9/lib/python2.6/site-packages/pip/req.py", line 669, in install
    pip.wheel.check_compatibility(version, self.name)
  File "/home/travis/virtualenv/python2.6.9/lib/python2.6/site-packages/pip/wheel.py", line 438, in check_compatibility
    "%s is in an unsupported or invalid wheel" % name
UnsupportedWheel: natsort is in an unsupported or invalid wheel

That’s what pip does, when trying to install natsort. Though it’s random: it sometimes happens and sometimes doesn’t. With random versions — 2.6, 3.3 or 3.4. I’m running that on Travis CI.

Console script not installed when installing from wheel

When installed with pip, the natsort command line script is not installed.

This has likely been the case for several versions, but since nobody has reported this it looks like no one is using this feature :( It will be fixed in the next release.

Python3 "unorderable types" error with LOCALE and PyICU installed.

The test case is quite simple,

kf = natsort.natsort_keygen( alg = (natsort.ns.LOCALE | natsort.ns.TYPESAFE ) )
ll = ['0','Á','2','Z']
sorted(ll,key=kf)
Traceback (most recent call last):
    File "<string>", line 1, in <fragment>
    builtins.TypeError: unorderable types: bytes() < str()

The issue seems to be that when the input key is numeric e.g. '2', the output of kf is ('',2), where the first element is the null string. When the input key is a letter, the output is e.g. (b'*\x05 \x01E\x88\x01\x06\x00',) where the first element is bytes.

Frankly I don't understand how kf can return a tuple in any case, since docs for sorted() (and for SortedDict, which is where I actually hit this) seem to imply it should return a scalar item. But whatever -- if in the case of a number it returned b'' instead of just '' I think all would be well. I believe this would be line 135 of utils.py?

Enhancement to the version sorting (versorted) output

Hi Seth, thanks for the great work on this lib!
I'd like your opinion on something regarding the version sorting.

From https://github.com/SethMMorton/natsort/blob/master/test_natsort/test_natsort.py#L211

>>>  a = ['1.9.9a', '1.11', '1.9.9b', '1.11.4', '1.10.1']

Let's add the '1.11a' version to the list.

>>> a = ['1.9.9a', '1.11', '1.9.9b', '1.11.4', '1.10.1']
>>> natsorted(a)
['1.9.9a', '1.9.9b', '1.10.1', '1.11', '1.11.4', '1.11a']

I think the '1.11a' should be sorted before the '1.11.4'.
What's your take on this? Thanks.

[regression] Tests error in 5.4.0 on FreeBSD 11.2 in the port

This didn't happen with version 5.3.3.

================================================================================== ERRORS ==================================================================================
____________________________________________ ERROR at setup of test_main_passes_default_arguments_with_no_command_line_options _____________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py, line 23
  def test_main_passes_default_arguments_with_no_command_line_options(mocker):
E       fixture 'mocker' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py:23
________________________________________________ ERROR at setup of test_main_passes_arguments_with_all_command_line_options ________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py, line 38
  def test_main_passes_arguments_with_all_command_line_options(mocker):
E       fixture 'mocker' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py:38
______________________________________________________ ERROR at setup of test_sort_and_print_entries[options0-order0] ______________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py, line 89
  @pytest.mark.parametrize(
      "options, order",
      [
          # Defaults, all options false
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, False, False], [3, 2, 1, 0, 5, 6, 4]),
          # Path option True
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, True, False], [2, 3, 1, 0, 5, 6, 4]),
          # Filter option keeps only within range
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([[(20, 100)], None, False, False, False], [1, 0, 5, 6]),
          # Reverse filter, exclude in range
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a130/path1
          ([None, [(20, 100)], False, True, False], [2, 3, 4]),
          # Exclude given values with exclude list
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([None, None, [23, 130], True, False], [2, 3, 0, 5, 6]),
          # Reverse order
          # tmp/a130/path1
          # tmp/a64/path2
          # tmp/a64/path1
          # tmp/a57/path2
          # tmp/a23/path1
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          ([None, None, False, True, True], reversed([2, 3, 1, 0, 5, 6, 4])),
      ],
  )
  def test_sort_and_print_entries(options, order, mocker):
E       fixture 'mocker' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py:89
______________________________________________________ ERROR at setup of test_sort_and_print_entries[options1-order1] ______________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py, line 89
  @pytest.mark.parametrize(
      "options, order",
      [
          # Defaults, all options false
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, False, False], [3, 2, 1, 0, 5, 6, 4]),
          # Path option True
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, True, False], [2, 3, 1, 0, 5, 6, 4]),
          # Filter option keeps only within range
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([[(20, 100)], None, False, False, False], [1, 0, 5, 6]),
          # Reverse filter, exclude in range
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a130/path1
          ([None, [(20, 100)], False, True, False], [2, 3, 4]),
          # Exclude given values with exclude list
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([None, None, [23, 130], True, False], [2, 3, 0, 5, 6]),
          # Reverse order
          # tmp/a130/path1
          # tmp/a64/path2
          # tmp/a64/path1
          # tmp/a57/path2
          # tmp/a23/path1
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          ([None, None, False, True, True], reversed([2, 3, 1, 0, 5, 6, 4])),
      ],
  )
  def test_sort_and_print_entries(options, order, mocker):
E       fixture 'mocker' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py:89
______________________________________________________ ERROR at setup of test_sort_and_print_entries[options2-order2] ______________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py, line 89
  @pytest.mark.parametrize(
      "options, order",
      [
          # Defaults, all options false
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, False, False], [3, 2, 1, 0, 5, 6, 4]),
          # Path option True
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, True, False], [2, 3, 1, 0, 5, 6, 4]),
          # Filter option keeps only within range
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([[(20, 100)], None, False, False, False], [1, 0, 5, 6]),
          # Reverse filter, exclude in range
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a130/path1
          ([None, [(20, 100)], False, True, False], [2, 3, 4]),
          # Exclude given values with exclude list
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([None, None, [23, 130], True, False], [2, 3, 0, 5, 6]),
          # Reverse order
          # tmp/a130/path1
          # tmp/a64/path2
          # tmp/a64/path1
          # tmp/a57/path2
          # tmp/a23/path1
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          ([None, None, False, True, True], reversed([2, 3, 1, 0, 5, 6, 4])),
      ],
  )
  def test_sort_and_print_entries(options, order, mocker):
E       fixture 'mocker' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py:89
______________________________________________________ ERROR at setup of test_sort_and_print_entries[options3-order3] ______________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py, line 89
  @pytest.mark.parametrize(
      "options, order",
      [
          # Defaults, all options false
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, False, False], [3, 2, 1, 0, 5, 6, 4]),
          # Path option True
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, True, False], [2, 3, 1, 0, 5, 6, 4]),
          # Filter option keeps only within range
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([[(20, 100)], None, False, False, False], [1, 0, 5, 6]),
          # Reverse filter, exclude in range
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a130/path1
          ([None, [(20, 100)], False, True, False], [2, 3, 4]),
          # Exclude given values with exclude list
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([None, None, [23, 130], True, False], [2, 3, 0, 5, 6]),
          # Reverse order
          # tmp/a130/path1
          # tmp/a64/path2
          # tmp/a64/path1
          # tmp/a57/path2
          # tmp/a23/path1
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          ([None, None, False, True, True], reversed([2, 3, 1, 0, 5, 6, 4])),
      ],
  )
  def test_sort_and_print_entries(options, order, mocker):
E       fixture 'mocker' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py:89
______________________________________________________ ERROR at setup of test_sort_and_print_entries[options4-order4] ______________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py, line 89
  @pytest.mark.parametrize(
      "options, order",
      [
          # Defaults, all options false
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, False, False], [3, 2, 1, 0, 5, 6, 4]),
          # Path option True
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, True, False], [2, 3, 1, 0, 5, 6, 4]),
          # Filter option keeps only within range
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([[(20, 100)], None, False, False, False], [1, 0, 5, 6]),
          # Reverse filter, exclude in range
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a130/path1
          ([None, [(20, 100)], False, True, False], [2, 3, 4]),
          # Exclude given values with exclude list
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([None, None, [23, 130], True, False], [2, 3, 0, 5, 6]),
          # Reverse order
          # tmp/a130/path1
          # tmp/a64/path2
          # tmp/a64/path1
          # tmp/a57/path2
          # tmp/a23/path1
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          ([None, None, False, True, True], reversed([2, 3, 1, 0, 5, 6, 4])),
      ],
  )
  def test_sort_and_print_entries(options, order, mocker):
E       fixture 'mocker' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py:89
______________________________________________________ ERROR at setup of test_sort_and_print_entries[options5-order5] ______________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py, line 89
  @pytest.mark.parametrize(
      "options, order",
      [
          # Defaults, all options false
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, False, False], [3, 2, 1, 0, 5, 6, 4]),
          # Path option True
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          # tmp/a130/path1
          ([None, None, False, True, False], [2, 3, 1, 0, 5, 6, 4]),
          # Filter option keeps only within range
          # tmp/a23/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([[(20, 100)], None, False, False, False], [1, 0, 5, 6]),
          # Reverse filter, exclude in range
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a130/path1
          ([None, [(20, 100)], False, True, False], [2, 3, 4]),
          # Exclude given values with exclude list
          # tmp/a1/path1
          # tmp/a1 (1)/path1
          # tmp/a57/path2
          # tmp/a64/path1
          # tmp/a64/path2
          ([None, None, [23, 130], True, False], [2, 3, 0, 5, 6]),
          # Reverse order
          # tmp/a130/path1
          # tmp/a64/path2
          # tmp/a64/path1
          # tmp/a57/path2
          # tmp/a23/path1
          # tmp/a1 (1)/path1
          # tmp/a1/path1
          ([None, None, False, True, True], reversed([2, 3, 1, 0, 5, 6, 4])),
      ],
  )
  def test_sort_and_print_entries(options, order, mocker):
E       fixture 'mocker' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_main.py:89
_________________________________________________________ ERROR at setup of TestNatCmp.test_keys_are_being_cached __________________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_natsort_cmp.py, line 39
      def test_keys_are_being_cached(self, mocker):
E       fixture 'mocker' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_natsort_cmp.py:39
__________________________________________________ ERROR at setup of test_natsort_keygen_with_locale[48-expected0-False] ___________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_natsort_keygen.py, line 102
  @pytest.mark.parametrize(
      "alg, expected, is_dumb",
      [
          (
              ns.LOCALE,
              (
                  (null_string_locale, 6, "A-", 5, ".", 34, "e+", 1),
                  ("/Folder (", 1, ")/Foo"),
                  (null_string_locale, 56.7),
              ),
              False,
          ),
          (
              ns.LOCALE,
              (
                  (null_string_locale, 6, "aa--", 5, "..", 34, "eE++", 1),
                  ("//ffoOlLdDeErR  ((", 1, "))//ffoOoO"),
                  (null_string_locale, 56.7),
              ),
              True,
          ),
          (
              ns.LOCALE | ns.CAPITALFIRST,
              (
                  (("",), (null_string_locale, 6, "A-", 5, ".", 34, "e+", 1)),
                  (("/",), ("/Folder (", 1, ")/Foo")),
                  (("",), (null_string_locale, 56.7)),
              ),
              False,
          ),
      ],
  )
  @pytest.mark.usefixtures("with_locale_en_us")
  def test_natsort_keygen_with_locale(mocker, arbitrary_input, alg, expected, is_dumb):
E       fixture 'mocker' not found
>       available fixtures: arbitrary_input, bytes_input, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_natsort_keygen.py:102
___________________________________________________ ERROR at setup of test_natsort_keygen_with_locale[48-expected1-True] ___________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_natsort_keygen.py, line 102
  @pytest.mark.parametrize(
      "alg, expected, is_dumb",
      [
          (
              ns.LOCALE,
              (
                  (null_string_locale, 6, "A-", 5, ".", 34, "e+", 1),
                  ("/Folder (", 1, ")/Foo"),
                  (null_string_locale, 56.7),
              ),
              False,
          ),
          (
              ns.LOCALE,
              (
                  (null_string_locale, 6, "aa--", 5, "..", 34, "eE++", 1),
                  ("//ffoOlLdDeErR  ((", 1, "))//ffoOoO"),
                  (null_string_locale, 56.7),
              ),
              True,
          ),
          (
              ns.LOCALE | ns.CAPITALFIRST,
              (
                  (("",), (null_string_locale, 6, "A-", 5, ".", 34, "e+", 1)),
                  (("/",), ("/Folder (", 1, ")/Foo")),
                  (("",), (null_string_locale, 56.7)),
              ),
              False,
          ),
      ],
  )
  @pytest.mark.usefixtures("with_locale_en_us")
  def test_natsort_keygen_with_locale(mocker, arbitrary_input, alg, expected, is_dumb):
E       fixture 'mocker' not found
>       available fixtures: arbitrary_input, bytes_input, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_natsort_keygen.py:102
__________________________________________________ ERROR at setup of test_natsort_keygen_with_locale[560-expected2-False] __________________________________________________
file /usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_natsort_keygen.py, line 102
  @pytest.mark.parametrize(
      "alg, expected, is_dumb",
      [
          (
              ns.LOCALE,
              (
                  (null_string_locale, 6, "A-", 5, ".", 34, "e+", 1),
                  ("/Folder (", 1, ")/Foo"),
                  (null_string_locale, 56.7),
              ),
              False,
          ),
          (
              ns.LOCALE,
              (
                  (null_string_locale, 6, "aa--", 5, "..", 34, "eE++", 1),
                  ("//ffoOlLdDeErR  ((", 1, "))//ffoOoO"),
                  (null_string_locale, 56.7),
              ),
              True,
          ),
          (
              ns.LOCALE | ns.CAPITALFIRST,
              (
                  (("",), (null_string_locale, 6, "A-", 5, ".", 34, "e+", 1)),
                  (("/",), ("/Folder (", 1, ")/Foo")),
                  (("",), (null_string_locale, 56.7)),
              ),
              False,
          ),
      ],
  )
  @pytest.mark.usefixtures("with_locale_en_us")
  def test_natsort_keygen_with_locale(mocker, arbitrary_input, alg, expected, is_dumb):
E       fixture 'mocker' not found
>       available fixtures: arbitrary_input, bytes_input, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory, with_locale_de_de, with_locale_en_us
>       use 'pytest --fixtures [testpath]' for help on them.

/usr/ports/devel/py-natsort/work-py27/natsort-5.4.0/test_natsort/test_natsort_keygen.py:102
================================================================================= FAILURES =================================================================================
________________________________________________________ test_string_component_transform_factory[48-example_func5] _________________________________________________________

alg = 48, example_func = <functools.partial object at 0x807bf0838>

    @pytest.mark.parametrize(
>       "alg, example_func",
        [
            (ns.INT, fast_int),
            (ns.DEFAULT, fast_int),
            (ns.FLOAT, partial(fast_float, nan=float("-inf"))),
            (ns.FLOAT | ns.NANLAST, partial(fast_float, nan=float("+inf"))),
            (ns.GROUPLETTERS, partial(fast_int, key=groupletters)),
            (ns.LOCALE, partial(fast_int, key=get_strxfrm())),
            (
                ns.GROUPLETTERS | ns.LOCALE,
                partial(fast_int, key=lambda x: get_strxfrm()(groupletters(x))),
            ),
            (
                ns_DUMB | ns.LOCALE,
                partial(fast_int, key=lambda x: get_strxfrm()(groupletters(x))),
            ),
            (
                ns.GROUPLETTERS | ns.LOCALE | ns.FLOAT | ns.NANLAST,
                partial(
                    fast_float,
                    key=lambda x: get_strxfrm()(groupletters(x)),
                    nan=float("+inf"),
                ),
            ),
        ],
    )

test_natsort/test_string_component_transform_factory.py:37: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/usr/local/lib/python2.7/site-packages/hypothesis/core.py:290: in execute_explicit_examples
    lambda data: test(*arguments, **example_kwargs)
/usr/local/lib/python2.7/site-packages/hypothesis/executors.py:58: in default_new_style_executor
    return function(data)
/usr/local/lib/python2.7/site-packages/hypothesis/core.py:290: in <lambda>
    lambda data: test(*arguments, **example_kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

x = nan, alg = 48, example_func = <functools.partial object at 0x807bf0838>

    @pytest.mark.parametrize(
        "alg, example_func",
        [
            (ns.INT, fast_int),
            (ns.DEFAULT, fast_int),
            (ns.FLOAT, partial(fast_float, nan=float("-inf"))),
            (ns.FLOAT | ns.NANLAST, partial(fast_float, nan=float("+inf"))),
            (ns.GROUPLETTERS, partial(fast_int, key=groupletters)),
            (ns.LOCALE, partial(fast_int, key=get_strxfrm())),
            (
                ns.GROUPLETTERS | ns.LOCALE,
                partial(fast_int, key=lambda x: get_strxfrm()(groupletters(x))),
            ),
            (
                ns_DUMB | ns.LOCALE,
                partial(fast_int, key=lambda x: get_strxfrm()(groupletters(x))),
            ),
            (
                ns.GROUPLETTERS | ns.LOCALE | ns.FLOAT | ns.NANLAST,
                partial(
                    fast_float,
                    key=lambda x: get_strxfrm()(groupletters(x)),
                    nan=float("+inf"),
                ),
            ),
        ],
    )
    @example(x=float("nan"))
    @given(
        x=integers()
        | floats()
        | text().filter(bool).filter(no_bad_uni_chars).filter(no_null)
    )
    @pytest.mark.usefixtures("with_locale_en_us")
    def test_string_component_transform_factory(x, alg, example_func):
        string_component_transform_func = string_component_transform_factory(alg)
        try:
>           assert string_component_transform_func(py23_str(x)) == example_func(py23_str(x))
E           AssertionError: assert 'D*D\x01\x07\x01\x07\x00' == '+\x05M+\x05@+\x...\x00\x01\x07\x00'
E             - D*D\x01\x07\x01\x07\x00
E             + +\x05M+\x05@+\x05M\x01\x07\x01\x07\x00

test_natsort/test_string_component_transform_factory.py:73: AssertionError
-------------------------------------------------------------------------------- Hypothesis --------------------------------------------------------------------------------
Falsifying example: test_string_component_transform_factory(x=nan, alg=48, example_func=<functools.partial at 0x807bf0838>)
======================================================= 1 failed, 265 passed, 10 skipped, 12 error in 58.60 seconds ========================================================
*** Error code 1

Stop.
make: stopped in /usr/ports/devel/py-natsort

python setup.py install fails with setuptools==20.7.0

Minimum, Complete, Verifiable Example

python 2.7.12
setuptools 20.7.0 (Ubuntu 16.04 apt default version)
natsort 5.3.1

Either upgrading setuptools to newer version (39.1.0) or pass version and name variable
to setup() in setup.py fixes the problem.

If natsort doesn't support old version of setuptools, it would be better to note it under
https://github.com/SethMMorton/natsort#requirements

See https://stackoverflow.com/help/mcve for explanation.

Error message, Traceback, Desired behavior, Suggestion, Request, or Question

$ sudo python setup.py install
running install
running bdist_egg
running egg_info
writing src/UNKNOWN.egg-info/PKG-INFO
writing top-level names to src/UNKNOWN.egg-info/top_level.txt
writing dependency_links to src/UNKNOWN.egg-info/dependency_links.txt
reading manifest file 'src/UNKNOWN.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
warning: no previously-included files matching '*.py[cod]' found anywhere in distribution
warning: no previously-included files matching '__pycache__' found anywhere in distribution
warning: no previously-included files matching '*.so' found anywhere in distribution
writing manifest file 'src/UNKNOWN.egg-info/SOURCES.txt'
installing library code to build/bdist.linux-x86_64/egg
running install_lib
running build_py
creating build/bdist.linux-x86_64/egg
creating build/bdist.linux-x86_64/egg/natsort
copying build/lib.linux-x86_64-2.7/natsort/utils.py -> build/bdist.linux-x86_64/egg/natsort
copying build/lib.linux-x86_64-2.7/natsort/unicode_numbers.py -> build/bdist.linux-x86_64/egg/natsort
copying build/lib.linux-x86_64-2.7/natsort/__main__.py -> build/bdist.linux-x86_64/egg/natsort
copying build/lib.linux-x86_64-2.7/natsort/ns_enum.py -> build/bdist.linux-x86_64/egg/natsort
copying build/lib.linux-x86_64-2.7/natsort/__init__.py -> build/bdist.linux-x86_64/egg/natsort
creating build/bdist.linux-x86_64/egg/natsort/compat
copying build/lib.linux-x86_64-2.7/natsort/compat/locale.py -> build/bdist.linux-x86_64/egg/natsort/compat
copying build/lib.linux-x86_64-2.7/natsort/compat/__init__.py -> build/bdist.linux-x86_64/egg/natsort/compat
copying build/lib.linux-x86_64-2.7/natsort/compat/fake_fastnumbers.py -> build/bdist.linux-x86_64/egg/natsort/compat
copying build/lib.linux-x86_64-2.7/natsort/compat/py23.py -> build/bdist.linux-x86_64/egg/natsort/compat
copying build/lib.linux-x86_64-2.7/natsort/compat/fastnumbers.py -> build/bdist.linux-x86_64/egg/natsort/compat
copying build/lib.linux-x86_64-2.7/natsort/compat/pathlib.py -> build/bdist.linux-x86_64/egg/natsort/compat
copying build/lib.linux-x86_64-2.7/natsort/_version.py -> build/bdist.linux-x86_64/egg/natsort
copying build/lib.linux-x86_64-2.7/natsort/natsort.py -> build/bdist.linux-x86_64/egg/natsort
byte-compiling build/bdist.linux-x86_64/egg/natsort/utils.py to utils.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/unicode_numbers.py to unicode_numbers.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/__main__.py to __main__.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/ns_enum.py to ns_enum.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/compat/locale.py to locale.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/compat/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/compat/fake_fastnumbers.py to fake_fastnumbers.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/compat/py23.py to py23.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/compat/fastnumbers.py to fastnumbers.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/compat/pathlib.py to pathlib.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/_version.py to _version.pyc
byte-compiling build/bdist.linux-x86_64/egg/natsort/natsort.py to natsort.pyc
creating build/bdist.linux-x86_64/egg/EGG-INFO
copying src/UNKNOWN.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO
copying src/UNKNOWN.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying src/UNKNOWN.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying src/UNKNOWN.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
zip_safe flag not set; analyzing archive contents...
creating 'dist/UNKNOWN-0.0.0-py2.7.egg' and adding 'build/bdist.linux-x86_64/egg' to it
removing 'build/bdist.linux-x86_64/egg' (and everything under it)
Processing UNKNOWN-0.0.0-py2.7.egg
Removing /usr/local/lib/python2.7/dist-packages/UNKNOWN-0.0.0-py2.7.egg
Copying UNKNOWN-0.0.0-py2.7.egg to /usr/local/lib/python2.7/dist-packages
UNKNOWN 0.0.0 is already the active version in easy-install.pth

Installed /usr/local/lib/python2.7/dist-packages/UNKNOWN-0.0.0-py2.7.egg
Processing dependencies for UNKNOWN==0.0.0
Finished processing dependencies for UNKNOWN==0.0.0

Exception if key is a tuple or other value with ns.IC

list.sort(key = natsort_keygen(key=lambdaKey, alg=ns.U|ns.N|ns.IC))

where lambdaKey = lambda e: (e['val1'], e['val2']). Seems like you call .lower() somewhere with the key assuming it is always one string value. But the key can be other types since you allow to pass in a lambda.
Interestingly it works fine with ns.G

Test test_input_string_transform_factory_removes_thousands_separator_and_is_float_aware_with_LOCALE_and_FLOAT_example is failing on last release 5.3.3

Hi there, I'm the debian maintainer of this module :). I was packaging last version and I can repeat in a controlled environment the test mentioned on the subject is failing for both Python versions. Python2.7 and Python3.6.

=================================== FAILURES ===================================
 test_input_string_transform_factory_removes_thousands_separator_and_is_float_aware_with_LOCALE_and_FLOAT_example 
test_natsort/test_input_string_transform_factory.py:126: in test_input_string_transform_factory_removes_thousands_separator_and_is_float_aware_with_LOCALE_and_FLOAT_example
    assert _input_string_transform_factory(ns.LOCALE | ns.FLOAT)(x) == '12543642642.534,534980'
E   AssertionError: assert '12,543,642,642.534,534,980' == '12543642642.534,534980'
E     - 12,543,642,642.534,534,980
E     ?   -   -   -           -
E     + 12543642642.534,534980

You can see the detailed log here

https://salsa.debian.org/debian/natsort/-/jobs/40303

Unstable sort when input contains leading zeros

Describe the bug

from natsort import natsorted
a = ['8', '38', '41', '42', '53', '70', '79', '112', '135', '150', '153', '154', '155', '157', '162', '185', '189', '196', '197', '198', '202', '203', '204', '205', '211', '218', '242', '244', '250', '250.1', '250.01', '250.02', '250.03', '250.4', '250.5', '250.6', '250.7', '250.8', '250.11', '250.12', '250.13', '250.41', '250.42', '250.43', '250.51', '250.52', '250.53', '250.81', '250.82', '250.83', '250.91', '250.92', '250.93', '252', '253', '255', '263', '272', '275', '276', '277', '278', '280', '282', '284', '285', '286', '287', '288', '290', '291', '292', '293', '294', '295', '296', '300', '301', '303', '304', '305', '309', '311', '331', '332', '337', '340', '342', '344', '345', '346', '348', '357', '362', '386', '394', '396', '397', '398', '401', '402', '403', '404', '410', '411', '412', '413', '414', '415', '416', '420', '421', '424', '425', '426', '427', '428', '432', '433', '434', '435', '436', '437', '438', '440', '441', '443', '444', '446', '447', '451', '453', '456', '458', '459', '462', '465', '466', '478', '481', '482', '486', '491', '492', '493', '496', '507', '511', '512', '515', '516', '518', '519', '530', '531', '535', '536', '537', '552', '553', '558', '560', '562', '564', '567', '568', '569', '571', '572', '573', '574', '575', '576', '577', '578', '581', '583', '584', '585', '590', '591', '592', '593', '595', '596', '599', '600', '611', '616', '617', '618', '620', '625', '642', '648', '680', '682', '707', '710', '711', '714', '715', '718', '719', '721', '722', '723', '724', '727', '728', '729', '730', '733', '737', '738', '780', '781', '782', '784', '785', '786', '787', '788', '789', '790', '794', '799', '805', '808', '813', '820', '873', '996', '997', '998', '999', 'E878', 'E879', 'E880', 'E885', 'E888', 'E932', 'E942', 'V10', 'V12', 'V15', 'V42', 'V43', 'V45', 'V64']
r1 = natsorted(a)
r2 = natsorted(sorted(a))
>>> r1==r2
False

flip between '250.01', '250.1' vs. '250.1', '250.01'

Expected behavior
I expect 250.01 then 250.1 for natural sorting, and especially I expect the sort to be stable to what is inputted.

Environment (please complete the following information):

  • Python Version: 3.6.6
  • OS: Ubuntu 18.04

To Reproduce
see above

Add support for unicode normalization.

This is inspired by this StackOverflow question. The problem is that even with ns.LOCALE some non-ASCII letters are not sorted as you might expect, but running it through unicode.normalize does the trick.

It is not clear if this should be the default behavior or an add-on. It is also not clear if it should default to 'NFD' or if it can be more flexible.

Add thousands separator support when LOCALE is enabled.

This issue was discovered when I tried to suggest natsort as the way to go for this Stack Overflow question: http://stackoverflow.com/q/36431810/2988730

I was trying to do the following based on the docs:

import natsort, locale
locale.setlocale(locale.LC_ALL, 'german')
mylist = ['23 text', '23.130', '12 text', '1.482 text', '3,25']
natsort.humansorted(mylist)

or alternatively

natsort.natsorted(mylist, alg=natsort.ns.LOCALE)

The result in both cases is

['1.482 text', '3,25', '12 text', '23.130', '23 text']

The result that the OP (correctly) expected is

['3,25', '12 text', '23 text', '1.482 text', '23.130']

It appears that natsort is not picking up the locale correctly?

I am using Red Hat Enterprise Linux Release 6.5 (64 bit) with anaconda. natsort 4.0.3 is running under Python 3.5.

Also, just to check that the locale is being set, I ran locale.localeconv after locale.setlocale(locale.LC_ALL, 'german'):

{'currency_symbol': 'EUR',
 'decimal_point': ',',
 'frac_digits': 2,
 'grouping': [3, 3, 0],
 'int_curr_symbol': 'EUR ',
 'int_frac_digits': 2,
 'mon_decimal_point': ',',
 'mon_grouping': [3, 3, 0],
 'mon_thousands_sep': '.',
 'n_cs_precedes': 0,
 'n_sep_by_space': 1,
 'n_sign_posn': 1,
 'negative_sign': '-',
 'p_cs_precedes': 0,
 'p_sep_by_space': 1,
 'p_sign_posn': 1,
 'positive_sign': '',
 'thousands_sep': '.'}

Sorting ranges with ">" and "<"

Is there a way to sort the list:

["<1", "1-5", "6-10.5", ">10.5"]

I did a quick thing for my code like this:

import re
import natsort

def bigsmall(line):
    def replace(match):
        val = float(match.group(2))
        return "{0}".format(val + 1 if match.group(1) == ">" else val - 1)
    return re.sub(r"([<>])=?(\d+\.?\d*)", replace, line)

ranges = ["<1", "1-5", "6-10.5", ">10.5"]
print(natsort.natsorted(ranges), "default sort")
print(natsort.natsorted(ranges, key=bigsmall), "with key")

fastnumbers version check fails to accept fastnumbers v2.0.2

Minimum, Complete, Verifiable Example

current check code is:

    # Require >= version 0.7.1.
    v = list(map(int, fastnumbers.__version__.split('.')))
    if not (v[0] >= 0 and v[1] >= 7 and v[2] >= 1):
        raise ImportError  # pragma: no cover

Error message, Traceback, Desired behavior, Suggestion, Request, or Question

The check above fails with my currently installd fastnumers v2.0.2 as this has v[1] = 0 which is < 7
So the bundled fake_fastnumbers.py is always used even though the real fastnumbers package is installed.

Suggested fix: use StrictVersion() from distutils.version to perform comparison

diff --git a/natsort/compat/fastnumbers.py b/natsort/compat/fastnumbers.py
index 3cc331b..787b553 100644
--- a/natsort/compat/fastnumbers.py
+++ b/natsort/compat/fastnumbers.py
@@ -6,6 +6,8 @@ from __future__ import (
     absolute_import
 )
 
+from distutils.version import StrictVersion
+
 # If the user has fastnumbers installed, they will get great speed
 # benefits. If not, we use the simulated functions that come with natsort.
 try:
@@ -15,8 +17,7 @@ try:
     )
     import fastnumbers
     # Require >= version 0.7.1.
-    v = list(map(int, fastnumbers.__version__.split('.')))
-    if not (v[0] >= 0 and v[1] >= 7 and v[2] >= 1):
+    if StrictVersion(fastnumbers.__version__) < StrictVersion('0.7.1'):
         raise ImportError  # pragma: no cover
 except ImportError:
     from natsort.compat.fake_fastnumbers import (

versorted on list of tuples

Hi,

I'm trying to sort using "versorted" in the natsort package.
The sorting works on a list but fails on a list of tuples.

Is there an alternate way to accomplish the same ?

>>> from natsort import versorted

>>> l = ['2.1.10 Rule', '2.1.1 Rule', '2.1.12 Rule', '2.1.13 Rule', '2.1.2 Rule', '2.1.3 Rule', '2.1.4 Rule', '2.1.4a Rule', '2.1.4b Rule', '2.1.4c Rule']*
>>> versorted(l)
['2.1.1 Rule', '2.1.2 Rule', '2.1.3 Rule', '2.1.4 Rule', '2.1.4a Rule', '2.1.4b Rule', '2.1.4c Rule', '2.1.10 Rule', '2.1.12 Rule', '2.1.13 Rule']

>>> l = [('a', '2.1.10 Rule'), ('a', '2.1.1 Rule'), ('a', '2.1.12 Rule'), ('a', '2.1.13 Rule'), ('a', '2.1.2 Rule'), ('a', '2.1.3 Rule'), ('a', '2.1.4 Rule'), ('a', '2.1.4a Rule'), ('a', '2.1.4b Rule'), ('a', '2.1.4c Rule')]
>>> versorted(l)
[('a', '2.1.10 Rule'), ('a', '2.1.1 Rule'), ('a', '2.1.12 Rule'), ('a', '2.1.13 Rule'), ('a', '2.1.2 Rule'), ('a', '2.1.3 Rule'), ('a', '2.1.4 Rule'), ('a', '2.1.4a Rule'), ('a', '2.1.4b Rule'), ('a', '2.1.4c Rule')]

Thanks!

Python 3.7 Release

I'm using natsort in a project and I'd like to make it Python 3.7 compatible. The current master works just fine after the StopIteration fix. Is there anything I can do to help get it on PyPI?

pip install'ing v4.0.2 doesn't bring the compat directory

natsort v4.0.2 installed with pip doesn't come with the compat directory, which then breaks running natsort:

$ mkdir natsort-test; virtualenv natsort-test/; natsort-test/bin/pip install natsort==4.0.2 ; ls -lah natsort-test/lib/python2.7/site-packages/natsort/
Running virtualenv with interpreter /usr/bin/python2
New python executable in natsort-test/bin/python2
Also creating executable in natsort-test/bin/python
Installing setuptools, pip...done.
Downloading/unpacking natsort==4.0.2
  Downloading natsort-4.0.2-py2.py3-none-any.whl
Installing collected packages: natsort
Successfully installed natsort
Cleaning up...
total 160K
drwxr-xr-x  2 diidier diidier  360 jun 25 14:49 .
drwxr-xr-x 10 diidier diidier  240 jun 25 14:49 ..
-rw-r--r--  1 diidier diidier  772 jun 25 14:49 __init__.py
-rw-r--r--  1 diidier diidier 1.1K jun 25 14:49 __init__.pyc
-rw-r--r--  1 diidier diidier 2.4K jun 25 14:49 locale_help.py
-rw-r--r--  1 diidier diidier 2.5K jun 25 14:49 locale_help.pyc
-rw-r--r--  1 diidier diidier 8.2K jun 25 14:49 __main__.py
-rw-r--r--  1 diidier diidier 8.0K jun 25 14:49 __main__.pyc
-rw-r--r--  1 diidier diidier  21K jun 25 14:49 natsort.py
-rw-r--r--  1 diidier diidier  22K jun 25 14:49 natsort.pyc
-rw-r--r--  1 diidier diidier 7.3K jun 25 14:49 ns_enum.py
-rw-r--r--  1 diidier diidier 7.5K jun 25 14:49 ns_enum.pyc
-rw-r--r--  1 diidier diidier  12K jun 25 14:49 unicode_numbers.py
-rw-r--r--  1 diidier diidier  11K jun 25 14:49 unicode_numbers.pyc
-rw-r--r--  1 diidier diidier  15K jun 25 14:49 utils.py
-rw-r--r--  1 diidier diidier  11K jun 25 14:49 utils.pyc
-rw-r--r--  1 diidier diidier  150 jun 25 14:49 _version.py
-rw-r--r--  1 diidier diidier  322 jun 25 14:49 _version.pyc

$ ./natsort-test/bin/natsort
Traceback (most recent call last):
  File "./natsort-test/bin/natsort", line 7, in <module>
    from natsort.__main__ import main
  File "/tmp/natsort-test/local/lib/python2.7/site-packages/natsort/__init__.py", line 10, in <module>
    from natsort.natsort import (
  File "/tmp/natsort-test/local/lib/python2.7/site-packages/natsort/natsort.py", line 28, in <module>
    from natsort.compat.py23 import u_format
ImportError: No module named compat.py23

Python 3 unorderable types with natsort_keygen

This seems to be changed behavior since python 2.

>>> x = natsort.natsort_keygen()
>>> x('a.1.1.b')
('a', 0.1, 0.1, '.b')
>>> x('a.1.b')
('a', 0.1, '.b')
>>> x('a.1.1.b') < x('a.1.b')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: float() < str()

natsort.natsorted works fine, but sorted with key=x (same x as above) gives unorderable types.

I'm implementing a custom multilevel sort so I don't think I can use natsort.natsorted, unfortunately.

Why doesn't natsorted properly sort signed floats?

I saw in the documentation natsort should work for negative floats as well. Why then does it fail for this example?

from natsort import natsorted
# natsort==5.3.3

itemList = ['Current_2.0', 'Current_-1.0', 'Current_2.4']
print(natsorted(itemList))

# output: ['Current_2.0', 'Current_2.4', 'Current_-1.0']
# desired output: ['Current_-1.0', 'Current_2.0', 'Current_2.4']

Modify sort order of upper- and lower-case letters with ns.LOCALE?

Here's another I just found. However, using TYPESAFE corrects it.

kfunc = natsort.natsort_keygen( alg=( natsort.ns.LOCALE ) )
sorted( [ '10-12','10th'], key=kfunc)
Traceback (most recent call last):
  File "<string>", line 1, in <fragment>
    builtins.TypeError: unorderable types: bytes() < float()
ksafe = natsort.natsort_keygen(alg=(natsort.ns.LOCALE|natsort.ns.TYPESAFE))
sorted( [ '10-12','10th'], key=ksafe)
['10-12', '10th']

I am slightly concerned because I noted a comment in the code about TYPESAFE being in some way expensive to execute and I am sorting quite large tables.

Add a "versorted" method

I want to make it more clear to users that in some cases, using natsort directly with the default number_type value can give unexpected results when sorting version numbers. To achieve this, I would like to introduce a versorted function which will be a wrapper for natsorted(..., number_type=None, signed=False, noexp=True). This has the added benefit of being less typing for the common use case of sorting version numbers.

'_' can't be right sorted in Windows

In windows OS, I want to sorted files in a content with a natural way. But I found your code seems to be not well done in windows. The '_' is sorted after number '0-9'. But in windows OS, the '_' is showed before number '0-9'.

support for tuple/list as a key is missing

data = [{'s': 'a1'}, {'s': 'a2'},{'s': 'a10'}]
natsorted(data, key=lambda x: (x['s'],))

[{'s': 'a1'}, {'s': 'a10'}, {'s': 'a2'}]

I'd expect a1, a2, a10

(its actually needed for more then one value in a list of course, but I want to keep example simple)

TypeError when trying to sort a string of a number and a string

Python 3.3 and Python 3.4 fail to sort collections that contain strings that are also numbers:

>>> import natsort
>>> natsort.natsorted(('a', '1'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/kwpolska/virtualenvs/nikola-py3/lib/python3.4/site-packages/natsort/natsort.py", line 247, in natsorted
    return sorted(seq, key=lambda x: natsort_key(key(x),
TypeError: unorderable types: float() < str()

This works just fine in Python 2.7.6.

via getnikola/nikola#1275 (cc @devurandom)

Wrong sorting order with grouped numbers

natsort 3.5.2, python 3.2.3

>>> l=["li1-1", "li1-2", "li1-3", "li1-10", "li2-11", "li10-1", "li2-11b", "li2-11a", "li2-1b11", "li2-1b2"]
>>> natsort.natsorted(l)
['li1-10', 'li1-3', 'li1-2', 'li1-1', 'li2-11', 'li2-11a', 'li2-11b', 'li2-1b2', 'li2-1b11', 'li10-1']

But I expected the result:

['li1-1', 'li1-2', 'li1-3', 'li1-10', 'li2-1b2', 'li2-1b11', 'li2-11', 'li2-11a', 'li2-11b', 'li10-1']

Request for option to modify case-sensitivity when sorting

Hello, hopefully this is in the right place...

It seems that the library behaves weirdly with string case. For example, A a B b will be sorted as A B a b rather than A a B b, not sure if this is intended or not, but it differs from jquery natural sort so it gives some problems.
An easy fix is to use a lambda which casts the string to lower case but I'm wondering if it is possible to have a setting to change this behaviour.

versorted should follow SemVer rules

Minimum, Complete, Verifiable Example

In [1]: import natsort

In [2]: a = ['1.0.0-alpha', '1.0.0-alpha.1', '1.0.0-alpha.beta', '1.0.0-beta', '1.0.0-beta.2', '1.0.0
   ...: -beta.11', '1.0.0-rc.1', '1.0.0']

In [3]: natsort.versorted(a)
Out[3]: 
['1.0.0',
 '1.0.0-alpha',
 '1.0.0-alpha.1',
 '1.0.0-alpha.beta',
 '1.0.0-beta',
 '1.0.0-beta.2',
 '1.0.0-beta.11',
 '1.0.0-rc.1']

In [4]: natsort.__version__
Out[4]: '5.3.2'

According to https://semver.org/, 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0. natsort puts the 1.0.0 is in the wrong place.

Error message, Traceback, Desired behavior, Suggestion, Request, or Question

There is a useful hack to make this work, but that should not be needed for a function called versorted. It should handle this out-of-the-box.

This would be a breaking change, and might require updating the natsort major version.

Feature request: natsorted() should support the `key=` argument

The first thing I tried to do was to sort a list of objects by their name.

x = natsorted(y, key=lambda o: o.name)

I think this would be a useful addition. The only change that's needed is that natsorted should pass key=lambda o: natsorted(key(o)) to sorted.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.