matrixone-python-sdk 0.1.0__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.
- matrixone/__init__.py +155 -0
- matrixone/account.py +723 -0
- matrixone/async_client.py +3913 -0
- matrixone/async_metadata_manager.py +311 -0
- matrixone/async_orm.py +123 -0
- matrixone/async_vector_index_manager.py +633 -0
- matrixone/base_client.py +208 -0
- matrixone/client.py +4672 -0
- matrixone/config.py +452 -0
- matrixone/connection_hooks.py +286 -0
- matrixone/exceptions.py +89 -0
- matrixone/logger.py +782 -0
- matrixone/metadata.py +820 -0
- matrixone/moctl.py +219 -0
- matrixone/orm.py +2277 -0
- matrixone/pitr.py +646 -0
- matrixone/pubsub.py +771 -0
- matrixone/restore.py +411 -0
- matrixone/search_vector_index.py +1176 -0
- matrixone/snapshot.py +550 -0
- matrixone/sql_builder.py +844 -0
- matrixone/sqlalchemy_ext/__init__.py +161 -0
- matrixone/sqlalchemy_ext/adapters.py +163 -0
- matrixone/sqlalchemy_ext/dialect.py +534 -0
- matrixone/sqlalchemy_ext/fulltext_index.py +895 -0
- matrixone/sqlalchemy_ext/fulltext_search.py +1686 -0
- matrixone/sqlalchemy_ext/hnsw_config.py +194 -0
- matrixone/sqlalchemy_ext/ivf_config.py +252 -0
- matrixone/sqlalchemy_ext/table_builder.py +351 -0
- matrixone/sqlalchemy_ext/vector_index.py +1721 -0
- matrixone/sqlalchemy_ext/vector_type.py +948 -0
- matrixone/version.py +580 -0
- matrixone_python_sdk-0.1.0.dist-info/METADATA +706 -0
- matrixone_python_sdk-0.1.0.dist-info/RECORD +122 -0
- matrixone_python_sdk-0.1.0.dist-info/WHEEL +5 -0
- matrixone_python_sdk-0.1.0.dist-info/entry_points.txt +5 -0
- matrixone_python_sdk-0.1.0.dist-info/licenses/LICENSE +200 -0
- matrixone_python_sdk-0.1.0.dist-info/top_level.txt +2 -0
- tests/__init__.py +19 -0
- tests/offline/__init__.py +20 -0
- tests/offline/conftest.py +77 -0
- tests/offline/test_account.py +703 -0
- tests/offline/test_async_client_query_comprehensive.py +1218 -0
- tests/offline/test_basic.py +54 -0
- tests/offline/test_case_sensitivity.py +227 -0
- tests/offline/test_connection_hooks_offline.py +287 -0
- tests/offline/test_dialect_schema_handling.py +609 -0
- tests/offline/test_explain_methods.py +346 -0
- tests/offline/test_filter_logical_in.py +237 -0
- tests/offline/test_fulltext_search_comprehensive.py +795 -0
- tests/offline/test_ivf_config.py +249 -0
- tests/offline/test_join_methods.py +281 -0
- tests/offline/test_join_sqlalchemy_compatibility.py +276 -0
- tests/offline/test_logical_in_method.py +237 -0
- tests/offline/test_matrixone_version_parsing.py +264 -0
- tests/offline/test_metadata_offline.py +557 -0
- tests/offline/test_moctl.py +300 -0
- tests/offline/test_moctl_simple.py +251 -0
- tests/offline/test_model_support_offline.py +359 -0
- tests/offline/test_model_support_simple.py +225 -0
- tests/offline/test_pinecone_filter_offline.py +377 -0
- tests/offline/test_pitr.py +585 -0
- tests/offline/test_pubsub.py +712 -0
- tests/offline/test_query_update.py +283 -0
- tests/offline/test_restore.py +445 -0
- tests/offline/test_snapshot_comprehensive.py +384 -0
- tests/offline/test_sql_escaping_edge_cases.py +551 -0
- tests/offline/test_sqlalchemy_integration.py +382 -0
- tests/offline/test_sqlalchemy_vector_integration.py +434 -0
- tests/offline/test_table_builder.py +198 -0
- tests/offline/test_unified_filter.py +398 -0
- tests/offline/test_unified_transaction.py +495 -0
- tests/offline/test_vector_index.py +238 -0
- tests/offline/test_vector_operations.py +688 -0
- tests/offline/test_vector_type.py +174 -0
- tests/offline/test_version_core.py +328 -0
- tests/offline/test_version_management.py +372 -0
- tests/offline/test_version_standalone.py +652 -0
- tests/online/__init__.py +20 -0
- tests/online/conftest.py +216 -0
- tests/online/test_account_management.py +194 -0
- tests/online/test_advanced_features.py +344 -0
- tests/online/test_async_client_interfaces.py +330 -0
- tests/online/test_async_client_online.py +285 -0
- tests/online/test_async_model_insert_online.py +293 -0
- tests/online/test_async_orm_online.py +300 -0
- tests/online/test_async_simple_query_online.py +802 -0
- tests/online/test_async_transaction_simple_query.py +300 -0
- tests/online/test_basic_connection.py +130 -0
- tests/online/test_client_online.py +238 -0
- tests/online/test_config.py +90 -0
- tests/online/test_config_validation.py +123 -0
- tests/online/test_connection_hooks_new_online.py +217 -0
- tests/online/test_dialect_schema_handling_online.py +331 -0
- tests/online/test_filter_logical_in_online.py +374 -0
- tests/online/test_fulltext_comprehensive.py +1773 -0
- tests/online/test_fulltext_label_online.py +433 -0
- tests/online/test_fulltext_search_online.py +842 -0
- tests/online/test_ivf_stats_online.py +506 -0
- tests/online/test_logger_integration.py +311 -0
- tests/online/test_matrixone_query_orm.py +540 -0
- tests/online/test_metadata_online.py +579 -0
- tests/online/test_model_insert_online.py +255 -0
- tests/online/test_mysql_driver_validation.py +213 -0
- tests/online/test_orm_advanced_features.py +2022 -0
- tests/online/test_orm_cte_integration.py +269 -0
- tests/online/test_orm_online.py +270 -0
- tests/online/test_pinecone_filter.py +708 -0
- tests/online/test_pubsub_operations.py +352 -0
- tests/online/test_query_methods.py +225 -0
- tests/online/test_query_update_online.py +433 -0
- tests/online/test_search_vector_index.py +557 -0
- tests/online/test_simple_fulltext_online.py +915 -0
- tests/online/test_snapshot_comprehensive.py +998 -0
- tests/online/test_sqlalchemy_engine_integration.py +336 -0
- tests/online/test_sqlalchemy_integration.py +425 -0
- tests/online/test_transaction_contexts.py +1219 -0
- tests/online/test_transaction_insert_methods.py +356 -0
- tests/online/test_transaction_query_methods.py +288 -0
- tests/online/test_unified_filter_online.py +529 -0
- tests/online/test_vector_comprehensive.py +706 -0
- tests/online/test_version_management.py +291 -0
@@ -0,0 +1,336 @@
|
|
1
|
+
# Copyright 2021 - 2022 Matrix Origin
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
"""
|
16
|
+
Online tests for SQLAlchemy Engine integration - tests Client and AsyncClient construction from SQLAlchemy engines
|
17
|
+
"""
|
18
|
+
|
19
|
+
import pytest
|
20
|
+
import os
|
21
|
+
import sys
|
22
|
+
from sqlalchemy import create_engine, text
|
23
|
+
from sqlalchemy.ext.asyncio import create_async_engine
|
24
|
+
|
25
|
+
# Add the matrixone package to the path
|
26
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
27
|
+
|
28
|
+
from matrixone import Client, AsyncClient
|
29
|
+
from .test_config import online_config
|
30
|
+
|
31
|
+
|
32
|
+
class TestSQLAlchemyEngineIntegration:
|
33
|
+
"""Online tests for SQLAlchemy Engine integration"""
|
34
|
+
|
35
|
+
@pytest.fixture(scope="class")
|
36
|
+
def connection_params(self):
|
37
|
+
"""Get connection parameters"""
|
38
|
+
return online_config.get_connection_params()
|
39
|
+
|
40
|
+
@pytest.fixture(scope="class")
|
41
|
+
def test_database(self):
|
42
|
+
"""Get test database name"""
|
43
|
+
return "test_engine_integration_db"
|
44
|
+
|
45
|
+
def test_client_from_sync_engine(self, connection_params, test_database):
|
46
|
+
"""Test creating Client from SQLAlchemy sync engine"""
|
47
|
+
host, port, user, password, database = connection_params
|
48
|
+
|
49
|
+
# Create SQLAlchemy engine
|
50
|
+
connection_string = f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}"
|
51
|
+
engine = create_engine(connection_string)
|
52
|
+
|
53
|
+
try:
|
54
|
+
# Create Client from engine
|
55
|
+
client = Client.from_engine(engine)
|
56
|
+
|
57
|
+
# Test basic functionality
|
58
|
+
assert client.connected() is True
|
59
|
+
|
60
|
+
# Test query execution
|
61
|
+
result = client.execute("SELECT 1 as test_value")
|
62
|
+
rows = result.fetchall()
|
63
|
+
assert len(rows) == 1
|
64
|
+
assert rows[0][0] == 1
|
65
|
+
|
66
|
+
# Test database operations
|
67
|
+
client.execute(f"CREATE DATABASE IF NOT EXISTS {test_database}")
|
68
|
+
client.execute(f"USE {test_database}")
|
69
|
+
|
70
|
+
# Test table creation
|
71
|
+
client.execute(
|
72
|
+
"""
|
73
|
+
CREATE TABLE IF NOT EXISTS test_table (
|
74
|
+
id INT PRIMARY KEY,
|
75
|
+
name VARCHAR(100)
|
76
|
+
)
|
77
|
+
"""
|
78
|
+
)
|
79
|
+
|
80
|
+
# Test data insertion
|
81
|
+
client.execute("INSERT INTO test_table VALUES (1, 'test')")
|
82
|
+
|
83
|
+
# Test data retrieval
|
84
|
+
result = client.execute("SELECT * FROM test_table")
|
85
|
+
rows = result.fetchall()
|
86
|
+
assert len(rows) == 1
|
87
|
+
assert rows[0][0] == 1
|
88
|
+
assert rows[0][1] == 'test'
|
89
|
+
|
90
|
+
finally:
|
91
|
+
# Cleanup
|
92
|
+
try:
|
93
|
+
client.execute(f"DROP DATABASE IF EXISTS {test_database}")
|
94
|
+
except Exception as e:
|
95
|
+
print(f"Cleanup failed: {e}")
|
96
|
+
client.disconnect()
|
97
|
+
engine.dispose()
|
98
|
+
|
99
|
+
def test_client_from_sync_engine_with_config(self, connection_params, test_database):
|
100
|
+
"""Test creating Client from SQLAlchemy sync engine with custom configuration"""
|
101
|
+
host, port, user, password, database = connection_params
|
102
|
+
|
103
|
+
# Create SQLAlchemy engine
|
104
|
+
connection_string = f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}"
|
105
|
+
engine = create_engine(connection_string)
|
106
|
+
|
107
|
+
try:
|
108
|
+
# Create Client from engine with custom configuration
|
109
|
+
client = Client.from_engine(engine, sql_log_mode="auto", slow_query_threshold=0.1)
|
110
|
+
|
111
|
+
# Test basic functionality
|
112
|
+
assert client.connected() is True
|
113
|
+
|
114
|
+
# Test query execution
|
115
|
+
result = client.execute("SELECT 2 as test_value")
|
116
|
+
rows = result.fetchall()
|
117
|
+
assert len(rows) == 1
|
118
|
+
assert rows[0][0] == 2
|
119
|
+
|
120
|
+
finally:
|
121
|
+
# Cleanup
|
122
|
+
client.disconnect()
|
123
|
+
engine.dispose()
|
124
|
+
|
125
|
+
@pytest.mark.asyncio
|
126
|
+
async def test_async_client_from_async_engine(self, connection_params, test_database):
|
127
|
+
"""Test creating AsyncClient from SQLAlchemy async engine"""
|
128
|
+
host, port, user, password, database = connection_params
|
129
|
+
|
130
|
+
# Create SQLAlchemy async engine
|
131
|
+
connection_string = f"mysql+aiomysql://{user}:{password}@{host}:{port}/{database}"
|
132
|
+
engine = create_async_engine(connection_string)
|
133
|
+
|
134
|
+
try:
|
135
|
+
# Create AsyncClient from engine
|
136
|
+
client = AsyncClient.from_engine(engine)
|
137
|
+
|
138
|
+
# Test basic functionality
|
139
|
+
assert client.connected() is True
|
140
|
+
|
141
|
+
# Test query execution
|
142
|
+
result = await client.execute("SELECT 3 as test_value")
|
143
|
+
rows = result.fetchall()
|
144
|
+
assert len(rows) == 1
|
145
|
+
assert rows[0][0] == 3
|
146
|
+
|
147
|
+
# Test database operations
|
148
|
+
await client.execute(f"CREATE DATABASE IF NOT EXISTS {test_database}")
|
149
|
+
await client.execute(f"USE {test_database}")
|
150
|
+
|
151
|
+
# Test table creation
|
152
|
+
await client.execute(
|
153
|
+
"""
|
154
|
+
CREATE TABLE IF NOT EXISTS async_test_table (
|
155
|
+
id INT PRIMARY KEY,
|
156
|
+
name VARCHAR(100)
|
157
|
+
)
|
158
|
+
"""
|
159
|
+
)
|
160
|
+
|
161
|
+
# Test data insertion
|
162
|
+
await client.execute("INSERT INTO async_test_table VALUES (1, 'async_test')")
|
163
|
+
|
164
|
+
# Test data retrieval
|
165
|
+
result = await client.execute("SELECT * FROM async_test_table")
|
166
|
+
rows = result.fetchall()
|
167
|
+
assert len(rows) == 1
|
168
|
+
assert rows[0][0] == 1
|
169
|
+
assert rows[0][1] == 'async_test'
|
170
|
+
|
171
|
+
finally:
|
172
|
+
# Cleanup
|
173
|
+
try:
|
174
|
+
await client.execute(f"DROP DATABASE IF EXISTS {test_database}")
|
175
|
+
except Exception as e:
|
176
|
+
print(f"Cleanup failed: {e}")
|
177
|
+
await client.disconnect()
|
178
|
+
await engine.dispose()
|
179
|
+
|
180
|
+
@pytest.mark.asyncio
|
181
|
+
async def test_async_client_from_async_engine_with_config(self, connection_params, test_database):
|
182
|
+
"""Test creating AsyncClient from SQLAlchemy async engine with custom configuration"""
|
183
|
+
host, port, user, password, database = connection_params
|
184
|
+
|
185
|
+
# Create SQLAlchemy async engine
|
186
|
+
connection_string = f"mysql+aiomysql://{user}:{password}@{host}:{port}/{database}"
|
187
|
+
engine = create_async_engine(connection_string)
|
188
|
+
|
189
|
+
try:
|
190
|
+
# Create AsyncClient from engine with custom configuration
|
191
|
+
client = AsyncClient.from_engine(engine, sql_log_mode="auto", slow_query_threshold=0.1)
|
192
|
+
|
193
|
+
# Test basic functionality
|
194
|
+
assert client.connected() is True
|
195
|
+
|
196
|
+
# Test query execution
|
197
|
+
result = await client.execute("SELECT 4 as test_value")
|
198
|
+
rows = result.fetchall()
|
199
|
+
assert len(rows) == 1
|
200
|
+
assert rows[0][0] == 4
|
201
|
+
|
202
|
+
finally:
|
203
|
+
# Cleanup
|
204
|
+
await client.disconnect()
|
205
|
+
await engine.dispose()
|
206
|
+
|
207
|
+
def test_client_engine_reuse(self, connection_params):
|
208
|
+
"""Test that the same engine can be used to create multiple clients"""
|
209
|
+
host, port, user, password, database = connection_params
|
210
|
+
|
211
|
+
# Create SQLAlchemy engine
|
212
|
+
connection_string = f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}"
|
213
|
+
engine = create_engine(connection_string)
|
214
|
+
|
215
|
+
try:
|
216
|
+
# Create multiple clients from the same engine
|
217
|
+
client1 = Client.from_engine(engine)
|
218
|
+
client2 = Client.from_engine(engine)
|
219
|
+
|
220
|
+
# Both clients should be connected
|
221
|
+
assert client1.connected() is True
|
222
|
+
assert client2.connected() is True
|
223
|
+
|
224
|
+
# Test that both clients can execute queries
|
225
|
+
result1 = client1.execute("SELECT 5 as test_value")
|
226
|
+
result2 = client2.execute("SELECT 6 as test_value")
|
227
|
+
|
228
|
+
rows1 = result1.fetchall()
|
229
|
+
rows2 = result2.fetchall()
|
230
|
+
|
231
|
+
assert len(rows1) == 1
|
232
|
+
assert len(rows2) == 1
|
233
|
+
assert rows1[0][0] == 5
|
234
|
+
assert rows2[0][0] == 6
|
235
|
+
|
236
|
+
finally:
|
237
|
+
# Cleanup
|
238
|
+
client1.disconnect()
|
239
|
+
client2.disconnect()
|
240
|
+
engine.dispose()
|
241
|
+
|
242
|
+
@pytest.mark.asyncio
|
243
|
+
async def test_async_client_engine_reuse(self, connection_params):
|
244
|
+
"""Test that the same async engine can be used to create multiple async clients"""
|
245
|
+
host, port, user, password, database = connection_params
|
246
|
+
|
247
|
+
# Create SQLAlchemy async engine
|
248
|
+
connection_string = f"mysql+aiomysql://{user}:{password}@{host}:{port}/{database}"
|
249
|
+
engine = create_async_engine(connection_string)
|
250
|
+
|
251
|
+
try:
|
252
|
+
# Create multiple async clients from the same engine
|
253
|
+
client1 = AsyncClient.from_engine(engine)
|
254
|
+
client2 = AsyncClient.from_engine(engine)
|
255
|
+
|
256
|
+
# Both clients should be connected
|
257
|
+
assert client1.connected() is True
|
258
|
+
assert client2.connected() is True
|
259
|
+
|
260
|
+
# Test that both clients can execute queries
|
261
|
+
result1 = await client1.execute("SELECT 7 as test_value")
|
262
|
+
result2 = await client2.execute("SELECT 8 as test_value")
|
263
|
+
|
264
|
+
rows1 = result1.fetchall()
|
265
|
+
rows2 = result2.fetchall()
|
266
|
+
|
267
|
+
assert len(rows1) == 1
|
268
|
+
assert len(rows2) == 1
|
269
|
+
assert rows1[0][0] == 7
|
270
|
+
assert rows2[0][0] == 8
|
271
|
+
|
272
|
+
finally:
|
273
|
+
# Cleanup
|
274
|
+
await client1.disconnect()
|
275
|
+
await client2.disconnect()
|
276
|
+
await engine.dispose()
|
277
|
+
|
278
|
+
def test_client_managers_initialization(self, connection_params):
|
279
|
+
"""Test that all managers are properly initialized when creating client from engine"""
|
280
|
+
host, port, user, password, database = connection_params
|
281
|
+
|
282
|
+
# Create SQLAlchemy engine
|
283
|
+
connection_string = f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}"
|
284
|
+
engine = create_engine(connection_string)
|
285
|
+
|
286
|
+
try:
|
287
|
+
# Create Client from engine
|
288
|
+
client = Client.from_engine(engine)
|
289
|
+
|
290
|
+
# Test that all managers are initialized
|
291
|
+
assert hasattr(client, 'snapshots')
|
292
|
+
assert hasattr(client, 'clone')
|
293
|
+
assert hasattr(client, 'moctl')
|
294
|
+
assert hasattr(client, 'restore')
|
295
|
+
assert hasattr(client, 'pitr')
|
296
|
+
assert hasattr(client, 'pubsub')
|
297
|
+
assert hasattr(client, 'account')
|
298
|
+
|
299
|
+
# Test that managers are functional
|
300
|
+
# Test snapshot manager
|
301
|
+
assert client.snapshots is not None
|
302
|
+
|
303
|
+
# Test account manager
|
304
|
+
assert client.account is not None
|
305
|
+
|
306
|
+
finally:
|
307
|
+
# Cleanup
|
308
|
+
client.disconnect()
|
309
|
+
engine.dispose()
|
310
|
+
|
311
|
+
@pytest.mark.asyncio
|
312
|
+
async def test_async_client_managers_initialization(self, connection_params):
|
313
|
+
"""Test that all managers are properly initialized when creating async client from engine"""
|
314
|
+
host, port, user, password, database = connection_params
|
315
|
+
|
316
|
+
# Create SQLAlchemy async engine
|
317
|
+
connection_string = f"mysql+aiomysql://{user}:{password}@{host}:{port}/{database}"
|
318
|
+
engine = create_async_engine(connection_string)
|
319
|
+
|
320
|
+
try:
|
321
|
+
# Create AsyncClient from engine
|
322
|
+
client = AsyncClient.from_engine(engine)
|
323
|
+
|
324
|
+
# Test that vector managers are initialized (if available)
|
325
|
+
# Note: Some managers might be None if dependencies are not available
|
326
|
+
assert hasattr(client, '_vector')
|
327
|
+
assert hasattr(client, '_fulltext_index')
|
328
|
+
|
329
|
+
finally:
|
330
|
+
# Cleanup
|
331
|
+
await client.disconnect()
|
332
|
+
await engine.dispose()
|
333
|
+
|
334
|
+
|
335
|
+
if __name__ == "__main__":
|
336
|
+
pytest.main([__file__])
|