| 57 | return f"<TextLogStream {self.buffer.tag!r}>" |
| 58 | |
| 59 | def write(self, s): |
| 60 | if not isinstance(s, str): |
| 61 | raise TypeError( |
| 62 | f"write() argument must be str, not {type(s).__name__}") |
| 63 | |
| 64 | # In case `s` is a str subclass that writes itself to stdout or stderr |
| 65 | # when we call its methods, convert it to an actual str. |
| 66 | s = str.__str__(s) |
| 67 | |
| 68 | # We want to emit one log message per line wherever possible, so split |
| 69 | # the string into lines first. Note that "".splitlines() == [], so |
| 70 | # nothing will be logged for an empty string. |
| 71 | with self._lock: |
| 72 | for line in s.splitlines(keepends=True): |
| 73 | while line: |
| 74 | chunk = line[:MAX_CHARS_PER_WRITE] |
| 75 | line = line[MAX_CHARS_PER_WRITE:] |
| 76 | self._write_chunk(chunk) |
| 77 | |
| 78 | return len(s) |
| 79 | |
| 80 | # The size and behavior of TextIOWrapper's buffer is not part of its public |
| 81 | # API, so we handle buffering ourselves to avoid truncation. |