Coverage for Applications / PyCharm.app / Contents / plugins / python-ce / helpers / pycharm / teamcity / output.py: 81%
36 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-01 16:37 -0600
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-01 16:37 -0600
1# coding=utf-8
2import errno
3import sys
4from functools import wraps
5import time
7# Capture some time functions to allow monkeypatching them in tests
8_time = time.time
9_stderr = sys.stderr
12class TeamCityMessagesPrinter(object):
13 def __init__(self, output=None, context_manager=None):
14 if output is None:
15 output = sys.stdout
16 if sys.version_info < (3,) or not hasattr(output, 'buffer'):
17 self.output = output
18 else:
19 self.output = output.buffer
20 # context manager can be set for testing frameworks such as pytest, which may redirect
21 # normal output, to temporarily disable redirection for Teamcity messages
22 self.context_manager = context_manager
24 def send_message(self, message):
25 if self.context_manager:
26 with self.context_manager():
27 self._output(message)
28 else:
29 self._output(message)
31 def _output(self, message):
32 # Python may buffer it for a long time, flushing helps to see real-time result
33 retry_on_EAGAIN(self.output.write)(message)
34 retry_on_EAGAIN(self.output.flush)()
37def retry_on_EAGAIN(callable):
38 # output seems to be non-blocking when running under teamcity.
39 @wraps(callable)
40 def wrapped(*args, **kwargs):
41 start_time = _time()
42 while True:
43 try:
44 return callable(*args, **kwargs)
45 except IOError as e:
46 if e.errno != errno.EAGAIN:
47 raise
48 # Give up after a minute.
49 if _time() - start_time > 60:
50 raise
51 time.sleep(.1)
53 return wrapped