├── testproject ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── urls.py ├── constants.py ├── requirements.in ├── templates │ ├── home.html │ └── model_form.html ├── models.py ├── views.py ├── manage.py ├── forms.py ├── settings.py └── requirements.txt ├── docs ├── _static │ └── .do-not-delete ├── requirements.in ├── index.rst ├── setup.rst ├── requirements.txt ├── settings.rst ├── usage.rst ├── Makefile └── conf.py ├── django_bleach ├── tests │ ├── __init__.py │ ├── test_templatetags.py │ ├── test_settings.py │ ├── test_modelformfield.py │ ├── test_models.py │ └── test_forms.py ├── templatetags │ ├── __init__.py │ └── bleach_tags.py ├── __init__.py ├── utils.py ├── forms.py └── models.py ├── .pep8 ├── requirements.in ├── requirements ├── requirements.in ├── compile.py ├── py311-django41.txt ├── py311-django42.txt ├── py312-django42.txt ├── py38-django32.txt ├── py38-django40.txt ├── py38-django41.txt ├── py38-django42.txt ├── py39-django32.txt ├── py39-django40.txt ├── py39-django41.txt ├── py39-django42.txt ├── py310-django32.txt ├── py310-django40.txt ├── py310-django41.txt └── py310-django42.txt ├── MANIFEST.in ├── .editorconfig ├── .github ├── dependabot.yml ├── pull_request_template.md ├── workflows │ ├── docs.yml │ ├── publish-to-live-pypi.yml │ ├── publish-to-test-pypi.yml │ ├── lint.yml │ ├── codeql-analysis.yml │ └── test.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .readthedocs.yaml ├── tox.ini ├── setup.cfg ├── LICENSE ├── .pre-commit-config.yaml ├── requirements.txt ├── .gitignore ├── pyproject.toml ├── setup.py ├── CHANGELOG.md └── README.rst /testproject/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_static/.do-not-delete: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_bleach/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django_bleach/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testproject/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.pep8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E501 3 | exclude = migrations,.venv_*,docs -------------------------------------------------------------------------------- /requirements.in: -------------------------------------------------------------------------------- 1 | bump2version 2 | pip-tools 3 | pre-commit 4 | tox 5 | wheel 6 | -------------------------------------------------------------------------------- /requirements/requirements.in: -------------------------------------------------------------------------------- 1 | bleach>=5,<6 2 | coverage[toml] 3 | mock 4 | tinycss2 5 | -------------------------------------------------------------------------------- /django_bleach/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "3.1.0" 2 | 3 | VERSION = __version__.split(".") 4 | -------------------------------------------------------------------------------- /docs/requirements.in: -------------------------------------------------------------------------------- 1 | furo 2 | MarkupSafe 3 | sphinx 4 | sphinx-autobuild 5 | sphinxext-opengraph 6 | sphinxcontrib-spelling 7 | sphinx-autobuild 8 | -------------------------------------------------------------------------------- /testproject/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from .views import home, model_form 4 | 5 | 6 | urlpatterns = [ 7 | path("", home, name="home"), 8 | path("model_form/", model_form, name="model_form"), 9 | ] 10 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | include CHANGELOG.md 4 | include docs/*.rst 5 | prune docs/_build 6 | graft testproject 7 | global-exclude coverage.xml 8 | global-exclude .coverage 9 | recursive-exclude * *.pyc __pycache__ .DS_Store 10 | -------------------------------------------------------------------------------- /testproject/constants.py: -------------------------------------------------------------------------------- 1 | ALLOWED_ATTRIBUTES = {"*": ["class", "style"], "a": ["href", "title"]} 2 | 3 | ALLOWED_CSS_PROPERTIES = ["color"] 4 | 5 | ALLOWED_PROTOCOLS = [ 6 | "https", 7 | "data", 8 | ] 9 | 10 | ALLOWED_STYLES = ALLOWED_CSS_PROPERTIES 11 | 12 | ALLOWED_TAGS = ["a", "li", "ul"] 13 | -------------------------------------------------------------------------------- /testproject/requirements.in: -------------------------------------------------------------------------------- 1 | bleach 2 | django 3 | coverage 4 | mock 5 | flake8 6 | flake8-broken-line 7 | flake8-bugbear 8 | flake8-builtins 9 | flake8-commas 10 | flake8-comprehensions 11 | flake8-eradicate 12 | flake8-quotes 13 | flake8-tidy-imports 14 | pep8-naming 15 | pip-tools 16 | sphinx 17 | sphinx-rtd-theme 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | indent_style = space 11 | indent_size = 4 12 | 13 | [*.py] 14 | max_line_length = 80 15 | 16 | [*.toml] 17 | indent_size = 2 18 | 19 | [*.yml] 20 | indent_size = 2 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | commit-message: 6 | prefix: "ci:" 7 | include: "scope" 8 | schedule: 9 | interval: weekly 10 | - package-ecosystem: pip 11 | directory: "/" 12 | schedule: 13 | interval: weekly 14 | groups: 15 | python-packages: 16 | patterns: 17 | - "*" 18 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | version: 2 4 | 5 | build: 6 | os: ubuntu-22.04 7 | tools: 8 | python: "3.11" 9 | 10 | sphinx: 11 | configuration: docs/conf.py 12 | fail_on_warning: false 13 | 14 | formats: 15 | - epub 16 | - pdf 17 | 18 | python: 19 | install: 20 | - requirements: docs/requirements.txt 21 | -------------------------------------------------------------------------------- /testproject/templates/home.html: -------------------------------------------------------------------------------- 1 | 2 |

Form example

3 |
4 | {% csrf_token %} 5 | 6 | {{ form.errors }} 7 | {{ form.as_p }} 8 | 9 |
10 | 11 |
12 |
13 | Model form example(Note: you need to migrate database to use it) 14 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Describe: 4 | 5 | * Content of the pull request 6 | * Feature added / Problem fixed 7 | 8 | ## References 9 | 10 | Provide any github issue fixed (as in ``Fix #XYZ``) 11 | 12 | # Checklist 13 | 14 | * [ ] I have ran `tox` to ensure tests pass 15 | * [ ] Usage documentation added in case of new features 16 | * [ ] README & CHANGELOG updated 17 | * [ ] Tests added / I have not lowered coverage from 100% 18 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | requires = 3 | tox>=4.2 4 | env_list = 5 | py312-django{42} 6 | py311-django{42, 41} 7 | py310-django{42, 41, 40, 32} 8 | py39-django{42, 41, 40, 32} 9 | py38-django{42, 41, 40, 32} 10 | 11 | [testenv] 12 | package = wheel 13 | deps = 14 | -r {toxinidir}/requirements/{envname}.txt 15 | set_env = 16 | PYTHONDEVMODE = 1 17 | PYTHONDONTWRITEBYTECODE=1 18 | commands = 19 | python \ 20 | -W error::ResourceWarning \ 21 | -W error::DeprecationWarning \ 22 | -W error::PendingDeprecationWarning \ 23 | -m coverage run testproject/manage.py test django_bleach 24 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Docs 2 | 3 | on: [push, pull_request] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | docs: 11 | runs-on: ubuntu-latest 12 | name: docs 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | - name: Set up Python 17 | uses: actions/setup-python@v5 18 | with: 19 | python-version: 3.11 20 | - run: python -m pip install sphinx 21 | - name: Build docs 22 | run: | 23 | cd docs 24 | sphinx-build -W -b html -d _build/doctrees . _build/html 25 | -------------------------------------------------------------------------------- /testproject/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from bleach.css_sanitizer import CSSSanitizer 4 | 5 | from django_bleach.models import BleachField 6 | 7 | 8 | class Person(models.Model): 9 | name = models.CharField(max_length=20) 10 | biography = BleachField( 11 | max_length=100, 12 | verbose_name="Person biography", 13 | allowed_tags=["p", "a", "li", "ul", "strong"], 14 | allowed_attributes=["class", "href", "style"], 15 | allowed_protocols=["http", "https"], 16 | css_sanitizer=CSSSanitizer( 17 | allowed_css_properties=["color", "background-color"] 18 | ), 19 | ) 20 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. django-bleach documentation master file, created by 2 | sphinx-quickstart on Tue Jun 19 10:24:12 2012. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | ``django-bleach`` 7 | ======================= 8 | 9 | ``bleach`` is a Python module that takes any HTML input, and returns valid, 10 | sanitised HTML that contains only an allowed subset of HTML tags, attributes 11 | and styles. ``django-bleach`` is a Django app that makes using bleach extremely 12 | easy. 13 | 14 | Contents: 15 | 16 | .. toctree:: 17 | :maxdepth: 2 18 | 19 | setup 20 | usage 21 | settings 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /docs/setup.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Setup 3 | ===== 4 | 5 | .. _setup: 6 | 7 | 1. Get the source from the `Git repository`_ or install it from the Python 8 | Package Index by running ``pip install django-bleach``. 9 | 10 | 2. Add ``django_bleach`` to the ``INSTALLED_APPS`` setting:: 11 | 12 | INSTALLED_APPS += ( 13 | 'django_bleach', 14 | ) 15 | 16 | 3. Configure ``django_bleach``. It comes with some sensible defaults, but you 17 | will probably want to tweak the settings for your application. See the 18 | :ref:`settings` page for more information 19 | 20 | 3. Add a ``django_bleach.models.BleachField`` to a model, a 21 | ``django_bleach.forms.BleachField`` to a form, or use the ``bleach`` 22 | template filter in your templates. 23 | 24 | .. _Git repository: https://github.com/marksweb/django-bleach/ 25 | -------------------------------------------------------------------------------- /django_bleach/utils.py: -------------------------------------------------------------------------------- 1 | from bleach.css_sanitizer import CSSSanitizer 2 | from django.conf import settings 3 | 4 | 5 | def get_bleach_default_options(): 6 | bleach_args = {} 7 | bleach_settings = { 8 | "BLEACH_ALLOWED_TAGS": "tags", 9 | "BLEACH_ALLOWED_ATTRIBUTES": "attributes", 10 | "BLEACH_ALLOWED_STYLES": "css_sanitizer", 11 | "BLEACH_STRIP_TAGS": "strip", 12 | "BLEACH_STRIP_COMMENTS": "strip_comments", 13 | "BLEACH_ALLOWED_PROTOCOLS": "protocols", 14 | } 15 | 16 | for setting, kwarg in bleach_settings.items(): 17 | if hasattr(settings, setting): 18 | attr = getattr(settings, setting) 19 | if setting == "BLEACH_ALLOWED_STYLES": 20 | attr = CSSSanitizer(allowed_css_properties=attr) 21 | bleach_args[kwarg] = attr 22 | 23 | return bleach_args 24 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-live-pypi.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python 🐍 distributions 📦 to pypi 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | 8 | jobs: 9 | build-n-publish: 10 | name: Build and publish Python 🐍 distributions 📦 to pypi 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Set up Python 3.9 15 | uses: actions/setup-python@v5 16 | with: 17 | python-version: 3.9 18 | 19 | - name: Install pypa/build 20 | run: >- 21 | python -m 22 | pip install 23 | build 24 | --user 25 | - name: Build a binary wheel and a source tarball 26 | run: >- 27 | python -m 28 | build 29 | --sdist 30 | --wheel 31 | --outdir dist/ 32 | . 33 | 34 | - name: Publish distribution 📦 to PyPI 35 | if: startsWith(github.ref, 'refs/tags') 36 | uses: pypa/gh-action-pypi-publish@master 37 | with: 38 | password: ${{ secrets.PYPI_API_TOKEN }} 39 | -------------------------------------------------------------------------------- /testproject/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.4 on 2021-06-15 12:39 2 | 3 | from django.db import migrations, models 4 | import django_bleach.models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | initial = True 9 | 10 | dependencies = [] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name="Person", 15 | fields=[ 16 | ( 17 | "id", 18 | models.AutoField( 19 | auto_created=True, 20 | primary_key=True, 21 | serialize=False, 22 | verbose_name="ID", 23 | ), 24 | ), 25 | ("name", models.CharField(max_length=20)), 26 | ( 27 | "biography", 28 | django_bleach.models.BleachField( 29 | max_length=100, verbose_name="Person biography" 30 | ), 31 | ), 32 | ], 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-test-pypi.yml: -------------------------------------------------------------------------------- 1 | name: Publish Python 🐍 distributions 📦 to TestPyPI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build-n-publish: 10 | name: Build and publish Python 🐍 distributions 📦 to TestPyPI 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Set up Python 3.9 15 | uses: actions/setup-python@v5 16 | with: 17 | python-version: 3.9 18 | 19 | - name: Install pypa/build 20 | run: >- 21 | python -m 22 | pip install 23 | build 24 | --user 25 | - name: Build a binary wheel and a source tarball 26 | run: >- 27 | python -m 28 | build 29 | --sdist 30 | --wheel 31 | --outdir dist/ 32 | . 33 | 34 | - name: Publish distribution 📦 to Test PyPI 35 | uses: pypa/gh-action-pypi-publish@master 36 | with: 37 | password: ${{ secrets.TEST_PYPI_API_TOKEN }} 38 | repository_url: https://test.pypi.org/legacy/ 39 | skip_existing: true 40 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: [ push, pull_request ] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | ruff: 11 | name: ruff 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | - name: Set up Python 17 | uses: actions/setup-python@v5 18 | with: 19 | python-version: "3.11" 20 | cache: 'pip' 21 | - run: | 22 | python -m pip install --upgrade pip 23 | pip install ruff 24 | - name: Run Ruff 25 | run: ruff django_bleach 26 | 27 | codespell: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - name: Checkout 31 | uses: actions/checkout@v3 32 | - name: Set up Python 33 | uses: actions/setup-python@v5 34 | with: 35 | python-version: 3.11 36 | cache: 'pip' 37 | - run: python -m pip install codespell 38 | - name: codespell 39 | uses: codespell-project/actions-codespell@master 40 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 3.1.0 3 | commit = True 4 | tag = False 5 | 6 | [bumpversion:file:django_bleach/__init__.py] 7 | search = __version__ = "{current_version}" 8 | replace = __version__ = "{new_version}" 9 | 10 | [bumpversion:file:docs/conf.py] 11 | search = version = "{current_version}" 12 | replace = version = "{new_version}" 13 | 14 | [bumpversion:file:CHANGELOG.md] 15 | search = 16 | [unreleased](https://github.com/marksweb/django-bleach/compare/{current_version}...master) changes 17 | ------------------------------------------------------------------------------------- 18 | replace = 19 | [unreleased](https://github.com/marksweb/django-bleach/compare/{new_version}...master) changes 20 | ------------------------------------------------------------------------------------- 21 | 22 | Version {new_version} 23 | ============= 24 | **{utcnow:%%d-%%m-%%Y}** 25 | 26 | [bdist_wheel] 27 | universal = 1 28 | 29 | [codespell] 30 | skip = ./.git,./.env,./.venv,./.tox,./.eggs,./django_bleach/tests,./docs/_build,./testproject,./htmlcov 31 | count = 32 | quiet-level = 3 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mark Walker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /testproject/views.py: -------------------------------------------------------------------------------- 1 | from django.db import OperationalError 2 | from django.http import HttpResponseRedirect 3 | from django.shortcuts import render 4 | 5 | from .forms import BleachForm, PersonForm 6 | from .models import Person 7 | 8 | 9 | def home(request): 10 | if request.POST: 11 | form = BleachForm(request.POST) 12 | if form.is_valid(): 13 | return HttpResponseRedirect(request.path + "?ok") 14 | else: 15 | form = BleachForm() 16 | 17 | return render(request, "home.html", {"form": form}) 18 | 19 | 20 | def model_form(request): 21 | if request.POST: 22 | form = PersonForm(request.POST) 23 | if form.is_valid(): 24 | form.save() 25 | return HttpResponseRedirect("?ok") 26 | else: 27 | form = PersonForm() 28 | try: 29 | people = list(Person.objects.all()) 30 | except OperationalError: 31 | people = [] 32 | 33 | return render( 34 | request, 35 | "model_form.html", 36 | { 37 | "form": form, 38 | "people": people, 39 | }, 40 | ) 41 | -------------------------------------------------------------------------------- /testproject/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import os 4 | 5 | try: 6 | from django.core.management import execute_manager 7 | 8 | OLD_DJANGO = True 9 | except ImportError: 10 | from django.core.management import execute_from_command_line 11 | 12 | OLD_DJANGO = False 13 | 14 | if OLD_DJANGO: 15 | try: 16 | import settings # Assumed to be in the same directory. 17 | except ImportError: 18 | sys.stderr.write( 19 | "Error: Can't find the file 'settings.py' in the directory containing %r. " 20 | "It appears you've customized things.\nYou'll have to run django-admin.py, " 21 | "passing it your settings module.\n(If the file settings.py does indeed exist, " 22 | "it's causing an ImportError somehow.)\n" % __file__ 23 | ) 24 | sys.exit(1) 25 | 26 | BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) 27 | sys.path.insert(0, BASEDIR) 28 | 29 | if __name__ == "__main__": 30 | os.environ["DJANGO_SETTINGS_MODULE"] = "testproject.settings" 31 | if OLD_DJANGO: 32 | execute_manager(settings) 33 | else: 34 | execute_from_command_line(sys.argv) 35 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | ci: 2 | autofix_commit_msg: | 3 | ci: auto fixes from pre-commit hooks 4 | 5 | for more information, see https://pre-commit.ci 6 | autofix_prs: true 7 | autoupdate_commit_msg: 'ci: pre-commit autoupdate' 8 | autoupdate_schedule: monthly 9 | 10 | repos: 11 | - repo: https://github.com/asottile/pyupgrade 12 | rev: v3.15.2 13 | hooks: 14 | - id: pyupgrade 15 | args: ["--py38-plus"] 16 | 17 | - repo: https://github.com/adamchainz/django-upgrade 18 | rev: '1.16.0' 19 | hooks: 20 | - id: django-upgrade 21 | args: [--target-version, "3.2"] 22 | 23 | - repo: https://github.com/astral-sh/ruff-pre-commit 24 | rev: "v0.4.3" 25 | hooks: 26 | - id: ruff 27 | args: [--fix, --exit-non-zero-on-fix] 28 | 29 | - repo: https://github.com/asottile/yesqa 30 | rev: v1.5.0 31 | hooks: 32 | - id: yesqa 33 | 34 | - repo: https://github.com/pre-commit/pre-commit-hooks 35 | rev: v4.6.0 36 | hooks: 37 | - id: check-merge-conflict 38 | - id: mixed-line-ending 39 | 40 | - repo: https://github.com/psf/black 41 | rev: 24.4.2 42 | hooks: 43 | - id: black 44 | name: Black 45 | -------------------------------------------------------------------------------- /django_bleach/templatetags/bleach_tags.py: -------------------------------------------------------------------------------- 1 | import bleach 2 | from django import template 3 | from django.utils.safestring import mark_safe 4 | 5 | from django_bleach.utils import get_bleach_default_options 6 | 7 | register = template.Library() 8 | 9 | 10 | @register.filter(name="bleach") 11 | def bleach_value(value, tags=None): 12 | if value is None: 13 | return None 14 | 15 | bleach_args = get_bleach_default_options() 16 | if tags is not None: 17 | args = bleach_args.copy() 18 | args["tags"] = tags.split(",") 19 | else: 20 | args = bleach_args 21 | bleached_value = bleach.clean(value, **args) 22 | return mark_safe(bleached_value) 23 | 24 | 25 | @register.filter 26 | def bleach_linkify(value): 27 | """ 28 | Convert URL-like strings in an HTML fragment to links 29 | 30 | This function converts strings that look like URLs, domain names and email 31 | addresses in text that may be an HTML fragment to links, while preserving: 32 | 33 | 1. links already in the string 34 | 2. urls found in attributes 35 | 3. email addresses 36 | """ 37 | if value is None: 38 | return None 39 | 40 | return bleach.linkify(value, parse_email=True) 41 | -------------------------------------------------------------------------------- /testproject/templates/model_form.html: -------------------------------------------------------------------------------- 1 | {% load bleach_tags %} 2 | 3 | 13 | 14 | 15 |

Model form example

16 | Note: You must migrate project to add person! 17 | 18 |
19 | {% csrf_token %} 20 | 21 | {{ form.errors }} 22 | {{ form.as_p }} 23 | 24 |
25 | 26 |
27 |
28 | 29 |
30 |

People list

31 | 32 | 33 | 34 | 35 | 36 | 37 | {% for person in people %} 38 | 39 | 40 | 41 | 42 | {% endfor %} 43 | 44 |
NameBiography
{{person.name}}{{person.biography|safe}}
45 |
46 | 47 | Form example 48 | 49 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with python 3.9 3 | # To update, run: 4 | # 5 | # pip-compile 6 | # 7 | bump2version==1.0.1 8 | # via -r requirements.in 9 | cfgv==3.3.1 10 | # via pre-commit 11 | click==8.0.3 12 | # via pip-tools 13 | distlib==0.3.4 14 | # via virtualenv 15 | filelock==3.4.2 16 | # via 17 | # tox 18 | # virtualenv 19 | identify==2.4.2 20 | # via pre-commit 21 | nodeenv==1.6.0 22 | # via pre-commit 23 | packaging==21.3 24 | # via tox 25 | pep517==0.12.0 26 | # via pip-tools 27 | pip-tools==6.4.0 28 | # via -r requirements.in 29 | platformdirs==2.4.1 30 | # via virtualenv 31 | pluggy==1.0.0 32 | # via tox 33 | pre-commit==2.16.0 34 | # via -r requirements.in 35 | py==1.11.0 36 | # via tox 37 | pyparsing==3.0.6 38 | # via packaging 39 | pyyaml==6.0 40 | # via pre-commit 41 | six==1.16.0 42 | # via 43 | # tox 44 | # virtualenv 45 | toml==0.10.2 46 | # via 47 | # pre-commit 48 | # tox 49 | tomli==2.0.0 50 | # via pep517 51 | tox==3.24.5 52 | # via -r requirements.in 53 | virtualenv==20.13.0 54 | # via 55 | # pre-commit 56 | # tox 57 | wheel==0.38.1 58 | # via 59 | # -r requirements.in 60 | # pip-tools 61 | 62 | # The following packages are considered to be unsafe in a requirements file: 63 | # pip 64 | # setuptools 65 | -------------------------------------------------------------------------------- /testproject/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from bleach.css_sanitizer import CSSSanitizer 4 | 5 | from django_bleach.forms import BleachField 6 | from testproject.constants import ( 7 | ALLOWED_ATTRIBUTES, 8 | ALLOWED_CSS_PROPERTIES, 9 | ALLOWED_PROTOCOLS, 10 | ALLOWED_STYLES, 11 | ALLOWED_TAGS, 12 | ) 13 | from testproject.models import Person 14 | 15 | 16 | class CustomBleachWidget(forms.Textarea): 17 | def __init__(self, attrs=None): 18 | default_attrs = {"rows": 15, "cols": 60} 19 | default_attrs.update(attrs or {}) 20 | super().__init__(attrs=default_attrs) 21 | 22 | 23 | class BleachForm(forms.Form): 24 | """Form for testing BleachField""" 25 | 26 | no_tags = BleachField(max_length=100, strip_tags=True, allowed_tags=[]) 27 | 28 | no_strip = BleachField( 29 | max_length=100, allowed_tags=None, allowed_attributes=None 30 | ) 31 | 32 | bleach_strip = BleachField( 33 | max_length=100, 34 | strip_comments=True, 35 | strip_tags=True, 36 | allowed_tags=ALLOWED_TAGS, 37 | ) 38 | bleach_attrs = BleachField( 39 | max_length=100, 40 | strip_tags=False, 41 | allowed_tags=ALLOWED_TAGS, 42 | allowed_protocols=ALLOWED_PROTOCOLS, 43 | allowed_attributes=ALLOWED_ATTRIBUTES, 44 | ) 45 | bleach_styles = BleachField( 46 | max_length=100, 47 | strip_tags=False, 48 | allowed_attributes=["style"], 49 | allowed_tags=ALLOWED_TAGS, 50 | allowed_styles=ALLOWED_STYLES, 51 | ) 52 | bleach_css_sanitizer = BleachField( 53 | max_length=100, 54 | strip_tags=False, 55 | allowed_attributes=["style"], 56 | allowed_tags=ALLOWED_TAGS, 57 | css_sanitizer=CSSSanitizer( 58 | allowed_css_properties=ALLOWED_CSS_PROPERTIES 59 | ), 60 | ) 61 | 62 | 63 | class PersonForm(forms.ModelForm): 64 | class Meta: 65 | model = Person 66 | fields = "__all__" 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | .hypothesis/ 50 | .pytest_cache/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | db.sqlite3 60 | django-bleach.db 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # IPython 79 | profile_default/ 80 | ipython_config.py 81 | 82 | # pyenv 83 | .python-version 84 | 85 | # celery beat schedule file 86 | celerybeat-schedule 87 | 88 | # SageMath parsed files 89 | *.sage.py 90 | 91 | # Environments 92 | .env 93 | .venv 94 | env/ 95 | venv/ 96 | ENV/ 97 | env.bak/ 98 | venv.bak/ 99 | 100 | # Spyder project settings 101 | .spyderproject 102 | .spyproject 103 | 104 | # Rope project settings 105 | .ropeproject 106 | 107 | # mkdocs documentation 108 | /site 109 | 110 | # mypy 111 | .mypy_cache/ 112 | .dmypy.json 113 | dmypy.json 114 | 115 | # Pyre type checker 116 | .pyre/ 117 | 118 | # IDE 119 | .idea 120 | 121 | # OSX 122 | .DS_Store -------------------------------------------------------------------------------- /testproject/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | 5 | SITE_ID = 1 6 | 7 | PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) 8 | 9 | PYTHON_VERSION = "%s.%s" % sys.version_info[:2] 10 | 11 | 12 | DATABASES = { 13 | "default": { 14 | "ENGINE": "django.db.backends.sqlite3", 15 | "NAME": os.path.join(PROJECT_PATH, "django-bleach.db"), 16 | } 17 | } 18 | DEFAULT_AUTO_FIELD = "django.db.models.AutoField" 19 | DATABASE_SUPPORTS_TRANSACTIONS = True 20 | 21 | INSTALLED_APPS = [ 22 | "django.contrib.auth", 23 | "django.contrib.admin", 24 | "django.contrib.contenttypes", 25 | "django.contrib.sessions", 26 | "django.contrib.sites", 27 | "django.contrib.messages", 28 | "django_bleach", 29 | "testproject", 30 | ] 31 | 32 | LANGUAGE_CODE = "en" 33 | 34 | LANGUAGES = (("en", "English"),) 35 | 36 | ROOT_URLCONF = "testproject.urls" 37 | 38 | DEBUG = True 39 | 40 | TEMPLATES = [ 41 | { 42 | "BACKEND": "django.template.backends.django.DjangoTemplates", 43 | "APP_DIRS": True, 44 | "OPTIONS": { 45 | "debug": False, 46 | "context_processors": ( 47 | "django.contrib.auth.context_processors.auth", 48 | "django.template.context_processors.debug", 49 | "django.template.context_processors.i18n", 50 | "django.template.context_processors.media", 51 | "django.template.context_processors.request", 52 | "django.template.context_processors.static", 53 | "django.template.context_processors.tz", 54 | "django.contrib.messages.context_processors.messages", 55 | ), 56 | }, 57 | "DIRS": ("templates",), 58 | }, 59 | ] 60 | 61 | USE_TZ = True 62 | SECRET_KEY = "blah" 63 | 64 | MIDDLEWARE = ( 65 | "django.contrib.sessions.middleware.SessionMiddleware", 66 | "django.contrib.auth.middleware.AuthenticationMiddleware", 67 | "django.contrib.messages.middleware.MessageMiddleware", 68 | ) 69 | 70 | # BLEACH_DEFAULT_WIDGET = 'testproject.forms.CustomBleachWidget' 71 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | # Minimum requirements for the build system to execute. 3 | requires = ["setuptools", "wheel"] # PEP 508 specifications. 4 | 5 | [tool.black] 6 | line-length = 79 7 | target-version = ["py311"] 8 | 9 | [tool.coverage.run] 10 | branch = true 11 | parallel = true 12 | omit = [ 13 | "testproject/**" 14 | ] 15 | 16 | [tool.coverage.paths] 17 | source = [ 18 | "django_bleach", 19 | ".tox/**/site-packages" 20 | ] 21 | 22 | [tool.coverage.report] 23 | show_missing = true 24 | 25 | [tool.ruff] 26 | # https://beta.ruff.rs/docs/configuration/ 27 | line-length = 79 28 | select = [ 29 | "E", # pycodestyle errors 30 | "W", # pycodestyle warnings 31 | "F", # pyflakes 32 | "I", # isort 33 | "C", # flake8-comprehensions 34 | "B", # flake8-bugbear 35 | "Q", # flake8-quotes 36 | "PLE", # pylint error 37 | "PLR", # pylint refactor 38 | "PLW", # pylint warning 39 | "UP", # pyupgrade 40 | ] 41 | 42 | exclude = [ 43 | ".eggs", 44 | ".git", 45 | ".mypy_cache", 46 | ".ruff_cache", 47 | ".env", 48 | ".venv", 49 | "**migrations/**", 50 | "docs/**", 51 | "node_modules", 52 | "requirements", 53 | "venv", 54 | "testproject", 55 | ] 56 | 57 | ignore = [ 58 | "B006", # Do not use mutable data structures for argument defaults 59 | "B011", # tests use assert False 60 | "B019", # Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks 61 | "B905", # `zip()` without an explicit `strict=` parameter 62 | "C901", # too complex functions 63 | "E402", # module level import not at top of file 64 | "E731", # do not assign a lambda expression, use a def 65 | "PLR0911", # Too many return statements 66 | "PLR0912", # Too many branches 67 | "PLR0913", # Too many arguments to function call 68 | "PLR0915", # Too many statements 69 | "PLR2004", # Magic value used in comparison, consider replacing with a constant variable 70 | ] 71 | 72 | [tool.ruff.per-file-ignores] 73 | "__init__.py" = [ 74 | "F401" # unused-import 75 | ] 76 | 77 | [tool.ruff.isort] 78 | combine-as-imports = true 79 | known-first-party = [ 80 | "django_bleach", 81 | ] 82 | extra-standard-library = ["dataclasses"] 83 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.11 3 | # by the following command: 4 | # 5 | # pip-compile 6 | # 7 | alabaster==0.7.13 8 | # via sphinx 9 | babel==2.13.1 10 | # via sphinx 11 | beautifulsoup4==4.12.2 12 | # via furo 13 | certifi==2023.11.17 14 | # via requests 15 | charset-normalizer==3.3.2 16 | # via requests 17 | colorama==0.4.6 18 | # via sphinx-autobuild 19 | docutils==0.20.1 20 | # via sphinx 21 | furo==2023.9.10 22 | # via -r requirements.in 23 | idna==3.6 24 | # via requests 25 | imagesize==1.4.1 26 | # via sphinx 27 | jinja2==3.1.2 28 | # via sphinx 29 | livereload==2.6.3 30 | # via sphinx-autobuild 31 | markupsafe==2.1.3 32 | # via 33 | # -r requirements.in 34 | # jinja2 35 | packaging==23.2 36 | # via sphinx 37 | pyenchant==3.2.2 38 | # via sphinxcontrib-spelling 39 | pygments==2.17.2 40 | # via 41 | # furo 42 | # sphinx 43 | requests==2.31.0 44 | # via sphinx 45 | six==1.16.0 46 | # via livereload 47 | snowballstemmer==2.2.0 48 | # via sphinx 49 | soupsieve==2.5 50 | # via beautifulsoup4 51 | sphinx==7.2.6 52 | # via 53 | # -r requirements.in 54 | # furo 55 | # sphinx-autobuild 56 | # sphinx-basic-ng 57 | # sphinxcontrib-applehelp 58 | # sphinxcontrib-devhelp 59 | # sphinxcontrib-htmlhelp 60 | # sphinxcontrib-qthelp 61 | # sphinxcontrib-serializinghtml 62 | # sphinxcontrib-spelling 63 | # sphinxext-opengraph 64 | sphinx-autobuild==2021.3.14 65 | # via -r requirements.in 66 | sphinx-basic-ng==1.0.0b2 67 | # via furo 68 | sphinxcontrib-applehelp==1.0.7 69 | # via sphinx 70 | sphinxcontrib-devhelp==1.0.5 71 | # via sphinx 72 | sphinxcontrib-htmlhelp==2.0.4 73 | # via sphinx 74 | sphinxcontrib-jsmath==1.0.1 75 | # via sphinx 76 | sphinxcontrib-qthelp==1.0.6 77 | # via sphinx 78 | sphinxcontrib-serializinghtml==1.1.9 79 | # via sphinx 80 | sphinxcontrib-spelling==8.0.0 81 | # via -r requirements.in 82 | sphinxext-opengraph==0.9.0 83 | # via -r requirements.in 84 | tornado==6.4 85 | # via livereload 86 | urllib3==2.2.2 87 | # via requests 88 | -------------------------------------------------------------------------------- /django_bleach/tests/test_templatetags.py: -------------------------------------------------------------------------------- 1 | from django.template import Context, Template 2 | from django.test import TestCase 3 | 4 | 5 | class TestBleachTemplates(TestCase): 6 | """Test template tags""" 7 | 8 | def test_bleaching(self): 9 | """Test that unsafe tags are sanitised""" 10 | context = Context( 11 | {"some_unsafe_content": ''}, 12 | ) 13 | template_to_render = Template( 14 | "{% load bleach_tags %}" "{{ some_unsafe_content|bleach }}" 15 | ) 16 | rendered_template = template_to_render.render(context) 17 | self.assertInHTML( 18 | '<script>alert("Hello World!")</script>', 19 | rendered_template, 20 | ) 21 | 22 | def test_bleaching_none(self): 23 | """Test that None is handled properly as an input""" 24 | context = Context({"none_value": None}) 25 | template_to_render = Template( 26 | "{% load bleach_tags %}" "{{ none_value|bleach }}" 27 | ) 28 | rendered_template = template_to_render.render(context) 29 | self.assertEqual("None", rendered_template) 30 | 31 | def test_bleaching_tags(self): 32 | """Test provided tags are kept""" 33 | context = Context( 34 | {"some_unsafe_content": ''} 35 | ) 36 | template_to_render = Template( 37 | "{% load bleach_tags %}" 38 | '{{ some_unsafe_content|bleach:"script" }}' 39 | ) 40 | rendered_template = template_to_render.render(context) 41 | self.assertInHTML( 42 | '', rendered_template 43 | ) 44 | 45 | def test_linkify(self): 46 | """Test bleach linkify""" 47 | url = "www.google.com" 48 | context = Context({"link_this": url}) 49 | template_to_render = Template( 50 | "{% load bleach_tags %}" "{{ link_this|bleach_linkify|safe }}" 51 | ) 52 | rendered_template = template_to_render.render(context) 53 | self.assertInHTML( 54 | f'{url}', 55 | rendered_template, 56 | ) 57 | 58 | def test_linkify_none(self): 59 | """Test bleach linkify with None as an input""" 60 | context = Context({"none_value": None}) 61 | template_to_render = Template( 62 | "{% load bleach_tags %}" "{{ none_value|bleach_linkify }}" 63 | ) 64 | rendered_template = template_to_render.render(context) 65 | self.assertEqual( 66 | "None", 67 | rendered_template, 68 | ) 69 | -------------------------------------------------------------------------------- /docs/settings.rst: -------------------------------------------------------------------------------- 1 | .. _settings: 2 | 3 | ======== 4 | Settings 5 | ======== 6 | 7 | Configuring ``bleach`` 8 | ====================== 9 | 10 | You can configure how ``bleach`` acts for your whole project using the 11 | following settings. These settings map directly to the ``bleach`` parameters of 12 | the same name, so see the ``bleach`` `documentation` for more information. Each 13 | of these have a sensible default set by ``bleach``, and each of these are 14 | completely optional:: 15 | 16 | # Which HTML tags are allowed 17 | BLEACH_ALLOWED_TAGS = ['p', 'b', 'i', 'u', 'em', 'strong', 'a'] 18 | 19 | # Which HTML attributes are allowed 20 | BLEACH_ALLOWED_ATTRIBUTES = ['href', 'title', 'style'] 21 | 22 | # Which CSS properties are allowed in 'style' attributes (assuming style is 23 | # an allowed attribute) 24 | BLEACH_ALLOWED_STYLES = [ 25 | 'font-family', 'font-weight', 'text-decoration', 'font-variant' 26 | ] 27 | 28 | # Which protocols (and pseudo-protocols) are allowed in 'src' attributes 29 | # (assuming src is an allowed attribute) 30 | BLEACH_ALLOWED_PROTOCOLS = [ 31 | 'http', 'https', 'data' 32 | ] 33 | 34 | # Strip unknown tags if True, replace with HTML escaped characters if False 35 | BLEACH_STRIP_TAGS = True 36 | 37 | # Strip HTML comments, or leave them in. 38 | BLEACH_STRIP_COMMENTS = False 39 | 40 | You can override each of these for individual ``BleachField`` form and model 41 | fields if you need to. Simply pass in one of the following settings you want to 42 | override as a named parameter to the ``BleachField``: 43 | 44 | * ``allowed_tags`` 45 | * ``allowed_attributes`` 46 | * ``allowed_protocols`` 47 | * ``strip_tags`` 48 | * ``strip_comments`` 49 | * ``css_sanitizer`` 50 | 51 | The following argument will be deprecated in the near future: 52 | 53 | * ``allowed_styles`` 54 | 55 | An example, where blog posts should be allowed to contain images and headings:: 56 | 57 | # in app/models.py 58 | 59 | from django import models 60 | from django_bleach.models import BleachField 61 | 62 | class Post(models.Model): 63 | 64 | title = models.CharField() 65 | content = BleachField(allowed_tags=[ 66 | 'p', 'b', 'i', 'u', 'em', 'strong', 'a', 67 | 'img', 'h3', 'h4', 'h5', 'h6']) 68 | 69 | Default form widget 70 | =================== 71 | 72 | By default, a ``BleachField`` will use a ``django.forms.Textarea`` widget. This 73 | is obviously not great for users. You can override this to use a custom widget 74 | in your project. You will probably want to use a WYSIWYG editor, or something 75 | similar:: 76 | 77 | BLEACH_DEFAULT_WIDGET = 'wysiwyg.widgets.WysiwygWidget' 78 | 79 | I use ``django-ckeditor`` in my projects, but what you use is up to you. 80 | 81 | 82 | .. _documentation: http://bleach.readthedocs.org/en/latest/index.html 83 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [master] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [master] 14 | schedule: 15 | - cron: '0 18 * * 2' 16 | 17 | jobs: 18 | analyze: 19 | name: Analyze 20 | runs-on: ubuntu-latest 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | # Override automatic language detection by changing the below list 26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 27 | language: ['python'] 28 | # Learn more... 29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v3 34 | with: 35 | # We must fetch at least the immediate parents so that if this is 36 | # a pull request then we can checkout the head. 37 | fetch-depth: 2 38 | 39 | # If this run was triggered by a pull request event, then checkout 40 | # the head of the pull request instead of the merge commit. 41 | - run: git checkout HEAD^2 42 | if: ${{ github.event_name == 'pull_request' }} 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v3 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v3 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v3 72 | -------------------------------------------------------------------------------- /django_bleach/forms.py: -------------------------------------------------------------------------------- 1 | from importlib import import_module 2 | 3 | import bleach 4 | from bleach.css_sanitizer import CSSSanitizer 5 | from django import forms 6 | from django.conf import settings 7 | from django.core.exceptions import ImproperlyConfigured 8 | from django.utils.safestring import mark_safe 9 | 10 | from django_bleach.utils import get_bleach_default_options 11 | 12 | 13 | def load_widget(path): 14 | """Load custom widget for the form field""" 15 | i = path.rfind(".") 16 | module, attr = path[:i], path[i + 1 :] 17 | try: 18 | mod = import_module(module) 19 | except (ImportError, ValueError) as e: 20 | error_message = "Error importing widget for BleachField %s: '%s'" 21 | raise ImproperlyConfigured(error_message % (path, e)) from e 22 | 23 | try: 24 | cls = getattr(mod, attr) 25 | except AttributeError as e: 26 | raise ImproperlyConfigured( 27 | f"Module '{module}' does not define a '{attr}' widget" 28 | ) from e 29 | 30 | return cls 31 | 32 | 33 | def get_default_widget(): 34 | """Get the default widget or the widget defined in settings""" 35 | default_widget = forms.Textarea 36 | if hasattr(settings, "BLEACH_DEFAULT_WIDGET"): 37 | default_widget = load_widget(settings.BLEACH_DEFAULT_WIDGET) 38 | return default_widget 39 | 40 | 41 | class BleachField(forms.CharField): 42 | """Bleach form field""" 43 | 44 | empty_values = [None, "", [], (), {}] 45 | 46 | def __init__( 47 | self, 48 | allowed_tags=None, 49 | allowed_attributes=None, 50 | allowed_styles=None, 51 | allowed_protocols=None, 52 | strip_comments=None, 53 | strip_tags=None, 54 | css_sanitizer=None, 55 | *args, 56 | **kwargs, 57 | ): 58 | self.widget = get_default_widget() 59 | 60 | super().__init__(*args, **kwargs) 61 | 62 | self.bleach_options = get_bleach_default_options() 63 | 64 | if allowed_tags is not None: 65 | self.bleach_options["tags"] = allowed_tags 66 | if allowed_attributes is not None: 67 | self.bleach_options["attributes"] = allowed_attributes 68 | if allowed_styles: 69 | css_sanitizer = CSSSanitizer(allowed_css_properties=allowed_styles) 70 | if css_sanitizer is not None: 71 | self.bleach_options["css_sanitizer"] = css_sanitizer 72 | if allowed_protocols is not None: 73 | self.bleach_options["protocols"] = allowed_protocols 74 | if strip_tags is not None: 75 | self.bleach_options["strip"] = strip_tags 76 | if strip_comments is not None: 77 | self.bleach_options["strip_comments"] = strip_comments 78 | 79 | def to_python(self, value): 80 | """ 81 | Strips any dodgy HTML tags from the input. 82 | 83 | Mark the return value as template safe. 84 | """ 85 | if value in self.empty_values: 86 | return self.empty_value 87 | return mark_safe(bleach.clean(value, **self.bleach_options)) 88 | -------------------------------------------------------------------------------- /django_bleach/models.py: -------------------------------------------------------------------------------- 1 | from bleach import clean 2 | from bleach.css_sanitizer import CSSSanitizer 3 | from django.db import models 4 | from django.utils.safestring import mark_safe 5 | 6 | from . import forms 7 | from .utils import get_bleach_default_options 8 | 9 | 10 | class BleachField(models.TextField): 11 | def __init__( 12 | self, 13 | allowed_tags=None, 14 | allowed_attributes=None, 15 | allowed_styles=None, 16 | allowed_protocols=None, 17 | strip_tags=None, 18 | strip_comments=None, 19 | css_sanitizer=None, 20 | *args, 21 | **kwargs, 22 | ): 23 | super().__init__(*args, **kwargs) 24 | 25 | self.bleach_kwargs = get_bleach_default_options() 26 | 27 | if allowed_tags: 28 | self.bleach_kwargs["tags"] = allowed_tags 29 | if allowed_attributes: 30 | self.bleach_kwargs["attributes"] = allowed_attributes 31 | if allowed_styles: 32 | css_sanitizer = CSSSanitizer(allowed_css_properties=allowed_styles) 33 | if css_sanitizer: 34 | self.bleach_kwargs["css_sanitizer"] = css_sanitizer 35 | if allowed_protocols: 36 | self.bleach_kwargs["protocols"] = allowed_protocols 37 | if strip_tags: 38 | self.bleach_kwargs["strip"] = strip_tags 39 | if strip_comments: 40 | self.bleach_kwargs["strip_comments"] = strip_comments 41 | 42 | def formfield(self, form_class=forms.BleachField, **kwargs): 43 | """Makes the field for a ModelForm""" 44 | 45 | # If field doesn't have any choices add kwargs expected by BleachField. 46 | if not self.choices: 47 | kwargs.setdefault("widget", forms.get_default_widget()) 48 | kwargs.update( 49 | { 50 | "max_length": self.max_length, 51 | "allowed_tags": self.bleach_kwargs.get("tags"), 52 | "allowed_attributes": self.bleach_kwargs.get("attributes"), 53 | "css_sanitizer": self.bleach_kwargs.get("css_sanitizer"), 54 | "allowed_protocols": self.bleach_kwargs.get("protocols"), 55 | "strip_tags": self.bleach_kwargs.get("strip"), 56 | "strip_comments": self.bleach_kwargs.get("strip_comments"), 57 | "required": not self.blank, 58 | } 59 | ) 60 | 61 | return super().formfield(form_class=form_class, **kwargs) 62 | 63 | def pre_save(self, model_instance, add): 64 | data = getattr(model_instance, self.attname) 65 | if data is None: 66 | return data 67 | clean_value = clean(data, **self.bleach_kwargs) if data else "" 68 | setattr(model_instance, self.attname, mark_safe(clean_value)) 69 | return clean_value 70 | 71 | def from_db_value(self, value, expression, connection): 72 | if value is None: 73 | return value 74 | # Values are sanitised before saving, so any value returned from the DB 75 | # is safe to render unescaped. 76 | return mark_safe(value) 77 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import codecs 3 | import os 4 | import re 5 | 6 | from setuptools import find_packages, setup 7 | 8 | try: 9 | from sphinx.setup_command import BuildDoc 10 | except ImportError: 11 | BuildDoc = None 12 | 13 | 14 | def read(*parts): 15 | file_path = os.path.join(os.path.dirname(__file__), *parts) 16 | return codecs.open(file_path, encoding="utf-8").read() 17 | 18 | 19 | def find_variable(variable, *parts): 20 | version_file = read(*parts) 21 | version_match = re.search( 22 | rf"^{variable} = ['\"]([^'\"]*)['\"]", version_file, re.M 23 | ) 24 | if version_match: 25 | return str(version_match.group(1)) 26 | raise RuntimeError("Unable to find version string.") 27 | 28 | 29 | name = "django-bleach" 30 | release = find_variable("__version__", "django_bleach", "__init__.py") 31 | version = release.rstrip(".") 32 | 33 | setup( 34 | name=name, 35 | version=version, 36 | description="Easily use bleach with Django models and templates", 37 | long_description=read("README.rst"), 38 | long_description_content_type="text/x-rst", 39 | author="Tim Heap", 40 | maintainer="Mark Walker", 41 | maintainer_email="theshow+django-bleach@gmail.com", 42 | url="https://github.com/marksweb/django-bleach", 43 | license="MIT", 44 | packages=find_packages(exclude=("testproject*",)), 45 | install_requires=[ 46 | "bleach[css]>=5,<6", 47 | "Django>=3.2", 48 | ], 49 | python_requires=">=3.8", 50 | tests_require=["bleach[css]>=5,<6", "mock", "sphinx", "tox"], 51 | cmdclass={ 52 | "build_sphinx": BuildDoc, 53 | }, 54 | command_options={ 55 | "build_sphinx": { 56 | "project": ("setup.py", name), 57 | "version": ("setup.py", version), 58 | "release": ("setup.py", release), 59 | "source_dir": ("setup.py", "docs"), 60 | "build_dir": ("setup.py", "./docs/_build"), 61 | } 62 | }, 63 | package_data={}, 64 | classifiers=[ 65 | "Environment :: Web Environment", 66 | "Intended Audience :: Developers", 67 | "License :: OSI Approved :: MIT License", 68 | "Operating System :: OS Independent", 69 | "Programming Language :: Python", 70 | "Programming Language :: Python :: 3 :: Only", 71 | "Programming Language :: Python :: 3.8", 72 | "Programming Language :: Python :: 3.9", 73 | "Programming Language :: Python :: 3.10", 74 | "Programming Language :: Python :: 3.11", 75 | "Programming Language :: Python :: 3.12", 76 | "Framework :: Django :: 3.2", 77 | "Framework :: Django :: 4.0", 78 | "Framework :: Django :: 4.1", 79 | "Framework :: Django :: 4.2", 80 | "Development Status :: 5 - Production/Stable", 81 | ], 82 | project_urls={ 83 | "Documentation": "https://django-bleach.readthedocs.io/", 84 | "Release notes": "https://github.com/marksweb/django-bleach/blob/main/CHANGELOG.md", 85 | "Issues": "https://github.com/marksweb/django-bleach/issues", 86 | "Source": "https://github.com/marksweb/django-bleach", 87 | }, 88 | ) 89 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | concurrency: 10 | group: ${{ github.head_ref || github.run_id }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | unit-tests: 15 | name: Python ${{ matrix.python-version }} 16 | runs-on: ubuntu-22.04 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | python-version: 22 | - 3.8 23 | - 3.9 24 | - '3.10' 25 | - '3.11' 26 | - '3.12' 27 | 28 | steps: 29 | - uses: actions/checkout@v3 30 | 31 | - uses: actions/setup-python@v5 32 | with: 33 | python-version: ${{ matrix.python-version }} 34 | allow-prereleases: true 35 | cache: pip 36 | cache-dependency-path: 'requirements/*.txt' 37 | 38 | - name: Install dependencies 39 | run: | 40 | python -m pip install --upgrade pip setuptools wheel 41 | python -m pip install --upgrade 'tox>=4.0.0rc3' 42 | 43 | - name: Run tox targets for ${{ matrix.python-version }} 44 | run: tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) 45 | 46 | - name: Upload coverage data 47 | uses: actions/upload-artifact@v3 48 | with: 49 | name: coverage-data 50 | path: '.coverage.*' 51 | 52 | coverage: 53 | name: Coverage 54 | runs-on: ubuntu-22.04 55 | needs: unit-tests 56 | steps: 57 | - uses: actions/checkout@v3 58 | 59 | - uses: actions/setup-python@v5 60 | with: 61 | python-version: '3.11' 62 | 63 | - name: Install dependencies 64 | run: python -m pip install --upgrade coverage[toml] 65 | 66 | - name: Download data 67 | uses: actions/download-artifact@v3 68 | with: 69 | name: coverage-data 70 | 71 | - name: Fail if coverage is <100% 72 | run: | 73 | python -m coverage combine 74 | python -m coverage html --skip-covered --skip-empty 75 | python -m coverage report --fail-under=100 76 | 77 | - name: Upload HTML report 78 | if: ${{ failure() }} 79 | uses: actions/upload-artifact@v3 80 | with: 81 | name: html-report 82 | path: htmlcov 83 | 84 | unit-tests-future-versions: 85 | # Runs for all Django/Python versions which are not yet supported 86 | runs-on: ubuntu-22.04 87 | strategy: 88 | fail-fast: false 89 | matrix: 90 | python-version: ['3.11', '3.12'] 91 | django-version: [ 92 | 'https://github.com/django/django/archive/main.tar.gz' 93 | ] 94 | 95 | steps: 96 | - uses: actions/checkout@v3 97 | - name: Set up Python ${{ matrix.python-version }} 98 | uses: actions/setup-python@v5 99 | with: 100 | allow-prereleases: true 101 | cache: pip 102 | cache-dependency-path: 'requirements/*.txt' 103 | python-version: ${{ matrix.python-version }} 104 | - name: Install dependencies 105 | run: | 106 | python -m pip install --upgrade pip setuptools wheel 107 | python -m pip install --upgrade 'tox>=4.0.0rc3' 108 | 109 | - name: Run tox targets for ${{ matrix.python-version }} 110 | run: tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) 111 | -------------------------------------------------------------------------------- /testproject/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with python 3.9 3 | # To update, run: 4 | # 5 | # pip-compile 6 | # 7 | alabaster==0.7.12 8 | # via sphinx 9 | asgiref==3.6.0 10 | # via django 11 | attrs==21.4.0 12 | # via 13 | # flake8-bugbear 14 | # flake8-eradicate 15 | babel==2.9.1 16 | # via sphinx 17 | bleach==5.0.0 18 | # via -r requirements.in 19 | certifi==2022.12.7 20 | # via requests 21 | charset-normalizer==2.0.10 22 | # via requests 23 | click==8.0.3 24 | # via pip-tools 25 | coverage==6.2 26 | # via -r requirements.in 27 | django==4.1.9 28 | # via -r requirements.in 29 | docutils==0.17.1 30 | # via 31 | # sphinx 32 | # sphinx-rtd-theme 33 | eradicate==2.0.0 34 | # via flake8-eradicate 35 | flake8==4.0.1 36 | # via 37 | # -r requirements.in 38 | # flake8-broken-line 39 | # flake8-bugbear 40 | # flake8-builtins 41 | # flake8-commas 42 | # flake8-comprehensions 43 | # flake8-eradicate 44 | # flake8-polyfill 45 | # flake8-quotes 46 | # flake8-tidy-imports 47 | # pep8-naming 48 | flake8-broken-line==0.4.0 49 | # via -r requirements.in 50 | flake8-bugbear==21.11.29 51 | # via -r requirements.in 52 | flake8-builtins==1.5.3 53 | # via -r requirements.in 54 | flake8-commas==2.1.0 55 | # via -r requirements.in 56 | flake8-comprehensions==3.7.0 57 | # via -r requirements.in 58 | flake8-eradicate==1.2.0 59 | # via -r requirements.in 60 | flake8-polyfill==1.0.2 61 | # via pep8-naming 62 | flake8-quotes==3.3.1 63 | # via -r requirements.in 64 | flake8-tidy-imports==4.5.0 65 | # via -r requirements.in 66 | idna==3.3 67 | # via requests 68 | imagesize==1.3.0 69 | # via sphinx 70 | jinja2==3.0.3 71 | # via sphinx 72 | markupsafe==2.0.1 73 | # via jinja2 74 | mccabe==0.6.1 75 | # via flake8 76 | mock==4.0.3 77 | # via -r requirements.in 78 | packaging==21.3 79 | # via sphinx 80 | pep517==0.12.0 81 | # via pip-tools 82 | pep8-naming==0.12.1 83 | # via -r requirements.in 84 | pip-tools==6.4.0 85 | # via -r requirements.in 86 | pycodestyle==2.8.0 87 | # via flake8 88 | pyflakes==2.4.0 89 | # via flake8 90 | pygments==2.15.0 91 | # via sphinx 92 | pyparsing==3.0.6 93 | # via packaging 94 | pytz==2021.3 95 | # via babel 96 | requests==2.32.0 97 | # via sphinx 98 | six==1.16.0 99 | # via bleach 100 | snowballstemmer==2.2.0 101 | # via sphinx 102 | sphinx==4.3.2 103 | # via 104 | # -r requirements.in 105 | # sphinx-rtd-theme 106 | sphinx-rtd-theme==1.0.0 107 | # via -r requirements.in 108 | sphinxcontrib-applehelp==1.0.2 109 | # via sphinx 110 | sphinxcontrib-devhelp==1.0.2 111 | # via sphinx 112 | sphinxcontrib-htmlhelp==2.0.0 113 | # via sphinx 114 | sphinxcontrib-jsmath==1.0.1 115 | # via sphinx 116 | sphinxcontrib-qthelp==1.0.3 117 | # via sphinx 118 | sphinxcontrib-serializinghtml==1.1.5 119 | # via sphinx 120 | sqlparse==0.4.4 121 | # via django 122 | tomli==2.0.0 123 | # via pep517 124 | urllib3==1.26.7 125 | # via requests 126 | webencodings==0.5.1 127 | # via bleach 128 | wheel==0.38.1 129 | # via pip-tools 130 | 131 | # The following packages are considered to be unsafe in a requirements file: 132 | # pip 133 | # setuptools 134 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | .. _usage: 2 | 3 | ===== 4 | Usage 5 | ===== 6 | 7 | .. _models: 8 | 9 | In your models 10 | ============== 11 | 12 | ``django-bleach`` provides three ways of creating bleached output. The simplest 13 | way of including user-editable HTML content that is automatically sanitised is 14 | by using the BleachField model field:: 15 | 16 | # in app/models.py 17 | 18 | from django import models 19 | from django_bleach.models import BleachField 20 | 21 | class Post(models.Model): 22 | 23 | title = models.CharField() 24 | content = BleachField() 25 | 26 | ``BleachField`` takes the following arguments, to customise the output of 27 | ``bleach``. 28 | 29 | See the bleach documentation for their use: 30 | 31 | * ``allowed_tags`` 32 | * ``allowed_attributes`` 33 | * ``allowed_protocols`` 34 | * ``strip_tags`` 35 | * ``strip_comments`` 36 | * ``css_sanitizer`` 37 | 38 | The following argument will be deprecated in the near future: 39 | 40 | * ``allowed_styles`` 41 | 42 | In addition to the bleach-specific arguments, the ``BleachField`` model field 43 | accepts all of the normal field attributes. Behind the scenes, it is a 44 | ``TextField``, and accepts all the same arguments as ``TextField``. 45 | 46 | The ``BleachField`` model field sanitises its value before it is saved to the 47 | database and is marked safe so it can be immediately rendered in a template 48 | without further intervention. 49 | 50 | In model forms, ``BleachField`` model field are represented with the 51 | ``BleachField`` form field by default. 52 | 53 | .. _forms: 54 | 55 | In your forms 56 | ============= 57 | 58 | A ``BleachField`` form field is provided. This field sanitises HTML input from 59 | the user, and presents safe, clean HTML to your Django application and the 60 | returned value is marked safe for immediate rendering. 61 | 62 | Usually you will want to use a ``BleachField`` model field, as opposed to the 63 | form field, but if you want, you can just use the form field. One possible use 64 | case for this set up is to force user input to be bleached, but allow 65 | administrators to add any content they like via another form (e.g. the admin 66 | site):: 67 | 68 | # in app/forms.py 69 | 70 | from django import forms 71 | from django_bleach.forms import BleachField 72 | 73 | from app.models import Post 74 | 75 | class PostForm(forms.ModelForm): 76 | class Meta: 77 | model = Post 78 | 79 | fields = ['title', 'content'] 80 | 81 | content = BleachField() 82 | 83 | The ``BleachField`` form field takes exactly the same arguments as the 84 | ``BleachField`` model field above. 85 | 86 | .. _templates: 87 | 88 | In your templates 89 | ================= 90 | 91 | If you have a piece of content from somewhere that needs to be printed in a 92 | template, you can use the ``bleach`` filter:: 93 | 94 | {% load bleach_tags %} 95 | 96 | {{ some_unsafe_content|bleach }} 97 | 98 | It uses the ``ALLOWED_TAGS`` setting in your application, or optionally, 99 | ``bleach`` can pass tags:: 100 | 101 | {% load bleach_tags %} 102 | 103 | {{ some_unsafe_content|bleach:"p,span" }} 104 | 105 | If you have content which doesn't contain HTML, but contains links or email 106 | addresses, you can also use the ``bleach_linkify`` filter to convert 107 | content to links:: 108 | 109 | 110 | {% load bleach_tags %} 111 | 112 | {{ some_safe_content|bleach_linkify }} 113 | 114 | -------------------------------------------------------------------------------- /django_bleach/tests/test_settings.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import patch 2 | 3 | from bleach.css_sanitizer import CSSSanitizer 4 | from django.core.exceptions import ImproperlyConfigured 5 | from django.forms import Textarea 6 | from django.test import TestCase, override_settings 7 | 8 | from django_bleach.forms import get_default_widget 9 | from django_bleach.utils import get_bleach_default_options 10 | from testproject.constants import ( 11 | ALLOWED_ATTRIBUTES, 12 | ALLOWED_CSS_PROPERTIES, 13 | ALLOWED_PROTOCOLS, 14 | ALLOWED_TAGS, 15 | ) 16 | from testproject.forms import CustomBleachWidget 17 | 18 | 19 | class TestBleachOptions(TestCase): 20 | @patch( 21 | "django_bleach.utils.settings", 22 | BLEACH_ALLOWED_ATTRIBUTES=ALLOWED_ATTRIBUTES, 23 | ) 24 | def test_custom_attrs(self, settings): 25 | bleach_args = get_bleach_default_options() 26 | self.assertEqual(bleach_args["attributes"], ALLOWED_ATTRIBUTES) 27 | 28 | @patch( 29 | "django_bleach.utils.settings", 30 | BLEACH_ALLOWED_PROTOCOLS=ALLOWED_PROTOCOLS, 31 | ) 32 | def test_custom_proto(self, settings): 33 | bleach_args = get_bleach_default_options() 34 | self.assertEqual(bleach_args["protocols"], ALLOWED_PROTOCOLS) 35 | 36 | @patch( 37 | "django_bleach.utils.settings", 38 | BLEACH_ALLOWED_STYLES=ALLOWED_CSS_PROPERTIES, 39 | ) 40 | def test_custom_styles(self, settings): 41 | bleach_args = get_bleach_default_options() 42 | self.assertIsInstance(bleach_args["css_sanitizer"], CSSSanitizer) 43 | self.assertEqual( 44 | bleach_args["css_sanitizer"].allowed_css_properties, 45 | ALLOWED_CSS_PROPERTIES, 46 | ) 47 | 48 | @patch("django_bleach.utils.settings", BLEACH_ALLOWED_TAGS=ALLOWED_TAGS) 49 | def test_custom_tags(self, settings): 50 | bleach_args = get_bleach_default_options() 51 | self.assertEqual(bleach_args["tags"], ALLOWED_TAGS) 52 | 53 | @patch("django_bleach.utils.settings", BLEACH_STRIP_TAGS=True) 54 | def test_strip_tags(self, settings): 55 | bleach_args = get_bleach_default_options() 56 | self.assertEqual(bleach_args["strip"], True) 57 | 58 | @patch("django_bleach.utils.settings", BLEACH_STRIP_COMMENTS=True) 59 | def test_strip_comments(self, settings): 60 | bleach_args = get_bleach_default_options() 61 | self.assertEqual(bleach_args["strip_comments"], True) 62 | 63 | 64 | class TestDefaultWidget(TestCase): 65 | """Test form field widgets""" 66 | 67 | @override_settings(BLEACH_DEFAULT_WIDGET="django.forms.widgets.Textarea") 68 | def test_default_widget(self): 69 | self.assertEqual(get_default_widget(), Textarea) 70 | 71 | @patch( 72 | "django_bleach.forms.settings", 73 | BLEACH_DEFAULT_WIDGET="testproject.forms.CustomBleachWidget", 74 | ) 75 | def test_custom_widget(self, settings): 76 | self.assertEqual(get_default_widget(), CustomBleachWidget) 77 | 78 | @patch( 79 | "django_bleach.forms.settings", 80 | BLEACH_DEFAULT_WIDGET="testproject.forms.NoneExistentWidget", 81 | ) 82 | def test_attribute_err(self, settings): 83 | with self.assertRaises(ImproperlyConfigured): 84 | get_default_widget() 85 | 86 | @patch( 87 | "django_bleach.forms.settings", 88 | BLEACH_DEFAULT_WIDGET="testproject.forms2.CustomBleachWidget", 89 | ) 90 | def test_import_err(self, settings): 91 | with self.assertRaises(ImproperlyConfigured): 92 | get_default_widget() 93 | -------------------------------------------------------------------------------- /django_bleach/tests/test_modelformfield.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.test import TestCase, override_settings 3 | 4 | from django_bleach import forms as bleach_forms 5 | from testproject.forms import CustomBleachWidget 6 | from testproject.models import Person 7 | 8 | from .test_models import BleachContent 9 | 10 | 11 | class BleachContentModelForm(forms.ModelForm): 12 | class Meta: 13 | model = BleachContent 14 | fields = "__all__" 15 | 16 | 17 | class TestModelFormField(TestCase): 18 | def setUp(self): 19 | model_form = BleachContentModelForm() 20 | self.form_field = model_form.fields["content"] 21 | self.choice_form_field = model_form.fields["choice"] 22 | self.blank_field_form_field = model_form.fields["blank_field"] 23 | self.model_field = BleachContent()._meta.get_field("content") 24 | 25 | def test_formfield_type(self): 26 | """ 27 | Check content's form field is instance of BleachField 28 | """ 29 | self.assertIsInstance(self.form_field, bleach_forms.BleachField) 30 | 31 | def test_default_widget_type(self): 32 | """ 33 | Widget class is Textarea when BLEACH_DEFAULT_WIDGET is not set. 34 | """ 35 | form = forms.modelform_factory(Person, fields="__all__")() 36 | self.assertIsInstance( 37 | form.fields["biography"].widget, 38 | forms.Textarea, 39 | ) 40 | 41 | @override_settings( 42 | BLEACH_DEFAULT_WIDGET="testproject.forms.CustomBleachWidget" 43 | ) 44 | def test_custom_widget_type(self): 45 | """ 46 | Widget class matches BLEACH_DEFAULT_WIDGET setting. 47 | """ 48 | form = forms.modelform_factory(Person, fields="__all__")() 49 | self.assertIsInstance( 50 | form.fields["biography"].widget, CustomBleachWidget 51 | ) 52 | 53 | @override_settings( 54 | BLEACH_DEFAULT_WIDGET="testproject.forms.CustomBleachWidget" 55 | ) 56 | def test_widget_override(self): 57 | """ 58 | Widget class matches widget class specified in overrides. 59 | """ 60 | form = forms.modelform_factory( 61 | Person, 62 | fields="__all__", 63 | widgets={"biography": CustomBleachWidget}, 64 | )() 65 | self.assertIsInstance( 66 | form.fields["biography"].widget, CustomBleachWidget 67 | ) 68 | 69 | def test_same_allowed_args(self): 70 | """ 71 | Check model and form's allowed arguments (tags, attributes, ...) 72 | are the same 73 | """ 74 | form_allowed_args: dict = self.form_field.bleach_options 75 | model_allowed_args: dict = self.model_field.bleach_kwargs 76 | 77 | self.assertEqual(model_allowed_args, form_allowed_args) 78 | 79 | def test_with_choices(self): 80 | """ 81 | Check if choices specified, use TextField's default widget (Select). 82 | """ 83 | form_field_widget = self.choice_form_field.widget.__class__ 84 | self.assertEqual(form_field_widget, forms.widgets.Select) 85 | 86 | def test_optional_field(self): 87 | """ 88 | Check for the required flag on fields with `blank=True` 89 | """ 90 | self.assertEqual(self.blank_field_form_field.required, False) 91 | 92 | def test_required_field(self): 93 | """ 94 | Check for the required flag on fields 95 | """ 96 | self.assertEqual(self.form_field.required, True) 97 | 98 | 99 | class CustomBleachedFormField(bleach_forms.BleachField): ... 100 | 101 | 102 | class OverriddenBleachContentModelForm(forms.ModelForm): 103 | class Meta: 104 | model = BleachContent 105 | fields = "__all__" 106 | field_classes = { 107 | "content": CustomBleachedFormField, 108 | } 109 | 110 | 111 | class TestModelFormFieldOverrides(TestCase): 112 | def setUp(self): 113 | model_form = OverriddenBleachContentModelForm() 114 | self.form_field = model_form.fields["content"] 115 | 116 | def test_formfield_type(self): 117 | """ 118 | Check content's form field is instance of CustomBleachedFormField. 119 | """ 120 | self.assertIsInstance(self.form_field, CustomBleachedFormField) 121 | -------------------------------------------------------------------------------- /django_bleach/tests/test_models.py: -------------------------------------------------------------------------------- 1 | from bleach.css_sanitizer import CSSSanitizer 2 | from django.db import models 3 | from django.test import TestCase 4 | from django.utils.safestring import SafeString 5 | 6 | from django_bleach.models import BleachField 7 | from testproject.constants import ( 8 | ALLOWED_ATTRIBUTES, 9 | ALLOWED_CSS_PROPERTIES, 10 | ALLOWED_PROTOCOLS, 11 | ALLOWED_TAGS, 12 | ) 13 | 14 | 15 | class BleachContent(models.Model): 16 | """Bleach test model""" 17 | 18 | CHOICES = (("f", "first choice"), ("s", "second choice")) 19 | content = BleachField( 20 | allowed_attributes=ALLOWED_ATTRIBUTES, 21 | allowed_protocols=ALLOWED_PROTOCOLS, 22 | css_sanitizer=CSSSanitizer( 23 | allowed_css_properties=ALLOWED_CSS_PROPERTIES 24 | ), 25 | allowed_tags=ALLOWED_TAGS, 26 | allowed_styles=ALLOWED_CSS_PROPERTIES, 27 | strip_comments=True, 28 | strip_tags=True, 29 | ) 30 | choice = BleachField(choices=CHOICES) 31 | blank_field = BleachField(blank=True) 32 | null_field = BleachField(blank=True, null=True) 33 | 34 | 35 | class TestBleachModelField(TestCase): 36 | """Test model field""" 37 | 38 | def test_bleaching(self): 39 | """Test values are bleached""" 40 | test_data = { 41 | "no_tags": "

Heading

", 42 | "no_strip": "

Heading

", 43 | "bleach_strip": """""", 44 | "bleach_attrs": 'google.com', 46 | "bleach_css_sanitizer": '
  • item
  • ', 47 | "bleach_comment": "", 48 | } 49 | expected_values = { 50 | "no_tags": "Heading", 51 | "no_strip": "Heading", 52 | "bleach_strip": """alert("Hello World")""", 53 | "bleach_attrs": "google.com", 54 | "bleach_css_sanitizer": '
  • item
  • ', 55 | "bleach_comment": "", 56 | } 57 | 58 | for key, value in test_data.items(): 59 | obj = BleachContent.objects.create(content=value) 60 | self.assertEqual(obj.content, expected_values[key]) 61 | 62 | def test_retrieved_values_are_template_safe(self): 63 | obj = BleachContent.objects.create(content="some content") 64 | obj.refresh_from_db() 65 | self.assertIsInstance(obj.content, SafeString) 66 | obj = BleachContent.objects.create(content="") 67 | obj.refresh_from_db() 68 | self.assertIsInstance(obj.content, SafeString) 69 | 70 | def test_saved_values_are_template_safe(self): 71 | obj = BleachContent(content="some content") 72 | obj.save() 73 | self.assertIsInstance(obj.content, SafeString) 74 | obj = BleachContent(content="") 75 | obj.save() 76 | self.assertIsInstance(obj.content, SafeString) 77 | 78 | def test_saved_none_values_are_none(self): 79 | obj = BleachContent(null_field=None) 80 | obj.save() 81 | self.assertIsNone(obj.null_field) 82 | 83 | 84 | class BleachNullableContent(models.Model): 85 | """Bleach test model""" 86 | 87 | content = BleachField( 88 | allowed_attributes=ALLOWED_ATTRIBUTES, 89 | allowed_protocols=ALLOWED_PROTOCOLS, 90 | css_sanitizer=CSSSanitizer( 91 | allowed_css_properties=ALLOWED_CSS_PROPERTIES 92 | ), 93 | allowed_tags=ALLOWED_TAGS, 94 | strip_comments=True, 95 | strip_tags=True, 96 | blank=True, 97 | null=True, 98 | ) 99 | 100 | 101 | class TestBleachNullableModelField(TestCase): 102 | """Test model field""" 103 | 104 | def test_bleaching(self): 105 | """Test values are bleached""" 106 | test_data = { 107 | "none": None, 108 | "empty": "", 109 | "whitespaces": " ", 110 | "linebreak": "\n", 111 | } 112 | expected_values = { 113 | "none": None, 114 | "empty": "", 115 | "whitespaces": " ", 116 | "linebreak": "\n", 117 | } 118 | 119 | for key, value in test_data.items(): 120 | obj = BleachNullableContent.objects.create(content=value) 121 | self.assertEqual(obj.content, expected_values[key]) 122 | -------------------------------------------------------------------------------- /requirements/compile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import annotations 3 | 4 | import os 5 | import subprocess 6 | import sys 7 | from pathlib import Path 8 | 9 | if __name__ == "__main__": 10 | os.chdir(Path(__file__).parent) 11 | os.environ["CUSTOM_COMPILE_COMMAND"] = "requirements/compile.py" 12 | os.environ["PIP_REQUIRE_VIRTUALENV"] = "0" 13 | common_args = [ 14 | "-m", 15 | "piptools", 16 | "compile", 17 | "--generate-hashes", 18 | "--allow-unsafe", 19 | ] + sys.argv[1:] 20 | # mysqlclient requirements found on each version's "Databases" documentation page: 21 | # https://docs.djangoproject.com/en/3.0/ref/databases/#mysql-db-api-drivers 22 | subprocess.run( 23 | [ 24 | "python3.8", 25 | *common_args, 26 | "-P", 27 | "Django>=3.2a1,<3.3", 28 | "-o", 29 | "py38-django32.txt", 30 | ], 31 | check=True, 32 | capture_output=True, 33 | ) 34 | subprocess.run( 35 | [ 36 | "python3.8", 37 | *common_args, 38 | "-P", 39 | "Django>=4.0a1,<4.1", 40 | "-o", 41 | "py38-django40.txt", 42 | ], 43 | check=True, 44 | capture_output=True, 45 | ) 46 | subprocess.run( 47 | [ 48 | "python3.8", 49 | *common_args, 50 | "-P", 51 | "Django>=4.1a1,<4.2", 52 | "-o", 53 | "py38-django41.txt", 54 | ], 55 | check=True, 56 | capture_output=True, 57 | ) 58 | subprocess.run( 59 | [ 60 | "python3.8", 61 | *common_args, 62 | "-P", 63 | "Django>=4.2a1,<5.0", 64 | "-o", 65 | "py38-django42.txt", 66 | ], 67 | check=True, 68 | capture_output=True, 69 | ) 70 | subprocess.run( 71 | [ 72 | "python3.9", 73 | *common_args, 74 | "-P", 75 | "Django>=3.2a1,<3.3", 76 | "-o", 77 | "py39-django32.txt", 78 | ], 79 | check=True, 80 | capture_output=True, 81 | ) 82 | subprocess.run( 83 | [ 84 | "python3.9", 85 | *common_args, 86 | "-P", 87 | "Django>=4.0a1,<4.1", 88 | "-o", 89 | "py39-django40.txt", 90 | ], 91 | check=True, 92 | capture_output=True, 93 | ) 94 | subprocess.run( 95 | [ 96 | "python3.9", 97 | *common_args, 98 | "-P", 99 | "Django>=4.1a1,<4.2", 100 | "-o", 101 | "py39-django41.txt", 102 | ], 103 | check=True, 104 | capture_output=True, 105 | ) 106 | subprocess.run( 107 | [ 108 | "python3.9", 109 | *common_args, 110 | "-P", 111 | "Django>=4.2a1,<5.0", 112 | "-o", 113 | "py39-django42.txt", 114 | ], 115 | check=True, 116 | capture_output=True, 117 | ) 118 | subprocess.run( 119 | [ 120 | "python3.10", 121 | *common_args, 122 | "-P", 123 | "Django>=3.2a1,<3.3", 124 | "-o", 125 | "py310-django32.txt", 126 | ], 127 | check=True, 128 | capture_output=True, 129 | ) 130 | subprocess.run( 131 | [ 132 | "python3.10", 133 | *common_args, 134 | "-P", 135 | "Django>=4.0a1,<4.1", 136 | "-o", 137 | "py310-django40.txt", 138 | ], 139 | check=True, 140 | capture_output=True, 141 | ) 142 | subprocess.run( 143 | [ 144 | "python3.10", 145 | *common_args, 146 | "-P", 147 | "Django>=4.1a1,<4.2", 148 | "-o", 149 | "py310-django41.txt", 150 | ], 151 | check=True, 152 | capture_output=True, 153 | ) 154 | subprocess.run( 155 | [ 156 | "python3.10", 157 | *common_args, 158 | "-P", 159 | "Django>=4.2a1,<5.0", 160 | "-o", 161 | "py310-django42.txt", 162 | ], 163 | check=True, 164 | capture_output=True, 165 | ) 166 | subprocess.run( 167 | [ 168 | "python3.11", 169 | *common_args, 170 | "-P", 171 | "Django>=4.1a1,<4.2", 172 | "-o", 173 | "py311-django41.txt", 174 | ], 175 | check=True, 176 | capture_output=True, 177 | ) 178 | subprocess.run( 179 | [ 180 | "python3.11", 181 | *common_args, 182 | "-P", 183 | "Django>=4.2a1,<5.0", 184 | "-o", 185 | "py311-django42.txt", 186 | ], 187 | check=True, 188 | capture_output=True, 189 | ) 190 | subprocess.run( 191 | [ 192 | "python3.12", 193 | *common_args, 194 | "-P", 195 | "Django>=4.2a1,<5.0", 196 | "-o", 197 | "py312-django42.txt", 198 | ], 199 | check=True, 200 | capture_output=True, 201 | ) 202 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | ========== 3 | 4 | This document records all notable changes to [django-bleach](https://github.com/marksweb/django-bleach). 5 | This project adheres to [Semantic Versioning](https://semver.org/). 6 | 7 | [unreleased](https://github.com/marksweb/django-bleach/compare/3.1.0...master) changes 8 | ------------------------------------------------------------------------------------- 9 | 10 | Version 3.1.0 11 | ============= 12 | **05-08-2023** 13 | 14 | * Added support for django 4.2 15 | * Added support for python 3.12 16 | * Revamp package for easier maintenance 17 | 18 | 19 | Version 3.0.1 20 | ============= 21 | **11-10-2022** 22 | 23 | * Added support for django 4.1 24 | 25 | Version 3.0.0 26 | ============= 27 | **19-05-2022** 28 | 29 | * Bleach dependency is now at ``>=5,<6`` [#55](https://github.com/marksweb/django-bleach/pull/55) (Thanks [Laityned](https://github.com/Laityned)) 30 | * Deprecate bleach's `allowed_styles` kwarg 31 | * Added support for bleach's `css_sanitizer` kwarg 32 | * Add isort and codespell to ci 33 | * Dropped support for python 3.6 and 3.7 as well as django 3.0 and 3.1 34 | * Renamed default branch from `master` to `main`. If you have the project locally, you can update using: 35 | 36 | ```shell 37 | git branch -m master main 38 | git fetch origin 39 | git branch -u origin/main main 40 | git remote set-head origin -a 41 | ``` 42 | 43 | Version 2.0.0 44 | ============= 45 | ###### 08-04-2022 46 | 47 | * cap bleach version at ``<5`` [#51](https://github.com/marksweb/django-bleach/issues/51) 48 | * drop support for python 3.6 49 | * drop support for django 3.0 and 3.1 50 | * added support for django 4 51 | 52 | Version 1.0.0 53 | ============= 54 | ###### 13-11-2021 55 | Going to 1.0 is long overdue, especially considering SemVer. 56 | * automated pypi releases via github actions 57 | * pre-commit hooks 58 | * python 3.10 support 59 | * docs syntax highlighting [#38](https://github.com/marksweb/django-bleach/pull/38) 60 | 61 | Version 0.9.0 62 | ============= 63 | ###### 28-09-2021 64 | * Drop support for django <2.2 65 | * Added support for django 4.0 66 | 67 | Version 0.8.0 68 | ============= 69 | ###### 18-09-2021 70 | Thank you to [Mark Gregson](https://github.com/MrkGrgsn) for providing the changes in this release! 71 | * Fix for [#28](https://github.com/marksweb/django-bleach/issues/28): Return ``empty_value`` for any empty input value 72 | * Fix for [#27](https://github.com/marksweb/django-bleach/issues/27): Mark cleaned data as template safe 73 | * Fix for [#25](https://github.com/marksweb/django-bleach/issues/25): Respect the ``form_class`` argument 74 | * Fix custom widget tests [#34](https://github.com/marksweb/django-bleach/pulls/34) 75 | 76 | Version 0.7.2 77 | ============= 78 | ###### 27-07-2021 79 | * Fix for [#23](https://github.com/marksweb/django-bleach/issues/23): `kwargs` being lost in the default form field. 80 | 81 | Version 0.7.1 82 | ============= 83 | ###### 23-07-2021 84 | * Fix for [#21](https://github.com/marksweb/django-bleach/issues/21): default form field not respecting required fields. 85 | 86 | Version 0.7.0 87 | ============= 88 | ###### 09-07-2021 89 | * Default form field set to `forms.BleachField` for `models.BleachField` (Thanks [Alirezaja1384](https://github.com/Alirezaja1384)) 90 | * Introduced testing against Python 3.9 91 | 92 | Version 0.6.1 93 | ============= 94 | ###### 07-11-2019 95 | * Handle `None` as an input value of template tags (Thanks [pegler](https://github.com/pegler)) 96 | 97 | Version 0.6.0 98 | ============= 99 | ###### 18-10-2019 100 | * Introduced testing against Python 3.8 101 | * Drop support for Django <1.11 102 | * Test coverage at 100% 103 | 104 | Version 0.5.3 105 | ============= 106 | ###### 16-04-2019 107 | * Fix for `BleachField` set to allow `blank` or `null`. (Thanks [denisroldan](https://github.com/denisroldan)) 108 | 109 | Version 0.5.2 110 | ============= 111 | ###### 15-03-2019 112 | * Fix for `BleachField` receiving a `None` value. (Thanks [MrkGrgsn](https://github.com/MrkGrgsn)) 113 | 114 | Version 0.5.1 115 | ============= 116 | ###### 12-02-2019 117 | * 100% coverage achieved 118 | * Changelog updated with `0.5.0` changes. (Thanks [dyve](https://github.com/dyve)) 119 | 120 | Version 0.5.0 121 | ============= 122 | ###### 02-02-2019 123 | * Added support for bleach's `allowed_protocols` kwarg. (Thanks [blag](https://github.com/blag)) 124 | * Bleach dependency is now `>=1.5.0` 125 | 126 | Version 0.4.1 127 | ============= 128 | ###### 24-01-2019 129 | * Option to pass *allowed tags* to the `bleach` template filter added by [Rafał Selewońko](https://github.com/seler). 130 | * Moved project to Github. 131 | 132 | Version 0.4.0 133 | ============= 134 | ###### 18-12-2018 135 | * Added support for django>=1.9 136 | * Ensure that the `model_instance` field gets updated with the clean value 137 | 138 | Version 0.3.0 139 | ============= 140 | ###### 20-09-2014 141 | * The `BleachField` model field now does its own sanitisation, 142 | and does *not* specify a default form field or widget. 143 | Developers are expected to provide their own widget as needed. 144 | 145 | Version 0.2.1 146 | ============= 147 | ###### 02-09-2014 148 | * Make the package python3 compatible. 149 | 150 | Version 0.2.0 151 | ============= 152 | ###### 14-02-2014 153 | * Add `bleach_linkify` template filter from [whitehat2k13](https://bitbucket.org/%7B66836148-7eee-4894-acec-e073b30499ee%7D/) 154 | 155 | Version 0.1.5 156 | ============= 157 | ###### 25-09-2013 158 | 159 | Version 0.1.4 160 | ============= 161 | ###### 03-06-2013 162 | 163 | Version 0.1.3 164 | ============= 165 | ###### 22-08-2012 166 | * Add missing `templatetags` package, by using `find_packages()` 167 | * Correct templatetag name: ``bleach.py`` -> ``bleach_tags.py`` 168 | 169 | Version 0.1.2 170 | ============= 171 | ###### 13-08-2012 172 | * Fix south migration bug 173 | 174 | Version 0.1.1 175 | ============= 176 | ###### 13-08-2012 177 | * add south_triple_field for south integration 178 | * clean up files to meet pep8 compliance 179 | 180 | Version 0.1.0 181 | ============= 182 | ###### 13-08-2012 183 | * Initial release 184 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-bleach.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-bleach.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/django-bleach" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-bleach" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /requirements/py311-django41.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.11 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | webencodings==0.5.1 \ 86 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 87 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 88 | # via 89 | # bleach 90 | # tinycss2 91 | -------------------------------------------------------------------------------- /requirements/py311-django42.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.11 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | webencodings==0.5.1 \ 86 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 87 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 88 | # via 89 | # bleach 90 | # tinycss2 91 | -------------------------------------------------------------------------------- /requirements/py312-django42.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.12 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | webencodings==0.5.1 \ 86 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 87 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 88 | # via 89 | # bleach 90 | # tinycss2 91 | -------------------------------------------------------------------------------- /requirements/py38-django32.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.8 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py38-django40.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.8 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py38-django41.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.8 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py38-django42.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.8 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py39-django32.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.9 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py39-django40.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.9 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py39-django41.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.9 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py39-django42.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.9 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py310-django32.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.10 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py310-django40.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.10 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py310-django41.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.10 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /requirements/py310-django42.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.10 3 | # by the following command: 4 | # 5 | # requirements/compile.py 6 | # 7 | bleach==5.0.1 \ 8 | --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ 9 | --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c 10 | # via -r requirements.in 11 | coverage[toml]==7.2.7 \ 12 | --hash=sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f \ 13 | --hash=sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2 \ 14 | --hash=sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a \ 15 | --hash=sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a \ 16 | --hash=sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01 \ 17 | --hash=sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6 \ 18 | --hash=sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7 \ 19 | --hash=sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f \ 20 | --hash=sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02 \ 21 | --hash=sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c \ 22 | --hash=sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063 \ 23 | --hash=sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a \ 24 | --hash=sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5 \ 25 | --hash=sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959 \ 26 | --hash=sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97 \ 27 | --hash=sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6 \ 28 | --hash=sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f \ 29 | --hash=sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9 \ 30 | --hash=sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5 \ 31 | --hash=sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f \ 32 | --hash=sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562 \ 33 | --hash=sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe \ 34 | --hash=sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9 \ 35 | --hash=sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f \ 36 | --hash=sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb \ 37 | --hash=sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb \ 38 | --hash=sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1 \ 39 | --hash=sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb \ 40 | --hash=sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250 \ 41 | --hash=sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e \ 42 | --hash=sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511 \ 43 | --hash=sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5 \ 44 | --hash=sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59 \ 45 | --hash=sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2 \ 46 | --hash=sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d \ 47 | --hash=sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3 \ 48 | --hash=sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4 \ 49 | --hash=sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de \ 50 | --hash=sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9 \ 51 | --hash=sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833 \ 52 | --hash=sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0 \ 53 | --hash=sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9 \ 54 | --hash=sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d \ 55 | --hash=sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050 \ 56 | --hash=sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d \ 57 | --hash=sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6 \ 58 | --hash=sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353 \ 59 | --hash=sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb \ 60 | --hash=sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e \ 61 | --hash=sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8 \ 62 | --hash=sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495 \ 63 | --hash=sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2 \ 64 | --hash=sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd \ 65 | --hash=sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27 \ 66 | --hash=sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1 \ 67 | --hash=sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818 \ 68 | --hash=sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4 \ 69 | --hash=sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e \ 70 | --hash=sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850 \ 71 | --hash=sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3 72 | # via -r requirements.in 73 | mock==5.1.0 \ 74 | --hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \ 75 | --hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d 76 | # via -r requirements.in 77 | six==1.16.0 \ 78 | --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ 79 | --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 80 | # via bleach 81 | tinycss2==1.2.1 \ 82 | --hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \ 83 | --hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627 84 | # via -r requirements.in 85 | tomli==2.0.1 \ 86 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 87 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 88 | # via coverage 89 | webencodings==0.5.1 \ 90 | --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ 91 | --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 92 | # via 93 | # bleach 94 | # tinycss2 95 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | django-bleach - Bleach and sanitise user HTML 2 | ============================================= 3 | 4 | .. image:: https://readthedocs.org/projects/django-bleach/badge/?version=latest 5 | :target: https://django-bleach.readthedocs.io/en/latest/?badge=latest 6 | :alt: Documentation Status 7 | 8 | .. image:: http://img.shields.io/pypi/v/django-bleach.svg?style=flat-square 9 | :target: https://pypi.python.org/pypi/django-bleach/ 10 | :alt: Latest Version 11 | 12 | .. image:: http://img.shields.io/pypi/l/django-bleach.svg?style=flat-square 13 | :target: https://pypi.python.org/pypi/django-bleach/ 14 | :alt: License 15 | 16 | .. image:: http://img.shields.io/pypi/dm/django-bleach.svg?style=flat-square 17 | :target: https://pypi.python.org/pypi/django-bleach/ 18 | :alt: Downloads 19 | 20 | | 21 | 22 | .. image:: https://codecov.io/gh/marksweb/django-bleach/branch/master/graph/badge.svg 23 | :target: https://codecov.io/gh/marksweb/django-bleach 24 | 25 | .. image:: https://api.codacy.com/project/badge/Grade/c34f923ab0a84a6f96728866c749d511 26 | :alt: Codacy Badge 27 | :target: https://app.codacy.com/app/marksweb/django-bleach?utm_source=github.com&utm_medium=referral&utm_content=marksweb/django-bleach&utm_campaign=Badge_Grade_Dashboard 28 | 29 | .. image:: https://results.pre-commit.ci/badge/github/marksweb/django-bleach/master.svg 30 | :target: https://results.pre-commit.ci/latest/github/marksweb/django-bleach/master 31 | :alt: pre-commit.ci status 32 | 33 | .. image:: https://img.shields.io/lgtm/grade/python/g/marksweb/django-bleach.svg?logo=lgtm&logoWidth=18 34 | :target: https://lgtm.com/projects/g/marksweb/django-bleach/context:python 35 | :alt: Language grade: Python 36 | 37 | .. image:: https://img.shields.io/lgtm/alerts/g/marksweb/django-bleach.svg?logo=lgtm&logoWidth=18 38 | :target: https://lgtm.com/projects/g/marksweb/django-bleach/alerts/ 39 | :alt: Total alerts 40 | 41 | | 42 | 43 | Archived 44 | ======== 45 | 46 | This project has been archived because bleach is no longer supported. The supported means of sanitizing input data is the nh3 library and there's a similar package to this available: 47 | 48 | https://github.com/marksweb/django-nh3 49 | 50 | ------------ 51 | 52 | Bleach_ is a Python module that takes any HTML input, and returns 53 | valid, sanitised HTML that contains only an allowed subset of HTML tags, 54 | attributes and styles. ``django-bleach`` is a Django app that makes using 55 | ``bleach`` extremely easy. 56 | 57 | `Read the documentation here`_. 58 | 59 | Setup 60 | ----- 61 | 62 | 1. Install ``django-bleach`` via ``pip``:: 63 | 64 | pip install django-bleach 65 | 66 | 2. Add ``django-bleach`` to your ``INSTALLED_APPS``: 67 | 68 | .. code-block:: python 69 | 70 | INSTALLED_APPS = [ 71 | # ... 72 | 'django_bleach', 73 | # ... 74 | ] 75 | 76 | 3. Select some sensible defaults for the allowed tags, attributes and styles; 77 | and the behaviour when unknown tags are encountered. Each of these are 78 | optional, and default to using the ``bleach`` defaults. See the 79 | `bleach documentation`_: 80 | 81 | .. code-block:: python 82 | 83 | # Which HTML tags are allowed 84 | BLEACH_ALLOWED_TAGS = ['p', 'b', 'i', 'u', 'em', 'strong', 'a'] 85 | 86 | # Which HTML attributes are allowed 87 | BLEACH_ALLOWED_ATTRIBUTES = ['href', 'title', 'style'] 88 | 89 | # Which CSS properties are allowed in 'style' attributes (assuming 90 | # style is an allowed attribute) 91 | BLEACH_ALLOWED_STYLES = [ 92 | 'font-family', 'font-weight', 'text-decoration', 'font-variant'] 93 | 94 | # Strip unknown tags if True, replace with HTML escaped characters if 95 | # False 96 | BLEACH_STRIP_TAGS = True 97 | 98 | # Strip comments, or leave them in. 99 | BLEACH_STRIP_COMMENTS = False 100 | 101 | 4. Select the default widget for bleach fields. This defaults to 102 | ``django.forms.Textarea``, but you will probably want to replace it with a 103 | WYSIWYG editor, or something similar: 104 | 105 | .. code-block:: python 106 | 107 | # Use the CKEditorWidget for bleached HTML fields 108 | BLEACH_DEFAULT_WIDGET = 'wysiwyg.widgets.WysiwygWidget' 109 | 110 | I use `django-ckeditor`_ in my projects, but what you use is up to you. 111 | 112 | Usage 113 | ----- 114 | 115 | In your models 116 | ************** 117 | 118 | ``django-bleach`` provides three ways of creating bleached output. The simplest 119 | way of including user-editable HTML content that is automatically sanitised is 120 | by using the ``BleachField`` model field: 121 | 122 | .. code-block:: python 123 | 124 | # in app/models.py 125 | 126 | from django import models 127 | from django_bleach.models import BleachField 128 | 129 | class Post(models.Model): 130 | 131 | title = models.CharField() 132 | content = BleachField() 133 | 134 | # ... 135 | 136 | ``BleachField`` takes the following arguments, to customise the output of 137 | ``bleach``. See the `bleach documentation`_ for their use: 138 | 139 | * ``allowed_tags`` 140 | * ``allowed_attributes`` 141 | * ``strip_tags`` 142 | * ``strip_comments`` 143 | * ``css_sanitizer`` 144 | 145 | The following argument will be deprecated in the near future: 146 | 147 | * ``allowed_styles`` 148 | 149 | In addition to the ``bleach``-specific arguments, the ``BleachField`` model field 150 | accepts all of the normal field attributes. Behind the scenes, it is a 151 | ``TextField``, and accepts all the same arguments as the default ``TextField`` does. 152 | 153 | The ``BleachField`` model field sanitises its value before it is saved to the 154 | database and is marked safe so it can be immediately rendered in a template 155 | without further intervention. 156 | 157 | In model forms, ``BleachField`` model field are represented with the 158 | ``BleachField`` form field by default. 159 | 160 | In your forms 161 | ************* 162 | 163 | A ``BleachField`` form field is provided. This field sanitises HTML input from 164 | the user, and presents safe, clean HTML to your Django application and the 165 | returned value is marked safe for immediate rendering. 166 | 167 | In your templates 168 | ***************** 169 | 170 | If you have a piece of content from somewhere that needs to be printed in a 171 | template, you can use the ``bleach`` filter: 172 | 173 | .. code-block:: django 174 | 175 | {% load bleach_tags %} 176 | 177 | {{ some_unsafe_content|bleach }} 178 | 179 | If filter has no arguments it uses default settings defined in your 180 | application settings. You can override allowed tags by specifying them 181 | as a parameter to the filter: 182 | 183 | .. code-block:: django 184 | 185 | {{ some_unsafe_content|bleach:"p,span" }} 186 | 187 | There is also ``bleach_linkify`` which uses the linkify_ function of bleach 188 | which converts URL-like strings in an HTML fragment to links 189 | 190 | This function converts strings that look like URLs, domain names and email 191 | addresses in text that may be an HTML fragment to links, while preserving: 192 | 193 | 1. links already in the string 194 | 2. urls found in attributes 195 | 3. email addresses 196 | 197 | 198 | .. _bleach: https://github.com/mozilla/bleach 199 | .. _Read the documentation here: https://django-bleach.readthedocs.io/ 200 | .. _bleach documentation: https://bleach.readthedocs.io/en/latest/clean.html 201 | .. _django-ckeditor: https://github.com/shaunsephton/django-ckeditor 202 | .. _linkify: https://bleach.readthedocs.io/en/latest/linkify.html?highlight=linkify#bleach.linkify "linkify" 203 | -------------------------------------------------------------------------------- /django_bleach/tests/test_forms.py: -------------------------------------------------------------------------------- 1 | from bleach.css_sanitizer import CSSSanitizer 2 | from django import forms 3 | from django.test import TestCase, override_settings 4 | from django.utils.safestring import SafeString 5 | 6 | from django_bleach.forms import BleachField 7 | from testproject.constants import ( 8 | ALLOWED_ATTRIBUTES, 9 | ALLOWED_CSS_PROPERTIES, 10 | ALLOWED_PROTOCOLS, 11 | ALLOWED_STYLES, 12 | ALLOWED_TAGS, 13 | ) 14 | from testproject.forms import BleachForm, CustomBleachWidget 15 | 16 | 17 | class TestBleachField(TestCase): 18 | def test_empty(self): 19 | """ 20 | Test that the empty_value arg is returned for any input empty value 21 | """ 22 | for requested_empty_value in ("", None): 23 | field = BleachField(empty_value=requested_empty_value) 24 | for empty_value in field.empty_values: 25 | self.assertEqual( 26 | field.to_python(empty_value), requested_empty_value 27 | ) 28 | 29 | def test_return_type(self): 30 | """Test bleached values are SafeString objects""" 31 | field = BleachField() 32 | self.assertIsInstance(field.to_python("some text"), SafeString) 33 | 34 | def test_bleaching(self): 35 | """Test values are bleached""" 36 | test_data = { 37 | "no_tags": "

    Heading

    ", 38 | "no_strip": "

    Heading

    ", 39 | "bleach_strip": "" 40 | '', 41 | "bleach_attrs": 'google.com', 43 | "bleach_css_sanitizer": '
  • item
  • ', 44 | } 45 | form = BleachForm(data=test_data) 46 | form.is_valid() 47 | self.assertEqual(form.cleaned_data["no_tags"], "Heading") 48 | self.assertEqual( 49 | form.cleaned_data["no_strip"], "<h1>Heading</h1>" 50 | ) 51 | self.assertEqual( 52 | form.cleaned_data["bleach_strip"], 'alert("Hello World")' 53 | ) 54 | self.assertEqual( 55 | form.cleaned_data["bleach_attrs"], 56 | 'google.com', 57 | ) 58 | self.assertNotEqual( 59 | form.cleaned_data["bleach_css_sanitizer"], 60 | test_data["bleach_css_sanitizer"], 61 | ) 62 | 63 | def test_tags(self): 64 | """Test allowed tags are rendered""" 65 | test_data = { 66 | "no_tags": "

    No tags here

    ", 67 | "no_strip": "No tags here", 68 | "bleach_strip": "", 69 | "bleach_attrs": 'google.com', 71 | "bleach_css_sanitizer": '
  • item
  • ', 72 | } 73 | form = BleachForm(data=test_data) 74 | form.is_valid() 75 | self.assertEqual(form.cleaned_data["no_tags"], "No tags here") 76 | self.assertEqual(form.cleaned_data["no_strip"], "No tags here") 77 | 78 | self.assertEqual( 79 | form.cleaned_data["bleach_strip"], test_data["bleach_strip"] 80 | ) 81 | self.assertEqual( 82 | form.cleaned_data["bleach_attrs"], test_data["bleach_attrs"] 83 | ) 84 | self.assertEqual( 85 | form.cleaned_data["bleach_css_sanitizer"], 86 | test_data["bleach_css_sanitizer"], 87 | ) 88 | 89 | def test_attrs(self): 90 | """Test allowed attributes are rendered""" 91 | list_html = ( 92 | '" 96 | ) 97 | test_data = { 98 | "no_strip": "", 99 | "no_tags": list_html, 100 | "bleach_strip": list_html, 101 | "bleach_attrs": list_html, 102 | "bleach_css_sanitizer": list_html, 103 | } 104 | form = BleachForm(data=test_data) 105 | form.is_valid() 106 | self.assertEqual(form.cleaned_data["no_tags"], "\none\ntwo") 107 | 108 | self.assertEqual( 109 | form.cleaned_data["bleach_strip"], 110 | "", 111 | ) 112 | self.assertEqual( 113 | form.cleaned_data["bleach_attrs"], test_data["bleach_strip"] 114 | ) 115 | self.assertEqual( 116 | form.cleaned_data["bleach_css_sanitizer"], 117 | "", 118 | ) 119 | 120 | 121 | @override_settings( 122 | BLEACH_DEFAULT_WIDGET="testproject.forms.CustomBleachWidget" 123 | ) 124 | class TestCustomWidget(TestCase): 125 | def setUp(self): 126 | class CustomForm(forms.Form): 127 | # Define form inside function with overridden settings so 128 | # get_default_widget() sees the modified setting. 129 | no_tags = BleachField( 130 | max_length=100, strip_tags=True, allowed_tags=[] 131 | ) 132 | no_strip = BleachField( 133 | max_length=100, allowed_tags=None, allowed_attributes=None 134 | ) 135 | bleach_strip = BleachField( 136 | max_length=100, 137 | strip_comments=True, 138 | strip_tags=True, 139 | allowed_tags=ALLOWED_TAGS, 140 | ) 141 | bleach_attrs = BleachField( 142 | max_length=100, 143 | strip_tags=False, 144 | allowed_tags=ALLOWED_TAGS, 145 | allowed_protocols=ALLOWED_PROTOCOLS, 146 | allowed_attributes=ALLOWED_ATTRIBUTES, 147 | ) 148 | bleach_styles = BleachField( 149 | max_length=100, 150 | strip_tags=False, 151 | allowed_attributes=["style"], 152 | allowed_tags=ALLOWED_TAGS, 153 | allowed_styles=ALLOWED_STYLES, 154 | ) 155 | bleach_css_sanitizer = BleachField( 156 | max_length=100, 157 | strip_tags=False, 158 | allowed_attributes=["style"], 159 | allowed_tags=ALLOWED_TAGS, 160 | css_sanitizer=CSSSanitizer( 161 | allowed_css_properties=ALLOWED_CSS_PROPERTIES 162 | ), 163 | ) 164 | 165 | self.CustomForm = CustomForm 166 | 167 | def test_custom_widget_type(self): 168 | """Test widget class matches BLEACH_DEFAULT_WIDGET""" 169 | for field in self.CustomForm().fields.values(): 170 | self.assertIsInstance(field.widget, CustomBleachWidget) 171 | 172 | def test_custom_widget_bleaches_content(self): 173 | """ 174 | Test input is bleached according to config while using a custom 175 | widget 176 | """ 177 | test_data = { 178 | "no_tags": "

    Heading

    ", 179 | "no_strip": "

    Heading

    ", 180 | "bleach_strip": "" 181 | '', 182 | "bleach_attrs": ( 183 | 'google.com' 185 | 'google.com' 186 | ), 187 | "bleach_styles": '
  • item
  • ', 188 | "bleach_css_sanitizer": '
  • item
  • ', 189 | } 190 | form = self.CustomForm(data=test_data) 191 | form.is_valid() 192 | self.assertEqual(form.cleaned_data["no_tags"], "Heading") 193 | self.assertEqual( 194 | form.cleaned_data["no_strip"], "<h1>Heading</h1>" 195 | ) 196 | self.assertEqual( 197 | form.cleaned_data["bleach_strip"], 'alert("Hello World")' 198 | ) 199 | self.assertEqual( 200 | form.cleaned_data["bleach_attrs"], 201 | 'google.comgoogle.com', 202 | ) 203 | self.assertNotEqual( 204 | form.cleaned_data["bleach_styles"], test_data["bleach_styles"] 205 | ) 206 | self.assertNotEqual( 207 | form.cleaned_data["bleach_css_sanitizer"], 208 | test_data["bleach_css_sanitizer"], 209 | ) 210 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # 2 | # django-bleach documentation build configuration file, created by 3 | # sphinx-quickstart on Tue Jun 19 10:24:12 2012. 4 | # 5 | # This file is execfile()d with the current directory set to its containing dir. 6 | # 7 | # Note that not all possible configuration values are present in this 8 | # autogenerated file. 9 | # 10 | # All configuration values have a default; values that are commented out 11 | # serve to show the default. 12 | 13 | 14 | # If extensions (or modules to document with autodoc) are in another directory, 15 | # add these directories to sys.path here. If the directory is relative to the 16 | # documentation root, use os.path.abspath to make it absolute, like shown here. 17 | # sys.path.insert(0, os.path.abspath('.')) 18 | 19 | # -- General configuration ----------------------------------------------------- 20 | 21 | # If your documentation needs a minimal Sphinx version, state it here. 22 | # needs_sphinx = '1.0' 23 | 24 | # Add any Sphinx extension module names here, as strings. They can be extensions 25 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 26 | import datetime 27 | 28 | extensions = ["sphinx.ext.autodoc"] 29 | 30 | # Add any paths that contain templates here, relative to this directory. 31 | templates_path = ["_templates"] 32 | 33 | # The suffix of source filenames. 34 | source_suffix = ".rst" 35 | 36 | # The encoding of source files. 37 | # source_encoding = 'utf-8-sig' 38 | 39 | # The master toctree document. 40 | master_doc = "index" 41 | 42 | # General information about the project. 43 | project = "django-bleach" 44 | copyright = f"{datetime.date.today().year}, Tim Heap, Mark Walker" 45 | # The version info for the project you're documenting, acts as replacement for 46 | # |version| and |release|, also used in various other places throughout the 47 | # built documents. 48 | # 49 | # The short X.Y version. 50 | version = "3.1.0" 51 | # The full version, including alpha/beta/rc tags. 52 | # release = '1.0.0' 53 | 54 | # The language for content autogenerated by Sphinx. Refer to documentation 55 | # for a list of supported languages. 56 | # language = None 57 | 58 | # There are two options for replacing |today|: either, you set today to some 59 | # non-false value, then it is used: 60 | # today = '' 61 | # Else, today_fmt is used as the format for a strftime call. 62 | # today_fmt = '%B %d, %Y' 63 | 64 | # List of patterns, relative to source directory, that match files and 65 | # directories to ignore when looking for source files. 66 | exclude_patterns = ["_build"] 67 | 68 | # The reST default role (used for this markup: `text`) to use for all documents. 69 | # default_role = None 70 | 71 | # If true, '()' will be appended to :func: etc. cross-reference text. 72 | # add_function_parentheses = True 73 | 74 | # If true, the current module name will be prepended to all description 75 | # unit titles (such as .. function::). 76 | # add_module_names = True 77 | 78 | # If true, sectionauthor and moduleauthor directives will be shown in the 79 | # output. They are ignored by default. 80 | # show_authors = False 81 | 82 | # The name of the Pygments (syntax highlighting) style to use. 83 | pygments_style = "sphinx" 84 | 85 | # A list of ignored prefixes for module index sorting. 86 | # modindex_common_prefix = [] 87 | 88 | 89 | # -- Options for HTML output --------------------------------------------------- 90 | 91 | # The theme to use for HTML and HTML Help pages. See the documentation for 92 | # a list of builtin themes. 93 | try: 94 | import furo 95 | 96 | html_theme = "furo" 97 | html_theme_options = { 98 | "navigation_with_keys": True, 99 | } 100 | except ImportError: 101 | html_theme = "default" 102 | 103 | # Theme options are theme-specific and customize the look and feel of a theme 104 | # further. For a list of options available for each theme, see the 105 | # documentation. 106 | # html_theme_options = {} 107 | 108 | # Add any paths that contain custom themes here, relative to this directory. 109 | # html_theme_path = [] 110 | 111 | # The name for this set of Sphinx documents. If None, it defaults to 112 | # " v documentation". 113 | # html_title = None 114 | 115 | # A shorter title for the navigation bar. Default is the same as html_title. 116 | # html_short_title = None 117 | 118 | # The name of an image file (relative to this directory) to place at the top 119 | # of the sidebar. 120 | # html_logo = None 121 | 122 | # The name of an image file (within the static path) to use as favicon of the 123 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 124 | # pixels large. 125 | # html_favicon = None 126 | 127 | # Add any paths that contain custom static files (such as style sheets) here, 128 | # relative to this directory. They are copied after the builtin static files, 129 | # so a file named "default.css" will overwrite the builtin "default.css". 130 | html_static_path = ["_static"] 131 | 132 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 133 | # using the given strftime format. 134 | # html_last_updated_fmt = '%b %d, %Y' 135 | 136 | # If true, SmartyPants will be used to convert quotes and dashes to 137 | # typographically correct entities. 138 | # html_use_smartypants = True 139 | 140 | # Custom sidebar templates, maps document names to template names. 141 | # html_sidebars = {} 142 | 143 | # Additional templates that should be rendered to pages, maps page names to 144 | # template names. 145 | # html_additional_pages = {} 146 | 147 | # If false, no module index is generated. 148 | # html_domain_indices = True 149 | 150 | # If false, no index is generated. 151 | # html_use_index = True 152 | 153 | # If true, the index is split into individual pages for each letter. 154 | # html_split_index = False 155 | 156 | # If true, links to the reST sources are added to the pages. 157 | # html_show_sourcelink = True 158 | 159 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 160 | # html_show_sphinx = True 161 | 162 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 163 | # html_show_copyright = True 164 | 165 | # If true, an OpenSearch description file will be output, and all pages will 166 | # contain a tag referring to it. The value of this option must be the 167 | # base URL from which the finished HTML is served. 168 | # html_use_opensearch = '' 169 | 170 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 171 | # html_file_suffix = None 172 | 173 | # Output file base name for HTML help builder. 174 | htmlhelp_basename = "django-bleach" 175 | 176 | 177 | # -- Options for LaTeX output -------------------------------------------------- 178 | 179 | # latex_elements = { 180 | # The paper size ('letterpaper' or 'a4paper'). 181 | # 'papersize': 'letterpaper', 182 | 183 | # The font size ('10pt', '11pt' or '12pt'). 184 | # 'pointsize': '10pt', 185 | 186 | # Additional stuff for the LaTeX preamble. 187 | # 'preamble': '', 188 | # } 189 | 190 | # Grouping the document tree into LaTeX files. List of tuples 191 | # (source start file, target name, title, author, documentclass [howto/manual]). 192 | latex_documents = [ 193 | ( 194 | "index", 195 | "django-bleach.tex", 196 | "django-bleach Documentation", 197 | "Mark Walker", 198 | "manual", 199 | ), 200 | ] 201 | 202 | # The name of an image file (relative to this directory) to place at the top of 203 | # the title page. 204 | # latex_logo = None 205 | 206 | # For "manual" documents, if this is true, then toplevel headings are parts, 207 | # not chapters. 208 | # latex_use_parts = False 209 | 210 | # If true, show page references after internal links. 211 | # latex_show_pagerefs = False 212 | 213 | # If true, show URL addresses after external links. 214 | # latex_show_urls = False 215 | 216 | # Documents to append as an appendix to all manuals. 217 | # latex_appendices = [] 218 | 219 | # If false, no module index is generated. 220 | # latex_domain_indices = True 221 | 222 | 223 | # -- Options for manual page output -------------------------------------------- 224 | 225 | # One entry per manual page. List of tuples 226 | # (source start file, name, description, authors, manual section). 227 | man_pages = [ 228 | ( 229 | "index", 230 | "django-bleach", 231 | "django-bleach Documentation", 232 | ["Mark Walker"], 233 | 1, 234 | ) 235 | ] 236 | 237 | # If true, show URL addresses after external links. 238 | # man_show_urls = False 239 | 240 | 241 | # -- Options for Texinfo output ------------------------------------------------ 242 | 243 | # Grouping the document tree into Texinfo files. List of tuples 244 | # (source start file, target name, title, author, 245 | # dir menu entry, description, category) 246 | texinfo_documents = [ 247 | ( 248 | "index", 249 | "django-bleach", 250 | "django-bleach Documentation", 251 | "Mark Walker", 252 | "django-bleach", 253 | "One line description of project.", 254 | "Miscellaneous", 255 | ), 256 | ] 257 | 258 | # Documents to append as an appendix to all manuals. 259 | # texinfo_appendices = [] 260 | 261 | # If false, no module index is generated. 262 | # texinfo_domain_indices = True 263 | 264 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 265 | # texinfo_show_urls = 'footnote' 266 | --------------------------------------------------------------------------------