Repository: joke2k/django-environ

Issue:
Wrong missing environment variable name if using prefix
If setting a prefix, the name of a missing environment variable is incorrectly reported without it.

```python
# settings.py

env = environ.Env()
env.prefix = "DJANGO_"

SECRET_KEY = env.str("SECRET_KEY")
```

```sh
    raise ImproperlyConfigured(error_msg) from exc
django.core.exceptions.ImproperlyConfigured: Set the SECRET_KEY environment variable
```

The exception message should really read `"Set the DJANGO_SECRET_KEY environment variable"`.

Discussion:
@spenserblack: Just stumbled on this too. This isn't intentional, is it?@sergeyklay: This was fixed in #520, and I just merged it. The fix will be available in the next project release. Apologies for the wait, and thanks for reporting this!

Solution patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4e28fa5a..b5e76c06 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -26,10 +26,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v4.1.1
 
-      - name: Set up Python 3.10
-        uses: actions/setup-python@v4.7.1
+      - name: Set up Python 3.12
+        uses: actions/setup-python@v5.0.0
         with:
-          python-version: '3.10'
+          python-version: '3.12'
 
       - name: Install dependencies
         run: |
@@ -44,7 +44,7 @@ jobs:
 
       - name: Archive build artifacts
         if: success()
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           # To ensure that jobs don't overwrite existing artifacts,
           # use a different name per job.
@@ -66,10 +66,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v4.1.1
 
-      - name: Set up Python 3.10
-        uses: actions/setup-python@v4.7.1
+      - name: Set up Python 3.12
+        uses: actions/setup-python@v5.0.0
         with:
-          python-version: '3.10'
+          python-version: '3.12'
 
       - name: Install in dev mode
         run: python -m pip install -e .
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1fe3f1d6..32b597d2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -47,24 +47,14 @@ jobs:
 
       matrix:
         python:
-          - '3.8'
           - '3.9'
           - '3.10'
           - '3.11'
           - '3.12'
-          - 'pypy-3.7'
+          - '3.13'
+          - 'pypy-3.10'
         os: [ ubuntu-latest, macos-latest, windows-latest ]
 
-        # These versions are no longer supported by Python team, and may
-        # eventually be dropped from GitHub Actions.  The support of these
-        # versions by django-environ will continue for as long as possible,
-        # and may be discontinued at any time.
-        include:
-          - python: '3.6'
-            os: ubuntu-20.04
-          - python: '3.7'
-            os: ubuntu-20.04
-
     steps:
       - name: Checkout code
         uses: actions/checkout@v4.1.1
@@ -72,7 +62,7 @@ jobs:
           fetch-depth: 5
 
       - name: Set up Python ${{ matrix.python }}
-        uses: actions/setup-python@v4.7.1
+        uses: actions/setup-python@v5.0.0
         with:
           python-version: ${{ matrix.python }}
 
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 460c1e33..8d7b98f5 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -49,12 +49,12 @@ jobs:
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v2
+      uses: github/codeql-action/init@v3
       with:
         languages: ${{ matrix.language }}
         
     - name: Autobuild
-      uses: github/codeql-action/autobuild@v2
+      uses: github/codeql-action/autobuild@v3
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v2
+      uses: github/codeql-action/analyze@v3
diff --git a/.github/workflows/cs.yml b/.github/workflows/cs.yml
index 4daad7d5..edd720d9 100644
--- a/.github/workflows/cs.yml
+++ b/.github/workflows/cs.yml
@@ -27,10 +27,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v4.1.1
 
-      - name: Set up Python 3.10
-        uses: actions/setup-python@v4.7.1
+      - name: Set up Python 3.12
+        uses: actions/setup-python@v5.0.0
         with:
-          python-version: '3.10'
+          python-version: '3.12'
 
       - name: Install dependencies
         run: |
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index efef795c..bbb560d3 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -28,10 +28,10 @@ jobs:
       - name: Checkout code
         uses: actions/checkout@v4.1.1
 
