dukit 0.1.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.
- dukit/__init__.py +108 -0
- dukit/_test_utils.py +374 -0
- dukit/diffing.py +1461 -0
- dukit/excel.py +134 -0
- dukit/interfaces.py +160 -0
- dukit/os.py +280 -0
- dukit/pandas.py +563 -0
- dukit/py.typed +0 -0
- dukit/qlang/__init__.py +61 -0
- dukit/qlang/engine.py +447 -0
- dukit/qlang/symbols.py +6867 -0
- dukit/typing.py +683 -0
- dukit/utils.py +288 -0
- dukit-0.1.0.dist-info/METADATA +113 -0
- dukit-0.1.0.dist-info/RECORD +16 -0
- dukit-0.1.0.dist-info/WHEEL +4 -0
dukit/pandas.py
ADDED
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import numpy as np
|
|
4
|
+
import datetime
|
|
5
|
+
import copy
|
|
6
|
+
from .utils import log
|
|
7
|
+
from .typing import date_
|
|
8
|
+
|
|
9
|
+
def get_df() -> pd.DataFrame:
|
|
10
|
+
"""
|
|
11
|
+
Returns a small sample dataframe containing very messy fake medical data.
|
|
12
|
+
"""
|
|
13
|
+
data = {
|
|
14
|
+
'ID': [
|
|
15
|
+
10001,
|
|
16
|
+
10002,
|
|
17
|
+
10003,
|
|
18
|
+
20001,
|
|
19
|
+
20002,
|
|
20
|
+
20003,
|
|
21
|
+
30001,
|
|
22
|
+
30002,
|
|
23
|
+
30003,
|
|
24
|
+
30004,
|
|
25
|
+
30005,
|
|
26
|
+
],
|
|
27
|
+
'name': [
|
|
28
|
+
'John Doe',
|
|
29
|
+
'Jane Smith',
|
|
30
|
+
'Alice Johnson',
|
|
31
|
+
'Bob Brown',
|
|
32
|
+
'eva white',
|
|
33
|
+
'Frank miller',
|
|
34
|
+
'Grace TAYLOR',
|
|
35
|
+
'Harry Clark',
|
|
36
|
+
'IVY GREEN',
|
|
37
|
+
'JAck Williams',
|
|
38
|
+
'john Doe',
|
|
39
|
+
],
|
|
40
|
+
'date of birth': [
|
|
41
|
+
pd.to_datetime('1995-01-02'),
|
|
42
|
+
datetime.datetime(1990, 9, 14),
|
|
43
|
+
'1985.08.23',
|
|
44
|
+
'19800406',
|
|
45
|
+
'05-11-2007',
|
|
46
|
+
pd.to_datetime('06-30-1983').date(),
|
|
47
|
+
datetime.datetime(1975, 5, 28).date(),
|
|
48
|
+
'1960Mar08',
|
|
49
|
+
'1955-Jan-09',
|
|
50
|
+
'1950 Sep 10',
|
|
51
|
+
'1945 October 11',
|
|
52
|
+
],
|
|
53
|
+
'age': [
|
|
54
|
+
-25,
|
|
55
|
+
'30',
|
|
56
|
+
np.nan,
|
|
57
|
+
pd.NaT,
|
|
58
|
+
'40.0',
|
|
59
|
+
'forty-five',
|
|
60
|
+
'nan',
|
|
61
|
+
'unk',
|
|
62
|
+
'',
|
|
63
|
+
'unknown',
|
|
64
|
+
35,
|
|
65
|
+
],
|
|
66
|
+
'gender': [
|
|
67
|
+
'M',
|
|
68
|
+
'F',
|
|
69
|
+
'Female',
|
|
70
|
+
'Male',
|
|
71
|
+
'Other',
|
|
72
|
+
'm',
|
|
73
|
+
'ff',
|
|
74
|
+
'NaN',
|
|
75
|
+
None,
|
|
76
|
+
'Mal',
|
|
77
|
+
'female',
|
|
78
|
+
],
|
|
79
|
+
'height': [
|
|
80
|
+
170,
|
|
81
|
+
'175.5cm',
|
|
82
|
+
None,
|
|
83
|
+
'280',
|
|
84
|
+
'NULL',
|
|
85
|
+
'185',
|
|
86
|
+
'1',
|
|
87
|
+
'6ft 1in',
|
|
88
|
+
-10,
|
|
89
|
+
'',
|
|
90
|
+
200,
|
|
91
|
+
],
|
|
92
|
+
'weight': [
|
|
93
|
+
70.2,
|
|
94
|
+
'68',
|
|
95
|
+
'72.5lb',
|
|
96
|
+
'na',
|
|
97
|
+
'',
|
|
98
|
+
'75kg',
|
|
99
|
+
None,
|
|
100
|
+
'80.3',
|
|
101
|
+
'130lbs',
|
|
102
|
+
'1e2',
|
|
103
|
+
-65,
|
|
104
|
+
],
|
|
105
|
+
'bp systole': [
|
|
106
|
+
' 20 ',
|
|
107
|
+
130,
|
|
108
|
+
'<NA>',
|
|
109
|
+
-np.inf,
|
|
110
|
+
'135mmhg',
|
|
111
|
+
'125.5',
|
|
112
|
+
'NAN',
|
|
113
|
+
'122,3',
|
|
114
|
+
'',
|
|
115
|
+
130,
|
|
116
|
+
'45',
|
|
117
|
+
],
|
|
118
|
+
'bp diastole': [
|
|
119
|
+
80,
|
|
120
|
+
'85',
|
|
121
|
+
'N/A',
|
|
122
|
+
'90mmHg',
|
|
123
|
+
np.nan,
|
|
124
|
+
'75',
|
|
125
|
+
'NaN',
|
|
126
|
+
pd.NA,
|
|
127
|
+
'95',
|
|
128
|
+
'0',
|
|
129
|
+
'None ',
|
|
130
|
+
],
|
|
131
|
+
'cholesterol': [
|
|
132
|
+
'Normal',
|
|
133
|
+
'Highe',
|
|
134
|
+
'NaN',
|
|
135
|
+
'GOOD',
|
|
136
|
+
'n.a.',
|
|
137
|
+
'High',
|
|
138
|
+
'Normal',
|
|
139
|
+
'n/a',
|
|
140
|
+
'high',
|
|
141
|
+
'',
|
|
142
|
+
'Normal',
|
|
143
|
+
],
|
|
144
|
+
'diabetes': [
|
|
145
|
+
False,
|
|
146
|
+
'true',
|
|
147
|
+
'N/A',
|
|
148
|
+
0,
|
|
149
|
+
'1',
|
|
150
|
+
'Yes',
|
|
151
|
+
'NO',
|
|
152
|
+
None,
|
|
153
|
+
'NaN',
|
|
154
|
+
'n',
|
|
155
|
+
True,
|
|
156
|
+
],
|
|
157
|
+
'dose': [
|
|
158
|
+
'10kg',
|
|
159
|
+
'NaN',
|
|
160
|
+
'15 mg once a day',
|
|
161
|
+
'20mg',
|
|
162
|
+
'20 Mg',
|
|
163
|
+
'25g',
|
|
164
|
+
'NaN',
|
|
165
|
+
None,
|
|
166
|
+
'30 MG',
|
|
167
|
+
' 35 ',
|
|
168
|
+
'40ml',
|
|
169
|
+
],
|
|
170
|
+
}
|
|
171
|
+
df = pd.DataFrame(data).convert_dtypes()
|
|
172
|
+
df.columns = df.columns.to_series().convert_dtypes()
|
|
173
|
+
df.index = df.index.to_series().convert_dtypes()
|
|
174
|
+
return df
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def get_dfs():
|
|
179
|
+
df1 = pd.DataFrame({
|
|
180
|
+
'id': [
|
|
181
|
+
10001,
|
|
182
|
+
10002,
|
|
183
|
+
20001,
|
|
184
|
+
30001,
|
|
185
|
+
],
|
|
186
|
+
'name': [
|
|
187
|
+
'John Doe',
|
|
188
|
+
'Jane Smith',
|
|
189
|
+
'Alice Johnson',
|
|
190
|
+
'Bob Brown',
|
|
191
|
+
],
|
|
192
|
+
'age': [
|
|
193
|
+
25,
|
|
194
|
+
30,
|
|
195
|
+
35,
|
|
196
|
+
40,
|
|
197
|
+
],
|
|
198
|
+
})
|
|
199
|
+
df2 = pd.DataFrame({
|
|
200
|
+
'id': [
|
|
201
|
+
10002,
|
|
202
|
+
20001,
|
|
203
|
+
20001,
|
|
204
|
+
30001,
|
|
205
|
+
30001,
|
|
206
|
+
30001,
|
|
207
|
+
],
|
|
208
|
+
'medication': [
|
|
209
|
+
'Aspirin',
|
|
210
|
+
'Ibuprofen',
|
|
211
|
+
'Paracetamol',
|
|
212
|
+
'Amoxicillin',
|
|
213
|
+
'Ciprofloxacin',
|
|
214
|
+
'Metformin',
|
|
215
|
+
],
|
|
216
|
+
'dose': [
|
|
217
|
+
100,
|
|
218
|
+
200,
|
|
219
|
+
pd.NA,
|
|
220
|
+
250,
|
|
221
|
+
500,
|
|
222
|
+
1000,
|
|
223
|
+
],
|
|
224
|
+
'unit': [
|
|
225
|
+
'mg',
|
|
226
|
+
'mg',
|
|
227
|
+
'',
|
|
228
|
+
'mg',
|
|
229
|
+
'ml',
|
|
230
|
+
'mg',
|
|
231
|
+
]
|
|
232
|
+
})
|
|
233
|
+
return df1, df2
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def deduplicate(obj, name='object', verbosity=3):
|
|
239
|
+
"""
|
|
240
|
+
Deduplicate entries in object which can be converted
|
|
241
|
+
to pandas Series by appending consecutive numbers.
|
|
242
|
+
Note that the entries are converted to strings in the process.
|
|
243
|
+
"""
|
|
244
|
+
|
|
245
|
+
obj = copy.deepcopy(obj)
|
|
246
|
+
class_orig = obj.__class__
|
|
247
|
+
obj = _to_series(obj)
|
|
248
|
+
|
|
249
|
+
#Values can only be deduplicated if index is unique
|
|
250
|
+
if not obj.index.is_unique:
|
|
251
|
+
msg = (
|
|
252
|
+
f'info: duplicates found in index of {name}.'
|
|
253
|
+
' deduplicating by appending consecutive numbers.'
|
|
254
|
+
)
|
|
255
|
+
log(msg, 'dk.pandas.deduplicate', verbosity)
|
|
256
|
+
obj.index = _deduplicate(_to_series(obj.index))
|
|
257
|
+
|
|
258
|
+
rounds = 0
|
|
259
|
+
while not obj.is_unique:
|
|
260
|
+
if rounds == 0:
|
|
261
|
+
msg = (
|
|
262
|
+
f'debug: duplicates found in {name}.'
|
|
263
|
+
' deduplicating by appending consecutive numbers.'
|
|
264
|
+
)
|
|
265
|
+
else:
|
|
266
|
+
msg = (
|
|
267
|
+
f'debug: duplicates still found in {name} after'
|
|
268
|
+
f' {rounds} deduplication rounds.'
|
|
269
|
+
' deduplicating again by appending consecutive numbers.'
|
|
270
|
+
)
|
|
271
|
+
log(msg, 'dk.pandas.deduplicate', verbosity)
|
|
272
|
+
obj = _deduplicate(obj)
|
|
273
|
+
rounds += 1
|
|
274
|
+
|
|
275
|
+
if not isinstance(obj, class_orig):
|
|
276
|
+
try:
|
|
277
|
+
obj = class_orig(obj)
|
|
278
|
+
except Exception as e:
|
|
279
|
+
msg = (
|
|
280
|
+
'Error: could not convert deduplicated object'
|
|
281
|
+
f' back to original type {class_orig}: {e}'
|
|
282
|
+
)
|
|
283
|
+
log(msg, 'dk.pandas.deduplicate', verbosity)
|
|
284
|
+
|
|
285
|
+
return obj
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _to_series(obj, verbosity=3):
|
|
289
|
+
try:
|
|
290
|
+
obj = pd.Series(obj, dtype=str)
|
|
291
|
+
except Exception as e:
|
|
292
|
+
msg = (
|
|
293
|
+
'Error: could not convert input of type'
|
|
294
|
+
f' {type(obj)} to Series: {e}'
|
|
295
|
+
)
|
|
296
|
+
log(msg, 'dk.pandas._to_series', verbosity)
|
|
297
|
+
return obj
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def _deduplicate(series):
|
|
301
|
+
cumulative_count = series.groupby(series).cumcount()
|
|
302
|
+
duplicates_mask = series.index[cumulative_count > 0]
|
|
303
|
+
duplicates = series[duplicates_mask]
|
|
304
|
+
duplicates_new = (
|
|
305
|
+
duplicates.astype(str)
|
|
306
|
+
+ '_'
|
|
307
|
+
+ cumulative_count[duplicates_mask].astype(str)
|
|
308
|
+
)
|
|
309
|
+
series[duplicates_mask] = duplicates_new
|
|
310
|
+
return series
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def flatten(
|
|
316
|
+
df: pd.DataFrame,
|
|
317
|
+
on: str,
|
|
318
|
+
template='{colname} #{counter}',
|
|
319
|
+
):
|
|
320
|
+
|
|
321
|
+
#aggregate repeating rows into lists
|
|
322
|
+
df = df.groupby(on).agg(list)
|
|
323
|
+
|
|
324
|
+
#create new cols from lists
|
|
325
|
+
cols_new = []
|
|
326
|
+
for col in df.columns:
|
|
327
|
+
n_max = df[col].apply(lambda x: len(x)).max()
|
|
328
|
+
cols_flat = [
|
|
329
|
+
template.format(counter=i + 1, colname=col)
|
|
330
|
+
for i
|
|
331
|
+
in range(n_max)
|
|
332
|
+
]
|
|
333
|
+
split = pd.DataFrame(df[col].to_list(), columns=cols_flat)
|
|
334
|
+
split.index = df.index
|
|
335
|
+
df = df.merge(
|
|
336
|
+
split,
|
|
337
|
+
left_index=True,
|
|
338
|
+
right_index=True,
|
|
339
|
+
how='left',
|
|
340
|
+
)
|
|
341
|
+
cols_new += cols_flat
|
|
342
|
+
|
|
343
|
+
df = df[cols_new]
|
|
344
|
+
df.insert(0, on, df.index)
|
|
345
|
+
df.reset_index(drop=True, inplace=True)
|
|
346
|
+
|
|
347
|
+
return df
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def stagger(
|
|
352
|
+
df: pd.DataFrame,
|
|
353
|
+
on: str,
|
|
354
|
+
template='#{counter} {colname}',
|
|
355
|
+
separator_col='#{counter}'
|
|
356
|
+
):
|
|
357
|
+
|
|
358
|
+
duplicates_max = df[on].value_counts().max()
|
|
359
|
+
df = df.groupby(on).agg(list)
|
|
360
|
+
cols = df.columns.tolist()
|
|
361
|
+
df_new = pd.DataFrame(
|
|
362
|
+
df.index,
|
|
363
|
+
index=df.index,
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
for i in range(duplicates_max):
|
|
367
|
+
if separator_col:
|
|
368
|
+
separator_vals = pd.Series(
|
|
369
|
+
'',
|
|
370
|
+
index=df.index,
|
|
371
|
+
name=separator_col.format(counter=i + 1),
|
|
372
|
+
)
|
|
373
|
+
df_new = pd.concat([df_new, separator_vals], axis=1)
|
|
374
|
+
for col in cols:
|
|
375
|
+
if col == on:
|
|
376
|
+
continue
|
|
377
|
+
col_new = df[col].apply(lambda x: _get_from_list(x, i))
|
|
378
|
+
col_new.name = template.format(counter=i + 1, colname=col)
|
|
379
|
+
df_new = pd.concat([df_new, col_new], axis=1)
|
|
380
|
+
|
|
381
|
+
df_new.reset_index(drop=True, inplace=True)
|
|
382
|
+
|
|
383
|
+
return df_new
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def _get_from_list(x, i):
|
|
387
|
+
if len(x) > i:
|
|
388
|
+
return x[i]
|
|
389
|
+
else:
|
|
390
|
+
return None
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def embed(
|
|
395
|
+
df: pd.DataFrame,
|
|
396
|
+
on: str,
|
|
397
|
+
colname='',
|
|
398
|
+
template='{colname} #{counter}',
|
|
399
|
+
line_start='',
|
|
400
|
+
separator=':',
|
|
401
|
+
spacer='\u00A0', #non-breaking space
|
|
402
|
+
line_stop='\n',
|
|
403
|
+
):
|
|
404
|
+
|
|
405
|
+
combined_cols_str = pd.DataFrame({
|
|
406
|
+
on: df[on],
|
|
407
|
+
colname: ''
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
len_max_cols = (
|
|
411
|
+
df
|
|
412
|
+
.columns
|
|
413
|
+
.to_series()
|
|
414
|
+
.astype('string')
|
|
415
|
+
.str
|
|
416
|
+
.len()
|
|
417
|
+
.max()
|
|
418
|
+
)
|
|
419
|
+
for col in df.columns:
|
|
420
|
+
if col == on:
|
|
421
|
+
continue
|
|
422
|
+
len_spacer = (
|
|
423
|
+
len_max_cols
|
|
424
|
+
- len(str(col))
|
|
425
|
+
+ 1
|
|
426
|
+
)
|
|
427
|
+
combined_cols_str[colname] += (
|
|
428
|
+
line_start
|
|
429
|
+
+ str(col)
|
|
430
|
+
+ separator
|
|
431
|
+
+ spacer * len_spacer
|
|
432
|
+
+ df[col].apply(str)
|
|
433
|
+
+ line_stop
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
df_new = flatten(
|
|
437
|
+
combined_cols_str,
|
|
438
|
+
on=on,
|
|
439
|
+
template=template,
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
return df_new
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def collapse(
|
|
447
|
+
df: pd.DataFrame,
|
|
448
|
+
on: str,
|
|
449
|
+
template='{colname}',
|
|
450
|
+
line_start='#',
|
|
451
|
+
line_stop='\n',
|
|
452
|
+
):
|
|
453
|
+
df = df.groupby(on).agg(list)
|
|
454
|
+
df = df.map(lambda x: _to_lines(x, line_start, line_stop))
|
|
455
|
+
df.columns = [template.format(colname=col) for col in df.columns]
|
|
456
|
+
df.insert(0, on, df.index)
|
|
457
|
+
df.reset_index(drop=True, inplace=True)
|
|
458
|
+
return df
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def _to_lines(
|
|
462
|
+
x,
|
|
463
|
+
line_start='#',
|
|
464
|
+
line_stop='\n',
|
|
465
|
+
):
|
|
466
|
+
if not isinstance(x, list):
|
|
467
|
+
return x
|
|
468
|
+
if len(x) == 1:
|
|
469
|
+
return x[0]
|
|
470
|
+
else:
|
|
471
|
+
x_str = ''
|
|
472
|
+
for i, item in enumerate(x):
|
|
473
|
+
x_str += f'{line_start}{i + 1}: {item}{line_stop}'
|
|
474
|
+
return x_str
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def transpose(
|
|
479
|
+
df: pd.DataFrame,
|
|
480
|
+
header='uid',
|
|
481
|
+
) -> pd.DataFrame:
|
|
482
|
+
|
|
483
|
+
cols_old = df.columns
|
|
484
|
+
cols_new = df[header].values
|
|
485
|
+
|
|
486
|
+
df = df.T
|
|
487
|
+
df.columns = cols_new
|
|
488
|
+
df.insert(0, header, cols_old)
|
|
489
|
+
df.drop(header, axis=0, inplace=True)
|
|
490
|
+
df.reset_index(drop=True, inplace=True)
|
|
491
|
+
|
|
492
|
+
return df
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
def date_delta(
|
|
497
|
+
df,
|
|
498
|
+
reference_date=None,
|
|
499
|
+
reference_col=None,
|
|
500
|
+
verbosity=3,
|
|
501
|
+
):
|
|
502
|
+
"""
|
|
503
|
+
Calculates the number of days
|
|
504
|
+
between a reference date or col
|
|
505
|
+
and all other cols in the df.
|
|
506
|
+
"""
|
|
507
|
+
|
|
508
|
+
df = df.copy().map(date_).convert_dtypes()
|
|
509
|
+
|
|
510
|
+
for col in df.columns:
|
|
511
|
+
if df[col].isna().all():
|
|
512
|
+
df.drop(columns=col, inplace=True)
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
if reference_date is None and reference_col is None:
|
|
516
|
+
msg = 'ERROR: no reference date or column provided'
|
|
517
|
+
log(msg, 'dk.date_delta', verbosity)
|
|
518
|
+
return df
|
|
519
|
+
|
|
520
|
+
if reference_date is not None and reference_col is not None:
|
|
521
|
+
msg = 'ERROR: both reference date and column provided'
|
|
522
|
+
log(msg, 'dk.date_delta', verbosity)
|
|
523
|
+
return df
|
|
524
|
+
|
|
525
|
+
if 'reference_date' in df.columns:
|
|
526
|
+
msg = 'WARNING: column "reference_date" already exists, overwriting'
|
|
527
|
+
log(msg, 'dk.date_delta', verbosity)
|
|
528
|
+
if reference_date is not None:
|
|
529
|
+
df['reference_date'] = date_(reference_date)
|
|
530
|
+
reference_col = str(reference_date)
|
|
531
|
+
else:
|
|
532
|
+
df['reference_date'] = df[reference_col].apply(date_)
|
|
533
|
+
|
|
534
|
+
cols_reorder = ['reference_date']
|
|
535
|
+
cols_reorder += [
|
|
536
|
+
col
|
|
537
|
+
for col
|
|
538
|
+
in df.columns
|
|
539
|
+
if col != 'reference_date'
|
|
540
|
+
]
|
|
541
|
+
df = df[cols_reorder]
|
|
542
|
+
|
|
543
|
+
for col in df.columns:
|
|
544
|
+
if col == 'reference_date':
|
|
545
|
+
continue
|
|
546
|
+
|
|
547
|
+
name = f'days from<br>{reference_col}<br>to<br>{col}'
|
|
548
|
+
if name in df.columns:
|
|
549
|
+
log(f'WARNING: column "{name}" already exists, overwriting',
|
|
550
|
+
'dk.date_delta', verbosity)
|
|
551
|
+
|
|
552
|
+
#difference only works with pd.NA,
|
|
553
|
+
#but x.days only works with pd.NaT.
|
|
554
|
+
#_fix_nas converts accordingly
|
|
555
|
+
col_formatted = df[col].apply(date_).apply(_fix_nas)
|
|
556
|
+
col_diff = col_formatted - df['reference_date']
|
|
557
|
+
df[name] = col_diff.fillna(pd.NaT).apply(lambda x: x.days)
|
|
558
|
+
|
|
559
|
+
return df
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def _fix_nas(x):
|
|
563
|
+
return pd.NA if x is pd.NaT else x
|
dukit/py.typed
ADDED
|
File without changes
|
dukit/qlang/__init__.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from .engine import Query
|
|
4
|
+
from .symbols import all as symbols_all
|
|
5
|
+
from . import (
|
|
6
|
+
engine,
|
|
7
|
+
symbols,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
def q(
|
|
11
|
+
df: pd.DataFrame,
|
|
12
|
+
code: str = '',
|
|
13
|
+
verbosity: int = 3,
|
|
14
|
+
) -> Query:
|
|
15
|
+
query = Query(
|
|
16
|
+
df,
|
|
17
|
+
code,
|
|
18
|
+
symbols_all,
|
|
19
|
+
symbols.QueryStart(),
|
|
20
|
+
symbols.QueryStop(),
|
|
21
|
+
verbosity,
|
|
22
|
+
)
|
|
23
|
+
return query
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def qr(
|
|
27
|
+
df: pd.DataFrame,
|
|
28
|
+
code: str = '',
|
|
29
|
+
verbosity: int = 3,
|
|
30
|
+
) -> Query:
|
|
31
|
+
query_object = (
|
|
32
|
+
q(df, code, verbosity)
|
|
33
|
+
.scan(verbosity)
|
|
34
|
+
.parse(verbosity)
|
|
35
|
+
.run(verbosity)
|
|
36
|
+
)
|
|
37
|
+
return query_object
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def qs(
|
|
41
|
+
df: pd.DataFrame,
|
|
42
|
+
code: str = '',
|
|
43
|
+
verbosity: int = 3,
|
|
44
|
+
) -> pd.DataFrame | pd.io.formats.style.Styler:
|
|
45
|
+
result = (
|
|
46
|
+
q(df, code, verbosity)
|
|
47
|
+
.scan(verbosity)
|
|
48
|
+
.parse(verbosity)
|
|
49
|
+
.run(verbosity)
|
|
50
|
+
.show()
|
|
51
|
+
)
|
|
52
|
+
return result
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
__all__ = (
|
|
56
|
+
'engine',
|
|
57
|
+
'symbols',
|
|
58
|
+
'q',
|
|
59
|
+
'qr',
|
|
60
|
+
'qs',
|
|
61
|
+
)
|