def as_ascii(s: NatsortInType) -> NatsortInType:
    """
    Function to decode an input with the ASCII codec, or return as-is.

    Parameters
    ----------
    s : object

    Returns
    -------
    output
        If the input was of type `bytes`, the return value is a `str` decoded
        with the ASCII codec. Otherwise, the return value is identically the
        input.

    See Also
    --------
    decoder

    """
    return utils.do_decoding(s, "ascii") def as_utf8(s: NatsortInType) -> NatsortInType:
    """
    Function to decode an input with the UTF-8 codec, or return as-is.

    Parameters
    ----------
    s : object

    Returns
    -------
    output
        If the input was of type `bytes`, the return value is a `str` decoded
        with the UTF-8 codec. Otherwise, the return value is identically the
        input.

    See Also
    --------
    decoder

    """
    return utils.do_decoding(s, "utf-8") def decoder(encoding: str) -> Callable[[NatsortInType], NatsortInType]:
    """
    Return a function that can be used to decode bytes to unicode.

    Parameters
    ----------
    encoding : str
        The codec to use for decoding. This must be a valid unicode codec.

    Returns
    -------
    decode_function
        A function that takes a single argument and attempts to decode
        it using the supplied codec. Any `UnicodeErrors` are raised.
        If the argument was not of `bytes` type, it is simply returned
        as-is.

    See Also
    --------
    as_ascii
    as_utf8

    Examples
    --------

        >>> f = decoder('utf8')
        >>> f(b'bytes') == 'bytes'
        True
        >>> f(12345) == 12345
        True
        >>> # On Python 3, without decoder this would return [b'a10', b'a2']
        >>> natsorted([b'a10', b'a2'], key=decoder('utf8')) == [b'a2', b'a10']
        True
        >>> # On Python 3, without decoder this would raise a TypeError.
        >>> natsorted([b'a10', 'a2'], key=decoder('utf8')) == ['a2', b'a10']
        True

    """
    return partial(utils.do_decoding, encoding=encoding) @overload
def humansorted(
    seq: Iter_ns, key: None = None, reverse: bool = False, alg: NSType = ns.DEFAULT
) -> List_ns:
    ... @overload
def index_humansorted(
    seq: Iter_ns, key: None = None, reverse: bool = False, alg: NSType = ns.DEFAULT
) -> List_int:
    ... @overload
def index_natsorted(
    seq: Iter_ns, key: None = None, reverse: bool = False, alg: NSType = ns.DEFAULT
) -> List_int:
    ... @overload
def index_realsorted(
    seq: Iter_ns, key: None = None, reverse: bool = False, alg: NSType = ns.DEFAULT
) -> List_int:
    ... @overload
def natsorted(
    seq: Iter_ns, key: None = None, reverse: bool = False, alg: NSType = ns.DEFAULT
) -> List_ns:
    ... def order_by_index(
    seq: Sequence[Any], index: Iterable[int], iter: bool = False
) -> Iter_any:
    """
    Order a given sequence by an index sequence.

    The output of `index_natsorted` is a
    sequence of integers (index) that correspond to how its input
    sequence **would** be sorted. The idea is that this index can
    be used to reorder multiple sequences by the sorted order of the
    first sequence. This function is a convenient wrapper to
    apply this ordering to a sequence.

    Parameters
    ----------
    seq : sequence
        The sequence to order.

    index : iterable
        The iterable that indicates how to order `seq`.
        It should be the same length as `seq` and consist
        of integers only.

    iter : {{True, False}}, optional
        If `True`, the ordered sequence is returned as a
        iterator; otherwise it is returned as a
        list. The default is `False`.

    Returns
    -------
    out : {{list, iterator}}
        The sequence ordered by `index`, as a `list` or as an
        iterator (depending on the value of `iter`).

    See Also
    --------
    index_natsorted
    index_humansorted
    index_realsorted

    Examples
    --------

    `order_by_index` is a convenience function that helps you apply
    the result of `index_natsorted`::

        >>> a = ['num3', 'num5', 'num2']
        >>> b = ['foo', 'bar', 'baz']
        >>> index = index_natsorted(a)
        >>> index
        [2, 0, 1]
        >>> # Sort both lists by the sort order of a
        >>> order_by_index(a, index)
        ['num2', 'num3', 'num5']
        >>> order_by_index(b, index)
        ['baz', 'foo', 'bar']

    """
    return (seq[i] for i in index) if iter else [seq[i] for i in index] @overload
