Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  master (f31105fd)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
collect_for_ctest Namespace Reference

Functions

def pytest_addoption (parser, pluginmanager)
 
def pytest_collectstart (collector)
 
def pytest_collection_modifyitems (session, config, items)
 
def pytest_collection_finish (session)
 
def pytest_configure (config)
 

Variables

 TEST_DESC_TEMPLATE
 

Function Documentation

◆ pytest_addoption()

def collect_for_ctest.pytest_addoption (   parser,
  pluginmanager 
)

Definition at line 24 of file collect_for_ctest.py.

24 def pytest_addoption(parser, pluginmanager):
25  parser.addoption(
26  "--ctest-output-file",
27  help="name of the file to write to communicate to ctest the discovered tests",
28  )
29  parser.addoption(
30  "--ctest-pytest-command",
31  default="pytest",
32  help="how pytest has to be invoked (e.g. using wrapper commands)",
33  )
34  parser.addoption(
35  "--ctest-pytest-root-dir",
36  default=Path.cwd(),
37  help="root directory to compute test names",
38  )
39  parser.addoption(
40  "--ctest-prefix",
41  default="",
42  help="string to prefix to the generated test names",
43  )
44  parser.addoption(
45  "--ctest-label",
46  default=["pytest"],
47  action="append",
48  help="labels to attach to the test (the label pytest is always added)",
49  )
50  parser.addoption(
51  "--ctest-properties",
52  default=[],
53  action="append",
54  help="test properties to set for all discovered tests",
55  )
56  parser.addoption(
57  "--ctest-binary-dir",
58  default=None,
59  help="value of CMAKE_CURRENT_BINARY_DIR from which gaudi_add_pytest was invoked",
60  )
61  parser.addoption(
62  "--ctest-coverage",
63  default="",
64  help="select modules for which produce coverage reports",
65  )
66  parser.addoption(
67  "--ctest-coverage-command",
68  default="coverage report",
69  help="how coverage should be invoked to produce the final report",
70  )
71 
72 

◆ pytest_collection_finish()

def collect_for_ctest.pytest_collection_finish (   session)

Definition at line 109 of file collect_for_ctest.py.

109 def pytest_collection_finish(session):
110  args = session.ctest_args
111  output_filename = args.get("output_file")
112 
113  if not output_filename:
114  # nothing to do if no output file is specified
115  return
116 
117  output = open(output_filename, "w")
118  output_rootdir = Path(output_filename).parent
119 
120  coverage = args["coverage"].split(",") if args["coverage"] else []
121  if coverage:
122  args["pytest_command"] += " --cov-report= --cov-reset " + " ".join(
123  f"--cov={module}" for module in coverage
124  )
125 
126  properties = 'LABELS "{}" '.format(";".join(args["label"]))
127  if args.get("binary_dir"):
128  properties += f'ENVIRONMENT "CMAKE_CURRENT_BINARY_DIR={args["binary_dir"]}" '
129  properties += " ".join(args["properties"])
130 
131  producers = defaultdict(list) # test name -> list of fixtures it produces
132  consumers = defaultdict(list) # test name -> list of fixtures it depends on
133  fixtures = defaultdict(list) # fixture name -> list of tests that produce it
134  names = []
135  for path in sorted(session.ctest_files):
136  name = os.path.relpath(path, args["pytest_root_dir"]).replace("/", ".")
137  if name.endswith(".py"):
138  name = name[:-3]
139  if name == ".":
140  # when we pass a single file to pytest, pytest_root_dir and path are the same
141  # and relpath returns ".", so we take the prefix and drop the final dot
142  # (see https://gitlab.cern.ch/gaudi/Gaudi/-/issues/354)
143  name = args["prefix"][:-1]
144  else:
145  name = args["prefix"] + name
146  pytest_cmd = args["pytest_command"]
147 
148  output.write(
149  TEST_DESC_TEMPLATE.format(
150  name=name,
151  path=path,
152  pytest_cmd=pytest_cmd,
153  properties=properties,
154  )
155  )
156 
157  if session.ctest_fixture_setup.get(path):
158  for fixture in session.ctest_fixture_setup[path]:
159  producers[name].append(fixture)
160  fixtures[fixture].append(name)
161 
162  if session.ctest_fixture_required.get(path):
163  for fixture in session.ctest_fixture_required[path]:
164  consumers[name].append(fixture)
165 
166  names.append(name)
167 
168  for name in names:
169  if name in producers:
170  output.write(
171  'set_tests_properties('
172  f'{name} PROPERTIES FIXTURES_SETUP "{";".join(producers[name])}")\n'
173  )
174 
175  if name in consumers:
176  producer_test_names = []
177  for fixture in consumers[name]:
178  producer_test_names.extend(fixtures[fixture])
179  output.write(
180  'if (DEFINED ENV{PYTEST_DISABLE_FIXTURES_REQUIRED})\n'
181  f' set_tests_properties({name} PROPERTIES DEPENDS "{";".join(producer_test_names)}")\n'
182  'else()\n'
183  f' set_tests_properties({name} PROPERTIES FIXTURES_REQUIRED "{";".join(consumers[name])}")\n'
184  'endif()\n'
185  )
186 
187  # we force one test to be run one by one
188  if coverage:
189  # generate one coverage file per test
190  output.write(
191  f"set_tests_properties({name} PROPERTIES ENVIRONMENT COVERAGE_FILE={output_rootdir}/.coverage.{name})\n"
192  f"set_tests_properties({name} PROPERTIES FIXTURES_SETUP {name})\n"
193  )
194 
195  if coverage and names:
196  combine_test = (args["prefix"] + "coverage_combine").replace("/", ".")
197  combine_command = re.sub(
198  r" report .*",
199  f" combine {' '.join(f'{output_rootdir}/.coverage.{n}' for n in names)}",
200  args["coverage_command"],
201  )
202  output.write(
203  TEST_DESC_TEMPLATE.format(
204  name=combine_test,
205  path="",
206  pytest_cmd=combine_command,
207  properties=properties,
208  )
209  )
210  output.write(
211  f"set_tests_properties({combine_test} PROPERTIES ENVIRONMENT COVERAGE_FILE={output_rootdir}/.coverage)\n"
212  f"set_tests_properties({combine_test} PROPERTIES FIXTURES_REQUIRED \"{';'.join(names)}\")\n"
213  f"set_tests_properties({combine_test} PROPERTIES FIXTURES_SETUP {combine_test})\n"
214  )
215 
216  name = (args["prefix"] + "coverage_report").replace("/", ".")
217  output.write(
218  TEST_DESC_TEMPLATE.format(
219  name=name,
220  path="",
221  pytest_cmd=f"{args['coverage_command']}",
222  properties=properties + " LABELS coverage",
223  )
224  )
225  # coverage reports require all related tests to be run first
226  output.write(
227  f"set_tests_properties({name} PROPERTIES ENVIRONMENT COVERAGE_FILE={output_rootdir}/.coverage)\n"
228  f"set_tests_properties({name} PROPERTIES FIXTURES_REQUIRED {combine_test})\n"
229  )
230 
231  output.close()
232 
233 

