Note
Go to the end to download the full example code.
Creating command-line Tools#
7 from time import sleep
8
9 from ctapipe.core import Component, TelescopeComponent, Tool
10 from ctapipe.core.traits import (
11 FloatTelescopeParameter,
12 Integer,
13 Path,
14 TraitError,
15 observe,
16 )
17 from ctapipe.instrument import SubarrayDescription
18 from ctapipe.utils import get_dataset_path
21 GAMMA_FILE = get_dataset_path("gamma_prod5.simtel.zst")
Setup:#
Create a few Components that we will use later in a Tool:
37 class MyComponent(Component):
38 """A Component that does stuff"""
39
40 value = Integer(default_value=-1, help="Value to use").tag(config=True)
41
42 def do_thing(self):
43 self.log.debug("Did thing")
44
45
46 # in order to have 2 of the same components at once
47 class SecondaryMyComponent(MyComponent):
48 """A second component"""
49
50
51 class AdvancedComponent(Component):
52 """An advanced technique"""
53
54 value1 = Integer(default_value=-1, help="Value to use").tag(config=True)
55 infile = Path(
56 help="input file name",
57 exists=None, # set to True to require existing, False for requiring non-existing
58 directory_ok=False,
59 ).tag(config=True)
60 outfile = Path(help="output file name", exists=False, directory_ok=False).tag(
61 config=True
62 )
63
64 def __init__(self, config=None, parent=None, **kwargs):
65 super().__init__(config=config, parent=parent, **kwargs)
66 # components can have sub components, but these must have
67 # then parent=self as argument and be assigned as member
68 # so the full config can be received later
69 self.subcompent = MyComponent(parent=self)
70
71 @observe("outfile")
72 def on_outfile_changed(self, change):
73 self.log.warning("Outfile was changed to '{}'".format(change))
74
75
76 class TelescopeWiseComponent(TelescopeComponent):
77 """a component that contains parameters that are per-telescope configurable"""
78
79 param = FloatTelescopeParameter(
80 help="Something configurable with telescope patterns", default_value=5.0
81 ).tag(config=True)
85 MyComponent()
88 AdvancedComponent(infile="test.foo", outfile="out.foo")
Outfile was changed to '{'name': 'outfile', 'old': None, 'new': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/out.foo'), 'owner': <__main__.AdvancedComponent object at 0x79f08c4b6ef0>, 'type': 'change'}'
TelescopeComponents need to have a subarray given to them in order
to work (since they need one to turn a TelescopeParameter into a
concrete list of values for each telescope. Here we will give a dummy
one:
99 subarray = SubarrayDescription.read(GAMMA_FILE)
100 subarray.info()
Subarray : MonteCarloArray
Num Tels : 180
Footprint: 4.92 km2
Height : 2147.00 m
Lon/Lat : 0.0 deg, 0.0 deg
Type Count Tel IDs
----------------- ----- ---------------
SST_ASTRI_CHEC 120 30-99,131-180
LST_LST_LSTCam 4 1-4
MST_MST_NectarCam 28 100-124,128-130
MST_MST_FlashCam 28 5-29,125-127
This TelescopeParameters can then be set using a list of patterns like:
component.param = [(“type”, “LST*”,3.0),(“type”, “MST*”, 2.0),(id, 25, 4.0)]
These get translated into per-telescope-id values once the subarray is registered. After that one access the per-telescope id values via:
component.param.tel[tel_id]
Now create an executable Tool that contains the Components#
Note that all the components we wish to be configured via the tool must
be added to the classes attribute.
129 class MyTool(Tool):
130 name = "mytool"
131 description = "do some things and stuff"
132 aliases = dict(
133 infile="AdvancedComponent.infile",
134 outfile="AdvancedComponent.outfile",
135 iterations="MyTool.iterations",
136 )
137
138 # Which classes are registered for configuration
139 classes = [
140 MyComponent,
141 AdvancedComponent,
142 SecondaryMyComponent,
143 TelescopeWiseComponent,
144 ]
145
146 # local configuration parameters
147 iterations = Integer(5, help="Number of times to run", allow_none=False).tag(
148 config=True
149 )
150
151 def setup(self):
152 self.comp = MyComponent(parent=self)
153 self.comp2 = SecondaryMyComponent(parent=self)
154 self.comp3 = TelescopeWiseComponent(parent=self, subarray=subarray)
155 self.advanced = AdvancedComponent(parent=self)
156
157 def start(self):
158 self.log.info("Performing {} iterations...".format(self.iterations))
159 for ii in range(self.iterations):
160 self.log.info("ITERATION {}".format(ii))
161 self.comp.do_thing()
162 self.comp2.do_thing()
163 sleep(0.1)
164
165 def finish(self):
166 self.log.warning("Shutting down.")
Get Help info#
The following allows you to print the help info within a Jupyter notebook, but this same information would be displayed if the user types:
mytool --help
182 tool = MyTool()
183 tool
186 tool.print_help()
do some things and stuff
Options
=======
The options below are convenience aliases to configurable class-options,
as listed in the "Equivalent to" description-line of the aliases.
To see all configurable class-options for some <cmd>, use:
<cmd> --help-all
--debug
Set log-level to debug, for the most verbose logging.
Equivalent to: [--Application.log_level=10]
--show-config
Show the application's configuration (human-readable format)
Equivalent to: [--Application.show_config=True]
--show-config-json
Show the application's configuration (json format)
Equivalent to: [--Application.show_config_json=True]
-q, --quiet
Disable console logging.
Equivalent to: [--Tool.quiet=True]
-v, --verbose
Set log level to DEBUG
Equivalent to: [--Tool.log_level=DEBUG]
--overwrite
Overwrite existing output files without asking
Equivalent to: [--Tool.overwrite=True]
-c, --config=<list-item-1>...
List of configuration files with parameters to load in addition to command-
line parameters. The order listed is the order of precedence (later config
parameters overwrite earlier ones), however parameters specified on the
command line always have the highest precedence. Config files may be in
JSON, YAML, TOML, or Python format
Default: []
Equivalent to: [--Tool.config_files]
--log-level=<Enum>
Set the log level by value or name.
Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
Default: 30
Equivalent to: [--Tool.log_level]
-l, --log-file=<Path>
Filename for the log
Default: None
Equivalent to: [--Tool.log_file]
--log-file-level=<Enum>
Logging Level for File Logging
Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
Default: 'INFO'
Equivalent to: [--Tool.log_file_level]
--provenance-log=<Path>
Default: None
Equivalent to: [--Tool.provenance_log]
--infile=<Path>
input file name
Default: None
Equivalent to: [--AdvancedComponent.infile]
--outfile=<Path>
output file name
Default: None
Equivalent to: [--AdvancedComponent.outfile]
--iterations=<Long>
Number of times to run
Default: 5
Equivalent to: [--MyTool.iterations]
To see all available configurables, use `--help-all`.
The following is equivalent to the user typing mytool --help-all
193 tool.print_help(classes=True)
do some things and stuff
Options
=======
The options below are convenience aliases to configurable class-options,
as listed in the "Equivalent to" description-line of the aliases.
To see all configurable class-options for some <cmd>, use:
<cmd> --help-all
--debug
Set log-level to debug, for the most verbose logging.
Equivalent to: [--Application.log_level=10]
--show-config
Show the application's configuration (human-readable format)
Equivalent to: [--Application.show_config=True]
--show-config-json
Show the application's configuration (json format)
Equivalent to: [--Application.show_config_json=True]
-q, --quiet
Disable console logging.
Equivalent to: [--Tool.quiet=True]
-v, --verbose
Set log level to DEBUG
Equivalent to: [--Tool.log_level=DEBUG]
--overwrite
Overwrite existing output files without asking
Equivalent to: [--Tool.overwrite=True]
-c, --config=<list-item-1>...
List of configuration files with parameters to load in addition to command-
line parameters. The order listed is the order of precedence (later config
parameters overwrite earlier ones), however parameters specified on the
command line always have the highest precedence. Config files may be in
JSON, YAML, TOML, or Python format
Default: []
Equivalent to: [--Tool.config_files]
--log-level=<Enum>
Set the log level by value or name.
Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
Default: 30
Equivalent to: [--Tool.log_level]
-l, --log-file=<Path>
Filename for the log
Default: None
Equivalent to: [--Tool.log_file]
--log-file-level=<Enum>
Logging Level for File Logging
Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
Default: 'INFO'
Equivalent to: [--Tool.log_file_level]
--provenance-log=<Path>
Default: None
Equivalent to: [--Tool.provenance_log]
--infile=<Path>
input file name
Default: None
Equivalent to: [--AdvancedComponent.infile]
--outfile=<Path>
output file name
Default: None
Equivalent to: [--AdvancedComponent.outfile]
--iterations=<Long>
Number of times to run
Default: 5
Equivalent to: [--MyTool.iterations]
Class options
=============
The command-line option below sets the respective configurable class-parameter:
--Class.parameter=value
This line is evaluated in Python, so simple expressions are allowed.
For instance, to set `C.a=[0,1,2]`, you may type this:
--C.a='range(3)'
Application(SingletonConfigurable) options
------------------------------------------
--Application.log_datefmt=<Unicode>
The date format used by logging formatters for %(asctime)s
Default: '%Y-%m-%d %H:%M:%S'
--Application.log_format=<Unicode>
The Logging format template
Default: '[%(name)s]%(highlevel)s %(message)s'
--Application.log_level=<Enum>
Set the log level by value or name.
Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
Default: 30
--Application.logging_config=<key-1>=<value-1>...
Configure additional log handlers.
The default stderr logs handler is configured by the log_level, log_datefmt
and log_format settings.
This configuration can be used to configure additional handlers (e.g. to
output the log to a file) or for finer control over the default handlers.
If provided this should be a logging configuration dictionary, for more
information see:
https://docs.python.org/3/library/logging.config.html#logging-config-
dictschema
This dictionary is merged with the base logging configuration which defines
the following:
* A logging formatter intended for interactive use called
``console``.
* A logging handler that writes to stderr called
``console`` which uses the formatter ``console``.
* A logger with the name of this application set to ``DEBUG``
level.
This example adds a new handler that writes to a file:
.. code-block:: python
c.Application.logging_config = {
"handlers": {
"file": {
"class": "logging.FileHandler",
"level": "DEBUG",
"filename": "<path/to/file>",
}
},
"loggers": {
"<application-name>": {
"level": "DEBUG",
# NOTE: if you don't list the default "console"
# handler here then it will be disabled
"handlers": ["console", "file"],
},
},
}
Default: {}
--Application.show_config=<Bool>
Instead of starting the Application, dump configuration to stdout
Default: False
--Application.show_config_json=<Bool>
Instead of starting the Application, dump configuration to stdout (as JSON)
Default: False
Tool(Application) options
-------------------------
--Tool.config_files=<list-item-1>...
List of configuration files with parameters to load in addition to command-
line parameters. The order listed is the order of precedence (later config
parameters overwrite earlier ones), however parameters specified on the
command line always have the highest precedence. Config files may be in
JSON, YAML, TOML, or Python format
Default: []
--Tool.log_config=<key-1>=<value-1>...
Default: {}
--Tool.log_datefmt=<Unicode>
The date format used by logging formatters for %(asctime)s
Default: '%Y-%m-%d %H:%M:%S'
--Tool.log_file=<Path>
Filename for the log
Default: None
--Tool.log_file_level=<Enum>
Logging Level for File Logging
Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
Default: 'INFO'
--Tool.log_format=<Unicode>
The Logging format template
Default: '[%(name)s]%(highlevel)s %(message)s'
--Tool.log_level=<Enum>
Set the log level by value or name.
Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
Default: 30
--Tool.logging_config=<key-1>=<value-1>...
Configure additional log handlers.
The default stderr logs handler is configured by the log_level, log_datefmt
and log_format settings.
This configuration can be used to configure additional handlers (e.g. to
output the log to a file) or for finer control over the default handlers.
If provided this should be a logging configuration dictionary, for more
information see:
https://docs.python.org/3/library/logging.config.html#logging-config-
dictschema
This dictionary is merged with the base logging configuration which defines
the following:
* A logging formatter intended for interactive use called
``console``.
* A logging handler that writes to stderr called
``console`` which uses the formatter ``console``.
* A logger with the name of this application set to ``DEBUG``
level.
This example adds a new handler that writes to a file:
.. code-block:: python
c.Application.logging_config = {
"handlers": {
"file": {
"class": "logging.FileHandler",
"level": "DEBUG",
"filename": "<path/to/file>",
}
},
"loggers": {
"<application-name>": {
"level": "DEBUG",
# NOTE: if you don't list the default "console"
# handler here then it will be disabled
"handlers": ["console", "file"],
},
},
}
Default: {}
--Tool.overwrite=<Bool>
Default: False
--Tool.provenance_log=<Path>
Default: None
--Tool.quiet=<Bool>
Default: False
--Tool.show_config=<Bool>
Instead of starting the Application, dump configuration to stdout
Default: False
--Tool.show_config_json=<Bool>
Instead of starting the Application, dump configuration to stdout (as JSON)
Default: False
MyTool(Tool) options
--------------------
--MyTool.config_files=<list-item-1>...
List of configuration files with parameters to load in addition to command-
line parameters. The order listed is the order of precedence (later config
parameters overwrite earlier ones), however parameters specified on the
command line always have the highest precedence. Config files may be in
JSON, YAML, TOML, or Python format
Default: []
--MyTool.iterations=<Long>
Number of times to run
Default: 5
--MyTool.log_config=<key-1>=<value-1>...
Default: {}
--MyTool.log_datefmt=<Unicode>
The date format used by logging formatters for %(asctime)s
Default: '%Y-%m-%d %H:%M:%S'
--MyTool.log_file=<Path>
Filename for the log
Default: None
--MyTool.log_file_level=<Enum>
Logging Level for File Logging
Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
Default: 'INFO'
--MyTool.log_format=<Unicode>
The Logging format template
Default: '[%(name)s]%(highlevel)s %(message)s'
--MyTool.log_level=<Enum>
Set the log level by value or name.
Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
Default: 30
--MyTool.logging_config=<key-1>=<value-1>...
Configure additional log handlers.
The default stderr logs handler is configured by the log_level, log_datefmt
and log_format settings.
This configuration can be used to configure additional handlers (e.g. to
output the log to a file) or for finer control over the default handlers.
If provided this should be a logging configuration dictionary, for more
information see:
https://docs.python.org/3/library/logging.config.html#logging-config-
dictschema
This dictionary is merged with the base logging configuration which defines
the following:
* A logging formatter intended for interactive use called
``console``.
* A logging handler that writes to stderr called
``console`` which uses the formatter ``console``.
* A logger with the name of this application set to ``DEBUG``
level.
This example adds a new handler that writes to a file:
.. code-block:: python
c.Application.logging_config = {
"handlers": {
"file": {
"class": "logging.FileHandler",
"level": "DEBUG",
"filename": "<path/to/file>",
}
},
"loggers": {
"<application-name>": {
"level": "DEBUG",
# NOTE: if you don't list the default "console"
# handler here then it will be disabled
"handlers": ["console", "file"],
},
},
}
Default: {}
--MyTool.overwrite=<Bool>
Default: False
--MyTool.provenance_log=<Path>
Default: None
--MyTool.quiet=<Bool>
Default: False
--MyTool.show_config=<Bool>
Instead of starting the Application, dump configuration to stdout
Default: False
--MyTool.show_config_json=<Bool>
Instead of starting the Application, dump configuration to stdout (as JSON)
Default: False
MyComponent(Component) options
------------------------------
--MyComponent.value=<Long>
Value to use
Default: -1
AdvancedComponent(Component) options
------------------------------------
--AdvancedComponent.infile=<Path>
input file name
Default: None
--AdvancedComponent.outfile=<Path>
output file name
Default: None
--AdvancedComponent.value1=<Long>
Value to use
Default: -1
SecondaryMyComponent(MyComponent) options
-----------------------------------------
--SecondaryMyComponent.value=<Long>
Value to use
Default: -1
TelescopeWiseComponent(TelescopeComponent) options
--------------------------------------------------
--TelescopeWiseComponent.param=<floattelescopeparameter-item-1>...
Something configurable with telescope patterns.
Default: [('type', '*', 5.0)]
Run the tool#
here we pass in argv since it is a Notebook, but if argv is not
specified it’s read from sys.argv, so the following is the same as
running:
mytool –log_level=INFO –infile gamma_test.simtel.gz –iterations=3
As Tools are intended to be executables, they are raising
SystemExit on exit. Here, we use them to demonstrate how it would
work, so we catch the SystemExit.
212 try:
213 tool.run(argv=["--infile", str(GAMMA_FILE), "--outfile", "out.csv"])
214 except SystemExit as e:
215 assert e.code == 0, f"Tool returned with error status {e}"
216
217 tool.log_format = "%(asctime)s : %(levelname)s [%(name)s %(funcName)s] %(message)s"
2025-10-23 07:32:38,181 WARNING [__main__.mytool.AdvancedComponent] (command_line_tools.on_outfile_changed): Outfile was changed to '{'name': 'outfile', 'old': None, 'new': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/out.csv'), 'owner': <__main__.AdvancedComponent object at 0x79f08c4b5ed0>, 'type': 'change'}'
2025-10-23 07:32:38,683 WARNING [__main__.mytool] (command_line_tools.finish): Shutting down.
221 try:
222 tool.run(
223 argv=[
224 "--log-level",
225 "INFO",
226 "--infile",
227 str(GAMMA_FILE),
228 "--outfile",
229 "out.csv",
230 "--iterations",
231 "3",
232 ]
233 )
234 except SystemExit as e:
235 assert e.code == 0, f"Tool returned with error status {e}"
2025-10-23 07:32:38,879 INFO [__main__.mytool] (tool.initialize): Loading config from '[]'
2025-10-23 07:32:38,881 INFO [__main__.mytool] (tool.initialize): ctapipe version 0.27.1.dev15+g1af6977ab
2025-10-23 07:32:38,883 WARNING [__main__.mytool.AdvancedComponent] (command_line_tools.on_outfile_changed): Outfile was changed to '{'name': 'outfile', 'old': None, 'new': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/out.csv'), 'owner': <__main__.AdvancedComponent object at 0x79f08c4b7970>, 'type': 'change'}'
2025-10-23 07:32:38,883 INFO [__main__.mytool] (command_line_tools.start): Performing 3 iterations...
2025-10-23 07:32:38,883 INFO [__main__.mytool] (command_line_tools.start): ITERATION 0
2025-10-23 07:32:38,983 INFO [__main__.mytool] (command_line_tools.start): ITERATION 1
2025-10-23 07:32:39,084 INFO [__main__.mytool] (command_line_tools.start): ITERATION 2
2025-10-23 07:32:39,184 WARNING [__main__.mytool] (command_line_tools.finish): Shutting down.
2025-10-23 07:32:39,185 INFO [__main__.mytool] (tool.write_provenance): Output:
2025-10-23 07:32:39,185 INFO [__main__.mytool] (tool.write_provenance): Output:
2025-10-23 07:32:39,188 INFO [__main__.mytool] (tool.run): Finished mytool
here we change the log-level to DEBUG:
242 try:
243 tool.run(
244 argv=[
245 "--log-level",
246 "DEBUG",
247 "--infile",
248 str(GAMMA_FILE),
249 "--outfile",
250 "out.csv",
251 ]
252 )
253 except SystemExit as e:
254 assert e.code == 0, f"Tool returned with error status {e}"
2025-10-23 07:32:39,188 INFO [__main__.mytool] (tool.run): Starting: mytool
2025-10-23 07:32:39,382 INFO [__main__.mytool] (tool.initialize): Loading config from '[]'
2025-10-23 07:32:39,384 INFO [__main__.mytool] (tool.initialize): ctapipe version 0.27.1.dev15+g1af6977ab
2025-10-23 07:32:39,385 WARNING [__main__.mytool.AdvancedComponent] (command_line_tools.on_outfile_changed): Outfile was changed to '{'name': 'outfile', 'old': None, 'new': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/out.csv'), 'owner': <__main__.AdvancedComponent object at 0x79f08c4b78e0>, 'type': 'change'}'
2025-10-23 07:32:39,386 DEBUG [__main__.mytool] (tool.run): CONFIG: {'MyTool': {'config_files': [], 'iterations': 3, 'log_config': {}, 'log_datefmt': '%Y-%m-%d %H:%M:%S', 'log_file': None, 'log_file_level': 'INFO', 'log_format': '%(asctime)s : %(levelname)s [%(name)s %(funcName)s] %(message)s', 'log_level': 10, 'logging_config': {}, 'overwrite': False, 'provenance_log': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/docs/mytool.provenance.log'), 'quiet': False, 'show_config': False, 'show_config_json': False, 'MyComponent': {'value': -1}, 'SecondaryMyComponent': {'value': -1}, 'TelescopeWiseComponent': {'param': [('type', '*', 5.0)]}, 'AdvancedComponent': {'infile': PosixPath('/home/docs/.cache/ctapipe/minio-cta.zeuthen.desy.de/dpps-testdata-public/data/ctapipe-test-data/v1.1.0/gamma_prod5.simtel.zst'), 'outfile': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/out.csv'), 'value1': -1, 'MyComponent': {'value': -1}}}}
2025-10-23 07:32:39,386 INFO [__main__.mytool] (command_line_tools.start): Performing 3 iterations...
2025-10-23 07:32:39,386 INFO [__main__.mytool] (command_line_tools.start): ITERATION 0
2025-10-23 07:32:39,386 DEBUG [__main__.mytool.MyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:39,386 DEBUG [__main__.mytool.SecondaryMyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:39,486 INFO [__main__.mytool] (command_line_tools.start): ITERATION 1
2025-10-23 07:32:39,486 DEBUG [__main__.mytool.MyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:39,486 DEBUG [__main__.mytool.SecondaryMyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:39,587 INFO [__main__.mytool] (command_line_tools.start): ITERATION 2
2025-10-23 07:32:39,587 DEBUG [__main__.mytool.MyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:39,587 DEBUG [__main__.mytool.SecondaryMyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:39,687 WARNING [__main__.mytool] (command_line_tools.finish): Shutting down.
2025-10-23 07:32:39,688 INFO [__main__.mytool] (tool.write_provenance): Output:
2025-10-23 07:32:39,688 INFO [__main__.mytool] (tool.write_provenance): Output:
2025-10-23 07:32:39,688 INFO [__main__.mytool] (tool.write_provenance): Output:
2025-10-23 07:32:39,688 DEBUG [__main__.mytool] (tool.write_provenance): PROVENANCE: 'Details about provenance is found in /home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/docs/mytool.provenance.log'
2025-10-23 07:32:39,692 INFO [__main__.mytool] (tool.run): Finished mytool
2025-10-23 07:32:39,692 DEBUG [__main__.mytool] (application.exit): Exiting application: mytool
you can also set parameters directly in the class, rather than using the argument/configfile parser. This is useful if you are calling the Tool from a script rather than the command-line
263 tool.iterations = 1
264 tool.log_level = 0
265
266 try:
267 tool.run(["--infile", str(GAMMA_FILE), "--outfile", "out.csv"])
268 except SystemExit as e:
269 assert e.code == 0, f"Tool returned with error status {e}"
2025-10-23 07:32:39,693 INFO [__main__.mytool] (tool.run): Starting: mytool
2025-10-23 07:32:39,889 WARNING [__main__.mytool.AdvancedComponent] (command_line_tools.on_outfile_changed): Outfile was changed to '{'name': 'outfile', 'old': None, 'new': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/out.csv'), 'owner': <__main__.AdvancedComponent object at 0x79f09fae65f0>, 'type': 'change'}'
2025-10-23 07:32:39,989 WARNING [__main__.mytool] (command_line_tools.finish): Shutting down.
see what happens when a value is set that is not of the correct type:
276 try:
277 tool.iterations = "badval"
278 except TraitError as E:
279 print("bad value:", E)
280 except SystemExit as e:
281 assert e.code == 0, f"Tool returned with error status {e}"
bad value: The 'iterations' trait of a MyTool instance expected an int, not the str 'badval'.
Example of what happens when you change a parameter that is being “observed” in a class. It’s handler is called:
289 tool.advanced.outfile = "Another.txt"
2025-10-23 07:32:39,995 WARNING [__main__.mytool.AdvancedComponent] (command_line_tools.on_outfile_changed): Outfile was changed to '{'name': 'outfile', 'old': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/out.csv'), 'new': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/Another.txt'), 'owner': <__main__.AdvancedComponent object at 0x79f09fae65f0>, 'type': 'change'}'
we see that the handler for outfile was called, and it receive a
change dict that shows the old and new values.
create a tool using a config file:
302 tool2 = MyTool()
305 try:
306 tool2.run(argv=["--config", "config.json"])
307 except SystemExit as e:
308 assert e.code == 0, f"Tool returned with error status {e}"
2025-10-23 07:32:40,192 INFO [__main__.mytool] (tool.initialize): ctapipe version 0.27.1.dev15+g1af6977ab
2025-10-23 07:32:40,194 WARNING [__main__.mytool.AdvancedComponent] (command_line_tools.on_outfile_changed): Outfile was changed to '{'name': 'outfile', 'old': None, 'new': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/foo.txt'), 'owner': <__main__.AdvancedComponent object at 0x79f08ae15d20>, 'type': 'change'}'
2025-10-23 07:32:40,194 DEBUG [__main__.mytool] (tool.run): CONFIG: {'MyTool': {'config_files': [PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/config.json')], 'iterations': 5, 'log_config': {}, 'log_datefmt': '%Y-%m-%d %H:%M:%S', 'log_file': None, 'log_file_level': 'INFO', 'log_format': '[%(name)s]%(highlevel)s %(message)s', 'log_level': 10, 'logging_config': {}, 'overwrite': False, 'provenance_log': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/mytool.provenance.log'), 'quiet': False, 'show_config': False, 'show_config_json': False, 'MyComponent': {'value': -1}, 'SecondaryMyComponent': {'value': -1}, 'TelescopeWiseComponent': {'param': [('type', '*', 5.0)]}, 'AdvancedComponent': {'infile': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/something.txt'), 'outfile': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/foo.txt'), 'value1': -1, 'MyComponent': {'value': -1}}}}
2025-10-23 07:32:40,194 INFO [__main__.mytool] (command_line_tools.start): Performing 5 iterations...
2025-10-23 07:32:40,194 INFO [__main__.mytool] (command_line_tools.start): ITERATION 0
2025-10-23 07:32:40,194 DEBUG [__main__.mytool.MyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:40,194 DEBUG [__main__.mytool.SecondaryMyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:40,295 INFO [__main__.mytool] (command_line_tools.start): ITERATION 1
2025-10-23 07:32:40,295 DEBUG [__main__.mytool.MyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:40,295 DEBUG [__main__.mytool.SecondaryMyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:40,395 INFO [__main__.mytool] (command_line_tools.start): ITERATION 2
2025-10-23 07:32:40,395 DEBUG [__main__.mytool.MyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:40,395 DEBUG [__main__.mytool.SecondaryMyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:40,495 INFO [__main__.mytool] (command_line_tools.start): ITERATION 3
2025-10-23 07:32:40,496 DEBUG [__main__.mytool.MyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:40,496 DEBUG [__main__.mytool.SecondaryMyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:40,596 INFO [__main__.mytool] (command_line_tools.start): ITERATION 4
2025-10-23 07:32:40,596 DEBUG [__main__.mytool.MyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:40,596 DEBUG [__main__.mytool.SecondaryMyComponent] (command_line_tools.do_thing): Did thing
2025-10-23 07:32:40,696 WARNING [__main__.mytool] (command_line_tools.finish): Shutting down.
2025-10-23 07:32:40,698 INFO [__main__.mytool] (tool.write_provenance): Output:
2025-10-23 07:32:40,698 INFO [__main__.mytool] (tool.write_provenance): Output:
2025-10-23 07:32:40,698 INFO [__main__.mytool] (tool.write_provenance): Output:
2025-10-23 07:32:40,698 INFO [__main__.mytool] (tool.write_provenance): Output:
2025-10-23 07:32:40,698 INFO [__main__.mytool] (tool.write_provenance): Output:
2025-10-23 07:32:40,698 DEBUG [__main__.mytool] (tool.write_provenance): PROVENANCE: 'Details about provenance is found in /home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/mytool.provenance.log'
2025-10-23 07:32:40,703 INFO [__main__.mytool] (tool.run): Finished mytool
2025-10-23 07:32:40,703 DEBUG [__main__.mytool] (application.exit): Exiting application: mytool
311 print(tool2.advanced.infile)
/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/something.txt
314 print(tool2.config)
{'MyTool': {'config_files': ['config.json'], 'log_level': 'DEBUG'}, 'AdvancedComponent': {'infile': 'something.txt', 'outfile': 'foo.txt'}}
317 tool2.is_setup
True
320 tool3 = MyTool()
323 tool3.is_setup
False
326 tool3.initialize(argv=[])
329 tool3.is_setup
False
332 tool3
335 tool.setup()
336 tool
2025-10-23 07:32:40,713 WARNING [__main__.mytool.AdvancedComponent] (command_line_tools.on_outfile_changed): Outfile was changed to '{'name': 'outfile', 'old': None, 'new': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/out.csv'), 'owner': <__main__.AdvancedComponent object at 0x79f09fae5f00>, 'type': 'change'}'
339 tool.comp2
Getting the configuration of an instance#
347 tool.get_current_config()
{'MyTool': {'config_files': [], 'iterations': 1, 'log_config': {}, 'log_datefmt': '%Y-%m-%d %H:%M:%S', 'log_file': None, 'log_file_level': 'INFO', 'log_format': '%(asctime)s : %(levelname)s [%(name)s %(funcName)s] %(message)s', 'log_level': 0, 'logging_config': {}, 'overwrite': False, 'provenance_log': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/docs/mytool.provenance.log'), 'quiet': False, 'show_config': False, 'show_config_json': False, 'MyComponent': {'value': -1}, 'SecondaryMyComponent': {'value': -1}, 'TelescopeWiseComponent': {'param': [('type', '*', 5.0)]}, 'AdvancedComponent': {'infile': PosixPath('/home/docs/.cache/ctapipe/minio-cta.zeuthen.desy.de/dpps-testdata-public/data/ctapipe-test-data/v1.1.0/gamma_prod5.simtel.zst'), 'outfile': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/out.csv'), 'value1': -1, 'MyComponent': {'value': -1}}}}
350 tool.iterations = 12
351 tool.get_current_config()
{'MyTool': {'config_files': [], 'iterations': 12, 'log_config': {}, 'log_datefmt': '%Y-%m-%d %H:%M:%S', 'log_file': None, 'log_file_level': 'INFO', 'log_format': '%(asctime)s : %(levelname)s [%(name)s %(funcName)s] %(message)s', 'log_level': 0, 'logging_config': {}, 'overwrite': False, 'provenance_log': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/docs/mytool.provenance.log'), 'quiet': False, 'show_config': False, 'show_config_json': False, 'MyComponent': {'value': -1}, 'SecondaryMyComponent': {'value': -1}, 'TelescopeWiseComponent': {'param': [('type', '*', 5.0)]}, 'AdvancedComponent': {'infile': PosixPath('/home/docs/.cache/ctapipe/minio-cta.zeuthen.desy.de/dpps-testdata-public/data/ctapipe-test-data/v1.1.0/gamma_prod5.simtel.zst'), 'outfile': PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/ctapipe/checkouts/2868/examples/core/out.csv'), 'value1': -1, 'MyComponent': {'value': -1}}}}
Writing a Sample Config File#
359 print(tool.generate_config_file())
# Configuration file for mytool.
c = get_config() #noqa
#------------------------------------------------------------------------------
# Application(SingletonConfigurable) configuration
#------------------------------------------------------------------------------
## This is an application.
## The date format used by logging formatters for %(asctime)s
# Default: '%Y-%m-%d %H:%M:%S'
# c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S'
## The Logging format template
# Default: '[%(name)s]%(highlevel)s %(message)s'
# c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s'
## Set the log level by value or name.
# Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
# Default: 30
# c.Application.log_level = 30
## Configure additional log handlers.
#
# The default stderr logs handler is configured by the log_level, log_datefmt
# and log_format settings.
#
# This configuration can be used to configure additional handlers (e.g. to
# output the log to a file) or for finer control over the default handlers.
#
# If provided this should be a logging configuration dictionary, for more
# information see:
# https://docs.python.org/3/library/logging.config.html#logging-config-
# dictschema
#
# This dictionary is merged with the base logging configuration which defines
# the following:
#
# * A logging formatter intended for interactive use called
# ``console``.
# * A logging handler that writes to stderr called
# ``console`` which uses the formatter ``console``.
# * A logger with the name of this application set to ``DEBUG``
# level.
#
# This example adds a new handler that writes to a file:
#
# .. code-block:: python
#
# c.Application.logging_config = {
# "handlers": {
# "file": {
# "class": "logging.FileHandler",
# "level": "DEBUG",
# "filename": "<path/to/file>",
# }
# },
# "loggers": {
# "<application-name>": {
# "level": "DEBUG",
# # NOTE: if you don't list the default "console"
# # handler here then it will be disabled
# "handlers": ["console", "file"],
# },
# },
# }
# Default: {}
# c.Application.logging_config = {}
## Instead of starting the Application, dump configuration to stdout
# Default: False
# c.Application.show_config = False
## Instead of starting the Application, dump configuration to stdout (as JSON)
# Default: False
# c.Application.show_config_json = False
#------------------------------------------------------------------------------
# Tool(Application) configuration
#------------------------------------------------------------------------------
## This is an application.
## List of configuration files with parameters to load in addition to command-
# line parameters. The order listed is the order of precedence (later config
# parameters overwrite earlier ones), however parameters specified on the
# command line always have the highest precedence. Config files may be in JSON,
# YAML, TOML, or Python format
# Default: []
# c.Tool.config_files = []
# Default: {}
# c.Tool.log_config = {}
## The date format used by logging formatters for %(asctime)s
# See also: Application.log_datefmt
# c.Tool.log_datefmt = '%Y-%m-%d %H:%M:%S'
## Filename for the log
# Default: None
# c.Tool.log_file = None
## Logging Level for File Logging
# Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL']
# Default: 'INFO'
# c.Tool.log_file_level = 'INFO'
## The Logging format template
# See also: Application.log_format
# c.Tool.log_format = '[%(name)s]%(highlevel)s %(message)s'
## Set the log level by value or name.
# See also: Application.log_level
# c.Tool.log_level = 30
##
# See also: Application.logging_config
# c.Tool.logging_config = {}
# Default: False
# c.Tool.overwrite = False
# Default: None
# c.Tool.provenance_log = None
# Default: False
# c.Tool.quiet = False
## Instead of starting the Application, dump configuration to stdout
# See also: Application.show_config
# c.Tool.show_config = False
## Instead of starting the Application, dump configuration to stdout (as JSON)
# See also: Application.show_config_json
# c.Tool.show_config_json = False
#------------------------------------------------------------------------------
# MyTool(Tool) configuration
#------------------------------------------------------------------------------
## List of configuration files with parameters to load in addition to command-
# line parameters. The order listed is the order of precedence (later config
# parameters overwrite earlier ones), however parameters specified on the
# command line always have the highest precedence. Config files may be in JSON,
# YAML, TOML, or Python format
# See also: Tool.config_files
# c.MyTool.config_files = []
## Number of times to run
# Default: 5
# c.MyTool.iterations = 5
# See also: Tool.log_config
# c.MyTool.log_config = {}
## The date format used by logging formatters for %(asctime)s
# See also: Application.log_datefmt
# c.MyTool.log_datefmt = '%Y-%m-%d %H:%M:%S'
## Filename for the log
# See also: Tool.log_file
# c.MyTool.log_file = None
## Logging Level for File Logging
# See also: Tool.log_file_level
# c.MyTool.log_file_level = 'INFO'
## The Logging format template
# See also: Application.log_format
# c.MyTool.log_format = '[%(name)s]%(highlevel)s %(message)s'
## Set the log level by value or name.
# See also: Application.log_level
# c.MyTool.log_level = 30
##
# See also: Application.logging_config
# c.MyTool.logging_config = {}
# See also: Tool.overwrite
# c.MyTool.overwrite = False
# See also: Tool.provenance_log
# c.MyTool.provenance_log = None
# See also: Tool.quiet
# c.MyTool.quiet = False
## Instead of starting the Application, dump configuration to stdout
# See also: Application.show_config
# c.MyTool.show_config = False
## Instead of starting the Application, dump configuration to stdout (as JSON)
# See also: Application.show_config_json
# c.MyTool.show_config_json = False
#------------------------------------------------------------------------------
# MyComponent(Component) configuration
#------------------------------------------------------------------------------
## A Component that does stuff
## Value to use
# Default: -1
# c.MyComponent.value = -1
#------------------------------------------------------------------------------
# AdvancedComponent(Component) configuration
#------------------------------------------------------------------------------
## An advanced technique
## input file name
# Default: None
# c.AdvancedComponent.infile = None
## output file name
# Default: None
# c.AdvancedComponent.outfile = None
## Value to use
# Default: -1
# c.AdvancedComponent.value1 = -1
#------------------------------------------------------------------------------
# SecondaryMyComponent(MyComponent) configuration
#------------------------------------------------------------------------------
## A second component
## Value to use
# See also: MyComponent.value
# c.SecondaryMyComponent.value = -1
#------------------------------------------------------------------------------
# TelescopeWiseComponent(TelescopeComponent) configuration
#------------------------------------------------------------------------------
## a component that contains parameters that are per-telescope configurable
## Something configurable with telescope patterns.
# Default: [('type', '*', 5.0)]
# c.TelescopeWiseComponent.param = [('type', '*', 5.0)]
Total running time of the script: (0 minutes 3.766 seconds)