LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
Classes | Functions
lsst.daf.persistence.posixStorage Namespace Reference

Classes

class  PosixStorage
 

Functions

def readConfigStorage (butlerLocation)
 
def writeConfigStorage (butlerLocation, obj)
 
def readFitsStorage (butlerLocation)
 
def writeFitsStorage (butlerLocation, obj)
 
def readParquetStorage (butlerLocation)
 
def writeParquetStorage (butlerLocation, obj)
 
def writeYamlStorage (butlerLocation, obj)
 
def readPickleStorage (butlerLocation)
 
def writePickleStorage (butlerLocation, obj)
 
def readFitsCatalogStorage (butlerLocation)
 
def writeFitsCatalogStorage (butlerLocation, obj)
 
def readMatplotlibStorage (butlerLocation)
 
def writeMatplotlibStorage (butlerLocation, obj)
 
def readYamlStorage (butlerLocation)
 

Function Documentation

◆ readConfigStorage()

def lsst.daf.persistence.posixStorage.readConfigStorage (   butlerLocation)
Read an lsst.pex.config.Config from a butlerLocation.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object(s) to be read.

Returns
-------
A list of objects as described by the butler location. One item for
each location in butlerLocation.getLocations()

Definition at line 512 of file posixStorage.py.

512 def readConfigStorage(butlerLocation):
513  """Read an lsst.pex.config.Config from a butlerLocation.
514 
515  Parameters
516  ----------
517  butlerLocation : ButlerLocation
518  The location for the object(s) to be read.
519 
520  Returns
521  -------
522  A list of objects as described by the butler location. One item for
523  each location in butlerLocation.getLocations()
524  """
525  results = []
526  for locationString in butlerLocation.getLocations():
527  locStringWithRoot = os.path.join(butlerLocation.getStorage().root, locationString)
528  logLoc = LogicalLocation(locStringWithRoot, butlerLocation.getAdditionalData())
529  if not os.path.exists(logLoc.locString()):
530  raise RuntimeError("No such config file: " + logLoc.locString())
531 
532  # Automatically determine the Config class from the serialized form
533  with open(logLoc.locString(), "r") as fd:
534  config_py = fd.read()
535  config = pexConfig.Config._fromPython(config_py)
536 
537  pythonType = butlerLocation.getPythonType()
538  if pythonType is not None:
539  if isinstance(pythonType, str):
540  pythonType = doImport(pythonType)
541  if not isinstance(config, pythonType):
542  raise TypeError(f"Unexpected type of config: {type(config)}, expected {pythonType}")
543 
544  results.append(config)
545  return results
546 
547 
def readConfigStorage(butlerLocation)

◆ readFitsCatalogStorage()

def lsst.daf.persistence.posixStorage.readFitsCatalogStorage (   butlerLocation)
Read a catalog from a FITS table specified by ButlerLocation.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object(s) to be read.

Returns
-------
A list of objects as described by the butler location. One item for
each location in butlerLocation.getLocations()

Definition at line 776 of file posixStorage.py.

776 def readFitsCatalogStorage(butlerLocation):
777  """Read a catalog from a FITS table specified by ButlerLocation.
778 
779  Parameters
780  ----------
781  butlerLocation : ButlerLocation
782  The location for the object(s) to be read.
783 
784  Returns
785  -------
786  A list of objects as described by the butler location. One item for
787  each location in butlerLocation.getLocations()
788  """
789  pythonType = butlerLocation.getPythonType()
790  if pythonType is not None:
791  if isinstance(pythonType, str):
792  pythonType = doImport(pythonType)
793  results = []
794  additionalData = butlerLocation.getAdditionalData()
795  for locationString in butlerLocation.getLocations():
796  locStringWithRoot = os.path.join(butlerLocation.getStorage().root, locationString)
797  logLoc = LogicalLocation(locStringWithRoot, additionalData)
798  if not os.path.exists(logLoc.locString()):
799  raise RuntimeError("No such FITS catalog file: " + logLoc.locString())
800  kwds = {}
801  if additionalData.exists("hdu"):
802  kwds["hdu"] = additionalData.getInt("hdu")
803  if additionalData.exists("flags"):
804  kwds["flags"] = additionalData.getInt("flags")
805  finalItem = pythonType.readFits(logLoc.locString(), **kwds)
806  results.append(finalItem)
807  return results
808 
809 
def readFitsCatalogStorage(butlerLocation)

