bug: devcontainers uses an old debian version with no non-EOL python header libs
Describe the bug
The devcontainers config cannot be used for python development. mcr.microsoft.com/devcontainers/rust:bullseye is based on debian bullseye, which only has libpython*-dev up to v3.9, which is EOL. Microsoft provides a rust devcontainer image for bookworm, but that isn't much better, only going up to 3.11. However, this may be workable because the python bindings use the abi3-py311 target. If so, the uv config needs to be updated to lock the python version used in the dev environment, as currently it installs the latest (3.14).
Steps to Reproduce
- Create a fresh devcontainer
cd bindings/pythonjust setup(installs python 3.14)uv run just test: fails to generate type stubs due to missing header libraries
Expected Behavior
The devcontainer should include all tools necessary for development.
Additional Context
Changing the base image of the devcontainer could cause problems across many other regions of the monorepo and needs thorough testing.
Are you willing to submit a PR to fix this bug?
- [ ] Yes, I would like to submit a PR.
The root cause is that the devcontainer installs Python 3.14, but the base image (Debian Bullseye or Bookworm) only provides Python header libraries up to 3.9 or 3.11, which are EOL and incompatible with the latest Python. This breaks Python bindings development, especially since the project targets the abi3-py311 ABI and has officially moved to Python 3.11 as the base version for bindings going forward [source][discussion].
To work around this without changing the base image (which could have broad impact), pin the Python version in the devcontainer to 3.11 and update the uv configuration to match. This can be done by installing Python 3.11 explicitly (for example, using pyenv or by adding installation steps in the Dockerfile) and ensuring that just and uv use this version for all Python-related tasks. This aligns with the project's current support policy and should resolve the missing header issue.
Changing the base image is a larger change and would require thorough testing across the monorepo, so pinning Python 3.11 is the safest immediate fix.
To reply, just mention @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
@clbarnes instead of uv run just test you should be running something like
OPENDAL_TEST=fs OPENDAL_FS_ROOT=/tmp just test
I was using just test (noted in my steps to reproduce). Either way, it doesn't matter because the task fails during the stub-gen dependency task, which is where it first goes looking for the libpython headers.
the setup goal is configured to not rely on installed python version, uv downloads and manages the python version by itself. not sure what the issue is
see: https://github.com/apache/opendal/blob/ca92fc91dceb4458d8843b3cee2242c3f2a9611f/bindings/python/justfile#L35
maybe a .python-version with 3.12 can be added to the root of python bindings?
uv downloads python (the runtime) but not the C(++?) headers which pyo3 needs to link against during compilation; those are usually installed by the OS' package manager. In this case, the OS used by the devcontainer does not have packages available for in-date versions of the headers. It's not a python version problem, it's a host OS problem. The devcontainer post_create.sh installes python3-dev, but on debian bullseye (the image used by the devcontainer) that's python 3.9 (EOL), and on bookworm it's 3.11. The bookworm version might solve the issue, as I noted above, because the pyo3 build targets abi3-py311, the common subset of the the ABI available to python 3.11+.
Actually it looks like there is a trixie-based devcontainer, it just wasn't documented. That has headers for python 3.13.
apt-key is deprecated for security reasons, which means the PHP repo-adding lines fail on trixie. The replacement for apt-key is not obvious, but probably involves apt-manage from PopOS' RepoLib. Of course, that's from a repo too, which has the same problems, unless you use the quick install script, i.e. curl ... | sudo bash, which is a bigger ask.
Alternatively, extrepo.
ocamlformat then fails to compile
[ERROR] The compilation of ocamlformat-lib.0.28.1 failed at "dune build -p ocamlformat-lib -j 9 @install".
#=== ERROR while compiling ocamlformat-lib.0.28.1 =============================#
# context 2.3.0 | linux/arm64 | ocaml.5.3.0 | https://opam.ocaml.org#c65fcb116531ae66ad3316b265e233443ef25044
# path ~/.opam/default/.opam-switch/build/ocamlformat-lib.0.28.1
# command ~/.opam/default/bin/dune build -p ocamlformat-lib -j 9 @install
# exit-code 1
# env-file ~/.opam/log/ocamlformat-lib-51719-ba298c.env
# output-file ~/.opam/log/ocamlformat-lib-51719-ba298c.out
### output ###
# (cd _build/default && /usr/bin/ocamlc.opt -w -40 -noassert -w -50 -open Ocamlformat_parser_shims -g -bin-annot -bin-annot-occurrences -I vendor/odoc-parser/.ocamlformat_odoc_parser.objs/byte -I /home/vscode/.opam/default/lib/astring -I /usr/lib/aarch64-linux-gnu/ocaml/5.3.0/camlp-streams -I /usr/lib/aarch64-linux-gnu/ocaml/5.3.0/compiler-libs -I vendor/parser-shims/.ocamlformat_parser_shims.o[...]
# File "vendor/odoc-parser/syntax.mli", line 5, characters 28-36:
# 5 | Token.t Loc.with_location Stream.t ->
# ^^^^^^^^
# Error: Unbound module "Stream"
<><> Error report <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
┌─ The following actions failed
│ λ build ocamlformat-lib 0.28.1
└─
Another problem is dmd; it seems snaps are preferred now (but presumably not in a docker container...). Following this guide https://lindevs.com/install-dmd-on-ubuntu hits issues at the sudo apt install -y ./dmd.deb stage due to missing dependencies.
Note, selecting 'dmd:amd64' instead of './dmd.deb'
Solving dependencies... Error!
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:
Unsatisfied dependencies:
dmd:amd64 : Depends: libc6:amd64 but it is not installable
Depends: libc6-dev:amd64 but it is not installable
Depends: gcc:amd64 but it is not installable
Depends: libgcc1:amd64 but it is not installable
Depends: libstdc++6:amd64 but it is not installable
Depends: libcurl4:amd64 but it is not installable or
libcurl3:amd64 but it is not installable
Error: Unable to correct problems, you have held broken packages.
Error: The following information from --solver 3.0 may provide additional context:
Unable to satisfy dependencies. Reached two conflicting decisions:
1. dmd:amd64=2.111.0-0 is selected for install
2. dmd:amd64 Depends libc6:amd64
but none of the choices are installable:
[no choices]
Covering all bindings can be somewhat challenging. Would it be possible for us to set up separate dev containers for different bindings? For example, one for core, one for Python, and another for Java?
Yes, that seems like a good idea. It's unlikely that many people will be contributing to many languages at once, and the monolithic devcontainer takes quite a while to set up. On the other hand, it would be useful to know if changes in core broke functionality in any of the bindings, but CI is equally good at that.