about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authornfnty <git@nfnty.se>2017-01-24 06:27:07 +0100
committernfnty <git@nfnty.se>2017-01-24 06:27:07 +0100
commit009973f7f4b650aa20109e67edae673faf4f25f4 (patch)
tree7dd239d0db5cb4da131b22ca9b6e0c47fe48b9de
parentc5f776edfa1fe1ddf8027a6acec7b1caee8e9867 (diff)
downloadranger-009973f7f4b650aa20109e67edae673faf4f25f4.tar.gz
container.fsobject: Fix natural sort
Fixes #749
-rw-r--r--.gitignore1
-rw-r--r--ranger/container/fsobject.py32
-rw-r--r--tests/ranger/container/test_fsobject.py27
3 files changed, 43 insertions, 17 deletions
diff --git a/.gitignore b/.gitignore
index e97a99b7..dbbb1ce0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 *~
 *.pyc
 *.pyo
+/.cache
 stuff/*
 doc/ranger.1.html
 build
diff --git a/ranger/container/fsobject.py b/ranger/container/fsobject.py
index 0447d5a6..59807dfb 100644
--- a/ranger/container/fsobject.py
+++ b/ranger/container/fsobject.py
@@ -36,17 +36,13 @@ DOCUMENT_BASENAMES = ('bugs', 'bugs', 'changelog', 'copying', 'credits',
 
 BAD_INFO = '?'
 
-
-# pylint: disable=invalid-name
-_unsafe_chars = '\n' + ''.join(map(chr, range(32))) + ''.join(map(chr, range(128, 256)))
-_safe_string_table = maketrans(_unsafe_chars, '?' * len(_unsafe_chars))
-_extract_number_re = re.compile(r'(\d+|\D)')
-_integers = set("0123456789")
-# pylint: enable=invalid-name
+_UNSAFE_CHARS = '\n' + ''.join(map(chr, range(32))) + ''.join(map(chr, range(128, 256)))
+_SAFE_STRING_TABLE = maketrans(_UNSAFE_CHARS, '?' * len(_UNSAFE_CHARS))
+_EXTRACT_NUMBER_RE = re.compile(r'(\d+|\D)')
 
 
 def safe_path(path):
-    return path.translate(_safe_string_table)
+    return path.translate(_SAFE_STRING_TABLE)
 
 
 class FileSystemObject(  # pylint: disable=too-many-instance-attributes
@@ -149,17 +145,27 @@ class FileSystemObject(  # pylint: disable=too-many-instance-attributes
 
     @lazy_property
     def basename_natural(self):
-        return [('0', int(s)) if s in _integers else (s, 0)
-                for s in _extract_number_re.split(self.relative_path)]
+        basename_list = []
+        for string in _EXTRACT_NUMBER_RE.split(self.relative_path):
+            try:
+                basename_list += [('0', int(string))]
+            except ValueError:
+                basename_list += [(string, 0)]
+        return basename_list
 
     @lazy_property
     def basename_natural_lower(self):
-        return [('0', int(s)) if s in _integers else (s, 0)
-                for s in _extract_number_re.split(self.relative_path_lower)]
+        basename_list = []
+        for string in _EXTRACT_NUMBER_RE.split(self.relative_path_lower):
+            try:
+                basename_list += [('0', int(string))]
+            except ValueError:
+                basename_list += [(string, 0)]
+        return basename_list
 
     @lazy_property
     def safe_basename(self):
-        return self.basename.translate(_safe_string_table)
+        return self.basename.translate(_SAFE_STRING_TABLE)
 
     @lazy_property
     def user(self):
diff --git a/tests/ranger/container/test_fsobject.py b/tests/ranger/container/test_fsobject.py
index 2c6a693f..d2c9a770 100644
--- a/tests/ranger/container/test_fsobject.py
+++ b/tests/ranger/container/test_fsobject.py
@@ -21,15 +21,34 @@ def create_filesystem_object(path):
 
 def test_basename_natural1():
     """Test filenames without extensions."""
-    fsos = [create_filesystem_object(path)
-            for path in ("hello", "hello1", "hello2")]
+    fsos = [
+        create_filesystem_object(path)
+        for path in (
+            "0", "1", "2", "3",
+            "10", "11", "12", "13",
+            "100", "101", "102", "103",
+            "110", "111", "112", "113",
+            "hello",
+            "hello1", "hello2",
+            "hello11", "hello12",
+            "hello100", "hello101", "hello111", "hello112",
+        )
+    ]
     assert fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural"))
     assert fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural_lower"))
 
 
 def test_basename_natural2():
     """Test filenames with extensions."""
-    fsos = [create_filesystem_object(path)
-            for path in ("hello", "hello.txt", "hello1.txt", "hello2.txt")]
+    fsos = [
+        create_filesystem_object(path)
+        for path in (
+            "hello", "hello.txt",
+            "hello0.txt", "hello1.txt", "hello2.txt", "hello3.txt"
+            "hello10.txt", "hello11.txt", "hello12.txt", "hello13.txt"
+            "hello100.txt", "hello101.txt", "hello102.txt", "hello103.txt"
+            "hello110.txt", "hello111.txt", "hello112.txt", "hello113.txt"
+        )
+    ]
     assert fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural"))
     assert fsos == sorted(fsos[::-1], key=operator.attrgetter("basename_natural_lower"))