-      - name: Set up Python 3.10
-        uses: actions/setup-python@v4.7.1
+      - name: Set up Python 3.12
+        uses: actions/setup-python@v5.0.0
         with:
-          python-version: '3.10'
+          python-version: '3.12'
 
       - name: Install dependencies
         run: |
@@ -46,7 +46,7 @@ jobs:
 
       - name: Archive docs artifacts
         if: always()
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: docs
           path: docs
diff --git a/.readthedocs.yml b/.readthedocs.yml
index 27f93688..191e9990 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -1,6 +1,6 @@
 # This file is part of the django-environ.
 #
-# Copyright (c) 2021, Serghei Iakovlev <egrep@protonmail.ch>
+# Copyright (c) 2021-2024, Serghei Iakovlev <oss@serghei.pl>
 # Copyright (c) 2013-2021, Daniele Faraglia <daniele.faraglia@gmail.com>
 #
 # For the full copyright and license information, please view
@@ -17,7 +17,7 @@ build:
   tools:
     # Keep version in sync with tox.ini (testenv:docs) and
     # docs.yml (GitHub Action Workflow).
-    python: '3.10'
+    python: '3.12'
 
 python:
   install:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 6051aa4a..8de3f0e6 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -5,16 +5,27 @@ All notable changes to this project will be documented in this file.
 The format is inspired by `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_
 and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
 
-`v0.11.3`_ - 0-Undefined-2023
+`v0.12.0`_ - 0-Undefined-2024
 -----------------------------
+Added
++++++
+- Add support for Python 3.12 and 3.13
+  `#538 <https://github.com/joke2k/django-environ/issues/538>`_.
+- Add support for Django 5.1
+  `#535 <https://github.com/joke2k/django-environ/issues/535>`_.
+
 Changed
 +++++++
-- Formally support Python 3.12.
 - Disabled inline comments handling by default due to potential side effects.
   While the feature itself is useful, the project's philosophy dictates that
   it should not be enabled by default for all users
   `#499 <https://github.com/joke2k/django-environ/issues/499>`_.
 
+Removed
++++++++
+- Removed support of Python 3.6, 3.7 and 3.8.
+- Removed support of Django 1.x.
+
 
 `v0.11.2`_ - 1-September-2023
 -----------------------------
@@ -399,7 +410,7 @@ Added
 - Initial release.
 
 
-.. _v0.11.3: https://github.com/joke2k/django-environ/compare/v0.11.2...v0.11.3
+.. _v0.12.0: https://github.com/joke2k/django-environ/compare/v0.11.2...v0.12.0
 .. _v0.11.2: https://github.com/joke2k/django-environ/compare/v0.11.1...v0.11.2
 .. _v0.11.1: https://github.com/joke2k/django-environ/compare/v0.11.0...v0.11.1
 .. _v0.11.0: https://github.com/joke2k/django-environ/compare/v0.10.0...v0.11.0
@@ -417,4 +428,4 @@ Added
 .. _v0.4.1: https://github.com/joke2k/django-environ/compare/v0.4...v0.4.1
 .. _v0.4: https://github.com/joke2k/django-environ/compare/v0.3.1...v0.4
 .. _v0.3.1: https://github.com/joke2k/django-environ/compare/v0.3...v0.3.1
-.. _v0.3: https://github.com/joke2k/django-environ/compare/v0.2.1...v0.3
\ No newline at end of file
+.. _v0.3: https://github.com/joke2k/django-environ/compare/v0.2.1...v0.3
diff --git a/README.rst b/README.rst
index dbb572ba..ff8e0125 100644
--- a/README.rst
+++ b/README.rst
@@ -97,7 +97,8 @@ approach, some connection strings are expressed as url, so this package can pars
 it and return a ``urllib.parse.ParseResult``. These strings from ``os.environ``
 are loaded from a ``.env`` file and filled in ``os.environ`` with ``setdefault``
 method, to avoid to overwrite the real environ.
