Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tickets/dm 6074 #16

Merged
merged 3 commits into from
Jun 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
64 changes: 58 additions & 6 deletions doc/main.dox
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,18 @@ as shown in these examples:

\note `config` in a configuration override file is equivalent to `self.config` in a task.

There are important limitations `--config` (use `--configfile`, instead, in these situations):
- You cannot \ref pipeBase_argumentParser_retargetSubtasks "retarget subtasks"
You can use a config file (e.g. as specified by `--configfile`) to override any config parameter,
but the simpler `--config` command-line option has significant limitations:
- You cannot \ref pipeBase_argumentParser_retargetSubtasks "retarget a subtask" specified by a
\ref lsst.pex.config.configurableField.ConfigurableField "lsst.pex.config.ConfigurableField"
(which is the most common case)
- For items in registries, you can only specify values for the active (current) item
- You cannot specify values for lists of strings
- You cannot specify a subset of list; you must specify all values at once

See \ref pipeBase_argumentParser_retargetSubtasks for more information about
overriding configuration parmaters in subtasks.

\subsection pipeBase_argumentParser_retargetSubtasks Retargeting Subtasks

As a special case of \ref pipeBase_argumentParser_configOverride "overriding configuration parameters",
Expand All @@ -172,11 +178,57 @@ is to use a camera-specific variant of a subtask. Examples include:
- lsst.obs.sdss.selectSdssImages.SelectSdssImagesTask: an version of the task that selects images
for co-addition of SDSS stripe 82 images

Here is an example of retargeting a subtask in a config override file; this retargets
lsst.pipe.tasks.exampleCmdLineTask.ExampleCmdLineTask `stats` with a simpler version:
How you retarget a subtask and override its config parameters depends on whether
the task is specified as an
\ref lsst.pex.config.configurableField.ConfigurableField "lsst.pex.config.ConfigurableField"
(the most common case, and the source of the term "retarget") or as an
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as a?

\ref lsst.pex.config.registry.RegistryField "lsst.pex.config.RegistryField".

To override a subtask specified as an
\ref lsst.pex.config.configurableField.ConfigurableField "lsst.pex.config.ConfigurableField"
use `retarget` method of the field. To override config parameters use simple dotted
notation. Here is an example:
<pre>
from lsst.pipe.tasks.exampleStatsTasks import ExampleSimpleStatsTask
config.stats.retarget(ExampleSimpleStatsTask)
# Example of retargeting a subtask and overriding its configuration
# for a subtask specified by an lsst.pex.config.ConfigurableField

# import the task and then retarget it
from ... import FooTask
config.configurableSubtask.retarget(FooTask)

# override a config parameter
config.configurableSubtask.subtaskParam1 = newValue
</pre>

\warning when you retarget a task specified by an
\ref lsst.pex.config.configurableField.ConfigurableField "lsst.pex.config.ConfigurableField"
you lose all configuration overrides for both the old and new task. This limitation is not
shared by \ref lsst.pex.config.registry.RegistryField "lsst.pex.config.RegistryField".

To retarget a subtask is specified as an
\ref lsst.pex.config.registry.RegistryField "lsst.pex.config.RegistryField"
set the `name` property of the field. Overriding config parameters is a bit more complicated
than for \ref lsst.pex.config.configurableField.ConfigurableField "lsst.pex.config.ConfigurableField":
you can set the `active` attribute of the field to override the currently active subtask,
or use dictionary access notation to override any registered subtask. On the other hand,
retargeting does not lose any config overrides for any registered subtask.
Here is an example that assumes the same FooTask is defined
in module .../foo.py and registered using name "foo":

<pre>
# Example of retargeting a subtask and overriding its configuration
# for a subtask specified by an lsst.pex.config.RegistryField

# import the task's module, so the task registers itself,
# then set the name property of the field to the name in the registry
import .../foo.py
config.registrySubtask.name = "foo"

# you can override the active subtask's configuration using attribute `active`
config.registrySubtask.active.subtaskParam1 = newValue

# and/or you can override parameters in any subtask in the registry using dictionary access:
config.registrySubtask["foo"].subtaskParam1 = newValue
</pre>

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is clearer if you use the exact same example as above with the same names and modify that to the "RegistryField" case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If by "as above" you mean the same as used in the "how to write a task" documentation then I agree and will update it accordingly. I will also include an example of overriding configuration parameters.

