Source code for sertit.unistra

# Copyright 2026, SERTIT-ICube - France, https://sertit.unistra.fr/
# This file is part of sertit-utils project
#     https://github.com/sertit/sertit-utils
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Unistra tools
"""

import configparser
import logging
import os
from contextlib import contextmanager
from pathlib import Path

from sertit import AnyPath, s3
from sertit.logs import SU_NAME
from sertit.s3 import USE_S3_STORAGE, temp_s3
from sertit.types import AnyPathType

LOGGER = logging.getLogger(SU_NAME)

UNISTRA_S3_ENDPOINT = "s3.unistra.fr"
"""
Unistra S3 compatible storage endpoint: s3.unistra.fr
"""

UNISTRA_S3_ENPOINT = UNISTRA_S3_ENDPOINT
# Legacy, to be removed in v2.0


[docs] def s3_env(*args, **kwargs): """ Create Unistra's S3 compatible storage environment. This function searches for S3 configuration in many places. It does apply configuration variables precedence, and you might have a use for it. Here is the order of precedence from least to greatest (the last listed configuration variables override all other variables): #. AWS profile #. AWS environment variable Profile unistra is first read from X:/SI/Secrets/config and X:/SI/Secrets/credentials. If this file does not exist, it fallbacks to local file $USER/.aws/config and $USER/.aws/credentials. You can use ready-to-use environements provided by the Sertit or asks for s3 credentials. Args: function (Callable): Function to decorate Returns: Callable: decorated function Example: >>> from sertit.unistra import s3_env >>> from sertit import AnyPath >>> @s3_env >>> def file_exists(path: str): >>> pth = AnyPath(path) >>> print(pth.exists()) >>> file_exists("s3://sertit-geodatastore/GLOBAL/COPDEM_30m/COPDEM_30m.vrt") True """ _set_aws_file_path() use_s3 = kwargs.pop("use_s3_env_var", USE_S3_STORAGE) extra_args = {"profile_name": "unistra"} if does_unistra_profile_exist() else {} extra_args["endpoint"] = UNISTRA_S3_ENDPOINT return s3.s3_env(use_s3_env_var=use_s3, **extra_args)(*args, **kwargs)
[docs] @contextmanager def unistra_s3() -> None: """ Initialize a temporary S3 environment as a context manager, with Unistra endpoint This function searches for S3 configuration in many places. It does apply configuration variables precedence, and you might have a use for it. Here is the order of precedence from least to greatest (the last listed configuration variables override all other variables): #. AWS profile "unistra" #. AWS environment variable Profile unistra is first read from X:/SI/Secrets/config and X:/SI/Secrets/credentials. If this file does not exist, it fallbacks to local file $USER/.aws/config and $USER/.aws/credentials. You can use ready-to-use environements provided by the Sertit or asks for s3 credentials. Args: default_endpoint (str):Default Endpoint to look for Example: >>> from sertit.unistra import unistra_s3 >>> from sertit import AnyPath >>> def file_exists(path: str): >>> with unistra_s3(): >>> pth = AnyPath(path) >>> print(pth.exists()) >>> file_exists("s3://sertit-geodatastore/GLOBAL/COPDEM_30m/COPDEM_30m.vrt") True """ _set_aws_file_path() try: extra_args = {"profile_name": "unistra"} if does_unistra_profile_exist() else {} extra_args["endpoint"] = UNISTRA_S3_ENDPOINT with temp_s3(**extra_args): yield finally: pass
[docs] def define_s3_client(): """ Define Unistra's S3 client This function searches for S3 configuration in many places. It does apply configuration variables precedence, and you might have a use for it. Here is the order of precedence from least to greatest (the last listed configuration variables override all other variables): #. AWS profile #. AWS environment variable Profile unistra is first read from X:/SI/Secrets/config and X:/SI/Secrets/credentials. If this file does not exist, it fallbacks to local file $USER/.aws/config and $USER/.aws/credentials. You can use ready-to-use environements provided by the Sertit or asks for s3 credentials. """ _set_aws_file_path() profile_arg = {"profile_name": "unistra"} if does_unistra_profile_exist() else {} return s3.define_s3_client(endpoint=UNISTRA_S3_ENDPOINT, **profile_arg)
[docs] def get_geodatastore() -> AnyPathType: """ Get database directory. If :any:`USE_S3_STORAGE` is set to ``1``, this function returns ``AnyPath("s3://sertit-geodatastore")``. If :any:`USE_S3_STORAGE` is set to ``0`` it returns: * ``AnyPath("//ds2/database02/BASES_DE_DONNEES")`` if code is running on Windows * ``AnyPath(/home/ds2_db2/BASE_DE_DONNESS`)`` if code is running in a Docker containers on Windows Returns: AnyPath: Database directory Example: Don't set manually ``USE_S3_STORAGE`` with ``os.environ`` ! >>> from sertit.unistra import get_geodatastore >>> import os >>> os.environ["USE_S3_STORAGE"] = "1" >>> print(get_geodatastore()) s3://sertit-geodatastore >>> from sertit.unistra import get_geodatastore >>> import os >>> os.environ["USE_S3_STORAGE"] = "0" >>> print(get_geodatastore()) //ds2/database02/BASES_DE_DONNEES/GLOBAL """ if int(os.getenv(s3.USE_S3_STORAGE, 0)): # Define S3 client for S3 paths define_s3_client() return AnyPath("s3://sertit-geodatastore") else: try: db_dir = AnyPath(get_db2_path(), "BASES_DE_DONNEES") except NotADirectoryError: # pragma: no cover db_dir = AnyPath("/home", "ds2_db2", "BASES_DE_DONNEES") if not db_dir.is_dir(): # pragma: no cover raise NotADirectoryError("Impossible to open database directory !") return AnyPath(db_dir)
[docs] def does_unistra_profile_exist() -> bool: """ This function checks if "unistra" AWS profile exists. Returns: True if "unistra" AWS profile is present on the machine, False otherwise """ config = configparser.ConfigParser() default_credentials_path = Path.home() / ".aws" / "credentials" credentials_path = os.getenv( "AWS_SHARED_CREDENTIALS_FILE", str(default_credentials_path) ) credentials_path = AnyPath(credentials_path) if not credentials_path.exists(): return False else: # pragma: no cover config.read(credentials_path) return "unistra" in config.sections()
def _set_aws_file_path() -> None: """ This function sets AWS filepath config and credentials inside X network drive "X:/SI/Secrets/AWS" Returns: """ config_file = AnyPath("X:") / "SI" / "Secrets" / "AWS" / "config" credentials_file = AnyPath("X:") / "SI" / "Secrets" / "AWS" / "credentials" if config_file.exists(): os.environ["AWS_CONFIG_FILE"] = str(config_file) if credentials_file.exists(): os.environ["AWS_SHARED_CREDENTIALS_FILE"] = str(credentials_file)
[docs] def get_mnt_path() -> str: """ Return mounting directory :code:`/mnt`. Warnings: This won't work on Windows ! Returns: str: Mounting directory Example: >>> get_mnt_path() '/mnt' """ return r"/mnt"
def _get_db_path(db_nb=2) -> str: """ Returns DSx database0x path - :code:`/mnt/ds2_dbx` when mounted (docker...) """ db_path = f"{get_mnt_path()}/ds2_db{db_nb}" if not os.path.isdir(db_path): # pragma: no cover raise NotADirectoryError(f"Impossible to open {db_path}!") return db_path
[docs] def get_db2_path() -> str: """ Returns DS2 database02 path - :code:`/mnt/ds2_db2` when mounted (docker...) Returns: str: Mounted directory Example: >>> get_db2_path() '/mnt/ds2_db2' """ return _get_db_path(2)
[docs] def get_db3_path() -> str: """ Returns DS2 database03 path - :code:`/mnt/ds2_db3` when mounted (docker...) Returns: str: Mounted directory Example: >>> get_db3_path() '/mnt/ds2_db3' """ return _get_db_path(3)