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,174 @@
|
|
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
|
+
Offline tests for VectorType SQLAlchemy integration.
|
17
|
+
"""
|
18
|
+
|
19
|
+
import pytest
|
20
|
+
import sys
|
21
|
+
from unittest.mock import Mock
|
22
|
+
from matrixone.sqlalchemy_ext import VectorType, Vectorf32, Vectorf64, VectorTypeDecorator
|
23
|
+
|
24
|
+
pytestmark = pytest.mark.vector
|
25
|
+
|
26
|
+
# No longer needed - global mocks have been fixed
|
27
|
+
|
28
|
+
|
29
|
+
class TestVectorType:
|
30
|
+
"""Test VectorType functionality."""
|
31
|
+
|
32
|
+
def test_vector_type_creation(self):
|
33
|
+
"""Test VectorType creation with different parameters."""
|
34
|
+
# Test with dimension
|
35
|
+
vec_type = VectorType(dimension=128, precision="f32")
|
36
|
+
assert vec_type.dimension == 128
|
37
|
+
assert vec_type.precision == "f32"
|
38
|
+
|
39
|
+
# Test without dimension
|
40
|
+
vec_type_no_dim = VectorType(precision="f64")
|
41
|
+
assert vec_type_no_dim.dimension is None
|
42
|
+
assert vec_type_no_dim.precision == "f64"
|
43
|
+
|
44
|
+
def test_vector_type_column_spec(self):
|
45
|
+
"""Test VectorType column specification."""
|
46
|
+
# Test with dimension
|
47
|
+
vec_type = VectorType(dimension=64, precision="f32")
|
48
|
+
spec = vec_type.get_col_spec()
|
49
|
+
assert spec == "vecf32(64)"
|
50
|
+
|
51
|
+
# Test without dimension
|
52
|
+
vec_type_no_dim = VectorType(precision="f64")
|
53
|
+
spec = vec_type_no_dim.get_col_spec()
|
54
|
+
assert spec == "vecf64"
|
55
|
+
|
56
|
+
def test_vector_type_bind_processor(self):
|
57
|
+
"""Test VectorType bind processor."""
|
58
|
+
vec_type = VectorType(dimension=3, precision="f32")
|
59
|
+
processor = vec_type.bind_processor(None)
|
60
|
+
|
61
|
+
# Test with list
|
62
|
+
result = processor([1.0, 2.0, 3.0])
|
63
|
+
assert result == "[1.0,2.0,3.0]"
|
64
|
+
|
65
|
+
# Test with string
|
66
|
+
result = processor("[1.0,2.0,3.0]")
|
67
|
+
assert result == "[1.0,2.0,3.0]"
|
68
|
+
|
69
|
+
# Test with None
|
70
|
+
result = processor(None)
|
71
|
+
assert result is None
|
72
|
+
|
73
|
+
def test_vector_type_result_processor(self):
|
74
|
+
"""Test VectorType result processor."""
|
75
|
+
vec_type = VectorType(dimension=3, precision="f32")
|
76
|
+
processor = vec_type.result_processor(None, None)
|
77
|
+
|
78
|
+
# Test with vector string
|
79
|
+
result = processor("[1.0,2.0,3.0]")
|
80
|
+
assert result == [1.0, 2.0, 3.0]
|
81
|
+
|
82
|
+
# Test with empty vector
|
83
|
+
result = processor("[]")
|
84
|
+
assert result == []
|
85
|
+
|
86
|
+
# Test with None
|
87
|
+
result = processor(None)
|
88
|
+
assert result is None
|
89
|
+
|
90
|
+
def test_vectorf32_convenience_class(self):
|
91
|
+
"""Test Vectorf32 convenience class."""
|
92
|
+
vec32 = Vectorf32(dimension=64)
|
93
|
+
assert vec32.dimension == 64
|
94
|
+
assert vec32.precision == "f32"
|
95
|
+
|
96
|
+
spec = vec32.get_col_spec()
|
97
|
+
assert spec == "vecf32(64)"
|
98
|
+
|
99
|
+
def test_vectorf64_convenience_class(self):
|
100
|
+
"""Test Vectorf64 convenience class."""
|
101
|
+
vec64 = Vectorf64(dimension=128)
|
102
|
+
assert vec64.dimension == 128
|
103
|
+
assert vec64.precision == "f64"
|
104
|
+
|
105
|
+
spec = vec64.get_col_spec()
|
106
|
+
assert spec == "vecf64(128)"
|
107
|
+
|
108
|
+
def test_vector_type_decorator(self):
|
109
|
+
"""Test VectorTypeDecorator functionality."""
|
110
|
+
decorator = VectorTypeDecorator(dimension=256, precision="f32")
|
111
|
+
assert decorator.dimension == 256
|
112
|
+
assert decorator.precision == "f32"
|
113
|
+
|
114
|
+
def test_vector_type_decorator_bind_processing(self):
|
115
|
+
"""Test VectorTypeDecorator bind parameter processing."""
|
116
|
+
decorator = VectorTypeDecorator(dimension=3, precision="f32")
|
117
|
+
|
118
|
+
# Test with list
|
119
|
+
result = decorator.process_bind_param([1.0, 2.0, 3.0], None)
|
120
|
+
assert result == "[1.0,2.0,3.0]"
|
121
|
+
|
122
|
+
# Test with string
|
123
|
+
result = decorator.process_bind_param("[1.0,2.0,3.0]", None)
|
124
|
+
assert result == "[1.0,2.0,3.0]"
|
125
|
+
|
126
|
+
# Test with None
|
127
|
+
result = decorator.process_bind_param(None, None)
|
128
|
+
assert result is None
|
129
|
+
|
130
|
+
def test_vector_type_decorator_result_processing(self):
|
131
|
+
"""Test VectorTypeDecorator result processing."""
|
132
|
+
decorator = VectorTypeDecorator(dimension=3, precision="f32")
|
133
|
+
|
134
|
+
# Test with vector string
|
135
|
+
result = decorator.process_result_value("[1.0,2.0,3.0]", None)
|
136
|
+
assert result == [1.0, 2.0, 3.0]
|
137
|
+
|
138
|
+
# Test with empty vector
|
139
|
+
result = decorator.process_result_value("[]", None)
|
140
|
+
assert result == []
|
141
|
+
|
142
|
+
# Test with None
|
143
|
+
result = decorator.process_result_value(None, None)
|
144
|
+
assert result is None
|
145
|
+
|
146
|
+
def test_vector_type_repr(self):
|
147
|
+
"""Test VectorType string representation."""
|
148
|
+
# Test with dimension
|
149
|
+
vec_type = VectorType(dimension=128, precision="f32")
|
150
|
+
repr_str = repr(vec_type)
|
151
|
+
assert "VectorType" in repr_str
|
152
|
+
assert "dimension=128" in repr_str
|
153
|
+
assert "precision='f32'" in repr_str
|
154
|
+
|
155
|
+
# Test without dimension
|
156
|
+
vec_type_no_dim = VectorType(precision="f64")
|
157
|
+
repr_str = repr(vec_type_no_dim)
|
158
|
+
assert "VectorType" in repr_str
|
159
|
+
assert "precision='f64'" in repr_str
|
160
|
+
|
161
|
+
def test_vector_type_decorator_repr(self):
|
162
|
+
"""Test VectorTypeDecorator string representation."""
|
163
|
+
# Test with dimension
|
164
|
+
decorator = VectorTypeDecorator(dimension=256, precision="f32")
|
165
|
+
repr_str = repr(decorator)
|
166
|
+
assert "VectorTypeDecorator" in repr_str
|
167
|
+
assert "dimension=256" in repr_str
|
168
|
+
assert "precision='f32'" in repr_str
|
169
|
+
|
170
|
+
# Test without dimension
|
171
|
+
decorator_no_dim = VectorTypeDecorator(precision="f64")
|
172
|
+
repr_str = repr(decorator_no_dim)
|
173
|
+
assert "VectorTypeDecorator" in repr_str
|
174
|
+
assert "precision='f64'" in repr_str
|
@@ -0,0 +1,328 @@
|
|
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
|
+
MatrixOne Python SDK - Version Management Core Tests
|
19
|
+
|
20
|
+
Test suite for the version management framework core functionality
|
21
|
+
(without external dependencies).
|
22
|
+
"""
|
23
|
+
|
24
|
+
import unittest
|
25
|
+
import sys
|
26
|
+
import os
|
27
|
+
|
28
|
+
# Add the matrixone package to the path
|
29
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'matrixone'))
|
30
|
+
|
31
|
+
# Import only the version management module
|
32
|
+
from matrixone.version import (
|
33
|
+
VersionManager,
|
34
|
+
VersionInfo,
|
35
|
+
FeatureRequirement,
|
36
|
+
VersionComparison,
|
37
|
+
requires_version,
|
38
|
+
VersionError,
|
39
|
+
)
|
40
|
+
|
41
|
+
|
42
|
+
class TestVersionParsing(unittest.TestCase):
|
43
|
+
"""Test version parsing functionality"""
|
44
|
+
|
45
|
+
def setUp(self):
|
46
|
+
self.version_manager = VersionManager()
|
47
|
+
|
48
|
+
def test_valid_version_parsing(self):
|
49
|
+
"""Test parsing valid version strings"""
|
50
|
+
test_cases = [
|
51
|
+
("3.0.1", VersionInfo(3, 0, 1)),
|
52
|
+
("1.0.0", VersionInfo(1, 0, 0)),
|
53
|
+
("10.25.100", VersionInfo(10, 25, 100)),
|
54
|
+
("0.0.1", VersionInfo(0, 0, 1)),
|
55
|
+
]
|
56
|
+
|
57
|
+
for version_str, expected in test_cases:
|
58
|
+
with self.subTest(version=version_str):
|
59
|
+
result = self.version_manager.parse_version(version_str)
|
60
|
+
self.assertEqual(result.major, expected.major)
|
61
|
+
self.assertEqual(result.minor, expected.minor)
|
62
|
+
self.assertEqual(result.patch, expected.patch)
|
63
|
+
|
64
|
+
def test_invalid_version_parsing(self):
|
65
|
+
"""Test parsing invalid version strings"""
|
66
|
+
invalid_versions = [
|
67
|
+
"3.0", # Missing patch
|
68
|
+
"3.0.1.2", # Too many components
|
69
|
+
"3.0.a", # Non-numeric component
|
70
|
+
"3.0.1-beta", # Pre-release suffix
|
71
|
+
"", # Empty string
|
72
|
+
"invalid", # Completely invalid
|
73
|
+
]
|
74
|
+
|
75
|
+
for invalid_version in invalid_versions:
|
76
|
+
with self.subTest(version=invalid_version):
|
77
|
+
with self.assertRaises(ValueError):
|
78
|
+
self.version_manager.parse_version(invalid_version)
|
79
|
+
|
80
|
+
def test_version_string_representation(self):
|
81
|
+
"""Test version string representation"""
|
82
|
+
version = VersionInfo(3, 0, 1)
|
83
|
+
self.assertEqual(str(version), "3.0.1")
|
84
|
+
|
85
|
+
|
86
|
+
class TestVersionComparison(unittest.TestCase):
|
87
|
+
"""Test version comparison functionality"""
|
88
|
+
|
89
|
+
def setUp(self):
|
90
|
+
self.version_manager = VersionManager()
|
91
|
+
|
92
|
+
def test_version_comparisons(self):
|
93
|
+
"""Test various version comparisons"""
|
94
|
+
test_cases = [
|
95
|
+
# (version1, version2, expected_result)
|
96
|
+
("3.0.2", "3.0.1", VersionComparison.GREATER),
|
97
|
+
("3.0.1", "3.0.2", VersionComparison.LESS),
|
98
|
+
("3.0.1", "3.0.1", VersionComparison.EQUAL),
|
99
|
+
("2.1.19", "3.0.9", VersionComparison.LESS),
|
100
|
+
("3.0.9", "2.1.19", VersionComparison.GREATER),
|
101
|
+
("1.0.0", "2.0.0", VersionComparison.LESS),
|
102
|
+
("2.0.0", "1.9.9", VersionComparison.GREATER),
|
103
|
+
]
|
104
|
+
|
105
|
+
for v1, v2, expected in test_cases:
|
106
|
+
with self.subTest(v1=v1, v2=v2):
|
107
|
+
result = self.version_manager.compare_versions(v1, v2)
|
108
|
+
self.assertEqual(result, expected)
|
109
|
+
|
110
|
+
def test_version_compatibility_checks(self):
|
111
|
+
"""Test version compatibility checking"""
|
112
|
+
self.version_manager.set_backend_version("3.0.1")
|
113
|
+
|
114
|
+
# Test >= operator
|
115
|
+
self.assertTrue(self.version_manager.is_version_compatible("3.0.0", operator=">="))
|
116
|
+
self.assertTrue(self.version_manager.is_version_compatible("3.0.1", operator=">="))
|
117
|
+
self.assertFalse(self.version_manager.is_version_compatible("3.0.2", operator=">="))
|
118
|
+
|
119
|
+
# Test > operator
|
120
|
+
self.assertTrue(self.version_manager.is_version_compatible("3.0.0", operator=">"))
|
121
|
+
self.assertFalse(self.version_manager.is_version_compatible("3.0.1", operator=">"))
|
122
|
+
self.assertFalse(self.version_manager.is_version_compatible("3.0.2", operator=">"))
|
123
|
+
|
124
|
+
# Test <= operator
|
125
|
+
self.assertFalse(self.version_manager.is_version_compatible("3.0.0", operator="<="))
|
126
|
+
self.assertTrue(self.version_manager.is_version_compatible("3.0.1", operator="<="))
|
127
|
+
self.assertTrue(self.version_manager.is_version_compatible("3.0.2", operator="<="))
|
128
|
+
|
129
|
+
# Test < operator
|
130
|
+
self.assertFalse(self.version_manager.is_version_compatible("3.0.0", operator="<"))
|
131
|
+
self.assertFalse(self.version_manager.is_version_compatible("3.0.1", operator="<"))
|
132
|
+
self.assertTrue(self.version_manager.is_version_compatible("3.0.2", operator="<"))
|
133
|
+
|
134
|
+
# Test == operator
|
135
|
+
self.assertFalse(self.version_manager.is_version_compatible("3.0.0", operator="=="))
|
136
|
+
self.assertTrue(self.version_manager.is_version_compatible("3.0.1", operator="=="))
|
137
|
+
self.assertFalse(self.version_manager.is_version_compatible("3.0.2", operator="=="))
|
138
|
+
|
139
|
+
# Test != operator
|
140
|
+
self.assertTrue(self.version_manager.is_version_compatible("3.0.0", operator="!="))
|
141
|
+
self.assertFalse(self.version_manager.is_version_compatible("3.0.1", operator="!="))
|
142
|
+
self.assertTrue(self.version_manager.is_version_compatible("3.0.2", operator="!="))
|
143
|
+
|
144
|
+
|
145
|
+
class TestFeatureRequirements(unittest.TestCase):
|
146
|
+
"""Test feature requirement functionality"""
|
147
|
+
|
148
|
+
def setUp(self):
|
149
|
+
self.version_manager = VersionManager()
|
150
|
+
|
151
|
+
def test_feature_registration_and_availability(self):
|
152
|
+
"""Test feature registration and availability checking"""
|
153
|
+
# Register a feature requirement
|
154
|
+
feature = FeatureRequirement(
|
155
|
+
feature_name="test_feature",
|
156
|
+
min_version=VersionInfo(3, 0, 0),
|
157
|
+
max_version=VersionInfo(3, 5, 0),
|
158
|
+
description="Test feature",
|
159
|
+
alternative="Use alternative_feature instead",
|
160
|
+
)
|
161
|
+
self.version_manager.register_feature_requirement(feature)
|
162
|
+
|
163
|
+
# Test with compatible version
|
164
|
+
self.version_manager.set_backend_version("3.1.0")
|
165
|
+
self.assertTrue(self.version_manager.is_feature_available("test_feature"))
|
166
|
+
|
167
|
+
# Test with version too low
|
168
|
+
self.version_manager.set_backend_version("2.9.0")
|
169
|
+
self.assertFalse(self.version_manager.is_feature_available("test_feature"))
|
170
|
+
|
171
|
+
# Test with version too high
|
172
|
+
self.version_manager.set_backend_version("3.6.0")
|
173
|
+
self.assertFalse(self.version_manager.is_feature_available("test_feature"))
|
174
|
+
|
175
|
+
def test_feature_info_retrieval(self):
|
176
|
+
"""Test feature information retrieval"""
|
177
|
+
feature = FeatureRequirement(
|
178
|
+
feature_name="info_test",
|
179
|
+
min_version=VersionInfo(2, 0, 0),
|
180
|
+
description="Information test feature",
|
181
|
+
alternative="Alternative approach",
|
182
|
+
)
|
183
|
+
self.version_manager.register_feature_requirement(feature)
|
184
|
+
|
185
|
+
retrieved = self.version_manager.get_feature_info("info_test")
|
186
|
+
self.assertIsNotNone(retrieved)
|
187
|
+
self.assertEqual(retrieved.feature_name, "info_test")
|
188
|
+
self.assertEqual(retrieved.description, "Information test feature")
|
189
|
+
self.assertEqual(retrieved.alternative, "Alternative approach")
|
190
|
+
|
191
|
+
# Test non-existent feature
|
192
|
+
self.assertIsNone(self.version_manager.get_feature_info("non_existent"))
|
193
|
+
|
194
|
+
def test_version_hints(self):
|
195
|
+
"""Test version hint generation"""
|
196
|
+
self.version_manager.register_feature_requirement(
|
197
|
+
FeatureRequirement(
|
198
|
+
feature_name="hint_test",
|
199
|
+
min_version=VersionInfo(3, 0, 0),
|
200
|
+
description="Hint test feature",
|
201
|
+
alternative="Use hint_alternative",
|
202
|
+
)
|
203
|
+
)
|
204
|
+
|
205
|
+
# Test with version too low
|
206
|
+
self.version_manager.set_backend_version("2.5.0")
|
207
|
+
hint = self.version_manager.get_version_hint("hint_test", "Test context")
|
208
|
+
|
209
|
+
self.assertIn("3.0.0", hint)
|
210
|
+
self.assertIn("2.5.0", hint)
|
211
|
+
self.assertIn("hint_alternative", hint)
|
212
|
+
self.assertIn("Test context", hint)
|
213
|
+
|
214
|
+
|
215
|
+
class TestVersionDecorator(unittest.TestCase):
|
216
|
+
"""Test version checking decorator"""
|
217
|
+
|
218
|
+
def test_successful_version_check(self):
|
219
|
+
"""Test successful version check"""
|
220
|
+
|
221
|
+
class TestClass:
|
222
|
+
def __init__(self):
|
223
|
+
# Set global version manager
|
224
|
+
from matrixone.version import _version_manager
|
225
|
+
|
226
|
+
_version_manager.set_backend_version("3.0.0")
|
227
|
+
|
228
|
+
@requires_version(min_version="2.0.0", feature_name="test_feature", description="Test feature")
|
229
|
+
def test_method(self):
|
230
|
+
return "success"
|
231
|
+
|
232
|
+
obj = TestClass()
|
233
|
+
result = obj.test_method()
|
234
|
+
self.assertEqual(result, "success")
|
235
|
+
|
236
|
+
def test_failed_version_check(self):
|
237
|
+
"""Test failed version check"""
|
238
|
+
|
239
|
+
class TestClass:
|
240
|
+
def __init__(self):
|
241
|
+
# Set global version manager
|
242
|
+
from matrixone.version import _version_manager
|
243
|
+
|
244
|
+
_version_manager.set_backend_version("1.0.0")
|
245
|
+
|
246
|
+
@requires_version(
|
247
|
+
min_version="2.0.0",
|
248
|
+
feature_name="test_feature",
|
249
|
+
description="Test feature",
|
250
|
+
alternative="Use alternative method",
|
251
|
+
)
|
252
|
+
def test_method(self):
|
253
|
+
return "success"
|
254
|
+
|
255
|
+
obj = TestClass()
|
256
|
+
with self.assertRaises(VersionError):
|
257
|
+
obj.test_method()
|
258
|
+
|
259
|
+
def test_version_range_check(self):
|
260
|
+
"""Test version range checking"""
|
261
|
+
|
262
|
+
class TestClass:
|
263
|
+
def __init__(self, version):
|
264
|
+
# Set global version manager
|
265
|
+
from matrixone.version import _version_manager
|
266
|
+
|
267
|
+
_version_manager.set_backend_version(version)
|
268
|
+
|
269
|
+
@requires_version(
|
270
|
+
min_version="2.0.0",
|
271
|
+
max_version="2.9.9",
|
272
|
+
feature_name="legacy_feature",
|
273
|
+
description="Legacy feature",
|
274
|
+
)
|
275
|
+
def legacy_method(self):
|
276
|
+
return "legacy success"
|
277
|
+
|
278
|
+
# Test within range
|
279
|
+
obj = TestClass("2.5.0")
|
280
|
+
result = obj.legacy_method()
|
281
|
+
self.assertEqual(result, "legacy success")
|
282
|
+
|
283
|
+
# Test below range
|
284
|
+
obj = TestClass("1.9.0")
|
285
|
+
with self.assertRaises(VersionError):
|
286
|
+
obj.legacy_method()
|
287
|
+
|
288
|
+
# Test above range
|
289
|
+
obj = TestClass("3.0.0")
|
290
|
+
with self.assertRaises(VersionError):
|
291
|
+
obj.legacy_method()
|
292
|
+
|
293
|
+
|
294
|
+
def run_tests():
|
295
|
+
"""Run all tests"""
|
296
|
+
# Create test suite
|
297
|
+
test_suite = unittest.TestSuite()
|
298
|
+
|
299
|
+
# Add test classes
|
300
|
+
test_classes = [
|
301
|
+
TestVersionParsing,
|
302
|
+
TestVersionComparison,
|
303
|
+
TestFeatureRequirements,
|
304
|
+
TestVersionDecorator,
|
305
|
+
]
|
306
|
+
|
307
|
+
for test_class in test_classes:
|
308
|
+
tests = unittest.TestLoader().loadTestsFromTestCase(test_class)
|
309
|
+
test_suite.addTests(tests)
|
310
|
+
|
311
|
+
# Run tests
|
312
|
+
runner = unittest.TextTestRunner(verbosity=2)
|
313
|
+
result = runner.run(test_suite)
|
314
|
+
|
315
|
+
return result.wasSuccessful()
|
316
|
+
|
317
|
+
|
318
|
+
if __name__ == "__main__":
|
319
|
+
print("MatrixOne Python SDK - Version Management Core Test Suite")
|
320
|
+
print("=" * 60)
|
321
|
+
|
322
|
+
success = run_tests()
|
323
|
+
|
324
|
+
if success:
|
325
|
+
print("\n✓ All tests passed!")
|
326
|
+
else:
|
327
|
+
print("\n✗ Some tests failed!")
|
328
|
+
sys.exit(1)
|