singlestoredb 1.16.1__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.
Files changed (183) hide show
  1. singlestoredb/__init__.py +75 -0
  2. singlestoredb/ai/__init__.py +2 -0
  3. singlestoredb/ai/chat.py +139 -0
  4. singlestoredb/ai/embeddings.py +128 -0
  5. singlestoredb/alchemy/__init__.py +90 -0
  6. singlestoredb/apps/__init__.py +3 -0
  7. singlestoredb/apps/_cloud_functions.py +90 -0
  8. singlestoredb/apps/_config.py +72 -0
  9. singlestoredb/apps/_connection_info.py +18 -0
  10. singlestoredb/apps/_dashboards.py +47 -0
  11. singlestoredb/apps/_process.py +32 -0
  12. singlestoredb/apps/_python_udfs.py +100 -0
  13. singlestoredb/apps/_stdout_supress.py +30 -0
  14. singlestoredb/apps/_uvicorn_util.py +36 -0
  15. singlestoredb/auth.py +245 -0
  16. singlestoredb/config.py +484 -0
  17. singlestoredb/connection.py +1487 -0
  18. singlestoredb/converters.py +950 -0
  19. singlestoredb/docstring/__init__.py +33 -0
  20. singlestoredb/docstring/attrdoc.py +126 -0
  21. singlestoredb/docstring/common.py +230 -0
  22. singlestoredb/docstring/epydoc.py +267 -0
  23. singlestoredb/docstring/google.py +412 -0
  24. singlestoredb/docstring/numpydoc.py +562 -0
  25. singlestoredb/docstring/parser.py +100 -0
  26. singlestoredb/docstring/py.typed +1 -0
  27. singlestoredb/docstring/rest.py +256 -0
  28. singlestoredb/docstring/tests/__init__.py +1 -0
  29. singlestoredb/docstring/tests/_pydoctor.py +21 -0
  30. singlestoredb/docstring/tests/test_epydoc.py +729 -0
  31. singlestoredb/docstring/tests/test_google.py +1007 -0
  32. singlestoredb/docstring/tests/test_numpydoc.py +1100 -0
  33. singlestoredb/docstring/tests/test_parse_from_object.py +109 -0
  34. singlestoredb/docstring/tests/test_parser.py +248 -0
  35. singlestoredb/docstring/tests/test_rest.py +547 -0
  36. singlestoredb/docstring/tests/test_util.py +70 -0
  37. singlestoredb/docstring/util.py +141 -0
  38. singlestoredb/exceptions.py +120 -0
  39. singlestoredb/functions/__init__.py +16 -0
  40. singlestoredb/functions/decorator.py +201 -0
  41. singlestoredb/functions/dtypes.py +1793 -0
  42. singlestoredb/functions/ext/__init__.py +1 -0
  43. singlestoredb/functions/ext/arrow.py +375 -0
  44. singlestoredb/functions/ext/asgi.py +2133 -0
  45. singlestoredb/functions/ext/json.py +420 -0
  46. singlestoredb/functions/ext/mmap.py +413 -0
  47. singlestoredb/functions/ext/rowdat_1.py +724 -0
  48. singlestoredb/functions/ext/timer.py +89 -0
  49. singlestoredb/functions/ext/utils.py +218 -0
  50. singlestoredb/functions/signature.py +1578 -0
  51. singlestoredb/functions/typing/__init__.py +41 -0
  52. singlestoredb/functions/typing/numpy.py +20 -0
  53. singlestoredb/functions/typing/pandas.py +2 -0
  54. singlestoredb/functions/typing/polars.py +2 -0
  55. singlestoredb/functions/typing/pyarrow.py +2 -0
  56. singlestoredb/functions/utils.py +421 -0
  57. singlestoredb/fusion/__init__.py +11 -0
  58. singlestoredb/fusion/graphql.py +213 -0
  59. singlestoredb/fusion/handler.py +916 -0
  60. singlestoredb/fusion/handlers/__init__.py +0 -0
  61. singlestoredb/fusion/handlers/export.py +525 -0
  62. singlestoredb/fusion/handlers/files.py +690 -0
  63. singlestoredb/fusion/handlers/job.py +660 -0
  64. singlestoredb/fusion/handlers/models.py +250 -0
  65. singlestoredb/fusion/handlers/stage.py +502 -0
  66. singlestoredb/fusion/handlers/utils.py +324 -0
  67. singlestoredb/fusion/handlers/workspace.py +956 -0
  68. singlestoredb/fusion/registry.py +249 -0
  69. singlestoredb/fusion/result.py +399 -0
  70. singlestoredb/http/__init__.py +27 -0
  71. singlestoredb/http/connection.py +1267 -0
  72. singlestoredb/magics/__init__.py +34 -0
  73. singlestoredb/magics/run_personal.py +137 -0
  74. singlestoredb/magics/run_shared.py +134 -0
  75. singlestoredb/management/__init__.py +9 -0
  76. singlestoredb/management/billing_usage.py +148 -0
  77. singlestoredb/management/cluster.py +462 -0
  78. singlestoredb/management/export.py +295 -0
  79. singlestoredb/management/files.py +1102 -0
  80. singlestoredb/management/inference_api.py +105 -0
  81. singlestoredb/management/job.py +887 -0
  82. singlestoredb/management/manager.py +373 -0
  83. singlestoredb/management/organization.py +226 -0
  84. singlestoredb/management/region.py +169 -0
  85. singlestoredb/management/utils.py +423 -0
  86. singlestoredb/management/workspace.py +1927 -0
  87. singlestoredb/mysql/__init__.py +177 -0
  88. singlestoredb/mysql/_auth.py +298 -0
  89. singlestoredb/mysql/charset.py +214 -0
  90. singlestoredb/mysql/connection.py +2032 -0
  91. singlestoredb/mysql/constants/CLIENT.py +38 -0
  92. singlestoredb/mysql/constants/COMMAND.py +32 -0
  93. singlestoredb/mysql/constants/CR.py +78 -0
  94. singlestoredb/mysql/constants/ER.py +474 -0
  95. singlestoredb/mysql/constants/EXTENDED_TYPE.py +3 -0
  96. singlestoredb/mysql/constants/FIELD_TYPE.py +48 -0
  97. singlestoredb/mysql/constants/FLAG.py +15 -0
  98. singlestoredb/mysql/constants/SERVER_STATUS.py +10 -0
  99. singlestoredb/mysql/constants/VECTOR_TYPE.py +6 -0
  100. singlestoredb/mysql/constants/__init__.py +0 -0
  101. singlestoredb/mysql/converters.py +271 -0
  102. singlestoredb/mysql/cursors.py +896 -0
  103. singlestoredb/mysql/err.py +92 -0
  104. singlestoredb/mysql/optionfile.py +20 -0
  105. singlestoredb/mysql/protocol.py +450 -0
  106. singlestoredb/mysql/tests/__init__.py +19 -0
  107. singlestoredb/mysql/tests/base.py +126 -0
  108. singlestoredb/mysql/tests/conftest.py +37 -0
  109. singlestoredb/mysql/tests/test_DictCursor.py +132 -0
  110. singlestoredb/mysql/tests/test_SSCursor.py +141 -0
  111. singlestoredb/mysql/tests/test_basic.py +452 -0
  112. singlestoredb/mysql/tests/test_connection.py +851 -0
  113. singlestoredb/mysql/tests/test_converters.py +58 -0
  114. singlestoredb/mysql/tests/test_cursor.py +141 -0
  115. singlestoredb/mysql/tests/test_err.py +16 -0
  116. singlestoredb/mysql/tests/test_issues.py +514 -0
  117. singlestoredb/mysql/tests/test_load_local.py +75 -0
  118. singlestoredb/mysql/tests/test_nextset.py +88 -0
  119. singlestoredb/mysql/tests/test_optionfile.py +27 -0
  120. singlestoredb/mysql/tests/thirdparty/__init__.py +6 -0
  121. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
  122. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/capabilities.py +323 -0
  123. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py +865 -0
  124. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +110 -0
  125. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +224 -0
  126. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +101 -0
  127. singlestoredb/mysql/times.py +23 -0
  128. singlestoredb/notebook/__init__.py +16 -0
  129. singlestoredb/notebook/_objects.py +213 -0
  130. singlestoredb/notebook/_portal.py +352 -0
  131. singlestoredb/py.typed +0 -0
  132. singlestoredb/pytest.py +352 -0
  133. singlestoredb/server/__init__.py +0 -0
  134. singlestoredb/server/docker.py +452 -0
  135. singlestoredb/server/free_tier.py +267 -0
  136. singlestoredb/tests/__init__.py +0 -0
  137. singlestoredb/tests/alltypes.sql +307 -0
  138. singlestoredb/tests/alltypes_no_nulls.sql +208 -0
  139. singlestoredb/tests/empty.sql +0 -0
  140. singlestoredb/tests/ext_funcs/__init__.py +702 -0
  141. singlestoredb/tests/local_infile.csv +3 -0
  142. singlestoredb/tests/test.ipynb +18 -0
  143. singlestoredb/tests/test.sql +680 -0
  144. singlestoredb/tests/test2.ipynb +18 -0
  145. singlestoredb/tests/test2.sql +1 -0
  146. singlestoredb/tests/test_basics.py +1332 -0
  147. singlestoredb/tests/test_config.py +318 -0
  148. singlestoredb/tests/test_connection.py +3103 -0
  149. singlestoredb/tests/test_dbapi.py +27 -0
  150. singlestoredb/tests/test_exceptions.py +45 -0
  151. singlestoredb/tests/test_ext_func.py +1472 -0
  152. singlestoredb/tests/test_ext_func_data.py +1101 -0
  153. singlestoredb/tests/test_fusion.py +1527 -0
  154. singlestoredb/tests/test_http.py +288 -0
  155. singlestoredb/tests/test_management.py +1599 -0
  156. singlestoredb/tests/test_plugin.py +33 -0
  157. singlestoredb/tests/test_results.py +171 -0
  158. singlestoredb/tests/test_types.py +132 -0
  159. singlestoredb/tests/test_udf.py +737 -0
  160. singlestoredb/tests/test_udf_returns.py +459 -0
  161. singlestoredb/tests/test_vectorstore.py +51 -0
  162. singlestoredb/tests/test_xdict.py +333 -0
  163. singlestoredb/tests/utils.py +141 -0
  164. singlestoredb/types.py +373 -0
  165. singlestoredb/utils/__init__.py +0 -0
  166. singlestoredb/utils/config.py +950 -0
  167. singlestoredb/utils/convert_rows.py +69 -0
  168. singlestoredb/utils/debug.py +13 -0
  169. singlestoredb/utils/dtypes.py +205 -0
  170. singlestoredb/utils/events.py +65 -0
  171. singlestoredb/utils/mogrify.py +151 -0
  172. singlestoredb/utils/results.py +585 -0
  173. singlestoredb/utils/xdict.py +425 -0
  174. singlestoredb/vectorstore.py +192 -0
  175. singlestoredb/warnings.py +5 -0
  176. singlestoredb-1.16.1.dist-info/METADATA +165 -0
  177. singlestoredb-1.16.1.dist-info/RECORD +183 -0
  178. singlestoredb-1.16.1.dist-info/WHEEL +5 -0
  179. singlestoredb-1.16.1.dist-info/entry_points.txt +2 -0
  180. singlestoredb-1.16.1.dist-info/licenses/LICENSE +201 -0
  181. singlestoredb-1.16.1.dist-info/top_level.txt +3 -0
  182. sqlx/__init__.py +4 -0
  183. sqlx/magic.py +113 -0
