summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeth Morton <seth.m.morton@gmail.com>2021-10-28 21:42:27 -0700
committerSeth Morton <seth.m.morton@gmail.com>2021-10-28 21:42:27 -0700
commit64f13fe7ac23efdf72e0157af27c87adfc9ea577 (patch)
treed6112a9e274f3062f512f38030f48d2f981f73e3
parent90c68f35105361130c39c0fb4c4f62933304ae17 (diff)
downloadnatsort-64f13fe7ac23efdf72e0157af27c87adfc9ea577.tar.gz
Add type annotations to tests
That was... a lot. There are still errors in the os_sorted tests, but that requires me to rethink some typing decisions in the main code so that will be for a future commit.
-rw-r--r--tests/conftest.py10
-rw-r--r--tests/profile_natsorted.py9
-rw-r--r--tests/test_fake_fastnumbers.py49
-rw-r--r--tests/test_final_data_transform_factory.py13
-rw-r--r--tests/test_input_string_transform_factory.py27
-rw-r--r--tests/test_main.py66
-rw-r--r--tests/test_natsort_key.py23
-rw-r--r--tests/test_natsort_keygen.py58
-rw-r--r--tests/test_natsorted.py94
-rw-r--r--tests/test_natsorted_convenience.py39
-rw-r--r--tests/test_ns_enum.py4
-rw-r--r--tests/test_os_sorted.py11
-rw-r--r--tests/test_parse_bytes_function.py8
-rw-r--r--tests/test_parse_number_function.py14
-rw-r--r--tests/test_parse_string_function.py29
-rw-r--r--tests/test_regex.py9
-rw-r--r--tests/test_string_component_transform_factory.py11
-rw-r--r--tests/test_unicode_numbers.py14
-rw-r--r--tests/test_utils.py46
-rw-r--r--tox.ini5
20 files changed, 328 insertions, 211 deletions
diff --git a/tests/conftest.py b/tests/conftest.py
index 74d7f4f..c63e149 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -3,6 +3,7 @@ Fixtures for pytest.
"""
import locale
+from typing import Iterator
import hypothesis
import pytest
@@ -16,7 +17,7 @@ hypothesis.settings.register_profile(
)
-def load_locale(x):
+def load_locale(x: str) -> None:
"""Convenience to load a locale, trying ISO8859-1 first."""
try:
locale.setlocale(locale.LC_ALL, str("{}.ISO8859-1".format(x)))
@@ -25,15 +26,16 @@ def load_locale(x):
@pytest.fixture()
-def with_locale_en_us():
+def with_locale_en_us() -> Iterator[None]:
"""Convenience to load the en_US locale - reset when complete."""
orig = locale.getlocale()
- yield load_locale("en_US")
+ load_locale("en_US")
+ yield
locale.setlocale(locale.LC_ALL, orig)
@pytest.fixture()
-def with_locale_de_de():
+def with_locale_de_de() -> Iterator[None]:
"""
Convenience to load the de_DE locale - reset when complete - skip if missing.
"""
diff --git a/tests/profile_natsorted.py b/tests/profile_natsorted.py
index a2b1a5c..f6580a3 100644
--- a/tests/profile_natsorted.py
+++ b/tests/profile_natsorted.py
@@ -7,6 +7,7 @@ inputs and different settings.
import cProfile
import locale
import sys
+from typing import List, Union
try:
from natsort import ns, natsort_keygen
@@ -14,6 +15,8 @@ except ImportError:
sys.path.insert(0, ".")
from natsort import ns, natsort_keygen
+from natsort.natsort import NatsortKeyType
+
locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
# Samples to parse
@@ -32,7 +35,7 @@ path_key = natsort_keygen(alg=ns.PATH)
locale_key = natsort_keygen(alg=ns.LOCALE)
-def prof_time_to_generate():
+def prof_time_to_generate() -> None:
print("*** Generate Plain Key ***")
for _ in range(100000):
natsort_keygen()
@@ -41,7 +44,9 @@ def prof_time_to_generate():
cProfile.run("prof_time_to_generate()", sort="time")
-def prof_parsing(a, msg, key=basic_key):
+def prof_parsing(
+ a: Union[str, int, bytes, List[str]], msg: str, key: NatsortKeyType = basic_key
+) -> None:
print(msg)
for _ in range(100000):
key(a)
diff --git a/tests/test_fake_fastnumbers.py b/tests/test_fake_fastnumbers.py
index c75bb11..574f7cf 100644
--- a/tests/test_fake_fastnumbers.py
+++ b/tests/test_fake_fastnumbers.py
@@ -5,13 +5,14 @@ Test the fake fastnumbers module.
import unicodedata
from math import isnan
+from typing import Union, cast
from hypothesis import given
from hypothesis.strategies import floats, integers, text
from natsort.compat.fake_fastnumbers import fast_float, fast_int
-def is_float(x):
+def is_float(x: str) -> bool:
try:
float(x)
except ValueError:
@@ -25,19 +26,19 @@ def is_float(x):
return True
-def not_a_float(x):
+def not_a_float(x: str) -> bool:
return not is_float(x)
-def is_int(x):
+def is_int(x: Union[str, float]) -> bool:
try:
- return x.is_integer()
+ return cast(float, x).is_integer()
except AttributeError:
try:
int(x)
except ValueError:
try:
- unicodedata.digit(x)
+ unicodedata.digit(cast(str, x))
except (ValueError, TypeError):
return False
else:
@@ -46,7 +47,7 @@ def is_int(x):
return True
-def not_an_int(x):
+def not_an_int(x: Union[str, float]) -> bool:
return not is_int(x)
@@ -54,56 +55,56 @@ def not_an_int(x):
# and a test that uses the hypothesis module.
-def test_fast_float_returns_nan_alternate_if_nan_option_is_given():
+def test_fast_float_returns_nan_alternate_if_nan_option_is_given() -> None:
assert fast_float("nan", nan=7) == 7
-def test_fast_float_converts_float_string_to_float_example():
+def test_fast_float_converts_float_string_to_float_example() -> None:
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 isnan(cast(float, fast_float("nan")))
+ assert isnan(cast(float, fast_float("+nan")))
+ assert isnan(cast(float, fast_float("-NaN")))
assert fast_float("۱۲.۱۲") == 12.12
assert fast_float("-۱۲.۱۲") == -12.12
@given(floats(allow_nan=False))
-def test_fast_float_converts_float_string_to_float(x):
+def test_fast_float_converts_float_string_to_float(x: float) -> None:
assert fast_float(repr(x)) == x
-def test_fast_float_leaves_string_as_is_example():
+def test_fast_float_leaves_string_as_is_example() -> None:
assert fast_float("invalid") == "invalid"
@given(text().filter(not_a_float).filter(bool))
-def test_fast_float_leaves_string_as_is(x):
+def test_fast_float_leaves_string_as_is(x: str) -> None:
assert fast_float(x) == x
-def test_fast_float_with_key_applies_to_string_example():
+def test_fast_float_with_key_applies_to_string_example() -> None:
assert fast_float("invalid", key=len) == len("invalid")
@given(text().filter(not_a_float).filter(bool))
-def test_fast_float_with_key_applies_to_string(x):
+def test_fast_float_with_key_applies_to_string(x: str) -> None:
assert fast_float(x, key=len) == len(x)
-def test_fast_int_leaves_float_string_as_is_example():
+def test_fast_int_leaves_float_string_as_is_example() -> None:
assert fast_int("45.8") == "45.8"
assert fast_int("nan") == "nan"
assert fast_int("inf") == "inf"
@given(floats().filter(not_an_int))
-def test_fast_int_leaves_float_string_as_is(x):
+def test_fast_int_leaves_float_string_as_is(x: float) -> None:
assert fast_int(repr(x)) == repr(x)
-def test_fast_int_converts_int_string_to_int_example():
+def test_fast_int_converts_int_string_to_int_example() -> None:
assert fast_int("-45") == -45
assert fast_int("+45") == 45
assert fast_int("۱۲") == 12
@@ -111,23 +112,23 @@ def test_fast_int_converts_int_string_to_int_example():
@given(integers())
-def test_fast_int_converts_int_string_to_int(x):
+def test_fast_int_converts_int_string_to_int(x: int) -> None:
assert fast_int(repr(x)) == x
-def test_fast_int_leaves_string_as_is_example():
+def test_fast_int_leaves_string_as_is_example() -> None:
assert fast_int("invalid") == "invalid"
@given(text().filter(not_an_int).filter(bool))
-def test_fast_int_leaves_string_as_is(x):
+def test_fast_int_leaves_string_as_is(x: str) -> None:
assert fast_int(x) == x
-def test_fast_int_with_key_applies_to_string_example():
+def test_fast_int_with_key_applies_to_string_example() -> None:
assert fast_int("invalid", key=len) == len("invalid")
@given(text().filter(not_an_int).filter(bool))
-def test_fast_int_with_key_applies_to_string(x):
+def test_fast_int_with_key_applies_to_string(x: str) -> None:
assert fast_int(x, key=len) == len(x)
diff --git a/tests/test_final_data_transform_factory.py b/tests/test_final_data_transform_factory.py
index f6bf636..5437d53 100644
--- a/tests/test_final_data_transform_factory.py
+++ b/tests/test_final_data_transform_factory.py
@@ -1,17 +1,20 @@
# -*- coding: utf-8 -*-
"""These test the utils.py functions."""
+from typing import Callable, Union
import pytest
from hypothesis import example, given
from hypothesis.strategies import floats, integers, text
-from natsort.ns_enum import NS_DUMB, ns
+from natsort.ns_enum import NS_DUMB, NS_t, ns
from natsort.utils import final_data_transform_factory
@pytest.mark.parametrize("alg", [ns.DEFAULT, ns.UNGROUPLETTERS, ns.LOCALE])
@given(x=text(), y=floats(allow_nan=False, allow_infinity=False) | integers())
@pytest.mark.usefixtures("with_locale_en_us")
-def test_final_data_transform_factory_default(x, y, alg):
+def test_final_data_transform_factory_default(
+ x: str, y: Union[int, float], alg: NS_t
+) -> None:
final_data_transform_func = final_data_transform_factory(alg, "", "::")
value = (x, y)
original_value = "".join(map(str, value))
@@ -34,7 +37,9 @@ def test_final_data_transform_factory_default(x, y, alg):
@given(x=text(), y=floats(allow_nan=False, allow_infinity=False) | integers())
@example(x="İ", y=0)
@pytest.mark.usefixtures("with_locale_en_us")
-def test_final_data_transform_factory_ungroup_and_locale(x, y, alg, func):
+def test_final_data_transform_factory_ungroup_and_locale(
+ x: str, y: Union[int, float], alg: NS_t, func: Callable[[str], str]
+) -> None:
final_data_transform_func = final_data_transform_factory(alg, "", "::")
value = (x, y)
original_value = "".join(map(str, value))
@@ -46,6 +51,6 @@ def test_final_data_transform_factory_ungroup_and_locale(x, y, alg, func):
assert result == expected
-def test_final_data_transform_factory_ungroup_and_locale_empty_tuple():
+def test_final_data_transform_factory_ungroup_and_locale_empty_tuple() -> None:
final_data_transform_func = final_data_transform_factory(ns.UG | ns.L, "", "::")
assert final_data_transform_func((), "") == ((), ())
diff --git a/tests/test_input_string_transform_factory.py b/tests/test_input_string_transform_factory.py
index 7d54afd..d265492 100644
--- a/tests/test_input_string_transform_factory.py
+++ b/tests/test_input_string_transform_factory.py
@@ -1,14 +1,15 @@
# -*- coding: utf-8 -*-
"""These test the utils.py functions."""
+from typing import Callable
import pytest
from hypothesis import example, given
from hypothesis.strategies import integers, text
-from natsort.ns_enum import NS_DUMB, ns
+from natsort.ns_enum import NS_DUMB, NS_t, ns
from natsort.utils import input_string_transform_factory
-def thousands_separated_int(n):
+def thousands_separated_int(n: str) -> str:
"""Insert thousands separators in an int."""
new_int = ""
for i, y in enumerate(reversed(n), 1):
@@ -20,7 +21,7 @@ def thousands_separated_int(n):
@given(text())
-def test_input_string_transform_factory_is_no_op_for_no_alg_options(x):
+def test_input_string_transform_factory_is_no_op_for_no_alg_options(x: str) -> None:
input_string_transform_func = input_string_transform_factory(ns.DEFAULT)
assert input_string_transform_func(x) is x
@@ -36,7 +37,9 @@ def test_input_string_transform_factory_is_no_op_for_no_alg_options(x):
],
)
@given(x=text())
-def test_input_string_transform_factory(x, alg, example_func):
+def test_input_string_transform_factory(
+ x: str, alg: NS_t, example_func: Callable[[str], str]
+) -> None:
input_string_transform_func = input_string_transform_factory(alg)
assert input_string_transform_func(x) == example_func(x)
@@ -44,7 +47,7 @@ def test_input_string_transform_factory(x, alg, example_func):
@example(12543642642534980) # 12,543,642,642,534,980 => 12543642642534980
@given(x=integers(min_value=1000))
@pytest.mark.usefixtures("with_locale_en_us")
-def test_input_string_transform_factory_cleans_thousands(x):
+def test_input_string_transform_factory_cleans_thousands(x: int) -> None:
int_str = str(x).rstrip("lL")
thousands_int_str = thousands_separated_int(int_str)
assert thousands_int_str.replace(",", "") != thousands_int_str
@@ -69,7 +72,9 @@ def test_input_string_transform_factory_cleans_thousands(x):
],
)
@pytest.mark.usefixtures("with_locale_en_us")
-def test_input_string_transform_factory_handles_us_locale(x, expected):
+def test_input_string_transform_factory_handles_us_locale(
+ x: str, expected: str
+) -> None:
input_string_transform_func = input_string_transform_factory(ns.LOCALE)
assert input_string_transform_func(x) == expected
@@ -83,7 +88,9 @@ def test_input_string_transform_factory_handles_us_locale(x, expected):
],
)
@pytest.mark.usefixtures("with_locale_de_de")
-def test_input_string_transform_factory_handles_de_locale(x, expected):
+def test_input_string_transform_factory_handles_de_locale(
+ x: str, expected: str
+) -> None:
input_string_transform_func = input_string_transform_factory(ns.LOCALE)
assert input_string_transform_func(x) == expected
@@ -97,13 +104,15 @@ def test_input_string_transform_factory_handles_de_locale(x, expected):
],
)
@pytest.mark.usefixtures("with_locale_de_de")
-def test_input_string_transform_factory_handles_german_locale(alg, expected):
+def test_input_string_transform_factory_handles_german_locale(
+ alg: NS_t, expected: str
+) -> None:
input_string_transform_func = input_string_transform_factory(alg)
assert input_string_transform_func("1543,753") == expected
@pytest.mark.usefixtures("with_locale_de_de")
-def test_input_string_transform_factory_does_nothing_with_non_num_input():
+def test_input_string_transform_factory_does_nothing_with_non_num_input() -> None:
input_string_transform_func = input_string_transform_factory(ns.LOCALE | ns.FLOAT)
expected = "154s,t53"
assert input_string_transform_func("154s,t53") == expected
diff --git a/tests/test_main.py b/tests/test_main.py
index da91fdd..d2a3e28 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -5,11 +5,13 @@ Test the natsort command-line tool functions.
import re
import sys
+from typing import Any as Any_t, List, Union
import pytest
from hypothesis import given
-from hypothesis.strategies import data, floats, integers, lists
+from hypothesis.strategies import DataObject, data, floats, integers, lists
from natsort.__main__ import (
+ TypedArgs,
check_filters,
keep_entry_range,
keep_entry_value,
@@ -17,9 +19,12 @@ from natsort.__main__ import (
range_check,
sort_and_print_entries,
)
+from pytest_mock import MockerFixture
-def test_main_passes_default_arguments_with_no_command_line_options(mocker):
+def test_main_passes_default_arguments_with_no_command_line_options(
+ mocker: MockerFixture,
+) -> None:
p = mocker.patch("natsort.__main__.sort_and_print_entries")
main("num-2", "num-6", "num-1")
args = p.call_args[0][1]
@@ -34,7 +39,9 @@ def test_main_passes_default_arguments_with_no_command_line_options(mocker):
assert not args.locale
-def test_main_passes_arguments_with_all_command_line_options(mocker):
+def test_main_passes_arguments_with_all_command_line_options(
+ mocker: MockerFixture,
+) -> None:
arguments = ["--paths", "--reverse", "--locale"]
arguments.extend(["--filter", "4", "10"])
arguments.extend(["--reverse-filter", "100", "110"])
@@ -57,21 +64,6 @@ def test_main_passes_arguments_with_all_command_line_options(mocker):
assert args.locale
-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.signed = True
- self.exp = True
- self.paths = as_path
- self.locale = 0
-
-
mock_print = "__builtin__.print" if sys.version[0] == "2" else "builtins.print"
entries = [
@@ -135,9 +127,11 @@ entries = [
([None, None, False, True, True], reversed([2, 3, 1, 0, 5, 6, 4])),
],
)
-def test_sort_and_print_entries(options, order, mocker):
+def test_sort_and_print_entries(
+ options: List[Any_t], order: List[int], mocker: MockerFixture
+) -> None:
p = mocker.patch(mock_print)
- sort_and_print_entries(entries, Args(*options))
+ sort_and_print_entries(entries, TypedArgs(*options))
e = [mocker.call(entries[i]) for i in order]
p.assert_has_calls(e)
@@ -146,13 +140,15 @@ def test_sort_and_print_entries(options, order, mocker):
# and a test that uses the hypothesis module.
-def test_range_check_returns_range_as_is_but_with_floats_example():
+def test_range_check_returns_range_as_is_but_with_floats_example() -> None:
assert range_check(10, 11) == (10.0, 11.0)
assert range_check(6.4, 30) == (6.4, 30.0)
@given(x=floats(allow_nan=False, min_value=-1e8, max_value=1e8) | integers(), d=data())
-def test_range_check_returns_range_as_is_if_first_is_less_than_second(x, d):
+def test_range_check_returns_range_as_is_if_first_is_less_than_second(
+ x: Union[int, float], d: DataObject
+) -> None:
# Pull data such that the first is less than the second.
if isinstance(x, float):
y = d.draw(floats(min_value=x + 1.0, max_value=1e9, allow_nan=False))
@@ -161,44 +157,48 @@ def test_range_check_returns_range_as_is_if_first_is_less_than_second(x, d):
assert range_check(x, y) == (x, y)
-def test_range_check_raises_value_error_if_second_is_less_than_first_example():
+def test_range_check_raises_value_error_if_second_is_less_than_first_example() -> None:
with pytest.raises(ValueError, match="low >= high"):
range_check(7, 2)
@given(x=floats(allow_nan=False), d=data())
-def test_range_check_raises_value_error_if_second_is_less_than_first(x, d):
+def test_range_check_raises_value_error_if_second_is_less_than_first(
+ x: float, d: DataObject
+) -> None:
# Pull data such that the first is greater than or equal to the second.
y = d.draw(floats(max_value=x, allow_nan=False))
with pytest.raises(ValueError, match="low >= high"):
range_check(x, y)
-def test_check_filters_returns_none_if_filter_evaluates_to_false():
+def test_check_filters_returns_none_if_filter_evaluates_to_false() -> None:
assert check_filters(()) is None
- assert check_filters(False) is None
- assert check_filters(None) is None
-def test_check_filters_returns_input_as_is_if_filter_is_valid_example():
+def test_check_filters_returns_input_as_is_if_filter_is_valid_example() -> None:
assert check_filters([(6, 7)]) == [(6, 7)]
assert check_filters([(6, 7), (2, 8)]) == [(6, 7), (2, 8)]
@given(x=lists(integers(), min_size=1), d=data())
-def test_check_filters_returns_input_as_is_if_filter_is_valid(x, d):
+def test_check_filters_returns_input_as_is_if_filter_is_valid(
+ x: List[int], d: DataObject
+) -> None:
# ensure y is element-wise greater than x
y = [d.draw(integers(min_value=val + 1)) for val in x]
assert check_filters(list(zip(x, y))) == [(i, j) for i, j in zip(x, y)]
-def test_check_filters_raises_value_error_if_filter_is_invalid_example():
+def test_check_filters_raises_value_error_if_filter_is_invalid_example() -> None:
with pytest.raises(ValueError, match="Error in --filter: low >= high"):
check_filters([(7, 2)])
@given(x=lists(integers(), min_size=1), d=data())
-def test_check_filters_raises_value_error_if_filter_is_invalid(x, d):
+def test_check_filters_raises_value_error_if_filter_is_invalid(
+ x: List[int], d: DataObject
+) -> None:
# ensure y is element-wise less than or equal to x
y = [d.draw(integers(max_value=val)) for val in x]
with pytest.raises(ValueError, match="Error in --filter: low >= high"):
@@ -212,11 +212,11 @@ def test_check_filters_raises_value_error_if_filter_is_invalid(x, d):
# 3. No portion is between the bounds => False.
[([0], [100], True), ([1, 88], [20, 90], True), ([1], [20], False)],
)
-def test_keep_entry_range(lows, highs, truth):
+def test_keep_entry_range(lows: List[int], highs: List[int], truth: bool) -> None:
assert keep_entry_range("a56b23c89", lows, highs, int, re.compile(r"\d+")) is truth
# 1. Values not in entry => True. 2. Values in entry => False.
@pytest.mark.parametrize("values, truth", [([100, 45], True), ([23], False)])
-def test_keep_entry_value(values, truth):
+def test_keep_entry_value(values: List[int], truth: bool) -> None:
assert keep_entry_value("a56b23c89", values, int, re.compile(r"\d+")) is truth
diff --git a/tests/test_natsort_key.py b/tests/test_natsort_key.py
index 6b56bb1..8034a8c 100644
--- a/tests/test_natsort_key.py
+++ b/tests/test_natsort_key.py
@@ -1,42 +1,43 @@
# -*- coding: utf-8 -*-
"""These test the utils.py functions."""
+from typing import Any as Any_t, List, NoReturn, Tuple, Union
from hypothesis import given
from hypothesis.strategies import binary, floats, integers, lists, text
from natsort.utils import natsort_key
-def str_func(x):
+def str_func(x: Any_t) -> Tuple[str]:
if isinstance(x, str):
- return x
+ return (x,)
else:
raise TypeError("Not a str!")
-def fail(_):
+def fail(_: Any_t) -> NoReturn:
raise AssertionError("This should never be reached!")
@given(floats(allow_nan=False) | integers())
-def test_natsort_key_with_numeric_input_takes_number_path(x):
- assert natsort_key(x, None, str_func, fail, lambda y: y) is x
+def test_natsort_key_with_numeric_input_takes_number_path(x: Union[float, int]) -> None:
+ assert natsort_key(x, None, str_func, fail, lambda y: ("", y)) is x
@given(binary().filter(bool))
-def test_natsort_key_with_bytes_input_takes_bytes_path(x):
- assert natsort_key(x, None, str_func, lambda y: y, fail) is x
+def test_natsort_key_with_bytes_input_takes_bytes_path(x: bytes) -> None:
+ assert natsort_key(x, None, str_func, lambda y: (y,), fail) is x
@given(text())
-def test_natsort_key_with_text_input_takes_string_path(x):
+def test_natsort_key_with_text_input_takes_string_path(x: str) -> None:
assert natsort_key(x, None, str_func, fail, fail) is x
@given(lists(elements=text(), min_size=1, max_size=10))
-def test_natsort_key_with_nested_input_takes_nested_path(x):
+def test_natsort_key_with_nested_input_takes_nested_path(x: List[str]) -> None:
assert natsort_key(x, None, str_func, fail, fail) == tuple(x)
@given(text())
-def test_natsort_key_with_key_argument_applies_key_before_processing(x):
- assert natsort_key(x, len, str_func, fail, lambda y: y) == len(x)
+def test_natsort_key_with_key_argument_applies_key_before_processing(x: str) -> None:
+ assert natsort_key(x, len, str_func, fail, lambda y: ("", y)) == len(x)
diff --git a/tests/test_natsort_keygen.py b/tests/test_natsort_keygen.py
index 5fb8cf3..0abdefb 100644
--- a/tests/test_natsort_keygen.py
+++ b/tests/test_natsort_keygen.py
@@ -5,23 +5,27 @@ See the README or the natsort homepage for more details.
"""
import os
+from typing import List, Tuple, Union
import pytest
from natsort import natsort_key, natsort_keygen, natsorted, ns
from natsort.compat.locale import get_strxfrm, null_string_locale
+from natsort.ns_enum import NS_t
+from natsort.utils import BytesTransform, FinalTransform
+from pytest_mock import MockerFixture
@pytest.fixture
-def arbitrary_input():
+def arbitrary_input() -> List[Union[str, float]]:
return ["6A-5.034e+1", "/Folder (1)/Foo", 56.7]
@pytest.fixture
-def bytes_input():
+def bytes_input() -> bytes:
return b"6A-5.034e+1"
-def test_natsort_keygen_demonstration():
+def test_natsort_keygen_demonstration() -> None:
original_list = ["a50", "a51.", "a50.31", "a50.4", "a5.034e1", "a50.300"]
copy_of_list = original_list[:]
original_list.sort(key=natsort_keygen(alg=ns.F))
@@ -29,21 +33,23 @@ def test_natsort_keygen_demonstration():
assert original_list == natsorted(copy_of_list, alg=ns.F)
-def test_natsort_key_public():
+def test_natsort_key_public() -> None:
assert natsort_key("a-5.034e2") == ("a-", 5, ".", 34, "e", 2)
-def test_natsort_keygen_with_invalid_alg_input_raises_value_error():
+def test_natsort_keygen_with_invalid_alg_input_raises_value_error() -> None:
# Invalid arguments give the correct response
with pytest.raises(ValueError, match="'alg' argument"):
- natsort_keygen(None, "1")
+ natsort_keygen(None, "1") # type: ignore
@pytest.mark.parametrize(
"alg, expected",
[(ns.DEFAULT, ("a-", 5, ".", 34, "e", 1)), (ns.FLOAT | ns.SIGNED, ("a", -50.34))],
)
-def test_natsort_keygen_returns_natsort_key_that_parses_input(alg, expected):
+def test_natsort_keygen_returns_natsort_key_that_parses_input(
+ alg: NS_t, expected: Tuple[Union[str, int, float], ...]
+) -> None:
ns_key = natsort_keygen(alg=alg)
assert ns_key("a-5.034e1") == expected
@@ -78,7 +84,9 @@ def test_natsort_keygen_returns_natsort_key_that_parses_input(alg, expected):
),
],
)
-def test_natsort_keygen_handles_arbitrary_input(arbitrary_input, alg, expected):
+def test_natsort_keygen_handles_arbitrary_input(
+ arbitrary_input: List[Union[str, float]], alg: NS_t, expected: FinalTransform
+) -> None:
ns_key = natsort_keygen(alg=alg)
assert ns_key(arbitrary_input) == expected
@@ -93,13 +101,15 @@ def test_natsort_keygen_handles_arbitrary_input(arbitrary_input, alg, expected):
(ns.PATH | ns.GROUPLETTERS, ((b"6A-5.034e+1",),)),
],
)
-def test_natsort_keygen_handles_bytes_input(bytes_input, alg, expected):
+def test_natsort_keygen_handles_bytes_input(
+ bytes_input: bytes, alg: NS_t, expected: BytesTransform
+) -> None:
ns_key = natsort_keygen(alg=alg)
assert ns_key(bytes_input) == expected
@pytest.mark.parametrize(
- "alg, expected, is_dumb",
+ "alg, expected_in, is_dumb",
[
(
ns.LOCALE,
@@ -131,23 +141,29 @@ def test_natsort_keygen_handles_bytes_input(bytes_input, alg, expected):
],
)
@pytest.mark.usefixtures("with_locale_en_us")
-def test_natsort_keygen_with_locale(mocker, arbitrary_input, alg, expected, is_dumb):
+def test_natsort_keygen_with_locale(
+ mocker: MockerFixture,
+ arbitrary_input: List[Union[str, float]],
+ alg: NS_t,
+ expected: FinalTransform,
+ is_dumb: bool,
+) -> None:
# First, apply the correct strxfrm function to the string values.
strxfrm = get_strxfrm()
- expected = [list(sub) for sub in expected]
+ expected_tmp = [list(sub) for sub in expected]
try:
for i in (2, 4, 6):
- expected[0][i] = strxfrm(expected[0][i])
+ expected_tmp[0][i] = strxfrm(expected_tmp[0][i])
for i in (0, 2):
- expected[1][i] = strxfrm(expected[1][i])
- expected = tuple(tuple(sub) for sub in expected)
+ expected_tmp[1][i] = strxfrm(expected_tmp[1][i])
+ expected = tuple(tuple(sub) for sub in expected_tmp)
except IndexError: # ns.LOCALE | ns.CAPITALFIRST
- expected = [[list(subsub) for subsub in sub] for sub in expected]
+ expected_tmp = [[list(subsub) for subsub in sub] for sub in expected_tmp]
for i in (2, 4, 6):
- expected[0][1][i] = strxfrm(expected[0][1][i])
+ expected_tmp[0][1][i] = strxfrm(expected_tmp[0][1][i])
for i in (0, 2):
- expected[1][1][i] = strxfrm(expected[1][1][i])
- expected = tuple(tuple(tuple(subsub) for subsub in sub) for sub in expected)
+ expected_tmp[1][1][i] = strxfrm(expected_tmp[1][1][i])
+ expected = tuple(tuple(tuple(subsub) for subsub in sub) for sub in expected_tmp)
mocker.patch("natsort.compat.locale.dumb_sort", return_value=is_dumb)
ns_key = natsort_keygen(alg=alg)
@@ -159,7 +175,9 @@ def test_natsort_keygen_with_locale(mocker, arbitrary_input, alg, expected, is_d
[(ns.LOCALE, False), (ns.LOCALE, True), (ns.LOCALE | ns.CAPITALFIRST, False)],
)
@pytest.mark.usefixtures("with_locale_en_us")
-def test_natsort_keygen_with_locale_bytes(mocker, bytes_input, alg, is_dumb):
+def test_natsort_keygen_with_locale_bytes(
+ mocker: MockerFixture, bytes_input: bytes, alg: NS_t, is_dumb: bool
+) -> None:
expected = (b"6A-5.034e+1",)
mocker.patch("natsort.compat.locale.dumb_sort", return_value=is_dumb)
ns_key = natsort_keygen(alg=alg)
diff --git a/tests/test_natsorted.py b/tests/test_natsorted.py
index 4254e6c..e71678f 100644
--- a/tests/test_natsorted.py
+++ b/tests/test_natsorted.py
@@ -5,6 +5,8 @@ See the README or the natsort homepage for more details.
"""
from operator import itemgetter
+from typing import List, Tuple, Union
+from natsort.ns_enum import NS_t
import pytest
from natsort import as_utf8, natsorted, ns
@@ -12,27 +14,29 @@ from pytest import raises
@pytest.fixture
-def float_list():
+def float_list() -> List[str]:
return ["a50", "a51.", "a50.31", "a-50", "a50.4", "a5.034e1", "a50.300"]
@pytest.fixture
-def fruit_list():
+def fruit_list() -> List[str]:
return ["Apple", "corn", "Corn", "Banana", "apple", "banana"]
@pytest.fixture
-def mixed_list():
+def mixed_list() -> List[Union[str, int, float]]:
return ["Ä", "0", "ä", 3, "b", 1.5, "2", "Z"]
-def test_natsorted_numbers_in_ascending_order():
+def test_natsorted_numbers_in_ascending_order() -> None:
given = ["a2", "a5", "a9", "a1", "a4", "a10", "a6"]
expected = ["a1", "a2", "a4", "a5", "a6", "a9", "a10"]
assert natsorted(given) == expected
-def test_natsorted_can_sort_as_signed_floats_with_exponents(float_list):
+def test_natsorted_can_sort_as_signed_floats_with_exponents(
+ float_list: List[str],
+) -> None:
expected = ["a-50", "a50", "a50.300", "a50.31", "a5.034e1", "a50.4", "a51."]
assert natsorted(float_list, alg=ns.REAL) == expected
@@ -42,19 +46,23 @@ def test_natsorted_can_sort_as_signed_floats_with_exponents(float_list):
"alg",
[ns.NOEXP | ns.FLOAT | ns.UNSIGNED, ns.NOEXP | ns.FLOAT],
)
-def test_natsorted_can_sort_as_unsigned_and_ignore_exponents(float_list, alg):
+def test_natsorted_can_sort_as_unsigned_and_ignore_exponents(
+ float_list: List[str], alg: NS_t
+) -> None:
expected = ["a5.034e1", "a50", "a50.300", "a50.31", "a50.4", "a51.", "a-50"]
assert natsorted(float_list, alg=alg) == expected
# DEFAULT and INT are all equivalent.
@pytest.mark.parametrize("alg", [ns.DEFAULT, ns.INT])
-def test_natsorted_can_sort_as_unsigned_ints_which_is_default(float_list, alg):
+def test_natsorted_can_sort_as_unsigned_ints_which_is_default(
+ float_list: List[str], alg: NS_t
+) -> None:
expected = ["a5.034e1", "a50", "a50.4", "a50.31", "a50.300", "a51.", "a-50"]
assert natsorted(float_list, alg=alg) == expected
-def test_natsorted_can_sort_as_signed_ints(float_list):
+def test_natsorted_can_sort_as_signed_ints(float_list: List[str]) -> None:
expected = ["a-50", "a5.034e1", "a50", "a50.4", "a50.31", "a50.300", "a51."]
assert natsorted(float_list, alg=ns.SIGNED) == expected
@@ -63,12 +71,14 @@ def test_natsorted_can_sort_as_signed_ints(float_list):
"alg, expected",
[(ns.UNSIGNED, ["a7", "a+2", "a-5"]), (ns.SIGNED, ["a-5", "a+2", "a7"])],
)
-def test_natsorted_can_sort_with_or_without_accounting_for_sign(alg, expected):
+def test_natsorted_can_sort_with_or_without_accounting_for_sign(
+ alg: NS_t, expected: List[str]
+) -> None:
given = ["a-5", "a7", "a+2"]
assert natsorted(given, alg=alg) == expected
-def test_natsorted_can_sort_as_version_numbers():
+def test_natsorted_can_sort_as_version_numbers() -> None:
given = ["1.9.9a", "1.11", "1.9.9b", "1.11.4", "1.10.1"]
expected = ["1.9.9a", "1.9.9b", "1.10.1", "1.11", "1.11.4"]
assert natsorted(given) == expected
@@ -81,7 +91,11 @@ def test_natsorted_can_sort_as_version_numbers():
(ns.NUMAFTER, ["Ä", "Z", "ä", "b", "0", 1.5, "2", 3]),
],
)
-def test_natsorted_handles_mixed_types(mixed_list, alg, expected):
+def test_natsorted_handles_mixed_types(
+ mixed_list: List[Union[str, int, float]],
+ alg: NS_t,
+ expected: List[Union[str, int, float]],
+) -> None:
assert natsorted(mixed_list, alg=alg) == expected
@@ -92,14 +106,16 @@ def test_natsorted_handles_mixed_types(mixed_list, alg, expected):
(ns.NANLAST, [5, "25", 1e40, float("nan")], slice(None, 3)),
],
)
-def test_natsorted_handles_nan(alg, expected, slc):
- given = ["25", 5, float("nan"), 1e40]
+def test_natsorted_handles_nan(
+ alg: NS_t, expected: List[Union[str, float, int]], slc: slice
+) -> None:
+ given: List[Union[str, float, int]] = ["25", 5, float("nan"), 1e40]
# The slice is because NaN != NaN
# noinspection PyUnresolvedReferences
assert natsorted(given, alg=alg)[slc] == expected[slc]
-def test_natsorted_with_mixed_bytes_and_str_input_raises_type_error():
+def test_natsorted_with_mixed_bytes_and_str_input_raises_type_error() -> None:
with raises(TypeError, match="bytes"):
natsorted(["ä", b"b"])
@@ -107,29 +123,31 @@ def test_natsorted_with_mixed_bytes_and_str_input_raises_type_error():
assert natsorted(["ä", b"b"], key=as_utf8) == ["ä", b"b"]
-def test_natsorted_raises_type_error_for_non_iterable_input():
+def test_natsorted_raises_type_error_for_non_iterable_input() -> None:
with raises(TypeError, match="'int' object is not iterable"):
- natsorted(100)
+ natsorted(100) # type: ignore
-def test_natsorted_recurses_into_nested_lists():
+def test_natsorted_recurses_into_nested_lists() -> None:
given = [["a1", "a5"], ["a1", "a40"], ["a10", "a1"], ["a2", "a5"]]
expected = [["a1", "a5"], ["a1", "a40"], ["a2", "a5"], ["a10", "a1"]]
assert natsorted(given) == expected
-def test_natsorted_applies_key_to_each_list_element_before_sorting_list():
+def test_natsorted_applies_key_to_each_list_element_before_sorting_list() -> None:
given = [("a", "num3"), ("b", "num5"), ("c", "num2")]
expected = [("c", "num2"), ("a", "num3"), ("b", "num5")]
assert natsorted(given, key=itemgetter(1)) == expected
-def test_natsorted_returns_list_in_reversed_order_with_reverse_option(float_list):
+def test_natsorted_returns_list_in_reversed_order_with_reverse_option(
+ float_list: List[str],
+) -> None:
expected = natsorted(float_list)[::-1]
assert natsorted(float_list, reverse=True) == expected
-def test_natsorted_handles_filesystem_paths():
+def test_natsorted_handles_filesystem_paths() -> None:
given = [
"/p/Folder (10)/file.tar.gz",
"/p/Folder (1)/file (1).tar.gz",
@@ -157,10 +175,10 @@ def test_natsorted_handles_filesystem_paths():
assert natsorted(given, alg=ns.FLOAT | ns.PATH) == expected_correct
-def test_natsorted_handles_numbers_and_filesystem_paths_simultaneously():
+def test_natsorted_handles_numbers_and_filesystem_paths_simultaneously() -> None:
# You can sort paths and numbers, not that you'd want to
- given = ["/Folder (9)/file.exe", 43]
- expected = [43, "/Folder (9)/file.exe"]
+ given: List[Union[str, int]] = ["/Folder (9)/file.exe", 43]
+ expected: List[Union[str, int]] = [43, "/Folder (9)/file.exe"]
assert natsorted(given, alg=ns.PATH) == expected
@@ -174,7 +192,9 @@ def test_natsorted_handles_numbers_and_filesystem_paths_simultaneously():
(ns.G | ns.LF, ["apple", "Apple", "banana", "Banana", "corn", "Corn"]),
],
)
-def test_natsorted_supports_case_handling(alg, expected, fruit_list):
+def test_natsorted_supports_case_handling(
+ alg: NS_t, expected: List[str], fruit_list: List[str]
+) -> None:
assert natsorted(fruit_list, alg=alg) == expected
@@ -186,7 +206,9 @@ def test_natsorted_supports_case_handling(alg, expected, fruit_list):
(ns.IGNORECASE, [("a3", "a1"), ("A5", "a6")]),
],
)
-def test_natsorted_supports_nested_case_handling(alg, expected):
+def test_natsorted_supports_nested_case_handling(
+ alg: NS_t, expected: List[Tuple[str, str]]
+) -> None:
given = [("A5", "a6"), ("a3", "a1")]
assert natsorted(given, alg=alg) == expected
@@ -201,26 +223,28 @@ def test_natsorted_supports_nested_case_handling(alg, expected):
],
)
@pytest.mark.usefixtures("with_locale_en_us")
-def test_natsorted_can_sort_using_locale(fruit_list, alg, expected):
+def test_natsorted_can_sort_using_locale(
+ fruit_list: List[str], alg: NS_t, expected: List[str]
+) -> None:
assert natsorted(fruit_list, alg=ns.LOCALE | alg) == expected
@pytest.mark.usefixtures("with_locale_en_us")
-def test_natsorted_can_sort_locale_specific_numbers_en():
+def test_natsorted_can_sort_locale_specific_numbers_en() -> None:
given = ["c", "a5,467.86", "ä", "b", "a5367.86", "a5,6", "a5,50"]
expected = ["a5,6", "a5,50", "a5367.86", "a5,467.86", "ä", "b", "c"]
assert natsorted(given, alg=ns.LOCALE | ns.F) == expected
@pytest.mark.usefixtures("with_locale_de_de")
-def test_natsorted_can_sort_locale_specific_numbers_de():
+def test_natsorted_can_sort_locale_specific_numbers_de() -> None:
given = ["c", "a5.467,86", "ä", "b", "a5367.86", "a5,6", "a5,50"]
expected = ["a5,50", "a5,6", "a5367.86", "a5.467,86", "ä", "b", "c"]
assert natsorted(given, alg=ns.LOCALE | ns.F) == expected
@pytest.mark.usefixtures("with_locale_de_de")
-def test_natsorted_locale_bug_regression_test_109():
+def test_natsorted_locale_bug_regression_test_109() -> None:
# https://github.com/SethMMorton/natsort/issues/109
given = ["462166", "461761"]
expected = ["461761", "462166"]
@@ -242,7 +266,11 @@ def test_natsorted_locale_bug_regression_test_109():
],
)
@pytest.mark.usefixtures("with_locale_en_us")
-def test_natsorted_handles_mixed_types_with_locale(mixed_list, alg, expected):
+def test_natsorted_handles_mixed_types_with_locale(
+ mixed_list: List[Union[str, int, float]],
+ alg: NS_t,
+ expected: List[Union[str, int, float]],
+) -> None:
assert natsorted(mixed_list, alg=ns.LOCALE | alg) == expected
@@ -253,12 +281,14 @@ def test_natsorted_handles_mixed_types_with_locale(mixed_list, alg, expected):
(ns.NUMAFTER, ["Banana", "apple", "corn", "~~~~~~", "73", "5039"]),
],
)
-def test_natsorted_sorts_an_odd_collection_of_strings(alg, expected):
+def test_natsorted_sorts_an_odd_collection_of_strings(
+ alg: NS_t, expected: List[str]
+) -> None:
given = ["apple", "Banana", "73", "5039", "corn", "~~~~~~"]
assert natsorted(given, alg=alg) == expected
-def test_natsorted_sorts_mixed_ascii_and_non_ascii_numbers():
+def test_natsorted_sorts_mixed_ascii_and_non_ascii_numbers() -> None:
given = [
"1st street",
"10th street",
diff --git a/tests/test_natsorted_convenience.py b/tests/test_natsorted_convenience.py
index cdc2c50..599c4ba 100644
--- a/tests/test_natsorted_convenience.py
+++ b/tests/test_natsorted_convenience.py
@@ -5,6 +5,7 @@ See the README or the natsort homepage for more details.
"""
from operator import itemgetter
+from typing import List
import pytest
from natsort import (
@@ -23,21 +24,21 @@ from natsort import (
@pytest.fixture
-def version_list():
+def version_list() -> List[str]:
return ["1.9.9a", "1.11", "1.9.9b", "1.11.4", "1.10.1"]
@pytest.fixture
-def float_list():
+def float_list() -> List[str]:
return ["a50", "a51.", "a50.31", "a-50", "a50.4", "a5.034e1", "a50.300"]
@pytest.fixture
-def fruit_list():
+def fruit_list() -> List[str]:
return ["Apple", "corn", "Corn", "Banana", "apple", "banana"]
-def test_decoder_returns_function_that_can_decode_bytes_but_return_non_bytes_as_is():
+def test_decoder_returns_function_that_can_decode_bytes_but_return_non_bytes_as_is() -> None:
func = decoder("latin1")
str_obj = "bytes"
int_obj = 14
@@ -46,24 +47,28 @@ def test_decoder_returns_function_that_can_decode_bytes_but_return_non_bytes_as_
assert func(str_obj) is str_obj # same object returned b/c only bytes has decode
-def test_as_ascii_converts_bytes_to_ascii():
+def test_as_ascii_converts_bytes_to_ascii() -> None:
assert decoder("ascii")(b"bytes") == as_ascii(b"bytes")
-def test_as_utf8_converts_bytes_to_utf8():
+def test_as_utf8_converts_bytes_to_utf8() -> None:
assert decoder("utf8")(b"bytes") == as_utf8(b"bytes")
-def test_realsorted_is_identical_to_natsorted_with_real_alg(float_list):
+def test_realsorted_is_identical_to_natsorted_with_real_alg(
+ float_list: List[str],
+) -> None:
assert realsorted(float_list) == natsorted(float_list, alg=ns.REAL)
@pytest.mark.usefixtures("with_locale_en_us")
-def test_humansorted_is_identical_to_natsorted_with_locale_alg(fruit_list):
+def test_humansorted_is_identical_to_natsorted_with_locale_alg(
+ fruit_list: List[str],
+) -> None:
assert humansorted(fruit_list) == natsorted(fruit_list, alg=ns.LOCALE)
-def test_index_natsorted_returns_integer_list_of_sort_order_for_input_list():
+def test_index_natsorted_returns_integer_list_of_sort_order_for_input_list() -> None:
given = ["num3", "num5", "num2"]
other = ["foo", "bar", "baz"]
index = index_natsorted(given)
@@ -72,27 +77,31 @@ def test_index_natsorted_returns_integer_list_of_sort_order_for_input_list():
assert [other[i] for i in index] == ["baz", "foo", "bar"]
-def test_index_natsorted_reverse():
+def test_index_natsorted_reverse() -> None:
given = ["num3", "num5", "num2"]
assert index_natsorted(given, reverse=True) == index_natsorted(given)[::-1]
-def test_index_natsorted_applies_key_function_before_sorting():
+def test_index_natsorted_applies_key_function_before_sorting() -> None:
given = [("a", "num3"), ("b", "num5"), ("c", "num2")]
expected = [2, 0, 1]
assert index_natsorted(given, key=itemgetter(1)) == expected
-def test_index_realsorted_is_identical_to_index_natsorted_with_real_alg(float_list):
+def test_index_realsorted_is_identical_to_index_natsorted_with_real_alg(
+ float_list: List[str],
+) -> None:
assert index_realsorted(float_list) == index_natsorted(float_list, alg=ns.REAL)
@pytest.mark.usefixtures("with_locale_en_us")
-def test_index_humansorted_is_identical_to_index_natsorted_with_locale_alg(fruit_list):
+def test_index_humansorted_is_identical_to_index_natsorted_with_locale_alg(
+ fruit_list: List[str],
+) -> None:
assert index_humansorted(fruit_list) == index_natsorted(fruit_list, alg=ns.LOCALE)
-def test_order_by_index_sorts_list_according_to_order_of_integer_list():
+def test_order_by_index_sorts_list_according_to_order_of_integer_list() -> None:
given = ["num3", "num5", "num2"]
index = [2, 0, 1]
expected = [given[i] for i in index]
@@ -100,7 +109,7 @@ def test_order_by_index_sorts_list_according_to_order_of_integer_list():
assert order_by_index(given, index) == expected
-def test_order_by_index_returns_generator_with_iter_true():
+def test_order_by_index_returns_generator_with_iter_true() -> None:
given = ["num3", "num5", "num2"]
index = [2, 0, 1]
assert order_by_index(given, index, True) != [given[i] for i in index]
diff --git a/tests/test_ns_enum.py b/tests/test_ns_enum.py
index 312c454..7a30718 100644
--- a/tests/test_ns_enum.py
+++ b/tests/test_ns_enum.py
@@ -42,7 +42,7 @@ from natsort import ns
("NL", 0x0400),
("CN", 0x0800),
("NA", 0x1000),
- ]
+ ],
)
-def test_ns_enum(given, expected):
+def test_ns_enum(given: str, expected: int) -> None:
assert ns[given] == expected
diff --git a/tests/test_os_sorted.py b/tests/test_os_sorted.py
index afb15cf..d0ecc79 100644
--- a/tests/test_os_sorted.py
+++ b/tests/test_os_sorted.py
@@ -3,6 +3,7 @@
Testing for the OS sorting
"""
import platform
+from typing import cast
import natsort
import pytest
@@ -15,7 +16,7 @@ else:
has_icu = True
-def test_os_sorted_compound():
+def test_os_sorted_compound() -> None:
given = [
"/p/Folder (10)/file.tar.gz",
"/p/Folder (1)/file (1).tar.gz",
@@ -36,14 +37,14 @@ def test_os_sorted_compound():
assert result == expected
-def test_os_sorted_misc_no_fail():
+def test_os_sorted_misc_no_fail() -> None:
natsort.os_sorted([9, 4.3, None, float("nan")])
-def test_os_sorted_key():
+def test_os_sorted_key() -> None:
given = ["foo0", "foo2", "goo1"]
expected = ["foo0", "goo1", "foo2"]
- result = natsort.os_sorted(given, key=lambda x: x.replace("g", "f"))
+ result = natsort.os_sorted(given, key=lambda x: cast(str, x).replace("g", "f"))
assert result == expected
@@ -199,7 +200,7 @@ else:
@pytest.mark.usefixtures("with_locale_en_us")
-def test_os_sorted_corpus():
+def test_os_sorted_corpus() -> None:
result = natsort.os_sorted(given)
print(result)
assert result == expected
diff --git a/tests/test_parse_bytes_function.py b/tests/test_parse_bytes_function.py
index 6637cbd..fd358ba 100644
--- a/tests/test_parse_bytes_function.py
+++ b/tests/test_parse_bytes_function.py
@@ -4,8 +4,8 @@
import pytest
from hypothesis import given
from hypothesis.strategies import binary
-from natsort.ns_enum import ns
-from natsort.utils import parse_bytes_factory
+from natsort.ns_enum import NS_t, ns
+from natsort.utils import BytesTransformer, parse_bytes_factory
@pytest.mark.parametrize(
@@ -19,6 +19,8 @@ from natsort.utils import parse_bytes_factory
],
)
@given(x=binary())
-def test_parse_bytest_factory_makes_function_that_returns_tuple(x, alg, example_func):
+def test_parse_bytest_factory_makes_function_that_returns_tuple(
+ x: bytes, alg: NS_t, example_func: BytesTransformer
+) -> None:
parse_bytes_func = parse_bytes_factory(alg)
assert parse_bytes_func(x) == example_func(x)
diff --git a/tests/test_parse_number_function.py b/tests/test_parse_number_function.py
index 29ee5a3..3ce6d97 100644
--- a/tests/test_parse_number_function.py
+++ b/tests/test_parse_number_function.py
@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
"""These test the utils.py functions."""
+from typing import Optional, Tuple, Union
+
import pytest
from hypothesis import given
from hypothesis.strategies import floats, integers
-from natsort.ns_enum import ns
-from natsort.utils import parse_number_or_none_factory
+from natsort.ns_enum import NS_t, ns
+from natsort.utils import MaybeNumTransformer, parse_number_or_none_factory
@pytest.mark.usefixtures("with_locale_en_us")
@@ -19,7 +21,9 @@ from natsort.utils import parse_number_or_none_factory
],
)
@given(x=floats(allow_nan=False) | integers())
-def test_parse_number_factory_makes_function_that_returns_tuple(x, alg, example_func):
+def test_parse_number_factory_makes_function_that_returns_tuple(
+ x: Union[float, int], alg: NS_t, example_func: MaybeNumTransformer
+) -> None:
parse_number_func = parse_number_or_none_factory(alg, "", "xx")
assert parse_number_func(x) == example_func(x)
@@ -34,6 +38,8 @@ def test_parse_number_factory_makes_function_that_returns_tuple(x, alg, example_
(ns.NANLAST, None, ("", float("+inf"))), # NANLAST makes it +infinity
],
)
-def test_parse_number_factory_treats_nan_and_none_special(alg, x, result):
+def test_parse_number_factory_treats_nan_and_none_special(
+ alg: NS_t, x: Optional[Union[float, int]], result: Tuple[str, Union[float, int]]
+) -> None:
parse_number_func = parse_number_or_none_factory(alg, "", "xx")
assert parse_number_func(x) == result
diff --git a/tests/test_parse_string_function.py b/tests/test_parse_string_function.py
index 46347f1..c199964 100644
--- a/tests/test_parse_string_function.py
+++ b/tests/test_parse_string_function.py
@@ -2,23 +2,28 @@
"""These test the utils.py functions."""
import unicodedata
+from typing import Any as Any_t, Callable, Iterable, List, Tuple, Union
import pytest
from hypothesis import given
from hypothesis.strategies import floats, integers, lists, text
from natsort.compat.fastnumbers import fast_float
-from natsort.ns_enum import NS_DUMB, ns
-from natsort.utils import NumericalRegularExpressions as NumRegex
+from natsort.ns_enum import NS_DUMB, NS_t, ns
+from natsort.utils import (
+ FinalTransform,
+ NumericalRegularExpressions as NumRegex,
+ StrParser,
+)
from natsort.utils import parse_string_factory
-class CustomTuple(tuple):
+class CustomTuple(Tuple[Any_t, ...]):
"""Used to ensure what is given during testing is what is returned."""
- original = None
+ original: Any_t = None
-def input_transform(x):
+def input_transform(x: Any_t) -> Any_t:
"""Make uppercase."""
try:
return x.upper()
@@ -26,14 +31,14 @@ def input_transform(x):
return x
-def final_transform(x, original):
+def final_transform(x: Iterable[Any_t], original: str) -> FinalTransform:
"""Make the input a CustomTuple."""
t = CustomTuple(x)
t.original = original
return t
-def parse_string_func_factory(alg):
+def parse_string_func_factory(alg: NS_t) -> StrParser:
"""A parse_string_factory result with sample arguments."""
sep = ""
return parse_string_factory(
@@ -47,10 +52,12 @@ def parse_string_func_factory(alg):
@given(x=floats() | integers())
-def test_parse_string_factory_raises_type_error_if_given_number(x):
+def test_parse_string_factory_raises_type_error_if_given_number(
+ x: Union[int, float]
+) -> None:
parse_string_func = parse_string_func_factory(ns.DEFAULT)
with pytest.raises(TypeError):
- assert parse_string_func(x)
+ assert parse_string_func(x) # type: ignore
# noinspection PyCallingNonCallable
@@ -68,7 +75,9 @@ def test_parse_string_factory_raises_type_error_if_given_number(x):
)
)
@pytest.mark.usefixtures("with_locale_en_us")
-def test_parse_string_factory_invariance(x, alg, orig_func):
+def test_parse_string_factory_invariance(
+ x: List[Union[float, str, int]], alg: NS_t, orig_func: Callable[[str], str]
+) -> None:
parse_string_func = parse_string_func_factory(alg)
# parse_string_factory is the high-level combination of several dedicated
# functions involved in splitting and manipulating a string. The details of
diff --git a/tests/test_regex.py b/tests/test_regex.py
index f647f5f..67d66e0 100644
--- a/tests/test_regex.py
+++ b/tests/test_regex.py
@@ -1,8 +1,11 @@
# -*- coding: utf-8 -*-
"""These test the splitting regular expressions."""
+from typing import List, Pattern
+
import pytest
from natsort import ns, numeric_regex_chooser
+from natsort.ns_enum import NS_t
from natsort.utils import NumericalRegularExpressions as NumRegex
@@ -95,7 +98,9 @@ labels = ["{}-{}".format(given, regex_names[regex]) for given, _, regex in regex
@pytest.mark.parametrize("x, expected, regex", regex_params, ids=labels)
-def test_regex_splits_correctly(x, expected, regex):
+def test_regex_splits_correctly(
+ x: str, expected: List[str], regex: Pattern[str]
+) -> None:
# noinspection PyUnresolvedReferences
assert regex.split(x) == expected
@@ -115,5 +120,5 @@ def test_regex_splits_correctly(x, expected, regex):
(ns.FLOAT | ns.UNSIGNED | ns.NOEXP, NumRegex.float_nosign_noexp()),
],
)
-def test_regex_chooser(given, expected):
+def test_regex_chooser(given: NS_t, expected: Pattern[str]) -> None:
assert numeric_regex_chooser(given) == expected.pattern[1:-1] # remove parens
diff --git a/tests/test_string_component_transform_factory.py b/tests/test_string_component_transform_factory.py
index 8b77d38..7af2036 100644
--- a/tests/test_string_component_transform_factory.py
+++ b/tests/test_string_component_transform_factory.py
@@ -2,13 +2,14 @@
"""These test the utils.py functions."""
from functools import partial
+from typing import Any as Any_t, Callable, FrozenSet, Union
import pytest
from hypothesis import example, 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.ns_enum import NS_DUMB, ns
+from natsort.ns_enum import NS_DUMB, NS_t, ns
from natsort.utils import groupletters, string_component_transform_factory
# There are some unicode values that are known failures with the builtin locale
@@ -21,12 +22,12 @@ except ValueError:
bad_uni_chars = frozenset()
-def no_bad_uni_chars(x, _bad_chars=bad_uni_chars):
+def no_bad_uni_chars(x: str, _bad_chars: FrozenSet[str] = bad_uni_chars) -> bool:
"""Ensure text does not contain bad unicode characters"""
return not any(y in _bad_chars for y in x)
-def no_null(x):
+def no_null(x: str) -> bool:
"""Ensure text does not contain a null character."""
return "\0" not in x
@@ -65,7 +66,9 @@ def no_null(x):
| text().filter(bool).filter(no_bad_uni_chars).filter(no_null)
)
@pytest.mark.usefixtures("with_locale_en_us")
-def test_string_component_transform_factory(x, alg, example_func):
+def test_string_component_transform_factory(
+ x: Union[str, float, int], alg: NS_t, example_func: Callable[[str], Any_t]
+) -> None:
string_component_transform_func = string_component_transform_factory(alg)
try:
assert string_component_transform_func(str(x)) == example_func(str(x))
diff --git a/tests/test_unicode_numbers.py b/tests/test_unicode_numbers.py
index be0f4ee..eb71125 100644
--- a/tests/test_unicode_numbers.py
+++ b/tests/test_unicode_numbers.py
@@ -14,27 +14,27 @@ from natsort.unicode_numbers import (
digits_no_decimals,
numeric,
numeric_chars,
- numeric_hex,
numeric_no_decimals,
)
+from natsort.unicode_numeric_hex import numeric_hex
-def test_numeric_chars_contains_only_valid_unicode_numeric_characters():
+def test_numeric_chars_contains_only_valid_unicode_numeric_characters() -> None:
for a in numeric_chars:
assert unicodedata.numeric(a, None) is not None
-def test_digit_chars_contains_only_valid_unicode_digit_characters():
+def test_digit_chars_contains_only_valid_unicode_digit_characters() -> None:
for a in digit_chars:
assert unicodedata.digit(a, None) is not None
-def test_decimal_chars_contains_only_valid_unicode_decimal_characters():
+def test_decimal_chars_contains_only_valid_unicode_decimal_characters() -> None:
for a in decimal_chars:
assert unicodedata.decimal(a, None) is not None
-def test_numeric_chars_contains_all_valid_unicode_numeric_and_digit_characters():
+def test_numeric_chars_contains_all_valid_unicode_numeric_and_digit_characters() -> None:
set_numeric_chars = set(numeric_chars)
set_digit_chars = set(digit_chars)
set_decimal_chars = set(decimal_chars)
@@ -46,7 +46,7 @@ def test_numeric_chars_contains_all_valid_unicode_numeric_and_digit_characters()
assert set_numeric_chars.issuperset(numeric_no_decimals)
-def test_missing_unicode_number_in_collection():
+def test_missing_unicode_number_in_collection() -> None:
ok = True
set_numeric_hex = set(numeric_hex)
for i in range(0x110000):
@@ -71,7 +71,7 @@ repository (https://github.com/SethMMorton/natsort) with the resulting change.
)
-def test_combined_string_contains_all_characters_in_list():
+def test_combined_string_contains_all_characters_in_list() -> None:
assert numeric == "".join(numeric_chars)
assert digits == "".join(digit_chars)
assert decimals == "".join(decimal_chars)
diff --git a/tests/test_utils.py b/tests/test_utils.py
index d559803..ff866b6 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -6,15 +6,16 @@ import pathlib
import string
from itertools import chain
from operator import neg as op_neg
+from typing import List, Pattern, Union
import pytest
from hypothesis import given
from hypothesis.strategies import integers, lists, sampled_from, text
from natsort import utils
-from natsort.ns_enum import ns
+from natsort.ns_enum import NS_t, ns
-def test_do_decoding_decodes_bytes_string_to_unicode():
+def test_do_decoding_decodes_bytes_string_to_unicode() -> None:
assert type(utils.do_decoding(b"bytes", "ascii")) is str
assert utils.do_decoding(b"bytes", "ascii") == "bytes"
assert utils.do_decoding(b"bytes", "ascii") == b"bytes".decode("ascii")
@@ -33,7 +34,9 @@ def test_do_decoding_decodes_bytes_string_to_unicode():
(ns.F | ns.S | ns.N, utils.NumericalRegularExpressions.float_sign_noexp()),
],
)
-def test_regex_chooser_returns_correct_regular_expression_object(alg, expected):
+def test_regex_chooser_returns_correct_regular_expression_object(
+ alg: NS_t, expected: Pattern[str]
+) -> None:
assert utils.regex_chooser(alg).pattern == expected.pattern
@@ -68,21 +71,21 @@ def test_regex_chooser_returns_correct_regular_expression_object(alg, expected):
(ns.REAL, ns.FLOAT | ns.SIGNED),
],
)
-def test_ns_enum_values_and_aliases(alg, value_or_alias):
+def test_ns_enum_values_and_aliases(alg: NS_t, value_or_alias: NS_t) -> None:
assert alg == value_or_alias
-def test_chain_functions_is_a_no_op_if_no_functions_are_given():
+def test_chain_functions_is_a_no_op_if_no_functions_are_given() -> None:
x = 2345
assert utils.chain_functions([])(x) is x
-def test_chain_functions_does_one_function_if_one_function_is_given():
+def test_chain_functions_does_one_function_if_one_function_is_given() -> None:
x = "2345"
assert utils.chain_functions([len])(x) == 4
-def test_chain_functions_combines_functions_in_given_order():
+def test_chain_functions_combines_functions_in_given_order() -> None:
x = 2345
assert utils.chain_functions([str, len, op_neg])(x) == -len(str(x))
@@ -91,33 +94,37 @@ def test_chain_functions_combines_functions_in_given_order():
# and a test that uses the hypothesis module.
-def test_groupletters_returns_letters_with_lowercase_transform_of_letter_example():
+def test_groupletters_returns_letters_with_lowercase_transform_of_letter_example() -> None:
assert utils.groupletters("HELLO") == "hHeElLlLoO"
assert utils.groupletters("hello") == "hheelllloo"
@given(text().filter(bool))
-def test_groupletters_returns_letters_with_lowercase_transform_of_letter(x):
+def test_groupletters_returns_letters_with_lowercase_transform_of_letter(
+ x: str,
+) -> None:
assert utils.groupletters(x) == "".join(
chain.from_iterable([y.casefold(), y] for y in x)
)
-def test_sep_inserter_does_nothing_if_no_numbers_example():
+def test_sep_inserter_does_nothing_if_no_numbers_example() -> None:
assert list(utils.sep_inserter(iter(["a", "b", "c"]), "")) == ["a", "b", "c"]
assert list(utils.sep_inserter(iter(["a"]), "")) == ["a"]
-def test_sep_inserter_does_nothing_if_only_one_number_example():
+def test_sep_inserter_does_nothing_if_only_one_number_example() -> None:
assert list(utils.sep_inserter(iter(["a", 5]), "")) == ["a", 5]
-def test_sep_inserter_inserts_separator_string_between_two_numbers_example():
+def test_sep_inserter_inserts_separator_string_between_two_numbers_example() -> None:
assert list(utils.sep_inserter(iter([5, 9]), "")) == ["", 5, "", 9]
@given(lists(elements=text().filter(bool) | integers(), min_size=3))
-def test_sep_inserter_inserts_separator_between_two_numbers(x):
+def test_sep_inserter_inserts_separator_between_two_numbers(
+ x: List[Union[str, int]]
+) -> None:
# Rather than just replicating the results in a different algorithm,
# validate that the "shape" of the output is as expected.
result = list(utils.sep_inserter(iter(x), ""))
@@ -127,28 +134,29 @@ def test_sep_inserter_inserts_separator_between_two_numbers(x):
assert isinstance(result[i + 1], int)
-def test_path_splitter_splits_path_string_by_separator_example():
+def test_path_splitter_splits_path_string_by_separator_example() -> None:
given = "/this/is/a/path"
expected = (os.sep, "this", "is", "a", "path")
assert tuple(utils.path_splitter(given)) == tuple(expected)
- given = pathlib.Path(given)
- assert tuple(utils.path_splitter(given)) == tuple(expected)
+ assert tuple(utils.path_splitter(pathlib.Path(given))) == tuple(expected)
@given(lists(sampled_from(string.ascii_letters), min_size=2).filter(all))
-def test_path_splitter_splits_path_string_by_separator(x):
+def test_path_splitter_splits_path_string_by_separator(x: List[str]) -> None:
z = str(pathlib.Path(*x))
assert tuple(utils.path_splitter(z)) == tuple(pathlib.Path(z).parts)
-def test_path_splitter_splits_path_string_by_separator_and_removes_extension_example():
+def test_path_splitter_splits_path_string_by_separator_and_removes_extension_example() -> None:
given = "/this/is/a/path/file.x1.10.tar.gz"
expected = (os.sep, "this", "is", "a", "path", "file.x1.10", ".tar", ".gz")
assert tuple(utils.path_splitter(given)) == tuple(expected)
@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):
+def test_path_splitter_splits_path_string_by_separator_and_removes_extension(
+ x: List[str],
+) -> None:
z = str(pathlib.Path(*x[:-2])) + "." + x[-1]
y = tuple(pathlib.Path(z).parts)
assert tuple(utils.path_splitter(z)) == y[:-1] + (
diff --git a/tox.ini b/tox.ini
index fb2c58f..7bc66bc 100644
--- a/tox.ini
+++ b/tox.ini
@@ -56,8 +56,11 @@ skip_install = true
[testenv:mypy]
deps =
mypy
+ hypothesis
+ pytest
+ pytest-mock
commands =
- mypy --strict natsort
+ mypy --strict natsort tests
skip_install = true
# Build documentation.