44from biasanalyzer .cohort import CohortAction
55from biasanalyzer .config import load_config
66from ipywidgets import VBox , Label
7- from ipytree import Tree , Node
7+ from ipytree import Tree
88from IPython .display import display
9- from biasanalyzer .utils import get_direction_arrow
9+ from biasanalyzer .utils import get_direction_arrow , notify_users , build_concept_tree
1010
1111
1212class BIAS :
13- _instance = None
14-
15- def __init__ (self ):
16- self .config = {}
13+ def __init__ (self , config_file_path = None ):
1714 self .bias_db = None
1815 self .omop_cdm_db = None
1916 self .cohort_action = None
20-
21- def __new__ (cls , config_file_path = None ):
22- if cls ._instance is None :
23- cls ._instance = super (BIAS , cls ).__new__ (cls )
24- cls ._instance .set_config (config_file_path )
25- return cls ._instance
17+ if config_file_path is None :
18+ self .config = {}
19+ else :
20+ self .set_config (config_file_path )
2621
2722 def set_config (self , config_file_path : str ):
28- if config_file_path is None :
29- print ('no configuration file specified. '
30- 'Call set_config(config_file_path) next to specify configurations' )
23+ if not config_file_path :
24+ notify_users ('no configuration file specified. '
25+ 'Call set_config(config_file_path) next to specify configurations' )
3126 else :
3227 try :
3328 self .config = load_config (config_file_path )
34- print (f'configuration specified in { config_file_path } loaded successfully' )
29+ notify_users (f'configuration specified in { config_file_path } loaded successfully' )
3530 except FileNotFoundError :
36- print ('specified configuration file does not exist. '
37- 'Call set_config(config_file_path) next to specify a valid '
38- 'configuration file ' )
31+ notify_users ('specified configuration file does not exist. '
32+ 'Call set_config(config_file_path) next to specify a valid configuration file' ,
33+ level = 'error ' )
3934 except ValidationError as ex :
40- print (f'configuration yaml file is not valid with validation error: { ex } ' )
35+ notify_users (f'configuration yaml file is not valid with validation error: { ex } ' , level = 'error ' )
4136
4237 def set_root_omop (self ):
4338 if not self .config :
44- print ('no valid configuration to set root OMOP CDM data. '
45- 'Call set_config(config_file_path) to specify configurations first.' )
46- elif 'root_omop_cdm_database' in self . config :
39+ notify_users ('no valid configuration to set root OMOP CDM data. '
40+ 'Call set_config(config_file_path) to specify configurations first.' )
41+ else :
4742 db_type = self .config ['root_omop_cdm_database' ]['database_type' ]
4843 if db_type == 'postgresql' :
4944 user = self .config ['root_omop_cdm_database' ]['username' ]
@@ -65,64 +60,42 @@ def set_root_omop(self):
6560 self .bias_db = BiasDatabase (db_path )
6661 self .bias_db .omop_cdm_db_url = db_path
6762 else :
68- print (f"Unsupported database type: { db_type } " )
69- else :
70- print ('Configuration file must include configuration values for root_omop_cdm_database key.' )
63+ notify_users (f"Unsupported database type: { db_type } " )
7164
7265 def _set_cohort_action (self ):
7366 if self .omop_cdm_db is None :
74- print ('A valid OMOP CDM must be set before creating a cohort. '
75- 'Call set_root_omop first to set a valid root OMOP CDM' )
67+ notify_users ('A valid OMOP CDM must be set before creating a cohort. '
68+ 'Call set_root_omop first to set a valid root OMOP CDM' )
7669 return None
7770 if self .cohort_action is None :
7871 self .cohort_action = CohortAction (self .omop_cdm_db , self .bias_db )
7972 return self .cohort_action
8073
8174 def get_domains_and_vocabularies (self ):
75+ print (f'self.omop_cdm_db: { self .omop_cdm_db } ' )
8276 if self .omop_cdm_db is None :
83- print ('A valid OMOP CDM must be set before getting domains. '
84- 'Call set_root_omop first to set a valid root OMOP CDM' )
77+ notify_users ('A valid OMOP CDM must be set before getting domains. '
78+ 'Call set_root_omop first to set a valid root OMOP CDM' )
8579 return None
8680 return self .omop_cdm_db .get_domains_and_vocabularies ()
8781
8882 def get_concepts (self , search_term , domain = None , vocabulary = None ):
8983 if self .omop_cdm_db is None :
90- print ('A valid OMOP CDM must be set before getting concepts. '
91- 'Call set_root_omop first to set a valid root OMOP CDM' )
84+ notify_users ('A valid OMOP CDM must be set before getting concepts. '
85+ 'Call set_root_omop first to set a valid root OMOP CDM' )
9286 return None
9387 if domain is None and vocabulary is None :
94- print ('either domain or vocabulary must be set to constrain the number of returned concepts' )
88+ notify_users ('either domain or vocabulary must be set to constrain the number of returned concepts' )
9589 return None
9690 return self .omop_cdm_db .get_concepts (search_term , domain , vocabulary )
9791
9892 def get_concept_hierarchy (self , concept_id ):
9993 if self .omop_cdm_db is None :
100- print ('A valid OMOP CDM must be set before getting concepts. '
101- 'Call set_root_omop first to set a valid root OMOP CDM' )
94+ notify_users ('A valid OMOP CDM must be set before getting concepts. '
95+ 'Call set_root_omop first to set a valid root OMOP CDM' )
10296 return None
10397 return self .omop_cdm_db .get_concept_hierarchy (concept_id )
10498
105- def _build_concept_tree (self , concept_tree : dict , tree_type : str ) -> Node :
106- """
107- Recursively builds an ipytree Node for a given concept tree.
108- """
109- # Extract concept details
110- details = concept_tree .get ("details" , {})
111- concept_name = details .get ("concept_name" , "Unknown Concept" )
112- concept_id = details .get ("concept_id" , "" )
113- concept_code = details .get ("concept_code" , "" )
114- direction_arrow = get_direction_arrow (tree_type )
115- # Create a label for the current concept
116- label_text = f"{ direction_arrow } { concept_name } (ID: { concept_id } , Code: { concept_code } )"
117- node = Node (label_text )
118-
119- # Recursively add child nodes
120- for child in concept_tree .get (tree_type , []):
121- child_node = self ._build_concept_tree (child , tree_type )
122- node .add_node (child_node )
123-
124- return node
125-
12699 def display_concept_tree (self , concept_tree : dict , level : int = 0 , show_in_text_format = True , tree_type = None ):
127100 """
128101 Recursively prints the concept hierarchy tree in an indented format for display.
@@ -134,7 +107,7 @@ def display_concept_tree(self, concept_tree: dict, level: int = 0, show_in_text_
134107 elif 'children' in concept_tree :
135108 tree_type = 'children'
136109 else :
137- print ('The input concept tree must contain parents or children key as the type of the tree.' )
110+ notify_users ('The input concept tree must contain parents or children key as the type of the tree.' )
138111 return ''
139112
140113 if show_in_text_format :
@@ -152,12 +125,12 @@ def display_concept_tree(self, concept_tree: dict, level: int = 0, show_in_text_
152125 else :
153126 # Extract concept details
154127 # Build the root tree node
155- root_node = self . _build_concept_tree (concept_tree , tree_type )
128+ root_node = build_concept_tree (concept_tree , tree_type )
156129 tree = Tree ()
157130 tree .add_node (root_node )
158131 tree .opened = True
159132 display (VBox ([Label ("Concept Hierarchy" ), tree ]))
160- return None
133+ return root_node
161134
162135
163136 def create_cohort (self , cohort_name : str , cohort_desc : str , query_or_yaml_file : str , created_by : str ,
@@ -178,12 +151,12 @@ def create_cohort(self, cohort_name: str, cohort_desc: str, query_or_yaml_file:
178151 created_cohort = c_action .create_cohort (cohort_name , cohort_desc , query_or_yaml_file , created_by )
179152 if created_cohort is not None :
180153 if delay > 0 :
181- print (f"[DEBUG] Simulating long-running task with { delay } seconds delay..." )
154+ notify_users (f"[DEBUG] Simulating long-running task with { delay } seconds delay..." )
182155 time .sleep (delay )
183- print ('cohort created successfully' )
156+ notify_users ('cohort created successfully' )
184157 return created_cohort
185158 else :
186- print ('failed to create a valid cohort action object' )
159+ notify_users ('failed to create a valid cohort action object' )
187160 return None
188161
189162
@@ -192,11 +165,14 @@ def compare_cohorts(self, cohort_id1, cohort_id2):
192165 if c_action :
193166 return c_action .compare_cohorts (cohort_id1 , cohort_id2 )
194167 else :
195- print ('failed to create a valid cohort action object' )
168+ notify_users ('failed to create a valid cohort action object' )
196169 return None
197170
198171
199172 def cleanup (self ):
200- self .bias_db .close ()
201- self .omop_cdm_db .close ()
202- del self .cohort_action
173+ if self .bias_db :
174+ self .bias_db .close ()
175+ if self .omop_cdm_db :
176+ self .omop_cdm_db .close ()
177+ if self .cohort_action :
178+ del self .cohort_action
0 commit comments