Skip to content

Commit

Permalink
Fixed stdout/stderr redirection with extern Python controllers on Win…
Browse files Browse the repository at this point in the history
…dows (cyberbotics#5807)

* Fixed stdout/stderr redirection with extern Python controllers on Windows

* Update changelog-r2023.md

* Fixed PEP8

* Support for UTF-8 strings

* Cleaner support for UTF-8 strings
  • Loading branch information
omichel authored Feb 1, 2023
1 parent aa631d1 commit 6cbc643
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/reference/changelog-r2023.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Released on ??
- Improved plot representation in default robot window when a NaN value is received from a device ([#5680](https://github.com/cyberbotics/webots/pull/5680)).
- Improved default selected tab in Field Editor when nodes are selected ([#5726](https://github.com/cyberbotics/webots/pull/5726)).
- Bug Fixes
- Fixed redirection of stdout/stderr for Python controllers on Windows ([#5807](https://github.com/cyberbotics/webots/pull/5807)).
- Fixed crash in Python API when a robot controller was using several cameras with different resolutions ([#5705](https://github.com/cyberbotics/webots/pull/5705)).
- Fixed Python API `Supervisor.setSimulationMode` which was failing ([#5603](https://github.com/cyberbotics/webots/pull/5603)).
- Fixed Python API `Node.enableContactPointsTracking` which was failing ([#5633](https://github.com/cyberbotics/webots/pull/5633)).
Expand Down
47 changes: 47 additions & 0 deletions lib/controller/python/controller/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,53 @@
from .mouse import Mouse


if sys.platform == 'win32':
import atexit
import os
import threading

class StdStreamRedirect:
def __init__(self, stream):
r, w = os.pipe()
r, w = os.fdopen(r, 'r', encoding='utf-8'), os.fdopen(w, 'w', buffering=1, encoding='utf-8')
self._r = r
self._w = w
if stream == 1: # stdout
sys.stdout = self._w
elif stream == 2: # stderr
sys.stderr = self._w
self._stream = stream
self._thread = threading.Thread(target=self._handler)
self._thread.start()

def __del__(self):
self._w.close()
self._thread.join()
self._r.close()

def _handler(self):
libc = ctypes.CDLL('msvcrt')
while not self._w.closed:
try:
while True:
line = self._r.readline()
if len(line) == 0:
break
encoded = line.encode('utf-8')
libc._write(self._stream, encoded, len(encoded), 0)
except Exception:
break

def _delete_object(object):
del object
if 'WEBOTS_STDOUT_REDIRECT' in os.environ and os.environ['WEBOTS_STDOUT_REDIRECT']:
_stdout_redirect = StdStreamRedirect(1)
atexit.register(_delete_object, _stdout_redirect)
if 'WEBOTS_STDERR_REDIRECT' in os.environ and os.environ['WEBOTS_STDERR_REDIRECT']:
_stderr_redirect = StdStreamRedirect(2)
atexit.register(_delete_object, _stderr_redirect)


class Robot:
EVENT_QUIT = -1
EVENT_NO_EVENT = 0
Expand Down

0 comments on commit 6cbc643

Please sign in to comment.