@@ -0,0 +1,89 @@
1
+ import json
2
+ import time
3
+ from typing import Any
4
+ from typing import Dict
5
+ from typing import Optional
6
+
7
+
8
+ class RoundedFloatEncoder(json.JSONEncoder):
9
+
10
+ def encode(self, obj: Any) -> str:
11
+ if isinstance(obj, dict):
12
+ return '{' + ', '.join(
13
+ f'"{k}": {self._format_value(v)}'
14
+ for k, v in obj.items()
15
+ ) + '}'
16
+ return super().encode(obj)
17
+
18
+ def _format_value(self, value: Any) -> str:
19
+ if isinstance(value, float):
20
+ return f'{value:.2f}'
21
+ return json.dumps(value)
22
+
23
+
24
+ class Timer:
25
+ """
26
+ Timer context manager that supports nested timing using a stack.
27
+
28
+ Example
29
+ -------
30
+ timer = Timer()
31
+
32
+ with timer('total'):
33
+ with timer('receive_data'):
34
+ time.sleep(0.1)
35
+ with timer('parse_input'):
36
+ time.sleep(0.2)
37
+ with timer('call_function'):
38
+ with timer('inner_operation'):
39
+ time.sleep(0.05)
40
+ time.sleep(0.3)
41
+
42
+ print(timer.metrics)
43
+ # {'receive_data': 0.1, 'parse_input': 0.2, 'inner_operation': 0.05,
44
+ # 'call_function': 0.35, 'total': 0.65}
45
+
46
+ """
47
+
48
+ def __init__(self, **kwargs: Any) -> None:
49
+ self.metadata: Dict[str, Any] = kwargs
50
+ self.metrics: Dict[str, float] = dict()
51
+ self.entries: Dict[str, float] = dict()
52
+ self._current_key: Optional[str] = None
53
+ self.start_time = time.perf_counter()
54
+
55
+ def __call__(self, key: str) -> 'Timer':
56
+ self._current_key = key
57
+ return self
58
+
59
+ def __enter__(self) -> 'Timer':
60
+ if self._current_key is None:
61
+ raise ValueError(
62
+ "No key specified. Use timer('key_name') as context manager.",
63
+ )
64
+ self.entries[self._current_key] = time.perf_counter()
65
+ return self
66
+
67
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
68
+ key = self._current_key
69
+ if key and key in self.entries:
70
+ start = self.entries.pop(key)
71
+ elapsed = time.perf_counter() - start
72
+ self.metrics[key] = elapsed
73
+ self._current_key = None
74
+
75
+ async def __aenter__(self) -> 'Timer':
76
+ return self.__enter__()
77
+
78
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
79
+ self.__exit__(exc_type, exc_val, exc_tb)
80
+
81
+ def reset(self) -> None:
82
+ self.metrics.clear()
83
+ self.entries.clear()
84
+ self._current_key = None
85
+
86
+ def finish(self) -> Dict[str, Any]:
87
+ """Finish the current timing context and store the elapsed time."""
88
+ self.metrics['total'] = time.perf_counter() - self.start_time
89
+ return dict(type='function_metrics', **self.metadata, **self.metrics)
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env python
2
+ import datetime
3
+ import json
4
+ import logging
5
+ import re
6
+ import sys
7
+ import zipfile
8
+ from copy import copy
9
+ from typing import Any
10
+ from typing import Dict
11
+ from typing import List
12
+ from typing import Union
13
+
14
+ try:
15
+ import tomllib
16
+ except ImportError:
17
+ import tomli as tomllib # type: ignore
18
+
19
+ try:
20
+ from uvicorn.logging import DefaultFormatter
21
+
22
+ except ImportError:
23
+
24
+ class DefaultFormatter(logging.Formatter): # type: ignore
25
+
26
+ def formatMessage(self, record: logging.LogRecord) -> str:
27
+ recordcopy = copy(record)
28
+ levelname = recordcopy.levelname
29
+ seperator = ' ' * (8 - len(recordcopy.levelname))
30
+ recordcopy.__dict__['levelprefix'] = levelname + ':' + seperator
31
+ return super().formatMessage(recordcopy)
32
+
33
+
34
+ class JSONFormatter(logging.Formatter):
35
+ """Custom JSON formatter for structured logging."""
36
+
37
+ def format(self, record: logging.LogRecord) -> str:
38
+ # Create proper ISO timestamp with microseconds
39
+ timestamp = datetime.datetime.fromtimestamp(
40
+ record.created, tz=datetime.timezone.utc,
41
+ )
42
+ # Keep only 3 digits for milliseconds
43
+ iso_timestamp = timestamp.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
44
+
45
+ log_entry = {
46
+ 'timestamp': iso_timestamp,
47
+ 'level': record.levelname,
48
+ 'logger': record.name,
49
+ 'message': record.getMessage(),
50
+ }
51
+
52
+ # Add extra fields if present
53
+ allowed_fields = [
54
+ 'app_name', 'request_id', 'function_name',
55
+ 'content_type', 'accepts', 'metrics',
56
+ ]
57
+ for field in allowed_fields:
58
+ if hasattr(record, field):
59
+ log_entry[field] = getattr(record, field)
60
+
61
+ # Add exception info if present
62
+ if record.exc_info:
63
+ log_entry['exception'] = self.formatException(record.exc_info)
64
+
65
+ return json.dumps(log_entry)
66
+
67
+
68
+ def get_logger(name: str) -> logging.Logger:
69
+ """Return a logger with JSON formatting."""
70
+ logger = logging.getLogger(name)
71
+
72
+ # Only configure if not already configured with JSON formatter
73
+ has_json_formatter = any(
74
+ isinstance(getattr(handler, 'formatter', None), JSONFormatter)
75
+ for handler in logger.handlers
76
+ )
77
+
78
+ if not logger.handlers or not has_json_formatter:
79
+ # Clear handlers only if we need to reconfigure
80
+ logger.handlers.clear()
81
+ handler = logging.StreamHandler()
82
+ formatter = JSONFormatter()
83
+ handler.setFormatter(formatter)
84
+ logger.addHandler(handler)
85
+ logger.setLevel(logging.INFO)
86
+
87
+ # Prevent propagation to avoid duplicate messages or different formatting
88
+ logger.propagate = False
89
+
90
+ return logger
91
+
92
+
93
+ def read_config(
94
+ archive: str,
95
+ keys: Union[str, List[str]],
96
+ config_file: str = 'pyproject.toml',
97
+ ) -> Dict[str, Any]:
98
+ """
99
+ Read a key from a Toml config file.
100
+
101
+ Parameters
102
+ ----------
103
+ archive : str
104
+ Path to an environment file
105
+ keys : str or List[str]
106
+ Period-separated paths to the desired keys
107
+ config_file : str, optional
108
+ Name of the config file in the zip file
109
+
110
+ Returns
111
+ -------
112
+ Dict[str, Any]
113
+
114
+ """
115
+ defaults = {}
116
+ keys = [keys] if isinstance(keys, str) else list(keys)
117
+ with zipfile.ZipFile(archive) as arc:
118
+ try:
119
+ orig_options = tomllib.loads(arc.read(config_file).decode('utf8'))
120
+ verify_python_version(orig_options)
121
+ for key in keys:
122
+ path = key.split('.')
123
+ options = orig_options
124
+ while path:
125
+ options = options.get(path.pop(0), {})
126
+ for k, v in options.items():
127
+ defaults[k.lower().replace('-', '_')] = v
128
+ except KeyError:
129
+ pass
130
+ return defaults
131
+
132
+
133
+ def verify_python_version(options: Dict[str, Any]) -> None:
134
+ """Verify the version of Python matches the pyproject.toml requirement."""
135
+ requires_python = options.get('project', {}).get('requires_python', None)
136
+ if not requires_python:
137
+ return
138
+
139
+ m = re.match(r'\s*([<=>])+\s*((?:\d+\.)+\d+)\s*', requires_python)
140
+ if not m:
141
+ raise ValueError(f'python version string is not valid: {requires_python}')
142
+
143
+ operator = m.group(1)
144
+ version_info = tuple(int(x) for x in m.group(2))
145
+
146
+ if operator == '<=':
147
+ if not (sys.version_info <= version_info):
148
+ raise RuntimeError(
149
+ 'python version is not compatible: ' +
150
+ f'{sys.version_info} > {m.group(2)}',
151
+ )
152
+
153
+ elif operator == '>=':
154
+ if not (sys.version_info >= version_info):
155
+ raise RuntimeError(
156
+ 'python version is not compatible: ' +
157
+ f'{sys.version_info} < {m.group(2)}',
158
+ )
159
+
160
+ elif operator in ['==', '=']:
161
+ if not (sys.version_info == version_info):
162
+ raise RuntimeError(
163
+ 'python version is not compatible: ' +
164
+ f'{sys.version_info} != {m.group(2)}',
165
+ )
166
+
167
+ elif operator == '>':
168
+ if not (sys.version_info > version_info):
169
+ raise RuntimeError(
170
+ 'python version is not compatible: ' +
171
+ f'{sys.version_info} <= {m.group(2)}',
172
+ )
173
+
174
+ elif operator == '<':
175
+ if not (sys.version_info < version_info):
176
+ raise RuntimeError(
177
+ 'python version is not compatible: ' +
178
+ f'{sys.version_info} >= {m.group(2)}',
179
+ )
180
+
181
+ else:
182
+ raise ValueError(f'invalid python_version operator: {operator}')
183
+
184
+
185
+ def to_toml(data: Dict[str, Any]) -> str:
186
+ """Dump data to a pyproject.toml."""
187
+ out = []
188
+ for top_k, top_v in data.items():
189
+ if top_v is None:
190
+ continue
191
+ top_k = top_k.replace('_', '-')
192
+ out.append('')
193
+ out.append(f'[{top_k}]')
194
+ for k, v in top_v.items():
195
+ if v is None:
196
+ continue
197
+ k = k.replace('_', '-')
198
+ if isinstance(v, (tuple, list)):
199
+ out.append(f'{k} = [')
200
+ items = []
201
+ for item in v:
202
+ if item is None:
203
+ pass
204
+ elif isinstance(item, (tuple, list)):
205
+ items.append(f' {json.dumps(item)}')
206
+ elif isinstance(item, dict):
207
+ items.append(
208
+ re.sub(r'"([^"]+)":', r'\1 =', f' {json.dumps(item)}'),
209
+ )
210
+ else:
211
+ items.append(f' {json.dumps([item])[1:-1]}')
212
+ out.append(',\n'.join(items))
213
+ out.append(']')
214
+ elif isinstance(v, dict):
215
+ out.append(re.sub(r'"([^"]+)":', r'\1 =', f' {json.dumps(v)}'))
216
+ else:
217
+ out.append(f'{k} = {json.dumps([v])[1:-1]}')
218
+ return '\n'.join(out).strip()