Skip to content

Commit

Permalink
Allow compound file extensions
Browse files Browse the repository at this point in the history
os.path.splitext thinks that the extension for file.fits.gz
is .gz -- from a butler perspective it has to be .fits.gz
so change to use Path.suffixes in Location and ButlerURI.
  • Loading branch information
timj committed Jun 13, 2020
1 parent c2eb1d9 commit d10b122
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 18 deletions.
2 changes: 1 addition & 1 deletion python/lsst/daf/butler/core/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ def validateExtension(cls, location: Location) -> None:

if ext in supported:
return
raise ValueError(f"Extension '{ext}' is not supported by Formatter '{cls.__name__}'")
raise ValueError(f"Extension '{ext}' on '{location}' is not supported by Formatter '{cls.__name__}'")

def predictPath(self) -> str:
"""Return the path that would be returned by write, without actually
Expand Down
36 changes: 22 additions & 14 deletions python/lsst/daf/butler/core/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,19 +292,21 @@ def updateFile(self, newfile: str) -> None:
self._uri = self._uri._replace(path=newpath)

def getExtension(self) -> str:
"""Return the file extension associated with this URI path.
"""Return the file extension(s) associated with this URI path.
Returns
-------
ext : `str`
The file extension (including the ``.``). Can be empty string
if there is no file extension.
if there is no file extension. Will return all file extensions
as a single extension such that ``file.fits.gz`` will return
a value of ``.fits.gz``.
"""
if not self.scheme:
_, ext = os.path.splitext(self.path)
extensions = PurePath(self.path).suffixes
else:
_, ext = posixpath.splitext(self.path)
return ext
extensions = PurePosixPath(self.path).suffixes
return "".join(extensions)

def __str__(self) -> str:
return self.geturl()
Expand Down Expand Up @@ -547,6 +549,8 @@ def relativeToPathRoot(self) -> str:
def updateExtension(self, ext: Optional[str]) -> None:
"""Update the file extension associated with this `Location`.
All file extensions are replaced.
Parameters
----------
ext : `str`
Expand All @@ -556,10 +560,12 @@ def updateExtension(self, ext: Optional[str]) -> None:
if ext is None:
return

if not self._datastoreRootUri.scheme:
path, _ = os.path.splitext(self.pathInStore)
else:
path, _ = posixpath.splitext(self.pathInStore)
# Get the extension and remove it from the path if one is found
# .fits.gz counts as one extension do not use os.path.splitext
current = self.getExtension()
path = self.pathInStore
if current:
path = path[:-len(current)]

# Ensure that we have a leading "." on file extension (and we do not
# try to modify the empty string)
Expand All @@ -569,19 +575,21 @@ def updateExtension(self, ext: Optional[str]) -> None:
self._path = path + ext

def getExtension(self) -> str:
"""Return the file extension associated with this location.
"""Return the file extension(s) associated with this location.
Returns
-------
ext : `str`
The file extension (including the ``.``). Can be empty string
if there is no file extension.
if there is no file extension. Will return all file extensions
as a single extension such that ``file.fits.gz`` will return
a value of ``.fits.gz``.
"""
if not self._datastoreRootUri.scheme:
_, ext = os.path.splitext(self.pathInStore)
extensions = PurePath(self.path).suffixes
else:
_, ext = posixpath.splitext(self.pathInStore)
return ext
extensions = PurePath(self.path).suffixes
return "".join(extensions)


class LocationFactory:
Expand Down
10 changes: 7 additions & 3 deletions tests/test_location.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,15 @@ def testFileLocation(self):
self.assertTrue(loc1.uri.startswith("file:///"))
self.assertTrue(loc1.uri.endswith("file.ext"))
loc1.updateExtension("fits")
self.assertTrue(loc1.uri.endswith("file.fits"))
self.assertTrue(loc1.uri.endswith("file.fits"), f"Checking 'fits' extension in {loc1.uri}")
loc1.updateExtension("fits.gz")
self.assertTrue(loc1.uri.endswith("file.fits.gz"), f"Checking 'fits.gz' extension in {loc1.uri}")
loc1.updateExtension(".jpeg")
self.assertTrue(loc1.uri.endswith("file.jpeg"), f"Checking 'jpeg' extension in {loc1.uri}")
loc1.updateExtension(None)
self.assertTrue(loc1.uri.endswith("file.fits"))
self.assertTrue(loc1.uri.endswith("file.jpeg"), f"Checking unchanged extension in {loc1.uri}")
loc1.updateExtension("")
self.assertTrue(loc1.uri.endswith("file"))
self.assertTrue(loc1.uri.endswith("file"), f"Checking no extension in {loc1.uri}")

def testRelativeRoot(self):
root = os.path.abspath(os.path.curdir)
Expand Down

0 comments on commit d10b122

Please sign in to comment.