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,141 @@
1
+ """Utility functions for working with docstrings."""
2
+ import typing as T
3
+ from collections import ChainMap
4
+ from inspect import Signature
5
+ from itertools import chain
6
+
7
+ from .common import DocstringMeta
8
+ from .common import DocstringParam
9
+ from .common import DocstringReturns # noqa: F401
10
+ from .common import DocstringStyle
11
+ from .common import RenderingStyle
12
+ from .parser import compose
13
+ from .parser import parse
14
+
15
+ _Func = T.Callable[..., T.Any]
16
+
17
+
18
+ def combine_docstrings(
19
+ *others: _Func,
20
+ exclude: T.Iterable[T.Type[DocstringMeta]] = (),
21
+ style: DocstringStyle = DocstringStyle.AUTO,
22
+ rendering_style: RenderingStyle = RenderingStyle.COMPACT,
23
+ ) -> _Func:
24
+ """A function decorator that parses the docstrings from `others`,
25
+ programmatically combines them with the parsed docstring of the decorated
26
+ function, and replaces the docstring of the decorated function with the
27
+ composed result. Only parameters that are part of the decorated functions
28
+ signature are included in the combined docstring. When multiple sources for
29
+ a parameter or docstring metadata exists then the decorator will first
30
+ default to the wrapped function's value (when available) and otherwise use
31
+ the rightmost definition from ``others``.
32
+
33
+ The following example illustrates its usage:
34
+
35
+ >>> def fun1(a, b, c, d):
36
+ ... '''short_description: fun1
37
+ ...
38
+ ... :param a: fun1
39
+ ... :param b: fun1
40
+ ... :return: fun1
41
+ ... '''
42
+ >>> def fun2(b, c, d, e):
43
+ ... '''short_description: fun2
44
+ ...
45
+ ... long_description: fun2
46
+ ...
47
+ ... :param b: fun2
48
+ ... :param c: fun2
49
+ ... :param e: fun2
50
+ ... '''
51
+ >>> @combine_docstrings(fun1, fun2)
52
+ >>> def decorated(a, b, c, d, e, f):
53
+ ... '''
54
+ ... :param e: decorated
55
+ ... :param f: decorated
56
+ ... '''
57
+ >>> print(decorated.__doc__)
58
+ short_description: fun2
59
+ <BLANKLINE>
60
+ long_description: fun2
61
+ <BLANKLINE>
62
+ :param a: fun1
63
+ :param b: fun1
64
+ :param c: fun2
65
+ :param e: fun2
66
+ :param f: decorated
67
+ :returns: fun1
68
+ >>> @combine_docstrings(fun1, fun2, exclude=[DocstringReturns])
69
+ >>> def decorated(a, b, c, d, e, f): pass
70
+ >>> print(decorated.__doc__)
71
+ short_description: fun2
72
+ <BLANKLINE>
73
+ long_description: fun2
74
+ <BLANKLINE>
75
+ :param a: fun1
76
+ :param b: fun1
77
+ :param c: fun2
78
+ :param e: fun2
79
+
80
+ :param others: callables from which to parse docstrings.
81
+ :param exclude: an iterable of ``DocstringMeta`` subclasses to exclude when
82
+ combining docstrings.
83
+ :param style: style composed docstring. The default will infer the style
84
+ from the decorated function.
85
+ :param rendering_style: The rendering style used to compose a docstring.
86
+ :return: the decorated function with a modified docstring.
87
+ """
88
+
89
+ def wrapper(func: _Func) -> _Func:
90
+ sig = Signature.from_callable(func)
91
+
92
+ comb_doc = parse(func.__doc__ or '')
93
+ docs = [parse(other.__doc__ or '') for other in others] + [comb_doc]
94
+ params = dict(
95
+ ChainMap(
96
+ *(
97
+ {param.arg_name: param for param in doc.params}
98
+ for doc in docs
99
+ ),
100
+ ),
101
+ )
102
+
103
+ for doc in reversed(docs):
104
+ if not doc.short_description:
105
+ continue
106
+ comb_doc.short_description = doc.short_description
107
+ comb_doc.blank_after_short_description = (
108
+ doc.blank_after_short_description
109
+ )
110
+ break
111
+
112
+ for doc in reversed(docs):
113
+ if not doc.long_description:
114
+ continue
115
+ comb_doc.long_description = doc.long_description
116
+ comb_doc.blank_after_long_description = (
117
+ doc.blank_after_long_description
118
+ )
119
+ break
120
+
121
+ combined: T.Dict[T.Type[DocstringMeta], T.List[DocstringMeta]] = {}
122
+ for doc in docs:
123
+ metas: T.Dict[T.Type[DocstringMeta], T.List[DocstringMeta]] = {}
124
+ for meta in doc.meta:
125
+ meta_type = type(meta)
126
+ if meta_type in exclude:
127
+ continue
128
+ metas.setdefault(meta_type, []).append(meta)
129
+ for meta_type, meta_list in metas.items():
130
+ combined[meta_type] = meta_list
131
+
132
+ combined[DocstringParam] = [
133
+ params[name] for name in sig.parameters if name in params
134
+ ]
135
+ comb_doc.meta = list(chain(*combined.values()))
136
+ func.__doc__ = compose(
137
+ comb_doc, style=style, rendering_style=rendering_style,
138
+ )
139
+ return func
140
+
141
+ return wrapper
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env python
2
+ """Database exeception classes."""
3
+ from typing import Optional
4
+
5
+
6
+ class MySQLError(Exception):
7
+ """All MySQL-related exceptions."""
8
+
9
+
10
+ class Error(MySQLError):
11
+ """
12
+ Generic database exception.
13
+
14
+ Parameters
15
+ ----------
16
+ errno : int
17
+ Database error code
18
+ msg : str
19
+ Database error message
20
+ sqlstate : str, optional
21
+ SQL engine state code
22
+
23
+ """
24
+
25
+ def __init__(
26
+ self, errno: Optional[int] = None, msg: Optional[str] = None,
27
+ sqlstate: Optional[int] = None,
28
+ ):
29
+ self.errno = errno
30
+ self.errmsg = msg
31
+ self.sqlstate = sqlstate
32
+ super(Exception, self).__init__(errno, msg, sqlstate)
33
+
34
+ def __str__(self) -> str:
35
+ """Return string representation."""
36
+ prefix = []
37
+ if self.errno is not None:
38
+ prefix.append(f'{self.errno}')
39
+ if self.sqlstate is not None:
40
+ prefix.append(f'({self.sqlstate})')
41
+ if prefix and self.errmsg:
42
+ return ' '.join(prefix) + ': ' + self.errmsg
43
+ elif prefix:
44
+ return ' '.join(prefix)
45
+ elif self.errmsg:
46
+ return f'{self.errmsg}'
47
+ return 'Unknown error'
48
+
49
+ def __repr__(self) -> str:
50
+ """Return string representation."""
51
+ return str(self)
52
+
53
+ @property
54
+ def msg(self) -> Optional[str]:
55
+ """Return error message."""
56
+ return self.errmsg
57
+
58
+
59
+ class Warning(Warning, MySQLError): # type: ignore
60
+ """Exception for important warnings like data truncations, etc."""
61
+
62
+
63
+ class InterfaceError(Error):
64
+ """Exception for errors in the database interface rather than the database."""
65
+
66
+
67
+ class DatabaseError(Error):
68
+ """General exception for errors in the database."""
69
+
70
+
71
+ class InternalError(DatabaseError):
72
+ """Exception for internal database errors such as out of sync transactions."""
73
+
74
+
75
+ class OperationalError(DatabaseError):
76
+ """Exception for operational errors such as unexpected disconnections."""
77
+
78
+
79
+ class ProgrammingError(DatabaseError):
80
+ """Exception for programming errors."""
81
+
82
+
83
+ class IntegrityError(DatabaseError):
84
+ """Exception for relational integrity errors."""
85
+
86
+
87
+ class DataError(DatabaseError):
88
+ """Exception for problems with processed data like division by zero."""
89
+
90
+
91
+ class NotSupportedError(DatabaseError):
92
+ """Exception for using unsupported features of the database."""
93
+
94
+
95
+ class ManagementError(Error):
96
+ """Exception for errors in the management API."""
97
+
98
+ def __init__(
99
+ self, errno: Optional[int] = None, msg: Optional[str] = None,
100
+ response: Optional[str] = None,
101
+ ):
102
+ self.errno = errno
103
+ self.errmsg = msg
104
+ self.response = response
105
+ super(Exception, self).__init__(errno, msg)
106
+
107
+ def __str__(self) -> str:
108
+ """Return string representation."""
109
+ prefix = []
110
+ if self.errno is not None:
111
+ prefix.append(f'{self.errno}')
112
+ if self.response is not None:
113
+ prefix.append(f'({self.response})')
114
+ if prefix and self.errmsg:
115
+ return ' '.join(prefix) + ': ' + self.errmsg
116
+ elif prefix:
117
+ return ' '.join(prefix)
118
+ elif self.errmsg:
119
+ return f'{self.errmsg}'
120
+ return 'Unknown error'
@@ -0,0 +1,16 @@
1
+ from .decorator import udf # noqa: F401
2
+ from .typing import Masked # noqa: F401
3
+ from .typing import Table # noqa: F401
4
+ from .utils import pack_vector # noqa: F401
5
+ from .utils import pack_vectors # noqa: F401
6
+ from .utils import unpack_vector # noqa: F401
7
+ from .utils import unpack_vectors # noqa: F401
8
+ from .utils import VectorTypes
9
+
10
+
11
+ F32 = VectorTypes.F32
12
+ F64 = VectorTypes.F64
13
+ I8 = VectorTypes.I8
14
+ I16 = VectorTypes.I16
15
+ I32 = VectorTypes.I32
16
+ I64 = VectorTypes.I64
@@ -0,0 +1,201 @@
1
+ import asyncio
2
+ import functools
3
+ import inspect
4
+ from typing import Any
5
+ from typing import Callable
6
+ from typing import List
7
+ from typing import Optional
8
+ from typing import Type
9
+ from typing import Union
10
+
11
+ from . import utils
12
+ from .dtypes import SQLString
13
+
14
+
15
+ ParameterType = Union[
16
+ str,
17
+ Callable[..., SQLString],
18
+ List[Union[str, Callable[..., SQLString]]],
19
+ Type[Any],
20
+ ]
21
+
22
+ ReturnType = ParameterType
23
+ UDFType = Callable[..., Any]
24
+
25
+
26
+ def is_valid_type(obj: Any) -> bool:
27
+ """Check if the object is a valid type for a schema definition."""
28
+ if not inspect.isclass(obj):
29
+ return False
30
+
31
+ if utils.is_typeddict(obj):
32
+ return True
33
+
34
+ if utils.is_namedtuple(obj):
35
+ return True
36
+
37
+ if utils.is_dataclass(obj):
38
+ return True
39
+
40
+ # We don't want to import pydantic here, so we check if
41
+ # the class is a subclass
42
+ if utils.is_pydantic(obj):
43
+ return True
44
+
45
+ return False
46
+
47
+
48
+ def is_sqlstr_callable(obj: Any) -> bool:
49
+ """Check if the object is a valid callable for a parameter type."""
50
+ if not callable(obj):
51
+ return False
52
+
53
+ returns = utils.get_annotations(obj).get('return', None)
54
+
55
+ if inspect.isclass(returns) and issubclass(returns, SQLString):
56
+ return True
57
+
58
+ return False
59
+
60
+
61
+ def expand_types(args: Any) -> Optional[List[Any]]:
62
+ """Expand the types for the function arguments / return values."""
63
+ if args is None:
64
+ return None
65
+
66
+ # SQL string
67
+ if isinstance(args, str):
68
+ return [args]
69
+
70
+ # List of SQL strings or callables
71
+ elif isinstance(args, list):
72
+ new_args: List[Any] = []
73
+ for arg in args:
74
+ if isinstance(arg, str):
75
+ new_args.append(arg)
76
+ elif is_sqlstr_callable(arg):
77
+ new_args.append(arg())
78
+ elif type(arg) is type:
79
+ new_args.append(arg)
80
+ elif is_valid_type(arg):
81
+ new_args.append(arg)
82
+ else:
83
+ raise TypeError(f'unrecognized type for parameter: {arg}')
84
+ return new_args
85
+
86
+ # Callable that returns a SQL string
87
+ elif is_sqlstr_callable(args):
88
+ return [args()]
89
+
90
+ # General way of accepting pydantic.BaseModel, NamedTuple, TypedDict
91
+ elif is_valid_type(args):
92
+ return [args]
93
+
94
+ elif type(args) is type:
95
+ return [args]
96
+
97
+ raise TypeError(f'unrecognized type for parameter: {args}')
98
+
99
+
100
+ def _func(
101
+ func: Optional[Callable[..., Any]] = None,
102
+ *,
103
+ name: Optional[str] = None,
104
+ args: Optional[ParameterType] = None,
105
+ returns: Optional[ReturnType] = None,
106
+ timeout: Optional[int] = None,
107
+ ) -> UDFType:
108
+ """Generic wrapper for UDF and TVF decorators."""
109
+
110
+ _singlestoredb_attrs = { # type: ignore
111
+ k: v for k, v in dict(
112
+ name=name,
113
+ args=expand_types(args),
114
+ returns=expand_types(returns),
115
+ timeout=timeout,
116
+ ).items() if v is not None
117
+ }
118
+
119
+ # No func was specified, this is an uncalled decorator that will get
120
+ # called later, so the wrapper much be created with the func passed
121
+ # in at that time.
122
+ if func is None:
123
+ def decorate(func: UDFType) -> UDFType:
124
+
125
+ if asyncio.iscoroutinefunction(func):
126
+ async def async_wrapper(*args: Any, **kwargs: Any) -> UDFType:
127
+ return await func(*args, **kwargs) # type: ignore
128
+ async_wrapper._singlestoredb_attrs = _singlestoredb_attrs # type: ignore
129
+ return functools.wraps(func)(async_wrapper)
130
+
131
+ else:
132
+ def wrapper(*args: Any, **kwargs: Any) -> UDFType:
133
+ return func(*args, **kwargs) # type: ignore
134
+ wrapper._singlestoredb_attrs = _singlestoredb_attrs # type: ignore
135
+ return functools.wraps(func)(wrapper)
136
+
137
+ return decorate
138
+
139
+ if asyncio.iscoroutinefunction(func):
140
+ async def async_wrapper(*args: Any, **kwargs: Any) -> UDFType:
141
+ return await func(*args, **kwargs) # type: ignore
142
+ async_wrapper._singlestoredb_attrs = _singlestoredb_attrs # type: ignore
143
+ return functools.wraps(func)(async_wrapper)
144
+
145
+ else:
146
+ def wrapper(*args: Any, **kwargs: Any) -> UDFType:
147
+ return func(*args, **kwargs) # type: ignore
148
+ wrapper._singlestoredb_attrs = _singlestoredb_attrs # type: ignore
149
+ return functools.wraps(func)(wrapper)
150
+
151
+
152
+ def udf(
153
+ func: Optional[Callable[..., Any]] = None,
154
+ *,
155
+ name: Optional[str] = None,
156
+ args: Optional[ParameterType] = None,
157
+ returns: Optional[ReturnType] = None,
158
+ timeout: Optional[int] = None,
159
+ ) -> UDFType:
160
+ """
161
+ Define a user-defined function (UDF).
162
+
163
+ Parameters
164
+ ----------
165
+ func : callable, optional
166
+ The UDF to apply parameters to
167
+ name : str, optional
168
+ The name to use for the UDF in the database
169
+ args : str | Type | Callable | List[str | Callable], optional
170
+ Specifies the data types of the function arguments. Typically,
171
+ the function data types are derived from the function parameter
172
+ annotations. These annotations can be overridden. If the function
173
+ takes a single type for all parameters, `args` can be set to a
174
+ SQL string describing all parameters. If the function takes more
175
+ than one parameter and all of the parameters are being manually
176
+ defined, a list of SQL strings may be used (one for each parameter).
177
+ A dictionary of SQL strings may be used to specify a parameter type
178
+ for a subset of parameters; the keys are the names of the
179
+ function parameters. Callables may also be used for datatypes. This
180
+ is primarily for using the functions in the ``dtypes`` module that
181
+ are associated with SQL types with all default options (e.g., ``dt.FLOAT``).
182
+ returns : str | Type | Callable | List[str | Callable] | Table, optional
183
+ Specifies the return data type of the function. This parameter
184
+ works the same way as `args`. If the function is a table-valued
185
+ function, the return type should be a `Table` object.
186
+ timeout : int, optional
187
+ The timeout in seconds for the UDF execution. If not specified,
188
+ the global default timeout is used.
189
+
190
+ Returns
191
+ -------
192
+ Callable
193
+
194
+ """
195
+ return _func(
196
+ func=func,
197
+ name=name,
198
+ args=args,
199
+ returns=returns,
200
+ timeout=timeout,
201
+ )