singlestoredb 1.4.1__py3-none-any.whl → 1.4.3__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.
Potentially problematic release.
This version of singlestoredb might be problematic. Click here for more details.
- singlestoredb/__init__.py +1 -1
- singlestoredb/fusion/handler.py +107 -2
- singlestoredb/management/utils.py +20 -4
- singlestoredb/notebook/_portal.py +1 -1
- {singlestoredb-1.4.1.dist-info → singlestoredb-1.4.3.dist-info}/METADATA +1 -1
- {singlestoredb-1.4.1.dist-info → singlestoredb-1.4.3.dist-info}/RECORD +10 -10
- {singlestoredb-1.4.1.dist-info → singlestoredb-1.4.3.dist-info}/LICENSE +0 -0
- {singlestoredb-1.4.1.dist-info → singlestoredb-1.4.3.dist-info}/WHEEL +0 -0
- {singlestoredb-1.4.1.dist-info → singlestoredb-1.4.3.dist-info}/entry_points.txt +0 -0
- {singlestoredb-1.4.1.dist-info → singlestoredb-1.4.3.dist-info}/top_level.txt +0 -0
singlestoredb/__init__.py
CHANGED
singlestoredb/fusion/handler.py
CHANGED
|
@@ -28,8 +28,23 @@ CORE_GRAMMAR = r'''
|
|
|
28
28
|
eq = ws* "=" ws*
|
|
29
29
|
open_paren = ws* "(" ws*
|
|
30
30
|
close_paren = ws* ")" ws*
|
|
31
|
+
open_repeats = ws* ~r"[\(\[\{]" ws*
|
|
32
|
+
close_repeats = ws* ~r"[\)\]\}]" ws*
|
|
31
33
|
select = ~r"SELECT"i ws+ ~r".+" ws*
|
|
32
|
-
|
|
34
|
+
|
|
35
|
+
json = ws* json_object ws*
|
|
36
|
+
json_object = ~r"{\s*" json_members? ~r"\s*}"
|
|
37
|
+
json_members = json_mapping (~r"\s*,\s*" json_mapping)*
|
|
38
|
+
json_mapping = json_string ~r"\s*:\s*" json_value
|
|
39
|
+
json_array = ~r"\[\s*" json_items? ~r"\s*\]"
|
|
40
|
+
json_items = json_value (~r"\s*,\s*" json_value)*
|
|
41
|
+
json_value = json_object / json_array / json_string / json_true_val / json_false_val / json_null_val / json_number
|
|
42
|
+
json_true_val = "true"
|
|
43
|
+
json_false_val = "false"
|
|
44
|
+
json_null_val = "null"
|
|
45
|
+
json_string = ~r"\"[ !#-\[\]-\U0010ffff]*(?:\\(?:[\"\\/bfnrt]|u[0-9A-Fa-f]{4})[ !#-\[\]-\U0010ffff]*)*\""
|
|
46
|
+
json_number = ~r"-?(0|[1-9][0-9]*)(\.\d*)?([eE][-+]?\d+)?"
|
|
47
|
+
''' # noqa: E501
|
|
33
48
|
|
|
34
49
|
BUILTINS = {
|
|
35
50
|
'<order-by>': r'''
|
|
@@ -47,6 +62,7 @@ BUILTINS = {
|
|
|
47
62
|
''',
|
|
48
63
|
'<integer>': '',
|
|
49
64
|
'<number>': '',
|
|
65
|
+
'<json>': '',
|
|
50
66
|
}
|
|
51
67
|
|
|
52
68
|
BUILTIN_DEFAULTS = { # type: ignore
|
|
@@ -54,9 +70,36 @@ BUILTIN_DEFAULTS = { # type: ignore
|
|
|
54
70
|
'like': None,
|
|
55
71
|
'extended': False,
|
|
56
72
|
'limit': None,
|
|
73
|
+
'json': {},
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
_json_unesc_re = re.compile(r'\\(["/\\bfnrt]|u[0-9A-Fa-f])')
|
|
77
|
+
_json_unesc_map = {
|
|
78
|
+
'"': '"',
|
|
79
|
+
'/': '/',
|
|
80
|
+
'\\': '\\',
|
|
81
|
+
'b': '\b',
|
|
82
|
+
'f': '\f',
|
|
83
|
+
'n': '\n',
|
|
84
|
+
'r': '\r',
|
|
85
|
+
't': '\t',
|
|
57
86
|
}
|
|
58
87
|
|
|
59
88
|
|
|
89
|
+
def _json_unescape(m: Any) -> str:
|
|
90
|
+
c = m.group(1)
|
|
91
|
+
if c[0] == 'u':
|
|
92
|
+
return chr(int(c[1:], 16))
|
|
93
|
+
c2 = _json_unesc_map.get(c)
|
|
94
|
+
if not c2:
|
|
95
|
+
raise ValueError(f'invalid escape sequence: {m.group(0)}')
|
|
96
|
+
return c2
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def json_unescape(s: str) -> str:
|
|
100
|
+
return _json_unesc_re.sub(_json_unescape, s[1:-1])
|
|
101
|
+
|
|
102
|
+
|
|
60
103
|
def get_keywords(grammar: str) -> Tuple[str, ...]:
|
|
61
104
|
"""Return all all-caps words from the beginning of the line."""
|
|
62
105
|
m = re.match(r'^\s*((?:[A-Z0-9_]+)(\s+|$|;))+', grammar)
|
|
@@ -89,7 +132,7 @@ def process_alternates(m: Any) -> str:
|
|
|
89
132
|
def process_repeats(m: Any) -> str:
|
|
90
133
|
"""Add repeated patterns."""
|
|
91
134
|
sql = m.group(1).strip()
|
|
92
|
-
return f'
|
|
135
|
+
return f'open_repeats? {sql} ws* ( comma {sql} ws* )* close_repeats?'
|
|
93
136
|
|
|
94
137
|
|
|
95
138
|
def lower_and_regex(m: Any) -> str:
|
|
@@ -639,6 +682,14 @@ class SQLHandler(NodeVisitor):
|
|
|
639
682
|
"""Close parenthesis."""
|
|
640
683
|
return
|
|
641
684
|
|
|
685
|
+
def visit_open_repeats(self, node: Node, visited_children: Iterable[Any]) -> Any:
|
|
686
|
+
"""Open repeat grouping."""
|
|
687
|
+
return
|
|
688
|
+
|
|
689
|
+
def visit_close_repeats(self, node: Node, visited_children: Iterable[Any]) -> Any:
|
|
690
|
+
"""Close repeat grouping."""
|
|
691
|
+
return
|
|
692
|
+
|
|
642
693
|
def visit_init(self, node: Node, visited_children: Iterable[Any]) -> Any:
|
|
643
694
|
"""Entry point of the grammar."""
|
|
644
695
|
_, out, *_ = visited_children
|
|
@@ -662,6 +713,57 @@ class SQLHandler(NodeVisitor):
|
|
|
662
713
|
ascending.append(value[1].upper().startswith('A'))
|
|
663
714
|
return {'order_by': {'by': by, 'ascending': ascending}}
|
|
664
715
|
|
|
716
|
+
def _delimited(self, node: Node, children: Iterable[Any]) -> Any:
|
|
717
|
+
children = list(children)
|
|
718
|
+
items = [children[0]]
|
|
719
|
+
items.extend(item for _, item in children[1])
|
|
720
|
+
return items
|
|
721
|
+
|
|
722
|
+
def _atomic(self, node: Node, children: Iterable[Any]) -> Any:
|
|
723
|
+
return list(children)[0]
|
|
724
|
+
|
|
725
|
+
# visitors
|
|
726
|
+
visit_json_value = _atomic
|
|
727
|
+
visit_json_members = visit_json_items = _delimited
|
|
728
|
+
|
|
729
|
+
def visit_json_object(self, node: Node, children: Iterable[Any]) -> Any:
|
|
730
|
+
_, members, _ = children
|
|
731
|
+
if isinstance(members, list):
|
|
732
|
+
members = members[0]
|
|
733
|
+
else:
|
|
734
|
+
members = []
|
|
735
|
+
members = [x for x in members if x != '']
|
|
736
|
+
return dict(members)
|
|
737
|
+
|
|
738
|
+
def visit_json_array(self, node: Node, children: Iterable[Any]) -> Any:
|
|
739
|
+
_, values, _ = children
|
|
740
|
+
if isinstance(values, list):
|
|
741
|
+
values = values[0]
|
|
742
|
+
else:
|
|
743
|
+
values = []
|
|
744
|
+
return values
|
|
745
|
+
|
|
746
|
+
def visit_json_mapping(self, node: Node, children: Iterable[Any]) -> Any:
|
|
747
|
+
key, _, value = children
|
|
748
|
+
return key, value
|
|
749
|
+
|
|
750
|
+
def visit_json_string(self, node: Node, children: Iterable[Any]) -> Any:
|
|
751
|
+
return json_unescape(node.text)
|
|
752
|
+
|
|
753
|
+
def visit_json_number(self, node: Node, children: Iterable[Any]) -> Any:
|
|
754
|
+
if '.' in node.text:
|
|
755
|
+
return float(node.text)
|
|
756
|
+
return int(node.text)
|
|
757
|
+
|
|
758
|
+
def visit_json_true_val(self, node: Node, children: Iterable[Any]) -> Any:
|
|
759
|
+
return True
|
|
760
|
+
|
|
761
|
+
def visit_json_false_val(self, node: Node, children: Iterable[Any]) -> Any:
|
|
762
|
+
return False
|
|
763
|
+
|
|
764
|
+
def visit_json_null_val(self, node: Node, children: Iterable[Any]) -> Any:
|
|
765
|
+
return None
|
|
766
|
+
|
|
665
767
|
def generic_visit(self, node: Node, visited_children: Iterable[Any]) -> Any:
|
|
666
768
|
"""
|
|
667
769
|
Handle all undefined rules.
|
|
@@ -675,6 +777,9 @@ class SQLHandler(NodeVisitor):
|
|
|
675
777
|
rule can have repeated values, a list of values is returned.
|
|
676
778
|
|
|
677
779
|
"""
|
|
780
|
+
if node.expr_name.startswith('json'):
|
|
781
|
+
return visited_children or node.text
|
|
782
|
+
|
|
678
783
|
# Call a grammar rule
|
|
679
784
|
if node.expr_name in type(self).rule_info:
|
|
680
785
|
n_keywords = type(self).rule_info[node.expr_name]['n_keywords']
|
|
@@ -123,14 +123,14 @@ class NamedList(List[T]):
|
|
|
123
123
|
def _setup_authentication_info_handler() -> Callable[..., Dict[str, Any]]:
|
|
124
124
|
"""Setup authentication info event handler."""
|
|
125
125
|
|
|
126
|
-
authentication_info:
|
|
126
|
+
authentication_info: Dict[str, Any] = {}
|
|
127
127
|
|
|
128
128
|
def handle_authentication_info(msg: Dict[str, Any]) -> None:
|
|
129
129
|
"""Handle authentication info events."""
|
|
130
130
|
nonlocal authentication_info
|
|
131
131
|
if msg.get('name', '') != 'singlestore.portal.authentication_updated':
|
|
132
132
|
return
|
|
133
|
-
authentication_info =
|
|
133
|
+
authentication_info = dict(msg.get('data', {}))
|
|
134
134
|
|
|
135
135
|
events.subscribe(handle_authentication_info)
|
|
136
136
|
|
|
@@ -145,11 +145,27 @@ def _setup_authentication_info_handler() -> Callable[..., Dict[str, Any]]:
|
|
|
145
145
|
out['user'] = data['user']
|
|
146
146
|
if 'password' in data:
|
|
147
147
|
out['password'] = data['password']
|
|
148
|
-
authentication_info =
|
|
148
|
+
authentication_info = out
|
|
149
149
|
|
|
150
150
|
events.subscribe(handle_authentication_info)
|
|
151
151
|
|
|
152
|
+
def retrieve_current_authentication_info() -> List[Tuple[str, Any]]:
|
|
153
|
+
"""Retrieve JWT if not expired."""
|
|
154
|
+
nonlocal authentication_info
|
|
155
|
+
password = authentication_info.get('password')
|
|
156
|
+
if password:
|
|
157
|
+
expires = datetime.datetime.fromtimestamp(
|
|
158
|
+
jwt.decode(
|
|
159
|
+
password,
|
|
160
|
+
options={'verify_signature': False},
|
|
161
|
+
)['exp'],
|
|
162
|
+
)
|
|
163
|
+
if datetime.datetime.now() > expires:
|
|
164
|
+
authentication_info = {}
|
|
165
|
+
return list(authentication_info.items())
|
|
166
|
+
|
|
152
167
|
def get_env() -> List[Tuple[str, Any]]:
|
|
168
|
+
"""Retrieve JWT from environment."""
|
|
153
169
|
conn = {}
|
|
154
170
|
url = os.environ.get('SINGLESTOREDB_URL') or get_option('host')
|
|
155
171
|
if url:
|
|
@@ -170,7 +186,7 @@ def _setup_authentication_info_handler() -> Callable[..., Dict[str, Any]]:
|
|
|
170
186
|
return dict(
|
|
171
187
|
itertools.chain(
|
|
172
188
|
(get_env() if include_env else []),
|
|
173
|
-
|
|
189
|
+
retrieve_current_authentication_info(),
|
|
174
190
|
),
|
|
175
191
|
)
|
|
176
192
|
|
|
@@ -182,7 +182,7 @@ class Portal(object):
|
|
|
182
182
|
id = w.id
|
|
183
183
|
|
|
184
184
|
self._call_javascript(
|
|
185
|
-
'
|
|
185
|
+
'changeDeployment', [id],
|
|
186
186
|
wait_on_condition=lambda: self.workspace_id == id, # type: ignore
|
|
187
187
|
timeout_message='timeout waiting for workspace update',
|
|
188
188
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
singlestoredb/__init__.py,sha256=
|
|
1
|
+
singlestoredb/__init__.py,sha256=NTrIpxhbm7oMxrNbbjVKdK-4ShuyvUChQlP3z-kL9Ko,1634
|
|
2
2
|
singlestoredb/auth.py,sha256=u8D9tpKzrqa4ssaHjyZnGDX1q8XBpGtuoOkTkSv7B28,7599
|
|
3
3
|
singlestoredb/config.py,sha256=H4pQxqBEGGCmVHg40VEnAdqGXHun8ougZzj-Ed6ZLH4,11822
|
|
4
4
|
singlestoredb/connection.py,sha256=WL_TSSHhhjLV0pnJOtaeMAf0o1DI-PJv9xnLFf_cM08,45173
|
|
@@ -22,7 +22,7 @@ singlestoredb/functions/ext/rowdat_1.py,sha256=JgKRsVSQYczFD6cmo2xLilbNPYpyLL2tP
|
|
|
22
22
|
singlestoredb/functions/ext/utils.py,sha256=2-B8YU_Iekv8JcpI-ochs9TIeuyatLaLAH-AyYyUUIg,5311
|
|
23
23
|
singlestoredb/fusion/__init__.py,sha256=Qo7SuqGw-l-vE8-EI2jhm6hXJkYfOLUKIws9c7LFNX0,356
|
|
24
24
|
singlestoredb/fusion/graphql.py,sha256=ZA3HcDq5rER-dCEavwTqnF7KM0D2LCYIY7nLQk7lSso,5207
|
|
25
|
-
singlestoredb/fusion/handler.py,sha256=
|
|
25
|
+
singlestoredb/fusion/handler.py,sha256=wuNq-nzzBngSha_kZ_Da7V7VzQzmhgXgUfh2V0HXLVI,24976
|
|
26
26
|
singlestoredb/fusion/registry.py,sha256=jjdRTYZ3ylhy6gAoW5xBj0tkxGFBT-2yLQ0tztTgDIY,6112
|
|
27
27
|
singlestoredb/fusion/result.py,sha256=Bd3KbRpqWqQcWp_Chd4bzBy8Kfc8nXLS_Pn_GGbPO6o,11772
|
|
28
28
|
singlestoredb/fusion/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -37,7 +37,7 @@ singlestoredb/management/cluster.py,sha256=i23Smr1PBrDZ8NO_VPd_-bEYkyHvVe9CCRGUj
|
|
|
37
37
|
singlestoredb/management/manager.py,sha256=sFP1vZGS8WpN8E0XLu1N7Mxtq6Sixalln44HlTQEyXI,8800
|
|
38
38
|
singlestoredb/management/organization.py,sha256=Y0JFSxYF_UOjip53gcbBXWPCe_t92zo3d99jZNrhkx4,4995
|
|
39
39
|
singlestoredb/management/region.py,sha256=HnLcWUh7r_aLECliplCDHak4a_F3B7LOSXEYMW66qD0,1611
|
|
40
|
-
singlestoredb/management/utils.py,sha256=
|
|
40
|
+
singlestoredb/management/utils.py,sha256=t-O6NRb4Wad1qJJ1afxtFR1IX-0bezEqplKllnm8tto,11398
|
|
41
41
|
singlestoredb/management/workspace.py,sha256=9oamNIaE5vLZNAlpl5SK-xu27qPqx2Ff3ZIdKckNfmc,61673
|
|
42
42
|
singlestoredb/mysql/__init__.py,sha256=olUTAvkiERhDW41JXQMawkg-i0tvBEkoTkII1tt6lxU,4492
|
|
43
43
|
singlestoredb/mysql/_auth.py,sha256=AugRitoUwgRIDFuJxuAH4MWIAmckY7Ji2pP6r_Ng9dY,8043
|
|
@@ -82,7 +82,7 @@ singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py,sha256
|
|
|
82
82
|
singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py,sha256=pl0bvuZo_nzAlYOINxRiR-Zi9khz0W2Pc7vP-K3sQYQ,2819
|
|
83
83
|
singlestoredb/notebook/__init__.py,sha256=v0j1E3MFAtaC8wTrR-F7XY0nytUvQ4XpYhVXddv2xA0,533
|
|
84
84
|
singlestoredb/notebook/_objects.py,sha256=MkB1eowEq5SQXFHY00xAKAyyeLqHu_uaZiA20BCJPaE,8043
|
|
85
|
-
singlestoredb/notebook/_portal.py,sha256=
|
|
85
|
+
singlestoredb/notebook/_portal.py,sha256=08_8hFFuD9Ybq3K8ruHOgMhDqzdhjj7o0Sq368zH714,8486
|
|
86
86
|
singlestoredb/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
87
87
|
singlestoredb/tests/empty.sql,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
88
88
|
singlestoredb/tests/local_infile.csv,sha256=sBtqjvfkS9aoOVx8nMXYgYv4rDuT4OuYhqUhNRu0O68,42
|
|
@@ -114,9 +114,9 @@ singlestoredb/utils/events.py,sha256=9IB84T3pKQjs7aaoSSJCw7soNngnhoTDWIC52M51R9Y
|
|
|
114
114
|
singlestoredb/utils/mogrify.py,sha256=-a56IF70U6CkfadeaZgfjRSVsAD3PuqRrzPpjZlgbwY,4050
|
|
115
115
|
singlestoredb/utils/results.py,sha256=bJtaUaDiFq26IsPAKZ2FHGB7csMn94EAxLKrP4HaEEA,15277
|
|
116
116
|
singlestoredb/utils/xdict.py,sha256=S9HKgrPrnu_6b7iOwa2KrW8CmU1Uqx0BWdEyogFzWbE,12896
|
|
117
|
-
singlestoredb-1.4.
|
|
118
|
-
singlestoredb-1.4.
|
|
119
|
-
singlestoredb-1.4.
|
|
120
|
-
singlestoredb-1.4.
|
|
121
|
-
singlestoredb-1.4.
|
|
122
|
-
singlestoredb-1.4.
|
|
117
|
+
singlestoredb-1.4.3.dist-info/LICENSE,sha256=Mlq78idURT-9G026aMYswwwnnrLcgzTLuXeAs5hjDLM,11341
|
|
118
|
+
singlestoredb-1.4.3.dist-info/METADATA,sha256=sNKDftR6stTzMfX0NjKgcevlLjU9SQKhU6861nPiXQE,5570
|
|
119
|
+
singlestoredb-1.4.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
120
|
+
singlestoredb-1.4.3.dist-info/entry_points.txt,sha256=bSLaTWB5zGjpVYPAaI46MkkDup0su-eb3uAhCNYuRV0,48
|
|
121
|
+
singlestoredb-1.4.3.dist-info/top_level.txt,sha256=eet8bVPNRqiGeY0PrO5ERH2UpamwlrKHEQCffz4dOh8,14
|
|
122
|
+
singlestoredb-1.4.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|