diff options
author | Seth M Morton <seth.m.morton@gmail.com> | 2018-08-12 11:07:58 -0400 |
---|---|---|
committer | Seth M Morton <seth.m.morton@gmail.com> | 2018-08-12 11:07:58 -0400 |
commit | 8749af2c6c0e81db679792b78eb6eafa953a2ead (patch) | |
tree | 76c2d186e1771562b99cb1a8d16a91a76fb0800e | |
parent | ef9f871304731ad4cfbe6c5cbf2bb9c93894229c (diff) | |
download | natsort-8749af2c6c0e81db679792b78eb6eafa953a2ead.tar.gz |
Refactor test_natsort.compat into fixtures.
These have been moved to conftest.py, or now use the pytest-mocker
third-party plugin. Some tests have been re-written to account for the
change.
-rw-r--r-- | Pipfile | 4 | ||||
-rw-r--r-- | natsort/compat/py23.py | 18 | ||||
-rw-r--r-- | test_natsort/compat/__init__.py | 0 | ||||
-rw-r--r-- | test_natsort/compat/locale.py | 40 | ||||
-rw-r--r-- | test_natsort/compat/mock.py | 9 | ||||
-rw-r--r-- | test_natsort/conftest.py | 38 | ||||
-rw-r--r-- | test_natsort/test_input_string_transform_factory.py | 22 | ||||
-rw-r--r-- | test_natsort/test_main.py | 252 | ||||
-rw-r--r-- | test_natsort/test_natsort_cmp.py | 8 | ||||
-rw-r--r-- | test_natsort/test_natsort_keygen.py | 18 | ||||
-rw-r--r-- | test_natsort/test_natsorted.py | 23 | ||||
-rw-r--r-- | test_natsort/test_string_component_transform_factory.py | 11 | ||||
-rw-r--r-- | test_natsort/test_utils.py | 5 |
13 files changed, 212 insertions, 236 deletions
@@ -1,13 +1,13 @@ [dev-packages] coverage = "*" -pytest = "*" +pytest = ">=3.5" pytest-cov = "*" pytest-flakes = "*" pytest-pep8 = "*" +pytest-mock = ">=1.1" hypothesis = ">=3.8.0" astroid = "==1.5.3" pytest-faulthandler = {version = "*", platform_python_implementation = "== 'CPython'"} # These packages are standard on newer python versions. pathlib = {version = "*", python_version = "< '3.4'"} -mock = {version = "*", python_version = "< '3.3'"} diff --git a/natsort/compat/py23.py b/natsort/compat/py23.py index e7abb5e..df3eace 100644 --- a/natsort/compat/py23.py +++ b/natsort/compat/py23.py @@ -20,26 +20,29 @@ 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 PY_VERSION >= 3 else unicode # Use the range iterator always -py23_range = range if sys.version[0] == "3" else xrange +py23_range = range if PY_VERSION >= 3 else xrange # Uniform base string type -py23_basestring = str if sys.version[0] == "3" else basestring +py23_basestring = str if PY_VERSION >= 3 else basestring # unichr function -py23_unichr = chr if sys.version[0] == "3" else unichr +py23_unichr = chr if PY_VERSION >= 3 else unichr + +# Proper lower-casing of letters. +py23_lower = py23_str.casefold if NEWPY else py23_str.lower 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 PY_VERSION >= 3 else cmp # zip as an iterator -if sys.version[0] == "3": +if PY_VERSION >= 3: py23_zip = zip py23_map = map py23_filter = filter @@ -50,7 +53,6 @@ else: py23_map = itertools.imap py23_filter = itertools.ifilter - # cmp_to_key was not created till 2.7, so require this for 2.6 try: from functools import cmp_to_key @@ -113,7 +115,7 @@ def _modify_str_or_docstring(str_change_func): # Properly modify a doctstring to either have the unicode literal or not. -if sys.version[0] == "3": +if PY_VERSION >= 3: # Abstract u'abc' syntax: @_modify_str_or_docstring def u_format(s): diff --git a/test_natsort/compat/__init__.py b/test_natsort/compat/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/test_natsort/compat/__init__.py +++ /dev/null diff --git a/test_natsort/compat/locale.py b/test_natsort/compat/locale.py deleted file mode 100644 index 76e387c..0000000 --- a/test_natsort/compat/locale.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import print_function, division, unicode_literals, absolute_import - -# Std. lib imports. -import locale - -# Local imports -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))) - except locale.Error: - locale.setlocale(locale.LC_ALL, str("{0}.UTF-8".format(x))) - - -# Check if de_DE is installed. -try: - load_locale("de_DE") - has_locale_de_DE = True -except locale.Error: - has_locale_de_DE = False - -# Depending on the python version, use lower or casefold -# to make a string lowercase. -try: - low = py23_str.casefold -except AttributeError: - low = py23_str.lower - -# There are some unicode values that are known failures on BSD systems -# 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)) -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 deleted file mode 100644 index 32d3a64..0000000 --- a/test_natsort/compat/mock.py +++ /dev/null @@ -1,9 +0,0 @@ -# -*- coding: utf-8 -*- -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 -except ImportError: - # noinspection PyUnresolvedReferences,PyPackageRequirements - from mock import MagicMock, patch, call diff --git a/test_natsort/conftest.py b/test_natsort/conftest.py new file mode 100644 index 0000000..459e44e --- /dev/null +++ b/test_natsort/conftest.py @@ -0,0 +1,38 @@ +""" +Fixtures for pytest. +""" + +import pytest +import locale + + +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))) + except locale.Error: + locale.setlocale(locale.LC_ALL, str("{0}.UTF-8".format(x))) + + +@pytest.fixture() +def with_locale_en_us(): + """Convenience to load the en_US locale - reset when complete.""" + orig = locale.getlocale() + yield load_locale("en_US") + locale.setlocale(locale.LC_ALL, orig) + + +@pytest.fixture() +def with_locale_de_de(): + """ + Convenience to load the de_DE locale - reset when complete - skip if missing. + """ + orig = locale.getlocale() + try: + load_locale("de_DE") + except locale.Error: + pytest.skip("requires de_DE locale to be installed") + else: + yield + finally: + locale.setlocale(locale.LC_ALL, orig) diff --git a/test_natsort/test_input_string_transform_factory.py b/test_natsort/test_input_string_transform_factory.py index 2453873..2c3e329 100644 --- a/test_natsort/test_input_string_transform_factory.py +++ b/test_natsort/test_input_string_transform_factory.py @@ -12,8 +12,6 @@ from natsort.compat.py23 import NEWPY from natsort.ns_enum import ns, ns_DUMB from natsort.utils import _input_string_transform_factory -from compat.locale import has_locale_de_DE, load_locale - # Each test has an "example" version for demonstrative purposes, # and a test that uses the hypothesis module. @@ -105,8 +103,8 @@ def test_input_string_transform_factory_performs_swapcase_and_casefold_both_LOWE ) +@pytest.mark.usefixtures("with_locale_en_us") 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 = ( @@ -120,8 +118,8 @@ def test_input_string_transform_factory_removes_thousands_separator_with_LOCALE_ @given(lists(elements=integers(), min_size=4, max_size=20)) +@pytest.mark.usefixtures("with_locale_en_us") 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 @@ -146,10 +144,10 @@ def test_input_string_transform_factory_removes_thousands_separator_and_is_float lists(elements=integers(), min_size=4, max_size=20), lists(elements=integers(), min_size=4, max_size=20), ) +@pytest.mark.usefixtures("with_locale_en_us") 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 @@ -181,8 +179,8 @@ def test_input_string_transform_factory_removes_thousands_separator_and_is_float # These might be too much to test with hypothesis. +@pytest.mark.usefixtures("with_locale_en_us") 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" @@ -192,12 +190,8 @@ def test_input_string_transform_factory_leaves_invalid_thousands_separator_with_ 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.usefixtures("with_locale_de_de") 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" @@ -209,12 +203,8 @@ def test_input_string_transform_factory_replaces_decimal_separator_with_LOCALE_e 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.usefixtures("with_locale_de_de") 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("")) diff --git a/test_natsort/test_main.py b/test_natsort/test_main.py index 2971633..453dd1f 100644 --- a/test_natsort/test_main.py +++ b/test_natsort/test_main.py @@ -19,60 +19,58 @@ from natsort.__main__ import ( ) from pytest import raises -from compat.mock import call, patch - - -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"] - main() - args = p.call_args[0][1] - assert not args.paths - assert args.filter is None - assert args.reverse_filter is None - assert args.exclude is None - assert not args.reverse - 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", - ] - main() - args = p.call_args[0][1] - assert args.paths - assert args.filter == [(4.0, 10.0)] - assert args.reverse_filter == [(100.0, 110.0)] - assert args.exclude == [34, 35] - assert args.reverse - assert args.number_type == "float" - assert args.signed - assert not args.exp - assert args.locale + +def test_main_passes_default_arguments_with_no_command_line_options(mocker): + p = mocker.patch("natsort.__main__.sort_and_print_entries") + sys.argv[1:] = ["num-2", "num-6", "num-1"] + main() + args = p.call_args[0][1] + assert not args.paths + assert args.filter is None + assert args.reverse_filter is None + assert args.exclude is None + assert not args.reverse + 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(mocker): + p = mocker.patch("natsort.__main__.sort_and_print_entries") + 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 + assert args.filter == [(4.0, 10.0)] + assert args.reverse_filter == [(100.0, 110.0)] + assert args.exclude == [34, 35] + assert args.reverse + assert args.number_type == "float" + assert args.signed + assert not args.exp + assert args.locale class Args: @@ -103,79 +101,79 @@ entries = [ 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(): - with patch(mock_print) as p: - # tmp/a1 (1)/path1 - # tmp/a1/path1 - # tmp/a23/path1 - # tmp/a57/path2 - # tmp/a64/path1 - # tmp/a64/path2 - # tmp/a130/path1 - sort_and_print_entries(entries, Args(None, None, False, False, False)) - e = [call(entries[i]) for i in [3, 2, 1, 0, 5, 6, 4]] - p.assert_has_calls(e) - - -def test_sort_and_print_entries_uses_PATH_algorithm_with_path_option_true_to_properly_sort_OS_generated_path_names(): - with patch(mock_print) as p: - # tmp/a1/path1 - # tmp/a1 (1)/path1 - # tmp/a23/path1 - # tmp/a57/path2 - # tmp/a64/path1 - # tmp/a64/path2 - # tmp/a130/path1 - sort_and_print_entries(entries, Args(None, None, False, True, False)) - e = [call(entries[i]) for i in [2, 3, 1, 0, 5, 6, 4]] - p.assert_has_calls(e) - - -def test_sort_and_print_entries_keeps_only_paths_between_of_20_to_100_with_filter_option(): - with patch(mock_print) as p: - # tmp/a23/path1 - # tmp/a57/path2 - # tmp/a64/path1 - # tmp/a64/path2 - sort_and_print_entries(entries, Args([(20, 100)], None, False, False, False)) - e = [call(entries[i]) for i in [1, 0, 5, 6]] - p.assert_has_calls(e) - - -def test_sort_and_print_entries_excludes_paths_between_of_20_to_100_with_reverse_filter_option(): - with patch(mock_print) as p: - # tmp/a1/path1 - # tmp/a1 (1)/path1 - # tmp/a130/path1 - sort_and_print_entries(entries, Args(None, [(20, 100)], False, True, False)) - e = [call(entries[i]) for i in [2, 3, 4]] - p.assert_has_calls(e) - - -def test_sort_and_print_entries_excludes_paths_23_or_130_with_exclude_option_list(): - with patch(mock_print) as p: - # tmp/a1/path1 - # tmp/a1 (1)/path1 - # tmp/a57/path2 - # tmp/a64/path1 - # tmp/a64/path2 - sort_and_print_entries(entries, Args(None, None, [23, 130], True, False)) - e = [call(entries[i]) for i in [2, 3, 0, 5, 6]] - p.assert_has_calls(e) - - -def test_sort_and_print_entries_reverses_order_with_reverse_option(): - with patch(mock_print) as p: - # tmp/a130/path1 - # tmp/a64/path2 - # tmp/a64/path1 - # tmp/a57/path2 - # tmp/a23/path1 - # tmp/a1 (1)/path1 - # tmp/a1/path1 - sort_and_print_entries(entries, Args(None, None, False, True, True)) - e = [call(entries[i]) for i in reversed([2, 3, 1, 0, 5, 6, 4])] - p.assert_has_calls(e) +def test_sort_and_print_entries_uses_default_algorithm_with_all_options_false(mocker): + p = mocker.patch(mock_print) + # tmp/a1 (1)/path1 + # tmp/a1/path1 + # tmp/a23/path1 + # tmp/a57/path2 + # tmp/a64/path1 + # tmp/a64/path2 + # tmp/a130/path1 + sort_and_print_entries(entries, Args(None, None, False, False, False)) + e = [mocker.call(entries[i]) for i in [3, 2, 1, 0, 5, 6, 4]] + p.assert_has_calls(e) + + +def test_sort_and_print_entries_uses_PATH_algorithm_with_path_option_true_to_properly_sort_OS_generated_path_names(mocker): + p = mocker.patch(mock_print) + # tmp/a1/path1 + # tmp/a1 (1)/path1 + # tmp/a23/path1 + # tmp/a57/path2 + # tmp/a64/path1 + # tmp/a64/path2 + # tmp/a130/path1 + sort_and_print_entries(entries, Args(None, None, False, True, False)) + e = [mocker.call(entries[i]) for i in [2, 3, 1, 0, 5, 6, 4]] + p.assert_has_calls(e) + + +def test_sort_and_print_entries_keeps_only_paths_between_of_20_to_100_with_filter_option(mocker): + p = mocker.patch(mock_print) + # tmp/a23/path1 + # tmp/a57/path2 + # tmp/a64/path1 + # tmp/a64/path2 + sort_and_print_entries(entries, Args([(20, 100)], None, False, False, False)) + e = [mocker.call(entries[i]) for i in [1, 0, 5, 6]] + p.assert_has_calls(e) + + +def test_sort_and_print_entries_excludes_paths_between_of_20_to_100_with_reverse_filter_option(mocker): + p = mocker.patch(mock_print) + # tmp/a1/path1 + # tmp/a1 (1)/path1 + # tmp/a130/path1 + sort_and_print_entries(entries, Args(None, [(20, 100)], False, True, False)) + e = [mocker.call(entries[i]) for i in [2, 3, 4]] + p.assert_has_calls(e) + + +def test_sort_and_print_entries_excludes_paths_23_or_130_with_exclude_option_list(mocker): + p = mocker.patch(mock_print) + # tmp/a1/path1 + # tmp/a1 (1)/path1 + # tmp/a57/path2 + # tmp/a64/path1 + # tmp/a64/path2 + sort_and_print_entries(entries, Args(None, None, [23, 130], True, False)) + e = [mocker.call(entries[i]) for i in [2, 3, 0, 5, 6]] + p.assert_has_calls(e) + + +def test_sort_and_print_entries_reverses_order_with_reverse_option(mocker): + p = mocker.patch(mock_print) + # tmp/a130/path1 + # tmp/a64/path2 + # tmp/a64/path1 + # tmp/a57/path2 + # tmp/a23/path1 + # tmp/a1 (1)/path1 + # tmp/a1/path1 + sort_and_print_entries(entries, Args(None, None, False, True, True)) + e = [mocker.call(entries[i]) for i in reversed([2, 3, 1, 0, 5, 6, 4])] + p.assert_has_calls(e) # Each test has an "example" version for demonstrative purposes, diff --git a/test_natsort/test_natsort_cmp.py b/test_natsort/test_natsort_cmp.py index 4478049..d5e8e0f 100644 --- a/test_natsort/test_natsort_cmp.py +++ b/test_natsort/test_natsort_cmp.py @@ -13,8 +13,6 @@ from hypothesis.strategies import floats, integers, lists from natsort import ns from natsort.compat.py23 import py23_cmp -from compat.mock import patch - PY_VERSION = float(sys.version[:3]) if PY_VERSION < 3: @@ -42,7 +40,7 @@ def test__classes_can_be_compared(): @pytest.mark.skipif(PY_VERSION >= 3.0, reason="cmp() deprecated in Python 3") -def test__keys_are_being_cached(): +def test__keys_are_being_cached(mocker): natcmp.cached_keys = {} assert len(natcmp.cached_keys) == 0 natcmp(0, 0) @@ -50,13 +48,13 @@ 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 mocker.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 mocker.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) diff --git a/test_natsort/test_natsort_keygen.py b/test_natsort/test_natsort_keygen.py index 89f30ff..d070b9a 100644 --- a/test_natsort/test_natsort_keygen.py +++ b/test_natsort/test_natsort_keygen.py @@ -8,14 +8,12 @@ from __future__ import print_function, unicode_literals import locale import warnings +import pytest from natsort import natsort_key, natsort_keygen, natsorted, ns from natsort.compat.locale import get_strxfrm, null_string_locale from natsort.compat.py23 import PY_VERSION from pytest import raises -from compat.locale import load_locale -from compat.mock import patch - INPUT = ["6A-5.034e+1", "/Folder (1)/Foo", 56.7] @@ -92,10 +90,10 @@ def test_natsort_keygen_splits_input_with_lowercasefirst_noexp_float(): ) -def test_natsort_keygen_splits_input_with_locale(): - load_locale("en_US") +@pytest.mark.usefixtures("with_locale_en_us") +def test_natsort_keygen_splits_input_with_locale(mocker): strxfrm = get_strxfrm() - with patch("natsort.compat.locale.dumb_sort", return_value=False): + with mocker.patch("natsort.compat.locale.dumb_sort", return_value=False): assert natsort_keygen(alg=ns.L)(INPUT) == ( ( null_string_locale, @@ -110,7 +108,7 @@ def test_natsort_keygen_splits_input_with_locale(): (strxfrm("/Folder ("), 1, strxfrm(")/Foo")), (null_string_locale, 56.7), ) - with patch("natsort.compat.locale.dumb_sort", return_value=True): + with mocker.patch("natsort.compat.locale.dumb_sort", return_value=True): assert natsort_keygen(alg=ns.L)(INPUT) == ( ( null_string_locale, @@ -130,10 +128,10 @@ def test_natsort_keygen_splits_input_with_locale(): locale.setlocale(locale.LC_ALL, str("")) -def test_natsort_keygen_splits_input_with_locale_and_capitalfirst(): - load_locale("en_US") +@pytest.mark.usefixtures("with_locale_en_us") +def test_natsort_keygen_splits_input_with_locale_and_capitalfirst(mocker): strxfrm = get_strxfrm() - with patch("natsort.compat.locale.dumb_sort", return_value=False): + with mocker.patch("natsort.compat.locale.dumb_sort", return_value=False): assert natsort_keygen(alg=ns.LA | ns.C)(INPUT) == ( ( ("",), diff --git a/test_natsort/test_natsorted.py b/test_natsort/test_natsorted.py index 472c193..382403f 100644 --- a/test_natsort/test_natsorted.py +++ b/test_natsort/test_natsorted.py @@ -13,8 +13,6 @@ from natsort import natsorted, ns from natsort.compat.py23 import PY_VERSION from pytest import raises -from compat.locale import has_locale_de_DE, load_locale - def test_natsorted_returns_strings_with_numbers_in_ascending_order(): a = ["a2", "a5", "a9", "a1", "a4", "a10", "a6"] @@ -305,9 +303,9 @@ def test_natsorted_with_IGNORECASE_sorts_without_regard_to_case_for_nested_input assert natsorted(b, alg=ns.IGNORECASE) == [("a3", "a1"), ("A5", "a6")] +@pytest.mark.usefixtures("with_locale_en_us") 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", @@ -319,9 +317,9 @@ def test_natsorted_with_LOCALE_returns_results_sorted_by_lowercase_first_and_gro locale.setlocale(locale.LC_ALL, str("")) +@pytest.mark.usefixtures("with_locale_en_us") 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", @@ -333,9 +331,9 @@ def test_natsorted_with_LOCALE_and_CAPITALFIRST_returns_results_sorted_by_capita locale.setlocale(locale.LC_ALL, str("")) +@pytest.mark.usefixtures("with_locale_en_us") 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", @@ -347,9 +345,9 @@ def test_natsorted_with_LOCALE_and_LOWERCASEFIRST_returns_results_sorted_by_uppe locale.setlocale(locale.LC_ALL, str("")) +@pytest.mark.usefixtures("with_locale_en_us") 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", @@ -361,8 +359,8 @@ def test_natsorted_with_LOCALE_and_CAPITALFIRST_and_LOWERCASE_returns_results_so locale.setlocale(locale.LC_ALL, str("")) +@pytest.mark.usefixtures("with_locale_en_us") 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", @@ -376,11 +374,8 @@ def test_natsorted_with_LOCALE_and_en_setting_returns_results_sorted_by_en_langu locale.setlocale(locale.LC_ALL, str("")) -@pytest.mark.skipif( - not has_locale_de_DE, reason="requires de_DE locale and working locale" -) +@pytest.mark.usefixtures("with_locale_de_de") 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", @@ -394,8 +389,8 @@ def test_natsorted_with_LOCALE_and_de_setting_returns_results_sorted_by_de_langu locale.setlocale(locale.LC_ALL, str("")) +@pytest.mark.usefixtures("with_locale_en_us") 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"] @@ -405,8 +400,8 @@ def test_natsorted_with_LOCALE_and_mixed_input_returns_sorted_results_without_er locale.setlocale(locale.LC_ALL, str("")) +@pytest.mark.usefixtures("with_locale_en_us") 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) == [ @@ -427,8 +422,8 @@ def test_natsorted_with_LOCALE_and_UNGROUPLETTERS_and_mixed_input_returns_sorted locale.setlocale(locale.LC_ALL, str("")) +@pytest.mark.usefixtures("with_locale_en_us") 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", diff --git a/test_natsort/test_string_component_transform_factory.py b/test_natsort/test_string_component_transform_factory.py index aa506c3..4f3eb38 100644 --- a/test_natsort/test_string_component_transform_factory.py +++ b/test_natsort/test_string_component_transform_factory.py @@ -6,11 +6,18 @@ from hypothesis import given from hypothesis.strategies import floats, integers, text from natsort.compat.fastnumbers import fast_float, fast_int from natsort.compat.locale import get_strxfrm -from natsort.compat.py23 import py23_str +from natsort.compat.py23 import py23_str, py23_unichr, py23_range from natsort.ns_enum import ns, ns_DUMB from natsort.utils import _groupletters, _string_component_transform_factory -from compat.locale import bad_uni_chars +# There are some unicode values that are known failures with the builtin locale +# library on BSD systems 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)) +except ValueError: + # Narrow unicode build... no worries. + bad_uni_chars = set() def no_null(x): diff --git a/test_natsort/test_utils.py b/test_natsort/test_utils.py index b729adf..9f7c4bc 100644 --- a/test_natsort/test_utils.py +++ b/test_natsort/test_utils.py @@ -10,7 +10,7 @@ from operator import neg as op_neg from hypothesis import given from hypothesis.strategies import integers, lists, sampled_from, text from natsort.compat.locale import null_string_locale -from natsort.compat.py23 import py23_cmp, py23_str +from natsort.compat.py23 import py23_cmp, py23_str, py23_lower from natsort.ns_enum import ns from natsort.utils import ( _args_to_enum, @@ -24,7 +24,6 @@ from natsort.utils import ( ) from pytest import raises -from compat.locale import low from slow_splitters import add_leading_space_if_first_is_num, sep_inserter @@ -172,7 +171,7 @@ def test_groupletters_returns_letters_with_lowercase_transform_of_letter_example @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([py23_lower(y), y] for y in x)) def test_sep_inserter_does_nothing_if_no_numbers_example(): |