Skip to content

opensampl.config.base

Pydantic BaseSettings Object used to access and set the openSAMPL configuration options.

This module provides the main configuration class for openSAMPL, handling environment variables, configuration validation, and settings management.

BaseConfig

Bases: BaseSettings

Primary configuration settings for the opensampl cli.

Handles all configuration options including routing, database connections, logging, and API access settings.

Source code in opensampl/config/base.py
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
class BaseConfig(BaseSettings):
    """
    Primary configuration settings for the opensampl cli.

    Handles all configuration options including routing, database connections,
    logging, and API access settings.
    """

    model_config = SettingsConfigDict(env_file=".env", extra="ignore", env_nested_delimiter="__")
    env_file: Path = Field(description="Path to the env file to get variables from.")

    ROUTE_TO_BACKEND: bool = Field(
        False, description="URL of the backend service when routing is enabled", alias="ROUTE_TO_BACKEND"
    )
    BACKEND_URL: Optional[str] = Field(
        None, description="URL of the backend service when routing is enabled", alias="BACKEND_URL"
    )
    DATABASE_URL: Optional[str] = Field(None, description="URL for direct database connections", alias="DATABASE_URL")
    ARCHIVE_PATH: Path = Field(
        Path("archive"),
        description="Default path that files are moved to after they have been processed",
        alias="ARCHIVE_PATH",
    )
    LOG_LEVEL: str = Field("INFO", description="Log level for opensampl cli", alias="LOG_LEVEL")
    API_KEY: Optional[str] = Field(None, description="Access key for interacting with the backend", alias="API_KEY")
    INSECURE_REQUESTS: bool = Field(
        False, description="Allow insecure requests to be made to the backend", alias="INSECURE_REQUESTS"
    )

    @field_serializer("ARCHIVE_PATH")
    def convert_to_str(self, v: Path) -> str:
        """Convert archive path to a string for serialization"""
        return str(v.resolve())

    @property
    def _ignore_in_set(self) -> list[str]:
        """The fields to ignore when setting the configuration."""
        return ["env_file"]

    def __init__(self, **kwargs: Any):
        """
        Record the env file set in object creation before proceeding to super().__init__.

        Required because the default pydantic-settings behavior is not to store the filepath in the object.

        Args:
            **kwargs: Keyword arguments including env_file path configuration.

        """
        _env_file = kwargs.get("_env_file")
        env_file = kwargs.get("env_file")
        if _env_file:
            resolved_env_file = Path(_env_file)
        elif env_file is not None:
            resolved_env_file = Path(env_file)
            kwargs["_env_file"] = env_file
        else:
            fallback = self.model_config.get("env_file")
            resolved_env_file = Path(fallback) if fallback else None
        kwargs["env_file"] = resolved_env_file
        super().__init__(**kwargs)

    def get_by_name(self, name: str):
        """
        Return the field info object for the given model.

        Args:
            name: Name of the configuration field.

        Returns:
            Field info object if found, None otherwise.

        """
        return self.model_fields.get(name, None)

    def set_by_name(self, name: str, value: Any):
        """
        Set setting's value in the env file for current instance.

        Args:
            name: Name of the configuration setting.
            value: Value to set for the setting.

        Raises:
            ValueError: If the setting name is not found.

        """
        setting = self.get_by_name(name)
        if setting is None:
            raise ValueError(f"Setting {name} not found")

        if not self.env_file.is_file():
            logger.info("Env file does not exist. Creating one to save setting.")
            self.env_file.touch()

        set_key(self.env_file, name, str(value))

    def save_config(self, values: Optional[list[str]] = None):
        """
        Save the current env configuration.

        If values are provided, it will only encode the ones listed.
        Otherwise, will save all of them.

        Args:
            values: Optional list of setting names to save. If None, saves all settings.

        """
        if values is None:
            values_dict = self.model_dump(exclude=set(self._ignore_in_set))
        else:
            values_dict = self.model_dump(include=set(values))
        logger.debug(f"setting the following variables in env: {values_dict}")
        for key, val in values_dict.items():
            self.set_by_name(name=key, value=val)

    def check_routing_dependencies(self) -> "BaseConfig":
        """
        Ensure required URL (backend or database) is configured for routing option.

        Returns:
            Self for method chaining.

        Raises:
            ValueError: If required URLs are not configured for the current routing option.

        """
        if self.ROUTE_TO_BACKEND and not self.BACKEND_URL:
            raise ValueError("BACKEND_URL must be set if ROUTE_TO_BACKEND is True")
        if not self.ROUTE_TO_BACKEND and not self.DATABASE_URL:
            raise ValueError("DATABASE_URL must be set if ROUTE_TO_BACKEND is False")
        return self

