sflkit 0.2.19__tar.gz → 0.2.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. {sflkit-0.2.19/src/sflkit.egg-info → sflkit-0.2.20}/PKG-INFO +1 -1
  2. {sflkit-0.2.19 → sflkit-0.2.20}/pyproject.toml +1 -1
  3. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/python/factory.py +9 -6
  4. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/runners/run.py +126 -23
  5. {sflkit-0.2.19 → sflkit-0.2.20/src/sflkit.egg-info}/PKG-INFO +1 -1
  6. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit.egg-info/SOURCES.txt +1 -2
  7. sflkit-0.2.20/tests/test_runner_pytest_versions.py +121 -0
  8. sflkit-0.2.19/src/sflkit/runners/resources/__init__.py +0 -0
  9. sflkit-0.2.19/src/sflkit/runners/resources/pytest_main.py +0 -82
  10. {sflkit-0.2.19 → sflkit-0.2.20}/LICENSE +0 -0
  11. {sflkit-0.2.19 → sflkit-0.2.20}/README.md +0 -0
  12. {sflkit-0.2.19 → sflkit-0.2.20}/setup.cfg +0 -0
  13. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/__init__.py +0 -0
  14. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/analysis/__init__.py +0 -0
  15. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/analysis/analysis_type.py +0 -0
  16. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/analysis/analyzer.py +0 -0
  17. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/analysis/factory.py +0 -0
  18. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/analysis/mapping.py +0 -0
  19. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/analysis/predicate.py +0 -0
  20. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/analysis/similarity.py +0 -0
  21. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/analysis/spectra.py +0 -0
  22. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/analysis/suggestion.py +0 -0
  23. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/cli.py +0 -0
  24. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/color.py +0 -0
  25. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/config.py +0 -0
  26. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/instrumentation/__init__.py +0 -0
  27. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/instrumentation/dir_instrumentation.py +0 -0
  28. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/instrumentation/file_instrumentation.py +0 -0
  29. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/__init__.py +0 -0
  30. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/extract.py +0 -0
  31. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/finder.py +0 -0
  32. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/language.py +0 -0
  33. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/meta.py +0 -0
  34. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/python/__init__.py +0 -0
  35. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/python/extract.py +0 -0
  36. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/python/finder.py +0 -0
  37. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/python/visitor.py +0 -0
  38. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/language/visitor.py +0 -0
  39. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/logger.py +0 -0
  40. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/mapping.py +0 -0
  41. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/model/__init__.py +0 -0
  42. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/model/event_file.py +0 -0
  43. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/model/model.py +0 -0
  44. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/model/scope.py +0 -0
  45. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit/runners/__init__.py +0 -0
  46. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit.egg-info/dependency_links.txt +0 -0
  47. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit.egg-info/entry_points.txt +0 -0
  48. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit.egg-info/requires.txt +0 -0
  49. {sflkit-0.2.19 → sflkit-0.2.20}/src/sflkit.egg-info/top_level.txt +0 -0
  50. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_analysis_objects.py +0 -0
  51. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_cli.py +0 -0
  52. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_color.py +0 -0
  53. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_config.py +0 -0
  54. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_coverage.py +0 -0
  55. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_events.py +0 -0
  56. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_execution.py +0 -0
  57. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_instrumentation.py +0 -0
  58. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_language.py +0 -0
  59. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_predicates.py +0 -0
  60. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_runner.py +0 -0
  61. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_scope.py +0 -0
  62. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_spectra.py +0 -0
  63. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_suggestions.py +0 -0
  64. {sflkit-0.2.19 → sflkit-0.2.20}/tests/test_visitors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sflkit
3
- Version: 0.2.19
3
+ Version: 0.2.20
4
4
  Summary: SFLKit: : A Workbench for Statistical Fault Localization
5
5
  Author-email: Marius Smytzek <marius.smytzek@cispa.de>
6
6
  Project-URL: Homepage, https://github.com/uds-se/sflkit/
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "sflkit"
10
- version = "0.2.19"
10
+ version = "0.2.20"
11
11
  authors = [
12
12
  { name = "Marius Smytzek", email = "marius.smytzek@cispa.de" },
13
13
  ]
@@ -849,14 +849,17 @@ class LenEventFactory(DefEventFactory):
849
849
  keywords=[],
850
850
  )
851
851
  )