◆ readFitsStorage()

def lsst.daf.persistence.posixStorage.readFitsStorage (   butlerLocation)
Read objects from a FITS file specified by ButlerLocation.

The object is read using class or static method
``readFitsWithOptions(path, options)``, if it exists, else
``readFits(path)``. The ``options`` argument is the data returned by
``butlerLocation.getAdditionalData()``.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object(s) to be read.

Returns
-------
A list of objects as described by the butler location. One item for
each location in butlerLocation.getLocations()

Definition at line 565 of file posixStorage.py.

565 def readFitsStorage(butlerLocation):
566  """Read objects from a FITS file specified by ButlerLocation.
567 
568  The object is read using class or static method
569  ``readFitsWithOptions(path, options)``, if it exists, else
570  ``readFits(path)``. The ``options`` argument is the data returned by
571  ``butlerLocation.getAdditionalData()``.
572 
573  Parameters
574  ----------
575  butlerLocation : ButlerLocation
576  The location for the object(s) to be read.
577 
578  Returns
579  -------
580  A list of objects as described by the butler location. One item for
581  each location in butlerLocation.getLocations()
582  """
583  pythonType = butlerLocation.getPythonType()
584  if pythonType is not None:
585  if isinstance(pythonType, str):
586  pythonType = doImport(pythonType)
587  supportsOptions = hasattr(pythonType, "readFitsWithOptions")
588  if not supportsOptions:
589  from lsst.daf.base import PropertySet, PropertyList
590  if issubclass(pythonType, (PropertySet, PropertyList)):
591  from lsst.afw.fits import readMetadata
592  reader = readMetadata
593  else:
594  reader = pythonType.readFits
595  results = []
596  additionalData = butlerLocation.getAdditionalData()
597  for locationString in butlerLocation.getLocations():
598  locStringWithRoot = os.path.join(butlerLocation.getStorage().root, locationString)
599  logLoc = LogicalLocation(locStringWithRoot, additionalData)
600  # test for existence of file, ignoring trailing [...]
601  # because that can specify the HDU or other information
602  filePath = re.sub(r"(\.fits(.[a-zA-Z0-9]+)?)(\[.+\])$", r"\1", logLoc.locString())
603  if not os.path.exists(filePath):
604  raise RuntimeError("No such FITS file: " + logLoc.locString())
605  if supportsOptions:
606  finalItem = pythonType.readFitsWithOptions(logLoc.locString(), options=additionalData)
607  else:
608  fileName = logLoc.locString()
609  mat = re.search(r"^(.*)\[(\d+)\]$", fileName)
610 
611  if mat and reader == readMetadata: # readMetadata() only understands the hdu argument, not [hdu]
612  fileName = mat.group(1)
613  hdu = int(mat.group(2))
614 
615  finalItem = reader(fileName, hdu=hdu)
616  else:
617  finalItem = reader(fileName)
618  results.append(finalItem)
619  return results
620 
621 
def readFitsStorage(butlerLocation)

◆ readMatplotlibStorage()

def lsst.daf.persistence.posixStorage.readMatplotlibStorage (   butlerLocation)
Read from a butlerLocation (always fails for this storage type).

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object(s) to be read.

Returns
-------
A list of objects as described by the butler location. One item for
each location in butlerLocation.getLocations()

Definition at line 831 of file posixStorage.py.

