# HG changeset patch # User ufz # Date 1769439961 0 # Node ID 89fc1f215e77a8506c79d5defd655edbe5abe4b0 # Parent f5c4f523432dc3979d1a77b4e71acb2a04602f6a planemo upload for repository https://github.com/Helmholtz-UFZ/galaxy-tools/tree/main/tools/omero commit 233f0e70cb20a02ec8530dbcfd5c7e70eef74476 diff -r f5c4f523432d -r 89fc1f215e77 README.md --- a/README.md Fri Jun 13 20:47:38 2025 +0000 +++ b/README.md Mon Jan 26 15:06:01 2026 +0000 @@ -1,4 +1,4 @@ -# OMERO import images +# OMERO suite toolbox ## Set up user credentials on Galaxy to connect to other omero instance diff -r f5c4f523432d -r 89fc1f215e77 connect_omero.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/connect_omero.py Mon Jan 26 15:06:01 2026 +0000 @@ -0,0 +1,15 @@ +import sys + +import ezomero as ez +from omero.gateway import BlitzGateway + + +def establish_connection(uuid_key, usr, psw, host, port): + if uuid_key is not None: + conn = BlitzGateway(username="", passwd="", host=host, port=port, secure=True) + conn.connect(sUuid=uuid_key) + else: + conn = ez.connect(usr, psw, "", host, port, secure=True) + if not conn.connect(): + sys.exit("ERROR: Failed to connect to OMERO server") + return conn diff -r f5c4f523432d -r 89fc1f215e77 macros.xml --- a/macros.xml Fri Jun 13 20:47:38 2025 +0000 +++ b/macros.xml Mon Jan 26 15:06:01 2026 +0000 @@ -2,13 +2,14 @@ 5.18.0 3.0.1 - 23.0 + 25.1 ezomero pandas + @@ -18,9 +19,17 @@ openjdk + - + + + + + + + + @@ -30,27 +39,49 @@ + + + + + + + + + + + + --host '$omero_host' --port $omero_port - - - + + #if $session_id.session_id_input== "yes" + --session_close $close_connection + #else + --session_close "True" + #end if + + - **OMERO-suite Security Diclaimer:** To utilize the OMERO tools, the user must trust Galaxy instances. - The configuration file, which contains your OMERO password and username, is stored in the job working directory. - This directory only exists during the runtime of the job and should only be accessible by the system user that runs the job. - However, please be aware that your username and password may be exposed to users with administrative rights. - We are working on increasing the security of the OMERO suite + **OMERO-suite Security Notice** + + To use the OMERO tools, you must trust the Galaxy instance hosting your job. + Your OMERO username and password are stored in a temporary configuration file during job execution. + + This file is accessible only to the system account running the job, + but may in principle be viewed by Galaxy administrators with elevated rights. + + The file is removed after job completion and is not persistently stored. + **We recommend using service-specific or temporary OMERO credentials whenever possible.** + + We are actively working to further improve security, + for example by enabling the UUID-key authentication. + The European Galaxy Server is operated in compliance with the EU General Data Protection Regulation (GDPR). \ No newline at end of file diff -r f5c4f523432d -r 89fc1f215e77 omero_dataset_to_plate.py --- a/omero_dataset_to_plate.py Fri Jun 13 20:47:38 2025 +0000 +++ b/omero_dataset_to_plate.py Mon Jan 26 15:06:01 2026 +0000 @@ -1,23 +1,60 @@ import argparse import csv -import json +import os import re import sys from collections import defaultdict - +from pathlib import Path +from typing import Optional import omero -from omero.gateway import BlitzGateway +from connect_omero import establish_connection from omero.rtypes import rint, rstring +# Import environmental variables +usr = os.getenv("OMERO_USER") +psw = os.getenv("OMERO_PASSWORD") +uuid_key = os.getenv("UUID_SESSION_KEY") + -def convert_dataset_to_plate(host, user, pws, port, dataset_id, log_file, mapping_file, delete_dataset): +def convert_dataset_to_plate( + host: str, + port: str, + dataset_id: str, + log_file: Path, + mapping_file: str, + delete_dataset: bool, + uuid_key: Optional[str] = None, + ses_close: Optional[bool] = True +) -> str: """ Connect to OMERO server, convert a dataset to a plate using the specified well mapping file + + Parameters + ---------- + host : str + OMERO server host (i.e. OMERO address or domain name)" + port : int + OMERO server port (default:4064) + dataset_id : str + Dataset ID to convert plate + log_file : str + Output path for the log file + mapping_file: str + Tabular file mapping filenames to well positions (2 columns: filename, Well) + delete_dataset: bool + Input to delete the original dataset convert to plate or not + uuid_key : str, optional + OMERO UUID session key to connect without password + ses_close : bool + Decide if close or not the section after executing the script. Defaulf value is true, useful when connecting with the UUID session key. + + Returns + ------- + str + Return log file with info on the conversion """ - conn = BlitzGateway(user, pws, host=host, port=port, secure=True) - if not conn.connect(): - sys.exit("ERROR: Failed to connect to OMERO server") + conn = establish_connection(uuid_key, usr, psw, host, port) def log_message(message, status="INFO"): with open(log_file, 'w') as f: @@ -94,34 +131,28 @@ if delete_dataset is True: conn.deleteObjects("Dataset", [dataset_id], wait=True) log_message(f"Images from Dataset {dataset_id} successfully added to Plate {plate.id.val}") - conn.close() + if ses_close: + conn.close() if __name__ == "__main__": parser = argparse.ArgumentParser(description="Convert an OMERO dataset to a plate.") - parser.add_argument("--credential-file", dest="credential_file", type=str, required=True, - help="Credential file (JSON file with username and password for OMERO)") - parser.add_argument('--host', required=True, help='OMERO host') - parser.add_argument('--port', required=True, type=int, help='OMERO port') + parser.add_argument('--host', required=True, help="OMERO server host (i.e. OMERO address or domain name)") + parser.add_argument('--port', required=True, type=int, help="OMERO server port (default:4064)") parser.add_argument('--dataset_id', type=int, required=True, help="Dataset ID to convert plate") - parser.add_argument('--log_file', default='metadata_import_log.txt', - help='Path to the log file') - parser.add_argument('--mapping_file', - help='Tabular file mapping filenames to well positions (2 columns: filename, Well)') - parser.add_argument('--delete_dataset', action='store_true', - help='Flag to delete the original dataset') + parser.add_argument('--log_file', default='metadata_import_log.txt', help="Output path for the log file") + parser.add_argument('--mapping_file', help='Tabular file mapping filenames to well positions (2 columns: filename, Well)') + parser.add_argument('--session_close', required=False, help='Namespace or title for the annotation') + parser.add_argument('--delete_dataset', action='store_true', help='Flag to delete the original dataset') + args = parser.parse_args() - with open(args.credential_file, 'r') as f: - crds = json.load(f) - convert_dataset_to_plate( - user=crds['username'], - pws=crds['password'], host=args.host, port=args.port, dataset_id=args.dataset_id, log_file=args.log_file, mapping_file=args.mapping_file, + ses_close=args.session_close, delete_dataset=args.delete_dataset ) diff -r f5c4f523432d -r 89fc1f215e77 omero_filter.py --- a/omero_filter.py Fri Jun 13 20:47:38 2025 +0000 +++ b/omero_filter.py Mon Jan 26 15:06:01 2026 +0000 @@ -1,16 +1,59 @@ import argparse import csv -import json +import os import sys +from typing import Optional import ezomero as ez +from connect_omero import establish_connection + +# Import environmental variables +usr = os.getenv("OMERO_USER") +psw = os.getenv("OMERO_PASSWORD") +uuid_key = os.getenv("UUID_SESSION_KEY") -def filter_ids_ezo(user, pws, host, port, filter, id, value1, value2=None, tsv_file="filter_list.tsv"): +def filter_ids_ezo( + host: str, + port: int, + filter: str, + id: list, + value1: str, + value2: Optional[str] = None, + uuid_key: Optional[str] = None, + tsv_file: str = "filter_list.tsv", + ses_close: Optional[bool] = True +) -> int: + """ + + Apply filter_by_filename, filter_by_kv or filter_by_tag_value from the ezomero module to a list of images ID. - # Transform the id input in a list of integer - id = id.split(',') - id = list(map(int, id)) + Parameters + ---------- + host : str + OMERO server host (i.e. OMERO address or domain name)" + port : int + OMERO server port (default:4064) + filter : str + Filter to apply to the IDs list (Filename, Key-Value pairs or Tags) + id : int + A list of image IDs + value1 : str + Primary filter value. + value2 : str, optional + Optional secondary filter value. + uuuid_key : str, optional + OMERO UUID session key to connect without password + tsv_file : str, optional + Output TSV filename. Default is "filter_list.tsv". + ses_close : bool + Decide if close or not the section after executing the script. Defaulf value is true, useful when connecting with the UUID session key. + + Returns + ------- + csv.writer + A CSV writer object configured to write TSV data. Contain a list of IDs with the filtered IDs + """ # Function to write tabular file from the ezomero output def write_ids_to_tsv(data): @@ -19,8 +62,15 @@ for item in data: writer.writerow([item]) # Write each ID - with ez.connect(user, pws, "", host, port, secure=True) as conn: + # Try to connect with UUID or with username and password + conn = establish_connection(uuid_key, usr, psw, host, port) + # Transform the id input in a list of integer + id = id.split(',') + id = list(map(int, id)) + + try: + # Apply different filters to the image ID list if filter == "filename": fn_ids = ez.filter_by_filename(conn, id, value1) write_ids_to_tsv(fn_ids) @@ -39,39 +89,34 @@ else: sys.exit(f"Unsupported object type: {filter}") + finally: + if ses_close: + conn.close() -# Argument parsing + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Fetch and save data as TSV based on object type.") - parser.add_argument("--credential-file", dest="credential_file", type=str, required=True, - help="Credential file (JSON file with username and password for OMERO)") - parser.add_argument('--host', required=True, - help="Host server address.") - parser.add_argument('--port', required=True, type=int, - help='OMERO port') - parser.add_argument('--filter', required=True, - help="Filter type - Filename, Key-Value Pairs, Tag") - parser.add_argument('--id', required=True, - help="List of images IDs") - parser.add_argument('--value1', required=True, - help="First searching values - Filename, Key, Tag") + parser.add_argument('--host', required=True, help="OMERO server host (i.e. OMERO address or domain name)") + parser.add_argument('--port', required=True, type=int, help="OMERO server port (default:4064)") + parser.add_argument('--filter', required=True, help="Filter type - Filename, Key-Value Pairs, Tag") + parser.add_argument('--id', required=True, help="List of images IDs") + parser.add_argument('--value1', required=True, help="First searching values - Filename, Key, Tag") parser.add_argument('--value2', required=False, help="Second searching values - Value (necessary just for Key-Value Pairs filter") - parser.add_argument('--tsv_file', default='filter_list.tsv', - help="Output TSV file path.") + parser.add_argument('--session_close', required=False, help='Namespace or title for the annotation') + parser.add_argument('--tsv_file', default='filter_list.tsv', help="Output TSV file path.") + args = parser.parse_args() if args.filter == "KP" and args.value2 is None: raise ValueError("'--value 2' is necessary to retrieve KP") - with open(args.credential_file, 'r') as f: - crds = json.load(f) - # Call the main function to get the object and save it as a TSV - filter_ids_ezo(user=crds['username'], pws=crds['password'], host=args.host, + filter_ids_ezo(host=args.host, port=args.port, filter=args.filter, value1=args.value1, value2=args.value2, id=args.id, + ses_close=args.session_close, tsv_file=args.tsv_file) diff -r f5c4f523432d -r 89fc1f215e77 omero_get_id.py --- a/omero_get_id.py Fri Jun 13 20:47:38 2025 +0000 +++ b/omero_get_id.py Mon Jan 26 15:06:01 2026 +0000 @@ -1,12 +1,57 @@ import argparse import csv -import json +import os import sys +from typing import Optional import ezomero as ez +from connect_omero import establish_connection + +# Import environmental variables +usr = os.getenv("OMERO_USER") +psw = os.getenv("OMERO_PASSWORD") +uuid_key = os.getenv("UUID_SESSION_KEY") -def get_ids_ezo(user, pws, host, port, final_obj_type, parent_obj_type, parent_id=None, tsv_file="id_list.tsv"): +def get_ids_ezo( + host: str, + port: int, + final_obj_type: str, + parent_obj_type: str, + parent_id: Optional[int] = None, + uuid_key: Optional[str] = None, + tsv_file: str = "filter_list.tsv", + ses_close: Optional[bool] = True +) -> int: + """ + Fetch OMERO object IDs (Project, Dataset, Image, Annotation, Tag, ROI, or Table) as TSV from parent object (roject, Dataset, Plate, Well, Image) + + Parameters + ---------- + host : str + OMERO server host (i.e. OMERO address or domain name)" + port : int + OMERO server port (default:4064) + final_obj_type : str + Type of object to fetch ID: Project, Dataset, Image, Annotation, Tag, ROI, or Table. + parent_obj_type : int + Type of object from which you fetch IDs: Project, Dataset, Plate, Well, Image (or 'All' if you want to get all objects). + parent_id : str, optional + ID of the OMERO object in `--parent_obj_type`, not required if you used `--parent_obj_type All`. + uuid_key : str, optional + OMERO UUID session key to connect without password + tsv_file : str, optional + Output TSV filename. Default is "filter_list.tsv". + ses_close : bool + Decide if close or not the section after executing the script. Defaulf value is true, useful when connecting with the UUID session key. + + Returns + ------- + csv.writer + A CSV writer object configured to write TSV data. Contain a list of IDs. + """ + + conn = establish_connection(uuid_key, usr, psw, host, port) # Function to write tabular file from the ezomero output def write_ids_to_tsv(data): @@ -15,8 +60,8 @@ for item in data: writer.writerow([item]) # Write each ID - with ez.connect(user, pws, "", host, port, secure=True) as conn: - + try: + # Fetch different object according to the user input if final_obj_type == "Project": proj_ids = ez.get_project_ids(conn) write_ids_to_tsv(proj_ids) @@ -75,42 +120,40 @@ else: sys.exit(f"Unsupported object type: {filter}") + finally: + if ses_close: + conn.close() -# Argument parsing + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Fetch OMERO object IDs as TSV from parent object.") - parser.add_argument("--credential-file", dest="credential_file", type=str, - required=True, help="Credential file (JSON file with username and password for OMERO)") - parser.add_argument('--host', required=True, - help="Host server address.") - parser.add_argument('--port', required=True, type=int, - help='OMERO port') + parser.add_argument('--host', required=True, help="OMERO server host (i.e. OMERO address or domain name)") + parser.add_argument('--port', required=True, type=int, help="OMERO server port (default:4064)") parser.add_argument('--final_obj_type', required=True, help="Type of object to fetch ID: Project, Dataset, Image, Annotation, Tag, Roi, or Table.") parser.add_argument('--parent_obj_type', required=True, help="Type of object from which you fetch IDs: Project, Dataset, Plate, Well, Image (or 'All' if you want to get all objects).") parser.add_argument('--parent_id', required=False, type=int, help="ID of the OMERO object in `--parent_obj_type`, not required if you used `--parent_obj_type All`.") - parser.add_argument('--tsv_file', default='id_list.tsv', - help="Output TSV file path.") + parser.add_argument('--session_close', required=False, help='Namespace or title for the annotation') + parser.add_argument('--tsv_file', default='id_list.tsv', help="Output TSV file path.") + args = parser.parse_args() if args.parent_id is None and args.parent_obj_type != "All": raise ValueError("ID is only optional is you use `--parent_obj_type All`") if args.final_obj_type == "Roi" and args.parent_obj_type != "Image": - raise ValueError("Roi IDs can only be retrived from images, use `--parent_obj_type Image`") + raise ValueError("ROI IDs can only be retrived from images, use `--parent_obj_type Image`") if args.parent_obj_type == "All" and args.final_obj_type not in ["Image", "Dataset", "Project"]: raise ValueError("Only Images, Datasets and Projects is compatible with `--parent_obj_type All`") - with open(args.credential_file, 'r') as f: - crds = json.load(f) - # Call the main function to get the object and save it as a TSV - get_ids_ezo(user=crds['username'], pws=crds['password'], host=args.host, + get_ids_ezo(host=args.host, port=args.port, final_obj_type=args.final_obj_type, parent_obj_type=args.parent_obj_type, parent_id=args.parent_id, + ses_close=args.session_close, tsv_file=args.tsv_file) diff -r f5c4f523432d -r 89fc1f215e77 omero_get_value.py --- a/omero_get_value.py Fri Jun 13 20:47:38 2025 +0000 +++ b/omero_get_value.py Mon Jan 26 15:06:01 2026 +0000 @@ -1,14 +1,56 @@ import argparse import csv -import json import os import sys +from typing import Optional import ezomero as ez import pandas as pd +from connect_omero import establish_connection + +# Import environmental variables +usr = os.getenv("OMERO_USER") +psw = os.getenv("OMERO_PASSWORD") +uuid_key = os.getenv("UUID_SESSION_KEY") -def get_object_ezo(user, pws, host, port, obj_type, ids, out_dir): +def get_object_ezo( + host: str, + port: int, + obj_type: str, + ids: list, + out_dir: str, + uuid_key: Optional[str] = None, + ses_close: Optional[bool] = True +) -> str | dict: + + """ +Fetch OMERO objects (Annotation, Table and Key-Value Pairs list) and save them as TSV based on object type. + +Parameters +---------- +host : str + OMERO server host (i.e. OMERO address or domain name)" +port : int + OMERO server port (default:4064) +obj_type : str + Type of object to fetch ID: Project, Dataset, Image, Annotation, Tag, ROI, or Table. +ids : list + IDs of the OMERO objects. +out_dir : str + Output path of the file +uuid_key : str, optional + OMERO UUID session key to connect without password +ses_close : bool + Decide if close or not the section after executing the script. Defaulf value is true, useful when connecting with the UUID session key. +Returns +------- +csv.writer + A CSV writer object configured to write TSV data. +""" + + conn = establish_connection(uuid_key, usr, psw, host, port) + # Function to write tabular file from the ezomero output def write_values_to_tsv(data, header): with open("output.tsv", 'w', newline='') as f: @@ -31,7 +73,8 @@ for row in data: f.write('\t'.join([str(val) for val in row]) + '\n') - with ez.connect(user, pws, "", host, port, secure=True) as conn: + try: + # Fetch different object according to the user input if obj_type == "Annotation": ma_dict = {} for maid in ids: @@ -61,25 +104,22 @@ else: sys.exit(f"Unsupported object type: {filter}") + finally: + if ses_close: + conn.close() -# Argument parsing + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Fetch and save data as TSV based on object type.") - parser.add_argument("--credential-file", dest="credential_file", type=str, - required=True, help="Credential file (JSON file with username and password for OMERO)") - parser.add_argument('--host', required=True, - help="Host server address.") - parser.add_argument('--port', required=True, type=int, - help='OMERO port') - parser.add_argument('--obj_type', required=True, - help="Type of object to fetch: Annotation, Table or Tag.") + parser.add_argument('--host', required=True, help="OMERO server host (i.e. OMERO address or domain name)") + parser.add_argument('--port', required=True, type=int, help="OMERO server port (default:4064)") + parser.add_argument('--obj_type', required=True, help="Type of object to fetch: Annotation, Table or Tag.") group = parser.add_mutually_exclusive_group() - group.add_argument('--ids', nargs='+', type=int, - help="IDs of the OMERO objects.") - group.add_argument('--ids_path', - help="File with IDs of the OMERO objects (one per line).") - parser.add_argument('--out_dir', required=True, - help="Output path.") + group.add_argument('--ids', nargs='+', type=int, help="IDs of the OMERO objects.") + group.add_argument('--ids_path', help="File with IDs of the OMERO objects (one per line).") + parser.add_argument('--session_close', required=False, help='Namespace or title for the annotation') + parser.add_argument('--out_dir', required=True, help="Output path.") + args = parser.parse_args() if args.ids_path: @@ -93,12 +133,10 @@ if len(args.ids) == 0: raise ValueError("Cound not find a single ID in the file.") - with open(args.credential_file, 'r') as f: - crds = json.load(f) - # Call the main function to get the object and save it as a TSV - get_object_ezo(user=crds['username'], pws=crds['password'], host=args.host, + get_object_ezo(host=args.host, port=args.port, obj_type=args.obj_type, ids=args.ids, + ses_close=args.session_close, out_dir=args.out_dir) diff -r f5c4f523432d -r 89fc1f215e77 omero_get_value.xml --- a/omero_get_value.xml Fri Jun 13 20:47:38 2025 +0000 +++ b/omero_get_value.xml Mon Jan 26 15:06:01 2026 +0000 @@ -2,16 +2,24 @@ with ezomero macros.xml - 2 + 3 omero + + + + - - - @@ -155,4 +161,4 @@ 10.1038/nmeth.1896 - + \ No newline at end of file diff -r f5c4f523432d -r 89fc1f215e77 omero_metadata_upload.py --- a/omero_metadata_upload.py Fri Jun 13 20:47:38 2025 +0000 +++ b/omero_metadata_upload.py Mon Jan 26 15:06:01 2026 +0000 @@ -1,13 +1,66 @@ import argparse -import json +import os from datetime import datetime +from pathlib import Path +from typing import Optional import ezomero as ez import pandas as pd +from connect_omero import establish_connection + +# Import environmental variables +usr = os.getenv("OMERO_USER") +psw = os.getenv("OMERO_PASSWORD") +uuid = os.getenv("UUID_SESSION_KEY") -def metadata_import_ezo(user, pws, host, port, obj_type, did=None, ann_type="table", ann_file=None, an_name=None, - log_file='metadata_import_log.txt'): +def metadata_import_ezo( + host: str, + port: int, + obj_type: str, + ann_type: [str] = "table", + ann_file: Path = None, + an_name: [str] = None, + did: Optional[int] = None, + uuid_key: Optional[str] = None, + log_file: [str] = 'metadata_import_log.txt', + ses_close: Optional[bool] = True, +) -> str: + + ''' + Import metadata into OMERO as form of OMERO.table or Key-Value Pairs. + + Parameters + ---------- + host : str + OMERO server host (i.e. OMERO address or domain name)" + port : int + OMERO server port (default:4064) + did: list + ID of the object (if it exists) + obj_type : str + Annotation type meaning Table or Key-Value pairs + ann_type: str + Path to the annotation file + ann_file: [Path]=None + Path to the annotation file + an_name : str + Namespace or title for the annotation + uuid_key : str, optional + OMERO UUID session key to connect without password + log_file : str + Output path for the log file + ses_close : bool + Decide if close or not the section after executing the script. Defaulf value is true, useful when connecting with the UUID session key. + + Returns + ------- + csv.writer + A CSV writer object configured to write TSV data. + ''' + + conn = establish_connection(uuid_key, usr, psw, host, port) + def upload_metadata(conn, obj_type, did, data_dict, df, ann_type, an_name): try: if ann_type == "KV": @@ -48,59 +101,60 @@ data_dict = ann_file try: - with ez.connect(user, pws, "", host, port, secure=True) as conn: - if obj_type == "project": - if did is None: - did = ez.post_project(conn, project_name=str(datetime.now())) - result = upload_metadata(conn, "Project", did, data_dict, df, ann_type, an_name) - elif obj_type == "screen": - if did is None: - did = ez.post_screen(conn, screen_name=str(datetime.now())) - result = upload_metadata(conn, "Screen", did, data_dict, df, ann_type, an_name) - elif obj_type == "dataset": - if did is None: - did = ez.post_dataset(conn, dataset_name=str(datetime.now())) - result = upload_metadata(conn, "Dataset", did, data_dict, df, ann_type, an_name) - elif obj_type == "plate": - result = upload_metadata(conn, "Plate", did, data_dict, df, ann_type, an_name) - elif obj_type == "well": - result = upload_metadata(conn, "Well", did, data_dict, df, ann_type, an_name) - elif obj_type == "image": - result = upload_metadata(conn, "Image", did, data_dict, df, ann_type, an_name) - else: - raise ValueError("Unsupported object type provided: {}".format(obj_type)) - - if result is not None: - log_success(f"Successfully uploaded metadata for {obj_type} with ID {did}. Result: {result}") - else: - log_error(f"Failed to upload metadata for {obj_type} with ID {did}.") - - conn.close() - - except Exception as e: - log_error(f"Connection error: {str(e)}") + if obj_type == "project": + if did is None: + did = ez.post_project(conn, project_name=str(datetime.now())) + result = upload_metadata(conn, "Project", did, data_dict, df, ann_type, an_name) + elif obj_type == "screen": + if did is None: + did = ez.post_screen(conn, screen_name=str(datetime.now())) + result = upload_metadata(conn, "Screen", did, data_dict, df, ann_type, an_name) + elif obj_type == "dataset": + if did is None: + did = ez.post_dataset(conn, dataset_name=str(datetime.now())) + result = upload_metadata(conn, "Dataset", did, data_dict, df, ann_type, an_name) + elif obj_type == "plate": + result = upload_metadata(conn, "Plate", did, data_dict, df, ann_type, an_name) + elif obj_type == "well": + result = upload_metadata(conn, "Well", did, data_dict, df, ann_type, an_name) + elif obj_type == "image": + result = upload_metadata(conn, "Image", did, data_dict, df, ann_type, an_name) + else: + raise ValueError("Unsupported object type provided: {}".format(obj_type)) + finally: + if result is not None: + log_success(f"Successfully uploaded metadata for {obj_type} with ID {did}. Result: {result}") + if ses_close: + conn.close() + else: + log_error(f"Failed to upload metadata for {obj_type} with ID {did}.") + if ses_close: + conn.close() if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Import metadata into OMERO.') - parser.add_argument("--credential-file", dest="credential_file", type=str, required=True, - help="Credential file (JSON file with username and password for OMERO)") - parser.add_argument('--host', required=True, help='OMERO host') - parser.add_argument('--port', required=True, type=int, help='OMERO port') - parser.add_argument('--obj_type', required=True, choices=['project', 'screen', 'dataset', 'plate', - 'well ', 'image'], + parser = argparse.ArgumentParser( + description='Import metadata into OMERO as form of OMERO.table or Key-Value Pairs.') + parser.add_argument('--host', required=True, help="OMERO server host (i.e. OMERO address or domain name)") + parser.add_argument('--port', required=True, type=int, help="OMERO server port (default:4064)") + parser.add_argument('--obj_type', required=True, + choices=['project', 'screen', 'dataset', 'plate', 'well ', 'image'], help='Type of OMERO object') parser.add_argument('--did', type=int, help='ID of the object (if it exists)') parser.add_argument('--ann_type', required=True, choices=['table', 'KV', "attachement"], help='Annotation type') parser.add_argument('--ann_file', required=True, help='Path to the annotation file') parser.add_argument('--an_name', required=True, help='Namespace or title for the annotation') + parser.add_argument('--session_close', required=False, help='Namespace or title for the annotation') parser.add_argument('--log_file', default='metadata_import_log.txt', help='Path to the log file') args = parser.parse_args() - with open(args.credential_file, 'r') as f: - crds = json.load(f) - - metadata_import_ezo(user=crds['username'], pws=crds['password'], host=args.host, port=args.port, - obj_type=args.obj_type, did=args.did, ann_type=args.ann_type, - ann_file=args.ann_file, an_name=args.an_name, log_file=args.log_file) + metadata_import_ezo(host=args.host, + port=args.port, + obj_type=args.obj_type, + did=args.did, + ann_type=args.ann_type, + ann_file=args.ann_file, + an_name=args.an_name, + ses_close=args.session_close, + log_file=args.log_file) diff -r f5c4f523432d -r 89fc1f215e77 omero_roi_upload.py --- a/omero_roi_upload.py Fri Jun 13 20:47:38 2025 +0000 +++ b/omero_roi_upload.py Mon Jan 26 15:06:01 2026 +0000 @@ -1,12 +1,20 @@ import argparse -import json +import os import re +from pathlib import Path +from typing import Optional +import ezomero as ez import numpy as np import pandas as pd -from ezomero import connect, post_roi +from connect_omero import establish_connection from ezomero.rois import Ellipse, Label, Line, Point, Polygon, Polyline, Rectangle +# Import environmental variables +usr = os.getenv("OMERO_USER") +psw = os.getenv("OMERO_PASSWORD") +uuid_key = os.getenv("UUID_SESSION_KEY") + def parse_color(color_str): if not color_str: @@ -24,6 +32,7 @@ return [tuple(map(float, point.split(','))) for point in points] +# function to create different shapes def create_shape(row): shape_type = row['shape'] shape = None @@ -122,55 +131,85 @@ return shape -def main(input_file, conn, image_id, log_file): +def import_rois( + host: str, + port: int, + input_file: Path, + image_id: int, + log_file: Path, + uuid_key: Optional[str] = None, + ses_close: Optional[bool] = True, +) -> str | int: + + """ + Create shapes from a tabular file and upload them as an ROI to OMERO. + + Parameters + ---------- + host : str + OMERO server host (i.e. OMERO address or domain name)" + port : int + OMERO server port (default:4064) + image_id : str + ID of the image to which the ROI will be linked + input_file: Path + Path to the input tabular file + log_file : str + Output path for the log file + uuid_key : str, optional + OMERO UUID session key to connect without password + ses_close : bool + Decide if close or not the section after executing the script. Defaulf value is true, useful when connecting with the UUID session key. + Returns + ------- + str | int + A CSV writer object configured to write TSV data and ID of newly created ROI + """ + + # Try to connect with UUID or with username and password + conn = establish_connection(uuid_key, usr, psw, host, port) + # Open log file - with open(log_file, 'w') as log: - df = pd.read_csv(input_file, sep='\t') - # Replace nan to none - df = df.replace({np.nan: None}) - for index, row in df.iterrows(): - msg = f"Processing row {index + 1}/{len(df)}: {row.to_dict()}" - print(msg) - log.write(msg + "\n") - shape = create_shape(row) - if shape: - roi_name = row['roi_name'] if 'roi_name' in row else None - roi_description = row['roi_description'] if 'roi_description' in row else None - roi_id = post_roi(conn, image_id, [shape], name=roi_name, description=roi_description) - msg = f"ROI ID: {roi_id} for row {index + 1}" + try: + with open(log_file, 'w') as log: + df = pd.read_csv(input_file, sep='\t') + # Replace nan to none + df = df.replace({np.nan: None}) + for index, row in df.iterrows(): + msg = f"Processing row {index + 1}/{len(df)}: {row.to_dict()}" print(msg) log.write(msg + "\n") - else: - msg = f"Skipping row {index + 1}: Unable to create shape" - print(msg) - log.write(msg + "\n") + shape = create_shape(row) + if shape: + roi_name = row['roi_name'] if 'roi_name' in row else None + roi_description = row['roi_description'] if 'roi_description' in row else None + roi_id = ez.post_roi(conn, image_id, [shape], name=roi_name, description=roi_description) + msg = f"ROI ID: {roi_id} for row {index + 1}" + print(msg) + log.write(msg + "\n") + else: + msg = f"Skipping row {index + 1}: Unable to create shape" + print(msg) + log.write(msg + "\n") + finally: + if ses_close: + conn.close() if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Create shapes from a tabular file and optionally post them as an ROI to OMERO.") + parser = argparse.ArgumentParser(description="Create shapes from a tabular file and post them as an ROI to OMERO.") + parser.add_argument("--host", type=str, required=True, help="OMERO server host (i.e. OMERO address or domain name)") + parser.add_argument("--port", type=int, default=4064, help="OMERO server port (default:4064)") parser.add_argument("--input_file", help="Path to the input tabular file.") parser.add_argument("--image_id", type=int, required=True, help="ID of the image to which the ROI will be linked") - parser.add_argument("--host", type=str, required=True, help="OMERO server host") - parser.add_argument("--credential-file", dest="credential_file", type=str, required=True, help="Credential file (JSON file with username and password for OMERO)") - parser.add_argument("--port", type=int, default=4064, help="OMERO server port") - parser.add_argument("--log_file", type=str, default="process.txt", help="Log file path") + parser.add_argument('--session_close', required=False, help='Namespace or title for the annotation') + parser.add_argument("--log_file", type=str, default="process.txt", help="Output path for the log file") args = parser.parse_args() - with open(args.credential_file, 'r') as f: - crds = json.load(f) - - conn = connect( - host=args.host, - user=crds['username'], - password=crds['password'], - port=args.port, - group="", - secure=True - ) - - try: - main(args.input_file, conn, args.image_id, args.log_file) - finally: - conn.close() + import_rois(host=args.host, + port=args.port, + input_file=args.input_file, + image_id=args.image_id, + ses_close=args.session_close, + log_file=args.log_file) diff -r f5c4f523432d -r 89fc1f215e77 test-data/omero_output_2.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/omero_output_2.json Mon Jan 26 15:06:01 2026 +0000 @@ -0,0 +1,3 @@ +[{"#": "0", "Class": "DatasetI", "Id": "3", "details": "owner=0;group=0", "name": "galaxy_test_upload"}, +{"#": "1", "Class": "DatasetI", "Id": "2", "details": "owner=0;group=0", "name": "test_hcs_dts"}, +{"#": "2", "Class": "DatasetI", "Id": "1", "details": "owner=0;group=0", "name": "test_dts"}]