1 from threading
import Lock
2 from .utils
import supports_terminal_sequences
, TERMINAL_SEQUENCES
5 class MultilinePrinterBase
:
6 def __init__(self
, stream
=None, lines
=1):
8 self
.maximum
= lines
- 1
13 def __exit__(self
, *args
):
16 def print_at_line(self
, text
, pos
):
22 def _add_line_number(self
, text
, line
):
24 return f
'{line + 1}: {text}'
28 class QuietMultilinePrinter(MultilinePrinterBase
):
32 class MultilineLogger(MultilinePrinterBase
):
33 def print_at_line(self
, text
, pos
):
34 # stream is the logger object, not an actual stream
35 self
.stream
.debug(self
._add
_line
_number
(text
, pos
))
38 class BreaklineStatusPrinter(MultilinePrinterBase
):
39 def print_at_line(self
, text
, pos
):
40 self
.stream
.write(self
._add
_line
_number
(text
, pos
) + '\n')
43 class MultilinePrinter(MultilinePrinterBase
):
44 def __init__(self
, stream
=None, lines
=1, preserve_output
=True):
45 super().__init
__(stream
, lines
)
46 self
.preserve_output
= preserve_output
47 self
._lastline
= self
._lastlength
= 0
48 self
._movelock
= Lock()
49 self
._HAVE
_FULLCAP
= supports_terminal_sequences(self
.stream
)
52 def wrapper(self
, *args
, **kwargs
):
54 return func(self
, *args
, **kwargs
)
57 def _move_cursor(self
, dest
):
58 current
= min(self
._lastline
, self
.maximum
)
59 self
.stream
.write('\r')
60 distance
= dest
- current
62 self
.stream
.write(TERMINAL_SEQUENCES
['UP'] * -distance
)
64 self
.stream
.write(TERMINAL_SEQUENCES
['DOWN'] * distance
)
68 def print_at_line(self
, text
, pos
):
69 if self
._HAVE
_FULLCAP
:
70 self
._move
_cursor
(pos
)
71 self
.stream
.write(TERMINAL_SEQUENCES
['ERASE_LINE'])
72 self
.stream
.write(text
)
75 text
= self
._add
_line
_number
(text
, pos
)
77 if self
._lastline
== pos
:
78 # move cursor at the start of progress when writing to same line
79 self
.stream
.write('\r')
80 if self
._lastlength
> textlen
:
81 text
+= ' ' * (self
._lastlength
- textlen
)
82 self
._lastlength
= textlen
84 # otherwise, break the line
85 self
.stream
.write('\n')
86 self
._lastlength
= textlen
87 self
.stream
.write(text
)
92 # move cursor to the end of the last line, and write line break
93 # so that other to_screen calls can precede
94 if self
._HAVE
_FULLCAP
:
95 self
._move
_cursor
(self
.maximum
)
96 if self
.preserve_output
:
97 self
.stream
.write('\n')
100 if self
._HAVE
_FULLCAP
:
102 TERMINAL_SEQUENCES
['ERASE_LINE']
103 + f
'{TERMINAL_SEQUENCES["UP"]}{TERMINAL_SEQUENCES["ERASE_LINE"]}' * self
.maximum
)
105 self
.stream
.write(' ' * self
._lastlength
)