831 def readMatplotlibStorage(butlerLocation):
832  """Read from a butlerLocation (always fails for this storage type).
833 
834  Parameters
835  ----------
836  butlerLocation : ButlerLocation
837  The location for the object(s) to be read.
838 
839  Returns
840  -------
841  A list of objects as described by the butler location. One item for
842  each location in butlerLocation.getLocations()
843  """
844  raise NotImplementedError("Figures saved with MatplotlibStorage cannot be retreived using the Butler.")
845 
846 
def readMatplotlibStorage(butlerLocation)

◆ readParquetStorage()

def lsst.daf.persistence.posixStorage.readParquetStorage (   butlerLocation)
Read a catalog from a Parquet file specified by ButlerLocation.

The object returned by this is expected to be a subtype
of `ParquetTable`, which is a thin wrapper to `pyarrow.ParquetFile`
that allows for lazy loading of the data.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object(s) to be read.

Returns
-------
A list of objects as described by the butler location. One item for
each location in butlerLocation.getLocations()

Definition at line 648 of file posixStorage.py.

648 def readParquetStorage(butlerLocation):
649  """Read a catalog from a Parquet file specified by ButlerLocation.
650 
651  The object returned by this is expected to be a subtype
652  of `ParquetTable`, which is a thin wrapper to `pyarrow.ParquetFile`
653  that allows for lazy loading of the data.
654 
655  Parameters
656  ----------
657  butlerLocation : ButlerLocation
658  The location for the object(s) to be read.
659 
660  Returns
661  -------
662  A list of objects as described by the butler location. One item for
663  each location in butlerLocation.getLocations()
664  """
665  results = []
666  additionalData = butlerLocation.getAdditionalData()
667 
668  for locationString in butlerLocation.getLocations():
669  locStringWithRoot = os.path.join(butlerLocation.getStorage().root, locationString)
670  logLoc = LogicalLocation(locStringWithRoot, additionalData)
671  if not os.path.exists(logLoc.locString()):
672  raise RuntimeError("No such parquet file: " + logLoc.locString())
673 
674  pythonType = butlerLocation.getPythonType()
675  if pythonType is not None:
676  if isinstance(pythonType, str):
677  pythonType = doImport(pythonType)
678 
679  filename = logLoc.locString()
680 
681  # pythonType will be ParquetTable (or perhaps MultilevelParquetTable)
682  # filename should be the first kwarg, but being explicit here.
683  results.append(pythonType(filename=filename))
684 
685  return results
686 
687 
def readParquetStorage(butlerLocation)

◆ readPickleStorage()

def lsst.daf.persistence.posixStorage.readPickleStorage (   butlerLocation)
Read an object from a pickle file specified by ButlerLocation.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object(s) to be read.

Returns
-------
A list of objects as described by the butler location. One item for
each location in butlerLocation.getLocations()

Definition at line 725 of file posixStorage.py.

725 def readPickleStorage(butlerLocation):
726  """Read an object from a pickle file specified by ButlerLocation.
727 
728  Parameters
729  ----------
730  butlerLocation : ButlerLocation
731  The location for the object(s) to be read.
732 
733  Returns
734  -------
735  A list of objects as described by the butler location. One item for
736  each location in butlerLocation.getLocations()
737  """
738  # Create a list of Storages for the item.
739  results = []
740  additionalData = butlerLocation.getAdditionalData()
741  for locationString in butlerLocation.getLocations():
742  locStringWithRoot = os.path.join(butlerLocation.getStorage().root, locationString)
743  logLoc = LogicalLocation(locStringWithRoot, additionalData)
744  if not os.path.exists(logLoc.locString()):
745  raise RuntimeError("No such pickle file: " + logLoc.locString())
746  with open(logLoc.locString(), "rb") as infile:
747  # py3: We have to specify encoding since some files were written
748  # by python2, and 'latin1' manages that conversion safely. See:
749  # http://stackoverflow.com/questions/28218466/unpickling-a-python-2-object-with-python-3/28218598#28218598
750  if sys.version_info.major >= 3:
751  finalItem = pickle.load(infile, encoding="latin1")
752  else:
753  finalItem = pickle.load(infile)
754  results.append(finalItem)
755  return results
756 
757 
def readPickleStorage(butlerLocation)