852
- return If(
853
- test=Call(
854
- func=Name(id="hasattr"),
855
- args=[Name(id=event.var), Constant(value="__len__")],
856
- keywords=[],
857
- ),
852
+ return Try(
858
853
  body=[call],
854
+ handlers=[
855
+ ExceptHandler(
856
+ type=Name(id="TypeError"),
857
+ name=None,
858
+ body=[Pass()],
859
+ )
860
+ ],
859
861
  orelse=[],
862
+ finalbody=[],
860
863
  )
861
864
 
862
865
  def get_event_call(self, event: LenEvent):
@@ -53,6 +53,7 @@ class Runner(abc.ABC):
53
53
  files: Optional[List[os.PathLike] | os.PathLike] = None,
54
54
  base: Optional[os.PathLike] = None,
55
55
  environ: Environment = None,
56
+ k: str = None,
56
57
  ) -> List[str]:
57
58
  return []
58
59
 
@@ -101,6 +102,7 @@ class Runner(abc.ABC):
101
102
  files: Optional[List[os.PathLike] | os.PathLike] = None,
102
103
  base: Optional[os.PathLike] = None,
103
104
  environ: Environment = None,
105
+ k: str = None,
104
106
  ):
105
107
  self.passing_tests.clear()
106
108
  self.failing_tests.clear()
@@ -109,7 +111,7 @@ class Runner(abc.ABC):
109
111
  directory,
110
112
  output,
111
113
  self.filter_tests(
112
- self.get_tests(directory, files=files, base=base, environ=environ)
114
+ self.get_tests(directory, files=files, base=base, environ=environ, k=k)
113
115
  ),
114
116
  environ=environ,
115
117
  )
@@ -119,6 +121,120 @@ class VoidRunner(Runner):
119
121
  pass
120
122
 
121
123
 
124
+ class PytestStructure:
125
+ def __init__(self, name: str, parent: Optional["PytestStructure"] = None):
126
+ self.name = name
127
+ self.children = []
128
+ self.parent = parent
129
+ self.depth = 0
130
+
131
+ def add_child(self, child):
132
+ self.children.append(child)
133
+
134
+ def set_parent(self, parent):
135
+ self.parent = parent
136
+
137
+ def get_seperator(self):
138
+ return ""
139
+
140
+ def get_tests(self) -> List[str]:
141
+ if self.children:
142
+ return [
143
+ self.name + self.get_seperator() + test
144
+ for child in self.children
145
+ for test in child.get_tests()
146
+ ]
147
+ else:
148
+ return [self.name]
149
+
150
+ DIR = "Dir"
151
+ PACKAGE = "Package"
152
+ MODULE = "Module"
153
+ CLASS = "Class"
154
+ FUNCTION = "Function"
155
+ UNIT_TEST_CASE = "UnitTestCase"
156
+ TEST_CASE_FUNCTION = "TestCaseFunction"
157
+
158
+ @staticmethod
159
+ def get_pattern(obj):
160
+ return re.compile(rf"<{obj} ['\"]?(?P<name>[^>'\"]*)['\"]?>")
161
+
162
+ @staticmethod
163
+ def parse_tests(output: str) -> List[str]:
164
+ trees = []
165
+ current = None
166
+ for original_line in output.split("\n"):
167
+ line = original_line.lstrip()
168
+ level = len(original_line) - len(line)
169
+ if f"<{PytestStructure.DIR}" in line:
170
+ structure = Directory
171
+ pattern = PytestStructure.get_pattern(PytestStructure.DIR)
172
+ elif f"<{PytestStructure.PACKAGE}" in line:
173
+ structure = Directory
174
+ pattern = PytestStructure.get_pattern(PytestStructure.PACKAGE)
175
+ elif f"<{PytestStructure.MODULE}" in line:
176
+ structure = Module
177
+ pattern = PytestStructure.get_pattern(PytestStructure.MODULE)
178
+ elif f"<{PytestStructure.CLASS}" in line:
179
+ structure = Class
180
+ pattern = PytestStructure.get_pattern(PytestStructure.CLASS)
181
+ elif f"<{PytestStructure.FUNCTION}" in line:
182
+ structure = Function
183
+ pattern = PytestStructure.get_pattern(PytestStructure.FUNCTION)
184
+ elif f"<{PytestStructure.UNIT_TEST_CASE}" in line:
185
+ structure = Class
186
+ pattern = PytestStructure.get_pattern(PytestStructure.UNIT_TEST_CASE)
187
+ elif f"<{PytestStructure.TEST_CASE_FUNCTION}" in line:
188
+ structure = Function
189
+ pattern = PytestStructure.get_pattern(
190
+ PytestStructure.TEST_CASE_FUNCTION
191
+ )
192
+ else:
193
+ continue
194
+ match = pattern.search(line)
195
+ if match:
196
+ obj = structure(match.group("name"))
197
+ obj.depth = level
198
+ if current is None:
199
+ trees.append(obj)
200
+ elif current.depth < obj.depth:
201
+ obj.set_parent(current)
202
+ current.add_child(obj)
203
+ elif current.depth >= obj.depth:
204
+ while current.depth >= obj.depth and current:
205
+ current = current.parent
206
+ if current is None:
207
+ trees.append(obj)
208
+ else:
209
+ obj.set_parent(current)
210
+ current.add_child(obj)
211
+ current = obj
212
+ return [test for tree in trees for test in tree.get_tests()]
213
+
214
+ def __repr__(self):
215
+ return f"<{self.__class__.__name__} {self.name}>"
216
+
217
+
218
+ class Directory(PytestStructure):
219
+ def get_seperator(self):
220
+ return os.sep
221
+
222
+
223
+ class Module(PytestStructure):
224
+ def get_seperator(self):
225
+ return "::"
226
+
227
+
228
+ class Class(PytestStructure):
229
+ def get_seperator(self):
230
+ return "::"
231
+
232
+
233
+ class Function(PytestStructure):
234
+ def get_seperator(self):
235
+ return "::"
236
+
237
+
122
238
  class PytestRunner(Runner):
