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.
Files changed (50) hide show
  1. adapters/rag_templates_bridge.py +578 -0
  2. common/__init__.py +1 -0
  3. common/batch_utils.py +294 -0
  4. common/config.py +58 -0
  5. common/connection_manager.py +242 -0
  6. common/connection_pool.py +445 -0
  7. common/database.py +141 -0
  8. common/database_schema_manager.py +289 -0
  9. common/db_init_with_indexes.py +181 -0
  10. common/db_vector_utils.py +181 -0
  11. common/environment_manager.py +220 -0
  12. common/huggingface_utils.py +206 -0
  13. common/iris_client.py +92 -0
  14. common/iris_connection_manager.py +411 -0
  15. common/iris_connection_pool.py +360 -0
  16. common/iris_connector.py +71 -0
  17. common/iris_dbapi_connector.py +323 -0
  18. common/iris_index_utils.py +195 -0
  19. common/iris_sql_utils.py +704 -0
  20. common/iris_stream_reader.py +166 -0
  21. common/llm_cache_config.py +308 -0
  22. common/llm_cache_iris.py +671 -0
  23. common/llm_cache_manager.py +911 -0
  24. common/utils.py +559 -0
  25. common/vector_sql_utils.py +584 -0
  26. evaluation_framework/__init__.py +66 -0
  27. evaluation_framework/biomedical_question_generator.py +826 -0
  28. evaluation_framework/comparative_analysis_system.py +1173 -0
  29. evaluation_framework/empirical_reporting.py +1298 -0
  30. evaluation_framework/evaluation_orchestrator.py +1123 -0
  31. evaluation_framework/execute_production_evaluation.py +382 -0
  32. evaluation_framework/pmc_data_pipeline.py +1332 -0
  33. evaluation_framework/production_evaluation_config.py +353 -0
  34. evaluation_framework/ragas_metrics_framework.py +1013 -0
  35. evaluation_framework/real_production_evaluation.py +544 -0
  36. evaluation_framework/run_10k_evaluation.py +175 -0
  37. evaluation_framework/simple_test.py +364 -0
  38. evaluation_framework/statistical_evaluation_methodology.py +1016 -0
  39. evaluation_framework/test_framework.py +281 -0
  40. evaluation_framework/test_iris_connectivity.py +244 -0
  41. evaluation_framework/test_small_scale_evaluation.py +432 -0
  42. evaluation_framework/true_e2e_evaluation.py +639 -0
  43. evaluation_framework/visualization_engine.py +585 -0
  44. iris_rag/__init__.py +284 -0
  45. iris_rag/config/default_config.yaml +295 -0
  46. iris_vector_rag-0.2.1.dist-info/METADATA +499 -0
  47. iris_vector_rag-0.2.1.dist-info/RECORD +50 -0
  48. iris_vector_rag-0.2.1.dist-info/WHEEL +5 -0
  49. iris_vector_rag-0.2.1.dist-info/entry_points.txt +2 -0
  50. 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}")