diff --git a/src/imcflibs/pathtools.py b/src/imcflibs/pathtools.py index 7053b2ae..1b8ab400 100644 --- a/src/imcflibs/pathtools.py +++ b/src/imcflibs/pathtools.py @@ -10,7 +10,7 @@ def parse_path(path, prefix=""): - """Parse a path into its components. + r"""Parse a path into its components. If the path doesn't end with the pathsep, it is assumed being a file! No tests based on existing files are done, as this is supposed to also work @@ -20,6 +20,11 @@ def parse_path(path, prefix=""): *Script Parameter* `#@ File`) for either of the parameters, so it is safe to use this in ImageJ Python scripts without additional measures. + **WARNING**: when passing in **Windows paths** literally, make sure to + declare them as **raw strings** using the `r""` notation, otherwise + unexpected things might happen if the path contains sections that Python + will interpret as escape sequences (e.g. `\n`, `\t`, `\u2324`, ...). + Parameters ---------- path : str or str-like @@ -55,50 +60,61 @@ def parse_path(path, prefix=""): POSIX-style path to a file with a suffix: >>> parse_path('/tmp/foo/file.suffix') - {'dname': 'foo', - 'ext': '', - 'fname': 'file', - 'full': '/tmp/foo/file', - 'basename': 'file', - 'orig': '/tmp/foo/file', - 'parent': '/tmp/', - 'path': '/tmp/foo/'} + { + "dname": "foo", + "ext": "", + "fname": "file", + "full": "/tmp/foo/file", + "basename": "file", + "orig": "/tmp/foo/file", + "parent": "/tmp/", + "path": "/tmp/foo/", + } + POSIX-style path to a directory: >>> parse_path('/tmp/foo/') - {'dname': 'foo', - 'ext': '', - 'fname': '', - 'full': '/tmp/foo/', - 'basename': '', - 'orig': '/tmp/foo/', - 'parent': '/tmp/', - 'path': '/tmp/foo/'} + { + "dname": "foo", + "ext": "", + "fname": "", + "full": "/tmp/foo/", + "basename": "", + "orig": "/tmp/foo/", + "parent": "/tmp/", + "path": "/tmp/foo/", + } + Windows-style path to a file: - >>> parse_path('C:\\Temp\\foo\\file.ext') - {'dname': 'foo', - 'ext': '.ext', - 'fname': 'file.ext', - 'full': 'C:/Temp/foo/file.ext', - 'basename': 'file', - 'orig': 'C:\\Temp\\foo\\file.ext', - 'parent': 'C:/Temp/', - 'path': 'C:/Temp/foo/'} + >>> parse_path(r'C:\Temp\new\file.ext') + { + "dname": "new", + "ext": ".ext", + "fname": "file.ext", + "full": "C:/Temp/new/file.ext", + "basename": "file", + "orig": "C:\\Temp\\new\\file.ext", + "parent": "C:/Temp", + "path": "C:/Temp/new/", + } + Special treatment for *OME-TIFF* suffixes: >>> parse_path("/path/to/some/nice.OME.tIf") - {'basename': 'nice', - 'dname': 'some', - 'ext': '.OME.tIf', - 'fname': 'nice.OME.tIf', - 'full': '/path/to/some/nice.OME.tIf', - 'orig': '/path/to/some/nice.OME.tIf', - 'parent': '/path/to/', - 'path': '/path/to/some/'} + { + "basename": "nice", + "dname": "some", + "ext": ".OME.tIf", + "fname": "nice.OME.tIf", + "full": "/path/to/some/nice.OME.tIf", + "orig": "/path/to/some/nice.OME.tIf", + "parent": "/path/to/", + "path": "/path/to/some/", + } """ path = str(path) if prefix: diff --git a/tests/test_pathtools.py b/tests/test_pathtools.py index f8049de1..cc40e4bb 100644 --- a/tests/test_pathtools.py +++ b/tests/test_pathtools.py @@ -1,7 +1,6 @@ """Tests for `imcflibs.pathtools`.""" # -*- coding: utf-8 -*- -import pytest from imcflibs.pathtools import parse_path from imcflibs.pathtools import jython_fiji_exists from imcflibs.pathtools import image_basename @@ -12,6 +11,7 @@ def test_parse_path(): + """Tests using regular POSIX-style paths.""" path = "/tmp/foo/" path_to_dir = parse_path(path) path_to_file = parse_path(path + "file.ext") @@ -35,20 +35,53 @@ def test_parse_path(): def test_parse_path_windows(): - path = r"C:\foo\bar" + """Test using a Windows-style path.""" + path = r"C:\Foo\Bar" parsed = parse_path(path) assert parsed["orig"] == path - assert parsed["full"] == r"C:/foo/bar" - assert parsed["fname"] == "bar" - assert parsed["dname"] == "foo" + assert parsed["full"] == "C:/Foo/Bar" + assert parsed["fname"] == "Bar" + assert parsed["dname"] == "Foo" + + +def test_parse_path_windows_newline_tab(): + """Test a Windows path with newline and tab sequences as raw string.""" + path = r"C:\Temp\new\file.ext" + parsed = parse_path(path) + + assert parsed == { + "dname": "new", + "ext": ".ext", + "fname": "file.ext", + "full": "C:/Temp/new/file.ext", + "basename": "file", + "orig": "C:\\Temp\\new\\file.ext", + "parent": "C:/Temp", + "path": "C:/Temp/new/", + } + + +def test_parse_path_windows_nonraw(): + r"""Test non-raw string containing newline `\n` and tab `\t` sequences. + + As `parse_path()` cannot work on non-raw strings containing escape + sequences, the parsed result will not be the expected one. + """ + path = "C:\new_folder\test" + parsed = parse_path(path) + + assert parsed["full"] != r"C:\new_folder\test" + assert parsed["fname"] != "test" def test_jython_fiji_exists(tmpdir): + """Test the Jython/Fiji `os.path.exists()` workaround.""" assert jython_fiji_exists(str(tmpdir)) == True def test_image_basename(): + """Test basename extraction for various image file names.""" assert image_basename("/path/to/image_file_01.png") == "image_file_01" assert image_basename("more-complex-stack.ome.tif") == "more-complex-stack" assert image_basename("/tmp/FoObAr.OMe.tIf") == "FoObAr"