LSSTApplications  16.0-10-g0ee56ad+5,16.0-11-ga33d1f2+5,16.0-12-g3ef5c14+3,16.0-12-g71e5ef5+18,16.0-12-gbdf3636+3,16.0-13-g118c103+3,16.0-13-g8f68b0a+3,16.0-15-gbf5c1cb+4,16.0-16-gfd17674+3,16.0-17-g7c01f5c+3,16.0-18-g0a50484+1,16.0-20-ga20f992+8,16.0-21-g0e05fd4+6,16.0-21-g15e2d33+4,16.0-22-g62d8060+4,16.0-22-g847a80f+4,16.0-25-gf00d9b8+1,16.0-28-g3990c221+4,16.0-3-gf928089+3,16.0-32-g88a4f23+5,16.0-34-gd7987ad+3,16.0-37-gc7333cb+2,16.0-4-g10fc685+2,16.0-4-g18f3627+26,16.0-4-g5f3a788+26,16.0-5-gaf5c3d7+4,16.0-5-gcc1f4bb+1,16.0-6-g3b92700+4,16.0-6-g4412fcd+3,16.0-6-g7235603+4,16.0-69-g2562ce1b+2,16.0-8-g14ebd58+4,16.0-8-g2df868b+1,16.0-8-g4cec79c+6,16.0-8-gadf6c7a+1,16.0-8-gfc7ad86,16.0-82-g59ec2a54a+1,16.0-9-g5400cdc+2,16.0-9-ge6233d7+5,master-g2880f2d8cf+3,v17.0.rc1
LSSTDataManagementBasePackage
Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | List of all members
lsst.daf.persistence.butler.Butler Class Reference
Inheritance diagram for lsst.daf.persistence.butler.Butler:

Public Member Functions

def __init__ (self, root=None, mapper=None, inputs=None, outputs=None, mapperArgs)
 
def __repr__ (self)
 
def defineAlias (self, alias, datasetType)
 
def getKeys (self, datasetType=None, level=None, tag=None)
 
def queryMetadata (self, datasetType, format, dataId={}, rest)
 
def datasetExists (self, datasetType, dataId={}, write=False, rest)
 
def get (self, datasetType, dataId=None, immediate=True, rest)
 
def put (self, obj, datasetType, dataId={}, doBackup=False, rest)
 
def subset (self, datasetType, level=None, dataId={}, rest)
 
def dataRef (self, datasetType, level=None, dataId={}, rest)
 
def getUri (self, datasetType, dataId=None, write=False, rest)
 
def __reduce__ (self)
 

Static Public Member Functions

def getMapperClass (root)
 

Public Attributes

 log
 
 datasetTypeAliasDict
 
 storage
 

Static Public Attributes

int GENERATION = 2
 

Detailed Description

Butler provides a generic mechanism for persisting and retrieving data using mappers.

A Butler manages a collection of datasets known as a repository. Each dataset has a type representing its
intended usage and a location. Note that the dataset type is not the same as the C++ or Python type of the
object containing the data. For example, an ExposureF object might be used to hold the data for a raw
image, a post-ISR image, a calibrated science image, or a difference image. These would all be different
dataset types.

A Butler can produce a collection of possible values for a key (or tuples of values for multiple keys) if
given a partial data identifier. It can check for the existence of a file containing a dataset given its
type and data identifier. The Butler can then retrieve the dataset. Similarly, it can persist an object to
an appropriate location when given its associated data identifier.

Note that the Butler has two more advanced features when retrieving a data set. First, the retrieval is
lazy. Input does not occur until the data set is actually accessed. This allows datasets to be retrieved
and placed on a clipboard prospectively with little cost, even if the algorithm of a stage ends up not
using them. Second, the Butler will call a standardization hook upon retrieval of the dataset. This
function, contained in the input mapper object, must perform any necessary manipulations to force the
retrieved object to conform to standards, including translating metadata.

Public methods:

__init__(self, root, mapper=None, **mapperArgs)

defineAlias(self, alias, datasetType)

getKeys(self, datasetType=None, level=None)

queryMetadata(self, datasetType, format=None, dataId={}, **rest)

datasetExists(self, datasetType, dataId={}, **rest)

get(self, datasetType, dataId={}, immediate=False, **rest)

