Redirect stdout to StringIO works in Python3, how in MicroPython?

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
HermannSW
Posts: 197
Joined: Wed Nov 01, 2017 7:46 am
Contact:

Redirect stdout to StringIO works in Python3, how in MicroPython?

Post by HermannSW » Wed Oct 24, 2018 3:07 pm

This is how redirect from stdout to StringIO works in Python3:

Code: Select all

>>> import sys, io
>>> sys.implementation
namespace(cache_tag='cpython-34', hexversion=50596336, name='cpython', version=sys.version_info(major=3, minor=4, micro=9, releaselevel='final', serial=0))
>>> sys.stdout = io.StringIO()
>>> help
>>> str=sys.stdout.getvalue()
>>> sys.stdout=sys.__stdout__
>>> print(str)
Type help() for interactive help, or help(object) for help about object.

>>> 

I tried the same in MicroPython, but get an error:

Code: Select all

$ webrepl_client.py 192.168.4.1
Password: 

WebREPL connected
>>> 
>>> 
MicroPython v1.9.4-272-g46091b8a on 2018-07-18; ESP module with ESP8266
Type "help()" for more information.
>>> import sys, io
>>> sys.stdout = io.StringIO()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'stdout'
>>> 
I get same error when using "uio.StringIO()".

How can redirect from sys.stdout to string/StringIO be done in MicroPython?
Pico-W Access Point static file webserver:
https://github.com/Hermann-SW/pico-w

Tiny MicroPython robots (the PCB IS the robot platform)
viewtopic.php?f=5&t=11454

webrepl_client.py
https://github.com/Hermann-SW/webrepl#webrepl-shell

HermannSW
Posts: 197
Joined: Wed Nov 01, 2017 7:46 am
Contact:

Re: Redirect stdout to StringIO works in Python3, how in MicroPython?

Post by HermannSW » Thu Oct 25, 2018 11:48 am

RTFM, from 1.9.4 MicroPython doc :-(
6.4.6 sys
Overriding sys.stdin, sys.stdout and sys.stderr not possible
Cause: They are stored in read-only memory.
Pico-W Access Point static file webserver:
https://github.com/Hermann-SW/pico-w

Tiny MicroPython robots (the PCB IS the robot platform)
viewtopic.php?f=5&t=11454

webrepl_client.py
https://github.com/Hermann-SW/webrepl#webrepl-shell

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: Redirect stdout to StringIO works in Python3, how in MicroPython?

Post by jickster » Thu Oct 25, 2018 3:52 pm

HermannSW wrote:RTFM, from 1.9.4 MicroPython doc :-(
6.4.6 sys
Overriding sys.stdin, sys.stdout and sys.stderr not possible
Cause: They are stored in read-only memory.
Then you could build your own uPy and not put them in readonly memory


Sent from my iPhone using Tapatalk Pro

HermannSW
Posts: 197
Joined: Wed Nov 01, 2017 7:46 am
Contact:

Re: Redirect stdout to StringIO works in Python3, how in MicroPython?

Post by HermannSW » Thu Oct 25, 2018 9:57 pm

jickster wrote:
Thu Oct 25, 2018 3:52 pm
Then you could build your own uPy and not put them in readonly memory
Yes, but what I really want to do is using standard MicroPython and grab output sent to sys.stdout.

I just learned that this can be done!
Of course without redirecting sys.stdout, which is not possible.

The trick is to use os.dupterm() with DUP class and comment from pythoncoder:
viewtopic.php?f=2&t=3298&p=23108&hilit= ... erm#p28561

This really works, I just replaced

Code: Select all

class DUP(object):
with

Code: Select all

class DUP(io.IOBase):
and did minor change from "help('modules')" to "help(webrepl)" (for which I had to import webrepl).

In a screen session I did:
  1. machine.reset()
  2. import dup
  3. print(bytes(dup.s).decode())
Here you can see the output:

Code: Select all

...
d�l��ld����l�n�����cdl�;x���#$�c;l{l{�n��D�WebREPL daemon started on ws://192.168.4.1:8266
Started webrepl in normal mode
OSError: [Errno 2] ENOENT

MicroPython v1.9.4-272-g46091b8a on 2018-07-18; ESP module with ESP8266
Type "help()" for more information.
>>> import dup
object <class 'DUP'> is of type type
  __qualname__ -- DUP
  readinto -- <function readinto at 0x3fff1330>
  write -- <function write at 0x3fff12f0>
  __module__ -- dup
  __init__ -- <function __init__ at 0x3fff1300>
>>> print(bytes(dup.s).decode())
object <class 'DUP'> is of type type
  __qualname__ -- DUP
  readinto -- <function readinto at 0x3fff1330>
  write -- <function write at 0x3fff12f0>
  __module__ -- dup
  __init__ -- <function __init__ at 0x3fff1300>

>>> 
Summary:
Question to my original question on redirecting sys.stdout in MicroPython is "impossible.
But my real problem (capturing output sent to sys.stdout) can be solved with pagano.paganino's DUP class!
I tested this on ESP8266 as well as ESP32 MicroPython.

P.S:
For completeness:

Code: Select all

$ cat dup.py
import io
import os
import webrepl

class DUP(io.IOBase):

    def __init__(self, s):
        self.s = s

    def write(self, data):
        self.s += data
        return len(data)

    def readinto(self, data):
        return 0

s = bytearray()
os.dupterm(DUP(s))
help(webrepl)
os.dupterm(None)
$ 
Pico-W Access Point static file webserver:
https://github.com/Hermann-SW/pico-w

Tiny MicroPython robots (the PCB IS the robot platform)
viewtopic.php?f=5&t=11454

webrepl_client.py
https://github.com/Hermann-SW/webrepl#webrepl-shell

Post Reply