3535 have_collab_token_handler = False
3636
3737
38- __version__ = "0.9.1 "
38+ __version__ = "0.9.2 "
3939
4040
4141TOKENFILE = os .path .expanduser ("~/.ebrainstoken" )
@@ -90,7 +90,7 @@ class BaseClient(object):
9090
9191 __test__ = False
9292
93- def __init__ (self , username = None , password = None , environment = "production" , token = None ):
93+ def __init__ (self , username = None , password = None , environment = "production" , token = None , interactive = True ):
9494 self .username = username
9595 self .verify = True
9696 self .environment = environment
@@ -118,79 +118,85 @@ def __init__(self, username=None, password=None, environment="production", token
118118 raise KeyError (f"{ err_msg_base } does not contain environment = { environment } " )
119119 else :
120120 raise IOError (f"{ err_msg_base } not found in the current directory." )
121- if self .token :
122- pass
123- elif password is None :
124- self .token = None
121+ self ._authenticate (password , interactive )
122+
123+ def _authenticate (self , password , interactive ):
124+ # If a token is provided, we try using it.
125+ # If not, we try to get a token from the environment
126+ # or from a local cache
127+ if not self .token :
125128 if have_collab_token_handler :
126129 # if are we running in a Jupyter notebook within the Collaboratory
127130 # the token is already available
128131 self .token = oauth .get_token ()
129132 elif os .path .exists (TOKENFILE ):
130- if username :
131- # check for a stored token
133+ if self .username :
132134 with open (TOKENFILE ) as fp :
133- data = json .load (fp ).get (username , None )
135+ data = json .load (fp ).get (self . username , None )
134136 if data and "access_token" in data :
135137 self .token = data ["access_token" ]
136- if not self ._check_token_valid ():
137- print (
138- "EBRAINS authentication token is invalid or has expired. "
139- "Will need to re-authenticate."
140- )
141- self .token = None
142138 else :
143- print (f"EBRAINS authentication token file not having required JSON data. data = { data } " )
139+ print (f"No token for { self . username } found in { TOKENFILE } " )
144140 else :
145141 print ("Authentication token file found, but you have not provided your username." )
146142 else :
147143 print ("EBRAINS authentication token file not found locally." )
148144
149- if self .token is None :
150- if not username :
151- print ("\n ==============================================" )
152- print ("Please enter your EBRAINS username." )
153- username = input ("EBRAINS Username: " )
154-
155- password = os .environ .get ("EBRAINS_PASS" )
156- if password is not None :
157- try :
158- self ._ebrains_auth (username , password )
159- except Exception :
160- print (
161- "Authentication Failure. "
162- "Possibly incorrect EBRAINS password saved in environment variable 'EBRAINS_PASS'."
163- )
164- if not hasattr (self , "config" ):
145+ # If we don't have a token, we try to authenticate with username and password
146+ if not self ._check_token_valid ():
147+ print (
148+ "EBRAINS authentication token is invalid or has expired. "
149+ "Will need to re-authenticate."
150+ )
151+ if (not self .username ) and interactive :
152+ print ("\n ==============================================" )
153+ print ("Please enter your EBRAINS username." )
154+ self .username = input ("EBRAINS Username: " )
155+
156+ if self .username :
157+ password = password or os .environ .get ("EBRAINS_PASS" )
158+ if (not password ) and interactive :
159+ # prompt for password
160+ print ("Please enter your EBRAINS password: " )
161+ password = getpass .getpass ()
162+
163+ if password :
165164 try :
166- # prompt for password
167- print ("Please enter your EBRAINS password: " )
168- password = getpass .getpass ()
169- self ._ebrains_auth (username , password )
165+ self ._ebrains_auth (self .username , password )
170166 except Exception :
171167 print ("Authentication Failure! Password entered is possibly incorrect." )
172168 raise
173- with open (TOKENFILE , "w" ) as fp :
174- json .dump ({username : {"access_token" : self .config ["access_token" ]}}, fp )
175- os .chmod (TOKENFILE , 0o600 )
176- else :
177- try :
178- self ._ebrains_auth (username , password )
179- except Exception :
180- print ("Authentication Failure! Password entered is possibly incorrect." )
181- raise
169+
170+ if self .token :
171+ self .auth = EBRAINSAuth (self .token )
172+
173+ # store token in local cache
174+ if os .path .exists (TOKENFILE ):
175+ with open (TOKENFILE , "r" ) as fp :
176+ token_data = json .load (fp )
177+ else :
178+ token_data = {}
179+ token_data [self .username ] = {"access_token" : self .token }
180+
182181 with open (TOKENFILE , "w" ) as fp :
183- json .dump ({username : {"access_token" : self .config ["access_token" ]}}, fp )
182+ json .dump (token_data , fp )
183+ fp .write ("\n " )
184184 os .chmod (TOKENFILE , 0o600 )
185- self .auth = EBRAINSAuth (self .token )
185+ else :
186+ self .auth = None
186187
187188 def _check_token_valid (self ):
188- url = "https://iam.ebrains.eu/auth/realms/hbp/protocol/openid-connect/userinfo"
189- data = requests .get (url , auth = EBRAINSAuth (self .token ), verify = self .verify )
190- if data .status_code == 200 :
191- return True
192- else :
193- return False
189+ if self .token :
190+ url = "https://iam.ebrains.eu/auth/realms/hbp/protocol/openid-connect/userinfo"
191+ data = requests .get (url , auth = EBRAINSAuth (self .token ), verify = self .verify )
192+ if data .status_code == 200 :
193+ remote_username = data .json ()["preferred_username" ]
194+ if self .username and self .username != remote_username :
195+ raise Exception ("Username does not match token" )
196+ else :
197+ self .username = remote_username
198+ return True
199+ return False
194200
195201 def _format_people_name (self , names ):
196202 # converts a string of people names separated by semi-colons
@@ -447,7 +453,7 @@ class TestLibrary(BaseClient):
447453 }
448454
449455 token : string, optional
450- You may directly input a valid authenticated token from Collaboratory v1 or v2 .
456+ You may directly input a valid authenticated EBRAINS access token .
451457 Note: you should use the `access_token` and NOT `refresh_token`.
452458
453459 Examples
@@ -460,8 +466,8 @@ class TestLibrary(BaseClient):
460466
461467 __test__ = False
462468
463- def __init__ (self , username = None , password = None , environment = "production" , token = None ):
464- super (TestLibrary , self ).__init__ (username , password , environment , token )
469+ def __init__ (self , username = None , password = None , environment = "production" , token = None , interactive = True ):
470+ super (TestLibrary , self ).__init__ (username , password , environment , token , interactive )
465471 self ._set_app_info ()
466472
467473 def _set_app_info (self ):
@@ -1580,8 +1586,13 @@ def register_result(self, test_result, data_store=None, collab_id=None):
15801586 files_to_upload .extend (test_result .related_data ["figures" ])
15811587 if files_to_upload :
15821588 list_dict_files_uploaded = [
1583- {"download_url" : f ["filepath" ], "size" : f ["filesize" ]}
1584- for f in data_store .upload_data (files_to_upload )
1589+ {
1590+ "download_url" : ftu ["filepath" ],
1591+ "size" : ftu ["filesize" ],
1592+ "hash" : ftu ["hash" ],
1593+ "local_path" : ftu ["local_path" ]
1594+ }
1595+ for ftu in data_store .upload_data (files_to_upload )
15851596 ]
15861597 results_storage .extend (list_dict_files_uploaded )
15871598
@@ -1729,8 +1740,8 @@ class ModelCatalog(BaseClient):
17291740
17301741 __test__ = False
17311742
1732- def __init__ (self , username = None , password = None , environment = "production" , token = None ):
1733- super (ModelCatalog , self ).__init__ (username , password , environment , token )
1743+ def __init__ (self , username = None , password = None , environment = "production" , token = None , interactive = True ):
1744+ super (ModelCatalog , self ).__init__ (username , password , environment , token , interactive )
17341745 self ._set_app_info ()
17351746
17361747 def _set_app_info (self ):
@@ -2541,6 +2552,7 @@ def add_model_instance(
25412552 hash = "" ,
25422553 morphology = "" ,
25432554 license = "" ,
2555+ collab_id = None
25442556 ):
25452557 """Register a new model instance.
25462558
@@ -2569,6 +2581,10 @@ def add_model_instance(
25692581 URL(s) to the morphology file(s) employed in this model.
25702582 license : string
25712583 Indicates the license applicable for this model instance.
2584+ collab_id : string
2585+ Specifies the ID of the host collab in the EBRAINS Collaboratory
2586+ (the model instance would belong to this collab).
2587+ If not provided, defaults to the collab of the parent model project.
25722588
25732589 Returns
25742590 -------
@@ -2590,6 +2606,7 @@ def add_model_instance(
25902606
25912607 instance_data = locals ()
25922608 instance_data .pop ("self" )
2609+ instance_data ["project_id" ] = instance_data .pop ("collab_id" )
25932610
25942611 for key , val in instance_data .items ():
25952612 if val == "" :
@@ -2614,7 +2631,7 @@ def add_model_instance(
26142631 else :
26152632 handle_response_error ("Error in adding model instance" , response )
26162633
2617- def find_model_instance_else_add (self , model_obj ):
2634+ def find_model_instance_else_add (self , model_obj , collab_id = None ):
26182635 """Find existing model instance; else create a new instance
26192636
26202637 This checks if the input model object has an associated model instance.
@@ -2624,6 +2641,9 @@ def find_model_instance_else_add(self, model_obj):
26242641 ----------
26252642 model_obj : object
26262643 Python object representing a model.
2644+ collab_id : str
2645+ In case of adding a new model instance, add it to this collab.
2646+ If None, add to the same collab as the parent model.
26272647
26282648 Returns
26292649 -------
@@ -2664,6 +2684,7 @@ def find_model_instance_else_add(self, model_obj):
26642684 source = getattr (model_obj , "remote_url" , "" ),
26652685 version = model_obj .model_version ,
26662686 parameters = getattr (model_obj , "parameters" , "" ),
2687+ collab_id = collab_id or getattr (model_obj , "collab_id" , None )
26672688 )
26682689 else :
26692690 model_instance = self .get_model_instance (instance_id = model_obj .model_instance_uuid )
0 commit comments