import os, json, requests from getpass import getpass from APIHandler import APIHandler from classes import * def call_entrypoint_from_elabid(elabid): ''' Calls an entrypoint sample from eLabFTW using its elabid, then returns an object of the Entrypoint class. If the entry is not a sample (category_title not matching exactly "Sample") returns ValueError. ''' try: sample_data = APIHandler(apikey).get_entry_from_elabid(elabid, entryType="items") if not sample_data.get("category_title") == "Sample": raise ValueError("The resource you selected is not a sample, therefore it can't be used as an entrypoint.") sample_object = Entrypoint(sample_data) except ConnectionError as e: raise ConnectionError(e) return sample_object # Entrypoint-class object def call_material_from_elabid(elabid): ''' Calls a material from eLabFTW using its elabid, then returns an object of the Material class. If the entry is neither a PLD Target or a Substrate batch returns ValueError. Such entries always have a category_title key with its value either being "PLD Target" or "Substrate batch". Because of an old typo, the value "Subtrate batch" (second 's' is missing) is also accepted. ''' try: material_data = APIHandler(apikey).get_entry_from_elabid(elabid, entryType="items") # TO-DO: correct this typo on elabftw: Subtrate → Substrate. if not sample_data.get("category_title") in ["PLD Target", "Substrate batch", "Subtrate batch"]: raise ValueError(f"The referenced resource (elabid = {elabid}) is not a material.") material_object = Material(material_data) except ConnectionError as e: raise ConnectionError(e) return material_object # Material-class object def call_layers_from_list(elabid_list): ''' Calls a list of (PLD deposition) experiments from eLabFTW using their elabid - which means the input must be a list of integers instead of a single one - then returns a list of Layer-class objects. If one of the entries is not related to a deposition layer (category_title not matching exactly "PLD Deposition") that entry is skipped, with no error raised. ''' list_of_layers = [] for elabid in elabid_list: try: layer_data = APIHandler(apikey).get_entry_from_elabid(elabid, entryType="experiments") if not layer_data.get("category_title") == "PLD Deposition": continue layer_object = Layer(layer_data) list_of_layers.append(layer_object) except ConnectionError as e: nums = [ layer.layer_number for layer in list_of_layers ] nums.sort() print(f"LIST OF THE LAYERS PROCESSED (unordered):\n" + str(nums)) raise ConnectionError(f"An error occurred while fetching the experiment with elabid = {elabid}:\n" + str(e) + f"\nPlease solve the problem before retrying." + "\n\n" + f"Last resource attempted to call: {ELABFTW_API_URL}/experiments/{elabid}" ) return list_of_layers # list of Layer-class objects def chain_entrypoint_to_batch(sample_object): ''' Takes an Entrypoint-class object, looks at its .batch_elabid attribute and returns a Material-class object containing data on the substrate batch associated to the starting sample. Dependency: call_material_from_elabid. ''' material_elabid = sample_object.batch_elabid material_object = call_material_from_elabid(material_elabid) return material_object def chain_entrypoint_to_layers(sample_object): ''' Takes an Entrypoint-class object, looks at its .linked_experiments_elabid attribute (list) and returns a list of Layer-class objects containing data on the deposition layers associated to the starting sample - using the function call_layers_from_list. The list is sorted by progressive layer number (layer_number attribute). Dependency: call_layers_from_list. ''' linked_experiments_elabid = sample_object.linked_experiments_elabid # list of elabid layer_object_list = call_layers_from_list(linked_experiments_elabid) layer_object_list.sort(key=lambda x: x.layer_number) return layer_object_list #sample_object = call_entrypoint_from_elabid(elabid) #from_entrypoint_to_material(sample_object) if __name__=="__main__": print(f"=======================\n===== DEBUG MODE! =====\n=======================\n") ELABFTW_API_URL = "https://elabftw.fisica.unina.it/api/v2" apikey = getpass("Paste API key here: ") elabid = input("Enter elabid of your starting sample [default= 1111]: ") or 1111 data = APIHandler(apikey).get_entry_from_elabid(elabid) sample = Entrypoint(data) layers = chain_entrypoint_to_layers(sample) print(f"Sample name:\n{sample.name}\n") print(f"Layers data:") for layer in layers: ld = layer.__dict__ ld.pop("extra") print(ld) # entryType = None # while entryType not in ["items", "experiments"]: # eT = input("Enter a valid entry type [items, experiments]: ") # # This allows for a shortcut: instead of prompting the type before and the elabid after I can just prompt both at the same time - e.g. e51 is exp. 51, i1108 is item 1108... # if eT[0] in ["e", "i"] and eT[-1].isnumeric(): # try: # elabid = int(eT[1:]) # eT = eT[0] # except Exception: # print("Usage: i|item|items|i[ELABID] for items, e|experiment|experiments|e[ELABID] for experiments.") # continue # match eT: # case "items" | "i" | "item": # entryType = "items" # case "experiments" | "e" | "exp" | "experiment": # entryType = "experiments" # case _: # continue # # This will probably be reworked in production # try: # elabid = elabid # except NameError: # elabid = input("Input elabid here [default = 1111]: ") or 1111 # data = APIHandler(apikey).get_entry_from_elabid(elabid, entryType) # if entryType == "experiments": # layer = Layer(data) # result = layer.__dict__ # result.pop("extra") # print(result) # elif entryType == "items": # if data.get("category_title") == "Sample": # item = Entrypoint(data) # elif data.get("category_title") in ["PLD Target", "Substrate"]: # item = Material(data) # print(item.get_compound_formula(apikey)) # else: # raise Exception("The selected item or experiment is not in one of the following categories: [Sample, PLD Target, Substrate, PLD Deposition].") # result = item.__dict__ # result.pop("extra") # print(result)