summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeth Morton <seth.m.morton@gmail.com>2021-10-24 10:31:29 -0700
committerSeth Morton <seth.m.morton@gmail.com>2021-10-24 11:06:23 -0700
commitf87d6b5b74e331699a89f4675e4b95ba26587186 (patch)
tree9781beb909fb81573192ce4803556727f2f5f837
parent7a44a5e31ae0e7d036270fe67c66cfe63d6c239b (diff)
downloadnatsort-f87d6b5b74e331699a89f4675e4b95ba26587186.tar.gz
The ns enum actually now is a python enum
I have been wanting to do this for quite some time, but needed the functionality of the IntEnum for backwards-compatibility. Now that Python 3.5 is no longer supported, the IntEnum can be used and the definition of ns is far simpler than it used to be. This plays nice with mypy also, which is the driving change.
-rw-r--r--CHANGELOG.md5
-rw-r--r--natsort/__init__.py2
-rw-r--r--natsort/ns_enum.py103
-rw-r--r--tests/test_ns_enum.py11
4 files changed, 46 insertions, 75 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5683cb5..1e1d147 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,11 @@
Unreleased
---
+### Changed
+
+ - The `ns` enum is now implemented as an `enum.IntEnum` instead of a
+ `collections.namedtuple`
+
### Removed
- Support for Python 3.4 and Python 3.5
diff --git a/natsort/__init__.py b/natsort/__init__.py
index 8c8f87f..a83c9a7 100644
--- a/natsort/__init__.py
+++ b/natsort/__init__.py
@@ -45,4 +45,4 @@ __all__ = [
]
# Add the ns keys to this namespace for convenience.
-globals().update(ns._asdict())
+globals().update({name: value for name, value in ns.__members__.items()})
diff --git a/natsort/ns_enum.py b/natsort/ns_enum.py
index 283a793..f285a18 100644
--- a/natsort/ns_enum.py
+++ b/natsort/ns_enum.py
@@ -4,73 +4,14 @@ This module defines the "ns" enum for natsort is used to determine
what algorithm natsort uses.
"""
-import collections
-
-# 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.
-enum_options = [
- "FLOAT",
- "SIGNED",
- "NOEXP",
- "PATH",
- "LOCALEALPHA",
- "LOCALENUM",
- "IGNORECASE",
- "LOWERCASEFIRST",
- "GROUPLETTERS",
- "UNGROUPLETTERS",
- "NANLAST",
- "COMPATIBILITYNORMALIZE",
- "NUMAFTER",
-]
-
-# Following were previously options but are now defaults.
-enum_do_nothing = ["DEFAULT", "INT", "UNSIGNED"]
-
-# The following are bitwise-OR combinations of other fields.
-enum_combos = [("REAL", ("FLOAT", "SIGNED")), ("LOCALE", ("LOCALEALPHA", "LOCALENUM"))]
-
-# The following are aliases for other fields.
-enum_aliases = [
- ("I", "INT"),
- ("U", "UNSIGNED"),
- ("F", "FLOAT"),
- ("S", "SIGNED"),
- ("R", "REAL"),
- ("N", "NOEXP"),
- ("P", "PATH"),
- ("LA", "LOCALEALPHA"),
- ("LN", "LOCALENUM"),
- ("L", "LOCALE"),
- ("IC", "IGNORECASE"),
- ("LF", "LOWERCASEFIRST"),
- ("G", "GROUPLETTERS"),
- ("UG", "UNGROUPLETTERS"),
- ("C", "UNGROUPLETTERS"),
- ("CAPITALFIRST", "UNGROUPLETTERS"),
- ("NL", "NANLAST"),
- ("CN", "COMPATIBILITYNORMALIZE"),
- ("NA", "NUMAFTER"),
-]
-
-# Construct the list of bitwise distinct enums with their fields.
-enum_fields = collections.OrderedDict(
- (name, 1 << i) for i, name in enumerate(enum_options)
-)
-enum_fields.update((name, 0) for name in enum_do_nothing)
-
-for name, combo in enum_combos:
- combined_value = enum_fields[combo[0]]
- for combo_name in combo[1:]:
- combined_value |= enum_fields[combo_name]
- enum_fields[name] = combined_value
-
-enum_fields.update((alias, enum_fields[name]) for alias, name in enum_aliases)
-
-
-# Subclass the namedtuple to improve the docstring.
-# noinspection PyUnresolvedReferences
-class _NSEnum(collections.namedtuple("_NSEnum", enum_fields.keys())):
+import enum
+import itertools
+
+
+_counter = itertools.count(0)
+
+
+class ns(enum.IntEnum): # noqa: N801
"""
Enum to control the `natsort` algorithm.
@@ -185,11 +126,31 @@ class _NSEnum(collections.namedtuple("_NSEnum", enum_fields.keys())):
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
-# Here is where the instance of the ns enum that will be exported is created.
-# It is a poor-man's singleton.
-ns = _NSEnum(*enum_fields.values())
-
# The below is private for internal use only.
NS_DUMB = 1 << 31
diff --git a/tests/test_ns_enum.py b/tests/test_ns_enum.py
index 1d3803b..431a2f9 100644
--- a/tests/test_ns_enum.py
+++ b/tests/test_ns_enum.py
@@ -1,8 +1,11 @@
+import pytest
+
from natsort import ns
-def test_ns_enum():
- enum_name_values = [
+@pytest.mark.parametrize(
+ "given, expected",
+ [
("FLOAT", 0x0001),
("SIGNED", 0x0002),
("NOEXP", 0x0004),
@@ -41,4 +44,6 @@ def test_ns_enum():
("CN", 0x0800),
("NA", 0x1000),
]
- assert list(ns._asdict().items()) == enum_name_values
+)
+def test_ns_enum(given, expected):
+ assert ns[given] == expected