123
239
  def __init__(
124
240
  self,
@@ -171,9 +287,13 @@ class PytestRunner(Runner):
171
287
  files: Optional[List[os.PathLike] | os.PathLike] = None,
172
288
  base: Optional[os.PathLike] = None,
173
289
  environ: Environment = None,
290
+ k: str = None,
174
291
  ) -> List[str]:
175
292
  c = []
176
293
  directory = directory.absolute()
294
+ if k:
295
+ c.append("-k")
296
+ c.append(k)
177
297
  if files:
178
298
  if isinstance(files, (str, os.PathLike)):
179
299
  c.append(str(files))
@@ -185,21 +305,11 @@ class PytestRunner(Runner):
185
305
  root_dir = directory / base
186
306
  else:
187
307
  root_dir = directory
188
- tmp = Path(f"tmp_sflkit_pytest_tmp_{id(self)}").absolute()
189
- pytest_main = (
190
- Path(__file__).parent.resolve() / "resources" / "pytest_main.py"
191
- ).absolute()
192
- environ = dict(environ or os.environ)
193
- environ["SFLKIT_PYTEST_COLLECTION_FINISH_FILE"] = str(tmp)
194
- if self.set_python_path:
195
- if "PYTHONPATH" in environ:
196
- environ["PYTHONPATH"] = str(directory) + ":" + environ["PYTHONPATH"]
197
- else:
198
- environ["PYTHONPATH"] = str(directory)
199
308
  process = subprocess.run(
200
309
  [
201
310
  "python3",
202
- str(pytest_main),
311
+ "-m",
312
+ "pytest",
203
313
  "--collect-only",
204
314
  ]
205
315
  + c,
@@ -209,16 +319,8 @@ class PytestRunner(Runner):
209
319
  cwd=directory,
210
320
  )
211
321
  LOGGER.info(f"pytest collection finished with {process.returncode}")
212
- if not tmp.exists():
213
- tmp = directory / "tmp_sflkit_pytest"
214
- if tmp.exists():
215
- with open(tmp, "r") as f:
216
- tests = [line.strip() for line in f.readlines()]
217
- os.remove(tmp)
218
- return self._normalize_paths(tests, directory, root_dir)
219
- else:
220
- LOGGER.warn(f"Could not find {tmp}")
221
- return []
322
+ tests = PytestStructure.parse_tests(process.stdout.decode("utf8"))
323
+ return self._normalize_paths(tests, directory, root_dir)
222
324
 
223
325
  @staticmethod
224
326
  def __get_pytest_result__(
@@ -309,6 +411,7 @@ class InputRunner(Runner):
309
411
  files: Optional[List[os.PathLike] | os.PathLike] = None,
310
412
  base: Optional[os.PathLike] = None,
311
413
  environ: Environment = None,
414
+ k: str = None,
312
415
  ) -> List[str]:
313
416
  return list(self.passing.keys()) + list(self.failing.keys())
314
417
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sflkit
3
- Version: 0.2.19
3
+ Version: 0.2.20
4
4
  Summary: SFLKit: : A Workbench for Statistical Fault Localization
5
5
  Author-email: Marius Smytzek <marius.smytzek@cispa.de>
6
6
  Project-URL: Homepage, https://github.com/uds-se/sflkit/
