|
| 1 | +# ╔─────────────────────────────────────────────╗ |
| 2 | +# │ │ |
| 3 | +# │ Attach file to an existing experiment │ |
| 4 | +# │ by Unique eLabID and with validation │ |
| 5 | +# │ │ |
| 6 | +# ╚─────────────────────────────────────────────╝ |
| 7 | +# ----------------------------------------------- |
| 8 | +# ┌─────────────┐ |
| 9 | +# │ Objective │ |
| 10 | +# └─────────────┘ |
| 11 | +# We attach a local file to an experiment same as before as we did in "add_attachment_simple.py". |
| 12 | +# We will do some additional validations before uploading the attachment. |
| 13 | +# Furthermore, instead of using the experiment ID, we will use the "Unique eLabID," |
| 14 | +# which is more conspicuous on an experiment page. |
| 15 | +# ┌────────────────┐ |
| 16 | +# │ Requirements │ |
| 17 | +# └────────────────┘ |
| 18 | +# - We only attach to an experiment that already exists in eLabFTW. |
| 19 | +# - We get the path of the local file for attachment. Here, we already have two |
| 20 | +# example files stored in ./attachments directory. |
| 21 | +# - The minimum Python version required is 3.9. It's recommended that we create a |
| 22 | +# Python virtual environment, and we run/edit the script from inside the environment. |
| 23 | +# - We need to install elAPI from inside the activated virtual environment. |
| 24 | +# Simple `pip install elapi` should work. |
| 25 | +# Note: The elAPI we installed using `uv tool` or pipx remains isolated and is meant to work as |
| 26 | +# a user-friendly CLI tool. Here, we want to use elAPI as a library. |
| 27 | +# ┌─────────────────┐ |
| 28 | +# │ Code overview │ |
| 29 | +# └─────────────────┘ |
| 30 | +# We explain in comments around each significant line of code what the code does. |
| 31 | +# Here we will give a short overview: |
| 32 | +# 1. elAPI already offers a plugin for working with eLabFTW experiments. |
| 33 | +# We use "attach_to_experiment" method provided by the "experiments" plugin. |
| 34 | +# 2. We define the ID for the existing experiment we want to attach our file to. |
| 35 | +# 3. We define the path to our attachment file. |
| 36 | +# 4. We call "attach_to_experiment". |
| 37 | +# 5. We print a minimal success message. |
| 38 | +from pathlib import Path |
| 39 | + |
| 40 | +from httpx import HTTPError |
| 41 | + |
| 42 | +from elapi.loggers import Logger |
| 43 | +from elapi.plugins.experiments import attach_to_experiment, ExperimentIDValidator |
| 44 | +# For making sure we have the appropriate permission |
| 45 | +from elapi.validators import ( |
| 46 | + Validate, |
| 47 | + HostIdentityValidator, |
| 48 | + APITokenRWValidator, |
| 49 | + ValidationError, |
| 50 | + Exit, |
| 51 | +) |
| 52 | + |
| 53 | +# We use Logger instance for logging errors and other messages |
| 54 | +# Logs are printed to the terminal and to a local file. |
| 55 | +# See the log file location from `elapi show-config`. |
| 56 | +logger = Logger() |
| 57 | + |
| 58 | +# We need an API key/token with write permission to be able to upload an attachment. |
| 59 | +# We also need to make sure we have the right permission(s) to be able to create users in the first place. |
| 60 | +# These validations can be immensely helpful as they can help us understand any |
| 61 | +# permission or network related error early on without having to analyze the error response sent by eLabFTW. |
| 62 | +validate = Validate(HostIdentityValidator(), APITokenRWValidator(can_write=True)) |
| 63 | +# HostIdentityValidator mainly ensures if the configured host and api_token are valid. |
| 64 | +# APITokenRWValidator makes sure our API key/token has write permission. |
| 65 | +# If something is found to be wrong (or invalid) by the validator, elAPI will show the appropriate error message |
| 66 | +# and quit. |
| 67 | +# +------------------+ |
| 68 | +# | Run validation | |
| 69 | +# +------------------+ |
| 70 | +validate() |
| 71 | + |
| 72 | +UNIQUE_ELAB_ID = "20240309-b629ba4a6789fac1662505d057a3c57459ccc646" |
| 73 | +# Unique eLabID instead of experiment ID of our experiment |
| 74 | +ATTACHMENT_FILE = Path(__file__).parent / "attachments/elapi_get_architecture_old.pdf" |
| 75 | +# +-------------------------------+ |
| 76 | +# | Run validation for | |
| 77 | +# | experiment ID/unique eLabID | |
| 78 | +# +-------------------------------+ |
| 79 | +# We validate the unique eLabID, i.e., we want to check if the experiment exists first. |
| 80 | +try: |
| 81 | + experiment_id = Validate(ExperimentIDValidator(UNIQUE_ELAB_ID)).get() |
| 82 | +except ValidationError as e: |
| 83 | + logger.error(e) |
| 84 | + # If the ID/experiment does not exist, we abort/quit. |
| 85 | + raise Exit(1) |
| 86 | +try: |
| 87 | + # If ID does exist, we continue with uploading the attachment. |
| 88 | + attach_to_experiment( |
| 89 | + experiment_id=experiment_id, |
| 90 | + file_path=ATTACHMENT_FILE, |
| 91 | + comment="Uploaded via elAPI", |
| 92 | + ) |
| 93 | + # We catch any network error during upload. |
| 94 | +except HTTPError as e: |
| 95 | + logger.error( |
| 96 | + f"There was a network error in attaching the file '{ATTACHMENT_FILE}'. " |
| 97 | + f"Exception details: {e}" |
| 98 | + ) |
| 99 | + raise Exit(1) |
| 100 | +else: |
| 101 | + # If everything goes well (no error caught above), |
| 102 | + # we print a success message. |
| 103 | + logger.info(f"Successfully attached the file '{ATTACHMENT_FILE}' to experiment.") |
0 commit comments