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,110 @@
1
+ # type: ignore
2
+ import warnings
3
+
4
+ import singlestoredb.mysql as sv
5
+ from . import capabilities
6
+ from singlestoredb.mysql.tests import base
7
+
8
+ warnings.filterwarnings('error')
9
+
10
+
11
+ class test_MySQLdb(capabilities.DatabaseTest):
12
+
13
+ db_module = sv
14
+ connect_args = ()
15
+ connect_kwargs = base.PyMySQLTestCase.databases[0].copy()
16
+ connect_kwargs.update(
17
+ dict(
18
+ read_default_file='~/.my.cnf',
19
+ use_unicode=True,
20
+ binary_prefix=True,
21
+ charset='utf8mb4',
22
+ sql_mode='ANSI,STRICT_TRANS_TABLES,TRADITIONAL',
23
+ ),
24
+ )
25
+
26
+ leak_test = False
27
+
28
+ def quote_identifier(self, ident):
29
+ return '`%s`' % ident
30
+
31
+ def test_TIME(self):
32
+ from datetime import timedelta
33
+
34
+ def generator(row, col):
35
+ return timedelta(0, row * 8000)
36
+
37
+ self.check_data_integrity(('col1 TIME',), generator)
38
+
39
+ def test_TINYINT(self):
40
+ # Number data
41
+ def generator(row, col):
42
+ v = (row * row) % 256
43
+ if v > 127:
44
+ v = v - 256
45
+ return v
46
+
47
+ self.check_data_integrity(('col1 TINYINT',), generator)
48
+
49
+ def test_stored_procedures(self):
50
+ db = self.connection
51
+ c = self.cursor
52
+ try:
53
+ self.create_table(('pos INT', 'tree CHAR(20)'))
54
+ c.executemany(
55
+ 'INSERT INTO %s (pos,tree) VALUES (%%s,%%s)' % self.table,
56
+ list(enumerate('ash birch cedar larch pine'.split())),
57
+ )
58
+ db.commit()
59
+
60
+ c.execute(
61
+ """
62
+ CREATE PROCEDURE test_sp(t VARCHAR(255)) AS
63
+ BEGIN
64
+ ECHO SELECT pos FROM %s WHERE tree = t;
65
+ END
66
+ """
67
+ % self.table,
68
+ )
69
+ db.commit()
70
+
71
+ c.callproc('test_sp', ('larch',))
72
+ rows = c.fetchall()
73
+ self.assertEqual(len(rows), 1)
74
+ self.assertEqual(rows[0][0], 3)
75
+ c.nextset()
76
+ finally:
77
+ c.execute('DROP PROCEDURE IF EXISTS test_sp')
78
+ c.execute('drop table %s' % (self.table))
79
+
80
+ def test_small_CHAR(self):
81
+ # Character data
82
+ def generator(row, col):
83
+ i = ((row + 1) * (col + 1) + 62) % 256
84
+ if i == 62:
85
+ return ''
86
+ if i == 63:
87
+ return None
88
+ return chr(i)
89
+
90
+ self.check_data_integrity(('col1 char(1)', 'col2 char(1)'), generator)
91
+
92
+ def test_bug_2671682(self):
93
+ from singlestoredb.mysql.constants import ER
94
+
95
+ try:
96
+ self.cursor.execute('describe some_non_existent_table')
97
+ except self.connection.ProgrammingError as msg:
98
+ self.assertEqual(msg.args[0], ER.NO_SUCH_TABLE)
99
+
100
+ def test_ping(self):
101
+ self.connection.ping()
102
+
103
+ def test_literal_int(self):
104
+ self.assertTrue('2' == self.connection.literal(2))
105
+
106
+ def test_literal_float(self):
107
+ self.assertEqual('3.1415e0', self.connection.literal(3.1415))
108
+
109
+ def test_literal_string(self):
110
+ self.assertTrue("'foo'" == self.connection.literal('foo'))
@@ -0,0 +1,224 @@
1
+ # type: ignore
2
+ import singlestoredb.mysql as sv
3
+ from . import dbapi20
4
+ from singlestoredb.mysql.tests import base
5
+
6
+
7
+ class test_MySQLdb(dbapi20.DatabaseAPI20Test):
8
+
9
+ driver = sv
10
+ connect_args = ()
11
+ connect_kw_args = base.PyMySQLTestCase.databases[0].copy()
12
+ connect_kw_args.update(
13
+ dict(
14
+ read_default_file='~/.my.cnf',
15
+ charset='utf8',
16
+ sql_mode='ANSI,STRICT_TRANS_TABLES,TRADITIONAL',
17
+ ),
18
+ )
19
+
20
+ def test_setoutputsize(self):
21
+ pass
22
+
23
+ def test_setoutputsize_basic(self):
24
+ pass
25
+
26
+ # The tests on fetchone and fetchall and rowcount bogusly
27
+ # test for an exception if the statement cannot return a
28
+ # result set. MySQL always returns a result set; it's just that
29
+ # some things return empty result sets.
30
+
31
+ def test_fetchall(self):
32
+ con = self._connect()
33
+ try:
34
+ cur = con.cursor()
35
+ # cursor.fetchall should raise an Error if called
36
+ # without executing a query that may return rows (such
37
+ # as a select)
38
+ self.assertRaises(self.driver.Error, cur.fetchall)
39
+
40
+ self.executeDDL1(cur)
41
+ for sql in self._populate():
42
+ cur.execute(sql)
43
+
44
+ # cursor.fetchall should raise an Error if called
45
+ # after executing a a statement that cannot return rows
46
+ # self.assertRaises(self.driver.Error,cur.fetchall)
47
+
48
+ cur.execute('select name from %sbooze' % self.table_prefix)
49
+ rows = cur.fetchall()
50
+ self.assertTrue(cur.rowcount in (-1, len(self.samples)))
51
+ self.assertEqual(
52
+ len(rows),
53
+ len(self.samples),
54
+ 'cursor.fetchall did not retrieve all rows',
55
+ )
56
+ rows = [r[0] for r in rows]
57
+ rows.sort()
58
+ for i in range(0, len(self.samples)):
59
+ self.assertEqual(
60
+ rows[i], self.samples[i], 'cursor.fetchall retrieved incorrect rows',
61
+ )
62
+ rows = cur.fetchall()
63
+ self.assertEqual(
64
+ len(rows),
65
+ 0,
66
+ 'cursor.fetchall should return an empty list if called '
67
+ 'after the whole result set has been fetched',
68
+ )
69
+ self.assertTrue(cur.rowcount in (-1, len(self.samples)))
70
+
71
+ self.executeDDL2(cur)
72
+ cur.execute('select name from %sbarflys' % self.table_prefix)
73
+ rows = cur.fetchall()
74
+ self.assertTrue(cur.rowcount in (-1, 0))
75
+ self.assertEqual(
76
+ len(rows),
77
+ 0,
78
+ 'cursor.fetchall should return an empty list if '
79
+ 'a select query returns no rows',
80
+ )
81
+
82
+ finally:
83
+ con.close()
84
+
85
+ def test_fetchone(self):
86
+ con = self._connect()
87
+ try:
88
+ cur = con.cursor()
89
+
90
+ # cursor.fetchone should raise an Error if called before
91
+ # executing a select-type query
92
+ self.assertRaises(self.driver.Error, cur.fetchone)
93
+
94
+ # cursor.fetchone should raise an Error if called after
95
+ # executing a query that cannnot return rows
96
+ self.executeDDL1(cur)
97
+ # self.assertRaises(self.driver.Error,cur.fetchone)
98
+
99
+ cur.execute('select name from %sbooze' % self.table_prefix)
100
+ self.assertEqual(
101
+ cur.fetchone(),
102
+ None,
103
+ 'cursor.fetchone should return None if a query retrieves ' 'no rows',
104
+ )
105
+ self.assertTrue(cur.rowcount in (-1, 0))
106
+
107
+ # cursor.fetchone should raise an Error if called after
108
+ # executing a query that cannnot return rows
109
+ cur.execute(
110
+ "insert into %sbooze values ('Victoria Bitter')" % (self.table_prefix),
111
+ )
112
+ # self.assertRaises(self.driver.Error,cur.fetchone)
113
+
114
+ cur.execute('select name from %sbooze' % self.table_prefix)
115
+ r = cur.fetchone()
116
+ self.assertEqual(
117
+ len(r), 1, 'cursor.fetchone should have retrieved a single row',
118
+ )
119
+ self.assertEqual(
120
+ r[0], 'Victoria Bitter', 'cursor.fetchone retrieved incorrect data',
121
+ )
122
+ # self.assertEqual(cur.fetchone(), None,
123
+ # 'cursor.fetchone should return None if '
124
+ # 'no more rows available'
125
+ # )
126
+ self.assertTrue(cur.rowcount in (-1, 1))
127
+ finally:
128
+ con.close()
129
+
130
+ # Same complaint as for fetchall and fetchone
131
+ def test_rowcount(self):
132
+ con = self._connect()
133
+ try:
134
+ cur = con.cursor()
135
+ self.executeDDL1(cur)
136
+ # self.assertEqual(cur.rowcount,-1,
137
+ # 'cursor.rowcount should be -1 after executing no-result '
138
+ # 'statements'
139
+ # )
140
+ cur.execute(
141
+ "insert into %sbooze values ('Victoria Bitter')" % (self.table_prefix),
142
+ )
143
+ # self.assertTrue(cur.rowcount in (-1,1),
144
+ # 'cursor.rowcount should == number or rows inserted, or '
145
+ # 'set to -1 after executing an insert statement'
146
+ # )
147
+ cur.execute('select name from %sbooze' % self.table_prefix)
148
+ self.assertTrue(
149
+ cur.rowcount in (-1, 1),
150
+ 'cursor.rowcount should == number of rows returned, or '
151
+ 'set to -1 after executing a select statement',
152
+ )
153
+ cur.fetchall()
154
+ self.executeDDL2(cur)
155
+ # self.assertEqual(cur.rowcount, -1,
156
+ # 'cursor.rowcount not being reset to -1 after executing '
157
+ # 'no-result statements'
158
+ # )
159
+ finally:
160
+ con.close()
161
+
162
+ def test_callproc(self):
163
+ pass # performed in test_MySQL_capabilities
164
+
165
+ def help_nextset_setUp(self, cur):
166
+ """Should create a procedure called deleteme
167
+ that returns two result sets, first the
168
+ number of rows in booze then "name from booze"
169
+ """
170
+ sql = """
171
+ create procedure deleteme() as
172
+ begin
173
+ echo select count(*) from %(tp)sbooze;
174
+ echo select name from %(tp)sbooze;
175
+ end
176
+ """ % dict(
177
+ tp=self.table_prefix,
178
+ )
179
+ cur.execute(sql)
180
+
181
+ def help_nextset_tearDown(self, cur):
182
+ # If cleaning up is needed after nextSetTest
183
+ cur.execute('drop procedure deleteme')
184
+
185
+ def test_nextset(self):
186
+ # from warnings import warn
187
+
188
+ con = self._connect()
189
+ try:
190
+ cur = con.cursor()
191
+ if not hasattr(cur, 'nextset'):
192
+ return
193
+
194
+ try:
195
+ self.executeDDL1(cur)
196
+ sql = self._populate()
197
+ for sql in self._populate():
198
+ cur.execute(sql)
199
+
200
+ self.help_nextset_setUp(cur)
201
+
202
+ cur.callproc('deleteme')
203
+ numberofrows = cur.fetchone()
204
+ assert numberofrows[0] == len(self.samples)
205
+ if cur._result.unbuffered_active:
206
+ assert len(cur.fetchall()) == 0
207
+ assert cur.nextset()
208
+ names = cur.fetchall()
209
+ assert len(names) == len(self.samples)
210
+ s = cur.nextset()
211
+ if s:
212
+ empty = cur.fetchall()
213
+ self.assertEqual(
214
+ len(empty), 0, 'non-empty result set after other result sets',
215
+ )
216
+ # warn("Incompatibility: MySQL returns an empty result set "
217
+ # "for the CALL itself",
218
+ # Warning)
219
+ # assert s == None,'No more return sets, should return None'
220
+ finally:
221
+ self.help_nextset_tearDown(cur)
222
+
223
+ finally:
224
+ con.close()
@@ -0,0 +1,101 @@
1
+ # type: ignore
2
+ import unittest
3
+
4
+ import singlestoredb.mysql as sv
5
+ from singlestoredb.mysql.constants import FIELD_TYPE
6
+ from singlestoredb.mysql.tests import base
7
+
8
+ _mysql = sv
9
+
10
+
11
+ class TestDBAPISet(unittest.TestCase):
12
+
13
+ def test_set_equality(self):
14
+ self.assertTrue(sv.STRING == sv.STRING)
15
+
16
+ def test_set_inequality(self):
17
+ self.assertTrue(sv.STRING != sv.NUMBER)
18
+
19
+ def test_set_equality_membership(self):
20
+ self.assertTrue(FIELD_TYPE.VAR_STRING == sv.STRING)
21
+
22
+ def test_set_inequality_membership(self):
23
+ self.assertTrue(FIELD_TYPE.DATE != sv.STRING)
24
+
25
+
26
+ class CoreModule(unittest.TestCase):
27
+ """Core _mysql module features."""
28
+
29
+ def test_NULL(self):
30
+ """Should have a NULL constant."""
31
+ self.assertEqual(_mysql.NULL, 'NULL')
32
+
33
+ def test_version(self):
34
+ """Version information sanity."""
35
+ self.assertTrue(isinstance(_mysql.__version__, str))
36
+
37
+ self.assertTrue(isinstance(_mysql.version_info, tuple))
38
+ self.assertEqual(len(_mysql.version_info), 5)
39
+
40
+ def test_client_info(self):
41
+ self.assertTrue(isinstance(_mysql.get_client_info(), str))
42
+
43
+ def test_thread_safe(self):
44
+ self.assertTrue(isinstance(_mysql.thread_safe(), int))
45
+
46
+
47
+ class CoreAPI(unittest.TestCase):
48
+ """Test _mysql interaction internals."""
49
+
50
+ def setUp(self):
51
+ kwargs = base.PyMySQLTestCase.databases[0].copy()
52
+ kwargs['read_default_file'] = '~/.my.cnf'
53
+ self.conn = _mysql.connect(**kwargs)
54
+
55
+ def tearDown(self):
56
+ self.conn.close()
57
+
58
+ def test_thread_id(self):
59
+ tid = self.conn.thread_id()
60
+ self.assertTrue(
61
+ isinstance(tid, int), "thread_id didn't return an integral value.",
62
+ )
63
+
64
+ self.assertRaises(
65
+ TypeError,
66
+ self.conn.thread_id,
67
+ ('evil',),
68
+ "thread_id shouldn't accept arguments.",
69
+ )
70
+
71
+ def test_affected_rows(self):
72
+ self.assertEqual(
73
+ self.conn.affected_rows(), 0, 'Should return 0 before we do anything.',
74
+ )
75
+
76
+ # def test_debug(self):
77
+ # FIXME Only actually tests if you lack SUPER
78
+ # self.assertRaises(sv.OperationalError,
79
+ # self.conn.dump_debug_info)
80
+
81
+ def test_charset_name(self):
82
+ self.assertTrue(
83
+ isinstance(self.conn.character_set_name(), str), 'Should return a string.',
84
+ )
85
+
86
+ def test_host_info(self):
87
+ assert isinstance(self.conn.get_host_info(), str), 'should return a string'
88
+
89
+ def test_proto_info(self):
90
+ self.assertTrue(
91
+ isinstance(self.conn.get_proto_info(), int), 'Should return an int.',
92
+ )
93
+
94
+ def test_server_info(self):
95
+ self.assertTrue(
96
+ isinstance(self.conn.get_server_info(), str), 'Should return an str.',
97
+ )
98
+
99
+
100
+ if __name__ == '__main__':
101
+ unittest.main()
@@ -0,0 +1,23 @@
1
+ from datetime import date
2
+ from datetime import datetime
3
+ from datetime import time
4
+ from datetime import timedelta
5
+ from time import localtime
6
+
7
+
8
+ Date = date
9
+ Time = time
10
+ TimeDelta = timedelta
11
+ Timestamp = datetime
12
+
13
+
14
+ def DateFromTicks(ticks: int) -> date:
15
+ return date(*localtime(ticks)[:3])
16
+
17
+
18
+ def TimeFromTicks(ticks: int) -> time:
19
+ return time(*localtime(ticks)[3:6])
20
+
21
+
22
+ def TimestampFromTicks(ticks: int) -> datetime:
23
+ return datetime(*localtime(ticks)[:6])
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env python
2
+ import os as _os
3
+ import warnings as _warnings
4
+
5
+ from ._objects import organization # noqa: F401
6
+ from ._objects import secrets # noqa: F401
7
+ from ._objects import stage # noqa: F401
8
+ from ._objects import workspace # noqa: F401
9
+ from ._objects import workspace_group # noqa: F401
10
+ from ._portal import portal # noqa: F401
11
+
12
+ if 'SINGLESTOREDB_ORGANIZATION' not in _os.environ:
13
+ _warnings.warn(
14
+ 'This package is intended for use in the SingleStoreDB notebook environment',
15
+ RuntimeWarning,
16
+ )
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env python
2
+ import functools
3
+ from typing import Any
4
+ from typing import Optional
5
+
6
+ from ..management import workspace as _ws
7
+
8
+
9
+ class Secrets(object):
10
+ """Wrapper for accessing secrets as object attributes."""
11
+
12
+ def __getattr__(self, name: str) -> Optional[str]:
13
+ if name.startswith('_ipython') or name.startswith('_repr_'):
14
+ raise AttributeError(name)
15
+ return _ws.get_secret(name)
16
+
17
+ def __getitem__(self, name: str) -> Optional[str]:
18
+ return _ws.get_secret(name)
19
+
20
+
21
+ class Stage(object):
22
+
23
+ def __new__(cls, *args: Any, **kwargs: Any) -> Any:
24
+ # We are remapping the methods and attributes here so that
25
+ # autocomplete still works in Jupyter / IPython, but we
26
+ # bypass the real method / attribute calls and apply them
27
+ # to the currently selected stage.
28
+ for name in [x for x in dir(_ws.Stage) if not x.startswith('_')]:
29
+ if name in ['from_dict', 'refresh', 'update']:
30
+ continue
31
+ attr = getattr(_ws.Stage, name)
32
+
33
+ def make_wrapper(m: str, is_method: bool = False) -> Any:
34
+ if is_method:
35
+ def wrap(self: Stage, *a: Any, **kw: Any) -> Any:
36
+ return getattr(_ws.get_stage(), m)(*a, **kw)
37
+ return functools.update_wrapper(wrap, attr)
38
+ else:
39
+ def wrap(self: Stage, *a: Any, **kw: Any) -> Any:
40
+ return getattr(_ws.get_stage(), m)
41
+ return property(functools.update_wrapper(wrap, attr))
42
+
43
+ setattr(cls, name, make_wrapper(m=name, is_method=callable(attr)))
44
+
45
+ for name in [
46
+ x for x in _ws.Stage.__annotations__.keys()
47
+ if not x.startswith('_')
48
+ ]:
49
+
50
+ def make_wrapper(m: str, is_method: bool = False) -> Any:
51
+ def wrap(self: Stage) -> Any:
52
+ return getattr(_ws.get_stage(), m)
53
+ return property(functools.update_wrapper(wrap, attr))
54
+
55
+ setattr(cls, name, make_wrapper(m=name))
56
+
57
+ cls.__doc__ = _ws.Stage.__doc__
58
+
59
+ return super().__new__(cls, *args, **kwargs)
60
+
61
+
62
+ class WorkspaceGroup(object):
63
+
64
+ def __new__(cls, *args: Any, **kwargs: Any) -> Any:
65
+ # We are remapping the methods and attributes here so that
66
+ # autocomplete still works in Jupyter / IPython, but we
67
+ # bypass the real method / attribute calls and apply them
68
+ # to the currently selected workspace group.
69
+ for name in [x for x in dir(_ws.WorkspaceGroup) if not x.startswith('_')]:
70
+ if name in ['from_dict', 'refresh', 'update']:
71
+ continue
72
+
73
+ attr = getattr(_ws.WorkspaceGroup, name)
74
+
75
+ def make_wrapper(m: str, is_method: bool = False) -> Any:
76
+ if is_method:
77
+ def wrap(self: WorkspaceGroup, *a: Any, **kw: Any) -> Any:
78
+ return getattr(_ws.get_workspace_group(), m)(*a, **kw)
79
+ return functools.update_wrapper(wrap, attr)
80
+ else:
81
+ def wrap(self: WorkspaceGroup, *a: Any, **kw: Any) -> Any:
82
+ return getattr(_ws.get_workspace_group(), m)
83
+ return property(functools.update_wrapper(wrap, attr))
84
+
85
+ setattr(cls, name, make_wrapper(m=name, is_method=callable(attr)))
86
+
87
+ for name in [
88
+ x for x in _ws.WorkspaceGroup.__annotations__.keys()
89
+ if not x.startswith('_')
90
+ ]:
91
+
92
+ def make_wrapper(m: str, is_method: bool = False) -> Any:
93
+ def wrap(self: WorkspaceGroup) -> Any:
94
+ return getattr(_ws.get_workspace_group(), m)
95
+ return property(functools.update_wrapper(wrap, attr))
96
+
97
+ setattr(cls, name, make_wrapper(m=name))
98
+
99
+ cls.__doc__ = _ws.WorkspaceGroup.__doc__
100
+
101
+ return super().__new__(cls, *args, **kwargs)
102
+
103
+ def __str__(self) -> str:
104
+ return _ws.get_workspace_group().__str__()
105
+
106
+ def __repr__(self) -> str:
107
+ return _ws.get_workspace_group().__repr__()
108
+
109
+
110
+ class Workspace(object):
111
+
112
+ def __new__(cls, *args: Any, **kwargs: Any) -> Any:
113
+ # We are remapping the methods and attributes here so that
114
+ # autocomplete still works in Jupyter / IPython, but we
115
+ # bypass the real method / attribute calls and apply them
116
+ # to the currently selected workspace.
117
+ for name in [x for x in dir(_ws.Workspace) if not x.startswith('_')]:
118
+ if name in ['from_dict', 'refresh', 'update']:
119
+ continue
120
+
121
+ attr = getattr(_ws.Workspace, name)
122
+
123
+ def make_wrapper(m: str, is_method: bool = False) -> Any:
124
+ if is_method:
125
+ def wrap(self: Workspace, *a: Any, **kw: Any) -> Any:
126
+ return getattr(_ws.get_workspace(), m)(*a, **kw)
127
+ return functools.update_wrapper(wrap, attr)
128
+ else:
129
+ def wrap(self: Workspace, *a: Any, **kw: Any) -> Any:
130
+ return getattr(_ws.get_workspace(), m)
131
+ return property(functools.update_wrapper(wrap, attr))
132
+
133
+ setattr(cls, name, make_wrapper(m=name, is_method=callable(attr)))
134
+
135
+ for name in [
136
+ x for x in _ws.Workspace.__annotations__.keys()
137
+ if not x.startswith('_')
138
+ ]:
139
+
140
+ def make_wrapper(m: str, is_method: bool = False) -> Any:
141
+ def wrap(self: Workspace) -> Any:
142
+ return getattr(_ws.get_workspace(), m)
143
+ return property(functools.update_wrapper(wrap, attr))
144
+
145
+ setattr(cls, name, make_wrapper(m=name))
146
+
147
+ cls.__doc__ = _ws.Workspace.__doc__
148
+
149
+ return super().__new__(cls, *args, **kwargs)
150
+
151
+ def __str__(self) -> str:
152
+ return _ws.get_workspace().__str__()
153
+
154
+ def __repr__(self) -> str:
155
+ return _ws.get_workspace().__repr__()
156
+
157
+
158
+ class Organization(object):
159
+
160
+ def __new__(cls, *args: Any, **kwargs: Any) -> Any:
161
+ # We are remapping the methods and attributes here so that
162
+ # autocomplete still works in Jupyter / IPython, but we
163
+ # bypass the real method / attribute calls and apply them
164
+ # to the currently selected organization.
165
+ for name in [x for x in dir(_ws.Organization) if not x.startswith('_')]:
166
+ if name in ['from_dict', 'refresh', 'update']:
167
+ continue
168
+
169
+ attr = getattr(_ws.Organization, name)
170
+
171
+ def make_wrapper(m: str, is_method: bool = False) -> Any:
172
+ if is_method:
173
+ def wrap(self: Organization, *a: Any, **kw: Any) -> Any:
174
+ return getattr(_ws.get_organization(), m)(*a, **kw)
175
+ return functools.update_wrapper(wrap, attr)
176
+ else:
177
+ def wrap(self: Organization, *a: Any, **kw: Any) -> Any:
178
+ return getattr(_ws.get_organization(), m)
179
+ return property(functools.update_wrapper(wrap, attr))
180
+
181
+ setattr(cls, name, make_wrapper(m=name, is_method=callable(attr)))
182
+
183
+ for name in [
184
+ x for x in _ws.Organization.__annotations__.keys()
185
+ if not x.startswith('_')
186
+ ]:
187
+
188
+ def make_wrapper(m: str, is_method: bool = False) -> Any:
189
+ def wrap(self: Organization) -> Any:
190
+ return getattr(_ws.get_organization(), m)
191
+ return property(functools.update_wrapper(wrap, attr))
192
+
193
+ setattr(cls, name, make_wrapper(m=name))
194
+
195
+ cls.__doc__ = _ws.Organization.__doc__
196
+
197
+ return super().__new__(cls, *args, **kwargs)
198
+
199
+ def __str__(self) -> str:
200
+ return _ws.get_organization().__str__()
201
+
202
+ def __repr__(self) -> str:
203
+ return _ws.get_organization().__repr__()
204
+
205
+
206
+ secrets = Secrets()
207
+ stage = Stage()
208
+ organization = Organization()
209
+ workspace_group = WorkspaceGroup()
210
+ workspace = Workspace()
211
+
212
+
213
+ __all__ = ['secrets', 'stage', 'workspace', 'workspace_group', 'organization']