◆ readYamlStorage()

def lsst.daf.persistence.posixStorage.readYamlStorage (   butlerLocation)
Read an object from a YAML file specified by a butlerLocation.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object(s) to be read.

Returns
-------
A list of objects as described by the butler location. One item for
each location in butlerLocation.getLocations()

Definition at line 876 of file posixStorage.py.

876 def readYamlStorage(butlerLocation):
877  """Read an object from a YAML file specified by a butlerLocation.
878 
879  Parameters
880  ----------
881  butlerLocation : ButlerLocation
882  The location for the object(s) to be read.
883 
884  Returns
885  -------
886  A list of objects as described by the butler location. One item for
887  each location in butlerLocation.getLocations()
888  """
889  results = []
890  for locationString in butlerLocation.getLocations():
891  logLoc = LogicalLocation(butlerLocation.getStorage().locationWithRoot(locationString),
892  butlerLocation.getAdditionalData())
893  if not os.path.exists(logLoc.locString()):
894  raise RuntimeError("No such YAML file: " + logLoc.locString())
895  # Butler Gen2 repository configurations are handled specially
896  if butlerLocation.pythonType == 'lsst.daf.persistence.RepositoryCfg':
897  finalItem = Policy(filePath=logLoc.locString())
898  else:
899  try:
900  # PyYAML >=5.1 prefers a different loader
901  loader = yaml.UnsafeLoader
902  except AttributeError:
903  loader = yaml.Loader
904  with open(logLoc.locString(), "rb") as infile:
905  finalItem = yaml.load(infile, Loader=loader)
906  results.append(finalItem)
907  return results
908 
909 
910 PosixStorage.registerFormatters("FitsStorage", readFitsStorage, writeFitsStorage)
911 PosixStorage.registerFormatters("ParquetStorage", readParquetStorage, writeParquetStorage)
912 PosixStorage.registerFormatters("ConfigStorage", readConfigStorage, writeConfigStorage)
913 PosixStorage.registerFormatters("PickleStorage", readPickleStorage, writePickleStorage)
914 PosixStorage.registerFormatters("FitsCatalogStorage", readFitsCatalogStorage, writeFitsCatalogStorage)
915 PosixStorage.registerFormatters("MatplotlibStorage", readMatplotlibStorage, writeMatplotlibStorage)
916 PosixStorage.registerFormatters("YamlStorage", readYamlStorage, writeYamlStorage)
917 
918 Storage.registerStorageClass(scheme='', cls=PosixStorage)
919 Storage.registerStorageClass(scheme='file', cls=PosixStorage)
def readYamlStorage(butlerLocation)

◆ writeConfigStorage()

def lsst.daf.persistence.posixStorage.writeConfigStorage (   butlerLocation,
  obj 
)
Writes an lsst.pex.config.Config  object to a location specified by
ButlerLocation.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object to be written.
obj : object instance
    The object to be written.

Definition at line 548 of file posixStorage.py.

548 def writeConfigStorage(butlerLocation, obj):
549  """Writes an lsst.pex.config.Config object to a location specified by
550  ButlerLocation.
551 
552  Parameters
553  ----------
554  butlerLocation : ButlerLocation
555  The location for the object to be written.
556  obj : object instance
557  The object to be written.
558  """
559  filename = os.path.join(butlerLocation.getStorage().root, butlerLocation.getLocations()[0])
560  with SafeFilename(filename) as locationString:
561  logLoc = LogicalLocation(locationString, butlerLocation.getAdditionalData())
562  obj.save(logLoc.locString())
563 
564 
def writeConfigStorage(butlerLocation, obj)

