diff options
author | Seth M Morton <seth.m.morton@gmail.com> | 2018-08-04 19:48:12 -0700 |
---|---|---|
committer | Seth M Morton <seth.m.morton@gmail.com> | 2018-08-10 15:02:25 -0400 |
commit | c556296ff88902354da9f73a3555b5be3facaba8 (patch) | |
tree | 40473b8b999e7612c18a6cc91fc8b728f730e8b8 | |
parent | b613c763c581940561118ef4c3660db3d6a9cb2d (diff) | |
download | natsort-c556296ff88902354da9f73a3555b5be3facaba8.tar.gz |
Blacken code.
As part of the blackening, the huge tuple of hex literals that represent
unicode numerals has been placed into its own file, and the _version.py
contents has been moved to __init__.py.
PEP8 checks are updated to conform to black's style.
33 files changed, 3361 insertions, 1354 deletions
diff --git a/natsort/__init__.py b/natsort/__init__.py index 45ede6e..81a2309 100644 --- a/natsort/__init__.py +++ b/natsort/__init__.py @@ -1,17 +1,11 @@ # -*- coding: utf-8 -*- -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import -# Local imports. +# Std. lib imports. import sys +# Local imports. from natsort.utils import chain_functions -from natsort._version import __version__ - from natsort.natsort import ( natsort_key, natsort_keygen, @@ -33,27 +27,27 @@ from natsort.natsort import ( if float(sys.version[:3]) < 3: from natsort.natsort import natcmp +__version__ = "5.3.3" + __all__ = [ - 'natsort_key', - 'natsort_keygen', - 'natsorted', - 'versorted', - 'humansorted', - 'realsorted', - 'index_natsorted', - 'index_versorted', - 'index_humansorted', - 'index_realsorted', - 'order_by_index', - 'decoder', - 'natcmp', - 'as_ascii', - 'as_utf8', - 'ns', - 'chain_functions', + "natsort_key", + "natsort_keygen", + "natsorted", + "versorted", + "humansorted", + "realsorted", + "index_natsorted", + "index_versorted", + "index_humansorted", + "index_realsorted", + "order_by_index", + "decoder", + "natcmp", + "as_ascii", + "as_utf8", + "ns", + "chain_functions", ] # Add the ns keys to this namespace for convenience. -globals().update( - dict((k, v) for k, v in vars(ns).items() if not k.startswith('_')) -) +globals().update(dict((k, v) for k, v in vars(ns).items() if not k.startswith("_"))) diff --git a/natsort/__main__.py b/natsort/__main__.py index f2b4e29..5cdc0b2 100644 --- a/natsort/__main__.py +++ b/natsort/__main__.py @@ -1,18 +1,12 @@ # -*- coding: utf-8 -*- -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import # Std. lib imports. import sys # Local imports. -from natsort.natsort import natsorted, ns +import natsort from natsort.utils import _regex_chooser -from natsort._version import __version__ from natsort.compat.py23 import py23_str @@ -25,67 +19,118 @@ def main(): from argparse import ArgumentParser, RawDescriptionHelpFormatter from textwrap import dedent - parser = ArgumentParser(description=dedent(main.__doc__), - formatter_class=RawDescriptionHelpFormatter) - parser.add_argument('--version', action='version', - version='%(prog)s {0}'.format(__version__)) + + parser = ArgumentParser( + description=dedent(main.__doc__), formatter_class=RawDescriptionHelpFormatter + ) + parser.add_argument( + "--version", + action="version", + version="%(prog)s {0}".format(natsort.__version__), + ) parser.add_argument( - '-p', '--paths', default=False, action='store_true', - help='Interpret the input as file paths. This is not ' - 'strictly necessary to sort all file paths, but in cases ' - 'where there are OS-generated file paths like "Folder/" ' - 'and "Folder (1)/", this option is needed to make the ' - 'paths sorted in the order you expect ("Folder/" before ' - '"Folder (1)/").') + "-p", + "--paths", + default=False, + action="store_true", + help="Interpret the input as file paths. This is not " + "strictly necessary to sort all file paths, but in cases " + 'where there are OS-generated file paths like "Folder/" ' + 'and "Folder (1)/", this option is needed to make the ' + 'paths sorted in the order you expect ("Folder/" before ' + '"Folder (1)/").', + ) parser.add_argument( - '-f', '--filter', nargs=2, type=float, metavar=('LOW', 'HIGH'), - action='append', - help='Used for keeping only the entries that have a number ' - 'falling in the given range.') + "-f", + "--filter", + nargs=2, + type=float, + metavar=("LOW", "HIGH"), + action="append", + help="Used for keeping only the entries that have a number " + "falling in the given range.", + ) parser.add_argument( - '-F', '--reverse-filter', nargs=2, type=float, - metavar=('LOW', 'HIGH'), action='append', dest='reverse_filter', - help='Used for excluding the entries that have a number ' - 'falling in the given range.') + "-F", + "--reverse-filter", + nargs=2, + type=float, + metavar=("LOW", "HIGH"), + action="append", + dest="reverse_filter", + help="Used for excluding the entries that have a number " + "falling in the given range.", + ) parser.add_argument( - '-e', '--exclude', type=float, action='append', - help='Used to exclude an entry that contains a specific number.') + "-e", + "--exclude", + type=float, + action="append", + help="Used to exclude an entry that contains a specific number.", + ) parser.add_argument( - '-r', '--reverse', action='store_true', default=False, - help='Returns in reversed order.') + "-r", + "--reverse", + action="store_true", + default=False, + help="Returns in reversed order.", + ) parser.add_argument( - '-t', '--number-type', '--number_type', dest='number_type', - choices=('digit', 'int', 'float', 'version', 'ver', - 'real', 'f', 'i', 'r', 'd'), - default='int', + "-t", + "--number-type", + "--number_type", + dest="number_type", + choices=("digit", "int", "float", "version", "ver", "real", "f", "i", "r", "d"), + default="int", help='Choose the type of number to search for. "float" will search ' - 'for floating-point numbers. "int" will only search for ' - 'integers. "digit", "version", and "ver" are synonyms for "int".' - '"real" is a shortcut for "float" with --sign. ' - '"i" and "d" are synonyms for "int", "f" is a synonym for ' - '"float", and "r" is a synonym for "real".' - 'The default is %(default)s.') + 'for floating-point numbers. "int" will only search for ' + 'integers. "digit", "version", and "ver" are synonyms for "int".' + '"real" is a shortcut for "float" with --sign. ' + '"i" and "d" are synonyms for "int", "f" is a synonym for ' + '"float", and "r" is a synonym for "real".' + "The default is %(default)s.", + ) parser.add_argument( - '--nosign', default=False, action='store_false', dest='signed', + "--nosign", + default=False, + action="store_false", + dest="signed", help='Do not consider "+" or "-" as part of a number, i.e. do not ' - 'take sign into consideration. This is the default.') + "take sign into consideration. This is the default.", + ) parser.add_argument( - '-s', '--sign', default=False, action='store_true', dest='signed', + "-s", + "--sign", + default=False, + action="store_true", + dest="signed", help='Consider "+" or "-" as part of a number, i.e. ' - 'take sign into consideration. The default is unsigned.') + "take sign into consideration. The default is unsigned.", + ) parser.add_argument( - '--noexp', default=True, action='store_false', dest='exp', - help='Do not consider an exponential as part of a number, i.e. 1e4, ' - 'would be considered as 1, "e", and 4, not as 10000. This only ' - 'effects the --number-type=float.') + "--noexp", + default=True, + action="store_false", + dest="exp", + help="Do not consider an exponential as part of a number, i.e. 1e4, " + 'would be considered as 1, "e", and 4, not as 10000. This only ' + "effects the --number-type=float.", + ) parser.add_argument( - '-l', '--locale', action='store_true', default=False, - help='Causes natsort to use locale-aware sorting. You will get the ' - 'best results if you install PyICU.') + "-l", + "--locale", + action="store_true", + default=False, + help="Causes natsort to use locale-aware sorting. You will get the " + "best results if you install PyICU.", + ) parser.add_argument( - 'entries', nargs='*', default=sys.stdin, - help='The entries to sort. Taken from stdin if nothing is given on ' - 'the command line.', ) + "entries", + nargs="*", + default=sys.stdin, + help="The entries to sort. Taken from stdin if nothing is given on " + "the command line.", + ) args = parser.parse_args() # Make sure the filter range is given properly. Does nothing if no filter @@ -106,7 +151,7 @@ def range_check(low, high): Otherwise the input is returned as-is. """ if low >= high: - raise ValueError('low >= high') + raise ValueError("low >= high") else: return low, high @@ -123,8 +168,8 @@ def check_filter(filt): return None try: return [range_check(f[0], f[1]) for f in filt] - except ValueError as a: - raise ValueError('Error in --filter: '+py23_str(a)) + except ValueError as err: + raise ValueError("Error in --filter: " + py23_str(err)) def keep_entry_range(entry, lows, highs, converter, regex): @@ -135,9 +180,11 @@ def keep_entry_range(entry, lows, highs, converter, regex): Returns True if it should be kept (i.e. falls in the range), and False if it is not in the range and should not be kept. """ - return any(low <= converter(num) <= high - for num in regex.findall(entry) - for low, high in zip(lows, highs)) + return any( + low <= converter(num) <= high + for num in regex.findall(entry) + for low, high in zip(lows, highs) + ) def exclude_entry(entry, values, converter, regex): @@ -155,48 +202,58 @@ def sort_and_print_entries(entries, args): """Sort the entries, applying the filters first if necessary.""" # Extract the proper number type. - is_float = args.number_type in ('float', 'real', 'f', 'r') - signed = args.signed or args.number_type in ('real', 'r') - alg = (ns.FLOAT * is_float | - ns.SIGNED * signed | - ns.NOEXP * (not args.exp) | - ns.PATH * args.paths | - ns.LOCALE * args.locale) + is_float = args.number_type in ("float", "real", "f", "r") + signed = args.signed or args.number_type in ("real", "r") + alg = ( + natsort.ns.FLOAT * is_float + | natsort.ns.SIGNED * signed + | natsort.ns.NOEXP * (not args.exp) + | natsort.ns.PATH * args.paths + | natsort.ns.LOCALE * args.locale + ) # Pre-remove entries that don't pass the filtering criteria # Make sure we use the same searching algorithm for filtering # as for sorting. do_filter = args.filter is not None or args.reverse_filter is not None if do_filter or args.exclude: - inp_options = (ns.FLOAT * is_float | - ns.SIGNED * signed | - ns.NOEXP * (not args.exp) - ) + inp_options = ( + natsort.ns.FLOAT * is_float + | natsort.ns.SIGNED * signed + | natsort.ns.NOEXP * (not args.exp) + ) regex = _regex_chooser[inp_options] if args.filter is not None: - lows, highs = ([f[0] for f in args.filter], - [f[1] for f in args.filter]) - entries = [entry for entry in entries - if keep_entry_range(entry, lows, highs, - float, regex)] + lows, highs = ([f[0] for f in args.filter], [f[1] for f in args.filter]) + entries = [ + entry + for entry in entries + if keep_entry_range(entry, lows, highs, float, regex) + ] if args.reverse_filter is not None: - lows, highs = ([f[0] for f in args.reverse_filter], - [f[1] for f in args.reverse_filter]) - entries = [entry for entry in entries - if not keep_entry_range(entry, lows, highs, - float, regex)] + lows, highs = ( + [f[0] for f in args.reverse_filter], + [f[1] for f in args.reverse_filter], + ) + entries = [ + entry + for entry in entries + if not keep_entry_range(entry, lows, highs, float, regex) + ] if args.exclude: exclude = set(args.exclude) - entries = [entry for entry in entries - if exclude_entry(entry, exclude, - float, regex)] + entries = [ + entry + for entry in entries + if exclude_entry(entry, exclude, float, regex) + ] # Print off the sorted results - for entry in natsorted(entries, reverse=args.reverse, alg=alg): + for entry in natsort.natsorted(entries, reverse=args.reverse, alg=alg): print(entry) -if __name__ == '__main__': +if __name__ == "__main__": try: main() except ValueError as a: diff --git a/natsort/_version.py b/natsort/_version.py deleted file mode 100644 index e362806..0000000 --- a/natsort/_version.py +++ /dev/null @@ -1,9 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) - -__version__ = '5.3.3' diff --git a/natsort/compat/fake_fastnumbers.py b/natsort/compat/fake_fastnumbers.py index 6eee532..68076a4 100644 --- a/natsort/compat/fake_fastnumbers.py +++ b/natsort/compat/fake_fastnumbers.py @@ -4,31 +4,48 @@ This module is intended to replicate some of the functionality from the fastnumbers module in the event that module is not installed. """ -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import # Std. lib imports. import unicodedata from natsort.unicode_numbers import decimal_chars from natsort.compat.py23 import PY_VERSION + if PY_VERSION >= 3: long = int -NAN_INF = ['INF', 'INf', 'Inf', 'inF', 'iNF', 'InF', 'inf', 'iNf', - 'NAN', 'nan', 'NaN', 'nAn', 'naN', 'NAn', 'nAN', 'Nan'] -NAN_INF.extend(['+'+x[:2] for x in NAN_INF] + ['-'+x[:2] for x in NAN_INF]) +NAN_INF = [ + "INF", + "INf", + "Inf", + "inF", + "iNF", + "InF", + "inf", + "iNf", + "NAN", + "nan", + "NaN", + "nAn", + "naN", + "NAn", + "nAN", + "Nan", +] +NAN_INF.extend(["+" + x[:2] for x in NAN_INF] + ["-" + x[:2] for x in NAN_INF]) NAN_INF = frozenset(NAN_INF) -ASCII_NUMS = '0123456789+-' +ASCII_NUMS = "0123456789+-" -def fast_float(x, key=lambda x: x, nan=None, - uni=unicodedata.numeric, nan_inf=NAN_INF, - _first_char=frozenset(decimal_chars + list(ASCII_NUMS + '.'))): +def fast_float( + x, + key=lambda x: x, + nan=None, + uni=unicodedata.numeric, + nan_inf=NAN_INF, + _first_char=frozenset(decimal_chars + list(ASCII_NUMS + ".")), +): """\ Convert a string to a float quickly, return input as-is if not possible. We don't need to accept all input that the real fast_int accepts because @@ -50,13 +67,19 @@ def fast_float(x, key=lambda x: x, nan=None, return key(x) -def fast_int(x, key=lambda x: x, nan=None, uni=unicodedata.digit, - _first_char=frozenset(decimal_chars + list(ASCII_NUMS))): +def fast_int( + x, + key=lambda x: x, + nan=None, + uni=unicodedata.digit, + _first_char=frozenset(decimal_chars + list(ASCII_NUMS)), +): """\ Convert a string to a int quickly, return input as-is if not possible. We don't need to accept all input that the real fast_int accepts because the input will be controlled by the splitting algorithm. """ + del nan # explicitly indicate we are not using the nan argument if x[0] in _first_char: try: return long(x) diff --git a/natsort/compat/fastnumbers.py b/natsort/compat/fastnumbers.py index 787b553..3c15acc 100644 --- a/natsort/compat/fastnumbers.py +++ b/natsort/compat/fastnumbers.py @@ -1,26 +1,16 @@ # -*- coding: utf-8 -*- -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, 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: - from fastnumbers import ( - fast_float, - fast_int, - ) + from fastnumbers import fast_float, fast_int import fastnumbers + # Require >= version 0.7.1. - if StrictVersion(fastnumbers.__version__) < StrictVersion('0.7.1'): + if StrictVersion(fastnumbers.__version__) < StrictVersion("0.7.1"): raise ImportError # pragma: no cover except ImportError: - from natsort.compat.fake_fastnumbers import ( - fast_float, - fast_int, - ) + from natsort.compat.fake_fastnumbers import fast_float, fast_int diff --git a/natsort/compat/locale.py b/natsort/compat/locale.py index ab392ee..a31a42c 100644 --- a/natsort/compat/locale.py +++ b/natsort/compat/locale.py @@ -1,25 +1,16 @@ # -*- coding: utf-8 -*- -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import # Std. lib imports. import sys # Local imports. -from natsort.compat.py23 import ( - PY_VERSION, - cmp_to_key, - py23_unichr, -) +from natsort.compat.py23 import PY_VERSION, cmp_to_key, py23_unichr # This string should be sorted after any other byte string because # it contains the max unicode character repeated 20 times. # You would need some odd data to come after that. -null_string = '' +null_string = "" null_string_max = py23_unichr(sys.maxunicode) * 20 # Make the strxfrm function from strcoll on Python2 @@ -29,12 +20,12 @@ try: import icu from locale import getlocale - null_string_locale = b'' + null_string_locale = b"" # This string should in theory be sorted after any other byte # string because it contains the max byte char repeated many times. # You would need some odd data to come after that. - null_string_locale_max = b'x7f' * 50 + null_string_locale_max = b"x7f" * 50 def dumb_sort(): return False @@ -42,7 +33,7 @@ try: # If using icu, get the locale from the current global locale, def get_icu_locale(): try: - return icu.Locale('.'.join(getlocale())) + return icu.Locale(".".join(getlocale())) except TypeError: # pragma: no cover return icu.Locale() @@ -57,10 +48,13 @@ try: sep = icu.DecimalFormatSymbols.kDecimalSeparatorSymbol return icu.DecimalFormatSymbols(get_icu_locale()).getSymbol(sep) + except ImportError: import locale + if PY_VERSION < 3: from locale import strcoll + sentinel = object() def custom_strcoll(a, b, last=sentinel): @@ -73,11 +67,12 @@ except ImportError: return strcoll(a, b) strxfrm = cmp_to_key(custom_strcoll) - null_string_locale = strxfrm('') + null_string_locale = strxfrm("") null_string_locale_max = strxfrm(sentinel) else: from locale import strxfrm - null_string_locale = '' + + null_string_locale = "" # This string should be sorted after any other byte string because # it contains the max unicode character repeated 20 times. @@ -87,57 +82,58 @@ except ImportError: # On some systems, locale is broken and does not sort in the expected # order. We will try to detect this and compensate. def dumb_sort(): - return strxfrm('A') < strxfrm('a') + return strxfrm("A") < strxfrm("a") def get_strxfrm(): return strxfrm def get_thousands_sep(): - sep = locale.localeconv()['thousands_sep'] + sep = locale.localeconv()["thousands_sep"] # If this locale library is broken, some of the thousands separator # characters are incorrectly blank. Here is a lookup table of the # corrections I am aware of. if dumb_sort(): try: - loc = '.'.join(locale.getlocale()) + loc = ".".join(locale.getlocale()) except TypeError: # No locale loaded, default to ',' - return ',' - return {'de_DE.ISO8859-15': '.', - 'es_ES.ISO8859-1': '.', - 'de_AT.ISO8859-1': '.', - 'de_at': '\xa0', - 'nl_NL.UTF-8': '.', - 'es_es': '.', - 'fr_CH.ISO8859-15': '\xa0', - 'fr_CA.ISO8859-1': '\xa0', - 'de_CH.ISO8859-1': '.', - 'fr_FR.ISO8859-15': '\xa0', - 'nl_NL.ISO8859-1': '.', - 'ca_ES.UTF-8': '.', - 'nl_NL.ISO8859-15': '.', - 'de_ch': "'", - 'ca_es': '.', - 'de_AT.ISO8859-15': '.', - 'ca_ES.ISO8859-1': '.', - 'de_AT.UTF-8': '.', - 'es_ES.UTF-8': '.', - 'fr_fr': '\xa0', - 'es_ES.ISO8859-15': '.', - 'de_DE.ISO8859-1': '.', - 'nl_nl': '.', - 'fr_ch': '\xa0', - 'fr_ca': '\xa0', - 'de_DE.UTF-8': '.', - 'ca_ES.ISO8859-15': '.', - 'de_CH.ISO8859-15': '.', - 'fr_FR.ISO8859-1': '\xa0', - 'fr_CH.ISO8859-1': '\xa0', - 'de_de': '.', - 'fr_FR.UTF-8': '\xa0', - 'fr_CA.ISO8859-15': '\xa0', - }.get(loc, sep) + return "," + return { + "de_DE.ISO8859-15": ".", + "es_ES.ISO8859-1": ".", + "de_AT.ISO8859-1": ".", + "de_at": "\xa0", + "nl_NL.UTF-8": ".", + "es_es": ".", + "fr_CH.ISO8859-15": "\xa0", + "fr_CA.ISO8859-1": "\xa0", + "de_CH.ISO8859-1": ".", + "fr_FR.ISO8859-15": "\xa0", + "nl_NL.ISO8859-1": ".", + "ca_ES.UTF-8": ".", + "nl_NL.ISO8859-15": ".", + "de_ch": "'", + "ca_es": ".", + "de_AT.ISO8859-15": ".", + "ca_ES.ISO8859-1": ".", + "de_AT.UTF-8": ".", + "es_ES.UTF-8": ".", + "fr_fr": "\xa0", + "es_ES.ISO8859-15": ".", + "de_DE.ISO8859-1": ".", + "nl_nl": ".", + "fr_ch": "\xa0", + "fr_ca": "\xa0", + "de_DE.UTF-8": ".", + "ca_ES.ISO8859-15": ".", + "de_CH.ISO8859-15": ".", + "fr_FR.ISO8859-1": "\xa0", + "fr_CH.ISO8859-1": "\xa0", + "de_de": ".", + "fr_FR.UTF-8": "\xa0", + "fr_CA.ISO8859-15": "\xa0", + }.get(loc, sep) else: return sep def get_decimal_point(): - return locale.localeconv()['decimal_point'] + return locale.localeconv()["decimal_point"] diff --git a/natsort/compat/pathlib.py b/natsort/compat/pathlib.py index f0ab7eb..e95e847 100644 --- a/natsort/compat/pathlib.py +++ b/natsort/compat/pathlib.py @@ -1,10 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import try: from pathlib import PurePath # PurePath is the base object for Paths. diff --git a/natsort/compat/py23.py b/natsort/compat/py23.py index fa56b06..7d1bad2 100644 --- a/natsort/compat/py23.py +++ b/natsort/compat/py23.py @@ -1,10 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import import functools import sys @@ -19,31 +14,32 @@ PY_VERSION = float(sys.version[:3]) NEWPY = PY_VERSION >= 3.3 # Assume all strings are Unicode in Python 2 -py23_str = str if sys.version[0] == '3' else unicode +py23_str = str if sys.version[0] == "3" else unicode # Use the range iterator always -py23_range = range if sys.version[0] == '3' else xrange +py23_range = range if sys.version[0] == "3" else xrange # Uniform base string type -py23_basestring = str if sys.version[0] == '3' else basestring +py23_basestring = str if sys.version[0] == "3" else basestring # unichr function -py23_unichr = chr if sys.version[0] == '3' else unichr +py23_unichr = chr if sys.version[0] == "3" else unichr def _py23_cmp(a, b): return (a > b) - (a < b) -py23_cmp = _py23_cmp if sys.version[0] == '3' else cmp +py23_cmp = _py23_cmp if sys.version[0] == "3" else cmp # zip as an iterator -if sys.version[0] == '3': +if sys.version[0] == "3": py23_zip = zip py23_map = map py23_filter = filter else: import itertools + py23_zip = itertools.izip py23_map = itertools.imap py23_filter = itertools.ifilter @@ -53,10 +49,12 @@ else: 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'] + __slots__ = ["obj"] def __init__(self, obj): self.obj = obj @@ -80,7 +78,7 @@ except ImportError: # pragma: no cover return mycmp(self.obj, other.obj) != 0 def __hash__(self): - raise TypeError('hash not implemented') + raise TypeError("hash not implemented") return K @@ -104,18 +102,21 @@ def _modify_str_or_docstring(str_change_func): func.__doc__ = doc return func return doc + return wrapper # Properly modify a doctstring to either have the unicode literal or not. -if sys.version[0] == '3': +if sys.version[0] == "3": # Abstract u'abc' syntax: @_modify_str_or_docstring def u_format(s): """"{u}'abc'" --> "'abc'" (Python 3) Accepts a string or a function, so it can be used as a decorator.""" - return s.format(u='') + return s.format(u="") + + else: # Abstract u'abc' syntax: @_modify_str_or_docstring @@ -123,4 +124,4 @@ else: """"{u}'abc'" --> "u'abc'" (Python 2) Accepts a string or a function, so it can be used as a decorator.""" - return s.format(u='u') + return s.format(u="u") diff --git a/natsort/natsort.py b/natsort/natsort.py index 557e07b..66c663e 100644 --- a/natsort/natsort.py +++ b/natsort/natsort.py @@ -10,12 +10,7 @@ descend into lists of lists so you can sort by the sublist contents. See the README or the natsort homepage for more details. """ -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import # Std lib. imports. from operator import itemgetter @@ -27,10 +22,7 @@ import sys import natsort.compat.locale from natsort.ns_enum import ns -from natsort.compat.py23 import ( - u_format, - py23_str, - py23_cmp) +from natsort.compat.py23 import u_format, py23_str, py23_cmp from natsort.utils import ( _natsort_key, _args_to_enum, @@ -113,7 +105,7 @@ def as_ascii(s): decoder """ - return _do_decoding(s, 'ascii') + return _do_decoding(s, "ascii") @u_format @@ -138,7 +130,7 @@ def as_utf8(s): decoder """ - return _do_decoding(s, 'utf-8') + return _do_decoding(s, "utf-8") def natsort_key(val, key=None, alg=0, **_kwargs): @@ -200,7 +192,7 @@ def natsort_keygen(key=None, alg=0, **_kwargs): alg = _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 {0}".format(py23_str(alg))) # Add the _DUMB option if the locale library is broken. if alg & ns.LOCALEALPHA and natsort.compat.locale.dumb_sort(): @@ -228,8 +220,7 @@ def natsort_keygen(key=None, alg=0, **_kwargs): # Create the high-level parsing functions for strings, bytes, and numbers. string_func = _parse_string_factory( - alg, sep, regex.split, - input_transform, component_transform, final_transform + alg, sep, regex.split, input_transform, component_transform, final_transform ) if alg & ns.PATH: string_func = _parse_path_factory(string_func) @@ -242,7 +233,7 @@ def natsort_keygen(key=None, alg=0, **_kwargs): key=key, string_func=string_func, bytes_func=bytes_func, - num_func=num_func + num_func=num_func, ) @@ -485,12 +476,13 @@ def index_natsorted(seq, key=None, reverse=False, alg=0, **_kwargs): if key is None: newkey = itemgetter(1) else: + def newkey(x): return key(itemgetter(1)(x)) + # Pair the index and sequence together, then sort by element index_seq_pair = [[x, y] for x, y in enumerate(seq)] - index_seq_pair.sort(reverse=reverse, - key=natsort_keygen(newkey, alg, **_kwargs)) + index_seq_pair.sort(reverse=reverse, key=natsort_keygen(newkey, alg, **_kwargs)) return [x for x, _ in index_seq_pair] @@ -726,15 +718,15 @@ if float(sys.version[:3]) < 3: >>> natcmp(one, two) -1 """ + cached_keys = {} def __new__(cls, x, y, alg=0, *args, **kwargs): try: alg = _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))) + msg = "natsort_keygen: 'alg' argument must be " "from the enum 'ns'" + raise ValueError(msg + ", got {0}".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 b3aa917..54ca133 100644 --- a/natsort/ns_enum.py +++ b/natsort/ns_enum.py @@ -1,11 +1,6 @@ # -*- coding: utf-8 -*- """This module defines the "ns" enum for natsort.""" -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import class ns(object): @@ -130,32 +125,33 @@ class ns(object): True """ + # Following were previously now options but are now defaults. - TYPESAFE = T = 0 - INT = I = 0 - VERSION = V = 0 - DIGIT = D = 0 - UNSIGNED = U = 0 + TYPESAFE = T = 0 + INT = I = 0 + VERSION = V = 0 + DIGIT = D = 0 + UNSIGNED = U = 0 # The below are options. The values are stored as powers of two # so bitmasks can be used to extract the user's requested options. - FLOAT = F = 1 << 0 - SIGNED = S = 1 << 1 - REAL = R = FLOAT | SIGNED - NOEXP = N = 1 << 2 - PATH = P = 1 << 3 - LOCALEALPHA = LA = 1 << 4 - LOCALENUM = LN = 1 << 5 - LOCALE = L = LOCALEALPHA | LOCALENUM - IGNORECASE = IC = 1 << 6 - LOWERCASEFIRST = LF = 1 << 7 - GROUPLETTERS = G = 1 << 8 - UNGROUPLETTERS = UG = 1 << 9 - CAPITALFIRST = C = UNGROUPLETTERS - NANLAST = NL = 1 << 10 + FLOAT = F = 1 << 0 + SIGNED = S = 1 << 1 + REAL = R = FLOAT | SIGNED + NOEXP = N = 1 << 2 + PATH = P = 1 << 3 + LOCALEALPHA = LA = 1 << 4 + LOCALENUM = LN = 1 << 5 + LOCALE = L = LOCALEALPHA | LOCALENUM + IGNORECASE = IC = 1 << 6 + LOWERCASEFIRST = LF = 1 << 7 + GROUPLETTERS = G = 1 << 8 + UNGROUPLETTERS = UG = 1 << 9 + CAPITALFIRST = C = UNGROUPLETTERS + NANLAST = NL = 1 << 10 COMPATIBILITYNORMALIZE = CN = 1 << 11 - NUMAFTER = NA = 1 << 12 + NUMAFTER = NA = 1 << 12 # The below are private options for internal use only. - _NUMERIC_ONLY = REAL | NOEXP - _DUMB = 1 << 31 + _NUMERIC_ONLY = REAL | NOEXP + _DUMB = 1 << 31 diff --git a/natsort/unicode_numbers.py b/natsort/unicode_numbers.py index a0ae0a5..86172df 100644 --- a/natsort/unicode_numbers.py +++ b/natsort/unicode_numbers.py @@ -2,291 +2,15 @@ """ Contains all possible non-ASCII unicode numbers. """ -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import # Std. lib imports. import unicodedata # Local imports. +from natsort.unicode_numeric_hex import numeric_hex from natsort.compat.py23 import py23_unichr - -# Rather than determine this on the fly, which would incur a startup -# runtime penalty, the hex values of the Unicode numeric characters -# are hard-coded below. -numeric_hex = ( - 0XB2, 0XB3, 0XB9, 0XBC, 0XBD, 0XBE, 0X660, 0X661, 0X662, - 0X663, 0X664, 0X665, 0X666, 0X667, 0X668, 0X669, 0X6F0, - 0X6F1, 0X6F2, 0X6F3, 0X6F4, 0X6F5, 0X6F6, 0X6F7, 0X6F8, - 0X6F9, 0X7C0, 0X7C1, 0X7C2, 0X7C3, 0X7C4, 0X7C5, 0X7C6, - 0X7C7, 0X7C8, 0X7C9, 0X966, 0X967, 0X968, 0X969, 0X96A, - 0X96B, 0X96C, 0X96D, 0X96E, 0X96F, 0X9E6, 0X9E7, 0X9E8, - 0X9E9, 0X9EA, 0X9EB, 0X9EC, 0X9ED, 0X9EE, 0X9EF, 0X9F4, - 0X9F5, 0X9F6, 0X9F7, 0X9F8, 0X9F9, 0XA66, 0XA67, 0XA68, - 0XA69, 0XA6A, 0XA6B, 0XA6C, 0XA6D, 0XA6E, 0XA6F, 0XAE6, - 0XAE7, 0XAE8, 0XAE9, 0XAEA, 0XAEB, 0XAEC, 0XAED, 0XAEE, - 0XAEF, 0XB66, 0XB67, 0XB68, 0XB69, 0XB6A, 0XB6B, 0XB6C, - 0XB6D, 0XB6E, 0XB6F, 0XB72, 0XB73, 0XB74, 0XB75, 0XB76, - 0XB77, 0XBE6, 0XBE7, 0XBE8, 0XBE9, 0XBEA, 0XBEB, 0XBEC, - 0XBED, 0XBEE, 0XBEF, 0XBF0, 0XBF1, 0XBF2, 0XC66, 0XC67, - 0XC68, 0XC69, 0XC6A, 0XC6B, 0XC6C, 0XC6D, 0XC6E, 0XC6F, - 0XC78, 0XC79, 0XC7A, 0XC7B, 0XC7C, 0XC7D, 0XC7E, 0XCE6, - 0XCE7, 0XCE8, 0XCE9, 0XCEA, 0XCEB, 0XCEC, 0XCED, 0XCEE, - 0XCEF, 0XD58, 0XD59, 0XD5A, 0XD5B, 0XD5C, 0XD5D, 0XD5E, - 0XD66, 0XD67, 0XD68, 0XD69, 0XD6A, 0XD6B, 0XD6C, 0XD6D, - 0XD6E, 0XD6F, 0XD70, 0XD71, 0XD72, 0XD73, 0XD74, 0XD75, - 0XD76, 0XD77, 0XD78, 0XDE6, 0XDE7, 0XDE8, 0XDE9, 0XDEA, - 0XDEB, 0XDEC, 0XDED, 0XDEE, 0XDEF, 0XE50, 0XE51, 0XE52, - 0XE53, 0XE54, 0XE55, 0XE56, 0XE57, 0XE58, 0XE59, 0XED0, - 0XED1, 0XED2, 0XED3, 0XED4, 0XED5, 0XED6, 0XED7, 0XED8, - 0XED9, 0XF20, 0XF21, 0XF22, 0XF23, 0XF24, 0XF25, 0XF26, - 0XF27, 0XF28, 0XF29, 0XF2A, 0XF2B, 0XF2C, 0XF2D, 0XF2E, - 0XF2F, 0XF30, 0XF31, 0XF32, 0XF33, 0X1040, 0X1041, 0X1042, - 0X1043, 0X1044, 0X1045, 0X1046, 0X1047, 0X1048, 0X1049, - 0X1090, 0X1091, 0X1092, 0X1093, 0X1094, 0X1095, 0X1096, - 0X1097, 0X1098, 0X1099, 0X1369, 0X136A, 0X136B, 0X136C, - 0X136D, 0X136E, 0X136F, 0X1370, 0X1371, 0X1372, 0X1373, - 0X1374, 0X1375, 0X1376, 0X1377, 0X1378, 0X1379, 0X137A, - 0X137B, 0X137C, 0X16EE, 0X16EF, 0X16F0, 0X17E0, 0X17E1, - 0X17E2, 0X17E3, 0X17E4, 0X17E5, 0X17E6, 0X17E7, 0X17E8, - 0X17E9, 0X17F0, 0X17F1, 0X17F2, 0X17F3, 0X17F4, 0X17F5, - 0X17F6, 0X17F7, 0X17F8, 0X17F9, 0X1810, 0X1811, 0X1812, - 0X1813, 0X1814, 0X1815, 0X1816, 0X1817, 0X1818, 0X1819, - 0X1946, 0X1947, 0X1948, 0X1949, 0X194A, 0X194B, 0X194C, - 0X194D, 0X194E, 0X194F, 0X19D0, 0X19D1, 0X19D2, 0X19D3, - 0X19D4, 0X19D5, 0X19D6, 0X19D7, 0X19D8, 0X19D9, 0X19DA, - 0X1A80, 0X1A81, 0X1A82, 0X1A83, 0X1A84, 0X1A85, 0X1A86, - 0X1A87, 0X1A88, 0X1A89, 0X1A90, 0X1A91, 0X1A92, 0X1A93, - 0X1A94, 0X1A95, 0X1A96, 0X1A97, 0X1A98, 0X1A99, 0X1B50, - 0X1B51, 0X1B52, 0X1B53, 0X1B54, 0X1B55, 0X1B56, 0X1B57, - 0X1B58, 0X1B59, 0X1BB0, 0X1BB1, 0X1BB2, 0X1BB3, 0X1BB4, - 0X1BB5, 0X1BB6, 0X1BB7, 0X1BB8, 0X1BB9, 0X1C40, 0X1C41, - 0X1C42, 0X1C43, 0X1C44, 0X1C45, 0X1C46, 0X1C47, 0X1C48, - 0X1C49, 0X1C50, 0X1C51, 0X1C52, 0X1C53, 0X1C54, 0X1C55, - 0X1C56, 0X1C57, 0X1C58, 0X1C59, 0X2070, 0X2074, 0X2075, - 0X2076, 0X2077, 0X2078, 0X2079, 0X2080, 0X2081, 0X2082, - 0X2083, 0X2084, 0X2085, 0X2086, 0X2087, 0X2088, 0X2089, - 0X2150, 0X2151, 0X2152, 0X2153, 0X2154, 0X2155, 0X2156, - 0X2157, 0X2158, 0X2159, 0X215A, 0X215B, 0X215C, 0X215D, - 0X215E, 0X215F, 0X2160, 0X2161, 0X2162, 0X2163, 0X2164, - 0X2165, 0X2166, 0X2167, 0X2168, 0X2169, 0X216A, 0X216B, - 0X216C, 0X216D, 0X216E, 0X216F, 0X2170, 0X2171, 0X2172, - 0X2173, 0X2174, 0X2175, 0X2176, 0X2177, 0X2178, 0X2179, - 0X217A, 0X217B, 0X217C, 0X217D, 0X217E, 0X217F, 0X2180, - 0X2181, 0X2182, 0X2185, 0X2186, 0X2187, 0X2188, 0X2189, - 0X2460, 0X2461, 0X2462, 0X2463, 0X2464, 0X2465, 0X2466, - 0X2467, 0X2468, 0X2469, 0X246A, 0X246B, 0X246C, 0X246D, - 0X246E, 0X246F, 0X2470, 0X2471, 0X2472, 0X2473, 0X2474, - 0X2475, 0X2476, 0X2477, 0X2478, 0X2479, 0X247A, 0X247B, - 0X247C, 0X247D, 0X247E, 0X247F, 0X2480, 0X2481, 0X2482, - 0X2483, 0X2484, 0X2485, 0X2486, 0X2487, 0X2488, 0X2489, - 0X248A, 0X248B, 0X248C, 0X248D, 0X248E, 0X248F, 0X2490, - 0X2491, 0X2492, 0X2493, 0X2494, 0X2495, 0X2496, 0X2497, - 0X2498, 0X2499, 0X249A, 0X249B, 0X24EA, 0X24EB, 0X24EC, - 0X24ED, 0X24EE, 0X24EF, 0X24F0, 0X24F1, 0X24F2, 0X24F3, - 0X24F4, 0X24F5, 0X24F6, 0X24F7, 0X24F8, 0X24F9, 0X24FA, - 0X24FB, 0X24FC, 0X24FD, 0X24FE, 0X24FF, 0X2776, 0X2777, - 0X2778, 0X2779, 0X277A, 0X277B, 0X277C, 0X277D, 0X277E, - 0X277F, 0X2780, 0X2781, 0X2782, 0X2783, 0X2784, 0X2785, - 0X2786, 0X2787, 0X2788, 0X2789, 0X278A, 0X278B, 0X278C, - 0X278D, 0X278E, 0X278F, 0X2790, 0X2791, 0X2792, 0X2793, - 0X2CFD, 0X3007, 0X3021, 0X3022, 0X3023, 0X3024, 0X3025, - 0X3026, 0X3027, 0X3028, 0X3029, 0X3038, 0X3039, 0X303A, - 0X3192, 0X3193, 0X3194, 0X3195, 0X3220, 0X3221, 0X3222, - 0X3223, 0X3224, 0X3225, 0X3226, 0X3227, 0X3228, 0X3229, - 0X3248, 0X3249, 0X324A, 0X324B, 0X324C, 0X324D, 0X324E, - 0X324F, 0X3251, 0X3252, 0X3253, 0X3254, 0X3255, 0X3256, - 0X3257, 0X3258, 0X3259, 0X325A, 0X325B, 0X325C, 0X325D, - 0X325E, 0X325F, 0X3280, 0X3281, 0X3282, 0X3283, 0X3284, - 0X3285, 0X3286, 0X3287, 0X3288, 0X3289, 0X32B1, 0X32B2, - 0X32B3, 0X32B4, 0X32B5, 0X32B6, 0X32B7, 0X32B8, 0X32B9, - 0X32BA, 0X32BB, 0X32BC, 0X32BD, 0X32BE, 0X32BF, 0X3405, - 0X3483, 0X382A, 0X3B4D, 0X4E00, 0X4E03, 0X4E07, 0X4E09, - 0X4E5D, 0X4E8C, 0X4E94, 0X4E96, 0X4EBF, 0X4EC0, 0X4EDF, - 0X4EE8, 0X4F0D, 0X4F70, 0X5104, 0X5146, 0X5169, 0X516B, - 0X516D, 0X5341, 0X5343, 0X5344, 0X5345, 0X534C, 0X53C1, - 0X53C2, 0X53C3, 0X53C4, 0X56DB, 0X58F1, 0X58F9, 0X5E7A, - 0X5EFE, 0X5EFF, 0X5F0C, 0X5F0D, 0X5F0E, 0X5F10, 0X62FE, - 0X634C, 0X67D2, 0X6F06, 0X7396, 0X767E, 0X8086, 0X842C, - 0X8CAE, 0X8CB3, 0X8D30, 0X9621, 0X9646, 0X964C, 0X9678, - 0X96F6, 0XA620, 0XA621, 0XA622, 0XA623, 0XA624, 0XA625, - 0XA626, 0XA627, 0XA628, 0XA629, 0XA6E6, 0XA6E7, 0XA6E8, - 0XA6E9, 0XA6EA, 0XA6EB, 0XA6EC, 0XA6ED, 0XA6EE, 0XA6EF, - 0XA830, 0XA831, 0XA832, 0XA833, 0XA834, 0XA835, 0XA8D0, - 0XA8D1, 0XA8D2, 0XA8D3, 0XA8D4, 0XA8D5, 0XA8D6, 0XA8D7, - 0XA8D8, 0XA8D9, 0XA900, 0XA901, 0XA902, 0XA903, 0XA904, - 0XA905, 0XA906, 0XA907, 0XA908, 0XA909, 0XA9D0, 0XA9D1, - 0XA9D2, 0XA9D3, 0XA9D4, 0XA9D5, 0XA9D6, 0XA9D7, 0XA9D8, - 0XA9D9, 0XA9F0, 0XA9F1, 0XA9F2, 0XA9F3, 0XA9F4, 0XA9F5, - 0XA9F6, 0XA9F7, 0XA9F8, 0XA9F9, 0XAA50, 0XAA51, 0XAA52, - 0XAA53, 0XAA54, 0XAA55, 0XAA56, 0XAA57, 0XAA58, 0XAA59, - 0XABF0, 0XABF1, 0XABF2, 0XABF3, 0XABF4, 0XABF5, 0XABF6, - 0XABF7, 0XABF8, 0XABF9, 0XF96B, 0XF973, 0XF978, 0XF9B2, - 0XF9D1, 0XF9D3, 0XF9FD, 0XFF10, 0XFF11, 0XFF12, 0XFF13, - 0XFF14, 0XFF15, 0XFF16, 0XFF17, 0XFF18, 0XFF19, 0X10107, - 0X10108, 0X10109, 0X1010A, 0X1010B, 0X1010C, 0X1010D, - 0X1010E, 0X1010F, 0X10110, 0X10111, 0X10112, 0X10113, - 0X10114, 0X10115, 0X10116, 0X10117, 0X10118, 0X10119, - 0X1011A, 0X1011B, 0X1011C, 0X1011D, 0X1011E, 0X1011F, - 0X10120, 0X10121, 0X10122, 0X10123, 0X10124, 0X10125, - 0X10126, 0X10127, 0X10128, 0X10129, 0X1012A, 0X1012B, - 0X1012C, 0X1012D, 0X1012E, 0X1012F, 0X10130, 0X10131, - 0X10132, 0X10133, 0X10140, 0X10141, 0X10142, 0X10143, - 0X10144, 0X10145, 0X10146, 0X10147, 0X10148, 0X10149, - 0X1014A, 0X1014B, 0X1014C, 0X1014D, 0X1014E, 0X1014F, - 0X10150, 0X10151, 0X10152, 0X10153, 0X10154, 0X10155, - 0X10156, 0X10157, 0X10158, 0X10159, 0X1015A, 0X1015B, - 0X1015C, 0X1015D, 0X1015E, 0X1015F, 0X10160, 0X10161, - 0X10162, 0X10163, 0X10164, 0X10165, 0X10166, 0X10167, - 0X10168, 0X10169, 0X1016A, 0X1016B, 0X1016C, 0X1016D, - 0X1016E, 0X1016F, 0X10170, 0X10171, 0X10172, 0X10173, - 0X10174, 0X10175, 0X10176, 0X10177, 0X10178, 0X1018A, - 0X1018B, 0X102E1, 0X102E2, 0X102E3, 0X102E4, 0X102E5, - 0X102E6, 0X102E7, 0X102E8, 0X102E9, 0X102EA, 0X102EB, - 0X102EC, 0X102ED, 0X102EE, 0X102EF, 0X102F0, 0X102F1, - 0X102F2, 0X102F3, 0X102F4, 0X102F5, 0X102F6, 0X102F7, - 0X102F8, 0X102F9, 0X102FA, 0X102FB, 0X10320, 0X10321, - 0X10322, 0X10323, 0X10341, 0X1034A, 0X103D1, 0X103D2, - 0X103D3, 0X103D4, 0X103D5, 0X104A0, 0X104A1, 0X104A2, - 0X104A3, 0X104A4, 0X104A5, 0X104A6, 0X104A7, 0X104A8, - 0X104A9, 0X10858, 0X10859, 0X1085A, 0X1085B, 0X1085C, - 0X1085D, 0X1085E, 0X1085F, 0X10879, 0X1087A, 0X1087B, - 0X1087C, 0X1087D, 0X1087E, 0X1087F, 0X108A7, 0X108A8, - 0X108A9, 0X108AA, 0X108AB, 0X108AC, 0X108AD, 0X108AE, - 0X108AF, 0X108FB, 0X108FC, 0X108FD, 0X108FE, 0X108FF, - 0X10916, 0X10917, 0X10918, 0X10919, 0X1091A, 0X1091B, - 0X109BC, 0X109BD, 0X109C0, 0X109C1, 0X109C2, 0X109C3, - 0X109C4, 0X109C5, 0X109C6, 0X109C7, 0X109C8, 0X109C9, - 0X109CA, 0X109CB, 0X109CC, 0X109CD, 0X109CE, 0X109CF, - 0X109D2, 0X109D3, 0X109D4, 0X109D5, 0X109D6, 0X109D7, - 0X109D8, 0X109D9, 0X109DA, 0X109DB, 0X109DC, 0X109DD, - 0X109DE, 0X109DF, 0X109E0, 0X109E1, 0X109E2, 0X109E3, - 0X109E4, 0X109E5, 0X109E6, 0X109E7, 0X109E8, 0X109E9, - 0X109EA, 0X109EB, 0X109EC, 0X109ED, 0X109EE, 0X109EF, - 0X109F0, 0X109F1, 0X109F2, 0X109F3, 0X109F4, 0X109F5, - 0X109F6, 0X109F7, 0X109F8, 0X109F9, 0X109FA, 0X109FB, - 0X109FC, 0X109FD, 0X109FE, 0X109FF, 0X10A40, 0X10A41, - 0X10A42, 0X10A43, 0X10A44, 0X10A45, 0X10A46, 0X10A47, - 0X10A48, 0X10A7D, 0X10A7E, 0X10A9D, 0X10A9E, 0X10A9F, - 0X10AEB, 0X10AEC, 0X10AED, 0X10AEE, 0X10AEF, 0X10B58, - 0X10B59, 0X10B5A, 0X10B5B, 0X10B5C, 0X10B5D, 0X10B5E, - 0X10B5F, 0X10B78, 0X10B79, 0X10B7A, 0X10B7B, 0X10B7C, - 0X10B7D, 0X10B7E, 0X10B7F, 0X10BA9, 0X10BAA, 0X10BAB, - 0X10BAC, 0X10BAD, 0X10BAE, 0X10BAF, 0X10CFA, 0X10CFB, - 0X10CFC, 0X10CFD, 0X10CFE, 0X10CFF, 0X10D30, 0X10D31, - 0X10D32, 0X10D33, 0X10D34, 0X10D35, 0X10D36, 0X10D37, - 0X10D38, 0X10D39, 0X10E60, 0X10E61, 0X10E62, 0X10E63, - 0X10E64, 0X10E65, 0X10E66, 0X10E67, 0X10E68, 0X10E69, - 0X10E6A, 0X10E6B, 0X10E6C, 0X10E6D, 0X10E6E, 0X10E6F, - 0X10E70, 0X10E71, 0X10E72, 0X10E73, 0X10E74, 0X10E75, - 0X10E76, 0X10E77, 0X10E78, 0X10E79, 0X10E7A, 0X10E7B, - 0X10E7C, 0X10E7D, 0X10E7E, 0X10F1D, 0X10F1E, 0X10F1F, - 0X10F20, 0X10F21, 0X10F22, 0X10F23, 0X10F24, 0X10F25, - 0X10F26, 0X10F51, 0X10F52, 0X10F53, 0X10F54, 0X11052, - 0X11053, 0X11054, 0X11055, 0X11056, 0X11057, 0X11058, - 0X11059, 0X1105A, 0X1105B, 0X1105C, 0X1105D, 0X1105E, - 0X1105F, 0X11060, 0X11061, 0X11062, 0X11063, 0X11064, - 0X11065, 0X11066, 0X11067, 0X11068, 0X11069, 0X1106A, - 0X1106B, 0X1106C, 0X1106D, 0X1106E, 0X1106F, 0X110F0, - 0X110F1, 0X110F2, 0X110F3, 0X110F4, 0X110F5, 0X110F6, - 0X110F7, 0X110F8, 0X110F9, 0X11136, 0X11137, 0X11138, - 0X11139, 0X1113A, 0X1113B, 0X1113C, 0X1113D, 0X1113E, - 0X1113F, 0X111D0, 0X111D1, 0X111D2, 0X111D3, 0X111D4, - 0X111D5, 0X111D6, 0X111D7, 0X111D8, 0X111D9, 0X111E1, - 0X111E2, 0X111E3, 0X111E4, 0X111E5, 0X111E6, 0X111E7, - 0X111E8, 0X111E9, 0X111EA, 0X111EB, 0X111EC, 0X111ED, - 0X111EE, 0X111EF, 0X111F0, 0X111F1, 0X111F2, 0X111F3, - 0X111F4, 0X112F0, 0X112F1, 0X112F2, 0X112F3, 0X112F4, - 0X112F5, 0X112F6, 0X112F7, 0X112F8, 0X112F9, 0X11450, - 0X11451, 0X11452, 0X11453, 0X11454, 0X11455, 0X11456, - 0X11457, 0X11458, 0X11459, 0X114D0, 0X114D1, 0X114D2, - 0X114D3, 0X114D4, 0X114D5, 0X114D6, 0X114D7, 0X114D8, - 0X114D9, 0X11650, 0X11651, 0X11652, 0X11653, 0X11654, - 0X11655, 0X11656, 0X11657, 0X11658, 0X11659, 0X116C0, - 0X116C1, 0X116C2, 0X116C3, 0X116C4, 0X116C5, 0X116C6, - 0X116C7, 0X116C8, 0X116C9, 0X11730, 0X11731, 0X11732, - 0X11733, 0X11734, 0X11735, 0X11736, 0X11737, 0X11738, - 0X11739, 0X1173A, 0X1173B, 0X118E0, 0X118E1, 0X118E2, - 0X118E3, 0X118E4, 0X118E5, 0X118E6, 0X118E7, 0X118E8, - 0X118E9, 0X118EA, 0X118EB, 0X118EC, 0X118ED, 0X118EE, - 0X118EF, 0X118F0, 0X118F1, 0X118F2, 0X11C50, 0X11C51, - 0X11C52, 0X11C53, 0X11C54, 0X11C55, 0X11C56, 0X11C57, - 0X11C58, 0X11C59, 0X11C5A, 0X11C5B, 0X11C5C, 0X11C5D, - 0X11C5E, 0X11C5F, 0X11C60, 0X11C61, 0X11C62, 0X11C63, - 0X11C64, 0X11C65, 0X11C66, 0X11C67, 0X11C68, 0X11C69, - 0X11C6A, 0X11C6B, 0X11C6C, 0X11D50, 0X11D51, 0X11D52, - 0X11D53, 0X11D54, 0X11D55, 0X11D56, 0X11D57, 0X11D58, - 0X11D59, 0X11DA0, 0X11DA1, 0X11DA2, 0X11DA3, 0X11DA4, - 0X11DA5, 0X11DA6, 0X11DA7, 0X11DA8, 0X11DA9, 0X12400, - 0X12401, 0X12402, 0X12403, 0X12404, 0X12405, 0X12406, - 0X12407, 0X12408, 0X12409, 0X1240A, 0X1240B, 0X1240C, - 0X1240D, 0X1240E, 0X1240F, 0X12410, 0X12411, 0X12412, - 0X12413, 0X12414, 0X12415, 0X12416, 0X12417, 0X12418, - 0X12419, 0X1241A, 0X1241B, 0X1241C, 0X1241D, 0X1241E, - 0X1241F, 0X12420, 0X12421, 0X12422, 0X12423, 0X12424, - 0X12425, 0X12426, 0X12427, 0X12428, 0X12429, 0X1242A, - 0X1242B, 0X1242C, 0X1242D, 0X1242E, 0X1242F, 0X12430, - 0X12431, 0X12432, 0X12433, 0X12434, 0X12435, 0X12436, - 0X12437, 0X12438, 0X12439, 0X1243A, 0X1243B, 0X1243C, - 0X1243D, 0X1243E, 0X1243F, 0X12440, 0X12441, 0X12442, - 0X12443, 0X12444, 0X12445, 0X12446, 0X12447, 0X12448, - 0X12449, 0X1244A, 0X1244B, 0X1244C, 0X1244D, 0X1244E, - 0X1244F, 0X12450, 0X12451, 0X12452, 0X12453, 0X12454, - 0X12455, 0X12456, 0X12457, 0X12458, 0X12459, 0X1245A, - 0X1245B, 0X1245C, 0X1245D, 0X1245E, 0X1245F, 0X12460, - 0X12461, 0X12462, 0X12463, 0X12464, 0X12465, 0X12466, - 0X12467, 0X12468, 0X12469, 0X1246A, 0X1246B, 0X1246C, - 0X1246D, 0X1246E, 0X16A60, 0X16A61, 0X16A62, 0X16A63, - 0X16A64, 0X16A65, 0X16A66, 0X16A67, 0X16A68, 0X16A69, - 0X16B50, 0X16B51, 0X16B52, 0X16B53, 0X16B54, 0X16B55, - 0X16B56, 0X16B57, 0X16B58, 0X16B59, 0X16B5B, 0X16B5C, - 0X16B5D, 0X16B5E, 0X16B5F, 0X16B60, 0X16B61, 0X16E80, - 0X16E81, 0X16E82, 0X16E83, 0X16E84, 0X16E85, 0X16E86, - 0X16E87, 0X16E88, 0X16E89, 0X16E8A, 0X16E8B, 0X16E8C, - 0X16E8D, 0X16E8E, 0X16E8F, 0X16E90, 0X16E91, 0X16E92, - 0X16E93, 0X16E94, 0X16E95, 0X16E96, 0X1D2E0, 0X1D2E1, - 0X1D2E2, 0X1D2E3, 0X1D2E4, 0X1D2E5, 0X1D2E6, 0X1D2E7, - 0X1D2E8, 0X1D2E9, 0X1D2EA, 0X1D2EB, 0X1D2EC, 0X1D2ED, - 0X1D2EE, 0X1D2EF, 0X1D2F0, 0X1D2F1, 0X1D2F2, 0X1D2F3, - 0X1D360, 0X1D361, 0X1D362, 0X1D363, 0X1D364, 0X1D365, - 0X1D366, 0X1D367, 0X1D368, 0X1D369, 0X1D36A, 0X1D36B, - 0X1D36C, 0X1D36D, 0X1D36E, 0X1D36F, 0X1D370, 0X1D371, - 0X1D372, 0X1D373, 0X1D374, 0X1D375, 0X1D376, 0X1D377, - 0X1D378, 0X1D7CE, 0X1D7CF, 0X1D7D0, 0X1D7D1, 0X1D7D2, - 0X1D7D3, 0X1D7D4, 0X1D7D5, 0X1D7D6, 0X1D7D7, 0X1D7D8, - 0X1D7D9, 0X1D7DA, 0X1D7DB, 0X1D7DC, 0X1D7DD, 0X1D7DE, - 0X1D7DF, 0X1D7E0, 0X1D7E1, 0X1D7E2, 0X1D7E3, 0X1D7E4, - 0X1D7E5, 0X1D7E6, 0X1D7E7, 0X1D7E8, 0X1D7E9, 0X1D7EA, - 0X1D7EB, 0X1D7EC, 0X1D7ED, 0X1D7EE, 0X1D7EF, 0X1D7F0, - 0X1D7F1, 0X1D7F2, 0X1D7F3, 0X1D7F4, 0X1D7F5, 0X1D7F6, - 0X1D7F7, 0X1D7F8, 0X1D7F9, 0X1D7FA, 0X1D7FB, 0X1D7FC, - 0X1D7FD, 0X1D7FE, 0X1D7FF, 0X1E8C7, 0X1E8C8, 0X1E8C9, - 0X1E8CA, 0X1E8CB, 0X1E8CC, 0X1E8CD, 0X1E8CE, 0X1E8CF, - 0X1E950, 0X1E951, 0X1E952, 0X1E953, 0X1E954, 0X1E955, - 0X1E956, 0X1E957, 0X1E958, 0X1E959, 0X1EC71, 0X1EC72, - 0X1EC73, 0X1EC74, 0X1EC75, 0X1EC76, 0X1EC77, 0X1EC78, - 0X1EC79, 0X1EC7A, 0X1EC7B, 0X1EC7C, 0X1EC7D, 0X1EC7E, - 0X1EC7F, 0X1EC80, 0X1EC81, 0X1EC82, 0X1EC83, 0X1EC84, - 0X1EC85, 0X1EC86, 0X1EC87, 0X1EC88, 0X1EC89, 0X1EC8A, - 0X1EC8B, 0X1EC8C, 0X1EC8D, 0X1EC8E, 0X1EC8F, 0X1EC90, - 0X1EC91, 0X1EC92, 0X1EC93, 0X1EC94, 0X1EC95, 0X1EC96, - 0X1EC97, 0X1EC98, 0X1EC99, 0X1EC9A, 0X1EC9B, 0X1EC9C, - 0X1EC9D, 0X1EC9E, 0X1EC9F, 0X1ECA0, 0X1ECA1, 0X1ECA2, - 0X1ECA3, 0X1ECA4, 0X1ECA5, 0X1ECA6, 0X1ECA7, 0X1ECA8, - 0X1ECA9, 0X1ECAA, 0X1ECAB, 0X1ECAD, 0X1ECAE, 0X1ECAF, - 0X1ECB1, 0X1ECB2, 0X1ECB3, 0X1ECB4, 0X1F100, 0X1F101, - 0X1F102, 0X1F103, 0X1F104, 0X1F105, 0X1F106, 0X1F107, - 0X1F108, 0X1F109, 0X1F10A, 0X1F10B, 0X1F10C, 0X20001, - 0X20064, 0X200E2, 0X20121, 0X2092A, 0X20983, 0X2098C, - 0X2099C, 0X20AEA, 0X20AFD, 0X20B19, 0X22390, 0X22998, - 0X23B1B, 0X2626D, 0X2F890, -) - # Convert each hex into the literal Unicode character. # Stop if a ValueError is raised in case of a narrow Unicode build. # The extra check with unicodedata is in case this Python version @@ -294,45 +18,23 @@ numeric_hex = ( numeric_chars = [] for a in numeric_hex: try: - l = py23_unichr(a) + character = py23_unichr(a) except ValueError: # pragma: no cover break - if unicodedata.numeric(l, None) is None: + if unicodedata.numeric(character, None) is None: continue # pragma: no cover - numeric_chars.append(l) + numeric_chars.append(character) # The digit characters are a subset of the numerals. -digit_chars = [a for a in numeric_chars - if unicodedata.digit(a, None) is not None] +digit_chars = [a for a in numeric_chars if unicodedata.digit(a, None) is not None] # The decimal characters are a subset of the numberals # (probably of the digits, but let's be safe). -decimal_chars = [a for a in numeric_chars - if unicodedata.decimal(a, None) is not None] +decimal_chars = [a for a in numeric_chars if unicodedata.decimal(a, None) is not None] # Create a single string with the above data. -decimals = ''.join(decimal_chars) -digits = ''.join(digit_chars) -numeric = ''.join(numeric_chars) -digits_no_decimals = ''.join([x for x in digits if x not in decimals]) -numeric_no_decimals = ''.join([x for x in numeric if x not in decimals]) - -# Some code that can be used to create the above list of hex numbers. -if __name__ == '__main__': - import textwrap - from natsort.compat.py23 import py23_range - - hex_chars = [] - for i in py23_range(0X110000): - try: - a = py23_unichr(i) - except ValueError: - break - if a in set('0123456789'): - continue - if unicodedata.numeric(a, None) is not None: - hex_chars.append(i) - - hex_string = ', '.join(['0X{:X}'.format(i) for i in hex_chars]) - for line in textwrap.wrap(hex_string, width=60): - print(' ', line) +decimals = "".join(decimal_chars) +digits = "".join(digit_chars) +numeric = "".join(numeric_chars) +digits_no_decimals = "".join([x for x in digits if x not in decimals]) +numeric_no_decimals = "".join([x for x in numeric if x not in decimals]) diff --git a/natsort/unicode_numeric_hex.py b/natsort/unicode_numeric_hex.py new file mode 100644 index 0000000..0a74144 --- /dev/null +++ b/natsort/unicode_numeric_hex.py @@ -0,0 +1,1750 @@ +# -*- coding: utf-8 -*- +""" +Rather than determine what unicode characters are numeric on the fly which +would incur a startup runtime penalty, the hex values are hard-coded below. +""" + +numeric_hex = ( + 0XB2, + 0XB3, + 0XB9, + 0XBC, + 0XBD, + 0XBE, + 0X660, + 0X661, + 0X662, + 0X663, + 0X664, + 0X665, + 0X666, + 0X667, + 0X668, + 0X669, + 0X6F0, + 0X6F1, + 0X6F2, + 0X6F3, + 0X6F4, + 0X6F5, + 0X6F6, + 0X6F7, + 0X6F8, + 0X6F9, + 0X7C0, + 0X7C1, + 0X7C2, + 0X7C3, + 0X7C4, + 0X7C5, + 0X7C6, + 0X7C7, + 0X7C8, + 0X7C9, + 0X966, + 0X967, + 0X968, + 0X969, + 0X96A, + 0X96B, + 0X96C, + 0X96D, + 0X96E, + 0X96F, + 0X9E6, + 0X9E7, + 0X9E8, + 0X9E9, + 0X9EA, + 0X9EB, + 0X9EC, + 0X9ED, + 0X9EE, + 0X9EF, + 0X9F4, + 0X9F5, + 0X9F6, + 0X9F7, + 0X9F8, + 0X9F9, + 0XA66, + 0XA67, + 0XA68, + 0XA69, + 0XA6A, + 0XA6B, + 0XA6C, + 0XA6D, + 0XA6E, + 0XA6F, + 0XAE6, + 0XAE7, + 0XAE8, + 0XAE9, + 0XAEA, + 0XAEB, + 0XAEC, + 0XAED, + 0XAEE, + 0XAEF, + 0XB66, + 0XB67, + 0XB68, + 0XB69, + 0XB6A, + 0XB6B, + 0XB6C, + 0XB6D, + 0XB6E, + 0XB6F, + 0XB72, + 0XB73, + 0XB74, + 0XB75, + 0XB76, + 0XB77, + 0XBE6, + 0XBE7, + 0XBE8, + 0XBE9, + 0XBEA, + 0XBEB, + 0XBEC, + 0XBED, + 0XBEE, + 0XBEF, + 0XBF0, + 0XBF1, + 0XBF2, + 0XC66, + 0XC67, + 0XC68, + 0XC69, + 0XC6A, + 0XC6B, + 0XC6C, + 0XC6D, + 0XC6E, + 0XC6F, + 0XC78, + 0XC79, + 0XC7A, + 0XC7B, + 0XC7C, + 0XC7D, + 0XC7E, + 0XCE6, + 0XCE7, + 0XCE8, + 0XCE9, + 0XCEA, + 0XCEB, + 0XCEC, + 0XCED, + 0XCEE, + 0XCEF, + 0XD58, + 0XD59, + 0XD5A, + 0XD5B, + 0XD5C, + 0XD5D, + 0XD5E, + 0XD66, + 0XD67, + 0XD68, + 0XD69, + 0XD6A, + 0XD6B, + 0XD6C, + 0XD6D, + 0XD6E, + 0XD6F, + 0XD70, + 0XD71, + 0XD72, + 0XD73, + 0XD74, + 0XD75, + 0XD76, + 0XD77, + 0XD78, + 0XDE6, + 0XDE7, + 0XDE8, + 0XDE9, + 0XDEA, + 0XDEB, + 0XDEC, + 0XDED, + 0XDEE, + 0XDEF, + 0XE50, + 0XE51, + 0XE52, + 0XE53, + 0XE54, + 0XE55, + 0XE56, + 0XE57, + 0XE58, + 0XE59, + 0XED0, + 0XED1, + 0XED2, + 0XED3, + 0XED4, + 0XED5, + 0XED6, + 0XED7, + 0XED8, + 0XED9, + 0XF20, + 0XF21, + 0XF22, + 0XF23, + 0XF24, + 0XF25, + 0XF26, + 0XF27, + 0XF28, + 0XF29, + 0XF2A, + 0XF2B, + 0XF2C, + 0XF2D, + 0XF2E, + 0XF2F, + 0XF30, + 0XF31, + 0XF32, + 0XF33, + 0X1040, + 0X1041, + 0X1042, + 0X1043, + 0X1044, + 0X1045, + 0X1046, + 0X1047, + 0X1048, + 0X1049, + 0X1090, + 0X1091, + 0X1092, + 0X1093, + 0X1094, + 0X1095, + 0X1096, + 0X1097, + 0X1098, + 0X1099, + 0X1369, + 0X136A, + 0X136B, + 0X136C, + 0X136D, + 0X136E, + 0X136F, + 0X1370, + 0X1371, + 0X1372, + 0X1373, + 0X1374, + 0X1375, + 0X1376, + 0X1377, + 0X1378, + 0X1379, + 0X137A, + 0X137B, + 0X137C, + 0X16EE, + 0X16EF, + 0X16F0, + 0X17E0, + 0X17E1, + 0X17E2, + 0X17E3, + 0X17E4, + 0X17E5, + 0X17E6, + 0X17E7, + 0X17E8, + 0X17E9, + 0X17F0, + 0X17F1, + 0X17F2, + 0X17F3, + 0X17F4, + 0X17F5, + 0X17F6, + 0X17F7, + 0X17F8, + 0X17F9, + 0X1810, + 0X1811, + 0X1812, + 0X1813, + 0X1814, + 0X1815, + 0X1816, + 0X1817, + 0X1818, + 0X1819, + 0X1946, + 0X1947, + 0X1948, + 0X1949, + 0X194A, + 0X194B, + 0X194C, + 0X194D, + 0X194E, + 0X194F, + 0X19D0, + 0X19D1, + 0X19D2, + 0X19D3, + 0X19D4, + 0X19D5, + 0X19D6, + 0X19D7, + 0X19D8, + 0X19D9, + 0X19DA, + 0X1A80, + 0X1A81, + 0X1A82, + 0X1A83, + 0X1A84, + 0X1A85, + 0X1A86, + 0X1A87, + 0X1A88, + 0X1A89, + 0X1A90, + 0X1A91, + 0X1A92, + 0X1A93, + 0X1A94, + 0X1A95, + 0X1A96, + 0X1A97, + 0X1A98, + 0X1A99, + 0X1B50, + 0X1B51, + 0X1B52, + 0X1B53, + 0X1B54, + 0X1B55, + 0X1B56, + 0X1B57, + 0X1B58, + 0X1B59, + 0X1BB0, + 0X1BB1, + 0X1BB2, + 0X1BB3, + 0X1BB4, + 0X1BB5, + 0X1BB6, + 0X1BB7, + 0X1BB8, + 0X1BB9, + 0X1C40, + 0X1C41, + 0X1C42, + 0X1C43, + 0X1C44, + 0X1C45, + 0X1C46, + 0X1C47, + 0X1C48, + 0X1C49, + 0X1C50, + 0X1C51, + 0X1C52, + 0X1C53, + 0X1C54, + 0X1C55, + 0X1C56, + 0X1C57, + 0X1C58, + 0X1C59, + 0X2070, + 0X2074, + 0X2075, + 0X2076, + 0X2077, + 0X2078, + 0X2079, + 0X2080, + 0X2081, + 0X2082, + 0X2083, + 0X2084, + 0X2085, + 0X2086, + 0X2087, + 0X2088, + 0X2089, + 0X2150, + 0X2151, + 0X2152, + 0X2153, + 0X2154, + 0X2155, + 0X2156, + 0X2157, + 0X2158, + 0X2159, + 0X215A, + 0X215B, + 0X215C, + 0X215D, + 0X215E, + 0X215F, + 0X2160, + 0X2161, + 0X2162, + 0X2163, + 0X2164, + 0X2165, + 0X2166, + 0X2167, + 0X2168, + 0X2169, + 0X216A, + 0X216B, + 0X216C, + 0X216D, + 0X216E, + 0X216F, + 0X2170, + 0X2171, + 0X2172, + 0X2173, + 0X2174, + 0X2175, + 0X2176, + 0X2177, + 0X2178, + 0X2179, + 0X217A, + 0X217B, + 0X217C, + 0X217D, + 0X217E, + 0X217F, + 0X2180, + 0X2181, + 0X2182, + 0X2185, + 0X2186, + 0X2187, + 0X2188, + 0X2189, + 0X2460, + 0X2461, + 0X2462, + 0X2463, + 0X2464, + 0X2465, + 0X2466, + 0X2467, + 0X2468, + 0X2469, + 0X246A, + 0X246B, + 0X246C, + 0X246D, + 0X246E, + 0X246F, + 0X2470, + 0X2471, + 0X2472, + 0X2473, + 0X2474, + 0X2475, + 0X2476, + 0X2477, + 0X2478, + 0X2479, + 0X247A, + 0X247B, + 0X247C, + 0X247D, + 0X247E, + 0X247F, + 0X2480, + 0X2481, + 0X2482, + 0X2483, + 0X2484, + 0X2485, + 0X2486, + 0X2487, + 0X2488, + 0X2489, + 0X248A, + 0X248B, + 0X248C, + 0X248D, + 0X248E, + 0X248F, + 0X2490, + 0X2491, + 0X2492, + 0X2493, + 0X2494, + 0X2495, + 0X2496, + 0X2497, + 0X2498, + 0X2499, + 0X249A, + 0X249B, + 0X24EA, + 0X24EB, + 0X24EC, + 0X24ED, + 0X24EE, + 0X24EF, + 0X24F0, + 0X24F1, + 0X24F2, + 0X24F3, + 0X24F4, + 0X24F5, + 0X24F6, + 0X24F7, + 0X24F8, + 0X24F9, + 0X24FA, + 0X24FB, + 0X24FC, + 0X24FD, + 0X24FE, + 0X24FF, + 0X2776, + 0X2777, + 0X2778, + 0X2779, + 0X277A, + 0X277B, + 0X277C, + 0X277D, + 0X277E, + 0X277F, + 0X2780, + 0X2781, + 0X2782, + 0X2783, + 0X2784, + 0X2785, + 0X2786, + 0X2787, + 0X2788, + 0X2789, + 0X278A, + 0X278B, + 0X278C, + 0X278D, + 0X278E, + 0X278F, + 0X2790, + 0X2791, + 0X2792, + 0X2793, + 0X2CFD, + 0X3007, + 0X3021, + 0X3022, + 0X3023, + 0X3024, + 0X3025, + 0X3026, + 0X3027, + 0X3028, + 0X3029, + 0X3038, + 0X3039, + 0X303A, + 0X3192, + 0X3193, + 0X3194, + 0X3195, + 0X3220, + 0X3221, + 0X3222, + 0X3223, + 0X3224, + 0X3225, + 0X3226, + 0X3227, + 0X3228, + 0X3229, + 0X3248, + 0X3249, + 0X324A, + 0X324B, + 0X324C, + 0X324D, + 0X324E, + 0X324F, + 0X3251, + 0X3252, + 0X3253, + 0X3254, + 0X3255, + 0X3256, + 0X3257, + 0X3258, + 0X3259, + 0X325A, + 0X325B, + 0X325C, + 0X325D, + 0X325E, + 0X325F, + 0X3280, + 0X3281, + 0X3282, + 0X3283, + 0X3284, + 0X3285, + 0X3286, + 0X3287, + 0X3288, + 0X3289, + 0X32B1, + 0X32B2, + 0X32B3, + 0X32B4, + 0X32B5, + 0X32B6, + 0X32B7, + 0X32B8, + 0X32B9, + 0X32BA, + 0X32BB, + 0X32BC, + 0X32BD, + 0X32BE, + 0X32BF, + 0X3405, + 0X3483, + 0X382A, + 0X3B4D, + 0X4E00, + 0X4E03, + 0X4E07, + 0X4E09, + 0X4E5D, + 0X4E8C, + 0X4E94, + 0X4E96, + 0X4EBF, + 0X4EC0, + 0X4EDF, + 0X4EE8, + 0X4F0D, + 0X4F70, + 0X5104, + 0X5146, + 0X5169, + 0X516B, + 0X516D, + 0X5341, + 0X5343, + 0X5344, + 0X5345, + 0X534C, + 0X53C1, + 0X53C2, + 0X53C3, + 0X53C4, + 0X56DB, + 0X58F1, + 0X58F9, + 0X5E7A, + 0X5EFE, + 0X5EFF, + 0X5F0C, + 0X5F0D, + 0X5F0E, + 0X5F10, + 0X62FE, + 0X634C, + 0X67D2, + 0X6F06, + 0X7396, + 0X767E, + 0X8086, + 0X842C, + 0X8CAE, + 0X8CB3, + 0X8D30, + 0X9621, + 0X9646, + 0X964C, + 0X9678, + 0X96F6, + 0XA620, + 0XA621, + 0XA622, + 0XA623, + 0XA624, + 0XA625, + 0XA626, + 0XA627, + 0XA628, + 0XA629, + 0XA6E6, + 0XA6E7, + 0XA6E8, + 0XA6E9, + 0XA6EA, + 0XA6EB, + 0XA6EC, + 0XA6ED, + 0XA6EE, + 0XA6EF, + 0XA830, + 0XA831, + 0XA832, + 0XA833, + 0XA834, + 0XA835, + 0XA8D0, + 0XA8D1, + 0XA8D2, + 0XA8D3, + 0XA8D4, + 0XA8D5, + 0XA8D6, + 0XA8D7, + 0XA8D8, + 0XA8D9, + 0XA900, + 0XA901, + 0XA902, + 0XA903, + 0XA904, + 0XA905, + 0XA906, + 0XA907, + 0XA908, + 0XA909, + 0XA9D0, + 0XA9D1, + 0XA9D2, + 0XA9D3, + 0XA9D4, + 0XA9D5, + 0XA9D6, + 0XA9D7, + 0XA9D8, + 0XA9D9, + 0XA9F0, + 0XA9F1, + 0XA9F2, + 0XA9F3, + 0XA9F4, + 0XA9F5, + 0XA9F6, + 0XA9F7, + 0XA9F8, + 0XA9F9, + 0XAA50, + 0XAA51, + 0XAA52, + 0XAA53, + 0XAA54, + 0XAA55, + 0XAA56, + 0XAA57, + 0XAA58, + 0XAA59, + 0XABF0, + 0XABF1, + 0XABF2, + 0XABF3, + 0XABF4, + 0XABF5, + 0XABF6, + 0XABF7, + 0XABF8, + 0XABF9, + 0XF96B, + 0XF973, + 0XF978, + 0XF9B2, + 0XF9D1, + 0XF9D3, + 0XF9FD, + 0XFF10, + 0XFF11, + 0XFF12, + 0XFF13, + 0XFF14, + 0XFF15, + 0XFF16, + 0XFF17, + 0XFF18, + 0XFF19, + 0X10107, + 0X10108, + 0X10109, + 0X1010A, + 0X1010B, + 0X1010C, + 0X1010D, + 0X1010E, + 0X1010F, + 0X10110, + 0X10111, + 0X10112, + 0X10113, + 0X10114, + 0X10115, + 0X10116, + 0X10117, + 0X10118, + 0X10119, + 0X1011A, + 0X1011B, + 0X1011C, + 0X1011D, + 0X1011E, + 0X1011F, + 0X10120, + 0X10121, + 0X10122, + 0X10123, + 0X10124, + 0X10125, + 0X10126, + 0X10127, + 0X10128, + 0X10129, + 0X1012A, + 0X1012B, + 0X1012C, + 0X1012D, + 0X1012E, + 0X1012F, + 0X10130, + 0X10131, + 0X10132, + 0X10133, + 0X10140, + 0X10141, + 0X10142, + 0X10143, + 0X10144, + 0X10145, + 0X10146, + 0X10147, + 0X10148, + 0X10149, + 0X1014A, + 0X1014B, + 0X1014C, + 0X1014D, + 0X1014E, + 0X1014F, + 0X10150, + 0X10151, + 0X10152, + 0X10153, + 0X10154, + 0X10155, + 0X10156, + 0X10157, + 0X10158, + 0X10159, + 0X1015A, + 0X1015B, + 0X1015C, + 0X1015D, + 0X1015E, + 0X1015F, + 0X10160, + 0X10161, + 0X10162, + 0X10163, + 0X10164, + 0X10165, + 0X10166, + 0X10167, + 0X10168, + 0X10169, + 0X1016A, + 0X1016B, + 0X1016C, + 0X1016D, + 0X1016E, + 0X1016F, + 0X10170, + 0X10171, + 0X10172, + 0X10173, + 0X10174, + 0X10175, + 0X10176, + 0X10177, + 0X10178, + 0X1018A, + 0X1018B, + 0X102E1, + 0X102E2, + 0X102E3, + 0X102E4, + 0X102E5, + 0X102E6, + 0X102E7, + 0X102E8, + 0X102E9, + 0X102EA, + 0X102EB, + 0X102EC, + 0X102ED, + 0X102EE, + 0X102EF, + 0X102F0, + 0X102F1, + 0X102F2, + 0X102F3, + 0X102F4, + 0X102F5, + 0X102F6, + 0X102F7, + 0X102F8, + 0X102F9, + 0X102FA, + 0X102FB, + 0X10320, + 0X10321, + 0X10322, + 0X10323, + 0X10341, + 0X1034A, + 0X103D1, + 0X103D2, + 0X103D3, + 0X103D4, + 0X103D5, + 0X104A0, + 0X104A1, + 0X104A2, + 0X104A3, + 0X104A4, + 0X104A5, + 0X104A6, + 0X104A7, + 0X104A8, + 0X104A9, + 0X10858, + 0X10859, + 0X1085A, + 0X1085B, + 0X1085C, + 0X1085D, + 0X1085E, + 0X1085F, + 0X10879, + 0X1087A, + 0X1087B, + 0X1087C, + 0X1087D, + 0X1087E, + 0X1087F, + 0X108A7, + 0X108A8, + 0X108A9, + 0X108AA, + 0X108AB, + 0X108AC, + 0X108AD, + 0X108AE, + 0X108AF, + 0X108FB, + 0X108FC, + 0X108FD, + 0X108FE, + 0X108FF, + 0X10916, + 0X10917, + 0X10918, + 0X10919, + 0X1091A, + 0X1091B, + 0X109BC, + 0X109BD, + 0X109C0, + 0X109C1, + 0X109C2, + 0X109C3, + 0X109C4, + 0X109C5, + 0X109C6, + 0X109C7, + 0X109C8, + 0X109C9, + 0X109CA, + 0X109CB, + 0X109CC, + 0X109CD, + 0X109CE, + 0X109CF, + 0X109D2, + 0X109D3, + 0X109D4, + 0X109D5, + 0X109D6, + 0X109D7, + 0X109D8, + 0X109D9, + 0X109DA, + 0X109DB, + 0X109DC, + 0X109DD, + 0X109DE, + 0X109DF, + 0X109E0, + 0X109E1, + 0X109E2, + 0X109E3, + 0X109E4, + 0X109E5, + 0X109E6, + 0X109E7, + 0X109E8, + 0X109E9, + 0X109EA, + 0X109EB, + 0X109EC, + 0X109ED, + 0X109EE, + 0X109EF, + 0X109F0, + 0X109F1, + 0X109F2, + 0X109F3, + 0X109F4, + 0X109F5, + 0X109F6, + 0X109F7, + 0X109F8, + 0X109F9, + 0X109FA, + 0X109FB, + 0X109FC, + 0X109FD, + 0X109FE, + 0X109FF, + 0X10A40, + 0X10A41, + 0X10A42, + 0X10A43, + 0X10A44, + 0X10A45, + 0X10A46, + 0X10A47, + 0X10A48, + 0X10A7D, + 0X10A7E, + 0X10A9D, + 0X10A9E, + 0X10A9F, + 0X10AEB, + 0X10AEC, + 0X10AED, + 0X10AEE, + 0X10AEF, + 0X10B58, + 0X10B59, + 0X10B5A, + 0X10B5B, + 0X10B5C, + 0X10B5D, + 0X10B5E, + 0X10B5F, + 0X10B78, + 0X10B79, + 0X10B7A, + 0X10B7B, + 0X10B7C, + 0X10B7D, + 0X10B7E, + 0X10B7F, + 0X10BA9, + 0X10BAA, + 0X10BAB, + 0X10BAC, + 0X10BAD, + 0X10BAE, + 0X10BAF, + 0X10CFA, + 0X10CFB, + 0X10CFC, + 0X10CFD, + 0X10CFE, + 0X10CFF, + 0X10D30, + 0X10D31, + 0X10D32, + 0X10D33, + 0X10D34, + 0X10D35, + 0X10D36, + 0X10D37, + 0X10D38, + 0X10D39, + 0X10E60, + 0X10E61, + 0X10E62, + 0X10E63, + 0X10E64, + 0X10E65, + 0X10E66, + 0X10E67, + 0X10E68, + 0X10E69, + 0X10E6A, + 0X10E6B, + 0X10E6C, + 0X10E6D, + 0X10E6E, + 0X10E6F, + 0X10E70, + 0X10E71, + 0X10E72, + 0X10E73, + 0X10E74, + 0X10E75, + 0X10E76, + 0X10E77, + 0X10E78, + 0X10E79, + 0X10E7A, + 0X10E7B, + 0X10E7C, + 0X10E7D, + 0X10E7E, + 0X10F1D, + 0X10F1E, + 0X10F1F, + 0X10F20, + 0X10F21, + 0X10F22, + 0X10F23, + 0X10F24, + 0X10F25, + 0X10F26, + 0X10F51, + 0X10F52, + 0X10F53, + 0X10F54, + 0X11052, + 0X11053, + 0X11054, + 0X11055, + 0X11056, + 0X11057, + 0X11058, + 0X11059, + 0X1105A, + 0X1105B, + 0X1105C, + 0X1105D, + 0X1105E, + 0X1105F, + 0X11060, + 0X11061, + 0X11062, + 0X11063, + 0X11064, + 0X11065, + 0X11066, + 0X11067, + 0X11068, + 0X11069, + 0X1106A, + 0X1106B, + 0X1106C, + 0X1106D, + 0X1106E, + 0X1106F, + 0X110F0, + 0X110F1, + 0X110F2, + 0X110F3, + 0X110F4, + 0X110F5, + 0X110F6, + 0X110F7, + 0X110F8, + 0X110F9, + 0X11136, + 0X11137, + 0X11138, + 0X11139, + 0X1113A, + 0X1113B, + 0X1113C, + 0X1113D, + 0X1113E, + 0X1113F, + 0X111D0, + 0X111D1, + 0X111D2, + 0X111D3, + 0X111D4, + 0X111D5, + 0X111D6, + 0X111D7, + 0X111D8, + 0X111D9, + 0X111E1, + 0X111E2, + 0X111E3, + 0X111E4, + 0X111E5, + 0X111E6, + 0X111E7, + 0X111E8, + 0X111E9, + 0X111EA, + 0X111EB, + 0X111EC, + 0X111ED, + 0X111EE, + 0X111EF, + 0X111F0, + 0X111F1, + 0X111F2, + 0X111F3, + 0X111F4, + 0X112F0, + 0X112F1, + 0X112F2, + 0X112F3, + 0X112F4, + 0X112F5, + 0X112F6, + 0X112F7, + 0X112F8, + 0X112F9, + 0X11450, + 0X11451, + 0X11452, + 0X11453, + 0X11454, + 0X11455, + 0X11456, + 0X11457, + 0X11458, + 0X11459, + 0X114D0, + 0X114D1, + 0X114D2, + 0X114D3, + 0X114D4, + 0X114D5, + 0X114D6, + 0X114D7, + 0X114D8, + 0X114D9, + 0X11650, + 0X11651, + 0X11652, + 0X11653, + 0X11654, + 0X11655, + 0X11656, + 0X11657, + 0X11658, + 0X11659, + 0X116C0, + 0X116C1, + 0X116C2, + 0X116C3, + 0X116C4, + 0X116C5, + 0X116C6, + 0X116C7, + 0X116C8, + 0X116C9, + 0X11730, + 0X11731, + 0X11732, + 0X11733, + 0X11734, + 0X11735, + 0X11736, + 0X11737, + 0X11738, + 0X11739, + 0X1173A, + 0X1173B, + 0X118E0, + 0X118E1, + 0X118E2, + 0X118E3, + 0X118E4, + 0X118E5, + 0X118E6, + 0X118E7, + 0X118E8, + 0X118E9, + 0X118EA, + 0X118EB, + 0X118EC, + 0X118ED, + 0X118EE, + 0X118EF, + 0X118F0, + 0X118F1, + 0X118F2, + 0X11C50, + 0X11C51, + 0X11C52, + 0X11C53, + 0X11C54, + 0X11C55, + 0X11C56, + 0X11C57, + 0X11C58, + 0X11C59, + 0X11C5A, + 0X11C5B, + 0X11C5C, + 0X11C5D, + 0X11C5E, + 0X11C5F, + 0X11C60, + 0X11C61, + 0X11C62, + 0X11C63, + 0X11C64, + 0X11C65, + 0X11C66, + 0X11C67, + 0X11C68, + 0X11C69, + 0X11C6A, + 0X11C6B, + 0X11C6C, + 0X11D50, + 0X11D51, + 0X11D52, + 0X11D53, + 0X11D54, + 0X11D55, + 0X11D56, + 0X11D57, + 0X11D58, + 0X11D59, + 0X11DA0, + 0X11DA1, + 0X11DA2, + 0X11DA3, + 0X11DA4, + 0X11DA5, + 0X11DA6, + 0X11DA7, + 0X11DA8, + 0X11DA9, + 0X12400, + 0X12401, + 0X12402, + 0X12403, + 0X12404, + 0X12405, + 0X12406, + 0X12407, + 0X12408, + 0X12409, + 0X1240A, + 0X1240B, + 0X1240C, + 0X1240D, + 0X1240E, + 0X1240F, + 0X12410, + 0X12411, + 0X12412, + 0X12413, + 0X12414, + 0X12415, + 0X12416, + 0X12417, + 0X12418, + 0X12419, + 0X1241A, + 0X1241B, + 0X1241C, + 0X1241D, + 0X1241E, + 0X1241F, + 0X12420, + 0X12421, + 0X12422, + 0X12423, + 0X12424, + 0X12425, + 0X12426, + 0X12427, + 0X12428, + 0X12429, + 0X1242A, + 0X1242B, + 0X1242C, + 0X1242D, + 0X1242E, + 0X1242F, + 0X12430, + 0X12431, + 0X12432, + 0X12433, + 0X12434, + 0X12435, + 0X12436, + 0X12437, + 0X12438, + 0X12439, + 0X1243A, + 0X1243B, + 0X1243C, + 0X1243D, + 0X1243E, + 0X1243F, + 0X12440, + 0X12441, + 0X12442, + 0X12443, + 0X12444, + 0X12445, + 0X12446, + 0X12447, + 0X12448, + 0X12449, + 0X1244A, + 0X1244B, + 0X1244C, + 0X1244D, + 0X1244E, + 0X1244F, + 0X12450, + 0X12451, + 0X12452, + 0X12453, + 0X12454, + 0X12455, + 0X12456, + 0X12457, + 0X12458, + 0X12459, + 0X1245A, + 0X1245B, + 0X1245C, + 0X1245D, + 0X1245E, + 0X1245F, + 0X12460, + 0X12461, + 0X12462, + 0X12463, + 0X12464, + 0X12465, + 0X12466, + 0X12467, + 0X12468, + 0X12469, + 0X1246A, + 0X1246B, + 0X1246C, + 0X1246D, + 0X1246E, + 0X16A60, + 0X16A61, + 0X16A62, + 0X16A63, + 0X16A64, + 0X16A65, + 0X16A66, + 0X16A67, + 0X16A68, + 0X16A69, + 0X16B50, + 0X16B51, + 0X16B52, + 0X16B53, + 0X16B54, + 0X16B55, + 0X16B56, + 0X16B57, + 0X16B58, + 0X16B59, + 0X16B5B, + 0X16B5C, + 0X16B5D, + 0X16B5E, + 0X16B5F, + 0X16B60, + 0X16B61, + 0X16E80, + 0X16E81, + 0X16E82, + 0X16E83, + 0X16E84, + 0X16E85, + 0X16E86, + 0X16E87, + 0X16E88, + 0X16E89, + 0X16E8A, + 0X16E8B, + 0X16E8C, + 0X16E8D, + 0X16E8E, + 0X16E8F, + 0X16E90, + 0X16E91, + 0X16E92, + 0X16E93, + 0X16E94, + 0X16E95, + 0X16E96, + 0X1D2E0, + 0X1D2E1, + 0X1D2E2, + 0X1D2E3, + 0X1D2E4, + 0X1D2E5, + 0X1D2E6, + 0X1D2E7, + 0X1D2E8, + 0X1D2E9, + 0X1D2EA, + 0X1D2EB, + 0X1D2EC, + 0X1D2ED, + 0X1D2EE, + 0X1D2EF, + 0X1D2F0, + 0X1D2F1, + 0X1D2F2, + 0X1D2F3, + 0X1D360, + 0X1D361, + 0X1D362, + 0X1D363, + 0X1D364, + 0X1D365, + 0X1D366, + 0X1D367, + 0X1D368, + 0X1D369, + 0X1D36A, + 0X1D36B, + 0X1D36C, + 0X1D36D, + 0X1D36E, + 0X1D36F, + 0X1D370, + 0X1D371, + 0X1D372, + 0X1D373, + 0X1D374, + 0X1D375, + 0X1D376, + 0X1D377, + 0X1D378, + 0X1D7CE, + 0X1D7CF, + 0X1D7D0, + 0X1D7D1, + 0X1D7D2, + 0X1D7D3, + 0X1D7D4, + 0X1D7D5, + 0X1D7D6, + 0X1D7D7, + 0X1D7D8, + 0X1D7D9, + 0X1D7DA, + 0X1D7DB, + 0X1D7DC, + 0X1D7DD, + 0X1D7DE, + 0X1D7DF, + 0X1D7E0, + 0X1D7E1, + 0X1D7E2, + 0X1D7E3, + 0X1D7E4, + 0X1D7E5, + 0X1D7E6, + 0X1D7E7, + 0X1D7E8, + 0X1D7E9, + 0X1D7EA, + 0X1D7EB, + 0X1D7EC, + 0X1D7ED, + 0X1D7EE, + 0X1D7EF, + 0X1D7F0, + 0X1D7F1, + 0X1D7F2, + 0X1D7F3, + 0X1D7F4, + 0X1D7F5, + 0X1D7F6, + 0X1D7F7, + 0X1D7F8, + 0X1D7F9, + 0X1D7FA, + 0X1D7FB, + 0X1D7FC, + 0X1D7FD, + 0X1D7FE, + 0X1D7FF, + 0X1E8C7, + 0X1E8C8, + 0X1E8C9, + 0X1E8CA, + 0X1E8CB, + 0X1E8CC, + 0X1E8CD, + 0X1E8CE, + 0X1E8CF, + 0X1E950, + 0X1E951, + 0X1E952, + 0X1E953, + 0X1E954, + 0X1E955, + 0X1E956, + 0X1E957, + 0X1E958, + 0X1E959, + 0X1EC71, + 0X1EC72, + 0X1EC73, + 0X1EC74, + 0X1EC75, + 0X1EC76, + 0X1EC77, + 0X1EC78, + 0X1EC79, + 0X1EC7A, + 0X1EC7B, + 0X1EC7C, + 0X1EC7D, + 0X1EC7E, + 0X1EC7F, + 0X1EC80, + 0X1EC81, + 0X1EC82, + 0X1EC83, + 0X1EC84, + 0X1EC85, + 0X1EC86, + 0X1EC87, + 0X1EC88, + 0X1EC89, + 0X1EC8A, + 0X1EC8B, + 0X1EC8C, + 0X1EC8D, + 0X1EC8E, + 0X1EC8F, + 0X1EC90, + 0X1EC91, + 0X1EC92, + 0X1EC93, + 0X1EC94, + 0X1EC95, + 0X1EC96, + 0X1EC97, + 0X1EC98, + 0X1EC99, + 0X1EC9A, + 0X1EC9B, + 0X1EC9C, + 0X1EC9D, + 0X1EC9E, + 0X1EC9F, + 0X1ECA0, + 0X1ECA1, + 0X1ECA2, + 0X1ECA3, + 0X1ECA4, + 0X1ECA5, + 0X1ECA6, + 0X1ECA7, + 0X1ECA8, + 0X1ECA9, + 0X1ECAA, + 0X1ECAB, + 0X1ECAD, + 0X1ECAE, + 0X1ECAF, + 0X1ECB1, + 0X1ECB2, + 0X1ECB3, + 0X1ECB4, + 0X1F100, + 0X1F101, + 0X1F102, + 0X1F103, + 0X1F104, + 0X1F105, + 0X1F106, + 0X1F107, + 0X1F108, + 0X1F109, + 0X1F10A, + 0X1F10B, + 0X1F10C, + 0X20001, + 0X20064, + 0X200E2, + 0X20121, + 0X2092A, + 0X20983, + 0X2098C, + 0X2099C, + 0X20AEA, + 0X20AFD, + 0X20B19, + 0X22390, + 0X22998, + 0X23B1B, + 0X2626D, + 0X2F890, +) + +# Some code that can be used to create the above list of hex numbers. +if __name__ == "__main__": + import unicodedata + from natsort.compat.py23 import py23_range, py23_unichr + + hex_chars = [] + for i in py23_range(0X110000): + try: + a = py23_unichr(i) + except ValueError: + break + if a in set("0123456789"): + continue + if unicodedata.numeric(a, None) is not None: + hex_chars.append(i) + + print(", ".join(["0X{:X}".format(i) for i in hex_chars])) diff --git a/natsort/utils.py b/natsort/utils.py index 306762a..0da401a 100644 --- a/natsort/utils.py +++ b/natsort/utils.py @@ -38,12 +38,7 @@ that ensures "val" is a local variable instead of global variable and thus has a slightly improved performance at runtime. """ -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import # Std. lib imports. import re @@ -60,57 +55,45 @@ from unicodedata import normalize from natsort.ns_enum import ns from natsort.unicode_numbers import numeric_no_decimals, digits_no_decimals from natsort.compat.pathlib import PurePath, has_pathlib -from natsort.compat.locale import ( - get_strxfrm, - get_thousands_sep, - get_decimal_point, -) -from natsort.compat.py23 import ( - py23_str, - py23_map, - py23_filter, - PY_VERSION, - NEWPY, -) -from natsort.compat.fastnumbers import ( - fast_float, - fast_int, -) +from natsort.compat.locale import get_strxfrm, get_thousands_sep, get_decimal_point +from natsort.compat.py23 import py23_str, py23_map, py23_filter, PY_VERSION, NEWPY +from natsort.compat.fastnumbers import fast_float, fast_int + if PY_VERSION >= 3: long = int # The regex that locates floats - include Unicode numerals. _nnd = numeric_no_decimals -_exp = r'(?:[eE][-+]?\d+)?' -_num = r'(?:\d+\.?\d*|\.\d+)' -_float_sign_exp_re = r'([-+]?{0}{1}|[{2}])' +_exp = r"(?:[eE][-+]?\d+)?" +_num = r"(?:\d+\.?\d*|\.\d+)" +_float_sign_exp_re = r"([-+]?{0}{1}|[{2}])" _float_sign_exp_re = _float_sign_exp_re.format(_num, _exp, _nnd) _float_sign_exp_re = re.compile(_float_sign_exp_re, flags=re.U) -_float_nosign_exp_re = r'({0}{1}|[{2}])' +_float_nosign_exp_re = r"({0}{1}|[{2}])" _float_nosign_exp_re = _float_nosign_exp_re.format(_num, _exp, _nnd) _float_nosign_exp_re = re.compile(_float_nosign_exp_re, flags=re.U) -_float_sign_noexp_re = r'([-+]?{0}|[{1}])' +_float_sign_noexp_re = r"([-+]?{0}|[{1}])" _float_sign_noexp_re = _float_sign_noexp_re.format(_num, _nnd) _float_sign_noexp_re = re.compile(_float_sign_noexp_re, flags=re.U) -_float_nosign_noexp_re = r'({0}|[{1}])' +_float_nosign_noexp_re = r"({0}|[{1}])" _float_nosign_noexp_re = _float_nosign_noexp_re.format(_num, _nnd) _float_nosign_noexp_re = re.compile(_float_nosign_noexp_re, flags=re.U) # Integer regexes - include Unicode digits. -_int_nosign_re = r'(\d+|[{0}])'.format(digits_no_decimals) +_int_nosign_re = r"(\d+|[{0}])".format(digits_no_decimals) _int_nosign_re = re.compile(_int_nosign_re, flags=re.U) -_int_sign_re = r'([-+]?\d+|[{0}])'.format(digits_no_decimals) +_int_sign_re = r"([-+]?\d+|[{0}])".format(digits_no_decimals) _int_sign_re = re.compile(_int_sign_re, flags=re.U) # This dict will help select the correct regex and number conversion function. _regex_chooser = { - (ns.F | ns.S): _float_sign_exp_re, + (ns.F | ns.S): _float_sign_exp_re, (ns.F | ns.S | ns.N): _float_sign_noexp_re, - (ns.F | ns.U): _float_nosign_exp_re, + (ns.F | ns.U): _float_nosign_exp_re, (ns.F | ns.U | ns.N): _float_nosign_noexp_re, - (ns.I | ns.S): _int_sign_re, + (ns.I | ns.S): _int_sign_re, (ns.I | ns.S | ns.N): _int_sign_re, - (ns.I | ns.U): _int_nosign_re, + (ns.I | ns.U): _int_nosign_re, (ns.I | ns.U | ns.N): _int_nosign_re, } @@ -122,17 +105,19 @@ def _no_op(x): def _normalize_input_factory(alg): """Create a function that will normalize unicode input data.""" - normalization_form = 'NFKD' if alg & ns.COMPATIBILITYNORMALIZE else 'NFD' + normalization_form = "NFKD" if alg & ns.COMPATIBILITYNORMALIZE else "NFD" if NEWPY: return partial(normalize, normalization_form) else: + def func(x): """Normalize unicode input.""" if isinstance(x, py23_str): # unicode return normalize(normalization_form, x) else: return x + return func @@ -175,9 +160,9 @@ def _natsort_key(val, key, string_func, bytes_func, num_func): # Otherwise, assume it is an iterable that must be parses recursively. # Do not apply the key recursively. try: - return tuple(_natsort_key( - x, None, string_func, bytes_func, num_func - ) for x in val) + return tuple( + _natsort_key(x, None, string_func, bytes_func, num_func) for x in val + ) # If that failed, it must be a number. except TypeError: @@ -200,7 +185,7 @@ def _parse_bytes_factory(alg): def _parse_number_factory(alg, sep, pre_sep): """Create a function that will properly format a number in a tuple.""" - nan_replace = float('+inf') if alg & ns.NANLAST else float('-inf') + nan_replace = float("+inf") if alg & ns.NANLAST else float("-inf") def func(val, nan_replace=nan_replace, sep=sep): """Given a number, place it in a tuple with a leading null string.""" @@ -217,10 +202,9 @@ def _parse_number_factory(alg, sep, pre_sep): return func -def _parse_string_factory(alg, sep, splitter, - input_transform, - component_transform, - final_transform): +def _parse_string_factory( + alg, sep, splitter, input_transform, component_transform, final_transform +): """Create a function that will properly split and format a string.""" # Sometimes we store the "original" input before transformation, # sometimes after. @@ -234,11 +218,11 @@ def _parse_string_factory(alg, sep, splitter, # to also be the transformation function. x = normalize_input(x) x, original = input_transform(x), original_func(x) - x = splitter(x) # Split string into components. - x = py23_filter(None, x) # Remove empty strings. + x = splitter(x) # Split string into components. + x = py23_filter(None, x) # Remove empty strings. x = py23_map(component_transform, x) # Apply transform on components. - x = _sep_inserter(x, sep) # Insert '' between numbers. - return final_transform(x, original) # Apply the final transform. + x = _sep_inserter(x, sep) # Insert '' between numbers. + return final_transform(x, original) # Apply the final transform. return func @@ -291,17 +275,17 @@ def _input_string_transform_factory(alg): # Build the chain of functions to execute in order. function_chain = [] if (dumb and not lowfirst) or (lowfirst and not dumb): - function_chain.append(methodcaller('swapcase')) + function_chain.append(methodcaller("swapcase")) if alg & ns.IGNORECASE: if NEWPY: - function_chain.append(methodcaller('casefold')) + function_chain.append(methodcaller("casefold")) else: - function_chain.append(methodcaller('lower')) + function_chain.append(methodcaller("lower")) if alg & ns.LOCALENUM: # Create a regular expression that will remove thousands separators. - strip_thousands = r''' + strip_thousands = r""" (?<=[0-9]{{1}}) # At least 1 number (?<![0-9]{{4}}) # No more than 3 numbers {nodecimal} # Cannot follow decimal @@ -309,29 +293,30 @@ def _input_string_transform_factory(alg): (?=[0-9]{{3}} # Three numbers must follow ([^0-9]|$) # But a non-number after that ) - ''' - nodecimal = r'' + """ + nodecimal = r"" if alg & ns.FLOAT: # Make a regular expression component that will ensure no # separators are removed after a decimal point. d = get_decimal_point() - d = r'\.' if d == r'.' else d - nodecimal += r'(?<!' + d + r'[0-9])' - nodecimal += r'(?<!' + d + r'[0-9]{2})' - nodecimal += r'(?<!' + d + r'[0-9]{3})' - strip_thousands = strip_thousands.format(thou=get_thousands_sep(), - nodecimal=nodecimal) + d = r"\." if d == r"." else d + nodecimal += r"(?<!" + d + r"[0-9])" + nodecimal += r"(?<!" + d + r"[0-9]{2})" + nodecimal += r"(?<!" + d + r"[0-9]{3})" + strip_thousands = strip_thousands.format( + thou=get_thousands_sep(), nodecimal=nodecimal + ) strip_thousands = re.compile(strip_thousands, flags=re.VERBOSE) - function_chain.append(partial(strip_thousands.sub, '')) + function_chain.append(partial(strip_thousands.sub, "")) # Create a regular expression that will change the decimal point to # a period if not already a period. decimal = get_decimal_point() - if alg & ns.FLOAT and decimal != '.': - switch_decimal = r'(?<=[0-9]){decimal}|{decimal}(?=[0-9])' + if alg & ns.FLOAT and decimal != ".": + switch_decimal = r"(?<=[0-9]){decimal}|{decimal}(?=[0-9])" switch_decimal = switch_decimal.format(decimal=decimal) switch_decimal = re.compile(switch_decimal) - function_chain.append(partial(switch_decimal.sub, '.')) + function_chain.append(partial(switch_decimal.sub, ".")) # Return the chained functions. return chain_functions(function_chain) @@ -346,7 +331,7 @@ def _string_component_transform_factory(alg): use_locale = alg & ns.LOCALEALPHA dumb = alg & ns._DUMB group_letters = (alg & ns.GROUPLETTERS) or (use_locale and dumb) - nan_val = float('+inf') if alg & ns.NANLAST else float('-inf') + nan_val = float("+inf") if alg & ns.NANLAST else float("-inf") # Build the chain of functions to execute in order. func_chain = [] @@ -354,11 +339,11 @@ def _string_component_transform_factory(alg): func_chain.append(_groupletters) if use_locale: func_chain.append(get_strxfrm()) - kwargs = {'key': chain_functions(func_chain)} if func_chain else {} + kwargs = {"key": chain_functions(func_chain)} if func_chain else {} # Return the correct chained functions. if alg & ns.FLOAT: - kwargs['nan'] = nan_val + kwargs["nan"] = nan_val return partial(fast_float, **kwargs) else: return partial(fast_int, **kwargs) @@ -371,7 +356,7 @@ def _final_data_transform_factory(alg, sep, pre_sep): """ if alg & ns.UNGROUPLETTERS and alg & ns.LOCALEALPHA: swap = alg & ns._DUMB and alg & ns.LOWERCASEFIRST - transform = methodcaller('swapcase') if swap else _no_op + transform = methodcaller("swapcase") if swap else _no_op def func(split_val, val, transform=transform): """ @@ -387,14 +372,15 @@ def _final_data_transform_factory(alg, sep, pre_sep): return (pre_sep,), split_val else: return (transform(val[0]),), split_val + return func else: return lambda split_val, val: tuple(split_val) -def _groupletters(x, _low=methodcaller('casefold' if NEWPY else 'lower')): +def _groupletters(x, _low=methodcaller("casefold" if NEWPY else "lower")): """Double all characters, making doubled letters lowercase.""" - return ''.join(ichain.from_iterable((_low(y), y) for y in x)) + return "".join(ichain.from_iterable((_low(y), y) for y in x)) def chain_functions(functions): @@ -443,7 +429,7 @@ def _do_decoding(s, encoding): return s -def _path_splitter(s, _d_match=re.compile(r'\.\d').match): +def _path_splitter(s, _d_match=re.compile(r"\.\d").match): """Split a string into its path components. Assumes a string is a path.""" # If a PathLib Object, use it's functionality to perform the split. if has_pathlib and isinstance(s, PurePath): @@ -490,30 +476,30 @@ def _path_splitter(s, _d_match=re.compile(r'\.\d').match): def _args_to_enum(**kwargs): """A function to convert input booleans to an enum-type argument.""" alg = 0 - keys = ('number_type', 'signed', 'exp', 'as_path', 'py3_safe') + keys = ("number_type", "signed", "exp", "as_path", "py3_safe") if any(x not in keys for x in kwargs): x = set(kwargs) - set(keys) - raise TypeError('Invalid argument(s): ' + ', '.join(x)) - if 'number_type' in kwargs and kwargs['number_type'] is not int: + raise TypeError("Invalid argument(s): " + ", ".join(x)) + if "number_type" in kwargs and kwargs["number_type"] is not int: msg = "The 'number_type' argument is deprecated as of 3.5.0, " msg += "please use 'alg=ns.FLOAT', 'alg=ns.INT', or 'alg=ns.VERSION'" warn(msg, DeprecationWarning) - alg |= (ns.FLOAT * bool(kwargs['number_type'] is float)) - alg |= (ns.INT * bool(kwargs['number_type'] in (int, None))) - alg |= (ns.SIGNED * (kwargs['number_type'] not in (float, None))) - if 'signed' in kwargs and kwargs['signed'] is not None: + alg |= ns.FLOAT * bool(kwargs["number_type"] is float) + alg |= ns.INT * bool(kwargs["number_type"] in (int, None)) + alg |= ns.SIGNED * (kwargs["number_type"] not in (float, None)) + if "signed" in kwargs and kwargs["signed"] is not None: msg = "The 'signed' argument is deprecated as of 3.5.0, " msg += "please use 'alg=ns.SIGNED'." warn(msg, DeprecationWarning) - alg |= (ns.SIGNED * bool(kwargs['signed'])) - if 'exp' in kwargs and kwargs['exp'] is not None: + alg |= ns.SIGNED * bool(kwargs["signed"]) + if "exp" in kwargs and kwargs["exp"] is not None: msg = "The 'exp' argument is deprecated as of 3.5.0, " msg += "please use 'alg=ns.NOEXP'." warn(msg, DeprecationWarning) - alg |= (ns.NOEXP * (not kwargs['exp'])) - if 'as_path' in kwargs and kwargs['as_path'] is not None: + alg |= ns.NOEXP * (not kwargs["exp"]) + if "as_path" in kwargs and kwargs["as_path"] is not None: msg = "The 'as_path' argument is deprecated as of 3.5.0, " msg += "please use 'alg=ns.PATH'." warn(msg, DeprecationWarning) - alg |= (ns.PATH * kwargs['as_path']) + alg |= ns.PATH * kwargs["as_path"] return alg @@ -41,7 +41,7 @@ formats = gztar [bumpversion:file:setup.py] -[bumpversion:file:natsort/_version.py] +[bumpversion:file:natsort/__init__.py] [bumpversion:file:docs/source/conf.py] @@ -64,8 +64,5 @@ pep8ignore = test_natsort/test_natsort_keygen.py E501 E241 E221 E701 test_natsort/profile_natsorted.py ALL docs/source/conf.py ALL - -[flake8] -max-line-length = 160 -ignore = E231,E302 - + * W503 +pep8maxlinelength = 90 diff --git a/test_natsort/compat/locale.py b/test_natsort/compat/locale.py index bf484a3..76e387c 100644 --- a/test_natsort/compat/locale.py +++ b/test_natsort/compat/locale.py @@ -1,10 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import # Std. lib imports. import locale @@ -16,13 +11,14 @@ from natsort.compat.py23 import py23_str, py23_unichr, py23_range 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("{0}.ISO8859-1".format(x))) except locale.Error: - locale.setlocale(locale.LC_ALL, str('{0}.UTF-8'.format(x))) + locale.setlocale(locale.LC_ALL, str("{0}.UTF-8".format(x))) + # Check if de_DE is installed. try: - load_locale('de_DE') + load_locale("de_DE") has_locale_de_DE = True except locale.Error: has_locale_de_DE = False @@ -38,8 +34,7 @@ except AttributeError: # that has nothing to do with natsort (a ValueError is raised by strxfrm). # Let's filter them out. try: - bad_uni_chars = set(py23_unichr(x) for x in py23_range(0X10fefd, - 0X10ffff+1)) + bad_uni_chars = set(py23_unichr(x) for x in py23_range(0X10fefd, 0X10ffff + 1)) except ValueError: # Narrow unicode build... no worries. bad_uni_chars = set() diff --git a/test_natsort/compat/mock.py b/test_natsort/compat/mock.py index 9ddb302..10c6ccd 100644 --- a/test_natsort/compat/mock.py +++ b/test_natsort/compat/mock.py @@ -1,10 +1,6 @@ # -*- coding: utf-8 -*- -from __future__ import ( - print_function, - division, - unicode_literals, - absolute_import -) +from __future__ import print_function, division, unicode_literals, absolute_import + # Load mock functions from the right place. try: from unittest.mock import MagicMock, patch, call diff --git a/test_natsort/profile_natsorted.py b/test_natsort/profile_natsorted.py index e744b16..6fe5746 100644 --- a/test_natsort/profile_natsorted.py +++ b/test_natsort/profile_natsorted.py @@ -7,21 +7,22 @@ from __future__ import print_function import cProfile import sys -sys.path.insert(0, '.') +sys.path.insert(0, ".") from natsort import natsort_keygen, ns from natsort.compat.py23 import py23_range import locale -locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') + +locale.setlocale(locale.LC_ALL, "en_US.UTF-8") # Samples to parse number = 14695498 -int_string = '43493' -float_string = '-434.93e7' -plain_string = 'hello world' -fancy_string = '7abba9342fdab' -a_path = '/p/Folder (1)/file (1).tar.gz' -some_bytes = b'these are bytes' -a_list = ['hello', 'goodbye', '74'] +int_string = "43493" +float_string = "-434.93e7" +plain_string = "hello world" +fancy_string = "7abba9342fdab" +a_path = "/p/Folder (1)/file (1).tar.gz" +some_bytes = b"these are bytes" +a_list = ["hello", "goodbye", "74"] basic_key = natsort_keygen() real_key = natsort_keygen(alg=ns.REAL) @@ -30,22 +31,35 @@ locale_key = natsort_keygen(alg=ns.LOCALE) def prof_time_to_generate(): - print('*** Generate Plain Key ***') + print("*** Generate Plain Key ***") for _ in py23_range(100000): natsort_keygen() -cProfile.run('prof_time_to_generate()', sort='time') + + +cProfile.run("prof_time_to_generate()", sort="time") def prof_parsing(a, msg, key=basic_key): print(msg) for _ in py23_range(100000): key(a) -cProfile.run('prof_parsing(int_string, "*** Basic Call, Int as String ***")', sort='time') -cProfile.run('prof_parsing(float_string, "*** Basic Call, Float as String ***")', sort='time') -cProfile.run('prof_parsing(float_string, "*** Real Call ***", real_key)', sort='time') -cProfile.run('prof_parsing(number, "*** Basic Call, Number ***")', sort='time') -cProfile.run('prof_parsing(fancy_string, "*** Basic Call, Mixed String ***")', sort='time') -cProfile.run('prof_parsing(some_bytes, "*** Basic Call, Byte String ***")', sort='time') -cProfile.run('prof_parsing(a_path, "*** Path Call ***", path_key)', sort='time') -cProfile.run('prof_parsing(a_list, "*** Basic Call, Recursive ***")', sort='time') -cProfile.run('prof_parsing("434,930,000 dollars", "*** Locale Call ***", locale_key)', sort='time') + + +cProfile.run( + 'prof_parsing(int_string, "*** Basic Call, Int as String ***")', sort="time" +) +cProfile.run( + 'prof_parsing(float_string, "*** Basic Call, Float as String ***")', sort="time" +) +cProfile.run('prof_parsing(float_string, "*** Real Call ***", real_key)', sort="time") +cProfile.run('prof_parsing(number, "*** Basic Call, Number ***")', sort="time") +cProfile.run( + 'prof_parsing(fancy_string, "*** Basic Call, Mixed String ***")', sort="time" +) +cProfile.run('prof_parsing(some_bytes, "*** Basic Call, Byte String ***")', sort="time") +cProfile.run('prof_parsing(a_path, "*** Path Call ***", path_key)', sort="time") +cProfile.run('prof_parsing(a_list, "*** Basic Call, Recursive ***")', sort="time") +cProfile.run( + 'prof_parsing("434,930,000 dollars", "*** Locale Call ***", locale_key)', + sort="time", +) diff --git a/test_natsort/slow_splitters.py b/test_natsort/slow_splitters.py index cd36161..51989ab 100644 --- a/test_natsort/slow_splitters.py +++ b/test_natsort/slow_splitters.py @@ -14,13 +14,12 @@ if PY_VERSION >= 3.0: triple_none = None, None, None _sentinel = object() -SplitElement = collections.namedtuple('SplitElement', - ['isnum', 'val', 'isuni']) +SplitElement = collections.namedtuple("SplitElement", ["isnum", "val", "isuni"]) def int_splitter(iterable, signed, sep): """Alternate (slow) method to split a string into numbers.""" - iterable = unicodedata.normalize('NFD', iterable) + iterable = unicodedata.normalize("NFD", iterable) split_by_decimal = itertools.groupby(iterable, lambda a: a.isdigit()) split_by_decimal = refine_split_grouping(split_by_decimal) split = int_splitter_iter(split_by_decimal, signed) @@ -34,7 +33,7 @@ def float_splitter(iterable, signed, exp, sep): def number_tester(x): return x.isdecimal() or unicodedata.numeric(x, None) is not None - iterable = unicodedata.normalize('NFD', iterable) + iterable = unicodedata.normalize("NFD", iterable) split_by_decimal = itertools.groupby(iterable, number_tester) split_by_decimal = peekable(refine_split_grouping(split_by_decimal)) split = float_splitter_iter(split_by_decimal, signed, exp) @@ -56,17 +55,17 @@ def refine_split_grouping(iterable): yield SplitElement(True, u, True) # If ASCII, combine into a single multicharacter number. else: - val = ''.join(num_values) + val = "".join(num_values) yield SplitElement(True, val, False) else: # If non-numeric, combine into a single string. - val = ''.join(values) + val = "".join(values) yield SplitElement(False, val, False) def group_unicode_and_ascii_numbers( - iterable, ascii_digits=frozenset(decimals + '0123456789') + iterable, ascii_digits=frozenset(decimals + "0123456789") ): """ Use groupby to group ASCII and unicode numeric characters. @@ -84,31 +83,42 @@ def int_splitter_iter(iterable, signed): yield int(val) elif signed: for x in try_to_read_signed_integer(iterable, val): - yield int(''.join(x)) if isinstance(x, list) else x + yield int("".join(x)) if isinstance(x, list) else x else: yield val def float_splitter_iter(iterable, signed, exp): """Split the input into integers and other.""" - weird_check = ('-inf', '-infinity', '+inf', '+infinity', - 'inf', 'infinity', 'nan', '-nan', '+nan') + weird_check = ( + "-inf", + "-infinity", + "+inf", + "+infinity", + "inf", + "infinity", + "nan", + "-nan", + "+nan", + ) try_to_read_float_correctly = [ try_to_read_float, try_to_read_float_with_exp, - functools.partial(try_to_read_signed_float_template, - key=try_to_read_float), - functools.partial(try_to_read_signed_float_template, - key=try_to_read_float_with_exp), - ][signed * 2 + exp * 1] # Choose the appropriate converter function. + functools.partial(try_to_read_signed_float_template, key=try_to_read_float), + functools.partial( + try_to_read_signed_float_template, key=try_to_read_float_with_exp + ), + ][ + signed * 2 + exp * 1 + ] # Choose the appropriate converter function. for isnum, val, isuni in iterable: if isuni: yield unicodedata.numeric(val) else: for x in try_to_read_float_correctly(iterable, isnum, val): if isinstance(x, list): - yield float(''.join(x)) - elif x.lower().strip(' \t\n\r\f\v') in weird_check: + yield float("".join(x)) + elif x.lower().strip(" \t\n\r\f\v") in weird_check: yield float(x) else: yield x @@ -119,7 +129,7 @@ def try_to_read_signed_integer(iterable, val): If the given string ends with +/-, attempt to return a signed int. Otherwise, return the string as-is. """ - if val.endswith(('+', '-')): + if val.endswith(("+", "-")): next_element = next(iterable, None) # Last element, return as-is. @@ -138,7 +148,7 @@ def try_to_read_signed_integer(iterable, val): yield unicodedata.digit(next_val) # If the val is *only* the sign, return only the number. - elif val in ('-', '+'): + elif val in ("-", "+"): yield [val, next_val] # Otherwise, remove the sign from the val and apply it to the number, @@ -167,14 +177,14 @@ def try_to_read_float(iterable, isnum, val): yield val # If this the decimal point, add it to the number and return. - elif val == '.': + elif val == ".": next(iterable) # To progress the iterator. yield [val, next_val] # If the val ends with the decimal point, split the decimal point # off the end of the string then place it to the front of the # iterable so that we can use it later. - elif val.endswith('.'): + elif val.endswith("."): iterable.push(SplitElement(False, val[-1], False)) yield val[:-1] @@ -186,9 +196,9 @@ def try_to_read_float(iterable, isnum, val): else: # If the next element is not '.', return now. - if next_val != '.': + if next_val != ".": # If the next val starts with a '.', let's add that. - if next_val is not None and next_val.startswith('.'): + if next_val is not None and next_val.startswith("."): next(iterable) # To progress the iterator. iterable.push(SplitElement(False, next_val[1:], False)) yield [val, next_val[0]] @@ -214,7 +224,7 @@ def try_to_read_float_with_exp(iterable, isnum, val): Try to read a string that matches num.numE[+-]num and return as a float. Otherwise return the input as found. """ - exp_ident = ('e', 'E', 'e-', 'E-', 'e+', 'E+') + exp_ident = ("e", "E", "e-", "E-", "e+", "E+") # Start by reading the floating point part. float_ret = next(try_to_read_float(iterable, isnum, val)) @@ -253,10 +263,10 @@ def try_to_read_signed_float_template(iterable, isnum, val, key): # If it looks like there is a sign here and the next value is a # non-unicode number, try to parse that with the sign. - if val.endswith(('+', '-')) and next_isnum and not next_isuni: + if val.endswith(("+", "-")) and next_isnum and not next_isuni: # If this value is a sign, return the combo. - if val in ('+', '-'): + if val in ("+", "-"): next(iterable) # To progress the iterator. yield [val] + next(key(iterable, next_isnum, next_val)) @@ -269,13 +279,13 @@ def try_to_read_signed_float_template(iterable, isnum, val, key): # If it looks like there is a sign here and the next value is a # decimal, try to parse as a decimal. - elif val.endswith(('+.', '-.')) and next_isnum and not next_isuni: + elif val.endswith(("+.", "-.")) and next_isnum and not next_isuni: # Push back a zero before the decimal then parse. print(val, iterable.peek()) # If this value is a sign, return the combo - if val[:-1] in ('+', '-'): + if val[:-1] in ("+", "-"): yield [val[:-1]] + next(key(iterable, False, val[-1])) # If the val ends with the sign split the decimal the end of @@ -366,6 +376,7 @@ class peekable(object): >>> assert peekable(xrange(1)) >>> assert not peekable([]) """ + # Lowercase to blend in with itertools. The fact that it's a class is an # implementation detail. @@ -389,7 +400,7 @@ class peekable(object): Return ``default`` if there are no items left. If ``default`` is not provided, raise ``StopIteration``. """ - if not hasattr(self, '_peek'): + if not hasattr(self, "_peek"): try: self._peek = next(self._it) except StopIteration: @@ -410,7 +421,7 @@ class peekable(object): def push(self, value): """Put an element at the front of the iterable.""" - if hasattr(self, '_peek'): + if hasattr(self, "_peek"): self._it = itertools.chain([value, self._peek], self._it) del self._peek else: diff --git a/test_natsort/test_fake_fastnumbers.py b/test_natsort/test_fake_fastnumbers.py index 52bbb8c..e22714d 100644 --- a/test_natsort/test_fake_fastnumbers.py +++ b/test_natsort/test_fake_fastnumbers.py @@ -7,18 +7,9 @@ from __future__ import unicode_literals import unicodedata from math import isnan from natsort.compat.py23 import PY_VERSION -from natsort.compat.fake_fastnumbers import ( - fast_float, - fast_int, -) -from hypothesis import ( - given, -) -from hypothesis.strategies import ( - floats, - integers, - text, -) +from natsort.compat.fake_fastnumbers import fast_float, fast_int +from hypothesis import given +from hypothesis.strategies import floats, integers, text if PY_VERSION >= 3: long = int @@ -68,18 +59,18 @@ def not_an_int(x): def test_fast_float_returns_nan_alternate_if_nan_option_is_given(): - assert fast_float('nan', nan=7) == 7 + assert fast_float("nan", nan=7) == 7 def test_fast_float_converts_float_string_to_float_example(): - assert fast_float('45.8') == 45.8 - assert fast_float('-45') == -45.0 - assert fast_float('45.8e-2', key=len) == 45.8e-2 - assert isnan(fast_float('nan')) - assert isnan(fast_float('+nan')) - assert isnan(fast_float('-NaN')) - assert fast_float('۱۲.۱۲') == 12.12 - assert fast_float('-۱۲.۱۲') == -12.12 + assert fast_float("45.8") == 45.8 + assert fast_float("-45") == -45.0 + assert fast_float("45.8e-2", key=len) == 45.8e-2 + assert isnan(fast_float("nan")) + assert isnan(fast_float("+nan")) + assert isnan(fast_float("-NaN")) + assert fast_float("۱۲.۱۲") == 12.12 + assert fast_float("-۱۲.۱۲") == -12.12 @given(floats(allow_nan=False)) @@ -88,7 +79,7 @@ def test_fast_float_converts_float_string_to_float(x): def test_fast_float_leaves_string_as_is_example(): - assert fast_float('invalid') == 'invalid' + assert fast_float("invalid") == "invalid" @given(text().filter(not_a_float).filter(bool)) @@ -97,7 +88,7 @@ def test_fast_float_leaves_string_as_is(x): def test_fast_float_with_key_applies_to_string_example(): - assert fast_float('invalid', key=len) == len('invalid') + assert fast_float("invalid", key=len) == len("invalid") @given(text().filter(not_a_float).filter(bool)) @@ -106,9 +97,9 @@ def test_fast_float_with_key_applies_to_string(x): def test_fast_int_leaves_float_string_as_is_example(): - assert fast_int('45.8') == '45.8' - assert fast_int('nan') == 'nan' - assert fast_int('inf') == 'inf' + assert fast_int("45.8") == "45.8" + assert fast_int("nan") == "nan" + assert fast_int("inf") == "inf" @given(floats().filter(not_an_int)) @@ -117,10 +108,10 @@ def test_fast_int_leaves_float_string_as_is(x): def test_fast_int_converts_int_string_to_int_example(): - assert fast_int('-45') == -45 - assert fast_int('+45') == 45 - assert fast_int('۱۲') == 12 - assert fast_int('-۱۲') == -12 + assert fast_int("-45") == -45 + assert fast_int("+45") == 45 + assert fast_int("۱۲") == 12 + assert fast_int("-۱۲") == -12 @given(integers()) @@ -129,7 +120,7 @@ def test_fast_int_converts_int_string_to_int(x): def test_fast_int_leaves_string_as_is_example(): - assert fast_int('invalid') == 'invalid' + assert fast_int("invalid") == "invalid" @given(text().filter(not_an_int).filter(bool)) @@ -138,7 +129,7 @@ def test_fast_int_leaves_string_as_is(x): def test_fast_int_with_key_applies_to_string_example(): - assert fast_int('invalid', key=len) == len('invalid') + assert fast_int("invalid", key=len) == len("invalid") @given(text().filter(not_an_int).filter(bool)) diff --git a/test_natsort/test_final_data_transform_factory.py b/test_natsort/test_final_data_transform_factory.py index f0207e6..d5f5d61 100644 --- a/test_natsort/test_final_data_transform_factory.py +++ b/test_natsort/test_final_data_transform_factory.py @@ -5,14 +5,8 @@ from __future__ import unicode_literals from natsort.ns_enum import ns from natsort.utils import _final_data_transform_factory from natsort.compat.py23 import py23_str -from hypothesis import ( - given, -) -from hypothesis.strategies import ( - text, - floats, - integers, -) +from hypothesis import given +from hypothesis.strategies import text, floats, integers # Each test has an "example" version for demonstrative purposes, @@ -20,38 +14,62 @@ from hypothesis.strategies import ( def test_final_data_transform_factory_with_iterable_returns_tuple_with_no_options_example(): - assert _final_data_transform_factory(0, '', '')(iter([7]), '') == (7,) + assert _final_data_transform_factory(0, "", "")(iter([7]), "") == (7,) @given(text()) def test_final_data_transform_factory_with_iterable_returns_tuple_with_no_options(x): - assert _final_data_transform_factory(0, '', '')(iter([x]), '') == (x,) + assert _final_data_transform_factory(0, "", "")(iter([x]), "") == (x,) # UNGROUPLETTERS without LOCALE does nothing, as does LOCALE without UNGROUPLETTERS - assert _final_data_transform_factory(ns.UNGROUPLETTERS, '', '')(iter([x]), '') == _final_data_transform_factory(0, '', '')(iter([x]), '') - assert _final_data_transform_factory(ns.LOCALE, '', '')(iter([x]), '') == _final_data_transform_factory(0, '', '')(iter([x]), '') + assert _final_data_transform_factory(ns.UNGROUPLETTERS, "", "")( + iter([x]), "" + ) == _final_data_transform_factory(0, "", "")(iter([x]), "") + assert _final_data_transform_factory(ns.LOCALE, "", "")( + iter([x]), "" + ) == _final_data_transform_factory(0, "", "")(iter([x]), "") def test_final_data_transform_factory_with_empty_tuple_returns_double_empty_tuple(): - assert _final_data_transform_factory(ns.LOCALE | ns.UNGROUPLETTERS, '', '')((), '') == ((), ()) + assert _final_data_transform_factory(ns.LOCALE | ns.UNGROUPLETTERS, "", "")( + (), "" + ) == ((), ()) def test_final_data_transform_factory_with_null_string_first_element_adds_empty_string_on_first_tuple_element(): - assert _final_data_transform_factory(ns.LOCALE | ns.UNGROUPLETTERS, '', 'xx')(('', 60), '') == (('xx',), ('', 60)) + assert _final_data_transform_factory(ns.LOCALE | ns.UNGROUPLETTERS, "", "xx")( + ("", 60), "" + ) == (("xx",), ("", 60)) def test_final_data_transform_factory_returns_first_element_in_first_tuple_element_example(): - assert _final_data_transform_factory(ns.LOCALE | ns.UNGROUPLETTERS, '', '')(('this', 60), 'this60') == (('t',), ('this', 60)) + assert _final_data_transform_factory(ns.LOCALE | ns.UNGROUPLETTERS, "", "")( + ("this", 60), "this60" + ) == (("t",), ("this", 60)) -@given(x=text().filter(bool), y=floats(allow_nan=False, allow_infinity=False) | integers()) -def test_final_data_transform_factory_returns_first_element_in_first_tuple_element(x, y): - assert _final_data_transform_factory(ns.LOCALE | ns.UNGROUPLETTERS, '', '')((x, y), ''.join(map(py23_str, [x, y]))) == ((x[0],), (x, y)) +@given( + x=text().filter(bool), y=floats(allow_nan=False, allow_infinity=False) | integers() +) +def test_final_data_transform_factory_returns_first_element_in_first_tuple_element( + x, y +): + assert _final_data_transform_factory(ns.LOCALE | ns.UNGROUPLETTERS, "", "")( + (x, y), "".join(map(py23_str, [x, y])) + ) == ((x[0],), (x, y)) def test_final_data_transform_factory_returns_first_element_in_first_tuple_element_caseswapped_with_DUMB_and_LOWERCASEFIRST_example(): - assert _final_data_transform_factory(ns.LOCALE | ns.UNGROUPLETTERS | ns._DUMB | ns.LOWERCASEFIRST, '', '')(('this', 60), 'this60') == (('T',), ('this', 60)) + assert _final_data_transform_factory( + ns.LOCALE | ns.UNGROUPLETTERS | ns._DUMB | ns.LOWERCASEFIRST, "", "" + )(("this", 60), "this60") == (("T",), ("this", 60)) -@given(x=text().filter(bool), y=floats(allow_nan=False, allow_infinity=False) | integers()) -def test_final_data_transform_factory_returns_first_element_in_first_tuple_element_caseswapped_with_DUMB_and_LOWERCASEFIRST(x, y): - assert _final_data_transform_factory(ns.LOCALE | ns.UNGROUPLETTERS | ns._DUMB | ns.LOWERCASEFIRST, '', '')((x, y), ''.join(map(py23_str, [x, y]))) == ((x[0].swapcase(),), (x, y)) +@given( + x=text().filter(bool), y=floats(allow_nan=False, allow_infinity=False) | integers() +) +def test_final_data_transform_factory_returns_first_element_in_first_tuple_element_caseswapped_with_DUMB_and_LOWERCASEFIRST( + x, y +): + assert _final_data_transform_factory( + ns.LOCALE | ns.UNGROUPLETTERS | ns._DUMB | ns.LOWERCASEFIRST, "", "" + )((x, y), "".join(map(py23_str, [x, y]))) == ((x[0].swapcase(),), (x, y)) diff --git a/test_natsort/test_input_string_transform_factory.py b/test_natsort/test_input_string_transform_factory.py index 3dbd843..dbc4c09 100644 --- a/test_natsort/test_input_string_transform_factory.py +++ b/test_natsort/test_input_string_transform_factory.py @@ -8,18 +8,9 @@ from operator import methodcaller from natsort.ns_enum import ns from natsort.utils import _input_string_transform_factory from natsort.compat.py23 import NEWPY -from compat.locale import ( - load_locale, - has_locale_de_DE, -) -from hypothesis import ( - given, -) -from hypothesis.strategies import ( - text, - integers, - lists, -) +from compat.locale import load_locale, has_locale_de_DE +from hypothesis import given +from hypothesis.strategies import text, integers, lists # Each test has an "example" version for demonstrative purposes, @@ -27,7 +18,7 @@ from hypothesis.strategies import ( def test_input_string_transform_factory_is_no_op_for_no_alg_options_examples(): - x = 'feijGGAd' + x = "feijGGAd" assert _input_string_transform_factory(0)(x) is x @@ -37,7 +28,7 @@ def test_input_string_transform_factory_is_no_op_for_no_alg_options(x): def test_input_string_transform_factory_performs_casefold_with_IGNORECASE_examples(): - x = 'feijGGAd' + x = "feijGGAd" if NEWPY: assert _input_string_transform_factory(ns.IGNORECASE)(x) == x.casefold() else: @@ -53,7 +44,7 @@ def test_input_string_transform_factory_performs_casefold_with_IGNORECASE(x): def test_input_string_transform_factory_performs_swapcase_with_DUMB_examples(): - x = 'feijGGAd' + x = "feijGGAd" assert _input_string_transform_factory(ns._DUMB)(x) == x.swapcase() @@ -63,18 +54,18 @@ def test_input_string_transform_factory_performs_swapcase_with_DUMB(x): def test_input_string_transform_factory_performs_swapcase_with_LOWERCASEFIRST_example(): - x = 'feijGGAd' + x = "feijGGAd" assert _input_string_transform_factory(ns.LOWERCASEFIRST)(x) == x.swapcase() @given(text()) def test_input_string_transform_factory_performs_swapcase_with_LOWERCASEFIRST(x): - x = 'feijGGAd' + x = "feijGGAd" assert _input_string_transform_factory(ns.LOWERCASEFIRST)(x) == x.swapcase() def test_input_string_transform_factory_is_no_op_with_both_LOWERCASEFIRST_AND_DUMB_example(): - x = 'feijGGAd' + x = "feijGGAd" assert _input_string_transform_factory(ns._DUMB | ns.LOWERCASEFIRST)(x) is x @@ -84,100 +75,145 @@ def test_input_string_transform_factory_is_no_op_with_both_LOWERCASEFIRST_AND_DU def test_input_string_transform_factory_performs_swapcase_and_casefold_both_LOWERCASEFIRST_AND_IGNORECASE_example(): - x = 'feijGGAd' + x = "feijGGAd" if NEWPY: - assert _input_string_transform_factory(ns.IGNORECASE | ns.LOWERCASEFIRST)(x) == x.swapcase().casefold() + assert ( + _input_string_transform_factory(ns.IGNORECASE | ns.LOWERCASEFIRST)(x) + == x.swapcase().casefold() + ) else: - assert _input_string_transform_factory(ns.IGNORECASE | ns.LOWERCASEFIRST)(x) == x.swapcase().lower() + assert ( + _input_string_transform_factory(ns.IGNORECASE | ns.LOWERCASEFIRST)(x) + == x.swapcase().lower() + ) @given(text()) -def test_input_string_transform_factory_performs_swapcase_and_casefold_both_LOWERCASEFIRST_AND_IGNORECASE(x): +def test_input_string_transform_factory_performs_swapcase_and_casefold_both_LOWERCASEFIRST_AND_IGNORECASE( + x +): if NEWPY: - assert _input_string_transform_factory(ns.IGNORECASE | ns.LOWERCASEFIRST)(x) == x.swapcase().casefold() + assert ( + _input_string_transform_factory(ns.IGNORECASE | ns.LOWERCASEFIRST)(x) + == x.swapcase().casefold() + ) else: - assert _input_string_transform_factory(ns.IGNORECASE | ns.LOWERCASEFIRST)(x) == x.swapcase().lower() + assert ( + _input_string_transform_factory(ns.IGNORECASE | ns.LOWERCASEFIRST)(x) + == x.swapcase().lower() + ) def test_input_string_transform_factory_removes_thousands_separator_with_LOCALE_example(): - load_locale('en_US') - x = '12,543,642,642.534,534,980' # Without FLOAT it does not account for decimal. - assert _input_string_transform_factory(ns.LOCALE)(x) == '12543642642.534534980' - x = '12,543,642,642.534,534,980' # LOCALEALPHA doesn't do anything... need LOCALENUM - assert _input_string_transform_factory(ns.LOCALEALPHA)(x) == '12,543,642,642.534,534,980' - locale.setlocale(locale.LC_ALL, str('')) + load_locale("en_US") + x = "12,543,642,642.534,534,980" # Without FLOAT it does not account for decimal. + assert _input_string_transform_factory(ns.LOCALE)(x) == "12543642642.534534980" + x = ( + "12,543,642,642.534,534,980" + ) # LOCALEALPHA doesn't do anything... need LOCALENUM + assert ( + _input_string_transform_factory(ns.LOCALEALPHA)(x) + == "12,543,642,642.534,534,980" + ) + locale.setlocale(locale.LC_ALL, str("")) @given(lists(elements=integers(), min_size=4, max_size=20)) def test_input_string_transform_factory_removes_thousands_separator_with_LOCALE(x): - load_locale('en_US') - t = ''.join(map(methodcaller('rstrip', 'lL'), map(str, map(abs, x)))) # Remove negative signs trailing L - s = '' + load_locale("en_US") + t = "".join( + map(methodcaller("rstrip", "lL"), map(str, map(abs, x))) + ) # Remove negative signs trailing L + s = "" for i, y in enumerate(reversed(t), 1): s = y + s if i % 3 == 0 and i != len(t): - s = ',' + s + s = "," + s assert _input_string_transform_factory(ns.LOCALE)(s) == t - locale.setlocale(locale.LC_ALL, str('')) + locale.setlocale(locale.LC_ALL, str("")) def test_input_string_transform_factory_removes_thousands_separator_and_is_float_aware_with_LOCALE_and_FLOAT_example(): - x = '12,543,642,642.534,534,980' - assert _input_string_transform_factory(ns.LOCALE | ns.FLOAT)(x) == '12543642642.534,534980' + x = "12,543,642,642.534,534,980" + assert ( + _input_string_transform_factory(ns.LOCALE | ns.FLOAT)(x) + == "12543642642.534,534980" + ) -@given(lists(elements=integers(), min_size=4, max_size=20), lists(elements=integers(), min_size=4, max_size=20)) -def test_input_string_transform_factory_removes_thousands_separator_and_is_float_aware_with_LOCALE_and_FLOAT(x, y): - load_locale('en_US') - t = ''.join(map(methodcaller('rstrip', 'lL'), map(str, map(abs, x)))) # Remove negative signs trailing L - s = '' +@given( + lists(elements=integers(), min_size=4, max_size=20), + lists(elements=integers(), min_size=4, max_size=20), +) +def test_input_string_transform_factory_removes_thousands_separator_and_is_float_aware_with_LOCALE_and_FLOAT( + x, y +): + load_locale("en_US") + t = "".join( + map(methodcaller("rstrip", "lL"), map(str, map(abs, x))) + ) # Remove negative signs trailing L + s = "" for i, z in enumerate(reversed(t), 1): s = z + s if i % 3 == 0 and i != len(t): - s = ',' + s - u = ''.join(map(methodcaller('rstrip', 'lL'), map(str, map(abs, y)))) # Remove negative signs trailing L - v = '' + s = "," + s + u = "".join( + map(methodcaller("rstrip", "lL"), map(str, map(abs, y))) + ) # Remove negative signs trailing L + v = "" for i, z in enumerate(reversed(u), 1): v = z + v if i % 3 == 0 and i != len(u): - v = ',' + v + v = "," + v # Remove all but first comma. - a = v.split(',', 1) - p = a[0] + ',' + a[1].replace(',', '') - assert _input_string_transform_factory(ns.LOCALE)('.'.join([s, v])) == '.'.join([t, u]) - assert _input_string_transform_factory(ns.LOCALE | ns.FLOAT)('.'.join([s, v])) == '.'.join([t, p]) - locale.setlocale(locale.LC_ALL, str('')) + a = v.split(",", 1) + p = a[0] + "," + a[1].replace(",", "") + assert _input_string_transform_factory(ns.LOCALE)(".".join([s, v])) == ".".join( + [t, u] + ) + assert _input_string_transform_factory(ns.LOCALE | ns.FLOAT)( + ".".join([s, v]) + ) == ".".join([t, p]) + locale.setlocale(locale.LC_ALL, str("")) # These might be too much to test with hypothesis. def test_input_string_transform_factory_leaves_invalid_thousands_separator_with_LOCALE_example(): - load_locale('en_US') - x = '12,543,642642.5345,34980' - assert _input_string_transform_factory(ns.LOCALE)(x) == '12543,642642.5345,34980' - x = '12,59443,642,642.53,4534980' - assert _input_string_transform_factory(ns.LOCALE)(x) == '12,59443,642642.53,4534980' - x = '12543,642,642.5,34534980' - assert _input_string_transform_factory(ns.LOCALE)(x) == '12543,642642.5,34534980' - locale.setlocale(locale.LC_ALL, str('')) + load_locale("en_US") + x = "12,543,642642.5345,34980" + assert _input_string_transform_factory(ns.LOCALE)(x) == "12543,642642.5345,34980" + x = "12,59443,642,642.53,4534980" + assert _input_string_transform_factory(ns.LOCALE)(x) == "12,59443,642642.53,4534980" + x = "12543,642,642.5,34534980" + assert _input_string_transform_factory(ns.LOCALE)(x) == "12543,642642.5,34534980" + locale.setlocale(locale.LC_ALL, str("")) # @pytest.mark.skipif(not has_locale_de_DE or dumb_sort(), reason='requires de_DE locale and working locale') -@pytest.mark.skipif(not has_locale_de_DE, reason='requires de_DE locale and working locale') +@pytest.mark.skipif( + not has_locale_de_DE, reason="requires de_DE locale and working locale" +) def test_input_string_transform_factory_replaces_decimal_separator_with_LOCALE_example(): - load_locale('de_DE') - x = '1543,753' - assert _input_string_transform_factory(ns.LOCALE)(x) == '1543,753' # Does nothing without FLOAT - assert _input_string_transform_factory(ns.LOCALE | ns.FLOAT)(x) == '1543.753' - assert _input_string_transform_factory(ns.LOCALEALPHA)(x) == '1543,753' # LOCALEALPHA doesn't do anything... need LOCALENUM - locale.setlocale(locale.LC_ALL, str('')) + load_locale("de_DE") + x = "1543,753" + assert ( + _input_string_transform_factory(ns.LOCALE)(x) == "1543,753" + ) # Does nothing without FLOAT + assert _input_string_transform_factory(ns.LOCALE | ns.FLOAT)(x) == "1543.753" + assert ( + _input_string_transform_factory(ns.LOCALEALPHA)(x) == "1543,753" + ) # LOCALEALPHA doesn't do anything... need LOCALENUM + locale.setlocale(locale.LC_ALL, str("")) # @pytest.mark.skipif(not has_locale_de_DE or dumb_sort(), reason='requires de_DE locale and working locale') -@pytest.mark.skipif(not has_locale_de_DE, reason='requires de_DE locale and working locale') +@pytest.mark.skipif( + not has_locale_de_DE, reason="requires de_DE locale and working locale" +) def test_input_string_transform_factory_does_not_replace_invalid_decimal_separator_with_LOCALE_example(): - load_locale('de_DE') - x = '154s,t53' - assert _input_string_transform_factory(ns.LOCALE | ns.FLOAT)(x) == '154s,t53' - locale.setlocale(locale.LC_ALL, str('')) + load_locale("de_DE") + x = "154s,t53" + assert _input_string_transform_factory(ns.LOCALE | ns.FLOAT)(x) == "154s,t53" + locale.setlocale(locale.LC_ALL, str("")) diff --git a/test_natsort/test_main.py b/test_natsort/test_main.py index 6455c69..85b7151 100644 --- a/test_natsort/test_main.py +++ b/test_natsort/test_main.py @@ -7,15 +7,8 @@ import re import sys from pytest import raises from compat.mock import patch, call -from hypothesis import ( - given, -) -from hypothesis.strategies import ( - integers, - floats, - lists, - data, -) +from hypothesis import given +from hypothesis.strategies import integers, floats, lists, data from natsort.__main__ import ( main, range_check, @@ -27,8 +20,8 @@ from natsort.__main__ import ( def test_main_passes_default_arguments_with_no_command_line_options(): - with patch('natsort.__main__.sort_and_print_entries') as p: - sys.argv[1:] = ['num-2', 'num-6', 'num-1'] + with patch("natsort.__main__.sort_and_print_entries") as p: + sys.argv[1:] = ["num-2", "num-6", "num-1"] main() args = p.call_args[0][1] assert not args.paths @@ -36,20 +29,36 @@ def test_main_passes_default_arguments_with_no_command_line_options(): assert args.reverse_filter is None assert args.exclude is None assert not args.reverse - assert args.number_type == 'int' + assert args.number_type == "int" assert not args.signed assert args.exp assert not args.locale def test_main_passes_arguments_with_all_command_line_options(): - with patch('natsort.__main__.sort_and_print_entries') as p: - sys.argv[1:] = ['--paths', '--reverse', '--locale', - '--filter', '4', '10', - '--reverse-filter', '100', '110', - '--number-type', 'float', '--noexp', '--sign', - '--exclude', '34', '--exclude', '35', - 'num-2', 'num-6', 'num-1'] + with patch("natsort.__main__.sort_and_print_entries") as p: + sys.argv[1:] = [ + "--paths", + "--reverse", + "--locale", + "--filter", + "4", + "10", + "--reverse-filter", + "100", + "110", + "--number-type", + "float", + "--noexp", + "--sign", + "--exclude", + "34", + "--exclude", + "35", + "num-2", + "num-6", + "num-1", + ] main() args = p.call_args[0][1] assert args.paths @@ -57,7 +66,7 @@ def test_main_passes_arguments_with_all_command_line_options(): assert args.reverse_filter == [(100.0, 110.0)] assert args.exclude == [34, 35] assert args.reverse - assert args.number_type == 'float' + assert args.number_type == "float" assert args.signed assert not args.exp assert args.locale @@ -65,26 +74,30 @@ def test_main_passes_arguments_with_all_command_line_options(): class Args: """A dummy class to simulate the argparse Namespace object""" + def __init__(self, filt, reverse_filter, exclude, as_path, reverse): self.filter = filt self.reverse_filter = reverse_filter self.exclude = exclude self.reverse = reverse - self.number_type = 'float' + self.number_type = "float" self.signed = True self.exp = True self.paths = as_path self.locale = 0 -entries = ['tmp/a57/path2', - 'tmp/a23/path1', - 'tmp/a1/path1', - 'tmp/a1 (1)/path1', - 'tmp/a130/path1', - 'tmp/a64/path1', - 'tmp/a64/path2'] -mock_print = '__builtin__.print' if sys.version[0] == '2' else 'builtins.print' +entries = [ + "tmp/a57/path2", + "tmp/a23/path1", + "tmp/a1/path1", + "tmp/a1 (1)/path1", + "tmp/a130/path1", + "tmp/a64/path1", + "tmp/a64/path2", +] + +mock_print = "__builtin__.print" if sys.version[0] == "2" else "builtins.print" def test_sort_and_print_entries_uses_default_algorithm_with_all_options_false(): @@ -165,20 +178,27 @@ def test_sort_and_print_entries_reverses_order_with_reverse_option(): # Each test has an "example" version for demonstrative purposes, # and a test that uses the hypothesis module. + def test_range_check_returns_range_as_is_but_with_floats_if_first_is_less_than_second_example(): assert range_check(10, 11) == (10.0, 11.0) assert range_check(6.4, 30) == (6.4, 30.0) @given(x=integers(), data=data()) # Defer data selection for y till test is run. -def test_range_check_returns_range_as_is_but_with_floats_if_first_is_less_than_second(x, data): +def test_range_check_returns_range_as_is_but_with_floats_if_first_is_less_than_second( + x, data +): # Pull data such that the first is less than the second. y = data.draw(integers(min_value=x + 1)) assert range_check(x, y) == (x, y) -@given(x=floats(allow_nan=False, min_value=-1E8, max_value=1E8), data=data()) # Defer data selection for y till test is run. -def test_range_check_returns_range_as_is_but_with_floats_if_first_is_less_than_second2(x, data): +@given( + x=floats(allow_nan=False, min_value=-1E8, max_value=1E8), data=data() +) # Defer data selection for y till test is run. +def test_range_check_returns_range_as_is_but_with_floats_if_first_is_less_than_second2( + x, data +): # Pull data such that the first is less than the second. y = data.draw(floats(min_value=x + 1.0, max_value=1E9, allow_nan=False)) assert range_check(x, y) == (x, y) @@ -187,16 +207,18 @@ def test_range_check_returns_range_as_is_but_with_floats_if_first_is_less_than_s def test_range_check_raises_ValueError_if_second_is_less_than_first_example(): with raises(ValueError) as err: range_check(7, 2) - assert str(err.value) == 'low >= high' + assert str(err.value) == "low >= high" -@given(x=floats(allow_nan=False), data=data()) # Defer data selection for y till test is run. +@given( + x=floats(allow_nan=False), data=data() +) # Defer data selection for y till test is run. def test_range_check_raises_ValueError_if_second_is_less_than_first(x, data): # Pull data such that the first is greater than or equal to the second. y = data.draw(floats(max_value=x, allow_nan=False)) with raises(ValueError) as err: range_check(x, y) - assert str(err.value) == 'low >= high' + assert str(err.value) == "low >= high" def test_check_filter_returns_None_if_filter_evaluates_to_False(): @@ -210,41 +232,50 @@ def test_check_filter_returns_input_as_is_if_filter_is_valid_example(): assert check_filter([(6, 7), (2, 8)]) == [(6, 7), (2, 8)] -@given(x=lists(integers(), min_size=1), data=data()) # Defer data selection for y till test is run. +@given( + x=lists(integers(), min_size=1), data=data() +) # Defer data selection for y till test is run. def test_check_filter_returns_input_as_is_if_filter_is_valid(x, data): - y = [data.draw(integers(min_value=val + 1)) for val in x] # ensure y is element-wise greater than x + y = [ + data.draw(integers(min_value=val + 1)) for val in x + ] # ensure y is element-wise greater than x assert check_filter(list(zip(x, y))) == [(i, j) for i, j in zip(x, y)] def test_check_filter_raises_ValueError_if_filter_is_invalid_example(): with raises(ValueError) as err: check_filter([(7, 2)]) - assert str(err.value) == 'Error in --filter: low >= high' + assert str(err.value) == "Error in --filter: low >= high" -@given(x=lists(integers(), min_size=1), data=data()) # Defer data selection for y till test is run. +@given( + x=lists(integers(), min_size=1), data=data() +) # Defer data selection for y till test is run. def test_check_filter_raises_ValueError_if_filter_is_invalid(x, data): - y = [data.draw(integers(max_value=val)) for val in x] # ensure y is element-wise less than or equal to x + y = [ + data.draw(integers(max_value=val)) for val in x + ] # ensure y is element-wise less than or equal to x + with raises(ValueError) as err: check_filter(list(zip(x, y))) - assert str(err.value) == 'Error in --filter: low >= high' + assert str(err.value) == "Error in --filter: low >= high" def test_keep_entry_range_returns_True_if_any_portion_of_input_is_between_the_range_bounds_example(): - assert keep_entry_range('a56b23c89', [0], [100], int, re.compile(r'\d+')) + assert keep_entry_range("a56b23c89", [0], [100], int, re.compile(r"\d+")) def test_keep_entry_range_returns_True_if_any_portion_of_input_is_between_any_range_bounds_example(): - assert keep_entry_range('a56b23c89', [1, 88], [20, 90], int, re.compile(r'\d+')) + assert keep_entry_range("a56b23c89", [1, 88], [20, 90], int, re.compile(r"\d+")) def test_keep_entry_range_returns_False_if_no_portion_of_input_is_between_the_range_bounds_example(): - assert not keep_entry_range('a56b23c89', [1], [20], int, re.compile(r'\d+')) + assert not keep_entry_range("a56b23c89", [1], [20], int, re.compile(r"\d+")) def test_exclude_entry_returns_True_if_exlcude_parameters_are_not_in_input_example(): - assert exclude_entry('a56b23c89', [100, 45], int, re.compile(r'\d+')) + assert exclude_entry("a56b23c89", [100, 45], int, re.compile(r"\d+")) def test_exclude_entry_returns_False_if_exlcude_parameters_are_in_input_example(): - assert not exclude_entry('a56b23c89', [23], int, re.compile(r'\d+')) + assert not exclude_entry("a56b23c89", [23], int, re.compile(r"\d+")) diff --git a/test_natsort/test_natsort_cmp.py b/test_natsort/test_natsort_cmp.py index 6c6d87b..f7d5d8b 100644 --- a/test_natsort/test_natsort_cmp.py +++ b/test_natsort/test_natsort_cmp.py @@ -24,6 +24,7 @@ if PY_VERSION < 3: class Comparable(object): """Stub class for testing natcmp functionality.""" + def __init__(self, value): self.value = value @@ -31,7 +32,7 @@ class Comparable(object): return natcmp(self.value, other.value) -@pytest.mark.skipif(PY_VERSION >= 3.0, reason='cmp() deprecated in Python 3') +@pytest.mark.skipif(PY_VERSION >= 3.0, reason="cmp() deprecated in Python 3") def test__classes_can_be_compared(): one = Comparable("1") two = Comparable("2") @@ -41,7 +42,7 @@ def test__classes_can_be_compared(): assert ten > two == another_two > one -@pytest.mark.skipif(PY_VERSION >= 3.0, reason='cmp() deprecated in Python 3') +@pytest.mark.skipif(PY_VERSION >= 3.0, reason="cmp() deprecated in Python 3") def test__keys_are_being_cached(): natcmp.cached_keys = {} assert len(natcmp.cached_keys) == 0 @@ -50,20 +51,20 @@ def test__keys_are_being_cached(): natcmp(0, 0) assert len(natcmp.cached_keys) == 1 - with patch('natsort.compat.locale.dumb_sort', return_value=False): + with patch("natsort.compat.locale.dumb_sort", return_value=False): natcmp(0, 0, alg=ns.L) assert len(natcmp.cached_keys) == 2 natcmp(0, 0, alg=ns.L) assert len(natcmp.cached_keys) == 2 - with patch('natsort.compat.locale.dumb_sort', return_value=True): + with patch("natsort.compat.locale.dumb_sort", return_value=True): natcmp(0, 0, alg=ns.L) assert len(natcmp.cached_keys) == 3 natcmp(0, 0, alg=ns.L) assert len(natcmp.cached_keys) == 3 -@pytest.mark.skipif(PY_VERSION >= 3.0, reason='cmp() deprecated in Python 3') +@pytest.mark.skipif(PY_VERSION >= 3.0, reason="cmp() deprecated in Python 3") def test__illegal_algorithm_raises_error(): try: natcmp(0, 0, alg="Just random stuff") @@ -76,7 +77,7 @@ def test__illegal_algorithm_raises_error(): assert False -@pytest.mark.skipif(PY_VERSION >= 3.0, reason='cmp() deprecated in Python 3') +@pytest.mark.skipif(PY_VERSION >= 3.0, reason="cmp() deprecated in Python 3") def test__classes_can_utilize_max_or_min(): comparables = [Comparable(i) for i in range(10)] @@ -84,19 +85,19 @@ def test__classes_can_utilize_max_or_min(): assert min(comparables) == comparables[0] -@pytest.mark.skipif(PY_VERSION >= 3.0, reason='cmp() deprecated in Python 3') +@pytest.mark.skipif(PY_VERSION >= 3.0, reason="cmp() deprecated in Python 3") @given(integers(), integers()) def test__natcmp_works_the_same_for_integers_as_cmp(x, y): assert py23_cmp(x, y) == natcmp(x, y) -@pytest.mark.skipif(PY_VERSION >= 3.0, reason='cmp() deprecated in Python 3') +@pytest.mark.skipif(PY_VERSION >= 3.0, reason="cmp() deprecated in Python 3") @given(floats(allow_nan=False), floats(allow_nan=False)) def test__natcmp_works_the_same_for_floats_as_cmp(x, y): assert py23_cmp(x, y) == natcmp(x, y) -@pytest.mark.skipif(PY_VERSION >= 3.0, reason='cmp() deprecated in Python 3') +@pytest.mark.skipif(PY_VERSION >= 3.0, reason="cmp() deprecated in Python 3") @given(lists(elements=integers())) def test_sort_strings_with_numbers(a_list): strings = [str(var) for var in a_list] diff --git a/test_natsort/test_natsort_key.py b/test_natsort/test_natsort_key.py index 9aabd11..0d35d54 100644 --- a/test_natsort/test_natsort_key.py +++ b/test_natsort/test_natsort_key.py @@ -16,16 +16,8 @@ from natsort.utils import ( _string_component_transform_factory, _final_data_transform_factory, ) -from hypothesis import ( - given, -) -from hypothesis.strategies import ( - lists, - text, - floats, - integers, - binary, -) +from hypothesis import given +from hypothesis.strategies import lists, text, floats, integers, binary if PY_VERSION >= 3: long = int @@ -34,10 +26,10 @@ if PY_VERSION >= 3: regex = _regex_chooser[ns.INT] pre = _input_string_transform_factory(ns.INT) post = _string_component_transform_factory(ns.INT) -after = _final_data_transform_factory(ns.INT, '', '') -string_func = _parse_string_factory(ns.INT, '', regex.split, pre, post, after) +after = _final_data_transform_factory(ns.INT, "", "") +string_func = _parse_string_factory(ns.INT, "", regex.split, pre, post, after) bytes_func = _parse_bytes_factory(ns.INT) -num_func = _parse_number_factory(ns.INT, '', '') +num_func = _parse_number_factory(ns.INT, "", "") def test__natsort_key_with_numeric_input_and_PATH_returns_number_in_nested_tuple(): @@ -45,26 +37,30 @@ def test__natsort_key_with_numeric_input_and_PATH_returns_number_in_nested_tuple # so it will sort against the other as_path results. sfunc = _parse_path_factory(string_func) bytes_func = _parse_bytes_factory(ns.PATH) - num_func = _parse_number_factory(ns.PATH, '', '') - assert _natsort_key(10, None, sfunc, bytes_func, num_func) == (('', 10),) + num_func = _parse_number_factory(ns.PATH, "", "") + assert _natsort_key(10, None, sfunc, bytes_func, num_func) == (("", 10),) -@pytest.mark.skipif(PY_VERSION < 3, reason='only valid on python3') +@pytest.mark.skipif(PY_VERSION < 3, reason="only valid on python3") def test__natsort_key_with_bytes_input_and_PATH_returns_number_in_nested_tuple(): # It gracefully handles as_path for numeric input by putting an extra tuple around it # so it will sort against the other as_path results. sfunc = _parse_path_factory(string_func) bytes_func = _parse_bytes_factory(ns.PATH) - num_func = _parse_number_factory(ns.PATH, '', '') - assert _natsort_key(b'/hello/world', None, sfunc, bytes_func, num_func) == ((b'/hello/world',),) + num_func = _parse_number_factory(ns.PATH, "", "") + assert _natsort_key(b"/hello/world", None, sfunc, bytes_func, num_func) == ( + (b"/hello/world",), + ) def test__natsort_key_with_tuple_of_paths_and_PATH_returns_triply_nested_tuple(): # PATH also handles recursion well. sfunc = _parse_path_factory(string_func) bytes_func = _parse_bytes_factory(ns.PATH) - num_func = _parse_number_factory(ns.PATH, '', '') - assert _natsort_key(('/Folder', '/Folder (1)'), None, sfunc, bytes_func, num_func) == ((('/',), ('Folder',)), (('/',), ('Folder (', 1, ')'))) + num_func = _parse_number_factory(ns.PATH, "", "") + assert _natsort_key( + ("/Folder", "/Folder (1)"), None, sfunc, bytes_func, num_func + ) == ((("/",), ("Folder",)), (("/",), ("Folder (", 1, ")"))) # The remaining tests provide no examples, just hypothesis tests. @@ -76,21 +72,27 @@ def test__natsort_key_with_numeric_input_takes_number_path(x): assert _natsort_key(x, None, string_func, bytes_func, num_func) == num_func(x) -@pytest.mark.skipif(PY_VERSION < 3, reason='only valid on python3') +@pytest.mark.skipif(PY_VERSION < 3, reason="only valid on python3") @given(binary().filter(bool)) def test__natsort_key_with_bytes_input_takes_bytes_path(x): assert _natsort_key(x, None, string_func, bytes_func, num_func) == bytes_func(x) -@given(lists(elements=floats(allow_nan=False) | text() | integers(), min_size=1, max_size=10)) +@given( + lists( + elements=floats(allow_nan=False) | text() | integers(), min_size=1, max_size=10 + ) +) def test__natsort_key_with_text_input_takes_string_path(x): - s = ''.join(repr(y) if type(y) in (float, long, int) else y for y in x) + s = "".join(repr(y) if type(y) in (float, long, int) else y for y in x) assert _natsort_key(s, None, string_func, bytes_func, num_func) == string_func(s) @given(lists(elements=text(), min_size=1, max_size=10)) def test__natsort_key_with_nested_input_takes_nested_path(x): - assert _natsort_key(x, None, string_func, bytes_func, num_func) == tuple(string_func(s) for s in x) + assert _natsort_key(x, None, string_func, bytes_func, num_func) == tuple( + string_func(s) for s in x + ) @given(text()) diff --git a/test_natsort/test_natsort_keygen.py b/test_natsort/test_natsort_keygen.py index 9ea408a..5fc10d6 100644 --- a/test_natsort/test_natsort_keygen.py +++ b/test_natsort/test_natsort_keygen.py @@ -8,34 +8,29 @@ from __future__ import unicode_literals, print_function import warnings import locale from pytest import raises -from natsort import ( - natsorted, - natsort_key, - natsort_keygen, - ns, -) +from natsort import natsorted, natsort_key, natsort_keygen, ns from natsort.compat.py23 import PY_VERSION -from natsort.compat.locale import ( - null_string_locale, - get_strxfrm, -) +from natsort.compat.locale import null_string_locale, get_strxfrm from compat.mock import patch from compat.locale import load_locale -INPUT = ['6A-5.034e+1', '/Folder (1)/Foo', 56.7] +INPUT = ["6A-5.034e+1", "/Folder (1)/Foo", 56.7] def test_natsort_key_public_raises_DeprecationWarning_when_called(): # But it raises a deprecation warning with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") - assert natsort_key('a-5.034e2') == ('a-', 5, '.', 34, 'e', 2) + assert natsort_key("a-5.034e2") == ("a-", 5, ".", 34, "e", 2) assert len(w) == 1 - assert "natsort_key is deprecated as of 3.4.0, please use natsort_keygen" in str(w[-1].message) + assert ( + "natsort_key is deprecated as of 3.4.0, please use natsort_keygen" + in str(w[-1].message) + ) # It is called for each element in a list when sorting with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") - a = ['a2', 'a5', 'a9', 'a1', 'a4', 'a10', 'a6'] + a = ["a2", "a5", "a9", "a1", "a4", "a10", "a6"] a.sort(key=natsort_key) assert len(w) == 7 @@ -43,63 +38,137 @@ def test_natsort_key_public_raises_DeprecationWarning_when_called(): def test_natsort_keygen_with_invalid_alg_input_raises_ValueError(): # Invalid arguments give the correct response with raises(ValueError) as err: - natsort_keygen(None, '1') - assert str(err.value) == "natsort_keygen: 'alg' argument must be from the enum 'ns', got 1" + natsort_keygen(None, "1") + assert ( + str(err.value) + == "natsort_keygen: 'alg' argument must be from the enum 'ns', got 1" + ) def test_natsort_keygen_returns_natsort_key_that_parses_input(): - a = 'a-5.034e1' - assert natsort_keygen()(a) == ('a-', 5, '.', 34, 'e', 1) - assert natsort_keygen(alg=ns.F | ns.S)(a) == ('a', -50.34) + a = "a-5.034e1" + assert natsort_keygen()(a) == ("a-", 5, ".", 34, "e", 1) + assert natsort_keygen(alg=ns.F | ns.S)(a) == ("a", -50.34) def test_natsort_keygen_returns_key_that_can_be_used_to_sort_list_in_place_with_same_result_as_natsorted(): - a = ['a50', 'a51.', 'a50.31', 'a50.4', 'a5.034e1', 'a50.300'] + a = ["a50", "a51.", "a50.31", "a50.4", "a5.034e1", "a50.300"] b = a[:] a.sort(key=natsort_keygen(alg=ns.F)) assert a == natsorted(b, alg=ns.F) def test_natsort_keygen_splits_input_with_defaults(): - assert natsort_keygen()(INPUT) == (('', 6, 'A-', 5, '.', 34, 'e+', 1), ('/Folder (', 1, ')/Foo'), ('', 56.7)) - if PY_VERSION >= 3: assert natsort_keygen()(b'6A-5.034e+1') == (b'6A-5.034e+1',) + assert natsort_keygen()(INPUT) == ( + ("", 6, "A-", 5, ".", 34, "e+", 1), + ("/Folder (", 1, ")/Foo"), + ("", 56.7), + ) + if PY_VERSION >= 3: + assert natsort_keygen()(b"6A-5.034e+1") == (b"6A-5.034e+1",) def test_natsort_keygen_splits_input_with_real(): - assert natsort_keygen(alg=ns.R)(INPUT) == (('', 6.0, 'A', -50.34), ('/Folder (', 1.0, ')/Foo'), ('', 56.7)) - if PY_VERSION >= 3: assert natsort_keygen(alg=ns.R)(b'6A-5.034e+1') == (b'6A-5.034e+1',) + assert natsort_keygen(alg=ns.R)(INPUT) == ( + ("", 6.0, "A", -50.34), + ("/Folder (", 1.0, ")/Foo"), + ("", 56.7), + ) + if PY_VERSION >= 3: + assert natsort_keygen(alg=ns.R)(b"6A-5.034e+1") == (b"6A-5.034e+1",) def test_natsort_keygen_splits_input_with_lowercasefirst_noexp_float(): - assert natsort_keygen(alg=ns.LF | ns.F | ns.N)(INPUT) == (('', 6.0, 'a-', 5.034, 'E+', 1.0), ('/fOLDER (', 1.0, ')/fOO'), ('', 56.7)) - if PY_VERSION >= 3: assert natsort_keygen(alg=ns.LF | ns.F | ns.N)(b'6A-5.034e+1') == (b'6A-5.034e+1',) + assert natsort_keygen(alg=ns.LF | ns.F | ns.N)(INPUT) == ( + ("", 6.0, "a-", 5.034, "E+", 1.0), + ("/fOLDER (", 1.0, ")/fOO"), + ("", 56.7), + ) + if PY_VERSION >= 3: + assert natsort_keygen(alg=ns.LF | ns.F | ns.N)(b"6A-5.034e+1") == ( + b"6A-5.034e+1", + ) def test_natsort_keygen_splits_input_with_locale(): - load_locale('en_US') + load_locale("en_US") strxfrm = get_strxfrm() - with patch('natsort.compat.locale.dumb_sort', return_value=False): - assert natsort_keygen(alg=ns.L)(INPUT) == ((null_string_locale, 6, strxfrm('A-'), 5, strxfrm('.'), 34, strxfrm('e+'), 1), (strxfrm('/Folder ('), 1, strxfrm(')/Foo')), (null_string_locale, 56.7)) - with patch('natsort.compat.locale.dumb_sort', return_value=True): - assert natsort_keygen(alg=ns.L)(INPUT) == ((null_string_locale, 6, strxfrm('aa--'), 5, strxfrm('..'), 34, strxfrm('eE++'), 1), (strxfrm('//ffoOlLdDeErR (('), 1, strxfrm('))//ffoOoO')), (null_string_locale, 56.7)) - if PY_VERSION >= 3: assert natsort_keygen(alg=ns.LA)(b'6A-5.034e+1') == (b'6A-5.034e+1',) - locale.setlocale(locale.LC_ALL, str('')) + with patch("natsort.compat.locale.dumb_sort", return_value=False): + assert natsort_keygen(alg=ns.L)(INPUT) == ( + ( + null_string_locale, + 6, + strxfrm("A-"), + 5, + strxfrm("."), + 34, + strxfrm("e+"), + 1, + ), + (strxfrm("/Folder ("), 1, strxfrm(")/Foo")), + (null_string_locale, 56.7), + ) + with patch("natsort.compat.locale.dumb_sort", return_value=True): + assert natsort_keygen(alg=ns.L)(INPUT) == ( + ( + null_string_locale, + 6, + strxfrm("aa--"), + 5, + strxfrm(".."), + 34, + strxfrm("eE++"), + 1, + ), + (strxfrm("//ffoOlLdDeErR (("), 1, strxfrm("))//ffoOoO")), + (null_string_locale, 56.7), + ) + if PY_VERSION >= 3: + assert natsort_keygen(alg=ns.LA)(b"6A-5.034e+1") == (b"6A-5.034e+1",) + locale.setlocale(locale.LC_ALL, str("")) def test_natsort_keygen_splits_input_with_locale_and_capitalfirst(): - load_locale('en_US') + load_locale("en_US") strxfrm = get_strxfrm() - with patch('natsort.compat.locale.dumb_sort', return_value=False): - assert natsort_keygen(alg=ns.LA | ns.C)(INPUT) == ((('',), (null_string_locale, 6, strxfrm('A-'), 5, strxfrm('.'), 34, strxfrm('e+'), 1)), (('/',), (strxfrm('/Folder ('), 1, strxfrm(')/Foo'))), (('',), (null_string_locale, 56.7))) - if PY_VERSION >= 3: assert natsort_keygen(alg=ns.LA | ns.C)(b'6A-5.034e+1') == (b'6A-5.034e+1',) - locale.setlocale(locale.LC_ALL, str('')) + with patch("natsort.compat.locale.dumb_sort", return_value=False): + assert natsort_keygen(alg=ns.LA | ns.C)(INPUT) == ( + ( + ("",), + ( + null_string_locale, + 6, + strxfrm("A-"), + 5, + strxfrm("."), + 34, + strxfrm("e+"), + 1, + ), + ), + (("/",), (strxfrm("/Folder ("), 1, strxfrm(")/Foo"))), + (("",), (null_string_locale, 56.7)), + ) + if PY_VERSION >= 3: + assert natsort_keygen(alg=ns.LA | ns.C)(b"6A-5.034e+1") == (b"6A-5.034e+1",) + locale.setlocale(locale.LC_ALL, str("")) def test_natsort_keygen_splits_input_with_path(): - assert natsort_keygen(alg=ns.P | ns.G)(INPUT) == ((('', 6, 'aA--', 5, '..', 34, 'ee++', 1),), (('//',), ('fFoollddeerr ((', 1, '))'), ('fFoooo',)), (('', 56.7),)) - if PY_VERSION >= 3: assert natsort_keygen(alg=ns.P | ns.G)(b'6A-5.034e+1') == ((b'6A-5.034e+1',),) + assert natsort_keygen(alg=ns.P | ns.G)(INPUT) == ( + (("", 6, "aA--", 5, "..", 34, "ee++", 1),), + (("//",), ("fFoollddeerr ((", 1, "))"), ("fFoooo",)), + (("", 56.7),), + ) + if PY_VERSION >= 3: + assert natsort_keygen(alg=ns.P | ns.G)(b"6A-5.034e+1") == ((b"6A-5.034e+1",),) def test_natsort_keygen_splits_input_with_ignorecase(): - assert natsort_keygen(alg=ns.IC)(INPUT) == (('', 6, 'a-', 5, '.', 34, 'e+', 1), ('/folder (', 1, ')/foo'), ('', 56.7)) - if PY_VERSION >= 3: assert natsort_keygen(alg=ns.IC)(b'6A-5.034e+1') == (b'6a-5.034e+1',) + assert natsort_keygen(alg=ns.IC)(INPUT) == ( + ("", 6, "a-", 5, ".", 34, "e+", 1), + ("/folder (", 1, ")/foo"), + ("", 56.7), + ) + if PY_VERSION >= 3: + assert natsort_keygen(alg=ns.IC)(b"6A-5.034e+1") == (b"6a-5.034e+1",) diff --git a/test_natsort/test_natsorted.py b/test_natsort/test_natsorted.py index ce6b879..b698595 100644 --- a/test_natsort/test_natsorted.py +++ b/test_natsort/test_natsorted.py @@ -9,102 +9,166 @@ import locale from natsort.compat.py23 import PY_VERSION from operator import itemgetter from pytest import raises -from natsort import ( - natsorted, - ns, -) -from compat.locale import ( - load_locale, - has_locale_de_DE, -) +from natsort import natsorted, ns +from compat.locale import load_locale, has_locale_de_DE def test_natsorted_returns_strings_with_numbers_in_ascending_order(): - a = ['a2', 'a5', 'a9', 'a1', 'a4', 'a10', 'a6'] - assert natsorted(a) == ['a1', 'a2', 'a4', 'a5', 'a6', 'a9', 'a10'] + a = ["a2", "a5", "a9", "a1", "a4", "a10", "a6"] + assert natsorted(a) == ["a1", "a2", "a4", "a5", "a6", "a9", "a10"] def test_natsorted_returns_list_of_numbers_sorted_as_signed_floats_with_exponents(): - a = ['a50', 'a51.', 'a50.31', 'a-50', 'a50.4', 'a5.034e1', 'a50.300'] - assert natsorted(a, alg=ns.REAL) == ['a-50', 'a50', 'a50.300', 'a50.31', 'a5.034e1', 'a50.4', 'a51.'] + a = ["a50", "a51.", "a50.31", "a-50", "a50.4", "a5.034e1", "a50.300"] + assert natsorted(a, alg=ns.REAL) == [ + "a-50", + "a50", + "a50.300", + "a50.31", + "a5.034e1", + "a50.4", + "a51.", + ] def test_natsorted_returns_list_of_numbers_sorted_as_unsigned_floats_without_exponents_with_NOEXP_option(): - a = ['a50', 'a51.', 'a50.31', 'a-50', 'a50.4', 'a5.034e1', 'a50.300'] - assert natsorted(a, alg=ns.N | ns.F | ns.U) == ['a5.034e1', 'a50', 'a50.300', 'a50.31', 'a50.4', 'a51.', 'a-50'] + a = ["a50", "a51.", "a50.31", "a-50", "a50.4", "a5.034e1", "a50.300"] + assert natsorted(a, alg=ns.N | ns.F | ns.U) == [ + "a5.034e1", + "a50", + "a50.300", + "a50.31", + "a50.4", + "a51.", + "a-50", + ] # UNSIGNED is default - assert natsorted(a, alg=ns.NOEXP | ns.FLOAT) == ['a5.034e1', 'a50', 'a50.300', 'a50.31', 'a50.4', 'a51.', 'a-50'] + assert natsorted(a, alg=ns.NOEXP | ns.FLOAT) == [ + "a5.034e1", + "a50", + "a50.300", + "a50.31", + "a50.4", + "a51.", + "a-50", + ] def test_natsorted_returns_list_of_numbers_sorted_as_unsigned_ints_with_INT_option(): - a = ['a50', 'a51.', 'a50.31', 'a-50', 'a50.4', 'a5.034e1', 'a50.300'] - assert natsorted(a, alg=ns.INT) == ['a5.034e1', 'a50', 'a50.4', 'a50.31', 'a50.300', 'a51.', 'a-50'] + a = ["a50", "a51.", "a50.31", "a-50", "a50.4", "a5.034e1", "a50.300"] + assert natsorted(a, alg=ns.INT) == [ + "a5.034e1", + "a50", + "a50.4", + "a50.31", + "a50.300", + "a51.", + "a-50", + ] # INT is default - assert natsorted(a) == ['a5.034e1', 'a50', 'a50.4', 'a50.31', 'a50.300', 'a51.', 'a-50'] + assert natsorted(a) == [ + "a5.034e1", + "a50", + "a50.4", + "a50.31", + "a50.300", + "a51.", + "a-50", + ] def test_natsorted_returns_list_of_numbers_sorted_as_unsigned_ints_with_DIGIT_and_VERSION_option(): - a = ['a50', 'a51.', 'a50.31', 'a-50', 'a50.4', 'a5.034e1', 'a50.300'] - assert natsorted(a, alg=ns.DIGIT) == ['a5.034e1', 'a50', 'a50.4', 'a50.31', 'a50.300', 'a51.', 'a-50'] - assert natsorted(a, alg=ns.VERSION) == ['a5.034e1', 'a50', 'a50.4', 'a50.31', 'a50.300', 'a51.', 'a-50'] + a = ["a50", "a51.", "a50.31", "a-50", "a50.4", "a5.034e1", "a50.300"] + assert natsorted(a, alg=ns.DIGIT) == [ + "a5.034e1", + "a50", + "a50.4", + "a50.31", + "a50.300", + "a51.", + "a-50", + ] + assert natsorted(a, alg=ns.VERSION) == [ + "a5.034e1", + "a50", + "a50.4", + "a50.31", + "a50.300", + "a51.", + "a-50", + ] def test_natsorted_returns_list_of_numbers_sorted_as_signed_ints_with_SIGNED_option(): - a = ['a50', 'a51.', 'a50.31', 'a-50', 'a50.4', 'a5.034e1', 'a50.300'] - assert natsorted(a, alg=ns.SIGNED) == ['a-50', 'a5.034e1', 'a50', 'a50.4', 'a50.31', 'a50.300', 'a51.'] + a = ["a50", "a51.", "a50.31", "a-50", "a50.4", "a5.034e1", "a50.300"] + assert natsorted(a, alg=ns.SIGNED) == [ + "a-50", + "a5.034e1", + "a50", + "a50.4", + "a50.31", + "a50.300", + "a51.", + ] def test_natsorted_returns_list_of_numbers_sorted_accounting_for_sign_with_SIGNED_option(): - a = ['a-5', 'a7', 'a+2'] - assert natsorted(a, alg=ns.SIGNED) == ['a-5', 'a+2', 'a7'] + a = ["a-5", "a7", "a+2"] + assert natsorted(a, alg=ns.SIGNED) == ["a-5", "a+2", "a7"] def test_natsorted_returns_list_of_numbers_sorted_not_accounting_for_sign_without_SIGNED_option(): - a = ['a-5', 'a7', 'a+2'] - assert natsorted(a) == ['a7', 'a+2', 'a-5'] + a = ["a-5", "a7", "a+2"] + assert natsorted(a) == ["a7", "a+2", "a-5"] def test_natsorted_returns_sorted_list_of_version_numbers_by_default_or_with_VERSION_option(): - a = ['1.9.9a', '1.11', '1.9.9b', '1.11.4', '1.10.1'] - assert natsorted(a) == ['1.9.9a', '1.9.9b', '1.10.1', '1.11', '1.11.4'] - assert natsorted(a, alg=ns.VERSION) == ['1.9.9a', '1.9.9b', '1.10.1', '1.11', '1.11.4'] + a = ["1.9.9a", "1.11", "1.9.9b", "1.11.4", "1.10.1"] + assert natsorted(a) == ["1.9.9a", "1.9.9b", "1.10.1", "1.11", "1.11.4"] + assert natsorted(a, alg=ns.VERSION) == [ + "1.9.9a", + "1.9.9b", + "1.10.1", + "1.11", + "1.11.4", + ] def test_natsorted_returns_sorted_list_with_mixed_type_input_and_does_not_raise_TypeError_on_Python3(): # You can mix types with natsorted. This can get around the new # 'unorderable types' issue with Python 3. - a = [6, 4.5, '7', '2.5', 'a'] - assert natsorted(a) == ['2.5', 4.5, 6, '7', 'a'] - a = [46, '5a5b2', 'af5', '5a5-4'] - assert natsorted(a) == ['5a5-4', '5a5b2', 46, 'af5'] + a = [6, 4.5, "7", "2.5", "a"] + assert natsorted(a) == ["2.5", 4.5, 6, "7", "a"] + a = [46, "5a5b2", "af5", "5a5-4"] + assert natsorted(a) == ["5a5-4", "5a5b2", 46, "af5"] def test_natsorted_with_mixed_input_returns_sorted_results_without_error(): - a = ['0', 'Á', '2', 'Z'] - assert natsorted(a) == ['0', '2', 'Á', 'Z'] - assert natsorted(a, alg=ns.NUMAFTER) == ['Á', 'Z', '0', '2'] - a = ['2', 'ä', 'b', 1.5, 3] - assert natsorted(a) == [1.5, '2', 3, 'ä', 'b'] - assert natsorted(a, alg=ns.NUMAFTER) == ['ä', 'b', 1.5, '2', 3] + a = ["0", "Á", "2", "Z"] + assert natsorted(a) == ["0", "2", "Á", "Z"] + assert natsorted(a, alg=ns.NUMAFTER) == ["Á", "Z", "0", "2"] + a = ["2", "ä", "b", 1.5, 3] + assert natsorted(a) == [1.5, "2", 3, "ä", "b"] + assert natsorted(a, alg=ns.NUMAFTER) == ["ä", "b", 1.5, "2", 3] def test_natsorted_with_nan_input_returns_sorted_results_with_nan_last_with_NANLAST(): - a = ['25', 5, float('nan'), 1E40] + a = ["25", 5, float("nan"), 1E40] # The slice is because NaN != NaN - assert natsorted(a, alg=ns.NANLAST)[:3] == [5, '25', 1E40, float('nan')][:3] + assert natsorted(a, alg=ns.NANLAST)[:3] == [5, "25", 1E40, float("nan")][:3] def test_natsorted_with_nan_input_returns_sorted_results_with_nan_first_without_NANLAST(): - a = ['25', 5, float('nan'), 1E40] + a = ["25", 5, float("nan"), 1E40] # The slice is because NaN != NaN - assert natsorted(a)[1:] == [float('nan'), 5, '25', 1E40][1:] + assert natsorted(a)[1:] == [float("nan"), 5, "25", 1E40][1:] def test_natsorted_with_mixed_input_raises_TypeError_if_bytes_type_is_involved_on_Python3(): if PY_VERSION >= 3: with raises(TypeError) as e: - assert natsorted(['ä', b'b']) - assert 'bytes' in str(e.value) + assert natsorted(["ä", b"b"]) + assert "bytes" in str(e.value) else: assert True @@ -116,177 +180,352 @@ def test_natsorted_raises_ValueError_for_non_iterable_input(): def test_natsorted_recursivley_applies_key_to_nested_lists_to_return_sorted_nested_list(): - data = [['a1', 'a5'], ['a1', 'a40'], ['a10', 'a1'], ['a2', 'a5']] - assert natsorted(data) == [['a1', 'a5'], ['a1', 'a40'], ['a2', 'a5'], ['a10', 'a1']] + data = [["a1", "a5"], ["a1", "a40"], ["a10", "a1"], ["a2", "a5"]] + assert natsorted(data) == [["a1", "a5"], ["a1", "a40"], ["a2", "a5"], ["a10", "a1"]] def test_natsorted_applies_key_to_each_list_element_before_sorting_list(): - b = [('a', 'num3'), ('b', 'num5'), ('c', 'num2')] - assert natsorted(b, key=itemgetter(1)) == [('c', 'num2'), ('a', 'num3'), ('b', 'num5')] + b = [("a", "num3"), ("b", "num5"), ("c", "num2")] + assert natsorted(b, key=itemgetter(1)) == [ + ("c", "num2"), + ("a", "num3"), + ("b", "num5"), + ] def test_natsorted_returns_list_in_reversed_order_with_reverse_option(): - a = ['a50', 'a51.', 'a50.31', 'a50.4', 'a5.034e1', 'a50.300'] + a = ["a50", "a51.", "a50.31", "a50.4", "a5.034e1", "a50.300"] assert natsorted(a, reverse=True) == natsorted(a)[::-1] def test_natsorted_sorts_OS_generated_paths_incorrectly_without_PATH_option(): - a = ['/p/Folder (10)/file.tar.gz', - '/p/Folder/file.tar.gz', - '/p/Folder (1)/file (1).tar.gz', - '/p/Folder (1)/file.tar.gz'] - assert natsorted(a) == ['/p/Folder (1)/file (1).tar.gz', - '/p/Folder (1)/file.tar.gz', - '/p/Folder (10)/file.tar.gz', - '/p/Folder/file.tar.gz'] + a = [ + "/p/Folder (10)/file.tar.gz", + "/p/Folder/file.tar.gz", + "/p/Folder (1)/file (1).tar.gz", + "/p/Folder (1)/file.tar.gz", + ] + assert natsorted(a) == [ + "/p/Folder (1)/file (1).tar.gz", + "/p/Folder (1)/file.tar.gz", + "/p/Folder (10)/file.tar.gz", + "/p/Folder/file.tar.gz", + ] def test_natsorted_sorts_OS_generated_paths_correctly_with_PATH_option(): - a = ['/p/Folder (10)/file.tar.gz', - '/p/Folder/file.tar.gz', - '/p/Folder (1)/file (1).tar.gz', - '/p/Folder (1)/file.tar.gz'] - assert natsorted(a, alg=ns.PATH) == ['/p/Folder/file.tar.gz', - '/p/Folder (1)/file.tar.gz', - '/p/Folder (1)/file (1).tar.gz', - '/p/Folder (10)/file.tar.gz'] + a = [ + "/p/Folder (10)/file.tar.gz", + "/p/Folder/file.tar.gz", + "/p/Folder (1)/file (1).tar.gz", + "/p/Folder (1)/file.tar.gz", + ] + assert natsorted(a, alg=ns.PATH) == [ + "/p/Folder/file.tar.gz", + "/p/Folder (1)/file.tar.gz", + "/p/Folder (1)/file (1).tar.gz", + "/p/Folder (10)/file.tar.gz", + ] def test_natsorted_can_handle_sorting_paths_and_numbers_with_PATH(): # You can sort paths and numbers, not that you'd want to - a = ['/Folder (9)/file.exe', 43] - assert natsorted(a, alg=ns.PATH) == [43, '/Folder (9)/file.exe'] + a = ["/Folder (9)/file.exe", 43] + assert natsorted(a, alg=ns.PATH) == [43, "/Folder (9)/file.exe"] def test_natsorted_returns_results_in_ASCII_order_with_no_case_options(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] - assert natsorted(a) == ['Apple', 'Banana', 'Corn', 'apple', 'banana', 'corn'] + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] + assert natsorted(a) == ["Apple", "Banana", "Corn", "apple", "banana", "corn"] def test_natsorted_returns_results_sorted_by_lowercase_ASCII_order_with_IGNORECASE(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] - assert natsorted(a, alg=ns.IGNORECASE) == ['Apple', 'apple', 'Banana', 'banana', 'corn', 'Corn'] + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] + assert natsorted(a, alg=ns.IGNORECASE) == [ + "Apple", + "apple", + "Banana", + "banana", + "corn", + "Corn", + ] def test_natsorted_returns_results_in_ASCII_order_but_with_lowercase_letters_first_with_LOWERCASEFIRST(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] - assert natsorted(a, alg=ns.LOWERCASEFIRST) == ['apple', 'banana', 'corn', 'Apple', 'Banana', 'Corn'] + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] + assert natsorted(a, alg=ns.LOWERCASEFIRST) == [ + "apple", + "banana", + "corn", + "Apple", + "Banana", + "Corn", + ] def test_natsorted_returns_results_with_uppercase_and_lowercase_letters_grouped_together_with_GROUPLETTERS(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] - assert natsorted(a, alg=ns.GROUPLETTERS) == ['Apple', 'apple', 'Banana', 'banana', 'Corn', 'corn'] + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] + assert natsorted(a, alg=ns.GROUPLETTERS) == [ + "Apple", + "apple", + "Banana", + "banana", + "Corn", + "corn", + ] def test_natsorted_returns_results_in_natural_order_with_GROUPLETTERS_and_LOWERCASEFIRST(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] - assert natsorted(a, alg=ns.G | ns.LF) == ['apple', 'Apple', 'banana', 'Banana', 'corn', 'Corn'] + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] + assert natsorted(a, alg=ns.G | ns.LF) == [ + "apple", + "Apple", + "banana", + "Banana", + "corn", + "Corn", + ] def test_natsorted_places_uppercase_letters_before_lowercase_letters_for_nested_input(): - b = [('A5', 'a6'), ('a3', 'a1')] - assert natsorted(b) == [('A5', 'a6'), ('a3', 'a1')] + b = [("A5", "a6"), ("a3", "a1")] + assert natsorted(b) == [("A5", "a6"), ("a3", "a1")] def test_natsorted_with_LOWERCASEFIRST_places_lowercase_letters_before_uppercase_letters_for_nested_input(): - b = [('A5', 'a6'), ('a3', 'a1')] - assert natsorted(b, alg=ns.LOWERCASEFIRST) == [('a3', 'a1'), ('A5', 'a6')] + b = [("A5", "a6"), ("a3", "a1")] + assert natsorted(b, alg=ns.LOWERCASEFIRST) == [("a3", "a1"), ("A5", "a6")] def test_natsorted_with_IGNORECASE_sorts_without_regard_to_case_for_nested_input(): - b = [('A5', 'a6'), ('a3', 'a1')] - assert natsorted(b, alg=ns.IGNORECASE) == [('a3', 'a1'), ('A5', 'a6')] + b = [("A5", "a6"), ("a3", "a1")] + assert natsorted(b, alg=ns.IGNORECASE) == [("a3", "a1"), ("A5", "a6")] def test_natsorted_with_LOCALE_returns_results_sorted_by_lowercase_first_and_grouped_letters(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] - load_locale('en_US') - assert natsorted(a, alg=ns.LOCALE) == ['apple', 'Apple', 'banana', 'Banana', 'corn', 'Corn'] - locale.setlocale(locale.LC_ALL, str('')) + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] + load_locale("en_US") + assert natsorted(a, alg=ns.LOCALE) == [ + "apple", + "Apple", + "banana", + "Banana", + "corn", + "Corn", + ] + locale.setlocale(locale.LC_ALL, str("")) def test_natsorted_with_LOCALE_and_CAPITALFIRST_returns_results_sorted_by_capital_first_and_ungrouped(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] - load_locale('en_US') - assert natsorted(a, alg=ns.LOCALE | ns.CAPITALFIRST) == ['Apple', 'Banana', 'Corn', 'apple', 'banana', 'corn'] - locale.setlocale(locale.LC_ALL, str('')) + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] + load_locale("en_US") + assert natsorted(a, alg=ns.LOCALE | ns.CAPITALFIRST) == [ + "Apple", + "Banana", + "Corn", + "apple", + "banana", + "corn", + ] + locale.setlocale(locale.LC_ALL, str("")) def test_natsorted_with_LOCALE_and_LOWERCASEFIRST_returns_results_sorted_by_uppercase_first_and_grouped_letters(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] - load_locale('en_US') - assert natsorted(a, alg=ns.LOCALE | ns.LOWERCASEFIRST) == ['Apple', 'apple', 'Banana', 'banana', 'Corn', 'corn'] - locale.setlocale(locale.LC_ALL, str('')) + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] + load_locale("en_US") + assert natsorted(a, alg=ns.LOCALE | ns.LOWERCASEFIRST) == [ + "Apple", + "apple", + "Banana", + "banana", + "Corn", + "corn", + ] + locale.setlocale(locale.LC_ALL, str("")) def test_natsorted_with_LOCALE_and_CAPITALFIRST_and_LOWERCASE_returns_results_sorted_by_capital_last_and_ungrouped(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] - load_locale('en_US') - assert natsorted(a, alg=ns.LOCALE | ns.CAPITALFIRST | ns.LOWERCASEFIRST) == ['apple', 'banana', 'corn', 'Apple', 'Banana', 'Corn'] - locale.setlocale(locale.LC_ALL, str('')) + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] + load_locale("en_US") + assert natsorted(a, alg=ns.LOCALE | ns.CAPITALFIRST | ns.LOWERCASEFIRST) == [ + "apple", + "banana", + "corn", + "Apple", + "Banana", + "Corn", + ] + locale.setlocale(locale.LC_ALL, str("")) def test_natsorted_with_LOCALE_and_en_setting_returns_results_sorted_by_en_language(): - load_locale('en_US') - a = ['c', 'a5,467.86', 'ä', 'b', 'a5367.86', 'a5,6', 'a5,50'] - assert natsorted(a, alg=ns.LOCALE | ns.F) == ['a5,6', 'a5,50', 'a5367.86', 'a5,467.86', 'ä', 'b', 'c'] - locale.setlocale(locale.LC_ALL, str('')) - - -@pytest.mark.skipif(not has_locale_de_DE, reason='requires de_DE locale and working locale') + load_locale("en_US") + a = ["c", "a5,467.86", "ä", "b", "a5367.86", "a5,6", "a5,50"] + assert natsorted(a, alg=ns.LOCALE | ns.F) == [ + "a5,6", + "a5,50", + "a5367.86", + "a5,467.86", + "ä", + "b", + "c", + ] + locale.setlocale(locale.LC_ALL, str("")) + + +@pytest.mark.skipif( + not has_locale_de_DE, reason="requires de_DE locale and working locale" +) def test_natsorted_with_LOCALE_and_de_setting_returns_results_sorted_by_de_language(): - load_locale('de_DE') - a = ['c', 'a5.467,86', 'ä', 'b', 'a5367.86', 'a5,6', 'a5,50'] - assert natsorted(a, alg=ns.LOCALE | ns.F) == ['a5,50', 'a5,6', 'a5367.86', 'a5.467,86', 'ä', 'b', 'c'] - locale.setlocale(locale.LC_ALL, str('')) + load_locale("de_DE") + a = ["c", "a5.467,86", "ä", "b", "a5367.86", "a5,6", "a5,50"] + assert natsorted(a, alg=ns.LOCALE | ns.F) == [ + "a5,50", + "a5,6", + "a5367.86", + "a5.467,86", + "ä", + "b", + "c", + ] + locale.setlocale(locale.LC_ALL, str("")) def test_natsorted_with_LOCALE_and_mixed_input_returns_sorted_results_without_error(): - load_locale('en_US') - a = ['0', 'Á', '2', 'Z'] - assert natsorted(a, alg=ns.LOCALE) == ['0', '2', 'Á', 'Z'] - assert natsorted(a, alg=ns.LOCALE | ns.NUMAFTER) == ['Á', 'Z', '0', '2'] - a = ['2', 'ä', 'b', 1.5, 3] - assert natsorted(a, alg=ns.LOCALE) == [1.5, '2', 3, 'ä', 'b'] - assert natsorted(a, alg=ns.LOCALE | ns.NUMAFTER) == ['ä', 'b', 1.5, '2', 3] - locale.setlocale(locale.LC_ALL, str('')) + load_locale("en_US") + a = ["0", "Á", "2", "Z"] + assert natsorted(a, alg=ns.LOCALE) == ["0", "2", "Á", "Z"] + assert natsorted(a, alg=ns.LOCALE | ns.NUMAFTER) == ["Á", "Z", "0", "2"] + a = ["2", "ä", "b", 1.5, 3] + assert natsorted(a, alg=ns.LOCALE) == [1.5, "2", 3, "ä", "b"] + assert natsorted(a, alg=ns.LOCALE | ns.NUMAFTER) == ["ä", "b", 1.5, "2", 3] + locale.setlocale(locale.LC_ALL, str("")) def test_natsorted_with_LOCALE_and_UNGROUPLETTERS_and_mixed_input_returns_sorted_results_without_error(): - load_locale('en_US') - a = ['0', 'Á', '2', 'Z'] - assert natsorted(a, alg=ns.LOCALE | ns.UNGROUPLETTERS) == ['0', '2', 'Á', 'Z'] - assert natsorted(a, alg=ns.LOCALE | ns.UNGROUPLETTERS | ns.NUMAFTER) == ['Á', 'Z', '0', '2'] - a = ['2', 'ä', 'b', 1.5, 3] - assert natsorted(a, alg=ns.LOCALE | ns.UNGROUPLETTERS) == [1.5, '2', 3, 'ä', 'b'] - assert natsorted(a, alg=ns.LOCALE | ns.UNGROUPLETTERS | ns.NUMAFTER) == ['ä', 'b', 1.5, '2', 3] - locale.setlocale(locale.LC_ALL, str('')) + load_locale("en_US") + a = ["0", "Á", "2", "Z"] + assert natsorted(a, alg=ns.LOCALE | ns.UNGROUPLETTERS) == ["0", "2", "Á", "Z"] + assert natsorted(a, alg=ns.LOCALE | ns.UNGROUPLETTERS | ns.NUMAFTER) == [ + "Á", + "Z", + "0", + "2", + ] + a = ["2", "ä", "b", 1.5, 3] + assert natsorted(a, alg=ns.LOCALE | ns.UNGROUPLETTERS) == [1.5, "2", 3, "ä", "b"] + assert natsorted(a, alg=ns.LOCALE | ns.UNGROUPLETTERS | ns.NUMAFTER) == [ + "ä", + "b", + 1.5, + "2", + 3, + ] + locale.setlocale(locale.LC_ALL, str("")) def test_natsorted_with_PATH_and_LOCALE_and_UNGROUPLETTERS_and_mixed_input_returns_sorted_results_without_error(): - load_locale('en_US') - a = ['0', 'Á', '2', 'Z'] - assert natsorted(a, alg=ns.PATH | ns.LOCALE | ns.UNGROUPLETTERS) == ['0', '2', 'Á', 'Z'] - assert natsorted(a, alg=ns.PATH | ns.LOCALE | ns.UNGROUPLETTERS | ns.NUMAFTER) == ['Á', 'Z', '0', '2'] - a = ['2', 'ä', 'b', 1.5, 3] - assert natsorted(a, alg=ns.PATH | ns.LOCALE | ns.UNGROUPLETTERS) == [1.5, '2', 3, 'ä', 'b'] - assert natsorted(a, alg=ns.PATH | ns.LOCALE | ns.UNGROUPLETTERS | ns.NUMAFTER) == ['ä', 'b', 1.5, '2', 3] - locale.setlocale(locale.LC_ALL, str('')) + load_locale("en_US") + a = ["0", "Á", "2", "Z"] + assert natsorted(a, alg=ns.PATH | ns.LOCALE | ns.UNGROUPLETTERS) == [ + "0", + "2", + "Á", + "Z", + ] + assert natsorted(a, alg=ns.PATH | ns.LOCALE | ns.UNGROUPLETTERS | ns.NUMAFTER) == [ + "Á", + "Z", + "0", + "2", + ] + a = ["2", "ä", "b", 1.5, 3] + assert natsorted(a, alg=ns.PATH | ns.LOCALE | ns.UNGROUPLETTERS) == [ + 1.5, + "2", + 3, + "ä", + "b", + ] + assert natsorted(a, alg=ns.PATH | ns.LOCALE | ns.UNGROUPLETTERS | ns.NUMAFTER) == [ + "ä", + "b", + 1.5, + "2", + 3, + ] + locale.setlocale(locale.LC_ALL, str("")) def test_natsorted_sorts_an_odd_collection_of_string(): - a = ['Corn', 'apple', 'Banana', '73', 'Apple', '5039', 'corn', '~~~~~~', 'banana'] - assert natsorted(a) == ['73', '5039', 'Apple', 'Banana', 'Corn', - 'apple', 'banana', 'corn', '~~~~~~'] - assert natsorted(a, alg=ns.NUMAFTER) == ['Apple', 'Banana', 'Corn', - 'apple', 'banana', 'corn', '~~~~~~', '73', '5039'] + a = ["Corn", "apple", "Banana", "73", "Apple", "5039", "corn", "~~~~~~", "banana"] + assert natsorted(a) == [ + "73", + "5039", + "Apple", + "Banana", + "Corn", + "apple", + "banana", + "corn", + "~~~~~~", + ] + assert natsorted(a, alg=ns.NUMAFTER) == [ + "Apple", + "Banana", + "Corn", + "apple", + "banana", + "corn", + "~~~~~~", + "73", + "5039", + ] def test_natsorted_sorts_mixed_ascii_and_non_ascii_numbers(): - a = ['1st street', '10th street', '2nd street', '2 street', '1 street', '1street', - '11 street', 'street 2', 'street 1', 'Street 11', '۲ street', '۱ street', '۱street', - '۱۲street', '۱۱ street', 'street ۲', 'street ۱', 'street ۱', 'street ۱۲', 'street ۱۱'] - expected = ['1 street', '۱ street', '1st street', '1street', '۱street', '2 street', '۲ street', - '2nd street', '10th street', '11 street', '۱۱ street', '۱۲street', 'street 1', - 'street ۱', 'street ۱', 'street 2', 'street ۲', 'Street 11', 'street ۱۱', 'street ۱۲'] + a = [ + "1st street", + "10th street", + "2nd street", + "2 street", + "1 street", + "1street", + "11 street", + "street 2", + "street 1", + "Street 11", + "۲ street", + "۱ street", + "۱street", + "۱۲street", + "۱۱ street", + "street ۲", + "street ۱", + "street ۱", + "street ۱۲", + "street ۱۱", + ] + expected = [ + "1 street", + "۱ street", + "1st street", + "1street", + "۱street", + "2 street", + "۲ street", + "2nd street", + "10th street", + "11 street", + "۱۱ street", + "۱۲street", + "street 1", + "street ۱", + "street ۱", + "street 2", + "street ۲", + "Street 11", + "street ۱۱", + "street ۱۲", + ] assert natsorted(a, alg=ns.IGNORECASE) == expected diff --git a/test_natsort/test_natsorted_convenience.py b/test_natsort/test_natsorted_convenience.py index 9e04493..850b6ff 100644 --- a/test_natsort/test_natsorted_convenience.py +++ b/test_natsort/test_natsorted_convenience.py @@ -24,10 +24,10 @@ from natsort import ( def test_decoder_returns_function_that_can_decode_bytes_but_return_non_bytes_as_is(): - f = decoder('latin1') - a = 'bytes' + f = decoder("latin1") + a = "bytes" b = 14 - assert f(b'bytes') == a + assert f(b"bytes") == a assert f(b) is b # returns as-is, same object ID if PY_VERSION >= 3: assert f(a) is a # same object returned on Python3 b/c only bytes has decode @@ -37,90 +37,88 @@ def test_decoder_returns_function_that_can_decode_bytes_but_return_non_bytes_as_ def test_as_ascii_returns_bytes_as_ascii(): - assert decoder('ascii')(b'bytes') == as_ascii(b'bytes') + assert decoder("ascii")(b"bytes") == as_ascii(b"bytes") def test_as_utf8_returns_bytes_as_utf8(): - assert decoder('utf8')(b'bytes') == as_utf8(b'bytes') + assert decoder("utf8")(b"bytes") == as_utf8(b"bytes") def test_versorted_returns_results_identical_to_natsorted(): - a = ['1.9.9a', '1.11', '1.9.9b', '1.11.4', '1.10.1'] + a = ["1.9.9a", "1.11", "1.9.9b", "1.11.4", "1.10.1"] # versorted is retained for backwards compatibility assert versorted(a) == natsorted(a) def test_realsorted_returns_results_identical_to_natsorted_with_REAL(): - a = ['a50', 'a51.', 'a50.31', 'a-50', 'a50.4', 'a5.034e1', 'a50.300'] + a = ["a50", "a51.", "a50.31", "a-50", "a50.4", "a5.034e1", "a50.300"] assert realsorted(a) == natsorted(a, alg=ns.REAL) def test_humansorted_returns_results_identical_to_natsorted_with_LOCALE(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] assert humansorted(a) == natsorted(a, alg=ns.LOCALE) def test_index_natsorted_returns_integer_list_of_sort_order_for_input_list(): - a = ['num3', 'num5', 'num2'] - b = ['foo', 'bar', 'baz'] + a = ["num3", "num5", "num2"] + b = ["foo", "bar", "baz"] index = index_natsorted(a) assert index == [2, 0, 1] - assert [a[i] for i in index] == ['num2', 'num3', 'num5'] - assert [b[i] for i in index] == ['baz', 'foo', 'bar'] + assert [a[i] for i in index] == ["num2", "num3", "num5"] + assert [b[i] for i in index] == ["baz", "foo", "bar"] def test_index_natsorted_returns_reversed_integer_list_of_sort_order_for_input_list_with_reverse_option(): - a = ['num3', 'num5', 'num2'] + a = ["num3", "num5", "num2"] assert index_natsorted(a, reverse=True) == [1, 0, 2] def test_index_natsorted_applies_key_function_before_sorting(): - c = [('a', 'num3'), ('b', 'num5'), ('c', 'num2')] + c = [("a", "num3"), ("b", "num5"), ("c", "num2")] assert index_natsorted(c, key=itemgetter(1)) == [2, 0, 1] def test_index_natsorted_handles_unorderable_types_error_on_Python3(): - a = [46, '5a5b2', 'af5', '5a5-4'] + a = [46, "5a5b2", "af5", "5a5-4"] assert index_natsorted(a) == [3, 1, 0, 2] def test_index_natsorted_returns_integer_list_of_nested_input_list(): - data = [['a1', 'a5'], ['a1', 'a40'], ['a10', 'a1'], ['a2', 'a5']] + data = [["a1", "a5"], ["a1", "a40"], ["a10", "a1"], ["a2", "a5"]] assert index_natsorted(data) == [0, 1, 3, 2] def test_index_natsorted_returns_integer_list_in_proper_order_for_input_paths_with_PATH(): - a = ['/p/Folder (10)/', - '/p/Folder/', - '/p/Folder (1)/'] + a = ["/p/Folder (10)/", "/p/Folder/", "/p/Folder (1)/"] assert index_natsorted(a, alg=ns.PATH) == [1, 2, 0] def test_index_versorted_returns_results_identical_to_index_natsorted(): - a = ['1.9.9a', '1.11', '1.9.9b', '1.11.4', '1.10.1'] + a = ["1.9.9a", "1.11", "1.9.9b", "1.11.4", "1.10.1"] # index_versorted is retained for backwards compatibility assert index_versorted(a) == index_natsorted(a) def test_index_realsorted_returns_results_identical_to_index_natsorted_with_REAL(): - a = ['a50', 'a51.', 'a50.31', 'a-50', 'a50.4', 'a5.034e1', 'a50.300'] + a = ["a50", "a51.", "a50.31", "a-50", "a50.4", "a5.034e1", "a50.300"] assert index_realsorted(a) == index_natsorted(a, alg=ns.REAL) def test_index_humansorted_returns_results_identical_to_index_natsorted_with_LOCALE(): - a = ['Apple', 'corn', 'Corn', 'Banana', 'apple', 'banana'] + a = ["Apple", "corn", "Corn", "Banana", "apple", "banana"] assert index_humansorted(a) == index_natsorted(a, alg=ns.LOCALE) def test_order_by_index_sorts_list_according_to_order_of_integer_list(): - a = ['num3', 'num5', 'num2'] + a = ["num3", "num5", "num2"] index = [2, 0, 1] - assert order_by_index(a, index) == ['num2', 'num3', 'num5'] + assert order_by_index(a, index) == ["num2", "num3", "num5"] assert order_by_index(a, index) == [a[i] for i in index] def test_order_by_index_returns_generator_with_iter_True(): - a = ['num3', 'num5', 'num2'] + a = ["num3", "num5", "num2"] index = [2, 0, 1] assert order_by_index(a, index, True) != [a[i] for i in index] assert list(order_by_index(a, index, True)) == [a[i] for i in index] diff --git a/test_natsort/test_parse_bytes_function.py b/test_natsort/test_parse_bytes_function.py index a0ab3f8..602aa80 100644 --- a/test_natsort/test_parse_bytes_function.py +++ b/test_natsort/test_parse_bytes_function.py @@ -13,7 +13,7 @@ from hypothesis.strategies import binary def test_parse_bytes_factory_makes_function_that_returns_tuple_example(): - assert _parse_bytes_factory(0)(b'hello') == (b'hello',) + assert _parse_bytes_factory(0)(b"hello") == (b"hello",) @given(binary()) @@ -22,16 +22,18 @@ def test_parse_bytes_factory_makes_function_that_returns_tuple(x): def test_parse_bytes_factory_with_IGNORECASE_makes_function_that_returns_tuple_with_lowercase_example(): - assert _parse_bytes_factory(ns.IGNORECASE)(b'HelLo') == (b'hello',) + assert _parse_bytes_factory(ns.IGNORECASE)(b"HelLo") == (b"hello",) @given(binary()) -def test_parse_bytes_factory_with_IGNORECASE_makes_function_that_returns_tuple_with_lowercase(x): +def test_parse_bytes_factory_with_IGNORECASE_makes_function_that_returns_tuple_with_lowercase( + x +): assert _parse_bytes_factory(ns.IGNORECASE)(x) == (x.lower(),) def test_parse_bytes_factory_with_PATH_makes_function_that_returns_nested_tuple_example(): - assert _parse_bytes_factory(ns.PATH)(b'hello') == ((b'hello',),) + assert _parse_bytes_factory(ns.PATH)(b"hello") == ((b"hello",),) @given(binary()) @@ -40,9 +42,11 @@ def test_parse_bytes_factory_with_PATH_makes_function_that_returns_nested_tuple( def test_parse_bytes_factory_with_PATH_and_IGNORECASE_makes_function_that_returns_nested_tuple_with_lowercase_example(): - assert _parse_bytes_factory(ns.PATH | ns.IGNORECASE)(b'HelLo') == ((b'hello',),) + assert _parse_bytes_factory(ns.PATH | ns.IGNORECASE)(b"HelLo") == ((b"hello",),) @given(binary()) -def test_parse_bytes_factory_with_PATH_and_IGNORECASE_makes_function_that_returns_nested_tuple_with_lowercase(x): +def test_parse_bytes_factory_with_PATH_and_IGNORECASE_makes_function_that_returns_nested_tuple_with_lowercase( + x +): assert _parse_bytes_factory(ns.PATH | ns.IGNORECASE)(x) == ((x.lower(),),) diff --git a/test_natsort/test_parse_number_function.py b/test_natsort/test_parse_number_function.py index 2e7a9fe..119b724 100644 --- a/test_natsort/test_parse_number_function.py +++ b/test_natsort/test_parse_number_function.py @@ -4,13 +4,8 @@ from __future__ import unicode_literals from natsort.ns_enum import ns from natsort.utils import _parse_number_factory -from hypothesis import ( - given, -) -from hypothesis.strategies import ( - floats, - integers, -) +from hypothesis import given +from hypothesis.strategies import floats, integers # Each test has an "example" version for demonstrative purposes, @@ -18,38 +13,55 @@ from hypothesis.strategies import ( def test_parse_number_factory_makes_function_that_returns_tuple_example(): - assert _parse_number_factory(0, '', '')(57) == ('', 57) - assert _parse_number_factory(0, '', '')(float('nan')) == ('', float('-inf')) - assert _parse_number_factory(ns.NANLAST, '', '')(float('nan')) == ('', float('+inf')) + assert _parse_number_factory(0, "", "")(57) == ("", 57) + assert _parse_number_factory(0, "", "")(float("nan")) == ("", float("-inf")) + assert _parse_number_factory(ns.NANLAST, "", "")(float("nan")) == ( + "", + float("+inf"), + ) @given(floats(allow_nan=False) | integers()) def test_parse_number_factory_makes_function_that_returns_tuple(x): - assert _parse_number_factory(0, '', '')(x) == ('', x) + assert _parse_number_factory(0, "", "")(x) == ("", x) def test_parse_number_factory_with_PATH_makes_function_that_returns_nested_tuple_example(): - assert _parse_number_factory(ns.PATH, '', '')(57) == (('', 57),) + assert _parse_number_factory(ns.PATH, "", "")(57) == (("", 57),) @given(floats(allow_nan=False) | integers()) def test_parse_number_factory_with_PATH_makes_function_that_returns_nested_tuple(x): - assert _parse_number_factory(ns.PATH, '', '')(x) == (('', x),) + assert _parse_number_factory(ns.PATH, "", "")(x) == (("", x),) def test_parse_number_factory_with_UNGROUPLETTERS_LOCALE_makes_function_that_returns_nested_tuple_example(): - assert _parse_number_factory(ns.UNGROUPLETTERS | ns.LOCALE, '', 'xx')(57) == (('xx',), ('', 57)) + assert _parse_number_factory(ns.UNGROUPLETTERS | ns.LOCALE, "", "xx")(57) == ( + ("xx",), + ("", 57), + ) @given(floats(allow_nan=False) | integers()) -def test_parse_number_factory_with_UNGROUPLETTERS_LOCALE_makes_function_that_returns_nested_tuple(x): - assert _parse_number_factory(ns.UNGROUPLETTERS | ns.LOCALE, '', 'xx')(x) == (('xx',), ('', x)) +def test_parse_number_factory_with_UNGROUPLETTERS_LOCALE_makes_function_that_returns_nested_tuple( + x +): + assert _parse_number_factory(ns.UNGROUPLETTERS | ns.LOCALE, "", "xx")(x) == ( + ("xx",), + ("", x), + ) def test_parse_number_factory_with_PATH_UNGROUPLETTERS_LOCALE_makes_function_that_returns_nested_tuple_example(): - assert _parse_number_factory(ns.PATH | ns.UNGROUPLETTERS | ns.LOCALE, '', 'xx')(57) == ((('xx',), ('', 57)),) + assert _parse_number_factory(ns.PATH | ns.UNGROUPLETTERS | ns.LOCALE, "", "xx")( + 57 + ) == ((("xx",), ("", 57)),) @given(floats(allow_nan=False) | integers()) -def test_parse_number_factory_with_PATH_UNGROUPLETTERS_LOCALE_makes_function_that_returns_nested_tuple(x): - assert _parse_number_factory(ns.PATH | ns.UNGROUPLETTERS | ns.LOCALE, '', 'xx')(x) == ((('xx',), ('', x)),) +def test_parse_number_factory_with_PATH_UNGROUPLETTERS_LOCALE_makes_function_that_returns_nested_tuple( + x +): + assert _parse_number_factory(ns.PATH | ns.UNGROUPLETTERS | ns.LOCALE, "", "xx")( + x + ) == ((("xx",), ("", x)),) diff --git a/test_natsort/test_parse_string_function.py b/test_natsort/test_parse_string_function.py index 91dcf08..c8ea45b 100644 --- a/test_natsort/test_parse_string_function.py +++ b/test_natsort/test_parse_string_function.py @@ -15,24 +15,10 @@ from natsort.utils import ( _parse_path_factory, ) from natsort.compat.py23 import py23_str, PY_VERSION -from natsort.compat.fastnumbers import ( - fast_float, - fast_int, -) -from slow_splitters import ( - int_splitter, - float_splitter, -) -from hypothesis import ( - given, - example, -) -from hypothesis.strategies import ( - lists, - text, - floats, - integers, -) +from natsort.compat.fastnumbers import fast_float, fast_int +from slow_splitters import int_splitter, float_splitter +from hypothesis import given, example +from hypothesis.strategies import lists, text, floats, integers if PY_VERSION >= 3: long = int @@ -42,7 +28,7 @@ def whitespace_check(x): """Simplifies testing""" try: if x.isspace(): - return x in ' \t\n\r\f\v' + return x in " \t\n\r\f\v" else: return True except (AttributeError, TypeError): @@ -65,91 +51,195 @@ def tuple2(x, dummy): def test_parse_string_factory_raises_TypeError_if_given_a_number_example(): with raises(TypeError): - assert _parse_string_factory(0, '', _float_sign_exp_re.split, no_op, fast_float, tuple2)(50.0) + assert _parse_string_factory( + 0, "", _float_sign_exp_re.split, no_op, fast_float, tuple2 + )(50.0) @given(floats()) def test_parse_string_factory_raises_TypeError_if_given_a_number(x): with raises(TypeError): - assert _parse_string_factory(0, '', _float_sign_exp_re.split, no_op, fast_float, tuple2)(x) + assert _parse_string_factory( + 0, "", _float_sign_exp_re.split, no_op, fast_float, tuple2 + )(x) def test_parse_string_factory_only_parses_digits_with_nosign_int_example(): - assert _parse_string_factory(0, '', _int_nosign_re.split, no_op, fast_int, tuple2)('a5+5.034e-1') == ('a', 5, '+', 5, '.', 34, 'e-', 1) + assert _parse_string_factory(0, "", _int_nosign_re.split, no_op, fast_int, tuple2)( + "a5+5.034e-1" + ) == ("a", 5, "+", 5, ".", 34, "e-", 1) -@given(lists(elements=floats() | text().filter(whitespace_check) | integers(), min_size=1, max_size=10)) -@example([10000000000000000000000000000000000000000000000000000000000000000000000000, - 100000000000000000000000000000000000000000000000000000000000000000000000000, - 100000000000000000000000000000000000000000000000000000000000000000000000000]) +@given( + lists( + elements=floats() | text().filter(whitespace_check) | integers(), + min_size=1, + max_size=10, + ) +) +@example( + [ + 10000000000000000000000000000000000000000000000000000000000000000000000000, + 100000000000000000000000000000000000000000000000000000000000000000000000000, + 100000000000000000000000000000000000000000000000000000000000000000000000000, + ] +) def test_parse_string_factory_only_parses_digits_with_nosign_int(x): - s = ''.join(repr(y) if type(y) in (float, long, int) else y for y in x) - assert _parse_string_factory(0, '', _int_nosign_re.split, no_op, fast_int, tuple2)(s) == int_splitter(s, False, '') + s = "".join(repr(y) if type(y) in (float, long, int) else y for y in x) + assert _parse_string_factory(0, "", _int_nosign_re.split, no_op, fast_int, tuple2)( + s + ) == int_splitter(s, False, "") def test_parse_string_factory_parses_digit_with_sign_with_signed_int_example(): - assert _parse_string_factory(0, '', _int_sign_re.split, no_op, fast_int, tuple2)('a5+5.034e-1') == ('a', 5, '', 5, '.', 34, 'e', -1) + assert _parse_string_factory(0, "", _int_sign_re.split, no_op, fast_int, tuple2)( + "a5+5.034e-1" + ) == ("a", 5, "", 5, ".", 34, "e", -1) -@given(lists(elements=floats() | text().filter(whitespace_check) | integers(), min_size=1, max_size=10)) +@given( + lists( + elements=floats() | text().filter(whitespace_check) | integers(), + min_size=1, + max_size=10, + ) +) def test_parse_string_factory_parses_digit_with_sign_with_signed_int(x): - s = ''.join(repr(y) if type(y) in (float, long, int) else y for y in x) - assert _parse_string_factory(0, '', _int_sign_re.split, no_op, fast_int, tuple2)(s) == int_splitter(s, True, '') + s = "".join(repr(y) if type(y) in (float, long, int) else y for y in x) + assert _parse_string_factory(0, "", _int_sign_re.split, no_op, fast_int, tuple2)( + s + ) == int_splitter(s, True, "") def test_parse_string_factory_only_parses_float_with_nosign_noexp_float_example(): - assert _parse_string_factory(0, '', _float_nosign_noexp_re.split, no_op, fast_float, tuple2)('a5+5.034e-1') == ('a', 5.0, '+', 5.034, 'e-', 1.0) + assert _parse_string_factory( + 0, "", _float_nosign_noexp_re.split, no_op, fast_float, tuple2 + )("a5+5.034e-1") == ("a", 5.0, "+", 5.034, "e-", 1.0) -@given(lists(elements=floats(allow_nan=False) | text().filter(whitespace_check) | integers(), min_size=1, max_size=10)) +@given( + lists( + elements=floats(allow_nan=False) | text().filter(whitespace_check) | integers(), + min_size=1, + max_size=10, + ) +) def test_parse_string_factory_only_parses_float_with_nosign_noexp_float(x): - s = ''.join(repr(y) if type(y) in (float, long, int) else y for y in x) - assert _parse_string_factory(0, '', _float_nosign_noexp_re.split, no_op, fast_float, tuple2)(s) == float_splitter(s, False, False, '') + s = "".join(repr(y) if type(y) in (float, long, int) else y for y in x) + assert _parse_string_factory( + 0, "", _float_nosign_noexp_re.split, no_op, fast_float, tuple2 + )(s) == float_splitter(s, False, False, "") def test_parse_string_factory_only_parses_float_with_exponent_with_nosign_exp_float_example(): - assert _parse_string_factory(0, '', _float_nosign_exp_re.split, no_op, fast_float, tuple2)('a5+5.034e-1') == ('a', 5.0, '+', 0.5034) + assert _parse_string_factory( + 0, "", _float_nosign_exp_re.split, no_op, fast_float, tuple2 + )("a5+5.034e-1") == ("a", 5.0, "+", 0.5034) -@given(lists(elements=floats(allow_nan=False) | text().filter(whitespace_check) | integers(), min_size=1, max_size=10)) +@given( + lists( + elements=floats(allow_nan=False) | text().filter(whitespace_check) | integers(), + min_size=1, + max_size=10, + ) +) def test_parse_string_factory_only_parses_float_with_exponent_with_nosign_exp_float(x): - s = ''.join(repr(y) if type(y) in (float, long, int) else y for y in x) - assert _parse_string_factory(0, '', _float_nosign_exp_re.split, no_op, fast_float, tuple2)(s) == float_splitter(s, False, True, '') + s = "".join(repr(y) if type(y) in (float, long, int) else y for y in x) + assert _parse_string_factory( + 0, "", _float_nosign_exp_re.split, no_op, fast_float, tuple2 + )(s) == float_splitter(s, False, True, "") def test_parse_string_factory_only_parses_float_with_sign_with_sign_noexp_float_example(): - assert _parse_string_factory(0, '', _float_sign_noexp_re.split, no_op, fast_float, tuple2)('a5+5.034e-1') == ('a', 5.0, '', 5.034, 'e', -1.0) + assert _parse_string_factory( + 0, "", _float_sign_noexp_re.split, no_op, fast_float, tuple2 + )("a5+5.034e-1") == ("a", 5.0, "", 5.034, "e", -1.0) -@given(lists(elements=floats(allow_nan=False) | text().filter(whitespace_check) | integers(), min_size=1, max_size=10)) +@given( + lists( + elements=floats(allow_nan=False) | text().filter(whitespace_check) | integers(), + min_size=1, + max_size=10, + ) +) def test_parse_string_factory_only_parses_float_with_sign_with_sign_noexp_float(x): - s = ''.join(repr(y) if type(y) in (float, long, int) else y for y in x) - assert _parse_string_factory(0, '', _float_sign_noexp_re.split, no_op, fast_float, tuple2)(s) == float_splitter(s, True, False, '') + s = "".join(repr(y) if type(y) in (float, long, int) else y for y in x) + assert _parse_string_factory( + 0, "", _float_sign_noexp_re.split, no_op, fast_float, tuple2 + )(s) == float_splitter(s, True, False, "") def test_parse_string_factory_parses_float_with_sign_exp_float_example(): - assert _parse_string_factory(0, '', _float_sign_exp_re.split, no_op, fast_float, tuple2)('a5+5.034e-1') == ('a', 5.0, '', 0.5034) - assert _parse_string_factory(0, '', _float_sign_exp_re.split, no_op, fast_float, tuple2)('6a5+5.034e-1') == ('', 6.0, 'a', 5.0, '', 0.5034) - - -@given(lists(elements=floats(allow_nan=False) | text().filter(whitespace_check) | integers(), min_size=1, max_size=10)) + assert _parse_string_factory( + 0, "", _float_sign_exp_re.split, no_op, fast_float, tuple2 + )("a5+5.034e-1") == ("a", 5.0, "", 0.5034) + assert _parse_string_factory( + 0, "", _float_sign_exp_re.split, no_op, fast_float, tuple2 + )("6a5+5.034e-1") == ("", 6.0, "a", 5.0, "", 0.5034) + + +@given( + lists( + elements=floats(allow_nan=False) | text().filter(whitespace_check) | integers(), + min_size=1, + max_size=10, + ) +) def test_parse_string_factory_parses_float_with_sign_exp_float(x): - s = ''.join(repr(y) if type(y) in (float, long, int) else y for y in x) - assert _parse_string_factory(0, '', _float_sign_exp_re.split, no_op, fast_float, tuple2)(s) == float_splitter(s, True, True, '') + s = "".join(repr(y) if type(y) in (float, long, int) else y for y in x) + assert _parse_string_factory( + 0, "", _float_sign_exp_re.split, no_op, fast_float, tuple2 + )(s) == float_splitter(s, True, True, "") def test_parse_string_factory_selects_pre_function_value_if_not_dumb(): def tuple2(x, orig): """Make the input a tuple.""" return (orig[0], tuple(x)) - assert _parse_string_factory(0, '', _int_nosign_re.split, py23_str.upper, fast_float, tuple2)('a5+5.034e-1') == ('A', ('A', 5, '+', 5, '.', 34, 'E-', 1)) - assert _parse_string_factory(ns._DUMB, '', _int_nosign_re.split, py23_str.upper, fast_float, tuple2)('a5+5.034e-1') == ('A', ('A', 5, '+', 5, '.', 34, 'E-', 1)) - assert _parse_string_factory(ns.LOCALE, '', _int_nosign_re.split, py23_str.upper, fast_float, tuple2)('a5+5.034e-1') == ('A', ('A', 5, '+', 5, '.', 34, 'E-', 1)) - assert _parse_string_factory(ns.LOCALE | ns._DUMB, '', _int_nosign_re.split, py23_str.upper, fast_float, tuple2)('a5+5.034e-1') == ('a', ('A', 5, '+', 5, '.', 34, 'E-', 1)) + + assert _parse_string_factory( + 0, "", _int_nosign_re.split, py23_str.upper, fast_float, tuple2 + )("a5+5.034e-1") == ("A", ("A", 5, "+", 5, ".", 34, "E-", 1)) + assert _parse_string_factory( + ns._DUMB, "", _int_nosign_re.split, py23_str.upper, fast_float, tuple2 + )("a5+5.034e-1") == ("A", ("A", 5, "+", 5, ".", 34, "E-", 1)) + assert _parse_string_factory( + ns.LOCALE, "", _int_nosign_re.split, py23_str.upper, fast_float, tuple2 + )("a5+5.034e-1") == ("A", ("A", 5, "+", 5, ".", 34, "E-", 1)) + assert _parse_string_factory( + ns.LOCALE | ns._DUMB, + "", + _int_nosign_re.split, + py23_str.upper, + fast_float, + tuple2, + )("a5+5.034e-1") == ("a", ("A", 5, "+", 5, ".", 34, "E-", 1)) def test_parse_path_function_parses_string_as_path_then_as_string(): - splt = _parse_string_factory(0, '', _float_sign_exp_re.split, no_op, fast_float, tuple2) - assert _parse_path_factory(splt)('/p/Folder (10)/file34.5nm (2).tar.gz') == (('/',), ('p',), ('Folder (', 10.0, ')',), ('file', 34.5, 'nm (', 2.0, ')'), ('.tar',), ('.gz',)) - assert _parse_path_factory(splt)('../Folder (10)/file (2).tar.gz') == (('..',), ('Folder (', 10.0, ')',), ('file (', 2.0, ')'), ('.tar',), ('.gz',)) - assert _parse_path_factory(splt)('Folder (10)/file.f34.5nm (2).tar.gz') == (('Folder (', 10.0, ')',), ('file.f', 34.5, 'nm (', 2.0, ')'), ('.tar',), ('.gz',)) + splt = _parse_string_factory( + 0, "", _float_sign_exp_re.split, no_op, fast_float, tuple2 + ) + assert _parse_path_factory(splt)("/p/Folder (10)/file34.5nm (2).tar.gz") == ( + ("/",), + ("p",), + ("Folder (", 10.0, ")"), + ("file", 34.5, "nm (", 2.0, ")"), + (".tar",), + (".gz",), + ) + assert _parse_path_factory(splt)("../Folder (10)/file (2).tar.gz") == ( + ("..",), + ("Folder (", 10.0, ")"), + ("file (", 2.0, ")"), + (".tar",), + (".gz",), + ) + assert _parse_path_factory(splt)("Folder (10)/file.f34.5nm (2).tar.gz") == ( + ("Folder (", 10.0, ")"), + ("file.f", 34.5, "nm (", 2.0, ")"), + (".tar",), + (".gz",), + ) diff --git a/test_natsort/test_string_component_transform_factory.py b/test_natsort/test_string_component_transform_factory.py index 4f419d7..41c7ecb 100644 --- a/test_natsort/test_string_component_transform_factory.py +++ b/test_natsort/test_string_component_transform_factory.py @@ -3,29 +3,17 @@ from __future__ import unicode_literals from natsort.ns_enum import ns -from natsort.utils import ( - _string_component_transform_factory, - _groupletters, -) +from natsort.utils import _string_component_transform_factory, _groupletters from natsort.compat.py23 import py23_str from natsort.compat.locale import get_strxfrm -from natsort.compat.fastnumbers import ( - fast_float, - fast_int, -) -from hypothesis import ( - given, -) -from hypothesis.strategies import ( - text, - floats, - integers, -) +from natsort.compat.fastnumbers import fast_float, fast_int +from hypothesis import given +from hypothesis.strategies import text, floats, integers from compat.locale import bad_uni_chars def no_null(x): - return '\0' not in x + return "\0" not in x # Each test has an "example" version for demonstrative purposes, @@ -33,9 +21,9 @@ def no_null(x): def test_string_component_transform_factory_returns_fast_int_example(): - x = 'hello' + x = "hello" assert _string_component_transform_factory(0)(x) is fast_int(x) - assert _string_component_transform_factory(0)('5007') == fast_int('5007') + assert _string_component_transform_factory(0)("5007") == fast_int("5007") @given(text().filter(bool) | floats() | integers()) @@ -44,67 +32,102 @@ def test_string_component_transform_factory_returns_fast_int(x): def test_string_component_transform_factory_with_FLOAT_returns_fast_float_example(): - x = 'hello' + x = "hello" assert _string_component_transform_factory(ns.FLOAT)(x) is fast_float(x) - assert _string_component_transform_factory(ns.FLOAT)('5007') == fast_float('5007') + assert _string_component_transform_factory(ns.FLOAT)("5007") == fast_float("5007") @given(text().filter(bool) | floats() | integers()) def test_string_component_transform_factory_with_FLOAT_returns_fast_float(x): - assert _string_component_transform_factory(ns.FLOAT)(py23_str(x)) == fast_float(py23_str(x), nan=float('-inf')) + assert _string_component_transform_factory(ns.FLOAT)(py23_str(x)) == fast_float( + py23_str(x), nan=float("-inf") + ) def test_string_component_transform_factory_with_FLOAT_returns_fast_float_with_neg_inf_replacing_nan(): - assert _string_component_transform_factory(ns.FLOAT)('nan') == fast_float('nan', nan=float('-inf')) + assert _string_component_transform_factory(ns.FLOAT)("nan") == fast_float( + "nan", nan=float("-inf") + ) def test_string_component_transform_factory_with_FLOAT_and_NANLAST_returns_fast_float_with_pos_inf_replacing_nan(): - assert _string_component_transform_factory(ns.FLOAT | ns.NANLAST)('nan') == fast_float('nan', nan=float('+inf')) + assert _string_component_transform_factory(ns.FLOAT | ns.NANLAST)( + "nan" + ) == fast_float("nan", nan=float("+inf")) def test_string_component_transform_factory_with_GROUPLETTERS_returns_fast_int_and_groupletters_example(): - x = 'hello' - assert _string_component_transform_factory(ns.GROUPLETTERS)(x) == fast_int(x, key=_groupletters) + x = "hello" + assert _string_component_transform_factory(ns.GROUPLETTERS)(x) == fast_int( + x, key=_groupletters + ) @given(text().filter(bool)) -def test_string_component_transform_factory_with_GROUPLETTERS_returns_fast_int_and_groupletters(x): - assert _string_component_transform_factory(ns.GROUPLETTERS)(x) == fast_int(x, key=_groupletters) +def test_string_component_transform_factory_with_GROUPLETTERS_returns_fast_int_and_groupletters( + x +): + assert _string_component_transform_factory(ns.GROUPLETTERS)(x) == fast_int( + x, key=_groupletters + ) def test_string_component_transform_factory_with_LOCALE_returns_fast_int_and_groupletters_example(): - x = 'hello' - assert _string_component_transform_factory(ns.LOCALE)(x) == fast_int(x, key=get_strxfrm()) + x = "hello" + assert _string_component_transform_factory(ns.LOCALE)(x) == fast_int( + x, key=get_strxfrm() + ) -@given(text().filter(bool).filter(lambda x: not any(y in bad_uni_chars for y in x)).filter(no_null)) -def test_string_component_transform_factory_with_LOCALE_returns_fast_int_and_groupletters(x): - assert _string_component_transform_factory(ns.LOCALE)(x) == fast_int(x, key=get_strxfrm()) +@given( + text() + .filter(bool) + .filter(lambda x: not any(y in bad_uni_chars for y in x)) + .filter(no_null) +) +def test_string_component_transform_factory_with_LOCALE_returns_fast_int_and_groupletters( + x +): + assert _string_component_transform_factory(ns.LOCALE)(x) == fast_int( + x, key=get_strxfrm() + ) def test_string_component_transform_factory_with_LOCALE_and_GROUPLETTERS_returns_fast_int_and_groupletters_and_locale_convert_example(): - x = 'hello' - assert _string_component_transform_factory(ns.GROUPLETTERS | ns.LOCALE)(x) == fast_int(x, key=lambda x: get_strxfrm()(_groupletters(x))) + x = "hello" + assert _string_component_transform_factory(ns.GROUPLETTERS | ns.LOCALE)( + x + ) == fast_int(x, key=lambda x: get_strxfrm()(_groupletters(x))) @given(text().filter(bool).filter(no_null)) -def test_string_component_transform_factory_with_LOCALE_and_GROUPLETTERS_returns_fast_int_and_groupletters_and_locale_convert(x): +def test_string_component_transform_factory_with_LOCALE_and_GROUPLETTERS_returns_fast_int_and_groupletters_and_locale_convert( + x +): try: - assert _string_component_transform_factory(ns.GROUPLETTERS | ns.LOCALE)(x) == fast_int(x, key=lambda x: get_strxfrm()(_groupletters(x))) + assert _string_component_transform_factory(ns.GROUPLETTERS | ns.LOCALE)( + x + ) == fast_int(x, key=lambda x: get_strxfrm()(_groupletters(x))) except ValueError as e: # handle broken locale lib on BSD. - if 'is not in range' not in str(e): + if "is not in range" not in str(e): raise def test_string_component_transform_factory_with_LOCALE_and_DUMB_returns_fast_int_and_groupletters_and_locale_convert_example(): - x = 'hello' - assert _string_component_transform_factory(ns._DUMB | ns.LOCALE)(x) == fast_int(x, key=lambda x: get_strxfrm()(_groupletters(x))) + x = "hello" + assert _string_component_transform_factory(ns._DUMB | ns.LOCALE)(x) == fast_int( + x, key=lambda x: get_strxfrm()(_groupletters(x)) + ) @given(text().filter(bool).filter(no_null)) -def test_string_component_transform_factory_with_LOCALE_and_DUMB_returns_fast_int_and_groupletters_and_locale_convert(x): +def test_string_component_transform_factory_with_LOCALE_and_DUMB_returns_fast_int_and_groupletters_and_locale_convert( + x +): try: - assert _string_component_transform_factory(ns._DUMB | ns.LOCALE)(x) == fast_int(x, key=lambda x: get_strxfrm()(_groupletters(x))) + assert _string_component_transform_factory(ns._DUMB | ns.LOCALE)(x) == fast_int( + x, key=lambda x: get_strxfrm()(_groupletters(x)) + ) except ValueError as e: # handle broken locale lib on BSD. - if 'is not in range' not in str(e): + if "is not in range" not in str(e): raise diff --git a/test_natsort/test_unicode_numbers.py b/test_natsort/test_unicode_numbers.py index e257914..68758e5 100644 --- a/test_natsort/test_unicode_numbers.py +++ b/test_natsort/test_unicode_numbers.py @@ -43,7 +43,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 set("0123456789"): continue if unicodedata.numeric(a, None) is not None: assert i in set_numeric_hex @@ -63,6 +63,6 @@ def test_numeric_chars_contains_all_valid_unicode_numeric_and_digit_characters() def test_combined_string_contains_all_characters_in_list(): - assert numeric == ''.join(numeric_chars) - assert digits == ''.join(digit_chars) - assert decimals == ''.join(decimal_chars) + assert numeric == "".join(numeric_chars) + assert digits == "".join(digit_chars) + assert decimals == "".join(decimal_chars) diff --git a/test_natsort/test_utils.py b/test_natsort/test_utils.py index 10ad0fa..3aebae5 100644 --- a/test_natsort/test_utils.py +++ b/test_natsort/test_utils.py @@ -25,88 +25,81 @@ from natsort.utils import ( ) from natsort.compat.py23 import py23_str, py23_cmp from natsort.compat.locale import null_string_locale -from slow_splitters import ( - sep_inserter, - add_leading_space_if_first_is_num, -) +from slow_splitters import sep_inserter, add_leading_space_if_first_is_num from compat.locale import low -from hypothesis import ( - given, -) -from hypothesis.strategies import ( - sampled_from, - lists, - text, - integers, -) +from hypothesis import given +from hypothesis.strategies import sampled_from, lists, text, integers def test_do_decoding_decodes_bytes_string_to_unicode(): - assert type(_do_decoding(b'bytes', 'ascii')) is py23_str - assert _do_decoding(b'bytes', 'ascii') == 'bytes' - assert _do_decoding(b'bytes', 'ascii') == b'bytes'.decode('ascii') + assert type(_do_decoding(b"bytes", "ascii")) is py23_str + assert _do_decoding(b"bytes", "ascii") == "bytes" + assert _do_decoding(b"bytes", "ascii") == b"bytes".decode("ascii") def test_args_to_enum_raises_TypeError_for_invalid_argument(): with raises(TypeError): - _args_to_enum(**{'alf': 0}) + _args_to_enum(**{"alf": 0}) def test_args_to_enum_converts_signed_exp_float_to_ns_F(): # number_type, signed, exp, as_path, py3_safe - assert _args_to_enum(**{'number_type': float, - 'signed': True, - 'exp': True}) == ns.F | ns.S + assert ( + _args_to_enum(**{"number_type": float, "signed": True, "exp": True}) + == ns.F | ns.S + ) def test_args_to_enum_converts_signed_noexp_float_to_ns_FN(): # number_type, signed, exp, as_path, py3_safe - assert _args_to_enum(**{'number_type': float, - 'signed': True, - 'exp': False}) == ns.F | ns.N | ns.S + assert ( + _args_to_enum(**{"number_type": float, "signed": True, "exp": False}) + == ns.F | ns.N | ns.S + ) def test_args_to_enum_converts_unsigned_exp_float_to_ns_FU(): # number_type, signed, exp, as_path, py3_safe - assert _args_to_enum(**{'number_type': float, - 'signed': False, - 'exp': True}) == ns.F | ns.U + assert ( + _args_to_enum(**{"number_type": float, "signed": False, "exp": True}) + == ns.F | ns.U + ) # unsigned is default - assert _args_to_enum(**{'number_type': float, - 'signed': False, - 'exp': True}) == ns.F + assert _args_to_enum(**{"number_type": float, "signed": False, "exp": True}) == ns.F def test_args_to_enum_converts_unsigned_unexp_float_to_ns_FNU(): # number_type, signed, exp, as_path, py3_safe - assert _args_to_enum(**{'number_type': float, - 'signed': False, - 'exp': False}) == ns.F | ns.U | ns.N + assert ( + _args_to_enum(**{"number_type": float, "signed": False, "exp": False}) + == ns.F | ns.U | ns.N + ) def test_args_to_enum_converts_float_and_path_and_py3safe_to_ns_FPT(): # number_type, signed, exp, as_path, py3_safe - assert _args_to_enum(**{'number_type': float, - 'as_path': True, - 'py3_safe': True}) == ns.F | ns.P | ns.T + assert ( + _args_to_enum(**{"number_type": float, "as_path": True, "py3_safe": True}) + == ns.F | ns.P | ns.T + ) def test_args_to_enum_converts_int_and_path_to_ns_IP(): # number_type, signed, exp, as_path, py3_safe - assert _args_to_enum(**{'number_type': int, 'as_path': True}) == ns.I | ns.P + assert _args_to_enum(**{"number_type": int, "as_path": True}) == ns.I | ns.P def test_args_to_enum_converts_unsigned_int_and_py3safe_to_ns_IUT(): # number_type, signed, exp, as_path, py3_safe - assert _args_to_enum(**{'number_type': int, - 'signed': False, - 'py3_safe': True}) == ns.I | ns.U | ns.T + assert ( + _args_to_enum(**{"number_type": int, "signed": False, "py3_safe": True}) + == ns.I | ns.U | ns.T + ) def test_args_to_enum_converts_None_to_ns_IU(): # number_type, signed, exp, as_path, py3_safe - assert _args_to_enum(**{'number_type': None, - 'exp': True}) == ns.I | ns.U + assert _args_to_enum(**{"number_type": None, "exp": True}) == ns.I | ns.U def test_regex_chooser_returns_correct_regular_expression_object(): @@ -163,7 +156,7 @@ def test_chain_functions_is_a_no_op_if_no_functions_are_given(): def test_chain_functions_does_one_function_if_one_function_is_given(): - x = '2345' + x = "2345" assert chain_functions([len])(x) == 4 @@ -175,39 +168,47 @@ def test_chain_functions_combines_functions_in_given_order(): # Each test has an "example" version for demonstrative purposes, # and a test that uses the hypothesis module. + def test_groupletters_returns_letters_with_lowercase_transform_of_letter_example(): - assert _groupletters('HELLO') == 'hHeElLlLoO' - assert _groupletters('hello') == 'hheelllloo' + assert _groupletters("HELLO") == "hHeElLlLoO" + assert _groupletters("hello") == "hheelllloo" @given(text().filter(bool)) def test_groupeletters_returns_letters_with_lowercase_transform_of_letter(x): - assert _groupletters(x) == ''.join(chain.from_iterable([low(y), y] for y in x)) + assert _groupletters(x) == "".join(chain.from_iterable([low(y), y] for y in x)) def test_sep_inserter_does_nothing_if_no_numbers_example(): - assert list(_sep_inserter(iter(['a', 'b', 'c']), '')) == ['a', 'b', 'c'] - assert list(_sep_inserter(iter(['a']), '')) == ['a'] + assert list(_sep_inserter(iter(["a", "b", "c"]), "")) == ["a", "b", "c"] + assert list(_sep_inserter(iter(["a"]), "")) == ["a"] def test_sep_inserter_does_nothing_if_only_one_number_example(): - assert list(_sep_inserter(iter(['a', 5]), '')) == ['a', 5] + assert list(_sep_inserter(iter(["a", 5]), "")) == ["a", 5] def test_sep_inserter_inserts_separator_string_between_two_numbers_example(): - assert list(_sep_inserter(iter([5, 9]), '')) == ['', 5, '', 9] - assert list(_sep_inserter(iter([5, 9]), null_string_locale)) == [null_string_locale, 5, null_string_locale, 9] + assert list(_sep_inserter(iter([5, 9]), "")) == ["", 5, "", 9] + assert list(_sep_inserter(iter([5, 9]), null_string_locale)) == [ + null_string_locale, + 5, + null_string_locale, + 9, + ] @given(lists(elements=text().filter(bool) | integers())) def test_sep_inserter_inserts_separator_between_two_numbers(x): - assert list(_sep_inserter(iter(x), '')) == list(add_leading_space_if_first_is_num(sep_inserter(x, ''), '')) + assert list(_sep_inserter(iter(x), "")) == list( + add_leading_space_if_first_is_num(sep_inserter(x, ""), "") + ) def test_path_splitter_splits_path_string_by_separator_example(): - z = '/this/is/a/path' + z = "/this/is/a/path" assert tuple(_path_splitter(z)) == tuple(pathlib.Path(z).parts) - z = pathlib.Path('/this/is/a/path') + z = pathlib.Path("/this/is/a/path") assert tuple(_path_splitter(z)) == tuple(pathlib.Path(z).parts) @@ -218,16 +219,22 @@ def test_path_splitter_splits_path_string_by_separator(x): def test_path_splitter_splits_path_string_by_separator_and_removes_extension_example(): - z = '/this/is/a/path/file.exe' + z = "/this/is/a/path/file.exe" y = tuple(pathlib.Path(z).parts) - assert tuple(_path_splitter(z)) == y[:-1] + (pathlib.Path(z).stem, pathlib.Path(z).suffix) + assert tuple(_path_splitter(z)) == y[:-1] + ( + pathlib.Path(z).stem, + pathlib.Path(z).suffix, + ) @given(lists(sampled_from(string.ascii_letters), min_size=3).filter(all)) def test_path_splitter_splits_path_string_by_separator_and_removes_extension(x): - z = py23_str(pathlib.Path(*x[:-2])) + '.' + x[-1] + z = py23_str(pathlib.Path(*x[:-2])) + "." + x[-1] y = tuple(pathlib.Path(z).parts) - assert tuple(_path_splitter(z)) == y[:-1] + (pathlib.Path(z).stem, pathlib.Path(z).suffix) + assert tuple(_path_splitter(z)) == y[:-1] + ( + pathlib.Path(z).stem, + pathlib.Path(z).suffix, + ) @given(integers()) |