@@ -42,8 +42,6 @@ src/sflkit/model/model.py
42
42
  src/sflkit/model/scope.py
43
43
  src/sflkit/runners/__init__.py
44
44
  src/sflkit/runners/run.py
45
- src/sflkit/runners/resources/__init__.py
46
- src/sflkit/runners/resources/pytest_main.py
47
45
  tests/test_analysis_objects.py
48
46
  tests/test_cli.py
49
47
  tests/test_color.py
@@ -55,6 +53,7 @@ tests/test_instrumentation.py
55
53
  tests/test_language.py
56
54
  tests/test_predicates.py
57
55
  tests/test_runner.py
56
+ tests/test_runner_pytest_versions.py
58
57
  tests/test_scope.py
59
58
  tests/test_spectra.py
60
59
  tests/test_suggestions.py
@@ -0,0 +1,121 @@
1
+ import os
2
+ import shutil
3
+ import subprocess
4
+ import sys
5
+ import unittest
6
+ from pathlib import Path
7
+
8
+ from sflkit import Config, instrument_config, Analyzer
9
+ from sflkit.analysis.analysis_type import AnalysisType
10
+ from sflkit.analysis.suggestion import Location
11
+ from sflkit.mapping import EventMapping
12
+ from sflkit.model import EventFile
13
+ from sflkit.runners.run import (
14
+ PytestRunner,
15
+ )
16
+ from tests.utils import BaseTest
17
+
18
+
19
+ @unittest.skip
20
+ class RunnerTests(BaseTest):
21
+ VENV = Path("test_venv")
22
+ PYTHON_BASE = os.path.join(
23
+ os.path.expanduser("~"), ".pyenv", "versions", "3.8.4", "bin", "python3"
24
+ )
25
+ PYTHON = "python3"
26
+
27
+ def assertPathExists(self, path: os.PathLike):
28
+ self.assertTrue(os.path.exists(path), f"{path} does not exists.")
29
+
30
+ def create_venv(self, environ):
31
+ shutil.rmtree(self.VENV, ignore_errors=True)
32
+ subprocess.check_call([self.PYTHON_BASE, "-m", "venv", self.VENV], env=environ)
33
+
34
+ def activate_venv(self, environ):
35
+ environ["VIRTUAL_ENV"] = str(self.VENV.absolute())
36
+ environ["_OLD_VIRTUAL_PATH"] = environ["PATH"]
37
+ if sys.platform.startswith("win"):
38
+ environ["PATH"] = f'{(self.VENV / "Scripts").absolute()};{environ["PATH"]}'
39
+ else:
40
+ environ["PATH"] = f'{(self.VENV / "bin").absolute()}:{environ["PATH"]}'
41
+ if "PYTHONHOME" in environ:
42
+ environ["_OLD_VIRTUAL_PYTHONHOME"] = environ["PYTHONHOME"]
43
+ del environ["PYTHONHOME"]
44
+ if "VIRTUAL_ENV_DISABLE_PROMPT" not in environ:
45
+ environ["_OLD_VIRTUAL_PS1"] = environ["PS1"] if "PS1" in environ else ""
46
+ environ[
47
+ "PS1"
48
+ ] = f'({self.VENV}) {environ["PS1"] if "PS1" in environ else ""}'
49
+ environ["VIRTUAL_ENV_PROMPT"] = f"({self.VENV})"
50
+ return environ
51
+
52
+ def install_pytest(self, environ, pytest_version):
53
+ subprocess.check_call(
54
+ [self.PYTHON, "-m", "pip", "install", f"pytest=={pytest_version}"],
55
+ env=environ,
56
+ )
57
+ subprocess.check_call(
58
+ [self.PYTHON, "-m", "pip", "install", f"sflkitlib"],
59
+ env=environ,
60
+ )
61
+
62
+ def tearDown(self):
63
+ shutil.rmtree(self.VENV, ignore_errors=True)
64
+
65
+ def _runner_test(self, pytest_version):
66
+ environ = os.environ.copy()
67
+ self.create_venv(environ)
68
+ environ = self.activate_venv(environ)
69
+ self.install_pytest(environ, pytest_version)
70
+ config = Config.create(
71
+ path=os.path.join(self.TEST_RESOURCES, BaseTest.TEST_RUNNER),
72
+ language="python",
73
+ events="line",
74
+ predicates="line",
75
+ working=BaseTest.TEST_DIR,
76
+ exclude="tests",
77
+ )
78
+ instrument_config(config)
79
+ runner = PytestRunner(set_python_path=True)
80
+ output = Path(BaseTest.TEST_DIR, "events").absolute()
81
+ runner.run(
82
+ Path(BaseTest.TEST_DIR),
83
+ output,
84
+ files=[Path("tests", "test_middle.py")],
85
+ environ=environ,
86
+ )
87
+ self.assertPathExists(output)
88
+ self.assertPathExists(output / "passing")
89
+ self.assertPathExists(output / "failing")
90
+ self.assertPathExists(output / "undefined")
91
+ mapping = EventMapping.load(config)
92
+ analyzer = Analyzer(
93
+ [
94
+ EventFile(
95
+ output / "failing" / os.listdir(output / "failing")[0],
96
+ 0,
97
+ mapping,
98
+ failing=True,
99
+ )
100
+ ],
101
+ [
102
+ EventFile(output / "passing" / path, run_id, mapping)
103
+ for run_id, path in enumerate(os.listdir(output / "passing"), start=1)
104
+ ],
105
+ config.factory,
106
+ )
107
+ analyzer.analyze()
108
+ predicates = analyzer.get_analysis_by_type(AnalysisType.LINE)
109
+ suggestions = sorted(map(lambda p: p.get_suggestion(), predicates))
110
+ self.assertEqual(1, suggestions[-1].suspiciousness)
111
+ self.assertEqual(1, len(suggestions[-1].lines))
112
+ self.assertEqual(Location("middle.py", 7), suggestions[-1].lines[0])
113
+
114
+ def test_pytest_3_10_1(self):
115
+ self._runner_test("3.10.1")
116
+
117
+ def test_pytest_5_4_3(self):
118
+ self._runner_test("5.4.3")
119
+
120
+ def test_pytest_7_0_1(self):
121
+ self._runner_test("7.0.1")
File without changes
@@ -1,82 +0,0 @@
1
- import os
2
- import sys
3
- from typing import Optional, Union, List, Sequence
4
-
5
- # noinspection PyPackageRequirements
6
- from _pytest._code import ExceptionInfo
7
-
8
- # noinspection PyPackageRequirements
9
- from _pytest._io import TerminalWriter
10
-
11
- # noinspection PyPackageRequirements
12
- from _pytest.config import (
13
- ExitCode,
14
- _prepareconfig,
15
- ConftestImportFailure,
16
- UsageError,
17
- filter_traceback_for_conftest_import_failure,
18
- _PluggyPlugin,
19
- )
20
-
21
-
22
- def pytest_collection_finish(session):
23
- """
24
- Called after collection has been performed and modified.
25
- """
26
- file = os.getenv("SFLKIT_PYTEST_COLLECTION_FINISH_FILE", "tmp_sflkit_pytest")
27
- with open(file, "w") as f:
28
- for item in session.items:
29
- f.write(item.nodeid + "\n")
30
-
31
-
32
- def main(
33
- args: Optional[Union[List[str], "os.PathLike[str]"]] = None,
34
- plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None,
35
- ) -> Union[int, ExitCode]:
36
- """Perform an in-process test run.
37
-
38
- :param args: List of command line arguments.
39
- :param plugins: List of plugin objects to be auto-registered during initialization.
40
-
41
- :returns: An exit code.
42
- """
43
- try:
44
- try:
45
- config = _prepareconfig(args, plugins)
46
- except ConftestImportFailure as e:
47
- exc_info = ExceptionInfo.from_exc_info(e.excinfo)
48
- tw = TerminalWriter(sys.stderr)
49
- tw.line(f"ImportError while loading conftest '{e.path}'.", red=True)
50
- exc_info.traceback = exc_info.traceback.filter(
51
- filter_traceback_for_conftest_import_failure
52
- )
53
- exc_repr = (
54
- exc_info.getrepr(style="short", chain=False)
55
- if exc_info.traceback
56
- else exc_info.exconly()
57
- )
58
- formatted_tb = str(exc_repr)
59
- for line in formatted_tb.splitlines():
60
- tw.line(line.rstrip(), red=True)
61
- return ExitCode.USAGE_ERROR
62
- else:
63
- try:
64
- config.hook.pytest_collection_finish = pytest_collection_finish
65
- ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
66
- config=config
67
- )
68
- try:
69
- return ExitCode(ret)
70
- except ValueError:
71
- return ret
72
- finally:
73
- config._ensure_unconfigure()
74
- except UsageError as e:
75
- tw = TerminalWriter(sys.stderr)
76
- for msg in e.args:
77
- tw.line(f"ERROR: {msg}\n", red=True)
78
- return ExitCode.USAGE_ERROR
79
-
80
-
81
- if __name__ == "__main__":
82
- main(sys.argv[1:])
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes