Coverage for python/lsst/ctrl/mpexec/util.py: 11%
52 statements
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-05 18:04 -0800
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-05 18:04 -0800
1# This file is part of ctrl_mpexec.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
22"""Few utility methods used by the rest of a package.
23"""
25__all__ = ["profile", "printTable", "filterTasks", "subTaskIter"]
27# -------------------------------
28# Imports of standard modules --
29# -------------------------------
30import contextlib
32# -----------------------------
33# Imports for other modules --
34# -----------------------------
35import lsst.pex.config as pexConfig
37# ----------------------------------
38# Local non-exported definitions --
39# ----------------------------------
41# ------------------------
42# Exported definitions --
43# ------------------------
46@contextlib.contextmanager
47def profile(filename, log=None):
48 """Context manager for profiling with cProfile
50 Parameters
51 ----------
52 filename :
53 Filename to which to write profile (profiling disabled if `None`
54 or empty).
55 log :
56 Log object for logging the profile operations.
58 Yields
59 ------
60 profile : `cProfile.Profile` or `None`
61 If profiling is enabled, the context manager returns the
62 `cProfile.Profile` object (otherwise it returns `None`)
64 Notes
65 -----
66 The returned profile object allows additional control
67 over profiling. You can obtain this using the ``as`` clause, e.g.:
69 .. code-block:: py
71 with profile(filename) as prof:
72 runYourCodeHere()
74 The output cumulative profile can be printed with a command-line like:
76 .. code-block:: bash
78 python -c 'import pstats; pstats.Stats("<filename>").\
79 sort_stats("cumtime").print_stats(30)'
80 """
81 if not filename:
82 # Nothing to do
83 yield
84 return
85 from cProfile import Profile
87 prof = Profile()
88 if log is not None:
89 log.info("Enabling cProfile profiling")
90 prof.enable()
91 yield prof
92 prof.disable()
93 prof.dump_stats(filename)
94 if log is not None:
95 log.info("cProfile stats written to %s" % filename)
98def printTable(rows, header):
99 """Nice formatting of 2-column table.
101 Parameters
102 ----------
103 rows : `list` of `tuple`
104 Each item in the list is a 2-tuple containg left and righ column values
105 header: `tuple` or `None`
106 If `None` then table header are not prined, otherwise it's a 2-tuple
107 with column headings.
108 """
109 if not rows:
110 return
111 width = max(len(x[0]) for x in rows)
112 if header:
113 width = max(width, len(header[0]))
114 print(header[0].ljust(width), header[1])
115 print("".ljust(width, "-"), "".ljust(len(header[1]), "-"))
116 for col1, col2 in rows:
117 print(col1.ljust(width), col2)
120def filterTasks(pipeline, name):
121 """Finds list of tasks matching given name.
123 For matching task either task label or task name after last dot should
124 be identical to `name`. If task label is non-empty then task name is not
125 checked.
127 Parameters
128 ----------
129 pipeline : `Pipeline`
130 name : str or none
131 If empty or None then all tasks are returned
133 Returns
134 -------
135 Lsit of `TaskDef` instances.
136 """
137 if not name:
138 return list(pipeline.toExpandedPipeline())
139 tasks = []
140 for taskDef in pipeline.toExpandedPipeline():
141 if taskDef.label:
142 if taskDef.label == name:
143 tasks.append(taskDef)
144 elif taskDef.taskName.split('.')[-1] == name:
145 tasks.append(taskDef)
146 return tasks
149def subTaskIter(config):
150 """Recursively generates subtask names.
152 Parameters
153 ----------
154 config : `lsst.pex.config.Config`
155 Configuration of the task
157 Returns
158 -------
159 Iterator which returns tuples of (configFieldPath, taskName).
160 """
161 for fieldName, field in sorted(config.items()):
162 if hasattr(field, "value") and hasattr(field, "target"):
163 subConfig = field.value
164 if isinstance(subConfig, pexConfig.Config):
165 try:
166 taskName = "%s.%s" % (field.target.__module__, field.target.__name__)
167 except Exception:
168 taskName = repr(field.target)
169 yield fieldName, taskName
170 for subFieldName, taskName in subTaskIter(subConfig):
171 yield fieldName + '.' + subFieldName, taskName