__init__(**kwargs)

Record the env file set in object creation before proceeding to super().init.

Required because the default pydantic-settings behavior is not to store the filepath in the object.

Parameters:

Name Type Description Default
**kwargs Any

Keyword arguments including env_file path configuration.

{}
Source code in opensampl/config/base.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def __init__(self, **kwargs: Any):
    """
    Record the env file set in object creation before proceeding to super().__init__.

    Required because the default pydantic-settings behavior is not to store the filepath in the object.

    Args:
        **kwargs: Keyword arguments including env_file path configuration.

    """
    _env_file = kwargs.get("_env_file")
    env_file = kwargs.get("env_file")
    if _env_file:
        resolved_env_file = Path(_env_file)
    elif env_file is not None:
        resolved_env_file = Path(env_file)
        kwargs["_env_file"] = env_file
    else:
        fallback = self.model_config.get("env_file")
        resolved_env_file = Path(fallback) if fallback else None
    kwargs["env_file"] = resolved_env_file
    super().__init__(**kwargs)

check_routing_dependencies()

Ensure required URL (backend or database) is configured for routing option.

Returns:

Type Description
BaseConfig

Self for method chaining.

Raises:

Type Description
ValueError

If required URLs are not configured for the current routing option.

Source code in opensampl/config/base.py
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def check_routing_dependencies(self) -> "BaseConfig":
    """
    Ensure required URL (backend or database) is configured for routing option.

    Returns:
        Self for method chaining.

    Raises:
        ValueError: If required URLs are not configured for the current routing option.

    """
    if self.ROUTE_TO_BACKEND and not self.BACKEND_URL:
        raise ValueError("BACKEND_URL must be set if ROUTE_TO_BACKEND is True")
    if not self.ROUTE_TO_BACKEND and not self.DATABASE_URL:
        raise ValueError("DATABASE_URL must be set if ROUTE_TO_BACKEND is False")
    return self

convert_to_str(v)

Convert archive path to a string for serialization

Source code in opensampl/config/base.py
46
47
48
49
@field_serializer("ARCHIVE_PATH")
def convert_to_str(self, v: Path) -> str:
    """Convert archive path to a string for serialization"""
    return str(v.resolve())

get_by_name(name)

Return the field info object for the given model.

Parameters:

Name Type Description Default
name str

Name of the configuration field.

required

Returns:

Type Description

Field info object if found, None otherwise.

Source code in opensampl/config/base.py
79
80
81
82
83
84
85
86
87
88
89
90
def get_by_name(self, name: str):
    """
    Return the field info object for the given model.

    Args:
        name: Name of the configuration field.

    Returns:
        Field info object if found, None otherwise.

    """
    return self.model_fields.get(name, None)

save_config(values=None)

Save the current env configuration.

If values are provided, it will only encode the ones listed. Otherwise, will save all of them.

Parameters:

Name Type Description Default
values Optional[list[str]]

Optional list of setting names to save. If None, saves all settings.

None
Source code in opensampl/config/base.py
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
def save_config(self, values: Optional[list[str]] = None):
    """
    Save the current env configuration.

    If values are provided, it will only encode the ones listed.
    Otherwise, will save all of them.

    Args:
        values: Optional list of setting names to save. If None, saves all settings.

    """
    if values is None:
        values_dict = self.model_dump(exclude=set(self._ignore_in_set))
    else:
        values_dict = self.model_dump(include=set(values))
    logger.debug(f"setting the following variables in env: {values_dict}")
    for key, val in values_dict.items():
        self.set_by_name(name=key, value=val)

set_by_name(name, value)

Set setting's value in the env file for current instance.

Parameters:

Name Type Description Default
name str

Name of the configuration setting.

required
value Any

Value to set for the setting.

required

Raises:

Type Description
ValueError

If the setting name is not found.

Source code in opensampl/config/base.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
def set_by_name(self, name: str, value: Any):
    """
    Set setting's value in the env file for current instance.

    Args:
        name: Name of the configuration setting.
        value: Value to set for the setting.

    Raises:
        ValueError: If the setting name is not found.

    """
    setting = self.get_by_name(name)
    if setting is None:
        raise ValueError(f"Setting {name} not found")

    if not self.env_file.is_file():
        logger.info("Env file does not exist. Creating one to save setting.")
        self.env_file.touch()

    set_key(self.env_file, name, str(value))