Module pipettin-piper.piper.datatools.jsondb
Functions
def load_datatools(controller: Controller)-
Expand source code
def load_datatools(controller: Controller): if controller.database_tools: raise DataError("Database tools already set in controller to: " + str(controller.database_tools)) # Set the databse_tools property to an instance of JsonObjects. controller.database_tools = JsonObjects(controller=controller) return controller.database_tools def load_from_config(**db_config: dict)-
Expand source code
def load_from_config(**db_config : dict): return JsonObjects(**db_config)
Classes
class JsonObjects (database_url=None,
database_name=None,
controller=None,
verbose=True,
env_file: str = None)-
Expand source code
class JsonObjects(DataTools): """A class holding data about the machine, objects on it, and its configuration. Uses a JSON file as a data backend. """ verbose: bool = False controller: Controller = None database_url: str = db_location database_name: str = 'pipettin' env_file: str = '../pipettin-gui/.env' """Path to the UI's '.env' file, containing DATABASE_NAME and DATABASE_URI variables.""" def __init__(self, database_url=None, database_name=None, controller=None, verbose=True, env_file:str=None): self.verbose = verbose # Default connection details. self.config = {"database": { "database_url": self.database_url, "database_name": self.database_name }} # Get the config from the controller, if any. if controller: self.controller = controller self.verbose = controller.verbose # Update connection details. self.config["database"].update(controller.config["database"]) # Load variables from ".env". self.env_file = self.config.get("env_file", env_file) if self.env_file is not None: self.update_from_env_file(self.config, self.env_file) # Override connection details from init arguments. if database_url is not None: self.config["database"]["database_url"] = database_url if database_name is not None: self.config["database"]["database_name"] = database_name self.database_url = self.config["database"]["database_url"] self.database_name = self.config["database"]["database_name"] self.setup_db(self.database_url, self.database_name) # DATABASE SETUP ############ def setup_db(self, database_url: str, database_name: str): """Load and configure a JSON-based database from a given URL. This method sets up a connection to a JSON-based database by loading JSON data from the specified `database_url`. It initializes various collections within the database, ensuring the specified `database_name` exists and can be accessed. Args: database_url (str): The file path or URL to the JSON file containing the database data. database_name (str): The name of the database to load from the JSON data. Raises: KeyError: Raised if the `database_name` or any required collection (e.g., protocols, workspaces, platforms) is missing from the loaded JSON data. Exception: Raised if any other issue occurs during loading or accessing the database, including issues with file access or malformed JSON content. """ try: # Connect and select database name. logging.info(f"Loading JSON from: '{database_url}'") self.json = load_objects(database_url) # The databases in the MongoClient are accessed with a dict-style syntax. logging.info(f"Loaded database: '{database_name}'") self.db = self.json[database_name] except Exception as e: logging.error(f"Failed connect to the database or to load objects from it: {e}\n{traceback.print_exc()}") raise e # Main class methods #### #### POP METHODS #### def pop_content_by_idx(self, workspace_name: str, item_name: str, content_idx: int): """Remove a content from a platform item by index, deleting it form the DB.""" try: workspace = self.getWorkspaceByName(workspace_name) item = self.getWorkspaceItemByName(workspace=workspace, item_name=item_name) # Referencing will remove it from the task class/workspace object class as well. # This is the desired (side)effect. popped_content = item["content"].pop(content_idx) except Exception as e: msg = f"Failed to pull content {content_idx}" msg += f" from item '{item_name}' in workspace '{workspace_name}'." logging.error(msg) raise DataError(msg) from e return popped_content #### GET METHODS #### def listProtocols(self): """ Annoying function to get protocols from MongoDB as a list, log protocol names, and return them. """ protocols = self.db['protocols'] logging.debug(f"Found the following protocols: {[p['name'] for p in protocols]}") return protocols def listHlProtocols(self): """Method to get high-level protocols from MongoDB as a list, log protocol names, and return them.""" hl_protocols = self.db['hLprotocols'] logging.debug(f"Found the following high-level protocols: {[p['name'] for p in hl_protocols]}") return hl_protocols def listWorkspaces(self): """ Annoying function to get workspaces from MongoDB as a list, log names, and return them. """ workspaces = self.db['workspaces'] logging.debug(f"\nFound the following workspaces: {[w['name'] for w in workspaces]}") return workspaces def listPlatforms(self): """ Annoying function to get platforms from MongoDB as a list, log names, and return them. """ platforms = self.db['platforms'] logging.debug(f"Found the following platforms: {[pl['name'] for pl in platforms]}") return platforms def listContainers(self): """ Annoying function to get 'containers' from MongoDB as a list, log names, and return them. """ containers = self.db['containers'] logging.debug(f"Found the following containers: {[t['name'] for t in containers]}") return containers def listTools(self): """ Annoying function to get tools from MongoDB as a list, log names, and return them. """ tools = self.db['tools'] logging.debug(f"Found the following tools: {[t['name'] for t in tools]}") return tools def listSettings(self): """ Annoying function to get 'settings' from MongoDB as a list, log names, and return them. """ settings = self.db['settings'] logging.debug(f"Found {len(settings)} set(s) of settings.") if settings is None: pass elif len(settings) > 1: logging.warning("More than one set of settings was retreived from the database.") return settings #### CUSTOM UPDATE METHODS #### def updateActionBy(self, action: dict, protocol_name: str, new_data: dict, field: str = None, find_by: str = "index"): """Update an action's data by its Object ID.""" msg = f"Updating action with {find_by}={action[find_by]} " + \ f"from protocol '{protocol_name}' with new_data={new_data} and field={field}" logging.info(msg) try: _, db_action, _ = self.getActionDataBy(action[find_by], id_field=find_by) if field is not None: # Field-specific update. db_action[field] = new_data else: # Non-specific update. db_action.update(new_data) except Exception as e: msg = f"Failed to update action by {find_by}={action[find_by]}." logging.error(msg) raise DataError(msg) from eA class holding data about the machine, objects on it, and its configuration. Uses a JSON file as a data backend.
Ancestors
Subclasses
Class variables
var controller : Controllervar database_name : strvar database_url : strvar env_file : str-
Path to the UI's '.env' file, containing DATABASE_NAME and DATABASE_URI variables.
var verbose : bool
Methods
def listContainers(self)-
Expand source code
def listContainers(self): """ Annoying function to get 'containers' from MongoDB as a list, log names, and return them. """ containers = self.db['containers'] logging.debug(f"Found the following containers: {[t['name'] for t in containers]}") return containersAnnoying function to get 'containers' from MongoDB as a list, log names, and return them.
def listHlProtocols(self)-
Expand source code
def listHlProtocols(self): """Method to get high-level protocols from MongoDB as a list, log protocol names, and return them.""" hl_protocols = self.db['hLprotocols'] logging.debug(f"Found the following high-level protocols: {[p['name'] for p in hl_protocols]}") return hl_protocolsMethod to get high-level protocols from MongoDB as a list, log protocol names, and return them.
def listPlatforms(self)-
Expand source code
def listPlatforms(self): """ Annoying function to get platforms from MongoDB as a list, log names, and return them. """ platforms = self.db['platforms'] logging.debug(f"Found the following platforms: {[pl['name'] for pl in platforms]}") return platformsAnnoying function to get platforms from MongoDB as a list, log names, and return them.
def listProtocols(self)-
Expand source code
def listProtocols(self): """ Annoying function to get protocols from MongoDB as a list, log protocol names, and return them. """ protocols = self.db['protocols'] logging.debug(f"Found the following protocols: {[p['name'] for p in protocols]}") return protocolsAnnoying function to get protocols from MongoDB as a list, log protocol names, and return them.
def listSettings(self)-
Expand source code
def listSettings(self): """ Annoying function to get 'settings' from MongoDB as a list, log names, and return them. """ settings = self.db['settings'] logging.debug(f"Found {len(settings)} set(s) of settings.") if settings is None: pass elif len(settings) > 1: logging.warning("More than one set of settings was retreived from the database.") return settingsAnnoying function to get 'settings' from MongoDB as a list, log names, and return them.
def listTools(self)-
Expand source code
def listTools(self): """ Annoying function to get tools from MongoDB as a list, log names, and return them. """ tools = self.db['tools'] logging.debug(f"Found the following tools: {[t['name'] for t in tools]}") return toolsAnnoying function to get tools from MongoDB as a list, log names, and return them.
def listWorkspaces(self)-
Expand source code
def listWorkspaces(self): """ Annoying function to get workspaces from MongoDB as a list, log names, and return them. """ workspaces = self.db['workspaces'] logging.debug(f"\nFound the following workspaces: {[w['name'] for w in workspaces]}") return workspacesAnnoying function to get workspaces from MongoDB as a list, log names, and return them.
def setup_db(self, database_url: str, database_name: str)-
Expand source code
def setup_db(self, database_url: str, database_name: str): """Load and configure a JSON-based database from a given URL. This method sets up a connection to a JSON-based database by loading JSON data from the specified `database_url`. It initializes various collections within the database, ensuring the specified `database_name` exists and can be accessed. Args: database_url (str): The file path or URL to the JSON file containing the database data. database_name (str): The name of the database to load from the JSON data. Raises: KeyError: Raised if the `database_name` or any required collection (e.g., protocols, workspaces, platforms) is missing from the loaded JSON data. Exception: Raised if any other issue occurs during loading or accessing the database, including issues with file access or malformed JSON content. """ try: # Connect and select database name. logging.info(f"Loading JSON from: '{database_url}'") self.json = load_objects(database_url) # The databases in the MongoClient are accessed with a dict-style syntax. logging.info(f"Loaded database: '{database_name}'") self.db = self.json[database_name] except Exception as e: logging.error(f"Failed connect to the database or to load objects from it: {e}\n{traceback.print_exc()}") raise eLoad and configure a JSON-based database from a given URL.
This method sets up a connection to a JSON-based database by loading JSON data from the specified
database_url. It initializes various collections within the database, ensuring the specifieddatabase_nameexists and can be accessed.Args
database_url:str- The file path or URL to the JSON file containing the database data.
database_name:str- The name of the database to load from the JSON data.
Raises
KeyError- Raised if the
database_nameor any required collection (e.g., protocols, workspaces, platforms) is missing from the loaded JSON data. Exception- Raised if any other issue occurs during loading or accessing the database, including issues with file access or malformed JSON content.
def updateActionBy(self,
action: dict,
protocol_name: str,
new_data: dict,
field: str = None,
find_by: str = 'index')-
Expand source code
def updateActionBy(self, action: dict, protocol_name: str, new_data: dict, field: str = None, find_by: str = "index"): """Update an action's data by its Object ID.""" msg = f"Updating action with {find_by}={action[find_by]} " + \ f"from protocol '{protocol_name}' with new_data={new_data} and field={field}" logging.info(msg) try: _, db_action, _ = self.getActionDataBy(action[find_by], id_field=find_by) if field is not None: # Field-specific update. db_action[field] = new_data else: # Non-specific update. db_action.update(new_data) except Exception as e: msg = f"Failed to update action by {find_by}={action[find_by]}." logging.error(msg) raise DataError(msg) from eUpdate an action's data by its Object ID.
Inherited members
DataTools:containersfilterContentByfilterContentByTypefindfind_matchfind_matchesfind_onegetActionDataBygetContainerByNamegetContentByNamegetNextContentgetNextContentByNamegetPlatformByNamegetProtocolByNamegetProtocolObjectsgetToolByNamegetWorkspaceByNamegetWorkspaceItemByNameget_dbhl_protocolsis_subsetplatformspop_content_by_idxprotocolssettingstoolsupdate_from_env_fileupdate_nestedworkspaces