New Upstream Release - django-maintenance-mode
Ready changes
Summary
Merged new upstream version: 0.18.0 (was: 0.16.1).
Resulting package
Built on 2022-12-31T01:11 (took 5m32s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases python3-django-maintenance-mode
Lintian Result
Diff
diff --git a/LICENSE.txt b/LICENSE.txt
index 08c3cb0..263e288 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2016 Fabio Caccamo - fabio.caccamo@gmail.com
+Copyright (c) 2016-present Fabio Caccamo - fabio.caccamo@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/PKG-INFO b/PKG-INFO
index 17a5033..a785de3 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,350 +1,360 @@
Metadata-Version: 2.1
Name: django-maintenance-mode
-Version: 0.16.1
+Version: 0.18.0
Summary: django-maintenance-mode shows a 503 error page when maintenance-mode is on.
Home-page: https://github.com/fabiocaccamo/django-maintenance-mode
+Download-URL: https://github.com/fabiocaccamo/django-maintenance-mode/archive/0.18.0.tar.gz
Author: Fabio Caccamo
Author-email: fabio.caccamo@gmail.com
License: MIT
-Download-URL: https://github.com/fabiocaccamo/django-maintenance-mode/archive/0.16.1.tar.gz
-Description: [![](https://img.shields.io/pypi/pyversions/django-maintenance-mode.svg?color=3776AB&logo=python&logoColor=white)](https://www.python.org/)
- [![](https://img.shields.io/pypi/djversions/django-maintenance-mode?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/)
-
- [![](https://img.shields.io/pypi/v/django-maintenance-mode.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-maintenance-mode/)
- [![](https://pepy.tech/badge/django-maintenance-mode)](https://pepy.tech/project/django-maintenance-mode)
- [![](https://img.shields.io/github/stars/fabiocaccamo/django-maintenance-mode?logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode/)
- [![](https://badges.pufler.dev/visits/fabiocaccamo/django-maintenance-mode?label=visitors&color=blue)](https://badges.pufler.dev)
- [![](https://img.shields.io/pypi/l/django-maintenance-mode.svg?color=blue)](https://github.com/fabiocaccamo/django-maintenance-mode/blob/master/LICENSE.txt)
-
- [![](https://img.shields.io/travis/fabiocaccamo/django-maintenance-mode?logo=travis&label=build)](https://travis-ci.org/fabiocaccamo/django-maintenance-mode)
- [![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-maintenance-mode?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-maintenance-mode)
- [![](https://img.shields.io/codacy/grade/918668ac85e74206a4d8d95923548d79?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-maintenance-mode)
- [![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/django-maintenance-mode?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/django-maintenance-mode/)
- [![](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements.svg?branch=master)](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements/?branch=master)
-
- # django-maintenance-mode
- django-maintenance-mode shows a 503 error page when **maintenance-mode** is **on**.
-
- It works at application level, so your django instance should be up.
-
- It doesn't use database and doesn't prevent database access.
-
- ## Installation
-
- 1. Run ``pip install django-maintenance-mode`` or [download django-maintenance-mode](http://pypi.python.org/pypi/django-maintenance-mode) and add the **maintenance_mode** package to your project
- 2. Add ``'maintenance_mode'`` to ``settings.INSTALLED_APPS`` before custom applications
- 3. Add ``'maintenance_mode.middleware.MaintenanceModeMiddleware'`` to ``settings.MIDDLEWARE_CLASSES``/``settings.MIDDLEWARE`` as last middleware
- 4. Add your custom ``templates/503.html`` file
- 5. Restart your application server
-
- ## Configuration (optional)
-
- ### Settings
- All these settings are optional, if not defined in ``settings.py`` the default values (listed below) will be used.
-
- ```python
- # if True the maintenance-mode will be activated
- MAINTENANCE_MODE = None
- ```
-
- ```python
- # by default, to get/set the state value a local file backend is used
- # if you want to use the db or cache, you can create a custom backend
- # custom backends must extend 'maintenance_mode.backends.AbstractStateBackend' class
- # and implement get_value(self) and set_value(self, val) methods
- MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.LocalFileBackend'
-
- # alternatively it is possible to use the default storage backend
- MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.DefaultStorageBackend'
- ```
-
- ```python
- # by default, a file named "maintenance_mode_state.txt" will be created in the settings.py directory
- # you can customize the state file path in case the default one is not writable
- MAINTENANCE_MODE_STATE_FILE_PATH = 'maintenance_mode_state.txt'
- ```
-
- ```python
- # if True admin site will not be affected by the maintenance-mode page
- MAINTENANCE_MODE_IGNORE_ADMIN_SITE = False
- ```
-
- ```python
- # if True anonymous users will not see the maintenance-mode page
- MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER = False
- ```
-
- ```python
- # if True authenticated users will not see the maintenance-mode page
- MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER = False
- ```
-
- ```python
- # if True the staff will not see the maintenance-mode page
- MAINTENANCE_MODE_IGNORE_STAFF = False
- ```
-
- ```python
- # if True the superuser will not see the maintenance-mode page
- MAINTENANCE_MODE_IGNORE_SUPERUSER = False
- ```
-
- ```python
- # list of ip-addresses that will not be affected by the maintenance-mode
- # ip-addresses will be used to compile regular expressions objects
- MAINTENANCE_MODE_IGNORE_IP_ADDRESSES = ()
- ```
-
- ```python
- # the path of the function that will return the client IP address given the request object -> 'myapp.mymodule.myfunction'
- # the default function ('maintenance_mode.utils.get_client_ip_address') returns request.META['REMOTE_ADDR']
- # in some cases the default function returns None, to avoid this scenario just use 'django-ipware'
- MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = None
- ```
- Retrieve user's real IP address using [`django-ipware`](https://github.com/un33k/django-ipware):
- ```python
- MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = 'ipware.ip.get_ip'
- ```
-
- ```python
- # list of urls that will not be affected by the maintenance-mode
- # urls will be used to compile regular expressions objects
- MAINTENANCE_MODE_IGNORE_URLS = ()
- ```
-
- ```python
- # if True the maintenance mode will not return 503 response while running tests
- # useful for running tests while maintenance mode is on, before opening the site to public use
- MAINTENANCE_MODE_IGNORE_TESTS = False
- ```
-
- ```python
- # the absolute url where users will be redirected to during maintenance-mode
- MAINTENANCE_MODE_REDIRECT_URL = None
- ```
-
- ```python
- # the template that will be shown by the maintenance-mode page
- MAINTENANCE_MODE_TEMPLATE = '503.html'
- ```
-
- ```python
- # the path of the function that will return the template context -> 'myapp.mymodule.myfunction'
- MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT = None
- ```
-
- ```python
- # the HTTP status code to send
- MAINTENANCE_MODE_STATUS_CODE = 503
- ```
-
- ```python
- # the value in seconds of the Retry-After header during maintenance-mode
- MAINTENANCE_MODE_RETRY_AFTER = 3600 # 1 hour
- ```
-
- #### Context Processors
- Add **maintenance_mode.context_processors.maintenance_mode** to your context_processors list in ``settings.py`` if you want to access the maintenance_mode status in your templates.
-
- ```python
- TEMPLATES = [
- {
- # ...
- 'OPTIONS': {
- 'context_processors': [
- # ...
- 'maintenance_mode.context_processors.maintenance_mode',
- # ...
- ],
- },
- # ...
- },
- ]
- ```
-
- #### Logging
- You can disable emailing 503 errors to admins while maintenance mode is enabled:
-
- ```python
- LOGGING = {
- 'filters': {
- 'require_not_maintenance_mode_503': {
- '()': 'maintenance_mode.logging.RequireNotMaintenanceMode503',
- },
- ...
- },
- 'handlers': {
- ...
- },
- ...
- }
- ```
-
- ### Context Managers
- You can force a block of code execution to run under maintenance mode or not using context managers:
-
- ```python
- from maintenance_mode.core import maintenance_mode_off, maintenance_mode_on
-
- with maintenance_mode_on():
- # do stuff
- pass
-
- with maintenance_mode_off():
- # do stuff
- pass
- ```
-
- ### URLs
- Add **maintenance_mode.urls** to ``urls.py`` if you want superusers able to set maintenance_mode using urls.
-
- ```python
- urlpatterns = [
- # ...
- url(r'^maintenance-mode/', include('maintenance_mode.urls')),
- # ...
- ]
- ```
-
- ### Views
- You can force maintenance mode on/off at view level using view decorators:
-
- ```python
- from maintenance_mode.decorators import force_maintenance_mode_off, force_maintenance_mode_on
-
- @force_maintenance_mode_off
- def my_view_a(request):
- # never return 503 response
- pass
-
- @force_maintenance_mode_on
- def my_view_b(request):
- # always return 503 response
- pass
- ```
-
- ## Usage
-
- ### Python
- ```python
- from maintenance_mode.core import get_maintenance_mode, set_maintenance_mode
-
- set_maintenance_mode(True)
-
- if get_maintenance_mode():
- set_maintenance_mode(False)
- ```
- or
- ```python
- from django.core.management import call_command
- from django.core.management.base import BaseCommand
-
-
- class Command(BaseCommand):
-
- def handle(self, *args, **options):
-
- call_command('maintenance_mode', 'on')
-
- # call your command(s)
-
- call_command('maintenance_mode', 'off')
-
-
-
- ```
-
- ### Templates
- ```html
- {% if maintenance_mode %}
- <!-- html -->
- {% endif %}
- ```
-
- ### Terminal
-
- Run ``python manage.py maintenance_mode <on|off>``
-
- *(**This is not Heroku-friendly because** any execution of heroku run* `manage.py` *will be run on a separate worker dyno, not the web one. Therefore **the state-file is set but on the wrong machine. You should use a custom*** `MAINTENANCE_MODE_STATE_BACKEND`*.)*
-
- ### URLs
- Superusers can change maintenance-mode using the following urls:
-
- ``/maintenance-mode/off/``
-
- ``/maintenance-mode/on/``
-
- ## Testing
- ```bash
- # create python virtual environment
- virtualenv testing_django_maintenance_mode
-
- # activate virtualenv
- cd testing_django_maintenance_mode && . bin/activate
-
- # clone repo
- git clone https://github.com/fabiocaccamo/django-maintenance-mode.git src && cd src
-
- # run tests
- tox
- # or
- python setup.py test
- # or
- python -m django test --settings "tests.settings"
- ```
-
- ## License
- Released under [MIT License](LICENSE.txt).
-
- ---
-
- ## See also
-
- - [`django-admin-interface`](https://github.com/fabiocaccamo/django-admin-interface) - the default admin interface made customizable by the admin itself. popup windows replaced by modals. ๐ง โก
-
- - [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. ๐จ
-
- - [`django-extra-settings`](https://github.com/fabiocaccamo/django-extra-settings) - config and manage typed extra settings using just the django admin. โ๏ธ
-
- - [`django-redirects`](https://github.com/fabiocaccamo/django-redirects) - redirects with full control. โช๏ธ
-
- - [`django-treenode`](https://github.com/fabiocaccamo/django-treenode) - probably the best abstract model / admin for your tree based stuff. ๐ณ
-
- - [`python-benedict`](https://github.com/fabiocaccamo/python-benedict) - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. ๐
-
- - [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. ๐ฎ๐น ๐ณ
-
- - [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. ๐งโโ๏ธ
-
+Project-URL: Documentation, https://github.com/fabiocaccamo/django-maintenance-mode#readme
+Project-URL: Issues, https://github.com/fabiocaccamo/django-maintenance-mode/issues
+Project-URL: Funding, https://github.com/sponsors/fabiocaccamo/
+Project-URL: Twitter, https://twitter.com/fabiocaccamo
Keywords: django,maintenance,mode,offline,under,503,service,temporarily,unavailable
-Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
-Classifier: Framework :: Django :: 1.7
-Classifier: Framework :: Django :: 1.8
-Classifier: Framework :: Django :: 1.9
-Classifier: Framework :: Django :: 1.10
-Classifier: Framework :: Django :: 1.11
-Classifier: Framework :: Django :: 2.0
-Classifier: Framework :: Django :: 2.1
Classifier: Framework :: Django :: 2.2
Classifier: Framework :: Django :: 3.0
Classifier: Framework :: Django :: 3.1
Classifier: Framework :: Django :: 3.2
+Classifier: Framework :: Django :: 4.0
+Classifier: Framework :: Django :: 4.1
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Software Development :: Build Tools
-Requires: django(>=1.7)
+Requires: django (>= 2.2)
Description-Content-Type: text/markdown
+License-File: LICENSE.txt
+
+[![](https://img.shields.io/pypi/pyversions/django-maintenance-mode.svg?color=3776AB&logo=python&logoColor=white)](https://www.python.org/)
+[![](https://img.shields.io/pypi/djversions/django-maintenance-mode?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/)
+
+[![](https://img.shields.io/pypi/v/django-maintenance-mode.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-maintenance-mode/)
+[![](https://pepy.tech/badge/django-maintenance-mode/month)](https://pepy.tech/project/django-maintenance-mode)
+[![](https://img.shields.io/github/stars/fabiocaccamo/django-maintenance-mode?logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode/)
+[![](https://badges.pufler.dev/visits/fabiocaccamo/django-maintenance-mode?label=visitors&color=blue)](https://badges.pufler.dev)
+[![](https://img.shields.io/pypi/l/django-maintenance-mode.svg?color=blue)](https://github.com/fabiocaccamo/django-maintenance-mode/blob/master/LICENSE.txt)
+
+[![](https://results.pre-commit.ci/badge/github/fabiocaccamo/django-maintenance-mode/master.svg)](https://results.pre-commit.ci/latest/github/fabiocaccamo/django-maintenance-mode/master)
+[![](https://img.shields.io/github/workflow/status/fabiocaccamo/django-maintenance-mode/Test%20package?label=build&logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode)
+[![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-maintenance-mode?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-maintenance-mode)
+[![](https://img.shields.io/codacy/grade/918668ac85e74206a4d8d95923548d79?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-maintenance-mode)
+[![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/django-maintenance-mode?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/django-maintenance-mode/)
+[![](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
+
+# django-maintenance-mode
+django-maintenance-mode shows a 503 error page when **maintenance-mode** is **on**.
+
+It works at application level, so your django instance should be up.
+
+It doesn't use database and doesn't prevent database access.
+
+## Installation
+
+1. Run `pip install django-maintenance-mode` or [download django-maintenance-mode](http://pypi.python.org/pypi/django-maintenance-mode) and add the **maintenance_mode** package to your project
+2. Add `maintenance_mode` to `settings.INSTALLED_APPS` before custom applications
+3. Add `maintenance_mode.middleware.MaintenanceModeMiddleware` to `settings.MIDDLEWARE` as last middleware
+4. Add your custom `templates/503.html` file
+5. Restart your application server
+
+## Configuration (optional)
+
+### Settings
+All these settings are optional, if not defined in `settings.py` the default values (listed below) will be used.
+
+```python
+# if True the maintenance-mode will be activated
+MAINTENANCE_MODE = None
+```
+
+```python
+# by default, to get/set the state value a local file backend is used
+# if you want to use the db or cache, you can create a custom backend
+# custom backends must extend 'maintenance_mode.backends.AbstractStateBackend' class
+# and implement get_value(self) and set_value(self, val) methods
+MAINTENANCE_MODE_STATE_BACKEND = "maintenance_mode.backends.LocalFileBackend"
+
+# alternatively it is possible to use the default storage backend
+MAINTENANCE_MODE_STATE_BACKEND = "maintenance_mode.backends.DefaultStorageBackend"
+
+# alternatively it is possible to use the static storage backend
+# make sure that STATIC_ROOT and STATIC_URL are also set
+MAINTENANCE_MODE_STATE_BACKEND = "maintenance_mode.backends.StaticStorageBackend"
+```
+
+```python
+# by default, a file named "maintenance_mode_state.txt" will be created in the settings.py directory
+# you can customize the state file path in case the default one is not writable
+MAINTENANCE_MODE_STATE_FILE_PATH = "maintenance_mode_state.txt"
+```
+
+```python
+# if True admin site will not be affected by the maintenance-mode page
+MAINTENANCE_MODE_IGNORE_ADMIN_SITE = False
+```
+
+```python
+# if True anonymous users will not see the maintenance-mode page
+MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER = False
+```
+
+```python
+# if True authenticated users will not see the maintenance-mode page
+MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER = False
+```
+
+```python
+# if True the staff will not see the maintenance-mode page
+MAINTENANCE_MODE_IGNORE_STAFF = False
+```
+
+```python
+# if True the superuser will not see the maintenance-mode page
+MAINTENANCE_MODE_IGNORE_SUPERUSER = False
+```
+
+```python
+# list of ip-addresses that will not be affected by the maintenance-mode
+# ip-addresses will be used to compile regular expressions objects
+MAINTENANCE_MODE_IGNORE_IP_ADDRESSES = ()
+```
+
+```python
+# the path of the function that will return the client IP address given the request object -> 'myapp.mymodule.myfunction'
+# the default function ('maintenance_mode.utils.get_client_ip_address') returns request.META['REMOTE_ADDR']
+# in some cases the default function returns None, to avoid this scenario just use 'django-ipware'
+MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = None
+```
+Retrieve user's real IP address using [`django-ipware`](https://github.com/un33k/django-ipware):
+```python
+MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = "ipware.ip.get_ip"
+```
+
+```python
+# list of urls that will not be affected by the maintenance-mode
+# urls will be used to compile regular expressions objects
+MAINTENANCE_MODE_IGNORE_URLS = ()
+```
+
+```python
+# if True the maintenance mode will not return 503 response while running tests
+# useful for running tests while maintenance mode is on, before opening the site to public use
+MAINTENANCE_MODE_IGNORE_TESTS = False
+```
+
+```python
+# the absolute url where users will be redirected to during maintenance-mode
+MAINTENANCE_MODE_REDIRECT_URL = None
+```
+
+```python
+# the template that will be shown by the maintenance-mode page
+MAINTENANCE_MODE_TEMPLATE = "503.html"
+```
+
+```python
+# the path of the function that will return the template context -> 'myapp.mymodule.myfunction'
+MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT = None
+```
+
+```python
+# the HTTP status code to send
+MAINTENANCE_MODE_STATUS_CODE = 503
+```
+
+```python
+# the value in seconds of the Retry-After header during maintenance-mode
+MAINTENANCE_MODE_RETRY_AFTER = 3600 # 1 hour
+```
+
+#### Context Processors
+Add **maintenance_mode.context_processors.maintenance_mode** to your context_processors list in `settings.py` if you want to access the maintenance_mode status in your templates.
+
+```python
+TEMPLATES = [
+ {
+ # ...
+ "OPTIONS": {
+ "context_processors": [
+ # ...
+ "maintenance_mode.context_processors.maintenance_mode",
+ # ...
+ ],
+ },
+ # ...
+ },
+]
+```
+
+#### Logging
+You can disable emailing 503 errors to admins while maintenance mode is enabled:
+
+```python
+LOGGING = {
+ "filters": {
+ "require_not_maintenance_mode_503": {
+ "()": "maintenance_mode.logging.RequireNotMaintenanceMode503",
+ },
+ ...
+ },
+ "handlers": {
+ ...
+ },
+ ...
+}
+```
+
+### Context Managers
+You can force a block of code execution to run under maintenance mode or not using context managers:
+
+```python
+from maintenance_mode.core import maintenance_mode_off, maintenance_mode_on
+
+with maintenance_mode_on():
+ # do stuff
+ pass
+
+with maintenance_mode_off():
+ # do stuff
+ pass
+```
+
+### URLs
+Add **maintenance_mode.urls** to `urls.py` if you want superusers able to set maintenance_mode using urls.
+
+```python
+urlpatterns = [
+ # ...
+ re_path(r"^maintenance-mode/", include("maintenance_mode.urls")),
+ # ...
+]
+```
+
+### Views
+You can force maintenance mode on/off at view level using view decorators:
+
+```python
+from maintenance_mode.decorators import force_maintenance_mode_off, force_maintenance_mode_on
+
+@force_maintenance_mode_off
+def my_view_a(request):
+ # never return 503 response
+ pass
+
+@force_maintenance_mode_on
+def my_view_b(request):
+ # always return 503 response
+ pass
+```
+
+## Usage
+
+### Python
+```python
+from maintenance_mode.core import get_maintenance_mode, set_maintenance_mode
+
+set_maintenance_mode(True)
+
+if get_maintenance_mode():
+ set_maintenance_mode(False)
+```
+or
+```python
+from django.core.management import call_command
+from django.core.management.base import BaseCommand
+
+
+class Command(BaseCommand):
+
+ def handle(self, *args, **options):
+
+ call_command("maintenance_mode", "on")
+
+ # call your command(s)
+
+ call_command("maintenance_mode", "off")
+
+```
+
+### Templates
+```html
+{% if maintenance_mode %}
+<!-- html -->
+{% endif %}
+```
+
+### Terminal
+
+Run ``python manage.py maintenance_mode <on|off>``
+
+*(**This is not Heroku-friendly because** any execution of heroku run* `manage.py` *will be run on a separate worker dyno, not the web one. Therefore **the state-file is set but on the wrong machine. You should use a custom*** `MAINTENANCE_MODE_STATE_BACKEND`*.)*
+
+### URLs
+Superusers can change maintenance-mode using the following urls:
+
+`/maintenance-mode/off/`
+
+`/maintenance-mode/on/`
+
+## Testing
+```bash
+# clone repository
+git clone https://github.com/fabiocaccamo/django-maintenance-mode.git && cd django-maintenance-mode
+
+# create virtualenv and activate it
+python -m venv venv && . venv/bin/activate
+
+# upgrade pip
+python -m pip install --upgrade pip
+
+# install requirements
+pip install -r requirements.txt -r requirements-test.txt
+
+# run tests
+tox
+# or
+python runtests.py
+# or
+python -m django test --settings "tests.settings"
+```
+
+## License
+Released under [MIT License](LICENSE.txt).
+
+---
+
+## Supporting
+
+- :star: Star this project on [GitHub](https://github.com/fabiocaccamo/django-maintenance-mode)
+- :octocat: Follow me on [GitHub](https://github.com/fabiocaccamo)
+- :blue_heart: Follow me on [Twitter](https://twitter.com/fabiocaccamo)
+- :moneybag: Sponsor me on [Github](https://github.com/sponsors/fabiocaccamo)
+
+## See also
+
+- [`django-admin-interface`](https://github.com/fabiocaccamo/django-admin-interface) - the default admin interface made customizable by the admin itself. popup windows replaced by modals. ๐ง โก
+
+- [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. ๐จ
+
+- [`django-extra-settings`](https://github.com/fabiocaccamo/django-extra-settings) - config and manage typed extra settings using just the django admin. โ๏ธ
+
+- [`django-redirects`](https://github.com/fabiocaccamo/django-redirects) - redirects with full control. โช๏ธ
+
+- [`django-treenode`](https://github.com/fabiocaccamo/django-treenode) - probably the best abstract model / admin for your tree based stuff. ๐ณ
+
+- [`python-benedict`](https://github.com/fabiocaccamo/python-benedict) - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. ๐
+
+- [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. ๐ฎ๐น ๐ณ
+
+- [`python-fontbro`](https://github.com/fabiocaccamo/python-fontbro) - friendly font operations. ๐งข
+
+- [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. ๐งโโ๏ธ
diff --git a/README.md b/README.md
index be8c9a2..41d91e0 100644
--- a/README.md
+++ b/README.md
@@ -2,16 +2,17 @@
[![](https://img.shields.io/pypi/djversions/django-maintenance-mode?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/)
[![](https://img.shields.io/pypi/v/django-maintenance-mode.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-maintenance-mode/)
-[![](https://pepy.tech/badge/django-maintenance-mode)](https://pepy.tech/project/django-maintenance-mode)
+[![](https://pepy.tech/badge/django-maintenance-mode/month)](https://pepy.tech/project/django-maintenance-mode)
[![](https://img.shields.io/github/stars/fabiocaccamo/django-maintenance-mode?logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode/)
[![](https://badges.pufler.dev/visits/fabiocaccamo/django-maintenance-mode?label=visitors&color=blue)](https://badges.pufler.dev)
[![](https://img.shields.io/pypi/l/django-maintenance-mode.svg?color=blue)](https://github.com/fabiocaccamo/django-maintenance-mode/blob/master/LICENSE.txt)
-[![](https://img.shields.io/travis/fabiocaccamo/django-maintenance-mode?logo=travis&label=build)](https://travis-ci.org/fabiocaccamo/django-maintenance-mode)
+[![](https://results.pre-commit.ci/badge/github/fabiocaccamo/django-maintenance-mode/master.svg)](https://results.pre-commit.ci/latest/github/fabiocaccamo/django-maintenance-mode/master)
+[![](https://img.shields.io/github/workflow/status/fabiocaccamo/django-maintenance-mode/Test%20package?label=build&logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode)
[![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-maintenance-mode?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-maintenance-mode)
[![](https://img.shields.io/codacy/grade/918668ac85e74206a4d8d95923548d79?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-maintenance-mode)
[![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/django-maintenance-mode?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/django-maintenance-mode/)
-[![](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements.svg?branch=master)](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements/?branch=master)
+[![](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
# django-maintenance-mode
django-maintenance-mode shows a 503 error page when **maintenance-mode** is **on**.
@@ -22,16 +23,16 @@ It doesn't use database and doesn't prevent database access.
## Installation
-1. Run ``pip install django-maintenance-mode`` or [download django-maintenance-mode](http://pypi.python.org/pypi/django-maintenance-mode) and add the **maintenance_mode** package to your project
-2. Add ``'maintenance_mode'`` to ``settings.INSTALLED_APPS`` before custom applications
-3. Add ``'maintenance_mode.middleware.MaintenanceModeMiddleware'`` to ``settings.MIDDLEWARE_CLASSES``/``settings.MIDDLEWARE`` as last middleware
-4. Add your custom ``templates/503.html`` file
+1. Run `pip install django-maintenance-mode` or [download django-maintenance-mode](http://pypi.python.org/pypi/django-maintenance-mode) and add the **maintenance_mode** package to your project
+2. Add `maintenance_mode` to `settings.INSTALLED_APPS` before custom applications
+3. Add `maintenance_mode.middleware.MaintenanceModeMiddleware` to `settings.MIDDLEWARE` as last middleware
+4. Add your custom `templates/503.html` file
5. Restart your application server
## Configuration (optional)
### Settings
-All these settings are optional, if not defined in ``settings.py`` the default values (listed below) will be used.
+All these settings are optional, if not defined in `settings.py` the default values (listed below) will be used.
```python
# if True the maintenance-mode will be activated
@@ -43,16 +44,20 @@ MAINTENANCE_MODE = None
# if you want to use the db or cache, you can create a custom backend
# custom backends must extend 'maintenance_mode.backends.AbstractStateBackend' class
# and implement get_value(self) and set_value(self, val) methods
-MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.LocalFileBackend'
+MAINTENANCE_MODE_STATE_BACKEND = "maintenance_mode.backends.LocalFileBackend"
# alternatively it is possible to use the default storage backend
-MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.DefaultStorageBackend'
+MAINTENANCE_MODE_STATE_BACKEND = "maintenance_mode.backends.DefaultStorageBackend"
+
+# alternatively it is possible to use the static storage backend
+# make sure that STATIC_ROOT and STATIC_URL are also set
+MAINTENANCE_MODE_STATE_BACKEND = "maintenance_mode.backends.StaticStorageBackend"
```
```python
# by default, a file named "maintenance_mode_state.txt" will be created in the settings.py directory
# you can customize the state file path in case the default one is not writable
-MAINTENANCE_MODE_STATE_FILE_PATH = 'maintenance_mode_state.txt'
+MAINTENANCE_MODE_STATE_FILE_PATH = "maintenance_mode_state.txt"
```
```python
@@ -94,7 +99,7 @@ MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = None
```
Retrieve user's real IP address using [`django-ipware`](https://github.com/un33k/django-ipware):
```python
-MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = 'ipware.ip.get_ip'
+MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = "ipware.ip.get_ip"
```
```python
@@ -116,7 +121,7 @@ MAINTENANCE_MODE_REDIRECT_URL = None
```python
# the template that will be shown by the maintenance-mode page
-MAINTENANCE_MODE_TEMPLATE = '503.html'
+MAINTENANCE_MODE_TEMPLATE = "503.html"
```
```python
@@ -135,16 +140,16 @@ MAINTENANCE_MODE_RETRY_AFTER = 3600 # 1 hour
```
#### Context Processors
-Add **maintenance_mode.context_processors.maintenance_mode** to your context_processors list in ``settings.py`` if you want to access the maintenance_mode status in your templates.
+Add **maintenance_mode.context_processors.maintenance_mode** to your context_processors list in `settings.py` if you want to access the maintenance_mode status in your templates.
```python
TEMPLATES = [
{
# ...
- 'OPTIONS': {
- 'context_processors': [
+ "OPTIONS": {
+ "context_processors": [
# ...
- 'maintenance_mode.context_processors.maintenance_mode',
+ "maintenance_mode.context_processors.maintenance_mode",
# ...
],
},
@@ -158,13 +163,13 @@ You can disable emailing 503 errors to admins while maintenance mode is enabled:
```python
LOGGING = {
- 'filters': {
- 'require_not_maintenance_mode_503': {
- '()': 'maintenance_mode.logging.RequireNotMaintenanceMode503',
+ "filters": {
+ "require_not_maintenance_mode_503": {
+ "()": "maintenance_mode.logging.RequireNotMaintenanceMode503",
},
...
},
- 'handlers': {
+ "handlers": {
...
},
...
@@ -187,12 +192,12 @@ with maintenance_mode_off():
```
### URLs
-Add **maintenance_mode.urls** to ``urls.py`` if you want superusers able to set maintenance_mode using urls.
+Add **maintenance_mode.urls** to `urls.py` if you want superusers able to set maintenance_mode using urls.
```python
urlpatterns = [
# ...
- url(r'^maintenance-mode/', include('maintenance_mode.urls')),
+ re_path(r"^maintenance-mode/", include("maintenance_mode.urls")),
# ...
]
```
@@ -235,13 +240,11 @@ class Command(BaseCommand):
def handle(self, *args, **options):
- call_command('maintenance_mode', 'on')
+ call_command("maintenance_mode", "on")
# call your command(s)
- call_command('maintenance_mode', 'off')
-
-
+ call_command("maintenance_mode", "off")
```
@@ -261,25 +264,28 @@ Run ``python manage.py maintenance_mode <on|off>``
### URLs
Superusers can change maintenance-mode using the following urls:
-``/maintenance-mode/off/``
+`/maintenance-mode/off/`
-``/maintenance-mode/on/``
+`/maintenance-mode/on/`
## Testing
```bash
-# create python virtual environment
-virtualenv testing_django_maintenance_mode
+# clone repository
+git clone https://github.com/fabiocaccamo/django-maintenance-mode.git && cd django-maintenance-mode
+
+# create virtualenv and activate it
+python -m venv venv && . venv/bin/activate
-# activate virtualenv
-cd testing_django_maintenance_mode && . bin/activate
+# upgrade pip
+python -m pip install --upgrade pip
-# clone repo
-git clone https://github.com/fabiocaccamo/django-maintenance-mode.git src && cd src
+# install requirements
+pip install -r requirements.txt -r requirements-test.txt
# run tests
tox
# or
-python setup.py test
+python runtests.py
# or
python -m django test --settings "tests.settings"
```
@@ -289,6 +295,13 @@ Released under [MIT License](LICENSE.txt).
---
+## Supporting
+
+- :star: Star this project on [GitHub](https://github.com/fabiocaccamo/django-maintenance-mode)
+- :octocat: Follow me on [GitHub](https://github.com/fabiocaccamo)
+- :blue_heart: Follow me on [Twitter](https://twitter.com/fabiocaccamo)
+- :moneybag: Sponsor me on [Github](https://github.com/sponsors/fabiocaccamo)
+
## See also
- [`django-admin-interface`](https://github.com/fabiocaccamo/django-admin-interface) - the default admin interface made customizable by the admin itself. popup windows replaced by modals. ๐ง โก
@@ -305,4 +318,6 @@ Released under [MIT License](LICENSE.txt).
- [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. ๐ฎ๐น ๐ณ
+- [`python-fontbro`](https://github.com/fabiocaccamo/python-fontbro) - friendly font operations. ๐งข
+
- [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. ๐งโโ๏ธ
diff --git a/debian/changelog b/debian/changelog
index 74e0910..123131e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+django-maintenance-mode (0.18.0-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Sat, 31 Dec 2022 01:06:48 -0000
+
django-maintenance-mode (0.16.1-2) unstable; urgency=medium
[ Debian Janitor ]
diff --git a/django_maintenance_mode.egg-info/PKG-INFO b/django_maintenance_mode.egg-info/PKG-INFO
index 17a5033..a785de3 100644
--- a/django_maintenance_mode.egg-info/PKG-INFO
+++ b/django_maintenance_mode.egg-info/PKG-INFO
@@ -1,350 +1,360 @@
Metadata-Version: 2.1
Name: django-maintenance-mode
-Version: 0.16.1
+Version: 0.18.0
Summary: django-maintenance-mode shows a 503 error page when maintenance-mode is on.
Home-page: https://github.com/fabiocaccamo/django-maintenance-mode
+Download-URL: https://github.com/fabiocaccamo/django-maintenance-mode/archive/0.18.0.tar.gz
Author: Fabio Caccamo
Author-email: fabio.caccamo@gmail.com
License: MIT
-Download-URL: https://github.com/fabiocaccamo/django-maintenance-mode/archive/0.16.1.tar.gz
-Description: [![](https://img.shields.io/pypi/pyversions/django-maintenance-mode.svg?color=3776AB&logo=python&logoColor=white)](https://www.python.org/)
- [![](https://img.shields.io/pypi/djversions/django-maintenance-mode?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/)
-
- [![](https://img.shields.io/pypi/v/django-maintenance-mode.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-maintenance-mode/)
- [![](https://pepy.tech/badge/django-maintenance-mode)](https://pepy.tech/project/django-maintenance-mode)
- [![](https://img.shields.io/github/stars/fabiocaccamo/django-maintenance-mode?logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode/)
- [![](https://badges.pufler.dev/visits/fabiocaccamo/django-maintenance-mode?label=visitors&color=blue)](https://badges.pufler.dev)
- [![](https://img.shields.io/pypi/l/django-maintenance-mode.svg?color=blue)](https://github.com/fabiocaccamo/django-maintenance-mode/blob/master/LICENSE.txt)
-
- [![](https://img.shields.io/travis/fabiocaccamo/django-maintenance-mode?logo=travis&label=build)](https://travis-ci.org/fabiocaccamo/django-maintenance-mode)
- [![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-maintenance-mode?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-maintenance-mode)
- [![](https://img.shields.io/codacy/grade/918668ac85e74206a4d8d95923548d79?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-maintenance-mode)
- [![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/django-maintenance-mode?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/django-maintenance-mode/)
- [![](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements.svg?branch=master)](https://requires.io/github/fabiocaccamo/django-maintenance-mode/requirements/?branch=master)
-
- # django-maintenance-mode
- django-maintenance-mode shows a 503 error page when **maintenance-mode** is **on**.
-
- It works at application level, so your django instance should be up.
-
- It doesn't use database and doesn't prevent database access.
-
- ## Installation
-
- 1. Run ``pip install django-maintenance-mode`` or [download django-maintenance-mode](http://pypi.python.org/pypi/django-maintenance-mode) and add the **maintenance_mode** package to your project
- 2. Add ``'maintenance_mode'`` to ``settings.INSTALLED_APPS`` before custom applications
- 3. Add ``'maintenance_mode.middleware.MaintenanceModeMiddleware'`` to ``settings.MIDDLEWARE_CLASSES``/``settings.MIDDLEWARE`` as last middleware
- 4. Add your custom ``templates/503.html`` file
- 5. Restart your application server
-
- ## Configuration (optional)
-
- ### Settings
- All these settings are optional, if not defined in ``settings.py`` the default values (listed below) will be used.
-
- ```python
- # if True the maintenance-mode will be activated
- MAINTENANCE_MODE = None
- ```
-
- ```python
- # by default, to get/set the state value a local file backend is used
- # if you want to use the db or cache, you can create a custom backend
- # custom backends must extend 'maintenance_mode.backends.AbstractStateBackend' class
- # and implement get_value(self) and set_value(self, val) methods
- MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.LocalFileBackend'
-
- # alternatively it is possible to use the default storage backend
- MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.DefaultStorageBackend'
- ```
-
- ```python
- # by default, a file named "maintenance_mode_state.txt" will be created in the settings.py directory
- # you can customize the state file path in case the default one is not writable
- MAINTENANCE_MODE_STATE_FILE_PATH = 'maintenance_mode_state.txt'
- ```
-
- ```python
- # if True admin site will not be affected by the maintenance-mode page
- MAINTENANCE_MODE_IGNORE_ADMIN_SITE = False
- ```
-
- ```python
- # if True anonymous users will not see the maintenance-mode page
- MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER = False
- ```
-
- ```python
- # if True authenticated users will not see the maintenance-mode page
- MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER = False
- ```
-
- ```python
- # if True the staff will not see the maintenance-mode page
- MAINTENANCE_MODE_IGNORE_STAFF = False
- ```
-
- ```python
- # if True the superuser will not see the maintenance-mode page
- MAINTENANCE_MODE_IGNORE_SUPERUSER = False
- ```
-
- ```python
- # list of ip-addresses that will not be affected by the maintenance-mode
- # ip-addresses will be used to compile regular expressions objects
- MAINTENANCE_MODE_IGNORE_IP_ADDRESSES = ()
- ```
-
- ```python
- # the path of the function that will return the client IP address given the request object -> 'myapp.mymodule.myfunction'
- # the default function ('maintenance_mode.utils.get_client_ip_address') returns request.META['REMOTE_ADDR']
- # in some cases the default function returns None, to avoid this scenario just use 'django-ipware'
- MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = None
- ```
- Retrieve user's real IP address using [`django-ipware`](https://github.com/un33k/django-ipware):
- ```python
- MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = 'ipware.ip.get_ip'
- ```
-
- ```python
- # list of urls that will not be affected by the maintenance-mode
- # urls will be used to compile regular expressions objects
- MAINTENANCE_MODE_IGNORE_URLS = ()
- ```
-
- ```python
- # if True the maintenance mode will not return 503 response while running tests
- # useful for running tests while maintenance mode is on, before opening the site to public use
- MAINTENANCE_MODE_IGNORE_TESTS = False
- ```
-
- ```python
- # the absolute url where users will be redirected to during maintenance-mode
- MAINTENANCE_MODE_REDIRECT_URL = None
- ```
-
- ```python
- # the template that will be shown by the maintenance-mode page
- MAINTENANCE_MODE_TEMPLATE = '503.html'
- ```
-
- ```python
- # the path of the function that will return the template context -> 'myapp.mymodule.myfunction'
- MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT = None
- ```
-
- ```python
- # the HTTP status code to send
- MAINTENANCE_MODE_STATUS_CODE = 503
- ```
-
- ```python
- # the value in seconds of the Retry-After header during maintenance-mode
- MAINTENANCE_MODE_RETRY_AFTER = 3600 # 1 hour
- ```
-
- #### Context Processors
- Add **maintenance_mode.context_processors.maintenance_mode** to your context_processors list in ``settings.py`` if you want to access the maintenance_mode status in your templates.
-
- ```python
- TEMPLATES = [
- {
- # ...
- 'OPTIONS': {
- 'context_processors': [
- # ...
- 'maintenance_mode.context_processors.maintenance_mode',
- # ...
- ],
- },
- # ...
- },
- ]
- ```
-
- #### Logging
- You can disable emailing 503 errors to admins while maintenance mode is enabled:
-
- ```python
- LOGGING = {
- 'filters': {
- 'require_not_maintenance_mode_503': {
- '()': 'maintenance_mode.logging.RequireNotMaintenanceMode503',
- },
- ...
- },
- 'handlers': {
- ...
- },
- ...
- }
- ```
-
- ### Context Managers
- You can force a block of code execution to run under maintenance mode or not using context managers:
-
- ```python
- from maintenance_mode.core import maintenance_mode_off, maintenance_mode_on
-
- with maintenance_mode_on():
- # do stuff
- pass
-
- with maintenance_mode_off():
- # do stuff
- pass
- ```
-
- ### URLs
- Add **maintenance_mode.urls** to ``urls.py`` if you want superusers able to set maintenance_mode using urls.
-
- ```python
- urlpatterns = [
- # ...
- url(r'^maintenance-mode/', include('maintenance_mode.urls')),
- # ...
- ]
- ```
-
- ### Views
- You can force maintenance mode on/off at view level using view decorators:
-
- ```python
- from maintenance_mode.decorators import force_maintenance_mode_off, force_maintenance_mode_on
-
- @force_maintenance_mode_off
- def my_view_a(request):
- # never return 503 response
- pass
-
- @force_maintenance_mode_on
- def my_view_b(request):
- # always return 503 response
- pass
- ```
-
- ## Usage
-
- ### Python
- ```python
- from maintenance_mode.core import get_maintenance_mode, set_maintenance_mode
-
- set_maintenance_mode(True)
-
- if get_maintenance_mode():
- set_maintenance_mode(False)
- ```
- or
- ```python
- from django.core.management import call_command
- from django.core.management.base import BaseCommand
-
-
- class Command(BaseCommand):
-
- def handle(self, *args, **options):
-
- call_command('maintenance_mode', 'on')
-
- # call your command(s)
-
- call_command('maintenance_mode', 'off')
-
-
-
- ```
-
- ### Templates
- ```html
- {% if maintenance_mode %}
- <!-- html -->
- {% endif %}
- ```
-
- ### Terminal
-
- Run ``python manage.py maintenance_mode <on|off>``
-
- *(**This is not Heroku-friendly because** any execution of heroku run* `manage.py` *will be run on a separate worker dyno, not the web one. Therefore **the state-file is set but on the wrong machine. You should use a custom*** `MAINTENANCE_MODE_STATE_BACKEND`*.)*
-
- ### URLs
- Superusers can change maintenance-mode using the following urls:
-
- ``/maintenance-mode/off/``
-
- ``/maintenance-mode/on/``
-
- ## Testing
- ```bash
- # create python virtual environment
- virtualenv testing_django_maintenance_mode
-
- # activate virtualenv
- cd testing_django_maintenance_mode && . bin/activate
-
- # clone repo
- git clone https://github.com/fabiocaccamo/django-maintenance-mode.git src && cd src
-
- # run tests
- tox
- # or
- python setup.py test
- # or
- python -m django test --settings "tests.settings"
- ```
-
- ## License
- Released under [MIT License](LICENSE.txt).
-
- ---
-
- ## See also
-
- - [`django-admin-interface`](https://github.com/fabiocaccamo/django-admin-interface) - the default admin interface made customizable by the admin itself. popup windows replaced by modals. ๐ง โก
-
- - [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. ๐จ
-
- - [`django-extra-settings`](https://github.com/fabiocaccamo/django-extra-settings) - config and manage typed extra settings using just the django admin. โ๏ธ
-
- - [`django-redirects`](https://github.com/fabiocaccamo/django-redirects) - redirects with full control. โช๏ธ
-
- - [`django-treenode`](https://github.com/fabiocaccamo/django-treenode) - probably the best abstract model / admin for your tree based stuff. ๐ณ
-
- - [`python-benedict`](https://github.com/fabiocaccamo/python-benedict) - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. ๐
-
- - [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. ๐ฎ๐น ๐ณ
-
- - [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. ๐งโโ๏ธ
-
+Project-URL: Documentation, https://github.com/fabiocaccamo/django-maintenance-mode#readme
+Project-URL: Issues, https://github.com/fabiocaccamo/django-maintenance-mode/issues
+Project-URL: Funding, https://github.com/sponsors/fabiocaccamo/
+Project-URL: Twitter, https://twitter.com/fabiocaccamo
Keywords: django,maintenance,mode,offline,under,503,service,temporarily,unavailable
-Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
-Classifier: Framework :: Django :: 1.7
-Classifier: Framework :: Django :: 1.8
-Classifier: Framework :: Django :: 1.9
-Classifier: Framework :: Django :: 1.10
-Classifier: Framework :: Django :: 1.11
-Classifier: Framework :: Django :: 2.0
-Classifier: Framework :: Django :: 2.1
Classifier: Framework :: Django :: 2.2
Classifier: Framework :: Django :: 3.0
Classifier: Framework :: Django :: 3.1
Classifier: Framework :: Django :: 3.2
+Classifier: Framework :: Django :: 4.0
+Classifier: Framework :: Django :: 4.1
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Software Development :: Build Tools
-Requires: django(>=1.7)
+Requires: django (>= 2.2)
Description-Content-Type: text/markdown
+License-File: LICENSE.txt
+
+[![](https://img.shields.io/pypi/pyversions/django-maintenance-mode.svg?color=3776AB&logo=python&logoColor=white)](https://www.python.org/)
+[![](https://img.shields.io/pypi/djversions/django-maintenance-mode?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/)
+
+[![](https://img.shields.io/pypi/v/django-maintenance-mode.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-maintenance-mode/)
+[![](https://pepy.tech/badge/django-maintenance-mode/month)](https://pepy.tech/project/django-maintenance-mode)
+[![](https://img.shields.io/github/stars/fabiocaccamo/django-maintenance-mode?logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode/)
+[![](https://badges.pufler.dev/visits/fabiocaccamo/django-maintenance-mode?label=visitors&color=blue)](https://badges.pufler.dev)
+[![](https://img.shields.io/pypi/l/django-maintenance-mode.svg?color=blue)](https://github.com/fabiocaccamo/django-maintenance-mode/blob/master/LICENSE.txt)
+
+[![](https://results.pre-commit.ci/badge/github/fabiocaccamo/django-maintenance-mode/master.svg)](https://results.pre-commit.ci/latest/github/fabiocaccamo/django-maintenance-mode/master)
+[![](https://img.shields.io/github/workflow/status/fabiocaccamo/django-maintenance-mode/Test%20package?label=build&logo=github)](https://github.com/fabiocaccamo/django-maintenance-mode)
+[![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-maintenance-mode?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-maintenance-mode)
+[![](https://img.shields.io/codacy/grade/918668ac85e74206a4d8d95923548d79?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/django-maintenance-mode)
+[![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/django-maintenance-mode?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/django-maintenance-mode/)
+[![](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
+
+# django-maintenance-mode
+django-maintenance-mode shows a 503 error page when **maintenance-mode** is **on**.
+
+It works at application level, so your django instance should be up.
+
+It doesn't use database and doesn't prevent database access.
+
+## Installation
+
+1. Run `pip install django-maintenance-mode` or [download django-maintenance-mode](http://pypi.python.org/pypi/django-maintenance-mode) and add the **maintenance_mode** package to your project
+2. Add `maintenance_mode` to `settings.INSTALLED_APPS` before custom applications
+3. Add `maintenance_mode.middleware.MaintenanceModeMiddleware` to `settings.MIDDLEWARE` as last middleware
+4. Add your custom `templates/503.html` file
+5. Restart your application server
+
+## Configuration (optional)
+
+### Settings
+All these settings are optional, if not defined in `settings.py` the default values (listed below) will be used.
+
+```python
+# if True the maintenance-mode will be activated
+MAINTENANCE_MODE = None
+```
+
+```python
+# by default, to get/set the state value a local file backend is used
+# if you want to use the db or cache, you can create a custom backend
+# custom backends must extend 'maintenance_mode.backends.AbstractStateBackend' class
+# and implement get_value(self) and set_value(self, val) methods
+MAINTENANCE_MODE_STATE_BACKEND = "maintenance_mode.backends.LocalFileBackend"
+
+# alternatively it is possible to use the default storage backend
+MAINTENANCE_MODE_STATE_BACKEND = "maintenance_mode.backends.DefaultStorageBackend"
+
+# alternatively it is possible to use the static storage backend
+# make sure that STATIC_ROOT and STATIC_URL are also set
+MAINTENANCE_MODE_STATE_BACKEND = "maintenance_mode.backends.StaticStorageBackend"
+```
+
+```python
+# by default, a file named "maintenance_mode_state.txt" will be created in the settings.py directory
+# you can customize the state file path in case the default one is not writable
+MAINTENANCE_MODE_STATE_FILE_PATH = "maintenance_mode_state.txt"
+```
+
+```python
+# if True admin site will not be affected by the maintenance-mode page
+MAINTENANCE_MODE_IGNORE_ADMIN_SITE = False
+```
+
+```python
+# if True anonymous users will not see the maintenance-mode page
+MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER = False
+```
+
+```python
+# if True authenticated users will not see the maintenance-mode page
+MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER = False
+```
+
+```python
+# if True the staff will not see the maintenance-mode page
+MAINTENANCE_MODE_IGNORE_STAFF = False
+```
+
+```python
+# if True the superuser will not see the maintenance-mode page
+MAINTENANCE_MODE_IGNORE_SUPERUSER = False
+```
+
+```python
+# list of ip-addresses that will not be affected by the maintenance-mode
+# ip-addresses will be used to compile regular expressions objects
+MAINTENANCE_MODE_IGNORE_IP_ADDRESSES = ()
+```
+
+```python
+# the path of the function that will return the client IP address given the request object -> 'myapp.mymodule.myfunction'
+# the default function ('maintenance_mode.utils.get_client_ip_address') returns request.META['REMOTE_ADDR']
+# in some cases the default function returns None, to avoid this scenario just use 'django-ipware'
+MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = None
+```
+Retrieve user's real IP address using [`django-ipware`](https://github.com/un33k/django-ipware):
+```python
+MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = "ipware.ip.get_ip"
+```
+
+```python
+# list of urls that will not be affected by the maintenance-mode
+# urls will be used to compile regular expressions objects
+MAINTENANCE_MODE_IGNORE_URLS = ()
+```
+
+```python
+# if True the maintenance mode will not return 503 response while running tests
+# useful for running tests while maintenance mode is on, before opening the site to public use
+MAINTENANCE_MODE_IGNORE_TESTS = False
+```
+
+```python
+# the absolute url where users will be redirected to during maintenance-mode
+MAINTENANCE_MODE_REDIRECT_URL = None
+```
+
+```python
+# the template that will be shown by the maintenance-mode page
+MAINTENANCE_MODE_TEMPLATE = "503.html"
+```
+
+```python
+# the path of the function that will return the template context -> 'myapp.mymodule.myfunction'
+MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT = None
+```
+
+```python
+# the HTTP status code to send
+MAINTENANCE_MODE_STATUS_CODE = 503
+```
+
+```python
+# the value in seconds of the Retry-After header during maintenance-mode
+MAINTENANCE_MODE_RETRY_AFTER = 3600 # 1 hour
+```
+
+#### Context Processors
+Add **maintenance_mode.context_processors.maintenance_mode** to your context_processors list in `settings.py` if you want to access the maintenance_mode status in your templates.
+
+```python
+TEMPLATES = [
+ {
+ # ...
+ "OPTIONS": {
+ "context_processors": [
+ # ...
+ "maintenance_mode.context_processors.maintenance_mode",
+ # ...
+ ],
+ },
+ # ...
+ },
+]
+```
+
+#### Logging
+You can disable emailing 503 errors to admins while maintenance mode is enabled:
+
+```python
+LOGGING = {
+ "filters": {
+ "require_not_maintenance_mode_503": {
+ "()": "maintenance_mode.logging.RequireNotMaintenanceMode503",
+ },
+ ...
+ },
+ "handlers": {
+ ...
+ },
+ ...
+}
+```
+
+### Context Managers
+You can force a block of code execution to run under maintenance mode or not using context managers:
+
+```python
+from maintenance_mode.core import maintenance_mode_off, maintenance_mode_on
+
+with maintenance_mode_on():
+ # do stuff
+ pass
+
+with maintenance_mode_off():
+ # do stuff
+ pass
+```
+
+### URLs
+Add **maintenance_mode.urls** to `urls.py` if you want superusers able to set maintenance_mode using urls.
+
+```python
+urlpatterns = [
+ # ...
+ re_path(r"^maintenance-mode/", include("maintenance_mode.urls")),
+ # ...
+]
+```
+
+### Views
+You can force maintenance mode on/off at view level using view decorators:
+
+```python
+from maintenance_mode.decorators import force_maintenance_mode_off, force_maintenance_mode_on
+
+@force_maintenance_mode_off
+def my_view_a(request):
+ # never return 503 response
+ pass
+
+@force_maintenance_mode_on
+def my_view_b(request):
+ # always return 503 response
+ pass
+```
+
+## Usage
+
+### Python
+```python
+from maintenance_mode.core import get_maintenance_mode, set_maintenance_mode
+
+set_maintenance_mode(True)
+
+if get_maintenance_mode():
+ set_maintenance_mode(False)
+```
+or
+```python
+from django.core.management import call_command
+from django.core.management.base import BaseCommand
+
+
+class Command(BaseCommand):
+
+ def handle(self, *args, **options):
+
+ call_command("maintenance_mode", "on")
+
+ # call your command(s)
+
+ call_command("maintenance_mode", "off")
+
+```
+
+### Templates
+```html
+{% if maintenance_mode %}
+<!-- html -->
+{% endif %}
+```
+
+### Terminal
+
+Run ``python manage.py maintenance_mode <on|off>``
+
+*(**This is not Heroku-friendly because** any execution of heroku run* `manage.py` *will be run on a separate worker dyno, not the web one. Therefore **the state-file is set but on the wrong machine. You should use a custom*** `MAINTENANCE_MODE_STATE_BACKEND`*.)*
+
+### URLs
+Superusers can change maintenance-mode using the following urls:
+
+`/maintenance-mode/off/`
+
+`/maintenance-mode/on/`
+
+## Testing
+```bash
+# clone repository
+git clone https://github.com/fabiocaccamo/django-maintenance-mode.git && cd django-maintenance-mode
+
+# create virtualenv and activate it
+python -m venv venv && . venv/bin/activate
+
+# upgrade pip
+python -m pip install --upgrade pip
+
+# install requirements
+pip install -r requirements.txt -r requirements-test.txt
+
+# run tests
+tox
+# or
+python runtests.py
+# or
+python -m django test --settings "tests.settings"
+```
+
+## License
+Released under [MIT License](LICENSE.txt).
+
+---
+
+## Supporting
+
+- :star: Star this project on [GitHub](https://github.com/fabiocaccamo/django-maintenance-mode)
+- :octocat: Follow me on [GitHub](https://github.com/fabiocaccamo)
+- :blue_heart: Follow me on [Twitter](https://twitter.com/fabiocaccamo)
+- :moneybag: Sponsor me on [Github](https://github.com/sponsors/fabiocaccamo)
+
+## See also
+
+- [`django-admin-interface`](https://github.com/fabiocaccamo/django-admin-interface) - the default admin interface made customizable by the admin itself. popup windows replaced by modals. ๐ง โก
+
+- [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. ๐จ
+
+- [`django-extra-settings`](https://github.com/fabiocaccamo/django-extra-settings) - config and manage typed extra settings using just the django admin. โ๏ธ
+
+- [`django-redirects`](https://github.com/fabiocaccamo/django-redirects) - redirects with full control. โช๏ธ
+
+- [`django-treenode`](https://github.com/fabiocaccamo/django-treenode) - probably the best abstract model / admin for your tree based stuff. ๐ณ
+
+- [`python-benedict`](https://github.com/fabiocaccamo/python-benedict) - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. ๐
+
+- [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. ๐ฎ๐น ๐ณ
+
+- [`python-fontbro`](https://github.com/fabiocaccamo/python-fontbro) - friendly font operations. ๐งข
+
+- [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. ๐งโโ๏ธ
diff --git a/django_maintenance_mode.egg-info/SOURCES.txt b/django_maintenance_mode.egg-info/SOURCES.txt
index ee86e98..7a60425 100644
--- a/django_maintenance_mode.egg-info/SOURCES.txt
+++ b/django_maintenance_mode.egg-info/SOURCES.txt
@@ -1,11 +1,13 @@
LICENSE.txt
MANIFEST.in
README.md
+pyproject.toml
setup.cfg
setup.py
django_maintenance_mode.egg-info/PKG-INFO
django_maintenance_mode.egg-info/SOURCES.txt
django_maintenance_mode.egg-info/dependency_links.txt
+django_maintenance_mode.egg-info/requires.txt
django_maintenance_mode.egg-info/top_level.txt
maintenance_mode/__init__.py
maintenance_mode/backends.py
diff --git a/django_maintenance_mode.egg-info/requires.txt b/django_maintenance_mode.egg-info/requires.txt
new file mode 100644
index 0000000..07a7b35
--- /dev/null
+++ b/django_maintenance_mode.egg-info/requires.txt
@@ -0,0 +1 @@
+python-fsutil>=0.7.0
diff --git a/maintenance_mode/__init__.py b/maintenance_mode/__init__.py
index 735d11c..9105a42 100644
--- a/maintenance_mode/__init__.py
+++ b/maintenance_mode/__init__.py
@@ -1,3 +1 @@
-# -*- coding: utf-8 -*-
-
from maintenance_mode import settings
diff --git a/maintenance_mode/backends.py b/maintenance_mode/backends.py
index bd1e173..a67f6cf 100644
--- a/maintenance_mode/backends.py
+++ b/maintenance_mode/backends.py
@@ -1,6 +1,5 @@
-# -*- coding: utf-8 -*-
-
from django.conf import settings
+from django.contrib.staticfiles.storage import staticfiles_storage
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
@@ -8,19 +7,18 @@ from maintenance_mode.io import read_file, write_file
class AbstractStateBackend(object):
-
@staticmethod
def from_bool_to_str_value(value):
value = str(int(value))
- if value not in ['0', '1']:
- raise ValueError('state value is not 0|1')
+ if value not in ["0", "1"]:
+ raise ValueError("state value is not 0|1")
return value
@staticmethod
def from_str_to_bool_value(value):
value = value.strip()
- if value not in ['0', '1']:
- raise ValueError('state value is not 0|1')
+ if value not in ["0", "1"]:
+ raise ValueError("state value is not 0|1")
value = bool(int(value))
return value
@@ -36,31 +34,59 @@ class DefaultStorageBackend(AbstractStateBackend):
django-maintenance-mode backend which uses the default storage.
Kindly provided by Dominik George https://github.com/Natureshadow
"""
+
+ def _get_filename(self):
+ return settings.MAINTENANCE_MODE_STATE_FILE_NAME
+
def get_value(self):
- filename = settings.MAINTENANCE_MODE_STATE_FILE_NAME
+ filename = self._get_filename()
try:
- with default_storage.open(filename, 'r') as statefile:
+ with default_storage.open(filename, "r") as statefile:
return self.from_str_to_bool_value(statefile.read())
except IOError:
return False
def set_value(self, value):
- filename = settings.MAINTENANCE_MODE_STATE_FILE_NAME
+ filename = self._get_filename()
if default_storage.exists(filename):
default_storage.delete(filename)
- content = ContentFile(self.from_bool_to_str_value(value))
+ content = ContentFile(self.from_bool_to_str_value(value).encode())
default_storage.save(filename, content)
+class StaticStorageBackend(AbstractStateBackend):
+ """
+ django-maintenance-mode backend which uses the staticfiles storage.
+ """
+
+ def get_value(self):
+ filename = settings.MAINTENANCE_MODE_STATE_FILE_NAME
+ if staticfiles_storage.exists(filename):
+ with staticfiles_storage.open(filename, "r") as statefile:
+ return self.from_str_to_bool_value(statefile.read())
+ return False
+
+ def set_value(self, value):
+ filename = settings.MAINTENANCE_MODE_STATE_FILE_NAME
+ if staticfiles_storage.exists(filename):
+ staticfiles_storage.delete(filename)
+ content = ContentFile(self.from_bool_to_str_value(value).encode())
+ staticfiles_storage.save(filename, content)
+
+
class LocalFileBackend(AbstractStateBackend):
"""
django-maintenance-mode backend which uses the local file-sistem.
"""
+
+ def _get_filepath(self):
+ return f"{settings.MAINTENANCE_MODE_STATE_FILE_PATH}"
+
def get_value(self):
- value = read_file(settings.MAINTENANCE_MODE_STATE_FILE_PATH, '0')
+ value = read_file(self._get_filepath(), "0")
value = self.from_str_to_bool_value(value)
return value
def set_value(self, value):
value = self.from_bool_to_str_value(value)
- write_file(settings.MAINTENANCE_MODE_STATE_FILE_PATH, value)
+ write_file(self._get_filepath(), value)
diff --git a/maintenance_mode/context_processors.py b/maintenance_mode/context_processors.py
index feb99c2..87ac670 100644
--- a/maintenance_mode/context_processors.py
+++ b/maintenance_mode/context_processors.py
@@ -1,7 +1,5 @@
-# -*- coding: utf-8 -*-
-
from maintenance_mode.core import get_maintenance_mode
def maintenance_mode(request):
- return { 'maintenance_mode':get_maintenance_mode() }
+ return {"maintenance_mode": get_maintenance_mode()}
diff --git a/maintenance_mode/core.py b/maintenance_mode/core.py
index cafc122..756aa3a 100644
--- a/maintenance_mode/core.py
+++ b/maintenance_mode/core.py
@@ -1,47 +1,32 @@
-# -*- coding: utf-8 -*-
+from contextlib import ContextDecorator
+from functools import wraps
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
-
-try:
- from contextlib import ContextDecorator
-except ImportError:
- # ContextDecorator was introduced in Django 1.8
- from django.utils.decorators import available_attrs
-
- class ContextDecorator(object):
- """
- A base class that enables a context manager to also be used as a decorator.
- """
- def __call__(self, func):
- @wraps(func, assigned=available_attrs(func))
- def inner(*args, **kwargs):
- with self:
- return func(*args, **kwargs)
- return inner
-
from django.utils.module_loading import import_string
-from functools import wraps
-
from maintenance_mode.backends import AbstractStateBackend
def get_maintenance_mode_backend():
try:
backend_class = import_string(settings.MAINTENANCE_MODE_STATE_BACKEND)
- if issubclass(backend_class, AbstractStateBackend) and \
- backend_class != AbstractStateBackend:
+ if (
+ issubclass(backend_class, AbstractStateBackend)
+ and backend_class != AbstractStateBackend
+ ):
backend = backend_class()
return backend
else:
raise ImproperlyConfigured(
- 'backend doesn\'t extend '
- '\'maintenance_mode.backends.AbstractStateBackend\' class.')
+ "backend doesn't extend "
+ "'maintenance_mode.backends.AbstractStateBackend' class."
+ )
except ImportError:
raise ImproperlyConfigured(
- 'backend not found, check '
- '\'settings.MAINTENANCE_MODE_STATE_BACKEND\' path.')
+ "backend not found, check "
+ "'settings.MAINTENANCE_MODE_STATE_BACKEND' path."
+ )
def get_maintenance_mode():
@@ -65,11 +50,11 @@ def set_maintenance_mode(value):
# If maintenance mode is defined in settings, it can't be changed.
if settings.MAINTENANCE_MODE is not None:
raise ImproperlyConfigured(
- 'Maintenance mode cannot be set dynamically '
- 'if defined in settings.')
+ "Maintenance mode cannot be set dynamically " "if defined in settings."
+ )
if not isinstance(value, bool):
- raise TypeError('value argument type is not boolean')
+ raise TypeError("value argument type is not boolean")
backend = get_maintenance_mode_backend()
backend.set_value(value)
@@ -82,6 +67,7 @@ class override_maintenance_mode(ContextDecorator):
@ivar value: Overriden value of maintenance mode
@ivar old_value: Original value of maintenance mode
"""
+
def __init__(self, value):
self.value = value
self.old_value = None
@@ -98,6 +84,7 @@ class maintenance_mode_on(override_maintenance_mode):
"""
Decorator/context manager to locally set maintenance mode to True.
"""
+
def __init__(self):
super(maintenance_mode_on, self).__init__(True)
@@ -106,5 +93,6 @@ class maintenance_mode_off(override_maintenance_mode):
"""
Decorator/context manager to locally set maintenance mode to False.
"""
+
def __init__(self):
super(maintenance_mode_off, self).__init__(False)
diff --git a/maintenance_mode/decorators.py b/maintenance_mode/decorators.py
index 58d8816..a029bc9 100644
--- a/maintenance_mode/decorators.py
+++ b/maintenance_mode/decorators.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
from functools import wraps
from maintenance_mode.http import get_maintenance_response
@@ -9,7 +7,8 @@ def force_maintenance_mode_off(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
return view_func(request, *args, **kwargs)
- wrapper.__dict__['force_maintenance_mode_off'] = True
+
+ wrapper.__dict__["force_maintenance_mode_off"] = True
return wrapper
@@ -17,5 +16,6 @@ def force_maintenance_mode_on(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
return get_maintenance_response(request)
- wrapper.__dict__['force_maintenance_mode_on'] = True
+
+ wrapper.__dict__["force_maintenance_mode_on"] = True
return wrapper
diff --git a/maintenance_mode/http.py b/maintenance_mode/http.py
index c87d87f..dc10b16 100644
--- a/maintenance_mode/http.py
+++ b/maintenance_mode/http.py
@@ -1,35 +1,17 @@
-# -*- coding: utf-8 -*-
+import re
+import sys
-import django
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
-
-if django.VERSION < (2, 0):
- from django.core.urlresolvers import (
- NoReverseMatch, resolve, Resolver404, reverse, )
-else:
- from django.urls import (
- NoReverseMatch, resolve, Resolver404, reverse, )
-
-from django.shortcuts import render, redirect
+from django.shortcuts import redirect, render
from django.template import RequestContext
+from django.urls import NoReverseMatch, Resolver404, resolve, reverse
from django.utils.cache import add_never_cache_headers
from django.utils.module_loading import import_string
from maintenance_mode.core import get_maintenance_mode
from maintenance_mode.utils import get_client_ip_address
-import re
-
-try:
- # since python 3.7
- pattern_class = re.Pattern
-except AttributeError:
- # before python 3.7
- pattern_class = re._pattern_type
-
-import sys
-
def get_maintenance_response(request):
"""
@@ -43,45 +25,44 @@ def get_maintenance_response(request):
if settings.MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT:
try:
get_request_context_func = import_string(
- settings.MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT)
+ settings.MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT
+ )
except ImportError:
raise ImproperlyConfigured(
- 'settings.MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT '
- 'is not a valid function path.'
+ "settings.MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT "
+ "is not a valid function path."
)
context = get_request_context_func(request=request)
- kwargs = {'context': context}
- if django.VERSION < (1, 8):
- kwargs = {'context_instance': RequestContext(request, context)}
-
- response = render(request, settings.MAINTENANCE_MODE_TEMPLATE,
- status=settings.MAINTENANCE_MODE_STATUS_CODE,
- **kwargs)
- response['Retry-After'] = settings.MAINTENANCE_MODE_RETRY_AFTER
+ kwargs = {"context": context}
+ response = render(
+ request,
+ settings.MAINTENANCE_MODE_TEMPLATE,
+ status=settings.MAINTENANCE_MODE_STATUS_CODE,
+ **kwargs
+ )
+ response["Retry-After"] = settings.MAINTENANCE_MODE_RETRY_AFTER
add_never_cache_headers(response)
return response
-def need_maintenance_response(request):
- """
- Tells if the given request needs a maintenance response or not.
- """
-
+def _need_maintenance_from_view(request):
try:
view_match = resolve(request.path)
view_func = view_match[0]
view_dict = view_func.__dict__
view_force_maintenance_mode_off = view_dict.get(
- 'force_maintenance_mode_off', False)
+ "force_maintenance_mode_off", False
+ )
if view_force_maintenance_mode_off:
# view has 'force_maintenance_mode_off' decorator
return False
view_force_maintenance_mode_on = view_dict.get(
- 'force_maintenance_mode_on', False)
+ "force_maintenance_mode_on", False
+ )
if view_force_maintenance_mode_on:
# view has 'force_maintenance_mode_on' decorator
return True
@@ -89,115 +70,157 @@ def need_maintenance_response(request):
except Resolver404:
pass
- if not get_maintenance_mode():
- return False
+def _need_maintenance_from_url(request):
try:
- url_off = reverse('maintenance_mode_off')
-
+ url_off = reverse("maintenance_mode_off")
resolve(url_off)
-
if url_off == request.path_info:
return False
-
except NoReverseMatch:
# maintenance_mode.urls not added
pass
- if hasattr(request, 'user'):
- if django.VERSION < (1, 10):
- if settings.MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER \
- and request.user.is_anonymous():
- return False
+def _need_maintenance_ignore_users(request):
+ if not hasattr(request, "user"):
+ return
- if settings.MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER \
- and request.user.is_authenticated():
- return False
- else:
- if settings.MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER \
- and request.user.is_anonymous:
- return False
+ user = request.user
- if settings.MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER \
- and request.user.is_authenticated:
- return False
+ if settings.MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER and user.is_anonymous:
+ return False
- if settings.MAINTENANCE_MODE_IGNORE_STAFF \
- and request.user.is_staff:
- return False
+ if settings.MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER and user.is_authenticated:
+ return False
+
+ if settings.MAINTENANCE_MODE_IGNORE_STAFF and user.is_staff:
+ return False
+
+ if settings.MAINTENANCE_MODE_IGNORE_SUPERUSER and user.is_superuser:
+ return False
+
+
+def _need_maintenance_ignore_admin_site(request):
+ if not settings.MAINTENANCE_MODE_IGNORE_ADMIN_SITE:
+ return
- if settings.MAINTENANCE_MODE_IGNORE_SUPERUSER \
- and request.user.is_superuser:
+ try:
+ request_path = request.path if request.path else ""
+ if not request_path.endswith("/"):
+ request_path += "/"
+
+ admin_url = reverse("admin:index")
+ if request_path.startswith(admin_url):
return False
+ except NoReverseMatch:
+ # admin.urls not added
+ pass
- if settings.MAINTENANCE_MODE_IGNORE_ADMIN_SITE:
- try:
- request_path = request.path if request.path else ''
- if not request_path.endswith('/'):
- request_path += '/'
+def _need_maintenance_ignore_tests(request):
+ if not settings.MAINTENANCE_MODE_IGNORE_TESTS:
+ return
- admin_url = reverse('admin:index')
- if request_path.startswith(admin_url):
- return False
+ is_testing = False
- except NoReverseMatch:
- # admin.urls not added
- pass
+ if (len(sys.argv) > 0 and "runtests" in sys.argv[0]) or (
+ len(sys.argv) > 1 and sys.argv[1] == "test"
+ ):
+ # python runtests.py | python manage.py test | python
+ # setup.py test | django-admin.py test
+ is_testing = True
- if settings.MAINTENANCE_MODE_IGNORE_TESTS:
+ if is_testing:
+ return False
- is_testing = False
- if (len(sys.argv) > 0 and 'runtests' in sys.argv[0]) \
- or (len(sys.argv) > 1 and sys.argv[1] == 'test'):
- # python runtests.py | python manage.py test | python
- # setup.py test | django-admin.py test
- is_testing = True
+def _need_maintenance_ignore_ip_addresses(request):
+ if not settings.MAINTENANCE_MODE_IGNORE_IP_ADDRESSES:
+ return
- if is_testing:
+ if settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS:
+ try:
+ get_client_ip_address_func = import_string(
+ settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS
+ )
+ except ImportError:
+ raise ImproperlyConfigured(
+ "settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS "
+ "is not a valid function path."
+ )
+ else:
+ client_ip_address = get_client_ip_address_func(request)
+ else:
+ client_ip_address = get_client_ip_address(request)
+
+ for ip_address in settings.MAINTENANCE_MODE_IGNORE_IP_ADDRESSES:
+ ip_address_re = re.compile(ip_address)
+ if ip_address_re.match(client_ip_address):
return False
- if settings.MAINTENANCE_MODE_IGNORE_IP_ADDRESSES:
-
- if settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS:
- try:
- get_client_ip_address_func = import_string(
- settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS)
- except ImportError:
- raise ImproperlyConfigured(
- 'settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS '
- 'is not a valid function path.')
- else:
- client_ip_address = get_client_ip_address_func(request)
- else:
- client_ip_address = get_client_ip_address(request)
- for ip_address in settings.MAINTENANCE_MODE_IGNORE_IP_ADDRESSES:
+def _need_maintenance_ignore_urls(request):
+ if not settings.MAINTENANCE_MODE_IGNORE_URLS:
+ return
- ip_address_re = re.compile(ip_address)
+ for url in settings.MAINTENANCE_MODE_IGNORE_URLS:
+ if not isinstance(url, re.Pattern):
+ url = str(url)
+ url_re = re.compile(url)
+ if url_re.match(request.path_info):
+ return False
- if ip_address_re.match(client_ip_address):
- return False
- if settings.MAINTENANCE_MODE_IGNORE_URLS:
+def _need_maintenance_redirects(request):
+ if not settings.MAINTENANCE_MODE_REDIRECT_URL:
+ return
- for url in settings.MAINTENANCE_MODE_IGNORE_URLS:
+ redirect_url_re = re.compile(settings.MAINTENANCE_MODE_REDIRECT_URL)
- if not isinstance(url, pattern_class):
- url = str(url)
- url_re = re.compile(url)
+ if redirect_url_re.match(request.path_info):
+ return False
- if url_re.match(request.path_info):
- return False
- if settings.MAINTENANCE_MODE_REDIRECT_URL:
+def need_maintenance_response(request):
+ """
+ Tells if the given request needs a maintenance response or not.
+ """
- redirect_url_re = re.compile(
- settings.MAINTENANCE_MODE_REDIRECT_URL)
+ value = _need_maintenance_from_view(request)
+ if isinstance(value, bool):
+ return value
- if redirect_url_re.match(request.path_info):
- return False
+ value = get_maintenance_mode()
+ if not value:
+ return value
+
+ value = _need_maintenance_from_url(request)
+ if isinstance(value, bool):
+ return value
+
+ value = _need_maintenance_ignore_users(request)
+ if isinstance(value, bool):
+ return value
+
+ value = _need_maintenance_ignore_admin_site(request)
+ if isinstance(value, bool):
+ return value
+
+ value = _need_maintenance_ignore_tests(request)
+ if isinstance(value, bool):
+ return value
+
+ value = _need_maintenance_ignore_ip_addresses(request)
+ if isinstance(value, bool):
+ return value
+
+ value = _need_maintenance_ignore_urls(request)
+ if isinstance(value, bool):
+ return value
+
+ value = _need_maintenance_redirects(request)
+ if isinstance(value, bool):
+ return value
return True
diff --git a/maintenance_mode/io.py b/maintenance_mode/io.py
index fd23745..cd825dc 100644
--- a/maintenance_mode/io.py
+++ b/maintenance_mode/io.py
@@ -1,21 +1,17 @@
-# -*- coding: utf-8 -*-
-
import os
+import fsutil
+
-def read_file(file_path, default_content=''):
+def read_file(file_path, default_content=""):
"""
Read file at the specified path.
If file doesn't exist, it will be created with default-content.
Returns the file content.
"""
- if not os.path.exists(file_path):
- write_file(file_path, default_content)
-
- handler = open(file_path, 'r')
- content = handler.read()
- handler.close()
- return content or default_content
+ if not fsutil.exists(file_path):
+ fsutil.write_file(file_path, default_content)
+ return fsutil.read_file(file_path) or default_content
def write_file(file_path, content):
@@ -23,6 +19,4 @@ def write_file(file_path, content):
Write file at the specified path with content.
If file exists, it will be overwritten.
"""
- handler = open(file_path, 'w+')
- handler.write(content)
- handler.close()
+ fsutil.write_file(file_path, content)
diff --git a/maintenance_mode/logging.py b/maintenance_mode/logging.py
index cb49c55..0e6d428 100644
--- a/maintenance_mode/logging.py
+++ b/maintenance_mode/logging.py
@@ -1,13 +1,9 @@
-# -*- coding: utf-8 -*-
-
-from __future__ import absolute_import
+import logging
from django.conf import settings
from maintenance_mode.core import get_maintenance_mode
-import logging
-
class RequireNotMaintenanceMode503(logging.Filter):
"""
@@ -19,7 +15,7 @@ class RequireNotMaintenanceMode503(logging.Filter):
Return False if maintenance mode is on and
the given record has a status code of 503.
"""
- status_code = getattr(record, 'status_code', None)
+ status_code = getattr(record, "status_code", None)
if get_maintenance_mode() and status_code == 503:
return False
return True
diff --git a/maintenance_mode/management/commands/maintenance_mode.py b/maintenance_mode/management/commands/maintenance_mode.py
index 9063342..d3b3e8d 100644
--- a/maintenance_mode/management/commands/maintenance_mode.py
+++ b/maintenance_mode/management/commands/maintenance_mode.py
@@ -1,9 +1,3 @@
-# -*- coding: utf-8 -*-
-
-from __future__ import absolute_import
-
-import django
-
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
@@ -12,13 +6,15 @@ from maintenance_mode import core
class Command(BaseCommand):
- args = '<on|off>'
- help = 'run python manage.py maintenance_mode %s '\
- 'to change maintenance-mode state' % args
+ args = "<on|off>"
+ help = (
+ "run python manage.py maintenance_mode %s "
+ "to change maintenance-mode state" % args
+ )
def add_arguments(self, parser):
- parser.add_argument('state')
- parser.add_argument('--interactive', dest='interactive', action='store_true')
+ parser.add_argument("state")
+ parser.add_argument("--interactive", dest="interactive", action="store_true")
def get_maintenance_mode(self):
try:
@@ -26,16 +22,18 @@ class Command(BaseCommand):
return value
except IOError:
raise CommandError(
- 'Unable to read state file at: %s' % (
- settings.MAINTENANCE_MODE_STATE_FILE_NAME, ))
+ "Unable to read state file at: %s"
+ % (settings.MAINTENANCE_MODE_STATE_FILE_NAME,)
+ )
def set_maintenance_mode(self, value):
try:
core.set_maintenance_mode(value)
except IOError:
raise CommandError(
- 'Unable to write state file at: %s' % (
- settings.MAINTENANCE_MODE_STATE_FILE_NAME, ))
+ "Unable to write state file at: %s"
+ % (settings.MAINTENANCE_MODE_STATE_FILE_NAME,)
+ )
def set_maintenance_mode_with_confirm(self, value, confirm_message, interactive):
if interactive:
@@ -45,61 +43,56 @@ class Command(BaseCommand):
self.set_maintenance_mode(value)
def confirm(self, message):
- # Fix for Python 2.x.
- try:
- input_func = raw_input
- except NameError:
- input_func = input
-
+ input_func = input
answer = input_func(message)
answer = answer.lower()
- return answer.find('y') == 0
+ return answer.find("y") == 0
def handle(self, *args, **options):
- verbosity = int(options['verbosity'])
+ verbosity = int(options["verbosity"])
verbose = True if verbosity == 3 else False
- interactive = options.get('interactive', False)
-
- if django.VERSION < (1, 8):
- if len(args) != 1:
- raise CommandError(
- 'Expected 1 argument: %s' % (self.args, ))
-
- state = args[0]
- else:
- state = options['state']
-
+ interactive = options.get("interactive", False)
+ state = options["state"]
state = state.lower()
value = self.get_maintenance_mode()
- if state in ['on', 'yes', 'true', '1']:
+ if state in ["on", "yes", "true", "1"]:
if value:
if verbose:
- self.stdout.write('maintenance mode is already on')
+ self.stdout.write("maintenance mode is already on")
return
self.set_maintenance_mode_with_confirm(
- True, 'maintenance mode on? (y/N) ', interactive)
+ True, "maintenance mode on? (y/N) ", interactive
+ )
- elif state in ['off', 'no', 'false', '0']:
+ elif state in ["off", "no", "false", "0"]:
if not value:
if verbose:
- self.stdout.write('maintenance mode is already off')
+ self.stdout.write("maintenance mode is already off")
return
self.set_maintenance_mode_with_confirm(
- False, 'maintenance mode off? (y/N) ', interactive)
+ False, "maintenance mode off? (y/N) ", interactive
+ )
else:
- raise CommandError('Invalid argument: \'%s\' '
- 'expected %s' % (state, self.args, ))
+ raise CommandError(
+ "Invalid argument: '%s' "
+ "expected %s"
+ % (
+ state,
+ self.args,
+ )
+ )
if verbose:
- output = 'maintenance mode: %s' % (
- 'on' if self.get_maintenance_mode() else 'off', )
+ output = "maintenance mode: %s" % (
+ "on" if self.get_maintenance_mode() else "off",
+ )
self.stdout.write(output)
return
diff --git a/maintenance_mode/middleware.py b/maintenance_mode/middleware.py
index b44577e..44ffe4e 100644
--- a/maintenance_mode/middleware.py
+++ b/maintenance_mode/middleware.py
@@ -1,22 +1,17 @@
-# -*- coding: utf-8 -*-
+from maintenance_mode.http import get_maintenance_response, need_maintenance_response
-import django
-if django.VERSION < (1, 10):
- __MaintenanceModeMiddlewareBaseClass = object
-else:
- # https://docs.djangoproject.com/en/1.10/topics/http/middleware/#upgrading-pre-django-1-10-style-middleware
- from django.utils.deprecation import MiddlewareMixin
- __MaintenanceModeMiddlewareBaseClass = MiddlewareMixin
+class MaintenanceModeMiddleware(object):
+ def __init__(self, get_response=None):
+ self.get_response = get_response
-from maintenance_mode.http import (
- get_maintenance_response, need_maintenance_response, )
-
-
-class MaintenanceModeMiddleware(__MaintenanceModeMiddlewareBaseClass):
+ def __call__(self, request):
+ response = self.process_request(request)
+ if response is None and callable(self.get_response):
+ response = self.get_response(request)
+ return response
def process_request(self, request):
if need_maintenance_response(request):
return get_maintenance_response(request)
- else:
- return None
+ return None
diff --git a/maintenance_mode/settings.py b/maintenance_mode/settings.py
index 5da1517..5a51e91 100644
--- a/maintenance_mode/settings.py
+++ b/maintenance_mode/settings.py
@@ -1,66 +1,64 @@
-# -*- coding: utf-8 -*-
+import os
+import fsutil
from django.conf import settings
from django.utils.module_loading import import_module
-import os
-
-
-if not hasattr(settings, 'MAINTENANCE_MODE'):
+if not hasattr(settings, "MAINTENANCE_MODE"):
settings.MAINTENANCE_MODE = None
-if not hasattr(settings, 'MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS'):
+if not hasattr(settings, "MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS"):
settings.MAINTENANCE_MODE_GET_CLIENT_IP_ADDRESS = None
-if not hasattr(settings, 'MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT'):
+if not hasattr(settings, "MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT"):
settings.MAINTENANCE_MODE_GET_TEMPLATE_CONTEXT = None
-if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_ADMIN_SITE'):
+if not hasattr(settings, "MAINTENANCE_MODE_IGNORE_ADMIN_SITE"):
settings.MAINTENANCE_MODE_IGNORE_ADMIN_SITE = None
-if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER'):
+if not hasattr(settings, "MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER"):
settings.MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER = False
-if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER'):
+if not hasattr(settings, "MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER"):
settings.MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER = False
-if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_IP_ADDRESSES'):
+if not hasattr(settings, "MAINTENANCE_MODE_IGNORE_IP_ADDRESSES"):
settings.MAINTENANCE_MODE_IGNORE_IP_ADDRESSES = None
-if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_STAFF'):
+if not hasattr(settings, "MAINTENANCE_MODE_IGNORE_STAFF"):
settings.MAINTENANCE_MODE_IGNORE_STAFF = False
-if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_SUPERUSER'):
+if not hasattr(settings, "MAINTENANCE_MODE_IGNORE_SUPERUSER"):
settings.MAINTENANCE_MODE_IGNORE_SUPERUSER = False
-if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_TESTS'):
+if not hasattr(settings, "MAINTENANCE_MODE_IGNORE_TESTS"):
settings.MAINTENANCE_MODE_IGNORE_TESTS = False
-if not hasattr(settings, 'MAINTENANCE_MODE_IGNORE_URLS'):
+if not hasattr(settings, "MAINTENANCE_MODE_IGNORE_URLS"):
settings.MAINTENANCE_MODE_IGNORE_URLS = None
-if not hasattr(settings, 'MAINTENANCE_MODE_REDIRECT_URL'):
+if not hasattr(settings, "MAINTENANCE_MODE_REDIRECT_URL"):
settings.MAINTENANCE_MODE_REDIRECT_URL = None
-if not hasattr(settings, 'MAINTENANCE_MODE_STATE_BACKEND'):
- settings.MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.LocalFileBackend'
+if not hasattr(settings, "MAINTENANCE_MODE_STATE_BACKEND"):
+ settings.MAINTENANCE_MODE_STATE_BACKEND = (
+ "maintenance_mode.backends.LocalFileBackend"
+ )
-if not hasattr(settings, 'MAINTENANCE_MODE_STATE_FILE_NAME'):
- settings.MAINTENANCE_MODE_STATE_FILE_NAME = 'maintenance_mode_state.txt'
+if not hasattr(settings, "MAINTENANCE_MODE_STATE_FILE_NAME"):
+ settings.MAINTENANCE_MODE_STATE_FILE_NAME = "maintenance_mode_state.txt"
-if not hasattr(settings, 'MAINTENANCE_MODE_STATE_FILE_PATH'):
- settings_module = import_module(os.environ['DJANGO_SETTINGS_MODULE'])
- settings_path = settings_module.__file__
- settings_dir = os.path.dirname(settings_path)
- settings.MAINTENANCE_MODE_STATE_FILE_PATH = os.path.abspath(
- os.path.join(settings_dir,
- settings.MAINTENANCE_MODE_STATE_FILE_NAME))
+if not hasattr(settings, "MAINTENANCE_MODE_STATE_FILE_PATH"):
+ settings_module = import_module(os.environ["DJANGO_SETTINGS_MODULE"])
+ settings.MAINTENANCE_MODE_STATE_FILE_PATH = fsutil.join_path(
+ settings_module.__file__, settings.MAINTENANCE_MODE_STATE_FILE_NAME
+ )
-if not hasattr(settings, 'MAINTENANCE_MODE_TEMPLATE'):
- settings.MAINTENANCE_MODE_TEMPLATE = '503.html'
+if not hasattr(settings, "MAINTENANCE_MODE_TEMPLATE"):
+ settings.MAINTENANCE_MODE_TEMPLATE = "503.html"
-if not hasattr(settings, 'MAINTENANCE_MODE_STATUS_CODE'):
+if not hasattr(settings, "MAINTENANCE_MODE_STATUS_CODE"):
settings.MAINTENANCE_MODE_STATUS_CODE = 503
-if not hasattr(settings, 'MAINTENANCE_MODE_RETRY_AFTER'):
+if not hasattr(settings, "MAINTENANCE_MODE_RETRY_AFTER"):
settings.MAINTENANCE_MODE_RETRY_AFTER = 3600
diff --git a/maintenance_mode/templates/503.html b/maintenance_mode/templates/503.html
index d813e12..c1d41df 100644
--- a/maintenance_mode/templates/503.html
+++ b/maintenance_mode/templates/503.html
@@ -1 +1 @@
-django-maintenance-mode
\ No newline at end of file
+django-maintenance-mode
diff --git a/maintenance_mode/urls.py b/maintenance_mode/urls.py
index 173a262..0fad943 100644
--- a/maintenance_mode/urls.py
+++ b/maintenance_mode/urls.py
@@ -1,16 +1,8 @@
-# -*- coding: utf-8 -*-
-
-import django
-
-if django.VERSION < (2, 0):
- from django.conf.urls import url as re_path
-else:
- from django.urls import re_path
+from django.urls import re_path
from maintenance_mode.views import maintenance_mode_off, maintenance_mode_on
-
urlpatterns = [
- re_path(r'^off/$', maintenance_mode_off, name='maintenance_mode_off'),
- re_path(r'^on/$', maintenance_mode_on, name='maintenance_mode_on'),
+ re_path(r"^off/$", maintenance_mode_off, name="maintenance_mode_off"),
+ re_path(r"^on/$", maintenance_mode_on, name="maintenance_mode_on"),
]
diff --git a/maintenance_mode/utils.py b/maintenance_mode/utils.py
index 27830a5..9982005 100644
--- a/maintenance_mode/utils.py
+++ b/maintenance_mode/utils.py
@@ -1,7 +1,5 @@
-# -*- coding: utf-8 -*-
-
def get_client_ip_address(request):
"""
Get the client IP Address.
"""
- return request.META['REMOTE_ADDR']
+ return request.META["REMOTE_ADDR"]
diff --git a/maintenance_mode/version.py b/maintenance_mode/version.py
index 8ea7850..1317d75 100644
--- a/maintenance_mode/version.py
+++ b/maintenance_mode/version.py
@@ -1,3 +1 @@
-# -*- coding: utf-8 -*-
-
-__version__ = '0.16.1'
+__version__ = "0.18.0"
diff --git a/maintenance_mode/views.py b/maintenance_mode/views.py
index b98d324..a916c92 100644
--- a/maintenance_mode/views.py
+++ b/maintenance_mode/views.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
from django.http import HttpResponseRedirect
from maintenance_mode.core import set_maintenance_mode
@@ -13,7 +11,7 @@ def maintenance_mode_off(request):
if request.user.is_superuser:
set_maintenance_mode(False)
- return HttpResponseRedirect('/')
+ return HttpResponseRedirect("/")
def maintenance_mode_on(request):
@@ -24,4 +22,4 @@ def maintenance_mode_on(request):
if request.user.is_superuser:
set_maintenance_mode(True)
- return HttpResponseRedirect('/')
+ return HttpResponseRedirect("/")
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..9e35679
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,16 @@
+[tool.black]
+include = '\.pyi?$'
+exclude = '''
+/(
+ \.git
+ | \.hg
+ | \.mypy_cache
+ | \.tox
+ | \.venv
+ | _build
+ | buck-out
+ | build
+ | dist
+ | venv
+)/
+'''
diff --git a/setup.cfg b/setup.cfg
index 9f88734..da016b5 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
[metadata]
-description-file = README.md
+description_file = README.md
[egg_info]
tag_build =
diff --git a/setup.py b/setup.py
index e871ca8..5d89d39 100644
--- a/setup.py
+++ b/setup.py
@@ -1,69 +1,84 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-from setuptools import setup, find_packages
+import os
+import sys
-import os, sys
+from setuptools import find_packages, setup
-exec(open('maintenance_mode/version.py').read())
+exec(open("maintenance_mode/version.py").read())
-github_url = 'https://github.com/fabiocaccamo'
-package_name = 'django-maintenance-mode'
-package_url = '{}/{}'.format(github_url, package_name)
+package_name = "django-maintenance-mode"
+package_url = f"https://github.com/fabiocaccamo/{package_name}"
package_path = os.path.abspath(os.path.dirname(__file__))
-long_description_file_path = os.path.join(package_path, 'README.md')
-long_description_content_type = 'text/markdown'
-long_description = ''
+download_url = f"{package_url}/archive/{__version__}.tar.gz"
+documentation_url = f"{package_url}#readme"
+issues_url = f"{package_url}/issues"
+sponsor_url = "https://github.com/sponsors/fabiocaccamo/"
+twitter_url = "https://twitter.com/fabiocaccamo"
+
+long_description_file_path = os.path.join(package_path, "README.md")
+long_description_content_type = "text/markdown"
+long_description = ""
try:
- long_description_file_options = {} if sys.version_info[0] < 3 else { 'encoding':'utf-8' }
- with open(long_description_file_path, 'r', **long_description_file_options) as f:
+ with open(long_description_file_path, "r", encoding="utf-8") as f:
long_description = f.read()
except IOError:
pass
setup(
name=package_name,
- packages=find_packages(exclude=['contrib', 'docs', 'tests*']),
+ packages=find_packages(exclude=["contrib", "docs", "tests*"]),
version=__version__,
- description='django-maintenance-mode shows a 503 error page when maintenance-mode is on.',
+ description="django-maintenance-mode shows a 503 error page when maintenance-mode is on.",
long_description=long_description,
long_description_content_type=long_description_content_type,
- author='Fabio Caccamo',
- author_email='fabio.caccamo@gmail.com',
+ author="Fabio Caccamo",
+ author_email="fabio.caccamo@gmail.com",
url=package_url,
- download_url='{}/archive/{}.tar.gz'.format(package_url, __version__),
- keywords=['django', 'maintenance', 'mode', 'offline', 'under', '503', 'service', 'temporarily', 'unavailable'],
- requires=['django(>=1.7)'],
+ download_url=download_url,
+ project_urls={
+ "Documentation": documentation_url,
+ "Issues": issues_url,
+ "Funding": sponsor_url,
+ "Twitter": twitter_url,
+ },
+ keywords=[
+ "django",
+ "maintenance",
+ "mode",
+ "offline",
+ "under",
+ "503",
+ "service",
+ "temporarily",
+ "unavailable",
+ ],
+ requires=[
+ "django (>= 2.2)",
+ ],
+ install_requires=[
+ "python-fsutil >= 0.7.0",
+ ],
classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Environment :: Web Environment',
- 'Framework :: Django',
- 'Framework :: Django :: 1.7',
- 'Framework :: Django :: 1.8',
- 'Framework :: Django :: 1.9',
- 'Framework :: Django :: 1.10',
- 'Framework :: Django :: 1.11',
- 'Framework :: Django :: 2.0',
- 'Framework :: Django :: 2.1',
- 'Framework :: Django :: 2.2',
- 'Framework :: Django :: 3.0',
- 'Framework :: Django :: 3.1',
- 'Framework :: Django :: 3.2',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: MIT License',
- 'Natural Language :: English',
- 'Operating System :: OS Independent',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: 3.8',
- 'Programming Language :: Python :: 3.9',
- 'Topic :: Software Development :: Build Tools',
+ "Development Status :: 5 - Production/Stable",
+ "Environment :: Web Environment",
+ "Framework :: Django",
+ "Framework :: Django :: 2.2",
+ "Framework :: Django :: 3.0",
+ "Framework :: Django :: 3.1",
+ "Framework :: Django :: 3.2",
+ "Framework :: Django :: 4.0",
+ "Framework :: Django :: 4.1",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: MIT License",
+ "Natural Language :: English",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Topic :: Software Development :: Build Tools",
],
- license='MIT',
- test_suite='runtests.runtests'
+ license="MIT",
)