◆ writeFitsCatalogStorage()

def lsst.daf.persistence.posixStorage.writeFitsCatalogStorage (   butlerLocation,
  obj 
)
Writes a catalog to a FITS table specified by ButlerLocation.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object to be written.
obj : object instance
    The object to be written.

Definition at line 810 of file posixStorage.py.

810 def writeFitsCatalogStorage(butlerLocation, obj):
811  """Writes a catalog to a FITS table specified by ButlerLocation.
812 
813  Parameters
814  ----------
815  butlerLocation : ButlerLocation
816  The location for the object to be written.
817  obj : object instance
818  The object to be written.
819  """
820  additionalData = butlerLocation.getAdditionalData()
821  locations = butlerLocation.getLocations()
822  with SafeFilename(os.path.join(butlerLocation.getStorage().root, locations[0])) as locationString:
823  logLoc = LogicalLocation(locationString, additionalData)
824  if additionalData.exists("flags"):
825  kwds = dict(flags=additionalData.getInt("flags"))
826  else:
827  kwds = {}
828  obj.writeFits(logLoc.locString(), **kwds)
829 
830 
def writeFitsCatalogStorage(butlerLocation, obj)

◆ writeFitsStorage()

def lsst.daf.persistence.posixStorage.writeFitsStorage (   butlerLocation,
  obj 
)
Writes an object to a FITS file specified by ButlerLocation.

The object is written using method
``writeFitsWithOptions(path, options)``, if it exists, else
``writeFits(path)``. The ``options`` argument is the data returned by
``butlerLocation.getAdditionalData()``.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object to be written.
obj : object instance
    The object to be written.

Definition at line 622 of file posixStorage.py.

622 def writeFitsStorage(butlerLocation, obj):
623  """Writes an object to a FITS file specified by ButlerLocation.
624 
625  The object is written using method
626  ``writeFitsWithOptions(path, options)``, if it exists, else
627  ``writeFits(path)``. The ``options`` argument is the data returned by
628  ``butlerLocation.getAdditionalData()``.
629 
630  Parameters
631  ----------
632  butlerLocation : ButlerLocation
633  The location for the object to be written.
634  obj : object instance
635  The object to be written.
636  """
637  supportsOptions = hasattr(obj, "writeFitsWithOptions")
638  additionalData = butlerLocation.getAdditionalData()
639  locations = butlerLocation.getLocations()
640  with SafeFilename(os.path.join(butlerLocation.getStorage().root, locations[0])) as locationString:
641  logLoc = LogicalLocation(locationString, additionalData)
642  if supportsOptions:
643  obj.writeFitsWithOptions(logLoc.locString(), options=additionalData)
644  else:
645  obj.writeFits(logLoc.locString())
646 
647 
def writeFitsStorage(butlerLocation, obj)

◆ writeMatplotlibStorage()

def lsst.daf.persistence.posixStorage.writeMatplotlibStorage (   butlerLocation,
  obj 
)
Writes a matplotlib.figure.Figure to a location, using the template's
filename suffix to infer the file format.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object to be written.
obj : matplotlib.figure.Figure
    The object to be written.

Definition at line 847 of file posixStorage.py.

847 def writeMatplotlibStorage(butlerLocation, obj):
848  """Writes a matplotlib.figure.Figure to a location, using the template's
849  filename suffix to infer the file format.
850 
851  Parameters
852  ----------
853  butlerLocation : ButlerLocation
854  The location for the object to be written.
855  obj : matplotlib.figure.Figure
856  The object to be written.
857  """
858  additionalData = butlerLocation.getAdditionalData()
859  locations = butlerLocation.getLocations()
860  with SafeFilename(os.path.join(butlerLocation.getStorage().root, locations[0])) as locationString:
861  logLoc = LogicalLocation(locationString, additionalData)
862  # SafeFilename appends a random suffix, which corrupts the extension
863  # matplotlib uses to guess the file format.
864  # Instead, we extract the extension from the original location
865  # and pass that as the format directly.
866  _, ext = os.path.splitext(locations[0])
867  if ext:
868  ext = ext[1:] # strip off leading '.'
869  else:
870  # If there is no extension, we let matplotlib fall back to its
871  # default.
872  ext = None
873  obj.savefig(logLoc.locString(), format=ext)
874 
875 
def writeMatplotlibStorage(butlerLocation, obj)

