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,331 @@
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 MatrixOne dialect schema handling.
17
+ Tests the has_table method and type compiler functionality with real database connections.
18
+ """
19
+
20
+ import pytest
21
+ import sqlalchemy
22
+ from sqlalchemy import (
23
+ create_engine,
24
+ MetaData,
25
+ Table,
26
+ Column,
27
+ Integer,
28
+ String,
29
+ Text,
30
+ Boolean,
31
+ Float,
32
+ Numeric,
33
+ Date,
34
+ DateTime,
35
+ Time,
36
+ TIMESTAMP,
37
+ text,
38
+ )
39
+ from sqlalchemy.orm import declarative_base
40
+ from sqlalchemy.exc import SQLAlchemyError
41
+
42
+ from matrixone.sqlalchemy_ext.dialect import MatrixOneDialect
43
+ from .test_config import online_config
44
+
45
+ # SQLAlchemy version compatibility
46
+ SA_VERSION = tuple(map(int, sqlalchemy.__version__.split(".")[:2]))
47
+
48
+
49
+ def execute_sql(connection, sql):
50
+ """Execute SQL in a version-compatible way."""
51
+ # For SQLAlchemy 2.0 compatibility, use explicit transaction management
52
+ if SA_VERSION >= (2, 0):
53
+ # SQLAlchemy 2.0+ style
54
+ return connection.execute(text(sql))
55
+ else:
56
+ # SQLAlchemy 1.4.x style - use begin() for explicit transaction
57
+ if hasattr(connection, 'in_transaction') and not connection.in_transaction():
58
+ with connection.begin():
59
+ return connection.execute(text(sql))
60
+ else:
61
+ return connection.execute(text(sql))
62
+
63
+
64
+ class TestMatrixOneDialectSchemaHandlingOnline:
65
+ """Test MatrixOne dialect schema handling with real database connections."""
66
+
67
+ @pytest.fixture(scope="class")
68
+ def engine(self):
69
+ """Create engine for testing."""
70
+ # Use configurable connection parameters
71
+ host, port, user, password, database = online_config.get_connection_params()
72
+ connection_string = f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}"
73
+ engine = create_engine(connection_string)
74
+ # Replace the dialect with our MatrixOne dialect but preserve dbapi
75
+ original_dbapi = engine.dialect.dbapi
76
+ engine.dialect = MatrixOneDialect()
77
+ engine.dialect.dbapi = original_dbapi
78
+ return engine
79
+
80
+ @pytest.fixture(scope="class")
81
+ def metadata(self):
82
+ """Create metadata for testing."""
83
+ return MetaData()
84
+
85
+ def test_has_table_with_none_schema_online(self, engine, metadata):
86
+ """Test has_table method with schema=None using real database connection."""
87
+ # Create a test table
88
+ test_table = Table(
89
+ 'test_schema_table',
90
+ metadata,
91
+ Column('id', Integer, primary_key=True),
92
+ Column('name', String(100)),
93
+ )
94
+
95
+ # Create the table
96
+ test_table.create(engine, checkfirst=True)
97
+
98
+ try:
99
+ # Test has_table with schema=None (this was the main issue)
100
+ dialect = engine.dialect
101
+ with engine.connect() as connection:
102
+ # This should not raise AssertionError
103
+ result = dialect.has_table(connection, 'test_schema_table', schema=None)
104
+ assert result is True
105
+
106
+ # Test with non-existent table
107
+ result = dialect.has_table(connection, 'non_existent_table', schema=None)
108
+ assert result is False
109
+
110
+ finally:
111
+ # Clean up
112
+ test_table.drop(engine, checkfirst=True)
113
+
114
+ def test_has_table_with_explicit_schema_online(self, engine, metadata):
115
+ """Test has_table method with explicit schema using real database connection."""
116
+ # Create a test table
117
+ test_table = Table(
118
+ 'test_explicit_schema_table',
119
+ metadata,
120
+ Column('id', Integer, primary_key=True),
121
+ Column('name', String(100)),
122
+ )
123
+
124
+ # Create the table
125
+ test_table.create(engine, checkfirst=True)
126
+
127
+ try:
128
+ # Get database name from connection
129
+ with engine.connect() as connection:
130
+ # Use version-compatible API
131
+ result = connection.execute(text("SELECT DATABASE()"))
132
+ current_db = result.scalar()
133
+
134
+ # Test has_table with explicit schema
135
+ dialect = engine.dialect
136
+ result = dialect.has_table(connection, 'test_explicit_schema_table', schema=current_db)
137
+ assert result is True
138
+
139
+ # Test with non-existent table
140
+ result = dialect.has_table(connection, 'non_existent_table', schema=current_db)
141
+ assert result is False
142
+
143
+ finally:
144
+ # Clean up
145
+ test_table.drop(engine, checkfirst=True)
146
+
147
+ def test_type_compiler_with_standard_types_online(self, engine, metadata):
148
+ """Test type compiler with standard SQLAlchemy types using real database connection."""
149
+ # Create a test table with various standard types
150
+ test_table = Table(
151
+ 'test_type_compiler_table',
152
+ metadata,
153
+ Column('id', Integer, primary_key=True),
154
+ Column('name', String(100)),
155
+ Column('description', Text),
156
+ Column('is_active', Boolean),
157
+ Column('price', Float),
158
+ Column('quantity', Numeric(10, 2)),
159
+ Column('created_date', Date),
160
+ Column('created_at', DateTime),
161
+ Column('updated_at', Time),
162
+ Column('timestamp', TIMESTAMP),
163
+ )
164
+
165
+ try:
166
+ # Create the table - this should not raise UnsupportedCompilationError
167
+ test_table.create(engine, checkfirst=True)
168
+
169
+ # Verify the table was created
170
+ with engine.connect() as connection:
171
+ dialect = engine.dialect
172
+ result = dialect.has_table(connection, 'test_type_compiler_table', schema=None)
173
+ assert result is True
174
+
175
+ finally:
176
+ # Clean up
177
+ test_table.drop(engine, checkfirst=True)
178
+
179
+ def test_create_all_with_declarative_base_online(self, engine):
180
+ """Test create_all with declarative_base (the original failing scenario)."""
181
+ # Create declarative base
182
+ Base = declarative_base()
183
+
184
+ # Define a test model
185
+ class TestModel(Base):
186
+ __tablename__ = 'test_declarative_model'
187
+
188
+ id = Column(Integer, primary_key=True)
189
+ name = Column(String(100))
190
+ description = Column(Text)
191
+
192
+ try:
193
+ # This should not raise AssertionError or UnsupportedCompilationError
194
+ Base.metadata.create_all(engine, checkfirst=True)
195
+
196
+ # Verify the table was created
197
+ with engine.connect() as connection:
198
+ dialect = engine.dialect
199
+ result = dialect.has_table(connection, 'test_declarative_model', schema=None)
200
+ assert result is True
201
+
202
+ finally:
203
+ # Clean up
204
+ Base.metadata.drop_all(engine, checkfirst=True)
205
+
206
+ def test_create_all_with_vector_types_online(self, engine):
207
+ """Test create_all with vector types (if available)."""
208
+ try:
209
+ from matrixone.sqlalchemy_ext import Vectorf32, create_vector_column
210
+
211
+ # Create declarative base
212
+ Base = declarative_base()
213
+
214
+ # Define a test model with vector types
215
+ class VectorTestModel(Base):
216
+ __tablename__ = 'test_vector_model'
217
+
218
+ id = Column(Integer, primary_key=True)
219
+ name = Column(String(100))
220
+ embedding = create_vector_column(128, "f32")
221
+
222
+ # This should not raise any errors
223
+ Base.metadata.create_all(engine, checkfirst=True)
224
+
225
+ # Verify the table was created
226
+ with engine.connect() as connection:
227
+ dialect = engine.dialect
228
+ result = dialect.has_table(connection, 'test_vector_model', schema=None)
229
+ assert result is True
230
+
231
+ except ImportError:
232
+ # Skip if vector types are not available
233
+ pytest.skip("Vector types not available")
234
+ finally:
235
+ # Clean up
236
+ try:
237
+ Base.metadata.drop_all(engine, checkfirst=True)
238
+ except:
239
+ pass
240
+
241
+ def test_dialect_connection_handling_online(self, engine):
242
+ """Test dialect connection handling with real database."""
243
+ dialect = engine.dialect
244
+
245
+ with engine.connect() as connection:
246
+ # Test that the dialect can handle the connection
247
+ assert hasattr(dialect, 'has_table')
248
+ assert hasattr(dialect, 'get_table_names')
249
+ assert hasattr(dialect, 'get_columns')
250
+
251
+ # Test basic dialect functionality
252
+ tables = dialect.get_table_names(connection, schema="test")
253
+ assert isinstance(tables, list)
254
+
255
+ # Test that we can get current database name
256
+ # Use version-compatible API
257
+ result = execute_sql(connection, "SELECT DATABASE()")
258
+ current_db = result.scalar()
259
+ assert current_db is not None
260
+
261
+ def test_dialect_error_handling_online(self, engine):
262
+ """Test dialect error handling with real database."""
263
+ dialect = engine.dialect
264
+
265
+ with engine.connect() as connection:
266
+ # Test error code extraction
267
+ try:
268
+ # Try to create a table that already exists (should raise an error)
269
+ # Use version-compatible API
270
+ execute_sql(connection, "CREATE TABLE test_error_handling (id INT PRIMARY KEY)")
271
+ execute_sql(connection, "CREATE TABLE test_error_handling (id INT PRIMARY KEY)")
272
+ # connection.execute(text("CREATE TABLE test_error_handling (id INT PRIMARY KEY)"))
273
+ except Exception as e:
274
+ # Test error code extraction
275
+ error_code = dialect._extract_error_code(e)
276
+ # The error code should be extracted if it's an integer
277
+ if error_code is not None:
278
+ assert isinstance(error_code, int)
279
+
280
+ # Clean up
281
+ try:
282
+ execute_sql(connection, "DROP TABLE IF EXISTS test_error_handling")
283
+ except:
284
+ pass
285
+
286
+ def test_dialect_type_compiler_registration_online(self, engine):
287
+ """Test that type compiler is properly registered with the dialect."""
288
+ dialect = engine.dialect
289
+
290
+ # Test that the type compiler is properly registered
291
+ assert hasattr(dialect, 'type_compiler')
292
+ assert dialect.type_compiler is not None
293
+
294
+ # Test that we can create a type compiler instance
295
+ # In SQLAlchemy 1.4.x, type_compiler is a class, not an instance
296
+ if hasattr(dialect.type_compiler, '__call__'):
297
+ type_compiler = dialect.type_compiler(dialect)
298
+ else:
299
+ type_compiler = dialect.type_compiler
300
+ assert type_compiler is not None
301
+
302
+ # Test that the type compiler has the required methods
303
+ assert hasattr(type_compiler, 'visit_integer')
304
+ assert hasattr(type_compiler, 'visit_string')
305
+ assert hasattr(type_compiler, 'visit_text')
306
+ assert hasattr(type_compiler, 'visit_boolean')
307
+ assert hasattr(type_compiler, 'visit_float')
308
+ assert hasattr(type_compiler, 'visit_numeric')
309
+ assert hasattr(type_compiler, 'visit_date')
310
+ assert hasattr(type_compiler, 'visit_datetime')
311
+ assert hasattr(type_compiler, 'visit_time')
312
+ assert hasattr(type_compiler, 'visit_timestamp')
313
+
314
+ def test_dialect_statement_compiler_registration_online(self, engine):
315
+ """Test that statement compiler is properly registered with the dialect."""
316
+ dialect = engine.dialect
317
+
318
+ # Test that the statement compiler is properly registered
319
+ assert hasattr(dialect, 'statement_compiler')
320
+ assert dialect.statement_compiler is not None
321
+
322
+ # Test that we can create a statement compiler instance
323
+ with engine.connect() as connection:
324
+ # Create a simple statement to test the compiler
325
+ # Use SQLAlchemy 1.4 compatible API
326
+ stmt = text("SELECT 1")
327
+ statement_compiler = dialect.statement_compiler(dialect, stmt)
328
+ assert statement_compiler is not None
329
+
330
+ # Test that the statement compiler has the required methods
331
+ assert hasattr(statement_compiler, 'visit_user_defined_type')