put(self, obj, datasetType, dataId={}, **rest)

subset(self, datasetType, level=None, dataId={}, **rest)

dataRef(self, datasetType, level=None, dataId={}, **rest)

Initialization:

The preferred method of initialization is to use the `inputs` and `outputs` __init__ parameters. These
are described in the parameters section, below.

For backward compatibility: this initialization method signature can take a posix root path, and
optionally a mapper class instance or class type that will be instantiated using the mapperArgs input
argument. However, for this to work in a backward compatible way it creates a single repository that is
used as both an input and an output repository. This is NOT preferred, and will likely break any
provenance system we have in place.

Parameters
----------
root : string
    .. note:: Deprecated in 12_0
              `root` will be removed in TBD, it is replaced by `inputs` and `outputs` for
              multiple-repository support.
    A file system path. Will only work with a PosixRepository.
mapper : string or instance
    .. note:: Deprecated in 12_0
              `mapper` will be removed in TBD, it is replaced by `inputs` and `outputs` for
              multiple-repository support.
    Provides a mapper to be used with Butler.
mapperArgs : dict
    .. note:: Deprecated in 12_0
              `mapperArgs` will be removed in TBD, it is replaced by `inputs` and `outputs` for
              multiple-repository support.
    Provides arguments to be passed to the mapper if the mapper input argument is a class type to be
    instantiated by Butler.
inputs : RepositoryArgs, dict, or string
    Can be a single item or a list. Provides arguments to load an existing repository (or repositories).
    String is assumed to be a URI and is used as the cfgRoot (URI to the location of the cfg file). (Local
    file system URI does not have to start with 'file://' and in this way can be a relative path). The
    `RepositoryArgs` class can be used to provide more parameters with which to initialize a repository
    (such as `mapper`, `mapperArgs`, `tags`, etc. See the `RepositoryArgs` documentation for more
    details). A dict may be used as shorthand for a `RepositoryArgs` class instance. The dict keys must
    match parameters to the `RepositoryArgs.__init__` function.
outputs : RepositoryArgs, dict, or string
    Provides arguments to load one or more existing repositories or create new ones. The different types
    are handled the same as for `inputs`.

The Butler init sequence loads all of the input and output repositories.
This creates the object hierarchy to read from and write to them. Each
repository can have 0 or more parents, which also get loaded as inputs.
This becomes a DAG of repositories. Ultimately, Butler creates a list of
these Repositories in the order that they are used.

Initialization Sequence
=======================

During initialization Butler creates a Repository class instance & support structure for each object
passed to `inputs` and `outputs` as well as the parent repositories recorded in the `RepositoryCfg` of
each existing readable repository.

This process is complex. It is explained below to shed some light on the intent of each step.

1. Input Argument Standardization
---------------------------------

In `Butler._processInputArguments` the input arguments are verified to be legal (and a RuntimeError is
raised if not), and they are converted into an expected format that is used for the rest of the Butler
init sequence. See the docstring for `_processInputArguments`.

2. Create RepoData Objects
--------------------------

Butler uses an object, called `RepoData`, to keep track of information about each repository; each
repository is contained in a single `RepoData`. The attributes are explained in its docstring.

After `_processInputArguments`, a RepoData is instantiated and put in a list for each repository in
`outputs` and `inputs`. This list of RepoData, the `repoDataList`, now represents all the output and input
repositories (but not parent repositories) that this Butler instance will use.

3. Get `RepositoryCfg`s
-----------------------

`Butler._getCfgs` gets the `RepositoryCfg` for each repository the `repoDataList`. The behavior is
described in the docstring.

4. Add Parents
--------------

`Butler._addParents` then considers the parents list in the `RepositoryCfg` of each `RepoData` in the
`repoDataList` and inserts new `RepoData` objects for each parent not represented in the proper location
in the `repoDataList`. Ultimately a flat list is built to represent the DAG of readable repositories
represented in depth-first order.

5. Set and Verify Parents of Outputs
------------------------------------

To be able to load parent repositories when output repositories are used as inputs, the input repositories
are recorded as parents in the `RepositoryCfg` file of new output repositories. When an output repository
already exists, for consistency the Butler's inputs must match the list of parents specified the already-
existing output repository's `RepositoryCfg` file.

