diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b9e6fb2424e92827f0beeeb26f658f6ec43c3b47..2641a5f0ff76da23ad8e7784c381676d8bd85ff4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,5 +1,5 @@
 default:
-  image: $CI_REGISTRY/lofar2.0/attributewrapper/ci_python38:$CI_COMMIT_SHORT_SHA # minimum supported version
+  image: $CI_REGISTRY/lofar2.0/attributewrapper/ci_python312:$CI_COMMIT_SHORT_SHA # minimum supported version
   # Make sure each step is executed in a virtual environment with some basic dependencies present
   before_script:
     - python --version # For debugging
@@ -21,7 +21,7 @@ stages:
 variables:
   PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
 
-build_test_image_python38:
+build_test_image_python312:
   stage: image
   image: docker
   tags:
@@ -29,8 +29,8 @@ build_test_image_python38:
   before_script:
     - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
   script:
-    - docker build -t $CI_REGISTRY/lofar2.0/attributewrapper/ci_python38:$CI_COMMIT_SHORT_SHA -f docker/Dockerfile.ci_python38 docker
-    - docker push $CI_REGISTRY/lofar2.0/attributewrapper/ci_python38:$CI_COMMIT_SHORT_SHA
+    - docker build -t $CI_REGISTRY/lofar2.0/attributewrapper/ci_python312:$CI_COMMIT_SHORT_SHA -f docker/Dockerfile.ci_python312 docker
+    - docker push $CI_REGISTRY/lofar2.0/attributewrapper/ci_python312:$CI_COMMIT_SHORT_SHA
 
 run_black:
   stage: lint
@@ -48,7 +48,7 @@ run_pylint:
     - tox -e pylint
   allow_failure: true
 
-run_unit_tests_coverage:
+run_unit_tests_coverage_py312:
   stage: test
   script:
    - tox -e coverage
