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,216 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright 2021 - 2022 Matrix Origin
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ """
18
+ Pytest configuration for online tests
19
+
20
+ This file ensures that fixtures are properly registered for online tests.
21
+ """
22
+
23
+ import pytest
24
+ import pytest_asyncio
25
+ import asyncio
26
+ from typing import Tuple
27
+ from matrixone import Client, AsyncClient
28
+ from matrixone.logger import create_default_logger
29
+ from .test_config import online_config
30
+
31
+
32
+ @pytest.fixture(scope="session")
33
+ def event_loop():
34
+ """Create an instance of the default event loop for the test session."""
35
+ policy = asyncio.get_event_loop_policy()
36
+ loop = policy.new_event_loop()
37
+ yield loop
38
+ loop.close()
39
+
40
+
41
+ def pytest_configure(config):
42
+ """Configure pytest with online test settings"""
43
+ config.addinivalue_line("markers", "online: mark test as requiring database connection")
44
+ config.addinivalue_line("markers", "slow: mark test as slow running")
45
+
46
+
47
+ class DatabaseTestHelper:
48
+ """Helper class for database operations in tests"""
49
+
50
+ def __init__(self):
51
+ self.logger = create_default_logger()
52
+
53
+ def create_client(self, host: str, port: int, user: str, password: str, database: str) -> Client:
54
+ """Create a synchronous client"""
55
+ return Client()
56
+
57
+ def connect_client(self, client: Client, host: str, port: int, user: str, password: str, database: str) -> bool:
58
+ """Connect a client and return success status"""
59
+ try:
60
+ client.connect(host=host, port=port, user=user, password=password, database=database)
61
+ return True
62
+ except Exception as e:
63
+ self.logger.error(f"Failed to connect client: {e}")
64
+ return False
65
+
66
+ def create_async_client(self, host: str, port: int, user: str, password: str, database: str) -> AsyncClient:
67
+ """Create an asynchronous client"""
68
+ return AsyncClient()
69
+
70
+ async def connect_async_client(
71
+ self, client: AsyncClient, host: str, port: int, user: str, password: str, database: str
72
+ ) -> bool:
73
+ """Connect an async client and return success status"""
74
+ try:
75
+ await client.connect(host=host, port=port, user=user, password=password, database=database)
76
+ return True
77
+ except Exception as e:
78
+ self.logger.error(f"Failed to connect async client: {e}")
79
+ return False
80
+
81
+ def test_connection(self, host: str, port: int, user: str, password: str, database: str) -> bool:
82
+ """Test database connection"""
83
+ try:
84
+ client = self.create_client(host, port, user, password, database)
85
+ return self.connect_client(client, host, port, user, password, database)
86
+ except Exception as e:
87
+ self.logger.error(f"Connection test failed: {e}")
88
+ return False
89
+
90
+ async def test_async_connection(self, host: str, port: int, user: str, password: str, database: str) -> bool:
91
+ """Test async database connection"""
92
+ try:
93
+ client = self.create_async_client(host, port, user, password, database)
94
+ return await self.connect_async_client(client, host, port, user, password, database)
95
+ except Exception as e:
96
+ self.logger.error(f"Async connection test failed: {e}")
97
+ return False
98
+
99
+
100
+ @pytest.fixture(scope="session")
101
+ def db_config():
102
+ """Provide database configuration"""
103
+ return online_config
104
+
105
+
106
+ @pytest.fixture(scope="session")
107
+ def connection_params():
108
+ """Provide connection parameters"""
109
+ return online_config.get_connection_params()
110
+
111
+
112
+ @pytest.fixture(scope="session")
113
+ def test_database():
114
+ """Provide test database name"""
115
+ return online_config.get_test_database()
116
+
117
+
118
+ @pytest.fixture(scope="session")
119
+ def sys_database():
120
+ """Provide system database name"""
121
+ return online_config.get_sys_database()
122
+
123
+
124
+ @pytest.fixture(scope="session")
125
+ def test_account():
126
+ """Provide test account name"""
127
+ return online_config.get_test_account()
128
+
129
+
130
+ @pytest.fixture(scope="session")
131
+ def table_prefix():
132
+ """Provide table prefix for tests"""
133
+ return online_config.table_prefix
134
+
135
+
136
+ @pytest.fixture(scope="session")
137
+ def snapshot_prefix():
138
+ """Provide snapshot prefix for tests"""
139
+ return online_config.snapshot_prefix
140
+
141
+
142
+ @pytest.fixture(scope="session")
143
+ def vector_dimensions():
144
+ """Provide vector dimensions for tests"""
145
+ return online_config.get_vector_dimensions()
146
+
147
+
148
+ @pytest.fixture(scope="session")
149
+ def vector_test_data_size():
150
+ """Provide vector test data size"""
151
+ return online_config.get_vector_test_data_size()
152
+
153
+
154
+ @pytest.fixture(scope="session")
155
+ def db_helper():
156
+ """Provide database helper instance"""
157
+ return DatabaseTestHelper()
158
+
159
+
160
+ @pytest.fixture(scope="session")
161
+ def db_connection_test(db_helper):
162
+ """Test database connection and provide result"""
163
+ host, port, user, password, database = online_config.get_connection_params()
164
+ success = db_helper.test_connection(host, port, user, password, database)
165
+ if not success:
166
+ pytest.skip("Database connection failed - skipping online tests")
167
+ return success
168
+
169
+
170
+ @pytest_asyncio.fixture(scope="session")
171
+ async def async_db_connection_test(db_helper):
172
+ """Test async database connection and provide result"""
173
+ host, port, user, password, database = online_config.get_connection_params()
174
+ success = await db_helper.test_async_connection(host, port, user, password, database)
175
+ if not success:
176
+ pytest.skip("Async database connection failed - skipping online tests")
177
+ return success
178
+
179
+
180
+ @pytest.fixture
181
+ def test_client(db_helper, db_connection_test):
182
+ """Provide a connected test client"""
183
+ host, port, user, password, database = online_config.get_connection_params()
184
+ client = db_helper.create_client(host, port, user, password, database)
185
+ db_helper.connect_client(client, host, port, user, password, database)
186
+ try:
187
+ yield client
188
+ finally:
189
+ try:
190
+ client.disconnect()
191
+ except Exception as e:
192
+ print(f"Warning: Failed to disconnect test client: {e}")
193
+ # Don't ignore - this could indicate a real problem
194
+ raise
195
+
196
+
197
+ @pytest_asyncio.fixture
198
+ async def test_async_client(db_helper, async_db_connection_test):
199
+ """Provide a connected async test client"""
200
+ host, port, user, password, database = online_config.get_connection_params()
201
+ client = db_helper.create_async_client(host, port, user, password, database)
202
+ await db_helper.connect_async_client(client, host, port, user, password, database)
203
+ try:
204
+ yield client
205
+ finally:
206
+ # Clean disconnect - the improved disconnect method should handle cleanup properly
207
+ try:
208
+ await client.disconnect()
209
+ except Exception as e:
210
+ # If async disconnect fails, try sync cleanup as fallback
211
+ try:
212
+ client.disconnect_sync()
213
+ except Exception:
214
+ pass
215
+ # Log the error for debugging
216
+ print(f"Warning: Failed to disconnect async client: {e}")
@@ -0,0 +1,194 @@
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 account management functionality
17
+
18
+ These tests are inspired by example_02_account_management.py
19
+ """
20
+
21
+ import pytest
22
+ from matrixone import Client, AsyncClient
23
+ from matrixone.account import AccountManager, AccountError
24
+
25
+
26
+ @pytest.mark.online
27
+ class TestAccountManagement:
28
+ """Test account management functionality"""
29
+
30
+ def test_create_and_drop_account(self, test_client):
31
+ """Test creating and dropping an account"""
32
+ account_manager = AccountManager(test_client)
33
+
34
+ # Create account
35
+ account_name = "test_account_001"
36
+ admin_name = "test_admin_001"
37
+ password = "test_password_001"
38
+
39
+ account = account_manager.create_account(account_name, admin_name, password)
40
+ assert account is not None
41
+ assert account.name == account_name
42
+
43
+ # Drop account
44
+ account_manager.drop_account(account_name)
45
+
46
+ # Verify account is dropped (should raise error when trying to get it)
47
+ try:
48
+ account_manager.get_account(account_name)
49
+ assert False, "Account should have been dropped"
50
+ except AccountError:
51
+ pass # Expected
52
+
53
+ def test_create_and_drop_user(self, test_client):
54
+ """Test creating and dropping a user"""
55
+ account_manager = AccountManager(test_client)
56
+
57
+ # Create user
58
+ username = "test_user_001"
59
+ password = "test_password_001"
60
+
61
+ user = account_manager.create_user(username, password)
62
+ assert user is not None
63
+ assert user.name == username
64
+
65
+ # List users (MatrixOne only returns current user)
66
+ users = account_manager.list_users()
67
+ assert isinstance(users, list)
68
+
69
+ # Drop user
70
+ account_manager.drop_user(username)
71
+
72
+ def test_alter_account(self, test_client):
73
+ """Test altering an account"""
74
+ account_manager = AccountManager(test_client)
75
+
76
+ # Create account first
77
+ account_name = "test_account_002"
78
+ admin_name = "test_admin_002"
79
+ password = "test_password_002"
80
+
81
+ account = account_manager.create_account(account_name, admin_name, password)
82
+ assert account is not None
83
+
84
+ try:
85
+ # Alter account (add comment)
86
+ account_manager.alter_account(account_name, comment="Updated account")
87
+
88
+ # Verify account still exists
89
+ updated_account = account_manager.get_account(account_name)
90
+ assert updated_account is not None
91
+ assert updated_account.name == account_name
92
+
93
+ finally:
94
+ # Clean up
95
+ account_manager.drop_account(account_name)
96
+
97
+ def test_alter_user(self, test_client):
98
+ """Test altering a user"""
99
+ account_manager = AccountManager(test_client)
100
+
101
+ # Create user first
102
+ username = "test_user_002"
103
+ password = "test_password_002"
104
+
105
+ user = account_manager.create_user(username, password)
106
+ assert user is not None
107
+
108
+ try:
109
+ # Alter user (change password)
110
+ new_password = "new_password_002"
111
+ account_manager.alter_user(username, password=new_password)
112
+
113
+ finally:
114
+ # Clean up
115
+ account_manager.drop_user(username)
116
+
117
+ def test_account_management_with_transaction(self, test_client):
118
+ """Test account management with transaction (limited by MatrixOne)"""
119
+ account_manager = AccountManager(test_client)
120
+
121
+ # Create account outside transaction (MatrixOne limitation)
122
+ account_name = "test_account_003"
123
+ admin_name = "test_admin_003"
124
+ password = "test_password_003"
125
+
126
+ account = account_manager.create_account(account_name, admin_name, password)
127
+ assert account is not None
128
+
129
+ try:
130
+ # Create user outside transaction (MatrixOne limitation)
131
+ username = "test_user_003"
132
+ user_password = "test_password_003"
133
+
134
+ user = account_manager.create_user(username, user_password)
135
+ assert user is not None
136
+
137
+ # Test transaction with regular SQL operations only
138
+ with test_client.transaction():
139
+ # Only regular SQL operations are allowed in transactions
140
+ result = test_client.execute("SELECT 1 as test_value")
141
+ assert result is not None
142
+ assert len(result.rows) > 0
143
+
144
+ # Alter user outside transaction
145
+ account_manager.alter_user(username, password="new_password_003")
146
+
147
+ # Drop user outside transaction
148
+ account_manager.drop_user(username)
149
+
150
+ finally:
151
+ # Clean up account
152
+ account_manager.drop_account(account_name)
153
+
154
+ @pytest.mark.asyncio
155
+ async def test_async_account_management(self, test_async_client):
156
+ """Test async account management"""
157
+ # Test async client with direct SQL operations instead of AccountManager
158
+ # since AccountManager is designed for sync clients only
159
+
160
+ # Test basic async operations
161
+ result = await test_async_client.execute("SELECT 1 as test_value, USER() as user_info")
162
+ assert result is not None
163
+ assert len(result.rows) > 0
164
+ assert result.rows[0][0] == 1 # test_value should be 1
165
+
166
+ # Test async transaction
167
+ async with test_async_client.transaction():
168
+ result = await test_async_client.execute("SELECT 2 as test_value")
169
+ assert result is not None
170
+ assert len(result.rows) > 0
171
+ assert result.rows[0][0] == 2
172
+
173
+ # Test async database info queries
174
+ result = await test_async_client.execute("SHOW DATABASES")
175
+ assert result is not None
176
+ assert len(result.rows) > 0
177
+
178
+ def test_account_error_handling(self, test_client):
179
+ """Test account error handling"""
180
+ account_manager = AccountManager(test_client)
181
+
182
+ # Test creating account with invalid name
183
+ try:
184
+ account_manager.create_account("", "", "password")
185
+ assert False, "Should have failed with empty admin name"
186
+ except AccountError:
187
+ pass # Expected
188
+
189
+ # Test dropping non-existent account
190
+ try:
191
+ account_manager.drop_account("non_existent_account")
192
+ assert False, "Should have failed with non-existent account"
193
+ except AccountError:
194
+ pass # Expected