◆ writeParquetStorage()

def lsst.daf.persistence.posixStorage.writeParquetStorage (   butlerLocation,
  obj 
)
Writes pandas dataframe to parquet file.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object(s) to be read.
obj : `lsst.qa.explorer.parquetTable.ParquetTable`
    Wrapped DataFrame to write.

Definition at line 688 of file posixStorage.py.

688 def writeParquetStorage(butlerLocation, obj):
689  """Writes pandas dataframe to parquet file.
690 
691  Parameters
692  ----------
693  butlerLocation : ButlerLocation
694  The location for the object(s) to be read.
695  obj : `lsst.qa.explorer.parquetTable.ParquetTable`
696  Wrapped DataFrame to write.
697 
698  """
699  additionalData = butlerLocation.getAdditionalData()
700  locations = butlerLocation.getLocations()
701  with SafeFilename(os.path.join(butlerLocation.getStorage().root, locations[0])) as locationString:
702  logLoc = LogicalLocation(locationString, additionalData)
703  filename = logLoc.locString()
704  obj.write(filename)
705 
706 
def writeParquetStorage(butlerLocation, obj)

◆ writePickleStorage()

def lsst.daf.persistence.posixStorage.writePickleStorage (   butlerLocation,
  obj 
)
Writes an object to a pickle file specified by ButlerLocation.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object to be written.
obj : object instance
    The object to be written.

Definition at line 758 of file posixStorage.py.

758 def writePickleStorage(butlerLocation, obj):
759  """Writes an object to a pickle file specified by ButlerLocation.
760 
761  Parameters
762  ----------
763  butlerLocation : ButlerLocation
764  The location for the object to be written.
765  obj : object instance
766  The object to be written.
767  """
768  additionalData = butlerLocation.getAdditionalData()
769  locations = butlerLocation.getLocations()
770  with SafeFilename(os.path.join(butlerLocation.getStorage().root, locations[0])) as locationString:
771  logLoc = LogicalLocation(locationString, additionalData)
772  with open(logLoc.locString(), "wb") as outfile:
773  pickle.dump(obj, outfile, pickle.HIGHEST_PROTOCOL)
774 
775 
def writePickleStorage(butlerLocation, obj)

◆ writeYamlStorage()

def lsst.daf.persistence.posixStorage.writeYamlStorage (   butlerLocation,
  obj 
)
Writes an object to a YAML file specified by ButlerLocation.

Parameters
----------
butlerLocation : ButlerLocation
    The location for the object to be written.
obj : object instance
    The object to be written.

Definition at line 707 of file posixStorage.py.

707 def writeYamlStorage(butlerLocation, obj):
708  """Writes an object to a YAML file specified by ButlerLocation.
709 
710  Parameters
711  ----------
712  butlerLocation : ButlerLocation
713  The location for the object to be written.
714  obj : object instance
715  The object to be written.
716  """
717  additionalData = butlerLocation.getAdditionalData()
718  locations = butlerLocation.getLocations()
719  with SafeFilename(os.path.join(butlerLocation.getStorage().root, locations[0])) as locationString:
720  logLoc = LogicalLocation(locationString, additionalData)
721  with open(logLoc.locString(), "w") as outfile:
722  yaml.dump(obj, outfile)
723 
724 
def writeYamlStorage(butlerLocation, obj)