From 556f228dbe9b94bd2c3790cd18867b96c2958f3e Mon Sep 17 00:00:00 2001 From: vladd-bit Date: Tue, 21 Jul 2026 18:38:42 +0100 Subject: [PATCH] Updated docker image to use LTS 26.04 and made relevant changes to migrate from python3.13 to 3.14. --- .github/workflows/run_tests.yml | 10 +++++----- Dockerfile | 20 ++++++++++---------- ocr_service/settings.py | 2 +- requirements.txt | 2 +- start_service_debug.sh | 12 +++++++----- start_service_production.sh | 9 +++++---- 6 files changed, 29 insertions(+), 26 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index f2f1bfe..a40b6c6 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -27,7 +27,7 @@ jobs: strategy: matrix: - python-version: ["3.12"] + python-version: ["3.14"] max-parallel: 4 # Steps represent a sequence of tasks that will be executed as part of the job @@ -87,7 +87,7 @@ jobs: sudo apt upgrade -y # install req packages - sudo apt install -y --no-install-recommends python3-all-dev python3-dev python3-pip python${{ matrix.python-version }} python${{ matrix.python-version }}-dev + sudo apt install -y --no-install-recommends python3-all-dev python3-dev python3-pip sudo apt -y --no-install-recommends -o Dpkg::Options::="--force-confold" -y -o Dpkg::Options::="--force-confdef" -fuy dist-upgrade sudo apt install -y --no-install-recommends \ gnupg \ @@ -148,12 +148,12 @@ jobs: - name: Install python deps & create virtual environment run: | - # BEFORE creating the venv so /usr/bin/python3.12 can run unoserver + # BEFORE creating the venv so the distro Python can run unoserver # the reason for this is that the uno python bindings are tied to the system python # and will not work in a venv # so we need to install unoserver globally to match the version in requirements.txt # this is a bit hacky but it works around the issue of unoserver not being available - # via pip for python3.12 (as of 2025-08) + # via pip for the distro Python used by LibreOffice/UNO set -eux UNOSERVER_PIN=$(awk -F'==' '/^unoserver==/ {print $2; exit}' requirements.txt || true) @@ -183,7 +183,7 @@ jobs: run: | export OCR_SERVICE_LOG_LEVEL=10 export OCR_SERVICE_DEBUG_MODE=True - export LIBRE_OFFICE_PYTHON_PATH=/usr/bin/python3.12 + export LIBRE_OFFICE_PYTHON_PATH=/usr/bin/python3 export OCR_TMP_DIR=${{ github.workspace }}/tmp source venv/bin/activate python -m unittest discover -s ocr_service/tests -p 'test_process.py' diff --git a/Dockerfile b/Dockerfile index 50eaba1..5ecab64 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ -FROM ubuntu:noble +FROM ubuntu:26.04 -ARG APP_PYTHON_VERSION=3.13 -ARG LO_PYTHON_VERSION=3.12 +ARG APP_PYTHON_VERSION=3.14 +ARG LO_PYTHON_VERSION=3.14 ARG HTTP_PROXY ARG HTTPS_PROXY @@ -45,7 +45,6 @@ RUN apt-get -o Acquire::Retries=5 update -yq && \ # add extra repos RUN apt-add-repository -y -n multiverse && \ apt-add-repository -y -n universe && \ - add-apt-repository -y -n ppa:deadsnakes/ppa && \ add-apt-repository -y -n ppa:graphics-drivers/ppa && \ apt-get -o Acquire::Retries=5 update -yq && \ apt-get upgrade -y @@ -88,9 +87,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends fontconfig ttf- libsm6 libxext6 gstreamer1.0-libav fonts-deva fonts-dejavu fonts-gfs-didot fonts-gfs-didot-classic fonts-junicode fonts-ebgaramond fonts-noto-cjk fonts-takao-gothic fonts-vlgothic \ ghostscript ghostscript-x gsfonts gsfonts-other gsfonts-x11 fonts-croscore fonts-crosextra-caladea fonts-crosextra-carlito fonts-liberation fonts-open-sans fonts-noto-core fonts-ibm-plex fonts-urw-base35 \ fonts-noto fonts-noto-cjk fonts-noto-extra xfonts-terminus fonts-font-awesome fonts-hack fonts-inconsolata fonts-liberation2 fonts-mononoki \ - libpcre3 libpcre3-dev libxml2 libxml2-dev libxslt1.1 libxslt-dev \ + libpcre2-8-0 libpcre2-dev libxml2-16 libxml2-dev libxslt1.1 libxslt-dev \ mesa-opencl-icd pocl-opencl-icd libvips-tools libvips libvips-dev \ - imagemagick libcairo2-dev tesseract-ocr tesseract-ocr-all libtesseract5 libtesseract-dev libleptonica-dev liblept5 + imagemagick libcairo2-dev tesseract-ocr tesseract-ocr-all libtesseract5 libtesseract-dev libleptonica-dev libleptonica6 # tessaract language packages RUN apt-get install -y --no-install-recommends --fix-missing tesseract-ocr-osd tesseract-ocr-lat \ @@ -127,12 +126,12 @@ COPY ./ /ocr_service WORKDIR /ocr_service # --- Install system-wide unoserver to match requirements.txt (for UNO/system Python) --- -# BEFORE creating the venv so /usr/bin/python3.12 can run unoserver +# BEFORE creating the venv so the distro Python can run unoserver # the reason for this is that the uno python bindings are tied to the system python # and will not work in a venv # so we need to install unoserver globally to match the version in requirements.txt # this is a bit hacky but it works around the issue of unoserver not being available -# via pip for the system python (3.12 on Ubuntu noble) +# via pip for the system Python used by LibreOffice/UNO RUN UNOSERVER_PIN=$(awk -F'==' '/^unoserver==/ {print $2; exit}' requirements.txt || true) && \ if [ -n "$UNOSERVER_PIN" ]; then \ echo "Installing system unoserver==$UNOSERVER_PIN"; \ @@ -146,9 +145,9 @@ RUN UNOSERVER_PIN=$(awk -F'==' '/^unoserver==/ {print $2; exit}' requirements.tx # Use a virtual environment for Python deps (single-stage build) ENV VIRTUAL_ENV=/opt/venv ENV PATH="$VIRTUAL_ENV/bin:$PATH" -ENV LIBRE_OFFICE_PYTHON_PATH=/usr/bin/python3.12 +ENV LIBRE_OFFICE_PYTHON_PATH=/usr/bin/python${LO_PYTHON_VERSION} -# Install the application into a Python 3.13 virtual environment while +# Install the application into a separate virtual environment while # keeping LibreOffice/UNO on the system Python. RUN python${APP_PYTHON_VERSION} -m venv "$VIRTUAL_ENV" && \ "$VIRTUAL_ENV/bin/python" && \ @@ -164,6 +163,7 @@ ARG OCR_SERVICE_GID=10001 RUN groupadd --system --gid "$OCR_SERVICE_GID" ocrsvc && \ useradd --system --uid "$OCR_SERVICE_UID" --gid "$OCR_SERVICE_GID" --create-home --home-dir /home/ocrsvc --shell /usr/sbin/nologin ocrsvc && \ mkdir -p /ocr_service/tmp /ocr_service/log && \ + chmod -R a+rX /ocr_service && \ chown -R ocrsvc:ocrsvc /ocr_service/tmp /ocr_service/log /home/ocrsvc ENV HOME=/home/ocrsvc USER ocrsvc diff --git a/ocr_service/settings.py b/ocr_service/settings.py index 09b861c..4a49ef6 100755 --- a/ocr_service/settings.py +++ b/ocr_service/settings.py @@ -100,7 +100,7 @@ def model_post_init(self, __context: Any) -> None: if platform in ("linux", "linux2"): default_lo_exec = "/usr/bin/soffice" - default_lo_python = "/usr/bin/python3.12" + default_lo_python = "/usr/bin/python3" tessdata_prefix = "/usr/share/tesseract-ocr/5/tessdata" if not os.path.exists(tessdata_prefix): diff --git a/requirements.txt b/requirements.txt index 57420ea..246612b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ html2image==2.0.7 tesserocr==2.9.2 gunicorn==23.0.0 pypdfium2==5.9.0 -opencv-python-headless==4.12.0.88 +opencv-python-headless==4.13.0.92 pyxml2pdf==0.3.4 fastapi==0.116.1 orjson==3.11.6 diff --git a/start_service_debug.sh b/start_service_debug.sh index cdf2eea..caaa919 100755 --- a/start_service_debug.sh +++ b/start_service_debug.sh @@ -43,14 +43,16 @@ echo "========================================================================== python_version=python3 -if command -v python3.11 &>/dev/null; then - python_version=python3.11 -elif command -v python3.12 &>/dev/null; then - python_version=python3.12 +if command -v python3.14 &>/dev/null; then + python_version=python3.14 elif command -v python3.13 &>/dev/null; then python_version=python3.13 +elif command -v python3.12 &>/dev/null; then + python_version=python3.12 +elif command -v python3.11 &>/dev/null; then + python_version=python3.11 else - echo "Python 3.11, 3.12, or 3.13 is required. Please install one of them." + echo "Python 3.11, 3.12, 3.13, or 3.14 is required. Please install one of them." exit 1 fi diff --git a/start_service_production.sh b/start_service_production.sh index 9fbfc93..0439a63 100755 --- a/start_service_production.sh +++ b/start_service_production.sh @@ -40,12 +40,14 @@ if [[ -x "$VIRTUAL_ENV/bin/gunicorn" ]]; then else # Fallback to system python if venv missing python_cmd=python3 - if command -v python3.12 &>/dev/null; then + if command -v python3.14 &>/dev/null; then + python_cmd=python3.14 + elif command -v python3.13 &>/dev/null; then + python_cmd=python3.13 + elif command -v python3.12 &>/dev/null; then python_cmd=python3.12 elif command -v python3.11 &>/dev/null; then python_cmd=python3.11 - elif command -v python3.13 &>/dev/null; then - python_cmd=python3.13 fi gunicorn_cmd=("$python_cmd" "-m" "gunicorn") fi @@ -60,4 +62,3 @@ exec "${gunicorn_cmd[@]}" wsgi:app --worker-class "$OCR_SERVICE_WORKER_CLASS" \ --max-requests-jitter "$OCR_SERVICE_GUNICORN_MAX_REQUESTS_JITTER" \ --timeout "$OCR_SERVICE_GUNICORN_TIMEOUT" \ --graceful-timeout "$OCR_SERVICE_GUNICORN_GRACEFUL_TIMEOUT" -