@@ -60,12 +60,6 @@ run_unit_tests_coverage:
     paths:
       - htmlcov/*
 
-run_unit_tests_py38:
-  stage: test
-  script:
-    - echo "run python3.7 unit tests /w coverage"
-    - tox -e py38
-
 .run_unit_tests_pyXX:
   # installs the prerequisites explicitly, instead of piggy backing
   # on the ci_python37 image. This allows us to use different base
@@ -97,13 +91,6 @@ run_unit_tests_py311:
     - echo "run python3.11 unit tests /w coverage"
     - tox -e py311
 
-run_unit_tests_py312:
-  extends: .run_unit_tests_pyXX
-  image: python:3.12-bullseye
-  script:
-    - echo "run python3.12 unit tests /w coverage"
-    - tox -e py312
-
 package_files:
   stage: package
   artifacts:
@@ -154,6 +141,7 @@ publish_on_gitlab:
 publish_on_test_pypi:
   stage: publish
   environment: pypi-test
+  allow_failure: true
   needs:
     - package_files
   when: manual
@@ -161,6 +149,7 @@ publish_on_test_pypi:
     - if: $CI_COMMIT_TAG
   script:
     - echo "run twine for test pypi"
+    - exit 1
     # - |
     #   TWINE_PASSWORD=${PIPY_TOKEN} \
     #   TWINE_USERNAME=${PIPY_USERNAME} \
@@ -171,6 +160,7 @@ publish_on_test_pypi:
 publish_on_pypi:
   stage: publish
   environment: pypi
+  allow_failure: true
   needs:
     - package_files
   when: manual
@@ -178,6 +168,7 @@ publish_on_pypi:
     - if: $CI_COMMIT_TAG
   script:
     - echo "run twine for pypi"
+    - exit 1
     # - |
     #   TWINE_PASSWORD=${PIPY_TOKEN} \
     #   TWINE_USERNAME=${PIPY_USERNAME} \
diff --git a/docker/Dockerfile.ci_python38 b/docker/Dockerfile.ci_python312
similarity index 64%
rename from docker/Dockerfile.ci_python38
rename to docker/Dockerfile.ci_python312
index e454417bd312db7b42339cd91812f16b7838f9d3..1ad11005eb4f282afb958c029cad4feb77b113ea 100644
--- a/docker/Dockerfile.ci_python38
+++ b/docker/Dockerfile.ci_python312
@@ -1,9 +1,8 @@
-FROM python:3.8-buster
+FROM python:3.12-bullseye
 
 # Install PyTango dependencies
 RUN apt-get update -y
 RUN DEBIAN_FRONTEND=noninteractive apt-get install -y git python3-pip
 
 # Make sure we have the latest tooling for our tests
-RUN python -m pip install --upgrade pip
-RUN pip install --upgrade "tox<4"
+RUN python -m pip install --upgrade pip tox
diff --git a/requirements.txt b/requirements.txt
index 2ef853cd1156c1aece86c1f89b885871b4e1d209..8e5ba02eebe22620c169fc75504e87d16d5004f0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,5 @@
-importlib-metadata>=0.12; python_version<"3.8"
 pip >= 1.5
-pytango >= 9.4.0
+pytango >= 9.5.1
 numpy >= 1.19.3; python_version >"3.9" and python_version <"3.10" # BSD
 numpy >= 1.21.6; python_version >"3.10" and python_version <"3.11" # BSD
 numpy >= 1.23.2; python_version >"3.11" and python_version <"3.12" # BSD
diff --git a/setup.cfg b/setup.cfg
index a56b8243081daf5671b3fcb15cfe8595f7f4756c..20d0abbcf910b17f4d90de8984d7c694ffd9493e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -15,8 +15,6 @@ classifiers =
     Programming Language :: Python
     Programming Language :: Python :: 3
     Programming Language :: Python :: 3 :: Only
-    Programming Language :: Python :: 3.7
-    Programming Language :: Python :: 3.8
     Programming Language :: Python :: 3.9
     Programming Language :: Python :: 3.10
     Programming Language :: Python :: 3.11
@@ -28,7 +26,7 @@ classifiers =
 [options]
 include_package_data = true
 packages = find:
-python_requires = >=3.7
+python_requires = >=3.9
 install_requires = file: requirements.txt
 
 [flake8]
diff --git a/tox.ini b/tox.ini
index a2899d8d3a56c93b399afb24c56597770f49241b..354877752da7a7bc52f4405c592f2845592146df 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
 [tox]
 # Generative environment list to test all supported Python versions
-envlist = py3{7,8,9,10,11},black,pep8,pylint
+envlist = py3{9,10,11},black,pep8,pylint
 minversion = 4.3.3
 
 [testenv]
@@ -8,8 +8,6 @@ usedevelop = True
 package = wheel
 wheel_build_env = .pkg
 setenv =
-    LANGUAGE=en_US
-    LC_ALL=en_US.UTF-8
     PYTHONWARNINGS=default::DeprecationWarning
 deps =
     -r{toxinidir}/requirements.txt
@@ -21,7 +19,7 @@ commands =
 [testenv:coverage]
 commands =
     {envpython} --version
-    {envpython} -m pytest --cov-report xml --cov-report html --cov-report xml:coverage.xml --cov=attribute_wrapper
+    {envpython} -m pytest --cov-report term  --cov-report xml --cov-report html --cov-report xml:coverage.xml --cov=attribute_wrapper
 
 # Use generative name and command prefixes to reuse the same virtualenv
 # for all linting jobs.
@@ -30,14 +28,14 @@ usedevelop = False
 envdir = {toxworkdir}/linting
 commands =
     pep8: {envpython} -m flake8 --version
-    pep8: {envpython} -m flake8 --extend-exclude './.venv/','./venv/'
+    pep8: {envpython} -m flake8 attribute_wrapper tests
     black: {envpython} -m black --version
-    black: {envpython} -m black --check --diff .
+    black: {envpython} -m black --check --diff attribute_wrapper tests
     pylint: {envpython} -m pylint --version
-    pylint: {envpython} -m pylint AttributeWrapper tests
+    pylint: {envpython} -m pylint attribute_wrapper tests
     format: {envpython} -m autopep8 -v -aa --in-place --recursive attribute_wrapper/
     format: {envpython} -m autopep8 -v -aa --in-place --recursive tests/
-    format: {envpython} -m black -v .
+    format: {envpython} -m black -v attribute_wrapper tests
 
 
 [testenv:build]