In `Butler._setAndVerifyParentsLists`, the list of parents is recorded in the `RepositoryCfg` of new
repositories. For existing repositories the list of parents is compared with the `RepositoryCfg`'s parents
list, and if they do not match a `RuntimeError` is raised.

6. Set the Default Mapper
-------------------------

If all the input repositories use the same mapper then we can assume that mapper to be the
"default mapper". If there are new output repositories whose `RepositoryArgs` do not specify a mapper and
there is a default mapper then the new output repository will be set to use that default mapper.

This is handled in `Butler._setDefaultMapper`.

7. Cache References to Parent RepoDatas
---------------------------------------

In `Butler._connectParentRepoDatas`, in each `RepoData` in `repoDataList`, a list of `RepoData` object
references is  built that matches the parents specified in that `RepoData`'s `RepositoryCfg`.

This list is used later to find things in that repository's parents, without considering peer repository's
parents. (e.g. finding the registry of a parent)

8. Set Tags
-----------

Tags are described at https://ldm-463.lsst.io/v/draft/#tagging

In `Butler._setRepoDataTags`, for each `RepoData`, the tags specified by its `RepositoryArgs` are recorded
in a set, and added to the tags set in each of its parents, for ease of lookup when mapping.

9. Find Parent Registry and Instantiate RepoData
------------------------------------------------

At this point there is enough information to instantiate the `Repository` instances. There is one final
step before instantiating the Repository, which is to try to get a parent registry that can be used by the
child repository. The criteria for "can be used" is spelled out in `Butler._setParentRegistry`. However,
to get the registry from the parent, the parent must be instantiated. The `repoDataList`, in depth-first
search order, is built so that the most-dependent repositories are first, and the least dependent
repositories are last. So the `repoDataList` is reversed and the Repositories are instantiated in that
order; for each RepoData a parent registry is searched for, and then the Repository is instantiated with
whatever registry could be found.

Definition at line 325 of file butler.py.

Constructor & Destructor Documentation

◆ __init__()

def lsst.daf.persistence.butler.Butler.__init__ (   self,
  root = None,
  mapper = None,
  inputs = None,
  outputs = None,
  mapperArgs 
)

Definition at line 507 of file butler.py.

507  def __init__(self, root=None, mapper=None, inputs=None, outputs=None, **mapperArgs):
508  self._initArgs = {'root': root, 'mapper': mapper, 'inputs': inputs, 'outputs': outputs,
509  'mapperArgs': mapperArgs}
510 
511  self.log = Log.getLogger("daf.persistence.butler")
512 
513  inputs, outputs = self._processInputArguments(
514  root=root, mapper=mapper, inputs=inputs, outputs=outputs, **mapperArgs)
515 
516  # convert the RepoArgs into RepoData
517  inputs = [RepoData(args, 'input') for args in inputs]
518  outputs = [RepoData(args, 'output') for args in outputs]
519  repoDataList = outputs + inputs
520 
521  self._getCfgs(repoDataList)
522 
523  self._addParents(repoDataList)
524 
525  self._setAndVerifyParentsLists(repoDataList)
526 
527  self._setDefaultMapper(repoDataList)
528 
529  self._connectParentRepoDatas(repoDataList)
530 
531  self._repos = RepoDataContainer(repoDataList)
532 
533  self._setRepoDataTags()
534 
535  for repoData in repoDataList:
536  self._initRepo(repoData)
537 
def __init__(self, minimum, dataRange, Q)

Member Function Documentation

◆ __reduce__()

def lsst.daf.persistence.butler.Butler.__reduce__ (   self)

Definition at line 1596 of file butler.py.

1596  def __reduce__(self):
1597  ret = (_unreduce, (self._initArgs, self.datasetTypeAliasDict))
1598  return ret
1599 

◆ __repr__()

def lsst.daf.persistence.butler.Butler.__repr__ (   self)

Definition at line 1035 of file butler.py.

1035  def __repr__(self):
1036  return 'Butler(datasetTypeAliasDict=%s, repos=%s)' % (
1037  self.datasetTypeAliasDict, self._repos)
1038 

◆ dataRef()

def lsst.daf.persistence.butler.Butler.dataRef (   self,
  datasetType,
  level = None,
  dataId = {},
  rest 
)
Returns a single ButlerDataRef.

