Repository 'omero_get_id'
hg clone https://toolshed.g2.bx.psu.edu/repos/ufz/omero_get_id

Changeset 5:518221701b10 (2026-01-26)
Previous changeset 4:426415e73f46 (2025-06-13)
Commit message:
planemo upload for repository https://github.com/Helmholtz-UFZ/galaxy-tools/tree/main/tools/omero commit 233f0e70cb20a02ec8530dbcfd5c7e70eef74476
modified:
README.md
macros.xml
omero_dataset_to_plate.py
omero_filter.py
omero_get_id.py
omero_get_id.xml
omero_get_value.py
omero_metadata_upload.py
omero_roi_upload.py
added:
connect_omero.py
test-data/omero_output_2.json
b
diff -r 426415e73f46 -r 518221701b10 README.md
--- a/README.md Fri Jun 13 20:47:02 2025 +0000
+++ b/README.md Mon Jan 26 15:06:13 2026 +0000
b
@@ -1,4 +1,4 @@
-# OMERO import images
+# OMERO suite toolbox
 
 ## Set up user credentials on Galaxy to connect to other omero instance
 
b
diff -r 426415e73f46 -r 518221701b10 connect_omero.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/connect_omero.py Mon Jan 26 15:06:13 2026 +0000
b
@@ -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
b
diff -r 426415e73f46 -r 518221701b10 macros.xml
--- a/macros.xml Fri Jun 13 20:47:02 2025 +0000
+++ b/macros.xml Mon Jan 26 15:06:13 2026 +0000
[
@@ -2,13 +2,14 @@
     <!-- for historic reasons the omero-py version is used as the version for all tools -->
     <token name="@TOOL_VERSION@">5.18.0</token>
     <token name="@EZOMERO_VERSION@">3.0.1</token>
-    <token name="@PROFILE@">23.0</token>
+    <token name="@PROFILE@">25.1</token>
 
     <xml name="ezomero_requirements">
         <requirements>
             <requirement type="package" version="@EZOMERO_VERSION@">ezomero</requirement>
             <requirement type="package" version="2.2.2">pandas</requirement>
             <yield/>
+            <expand macro="omero_credentials"/>
         </requirements>
     </xml>
 
@@ -18,9 +19,17 @@
             <!-- openjdk is needed: https://github.com/conda-forge/omero-py-feedstock/pull/16 -->
             <requirement type="package" version="21.0.2">openjdk</requirement>
             <yield/>
+            <expand macro="omero_credentials"/>
         </requirements>
     </xml>
-    
+
+    <xml name="omero_credentials">
+        <credentials name="OMERO" version="0.1" label="OMERO Credentials" description="Input a set of credentials to access a target OMERO.server">
+            <variable name="username" inject_as_env="OMERO_USER" optional="true" label="OMERO username" description="OMERO username" />
+            <secret name="password" inject_as_env="OMERO_PASSWORD" optional="true" label="OMERO password" description="OMERO password" />
+            <secret name="uuid-key" inject_as_env="UUID_SESSION_KEY" optional="true" label="OMERO UUID Session Key" description="Input your session key here to connect using an existing OMERO session key. More information on how to find a session key: https://omero.readthedocs.io/en/stable/users/cli/sessions.html" />
+        </credentials>
+    </xml>
 
     <xml name="host_port">
         <param name="omero_host" type="text" label="OMERO host URL">
@@ -30,27 +39,49 @@
         <param argument="omero_port" type="integer" optional="false" value="4064" label="OMERO port"/>
         <param name="test_username" type="hidden" value=""/>
         <param name="test_password" type="hidden" value=""/>
+        <conditional name="session_id">
+            <param name="session_id_input" type="select" label="Create an OMERO session using a UUID key?" help="Connect to OMERO trough an existing connection (no password/username input)">
+                <option value="no">No</option>
+                <option value="yes">Yes</option>
+            </param>
+            <when value="yes">
+                <param name="close_connection" type="boolean" truevalue="True" falsevalue="False" label="Close the connection after executing the tool?"
+                help="If yes, the current OMERO connection will be closed after tools execution. UUID key cannot be used again in further tools."/>
+            </when>
+            <when value="no">
+            </when>
+        </conditional>
     </xml>
+
     <token name="@HOST_PORT@">
         --host '$omero_host'
         --port $omero_port
     </token>
 
-    <xml name="credentials">
-        <configfile name="credentials"><![CDATA[
-{
-    "username": "$__user__.extra_preferences.get('omero_account|username', $test_username)",
-    "password": "$__user__.extra_preferences.get('omero_account|password', $test_password)"
-}
-        ]]></configfile>
-    </xml>
+    <token name="@SESSION_ID@">
+        #if $session_id.session_id_input== "yes"
+            --session_close $close_connection
+        #else
+            --session_close "True"
+        #end if
+    </token>
+
 
     <token name="@SECURITY_DISCLAIMER@">
-    **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).
     </token>
 
 </macros>
