Source code for qa4sm_api.globals

# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: Copyright (c) 2026 TU Wien & AWST
# SPDX-FileCopyrightText: For a full list of authors, see the AUTHORS file.

from pathlib import Path
import os
import warnings
import configparser
from datetime import datetime
import requests

if "QA4SM_DOTRC" in os.environ:
    QA4SM_DOTRC_PATH = Path(os.environ["QA4SM_DOTRC"])
else:
    QA4SM_DOTRC_PATH = Path.home() / ".qa4smapirc"

DEFAULT_INSTANCE = "qa4sm.eu"
KNOWN_INSTANCES = [
    "qa4sm.eu", "test.qa4sm.eu", "test2.qa4sm.eu", "0.0.0.0:8000"
]


[docs] class Qa4smEnvironmentError(KeyError): pass
[docs] class ValidationRunNotFoundError(ValueError): def __init__(self, id): self.message = (f"Validation run {id} not found on current " f"QA4SM instance.") super().__init__(self.message)
[docs] class ValidationRunError(Exception): def __init__(self, message="Validation run failed"): self.message = message super().__init__(self.message)
[docs] class ValidationInstanceError(KeyError): def __init__(self, message="Unknown validation instance"): self.message = message super().__init__(self.message)
[docs] class AuthenticationError(ValueError): def __init__(self, message="No API token is available for this user. " "Please generate one."): self.message = message super().__init__(self.message)
def _write_dotrc(config: dict, path=QA4SM_DOTRC_PATH): """ Write credentials to a .qa4smapirc file. Parameters ---------- config : dict Credentials keyed by hostname, e.g.: { "qa4sm.eu": {"token": "...", "username": "..."}, "test.qa4sm.eu": {"token": "..."}, } path : str or Path, optional Path to the .qa4smapirc file """ with open(path, 'w') as f: for host, fields in config.items(): f.write(f'[{host}]\n') for key, value in fields.items(): f.write(f'{key}: {value}\n') f.write('\n') def _load_dotrc(path=QA4SM_DOTRC_PATH): """ Read credentials from a .qa4smapirc file. Parameters ---------- path : str or Path, optional Path to the .qa4smapirc file Returns ------- config : dict Credentials keyed by hostname, e.g.: { "qa4sm.eu": {"token": "..."}, "test.qa4sm.eu": {"token": "..."}, } Sections named 'default' or 'qa4sm' both map to 'qa4sm.eu'. All other section names (e.g. 'test', 'test2') map to '<name>.qa4sm.eu'. """ path = Path(path) if not path.exists(): raise FileNotFoundError(f'QA4SM credentials file not found at {path}. ' f'Please check https://qa4sm.eu/ui/public-api') PRODUCTION_SECTIONS = {"default", "qa4sm", "qa4sm.eu"} def section_to_host(section: str) -> str: return "qa4sm.eu" if section.lower() in PRODUCTION_SECTIONS \ else section parser = configparser.ConfigParser() parser.read(path) config = {} # Handle DEFAULT first — named sections will override it if they resolve # to the same host (e.g. [qa4sm] overrides [DEFAULT] for 'qa4sm.eu') if parser.defaults(): config[section_to_host("default")] = dict(parser.defaults()) for section in parser.sections(): config[section_to_host(section)] = dict(parser[section]) return config def _connect_with_credentials(instance: str, username: str, password: str, quiet: bool = True) -> dict: """ Open a Session to the given instance, authenticate with username/password, and return the auth token. """ # Import here so the CLI works even if the rest of the package isn't # fully installed — errors surface only when login is actually attempted. from qa4sm_api.client_api import Session with warnings.catch_warnings(): warnings.simplefilter("ignore", UserWarning) session = Session(instance=instance, token="none", quiet_login=quiet) _ = session.login_with_credentials( username=username, password=password) access = session.access.access return access
[docs] def make_dummy_ok_response(json_data: dict = None, text: str = "", status_code: int = 200) -> requests.Response: response = requests.models.Response() response.status_code = status_code response.headers["Content-Type"] = "application/json" response._content = (text or "").encode("utf-8") return response