def realsorted(
    seq: Iter_ns, key: None = None, reverse: bool = False, alg: NSType = ns.DEFAULT
) -> List_ns:
    ... class ns(enum.IntEnum):  # noqa: N801
    """
    Enum to control the `natsort` algorithm.

    This class acts like an enum to control the `natsort` algorithm. The
    user may select several options simultaneously by or'ing the options
    together.  For example, to choose ``ns.INT``, ``ns.PATH``, and
    ``ns.LOCALE``, you could do ``ns.INT | ns.LOCALE | ns.PATH``. Each
    function in the :mod:`natsort` package has an `alg` option that accepts
    this enum to allow fine control over how your input is sorted.

    Each option has a shortened 1- or 2-letter form.

    .. note:: Please read :ref:`locale_issues` before using ``ns.LOCALE``.

    Attributes
    ----------
    INT, I (default)
        The default - parse numbers as integers.
    FLOAT, F
        Tell `natsort` to parse numbers as floats.
    UNSIGNED, U (default)
        Tell `natsort` to ignore any sign (i.e. "-" or "+") to the immediate
        left of a number.  This is the default.
    SIGNED, S
        Tell `natsort` to take into account any sign (i.e. "-" or "+")
        to the immediate left of a number.
    REAL, R
        This is a shortcut for ``ns.FLOAT | ns.SIGNED``, which is useful
        when attempting to sort real numbers.
    NOEXP, N
        Tell `natsort` to not search for exponents as part of a float number.
        For example, with `NOEXP` the number "5.6E5" would be interpreted
        as `5.6`, `"E"`, and `5` instead of `560000`.
    NUMAFTER, NA
        Tell `natsort` to sort numbers after non-numbers. By default
        numbers will be ordered before non-numbers.
    PATH, P
        Tell `natsort` to interpret strings as filesystem paths, so they
        will be split according to the filesystem separator
        (i.e. '/' on UNIX, '\\' on Windows), as well as splitting on the
        file extension, if any. Without this, lists of file paths like
        ``['Folder/', 'Folder (1)/', 'Folder (10)/']`` will not be
        sorted properly; 'Folder/' will be placed at the end, not at the
        front. It is the same as setting the old `as_path` option to
        `True`.
    COMPATIBILITYNORMALIZE, CN
        Use the "NFKD" unicode normalization form on input rather than the
        default "NFD". This will transform characters such as '⑦' into
        '7'. Please see https://stackoverflow.com/a/7934397/1399279,
        https://stackoverflow.com/a/7931547/1399279,
        and https://unicode.org/reports/tr15/ for full details into unicode
        normalization.
    LOCALE, L
        Tell `natsort` to be locale-aware when sorting. This includes both
        proper sorting of alphabetical characters as well as proper
        handling of locale-dependent decimal separators and thousands
        separators. This is a shortcut for
        ``ns.LOCALEALPHA | ns.LOCALENUM``.
        Your sorting results will vary depending on your current locale.
    LOCALEALPHA, LA
        Tell `natsort` to be locale-aware when sorting, but only for
        alphabetical characters.
    LOCALENUM, LN
        Tell `natsort` to be locale-aware when sorting, but only for
        decimal separators and thousands separators.
    IGNORECASE, IC
        Tell `natsort` to ignore case when sorting.  For example,
        ``['Banana', 'apple', 'banana', 'Apple']`` would be sorted as
        ``['apple', 'Apple', 'Banana', 'banana']``.
    LOWERCASEFIRST, LF
        Tell `natsort` to put lowercase letters before uppercase letters
        when sorting.  For example,
        ``['Banana', 'apple', 'banana', 'Apple']`` would be sorted as
        ``['apple', 'banana', 'Apple', 'Banana']`` (the default order
        would be ``['Apple', 'Banana', 'apple', 'banana']`` which is
        the order from a purely ordinal sort).
        Useless when used with `IGNORECASE`. Please note that if used
        with ``LOCALE``, this actually has the reverse effect and will
        put uppercase first (this is because ``LOCALE`` already puts
        lowercase first); you may use this to your advantage if you
        need to modify the order returned with ``LOCALE``.
    GROUPLETTERS, G
        Tell `natsort` to group lowercase and uppercase letters together
        when sorting.  For example,
        ``['Banana', 'apple', 'banana', 'Apple']`` would be sorted as
        ``['Apple', 'apple', 'Banana', 'banana']``.
        Useless when used with `IGNORECASE`; use with `LOWERCASEFIRST`
        to reverse the order of upper and lower case. Generally not
        needed with `LOCALE`.
    CAPITALFIRST, C
        Only used when `LOCALE` is enabled. Tell `natsort` to put all
        capitalized words before non-capitalized words. This is essentially
        the inverse of `GROUPLETTERS`, and is the default Python sorting
        behavior without `LOCALE`.
    UNGROUPLETTERS, UG
        An alias for `CAPITALFIRST`.
    NANLAST, NL
        If an NaN shows up in the input, this instructs `natsort` to
        treat these as +Infinity and place them after all the other numbers.
        By default, an NaN be treated as -Infinity and be placed first.
        Note that this ``None`` is treated like NaN internally.

    Notes
    -----
    If you prefer to use `import natsort as ns` as opposed to
    `from natsort import natsorted, ns`, the `ns` options are
    available as top-level imports.

        >>> import natsort as ns
        >>> a = ['num5.10', 'num-3', 'num5.3', 'num2']
        >>> ns.natsorted(a, alg=ns.REAL) == ns.natsorted(a, alg=ns.ns.REAL)
        True

    """

    # The below are the base ns options. The values will be stored as powers
    # of two so bitmasks can be used to extract the user's requested options.
    FLOAT = F = 1 << next(_counter)
    SIGNED = S = 1 << next(_counter)
    NOEXP = N = 1 << next(_counter)
    PATH = P = 1 << next(_counter)
    LOCALEALPHA = LA = 1 << next(_counter)
    LOCALENUM = LN = 1 << next(_counter)
    IGNORECASE = IC = 1 << next(_counter)
    LOWERCASEFIRST = LF = 1 << next(_counter)
    GROUPLETTERS = G = 1 << next(_counter)
    UNGROUPLETTERS = CAPITALFIRST = C = UG = 1 << next(_counter)
    NANLAST = NL = 1 << next(_counter)
    COMPATIBILITYNORMALIZE = CN = 1 << next(_counter)
    NUMAFTER = NA = 1 << next(_counter)

    # Following were previously options but are now defaults.
    DEFAULT = 0
    INT = I = 0  # noqa: E741
    UNSIGNED = U = 0

    # The following are bitwise-OR combinations of other fields.
    REAL = R = FLOAT | SIGNED
    LOCALE = L = LOCALEALPHA | LOCALENUM
from operator import itemgetter
from typing import List
from natsort import (
    as_ascii,
    as_utf8,
    decoder,
    humansorted,
    index_humansorted,
    index_natsorted,
    index_realsorted,
    natsorted,
    ns,
    order_by_index,
    realsorted,
)
import pytest
# -*- coding: utf-8 -*-
"""\
Here are a collection of examples of how this module can be used.
See the README or the natsort homepage for more details.
"""




@pytest.fixture
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() -> List[str]:
    return ["a50", "a51.", "a50.31", "a-50", "a50.4", "a5.034e1", "a50.300"]


@pytest.fixture
def fruit_list() -> List[str]:
    return ["Apple", "corn", "Corn", "Banana", "apple", "banana"]


def test_decoder_returns_function_that_decodes_bytes_but_returns_other_as_is() -> None:
    func = decoder("latin1")
    str_obj = "bytes"
    int_obj = 14
    assert func(b"bytes") == str_obj
    assert func(int_obj) is int_obj  # returns as-is, same object ID
    assert func(str_obj) is str_obj  # same object returned b/c only bytes has decode


def test_as_ascii_converts_bytes_to_ascii() -> None:

    assert decoder("ascii")(b"bytes") == as_ascii(b"bytes")