-A similar approach is used in `Two Scoops of Django <https://www.feldroy.com/books/two-scoops-of-django-3-x>`_
+A similar approach is used in
+`Two Scoops of Django <https://web.archive.org/web/20240121133956/https://www.feldroy.com/books/two-scoops-of-django-3-x>`_
 book and explained in `12factor-django <https://wellfire.co/learn/easier-12-factor-django>`_
 article.
 
@@ -126,8 +127,8 @@ its documentation lives at `Read the Docs <https://django-environ.readthedocs.io
 the code on `GitHub <https://github.com/joke2k/django-environ>`_,
 and the latest release on `PyPI <https://pypi.org/project/django-environ/>`_.
 
-It’s rigorously tested on Python 3.6+, and officially supports
-Django 1.11, 2.2, 3.0, 3.1, 3.2, 4.0, 4.1, 4.2, and 5.0.
+It’s rigorously tested on Python 3.9+, and officially supports
+Django 2.2, 3.0, 3.1, 3.2, 4.0, 4.1, 4.2, 5.0, and 5.1.
 
 If you'd like to contribute to ``django-environ`` you're most welcome!
 
diff --git a/docs/install.rst b/docs/install.rst
index 3dacca9e..b1a73c18 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -6,8 +6,8 @@ Installation
 Requirements
 ============
 
-* `Django <https://www.djangoproject.com/>`_ >= 1.11
-* `Python <https://www.python.org/>`_ >= 3.5
+* `Django <https://www.djangoproject.com/>`_ >= 2.2
+* `Python <https://www.python.org/>`_ >= 3.9
 
 Installing django-environ
 =========================
diff --git a/environ/environ.py b/environ/environ.py
index a3d64f2d..32a1b7ad 100644
--- a/environ/environ.py
+++ b/environ/environ.py
@@ -388,7 +388,7 @@ def get_value(self, var, cast=None, default=NOTSET, parse_default=False):
             value = self.ENVIRON[var_name]
         except KeyError as exc:
             if default is self.NOTSET:
-                error_msg = f'Set the {var} environment variable'
+                error_msg = f'Set the {var_name} environment variable'
                 raise ImproperlyConfigured(error_msg) from exc
 
             value = default
diff --git a/setup.py b/setup.py
index fd3cd811..e9272177 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
 #
 # This file is part of the django-environ.
 #
-# Copyright (c) 2021-2023, Serghei Iakovlev <egrep@protonmail.ch>
+# Copyright (c) 2021-2024, Serghei Iakovlev <oss@serghei.pl>
 # Copyright (c) 2013-2021, Daniele Faraglia <daniele.faraglia@gmail.com>
 #
 # For the full copyright and license information, please view
@@ -135,9 +135,6 @@ def get_version_string():
     'Development Status :: 5 - Production/Stable',
 
     'Framework :: Django',
-    'Framework :: Django :: 1.11',
-    'Framework :: Django :: 2.0',
-    'Framework :: Django :: 2.1',
     'Framework :: Django :: 2.2',
     'Framework :: Django :: 3.0',
     'Framework :: Django :: 3.1',
@@ -146,6 +143,7 @@ def get_version_string():
     'Framework :: Django :: 4.1',
     'Framework :: Django :: 4.2',
     'Framework :: Django :: 5.0',
+    'Framework :: Django :: 5.1',
 
     'Operating System :: OS Independent',
 
@@ -154,13 +152,11 @@ def get_version_string():
 
     'Programming Language :: Python',
     'Programming Language :: Python :: 3',
-    'Programming Language :: Python :: 3.6',
-    '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',
     'Programming Language :: Python :: 3.12',
+    'Programming Language :: Python :: 3.13',
     'Programming Language :: Python :: Implementation :: CPython',
     'Programming Language :: Python :: Implementation :: PyPy',
 
