codecs.getincrementaldecoder() is the equivalent of TextDecoder in JavaScript.
import codecs
# 世 界 \n
# e4 b8 96 e7 95 8c 0a
decoder = incremental_ansi_strip_decoder('utf-8')()
# s = decoder.decode(b'\xe4\xb8', final=True) # UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 0-1: unexpected end of data
decoder = incremental_ansi_strip_decoder('utf-8')(errors='replace')
assert decoder.decode(b'\xe4\xb8', final=True) == '�'
assert decoder.decode(b'\x96\xe7\x95', final=True) == '��'
assert decoder.decode(b'\x8c\x0a', final=True) == '�\n'
# final=False
assert decoder.decode(b'\xe4\xb8') == ''
assert decoder.decode(b'\x96\xe7\x95') == '世'
assert decoder.decode(b'\x8c\x0a') == '界\n'
# invalid utf-8
assert decoder.decode(b'\xff', final=True) == '�'
assert decoder.decode(b'\xff') == '�'
assert decoder.decode(b'\xe4\xb8') == ''
assert decoder.decode(b'\xff') == '��'
is equivalent to:
// 世 界 \n
// e4 b8 96 e7 95 8c 0a
const decoder = new TextDecoder();
let s;
s = decoder.decode(Uint8Array.from([0xe4, 0xb8])); // "�"
s = decoder.decode(Uint8Array.from([0x96, 0xe7, 0x95])); // "��"
s = decoder.decode(Uint8Array.from([0x8c, 0x0a])); // "�\n"
// stream: true
s = decoder.decode(Uint8Array.from([0xe4, 0xb8]), { stream: true }); // ""
s = decoder.decode(Uint8Array.from([0x96, 0xe7, 0x95]), { stream: true }); // "世"
s = decoder.decode(Uint8Array.from([0x8c, 0x0a]), { stream: true }); // "界\n"
// invalid utf-8
s = decoder.decode(Uint8Array.from([0xff])); // "�"
s = decoder.decode(Uint8Array.from([0xff]), { stream: true }); // "�"
s = decoder.decode(Uint8Array.from([0xe4, 0xb8]), { stream: true }); // ""
s = decoder.decode(Uint8Array.from([0xff]), { stream: true }); // "��"
I guess codecs.getincrementalencoder() is the one equivalent to TextEncoder.