◆ pytest_collection_modifyitems()

def collect_for_ctest.pytest_collection_modifyitems (   session,
  config,
  items 
)

Definition at line 89 of file collect_for_ctest.py.

89 def pytest_collection_modifyitems(session, config, items):
90  if not session.ctest_args.get("output_file"):
91  # nothing to do if no output file is specified
92  return
93 
94  session.ctest_files = set(item.path for item in items)
95  session.ctest_fixture_setup = defaultdict(set)
96  session.ctest_fixture_required = defaultdict(set)
97  for item in items:
98  for marker in ("ctest_fixture_setup", "ctest_fixture_required"):
99  for mark in item.iter_markers(name=marker):
100  getattr(session, marker)[item.path].update(mark.args)
101 
102 

◆ pytest_collectstart()

def collect_for_ctest.pytest_collectstart (   collector)

Definition at line 73 of file collect_for_ctest.py.

73 def pytest_collectstart(collector):
74  session, config = collector.session, collector.config
75  args = {
76  name[6:]: getattr(config.option, name)
77  for name in dir(config.option)
78  if name.startswith("ctest_")
79  }
80 
81  if args.get("binary_dir"):
82  # $CMAKE_CURRENT_BINARY_DIR will be set by CTest when the test is run
83  # so, for consistency, we set it at collection time too
84  os.environ["CMAKE_CURRENT_BINARY_DIR"] = args["binary_dir"]
85 
86  session.ctest_args = args
87 
88 

◆ pytest_configure()

def collect_for_ctest.pytest_configure (   config)

Definition at line 234 of file collect_for_ctest.py.

234 def pytest_configure(config):
235  config.addinivalue_line(
236  "markers",
237  "ctest_fixture_setup(name): mark test to set up a fixture needed by another test",
238  )
239  config.addinivalue_line(
240  "markers",
241  "ctest_fixture_required(name): mark test to require a fixture set up by another test",
242  )

Variable Documentation

◆ TEST_DESC_TEMPLATE

collect_for_ctest.TEST_DESC_TEMPLATE

Definition at line 103 of file collect_for_ctest.py.

ReadAndWriteWhiteBoard.Path
Path
Definition: ReadAndWriteWhiteBoard.py:58
collect_for_ctest.pytest_configure
def pytest_configure(config)
Definition: collect_for_ctest.py:234
collect_for_ctest.pytest_collection_finish
def pytest_collection_finish(session)
Definition: collect_for_ctest.py:109
collect_for_ctest.pytest_collection_modifyitems
def pytest_collection_modifyitems(session, config, items)
Definition: collect_for_ctest.py:89
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
GaudiPython.Pythonizations.update
update
Definition: Pythonizations.py:145
collect_for_ctest.pytest_collectstart
def pytest_collectstart(collector)
Definition: collect_for_ctest.py:73
collect_for_ctest.pytest_addoption
def pytest_addoption(parser, pluginmanager)
Definition: collect_for_ctest.py:24