← index #18555PR #6080
Related · medium · value 0.990
QUERY · ISSUE

dupterm on Unix blocks (slot 1) / replicates to stdout (slot 0)

openby smurfixopened 2025-12-12updated 2025-12-31
bugport-unix

Port, board and/or hardware

Unix

MicroPython version

MicroPython v1.27.0

Reproduction

  • compile the Unix port with #define MICROPY_PY_OS_DUPTERM (2)
  • run the binary
  • import the following test module
import io
import os

CHAN=1

class F(io.IOBase):
    def __init__(self):
        self.d=bytearray(b"2*21\n")

    def write(self, buf):
        return len(buf)

    def read(self,n):
        if not self.d:
            return None
        if n < (ld := len(self.d)):
            res = self.d[:n]
            self.d[:n] = b''
        else:
            res = self.d
            self.d = b''
            os.dupterm(None,CHAN)  # we're done
        return res

    def ioctl(self, req, flags):
        if req == 3:
            if self.d:
                return flags & 1
            return 0
        return None

buf = F()
os.dupterm(buf,CHAN)

Expected behaviour

>>> import duptest
>>> 2*21
42
>>> 

Note that the 2*21 part isn't typed by me.

Observed behaviour

>>> import duptest
>>>

Additional Information

strace shows that micropython blocks on reading standard input.

Using CHAN=0 "fixes" the problem but exhibits a different one: it sends output to both stdout and the dupterm'd IOBase subclass, but reads only from the latter. This is somewhat counter-intuitive and not what I'd like to happen.

Code of Conduct

Yes, I agree

CANDIDATE · PULL REQUEST

ports/unix: Add full uos.dupterm support.

openby andrewleechopened 2020-05-27updated 2026-03-23
port-unix

The unix port currently supports a very limited uos.dupterm implementation.
It can only replace stdin and/or duplicate stdout.
When using uos.dupterm to replace slot 0 it does not return a handle to the existing (posix stdio) stream.

This PR resolves these issues, preferring to use dupterm for all stdio on unix when MICROPY_PY_OS_DUPTERM=1 is configured in the build.

With this change simple modification of the output stream is possible, for example to format logging messaging with a basic timestamp

stdio = None

class logger:
    def write(self, buf):
        global stdio        
        stdio.write(str(utime.time()))
        stdio.write(" | ")
        stdio.write(buf)

stdio = uos.dupterm(logger(), 0)

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied