dukit 0.2.2__tar.gz → 0.2.3__tar.gz
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-0.2.2 → dukit-0.2.3}/PKG-INFO +1 -1
- {dukit-0.2.2 → dukit-0.2.3}/pyproject.toml +1 -1
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/__init__.py +2 -0
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/diffing.py +0 -4
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/excel.py +2 -5
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/interfaces.py +45 -6
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/pandas.py +201 -23
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/qlang/symbols.py +56 -6
- {dukit-0.2.2 → dukit-0.2.3}/README.md +0 -0
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/_test_utils.py +0 -0
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/os.py +0 -0
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/py.typed +0 -0
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/qlang/__init__.py +0 -0
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/qlang/engine.py +0 -0
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/typing.py +0 -0
- {dukit-0.2.2 → dukit-0.2.3}/src/dukit/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dukit"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.3"
|
|
4
4
|
description = "dukit - data utilities kit for exploring, modifying and visualizing small but messy data using pandas"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "MartinVoelkl94", email = "martinv16248@gmail.com" }]
|
|
@@ -25,6 +25,7 @@ from .pandas import (
|
|
|
25
25
|
collapse,
|
|
26
26
|
transpose,
|
|
27
27
|
date_delta,
|
|
28
|
+
date_table,
|
|
28
29
|
)
|
|
29
30
|
from .excel import (
|
|
30
31
|
format,
|
|
@@ -78,6 +79,7 @@ __all__ = (
|
|
|
78
79
|
'collapse',
|
|
79
80
|
'transpose',
|
|
80
81
|
'date_delta',
|
|
82
|
+
'date_table',
|
|
81
83
|
'format',
|
|
82
84
|
'save',
|
|
83
85
|
'Box',
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
|
|
2
2
|
import pandas as pd
|
|
3
|
-
import openpyxl
|
|
4
3
|
import typing
|
|
5
4
|
import os
|
|
6
5
|
|
|
@@ -447,7 +446,6 @@ class Diffs:
|
|
|
447
446
|
|
|
448
447
|
#format excel file
|
|
449
448
|
if apply_format:
|
|
450
|
-
wb = openpyxl.load_workbook(path)
|
|
451
449
|
|
|
452
450
|
#metadata sheets
|
|
453
451
|
sheets_hide = []
|
|
@@ -462,7 +460,6 @@ class Diffs:
|
|
|
462
460
|
sheet=[sheet_info, sheet_summary, sheet_details],
|
|
463
461
|
hide_sheets=sheets_hide,
|
|
464
462
|
freeze_panes='B2',
|
|
465
|
-
openpyxl_workbook=wb,
|
|
466
463
|
)
|
|
467
464
|
msg = 'DEBUG: info, summary, details sheets formatted'
|
|
468
465
|
log(msg, context, self.verbosity)
|
|
@@ -478,7 +475,6 @@ class Diffs:
|
|
|
478
475
|
sheet=diff.name,
|
|
479
476
|
hide_cols=cols_hide,
|
|
480
477
|
freeze_panes=freeze_panes,
|
|
481
|
-
openpyxl_workbook=wb,
|
|
482
478
|
)
|
|
483
479
|
msg = f'DEBUG: diff sheet formatted: "{diff.name}"'
|
|
484
480
|
log(msg, context, self.verbosity)
|
|
@@ -19,7 +19,6 @@ def format(
|
|
|
19
19
|
align_vertical='top',
|
|
20
20
|
align_horizontal='left',
|
|
21
21
|
wrap_text=True,
|
|
22
|
-
openpyxl_workbook=None,
|
|
23
22
|
verbosity=3,
|
|
24
23
|
): #pragma: no cover (does not affect reading of xlsx files)
|
|
25
24
|
"""
|
|
@@ -29,10 +28,8 @@ def format(
|
|
|
29
28
|
- hide specified columns
|
|
30
29
|
"""
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
else:
|
|
35
|
-
wb = openpyxl.load_workbook(path)
|
|
31
|
+
wb = openpyxl.load_workbook(path)
|
|
32
|
+
|
|
36
33
|
if sheet:
|
|
37
34
|
sheetnames = list_(sheet)
|
|
38
35
|
else:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import pandas as pd
|
|
3
|
+
import datetime
|
|
3
4
|
from .excel import save
|
|
4
5
|
from .qlang import (
|
|
5
6
|
q,
|
|
@@ -12,6 +13,8 @@ from .pandas import (
|
|
|
12
13
|
embed,
|
|
13
14
|
collapse,
|
|
14
15
|
transpose,
|
|
16
|
+
date_delta,
|
|
17
|
+
date_table,
|
|
15
18
|
)
|
|
16
19
|
|
|
17
20
|
|
|
@@ -104,16 +107,14 @@ class DukitAccessor():
|
|
|
104
107
|
def collapse(
|
|
105
108
|
self,
|
|
106
109
|
on: str,
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
line_stop='\n',
|
|
110
|
+
template_col='{colname}',
|
|
111
|
+
template_item='#{counter}: {item}\n',
|
|
110
112
|
):
|
|
111
113
|
df_new = collapse(
|
|
112
114
|
self.df,
|
|
113
115
|
on=on,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
line_stop=line_stop,
|
|
116
|
+
template_col=template_col,
|
|
117
|
+
template_item=template_item,
|
|
117
118
|
)
|
|
118
119
|
return df_new
|
|
119
120
|
|
|
@@ -129,6 +130,44 @@ class DukitAccessor():
|
|
|
129
130
|
return df_new
|
|
130
131
|
|
|
131
132
|
|
|
133
|
+
def date_delta(
|
|
134
|
+
self,
|
|
135
|
+
reference_date: str | datetime.date | pd.Timestamp = None,
|
|
136
|
+
reference_col: str = None,
|
|
137
|
+
linebreak: str = '<br>',
|
|
138
|
+
verbosity: int = 3,
|
|
139
|
+
):
|
|
140
|
+
return date_delta(
|
|
141
|
+
self.df,
|
|
142
|
+
reference_date=reference_date,
|
|
143
|
+
reference_col=reference_col,
|
|
144
|
+
linebreak=linebreak,
|
|
145
|
+
verbosity=verbosity,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def date_table(
|
|
150
|
+
self,
|
|
151
|
+
reference_date: str | datetime.date | pd.Timestamp = None,
|
|
152
|
+
reference_col: str = None,
|
|
153
|
+
uid: str = None,
|
|
154
|
+
upper: int = None,
|
|
155
|
+
lower: int = None,
|
|
156
|
+
linebreak: str = '<br>',
|
|
157
|
+
verbosity: int = 3,
|
|
158
|
+
):
|
|
159
|
+
return date_table(
|
|
160
|
+
df=self.df,
|
|
161
|
+
reference_date=reference_date,
|
|
162
|
+
reference_col=reference_col,
|
|
163
|
+
uid=uid,
|
|
164
|
+
upper=upper,
|
|
165
|
+
lower=lower,
|
|
166
|
+
linebreak=linebreak,
|
|
167
|
+
verbosity=verbosity,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
132
171
|
def save(
|
|
133
172
|
self,
|
|
134
173
|
path: str,
|
|
@@ -3,7 +3,7 @@ import pandas as pd
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
import datetime
|
|
5
5
|
import copy
|
|
6
|
-
from .utils import log
|
|
6
|
+
from .utils import log, GREEN_LIGHT
|
|
7
7
|
from .typing import date_
|
|
8
8
|
|
|
9
9
|
def get_df() -> pd.DataFrame:
|
|
@@ -446,13 +446,12 @@ def embed(
|
|
|
446
446
|
def collapse(
|
|
447
447
|
df: pd.DataFrame,
|
|
448
448
|
on: str,
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
line_stop='\n',
|
|
449
|
+
template_col='{colname}',
|
|
450
|
+
template_item='#{counter}: {item}\n',
|
|
452
451
|
):
|
|
453
452
|
df = df.groupby(on).agg(list)
|
|
454
|
-
df = df.map(lambda x: _to_lines(x,
|
|
455
|
-
df.columns = [
|
|
453
|
+
df = df.map(lambda x: _to_lines(x, template_item))
|
|
454
|
+
df.columns = [template_col.format(colname=col) for col in df.columns]
|
|
456
455
|
df.insert(0, on, df.index)
|
|
457
456
|
df.reset_index(drop=True, inplace=True)
|
|
458
457
|
return df
|
|
@@ -460,8 +459,7 @@ def collapse(
|
|
|
460
459
|
|
|
461
460
|
def _to_lines(
|
|
462
461
|
x,
|
|
463
|
-
|
|
464
|
-
line_stop='\n',
|
|
462
|
+
template_item='#{counter}: {item}\n',
|
|
465
463
|
):
|
|
466
464
|
if not isinstance(x, list):
|
|
467
465
|
return x
|
|
@@ -470,7 +468,7 @@ def _to_lines(
|
|
|
470
468
|
else:
|
|
471
469
|
x_str = ''
|
|
472
470
|
for i, item in enumerate(x):
|
|
473
|
-
x_str +=
|
|
471
|
+
x_str += template_item.format(counter=i + 1, item=item)
|
|
474
472
|
return x_str
|
|
475
473
|
|
|
476
474
|
|
|
@@ -494,24 +492,18 @@ def transpose(
|
|
|
494
492
|
|
|
495
493
|
|
|
496
494
|
def date_delta(
|
|
497
|
-
df,
|
|
498
|
-
reference_date=None,
|
|
499
|
-
reference_col=None,
|
|
500
|
-
|
|
495
|
+
df: pd.DataFrame,
|
|
496
|
+
reference_date: str | datetime.date | pd.Timestamp = None,
|
|
497
|
+
reference_col: str = None,
|
|
498
|
+
linebreak: str = '\n',
|
|
499
|
+
verbosity: int = 3,
|
|
501
500
|
):
|
|
502
501
|
"""
|
|
503
502
|
Calculates the number of days
|
|
504
503
|
between a reference date or col
|
|
505
|
-
and all other cols in the df.
|
|
504
|
+
and all other date cols in the df.
|
|
506
505
|
"""
|
|
507
506
|
|
|
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
507
|
if reference_date is None and reference_col is None:
|
|
516
508
|
msg = 'ERROR: no reference date or column provided'
|
|
517
509
|
log(msg, 'dk.date_delta', verbosity)
|
|
@@ -522,6 +514,27 @@ def date_delta(
|
|
|
522
514
|
log(msg, 'dk.date_delta', verbosity)
|
|
523
515
|
return df
|
|
524
516
|
|
|
517
|
+
|
|
518
|
+
df = df.copy()
|
|
519
|
+
df_dates = (
|
|
520
|
+
df
|
|
521
|
+
.copy()
|
|
522
|
+
.map(date_)
|
|
523
|
+
.convert_dtypes()
|
|
524
|
+
)
|
|
525
|
+
cols_dates = []
|
|
526
|
+
cols_all = list(df.columns)
|
|
527
|
+
|
|
528
|
+
for col in df_dates.columns:
|
|
529
|
+
if df_dates[col].isna().all():
|
|
530
|
+
df_dates.drop(columns=col, inplace=True)
|
|
531
|
+
else:
|
|
532
|
+
cols_dates.append(col)
|
|
533
|
+
df.drop(columns=col, inplace=True)
|
|
534
|
+
|
|
535
|
+
df = pd.concat([df, df_dates], axis=1)[cols_all]
|
|
536
|
+
|
|
537
|
+
|
|
525
538
|
if 'reference_date' in df.columns:
|
|
526
539
|
msg = 'WARNING: column "reference_date" already exists, overwriting'
|
|
527
540
|
log(msg, 'dk.date_delta', verbosity)
|
|
@@ -541,10 +554,12 @@ def date_delta(
|
|
|
541
554
|
df = df[cols_reorder]
|
|
542
555
|
|
|
543
556
|
for col in df.columns:
|
|
557
|
+
if col not in cols_dates:
|
|
558
|
+
continue
|
|
544
559
|
if col == 'reference_date':
|
|
545
560
|
continue
|
|
546
561
|
|
|
547
|
-
name = f'days from
|
|
562
|
+
name = f'days from{linebreak}{reference_col}{linebreak}to{linebreak}{col}'
|
|
548
563
|
if name in df.columns:
|
|
549
564
|
log(f'WARNING: column "{name}" already exists, overwriting',
|
|
550
565
|
'dk.date_delta', verbosity)
|
|
@@ -554,10 +569,173 @@ def date_delta(
|
|
|
554
569
|
#_fix_nas converts accordingly
|
|
555
570
|
col_formatted = df[col].apply(date_).apply(_fix_nas)
|
|
556
571
|
col_diff = col_formatted - df['reference_date']
|
|
557
|
-
df[name] =
|
|
572
|
+
df[name] = (
|
|
573
|
+
col_diff
|
|
574
|
+
.fillna(pd.NaT) #type:ignore (pylance doesnt know date_ enables this)
|
|
575
|
+
.apply(lambda x: x.days)
|
|
576
|
+
)
|
|
558
577
|
|
|
559
578
|
return df
|
|
560
579
|
|
|
561
580
|
|
|
562
581
|
def _fix_nas(x):
|
|
563
582
|
return pd.NA if x is pd.NaT else x
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def date_table(
|
|
588
|
+
df: pd.DataFrame,
|
|
589
|
+
reference_date: str | datetime.date | pd.Timestamp = None,
|
|
590
|
+
reference_col: str = None,
|
|
591
|
+
uid: str = None,
|
|
592
|
+
upper: int = None,
|
|
593
|
+
lower: int = None,
|
|
594
|
+
start_at_day1: bool = True,
|
|
595
|
+
schedule: dict = None,
|
|
596
|
+
linebreak: str = '\n',
|
|
597
|
+
verbosity: int = 3,
|
|
598
|
+
) -> pd.DataFrame | pd.io.formats.style.Styler:
|
|
599
|
+
"""
|
|
600
|
+
Arranges all dates into a table,
|
|
601
|
+
with positions relative to a
|
|
602
|
+
reference date or column.
|
|
603
|
+
"""
|
|
604
|
+
|
|
605
|
+
if reference_date is None and reference_col is None:
|
|
606
|
+
msg = 'ERROR: no reference date or column provided'
|
|
607
|
+
log(msg, 'dk.date_delta', verbosity)
|
|
608
|
+
return df
|
|
609
|
+
|
|
610
|
+
if reference_date is not None and reference_col is not None:
|
|
611
|
+
msg = 'ERROR: both reference date and column provided'
|
|
612
|
+
log(msg, 'dk.date_delta', verbosity)
|
|
613
|
+
return df
|
|
614
|
+
|
|
615
|
+
df = df.copy()
|
|
616
|
+
|
|
617
|
+
if uid:
|
|
618
|
+
df.index = df[uid]
|
|
619
|
+
|
|
620
|
+
if reference_date is not None:
|
|
621
|
+
reference = pd.Series(
|
|
622
|
+
date_(reference_date),
|
|
623
|
+
index=df.index
|
|
624
|
+
)
|
|
625
|
+
else:
|
|
626
|
+
reference = df[reference_col].apply(date_)
|
|
627
|
+
|
|
628
|
+
df = (
|
|
629
|
+
df
|
|
630
|
+
.copy()
|
|
631
|
+
.map(date_)
|
|
632
|
+
.convert_dtypes()
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
for col in df.columns:
|
|
636
|
+
if df[col].isna().all():
|
|
637
|
+
df.drop(columns=col, inplace=True)
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
blanks = {col: pd.NaT for col in df.columns}
|
|
641
|
+
deltas = pd.DataFrame(
|
|
642
|
+
blanks,
|
|
643
|
+
index=df.index,
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
for col in df.columns:
|
|
647
|
+
#difference only works with pd.NA,
|
|
648
|
+
#but x.days only works with pd.NaT.
|
|
649
|
+
#_fix_nas converts accordingly
|
|
650
|
+
col_formatted = df[col].apply(date_).apply(_fix_nas)
|
|
651
|
+
col_diff = col_formatted - reference
|
|
652
|
+
deltas[col] = (
|
|
653
|
+
col_diff
|
|
654
|
+
.fillna(pd.NaT) #type:ignore (pylance doesnt know date_ enables this)
|
|
655
|
+
.apply(lambda x: x.days)
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
deltas = deltas.T
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
if upper is None:
|
|
662
|
+
upper = int(deltas.max().max())
|
|
663
|
+
if lower is None:
|
|
664
|
+
lower = int(deltas.min().min())
|
|
665
|
+
|
|
666
|
+
days = list(range(lower, upper + 1))
|
|
667
|
+
if start_at_day1:
|
|
668
|
+
days.remove(0)
|
|
669
|
+
days_df = pd.DataFrame({'days': days})
|
|
670
|
+
|
|
671
|
+
df_timeline = days_df.copy()
|
|
672
|
+
if schedule is not None:
|
|
673
|
+
df_schedule = pd.DataFrame({
|
|
674
|
+
'days': list(schedule.values()),
|
|
675
|
+
'planned': list(schedule.keys()),
|
|
676
|
+
})
|
|
677
|
+
df_timeline = df_timeline.merge(
|
|
678
|
+
df_schedule,
|
|
679
|
+
on='days',
|
|
680
|
+
how='left',
|
|
681
|
+
).fillna('')
|
|
682
|
+
|
|
683
|
+
for col in deltas.columns:
|
|
684
|
+
events = pd.DataFrame({
|
|
685
|
+
'days': deltas[col].astype('Int64'),
|
|
686
|
+
col: deltas.index,
|
|
687
|
+
})
|
|
688
|
+
|
|
689
|
+
if start_at_day1:
|
|
690
|
+
events = _shift_day0(events)
|
|
691
|
+
|
|
692
|
+
merged = days_df.copy().merge(events, on='days', how='left').fillna('')
|
|
693
|
+
collapsed = collapse(
|
|
694
|
+
merged,
|
|
695
|
+
on='days',
|
|
696
|
+
template_item='{item}' + linebreak,
|
|
697
|
+
)
|
|
698
|
+
df_timeline = df_timeline.merge(
|
|
699
|
+
collapsed,
|
|
700
|
+
on='days',
|
|
701
|
+
how='left',
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
if schedule is not None:
|
|
705
|
+
df_timeline = _highlight_schedule(df_timeline, schedule)
|
|
706
|
+
|
|
707
|
+
return df_timeline
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def _shift_day0(df: pd.DataFrame) -> pd.DataFrame:
|
|
711
|
+
if 'days' not in df.columns:
|
|
712
|
+
return df
|
|
713
|
+
if 0 not in df['days'].values:
|
|
714
|
+
return df
|
|
715
|
+
mask_positive = df['days'] >= 0
|
|
716
|
+
df.loc[mask_positive, 'days'] += 1
|
|
717
|
+
return df
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
def _highlight_schedule(
|
|
721
|
+
df: pd.DataFrame,
|
|
722
|
+
schedule: dict,
|
|
723
|
+
) -> pd.io.formats.style.Styler:
|
|
724
|
+
|
|
725
|
+
days_highlight = list(schedule.values())
|
|
726
|
+
|
|
727
|
+
df_style = pd.DataFrame(
|
|
728
|
+
'text-align: left;',
|
|
729
|
+
columns=df.columns,
|
|
730
|
+
index=df.index
|
|
731
|
+
)
|
|
732
|
+
|
|
733
|
+
mask_highlight = df['days'].isin(days_highlight)
|
|
734
|
+
df_style.loc[mask_highlight, :] += f'background-color: {GREEN_LIGHT};'
|
|
735
|
+
|
|
736
|
+
df_styled = df.style.apply(
|
|
737
|
+
lambda x: df_style,
|
|
738
|
+
axis=None,
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
return df_styled
|
|
@@ -6075,8 +6075,20 @@ class ViewParserHelp(Symbol):
|
|
|
6075
6075
|
)
|
|
6076
6076
|
print('\n\n')
|
|
6077
6077
|
|
|
6078
|
+
|
|
6078
6079
|
if not q.op.operator:
|
|
6079
6080
|
|
|
6081
|
+
flags = _get_valid_operators(
|
|
6082
|
+
q.op,
|
|
6083
|
+
'flags',
|
|
6084
|
+
cols_show
|
|
6085
|
+
)
|
|
6086
|
+
_print_or_display(
|
|
6087
|
+
'flags:',
|
|
6088
|
+
flags[cols_show],
|
|
6089
|
+
)
|
|
6090
|
+
print('\n\n')
|
|
6091
|
+
|
|
6080
6092
|
generic_ops = _get_valid_operators(
|
|
6081
6093
|
q.op,
|
|
6082
6094
|
'generic',
|
|
@@ -6657,7 +6669,7 @@ class FlagNegate(Symbol):
|
|
|
6657
6669
|
>>> df.dk.qs(r'id %%!>20000')
|
|
6658
6670
|
"""
|
|
6659
6671
|
name = 'FlagNegate'
|
|
6660
|
-
category = '
|
|
6672
|
+
category = 'flag'
|
|
6661
6673
|
regex = (r'!',)
|
|
6662
6674
|
|
|
6663
6675
|
def parse(self, q: Query) -> Query:
|
|
@@ -6668,6 +6680,28 @@ class FlagNegate(Symbol):
|
|
|
6668
6680
|
|
|
6669
6681
|
|
|
6670
6682
|
|
|
6683
|
+
class FlagIndex(Symbol):
|
|
6684
|
+
"""
|
|
6685
|
+
Condition is applied to the index
|
|
6686
|
+
instead of the values.
|
|
6687
|
+
|
|
6688
|
+
Examples
|
|
6689
|
+
--------
|
|
6690
|
+
>>> df.dk.qs(r'%§0')
|
|
6691
|
+
>>> df.dk.qs(r'name §3')
|
|
6692
|
+
"""
|
|
6693
|
+
name = 'FlagIndex'
|
|
6694
|
+
category = 'flag'
|
|
6695
|
+
regex = (r'§',)
|
|
6696
|
+
|
|
6697
|
+
def parse(self, q: Query) -> Query:
|
|
6698
|
+
q = _preparse_for_getter(q)
|
|
6699
|
+
q.op.flags['index'] = 'apply condition to the index'
|
|
6700
|
+
return q
|
|
6701
|
+
|
|
6702
|
+
|
|
6703
|
+
|
|
6704
|
+
|
|
6671
6705
|
class FlagColref(Symbol):
|
|
6672
6706
|
"""
|
|
6673
6707
|
interpret args as col references
|
|
@@ -6678,7 +6712,7 @@ class FlagColref(Symbol):
|
|
|
6678
6712
|
>>> df.dk.qs(r'age <@height')
|
|
6679
6713
|
"""
|
|
6680
6714
|
name = 'FlagColref'
|
|
6681
|
-
category = '
|
|
6715
|
+
category = 'flag'
|
|
6682
6716
|
regex = (r'@',)
|
|
6683
6717
|
|
|
6684
6718
|
def parse(self, q: Query) -> Query:
|
|
@@ -6706,7 +6740,7 @@ class Flag(Symbol):
|
|
|
6706
6740
|
>>> df.dk.qs(r'age %%>30 +strict')
|
|
6707
6741
|
"""
|
|
6708
6742
|
name = 'Flag'
|
|
6709
|
-
category = '
|
|
6743
|
+
category = 'flag'
|
|
6710
6744
|
regex = (r'\+\w+',)
|
|
6711
6745
|
|
|
6712
6746
|
def build(self, str_matched: str) -> 'Symbol':
|
|
@@ -6735,6 +6769,7 @@ getters = []
|
|
|
6735
6769
|
setters = []
|
|
6736
6770
|
stylers = []
|
|
6737
6771
|
viewers = []
|
|
6772
|
+
flags = []
|
|
6738
6773
|
for _obj in list(locals().values()):
|
|
6739
6774
|
if isinstance(_obj, type) and issubclass(_obj, Symbol):
|
|
6740
6775
|
if _obj is not Symbol:
|
|
@@ -6758,6 +6793,8 @@ for _obj in list(locals().values()):
|
|
|
6758
6793
|
elif _obj.category == 'viewer':
|
|
6759
6794
|
operators.append(_obj())
|
|
6760
6795
|
viewers.append(_obj())
|
|
6796
|
+
elif _obj.category == 'flag':
|
|
6797
|
+
flags.append(_obj())
|
|
6761
6798
|
|
|
6762
6799
|
|
|
6763
6800
|
|
|
@@ -6782,6 +6819,7 @@ def as_df(category='all') -> pd.DataFrame:
|
|
|
6782
6819
|
'setter',
|
|
6783
6820
|
'styler',
|
|
6784
6821
|
'viewer',
|
|
6822
|
+
'flag',
|
|
6785
6823
|
)
|
|
6786
6824
|
if category in singular:
|
|
6787
6825
|
category += 's'
|
|
@@ -6804,6 +6842,8 @@ def as_df(category='all') -> pd.DataFrame:
|
|
|
6804
6842
|
symbols = stylers
|
|
6805
6843
|
elif category == 'viewers':
|
|
6806
6844
|
symbols = viewers
|
|
6845
|
+
elif category == 'flags':
|
|
6846
|
+
symbols = flags
|
|
6807
6847
|
else:
|
|
6808
6848
|
raise ValueError(f"Unknown category: {category}")
|
|
6809
6849
|
|
|
@@ -6813,7 +6853,7 @@ def as_df(category='all') -> pd.DataFrame:
|
|
|
6813
6853
|
descriptions = [_get_description(d) for d in docs]
|
|
6814
6854
|
examples = [_get_example(d) for d in docs]
|
|
6815
6855
|
categories = [s.category for s in symbols]
|
|
6816
|
-
|
|
6856
|
+
flags_actual = ['\n'.join(s.flags) for s in symbols]
|
|
6817
6857
|
flags_allowed = ['\n'.join(s.flags_allowed) for s in symbols]
|
|
6818
6858
|
scopes_allowed = ['\n'.join(s.scopes_allowed) for s in symbols]
|
|
6819
6859
|
connectors_allowed = ['\n'.join(s.connectors_allowed) for s in symbols]
|
|
@@ -6823,7 +6863,7 @@ def as_df(category='all') -> pd.DataFrame:
|
|
|
6823
6863
|
'description': descriptions,
|
|
6824
6864
|
'example': examples,
|
|
6825
6865
|
'category': categories,
|
|
6826
|
-
'flags':
|
|
6866
|
+
'flags': flags_actual,
|
|
6827
6867
|
'flags_allowed': flags_allowed,
|
|
6828
6868
|
'scopes_allowed': scopes_allowed,
|
|
6829
6869
|
'connectors_allowed': connectors_allowed,
|
|
@@ -6844,7 +6884,17 @@ def as_df_styled(category='all') -> pd.io.formats.style.Styler:
|
|
|
6844
6884
|
|
|
6845
6885
|
|
|
6846
6886
|
def _get_lexemes(symbol: Symbol) -> str:
|
|
6847
|
-
|
|
6887
|
+
show_raw = [
|
|
6888
|
+
'Newline',
|
|
6889
|
+
'Literal',
|
|
6890
|
+
'Whitespace',
|
|
6891
|
+
'Comment',
|
|
6892
|
+
'Flag',
|
|
6893
|
+
]
|
|
6894
|
+
if symbol.name in show_raw:
|
|
6895
|
+
string = '\n'.join(symbol.regex)
|
|
6896
|
+
else:
|
|
6897
|
+
string = '\n'.join(symbol.regex).replace('\\', '')
|
|
6848
6898
|
return string
|
|
6849
6899
|
|
|
6850
6900
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|