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.
Files changed (122) hide show
  1. matrixone/__init__.py +155 -0
  2. matrixone/account.py +723 -0
  3. matrixone/async_client.py +3913 -0
  4. matrixone/async_metadata_manager.py +311 -0
  5. matrixone/async_orm.py +123 -0
  6. matrixone/async_vector_index_manager.py +633 -0
  7. matrixone/base_client.py +208 -0
  8. matrixone/client.py +4672 -0
  9. matrixone/config.py +452 -0
  10. matrixone/connection_hooks.py +286 -0
  11. matrixone/exceptions.py +89 -0
  12. matrixone/logger.py +782 -0
  13. matrixone/metadata.py +820 -0
  14. matrixone/moctl.py +219 -0
  15. matrixone/orm.py +2277 -0
  16. matrixone/pitr.py +646 -0
  17. matrixone/pubsub.py +771 -0
  18. matrixone/restore.py +411 -0
  19. matrixone/search_vector_index.py +1176 -0
  20. matrixone/snapshot.py +550 -0
  21. matrixone/sql_builder.py +844 -0
  22. matrixone/sqlalchemy_ext/__init__.py +161 -0
  23. matrixone/sqlalchemy_ext/adapters.py +163 -0
  24. matrixone/sqlalchemy_ext/dialect.py +534 -0
  25. matrixone/sqlalchemy_ext/fulltext_index.py +895 -0
  26. matrixone/sqlalchemy_ext/fulltext_search.py +1686 -0
  27. matrixone/sqlalchemy_ext/hnsw_config.py +194 -0
  28. matrixone/sqlalchemy_ext/ivf_config.py +252 -0
  29. matrixone/sqlalchemy_ext/table_builder.py +351 -0
  30. matrixone/sqlalchemy_ext/vector_index.py +1721 -0
  31. matrixone/sqlalchemy_ext/vector_type.py +948 -0
  32. matrixone/version.py +580 -0
  33. matrixone_python_sdk-0.1.0.dist-info/METADATA +706 -0
  34. matrixone_python_sdk-0.1.0.dist-info/RECORD +122 -0
  35. matrixone_python_sdk-0.1.0.dist-info/WHEEL +5 -0
  36. matrixone_python_sdk-0.1.0.dist-info/entry_points.txt +5 -0
  37. matrixone_python_sdk-0.1.0.dist-info/licenses/LICENSE +200 -0
  38. matrixone_python_sdk-0.1.0.dist-info/top_level.txt +2 -0
  39. tests/__init__.py +19 -0
  40. tests/offline/__init__.py +20 -0
  41. tests/offline/conftest.py +77 -0
  42. tests/offline/test_account.py +703 -0
  43. tests/offline/test_async_client_query_comprehensive.py +1218 -0
  44. tests/offline/test_basic.py +54 -0
  45. tests/offline/test_case_sensitivity.py +227 -0
  46. tests/offline/test_connection_hooks_offline.py +287 -0
  47. tests/offline/test_dialect_schema_handling.py +609 -0
  48. tests/offline/test_explain_methods.py +346 -0
  49. tests/offline/test_filter_logical_in.py +237 -0
  50. tests/offline/test_fulltext_search_comprehensive.py +795 -0
  51. tests/offline/test_ivf_config.py +249 -0
  52. tests/offline/test_join_methods.py +281 -0
  53. tests/offline/test_join_sqlalchemy_compatibility.py +276 -0
  54. tests/offline/test_logical_in_method.py +237 -0
  55. tests/offline/test_matrixone_version_parsing.py +264 -0
  56. tests/offline/test_metadata_offline.py +557 -0
  57. tests/offline/test_moctl.py +300 -0
  58. tests/offline/test_moctl_simple.py +251 -0
  59. tests/offline/test_model_support_offline.py +359 -0
  60. tests/offline/test_model_support_simple.py +225 -0
  61. tests/offline/test_pinecone_filter_offline.py +377 -0
  62. tests/offline/test_pitr.py +585 -0
  63. tests/offline/test_pubsub.py +712 -0
  64. tests/offline/test_query_update.py +283 -0
  65. tests/offline/test_restore.py +445 -0
  66. tests/offline/test_snapshot_comprehensive.py +384 -0
  67. tests/offline/test_sql_escaping_edge_cases.py +551 -0
  68. tests/offline/test_sqlalchemy_integration.py +382 -0
  69. tests/offline/test_sqlalchemy_vector_integration.py +434 -0
  70. tests/offline/test_table_builder.py +198 -0
  71. tests/offline/test_unified_filter.py +398 -0
  72. tests/offline/test_unified_transaction.py +495 -0
  73. tests/offline/test_vector_index.py +238 -0
  74. tests/offline/test_vector_operations.py +688 -0
  75. tests/offline/test_vector_type.py +174 -0
  76. tests/offline/test_version_core.py +328 -0
  77. tests/offline/test_version_management.py +372 -0
  78. tests/offline/test_version_standalone.py +652 -0
  79. tests/online/__init__.py +20 -0
  80. tests/online/conftest.py +216 -0
  81. tests/online/test_account_management.py +194 -0
  82. tests/online/test_advanced_features.py +344 -0
  83. tests/online/test_async_client_interfaces.py +330 -0
  84. tests/online/test_async_client_online.py +285 -0
  85. tests/online/test_async_model_insert_online.py +293 -0
  86. tests/online/test_async_orm_online.py +300 -0
  87. tests/online/test_async_simple_query_online.py +802 -0
  88. tests/online/test_async_transaction_simple_query.py +300 -0
  89. tests/online/test_basic_connection.py +130 -0
  90. tests/online/test_client_online.py +238 -0
  91. tests/online/test_config.py +90 -0
  92. tests/online/test_config_validation.py +123 -0
  93. tests/online/test_connection_hooks_new_online.py +217 -0
  94. tests/online/test_dialect_schema_handling_online.py +331 -0
  95. tests/online/test_filter_logical_in_online.py +374 -0
  96. tests/online/test_fulltext_comprehensive.py +1773 -0
  97. tests/online/test_fulltext_label_online.py +433 -0
  98. tests/online/test_fulltext_search_online.py +842 -0
  99. tests/online/test_ivf_stats_online.py +506 -0
  100. tests/online/test_logger_integration.py +311 -0
  101. tests/online/test_matrixone_query_orm.py +540 -0
  102. tests/online/test_metadata_online.py +579 -0
  103. tests/online/test_model_insert_online.py +255 -0
  104. tests/online/test_mysql_driver_validation.py +213 -0
  105. tests/online/test_orm_advanced_features.py +2022 -0
  106. tests/online/test_orm_cte_integration.py +269 -0
  107. tests/online/test_orm_online.py +270 -0
  108. tests/online/test_pinecone_filter.py +708 -0
  109. tests/online/test_pubsub_operations.py +352 -0
  110. tests/online/test_query_methods.py +225 -0
  111. tests/online/test_query_update_online.py +433 -0
  112. tests/online/test_search_vector_index.py +557 -0
  113. tests/online/test_simple_fulltext_online.py +915 -0
  114. tests/online/test_snapshot_comprehensive.py +998 -0
  115. tests/online/test_sqlalchemy_engine_integration.py +336 -0
  116. tests/online/test_sqlalchemy_integration.py +425 -0
  117. tests/online/test_transaction_contexts.py +1219 -0
  118. tests/online/test_transaction_insert_methods.py +356 -0
  119. tests/online/test_transaction_query_methods.py +288 -0
  120. tests/online/test_unified_filter_online.py +529 -0
  121. tests/online/test_vector_comprehensive.py +706 -0
  122. 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__])