reykit 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
reykit/rmonkey.py ADDED
@@ -0,0 +1,341 @@
1
+ # !/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ @Time : 2023-03-19 19:36:47
6
+ @Author : Rey
7
+ @Contact : reyxbo@163.com
8
+ @Explain : Monkey patch methods.
9
+ """
10
+
11
+
12
+ from __future__ import annotations
13
+
14
+
15
+ __all__ = (
16
+ 'monkey_patch_sqlalchemy_result_more_fetch',
17
+ 'monkey_patch_sqlalchemy_row_index_field',
18
+ 'monkey_patch_pprint_modify_width_judgment'
19
+ )
20
+
21
+
22
+ def monkey_patch_sqlalchemy_result_more_fetch():
23
+ """
24
+ Monkey patch of package `sqlalchemy`, add more fetch methods to `CursorResult` object.
25
+
26
+ Returns
27
+ -------
28
+ Modified type.
29
+ """
30
+
31
+
32
+ from typing import Optional
33
+ from sqlalchemy.engine.cursor import CursorResult
34
+ from pandas import DataFrame, NA, concat
35
+
36
+ from .rstdout import echo
37
+ from .rtable import (
38
+ to_table,
39
+ to_dict,
40
+ to_list,
41
+ to_df,
42
+ to_json,
43
+ to_text,
44
+ to_sql,
45
+ to_html,
46
+ to_csv,
47
+ to_excel
48
+ )
49
+ from .rtime import time_to
50
+
51
+
52
+ # Fetch result as table in 'list[dict]' format.
53
+ CursorResult.fetch_table = to_table
54
+
55
+ # Fetch result as dictionary.
56
+ CursorResult.fetch_dict = to_dict
57
+
58
+ # Fetch result as list.
59
+ CursorResult.fetch_list = to_list
60
+
61
+ # Fetch result as DataFrame object.
62
+ CursorResult.fetch_df = to_df
63
+
64
+ # Fetch result as JSON string.
65
+ CursorResult.fetch_json = to_json
66
+
67
+ # Fetch result as text.
68
+ CursorResult.fetch_text = to_text
69
+
70
+ # Fetch result as SQL string.
71
+ CursorResult.fetch_sql = to_sql
72
+
73
+ # Fetch result as HTML string.
74
+ CursorResult.fetch_html = to_html
75
+
76
+ # Fetch result as save csv format file.
77
+ CursorResult.fetch_csv = to_csv
78
+
79
+ # Fetch result as save excel file.
80
+ CursorResult.fetch_excel = to_excel
81
+
82
+
83
+ # Print result.
84
+ def method_show(self: RResult, limit: Optional[int] = None) -> None:
85
+ """
86
+ Print result.
87
+
88
+ Parameters
89
+ ----------
90
+ limit : Limit row.
91
+ - `>0`: Limit first few row.
92
+ - `<0`: Limit last few row.
93
+ """
94
+
95
+ # Handle parameter.
96
+ if limit is None:
97
+ limit = 0
98
+
99
+ # Convert.
100
+ df: DataFrame = self.fetch_df()
101
+ df = df.applymap(time_to, raising=False)
102
+ df = df.astype(str)
103
+ df.replace(['NaT', '<NA>'], 'None', inplace=True)
104
+ row_len, column_len = df.shape
105
+
106
+ # Create omit row.
107
+ omit_row = (('...',) * column_len,)
108
+ omit_row = DataFrame(
109
+ omit_row,
110
+ columns=df.columns
111
+ )
112
+
113
+ # Limit.
114
+ if (
115
+ limit > 0
116
+ and limit < row_len
117
+ ):
118
+ df = df.head(limit)
119
+ omit_row.index = (row_len - 1,)
120
+ df = concat((df, omit_row))
121
+ elif (
122
+ limit < 0
123
+ and -limit < row_len
124
+ ):
125
+ df = df.tail(-limit)
126
+ omit_row.index = (0,)
127
+ df = concat((omit_row, df))
128
+
129
+ # Print.
130
+ echo(df, title='Result')
131
+
132
+
133
+ CursorResult.show = method_show
134
+
135
+
136
+ # Whether is exist.
137
+ @property
138
+ def method_exist(self: RResult) -> bool:
139
+ """
140
+ Judge whether is exist row.
141
+
142
+ Returns
143
+ -------
144
+ Judge result.
145
+ """
146
+
147
+ # Judge.
148
+ judge = self.rowcount != 0
149
+
150
+ return judge
151
+
152
+
153
+ CursorResult.exist = method_exist
154
+
155
+
156
+ # Whether is empty.
157
+ @property
158
+ def method_empty(self: RResult) -> bool:
159
+ """
160
+ Judge whether is empty row.
161
+
162
+ Returns
163
+ -------
164
+ Judge result.
165
+ """
166
+
167
+ # Judge.
168
+ judge = self.rowcount == 0
169
+
170
+ return judge
171
+
172
+
173
+ CursorResult.empty = method_empty
174
+
175
+
176
+ # Update annotations.
177
+ class RResult(CursorResult):
178
+ """
179
+ Update based on `CursorResult` object, for annotation return value.
180
+ """
181
+
182
+ # Inherit document.
183
+ __doc__ = CursorResult.__doc__
184
+
185
+ # Add method.
186
+ fetch_table = to_table
187
+ fetch_dict = to_dict
188
+ fetch_list = to_list
189
+ fetch_df = to_df
190
+ fetch_json = to_json
191
+ fetch_text = to_text
192
+ fetch_sql = to_sql
193
+ fetch_html = to_html
194
+ fetch_csv = to_csv
195
+ fetch_excel = to_excel
196
+ show = method_show
197
+ exist = method_exist
198
+ empty = method_empty
199
+
200
+
201
+ return RResult
202
+
203
+
204
+ def monkey_patch_sqlalchemy_row_index_field():
205
+ """
206
+ Monkey patch of package `sqlalchemy`, add index by field method to `Row` object.
207
+ """
208
+
209
+
210
+ from typing import Any, Union, overload
211
+ from sqlalchemy.engine.row import Row
212
+
213
+
214
+ # Define.
215
+ @overload
216
+ def __getitem__(self, index: Union[str, int]) -> Any: ...
217
+
218
+ @overload
219
+ def __getitem__(self, index: slice) -> tuple: ...
220
+
221
+ def __getitem__(self, index: Union[str, int, slice]) -> Union[Any, tuple]:
222
+ """
223
+ Index row value.
224
+
225
+ Parameters
226
+ ----------
227
+ index : Field name or subscript or slice.
228
+
229
+ Returns
230
+ -------
231
+ Index result.
232
+ """
233
+
234
+ # Index.
235
+ if index.__class__ == str:
236
+ value = self._mapping[index]
237
+ else:
238
+ value = self._data[index]
239
+
240
+ return value
241
+
242
+
243
+ # Add.
244
+ Row.__getitem__ = __getitem__
245
+
246
+
247
+ def monkey_patch_pprint_modify_width_judgment() -> None:
248
+ """
249
+ Monkey patch of package `pprint`, modify the chinese width judgment.
250
+ """
251
+
252
+
253
+ from pprint import PrettyPrinter, _recursion
254
+
255
+
256
+ # New method.
257
+ def _format(_self, obj, stream, indent, allowance, context, level):
258
+
259
+
260
+ from .rtext import get_width
261
+
262
+
263
+ objid = id(obj)
264
+ if objid in context:
265
+ stream.write(_recursion(obj))
266
+ _self._recursive = True
267
+ _self._readable = False
268
+ return
269
+ rep = _self._repr(obj, context, level)
270
+ max_width = _self._width - indent - allowance
271
+ width = get_width(rep)
272
+ if width > max_width:
273
+ p = _self._dispatch.get(type(obj).__repr__, None)
274
+ if p is not None:
275
+ context[objid] = 1
276
+ p(_self, obj, stream, indent, allowance, context, level + 1)
277
+ del context[objid]
278
+ return
279
+ elif isinstance(obj, dict):
280
+ context[objid] = 1
281
+ _self._pprint_dict(obj, stream, indent, allowance,
282
+ context, level + 1)
283
+ del context[objid]
284
+ return
285
+ stream.write(rep)
286
+
287
+
288
+ # Modify.
289
+ PrettyPrinter._format = _format
290
+
291
+
292
+ def monkey_path_pil_image_get_bytes():
293
+ """
294
+ Monkey patch of package `PIL`, add get bytes method to `Image` object.
295
+
296
+ Returns
297
+ -------
298
+ Image object.
299
+ """
300
+
301
+
302
+ from PIL.Image import Image
303
+ from io import BytesIO
304
+
305
+
306
+ # Define.
307
+ def method_get_bytes(self: Image) -> bytes:
308
+ """
309
+ Get image bytes data.
310
+
311
+ Returns
312
+ -------
313
+ Image bytes data.
314
+ """
315
+
316
+ # Extract.
317
+ bytes_io = BytesIO()
318
+ self.save(bytes_io, 'JPEG')
319
+ image_bytes = bytes_io.getvalue()
320
+
321
+ return image_bytes
322
+
323
+
324
+ # Add.
325
+ Image.get_bytes = method_get_bytes
326
+
327
+
328
+ # Update annotations.
329
+ class RImage(Image):
330
+ """
331
+ Update based on `Image` object, for annotation return value.
332
+ """
333
+
334
+ # Inherit document.
335
+ __doc__ = Image.__doc__
336
+
337
+ # Add method.
338
+ get_bytes = method_get_bytes
339
+
340
+
341
+ return RImage