\ No newline at end of file
b
diff -r 426415e73f46 -r 518221701b10 omero_dataset_to_plate.py
--- a/omero_dataset_to_plate.py Fri Jun 13 20:47:02 2025 +0000
+++ b/omero_dataset_to_plate.py Mon Jan 26 15:06:13 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
     )
b
diff -r 426415e73f46 -r 518221701b10 omero_filter.py
--- a/omero_filter.py Fri Jun 13 20:47:02 2025 +0000
+++ b/omero_filter.py Mon Jan 26 15:06:13 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)
b
diff -r 426415e73f46 -r 518221701b10 omero_get_id.py
--- a/omero_get_id.py Fri Jun 13 20:47:02 2025 +0000
+++ b/omero_get_id.py Mon Jan 26 15:06:13 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)
b
diff -r 426415e73f46 -r 518221701b10 omero_get_id.xml
--- a/omero_get_id.xml Fri Jun 13 20:47:02 2025 +0000
+++ b/omero_get_id.xml Mon Jan 26 15:06:13 2026 +0000
[
@@ -2,24 +2,30 @@
     <description> with ezomero </description>
     <macros>
         <import>macros.xml</import>
-        <token name="@VERSION_SUFFIX@">0</token>
+        <token name="@VERSION_SUFFIX@">1</token>
     </macros>
     <xrefs>
         <xref type="bio.tools">omero</xref>
     </xrefs>
     <expand macro="ezomero_requirements"/>
+    <required_files>
+        <include path="connect_omero.py" />
+        <include path="omero_get_id.py" />
+    </required_files>
     <command detect_errors="exit_code"><![CDATA[
+        #if $test_username != ""
+            export OMERO_USER="$test_username" &&
+            export OMERO_PASSWORD="$test_password" &&
+       #end if
+
         python '$__tool_directory__'/omero_get_id.py
-        --credential-file '$credentials'
         @HOST_PORT@
         --final_obj_type '$cond_obj_type.final_obj_type'
         --parent_obj_type '$cond_obj_type.parent_obj_type'
         --parent_id $cond_obj_type.parent_id
+        @SESSION_ID@
         --tsv_file '$tsv'
     ]]></command>
-    <configfiles>
-        <expand macro="credentials"/>
-    </configfiles>
     <inputs>
         <expand macro="host_port"/>
         <conditional name="cond_obj_type">
b
diff -r 426415e73f46 -r 518221701b10 omero_get_value.py
--- a/omero_get_value.py Fri Jun 13 20:47:02 2025 +0000
+++ b/omero_get_value.py Mon Jan 26 15:06:13 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)
b
diff -r 426415e73f46 -r 518221701b10 omero_metadata_upload.py
--- a/omero_metadata_upload.py Fri Jun 13 20:47:02 2025 +0000
+++ b/omero_metadata_upload.py Mon Jan 26 15:06:13 2026 +0000
[
b'@@ -1,13 +1,66 @@\n import argparse\n-import json\n+import os\n from datetime import datetime\n+from pathlib import Path\n+from typing import Optional\n \n import ezomero as ez\n import pandas as pd\n+from connect_omero import establish_connection\n+\n+# Import environmental variables\n+usr = os.getenv("OMERO_USER")\n+psw = os.getenv("OMERO_PASSWORD")\n+uuid = os.getenv("UUID_SESSION_KEY")\n \n \n-def metadata_import_ezo(user, pws, host, port, obj_type, did=None, ann_type="table", ann_file=None, an_name=None,\n-                        log_file=\'metadata_import_log.txt\'):\n+def metadata_import_ezo(\n+        host: str,\n+        port: int,\n+        obj_type: str,\n+        ann_type: [str] = "table",\n+        ann_file: Path = None,\n+        an_name: [str] = None,\n+        did: Optional[int] = None,\n+        uuid_key: Optional[str] = None,\n+        log_file: [str] = \'metadata_import_log.txt\',\n+        ses_close: Optional[bool] = True,\n+) -> str:\n+\n+    \'\'\'\n+    Import metadata into OMERO as form of OMERO.table or Key-Value Pairs.\n+\n+    Parameters\n+    ----------\n+    host : str\n+        OMERO server host (i.e. OMERO address or domain name)"\n+    port : int\n+        OMERO server port (default:4064)\n+    did: list\n+        ID of the object (if it exists)\n+    obj_type : str\n+        Annotation type meaning Table or Key-Value pairs\n+    ann_type: str\n+        Path to the annotation file\n+    ann_file: [Path]=None\n+        Path to the annotation file\n+    an_name : str\n+        Namespace or title for the annotation\n+    uuid_key : str, optional\n+        OMERO UUID session key to connect without password\n+    log_file : str\n+        Output path for the log file\n+    ses_close : bool\n+        Decide if close or not the section after executing the script. Defaulf value is true, useful when connecting with the UUID session key.\n+\n+    Returns\n+    -------\n+    csv.writer\n+        A CSV writer object configured to write TSV data.\n+    \'\'\'\n+\n+    conn = establish_connection(uuid_key, usr, psw, host, port)\n+\n     def upload_metadata(conn, obj_type, did, data_dict, df, ann_type, an_name):\n         try:\n             if ann_type == "KV":\n@@ -48,59 +101,60 @@\n         data_dict = ann_file\n \n     try:\n-        with ez.connect(user, pws, "", host, port, secure=True) as conn:\n-            if obj_type == "project":\n-                if did is None:\n-                    did = ez.post_project(conn, project_name=str(datetime.now()))\n-                result = upload_metadata(conn, "Project", did, data_dict, df, ann_type, an_name)\n-            elif obj_type == "screen":\n-                if did is None:\n-                    did = ez.post_screen(conn, screen_name=str(datetime.now()))\n-                result = upload_metadata(conn, "Screen", did, data_dict, df, ann_type, an_name)\n-            elif obj_type == "dataset":\n-                if did is None:\n-                    did = ez.post_dataset(conn, dataset_name=str(datetime.now()))\n-                result = upload_metadata(conn, "Dataset", did, data_dict, df, ann_type, an_name)\n-            elif obj_type == "plate":\n-                result = upload_metadata(conn, "Plate", did, data_dict, df, ann_type, an_name)\n-            elif obj_type == "well":\n-                result = upload_metadata(conn, "Well", did, data_dict, df, ann_type, an_name)\n-            elif obj_type == "image":\n-                result = upload_metadata(conn, "Image", did, data_dict, df, ann_type, an_name)\n-            else:\n-                raise ValueError("Unsupported object type provided: {}".format(obj_type))\n-\n-            if result is not None:\n-                log_success(f"Successfully uploaded metadata for {obj_type} with ID {did}. Result: {result}")\n-            else:\n-                log_error(f"Failed to upload metadata for {obj_type} with ID {did}.")\n-\n-        conn.close()\n-\n-    except Exception as e:\n-        log_error(f"Connection error: {str(e)}")\n+        if obj_type == "project":\n+            if did is None:\n+                did = ez.post'..b' upload_metadata(conn, "Project", did, data_dict, df, ann_type, an_name)\n+        elif obj_type == "screen":\n+            if did is None:\n+                did = ez.post_screen(conn, screen_name=str(datetime.now()))\n+            result = upload_metadata(conn, "Screen", did, data_dict, df, ann_type, an_name)\n+        elif obj_type == "dataset":\n+            if did is None:\n+                did = ez.post_dataset(conn, dataset_name=str(datetime.now()))\n+            result = upload_metadata(conn, "Dataset", did, data_dict, df, ann_type, an_name)\n+        elif obj_type == "plate":\n+            result = upload_metadata(conn, "Plate", did, data_dict, df, ann_type, an_name)\n+        elif obj_type == "well":\n+            result = upload_metadata(conn, "Well", did, data_dict, df, ann_type, an_name)\n+        elif obj_type == "image":\n+            result = upload_metadata(conn, "Image", did, data_dict, df, ann_type, an_name)\n+        else:\n+            raise ValueError("Unsupported object type provided: {}".format(obj_type))\n+    finally:\n+        if result is not None:\n+            log_success(f"Successfully uploaded metadata for {obj_type} with ID {did}. Result: {result}")\n+            if ses_close:\n+                conn.close()\n+        else:\n+            log_error(f"Failed to upload metadata for {obj_type} with ID {did}.")\n+            if ses_close:\n+                conn.close()\n \n \n if __name__ == "__main__":\n-    parser = argparse.ArgumentParser(description=\'Import metadata into OMERO.\')\n-    parser.add_argument("--credential-file", dest="credential_file", type=str, required=True,\n-                        help="Credential file (JSON file with username and password for OMERO)")\n-    parser.add_argument(\'--host\', required=True, help=\'OMERO host\')\n-    parser.add_argument(\'--port\', required=True, type=int, help=\'OMERO port\')\n-    parser.add_argument(\'--obj_type\', required=True, choices=[\'project\', \'screen\', \'dataset\', \'plate\',\n-                                                              \'well \', \'image\'],\n+    parser = argparse.ArgumentParser(\n+        description=\'Import metadata into OMERO as form of OMERO.table or Key-Value Pairs.\')\n+    parser.add_argument(\'--host\', required=True, help="OMERO server host (i.e. OMERO address or domain name)")\n+    parser.add_argument(\'--port\', required=True, type=int, help="OMERO server port (default:4064)")\n+    parser.add_argument(\'--obj_type\', required=True,\n+                        choices=[\'project\', \'screen\', \'dataset\', \'plate\', \'well \', \'image\'],\n                         help=\'Type of OMERO object\')\n     parser.add_argument(\'--did\', type=int, help=\'ID of the object (if it exists)\')\n     parser.add_argument(\'--ann_type\', required=True, choices=[\'table\', \'KV\', "attachement"], help=\'Annotation type\')\n     parser.add_argument(\'--ann_file\', required=True, help=\'Path to the annotation file\')\n     parser.add_argument(\'--an_name\', required=True, help=\'Namespace or title for the annotation\')\n+    parser.add_argument(\'--session_close\', required=False, help=\'Namespace or title for the annotation\')\n     parser.add_argument(\'--log_file\', default=\'metadata_import_log.txt\', help=\'Path to the log file\')\n \n     args = parser.parse_args()\n \n-    with open(args.credential_file, \'r\') as f:\n-        crds = json.load(f)\n-\n-    metadata_import_ezo(user=crds[\'username\'], pws=crds[\'password\'], host=args.host, port=args.port,\n-                        obj_type=args.obj_type, did=args.did, ann_type=args.ann_type,\n-                        ann_file=args.ann_file, an_name=args.an_name, log_file=args.log_file)\n+    metadata_import_ezo(host=args.host,\n+                        port=args.port,\n+                        obj_type=args.obj_type,\n+                        did=args.did,\n+                        ann_type=args.ann_type,\n+                        ann_file=args.ann_file,\n+                        an_name=args.an_name,\n+                        ses_close=args.session_close,\n+                        log_file=args.log_file)\n'
b
diff -r 426415e73f46 -r 518221701b10 omero_roi_upload.py
--- a/omero_roi_upload.py Fri Jun 13 20:47:02 2025 +0000
+++ b/omero_roi_upload.py Mon Jan 26 15:06:13 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)
b
diff -r 426415e73f46 -r 518221701b10 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:13 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"}]