From f31d99099acb5b8463686ac91891ed09ab212970 Mon Sep 17 00:00:00 2001
From: PGijsbers
Date: Fri, 20 Feb 2026 11:27:06 +0100
Subject: [PATCH 1/7] Update docker image structure to match new convention
---
docker-compose.yaml | 3 +++
docker/python/Dockerfile | 9 +++++++--
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/docker-compose.yaml b/docker-compose.yaml
index e0e76721..3541fee5 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -78,5 +78,8 @@ services:
- "8001:8000"
volumes:
- .:/python-api
+ - ./src/config.toml:/config/config.toml
+ environment:
+ OPENML_REST_API_CONFIG_DIRECTORY: "/config"
depends_on:
- database
diff --git a/docker/python/Dockerfile b/docker/python/Dockerfile
index 87516ed3..279be15a 100644
--- a/docker/python/Dockerfile
+++ b/docker/python/Dockerfile
@@ -5,16 +5,21 @@ RUN apt-get update \
ENV VIRTUAL_ENV=/opt/venv
RUN python -m venv $VIRTUAL_ENV
+# Prepending the path here means that `python` invocations below use the virtual environment
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
RUN python -m pip install uv
-WORKDIR /python-api
+WORKDIR /app
COPY pyproject.toml .
RUN uv pip install -e ".[dev]"
-COPY . /python-api
+COPY . /app
+RUN mkdir /config
+COPY ./src/config.toml /config/config.toml
+ENV OPENML_REST_API_CONFIG_FILE_PATH=/config/config.toml
+COPY ./docker/python/README.md /README.md
EXPOSE 8000
ENTRYPOINT ["python", "src/main.py"]
From aeafc8a9c367cde29d5283f18ff7540246ab956c Mon Sep 17 00:00:00 2001
From: PGijsbers
Date: Fri, 20 Feb 2026 11:39:21 +0100
Subject: [PATCH 2/7] Make configuration and dot files configurable
---
src/config.py | 41 ++++++++++++++++++++++++++++++++---------
1 file changed, 32 insertions(+), 9 deletions(-)
diff --git a/src/config.py b/src/config.py
index 0712271b..2d49246e 100644
--- a/src/config.py
+++ b/src/config.py
@@ -1,4 +1,5 @@
import functools
+import logging
import os
import tomllib
import typing
@@ -6,9 +7,32 @@
from dotenv import load_dotenv
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
TomlTable = dict[str, typing.Any]
-CONFIG_PATH = Path(__file__).parent / "config.toml"
+CONFIG_DIRECTORY_ENV = "OPENML_REST_API_CONFIG_DIRECTORY"
+CONFIG_FILE_ENV = "OPENML_REST_API_CONFIG_FILE"
+DOTENV_FILE_ENV = "OPENML_REST_API_DOTENV_FILE"
+
+OPENML_DB_USERNAME_ENV = "OPENML_DATABASES_OPENML_USERNAME"
+OPENML_DB_PASSWORD_ENV = "OPENML_DATABASES_OPENML_PASSWORD" # noqa: S105 # not a password
+EXPDB_DB_USERNAME_ENV = "OPENML_DATABASES_EXPDB_USERNAME"
+EXPDB_DB_PASSWORD_ENV = "OPENML_DATABASES_EXPDB_PASSWORD" # noqa: S105 # not a password
+
+_config_directory = Path(os.getenv(CONFIG_DIRECTORY_ENV, Path(__file__).parent))
+_config_directory = _config_directory.expanduser().absolute()
+_config_file = Path(os.getenv(CONFIG_FILE_ENV, _config_directory / "config.toml"))
+_config_file = _config_file.expanduser().absolute()
+_dotenv_file = Path(os.getenv(DOTENV_FILE_ENV, _config_directory / ".env"))
+_dotenv_file = _dotenv_file.expanduser().absolute()
+
+logger.info("Configuration directory is '%s'", _config_directory)
+logger.info("Loading configuration file from '%s'", _config_file)
+logger.info("Loading environment variables from '%s'", _dotenv_file)
+
+load_dotenv(dotenv_path=_dotenv_file)
def _apply_defaults_to_siblings(configuration: TomlTable) -> TomlTable:
@@ -25,35 +49,34 @@ def _load_configuration(file: Path) -> TomlTable:
return tomllib.loads(file.read_text())
-def load_routing_configuration(file: Path = CONFIG_PATH) -> TomlTable:
+def load_routing_configuration(file: Path = _config_file) -> TomlTable:
return typing.cast("TomlTable", _load_configuration(file)["routing"])
@functools.cache
-def load_database_configuration(file: Path = CONFIG_PATH) -> TomlTable:
+def load_database_configuration(file: Path = _config_file) -> TomlTable:
configuration = _load_configuration(file)
database_configuration = _apply_defaults_to_siblings(
configuration["databases"],
)
- load_dotenv()
database_configuration["openml"]["username"] = os.environ.get(
- "OPENML_DATABASES_OPENML_USERNAME",
+ OPENML_DB_USERNAME_ENV,
"root",
)
database_configuration["openml"]["password"] = os.environ.get(
- "OPENML_DATABASES_OPENML_PASSWORD",
+ OPENML_DB_PASSWORD_ENV,
"ok",
)
database_configuration["expdb"]["username"] = os.environ.get(
- "OPENML_DATABASES_EXPDB_USERNAME",
+ EXPDB_DB_USERNAME_ENV,
"root",
)
database_configuration["expdb"]["password"] = os.environ.get(
- "OPENML_DATABASES_EXPDB_PASSWORD",
+ EXPDB_DB_PASSWORD_ENV,
"ok",
)
return database_configuration
-def load_configuration(file: Path = Path(__file__).parent / "config.toml") -> TomlTable:
+def load_configuration(file: Path = _config_file) -> TomlTable:
return tomllib.loads(file.read_text())
From 2d42e9a4909befd3ebd463e8fbbb68883f9a5293 Mon Sep 17 00:00:00 2001
From: PGijsbers
Date: Fri, 20 Feb 2026 11:48:01 +0100
Subject: [PATCH 3/7] Push docker readme file to Docker Hub on publish
---
.github/workflows/docker-publish.yml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml
index 414ca12d..5f6143e5 100644
--- a/.github/workflows/docker-publish.yml
+++ b/.github/workflows/docker-publish.yml
@@ -48,3 +48,12 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
+
+ - name: Docker Hub Description
+ uses: peter-evans/dockerhub-description@v5
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_PASSWORD }}
+ repository: openml/rest-api
+ short-description: "Experimental OpenML REST API"
+ readme-filepath: docker/python/README.md
From 26891c91e0840e1791373ec21755f3e0e9c1b61f Mon Sep 17 00:00:00 2001
From: PGijsbers
Date: Fri, 20 Feb 2026 11:52:24 +0100
Subject: [PATCH 4/7] Add a README for the docker image
---
docker/python/README.md | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 docker/python/README.md
diff --git a/docker/python/README.md b/docker/python/README.md
new file mode 100644
index 00000000..a9671dfd
--- /dev/null
+++ b/docker/python/README.md
@@ -0,0 +1,32 @@
+# OpenML REST API
+This is the work-in-progress Python-based REST API implementation for OpenML.
+This should not be considered production ready.
+New releases may contain breaking changes without deprecation warnings.
+
+## Usage
+The image is not inteded to be used as a standalone image.
+Please reference either the docker compose file at [server-api](https://www.github.com/openml/server-api) for development purposes, or [services](https://www.github.com/openml/services) for deployment purposes.
+
+## Configuration
+Configuration is currently loaded from both a TOML file and a .env file.
+Environment variables are used for configurations that either shouldn't be shared (secrets), or that inform how to load the configuration.
+The TOML configuration file is used for all other settings.
+By default both of these files are loaded from the `/config` directory.
+
+### Configuration File
+A default configuration is available for reference at `/config/config.toml`, and can be used as reference.
+
+### Environment Variables
+Environment variables are used for configurations that either shouldn't be shared (secrets), or that inform how to load the configuration:
+
+ - `OPENML_REST_API_CONFIG_DIRECTORY`: points to the directory that contains configuration files (`config.toml`, `.env`) (default: `/config`)
+ - `OPENML_REST_API_CONFIG_FILE`: points to the file that contains the TOML configuration (default: not set). If set, takes precedence over `OPENML_REST_API_CONFIG_DIRECTORY`.
+ - `OPENML_REST_API_DOTENV_FILE`: points to the dot file that contains the environment variable settings (default: not set). If set, takes precedence over `OPENML_REST_API_CONFIG_DIRECTORY`.
+ - `OPENML_DATABASES_OPENML_USERNAME`: username for connecting to the `openml` database (default: `root`)
+ - `OPENML_DATABASES_OPENML_PASSWORD`: password for connecting to the `openml` database (default: `ok`)
+ - `OPENML_DATABASES_EXPDB_USERNAME`: username for connecting to the `openml_expdb` database (default: `root`)
+ - `OPENML_DATABASES_EXPDB_PASSWORD`: password for connecting to the `openml_expdb` database (default: `ok`)
+
+
+## Repository
+The code and dockerfile for this image are maintained [on GitHub](https://www.github.com/openml/server-api).
From 9e26db9af37bc3425e7ef7615617e6533ca296de Mon Sep 17 00:00:00 2001
From: PGijsbers
Date: Fri, 20 Feb 2026 12:02:31 +0100
Subject: [PATCH 5/7] Update variable name after rename
---
docker/python/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docker/python/Dockerfile b/docker/python/Dockerfile
index 279be15a..2837e165 100644
--- a/docker/python/Dockerfile
+++ b/docker/python/Dockerfile
@@ -18,7 +18,7 @@ COPY . /app
RUN mkdir /config
COPY ./src/config.toml /config/config.toml
-ENV OPENML_REST_API_CONFIG_FILE_PATH=/config/config.toml
+ENV OPENML_REST_API_CONFIG_FILE=/config/config.toml
COPY ./docker/python/README.md /README.md
EXPOSE 8000
From 5cf246e67cf8ea33c96dac07206e918aa1f65ab2 Mon Sep 17 00:00:00 2001
From: PGijsbers
Date: Fri, 20 Feb 2026 12:03:16 +0100
Subject: [PATCH 6/7] fix typo
---
docker/python/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docker/python/README.md b/docker/python/README.md
index a9671dfd..d17f5063 100644
--- a/docker/python/README.md
+++ b/docker/python/README.md
@@ -4,7 +4,7 @@ This should not be considered production ready.
New releases may contain breaking changes without deprecation warnings.
## Usage
-The image is not inteded to be used as a standalone image.
+The image is not intended to be used as a standalone image.
Please reference either the docker compose file at [server-api](https://www.github.com/openml/server-api) for development purposes, or [services](https://www.github.com/openml/services) for deployment purposes.
## Configuration
From db431b1d2553920bab2957dff8746e7273d55b8e Mon Sep 17 00:00:00 2001
From: PGijsbers
Date: Fri, 20 Feb 2026 12:12:52 +0100
Subject: [PATCH 7/7] Minor fixes
---
docker-compose.yaml | 2 +-
src/config.py | 1 -
src/main.py | 2 ++
3 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 3541fee5..e93b548b 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -77,7 +77,7 @@ services:
ports:
- "8001:8000"
volumes:
- - .:/python-api
+ - .:/app
- ./src/config.toml:/config/config.toml
environment:
OPENML_REST_API_CONFIG_DIRECTORY: "/config"
diff --git a/src/config.py b/src/config.py
index 2d49246e..4a234a51 100644
--- a/src/config.py
+++ b/src/config.py
@@ -7,7 +7,6 @@
from dotenv import load_dotenv
-logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
TomlTable = dict[str, typing.Any]
diff --git a/src/main.py b/src/main.py
index d8e61b34..560b4c50 100644
--- a/src/main.py
+++ b/src/main.py
@@ -1,4 +1,5 @@
import argparse
+import logging
import uvicorn
from fastapi import FastAPI
@@ -58,6 +59,7 @@ def create_api() -> FastAPI:
def main() -> None:
+ logging.basicConfig(level=logging.INFO)
args = _parse_args()
uvicorn.run(
app="main:create_api",