@@ -185,11 +181,12 @@ def get_version_string():
     'testing': [
         'coverage[toml]>=5.0a4',  # Code coverage measurement for Python
         'pytest>=4.6.11',  # Our tests framework
+        'setuptools>=71.0.0',  # Needed as a dependency for some tests
     ],
     # Dependencies that are required to build documentation
     'docs': [
-        'furo>=2021.8.17b43,==2021.8.*',  # Sphinx documentation theme
-        'sphinx>=3.5.0',  # Python documentation generator
+        'furo>=2024.8.6',  # Sphinx documentation theme
+        'sphinx>=5.0',  # Python documentation generator
         'sphinx-notfound-page',  # Create a custom 404 page
     ],
 }
@@ -232,7 +229,7 @@ def get_version_string():
         platforms=['any'],
         include_package_data=True,
         zip_safe=False,
-        python_requires='>=3.6,<4',
+        python_requires='>=3.9,<4',
         install_requires=INSTALL_REQUIRES,
         dependency_links=DEPENDENCY_LINKS,
         extras_require=EXTRAS_REQUIRE,
diff --git a/tox.ini b/tox.ini
index fa3da3df..a0b8dc28 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
 # This file is part of the django-environ.
 #
-# Copyright (c) 2021-2023, Serghei Iakovlev <egrep@protonmail.ch>
+# Copyright (c) 2021-2024, Serghei Iakovlev <oss@serghei.pl>
 # Copyright (c) 2013-2021, Daniele Faraglia <daniele.faraglia@gmail.com>
 #
 # For the full copyright and license information, please view
@@ -18,28 +18,23 @@ envlist =
     docs
     lint
     manifest
-    py{36,37,38,39,310,311}-django{111,22}
-    py{36,37,38,39,310,311}-django{30,31,32}
-    py{38,39,310,311}-django{40,41,42}
-    py{310,311}-django{50}
-    pypy-django{111,22,30,31,32}
+    py{39,310,311,312,313}-django{22,30,31,32,40,41,42}
+    py{310,311,312,313}-django{50,51}
+    pypy-django{22,30,31,32}
 
 [gh-actions]
 python =
-    3.6: py36
-    3.7: py37
-    3.8: py38
     3.9: py39
     3.10: py310
     3.11: py311
     3.12: py312
-    pypy-3.7: pypy
+    3.13: py313
+    pypy-3.10: pypy
 
 [testenv]
 description = Unit tests
 extras = testing
 deps =
-    django111: Django>=1.11,<2
     django22: Django>=2.2,<3.0
     django30: Django>=3.0,<3.1
     django31: Django>=3.1,<3.2
@@ -93,7 +88,7 @@ commands =
 description = Check external links in the package documentation
 # Keep basepython in sync with .readthedocs.yml and docs.yml
 # (GitHub Action Workflow).
-basepython = python3.10
+basepython = python3.12
 extras = docs
 commands =
     {envpython} -m sphinx \
@@ -111,7 +106,7 @@ isolated_build = true
 description = Build package documentation (HTML)
 # Keep basepython in sync with .readthedocs.yml and docs.yml
 # (GitHub Action Workflow).
-basepython = python3.10
+basepython = python3.12
 extras = docs
 commands =
     {envpython} -m sphinx \


Test patch:
diff --git a/tests/test_env.py b/tests/test_env.py
index 85e0499f..ac383773 100644
--- a/tests/test_env.py
+++ b/tests/test_env.py
@@ -407,6 +407,13 @@ def test_prefix(self):
         self.env.prefix = 'PREFIX_'
         assert self.env('TEST') == 'foo'
 
+    def test_prefix_and_not_present_without_default(self):
+        self.env.prefix = 'PREFIX_'
+        with pytest.raises(ImproperlyConfigured) as excinfo:
+            self.env('not_present')
+        assert str(excinfo.value) == 'Set the PREFIX_not_present environment variable'
+        assert excinfo.value.__cause__ is not None
+
 
 class TestFileEnv(TestEnv):
     def setup_method(self, method):