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"]:
38 def all_bugs(bz
: Bugzilla
) -> Iterator
[Bug
]:
42 if hasattr(os
, "ctermid"):
43 term
= open(os
.ctermid(), "wt", encoding
="utf-8")
45 term
= open("CONOUT$", "wt", encoding
="utf-8")
49 # no terminal available
51 try: # can't use `with` since it doesn't work with None
53 bugs
= list(range(chunk_start
, chunk_start
+ chunk_size
))
54 bugs
= bz
.getbugs(bugs
)
55 chunk_start
+= chunk_size
56 # progress indicator, should go to terminal
58 print("bugs loaded", len(bugs
), chunk_start
, flush
=True,
68 class SequencePrettyPrinter
:
70 pretty_printer
: "PrettyPrinter",
71 start_delimiter
: str = '[\n',
72 end_delimiter
: str = ']',
73 item_separator
: str = ',\n'):
74 self
.__pretty
_printer
= pretty_printer
75 self
.__start
_delimiter
= start_delimiter
76 self
.__end
_delimiter
= end_delimiter
77 self
.__item
_separator
= item_separator
80 self
.__pretty
_printer
.write_raw_str(self
.__start
_delimiter
)
81 self
.__pretty
_printer
.adjust_indent(1)
84 def item(self
, value
: Any
):
85 self
.__pretty
_printer
.write(value
)
86 self
.__pretty
_printer
.write_raw_str(self
.__item
_separator
)
88 def __exit__(self
, exc_type
, exc_value
, traceback
):
89 self
.__pretty
_printer
.adjust_indent(-1)
90 self
.__pretty
_printer
.write_raw_str(self
.__end
_delimiter
)
93 class MappingPrettyPrinter
:
95 pretty_printer
: "PrettyPrinter",
96 start_delimiter
: str = '[\n',
97 end_delimiter
: str = ']',
98 key_value_separator
: str = ': ',
99 item_separator
: str = ',\n'):
100 self
.__pretty
_printer
= pretty_printer
101 self
.__start
_delimiter
= start_delimiter
102 self
.__end
_delimiter
= end_delimiter
103 self
.__key
_value
_separator
= key_value_separator
104 self
.__item
_separator
= item_separator
107 self
.__pretty
_printer
.write_raw_str(self
.__start
_delimiter
)
108 self
.__pretty
_printer
.adjust_indent(1)
111 def item(self
, key
: Any
, value
: Any
):
112 self
.__pretty
_printer
.write(key
)
113 self
.__pretty
_printer
.write_raw_str(self
.__key
_value
_separator
)
114 self
.__pretty
_printer
.write(value
)
115 self
.__pretty
_printer
.write_raw_str(self
.__item
_separator
)
117 def __exit__(self
, exc_type
, exc_value
, traceback
):
118 self
.__pretty
_printer
.adjust_indent(-1)
119 self
.__pretty
_printer
.write_raw_str(self
.__end
_delimiter
)
122 class TypePrettyPrinter
:
124 pretty_printer
: "PrettyPrinter",
126 start_delimiter
: str = '(\n',
127 end_delimiter
: str = ')',
128 key_value_separator
: str = '=',
129 item_separator
: str = ',\n'):
130 self
.__pretty
_printer
= pretty_printer
132 self
.__start
_delimiter
= start_delimiter
133 self
.__end
_delimiter
= end_delimiter
134 self
.__key
_value
_separator
= key_value_separator
135 self
.__item
_separator
= item_separator
138 self
.__pretty
_printer
.write_raw_str(self
.__name
)
139 self
.__pretty
_printer
.write_raw_str(self
.__start
_delimiter
)
140 self
.__pretty
_printer
.adjust_indent(1)
143 def field(self
, key
: str, value
: Any
):
144 self
.__pretty
_printer
.write_raw_str(key
)
145 self
.__pretty
_printer
.write_raw_str(self
.__key
_value
_separator
)
146 self
.__pretty
_printer
.write(value
)
147 self
.__pretty
_printer
.write_raw_str(self
.__item
_separator
)
149 def try_field(self
, key
: str, value
: Callable
[[], Any
], exception
: Type
[Exception]):
150 self
.__pretty
_printer
.write_raw_str(key
)
151 self
.__pretty
_printer
.write_raw_str(self
.__key
_value
_separator
)
152 self
.__pretty
_printer
.try_write(value
, exception
)
153 self
.__pretty
_printer
.write_raw_str(self
.__item
_separator
)
155 def __exit__(self
, exc_type
, exc_value
, traceback
):
156 self
.__pretty
_printer
.adjust_indent(-1)
157 self
.__pretty
_printer
.write_raw_str(self
.__end
_delimiter
)
160 # pprint isn't good enough, it doesn't allow customization for types
162 __PRETTY_PRINT_OVERRIDES
: Dict
[type,
163 Callable
[["PrettyPrinter", Any
], None]] = {}
166 self
.__writer
= StringIO()
168 self
.__at
_line
_start
= True
170 def adjust_indent(self
, amount
: int):
171 self
.__depth
+= amount
175 self
.adjust_indent(1)
177 self
.adjust_indent(-1)
179 def write_raw_str(self
, s
: str):
182 self
.__at
_line
_start
= True
183 elif self
.__at
_line
_start
:
184 self
.__at
_line
_start
= False
185 self
.__writer
.write(' ' * (4 * self
.__depth
))
186 self
.__writer
.write(ch
)
188 def write(self
, obj
: Any
):
189 override
= self
.__PRETTY
_PRINT
_OVERRIDES
.get(type(obj
), None)
190 if override
is not None:
193 f
= getattr(obj
, "__pretty_print__", None)
197 self
.write_raw_str(repr(obj
))
199 def try_write(self
, f
: Callable
[[], Any
], exception
: Type
[Exception]):
203 self
.write_raw_str(f
"<failed with exception {exception.__name__}>")
207 def get_str(self
) -> str:
208 return self
.__writer
.getvalue()
211 def run(cls
, obj
: Any
) -> str:
214 return instance
.get_str()
217 def register_pretty_print_override(cls
, ty
: type, override
: Callable
[["PrettyPrinter", Any
], None]):
218 cls
.__PRETTY
_PRINT
_OVERRIDES
[ty
] = override
220 def type_pp(self
, name
: str, **kwargs
) -> TypePrettyPrinter
:
221 return TypePrettyPrinter(self
, name
, **kwargs
)
223 def mapping_pp(self
, **kwargs
) -> MappingPrettyPrinter
:
224 return MappingPrettyPrinter(self
, **kwargs
)
226 def sequence_pp(self
, **kwargs
) -> SequencePrettyPrinter
:
227 return SequencePrettyPrinter(self
, **kwargs
)
229 def __write_list(self
, obj
: List
[Any
]):
230 with self
.sequence_pp() as pp
:
234 __PRETTY_PRINT_OVERRIDES
[list] = __write_list
236 def __write_tuple(self
, obj
: List
[Any
]):
237 with self
.sequence_pp(start_delimiter
='(\n',
238 end_delimiter
=')',) as pp
:
242 __PRETTY_PRINT_OVERRIDES
[tuple] = __write_tuple
244 def __write_ordered_set(self
, obj
: OrderedSet
[Any
]):
245 with self
.sequence_pp(start_delimiter
='OrderedSet([\n',
246 end_delimiter
='])',) as pp
:
250 __PRETTY_PRINT_OVERRIDES
[OrderedSet
] = __write_ordered_set
252 def __write_dict(self
, obj
: Dict
[Any
, Any
]):
253 with self
.mapping_pp() as pp
:
254 for k
, v
in obj
.items():
257 __PRETTY_PRINT_OVERRIDES
[dict] = __write_dict
259 def __write_ellipsis(self
, obj
: Any
):
260 self
.write_raw_str("...")
262 __PRETTY_PRINT_OVERRIDES
[type(...)] = __write_ellipsis
265 def pretty_print(obj
: Any
, **kwargs
):
266 print(PrettyPrinter
.run(obj
), **kwargs
)