\subsection pipeBase_argumentParser_debugVariables Specifying Debug Variables
Expand Down
8 changes: 5 additions & 3 deletions python/lsst/pipe/base/argumentParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ def parse_args(self, config, args=None, log=None, override=None):
- configfile, id and loglevel are all missing
- obsPkg: name of obs_ package for this camera
"""
if args == None:
if args is None:
args = sys.argv[1:]

if len(args) < 1 or args[0].startswith("-") or args[0].startswith("@"):
Expand Down Expand Up @@ -839,7 +839,8 @@ def __call__(self, parser, namespace, values, option_string):
if mat:
v1 = int(mat.group(1))
v2 = int(mat.group(2))
v3 = mat.group(3); v3 = int(v3) if v3 else 1
v3 = mat.group(3)
v3 = int(v3) if v3 else 1
for v in range(v1, v2 + 1, v3):
idDict[name].append(str(v))
else:
Expand Down Expand Up @@ -880,7 +881,8 @@ def __call__(self, parser, namespace, values, option_string):
try:
logLevel = int(levelStr)
except Exception:
parser.error("loglevel=%r not int or one of %s" % (namespace.loglevel, permittedLevelList))
parser.error("loglevel=%r not int or one of %s" %
(namespace.loglevel, permittedLevelList))
if component is None:
namespace.log.setThreshold(logLevel)
else:
Expand Down
12 changes: 6 additions & 6 deletions python/lsst/pipe/base/cmdLineTask.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
from __future__ import absolute_import, division
#
#
# LSST Data Management System
# Copyright 2008-2015 AURA/LSST.
#
#
# This product includes software developed by the
# LSST Project (http://www.lsst.org/).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the LSST License Statement and
# the GNU General Public License along with this program. If not,
#
# You should have received a copy of the LSST License Statement and
# the GNU General Public License along with this program. If not,
# see <https://www.lsstcorp.org/LegalNotices/>.
#
import sys
Expand Down
28 changes: 14 additions & 14 deletions python/lsst/pipe/base/struct.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
from __future__ import absolute_import, division
#
#
# LSST Data Management System
# Copyright 2008, 2009, 2010, 2011 LSST Corporation.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjust copyright to LSST template?

#
#
# This product includes software developed by the
# LSST Project (http://www.lsst.org/).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the LSST License Statement and
# the GNU General Public License along with this program. If not,
#
# You should have received a copy of the LSST License Statement and
# the GNU General Public License along with this program. If not,
# see <http://www.lsstcorp.org/LegalNotices/>.
#
__all__ = ["Struct"]

class Struct(object):
"""!A struct to which you can add any fields

Intended to be used for the return value from Task.run and other Task methods,
and useful for any method that returns multiple values.

Expand Down Expand Up @@ -57,7 +57,7 @@ def __init__(self, **keyArgs):
object.__init__(self)
for name, val in keyArgs.iteritems():
self.__safeAdd(name, val)

def __safeAdd(self, name, val):
"""!Add a field if it does not already exist and name does not start with __ (two underscores)

Expand All @@ -74,7 +74,7 @@ def __safeAdd(self, name, val):

def getDict(self):
"""!Return a dictionary of attribute name: value

@warning: the values are shallow copies.
"""
return self.__dict__.copy()
Expand All @@ -84,7 +84,7 @@ def mergeItems(self, struct, *nameList):

@param[in] struct struct from which to copy
@param[in] *nameList all remaining arguments are names of items to copy

For example: foo.copyItems(other, "itemName1", "itemName2")
copies other.itemName1 and other.itemName2 into self.

Expand All @@ -93,18 +93,18 @@ def mergeItems(self, struct, *nameList):
"""
for name in nameList:
self.__safeAdd(name, getattr(struct, name))

def copy(self):
"""!Return a one-level-deep copy (values are not copied)
"""
return Struct(**self.getDict())

def __eq__(self, other):
return self.__dict__ == other.__dict__

def __len__(self):
return len(self.__dict__)

def __repr__(self):
itemList = ["%s=%r" % (name, val) for name, val in self.getDict().iteritems()]
return "%s(%s)" % (self.__class__.__name__, "; ".join(itemList))