iris-vector-rag 0.2.1__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.
- adapters/rag_templates_bridge.py +578 -0
- common/__init__.py +1 -0
- common/batch_utils.py +294 -0
- common/config.py +58 -0
- common/connection_manager.py +242 -0
- common/connection_pool.py +445 -0
- common/database.py +141 -0
- common/database_schema_manager.py +289 -0
- common/db_init_with_indexes.py +181 -0
- common/db_vector_utils.py +181 -0
- common/environment_manager.py +220 -0
- common/huggingface_utils.py +206 -0
- common/iris_client.py +92 -0
- common/iris_connection_manager.py +411 -0
- common/iris_connection_pool.py +360 -0
- common/iris_connector.py +71 -0
- common/iris_dbapi_connector.py +323 -0
- common/iris_index_utils.py +195 -0
- common/iris_sql_utils.py +704 -0
- common/iris_stream_reader.py +166 -0
- common/llm_cache_config.py +308 -0
- common/llm_cache_iris.py +671 -0
- common/llm_cache_manager.py +911 -0
- common/utils.py +559 -0
- common/vector_sql_utils.py +584 -0
- evaluation_framework/__init__.py +66 -0
- evaluation_framework/biomedical_question_generator.py +826 -0
- evaluation_framework/comparative_analysis_system.py +1173 -0
- evaluation_framework/empirical_reporting.py +1298 -0
- evaluation_framework/evaluation_orchestrator.py +1123 -0
- evaluation_framework/execute_production_evaluation.py +382 -0
- evaluation_framework/pmc_data_pipeline.py +1332 -0
- evaluation_framework/production_evaluation_config.py +353 -0
- evaluation_framework/ragas_metrics_framework.py +1013 -0
- evaluation_framework/real_production_evaluation.py +544 -0
- evaluation_framework/run_10k_evaluation.py +175 -0
- evaluation_framework/simple_test.py +364 -0
- evaluation_framework/statistical_evaluation_methodology.py +1016 -0
- evaluation_framework/test_framework.py +281 -0
- evaluation_framework/test_iris_connectivity.py +244 -0
- evaluation_framework/test_small_scale_evaluation.py +432 -0
- evaluation_framework/true_e2e_evaluation.py +639 -0
- evaluation_framework/visualization_engine.py +585 -0
- iris_rag/__init__.py +284 -0
- iris_rag/config/default_config.yaml +295 -0
- iris_vector_rag-0.2.1.dist-info/METADATA +499 -0
- iris_vector_rag-0.2.1.dist-info/RECORD +50 -0
- iris_vector_rag-0.2.1.dist-info/WHEEL +5 -0
- iris_vector_rag-0.2.1.dist-info/entry_points.txt +2 -0
- iris_vector_rag-0.2.1.dist-info/top_level.txt +4 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"""
|
|
2
|
+
IRIS Connection Manager - DBAPI First Architecture with Smart Environment Detection
|
|
3
|
+
|
|
4
|
+
This module provides a unified connection manager that prioritizes DBAPI connections
|
|
5
|
+
over JDBC, with automatic environment detection for optimal package availability.
|
|
6
|
+
|
|
7
|
+
Connection Priority:
|
|
8
|
+
1. DBAPI (intersystems-irispython package) - DEFAULT
|
|
9
|
+
2. JDBC (fallback for specific use cases)
|
|
10
|
+
3. Mock (for testing without database)
|
|
11
|
+
|
|
12
|
+
Environment Priority:
|
|
13
|
+
1. UV environment (.venv) if available and has IRIS packages
|
|
14
|
+
2. Current environment if it has IRIS packages
|
|
15
|
+
3. System Python as fallback
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
20
|
+
from typing import Any, Dict, Optional
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Smart environment detection
|
|
26
|
+
def _detect_best_iris_environment():
|
|
27
|
+
"""Detect the best environment for IRIS connections."""
|
|
28
|
+
try:
|
|
29
|
+
from .environment_manager import EnvironmentManager
|
|
30
|
+
|
|
31
|
+
env_manager = EnvironmentManager()
|
|
32
|
+
return env_manager.ensure_iris_available()
|
|
33
|
+
except ImportError:
|
|
34
|
+
# Fallback if environment manager not available
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class IRISConnectionManager:
|
|
39
|
+
"""
|
|
40
|
+
Unified connection manager for IRIS database with DBAPI-first approach.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, prefer_dbapi: bool = True):
|
|
44
|
+
"""
|
|
45
|
+
Initialize connection manager.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
prefer_dbapi: Whether to prefer DBAPI over JDBC (default: True)
|
|
49
|
+
"""
|
|
50
|
+
self.prefer_dbapi = prefer_dbapi
|
|
51
|
+
self._connection = None
|
|
52
|
+
self._connection_type = None
|
|
53
|
+
|
|
54
|
+
def get_connection(self, config: Optional[Dict[str, Any]] = None) -> Any:
|
|
55
|
+
"""
|
|
56
|
+
Get a database connection, preferring DBAPI by default.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
config: Optional configuration dictionary
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Database connection object
|
|
63
|
+
"""
|
|
64
|
+
if self._connection is not None:
|
|
65
|
+
return self._connection
|
|
66
|
+
|
|
67
|
+
if self.prefer_dbapi:
|
|
68
|
+
# Try DBAPI first
|
|
69
|
+
try:
|
|
70
|
+
self._connection = self._get_dbapi_connection(config)
|
|
71
|
+
self._connection_type = "DBAPI"
|
|
72
|
+
logger.info("✓ Connected using DBAPI (intersystems-irispython)")
|
|
73
|
+
return self._connection
|
|
74
|
+
except Exception as e:
|
|
75
|
+
# Only log as warning if it's a real failure, not just missing module
|
|
76
|
+
if "module 'iris' has no attribute 'connect'" in str(e):
|
|
77
|
+
logger.debug(f"DBAPI not available (iris module issue): {e}")
|
|
78
|
+
else:
|
|
79
|
+
logger.warning(f"DBAPI connection failed: {e}")
|
|
80
|
+
logger.info("Falling back to JDBC connection...")
|
|
81
|
+
|
|
82
|
+
# Fallback to JDBC
|
|
83
|
+
try:
|
|
84
|
+
self._connection = self._get_jdbc_connection(config)
|
|
85
|
+
self._connection_type = "JDBC"
|
|
86
|
+
logger.info("✓ Connected using JDBC")
|
|
87
|
+
return self._connection
|
|
88
|
+
except Exception as e:
|
|
89
|
+
# Check if this is a password change issue
|
|
90
|
+
if "Password change required" in str(e) or "password change required" in str(e).lower():
|
|
91
|
+
logger.warning("⚠️ IRIS password change required. Attempting automatic remediation...")
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
from tests.utils.iris_password_reset import reset_iris_password_if_needed
|
|
95
|
+
|
|
96
|
+
if reset_iris_password_if_needed(e, max_retries=1):
|
|
97
|
+
logger.info("✓ Password reset successful. Retrying connection...")
|
|
98
|
+
# Retry connection after password reset
|
|
99
|
+
self._connection = None # Clear failed connection
|
|
100
|
+
# NOTE: No recursion here - just let it fall through to raise
|
|
101
|
+
# The next connection attempt will use updated env vars
|
|
102
|
+
logger.info("Password reset complete. Please retry your operation.")
|
|
103
|
+
except ImportError:
|
|
104
|
+
logger.warning("Password reset utility not available. Manual reset required.")
|
|
105
|
+
|
|
106
|
+
logger.error(f"All connection methods failed. JDBC error: {e}")
|
|
107
|
+
raise ConnectionError(
|
|
108
|
+
"Failed to establish database connection with both DBAPI and JDBC. "
|
|
109
|
+
"If password was just reset, please retry your operation."
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def _get_dbapi_connection(self, config: Optional[Dict[str, Any]] = None) -> Any:
|
|
113
|
+
"""
|
|
114
|
+
Get DBAPI connection using intersystems-irispython package with smart environment detection.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
config: Optional configuration dictionary
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
DBAPI connection object
|
|
121
|
+
"""
|
|
122
|
+
try:
|
|
123
|
+
# Check environment first
|
|
124
|
+
if not _detect_best_iris_environment():
|
|
125
|
+
logger.warning(
|
|
126
|
+
"IRIS packages may not be available in current environment"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Import the correct IRIS DBAPI module
|
|
130
|
+
try:
|
|
131
|
+
import iris
|
|
132
|
+
|
|
133
|
+
logger.debug("Successfully imported iris")
|
|
134
|
+
except ImportError:
|
|
135
|
+
# Fallback to direct iris import for older installations
|
|
136
|
+
import iris
|
|
137
|
+
|
|
138
|
+
logger.debug("Fallback: imported iris module directly")
|
|
139
|
+
|
|
140
|
+
# Verify iris.connect is available
|
|
141
|
+
if not hasattr(iris, "connect"):
|
|
142
|
+
# Check if this is the wrong iris module
|
|
143
|
+
iris_module_name = getattr(iris, "__name__", "unknown")
|
|
144
|
+
iris_module_file = getattr(iris, "__file__", "unknown")
|
|
145
|
+
|
|
146
|
+
raise ConnectionError(
|
|
147
|
+
f"DBAPI connection failed: module '{iris_module_name}' has no attribute 'connect'. "
|
|
148
|
+
f"This indicates the wrong 'iris' module was imported (from: {iris_module_file}). "
|
|
149
|
+
f"The intersystems-irispython package is required for IRIS database connections. "
|
|
150
|
+
f"Please install it with: pip install intersystems-irispython"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Get connection parameters
|
|
154
|
+
conn_params = self._get_connection_params(config)
|
|
155
|
+
|
|
156
|
+
# Create an IRIS connection using the correct parameters
|
|
157
|
+
connection = iris.connect(
|
|
158
|
+
hostname=conn_params["hostname"],
|
|
159
|
+
port=conn_params["port"],
|
|
160
|
+
namespace=conn_params["namespace"],
|
|
161
|
+
username=conn_params["username"],
|
|
162
|
+
password=conn_params["password"],
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
logger.debug(
|
|
166
|
+
f"DBAPI connection established to {conn_params['hostname']}:{conn_params['port']}"
|
|
167
|
+
)
|
|
168
|
+
return connection
|
|
169
|
+
|
|
170
|
+
except ImportError as e:
|
|
171
|
+
raise ImportError(
|
|
172
|
+
f"intersystems-irispython package not available. Install with: pip install intersystems-irispython. Error: {e}"
|
|
173
|
+
)
|
|
174
|
+
except AttributeError as e:
|
|
175
|
+
raise ImportError(f"IRIS DBAPI not properly configured: {e}")
|
|
176
|
+
except Exception as e:
|
|
177
|
+
# Check if this is a password change issue
|
|
178
|
+
if "Password change required" in str(e) or "password change required" in str(e).lower():
|
|
179
|
+
logger.warning("⚠️ IRIS password change required. Attempting automatic remediation...")
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
from tests.utils.iris_password_reset import reset_iris_password_if_needed
|
|
183
|
+
|
|
184
|
+
if reset_iris_password_if_needed(e, max_retries=1):
|
|
185
|
+
logger.info("✓ Password reset successful. Retrying DBAPI connection...")
|
|
186
|
+
# Retry connection after password reset - refetch params to get new password from env
|
|
187
|
+
import iris
|
|
188
|
+
conn_params_refreshed = self._get_connection_params(config)
|
|
189
|
+
return iris.connect(
|
|
190
|
+
hostname=conn_params_refreshed["hostname"],
|
|
191
|
+
port=conn_params_refreshed["port"],
|
|
192
|
+
namespace=conn_params_refreshed["namespace"],
|
|
193
|
+
username=conn_params_refreshed["username"],
|
|
194
|
+
password=conn_params_refreshed["password"],
|
|
195
|
+
)
|
|
196
|
+
else:
|
|
197
|
+
logger.error("✗ Automatic password reset failed.")
|
|
198
|
+
except ImportError:
|
|
199
|
+
logger.warning("Password reset utility not available.")
|
|
200
|
+
|
|
201
|
+
raise ConnectionError(f"Failed to create DBAPI connection: {e}")
|
|
202
|
+
|
|
203
|
+
def _get_jdbc_connection(self, config: Optional[Dict[str, Any]] = None) -> Any:
|
|
204
|
+
"""
|
|
205
|
+
Get JDBC connection as fallback.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
config: Optional configuration dictionary
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
JDBC connection object
|
|
212
|
+
"""
|
|
213
|
+
try:
|
|
214
|
+
import jaydebeapi
|
|
215
|
+
|
|
216
|
+
# Get connection parameters
|
|
217
|
+
conn_params = self._get_connection_params(config)
|
|
218
|
+
|
|
219
|
+
# JDBC URL
|
|
220
|
+
jdbc_url = f"jdbc:IRIS://{conn_params['hostname']}:{conn_params['port']}/{conn_params['namespace']}"
|
|
221
|
+
|
|
222
|
+
# JDBC driver path - try multiple locations
|
|
223
|
+
possible_paths = [
|
|
224
|
+
os.path.join(
|
|
225
|
+
os.path.dirname(__file__), "..", "intersystems-jdbc-3.8.4.jar"
|
|
226
|
+
),
|
|
227
|
+
"./intersystems-jdbc-3.8.4.jar",
|
|
228
|
+
"../intersystems-jdbc-3.8.4.jar",
|
|
229
|
+
"./jdbc_exploration/intersystems-jdbc-3.8.4.jar",
|
|
230
|
+
os.path.expanduser("~/intersystems-jdbc-3.8.4.jar"),
|
|
231
|
+
"/opt/iris/jdbc/intersystems-jdbc-3.8.4.jar",
|
|
232
|
+
]
|
|
233
|
+
|
|
234
|
+
jdbc_jar_path = None
|
|
235
|
+
for path in possible_paths:
|
|
236
|
+
if os.path.exists(path):
|
|
237
|
+
jdbc_jar_path = path
|
|
238
|
+
break
|
|
239
|
+
|
|
240
|
+
if not jdbc_jar_path:
|
|
241
|
+
# List all attempted paths for debugging
|
|
242
|
+
attempted_paths = "\n - ".join(possible_paths)
|
|
243
|
+
raise FileNotFoundError(
|
|
244
|
+
f"JDBC driver not found. Attempted paths:\n - {attempted_paths}\n"
|
|
245
|
+
f"Download from: https://github.com/intersystems-community/iris-driver-distribution/raw/main/JDBC/JDK18/intersystems-jdbc-3.8.4.jar"
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# Create JDBC connection
|
|
249
|
+
connection = jaydebeapi.connect(
|
|
250
|
+
"com.intersystems.jdbc.IRISDriver",
|
|
251
|
+
jdbc_url,
|
|
252
|
+
[conn_params["username"], conn_params["password"]],
|
|
253
|
+
jdbc_jar_path,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
logger.debug(
|
|
257
|
+
f"JDBC connection established to {jdbc_url} using driver at {jdbc_jar_path}"
|
|
258
|
+
)
|
|
259
|
+
return connection
|
|
260
|
+
|
|
261
|
+
except ImportError:
|
|
262
|
+
raise ImportError(
|
|
263
|
+
"jaydebeapi package not available. Install with: pip install jaydebeapi"
|
|
264
|
+
)
|
|
265
|
+
except Exception as e:
|
|
266
|
+
raise ConnectionError(f"Failed to create JDBC connection: {e}")
|
|
267
|
+
|
|
268
|
+
def _get_connection_params(
|
|
269
|
+
self, config: Optional[Dict[str, Any]] = None
|
|
270
|
+
) -> Dict[str, Any]:
|
|
271
|
+
"""
|
|
272
|
+
Get connection parameters from config or environment variables.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
config: Optional configuration dictionary
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
Dictionary of connection parameters
|
|
279
|
+
"""
|
|
280
|
+
# Default parameters
|
|
281
|
+
params = {
|
|
282
|
+
"hostname": os.environ.get("IRIS_HOST", "localhost"),
|
|
283
|
+
"port": int(os.environ.get("IRIS_PORT", "1974")),
|
|
284
|
+
"namespace": os.environ.get("IRIS_NAMESPACE", "USER"),
|
|
285
|
+
"username": os.environ.get("IRIS_USERNAME", "SuperUser"),
|
|
286
|
+
"password": os.environ.get("IRIS_PASSWORD", "SYS"),
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
# Override with config if provided
|
|
290
|
+
if config:
|
|
291
|
+
params.update(config)
|
|
292
|
+
|
|
293
|
+
return params
|
|
294
|
+
|
|
295
|
+
def get_connection_type(self) -> Optional[str]:
|
|
296
|
+
"""
|
|
297
|
+
Get the type of the current connection.
|
|
298
|
+
|
|
299
|
+
Returns:
|
|
300
|
+
Connection type string ("DBAPI", "JDBC", or None)
|
|
301
|
+
"""
|
|
302
|
+
return self._connection_type
|
|
303
|
+
|
|
304
|
+
def close(self):
|
|
305
|
+
"""Close the current connection."""
|
|
306
|
+
if self._connection:
|
|
307
|
+
try:
|
|
308
|
+
self._connection.close()
|
|
309
|
+
logger.debug(f"Closed {self._connection_type} connection")
|
|
310
|
+
except Exception as e:
|
|
311
|
+
logger.warning(f"Error closing connection: {e}")
|
|
312
|
+
finally:
|
|
313
|
+
self._connection = None
|
|
314
|
+
self._connection_type = None
|
|
315
|
+
|
|
316
|
+
def __enter__(self):
|
|
317
|
+
"""Context manager entry."""
|
|
318
|
+
return self
|
|
319
|
+
|
|
320
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
321
|
+
"""Context manager exit."""
|
|
322
|
+
self.close()
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
# Convenience functions for backward compatibility
|
|
326
|
+
def get_iris_dbapi_connection(config: Optional[Dict[str, Any]] = None) -> Any:
|
|
327
|
+
"""
|
|
328
|
+
Get DBAPI connection specifically.
|
|
329
|
+
"""
|
|
330
|
+
manager = IRISConnectionManager()
|
|
331
|
+
return manager._get_dbapi_connection(config)
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def get_iris_jdbc_connection(config: Optional[Dict[str, Any]] = None) -> Any:
|
|
335
|
+
"""
|
|
336
|
+
Get JDBC connection specifically.
|
|
337
|
+
"""
|
|
338
|
+
manager = IRISConnectionManager()
|
|
339
|
+
return manager._get_jdbc_connection(config)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def get_iris_connection(
|
|
343
|
+
config: Optional[Dict[str, Any]] = None, prefer_dbapi: bool = True
|
|
344
|
+
) -> Any:
|
|
345
|
+
"""
|
|
346
|
+
Get an IRIS database connection, preferring DBAPI by default.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
config: Optional configuration dictionary
|
|
350
|
+
prefer_dbapi: Whether to prefer DBAPI over JDBC (default: True)
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Database connection object
|
|
354
|
+
"""
|
|
355
|
+
manager = IRISConnectionManager(prefer_dbapi=prefer_dbapi)
|
|
356
|
+
return manager.get_connection(config)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def get_dbapi_connection(config: Optional[Dict[str, Any]] = None) -> Any:
|
|
360
|
+
"""
|
|
361
|
+
Get a DBAPI connection specifically.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
config: Optional configuration dictionary
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
DBAPI connection object
|
|
368
|
+
"""
|
|
369
|
+
manager = IRISConnectionManager(prefer_dbapi=True)
|
|
370
|
+
return manager._get_dbapi_connection(config)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def test_connection() -> bool:
|
|
374
|
+
"""
|
|
375
|
+
Test database connectivity.
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
True if connection successful, False otherwise
|
|
379
|
+
"""
|
|
380
|
+
try:
|
|
381
|
+
with IRISConnectionManager() as manager:
|
|
382
|
+
conn = manager.get_connection()
|
|
383
|
+
cursor = conn.cursor()
|
|
384
|
+
cursor.execute("SELECT 1")
|
|
385
|
+
result = cursor.fetchone()
|
|
386
|
+
cursor.close()
|
|
387
|
+
return result is not None
|
|
388
|
+
except Exception as e:
|
|
389
|
+
logger.error(f"Connection test failed: {e}")
|
|
390
|
+
return False
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
if __name__ == "__main__":
|
|
394
|
+
# Test the connection manager
|
|
395
|
+
logging.basicConfig(level=logging.INFO)
|
|
396
|
+
|
|
397
|
+
print("Testing IRIS Connection Manager...")
|
|
398
|
+
|
|
399
|
+
# Test connection
|
|
400
|
+
if test_connection():
|
|
401
|
+
print("✓ Connection test passed")
|
|
402
|
+
else:
|
|
403
|
+
print("✗ Connection test failed")
|
|
404
|
+
|
|
405
|
+
# Test connection types
|
|
406
|
+
try:
|
|
407
|
+
with IRISConnectionManager(prefer_dbapi=True) as manager:
|
|
408
|
+
conn = manager.get_connection()
|
|
409
|
+
print(f"✓ Connection established using: {manager.get_connection_type()}")
|
|
410
|
+
except Exception as e:
|
|
411
|
+
print(f"✗ Connection failed: {e}")
|