From ada16532051fe3ae637e7ea28a89e50bb263b737 Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Wed, 22 Nov 2023 17:12:22 +0000 Subject: [PATCH 01/11] Add a new version of the python image. This new version is based on 22.04 and python3.10, and has an up to date version of all python packages. The versioning scheme is arbitrary major version, e.g. v1, v2, etc. The previous image is retained as v1, and the new image is v2. This move from maintaining 1 to 2 images requires some refactoring. Each major version has its own directory, and associated configuration files to track dependencies. They both share the same parameterised `Dockerfile` and `docker-compose.yaml`. In the process, I have also improved the local development tooling: - move from Makefile to parameterised justfile - some small reording of Dockerfile steps for efficiency and reuse - a proper solution for user the docker images themselves to add new dependencies and/or upgrade existing ones. This means you a) do not need all the python versions installed on your machine and b) this can be built on macos, in theory. --- Dockerfile | 56 +- Makefile | 35 - docker-compose.yml | 26 +- justfile | 40 ++ tests/test_import.py | 34 +- .../build-dependencies.txt | 0 dependencies.txt => v1/dependencies.txt | 0 v1/env | 2 + requirements.in => v1/requirements.in | 0 requirements.txt => v1/requirements.txt | 61 +- v2/build-dependencies.txt | 10 + v2/dependencies.txt | 15 + v2/env | 2 + v2/requirements.in | 39 ++ v2/requirements.txt | 643 ++++++++++++++++++ 15 files changed, 865 insertions(+), 98 deletions(-) delete mode 100644 Makefile create mode 100644 justfile rename build-dependencies.txt => v1/build-dependencies.txt (100%) rename dependencies.txt => v1/dependencies.txt (100%) create mode 100644 v1/env rename requirements.in => v1/requirements.in (100%) rename requirements.txt => v1/requirements.txt (88%) create mode 100644 v2/build-dependencies.txt create mode 100644 v2/dependencies.txt create mode 100644 v2/env create mode 100644 v2/requirements.in create mode 100644 v2/requirements.txt diff --git a/Dockerfile b/Dockerfile index 6de34b7..5ccef52 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,34 +8,48 @@ # and b) we specifically always want to build on the latest base image, by # design. # +ARG BASE # hadolint ignore=DL3007 -FROM ghcr.io/opensafely-core/base-action:latest as base-python -COPY dependencies.txt /root/dependencies.txt +FROM ghcr.io/opensafely-core/base-action:$BASE as base-python + +RUN mkdir /workspace +WORKDIR /workspace + +ARG MAJOR_VERSION +# ACTION_EXEC sets the default executable for the entrypoint in the base-docker image +ENV ACTION_EXEC=python MAJOR_VERSION=${MAJOR_VERSION} + +COPY ${MAJOR_VERSION}/dependencies.txt /root/dependencies.txt # use space efficient utility from base image RUN /root/docker-apt-install.sh /root/dependencies.txt +# now we have python, set up a venv to install packages to, for isolation from +# system python libraries +# hadolint ignore=DL3059 +RUN python3 -m venv /opt/venv +# "activate" the venv +ENV VIRTUAL_ENV=/opt/venv/ PATH="/opt/venv/bin:$PATH" +# We ensure up-to-date build tools (which why we ignore DL3013) +# hadolint ignore=DL3013,DL3042 +RUN --mount=type=cache,target=/root/.cache python -m pip install -U pip setuptools wheel pip-tools + + ################################################# # # Next, use the base-docker-plus-python image to create a build image FROM base-python as builder +ARG MAJOR_VERSION # install build time dependencies -COPY build-dependencies.txt /root/build-dependencies.txt +COPY ${MAJOR_VERSION}/build-dependencies.txt /root/build-dependencies.txt RUN /root/docker-apt-install.sh /root/build-dependencies.txt -# install everything in venv for isolation from system python libraries -# hadolint ignore=DL3059 -RUN python3 -m venv /opt/venv -ENV VIRTUAL_ENV=/opt/venv/ PATH="/opt/venv/bin:$PATH" LLVM_CONFIG=/usr/bin/llvm-config-10 - -COPY requirements.txt /root/requirements.txt -# We ensure up-to-date build tools (which why we ignore DL3013) +COPY ${MAJOR_VERSION}/requirements.txt /root/requirements.txt # Note: the mount command does two things: 1) caches across builds to speed up # local development and 2) ensures the pip cache does not get committed to the # layer (which is why we ignore DL3042). -# hadolint ignore=DL3013,DL3042 +# hadolint ignore=DL3042 RUN --mount=type=cache,target=/root/.cache \ - python -m pip install -U pip setuptools wheel && \ python -m pip install --requirement /root/requirements.txt ################################################ @@ -43,26 +57,26 @@ RUN --mount=type=cache,target=/root/.cache \ # Finally, build the actual image from the base-python image FROM base-python as python + +ARG MAJOR_VERSION # Some static metadata for this specific image, as defined by: # https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys # The org.opensafely.action label is used by the jobrunner to indicate this is # an approved action image to run. -LABEL org.opencontainers.image.title="python" \ +LABEL org.opencontainers.image.title="python:${MAJOR_VERSION}" \ org.opencontainers.image.description="Python action for opensafely.org" \ org.opencontainers.image.source="https://github.com/opensafely-core/python-docker" \ - org.opensafely.action="python" + org.opensafely.action="python:${MAJOR_VERSION}" # copy venv over from builder image COPY --from=builder /opt/venv /opt/venv -# ACTION_EXEC sets the default executable for the entrypoint in the base-docker image -ENV VIRTUAL_ENV=/opt/venv/ PATH="/opt/venv/bin:$PATH" ACTION_EXEC=python - -RUN mkdir /workspace -WORKDIR /workspace -# tag with build info as the very last step, as it will never be cached +# tag with build info as the very last step, as it will never be cacheable ARG BUILD_DATE ARG REVISION +ARG BUILD_NUMBER # RFC 3339. LABEL org.opencontainers.image.created=$BUILD_DATE \ - org.opencontainers.image.revision=$REVISION + org.opencontainers.image.revision=$REVISION \ + org.opencontainers.image.build=$BUILD_NUMBER \ + org.opencontainers.image.version=$MAJOR_VERSION.$BUILD_NUMBER diff --git a/Makefile b/Makefile deleted file mode 100644 index 3816bc8..0000000 --- a/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -INTERACTIVE:=$(shell [ -t 0 ] && echo 1) -export DOCKER_BUILDKIT=1 -export BUILD_DATE=$(shell date +'%y-%m-%dT%H:%M:%S.%3NZ') -export REVISION=$(shell git rev-parse --short HEAD) - -.PHONY: build -build: - docker-compose build --pull python - - -.PHONY: test -test: - docker-compose run --rm -v $(PWD):/workspace python pytest tests -v - -# test basic python invocation -functional-test: - docker-compose run --rm python -c '' - docker-compose run --rm python python -c '' - - -.PHONY: lint -lint: - @docker pull hadolint/hadolint:v2.8.0 - @docker run --rm -i hadolint/hadolint:v2.8.0 < Dockerfile - -requirements.txt: requirements.in venv/bin/pip-compile - venv/bin/pip-compile requirements.in - -venv/bin/pip-compile: | venv - venv/bin/pip install pip-tools - -venv: - virtualenv -p python3 venv - - diff --git a/docker-compose.yml b/docker-compose.yml index a9751fa..e9f4f17 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,26 @@ services: - # used to build the production image - python: - image: python + base: + init: true + image: python:${MAJOR_VERSION}-base build: context: . - target: python + target: base-python cache_from: # should speed up the build in CI, where we have a cold cache - - ghcr.io/opensafely-core/base-docker - - ghcr.io/opensafely-core/python + - ghcr.io/opensafely-core/base-action:${BASE} + - ghcr.io/opensafely-core/python:${MAJOR_VERSION} args: # this makes the image work for later cache_from: usage - BUILDKIT_INLINE_CACHE=1 - # env vars supplied by make/just + # env vars supplied by just + - BUILD_NUMBER - BUILD_DATE - REVISION - - VERSION - init: true + - BASE + - MAJOR_VERSION + + python: + extends: + service: base + image: python:${MAJOR_VERSION} + build: + target: python diff --git a/justfile b/justfile new file mode 100644 index 0000000..310f12e --- /dev/null +++ b/justfile @@ -0,0 +1,40 @@ +export DOCKER_BUILDKIT := "1" +export BUILD_DATE := `date +'%y-%m-%dT%H:%M:%S.%3NZ'` +export REVISION := `git rev-parse --short HEAD` + +# TODO: calculate this +export BUILD_NUMBER := "1234" + +build version target="python" *args="": + docker-compose --env-file {{ version }}/env build --pull {{ args }} {{ target }} + +test version *args="tests -v": + docker-compose --env-file {{ version }}/env run --rm -v $PWD:/workspace python pytest {{ args }} + +update version *args="": + docker-compose --env-file {{ version }}/env run --rm -v $PWD:/workspace base pip-compile {{ args }} {{ version }}/requirements.in -o {{ version }}/requirements.txt + +check: + @docker pull hadolint/hadolint:v2.12.0 + @docker run --rm -i hadolint/hadolint:v2.12.0 < Dockerfile + +publish version: + #!/bin/bash + set -euxo pipefail + docker tag python:{{ version }} ghcr.io/opensafely-core/python:{{ version }} + echo docker push ghcr.io/opensafely-core/python:{{ version }} + + if test "{{ version }}" = "v1"; then + # jupyter is only alias for v1 + docker tag python:{{ version }} ghcr.io/opensafely-core/jupyter:{{ version }} + echo docker push ghcr.io/opensafely-core/jupyter:{{ version }} + + # v1 is also known as latest, at least until we transition fully + docker tag python:{{ version }} ghcr.io/opensafely-core/python:latest + docker tag python:{{ version }} ghcr.io/opensafely-core/jupyter:latest + echo docker push ghcr.io/opensafely-core/python:latest + echo docker push ghcr.io/opensafely-core/jupyter:latest + fi + + + diff --git a/tests/test_import.py b/tests/test_import.py index 09d4a4a..f877650 100644 --- a/tests/test_import.py +++ b/tests/test_import.py @@ -1,21 +1,44 @@ +import os import subprocess from importlib import import_module from pathlib import Path +import re import pytest from pkg_resources import Requirement, get_provider +# packages that have no way to detect their importable name +BAD_PACKAGES = { + "beautifulsoup4": "bs4", + "protobuf": None, # AARRRRGG + "qtpy": None, # required dependency of jupyter-lab +} + def get_module_names(pkg_name): """Load pkg metadata to find out its importable module name(s).""" + # remove any extras + pkg_name = re.sub(r'\[.*\]', '', pkg_name) modules = set() provider = get_provider(Requirement.parse(pkg_name)) # top level package name is typically all we need - if provider.has_metadata("top_level.txt"): - modules |= set(provider.get_metadata_lines("top_level.txt")) + if pkg_name in BAD_PACKAGES: + name = BAD_PACKAGES[pkg_name] + if name is None: # unimportably package + return [] + modules.add(BAD_PACKAGES[pkg_name]) + elif provider.has_metadata("top_level.txt"): + first_line = list(provider.get_metadata_lines("top_level.txt"))[0] + modules.add(first_line) else: # badly packaged dependency, make an educated guess - modules.add(pkg_name.replace("-", "_")) + name = pkg_name + if pkg_name.endswith("-cffi"): + name = pkg_name[:-5] + elif pkg_name.endswith("-py"): + name = pkg_name[:-3] + + modules.add(name.replace("-", "_")) if provider.has_metadata("namespace_packages.txt"): modules |= set(provider.get_metadata_lines("namespace_packages.txt")) @@ -24,8 +47,9 @@ def get_module_names(pkg_name): return [n for n in modules if n[0] != "_"] -def generate_import_names(req_path): +def generate_import_names(major_version): """Generate list of expected modules to be able to import.""" + req_path = Path(major_version) / "requirements.txt" with req_path.open() as fp: for line in fp: line = line.strip() @@ -38,7 +62,7 @@ def generate_import_names(req_path): @pytest.mark.parametrize( - "name, module", generate_import_names(Path("requirements.txt")) + "name, module", generate_import_names(os.environ["MAJOR_VERSION"]) ) @pytest.mark.filterwarnings("ignore") def test_import_package(name, module): diff --git a/build-dependencies.txt b/v1/build-dependencies.txt similarity index 100% rename from build-dependencies.txt rename to v1/build-dependencies.txt diff --git a/dependencies.txt b/v1/dependencies.txt similarity index 100% rename from dependencies.txt rename to v1/dependencies.txt diff --git a/v1/env b/v1/env new file mode 100644 index 0000000..ea122d4 --- /dev/null +++ b/v1/env @@ -0,0 +1,2 @@ +MAJOR_VERSION=v1 +BASE=20.04 diff --git a/requirements.in b/v1/requirements.in similarity index 100% rename from requirements.in rename to v1/requirements.in diff --git a/requirements.txt b/v1/requirements.txt similarity index 88% rename from requirements.txt rename to v1/requirements.txt index 18935e4..a00935f 100644 --- a/requirements.txt +++ b/v1/requirements.txt @@ -1,8 +1,8 @@ # -# This file is autogenerated by pip-compile with python 3.8 -# To update, run: +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: # -# pip-compile +# pip-compile --output-file=v1/requirements.txt v1/requirements.in # astor==0.8.1 # via formulaic @@ -20,7 +20,7 @@ autograd-gamma==0.5.0 backcall==0.1.0 # via ipython bash-kernel==0.7.2 - # via -r requirements.in + # via -r v1/requirements.in bleach==3.1.2 # via nbconvert cachetools==4.0.0 @@ -28,7 +28,7 @@ cachetools==4.0.0 cairocffi==1.4.0 # via cairosvg cairosvg==2.5.2 - # via -r requirements.in + # via -r v1/requirements.in certifi==2019.11.28 # via requests cffi==1.15.1 @@ -37,6 +37,8 @@ chardet==3.0.4 # via requests click==7.0 # via + # click-plugins + # cligj # fiona # pip-tools click-plugins==1.1.1 @@ -120,7 +122,7 @@ ipython-genutils==0.2.0 # traitlets ipywidgets==7.5.1 # via - # -r requirements.in + # -r v1/requirements.in # jupyter jedi==0.16.0 # via ipython @@ -139,7 +141,7 @@ jsonschema==3.2.0 # jupyterlab-server # nbformat jupyter==1.0.0 - # via -r requirements.in + # via -r v1/requirements.in jupyter-client==5.3.4 # via # ipykernel @@ -157,17 +159,17 @@ jupyter-core==4.6.1 # notebook # qtconsole jupyterlab==1.2.6 - # via -r requirements.in + # via -r v1/requirements.in jupyterlab-server==1.0.6 # via jupyterlab jupytext==1.3.3 - # via -r requirements.in + # via -r v1/requirements.in kaleido==0.2.1 - # via -r requirements.in + # via -r v1/requirements.in kiwisolver==1.1.0 # via matplotlib lifelines==0.26.4 - # via -r requirements.in + # via -r v1/requirements.in llvmlite==0.34.0 # via numba lz4==3.1.3 @@ -176,7 +178,7 @@ markupsafe==1.1.1 # via jinja2 matplotlib==3.1.3 # via - # -r requirements.in + # -r v1/requirements.in # descartes # lifelines # seaborn @@ -200,7 +202,7 @@ nbformat==5.0.4 # nbval # notebook nbval==0.9.4 - # via -r requirements.in + # via -r v1/requirements.in notebook==6.0.3 # via # jupyter @@ -208,10 +210,10 @@ notebook==6.0.3 # jupyterlab-server # widgetsnbextension numba==0.51.2 - # via -r requirements.in + # via -r v1/requirements.in numpy==1.18.1 # via - # -r requirements.in + # -r v1/requirements.in # autograd # formulaic # lifelines @@ -229,12 +231,12 @@ oauthlib==3.1.0 opensafely-cohort-extractor==1.88.0 # via -r requirements.in opensafely-matching==0.2.0 - # via -r requirements.in + # via -r v1/requirements.in packaging==20.1 # via pytest pandas==1.0.1 # via - # -r requirements.in + # -r v1/requirements.in # ebmdatalab # formulaic # geopandas @@ -247,7 +249,7 @@ pandas==1.0.1 # upsetplot pandas-gbq==0.13.0 # via - # -r requirements.in + # -r v1/requirements.in # ebmdatalab pandocfilters==1.4.2 # via nbconvert @@ -265,12 +267,12 @@ pickleshare==0.7.5 # via ipython pillow==8.1.0 # via - # -r requirements.in + # -r v1/requirements.in # cairosvg pip-tools==6.2.0 - # via -r requirements.in + # via -r v1/requirements.in plotly==4.5.0 - # via -r requirements.in + # via -r v1/requirements.in pluggy==0.13.1 # via pytest prometheus-client==0.7.1 @@ -283,6 +285,7 @@ protobuf==3.11.3 # via # google-api-core # google-cloud-bigquery + # googleapis-common-protos ptyprocess==0.6.0 # via # pexpect @@ -293,7 +296,7 @@ py==1.8.1 # retry pyarrow==3.0.0 # via - # -r requirements.in + # -r v1/requirements.in # opensafely-cohort-extractor pyasn1==0.4.8 # via @@ -321,7 +324,7 @@ pyrsistent==0.15.7 # via jsonschema pytest==5.3.5 # via - # -r requirements.in + # -r v1/requirements.in # nbval python-dateutil==2.8.1 # via @@ -356,10 +359,10 @@ retrying==1.3.3 rsa==4.0 # via google-auth scikit-learn==0.24.1 - # via -r requirements.in + # via -r v1/requirements.in scipy==1.4.1 # via - # -r requirements.in + # -r v1/requirements.in # autograd-gamma # formulaic # lifelines @@ -384,11 +387,13 @@ six==1.14.0 # google-cloud-bigquery # google-resumable-media # jsonschema + # munch # nbval # packaging # patsy # plotly # protobuf + # pyrsistent # python-dateutil # retrying # traitlets @@ -420,7 +425,7 @@ tornado==6.0.3 # notebook # terminado tqdm==4.42.1 - # via -r requirements.in + # via -r v1/requirements.in traitlets==4.3.3 # via # ipykernel @@ -433,11 +438,11 @@ traitlets==4.3.3 # notebook # qtconsole upsetplot==0.6.1 - # via -r requirements.in + # via -r v1/requirements.in urllib3==1.25.8 # via requests venn==0.1.3 - # via -r requirements.in + # via -r v1/requirements.in wcwidth==0.1.8 # via # prompt-toolkit diff --git a/v2/build-dependencies.txt b/v2/build-dependencies.txt new file mode 100644 index 0000000..d5c2de8 --- /dev/null +++ b/v2/build-dependencies.txt @@ -0,0 +1,10 @@ +# build time dependencies +build-essential +gcc +python3-dev +python3-venv +python3-wheel +# for numba +#llvm-10-dev +# for cairosvg +libffi-dev diff --git a/v2/dependencies.txt b/v2/dependencies.txt new file mode 100644 index 0000000..9fb4f06 --- /dev/null +++ b/v2/dependencies.txt @@ -0,0 +1,15 @@ +# run time dependencies +# ensure fully working base python3 installation +# see: https://gist.github.com/tiran/2dec9e03c6f901814f6d1e8dad09528e +python3 +python3-venv +python3-pip +python3-distutils +tzdata +ca-certificates + +# for cairosvg +libcairo2 + +# Some jupyter notebooks rely on using git to get current version of repo +git diff --git a/v2/env b/v2/env new file mode 100644 index 0000000..7cd7324 --- /dev/null +++ b/v2/env @@ -0,0 +1,2 @@ +MAJOR_VERSION=v2 +BASE=22.04 diff --git a/v2/requirements.in b/v2/requirements.in new file mode 100644 index 0000000..a89dd8b --- /dev/null +++ b/v2/requirements.in @@ -0,0 +1,39 @@ +# Basic requirements for notebook infrastructure provided in base +# docker image +pip-tools +jupyter +jupyterlab +jupytext +bash_kernel +nbval +opensafely-matching + +# Commonly-used packages provided in base docker image +pandas-gbq +pandas +numpy +ebmdatalab +matplotlib +scipy +tqdm +numba +opensafely-cohort-extractor +pyarrow +venn +kaleido +scikit-learn +lifelines + +# Both these required for plotly+notebooks +plotly +ipywidgets + +# Add extra per-notebook packages here +pillow +cairosvg + +# Allow for projects to run tests inside the container +pytest + +# For visualisation of set overlaps +upsetplot diff --git a/v2/requirements.txt b/v2/requirements.txt new file mode 100644 index 0000000..aecf474 --- /dev/null +++ b/v2/requirements.txt @@ -0,0 +1,643 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile requirements-3.10.in +# +anyio==4.0.0 + # via jupyter-server +argon2-cffi==23.1.0 + # via jupyter-server +argon2-cffi-bindings==21.2.0 + # via argon2-cffi +arrow==1.3.0 + # via isoduration +astor==0.8.1 + # via formulaic +asttokens==2.4.1 + # via stack-data +async-lru==2.0.4 + # via jupyterlab +attrs==23.1.0 + # via + # fiona + # jsonschema + # referencing +autograd==1.6.2 + # via + # autograd-gamma + # lifelines +autograd-gamma==0.5.0 + # via lifelines +babel==2.13.1 + # via jupyterlab-server +bash-kernel==0.9.1 + # via -r requirements-3.10.in +beautifulsoup4==4.12.2 + # via nbconvert +bleach==6.1.0 + # via nbconvert +build==1.0.3 + # via pip-tools +cachetools==5.3.2 + # via google-auth +cairocffi==1.6.1 + # via cairosvg +cairosvg==2.7.1 + # via -r requirements-3.10.in +certifi==2023.11.17 + # via + # fiona + # pyproj + # requests +cffi==1.16.0 + # via + # argon2-cffi-bindings + # cairocffi +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via + # click-plugins + # cligj + # fiona + # pip-tools +click-plugins==1.1.1 + # via fiona +cligj==0.7.2 + # via fiona +comm==0.2.0 + # via + # ipykernel + # ipywidgets +contourpy==1.2.0 + # via matplotlib +coverage==7.3.2 + # via nbval +cssselect2==0.7.0 + # via cairosvg +cycler==0.12.1 + # via matplotlib +db-dtypes==1.1.1 + # via pandas-gbq +debugpy==1.8.0 + # via ipykernel +decorator==5.1.1 + # via + # ipython + # retry +defusedxml==0.7.1 + # via + # cairosvg + # nbconvert +descartes==1.1.0 + # via ebmdatalab +ebmdatalab==0.0.30 + # via -r requirements-3.10.in +exceptiongroup==1.2.0 + # via + # anyio + # ipython + # pytest +executing==2.0.1 + # via stack-data +fastjsonschema==2.19.0 + # via nbformat +fiona==1.9.5 + # via geopandas +fonttools==4.45.0 + # via matplotlib +formulaic==0.6.6 + # via lifelines +fqdn==1.5.1 + # via jsonschema +future==0.18.3 + # via autograd +geopandas==0.14.1 + # via ebmdatalab +google-api-core[grpc]==2.14.0 + # via + # google-cloud-bigquery + # google-cloud-bigquery-storage + # google-cloud-core + # pandas-gbq +google-auth==2.23.4 + # via + # google-api-core + # google-auth-oauthlib + # google-cloud-core + # pandas-gbq + # pydata-google-auth +google-auth-oauthlib==1.1.0 + # via + # pandas-gbq + # pydata-google-auth +google-cloud-bigquery==3.13.0 + # via pandas-gbq +google-cloud-bigquery-storage==2.22.0 + # via pandas-gbq +google-cloud-core==2.3.3 + # via google-cloud-bigquery +google-crc32c==1.5.0 + # via google-resumable-media +google-resumable-media==2.6.0 + # via google-cloud-bigquery +googleapis-common-protos==1.61.0 + # via + # google-api-core + # grpcio-status +grpcio==1.59.3 + # via + # google-api-core + # google-cloud-bigquery + # grpcio-status +grpcio-status==1.59.3 + # via google-api-core +idna==3.4 + # via + # anyio + # jsonschema + # requests +iniconfig==2.0.0 + # via pytest +interface-meta==1.3.0 + # via formulaic +ipykernel==6.27.0 + # via + # bash-kernel + # jupyter + # jupyter-console + # jupyterlab + # nbval + # qtconsole +ipython==8.17.2 + # via + # ipykernel + # ipywidgets + # jupyter-console +ipywidgets==8.1.1 + # via + # -r requirements-3.10.in + # jupyter +isoduration==20.11.0 + # via jsonschema +jedi==0.19.1 + # via ipython +jinja2==3.1.2 + # via + # jupyter-server + # jupyterlab + # jupyterlab-server + # nbconvert +joblib==1.3.2 + # via scikit-learn +json5==0.9.14 + # via jupyterlab-server +jsonpointer==2.4 + # via jsonschema +jsonschema[format-nongpl]==4.20.0 + # via + # jupyter-events + # jupyterlab-server + # nbformat +jsonschema-specifications==2023.11.1 + # via jsonschema +jupyter==1.0.0 + # via -r requirements-3.10.in +jupyter-client==8.6.0 + # via + # ipykernel + # jupyter-console + # jupyter-server + # nbclient + # nbval + # qtconsole +jupyter-console==6.6.3 + # via jupyter +jupyter-core==5.5.0 + # via + # ipykernel + # jupyter-client + # jupyter-console + # jupyter-server + # jupyterlab + # nbclient + # nbconvert + # nbformat + # qtconsole +jupyter-events==0.9.0 + # via jupyter-server +jupyter-lsp==2.2.0 + # via jupyterlab +jupyter-server==2.11.0 + # via + # jupyter-lsp + # jupyterlab + # jupyterlab-server + # notebook + # notebook-shim +jupyter-server-terminals==0.4.4 + # via jupyter-server +jupyterlab==4.0.9 + # via + # -r requirements-3.10.in + # notebook +jupyterlab-pygments==0.2.2 + # via nbconvert +jupyterlab-server==2.25.2 + # via + # jupyterlab + # notebook +jupyterlab-widgets==3.0.9 + # via ipywidgets +jupytext==1.15.2 + # via -r requirements-3.10.in +kaleido==0.2.1 + # via -r requirements-3.10.in +kiwisolver==1.4.5 + # via matplotlib +lifelines==0.27.8 + # via -r requirements-3.10.in +llvmlite==0.41.1 + # via numba +lz4==4.3.2 + # via opensafely-cohort-extractor +markdown-it-py==3.0.0 + # via + # jupytext + # mdit-py-plugins +markupsafe==2.1.3 + # via + # jinja2 + # nbconvert +matplotlib==3.8.2 + # via + # -r requirements-3.10.in + # descartes + # lifelines + # seaborn + # upsetplot + # venn +matplotlib-inline==0.1.6 + # via + # ipykernel + # ipython +mdit-py-plugins==0.4.0 + # via jupytext +mdurl==0.1.2 + # via markdown-it-py +mistune==3.0.2 + # via nbconvert +nbclient==0.9.0 + # via nbconvert +nbconvert==7.11.0 + # via + # jupyter + # jupyter-server +nbformat==5.9.2 + # via + # jupyter-server + # jupytext + # nbclient + # nbconvert + # nbval +nbval==0.10.0 + # via -r requirements-3.10.in +nest-asyncio==1.5.8 + # via ipykernel +notebook==7.0.6 + # via jupyter +notebook-shim==0.2.3 + # via + # jupyterlab + # notebook +numba==0.58.1 + # via -r requirements-3.10.in +numpy==1.26.2 + # via + # -r requirements-3.10.in + # autograd + # contourpy + # db-dtypes + # formulaic + # lifelines + # matplotlib + # numba + # pandas + # pandas-gbq + # patsy + # pyarrow + # scikit-learn + # scipy + # seaborn + # shapely + # statsmodels +oauthlib==3.2.2 + # via requests-oauthlib +opensafely-cohort-extractor==1.90.0 + # via -r requirements-3.10.in +opensafely-matching==0.2.0 + # via -r requirements-3.10.in +overrides==7.4.0 + # via jupyter-server +packaging==23.2 + # via + # build + # db-dtypes + # geopandas + # google-cloud-bigquery + # ipykernel + # jupyter-server + # jupyterlab + # jupyterlab-server + # matplotlib + # nbconvert + # plotly + # pytest + # qtconsole + # qtpy + # statsmodels +pandas==2.1.3 + # via + # -r requirements-3.10.in + # db-dtypes + # ebmdatalab + # formulaic + # geopandas + # lifelines + # opensafely-cohort-extractor + # opensafely-matching + # pandas-gbq + # seaborn + # statsmodels + # upsetplot +pandas-gbq==0.19.2 + # via + # -r requirements-3.10.in + # ebmdatalab +pandocfilters==1.5.0 + # via nbconvert +parso==0.8.3 + # via jedi +patsy==0.5.3 + # via statsmodels +pexpect==4.8.0 + # via + # bash-kernel + # ipython +pillow==10.1.0 + # via + # -r requirements-3.10.in + # cairosvg + # matplotlib +pip-tools==7.3.0 + # via -r requirements-3.10.in +platformdirs==4.0.0 + # via jupyter-core +plotly==5.18.0 + # via -r requirements-3.10.in +pluggy==1.3.0 + # via pytest +prometheus-client==0.19.0 + # via jupyter-server +prompt-toolkit==3.0.41 + # via + # ipython + # jupyter-console +proto-plus==1.22.3 + # via + # google-cloud-bigquery + # google-cloud-bigquery-storage +protobuf==4.25.1 + # via + # google-api-core + # google-cloud-bigquery + # google-cloud-bigquery-storage + # googleapis-common-protos + # grpcio-status + # proto-plus +psutil==5.9.6 + # via ipykernel +ptyprocess==0.7.0 + # via + # pexpect + # terminado +pure-eval==0.2.2 + # via stack-data +py==1.11.0 + # via retry +pyarrow==14.0.1 + # via + # -r requirements-3.10.in + # db-dtypes + # opensafely-cohort-extractor + # pandas-gbq +pyasn1==0.5.1 + # via + # pyasn1-modules + # rsa +pyasn1-modules==0.3.0 + # via google-auth +pycparser==2.21 + # via cffi +pydata-google-auth==1.8.2 + # via pandas-gbq +pygments==2.17.1 + # via + # ipython + # jupyter-console + # nbconvert + # qtconsole +pyparsing==3.1.1 + # via matplotlib +pyproj==3.6.1 + # via geopandas +pyproject-hooks==1.0.0 + # via build +pytest==7.4.3 + # via + # -r requirements-3.10.in + # nbval +python-dateutil==2.8.2 + # via + # arrow + # google-cloud-bigquery + # jupyter-client + # matplotlib + # pandas +python-json-logger==2.0.7 + # via jupyter-events +pytz==2023.3.post1 + # via pandas +pyyaml==6.0.1 + # via + # jupyter-events + # jupytext + # opensafely-cohort-extractor +pyzmq==25.1.1 + # via + # ipykernel + # jupyter-client + # jupyter-console + # jupyter-server + # qtconsole +qtconsole==5.5.1 + # via jupyter +qtpy==2.4.1 + # via qtconsole +referencing==0.31.0 + # via + # jsonschema + # jsonschema-specifications + # jupyter-events +requests==2.31.0 + # via + # google-api-core + # google-cloud-bigquery + # jupyterlab-server + # opensafely-cohort-extractor + # requests-oauthlib +requests-oauthlib==1.3.1 + # via google-auth-oauthlib +retry==0.9.2 + # via opensafely-cohort-extractor +rfc3339-validator==0.1.4 + # via + # jsonschema + # jupyter-events +rfc3986-validator==0.1.1 + # via + # jsonschema + # jupyter-events +rpds-py==0.13.1 + # via + # jsonschema + # referencing +rsa==4.9 + # via google-auth +scikit-learn==1.3.2 + # via -r requirements-3.10.in +scipy==1.11.4 + # via + # -r requirements-3.10.in + # autograd-gamma + # formulaic + # lifelines + # scikit-learn + # statsmodels +seaborn==0.13.0 + # via + # ebmdatalab + # opensafely-cohort-extractor +send2trash==1.8.2 + # via jupyter-server +shapely==2.0.2 + # via geopandas +six==1.16.0 + # via + # asttokens + # bleach + # fiona + # patsy + # python-dateutil + # rfc3339-validator +sniffio==1.3.0 + # via anyio +soupsieve==2.5 + # via beautifulsoup4 +sqlparse==0.4.4 + # via opensafely-cohort-extractor +stack-data==0.6.3 + # via ipython +statsmodels==0.14.0 + # via ebmdatalab +structlog==23.2.0 + # via opensafely-cohort-extractor +tabulate==0.9.0 + # via opensafely-cohort-extractor +tenacity==8.2.3 + # via plotly +terminado==0.18.0 + # via + # jupyter-server + # jupyter-server-terminals +threadpoolctl==3.2.0 + # via scikit-learn +tinycss2==1.2.1 + # via + # cairosvg + # cssselect2 + # nbconvert +toml==0.10.2 + # via jupytext +tomli==2.0.1 + # via + # build + # jupyterlab + # pip-tools + # pyproject-hooks + # pytest +tornado==6.3.3 + # via + # ipykernel + # jupyter-client + # jupyter-server + # jupyterlab + # notebook + # terminado +tqdm==4.66.1 + # via -r requirements-3.10.in +traitlets==5.13.0 + # via + # comm + # ipykernel + # ipython + # ipywidgets + # jupyter-client + # jupyter-console + # jupyter-core + # jupyter-events + # jupyter-server + # jupyterlab + # matplotlib-inline + # nbclient + # nbconvert + # nbformat + # qtconsole +types-python-dateutil==2.8.19.14 + # via arrow +typing-extensions==4.8.0 + # via + # async-lru + # formulaic +tzdata==2023.3 + # via pandas +upsetplot==0.8.0 + # via -r requirements-3.10.in +uri-template==1.3.0 + # via jsonschema +urllib3==2.1.0 + # via requests +venn==0.1.3 + # via -r requirements-3.10.in +wcwidth==0.2.11 + # via prompt-toolkit +webcolors==1.13 + # via jsonschema +webencodings==0.5.1 + # via + # bleach + # cssselect2 + # tinycss2 +websocket-client==1.6.4 + # via jupyter-server +wheel==0.41.3 + # via pip-tools +widgetsnbextension==4.0.9 + # via ipywidgets +wrapt==1.16.0 + # via formulaic + +# The following packages are considered to be unsafe in a requirements file: +# pip +# setuptools From c42b4c3db81f17bfee3b7a95dcda27399848ff9e Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Wed, 22 Nov 2023 17:20:42 +0000 Subject: [PATCH 02/11] CI test and publish for versions The github workflows have been updated to publish the v1 image as *both* `v1` and `latest` tags for now, as well as under the jupyter alias. The `v2` is published separately as just `v2`. --- .github/workflows/build_and_publish.yaml | 45 ++++++++++++------------ .github/workflows/tests.yaml | 31 ++++++++++------ 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/.github/workflows/build_and_publish.yaml b/.github/workflows/build_and_publish.yaml index 84349d8..f38c046 100644 --- a/.github/workflows/build_and_publish.yaml +++ b/.github/workflows/build_and_publish.yaml @@ -1,33 +1,34 @@ name: Build and publish on: + workflow_dispatch: push: branches: [main] - workflow_dispatch: -permissions: - packages: write -env: - IMAGE_NAME: python + jobs: - build-and-publish: - runs-on: ubuntu-20.04 + publish: + # note: this builds/tests all versions in serial for two reasons. Firstly we + # want all versions to release or none of them. Secondly, we will be able + # publish the exact images that were built and tested. + runs-on: ubuntu-22.04 steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Build image - run: make build + - uses: actions/checkout@v3 + - uses: "opensafely-core/setup-action@v1" + with: + install-just: true + - name: Build images + run: | + just build v1 + just build v2 - name: Run tests - run: make test functional-test - - name: Run lint - run: make lint + run: | + just test v1 + just test v2 + - name: Run linters + run: just check + - name: Log into GitHub Container Registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin - name: Push image to GitHub Container Registry run: | - IMAGE_ID="ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME" - docker tag "$IMAGE_NAME" "$IMAGE_ID:latest" - docker push "$IMAGE_ID:latest" - - JUPYTER_ID="ghcr.io/${{ github.repository_owner }}/jupyter" - # also publish as jupyter image for backward compatibility - docker tag "$IMAGE_NAME" "$JUPYTER_ID:latest" - docker push "$JUPYTER_ID:latest" + just publish v1 + just publish v2 diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index b449bd5..f5a9ed6 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -1,17 +1,28 @@ name: Run tests on: pull_request: -env: - IMAGE_NAME: python jobs: - tests: - runs-on: ubuntu-20.04 + version-tests: + runs-on: ubuntu-22.04 + strategy: + matrix: + version: [v1, v2] steps: - - name: Checkout - uses: actions/checkout@master + - uses: actions/checkout@v3 + - uses: "opensafely-core/setup-action@v1" + with: + install-just: true - name: Build image - run: make build + run: just build ${{ matrix.version }} - name: Run tests - run: make test functional-test - - name: Run lint - run: make lint + run: just test ${{ matrix.version }} + lint: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: "opensafely-core/setup-action@v1" + with: + install-just: true + - name: Run linters + run: just check + From adfa9a8a5574df5d92a56ec965a2498d9490d93f Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Thu, 23 Nov 2023 16:00:16 +0000 Subject: [PATCH 03/11] Add time based build number Used in docker image label and tag Refactored publishing script too. --- .github/workflows/build_and_publish.yaml | 5 ++-- justfile | 28 ++++--------------- scripts/publish.sh | 35 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 24 deletions(-) create mode 100755 scripts/publish.sh diff --git a/.github/workflows/build_and_publish.yaml b/.github/workflows/build_and_publish.yaml index f38c046..52966bc 100644 --- a/.github/workflows/build_and_publish.yaml +++ b/.github/workflows/build_and_publish.yaml @@ -30,5 +30,6 @@ jobs: run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin - name: Push image to GitHub Container Registry run: | - just publish v1 - just publish v2 + # just test publish for now + just publish v1 false + just publish v2 false diff --git a/justfile b/justfile index 310f12e..e3844d7 100644 --- a/justfile +++ b/justfile @@ -1,9 +1,11 @@ export DOCKER_BUILDKIT := "1" +# technically, these could differ by 1 seconds, but thats unlikely and doesn't matter +# human readable, used as label in docker image export BUILD_DATE := `date +'%y-%m-%dT%H:%M:%S.%3NZ'` +# monotonic, used as label in docker image *and* in docker tag +export BUILD_NUMBER := `date +'%y%m%d%H%M%S'` export REVISION := `git rev-parse --short HEAD` -# TODO: calculate this -export BUILD_NUMBER := "1234" build version target="python" *args="": docker-compose --env-file {{ version }}/env build --pull {{ args }} {{ target }} @@ -18,23 +20,5 @@ check: @docker pull hadolint/hadolint:v2.12.0 @docker run --rm -i hadolint/hadolint:v2.12.0 < Dockerfile -publish version: - #!/bin/bash - set -euxo pipefail - docker tag python:{{ version }} ghcr.io/opensafely-core/python:{{ version }} - echo docker push ghcr.io/opensafely-core/python:{{ version }} - - if test "{{ version }}" = "v1"; then - # jupyter is only alias for v1 - docker tag python:{{ version }} ghcr.io/opensafely-core/jupyter:{{ version }} - echo docker push ghcr.io/opensafely-core/jupyter:{{ version }} - - # v1 is also known as latest, at least until we transition fully - docker tag python:{{ version }} ghcr.io/opensafely-core/python:latest - docker tag python:{{ version }} ghcr.io/opensafely-core/jupyter:latest - echo docker push ghcr.io/opensafely-core/python:latest - echo docker push ghcr.io/opensafely-core/jupyter:latest - fi - - - +publish version publish="false": + PUBLISH={{ publish }} ./scripts/publish.sh {{ version }} diff --git a/scripts/publish.sh b/scripts/publish.sh new file mode 100755 index 0000000..19c8027 --- /dev/null +++ b/scripts/publish.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -euo pipefail + +version=$1 +registry=ghcr.io/opensafely-core + +run() { + echo "$@" + if test "${PUBLISH:-}" = "true"; then + # shellcheck disable=SC2068 + $@ + fi +} + +publish() { + local local_tag=$1; + local remote_tag=$2; + + run docker tag "$local_tag" "$remote_tag" + run docker push "$remote_tag" +} + +full_version="$(docker inspect --format='{{ index .Config.Labels "org.opencontainers.image.version"}}' "python:$version")" + +publish "python:$version" "$registry/python:$version" +publish "python:$version" "$registry/python:${full_version}" + +if test "$version" = "v1"; then + # jupyter is only alias for v1 + publish "python:$version" "$registry/jupyter:$version" + + # v1 is also known as latest, at least until we transition fully + publish "python:$version" "$registry/python:latest" + publish "python:$version" "$registry/jupyter:latest" +fi From 395ed4680142e440f1fffe9d246184338f4999a0 Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Fri, 24 Nov 2023 14:08:41 +0000 Subject: [PATCH 04/11] justfile doc and tweaks --- justfile | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/justfile b/justfile index e3844d7..5b4bb6a 100644 --- a/justfile +++ b/justfile @@ -6,19 +6,27 @@ export BUILD_DATE := `date +'%y-%m-%dT%H:%M:%S.%3NZ'` export BUILD_NUMBER := `date +'%y%m%d%H%M%S'` export REVISION := `git rev-parse --short HEAD` - +# build docker image for version build version target="python" *args="": docker-compose --env-file {{ version }}/env build --pull {{ args }} {{ target }} -test version *args="tests -v": + +# test docker image for version +test version *args="tests -v": (build version) docker-compose --env-file {{ version }}/env run --rm -v $PWD:/workspace python pytest {{ args }} -update version *args="": + +# run pip-compile to add new dependencies, or update existing ones with --upgrade +update version *args="": (build version) docker-compose --env-file {{ version }}/env run --rm -v $PWD:/workspace base pip-compile {{ args }} {{ version }}/requirements.in -o {{ version }}/requirements.txt + +# run linters check: @docker pull hadolint/hadolint:v2.12.0 @docker run --rm -i hadolint/hadolint:v2.12.0 < Dockerfile + +# publish version (dry run by default - pass "true" to perform publish) publish version publish="false": PUBLISH={{ publish }} ./scripts/publish.sh {{ version }} From 71f3cb185bcc6ce48452a7f73b9c34350eb4c54c Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Fri, 24 Nov 2023 15:39:57 +0000 Subject: [PATCH 05/11] Add documentation rendering of package versions This can be enhanced as needed, but the basic versions and tooling is there. Jinja2 is installed in the images, so we re-use the images themselves to render the template. --- Dockerfile | 3 +- justfile | 6 ++ scripts/packages.j2.md | 12 +++ scripts/render.py | 24 +++++ v1/packages.md | 145 ++++++++++++++++++++++++++++++ v1/requirements.txt | 4 +- v2/packages.md | 200 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 391 insertions(+), 3 deletions(-) create mode 100644 scripts/packages.j2.md create mode 100755 scripts/render.py create mode 100644 v1/packages.md create mode 100644 v2/packages.md diff --git a/Dockerfile b/Dockerfile index 5ccef52..7e3eec0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,8 +16,9 @@ RUN mkdir /workspace WORKDIR /workspace ARG MAJOR_VERSION +ARG BASE # ACTION_EXEC sets the default executable for the entrypoint in the base-docker image -ENV ACTION_EXEC=python MAJOR_VERSION=${MAJOR_VERSION} +ENV ACTION_EXEC=python MAJOR_VERSION=${MAJOR_VERSION} BASE=${BASE} COPY ${MAJOR_VERSION}/dependencies.txt /root/dependencies.txt # use space efficient utility from base image diff --git a/justfile b/justfile index 5b4bb6a..cdcf479 100644 --- a/justfile +++ b/justfile @@ -19,6 +19,12 @@ test version *args="tests -v": (build version) # run pip-compile to add new dependencies, or update existing ones with --upgrade update version *args="": (build version) docker-compose --env-file {{ version }}/env run --rm -v $PWD:/workspace base pip-compile {{ args }} {{ version }}/requirements.in -o {{ version }}/requirements.txt + {{ just_executable() }} render {{ version }} + + +# render package version information +render version *args: + docker-compose --env-file {{ version }}/env run --rm -v $PWD:/workspace python ./scripts/render.py {{ args }} > {{ version }}/packages.md # run linters diff --git a/scripts/packages.j2.md b/scripts/packages.j2.md new file mode 100644 index 0000000..e9dd3e1 --- /dev/null +++ b/scripts/packages.j2.md @@ -0,0 +1,12 @@ +# Package Versions for {{ MAJOR_VERSION }} + +This python:{{ MAJOR_VERSION }} OpenSAFELY image is based on Ubuntu {{ BASE }} with Python {{ PYTHON_VERSION }}. + +## Packages + +It comes pre-installed with a standard set of python packages. + +{% for pkg in PACKAGES -%} + - [{{ pkg | replace("==", ": ")}}](https://pypi.org/project/{{pkg.name}}/{{pkg.specs[0][1]}}/) +{% endfor -%} + diff --git a/scripts/render.py b/scripts/render.py new file mode 100755 index 0000000..f036bfe --- /dev/null +++ b/scripts/render.py @@ -0,0 +1,24 @@ +#!/usr/bin/env -S python3 -W ignore +from pathlib import Path +import os +import sys +import pkg_resources + +from jinja2 import Environment, FileSystemLoader +env = Environment(loader=FileSystemLoader("scripts")) + +version = os.environ["MAJOR_VERSION"] +requirements = Path(version) / "requirements.txt" + +context = { + "MAJOR_VERSION": version, + "BASE": os.environ["BASE"], + "PYTHON_VERSION": "{}.{}.{}".format(*sys.version_info), +} + +with requirements.open() as r: + context["PACKAGES"] = list(pkg_resources.parse_requirements(r)) + +template = env.get_template("packages.j2.md") + +print(template.render(**context)) diff --git a/v1/packages.md b/v1/packages.md new file mode 100644 index 0000000..58476de --- /dev/null +++ b/v1/packages.md @@ -0,0 +1,145 @@ +# Package Versions for v1 + +This python:v1 OpenSAFELY image is based on Ubuntu 20.04 with Python 3.8.10. + +## Packages + +It comes pre-installed with a standard set of python packages. + +- [astor: 0.8.1](https://pypi.org/project/astor/0.8.1/) +- [attrs: 19.3.0](https://pypi.org/project/attrs/19.3.0/) +- [autograd: 1.3](https://pypi.org/project/autograd/1.3/) +- [autograd-gamma: 0.5.0](https://pypi.org/project/autograd-gamma/0.5.0/) +- [backcall: 0.1.0](https://pypi.org/project/backcall/0.1.0/) +- [bash-kernel: 0.7.2](https://pypi.org/project/bash-kernel/0.7.2/) +- [bleach: 3.1.2](https://pypi.org/project/bleach/3.1.2/) +- [cachetools: 4.0.0](https://pypi.org/project/cachetools/4.0.0/) +- [cairocffi: 1.4.0](https://pypi.org/project/cairocffi/1.4.0/) +- [cairosvg: 2.5.2](https://pypi.org/project/cairosvg/2.5.2/) +- [certifi: 2019.11.28](https://pypi.org/project/certifi/2019.11.28/) +- [cffi: 1.15.1](https://pypi.org/project/cffi/1.15.1/) +- [chardet: 3.0.4](https://pypi.org/project/chardet/3.0.4/) +- [click: 7.0](https://pypi.org/project/click/7.0/) +- [click-plugins: 1.1.1](https://pypi.org/project/click-plugins/1.1.1/) +- [cligj: 0.5.0](https://pypi.org/project/cligj/0.5.0/) +- [coverage: 4.5.4](https://pypi.org/project/coverage/4.5.4/) +- [cssselect2: 0.7.0](https://pypi.org/project/cssselect2/0.7.0/) +- [cycler: 0.10.0](https://pypi.org/project/cycler/0.10.0/) +- [decorator: 4.4.1](https://pypi.org/project/decorator/4.4.1/) +- [defusedxml: 0.6.0](https://pypi.org/project/defusedxml/0.6.0/) +- [descartes: 1.1.0](https://pypi.org/project/descartes/1.1.0/) +- [ebmdatalab: 0.0.30](https://pypi.org/project/ebmdatalab/0.0.30/) +- [entrypoints: 0.3](https://pypi.org/project/entrypoints/0.3/) +- [fiona: 1.8.13](https://pypi.org/project/fiona/1.8.13/) +- [formulaic: 0.2.4](https://pypi.org/project/formulaic/0.2.4/) +- [future: 0.18.2](https://pypi.org/project/future/0.18.2/) +- [geopandas: 0.6.3](https://pypi.org/project/geopandas/0.6.3/) +- [google-api-core: 1.16.0](https://pypi.org/project/google-api-core/1.16.0/) +- [google-auth: 1.11.0](https://pypi.org/project/google-auth/1.11.0/) +- [google-auth-oauthlib: 0.4.1](https://pypi.org/project/google-auth-oauthlib/0.4.1/) +- [google-cloud-bigquery: 1.24.0](https://pypi.org/project/google-cloud-bigquery/1.24.0/) +- [google-cloud-core: 1.3.0](https://pypi.org/project/google-cloud-core/1.3.0/) +- [google-resumable-media: 0.5.0](https://pypi.org/project/google-resumable-media/0.5.0/) +- [googleapis-common-protos: 1.51.0](https://pypi.org/project/googleapis-common-protos/1.51.0/) +- [idna: 2.8](https://pypi.org/project/idna/2.8/) +- [interface-meta: 1.2.4](https://pypi.org/project/interface-meta/1.2.4/) +- [ipykernel: 5.1.4](https://pypi.org/project/ipykernel/5.1.4/) +- [ipython: 7.12.0](https://pypi.org/project/ipython/7.12.0/) +- [ipython-genutils: 0.2.0](https://pypi.org/project/ipython-genutils/0.2.0/) +- [ipywidgets: 7.5.1](https://pypi.org/project/ipywidgets/7.5.1/) +- [jedi: 0.16.0](https://pypi.org/project/jedi/0.16.0/) +- [jinja2: 2.11.1](https://pypi.org/project/jinja2/2.11.1/) +- [joblib: 1.0.1](https://pypi.org/project/joblib/1.0.1/) +- [json5: 0.9.0](https://pypi.org/project/json5/0.9.0/) +- [jsonschema: 3.2.0](https://pypi.org/project/jsonschema/3.2.0/) +- [jupyter: 1.0.0](https://pypi.org/project/jupyter/1.0.0/) +- [jupyter-client: 5.3.4](https://pypi.org/project/jupyter-client/5.3.4/) +- [jupyter-console: 6.1.0](https://pypi.org/project/jupyter-console/6.1.0/) +- [jupyter-core: 4.6.1](https://pypi.org/project/jupyter-core/4.6.1/) +- [jupyterlab: 1.2.6](https://pypi.org/project/jupyterlab/1.2.6/) +- [jupyterlab-server: 1.0.6](https://pypi.org/project/jupyterlab-server/1.0.6/) +- [jupytext: 1.3.3](https://pypi.org/project/jupytext/1.3.3/) +- [kaleido: 0.2.1](https://pypi.org/project/kaleido/0.2.1/) +- [kiwisolver: 1.1.0](https://pypi.org/project/kiwisolver/1.1.0/) +- [lifelines: 0.26.4](https://pypi.org/project/lifelines/0.26.4/) +- [llvmlite: 0.34.0](https://pypi.org/project/llvmlite/0.34.0/) +- [lz4: 3.1.3](https://pypi.org/project/lz4/3.1.3/) +- [markupsafe: 1.1.1](https://pypi.org/project/markupsafe/1.1.1/) +- [matplotlib: 3.1.3](https://pypi.org/project/matplotlib/3.1.3/) +- [mistune: 0.8.4](https://pypi.org/project/mistune/0.8.4/) +- [more-itertools: 8.2.0](https://pypi.org/project/more-itertools/8.2.0/) +- [munch: 2.5.0](https://pypi.org/project/munch/2.5.0/) +- [nbconvert: 5.6.1](https://pypi.org/project/nbconvert/5.6.1/) +- [nbformat: 5.0.4](https://pypi.org/project/nbformat/5.0.4/) +- [nbval: 0.9.4](https://pypi.org/project/nbval/0.9.4/) +- [notebook: 6.0.3](https://pypi.org/project/notebook/6.0.3/) +- [numba: 0.51.2](https://pypi.org/project/numba/0.51.2/) +- [numpy: 1.18.1](https://pypi.org/project/numpy/1.18.1/) +- [oauthlib: 3.1.0](https://pypi.org/project/oauthlib/3.1.0/) +- [opensafely-cohort-extractor: 1.88.0](https://pypi.org/project/opensafely-cohort-extractor/1.88.0/) +- [opensafely-matching: 0.2.0](https://pypi.org/project/opensafely-matching/0.2.0/) +- [packaging: 20.1](https://pypi.org/project/packaging/20.1/) +- [pandas: 1.0.1](https://pypi.org/project/pandas/1.0.1/) +- [pandas-gbq: 0.13.0](https://pypi.org/project/pandas-gbq/0.13.0/) +- [pandocfilters: 1.4.2](https://pypi.org/project/pandocfilters/1.4.2/) +- [parso: 0.6.1](https://pypi.org/project/parso/0.6.1/) +- [patsy: 0.5.1](https://pypi.org/project/patsy/0.5.1/) +- [pep517: 0.10.0](https://pypi.org/project/pep517/0.10.0/) +- [pexpect: 4.8.0](https://pypi.org/project/pexpect/4.8.0/) +- [pickleshare: 0.7.5](https://pypi.org/project/pickleshare/0.7.5/) +- [pillow: 8.1.0](https://pypi.org/project/pillow/8.1.0/) +- [pip-tools: 6.2.0](https://pypi.org/project/pip-tools/6.2.0/) +- [plotly: 4.5.0](https://pypi.org/project/plotly/4.5.0/) +- [pluggy: 0.13.1](https://pypi.org/project/pluggy/0.13.1/) +- [prometheus-client: 0.7.1](https://pypi.org/project/prometheus-client/0.7.1/) +- [prompt-toolkit: 3.0.3](https://pypi.org/project/prompt-toolkit/3.0.3/) +- [protobuf: 3.11.3](https://pypi.org/project/protobuf/3.11.3/) +- [ptyprocess: 0.6.0](https://pypi.org/project/ptyprocess/0.6.0/) +- [py: 1.8.1](https://pypi.org/project/py/1.8.1/) +- [pyarrow: 3.0.0](https://pypi.org/project/pyarrow/3.0.0/) +- [pyasn1: 0.4.8](https://pypi.org/project/pyasn1/0.4.8/) +- [pyasn1-modules: 0.2.8](https://pypi.org/project/pyasn1-modules/0.2.8/) +- [pycparser: 2.21](https://pypi.org/project/pycparser/2.21/) +- [pydata-google-auth: 0.3.0](https://pypi.org/project/pydata-google-auth/0.3.0/) +- [pygments: 2.5.2](https://pypi.org/project/pygments/2.5.2/) +- [pyparsing: 2.4.6](https://pypi.org/project/pyparsing/2.4.6/) +- [pyproj: 2.4.2.post1](https://pypi.org/project/pyproj/2.4.2.post1/) +- [pyrsistent: 0.15.7](https://pypi.org/project/pyrsistent/0.15.7/) +- [pytest: 5.3.5](https://pypi.org/project/pytest/5.3.5/) +- [python-dateutil: 2.8.1](https://pypi.org/project/python-dateutil/2.8.1/) +- [pytz: 2019.3](https://pypi.org/project/pytz/2019.3/) +- [pyyaml: 5.3](https://pypi.org/project/pyyaml/5.3/) +- [pyzmq: 18.1.1](https://pypi.org/project/pyzmq/18.1.1/) +- [qtconsole: 4.6.0](https://pypi.org/project/qtconsole/4.6.0/) +- [requests: 2.22.0](https://pypi.org/project/requests/2.22.0/) +- [requests-oauthlib: 1.3.0](https://pypi.org/project/requests-oauthlib/1.3.0/) +- [retry: 0.9.2](https://pypi.org/project/retry/0.9.2/) +- [retrying: 1.3.3](https://pypi.org/project/retrying/1.3.3/) +- [rsa: 4.0](https://pypi.org/project/rsa/4.0/) +- [scikit-learn: 0.24.1](https://pypi.org/project/scikit-learn/0.24.1/) +- [scipy: 1.4.1](https://pypi.org/project/scipy/1.4.1/) +- [seaborn: 0.10.0](https://pypi.org/project/seaborn/0.10.0/) +- [send2trash: 1.5.0](https://pypi.org/project/send2trash/1.5.0/) +- [shapely: 1.7.0](https://pypi.org/project/shapely/1.7.0/) +- [six: 1.14.0](https://pypi.org/project/six/1.14.0/) +- [sqlparse: 0.4.1](https://pypi.org/project/sqlparse/0.4.1/) +- [statsmodels: 0.11.0](https://pypi.org/project/statsmodels/0.11.0/) +- [structlog: 20.2.0](https://pypi.org/project/structlog/20.2.0/) +- [tabulate: 0.8.7](https://pypi.org/project/tabulate/0.8.7/) +- [terminado: 0.8.3](https://pypi.org/project/terminado/0.8.3/) +- [testpath: 0.4.4](https://pypi.org/project/testpath/0.4.4/) +- [threadpoolctl: 2.1.0](https://pypi.org/project/threadpoolctl/2.1.0/) +- [tinycss2: 1.2.1](https://pypi.org/project/tinycss2/1.2.1/) +- [toml: 0.10.2](https://pypi.org/project/toml/0.10.2/) +- [tornado: 6.0.3](https://pypi.org/project/tornado/6.0.3/) +- [tqdm: 4.42.1](https://pypi.org/project/tqdm/4.42.1/) +- [traitlets: 4.3.3](https://pypi.org/project/traitlets/4.3.3/) +- [upsetplot: 0.6.1](https://pypi.org/project/upsetplot/0.6.1/) +- [urllib3: 1.25.8](https://pypi.org/project/urllib3/1.25.8/) +- [venn: 0.1.3](https://pypi.org/project/venn/0.1.3/) +- [wcwidth: 0.1.8](https://pypi.org/project/wcwidth/0.1.8/) +- [webencodings: 0.5.1](https://pypi.org/project/webencodings/0.5.1/) +- [wheel: 0.36.2](https://pypi.org/project/wheel/0.36.2/) +- [widgetsnbextension: 3.5.1](https://pypi.org/project/widgetsnbextension/3.5.1/) +- [wrapt: 1.13.3](https://pypi.org/project/wrapt/1.13.3/) + diff --git a/v1/requirements.txt b/v1/requirements.txt index a00935f..4b4b48a 100644 --- a/v1/requirements.txt +++ b/v1/requirements.txt @@ -63,7 +63,7 @@ defusedxml==0.6.0 descartes==1.1.0 # via ebmdatalab ebmdatalab==0.0.30 - # via -r requirements.in + # via -r v1/requirements.in entrypoints==0.3 # via nbconvert fiona==1.8.13 @@ -229,7 +229,7 @@ numpy==1.18.1 oauthlib==3.1.0 # via requests-oauthlib opensafely-cohort-extractor==1.88.0 - # via -r requirements.in + # via -r v1/requirements.in opensafely-matching==0.2.0 # via -r v1/requirements.in packaging==20.1 diff --git a/v2/packages.md b/v2/packages.md new file mode 100644 index 0000000..61176a1 --- /dev/null +++ b/v2/packages.md @@ -0,0 +1,200 @@ +# Package Versions for v2 + +> [!NOTE] +> This file is auto-generated - do not edit. + +This python:v2 OpenSAFELY image is based on Ubuntu 22.04 with Python 3.10.12. + +## Packages + +It comes pre-installed with a standard set of python packages. + +- [anyio: 4.0.0](https://pypi.org/project/anyio/4.0.0/) +- [argon2-cffi: 23.1.0](https://pypi.org/project/argon2-cffi/23.1.0/) +- [argon2-cffi-bindings: 21.2.0](https://pypi.org/project/argon2-cffi-bindings/21.2.0/) +- [arrow: 1.3.0](https://pypi.org/project/arrow/1.3.0/) +- [astor: 0.8.1](https://pypi.org/project/astor/0.8.1/) +- [asttokens: 2.4.1](https://pypi.org/project/asttokens/2.4.1/) +- [async-lru: 2.0.4](https://pypi.org/project/async-lru/2.0.4/) +- [attrs: 23.1.0](https://pypi.org/project/attrs/23.1.0/) +- [autograd: 1.6.2](https://pypi.org/project/autograd/1.6.2/) +- [autograd-gamma: 0.5.0](https://pypi.org/project/autograd-gamma/0.5.0/) +- [babel: 2.13.1](https://pypi.org/project/babel/2.13.1/) +- [bash-kernel: 0.9.1](https://pypi.org/project/bash-kernel/0.9.1/) +- [beautifulsoup4: 4.12.2](https://pypi.org/project/beautifulsoup4/4.12.2/) +- [bleach: 6.1.0](https://pypi.org/project/bleach/6.1.0/) +- [build: 1.0.3](https://pypi.org/project/build/1.0.3/) +- [cachetools: 5.3.2](https://pypi.org/project/cachetools/5.3.2/) +- [cairocffi: 1.6.1](https://pypi.org/project/cairocffi/1.6.1/) +- [cairosvg: 2.7.1](https://pypi.org/project/cairosvg/2.7.1/) +- [certifi: 2023.11.17](https://pypi.org/project/certifi/2023.11.17/) +- [cffi: 1.16.0](https://pypi.org/project/cffi/1.16.0/) +- [charset-normalizer: 3.3.2](https://pypi.org/project/charset-normalizer/3.3.2/) +- [click: 8.1.7](https://pypi.org/project/click/8.1.7/) +- [click-plugins: 1.1.1](https://pypi.org/project/click-plugins/1.1.1/) +- [cligj: 0.7.2](https://pypi.org/project/cligj/0.7.2/) +- [comm: 0.2.0](https://pypi.org/project/comm/0.2.0/) +- [contourpy: 1.2.0](https://pypi.org/project/contourpy/1.2.0/) +- [coverage: 7.3.2](https://pypi.org/project/coverage/7.3.2/) +- [cssselect2: 0.7.0](https://pypi.org/project/cssselect2/0.7.0/) +- [cycler: 0.12.1](https://pypi.org/project/cycler/0.12.1/) +- [db-dtypes: 1.1.1](https://pypi.org/project/db-dtypes/1.1.1/) +- [debugpy: 1.8.0](https://pypi.org/project/debugpy/1.8.0/) +- [decorator: 5.1.1](https://pypi.org/project/decorator/5.1.1/) +- [defusedxml: 0.7.1](https://pypi.org/project/defusedxml/0.7.1/) +- [descartes: 1.1.0](https://pypi.org/project/descartes/1.1.0/) +- [ebmdatalab: 0.0.30](https://pypi.org/project/ebmdatalab/0.0.30/) +- [exceptiongroup: 1.2.0](https://pypi.org/project/exceptiongroup/1.2.0/) +- [executing: 2.0.1](https://pypi.org/project/executing/2.0.1/) +- [fastjsonschema: 2.19.0](https://pypi.org/project/fastjsonschema/2.19.0/) +- [fiona: 1.9.5](https://pypi.org/project/fiona/1.9.5/) +- [fonttools: 4.45.0](https://pypi.org/project/fonttools/4.45.0/) +- [formulaic: 0.6.6](https://pypi.org/project/formulaic/0.6.6/) +- [fqdn: 1.5.1](https://pypi.org/project/fqdn/1.5.1/) +- [future: 0.18.3](https://pypi.org/project/future/0.18.3/) +- [geopandas: 0.14.1](https://pypi.org/project/geopandas/0.14.1/) +- [google-api-core[grpc]: 2.14.0](https://pypi.org/project/google-api-core/2.14.0/) +- [google-auth: 2.23.4](https://pypi.org/project/google-auth/2.23.4/) +- [google-auth-oauthlib: 1.1.0](https://pypi.org/project/google-auth-oauthlib/1.1.0/) +- [google-cloud-bigquery: 3.13.0](https://pypi.org/project/google-cloud-bigquery/3.13.0/) +- [google-cloud-bigquery-storage: 2.22.0](https://pypi.org/project/google-cloud-bigquery-storage/2.22.0/) +- [google-cloud-core: 2.3.3](https://pypi.org/project/google-cloud-core/2.3.3/) +- [google-crc32c: 1.5.0](https://pypi.org/project/google-crc32c/1.5.0/) +- [google-resumable-media: 2.6.0](https://pypi.org/project/google-resumable-media/2.6.0/) +- [googleapis-common-protos: 1.61.0](https://pypi.org/project/googleapis-common-protos/1.61.0/) +- [grpcio: 1.59.3](https://pypi.org/project/grpcio/1.59.3/) +- [grpcio-status: 1.59.3](https://pypi.org/project/grpcio-status/1.59.3/) +- [idna: 3.4](https://pypi.org/project/idna/3.4/) +- [iniconfig: 2.0.0](https://pypi.org/project/iniconfig/2.0.0/) +- [interface-meta: 1.3.0](https://pypi.org/project/interface-meta/1.3.0/) +- [ipykernel: 6.27.0](https://pypi.org/project/ipykernel/6.27.0/) +- [ipython: 8.17.2](https://pypi.org/project/ipython/8.17.2/) +- [ipywidgets: 8.1.1](https://pypi.org/project/ipywidgets/8.1.1/) +- [isoduration: 20.11.0](https://pypi.org/project/isoduration/20.11.0/) +- [jedi: 0.19.1](https://pypi.org/project/jedi/0.19.1/) +- [jinja2: 3.1.2](https://pypi.org/project/jinja2/3.1.2/) +- [joblib: 1.3.2](https://pypi.org/project/joblib/1.3.2/) +- [json5: 0.9.14](https://pypi.org/project/json5/0.9.14/) +- [jsonpointer: 2.4](https://pypi.org/project/jsonpointer/2.4/) +- [jsonschema[format-nongpl]: 4.20.0](https://pypi.org/project/jsonschema/4.20.0/) +- [jsonschema-specifications: 2023.11.1](https://pypi.org/project/jsonschema-specifications/2023.11.1/) +- [jupyter: 1.0.0](https://pypi.org/project/jupyter/1.0.0/) +- [jupyter-client: 8.6.0](https://pypi.org/project/jupyter-client/8.6.0/) +- [jupyter-console: 6.6.3](https://pypi.org/project/jupyter-console/6.6.3/) +- [jupyter-core: 5.5.0](https://pypi.org/project/jupyter-core/5.5.0/) +- [jupyter-events: 0.9.0](https://pypi.org/project/jupyter-events/0.9.0/) +- [jupyter-lsp: 2.2.0](https://pypi.org/project/jupyter-lsp/2.2.0/) +- [jupyter-server: 2.11.0](https://pypi.org/project/jupyter-server/2.11.0/) +- [jupyter-server-terminals: 0.4.4](https://pypi.org/project/jupyter-server-terminals/0.4.4/) +- [jupyterlab: 4.0.9](https://pypi.org/project/jupyterlab/4.0.9/) +- [jupyterlab-pygments: 0.2.2](https://pypi.org/project/jupyterlab-pygments/0.2.2/) +- [jupyterlab-server: 2.25.2](https://pypi.org/project/jupyterlab-server/2.25.2/) +- [jupyterlab-widgets: 3.0.9](https://pypi.org/project/jupyterlab-widgets/3.0.9/) +- [jupytext: 1.15.2](https://pypi.org/project/jupytext/1.15.2/) +- [kaleido: 0.2.1](https://pypi.org/project/kaleido/0.2.1/) +- [kiwisolver: 1.4.5](https://pypi.org/project/kiwisolver/1.4.5/) +- [lifelines: 0.27.8](https://pypi.org/project/lifelines/0.27.8/) +- [llvmlite: 0.41.1](https://pypi.org/project/llvmlite/0.41.1/) +- [lz4: 4.3.2](https://pypi.org/project/lz4/4.3.2/) +- [markdown-it-py: 3.0.0](https://pypi.org/project/markdown-it-py/3.0.0/) +- [markupsafe: 2.1.3](https://pypi.org/project/markupsafe/2.1.3/) +- [matplotlib: 3.8.2](https://pypi.org/project/matplotlib/3.8.2/) +- [matplotlib-inline: 0.1.6](https://pypi.org/project/matplotlib-inline/0.1.6/) +- [mdit-py-plugins: 0.4.0](https://pypi.org/project/mdit-py-plugins/0.4.0/) +- [mdurl: 0.1.2](https://pypi.org/project/mdurl/0.1.2/) +- [mistune: 3.0.2](https://pypi.org/project/mistune/3.0.2/) +- [nbclient: 0.9.0](https://pypi.org/project/nbclient/0.9.0/) +- [nbconvert: 7.11.0](https://pypi.org/project/nbconvert/7.11.0/) +- [nbformat: 5.9.2](https://pypi.org/project/nbformat/5.9.2/) +- [nbval: 0.10.0](https://pypi.org/project/nbval/0.10.0/) +- [nest-asyncio: 1.5.8](https://pypi.org/project/nest-asyncio/1.5.8/) +- [notebook: 7.0.6](https://pypi.org/project/notebook/7.0.6/) +- [notebook-shim: 0.2.3](https://pypi.org/project/notebook-shim/0.2.3/) +- [numba: 0.58.1](https://pypi.org/project/numba/0.58.1/) +- [numpy: 1.26.2](https://pypi.org/project/numpy/1.26.2/) +- [oauthlib: 3.2.2](https://pypi.org/project/oauthlib/3.2.2/) +- [opensafely-cohort-extractor: 1.90.0](https://pypi.org/project/opensafely-cohort-extractor/1.90.0/) +- [opensafely-matching: 0.2.0](https://pypi.org/project/opensafely-matching/0.2.0/) +- [overrides: 7.4.0](https://pypi.org/project/overrides/7.4.0/) +- [packaging: 23.2](https://pypi.org/project/packaging/23.2/) +- [pandas: 2.1.3](https://pypi.org/project/pandas/2.1.3/) +- [pandas-gbq: 0.19.2](https://pypi.org/project/pandas-gbq/0.19.2/) +- [pandocfilters: 1.5.0](https://pypi.org/project/pandocfilters/1.5.0/) +- [parso: 0.8.3](https://pypi.org/project/parso/0.8.3/) +- [patsy: 0.5.3](https://pypi.org/project/patsy/0.5.3/) +- [pexpect: 4.8.0](https://pypi.org/project/pexpect/4.8.0/) +- [pillow: 10.1.0](https://pypi.org/project/pillow/10.1.0/) +- [pip-tools: 7.3.0](https://pypi.org/project/pip-tools/7.3.0/) +- [platformdirs: 4.0.0](https://pypi.org/project/platformdirs/4.0.0/) +- [plotly: 5.18.0](https://pypi.org/project/plotly/5.18.0/) +- [pluggy: 1.3.0](https://pypi.org/project/pluggy/1.3.0/) +- [prometheus-client: 0.19.0](https://pypi.org/project/prometheus-client/0.19.0/) +- [prompt-toolkit: 3.0.41](https://pypi.org/project/prompt-toolkit/3.0.41/) +- [proto-plus: 1.22.3](https://pypi.org/project/proto-plus/1.22.3/) +- [protobuf: 4.25.1](https://pypi.org/project/protobuf/4.25.1/) +- [psutil: 5.9.6](https://pypi.org/project/psutil/5.9.6/) +- [ptyprocess: 0.7.0](https://pypi.org/project/ptyprocess/0.7.0/) +- [pure-eval: 0.2.2](https://pypi.org/project/pure-eval/0.2.2/) +- [py: 1.11.0](https://pypi.org/project/py/1.11.0/) +- [pyarrow: 14.0.1](https://pypi.org/project/pyarrow/14.0.1/) +- [pyasn1: 0.5.1](https://pypi.org/project/pyasn1/0.5.1/) +- [pyasn1-modules: 0.3.0](https://pypi.org/project/pyasn1-modules/0.3.0/) +- [pycparser: 2.21](https://pypi.org/project/pycparser/2.21/) +- [pydata-google-auth: 1.8.2](https://pypi.org/project/pydata-google-auth/1.8.2/) +- [pygments: 2.17.1](https://pypi.org/project/pygments/2.17.1/) +- [pyparsing: 3.1.1](https://pypi.org/project/pyparsing/3.1.1/) +- [pyproj: 3.6.1](https://pypi.org/project/pyproj/3.6.1/) +- [pyproject-hooks: 1.0.0](https://pypi.org/project/pyproject-hooks/1.0.0/) +- [pytest: 7.4.3](https://pypi.org/project/pytest/7.4.3/) +- [python-dateutil: 2.8.2](https://pypi.org/project/python-dateutil/2.8.2/) +- [python-json-logger: 2.0.7](https://pypi.org/project/python-json-logger/2.0.7/) +- [pytz: 2023.3.post1](https://pypi.org/project/pytz/2023.3.post1/) +- [pyyaml: 6.0.1](https://pypi.org/project/pyyaml/6.0.1/) +- [pyzmq: 25.1.1](https://pypi.org/project/pyzmq/25.1.1/) +- [qtconsole: 5.5.1](https://pypi.org/project/qtconsole/5.5.1/) +- [qtpy: 2.4.1](https://pypi.org/project/qtpy/2.4.1/) +- [referencing: 0.31.0](https://pypi.org/project/referencing/0.31.0/) +- [requests: 2.31.0](https://pypi.org/project/requests/2.31.0/) +- [requests-oauthlib: 1.3.1](https://pypi.org/project/requests-oauthlib/1.3.1/) +- [retry: 0.9.2](https://pypi.org/project/retry/0.9.2/) +- [rfc3339-validator: 0.1.4](https://pypi.org/project/rfc3339-validator/0.1.4/) +- [rfc3986-validator: 0.1.1](https://pypi.org/project/rfc3986-validator/0.1.1/) +- [rpds-py: 0.13.1](https://pypi.org/project/rpds-py/0.13.1/) +- [rsa: 4.9](https://pypi.org/project/rsa/4.9/) +- [scikit-learn: 1.3.2](https://pypi.org/project/scikit-learn/1.3.2/) +- [scipy: 1.11.4](https://pypi.org/project/scipy/1.11.4/) +- [seaborn: 0.13.0](https://pypi.org/project/seaborn/0.13.0/) +- [send2trash: 1.8.2](https://pypi.org/project/send2trash/1.8.2/) +- [shapely: 2.0.2](https://pypi.org/project/shapely/2.0.2/) +- [six: 1.16.0](https://pypi.org/project/six/1.16.0/) +- [sniffio: 1.3.0](https://pypi.org/project/sniffio/1.3.0/) +- [soupsieve: 2.5](https://pypi.org/project/soupsieve/2.5/) +- [sqlparse: 0.4.4](https://pypi.org/project/sqlparse/0.4.4/) +- [stack-data: 0.6.3](https://pypi.org/project/stack-data/0.6.3/) +- [statsmodels: 0.14.0](https://pypi.org/project/statsmodels/0.14.0/) +- [structlog: 23.2.0](https://pypi.org/project/structlog/23.2.0/) +- [tabulate: 0.9.0](https://pypi.org/project/tabulate/0.9.0/) +- [tenacity: 8.2.3](https://pypi.org/project/tenacity/8.2.3/) +- [terminado: 0.18.0](https://pypi.org/project/terminado/0.18.0/) +- [threadpoolctl: 3.2.0](https://pypi.org/project/threadpoolctl/3.2.0/) +- [tinycss2: 1.2.1](https://pypi.org/project/tinycss2/1.2.1/) +- [toml: 0.10.2](https://pypi.org/project/toml/0.10.2/) +- [tomli: 2.0.1](https://pypi.org/project/tomli/2.0.1/) +- [tornado: 6.3.3](https://pypi.org/project/tornado/6.3.3/) +- [tqdm: 4.66.1](https://pypi.org/project/tqdm/4.66.1/) +- [traitlets: 5.13.0](https://pypi.org/project/traitlets/5.13.0/) +- [types-python-dateutil: 2.8.19.14](https://pypi.org/project/types-python-dateutil/2.8.19.14/) +- [typing-extensions: 4.8.0](https://pypi.org/project/typing-extensions/4.8.0/) +- [tzdata: 2023.3](https://pypi.org/project/tzdata/2023.3/) +- [upsetplot: 0.8.0](https://pypi.org/project/upsetplot/0.8.0/) +- [uri-template: 1.3.0](https://pypi.org/project/uri-template/1.3.0/) +- [urllib3: 2.1.0](https://pypi.org/project/urllib3/2.1.0/) +- [venn: 0.1.3](https://pypi.org/project/venn/0.1.3/) +- [wcwidth: 0.2.11](https://pypi.org/project/wcwidth/0.2.11/) +- [webcolors: 1.13](https://pypi.org/project/webcolors/1.13/) +- [webencodings: 0.5.1](https://pypi.org/project/webencodings/0.5.1/) +- [websocket-client: 1.6.4](https://pypi.org/project/websocket-client/1.6.4/) +- [wheel: 0.41.3](https://pypi.org/project/wheel/0.41.3/) +- [widgetsnbextension: 4.0.9](https://pypi.org/project/widgetsnbextension/4.0.9/) +- [wrapt: 1.16.0](https://pypi.org/project/wrapt/1.16.0/) + From 7eff38f95f26578208660dabfeb0ef3ba8cffcfc Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Mon, 27 Nov 2023 14:01:59 +0000 Subject: [PATCH 06/11] Rework documentation - Completely new user-facing README.md content - DEVELOPERS.md with playbook style info - Issue template for requesting packages --- .github/ISSUE_TEMPLATE/new-package.md | 29 +++++++++++ DEVELOPERS.md | 71 +++++++++++++++++++++++++++ README.md | 60 +++++++++++++++++++--- justfile | 2 +- 4 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/new-package.md create mode 100644 DEVELOPERS.md diff --git a/.github/ISSUE_TEMPLATE/new-package.md b/.github/ISSUE_TEMPLATE/new-package.md new file mode 100644 index 0000000..6ed3097 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new-package.md @@ -0,0 +1,29 @@ +--- +name: New Package +about: Request a new python package and/or system library be installed +title: "Request a New Package" +labels: 'new-package' + +--- + +Please fill in the fields below to request new packages for the OpenSAFELY python image. + + +### Python package(s) you wish to add to the image + + + + +### System Libraries + + + + +### Requesting Project + + + + +### Rationale + + diff --git a/DEVELOPERS.md b/DEVELOPERS.md new file mode 100644 index 0000000..1c9deea --- /dev/null +++ b/DEVELOPERS.md @@ -0,0 +1,71 @@ +# Basics + +Each major version has its configuration in a subdirectory named after the +version, e.g. ./v1/ has all the configuration for the `v1` image. + +Inside each version's directory there are 4 main files: + +- `env`: environment variables used to parameterise the Docker/docker-compose + files: + - `BASE`: the base Ubuntu version to build from, e.g. `22.04` + - `MAJOR_VERSION`: this shoud match the directory name. +- `dependencies.txt`: the Ubuntu packages that need to be installed +- `build-dependencies.txt`: the Ubuntu package needed to *build* any + dependencies (these will *not* be included in the final image). +- `requirements.in`: the list of packages to install (*without* version + specfiers, unless needed for some reason). + +There will also be two autogenerated files: + +- `requirements.txt`: the fully pinned set of python dependences generated with + `pip-compile`. +- `packages.md`: generated user facing documentation of package versions + + +Use just to build and test image versions: + +``` +just build v2 +just test v2 +``` + + +## Add a new package to existing version + +* Add the new package without version specifier to all relevant version's + `requirement.in` files +* For each version, do the following: + * Run `just update $VERSION`. This will update pacakges, then build and + test the new image. + * If the build fails, depending on the error message: + - you may need to add a new system package to `dependencies.txt` + - you may need to add a new build dependency package to + `build-dependencies.txt` + - you may need to finesse the tests for poorly packaged libraries: see + [`BAD_PACKAGES`](./tests/test_import.py) + * Inspect the changes to requirements.txt + - ensure no pre-existing package has been updated by this change. + + +## Create a new version + +TODO, but basically, `cp -a v$N v${N+1}` and edit. + + +## Publishing + +> ![WARNING] +> By default, these images are published via CI, so only do this if you know +> you need to, e.g. testing publishing a new version + +To publish a version locally, you will need to be logged in to ghcr.io with the +right permissions (`docker login ghcr.io`) + +By default, this command is a dry run, and will show you the commands it *will* run: + +`just publish $version` + +To run for real, pass `true`: + +`just publish $version true` + diff --git a/README.md b/README.md index ba68d92..19fe6f9 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,57 @@ -# OpenSAFELY Python image +# OpenSAFELY Python Runtime Image -This is a dockerfile for running python in an OpenSAFELY -environment. +This repo manages the Docker image for the OpenSAFELY Python runtime. These +images are based on a base Ubuntu LTS version, and come pre-installed with +a set of standard scientific python packages. -To make a new release, use conventional commits to bump version -(i.e. subject lines starting `feat:` or `fix:`) +The current latest version is `v2`, and you should use that unless you have +a specific reason. You can use it in your `project.yaml` like so: -See `requirements.txt` for current available packages and versions +``` +actions: + my_action: + run: python:v2 my_script.py ... +``` + +## Version List + +Current available versions, in reverse chronological order: + + - v2: Ubuntu 22.04 and Python 3.10 - [full package list](v2/packages.md) + - v1: Ubuntu 20.04 and Python 3.8 - [full package list](v1/packages.md) + +### Legacy version: `latest` + +Initially, OpenSAFELY only had one version of the python image. This is the +`v1` image, but was originally published under the `:latest` tag. You can use +either `v1` or `latest` - they are the same version. In future, we may +deprecate the `latest` tag and require users to update their `project.yaml` to +use `v1` instead of `latest`. + + +## Update Policy + +### Python Package Versions + +For each version of the python image, we do *not* upgade the python packages +from their initially installed version. This is done in order to backwards +compatiblity and thus ensure reproduciblity. We do [add new packages on user +request](https://github.com/opensafely-core/python-dockerissues/new?template=new-package.md), +as such a change will not break backwards incompatibilty. + +Occasionally, we will create a new major version of the image with all packages +updated to their latest version. We may also possibly remove old and uneeded +pacakges at this point. A new major version is chance to make backwards +incompatible changes, which is occasionally needed. + +Once this new version of the image is intially released, its set of package +versions will be frozen and no longer updatable. + +### Operating System Packages + +We *do* update the underlying operating system packages on a regular basis, in +order to apply security updates to the base system. It is very unlikely that +this will break backwards compatibility, as these are a small set very +conservative set of updates to address security issues. + +We also add additional operating system libraries on user request. diff --git a/justfile b/justfile index cdcf479..996271b 100644 --- a/justfile +++ b/justfile @@ -20,7 +20,7 @@ test version *args="tests -v": (build version) update version *args="": (build version) docker-compose --env-file {{ version }}/env run --rm -v $PWD:/workspace base pip-compile {{ args }} {{ version }}/requirements.in -o {{ version }}/requirements.txt {{ just_executable() }} render {{ version }} - + {{ just_executable() }} test {{ version }} # render package version information render version *args: From 45ab7ddeb29c4014fb086d0f80c273a7b77b9ee8 Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Tue, 5 Dec 2023 14:53:29 +0000 Subject: [PATCH 07/11] Include package metadata in image for local interrogation Seems like a useful thing to bundle documentation. --- Dockerfile | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7e3eec0..8bdf3af 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,9 +20,9 @@ ARG BASE # ACTION_EXEC sets the default executable for the entrypoint in the base-docker image ENV ACTION_EXEC=python MAJOR_VERSION=${MAJOR_VERSION} BASE=${BASE} -COPY ${MAJOR_VERSION}/dependencies.txt /root/dependencies.txt +COPY ${MAJOR_VERSION}/dependencies.txt /opt/dependencies.txt # use space efficient utility from base image -RUN /root/docker-apt-install.sh /root/dependencies.txt +RUN /root/docker-apt-install.sh /opt/dependencies.txt # now we have python, set up a venv to install packages to, for isolation from # system python libraries @@ -42,16 +42,17 @@ FROM base-python as builder ARG MAJOR_VERSION # install build time dependencies -COPY ${MAJOR_VERSION}/build-dependencies.txt /root/build-dependencies.txt -RUN /root/docker-apt-install.sh /root/build-dependencies.txt +COPY ${MAJOR_VERSION}/build-dependencies.txt /opt/build-dependencies.txt +RUN /root/docker-apt-install.sh /opt/build-dependencies.txt -COPY ${MAJOR_VERSION}/requirements.txt /root/requirements.txt +COPY ${MAJOR_VERSION}/requirements.txt /opt/requirements.txt +COPY ${MAJOR_VERSION}/packages.md /opt/packages.md # Note: the mount command does two things: 1) caches across builds to speed up # local development and 2) ensures the pip cache does not get committed to the # layer (which is why we ignore DL3042). # hadolint ignore=DL3042 RUN --mount=type=cache,target=/root/.cache \ - python -m pip install --requirement /root/requirements.txt + python -m pip install --requirement /opt/requirements.txt ################################################ # @@ -70,7 +71,7 @@ LABEL org.opencontainers.image.title="python:${MAJOR_VERSION}" \ org.opensafely.action="python:${MAJOR_VERSION}" # copy venv over from builder image -COPY --from=builder /opt/venv /opt/venv +COPY --from=builder /opt/ /opt/ # tag with build info as the very last step, as it will never be cacheable ARG BUILD_DATE From b9032c4ff2faf3de523e1c034a51f6a8f897446f Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Tue, 5 Dec 2023 14:57:49 +0000 Subject: [PATCH 08/11] Use compose v2 Also, updated missed rendering of v1/packages.md --- justfile | 8 +- v1/packages.md | 290 ++++++++++++++++++++++++------------------------- 2 files changed, 149 insertions(+), 149 deletions(-) diff --git a/justfile b/justfile index 996271b..582c373 100644 --- a/justfile +++ b/justfile @@ -8,23 +8,23 @@ export REVISION := `git rev-parse --short HEAD` # build docker image for version build version target="python" *args="": - docker-compose --env-file {{ version }}/env build --pull {{ args }} {{ target }} + docker compose --env-file {{ version }}/env build --pull {{ args }} {{ target }} # test docker image for version test version *args="tests -v": (build version) - docker-compose --env-file {{ version }}/env run --rm -v $PWD:/workspace python pytest {{ args }} + docker compose --env-file {{ version }}/env run --rm -v $PWD:/workspace python pytest {{ args }} # run pip-compile to add new dependencies, or update existing ones with --upgrade update version *args="": (build version) - docker-compose --env-file {{ version }}/env run --rm -v $PWD:/workspace base pip-compile {{ args }} {{ version }}/requirements.in -o {{ version }}/requirements.txt + docker compose --env-file {{ version }}/env run --rm -v $PWD:/workspace base pip-compile {{ args }} {{ version }}/requirements.in -o {{ version }}/requirements.txt {{ just_executable() }} render {{ version }} {{ just_executable() }} test {{ version }} # render package version information render version *args: - docker-compose --env-file {{ version }}/env run --rm -v $PWD:/workspace python ./scripts/render.py {{ args }} > {{ version }}/packages.md + docker compose --env-file {{ version }}/env run --rm -v $PWD:/workspace python ./scripts/render.py {{ args }} > {{ version }}/packages.md # run linters diff --git a/v1/packages.md b/v1/packages.md index 58476de..e578dc2 100644 --- a/v1/packages.md +++ b/v1/packages.md @@ -1,145 +1,145 @@ -# Package Versions for v1 - -This python:v1 OpenSAFELY image is based on Ubuntu 20.04 with Python 3.8.10. - -## Packages - -It comes pre-installed with a standard set of python packages. - -- [astor: 0.8.1](https://pypi.org/project/astor/0.8.1/) -- [attrs: 19.3.0](https://pypi.org/project/attrs/19.3.0/) -- [autograd: 1.3](https://pypi.org/project/autograd/1.3/) -- [autograd-gamma: 0.5.0](https://pypi.org/project/autograd-gamma/0.5.0/) -- [backcall: 0.1.0](https://pypi.org/project/backcall/0.1.0/) -- [bash-kernel: 0.7.2](https://pypi.org/project/bash-kernel/0.7.2/) -- [bleach: 3.1.2](https://pypi.org/project/bleach/3.1.2/) -- [cachetools: 4.0.0](https://pypi.org/project/cachetools/4.0.0/) -- [cairocffi: 1.4.0](https://pypi.org/project/cairocffi/1.4.0/) -- [cairosvg: 2.5.2](https://pypi.org/project/cairosvg/2.5.2/) -- [certifi: 2019.11.28](https://pypi.org/project/certifi/2019.11.28/) -- [cffi: 1.15.1](https://pypi.org/project/cffi/1.15.1/) -- [chardet: 3.0.4](https://pypi.org/project/chardet/3.0.4/) -- [click: 7.0](https://pypi.org/project/click/7.0/) -- [click-plugins: 1.1.1](https://pypi.org/project/click-plugins/1.1.1/) -- [cligj: 0.5.0](https://pypi.org/project/cligj/0.5.0/) -- [coverage: 4.5.4](https://pypi.org/project/coverage/4.5.4/) -- [cssselect2: 0.7.0](https://pypi.org/project/cssselect2/0.7.0/) -- [cycler: 0.10.0](https://pypi.org/project/cycler/0.10.0/) -- [decorator: 4.4.1](https://pypi.org/project/decorator/4.4.1/) -- [defusedxml: 0.6.0](https://pypi.org/project/defusedxml/0.6.0/) -- [descartes: 1.1.0](https://pypi.org/project/descartes/1.1.0/) -- [ebmdatalab: 0.0.30](https://pypi.org/project/ebmdatalab/0.0.30/) -- [entrypoints: 0.3](https://pypi.org/project/entrypoints/0.3/) -- [fiona: 1.8.13](https://pypi.org/project/fiona/1.8.13/) -- [formulaic: 0.2.4](https://pypi.org/project/formulaic/0.2.4/) -- [future: 0.18.2](https://pypi.org/project/future/0.18.2/) -- [geopandas: 0.6.3](https://pypi.org/project/geopandas/0.6.3/) -- [google-api-core: 1.16.0](https://pypi.org/project/google-api-core/1.16.0/) -- [google-auth: 1.11.0](https://pypi.org/project/google-auth/1.11.0/) -- [google-auth-oauthlib: 0.4.1](https://pypi.org/project/google-auth-oauthlib/0.4.1/) -- [google-cloud-bigquery: 1.24.0](https://pypi.org/project/google-cloud-bigquery/1.24.0/) -- [google-cloud-core: 1.3.0](https://pypi.org/project/google-cloud-core/1.3.0/) -- [google-resumable-media: 0.5.0](https://pypi.org/project/google-resumable-media/0.5.0/) -- [googleapis-common-protos: 1.51.0](https://pypi.org/project/googleapis-common-protos/1.51.0/) -- [idna: 2.8](https://pypi.org/project/idna/2.8/) -- [interface-meta: 1.2.4](https://pypi.org/project/interface-meta/1.2.4/) -- [ipykernel: 5.1.4](https://pypi.org/project/ipykernel/5.1.4/) -- [ipython: 7.12.0](https://pypi.org/project/ipython/7.12.0/) -- [ipython-genutils: 0.2.0](https://pypi.org/project/ipython-genutils/0.2.0/) -- [ipywidgets: 7.5.1](https://pypi.org/project/ipywidgets/7.5.1/) -- [jedi: 0.16.0](https://pypi.org/project/jedi/0.16.0/) -- [jinja2: 2.11.1](https://pypi.org/project/jinja2/2.11.1/) -- [joblib: 1.0.1](https://pypi.org/project/joblib/1.0.1/) -- [json5: 0.9.0](https://pypi.org/project/json5/0.9.0/) -- [jsonschema: 3.2.0](https://pypi.org/project/jsonschema/3.2.0/) -- [jupyter: 1.0.0](https://pypi.org/project/jupyter/1.0.0/) -- [jupyter-client: 5.3.4](https://pypi.org/project/jupyter-client/5.3.4/) -- [jupyter-console: 6.1.0](https://pypi.org/project/jupyter-console/6.1.0/) -- [jupyter-core: 4.6.1](https://pypi.org/project/jupyter-core/4.6.1/) -- [jupyterlab: 1.2.6](https://pypi.org/project/jupyterlab/1.2.6/) -- [jupyterlab-server: 1.0.6](https://pypi.org/project/jupyterlab-server/1.0.6/) -- [jupytext: 1.3.3](https://pypi.org/project/jupytext/1.3.3/) -- [kaleido: 0.2.1](https://pypi.org/project/kaleido/0.2.1/) -- [kiwisolver: 1.1.0](https://pypi.org/project/kiwisolver/1.1.0/) -- [lifelines: 0.26.4](https://pypi.org/project/lifelines/0.26.4/) -- [llvmlite: 0.34.0](https://pypi.org/project/llvmlite/0.34.0/) -- [lz4: 3.1.3](https://pypi.org/project/lz4/3.1.3/) -- [markupsafe: 1.1.1](https://pypi.org/project/markupsafe/1.1.1/) -- [matplotlib: 3.1.3](https://pypi.org/project/matplotlib/3.1.3/) -- [mistune: 0.8.4](https://pypi.org/project/mistune/0.8.4/) -- [more-itertools: 8.2.0](https://pypi.org/project/more-itertools/8.2.0/) -- [munch: 2.5.0](https://pypi.org/project/munch/2.5.0/) -- [nbconvert: 5.6.1](https://pypi.org/project/nbconvert/5.6.1/) -- [nbformat: 5.0.4](https://pypi.org/project/nbformat/5.0.4/) -- [nbval: 0.9.4](https://pypi.org/project/nbval/0.9.4/) -- [notebook: 6.0.3](https://pypi.org/project/notebook/6.0.3/) -- [numba: 0.51.2](https://pypi.org/project/numba/0.51.2/) -- [numpy: 1.18.1](https://pypi.org/project/numpy/1.18.1/) -- [oauthlib: 3.1.0](https://pypi.org/project/oauthlib/3.1.0/) -- [opensafely-cohort-extractor: 1.88.0](https://pypi.org/project/opensafely-cohort-extractor/1.88.0/) -- [opensafely-matching: 0.2.0](https://pypi.org/project/opensafely-matching/0.2.0/) -- [packaging: 20.1](https://pypi.org/project/packaging/20.1/) -- [pandas: 1.0.1](https://pypi.org/project/pandas/1.0.1/) -- [pandas-gbq: 0.13.0](https://pypi.org/project/pandas-gbq/0.13.0/) -- [pandocfilters: 1.4.2](https://pypi.org/project/pandocfilters/1.4.2/) -- [parso: 0.6.1](https://pypi.org/project/parso/0.6.1/) -- [patsy: 0.5.1](https://pypi.org/project/patsy/0.5.1/) -- [pep517: 0.10.0](https://pypi.org/project/pep517/0.10.0/) -- [pexpect: 4.8.0](https://pypi.org/project/pexpect/4.8.0/) -- [pickleshare: 0.7.5](https://pypi.org/project/pickleshare/0.7.5/) -- [pillow: 8.1.0](https://pypi.org/project/pillow/8.1.0/) -- [pip-tools: 6.2.0](https://pypi.org/project/pip-tools/6.2.0/) -- [plotly: 4.5.0](https://pypi.org/project/plotly/4.5.0/) -- [pluggy: 0.13.1](https://pypi.org/project/pluggy/0.13.1/) -- [prometheus-client: 0.7.1](https://pypi.org/project/prometheus-client/0.7.1/) -- [prompt-toolkit: 3.0.3](https://pypi.org/project/prompt-toolkit/3.0.3/) -- [protobuf: 3.11.3](https://pypi.org/project/protobuf/3.11.3/) -- [ptyprocess: 0.6.0](https://pypi.org/project/ptyprocess/0.6.0/) -- [py: 1.8.1](https://pypi.org/project/py/1.8.1/) -- [pyarrow: 3.0.0](https://pypi.org/project/pyarrow/3.0.0/) -- [pyasn1: 0.4.8](https://pypi.org/project/pyasn1/0.4.8/) -- [pyasn1-modules: 0.2.8](https://pypi.org/project/pyasn1-modules/0.2.8/) -- [pycparser: 2.21](https://pypi.org/project/pycparser/2.21/) -- [pydata-google-auth: 0.3.0](https://pypi.org/project/pydata-google-auth/0.3.0/) -- [pygments: 2.5.2](https://pypi.org/project/pygments/2.5.2/) -- [pyparsing: 2.4.6](https://pypi.org/project/pyparsing/2.4.6/) -- [pyproj: 2.4.2.post1](https://pypi.org/project/pyproj/2.4.2.post1/) -- [pyrsistent: 0.15.7](https://pypi.org/project/pyrsistent/0.15.7/) -- [pytest: 5.3.5](https://pypi.org/project/pytest/5.3.5/) -- [python-dateutil: 2.8.1](https://pypi.org/project/python-dateutil/2.8.1/) -- [pytz: 2019.3](https://pypi.org/project/pytz/2019.3/) -- [pyyaml: 5.3](https://pypi.org/project/pyyaml/5.3/) -- [pyzmq: 18.1.1](https://pypi.org/project/pyzmq/18.1.1/) -- [qtconsole: 4.6.0](https://pypi.org/project/qtconsole/4.6.0/) -- [requests: 2.22.0](https://pypi.org/project/requests/2.22.0/) -- [requests-oauthlib: 1.3.0](https://pypi.org/project/requests-oauthlib/1.3.0/) -- [retry: 0.9.2](https://pypi.org/project/retry/0.9.2/) -- [retrying: 1.3.3](https://pypi.org/project/retrying/1.3.3/) -- [rsa: 4.0](https://pypi.org/project/rsa/4.0/) -- [scikit-learn: 0.24.1](https://pypi.org/project/scikit-learn/0.24.1/) -- [scipy: 1.4.1](https://pypi.org/project/scipy/1.4.1/) -- [seaborn: 0.10.0](https://pypi.org/project/seaborn/0.10.0/) -- [send2trash: 1.5.0](https://pypi.org/project/send2trash/1.5.0/) -- [shapely: 1.7.0](https://pypi.org/project/shapely/1.7.0/) -- [six: 1.14.0](https://pypi.org/project/six/1.14.0/) -- [sqlparse: 0.4.1](https://pypi.org/project/sqlparse/0.4.1/) -- [statsmodels: 0.11.0](https://pypi.org/project/statsmodels/0.11.0/) -- [structlog: 20.2.0](https://pypi.org/project/structlog/20.2.0/) -- [tabulate: 0.8.7](https://pypi.org/project/tabulate/0.8.7/) -- [terminado: 0.8.3](https://pypi.org/project/terminado/0.8.3/) -- [testpath: 0.4.4](https://pypi.org/project/testpath/0.4.4/) -- [threadpoolctl: 2.1.0](https://pypi.org/project/threadpoolctl/2.1.0/) -- [tinycss2: 1.2.1](https://pypi.org/project/tinycss2/1.2.1/) -- [toml: 0.10.2](https://pypi.org/project/toml/0.10.2/) -- [tornado: 6.0.3](https://pypi.org/project/tornado/6.0.3/) -- [tqdm: 4.42.1](https://pypi.org/project/tqdm/4.42.1/) -- [traitlets: 4.3.3](https://pypi.org/project/traitlets/4.3.3/) -- [upsetplot: 0.6.1](https://pypi.org/project/upsetplot/0.6.1/) -- [urllib3: 1.25.8](https://pypi.org/project/urllib3/1.25.8/) -- [venn: 0.1.3](https://pypi.org/project/venn/0.1.3/) -- [wcwidth: 0.1.8](https://pypi.org/project/wcwidth/0.1.8/) -- [webencodings: 0.5.1](https://pypi.org/project/webencodings/0.5.1/) -- [wheel: 0.36.2](https://pypi.org/project/wheel/0.36.2/) -- [widgetsnbextension: 3.5.1](https://pypi.org/project/widgetsnbextension/3.5.1/) -- [wrapt: 1.13.3](https://pypi.org/project/wrapt/1.13.3/) - +# Package Versions for v1 + +This python:v1 OpenSAFELY image is based on Ubuntu 20.04 with Python 3.8.10. + +## Packages + +It comes pre-installed with a standard set of python packages. + +- [astor: 0.8.1](https://pypi.org/project/astor/0.8.1/) +- [attrs: 19.3.0](https://pypi.org/project/attrs/19.3.0/) +- [autograd: 1.3](https://pypi.org/project/autograd/1.3/) +- [autograd-gamma: 0.5.0](https://pypi.org/project/autograd-gamma/0.5.0/) +- [backcall: 0.1.0](https://pypi.org/project/backcall/0.1.0/) +- [bash-kernel: 0.7.2](https://pypi.org/project/bash-kernel/0.7.2/) +- [bleach: 3.1.2](https://pypi.org/project/bleach/3.1.2/) +- [cachetools: 4.0.0](https://pypi.org/project/cachetools/4.0.0/) +- [cairocffi: 1.4.0](https://pypi.org/project/cairocffi/1.4.0/) +- [cairosvg: 2.5.2](https://pypi.org/project/cairosvg/2.5.2/) +- [certifi: 2019.11.28](https://pypi.org/project/certifi/2019.11.28/) +- [cffi: 1.15.1](https://pypi.org/project/cffi/1.15.1/) +- [chardet: 3.0.4](https://pypi.org/project/chardet/3.0.4/) +- [click: 7.0](https://pypi.org/project/click/7.0/) +- [click-plugins: 1.1.1](https://pypi.org/project/click-plugins/1.1.1/) +- [cligj: 0.5.0](https://pypi.org/project/cligj/0.5.0/) +- [coverage: 4.5.4](https://pypi.org/project/coverage/4.5.4/) +- [cssselect2: 0.7.0](https://pypi.org/project/cssselect2/0.7.0/) +- [cycler: 0.10.0](https://pypi.org/project/cycler/0.10.0/) +- [decorator: 4.4.1](https://pypi.org/project/decorator/4.4.1/) +- [defusedxml: 0.6.0](https://pypi.org/project/defusedxml/0.6.0/) +- [descartes: 1.1.0](https://pypi.org/project/descartes/1.1.0/) +- [ebmdatalab: 0.0.30](https://pypi.org/project/ebmdatalab/0.0.30/) +- [entrypoints: 0.3](https://pypi.org/project/entrypoints/0.3/) +- [fiona: 1.8.13](https://pypi.org/project/fiona/1.8.13/) +- [formulaic: 0.2.4](https://pypi.org/project/formulaic/0.2.4/) +- [future: 0.18.2](https://pypi.org/project/future/0.18.2/) +- [geopandas: 0.6.3](https://pypi.org/project/geopandas/0.6.3/) +- [google-api-core: 1.16.0](https://pypi.org/project/google-api-core/1.16.0/) +- [google-auth: 1.11.0](https://pypi.org/project/google-auth/1.11.0/) +- [google-auth-oauthlib: 0.4.1](https://pypi.org/project/google-auth-oauthlib/0.4.1/) +- [google-cloud-bigquery: 1.24.0](https://pypi.org/project/google-cloud-bigquery/1.24.0/) +- [google-cloud-core: 1.3.0](https://pypi.org/project/google-cloud-core/1.3.0/) +- [google-resumable-media: 0.5.0](https://pypi.org/project/google-resumable-media/0.5.0/) +- [googleapis-common-protos: 1.51.0](https://pypi.org/project/googleapis-common-protos/1.51.0/) +- [idna: 2.8](https://pypi.org/project/idna/2.8/) +- [interface-meta: 1.2.4](https://pypi.org/project/interface-meta/1.2.4/) +- [ipykernel: 5.1.4](https://pypi.org/project/ipykernel/5.1.4/) +- [ipython: 7.12.0](https://pypi.org/project/ipython/7.12.0/) +- [ipython-genutils: 0.2.0](https://pypi.org/project/ipython-genutils/0.2.0/) +- [ipywidgets: 7.5.1](https://pypi.org/project/ipywidgets/7.5.1/) +- [jedi: 0.16.0](https://pypi.org/project/jedi/0.16.0/) +- [jinja2: 2.11.1](https://pypi.org/project/jinja2/2.11.1/) +- [joblib: 1.0.1](https://pypi.org/project/joblib/1.0.1/) +- [json5: 0.9.0](https://pypi.org/project/json5/0.9.0/) +- [jsonschema: 3.2.0](https://pypi.org/project/jsonschema/3.2.0/) +- [jupyter: 1.0.0](https://pypi.org/project/jupyter/1.0.0/) +- [jupyter-client: 5.3.4](https://pypi.org/project/jupyter-client/5.3.4/) +- [jupyter-console: 6.1.0](https://pypi.org/project/jupyter-console/6.1.0/) +- [jupyter-core: 4.6.1](https://pypi.org/project/jupyter-core/4.6.1/) +- [jupyterlab: 1.2.6](https://pypi.org/project/jupyterlab/1.2.6/) +- [jupyterlab-server: 1.0.6](https://pypi.org/project/jupyterlab-server/1.0.6/) +- [jupytext: 1.3.3](https://pypi.org/project/jupytext/1.3.3/) +- [kaleido: 0.2.1](https://pypi.org/project/kaleido/0.2.1/) +- [kiwisolver: 1.1.0](https://pypi.org/project/kiwisolver/1.1.0/) +- [lifelines: 0.26.4](https://pypi.org/project/lifelines/0.26.4/) +- [llvmlite: 0.34.0](https://pypi.org/project/llvmlite/0.34.0/) +- [lz4: 3.1.3](https://pypi.org/project/lz4/3.1.3/) +- [markupsafe: 1.1.1](https://pypi.org/project/markupsafe/1.1.1/) +- [matplotlib: 3.1.3](https://pypi.org/project/matplotlib/3.1.3/) +- [mistune: 0.8.4](https://pypi.org/project/mistune/0.8.4/) +- [more-itertools: 8.2.0](https://pypi.org/project/more-itertools/8.2.0/) +- [munch: 2.5.0](https://pypi.org/project/munch/2.5.0/) +- [nbconvert: 5.6.1](https://pypi.org/project/nbconvert/5.6.1/) +- [nbformat: 5.0.4](https://pypi.org/project/nbformat/5.0.4/) +- [nbval: 0.9.4](https://pypi.org/project/nbval/0.9.4/) +- [notebook: 6.0.3](https://pypi.org/project/notebook/6.0.3/) +- [numba: 0.51.2](https://pypi.org/project/numba/0.51.2/) +- [numpy: 1.18.1](https://pypi.org/project/numpy/1.18.1/) +- [oauthlib: 3.1.0](https://pypi.org/project/oauthlib/3.1.0/) +- [opensafely-cohort-extractor: 1.88.0](https://pypi.org/project/opensafely-cohort-extractor/1.88.0/) +- [opensafely-matching: 0.2.0](https://pypi.org/project/opensafely-matching/0.2.0/) +- [packaging: 20.1](https://pypi.org/project/packaging/20.1/) +- [pandas: 1.0.1](https://pypi.org/project/pandas/1.0.1/) +- [pandas-gbq: 0.13.0](https://pypi.org/project/pandas-gbq/0.13.0/) +- [pandocfilters: 1.4.2](https://pypi.org/project/pandocfilters/1.4.2/) +- [parso: 0.6.1](https://pypi.org/project/parso/0.6.1/) +- [patsy: 0.5.1](https://pypi.org/project/patsy/0.5.1/) +- [pep517: 0.10.0](https://pypi.org/project/pep517/0.10.0/) +- [pexpect: 4.8.0](https://pypi.org/project/pexpect/4.8.0/) +- [pickleshare: 0.7.5](https://pypi.org/project/pickleshare/0.7.5/) +- [pillow: 8.1.0](https://pypi.org/project/pillow/8.1.0/) +- [pip-tools: 6.2.0](https://pypi.org/project/pip-tools/6.2.0/) +- [plotly: 4.5.0](https://pypi.org/project/plotly/4.5.0/) +- [pluggy: 0.13.1](https://pypi.org/project/pluggy/0.13.1/) +- [prometheus-client: 0.7.1](https://pypi.org/project/prometheus-client/0.7.1/) +- [prompt-toolkit: 3.0.3](https://pypi.org/project/prompt-toolkit/3.0.3/) +- [protobuf: 3.11.3](https://pypi.org/project/protobuf/3.11.3/) +- [ptyprocess: 0.6.0](https://pypi.org/project/ptyprocess/0.6.0/) +- [py: 1.8.1](https://pypi.org/project/py/1.8.1/) +- [pyarrow: 3.0.0](https://pypi.org/project/pyarrow/3.0.0/) +- [pyasn1: 0.4.8](https://pypi.org/project/pyasn1/0.4.8/) +- [pyasn1-modules: 0.2.8](https://pypi.org/project/pyasn1-modules/0.2.8/) +- [pycparser: 2.21](https://pypi.org/project/pycparser/2.21/) +- [pydata-google-auth: 0.3.0](https://pypi.org/project/pydata-google-auth/0.3.0/) +- [pygments: 2.5.2](https://pypi.org/project/pygments/2.5.2/) +- [pyparsing: 2.4.6](https://pypi.org/project/pyparsing/2.4.6/) +- [pyproj: 2.4.2.post1](https://pypi.org/project/pyproj/2.4.2.post1/) +- [pyrsistent: 0.15.7](https://pypi.org/project/pyrsistent/0.15.7/) +- [pytest: 5.3.5](https://pypi.org/project/pytest/5.3.5/) +- [python-dateutil: 2.8.1](https://pypi.org/project/python-dateutil/2.8.1/) +- [pytz: 2019.3](https://pypi.org/project/pytz/2019.3/) +- [pyyaml: 5.3](https://pypi.org/project/pyyaml/5.3/) +- [pyzmq: 18.1.1](https://pypi.org/project/pyzmq/18.1.1/) +- [qtconsole: 4.6.0](https://pypi.org/project/qtconsole/4.6.0/) +- [requests: 2.22.0](https://pypi.org/project/requests/2.22.0/) +- [requests-oauthlib: 1.3.0](https://pypi.org/project/requests-oauthlib/1.3.0/) +- [retry: 0.9.2](https://pypi.org/project/retry/0.9.2/) +- [retrying: 1.3.3](https://pypi.org/project/retrying/1.3.3/) +- [rsa: 4.0](https://pypi.org/project/rsa/4.0/) +- [scikit-learn: 0.24.1](https://pypi.org/project/scikit-learn/0.24.1/) +- [scipy: 1.4.1](https://pypi.org/project/scipy/1.4.1/) +- [seaborn: 0.10.0](https://pypi.org/project/seaborn/0.10.0/) +- [send2trash: 1.5.0](https://pypi.org/project/send2trash/1.5.0/) +- [shapely: 1.7.0](https://pypi.org/project/shapely/1.7.0/) +- [six: 1.14.0](https://pypi.org/project/six/1.14.0/) +- [sqlparse: 0.4.1](https://pypi.org/project/sqlparse/0.4.1/) +- [statsmodels: 0.11.0](https://pypi.org/project/statsmodels/0.11.0/) +- [structlog: 20.2.0](https://pypi.org/project/structlog/20.2.0/) +- [tabulate: 0.8.7](https://pypi.org/project/tabulate/0.8.7/) +- [terminado: 0.8.3](https://pypi.org/project/terminado/0.8.3/) +- [testpath: 0.4.4](https://pypi.org/project/testpath/0.4.4/) +- [threadpoolctl: 2.1.0](https://pypi.org/project/threadpoolctl/2.1.0/) +- [tinycss2: 1.2.1](https://pypi.org/project/tinycss2/1.2.1/) +- [toml: 0.10.2](https://pypi.org/project/toml/0.10.2/) +- [tornado: 6.0.3](https://pypi.org/project/tornado/6.0.3/) +- [tqdm: 4.42.1](https://pypi.org/project/tqdm/4.42.1/) +- [traitlets: 4.3.3](https://pypi.org/project/traitlets/4.3.3/) +- [upsetplot: 0.6.1](https://pypi.org/project/upsetplot/0.6.1/) +- [urllib3: 1.25.8](https://pypi.org/project/urllib3/1.25.8/) +- [venn: 0.1.3](https://pypi.org/project/venn/0.1.3/) +- [wcwidth: 0.1.8](https://pypi.org/project/wcwidth/0.1.8/) +- [webencodings: 0.5.1](https://pypi.org/project/webencodings/0.5.1/) +- [wheel: 0.36.2](https://pypi.org/project/wheel/0.36.2/) +- [widgetsnbextension: 3.5.1](https://pypi.org/project/widgetsnbextension/3.5.1/) +- [wrapt: 1.13.3](https://pypi.org/project/wrapt/1.13.3/) + From 1bb8b105829a7ab9b576342554c83155b2b4cc51 Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Tue, 5 Dec 2023 15:47:25 +0000 Subject: [PATCH 09/11] Update to latest packages --- justfile | 2 +- v2/packages.md | 397 ++++++++++++++++++++++---------------------- v2/requirements.txt | 109 ++++++------ 3 files changed, 253 insertions(+), 255 deletions(-) diff --git a/justfile b/justfile index 582c373..2b05e3f 100644 --- a/justfile +++ b/justfile @@ -17,7 +17,7 @@ test version *args="tests -v": (build version) # run pip-compile to add new dependencies, or update existing ones with --upgrade -update version *args="": (build version) +update version *args="": docker compose --env-file {{ version }}/env run --rm -v $PWD:/workspace base pip-compile {{ args }} {{ version }}/requirements.in -o {{ version }}/requirements.txt {{ just_executable() }} render {{ version }} {{ just_executable() }} test {{ version }} diff --git a/v2/packages.md b/v2/packages.md index 61176a1..4320c60 100644 --- a/v2/packages.md +++ b/v2/packages.md @@ -1,200 +1,197 @@ -# Package Versions for v2 - -> [!NOTE] -> This file is auto-generated - do not edit. - -This python:v2 OpenSAFELY image is based on Ubuntu 22.04 with Python 3.10.12. - -## Packages - -It comes pre-installed with a standard set of python packages. - -- [anyio: 4.0.0](https://pypi.org/project/anyio/4.0.0/) -- [argon2-cffi: 23.1.0](https://pypi.org/project/argon2-cffi/23.1.0/) -- [argon2-cffi-bindings: 21.2.0](https://pypi.org/project/argon2-cffi-bindings/21.2.0/) -- [arrow: 1.3.0](https://pypi.org/project/arrow/1.3.0/) -- [astor: 0.8.1](https://pypi.org/project/astor/0.8.1/) -- [asttokens: 2.4.1](https://pypi.org/project/asttokens/2.4.1/) -- [async-lru: 2.0.4](https://pypi.org/project/async-lru/2.0.4/) -- [attrs: 23.1.0](https://pypi.org/project/attrs/23.1.0/) -- [autograd: 1.6.2](https://pypi.org/project/autograd/1.6.2/) -- [autograd-gamma: 0.5.0](https://pypi.org/project/autograd-gamma/0.5.0/) -- [babel: 2.13.1](https://pypi.org/project/babel/2.13.1/) -- [bash-kernel: 0.9.1](https://pypi.org/project/bash-kernel/0.9.1/) -- [beautifulsoup4: 4.12.2](https://pypi.org/project/beautifulsoup4/4.12.2/) -- [bleach: 6.1.0](https://pypi.org/project/bleach/6.1.0/) -- [build: 1.0.3](https://pypi.org/project/build/1.0.3/) -- [cachetools: 5.3.2](https://pypi.org/project/cachetools/5.3.2/) -- [cairocffi: 1.6.1](https://pypi.org/project/cairocffi/1.6.1/) -- [cairosvg: 2.7.1](https://pypi.org/project/cairosvg/2.7.1/) -- [certifi: 2023.11.17](https://pypi.org/project/certifi/2023.11.17/) -- [cffi: 1.16.0](https://pypi.org/project/cffi/1.16.0/) -- [charset-normalizer: 3.3.2](https://pypi.org/project/charset-normalizer/3.3.2/) -- [click: 8.1.7](https://pypi.org/project/click/8.1.7/) -- [click-plugins: 1.1.1](https://pypi.org/project/click-plugins/1.1.1/) -- [cligj: 0.7.2](https://pypi.org/project/cligj/0.7.2/) -- [comm: 0.2.0](https://pypi.org/project/comm/0.2.0/) -- [contourpy: 1.2.0](https://pypi.org/project/contourpy/1.2.0/) -- [coverage: 7.3.2](https://pypi.org/project/coverage/7.3.2/) -- [cssselect2: 0.7.0](https://pypi.org/project/cssselect2/0.7.0/) -- [cycler: 0.12.1](https://pypi.org/project/cycler/0.12.1/) -- [db-dtypes: 1.1.1](https://pypi.org/project/db-dtypes/1.1.1/) -- [debugpy: 1.8.0](https://pypi.org/project/debugpy/1.8.0/) -- [decorator: 5.1.1](https://pypi.org/project/decorator/5.1.1/) -- [defusedxml: 0.7.1](https://pypi.org/project/defusedxml/0.7.1/) -- [descartes: 1.1.0](https://pypi.org/project/descartes/1.1.0/) -- [ebmdatalab: 0.0.30](https://pypi.org/project/ebmdatalab/0.0.30/) -- [exceptiongroup: 1.2.0](https://pypi.org/project/exceptiongroup/1.2.0/) -- [executing: 2.0.1](https://pypi.org/project/executing/2.0.1/) -- [fastjsonschema: 2.19.0](https://pypi.org/project/fastjsonschema/2.19.0/) -- [fiona: 1.9.5](https://pypi.org/project/fiona/1.9.5/) -- [fonttools: 4.45.0](https://pypi.org/project/fonttools/4.45.0/) -- [formulaic: 0.6.6](https://pypi.org/project/formulaic/0.6.6/) -- [fqdn: 1.5.1](https://pypi.org/project/fqdn/1.5.1/) -- [future: 0.18.3](https://pypi.org/project/future/0.18.3/) -- [geopandas: 0.14.1](https://pypi.org/project/geopandas/0.14.1/) -- [google-api-core[grpc]: 2.14.0](https://pypi.org/project/google-api-core/2.14.0/) -- [google-auth: 2.23.4](https://pypi.org/project/google-auth/2.23.4/) -- [google-auth-oauthlib: 1.1.0](https://pypi.org/project/google-auth-oauthlib/1.1.0/) -- [google-cloud-bigquery: 3.13.0](https://pypi.org/project/google-cloud-bigquery/3.13.0/) -- [google-cloud-bigquery-storage: 2.22.0](https://pypi.org/project/google-cloud-bigquery-storage/2.22.0/) -- [google-cloud-core: 2.3.3](https://pypi.org/project/google-cloud-core/2.3.3/) -- [google-crc32c: 1.5.0](https://pypi.org/project/google-crc32c/1.5.0/) -- [google-resumable-media: 2.6.0](https://pypi.org/project/google-resumable-media/2.6.0/) -- [googleapis-common-protos: 1.61.0](https://pypi.org/project/googleapis-common-protos/1.61.0/) -- [grpcio: 1.59.3](https://pypi.org/project/grpcio/1.59.3/) -- [grpcio-status: 1.59.3](https://pypi.org/project/grpcio-status/1.59.3/) -- [idna: 3.4](https://pypi.org/project/idna/3.4/) -- [iniconfig: 2.0.0](https://pypi.org/project/iniconfig/2.0.0/) -- [interface-meta: 1.3.0](https://pypi.org/project/interface-meta/1.3.0/) -- [ipykernel: 6.27.0](https://pypi.org/project/ipykernel/6.27.0/) -- [ipython: 8.17.2](https://pypi.org/project/ipython/8.17.2/) -- [ipywidgets: 8.1.1](https://pypi.org/project/ipywidgets/8.1.1/) -- [isoduration: 20.11.0](https://pypi.org/project/isoduration/20.11.0/) -- [jedi: 0.19.1](https://pypi.org/project/jedi/0.19.1/) -- [jinja2: 3.1.2](https://pypi.org/project/jinja2/3.1.2/) -- [joblib: 1.3.2](https://pypi.org/project/joblib/1.3.2/) -- [json5: 0.9.14](https://pypi.org/project/json5/0.9.14/) -- [jsonpointer: 2.4](https://pypi.org/project/jsonpointer/2.4/) -- [jsonschema[format-nongpl]: 4.20.0](https://pypi.org/project/jsonschema/4.20.0/) -- [jsonschema-specifications: 2023.11.1](https://pypi.org/project/jsonschema-specifications/2023.11.1/) -- [jupyter: 1.0.0](https://pypi.org/project/jupyter/1.0.0/) -- [jupyter-client: 8.6.0](https://pypi.org/project/jupyter-client/8.6.0/) -- [jupyter-console: 6.6.3](https://pypi.org/project/jupyter-console/6.6.3/) -- [jupyter-core: 5.5.0](https://pypi.org/project/jupyter-core/5.5.0/) -- [jupyter-events: 0.9.0](https://pypi.org/project/jupyter-events/0.9.0/) -- [jupyter-lsp: 2.2.0](https://pypi.org/project/jupyter-lsp/2.2.0/) -- [jupyter-server: 2.11.0](https://pypi.org/project/jupyter-server/2.11.0/) -- [jupyter-server-terminals: 0.4.4](https://pypi.org/project/jupyter-server-terminals/0.4.4/) -- [jupyterlab: 4.0.9](https://pypi.org/project/jupyterlab/4.0.9/) -- [jupyterlab-pygments: 0.2.2](https://pypi.org/project/jupyterlab-pygments/0.2.2/) -- [jupyterlab-server: 2.25.2](https://pypi.org/project/jupyterlab-server/2.25.2/) -- [jupyterlab-widgets: 3.0.9](https://pypi.org/project/jupyterlab-widgets/3.0.9/) -- [jupytext: 1.15.2](https://pypi.org/project/jupytext/1.15.2/) -- [kaleido: 0.2.1](https://pypi.org/project/kaleido/0.2.1/) -- [kiwisolver: 1.4.5](https://pypi.org/project/kiwisolver/1.4.5/) -- [lifelines: 0.27.8](https://pypi.org/project/lifelines/0.27.8/) -- [llvmlite: 0.41.1](https://pypi.org/project/llvmlite/0.41.1/) -- [lz4: 4.3.2](https://pypi.org/project/lz4/4.3.2/) -- [markdown-it-py: 3.0.0](https://pypi.org/project/markdown-it-py/3.0.0/) -- [markupsafe: 2.1.3](https://pypi.org/project/markupsafe/2.1.3/) -- [matplotlib: 3.8.2](https://pypi.org/project/matplotlib/3.8.2/) -- [matplotlib-inline: 0.1.6](https://pypi.org/project/matplotlib-inline/0.1.6/) -- [mdit-py-plugins: 0.4.0](https://pypi.org/project/mdit-py-plugins/0.4.0/) -- [mdurl: 0.1.2](https://pypi.org/project/mdurl/0.1.2/) -- [mistune: 3.0.2](https://pypi.org/project/mistune/3.0.2/) -- [nbclient: 0.9.0](https://pypi.org/project/nbclient/0.9.0/) -- [nbconvert: 7.11.0](https://pypi.org/project/nbconvert/7.11.0/) -- [nbformat: 5.9.2](https://pypi.org/project/nbformat/5.9.2/) -- [nbval: 0.10.0](https://pypi.org/project/nbval/0.10.0/) -- [nest-asyncio: 1.5.8](https://pypi.org/project/nest-asyncio/1.5.8/) -- [notebook: 7.0.6](https://pypi.org/project/notebook/7.0.6/) -- [notebook-shim: 0.2.3](https://pypi.org/project/notebook-shim/0.2.3/) -- [numba: 0.58.1](https://pypi.org/project/numba/0.58.1/) -- [numpy: 1.26.2](https://pypi.org/project/numpy/1.26.2/) -- [oauthlib: 3.2.2](https://pypi.org/project/oauthlib/3.2.2/) -- [opensafely-cohort-extractor: 1.90.0](https://pypi.org/project/opensafely-cohort-extractor/1.90.0/) -- [opensafely-matching: 0.2.0](https://pypi.org/project/opensafely-matching/0.2.0/) -- [overrides: 7.4.0](https://pypi.org/project/overrides/7.4.0/) -- [packaging: 23.2](https://pypi.org/project/packaging/23.2/) -- [pandas: 2.1.3](https://pypi.org/project/pandas/2.1.3/) -- [pandas-gbq: 0.19.2](https://pypi.org/project/pandas-gbq/0.19.2/) -- [pandocfilters: 1.5.0](https://pypi.org/project/pandocfilters/1.5.0/) -- [parso: 0.8.3](https://pypi.org/project/parso/0.8.3/) -- [patsy: 0.5.3](https://pypi.org/project/patsy/0.5.3/) -- [pexpect: 4.8.0](https://pypi.org/project/pexpect/4.8.0/) -- [pillow: 10.1.0](https://pypi.org/project/pillow/10.1.0/) -- [pip-tools: 7.3.0](https://pypi.org/project/pip-tools/7.3.0/) -- [platformdirs: 4.0.0](https://pypi.org/project/platformdirs/4.0.0/) -- [plotly: 5.18.0](https://pypi.org/project/plotly/5.18.0/) -- [pluggy: 1.3.0](https://pypi.org/project/pluggy/1.3.0/) -- [prometheus-client: 0.19.0](https://pypi.org/project/prometheus-client/0.19.0/) -- [prompt-toolkit: 3.0.41](https://pypi.org/project/prompt-toolkit/3.0.41/) -- [proto-plus: 1.22.3](https://pypi.org/project/proto-plus/1.22.3/) -- [protobuf: 4.25.1](https://pypi.org/project/protobuf/4.25.1/) -- [psutil: 5.9.6](https://pypi.org/project/psutil/5.9.6/) -- [ptyprocess: 0.7.0](https://pypi.org/project/ptyprocess/0.7.0/) -- [pure-eval: 0.2.2](https://pypi.org/project/pure-eval/0.2.2/) -- [py: 1.11.0](https://pypi.org/project/py/1.11.0/) -- [pyarrow: 14.0.1](https://pypi.org/project/pyarrow/14.0.1/) -- [pyasn1: 0.5.1](https://pypi.org/project/pyasn1/0.5.1/) -- [pyasn1-modules: 0.3.0](https://pypi.org/project/pyasn1-modules/0.3.0/) -- [pycparser: 2.21](https://pypi.org/project/pycparser/2.21/) -- [pydata-google-auth: 1.8.2](https://pypi.org/project/pydata-google-auth/1.8.2/) -- [pygments: 2.17.1](https://pypi.org/project/pygments/2.17.1/) -- [pyparsing: 3.1.1](https://pypi.org/project/pyparsing/3.1.1/) -- [pyproj: 3.6.1](https://pypi.org/project/pyproj/3.6.1/) -- [pyproject-hooks: 1.0.0](https://pypi.org/project/pyproject-hooks/1.0.0/) -- [pytest: 7.4.3](https://pypi.org/project/pytest/7.4.3/) -- [python-dateutil: 2.8.2](https://pypi.org/project/python-dateutil/2.8.2/) -- [python-json-logger: 2.0.7](https://pypi.org/project/python-json-logger/2.0.7/) -- [pytz: 2023.3.post1](https://pypi.org/project/pytz/2023.3.post1/) -- [pyyaml: 6.0.1](https://pypi.org/project/pyyaml/6.0.1/) -- [pyzmq: 25.1.1](https://pypi.org/project/pyzmq/25.1.1/) -- [qtconsole: 5.5.1](https://pypi.org/project/qtconsole/5.5.1/) -- [qtpy: 2.4.1](https://pypi.org/project/qtpy/2.4.1/) -- [referencing: 0.31.0](https://pypi.org/project/referencing/0.31.0/) -- [requests: 2.31.0](https://pypi.org/project/requests/2.31.0/) -- [requests-oauthlib: 1.3.1](https://pypi.org/project/requests-oauthlib/1.3.1/) -- [retry: 0.9.2](https://pypi.org/project/retry/0.9.2/) -- [rfc3339-validator: 0.1.4](https://pypi.org/project/rfc3339-validator/0.1.4/) -- [rfc3986-validator: 0.1.1](https://pypi.org/project/rfc3986-validator/0.1.1/) -- [rpds-py: 0.13.1](https://pypi.org/project/rpds-py/0.13.1/) -- [rsa: 4.9](https://pypi.org/project/rsa/4.9/) -- [scikit-learn: 1.3.2](https://pypi.org/project/scikit-learn/1.3.2/) -- [scipy: 1.11.4](https://pypi.org/project/scipy/1.11.4/) -- [seaborn: 0.13.0](https://pypi.org/project/seaborn/0.13.0/) -- [send2trash: 1.8.2](https://pypi.org/project/send2trash/1.8.2/) -- [shapely: 2.0.2](https://pypi.org/project/shapely/2.0.2/) -- [six: 1.16.0](https://pypi.org/project/six/1.16.0/) -- [sniffio: 1.3.0](https://pypi.org/project/sniffio/1.3.0/) -- [soupsieve: 2.5](https://pypi.org/project/soupsieve/2.5/) -- [sqlparse: 0.4.4](https://pypi.org/project/sqlparse/0.4.4/) -- [stack-data: 0.6.3](https://pypi.org/project/stack-data/0.6.3/) -- [statsmodels: 0.14.0](https://pypi.org/project/statsmodels/0.14.0/) -- [structlog: 23.2.0](https://pypi.org/project/structlog/23.2.0/) -- [tabulate: 0.9.0](https://pypi.org/project/tabulate/0.9.0/) -- [tenacity: 8.2.3](https://pypi.org/project/tenacity/8.2.3/) -- [terminado: 0.18.0](https://pypi.org/project/terminado/0.18.0/) -- [threadpoolctl: 3.2.0](https://pypi.org/project/threadpoolctl/3.2.0/) -- [tinycss2: 1.2.1](https://pypi.org/project/tinycss2/1.2.1/) -- [toml: 0.10.2](https://pypi.org/project/toml/0.10.2/) -- [tomli: 2.0.1](https://pypi.org/project/tomli/2.0.1/) -- [tornado: 6.3.3](https://pypi.org/project/tornado/6.3.3/) -- [tqdm: 4.66.1](https://pypi.org/project/tqdm/4.66.1/) -- [traitlets: 5.13.0](https://pypi.org/project/traitlets/5.13.0/) -- [types-python-dateutil: 2.8.19.14](https://pypi.org/project/types-python-dateutil/2.8.19.14/) -- [typing-extensions: 4.8.0](https://pypi.org/project/typing-extensions/4.8.0/) -- [tzdata: 2023.3](https://pypi.org/project/tzdata/2023.3/) -- [upsetplot: 0.8.0](https://pypi.org/project/upsetplot/0.8.0/) -- [uri-template: 1.3.0](https://pypi.org/project/uri-template/1.3.0/) -- [urllib3: 2.1.0](https://pypi.org/project/urllib3/2.1.0/) -- [venn: 0.1.3](https://pypi.org/project/venn/0.1.3/) -- [wcwidth: 0.2.11](https://pypi.org/project/wcwidth/0.2.11/) -- [webcolors: 1.13](https://pypi.org/project/webcolors/1.13/) -- [webencodings: 0.5.1](https://pypi.org/project/webencodings/0.5.1/) -- [websocket-client: 1.6.4](https://pypi.org/project/websocket-client/1.6.4/) -- [wheel: 0.41.3](https://pypi.org/project/wheel/0.41.3/) -- [widgetsnbextension: 4.0.9](https://pypi.org/project/widgetsnbextension/4.0.9/) -- [wrapt: 1.16.0](https://pypi.org/project/wrapt/1.16.0/) - +# Package Versions for v2 + +This python:v2 OpenSAFELY image is based on Ubuntu 22.04 with Python 3.10.12. + +## Packages + +It comes pre-installed with a standard set of python packages. + +- [anyio: 4.1.0](https://pypi.org/project/anyio/4.1.0/) +- [argon2-cffi: 23.1.0](https://pypi.org/project/argon2-cffi/23.1.0/) +- [argon2-cffi-bindings: 21.2.0](https://pypi.org/project/argon2-cffi-bindings/21.2.0/) +- [arrow: 1.3.0](https://pypi.org/project/arrow/1.3.0/) +- [astor: 0.8.1](https://pypi.org/project/astor/0.8.1/) +- [asttokens: 2.4.1](https://pypi.org/project/asttokens/2.4.1/) +- [async-lru: 2.0.4](https://pypi.org/project/async-lru/2.0.4/) +- [attrs: 23.1.0](https://pypi.org/project/attrs/23.1.0/) +- [autograd: 1.6.2](https://pypi.org/project/autograd/1.6.2/) +- [autograd-gamma: 0.5.0](https://pypi.org/project/autograd-gamma/0.5.0/) +- [babel: 2.13.1](https://pypi.org/project/babel/2.13.1/) +- [bash-kernel: 0.9.3](https://pypi.org/project/bash-kernel/0.9.3/) +- [beautifulsoup4: 4.12.2](https://pypi.org/project/beautifulsoup4/4.12.2/) +- [bleach: 6.1.0](https://pypi.org/project/bleach/6.1.0/) +- [build: 1.0.3](https://pypi.org/project/build/1.0.3/) +- [cachetools: 5.3.2](https://pypi.org/project/cachetools/5.3.2/) +- [cairocffi: 1.6.1](https://pypi.org/project/cairocffi/1.6.1/) +- [cairosvg: 2.7.1](https://pypi.org/project/cairosvg/2.7.1/) +- [certifi: 2023.11.17](https://pypi.org/project/certifi/2023.11.17/) +- [cffi: 1.16.0](https://pypi.org/project/cffi/1.16.0/) +- [charset-normalizer: 3.3.2](https://pypi.org/project/charset-normalizer/3.3.2/) +- [click: 8.1.7](https://pypi.org/project/click/8.1.7/) +- [click-plugins: 1.1.1](https://pypi.org/project/click-plugins/1.1.1/) +- [cligj: 0.7.2](https://pypi.org/project/cligj/0.7.2/) +- [comm: 0.2.0](https://pypi.org/project/comm/0.2.0/) +- [contourpy: 1.2.0](https://pypi.org/project/contourpy/1.2.0/) +- [coverage: 7.3.2](https://pypi.org/project/coverage/7.3.2/) +- [cssselect2: 0.7.0](https://pypi.org/project/cssselect2/0.7.0/) +- [cycler: 0.12.1](https://pypi.org/project/cycler/0.12.1/) +- [db-dtypes: 1.1.1](https://pypi.org/project/db-dtypes/1.1.1/) +- [debugpy: 1.8.0](https://pypi.org/project/debugpy/1.8.0/) +- [decorator: 5.1.1](https://pypi.org/project/decorator/5.1.1/) +- [defusedxml: 0.7.1](https://pypi.org/project/defusedxml/0.7.1/) +- [descartes: 1.1.0](https://pypi.org/project/descartes/1.1.0/) +- [ebmdatalab: 0.0.30](https://pypi.org/project/ebmdatalab/0.0.30/) +- [exceptiongroup: 1.2.0](https://pypi.org/project/exceptiongroup/1.2.0/) +- [executing: 2.0.1](https://pypi.org/project/executing/2.0.1/) +- [fastjsonschema: 2.19.0](https://pypi.org/project/fastjsonschema/2.19.0/) +- [fiona: 1.9.5](https://pypi.org/project/fiona/1.9.5/) +- [fonttools: 4.46.0](https://pypi.org/project/fonttools/4.46.0/) +- [formulaic: 0.6.6](https://pypi.org/project/formulaic/0.6.6/) +- [fqdn: 1.5.1](https://pypi.org/project/fqdn/1.5.1/) +- [future: 0.18.3](https://pypi.org/project/future/0.18.3/) +- [geopandas: 0.14.1](https://pypi.org/project/geopandas/0.14.1/) +- [google-api-core[grpc]: 2.14.0](https://pypi.org/project/google-api-core/2.14.0/) +- [google-auth: 2.24.0](https://pypi.org/project/google-auth/2.24.0/) +- [google-auth-oauthlib: 1.1.0](https://pypi.org/project/google-auth-oauthlib/1.1.0/) +- [google-cloud-bigquery: 3.13.0](https://pypi.org/project/google-cloud-bigquery/3.13.0/) +- [google-cloud-bigquery-storage: 2.23.0](https://pypi.org/project/google-cloud-bigquery-storage/2.23.0/) +- [google-cloud-core: 2.3.3](https://pypi.org/project/google-cloud-core/2.3.3/) +- [google-crc32c: 1.5.0](https://pypi.org/project/google-crc32c/1.5.0/) +- [google-resumable-media: 2.6.0](https://pypi.org/project/google-resumable-media/2.6.0/) +- [googleapis-common-protos: 1.61.0](https://pypi.org/project/googleapis-common-protos/1.61.0/) +- [grpcio: 1.59.3](https://pypi.org/project/grpcio/1.59.3/) +- [grpcio-status: 1.59.3](https://pypi.org/project/grpcio-status/1.59.3/) +- [idna: 3.6](https://pypi.org/project/idna/3.6/) +- [iniconfig: 2.0.0](https://pypi.org/project/iniconfig/2.0.0/) +- [interface-meta: 1.3.0](https://pypi.org/project/interface-meta/1.3.0/) +- [ipykernel: 6.27.1](https://pypi.org/project/ipykernel/6.27.1/) +- [ipython: 8.18.1](https://pypi.org/project/ipython/8.18.1/) +- [ipywidgets: 8.1.1](https://pypi.org/project/ipywidgets/8.1.1/) +- [isoduration: 20.11.0](https://pypi.org/project/isoduration/20.11.0/) +- [jedi: 0.19.1](https://pypi.org/project/jedi/0.19.1/) +- [jinja2: 3.1.2](https://pypi.org/project/jinja2/3.1.2/) +- [joblib: 1.3.2](https://pypi.org/project/joblib/1.3.2/) +- [json5: 0.9.14](https://pypi.org/project/json5/0.9.14/) +- [jsonpointer: 2.4](https://pypi.org/project/jsonpointer/2.4/) +- [jsonschema[format-nongpl]: 4.20.0](https://pypi.org/project/jsonschema/4.20.0/) +- [jsonschema-specifications: 2023.11.2](https://pypi.org/project/jsonschema-specifications/2023.11.2/) +- [jupyter: 1.0.0](https://pypi.org/project/jupyter/1.0.0/) +- [jupyter-client: 8.6.0](https://pypi.org/project/jupyter-client/8.6.0/) +- [jupyter-console: 6.6.3](https://pypi.org/project/jupyter-console/6.6.3/) +- [jupyter-core: 5.5.0](https://pypi.org/project/jupyter-core/5.5.0/) +- [jupyter-events: 0.9.0](https://pypi.org/project/jupyter-events/0.9.0/) +- [jupyter-lsp: 2.2.1](https://pypi.org/project/jupyter-lsp/2.2.1/) +- [jupyter-server: 2.11.2](https://pypi.org/project/jupyter-server/2.11.2/) +- [jupyter-server-terminals: 0.4.4](https://pypi.org/project/jupyter-server-terminals/0.4.4/) +- [jupyterlab: 4.0.9](https://pypi.org/project/jupyterlab/4.0.9/) +- [jupyterlab-pygments: 0.3.0](https://pypi.org/project/jupyterlab-pygments/0.3.0/) +- [jupyterlab-server: 2.25.2](https://pypi.org/project/jupyterlab-server/2.25.2/) +- [jupyterlab-widgets: 3.0.9](https://pypi.org/project/jupyterlab-widgets/3.0.9/) +- [jupytext: 1.16.0](https://pypi.org/project/jupytext/1.16.0/) +- [kaleido: 0.2.1](https://pypi.org/project/kaleido/0.2.1/) +- [kiwisolver: 1.4.5](https://pypi.org/project/kiwisolver/1.4.5/) +- [lifelines: 0.27.8](https://pypi.org/project/lifelines/0.27.8/) +- [llvmlite: 0.41.1](https://pypi.org/project/llvmlite/0.41.1/) +- [lz4: 4.3.2](https://pypi.org/project/lz4/4.3.2/) +- [markdown-it-py: 3.0.0](https://pypi.org/project/markdown-it-py/3.0.0/) +- [markupsafe: 2.1.3](https://pypi.org/project/markupsafe/2.1.3/) +- [matplotlib: 3.8.2](https://pypi.org/project/matplotlib/3.8.2/) +- [matplotlib-inline: 0.1.6](https://pypi.org/project/matplotlib-inline/0.1.6/) +- [mdit-py-plugins: 0.4.0](https://pypi.org/project/mdit-py-plugins/0.4.0/) +- [mdurl: 0.1.2](https://pypi.org/project/mdurl/0.1.2/) +- [mistune: 3.0.2](https://pypi.org/project/mistune/3.0.2/) +- [nbclient: 0.9.0](https://pypi.org/project/nbclient/0.9.0/) +- [nbconvert: 7.12.0](https://pypi.org/project/nbconvert/7.12.0/) +- [nbformat: 5.9.2](https://pypi.org/project/nbformat/5.9.2/) +- [nbval: 0.10.0](https://pypi.org/project/nbval/0.10.0/) +- [nest-asyncio: 1.5.8](https://pypi.org/project/nest-asyncio/1.5.8/) +- [notebook: 7.0.6](https://pypi.org/project/notebook/7.0.6/) +- [notebook-shim: 0.2.3](https://pypi.org/project/notebook-shim/0.2.3/) +- [numba: 0.58.1](https://pypi.org/project/numba/0.58.1/) +- [numpy: 1.26.2](https://pypi.org/project/numpy/1.26.2/) +- [oauthlib: 3.2.2](https://pypi.org/project/oauthlib/3.2.2/) +- [opensafely-cohort-extractor: 1.90.0](https://pypi.org/project/opensafely-cohort-extractor/1.90.0/) +- [opensafely-matching: 0.2.0](https://pypi.org/project/opensafely-matching/0.2.0/) +- [overrides: 7.4.0](https://pypi.org/project/overrides/7.4.0/) +- [packaging: 23.2](https://pypi.org/project/packaging/23.2/) +- [pandas: 2.1.3](https://pypi.org/project/pandas/2.1.3/) +- [pandas-gbq: 0.19.2](https://pypi.org/project/pandas-gbq/0.19.2/) +- [pandocfilters: 1.5.0](https://pypi.org/project/pandocfilters/1.5.0/) +- [parso: 0.8.3](https://pypi.org/project/parso/0.8.3/) +- [patsy: 0.5.4](https://pypi.org/project/patsy/0.5.4/) +- [pexpect: 4.9.0](https://pypi.org/project/pexpect/4.9.0/) +- [pillow: 10.1.0](https://pypi.org/project/pillow/10.1.0/) +- [pip-tools: 7.3.0](https://pypi.org/project/pip-tools/7.3.0/) +- [platformdirs: 4.1.0](https://pypi.org/project/platformdirs/4.1.0/) +- [plotly: 5.18.0](https://pypi.org/project/plotly/5.18.0/) +- [pluggy: 1.3.0](https://pypi.org/project/pluggy/1.3.0/) +- [prometheus-client: 0.19.0](https://pypi.org/project/prometheus-client/0.19.0/) +- [prompt-toolkit: 3.0.41](https://pypi.org/project/prompt-toolkit/3.0.41/) +- [proto-plus: 1.22.3](https://pypi.org/project/proto-plus/1.22.3/) +- [protobuf: 4.25.1](https://pypi.org/project/protobuf/4.25.1/) +- [psutil: 5.9.6](https://pypi.org/project/psutil/5.9.6/) +- [ptyprocess: 0.7.0](https://pypi.org/project/ptyprocess/0.7.0/) +- [pure-eval: 0.2.2](https://pypi.org/project/pure-eval/0.2.2/) +- [py: 1.11.0](https://pypi.org/project/py/1.11.0/) +- [pyarrow: 14.0.1](https://pypi.org/project/pyarrow/14.0.1/) +- [pyasn1: 0.5.1](https://pypi.org/project/pyasn1/0.5.1/) +- [pyasn1-modules: 0.3.0](https://pypi.org/project/pyasn1-modules/0.3.0/) +- [pycparser: 2.21](https://pypi.org/project/pycparser/2.21/) +- [pydata-google-auth: 1.8.2](https://pypi.org/project/pydata-google-auth/1.8.2/) +- [pygments: 2.17.2](https://pypi.org/project/pygments/2.17.2/) +- [pyparsing: 3.1.1](https://pypi.org/project/pyparsing/3.1.1/) +- [pyproj: 3.6.1](https://pypi.org/project/pyproj/3.6.1/) +- [pyproject-hooks: 1.0.0](https://pypi.org/project/pyproject-hooks/1.0.0/) +- [pytest: 7.4.3](https://pypi.org/project/pytest/7.4.3/) +- [python-dateutil: 2.8.2](https://pypi.org/project/python-dateutil/2.8.2/) +- [python-json-logger: 2.0.7](https://pypi.org/project/python-json-logger/2.0.7/) +- [pytz: 2023.3.post1](https://pypi.org/project/pytz/2023.3.post1/) +- [pyyaml: 6.0.1](https://pypi.org/project/pyyaml/6.0.1/) +- [pyzmq: 25.1.2](https://pypi.org/project/pyzmq/25.1.2/) +- [qtconsole: 5.5.1](https://pypi.org/project/qtconsole/5.5.1/) +- [qtpy: 2.4.1](https://pypi.org/project/qtpy/2.4.1/) +- [referencing: 0.31.1](https://pypi.org/project/referencing/0.31.1/) +- [requests: 2.31.0](https://pypi.org/project/requests/2.31.0/) +- [requests-oauthlib: 1.3.1](https://pypi.org/project/requests-oauthlib/1.3.1/) +- [retry: 0.9.2](https://pypi.org/project/retry/0.9.2/) +- [rfc3339-validator: 0.1.4](https://pypi.org/project/rfc3339-validator/0.1.4/) +- [rfc3986-validator: 0.1.1](https://pypi.org/project/rfc3986-validator/0.1.1/) +- [rpds-py: 0.13.2](https://pypi.org/project/rpds-py/0.13.2/) +- [rsa: 4.9](https://pypi.org/project/rsa/4.9/) +- [scikit-learn: 1.3.2](https://pypi.org/project/scikit-learn/1.3.2/) +- [scipy: 1.11.4](https://pypi.org/project/scipy/1.11.4/) +- [seaborn: 0.13.0](https://pypi.org/project/seaborn/0.13.0/) +- [send2trash: 1.8.2](https://pypi.org/project/send2trash/1.8.2/) +- [shapely: 2.0.2](https://pypi.org/project/shapely/2.0.2/) +- [six: 1.16.0](https://pypi.org/project/six/1.16.0/) +- [sniffio: 1.3.0](https://pypi.org/project/sniffio/1.3.0/) +- [soupsieve: 2.5](https://pypi.org/project/soupsieve/2.5/) +- [sqlparse: 0.4.4](https://pypi.org/project/sqlparse/0.4.4/) +- [stack-data: 0.6.3](https://pypi.org/project/stack-data/0.6.3/) +- [statsmodels: 0.14.0](https://pypi.org/project/statsmodels/0.14.0/) +- [structlog: 23.2.0](https://pypi.org/project/structlog/23.2.0/) +- [tabulate: 0.9.0](https://pypi.org/project/tabulate/0.9.0/) +- [tenacity: 8.2.3](https://pypi.org/project/tenacity/8.2.3/) +- [terminado: 0.18.0](https://pypi.org/project/terminado/0.18.0/) +- [threadpoolctl: 3.2.0](https://pypi.org/project/threadpoolctl/3.2.0/) +- [tinycss2: 1.2.1](https://pypi.org/project/tinycss2/1.2.1/) +- [toml: 0.10.2](https://pypi.org/project/toml/0.10.2/) +- [tomli: 2.0.1](https://pypi.org/project/tomli/2.0.1/) +- [tornado: 6.4](https://pypi.org/project/tornado/6.4/) +- [tqdm: 4.66.1](https://pypi.org/project/tqdm/4.66.1/) +- [traitlets: 5.14.0](https://pypi.org/project/traitlets/5.14.0/) +- [types-python-dateutil: 2.8.19.14](https://pypi.org/project/types-python-dateutil/2.8.19.14/) +- [typing-extensions: 4.8.0](https://pypi.org/project/typing-extensions/4.8.0/) +- [tzdata: 2023.3](https://pypi.org/project/tzdata/2023.3/) +- [upsetplot: 0.8.0](https://pypi.org/project/upsetplot/0.8.0/) +- [uri-template: 1.3.0](https://pypi.org/project/uri-template/1.3.0/) +- [urllib3: 2.1.0](https://pypi.org/project/urllib3/2.1.0/) +- [venn: 0.1.3](https://pypi.org/project/venn/0.1.3/) +- [wcwidth: 0.2.12](https://pypi.org/project/wcwidth/0.2.12/) +- [webcolors: 1.13](https://pypi.org/project/webcolors/1.13/) +- [webencodings: 0.5.1](https://pypi.org/project/webencodings/0.5.1/) +- [websocket-client: 1.7.0](https://pypi.org/project/websocket-client/1.7.0/) +- [wheel: 0.42.0](https://pypi.org/project/wheel/0.42.0/) +- [widgetsnbextension: 4.0.9](https://pypi.org/project/widgetsnbextension/4.0.9/) +- [wrapt: 1.16.0](https://pypi.org/project/wrapt/1.16.0/) + diff --git a/v2/requirements.txt b/v2/requirements.txt index aecf474..25c762f 100644 --- a/v2/requirements.txt +++ b/v2/requirements.txt @@ -2,9 +2,9 @@ # This file is autogenerated by pip-compile with Python 3.10 # by the following command: # -# pip-compile requirements-3.10.in +# pip-compile --output-file=v2/requirements.txt v2/requirements.in # -anyio==4.0.0 +anyio==4.1.0 # via jupyter-server argon2-cffi==23.1.0 # via jupyter-server @@ -31,8 +31,8 @@ autograd-gamma==0.5.0 # via lifelines babel==2.13.1 # via jupyterlab-server -bash-kernel==0.9.1 - # via -r requirements-3.10.in +bash-kernel==0.9.3 + # via -r v2/requirements.in beautifulsoup4==4.12.2 # via nbconvert bleach==6.1.0 @@ -44,7 +44,7 @@ cachetools==5.3.2 cairocffi==1.6.1 # via cairosvg cairosvg==2.7.1 - # via -r requirements-3.10.in + # via -r v2/requirements.in certifi==2023.11.17 # via # fiona @@ -93,7 +93,7 @@ defusedxml==0.7.1 descartes==1.1.0 # via ebmdatalab ebmdatalab==0.0.30 - # via -r requirements-3.10.in + # via -r v2/requirements.in exceptiongroup==1.2.0 # via # anyio @@ -105,7 +105,7 @@ fastjsonschema==2.19.0 # via nbformat fiona==1.9.5 # via geopandas -fonttools==4.45.0 +fonttools==4.46.0 # via matplotlib formulaic==0.6.6 # via lifelines @@ -121,7 +121,7 @@ google-api-core[grpc]==2.14.0 # google-cloud-bigquery-storage # google-cloud-core # pandas-gbq -google-auth==2.23.4 +google-auth==2.24.0 # via # google-api-core # google-auth-oauthlib @@ -134,7 +134,7 @@ google-auth-oauthlib==1.1.0 # pydata-google-auth google-cloud-bigquery==3.13.0 # via pandas-gbq -google-cloud-bigquery-storage==2.22.0 +google-cloud-bigquery-storage==2.23.0 # via pandas-gbq google-cloud-core==2.3.3 # via google-cloud-bigquery @@ -153,7 +153,7 @@ grpcio==1.59.3 # grpcio-status grpcio-status==1.59.3 # via google-api-core -idna==3.4 +idna==3.6 # via # anyio # jsonschema @@ -162,7 +162,7 @@ iniconfig==2.0.0 # via pytest interface-meta==1.3.0 # via formulaic -ipykernel==6.27.0 +ipykernel==6.27.1 # via # bash-kernel # jupyter @@ -170,14 +170,14 @@ ipykernel==6.27.0 # jupyterlab # nbval # qtconsole -ipython==8.17.2 +ipython==8.18.1 # via # ipykernel # ipywidgets # jupyter-console ipywidgets==8.1.1 # via - # -r requirements-3.10.in + # -r v2/requirements.in # jupyter isoduration==20.11.0 # via jsonschema @@ -200,10 +200,10 @@ jsonschema[format-nongpl]==4.20.0 # jupyter-events # jupyterlab-server # nbformat -jsonschema-specifications==2023.11.1 +jsonschema-specifications==2023.11.2 # via jsonschema jupyter==1.0.0 - # via -r requirements-3.10.in + # via -r v2/requirements.in jupyter-client==8.6.0 # via # ipykernel @@ -227,9 +227,9 @@ jupyter-core==5.5.0 # qtconsole jupyter-events==0.9.0 # via jupyter-server -jupyter-lsp==2.2.0 +jupyter-lsp==2.2.1 # via jupyterlab -jupyter-server==2.11.0 +jupyter-server==2.11.2 # via # jupyter-lsp # jupyterlab @@ -240,9 +240,9 @@ jupyter-server-terminals==0.4.4 # via jupyter-server jupyterlab==4.0.9 # via - # -r requirements-3.10.in + # -r v2/requirements.in # notebook -jupyterlab-pygments==0.2.2 +jupyterlab-pygments==0.3.0 # via nbconvert jupyterlab-server==2.25.2 # via @@ -250,14 +250,14 @@ jupyterlab-server==2.25.2 # notebook jupyterlab-widgets==3.0.9 # via ipywidgets -jupytext==1.15.2 - # via -r requirements-3.10.in +jupytext==1.16.0 + # via -r v2/requirements.in kaleido==0.2.1 - # via -r requirements-3.10.in + # via -r v2/requirements.in kiwisolver==1.4.5 # via matplotlib lifelines==0.27.8 - # via -r requirements-3.10.in + # via -r v2/requirements.in llvmlite==0.41.1 # via numba lz4==4.3.2 @@ -272,7 +272,7 @@ markupsafe==2.1.3 # nbconvert matplotlib==3.8.2 # via - # -r requirements-3.10.in + # -r v2/requirements.in # descartes # lifelines # seaborn @@ -290,7 +290,7 @@ mistune==3.0.2 # via nbconvert nbclient==0.9.0 # via nbconvert -nbconvert==7.11.0 +nbconvert==7.12.0 # via # jupyter # jupyter-server @@ -302,7 +302,7 @@ nbformat==5.9.2 # nbconvert # nbval nbval==0.10.0 - # via -r requirements-3.10.in + # via -r v2/requirements.in nest-asyncio==1.5.8 # via ipykernel notebook==7.0.6 @@ -312,10 +312,10 @@ notebook-shim==0.2.3 # jupyterlab # notebook numba==0.58.1 - # via -r requirements-3.10.in + # via -r v2/requirements.in numpy==1.26.2 # via - # -r requirements-3.10.in + # -r v2/requirements.in # autograd # contourpy # db-dtypes @@ -335,9 +335,9 @@ numpy==1.26.2 oauthlib==3.2.2 # via requests-oauthlib opensafely-cohort-extractor==1.90.0 - # via -r requirements-3.10.in + # via -r v2/requirements.in opensafely-matching==0.2.0 - # via -r requirements-3.10.in + # via -r v2/requirements.in overrides==7.4.0 # via jupyter-server packaging==23.2 @@ -350,6 +350,7 @@ packaging==23.2 # jupyter-server # jupyterlab # jupyterlab-server + # jupytext # matplotlib # nbconvert # plotly @@ -359,7 +360,7 @@ packaging==23.2 # statsmodels pandas==2.1.3 # via - # -r requirements-3.10.in + # -r v2/requirements.in # db-dtypes # ebmdatalab # formulaic @@ -373,29 +374,29 @@ pandas==2.1.3 # upsetplot pandas-gbq==0.19.2 # via - # -r requirements-3.10.in + # -r v2/requirements.in # ebmdatalab pandocfilters==1.5.0 # via nbconvert parso==0.8.3 # via jedi -patsy==0.5.3 +patsy==0.5.4 # via statsmodels -pexpect==4.8.0 +pexpect==4.9.0 # via # bash-kernel # ipython pillow==10.1.0 # via - # -r requirements-3.10.in + # -r v2/requirements.in # cairosvg # matplotlib pip-tools==7.3.0 - # via -r requirements-3.10.in -platformdirs==4.0.0 + # via -r v2/requirements.in +platformdirs==4.1.0 # via jupyter-core plotly==5.18.0 - # via -r requirements-3.10.in + # via -r v2/requirements.in pluggy==1.3.0 # via pytest prometheus-client==0.19.0 @@ -428,7 +429,7 @@ py==1.11.0 # via retry pyarrow==14.0.1 # via - # -r requirements-3.10.in + # -r v2/requirements.in # db-dtypes # opensafely-cohort-extractor # pandas-gbq @@ -442,7 +443,7 @@ pycparser==2.21 # via cffi pydata-google-auth==1.8.2 # via pandas-gbq -pygments==2.17.1 +pygments==2.17.2 # via # ipython # jupyter-console @@ -456,7 +457,7 @@ pyproject-hooks==1.0.0 # via build pytest==7.4.3 # via - # -r requirements-3.10.in + # -r v2/requirements.in # nbval python-dateutil==2.8.2 # via @@ -474,7 +475,7 @@ pyyaml==6.0.1 # jupyter-events # jupytext # opensafely-cohort-extractor -pyzmq==25.1.1 +pyzmq==25.1.2 # via # ipykernel # jupyter-client @@ -485,7 +486,7 @@ qtconsole==5.5.1 # via jupyter qtpy==2.4.1 # via qtconsole -referencing==0.31.0 +referencing==0.31.1 # via # jsonschema # jsonschema-specifications @@ -509,17 +510,17 @@ rfc3986-validator==0.1.1 # via # jsonschema # jupyter-events -rpds-py==0.13.1 +rpds-py==0.13.2 # via # jsonschema # referencing rsa==4.9 # via google-auth scikit-learn==1.3.2 - # via -r requirements-3.10.in + # via -r v2/requirements.in scipy==1.11.4 # via - # -r requirements-3.10.in + # -r v2/requirements.in # autograd-gamma # formulaic # lifelines @@ -577,7 +578,7 @@ tomli==2.0.1 # pip-tools # pyproject-hooks # pytest -tornado==6.3.3 +tornado==6.4 # via # ipykernel # jupyter-client @@ -586,8 +587,8 @@ tornado==6.3.3 # notebook # terminado tqdm==4.66.1 - # via -r requirements-3.10.in -traitlets==5.13.0 + # via -r v2/requirements.in +traitlets==5.14.0 # via # comm # ipykernel @@ -613,14 +614,14 @@ typing-extensions==4.8.0 tzdata==2023.3 # via pandas upsetplot==0.8.0 - # via -r requirements-3.10.in + # via -r v2/requirements.in uri-template==1.3.0 # via jsonschema urllib3==2.1.0 # via requests venn==0.1.3 - # via -r requirements-3.10.in -wcwidth==0.2.11 + # via -r v2/requirements.in +wcwidth==0.2.12 # via prompt-toolkit webcolors==1.13 # via jsonschema @@ -629,9 +630,9 @@ webencodings==0.5.1 # bleach # cssselect2 # tinycss2 -websocket-client==1.6.4 +websocket-client==1.7.0 # via jupyter-server -wheel==0.41.3 +wheel==0.42.0 # via pip-tools widgetsnbextension==4.0.9 # via ipywidgets From ddeb4285af58c869e9478f9c38b74c79f6eab61f Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Mon, 11 Dec 2023 11:58:02 +0000 Subject: [PATCH 10/11] Remove ebmdatalab and cohortextractor packages from v2 Also, switch from generic end-user package `jupyter` package to specific packages we need. This drops the dependency on qtconsole. --- v2/packages.md | 35 ---------- v2/requirements.in | 5 +- v2/requirements.txt | 159 ++------------------------------------------ 3 files changed, 9 insertions(+), 190 deletions(-) diff --git a/v2/packages.md b/v2/packages.md index 4320c60..b9d3e05 100644 --- a/v2/packages.md +++ b/v2/packages.md @@ -21,46 +21,27 @@ It comes pre-installed with a standard set of python packages. - [beautifulsoup4: 4.12.2](https://pypi.org/project/beautifulsoup4/4.12.2/) - [bleach: 6.1.0](https://pypi.org/project/bleach/6.1.0/) - [build: 1.0.3](https://pypi.org/project/build/1.0.3/) -- [cachetools: 5.3.2](https://pypi.org/project/cachetools/5.3.2/) - [cairocffi: 1.6.1](https://pypi.org/project/cairocffi/1.6.1/) - [cairosvg: 2.7.1](https://pypi.org/project/cairosvg/2.7.1/) - [certifi: 2023.11.17](https://pypi.org/project/certifi/2023.11.17/) - [cffi: 1.16.0](https://pypi.org/project/cffi/1.16.0/) - [charset-normalizer: 3.3.2](https://pypi.org/project/charset-normalizer/3.3.2/) - [click: 8.1.7](https://pypi.org/project/click/8.1.7/) -- [click-plugins: 1.1.1](https://pypi.org/project/click-plugins/1.1.1/) -- [cligj: 0.7.2](https://pypi.org/project/cligj/0.7.2/) - [comm: 0.2.0](https://pypi.org/project/comm/0.2.0/) - [contourpy: 1.2.0](https://pypi.org/project/contourpy/1.2.0/) - [coverage: 7.3.2](https://pypi.org/project/coverage/7.3.2/) - [cssselect2: 0.7.0](https://pypi.org/project/cssselect2/0.7.0/) - [cycler: 0.12.1](https://pypi.org/project/cycler/0.12.1/) -- [db-dtypes: 1.1.1](https://pypi.org/project/db-dtypes/1.1.1/) - [debugpy: 1.8.0](https://pypi.org/project/debugpy/1.8.0/) - [decorator: 5.1.1](https://pypi.org/project/decorator/5.1.1/) - [defusedxml: 0.7.1](https://pypi.org/project/defusedxml/0.7.1/) -- [descartes: 1.1.0](https://pypi.org/project/descartes/1.1.0/) -- [ebmdatalab: 0.0.30](https://pypi.org/project/ebmdatalab/0.0.30/) - [exceptiongroup: 1.2.0](https://pypi.org/project/exceptiongroup/1.2.0/) - [executing: 2.0.1](https://pypi.org/project/executing/2.0.1/) - [fastjsonschema: 2.19.0](https://pypi.org/project/fastjsonschema/2.19.0/) -- [fiona: 1.9.5](https://pypi.org/project/fiona/1.9.5/) - [fonttools: 4.46.0](https://pypi.org/project/fonttools/4.46.0/) - [formulaic: 0.6.6](https://pypi.org/project/formulaic/0.6.6/) - [fqdn: 1.5.1](https://pypi.org/project/fqdn/1.5.1/) - [future: 0.18.3](https://pypi.org/project/future/0.18.3/) -- [geopandas: 0.14.1](https://pypi.org/project/geopandas/0.14.1/) -- [google-api-core[grpc]: 2.14.0](https://pypi.org/project/google-api-core/2.14.0/) -- [google-auth: 2.24.0](https://pypi.org/project/google-auth/2.24.0/) -- [google-auth-oauthlib: 1.1.0](https://pypi.org/project/google-auth-oauthlib/1.1.0/) -- [google-cloud-bigquery: 3.13.0](https://pypi.org/project/google-cloud-bigquery/3.13.0/) -- [google-cloud-bigquery-storage: 2.23.0](https://pypi.org/project/google-cloud-bigquery-storage/2.23.0/) -- [google-cloud-core: 2.3.3](https://pypi.org/project/google-cloud-core/2.3.3/) -- [google-crc32c: 1.5.0](https://pypi.org/project/google-crc32c/1.5.0/) -- [google-resumable-media: 2.6.0](https://pypi.org/project/google-resumable-media/2.6.0/) -- [googleapis-common-protos: 1.61.0](https://pypi.org/project/googleapis-common-protos/1.61.0/) -- [grpcio: 1.59.3](https://pypi.org/project/grpcio/1.59.3/) -- [grpcio-status: 1.59.3](https://pypi.org/project/grpcio-status/1.59.3/) - [idna: 3.6](https://pypi.org/project/idna/3.6/) - [iniconfig: 2.0.0](https://pypi.org/project/iniconfig/2.0.0/) - [interface-meta: 1.3.0](https://pypi.org/project/interface-meta/1.3.0/) @@ -75,7 +56,6 @@ It comes pre-installed with a standard set of python packages. - [jsonpointer: 2.4](https://pypi.org/project/jsonpointer/2.4/) - [jsonschema[format-nongpl]: 4.20.0](https://pypi.org/project/jsonschema/4.20.0/) - [jsonschema-specifications: 2023.11.2](https://pypi.org/project/jsonschema-specifications/2023.11.2/) -- [jupyter: 1.0.0](https://pypi.org/project/jupyter/1.0.0/) - [jupyter-client: 8.6.0](https://pypi.org/project/jupyter-client/8.6.0/) - [jupyter-console: 6.6.3](https://pypi.org/project/jupyter-console/6.6.3/) - [jupyter-core: 5.5.0](https://pypi.org/project/jupyter-core/5.5.0/) @@ -109,16 +89,13 @@ It comes pre-installed with a standard set of python packages. - [notebook-shim: 0.2.3](https://pypi.org/project/notebook-shim/0.2.3/) - [numba: 0.58.1](https://pypi.org/project/numba/0.58.1/) - [numpy: 1.26.2](https://pypi.org/project/numpy/1.26.2/) -- [oauthlib: 3.2.2](https://pypi.org/project/oauthlib/3.2.2/) - [opensafely-cohort-extractor: 1.90.0](https://pypi.org/project/opensafely-cohort-extractor/1.90.0/) - [opensafely-matching: 0.2.0](https://pypi.org/project/opensafely-matching/0.2.0/) - [overrides: 7.4.0](https://pypi.org/project/overrides/7.4.0/) - [packaging: 23.2](https://pypi.org/project/packaging/23.2/) - [pandas: 2.1.3](https://pypi.org/project/pandas/2.1.3/) -- [pandas-gbq: 0.19.2](https://pypi.org/project/pandas-gbq/0.19.2/) - [pandocfilters: 1.5.0](https://pypi.org/project/pandocfilters/1.5.0/) - [parso: 0.8.3](https://pypi.org/project/parso/0.8.3/) -- [patsy: 0.5.4](https://pypi.org/project/patsy/0.5.4/) - [pexpect: 4.9.0](https://pypi.org/project/pexpect/4.9.0/) - [pillow: 10.1.0](https://pypi.org/project/pillow/10.1.0/) - [pip-tools: 7.3.0](https://pypi.org/project/pip-tools/7.3.0/) @@ -127,20 +104,14 @@ It comes pre-installed with a standard set of python packages. - [pluggy: 1.3.0](https://pypi.org/project/pluggy/1.3.0/) - [prometheus-client: 0.19.0](https://pypi.org/project/prometheus-client/0.19.0/) - [prompt-toolkit: 3.0.41](https://pypi.org/project/prompt-toolkit/3.0.41/) -- [proto-plus: 1.22.3](https://pypi.org/project/proto-plus/1.22.3/) -- [protobuf: 4.25.1](https://pypi.org/project/protobuf/4.25.1/) - [psutil: 5.9.6](https://pypi.org/project/psutil/5.9.6/) - [ptyprocess: 0.7.0](https://pypi.org/project/ptyprocess/0.7.0/) - [pure-eval: 0.2.2](https://pypi.org/project/pure-eval/0.2.2/) - [py: 1.11.0](https://pypi.org/project/py/1.11.0/) - [pyarrow: 14.0.1](https://pypi.org/project/pyarrow/14.0.1/) -- [pyasn1: 0.5.1](https://pypi.org/project/pyasn1/0.5.1/) -- [pyasn1-modules: 0.3.0](https://pypi.org/project/pyasn1-modules/0.3.0/) - [pycparser: 2.21](https://pypi.org/project/pycparser/2.21/) -- [pydata-google-auth: 1.8.2](https://pypi.org/project/pydata-google-auth/1.8.2/) - [pygments: 2.17.2](https://pypi.org/project/pygments/2.17.2/) - [pyparsing: 3.1.1](https://pypi.org/project/pyparsing/3.1.1/) -- [pyproj: 3.6.1](https://pypi.org/project/pyproj/3.6.1/) - [pyproject-hooks: 1.0.0](https://pypi.org/project/pyproject-hooks/1.0.0/) - [pytest: 7.4.3](https://pypi.org/project/pytest/7.4.3/) - [python-dateutil: 2.8.2](https://pypi.org/project/python-dateutil/2.8.2/) @@ -148,27 +119,21 @@ It comes pre-installed with a standard set of python packages. - [pytz: 2023.3.post1](https://pypi.org/project/pytz/2023.3.post1/) - [pyyaml: 6.0.1](https://pypi.org/project/pyyaml/6.0.1/) - [pyzmq: 25.1.2](https://pypi.org/project/pyzmq/25.1.2/) -- [qtconsole: 5.5.1](https://pypi.org/project/qtconsole/5.5.1/) -- [qtpy: 2.4.1](https://pypi.org/project/qtpy/2.4.1/) - [referencing: 0.31.1](https://pypi.org/project/referencing/0.31.1/) - [requests: 2.31.0](https://pypi.org/project/requests/2.31.0/) -- [requests-oauthlib: 1.3.1](https://pypi.org/project/requests-oauthlib/1.3.1/) - [retry: 0.9.2](https://pypi.org/project/retry/0.9.2/) - [rfc3339-validator: 0.1.4](https://pypi.org/project/rfc3339-validator/0.1.4/) - [rfc3986-validator: 0.1.1](https://pypi.org/project/rfc3986-validator/0.1.1/) - [rpds-py: 0.13.2](https://pypi.org/project/rpds-py/0.13.2/) -- [rsa: 4.9](https://pypi.org/project/rsa/4.9/) - [scikit-learn: 1.3.2](https://pypi.org/project/scikit-learn/1.3.2/) - [scipy: 1.11.4](https://pypi.org/project/scipy/1.11.4/) - [seaborn: 0.13.0](https://pypi.org/project/seaborn/0.13.0/) - [send2trash: 1.8.2](https://pypi.org/project/send2trash/1.8.2/) -- [shapely: 2.0.2](https://pypi.org/project/shapely/2.0.2/) - [six: 1.16.0](https://pypi.org/project/six/1.16.0/) - [sniffio: 1.3.0](https://pypi.org/project/sniffio/1.3.0/) - [soupsieve: 2.5](https://pypi.org/project/soupsieve/2.5/) - [sqlparse: 0.4.4](https://pypi.org/project/sqlparse/0.4.4/) - [stack-data: 0.6.3](https://pypi.org/project/stack-data/0.6.3/) -- [statsmodels: 0.14.0](https://pypi.org/project/statsmodels/0.14.0/) - [structlog: 23.2.0](https://pypi.org/project/structlog/23.2.0/) - [tabulate: 0.9.0](https://pypi.org/project/tabulate/0.9.0/) - [tenacity: 8.2.3](https://pypi.org/project/tenacity/8.2.3/) diff --git a/v2/requirements.in b/v2/requirements.in index a89dd8b..82a8776 100644 --- a/v2/requirements.in +++ b/v2/requirements.in @@ -1,7 +1,8 @@ # Basic requirements for notebook infrastructure provided in base # docker image pip-tools -jupyter +notebook +jupyter-console jupyterlab jupytext bash_kernel @@ -9,10 +10,8 @@ nbval opensafely-matching # Commonly-used packages provided in base docker image -pandas-gbq pandas numpy -ebmdatalab matplotlib scipy tqdm diff --git a/v2/requirements.txt b/v2/requirements.txt index 25c762f..cf29f44 100644 --- a/v2/requirements.txt +++ b/v2/requirements.txt @@ -20,7 +20,6 @@ async-lru==2.0.4 # via jupyterlab attrs==23.1.0 # via - # fiona # jsonschema # referencing autograd==1.6.2 @@ -39,17 +38,12 @@ bleach==6.1.0 # via nbconvert build==1.0.3 # via pip-tools -cachetools==5.3.2 - # via google-auth cairocffi==1.6.1 # via cairosvg cairosvg==2.7.1 # via -r v2/requirements.in certifi==2023.11.17 - # via - # fiona - # pyproj - # requests + # via requests cffi==1.16.0 # via # argon2-cffi-bindings @@ -57,15 +51,7 @@ cffi==1.16.0 charset-normalizer==3.3.2 # via requests click==8.1.7 - # via - # click-plugins - # cligj - # fiona - # pip-tools -click-plugins==1.1.1 - # via fiona -cligj==0.7.2 - # via fiona + # via pip-tools comm==0.2.0 # via # ipykernel @@ -78,8 +64,6 @@ cssselect2==0.7.0 # via cairosvg cycler==0.12.1 # via matplotlib -db-dtypes==1.1.1 - # via pandas-gbq debugpy==1.8.0 # via ipykernel decorator==5.1.1 @@ -90,10 +74,6 @@ defusedxml==0.7.1 # via # cairosvg # nbconvert -descartes==1.1.0 - # via ebmdatalab -ebmdatalab==0.0.30 - # via -r v2/requirements.in exceptiongroup==1.2.0 # via # anyio @@ -103,8 +83,6 @@ executing==2.0.1 # via stack-data fastjsonschema==2.19.0 # via nbformat -fiona==1.9.5 - # via geopandas fonttools==4.46.0 # via matplotlib formulaic==0.6.6 @@ -113,46 +91,6 @@ fqdn==1.5.1 # via jsonschema future==0.18.3 # via autograd -geopandas==0.14.1 - # via ebmdatalab -google-api-core[grpc]==2.14.0 - # via - # google-cloud-bigquery - # google-cloud-bigquery-storage - # google-cloud-core - # pandas-gbq -google-auth==2.24.0 - # via - # google-api-core - # google-auth-oauthlib - # google-cloud-core - # pandas-gbq - # pydata-google-auth -google-auth-oauthlib==1.1.0 - # via - # pandas-gbq - # pydata-google-auth -google-cloud-bigquery==3.13.0 - # via pandas-gbq -google-cloud-bigquery-storage==2.23.0 - # via pandas-gbq -google-cloud-core==2.3.3 - # via google-cloud-bigquery -google-crc32c==1.5.0 - # via google-resumable-media -google-resumable-media==2.6.0 - # via google-cloud-bigquery -googleapis-common-protos==1.61.0 - # via - # google-api-core - # grpcio-status -grpcio==1.59.3 - # via - # google-api-core - # google-cloud-bigquery - # grpcio-status -grpcio-status==1.59.3 - # via google-api-core idna==3.6 # via # anyio @@ -165,20 +103,16 @@ interface-meta==1.3.0 ipykernel==6.27.1 # via # bash-kernel - # jupyter # jupyter-console # jupyterlab # nbval - # qtconsole ipython==8.18.1 # via # ipykernel # ipywidgets # jupyter-console ipywidgets==8.1.1 - # via - # -r v2/requirements.in - # jupyter + # via -r v2/requirements.in isoduration==20.11.0 # via jsonschema jedi==0.19.1 @@ -202,8 +136,6 @@ jsonschema[format-nongpl]==4.20.0 # nbformat jsonschema-specifications==2023.11.2 # via jsonschema -jupyter==1.0.0 - # via -r v2/requirements.in jupyter-client==8.6.0 # via # ipykernel @@ -211,9 +143,8 @@ jupyter-client==8.6.0 # jupyter-server # nbclient # nbval - # qtconsole jupyter-console==6.6.3 - # via jupyter + # via -r v2/requirements.in jupyter-core==5.5.0 # via # ipykernel @@ -224,7 +155,6 @@ jupyter-core==5.5.0 # nbclient # nbconvert # nbformat - # qtconsole jupyter-events==0.9.0 # via jupyter-server jupyter-lsp==2.2.1 @@ -273,7 +203,6 @@ markupsafe==2.1.3 matplotlib==3.8.2 # via # -r v2/requirements.in - # descartes # lifelines # seaborn # upsetplot @@ -291,9 +220,7 @@ mistune==3.0.2 nbclient==0.9.0 # via nbconvert nbconvert==7.12.0 - # via - # jupyter - # jupyter-server + # via jupyter-server nbformat==5.9.2 # via # jupyter-server @@ -306,7 +233,7 @@ nbval==0.10.0 nest-asyncio==1.5.8 # via ipykernel notebook==7.0.6 - # via jupyter + # via -r v2/requirements.in notebook-shim==0.2.3 # via # jupyterlab @@ -318,22 +245,15 @@ numpy==1.26.2 # -r v2/requirements.in # autograd # contourpy - # db-dtypes # formulaic # lifelines # matplotlib # numba # pandas - # pandas-gbq - # patsy # pyarrow # scikit-learn # scipy # seaborn - # shapely - # statsmodels -oauthlib==3.2.2 - # via requests-oauthlib opensafely-cohort-extractor==1.90.0 # via -r v2/requirements.in opensafely-matching==0.2.0 @@ -343,9 +263,6 @@ overrides==7.4.0 packaging==23.2 # via # build - # db-dtypes - # geopandas - # google-cloud-bigquery # ipykernel # jupyter-server # jupyterlab @@ -355,33 +272,19 @@ packaging==23.2 # nbconvert # plotly # pytest - # qtconsole - # qtpy - # statsmodels pandas==2.1.3 # via # -r v2/requirements.in - # db-dtypes - # ebmdatalab # formulaic - # geopandas # lifelines # opensafely-cohort-extractor # opensafely-matching - # pandas-gbq # seaborn - # statsmodels # upsetplot -pandas-gbq==0.19.2 - # via - # -r v2/requirements.in - # ebmdatalab pandocfilters==1.5.0 # via nbconvert parso==0.8.3 # via jedi -patsy==0.5.4 - # via statsmodels pexpect==4.9.0 # via # bash-kernel @@ -405,18 +308,6 @@ prompt-toolkit==3.0.41 # via # ipython # jupyter-console -proto-plus==1.22.3 - # via - # google-cloud-bigquery - # google-cloud-bigquery-storage -protobuf==4.25.1 - # via - # google-api-core - # google-cloud-bigquery - # google-cloud-bigquery-storage - # googleapis-common-protos - # grpcio-status - # proto-plus psutil==5.9.6 # via ipykernel ptyprocess==0.7.0 @@ -430,29 +321,16 @@ py==1.11.0 pyarrow==14.0.1 # via # -r v2/requirements.in - # db-dtypes # opensafely-cohort-extractor - # pandas-gbq -pyasn1==0.5.1 - # via - # pyasn1-modules - # rsa -pyasn1-modules==0.3.0 - # via google-auth pycparser==2.21 # via cffi -pydata-google-auth==1.8.2 - # via pandas-gbq pygments==2.17.2 # via # ipython # jupyter-console # nbconvert - # qtconsole pyparsing==3.1.1 # via matplotlib -pyproj==3.6.1 - # via geopandas pyproject-hooks==1.0.0 # via build pytest==7.4.3 @@ -462,7 +340,6 @@ pytest==7.4.3 python-dateutil==2.8.2 # via # arrow - # google-cloud-bigquery # jupyter-client # matplotlib # pandas @@ -481,11 +358,6 @@ pyzmq==25.1.2 # jupyter-client # jupyter-console # jupyter-server - # qtconsole -qtconsole==5.5.1 - # via jupyter -qtpy==2.4.1 - # via qtconsole referencing==0.31.1 # via # jsonschema @@ -493,13 +365,8 @@ referencing==0.31.1 # jupyter-events requests==2.31.0 # via - # google-api-core - # google-cloud-bigquery # jupyterlab-server # opensafely-cohort-extractor - # requests-oauthlib -requests-oauthlib==1.3.1 - # via google-auth-oauthlib retry==0.9.2 # via opensafely-cohort-extractor rfc3339-validator==0.1.4 @@ -514,8 +381,6 @@ rpds-py==0.13.2 # via # jsonschema # referencing -rsa==4.9 - # via google-auth scikit-learn==1.3.2 # via -r v2/requirements.in scipy==1.11.4 @@ -525,21 +390,14 @@ scipy==1.11.4 # formulaic # lifelines # scikit-learn - # statsmodels seaborn==0.13.0 - # via - # ebmdatalab - # opensafely-cohort-extractor + # via opensafely-cohort-extractor send2trash==1.8.2 # via jupyter-server -shapely==2.0.2 - # via geopandas six==1.16.0 # via # asttokens # bleach - # fiona - # patsy # python-dateutil # rfc3339-validator sniffio==1.3.0 @@ -550,8 +408,6 @@ sqlparse==0.4.4 # via opensafely-cohort-extractor stack-data==0.6.3 # via ipython -statsmodels==0.14.0 - # via ebmdatalab structlog==23.2.0 # via opensafely-cohort-extractor tabulate==0.9.0 @@ -604,7 +460,6 @@ traitlets==5.14.0 # nbclient # nbconvert # nbformat - # qtconsole types-python-dateutil==2.8.19.14 # via arrow typing-extensions==4.8.0 From 39e93f98c74cf59be4be1177fbc83e5fa5d082a6 Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Mon, 11 Dec 2023 12:05:50 +0000 Subject: [PATCH 11/11] enable publishing --- .github/workflows/build_and_publish.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_and_publish.yaml b/.github/workflows/build_and_publish.yaml index 52966bc..ad4161e 100644 --- a/.github/workflows/build_and_publish.yaml +++ b/.github/workflows/build_and_publish.yaml @@ -30,6 +30,5 @@ jobs: run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin - name: Push image to GitHub Container Registry run: | - # just test publish for now - just publish v1 false - just publish v2 false + just publish v1 true + just publish v2 true