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,382 @@
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
+ Test SQLAlchemy integration with MatrixOne (without database connection)
17
+ """
18
+
19
+ import unittest
20
+ from unittest.mock import Mock, patch
21
+ from datetime import datetime
22
+ import sys
23
+ import os
24
+
25
+ # Store original modules to restore later
26
+ _original_modules = {}
27
+
28
+
29
+ def setup_sqlalchemy_mocks():
30
+ """Setup SQLAlchemy mocks for this test class"""
31
+ global _original_modules
32
+
33
+ # Store original modules
34
+ _original_modules['pymysql'] = sys.modules.get('pymysql')
35
+ _original_modules['sqlalchemy'] = sys.modules.get('sqlalchemy')
36
+ _original_modules['sqlalchemy.engine'] = sys.modules.get('sqlalchemy.engine')
37
+ _original_modules['sqlalchemy.orm'] = sys.modules.get('sqlalchemy.orm')
38
+
39
+ # Mock the external dependencies
40
+ sys.modules['pymysql'] = Mock()
41
+ sys.modules['sqlalchemy'] = Mock()
42
+ sys.modules['sqlalchemy.engine'] = Mock()
43
+ sys.modules['sqlalchemy.engine'].Engine = Mock()
44
+ sys.modules['sqlalchemy.orm'] = Mock()
45
+ sys.modules['sqlalchemy.orm'].sessionmaker = Mock()
46
+ sys.modules['sqlalchemy.orm'].declarative_base = Mock()
47
+ sys.modules['sqlalchemy'].create_engine = Mock()
48
+ sys.modules['sqlalchemy'].text = Mock()
49
+ sys.modules['sqlalchemy'].Column = Mock()
50
+ sys.modules['sqlalchemy'].Integer = Mock()
51
+ sys.modules['sqlalchemy'].String = Mock()
52
+ sys.modules['sqlalchemy'].DateTime = Mock()
53
+
54
+
55
+ def teardown_sqlalchemy_mocks():
56
+ """Restore original modules"""
57
+ global _original_modules
58
+
59
+ for module_name, original_module in _original_modules.items():
60
+ if original_module is not None:
61
+ sys.modules[module_name] = original_module
62
+ elif module_name in sys.modules:
63
+ del sys.modules[module_name]
64
+
65
+
66
+ # Add the matrixone package to the path
67
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'matrixone'))
68
+
69
+ from matrixone.snapshot import SnapshotLevel, Snapshot, SnapshotManager, CloneManager
70
+ from matrixone.client import (
71
+ Client,
72
+ TransactionWrapper,
73
+ TransactionSnapshotManager,
74
+ TransactionCloneManager,
75
+ )
76
+ from matrixone.exceptions import SnapshotError, CloneError
77
+
78
+
79
+ class TestSQLAlchemyIntegration(unittest.TestCase):
80
+ """Test SQLAlchemy integration concepts"""
81
+
82
+ @classmethod
83
+ def setUpClass(cls):
84
+ """Setup mocks for the entire test class"""
85
+ setup_sqlalchemy_mocks()
86
+
87
+ @classmethod
88
+ def tearDownClass(cls):
89
+ """Restore original modules after tests"""
90
+ teardown_sqlalchemy_mocks()
91
+
92
+ def test_enum_usage(self):
93
+ """Test SnapshotLevel enum usage"""
94
+ # Test enum values
95
+ self.assertEqual(SnapshotLevel.CLUSTER.value, "cluster")
96
+ self.assertEqual(SnapshotLevel.ACCOUNT.value, "account")
97
+ self.assertEqual(SnapshotLevel.DATABASE.value, "database")
98
+ self.assertEqual(SnapshotLevel.TABLE.value, "table")
99
+
100
+ # Test enum creation from string
101
+ self.assertEqual(SnapshotLevel("cluster"), SnapshotLevel.CLUSTER)
102
+ self.assertEqual(SnapshotLevel("table"), SnapshotLevel.TABLE)
103
+
104
+ def test_snapshot_with_enum(self):
105
+ """Test Snapshot creation with enum"""
106
+ now = datetime.now()
107
+ snapshot = Snapshot("test_snap", SnapshotLevel.TABLE, now, database="test_db", table="test_table")
108
+
109
+ self.assertEqual(snapshot.name, "test_snap")
110
+ self.assertEqual(snapshot.level, SnapshotLevel.TABLE)
111
+ self.assertEqual(snapshot.database, "test_db")
112
+ self.assertEqual(snapshot.table, "test_table")
113
+
114
+ def test_snapshot_manager_with_enum(self):
115
+ """Test SnapshotManager with enum"""
116
+ mock_client = Mock()
117
+ mock_client._connection = Mock()
118
+ snapshot_manager = SnapshotManager(mock_client)
119
+
120
+ # Mock the execute method
121
+ mock_client.execute = Mock()
122
+ mock_client.execute.return_value = Mock()
123
+
124
+ # Mock get method to return a snapshot
125
+ mock_snapshot = Snapshot("test_snap", SnapshotLevel.TABLE, datetime.now(), database="test_db", table="test_table")
126
+ with patch.object(snapshot_manager, 'get', return_value=mock_snapshot):
127
+ result = snapshot_manager.create("test_snap", SnapshotLevel.TABLE, database="test_db", table="test_table")
128
+
129
+ # Verify the correct SQL was generated
130
+ expected_sql = "CREATE SNAPSHOT test_snap FOR TABLE test_db test_table"
131
+ mock_client.execute.assert_called_once_with(expected_sql)
132
+ self.assertEqual(result, mock_snapshot)
133
+
134
+ def test_clone_manager_with_enum(self):
135
+ """Test CloneManager with enum"""
136
+ mock_client = Mock()
137
+ mock_client._connection = Mock()
138
+ clone_manager = CloneManager(mock_client)
139
+
140
+ # Mock the execute method
141
+ mock_client.execute = Mock()
142
+
143
+ # Test database clone
144
+ clone_manager.clone_database("target_db", "source_db")
145
+
146
+ expected_sql = "CREATE DATABASE target_db CLONE source_db"
147
+ mock_client.execute.assert_called_once_with(expected_sql)
148
+
149
+ def test_transaction_wrapper(self):
150
+ """Test TransactionWrapper with snapshots and clones"""
151
+ mock_client = Mock()
152
+ mock_client._connection = Mock()
153
+ mock_tx = TransactionWrapper(mock_client._connection, mock_client)
154
+
155
+ # Test that transaction wrapper has snapshot and clone managers
156
+ self.assertIsInstance(mock_tx.snapshots, TransactionSnapshotManager)
157
+ self.assertIsInstance(mock_tx.clone, TransactionCloneManager)
158
+
159
+ def test_transaction_snapshot_manager(self):
160
+ """Test TransactionSnapshotManager"""
161
+ mock_client = Mock()
162
+ mock_client._connection = Mock()
163
+ mock_tx = Mock()
164
+ mock_tx.execute = Mock()
165
+
166
+ tx_snapshots = TransactionSnapshotManager(mock_client, mock_tx)
167
+
168
+ # Mock get method
169
+ mock_snapshot = Snapshot("test_snap", SnapshotLevel.CLUSTER, datetime.now())
170
+ with patch.object(tx_snapshots, 'get', return_value=mock_snapshot):
171
+ result = tx_snapshots.create("test_snap", SnapshotLevel.CLUSTER)
172
+
173
+ # Verify that the transaction's execute was called
174
+ mock_tx.execute.assert_called_once_with("CREATE SNAPSHOT test_snap FOR CLUSTER")
175
+
176
+ def test_transaction_clone_manager(self):
177
+ """Test TransactionCloneManager"""
178
+ mock_client = Mock()
179
+ mock_client._connection = Mock()
180
+ mock_tx = Mock()
181
+ mock_tx.execute = Mock()
182
+
183
+ tx_clone = TransactionCloneManager(mock_client, mock_tx)
184
+
185
+ # Test database clone
186
+ tx_clone.clone_database("target_db", "source_db")
187
+
188
+ # Verify that the transaction's execute was called
189
+ mock_tx.execute.assert_called_once_with("CREATE DATABASE target_db CLONE source_db")
190
+
191
+ def test_sqlalchemy_integration_pattern(self):
192
+ """Test the integration pattern without actual SQLAlchemy"""
193
+
194
+ # Simulate SQLAlchemy session
195
+ class MockSession:
196
+ def __init__(self):
197
+ self.data = []
198
+ self.committed = False
199
+ self.rolled_back = False
200
+
201
+ def add(self, item):
202
+ self.data.append(item)
203
+
204
+ def commit(self):
205
+ self.committed = True
206
+
207
+ def rollback(self):
208
+ self.rolled_back = True
209
+ self.data.clear()
210
+
211
+ def close(self):
212
+ pass
213
+
214
+ # Simulate MatrixOne client
215
+ mock_client = Mock()
216
+ mock_client._connection = Mock()
217
+
218
+ # Test the integration pattern
219
+ session = MockSession()
220
+
221
+ try:
222
+ # Simulate MatrixOne transaction
223
+ with patch.object(mock_client, 'transaction') as mock_transaction:
224
+ mock_tx = Mock()
225
+ mock_tx.execute = Mock()
226
+ mock_tx.snapshots = Mock()
227
+ mock_tx.clone = Mock()
228
+
229
+ mock_transaction.return_value.__enter__ = Mock(return_value=mock_tx)
230
+ mock_transaction.return_value.__exit__ = Mock(return_value=None)
231
+
232
+ with mock_client.transaction() as tx:
233
+ # Simulate SQLAlchemy operations
234
+ session.add("user1")
235
+ session.add("user2")
236
+ session.commit()
237
+
238
+ # Simulate MatrixOne operations
239
+ tx.snapshots.create("test_snapshot", SnapshotLevel.DATABASE, database="test")
240
+ tx.clone.clone_database("backup", "test")
241
+
242
+ # Verify SQLAlchemy operations
243
+ self.assertTrue(session.committed)
244
+ self.assertEqual(len(session.data), 2)
245
+
246
+ # Verify MatrixOne operations were called
247
+ tx.snapshots.create.assert_called_once()
248
+ tx.clone.clone_database.assert_called_once()
249
+
250
+ except Exception as e:
251
+ session.rollback()
252
+ raise
253
+ finally:
254
+ session.close()
255
+
256
+ def test_error_handling_pattern(self):
257
+ """Test error handling pattern"""
258
+
259
+ class MockSession:
260
+ def __init__(self):
261
+ self.data = []
262
+ self.committed = False
263
+ self.rolled_back = False
264
+
265
+ def add(self, item):
266
+ if item == "error_item":
267
+ raise Exception("Simulated error")
268
+ self.data.append(item)
269
+
270
+ def commit(self):
271
+ self.committed = True
272
+
273
+ def rollback(self):
274
+ self.rolled_back = True
275
+ self.data.clear()
276
+
277
+ def close(self):
278
+ pass
279
+
280
+ mock_client = Mock()
281
+ mock_client._connection = Mock()
282
+
283
+ session = MockSession()
284
+
285
+ try:
286
+ with patch.object(mock_client, 'transaction') as mock_transaction:
287
+ mock_tx = Mock()
288
+ mock_tx.execute = Mock()
289
+ mock_tx.snapshots = Mock()
290
+
291
+ mock_transaction.return_value.__enter__ = Mock(return_value=mock_tx)
292
+ mock_transaction.return_value.__exit__ = Mock(return_value=None)
293
+
294
+ with mock_client.transaction() as tx:
295
+ # This will cause an error
296
+ session.add("error_item")
297
+ session.commit()
298
+
299
+ # This should not be reached
300
+ tx.snapshots.create("should_not_exist", SnapshotLevel.DATABASE, database="test")
301
+
302
+ except Exception as e:
303
+ session.rollback()
304
+ # Verify rollback occurred
305
+ self.assertTrue(session.rolled_back)
306
+ self.assertEqual(len(session.data), 0)
307
+
308
+ finally:
309
+ session.close()
310
+
311
+ def test_batch_operation_pattern(self):
312
+ """Test batch operation pattern"""
313
+
314
+ class MockSession:
315
+ def __init__(self):
316
+ self.data = []
317
+ self.committed = False
318
+
319
+ def bulk_insert_mappings(self, model, data_list):
320
+ self.data.extend(data_list)
321
+
322
+ def commit(self):
323
+ self.committed = True
324
+
325
+ def close(self):
326
+ pass
327
+
328
+ mock_client = Mock()
329
+ mock_client._connection = Mock()
330
+
331
+ session = MockSession()
332
+
333
+ try:
334
+ # Simulate batch data
335
+ batch_data = [{"name": f"User_{i}", "email": f"user{i}@example.com"} for i in range(1, 11)] # 10 users
336
+
337
+ # Batch insert
338
+ session.bulk_insert_mappings("User", batch_data)
339
+ session.commit()
340
+
341
+ # Create snapshot
342
+ mock_client.execute = Mock()
343
+ snapshot_manager = SnapshotManager(mock_client)
344
+ mock_snapshot = Snapshot("batch_snapshot", SnapshotLevel.DATABASE, datetime.now(), database="test")
345
+ with patch.object(snapshot_manager, 'get', return_value=mock_snapshot):
346
+ result = snapshot_manager.create("batch_snapshot", SnapshotLevel.DATABASE, database="test")
347
+
348
+ # Verify batch operation
349
+ self.assertTrue(session.committed)
350
+ self.assertEqual(len(session.data), 10)
351
+
352
+ finally:
353
+ session.close()
354
+
355
+
356
+ if __name__ == '__main__':
357
+ # Create a test suite
358
+ test_suite = unittest.TestSuite()
359
+
360
+ # Add test cases using TestLoader
361
+ loader = unittest.TestLoader()
362
+ test_suite.addTests(loader.loadTestsFromTestCase(TestSQLAlchemyIntegration))
363
+
364
+ # Run the tests
365
+ runner = unittest.TextTestRunner(verbosity=2)
366
+ result = runner.run(test_suite)
367
+
368
+ # Print summary
369
+ print(f"\n{'='*50}")
370
+ print(f"Tests run: {result.testsRun}")
371
+ print(f"Failures: {len(result.failures)}")
372
+ print(f"Errors: {len(result.errors)}")
373
+ if result.testsRun > 0:
374
+ success_rate = (result.testsRun - len(result.failures) - len(result.errors)) / result.testsRun * 100
375
+ print(f"Success rate: {success_rate:.1f}%")
376
+ print(f"{'='*50}")
377
+
378
+ # Exit with appropriate code
379
+ if result.failures or result.errors:
380
+ sys.exit(1)
381
+ else:
382
+ sys.exit(0)