Given a complete dataId specified in dataId and **rest, find the unique dataset at the given level
specified by a dataId key (e.g. visit or sensor or amp for a camera) and return a ButlerDataRef.

Parameters
----------
datasetType - string
    The type of dataset collection to reference
level - string
    The level of dataId at which to reference
dataId - dict
    The data id.
**rest
    Keyword arguments for the data id.

Returns
-------
dataRef - ButlerDataRef
    ButlerDataRef for dataset matching the data id

Definition at line 1481 of file butler.py.

1481  def dataRef(self, datasetType, level=None, dataId={}, **rest):
1482  """Returns a single ButlerDataRef.
1483 
1484  Given a complete dataId specified in dataId and **rest, find the unique dataset at the given level
1485  specified by a dataId key (e.g. visit or sensor or amp for a camera) and return a ButlerDataRef.
1486 
1487  Parameters
1488  ----------
1489  datasetType - string
1490  The type of dataset collection to reference
1491  level - string
1492  The level of dataId at which to reference
1493  dataId - dict
1494  The data id.
1495  **rest
1496  Keyword arguments for the data id.
1497 
1498  Returns
1499  -------
1500  dataRef - ButlerDataRef
1501  ButlerDataRef for dataset matching the data id
1502  """
1503 
1504  datasetType = self._resolveDatasetTypeAlias(datasetType)
1505  dataId = DataId(dataId)
1506  subset = self.subset(datasetType, level, dataId, **rest)
1507  if len(subset) != 1:
1508  raise RuntimeError("No unique dataset for: Dataset type:%s Level:%s Data ID:%s Keywords:%s" %
1509  (str(datasetType), str(level), str(dataId), str(rest)))
1510  return ButlerDataRef(subset, subset.cache[0])
1511 

◆ datasetExists()

def lsst.daf.persistence.butler.Butler.datasetExists (   self,
  datasetType,
  dataId = {},
  write = False,
  rest 
)
Determines if a dataset file exists.

Parameters
----------
datasetType - string
    The type of dataset to inquire about.
dataId - DataId, dict
    The data id of the dataset.
write - bool
    If True, look only in locations where the dataset could be written,
    and return True only if it is present in all of them.
**rest keyword arguments for the data id.

Returns
-------
exists - bool
    True if the dataset exists or is non-file-based.

Definition at line 1218 of file butler.py.

1218  def datasetExists(self, datasetType, dataId={}, write=False, **rest):
1219  """Determines if a dataset file exists.
1220 
1221  Parameters
1222  ----------
1223  datasetType - string
1224  The type of dataset to inquire about.
1225  dataId - DataId, dict
1226  The data id of the dataset.
1227  write - bool
1228  If True, look only in locations where the dataset could be written,
1229  and return True only if it is present in all of them.
1230  **rest keyword arguments for the data id.
1231 
1232  Returns
1233  -------
1234  exists - bool
1235  True if the dataset exists or is non-file-based.
1236  """
1237  datasetType = self._resolveDatasetTypeAlias(datasetType)
1238  dataId = DataId(dataId)
1239  dataId.update(**rest)
1240  locations = self._locate(datasetType, dataId, write=write)
1241  if not write: # when write=False, locations is not a sequence
1242  if locations is None:
1243  return False
1244  locations = [locations]
1245 
1246  if not locations: # empty list
1247  return False
1248 
1249  for location in locations:
1250  # If the location is a ButlerComposite (as opposed to a ButlerLocation),
1251  # verify the component objects exist.
1252  if isinstance(location, ButlerComposite):
1253  for name, componentInfo in location.componentInfo.items():
1254  if componentInfo.subset:
1255  subset = self.subset(datasetType=componentInfo.datasetType, dataId=location.dataId)
1256  exists = all([obj.datasetExists() for obj in subset])
1257  else:
1258  exists = self.datasetExists(componentInfo.datasetType, location.dataId)
1259  if exists is False:
1260  return False
1261  else:
1262  if not location.repository.exists(location):
1263  return False
1264  return True
1265 
bool all(CoordinateExpr< N > const &expr) noexcept
Return true if all elements are true.

◆ defineAlias()

def lsst.daf.persistence.butler.Butler.defineAlias (   self,
  alias,
  datasetType 
)
Register an alias that will be substituted in datasetTypes.

