diff --git a/CHANGELOG.md b/CHANGELOG.md index d442f284..4503eb64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - Typing information -- Added ext attribute to info +- Added Info.suffix, Info.suffixes, Info.stem attributes ### Fixed - Fixed issue with implied directories in TarFS +### Changed + +- Changed path.splitext so that 'leading periods on the basename are + ignored', which is the behaviour of os.path.splitext + ## [2.0.20] - 2018-03-13 ### Fixed diff --git a/fs/info.py b/fs/info.py index 1d90abcf..ab076fd0 100644 --- a/fs/info.py +++ b/fs/info.py @@ -183,17 +183,47 @@ def name(self): return self.get('basic', 'name') @property - def ext(self): + def suffix(self): # type: () -> Text - """`str`: the resource extension (including dot). + """`str`: the final resource extension (including dot), or an + empty string if there is no extension. Example: - >>> info.ext + >>> info + + >>> info.suffix '.py' """ name = self.get('basic', 'name') + if name.startswith('.') and name.count('.') == 1: + return '' basename, dot, ext = name.rpartition('.') - return dot + ext if dot else '' + return '.' + ext if dot else '' + + @property + def suffixes(self): + # type: () -> List[Text] + """`List`: a list of the resource's extensions. + + Example: + >>> info + + >>> info.suffixes + ['.tar', '.py'] + """ + name = self.get('basic', 'name') + if name.startswith('.') and name.count('.') == 1: + return [] + return ['.' + suffix for suffix in name.split('.')[1:]] + + @property + def stem(self): + # type: () -> Text + """`str`: the name minus any extensions.""" + name = self.get('basic', 'name') + if name.startswith('.'): + return name + return name.split('.')[0] @property def is_dir(self): diff --git a/fs/path.py b/fs/path.py index ad6ff6e4..026a307c 100644 --- a/fs/path.py +++ b/fs/path.py @@ -336,9 +336,13 @@ def splitext(path): ('baz', '.txt') >>> splitext('foo/bar/baz.txt') ('foo/bar/baz', '.txt') + >>> splitext('foo/bar/.foo') + ('foo/bar/.foo', '') """ parent_path, pathname = split(path) + if pathname.startswith('.') and pathname.count('.') == 1: + return path, '' if '.' not in pathname: return path, '' pathname, ext = pathname.rsplit('.', 1) diff --git a/tests/test_info.py b/tests/test_info.py index 8bb1fc96..0de4804e 100644 --- a/tests/test_info.py +++ b/tests/test_info.py @@ -75,7 +75,7 @@ def test_basic(self): self.assertIsInstance(info.is_dir, bool) self.assertFalse(info.is_dir) self.assertEqual(repr(info), "") - self.assertEqual(info.ext, '.py') + self.assertEqual(info.suffix, '.py') # Check dir info = Info({ @@ -86,7 +86,7 @@ def test_basic(self): }) self.assertTrue(info.is_dir) self.assertEqual(repr(info), "") - self.assertEqual(info.ext, '') + self.assertEqual(info.suffix, '') def test_details(self): dates = [ @@ -137,3 +137,24 @@ def test_get(self): info = Info({'baz': {}}) self.assertIsNone(info.get('foo', 'bar')) self.assertIsNone(info.get('baz', 'bar')) + + def test_suffix(self): + info = Info({ + 'basic': {'name': 'foo.tar.gz'} + }) + self.assertEqual(info.suffix, '.gz') + self.assertEqual(info.suffixes, ['.tar', '.gz']) + self.assertEqual(info.stem, 'foo') + info = Info({ + 'basic': {'name': 'foo'} + }) + self.assertEqual(info.suffix, '') + self.assertEqual(info.suffixes, []) + self.assertEqual(info.stem, 'foo') + + info = Info({ + 'basic': {'name': '.foo'} + }) + self.assertEqual(info.suffix, '') + self.assertEqual(info.suffixes, []) + self.assertEqual(info.stem, '.foo') \ No newline at end of file diff --git a/tests/test_path.py b/tests/test_path.py index 6b67d2a8..dbf613f7 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -135,6 +135,7 @@ def test_splitext(self): self.assertEqual(splitext('foo.bar'), ('foo', '.bar')) self.assertEqual(splitext('foo.bar.baz'), ('foo.bar', '.baz')) self.assertEqual(splitext('foo'), ('foo', '')) + self.assertEqual(splitext('.foo'), ('.foo', '')) def test_recursepath(self): self.assertEquals(recursepath("/"), ["/"]) @@ -147,7 +148,7 @@ def test_recursepath(self): def test_isbase(self): self.assertTrue(isbase('foo', 'foo/bar')) - self.assertFalse(isbase('baz', 'foo/bar')) + self.assertFalse(isbase('baz', 'foo/bar')) def test_isparent(self): self.assertTrue(isparent("foo/bar", "foo/bar/spam.txt"))