1import os 2import sys 3helpers_dir = os.getenv("PYCHARM_HELPERS_DIR", sys.path[0]) 4if sys.path[0] != helpers_dir: 5 sys.path.insert(0, helpers_dir) 6 7from tcmessages import TeamcityServiceMessages 8from pycharm_run_utils import adjust_sys_path 9 10adjust_sys_path(False) 11 12# Directory where test script exist 13CURRENT_DIR_NAME = "" 14if sys.argv: 15 last_arg = sys.argv[-1] 16 17 if os.path.isfile(last_arg): 18 CURRENT_DIR_NAME = os.path.dirname(last_arg) 19 else: 20 CURRENT_DIR_NAME = last_arg 21 if not str(last_arg).endswith(os.sep): 22 CURRENT_DIR_NAME = last_arg + os.sep 23 24messages = TeamcityServiceMessages(prepend_linebreak=True) 25if not "_jb_do_not_call_enter_matrix" in os.environ: 26 messages.testMatrixEntered() 27try: 28 import pytest 29 PYVERSION = [int(x) for x in pytest.__version__.split(".")] 30except: 31 import py 32 PYVERSION = [int(x) for x in py.__version__.split(".")] 33 34def get_name(nodeid): 35 return nodeid.split("::")[-1] 36 37def fspath_to_url(fspath): 38 return "file:///" + str(fspath).replace("\\", "/") 39 40if PYVERSION > [1, 4, 0]: 41 items = {} 42 current_suite = None 43 current_file = None 44 current_file_suite = None 45 46 def pytest_collection_finish(session): 47 messages.testCount(len(session.items)) 48 49 def pytest_runtest_logstart(nodeid, location): 50 path = "file://" + os.path.realpath(os.path.join(CURRENT_DIR_NAME, location[0])) 51 if location[1]: 52 path += ":" +str(location[1] + 1) 53 global current_suite, current_file, current_file_suite 54 current_file = nodeid.split("::")[0] 55 56 file_suite = current_file.split("/")[-1] 57 if file_suite != current_file_suite: 58 if current_suite: 59 messages.testSuiteFinished(current_suite) 60 if current_file_suite: 61 messages.testSuiteFinished(current_file_suite) 62 current_file_suite = file_suite 63 if current_file_suite: 64 messages.testSuiteStarted(current_file_suite, location=path) 65 66 if location[2].find(".") != -1: 67 suite = location[2].split(".")[0] 68 name = location[2].split(".")[-1] 69 else: 70 name = location[2] 71 splitted = nodeid.split("::") 72 try: 73 ind = splitted.index(name.split("[")[0]) 74 except ValueError: 75 try: 76 ind = splitted.index(name) 77 except ValueError: 78 ind = 0 79 if splitted[ind-1] == current_file: 80 suite = None 81 else: 82 suite = current_suite 83 if suite != current_suite: 84 if current_suite: 85 messages.testSuiteFinished(current_suite) 86 current_suite = suite 87 if current_suite: 88 messages.testSuiteStarted(current_suite, location=path) 89 messages.testStarted(name, location=path) 90 items[nodeid] = name 91 92 def pytest_runtest_logreport(report): 93 name = items[report.nodeid] 94 95 if report.skipped: 96 messages.testIgnored(name) 97 elif report.failed: # Duration should be in ms, but report has s 98 messages.testFailed(name, details=report.longrepr, duration=int(report.duration * 1000)) 99 elif report.when == "call": 100 messages.testFinished(name, duration=int(report.duration * 1000)) 101 102 def pytest_sessionfinish(session, exitstatus): 103 if not messages.number_of_tests and not current_suite and not current_file_suite: 104 messages.testError("ERROR", "No tests found") 105 if current_suite: 106 messages.testSuiteFinished(current_suite) 107 if current_file_suite: 108 messages.testSuiteFinished(current_file_suite) 109 110 from _pytest.terminal import TerminalReporter 111 class PycharmTestReporter(TerminalReporter): 112 def __init__(self, config, file=None): 113 TerminalReporter.__init__(self, config, file) 114 115 def summary_errors(self): 116 reports = self.getreports('error') 117 if not reports: 118 return 119 for rep in self.stats['error']: 120 name = rep.nodeid.split("/")[-1] 121 location = None 122 if hasattr(rep, 'location'): 123 location, lineno, domain = rep.location 124 125 messages.testSuiteStarted(name, location=fspath_to_url(location)) 126 messages.testStarted("ERROR", location=fspath_to_url(location)) 127 TerminalReporter.summary_errors(self) 128 messages.testError("ERROR") 129 messages.testSuiteFinished(name) 130 131else: 132 def pytest_collectstart(collector): 133 if collector.name != "()": 134 messages.testSuiteStarted(collector.name, location=fspath_to_url(collector.fspath)) 135 136 def pytest_runtest_makereport(item, call): 137 if call.when == "setup": 138 fspath, lineno, msg = item.reportinfo() 139 url = fspath_to_url(fspath) 140 if lineno: url += ":" + str(lineno) 141 # messages.testStarted(item.name, location=url) 142 143 def pytest_runtest_logreport(report): 144 if report.item._args: 145 name = report.item.function.__name__ + str(report.item._args) 146 else: 147 name = report.item.name 148 if report.failed: 149 messages.testFailed(name, details=report.longrepr) 150 elif report.skipped: 151 messages.testIgnored(name) 152 else: 153 messages.testFinished(name) 154 155 def pytest_collectreport(report): 156 if report.collector.name != "()": 157 messages.testSuiteFinished(report.collector.name) 158 159 def pytest_itemstart(item, node=None): 160 if item._args: 161 name = item.function.__name__ + str(item._args) 162 else: 163 name = item.name 164 if hasattr(item, "_fslineno"): 165 path = fspath_to_url(item._fslineno[0]) + ":" + str(item._fslineno[1] + 1) 166 else: 167 path = fspath_to_url(item.fspath) 168 messages.testStarted(name, location=path) 169 170 171try: 172 @pytest.hookimpl(trylast=True) 173 def pytest_configure(config): 174 reporter = PycharmTestReporter(config, sys.stdout) 175 config.pluginmanager.unregister(name="terminalreporter") 176 config.pluginmanager.register(reporter, 'terminalreporter') 177except AttributeError as e: 178 sys.stderr.write("Unable to set hookimpl. Some errors may be ignored. Make sure you use PyTest 2.8.0+. Error was {0}".format(e))