Parameters
----------
alias - string
    The alias keyword. It may start with @ or not. It may not contain @ except as the first character.
datasetType - string
    The string that will be substituted when @alias is passed into datasetType. It may not contain '@'

Definition at line 1105 of file butler.py.

1105  def defineAlias(self, alias, datasetType):
1106  """Register an alias that will be substituted in datasetTypes.
1107 
1108  Parameters
1109  ----------
1110  alias - string
1111  The alias keyword. It may start with @ or not. It may not contain @ except as the first character.
1112  datasetType - string
1113  The string that will be substituted when @alias is passed into datasetType. It may not contain '@'
1114  """
1115  # verify formatting of alias:
1116  # it can have '@' as the first character (if not it's okay, we will add it) or not at all.
1117  atLoc = alias.rfind('@')
1118  if atLoc == -1:
1119  alias = "@" + str(alias)
1120  elif atLoc > 0:
1121  raise RuntimeError("Badly formatted alias string: %s" % (alias,))
1122 
1123  # verify that datasetType does not contain '@'
1124  if datasetType.count('@') != 0:
1125  raise RuntimeError("Badly formatted type string: %s" % (datasetType))
1126 
1127  # verify that the alias keyword does not start with another alias keyword,
1128  # and vice versa
1129  for key in self.datasetTypeAliasDict:
1130  if key.startswith(alias) or alias.startswith(key):
1131  raise RuntimeError("Alias: %s overlaps with existing alias: %s" % (alias, key))
1132 
1133  self.datasetTypeAliasDict[alias] = datasetType
1134 

◆ get()

def lsst.daf.persistence.butler.Butler.get (   self,
  datasetType,
  dataId = None,
  immediate = True,
  rest 
)
Retrieves a dataset given an input collection data id.

Parameters
----------
datasetType - string
    The type of dataset to retrieve.
dataId - dict
    The data id.
immediate - bool
    If False use a proxy for delayed loading.
**rest
    keyword arguments for the data id.

Returns
-------
    An object retrieved from the dataset (or a proxy for one).

Definition at line 1356 of file butler.py.

1356  def get(self, datasetType, dataId=None, immediate=True, **rest):
1357  """Retrieves a dataset given an input collection data id.
1358 
1359  Parameters
1360  ----------
1361  datasetType - string
1362  The type of dataset to retrieve.
1363  dataId - dict
1364  The data id.
1365  immediate - bool
1366  If False use a proxy for delayed loading.
1367  **rest
1368  keyword arguments for the data id.
1369 
1370  Returns
1371  -------
1372  An object retrieved from the dataset (or a proxy for one).
1373  """
1374  datasetType = self._resolveDatasetTypeAlias(datasetType)
1375  dataId = DataId(dataId)
1376  dataId.update(**rest)
1377 
1378  location = self._locate(datasetType, dataId, write=False)
1379  if location is None:
1380  raise NoResults("No locations for get:", datasetType, dataId)
1381  self.log.debug("Get type=%s keys=%s from %s", datasetType, dataId, str(location))
1382 
1383  if hasattr(location, 'bypass'):
1384  # this type loader block should get moved into a helper someplace, and duplications removed.
1385  def callback():
1386  return location.bypass
1387  else:
1388  def callback():
1389  return self._read(location)
1390  if location.mapper.canStandardize(location.datasetType):
1391  innerCallback = callback
1392 
1393  def callback():
1394  return location.mapper.standardize(location.datasetType, innerCallback(), dataId)
1395  if immediate:
1396  return callback()
1397  return ReadProxy(callback)
1398 

◆ getKeys()

def lsst.daf.persistence.butler.Butler.getKeys (   self,
  datasetType = None,
  level = None,
  tag = None 
)
Get the valid data id keys at or above the given level of hierarchy for the dataset type or the
entire collection if None. The dict values are the basic Python types corresponding to the keys (int,
float, string).

Parameters
----------
datasetType - string
    The type of dataset to get keys for, entire collection if None.
level - string
    The hierarchy level to descend to. None if it should not be restricted. Use an empty string if the
    mapper should lookup the default level.
tags - any, or list of any
    Any object that can be tested to be the same as the tag in a dataId passed into butler input
    functions. Applies only to input repositories: If tag is specified by the dataId then the repo
    will only be read from used if the tag in the dataId matches a tag used for that repository.

Returns
-------
Returns a dict. The dict keys are the valid data id keys at or above the given level of hierarchy for
the dataset type or the entire collection if None. The dict values are the basic Python types
corresponding to the keys (int, float, string).

Definition at line 1135 of file butler.py.

1135  def getKeys(self, datasetType=None, level=None, tag=None):
1136  """Get the valid data id keys at or above the given level of hierarchy for the dataset type or the
1137  entire collection if None. The dict values are the basic Python types corresponding to the keys (int,
1138  float, string).
1139 
1140  Parameters
1141  ----------
1142  datasetType - string
1143  The type of dataset to get keys for, entire collection if None.
1144  level - string
1145  The hierarchy level to descend to. None if it should not be restricted. Use an empty string if the
1146  mapper should lookup the default level.
1147  tags - any, or list of any
1148  Any object that can be tested to be the same as the tag in a dataId passed into butler input
1149  functions. Applies only to input repositories: If tag is specified by the dataId then the repo
1150  will only be read from used if the tag in the dataId matches a tag used for that repository.
1151 
1152  Returns
1153  -------
1154  Returns a dict. The dict keys are the valid data id keys at or above the given level of hierarchy for
1155  the dataset type or the entire collection if None. The dict values are the basic Python types
1156  corresponding to the keys (int, float, string).
1157  """
1158  datasetType = self._resolveDatasetTypeAlias(datasetType)
1159 
1160  keys = None
1161  tag = setify(tag)
1162  for repoData in self._repos.inputs():
1163  if not tag or len(tag.intersection(repoData.tags)) > 0:
1164  keys = repoData.repo.getKeys(datasetType, level)
1165  # An empty dict is a valid "found" condition for keys. The only value for keys that should
1166  # cause the search to continue is None
1167  if keys is not None:
1168  break
1169  return keys
1170 

◆ getMapperClass()

def lsst.daf.persistence.butler.Butler.getMapperClass (   root)
static
posix-only; gets the mapper class at the path specified by root (if a file _mapper can be found at
that location or in a parent location.

As we abstract the storage and support different types of storage locations this method will be
moved entirely into Butler Access, or made more dynamic, and the API will very likely change.

Definition at line 1097 of file butler.py.

1097  def getMapperClass(root):
1098  """posix-only; gets the mapper class at the path specified by root (if a file _mapper can be found at
1099  that location or in a parent location.
1100 
1101  As we abstract the storage and support different types of storage locations this method will be
1102  moved entirely into Butler Access, or made more dynamic, and the API will very likely change."""
1103  return Storage.getMapperClass(root)
1104 

◆ getUri()

def lsst.daf.persistence.butler.Butler.getUri (   self,
  datasetType,
  dataId = None,
  write = False,
  rest 
)
Return the URI for a dataset

.. warning:: This is intended only for debugging. The URI should
never be used for anything other than printing.

.. note:: In the event there are multiple URIs for read, we return only
the first.

.. note:: getUri() does not currently support composite datasets.

Parameters
----------
datasetType : `str`
   The dataset type of interest.
dataId : `dict`, optional
   The data identifier.
write : `bool`, optional
   Return the URI for writing?
rest : `dict`, optional
   Keyword arguments for the data id.

Returns
-------
uri : `str`
   URI for dataset.

Definition at line 1512 of file butler.py.

1512  def getUri(self, datasetType, dataId=None, write=False, **rest):
1513  """Return the URI for a dataset
1514 
1515  .. warning:: This is intended only for debugging. The URI should
1516  never be used for anything other than printing.
1517 
1518  .. note:: In the event there are multiple URIs for read, we return only
1519  the first.
1520 
1521  .. note:: getUri() does not currently support composite datasets.
1522 
1523  Parameters
1524  ----------
1525  datasetType : `str`
1526  The dataset type of interest.
1527  dataId : `dict`, optional
1528  The data identifier.
1529  write : `bool`, optional
1530  Return the URI for writing?
1531  rest : `dict`, optional
1532  Keyword arguments for the data id.
1533 
1534  Returns
1535  -------
1536  uri : `str`
1537  URI for dataset.
1538  """
1539  datasetType = self._resolveDatasetTypeAlias(datasetType)
1540  dataId = DataId(dataId)
1541  dataId.update(**rest)
1542  locations = self._locate(datasetType, dataId, write=write)
1543  if locations is None:
1544  raise NoResults("No locations for getUri: ", datasetType, dataId)
1545 
1546  if write:
1547  # Follow the write path
1548  # Return the first valid write location.
1549  for location in locations:
1550  if isinstance(location, ButlerComposite):
1551  for name, info in location.componentInfo.items():
1552  if not info.inputOnly:
1553  return self.getUri(info.datasetType, location.dataId, write=True)
1554  else:
1555  return location.getLocationsWithRoot()[0]
1556  # fall back to raise
1557  raise NoResults("No locations for getUri(write=True): ", datasetType, dataId)
1558  else:
1559  # Follow the read path, only return the first valid read
1560  return locations.getLocationsWithRoot()[0]
1561 

◆ put()

def lsst.daf.persistence.butler.Butler.put (   self,
  obj,
  datasetType,
  dataId = {},
  doBackup = False,
  rest 
)
Persists a dataset given an output collection data id.

Parameters
----------
obj -
    The object to persist.
datasetType - string
    The type of dataset to persist.
dataId - dict
    The data id.
doBackup - bool
    If True, rename existing instead of overwriting.
    WARNING: Setting doBackup=True is not safe for parallel processing, as it may be subject to race
    conditions.
**rest
    Keyword arguments for the data id.

Definition at line 1399 of file butler.py.

1399  def put(self, obj, datasetType, dataId={}, doBackup=False, **rest):
1400  """Persists a dataset given an output collection data id.
1401 
1402  Parameters
1403  ----------
1404  obj -
1405  The object to persist.
1406  datasetType - string
1407  The type of dataset to persist.
1408  dataId - dict
1409  The data id.
1410  doBackup - bool
1411  If True, rename existing instead of overwriting.
1412  WARNING: Setting doBackup=True is not safe for parallel processing, as it may be subject to race
1413  conditions.
1414  **rest
1415  Keyword arguments for the data id.
1416  """
1417  datasetType = self._resolveDatasetTypeAlias(datasetType)
1418  dataId = DataId(dataId)
1419  dataId.update(**rest)
1420 
1421  locations = self._locate(datasetType, dataId, write=True)
1422  if not locations:
1423  raise NoResults("No locations for put:", datasetType, dataId)
1424  for location in locations:
1425  if isinstance(location, ButlerComposite):
1426  disassembler = location.disassembler if location.disassembler else genericDisassembler
1427  disassembler(obj=obj, dataId=location.dataId, componentInfo=location.componentInfo)
1428  for name, info in location.componentInfo.items():
1429  if not info.inputOnly:
1430  self.put(info.obj, info.datasetType, location.dataId, doBackup=doBackup)
1431  else:
1432  if doBackup:
1433  location.getRepository().backup(location.datasetType, dataId)
1434  location.getRepository().write(location, obj)
1435 

◆ queryMetadata()

def lsst.daf.persistence.butler.Butler.queryMetadata (   self,
  datasetType,
  format,
  dataId = {},
  rest 
)
Returns the valid values for one or more keys when given a partial
input collection data id.

Parameters
----------
datasetType - string
    The type of dataset to inquire about.
format - str, tuple
    Key or tuple of keys to be returned.
dataId - DataId, dict
    The partial data id.
**rest -
    Keyword arguments for the partial data id.

Returns
-------
A list of valid values or tuples of valid values as specified by the
format.

Definition at line 1171 of file butler.py.

1171  def queryMetadata(self, datasetType, format, dataId={}, **rest):
1172  """Returns the valid values for one or more keys when given a partial
1173  input collection data id.
1174 
1175  Parameters
1176  ----------
1177  datasetType - string
1178  The type of dataset to inquire about.
1179  format - str, tuple
1180  Key or tuple of keys to be returned.
1181  dataId - DataId, dict
1182  The partial data id.
1183  **rest -
1184  Keyword arguments for the partial data id.
1185 
1186  Returns
1187  -------
1188  A list of valid values or tuples of valid values as specified by the
1189  format.
1190  """
1191 
1192  datasetType = self._resolveDatasetTypeAlias(datasetType)
1193  dataId = DataId(dataId)
1194  dataId.update(**rest)
1195  format = sequencify(format)
1196 
1197  tuples = None
1198  for repoData in self._repos.inputs():
1199  if not dataId.tag or len(dataId.tag.intersection(repoData.tags)) > 0:
1200  tuples = repoData.repo.queryMetadata(datasetType, format, dataId)
1201  if tuples:
1202  break
1203 
1204  if not tuples:
1205  return []
1206 
1207  if len(format) == 1:
1208  ret = []
1209  for x in tuples:
1210  try:
1211  ret.append(x[0])
1212  except TypeError:
1213  ret.append(x)
1214  return ret
1215 
1216  return tuples
1217 

◆ subset()

def lsst.daf.persistence.butler.Butler.subset (   self,
  datasetType,
  level = None,
  dataId = {},
  rest 
)
Return complete dataIds for a dataset type that match a partial (or empty) dataId.

Given a partial (or empty) dataId specified in dataId and **rest, find all datasets that match the
dataId.  Optionally restrict the results to a given level specified by a dataId key (e.g. visit or
sensor or amp for a camera).  Return an iterable collection of complete dataIds as ButlerDataRefs.
Datasets with the resulting dataIds may not exist; that needs to be tested with datasetExists().

Parameters
----------
datasetType - string
    The type of dataset collection to subset
level - string
    The level of dataId at which to subset. Use an empty string if the mapper should look up the
    default level.
dataId - dict
    The data id.
**rest
    Keyword arguments for the data id.

Returns
-------
subset - ButlerSubset
    Collection of ButlerDataRefs for datasets matching the data id.

Examples
-----------
To print the full dataIds for all r-band measurements in a source catalog
(note that the subset call is equivalent to: `butler.subset('src', dataId={'filter':'r'})`):

>>> subset = butler.subset('src', filter='r')
>>> for data_ref in subset: print(data_ref.dataId)

Definition at line 1436 of file butler.py.

1436  def subset(self, datasetType, level=None, dataId={}, **rest):
1437  """Return complete dataIds for a dataset type that match a partial (or empty) dataId.
1438 
1439  Given a partial (or empty) dataId specified in dataId and **rest, find all datasets that match the
1440  dataId. Optionally restrict the results to a given level specified by a dataId key (e.g. visit or
1441  sensor or amp for a camera). Return an iterable collection of complete dataIds as ButlerDataRefs.
1442  Datasets with the resulting dataIds may not exist; that needs to be tested with datasetExists().
1443 
1444  Parameters
1445  ----------
1446  datasetType - string
1447  The type of dataset collection to subset
1448  level - string
1449  The level of dataId at which to subset. Use an empty string if the mapper should look up the
1450  default level.
1451  dataId - dict
1452  The data id.
1453  **rest
1454  Keyword arguments for the data id.
1455 
1456  Returns
1457  -------
1458  subset - ButlerSubset
1459  Collection of ButlerDataRefs for datasets matching the data id.
1460 
1461  Examples
1462  -----------
1463  To print the full dataIds for all r-band measurements in a source catalog
1464  (note that the subset call is equivalent to: `butler.subset('src', dataId={'filter':'r'})`):
1465  >>> subset = butler.subset('src', filter='r')
1466  >>> for data_ref in subset: print(data_ref.dataId)
1467  """
1468  datasetType = self._resolveDatasetTypeAlias(datasetType)
1469 
1470  # Currently expected behavior of subset is that if specified level is None then the mapper's default
1471  # level should be used. Convention for level within Butler is that an empty string is used to indicate
1472  # 'get default'.
1473  if level is None:
1474  level = ''
1475 
1476  dataId = DataId(dataId)
1477  dataId.update(**rest)
1478  return ButlerSubset(self, datasetType, level, dataId)
1479 
1480 

Member Data Documentation

◆ datasetTypeAliasDict

lsst.daf.persistence.butler.Butler.datasetTypeAliasDict

Definition at line 601 of file butler.py.

◆ GENERATION

int lsst.daf.persistence.butler.Butler.GENERATION = 2
static

Definition at line 503 of file butler.py.

◆ log

lsst.daf.persistence.butler.Butler.log

Definition at line 511 of file butler.py.

◆ storage

lsst.daf.persistence.butler.Butler.storage

Definition at line 603 of file butler.py.


The documentation for this class was generated from the following file: