1 from contextlib
import contextmanager
2 from budget_sync
.ordered_set
import OrderedSet
3 from bugzilla
import Bugzilla
4 from bugzilla
.bug
import Bug
5 from typing
import Any
, Callable
, Dict
, Iterator
, List
, Type
, Union
7 from io
import StringIO
11 class BugStatus(Enum
):
12 UNCONFIRMED
= "UNCONFIRMED"
13 CONFIRMED
= "CONFIRMED"
14 IN_PROGRESS
= "IN_PROGRESS"
18 PAYMENTPENDING
= "PAYMENTPENDING"
24 return f
"BugStatus.{self.value}"
27 def cast(v
: Union
[str, "BugStatus"],
28 unknown_allowed
: bool = False) -> Union
[str, "BugStatus"]:
41 if hasattr(os
, "ctermid"):
42 term
= open(os
.ctermid(), "wt", encoding
="utf-8")
44 term
= open("CONOUT$", "wt", encoding
="utf-8")
48 # no terminal available
50 try: # can't use `with` since it doesn't work with None
57 def all_bugs(bz
: Bugzilla
) -> Iterator
[Bug
]:
60 with
tty_out() as term
:
62 bugs
= list(range(chunk_start
, chunk_start
+ chunk_size
))
63 bugs
= bz
.getbugs(bugs
)
64 chunk_start
+= chunk_size
65 # progress indicator, should go to terminal
67 print("bugs loaded", len(bugs
), chunk_start
, flush
=True,
74 class SequencePrettyPrinter
:
76 pretty_printer
: "PrettyPrinter",
77 start_delimiter
: str = '[\n',
78 end_delimiter
: str = ']',
79 item_separator
: str = ',\n'):
80 self
.__pretty
_printer
= pretty_printer
81 self
.__start
_delimiter
= start_delimiter
82 self
.__end
_delimiter
= end_delimiter
83 self
.__item
_separator
= item_separator
86 self
.__pretty
_printer
.write_raw_str(self
.__start
_delimiter
)
87 self
.__pretty
_printer
.adjust_indent(1)
90 def item(self
, value
: Any
):
91 self
.__pretty
_printer
.write(value
)
92 self
.__pretty
_printer
.write_raw_str(self
.__item
_separator
)
94 def __exit__(self
, exc_type
, exc_value
, traceback
):
95 self
.__pretty
_printer
.adjust_indent(-1)
96 self
.__pretty
_printer
.write_raw_str(self
.__end
_delimiter
)
99 class MappingPrettyPrinter
:
101 pretty_printer
: "PrettyPrinter",
102 start_delimiter
: str = '[\n',
103 end_delimiter
: str = ']',
104 key_value_separator
: str = ': ',
105 item_separator
: str = ',\n'):
106 self
.__pretty
_printer
= pretty_printer
107 self
.__start
_delimiter
= start_delimiter
108 self
.__end
_delimiter
= end_delimiter
109 self
.__key
_value
_separator
= key_value_separator
110 self
.__item
_separator
= item_separator
113 self
.__pretty
_printer
.write_raw_str(self
.__start
_delimiter
)
114 self
.__pretty
_printer
.adjust_indent(1)
117 def item(self
, key
: Any
, value
: Any
):
118 self
.__pretty
_printer
.write(key
)
119 self
.__pretty
_printer
.write_raw_str(self
.__key
_value
_separator
)
120 self
.__pretty
_printer
.write(value
)
121 self
.__pretty
_printer
.write_raw_str(self
.__item
_separator
)
123 def __exit__(self
, exc_type
, exc_value
, traceback
):
124 self
.__pretty
_printer
.adjust_indent(-1)
125 self
.__pretty
_printer
.write_raw_str(self
.__end
_delimiter
)
128 class TypePrettyPrinter
:
130 pretty_printer
: "PrettyPrinter",
132 start_delimiter
: str = '(\n',
133 end_delimiter
: str = ')',
134 key_value_separator
: str = '=',
135 item_separator
: str = ',\n'):
136 self
.__pretty
_printer
= pretty_printer
138 self
.__start
_delimiter
= start_delimiter
139 self
.__end
_delimiter
= end_delimiter
140 self
.__key
_value
_separator
= key_value_separator
141 self
.__item
_separator
= item_separator
144 self
.__pretty
_printer
.write_raw_str(self
.__name
)
145 self
.__pretty
_printer
.write_raw_str(self
.__start
_delimiter
)
146 self
.__pretty
_printer
.adjust_indent(1)
149 def field(self
, key
: str, value
: Any
):
150 self
.__pretty
_printer
.write_raw_str(key
)
151 self
.__pretty
_printer
.write_raw_str(self
.__key
_value
_separator
)
152 self
.__pretty
_printer
.write(value
)
153 self
.__pretty
_printer
.write_raw_str(self
.__item
_separator
)
155 def try_field(self
, key
: str, value
: Callable
[[], Any
], exception
: Type
[Exception]):
156 self
.__pretty
_printer
.write_raw_str(key
)
157 self
.__pretty
_printer
.write_raw_str(self
.__key
_value
_separator
)
158 self
.__pretty
_printer
.try_write(value
, exception
)
159 self
.__pretty
_printer
.write_raw_str(self
.__item
_separator
)
161 def __exit__(self
, exc_type
, exc_value
, traceback
):
162 self
.__pretty
_printer
.adjust_indent(-1)
163 self
.__pretty
_printer
.write_raw_str(self
.__end
_delimiter
)
166 # pprint isn't good enough, it doesn't allow customization for types
168 __PRETTY_PRINT_OVERRIDES
: Dict
[type,
169 Callable
[["PrettyPrinter", Any
], None]] = {}
172 self
.__writer
= StringIO()
174 self
.__at
_line
_start
= True
176 def adjust_indent(self
, amount
: int):
177 self
.__depth
+= amount
181 self
.adjust_indent(1)
183 self
.adjust_indent(-1)
185 def write_raw_str(self
, s
: str):
188 self
.__at
_line
_start
= True
189 elif self
.__at
_line
_start
:
190 self
.__at
_line
_start
= False
191 self
.__writer
.write(' ' * (4 * self
.__depth
))
192 self
.__writer
.write(ch
)
194 def write(self
, obj
: Any
):
195 override
= self
.__PRETTY
_PRINT
_OVERRIDES
.get(type(obj
), None)
196 if override
is not None:
199 f
= getattr(obj
, "__pretty_print__", None)
203 self
.write_raw_str(repr(obj
))
205 def try_write(self
, f
: Callable
[[], Any
], exception
: Type
[Exception]):
209 self
.write_raw_str(f
"<failed with exception {exception.__name__}>")
213 def get_str(self
) -> str:
214 return self
.__writer
.getvalue()
217 def run(cls
, obj
: Any
) -> str:
220 return instance
.get_str()
223 def register_pretty_print_override(cls
, ty
: type, override
: Callable
[["PrettyPrinter", Any
], None]):
224 cls
.__PRETTY
_PRINT
_OVERRIDES
[ty
] = override
226 def type_pp(self
, name
: str, **kwargs
) -> TypePrettyPrinter
:
227 return TypePrettyPrinter(self
, name
, **kwargs
)
229 def mapping_pp(self
, **kwargs
) -> MappingPrettyPrinter
:
230 return MappingPrettyPrinter(self
, **kwargs
)
232 def sequence_pp(self
, **kwargs
) -> SequencePrettyPrinter
:
233 return SequencePrettyPrinter(self
, **kwargs
)
235 def __write_list(self
, obj
: List
[Any
]):
236 with self
.sequence_pp() as pp
:
240 __PRETTY_PRINT_OVERRIDES
[list] = __write_list
242 def __write_tuple(self
, obj
: List
[Any
]):
243 with self
.sequence_pp(start_delimiter
='(\n',
244 end_delimiter
=')',) as pp
:
248 __PRETTY_PRINT_OVERRIDES
[tuple] = __write_tuple
250 def __write_ordered_set(self
, obj
: OrderedSet
[Any
]):
251 with self
.sequence_pp(start_delimiter
='OrderedSet([\n',
252 end_delimiter
='])',) as pp
:
256 __PRETTY_PRINT_OVERRIDES
[OrderedSet
] = __write_ordered_set
258 def __write_dict(self
, obj
: Dict
[Any
, Any
]):
259 with self
.mapping_pp() as pp
:
260 for k
, v
in obj
.items():
263 __PRETTY_PRINT_OVERRIDES
[dict] = __write_dict
265 def __write_ellipsis(self
, obj
: Any
):
266 self
.write_raw_str("...")
268 __PRETTY_PRINT_OVERRIDES
[type(...)] = __write_ellipsis
271 def pretty_print(obj
: Any
, **kwargs
):
272 print(PrettyPrinter
.run(obj
), **kwargs
)