Browse Source

HUE-9483 [test] Adding pytest-django compatible with Python 2

Romain 5 years ago
parent
commit
cf328f371d
70 changed files with 9015 additions and 0 deletions
  1. 8 0
      desktop/core/ext-py/pytest-django-3.10.0/.coveragerc
  2. 18 0
      desktop/core/ext-py/pytest-django-3.10.0/.gitignore
  3. 112 0
      desktop/core/ext-py/pytest-django-3.10.0/.travis.yml
  4. 15 0
      desktop/core/ext-py/pytest-django-3.10.0/AUTHORS
  5. 54 0
      desktop/core/ext-py/pytest-django-3.10.0/LICENSE
  6. 15 0
      desktop/core/ext-py/pytest-django-3.10.0/MANIFEST.in
  7. 28 0
      desktop/core/ext-py/pytest-django-3.10.0/Makefile
  8. 104 0
      desktop/core/ext-py/pytest-django-3.10.0/PKG-INFO
  9. 63 0
      desktop/core/ext-py/pytest-django-3.10.0/README.rst
  10. 6 0
      desktop/core/ext-py/pytest-django-3.10.0/codecov.yml
  11. 155 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/Makefile
  12. 6 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/_ext/pytestdocs.py
  13. 727 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/changelog.rst
  14. 58 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/conf.py
  15. 106 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/configuring_django.rst
  16. 242 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/contributing.rst
  17. 493 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/database.rst
  18. 150 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/faq.rst
  19. 393 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/helpers.rst
  20. 79 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/index.rst
  21. 190 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/make.bat
  22. 83 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/managing_python_path.rst
  23. 98 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/tutorial.rst
  24. 56 0
      desktop/core/ext-py/pytest-django-3.10.0/docs/usage.rst
  25. 0 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django/__init__.py
  26. 34 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django/asserts.py
  27. 39 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django/compat.py
  28. 14 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django/django_compat.py
  29. 481 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django/fixtures.py
  30. 33 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django/lazy_django.py
  31. 109 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django/live_server_helper.py
  32. 16 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django/migrations.py
  33. 824 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django/plugin.py
  34. 0 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/__init__.py
  35. 0 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/__init__.py
  36. 9 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/fixtures/items.json
  37. 30 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/migrations/0001_initial.py
  38. 0 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/migrations/__init__.py
  39. 5 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/models.py
  40. 1 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/static/a_file.txt
  41. 14 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/views.py
  42. 4 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/compat.py
  43. 162 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/db_helpers.py
  44. 34 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_base.py
  45. 11 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_mysql_innodb.py
  46. 11 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_mysql_myisam.py
  47. 19 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_postgres.py
  48. 8 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_sqlite.py
  49. 17 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_sqlite_file.py
  50. 8 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/urls.py
  51. 6 0
      desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/urls_overridden.py
  52. 10 0
      desktop/core/ext-py/pytest-django-3.10.0/requirements.txt
  53. 23 0
      desktop/core/ext-py/pytest-django-3.10.0/setup.cfg
  54. 78 0
      desktop/core/ext-py/pytest-django-3.10.0/setup.py
  55. 165 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/conftest.py
  56. 56 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_asserts.py
  57. 296 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_database.py
  58. 27 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_db_access_in_repr.py
  59. 564 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_db_setup.py
  60. 140 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_django_configurations.py
  61. 452 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_django_settings_module.py
  62. 4 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_doctest.txt
  63. 327 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_environment.py
  64. 718 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_fixtures.py
  65. 60 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_initialization.py
  66. 142 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_manage_py_scan.py
  67. 497 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_unittest.py
  68. 103 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_urls.py
  69. 117 0
      desktop/core/ext-py/pytest-django-3.10.0/tests/test_without_django_loaded.py
  70. 88 0
      desktop/core/ext-py/pytest-django-3.10.0/tox.ini

+ 8 - 0
desktop/core/ext-py/pytest-django-3.10.0/.coveragerc

@@ -0,0 +1,8 @@
+[run]
+parallel = 1
+source = ${PYTESTDJANGO_COVERAGE_SRC}.
+branch = 1
+
+[report]
+include = pytest_django/*,pytest_django_test/*,tests/*
+skip_covered = 1

+ 18 - 0
desktop/core/ext-py/pytest-django-3.10.0/.gitignore

@@ -0,0 +1,18 @@
+*.pyc
+build/
+/dist/
+*.egg-info
+_build
+.tox
+.DS_Store
+*~
+.env
+/.coverage.*
+/.coverage
+/coverage.xml
+/htmlcov/
+.cache
+.pytest_cache/
+.Python
+.eggs
+*.egg

+ 112 - 0
desktop/core/ext-py/pytest-django-3.10.0/.travis.yml

@@ -0,0 +1,112 @@
+language: python
+dist: xenial
+cache: false
+
+jobs:
+  fast_finish: true
+  include:
+    - stage: baseline
+      python: 3.6
+      env:
+        - TOXENV=py36-dj20-postgres-xdist-coverage
+        # Test in verbose mode.
+        - PYTEST_ADDOPTS=-vv
+      services:
+        - postgresql
+    - python: 3.6
+      env: TOXENV=py36-dj111-mysql_innodb-coverage
+      services:
+        - mysql
+    - python: 2.7
+      env: TOXENV=py27-dj111-sqlite-xdist-coverage
+    - python: 3.6
+      env: TOXENV=checkqa,docs
+
+    - stage: test
+      python: 3.7
+      env: TOXENV=py37-dj21-sqlite-coverage
+    - python: 3.7
+      env: TOXENV=py37-dj22-sqlite-xdist-coverage
+    - python: 3.8
+      env: TOXENV=py38-dj30-sqlite-xdist-coverage
+    - python: 3.8
+      env: TOXENV=py38-dj31-sqlite-xdist-coverage
+
+    # Explicitly test (older) pytest 4.1.
+    - python: 3.7
+      env: TOXENV=py37-dj21-sqlite-pytest41-coverage
+
+    - python: 3.6
+      env: TOXENV=py36-djmaster-sqlite-coverage
+
+    # Explicitly test (older) pytest 5.3.
+    - python: 3.5
+      env: TOXENV=py35-dj110-postgres-pytest53-coverage
+      services:
+        - postgresql
+
+    - python: 3.4
+      env: TOXENV=py34-dj19-sqlite_file-coverage
+
+    - python: 2.7
+      env: TOXENV=py27-dj111-mysql_myisam-coverage
+      services:
+        - mysql
+    - python: 2.7
+      env: TOXENV=py27-dj18-postgres-coverage
+      services:
+        - postgresql
+
+    # pypy/pypy3: not included with coverage reports (much slower then).
+    - python: pypy
+      env: TOXENV=pypy-dj111-sqlite_file
+    - python: pypy3
+      env: TOXENV=pypy3-dj110-sqlite
+
+    - stage: test_release
+      python: 3.6
+      env: TOXENV=py36-dj20-postgres
+      services:
+        - postgresql
+
+    - stage: release
+      script: skip
+      install: skip
+      after_success: true
+      deploy:
+        provider: pypi
+        user: blueyed
+        password:
+          secure: "FY7qbX/N0XRcH8hVk00SsQWvNIkuxKvY7Br4ghRnHvleHG3YulJ7WbJnik+9eoBGeMfJeNyzBfVjpeo1ZIq9IZBiyTdNfG/sZFsC5LOoG/CPxPH3nD9JktI2HoBMnlSbGg/MMHjY+wXuOY647U/3qNedcnQmGztYt6QWi5DRxu8="
+        on:
+          tags: true
+        distributions: "sdist bdist_wheel"
+
+  # NOTE: does not show up in "allowed failures" section, but is allowed to
+  # fail (for the "test" stage).
+  allow_failures:
+    - env: TOXENV=py36-djmaster-sqlite-coverage
+
+stages:
+  - name: baseline
+    if: tag IS NOT present
+  - name: test
+    if: tag IS NOT present
+  - name: test_release
+    if: tag IS present
+  - name: release
+    if: tag IS present
+
+install:
+  - pip install tox==3.9.0
+
+script:
+  - tox
+
+after_success:
+  - |
+    set -ex
+    if [[ "${TOXENV%-coverage}" != "$TOXENV" ]]; then
+      bash <(curl -s https://codecov.io/bash) -Z -X gcov -X xcode -X gcovout
+    fi
+    set +ex

+ 15 - 0
desktop/core/ext-py/pytest-django-3.10.0/AUTHORS

@@ -0,0 +1,15 @@
+Ben Firshman <ben@firshman.co.uk> created the original version of pytest-django.
+
+This fork is currently maintained by Andreas Pelme <andreas@pelme.se>.
+
+These people have provided bug fixes, new features, improved the documentation
+or just made pytest-django more awesome:
+
+Ruben Bakker
+Ralf Schmitt <ralf@systemexit.de>
+Rob Berry <rob@luvhate.us>
+Floris Bruynooghe <flub@devork.be>
+Rafal Stozek
+Donald Stufft <donald@stufft.io>
+Nicolas Delaby <ticosax@free.fr>
+Daniel Hahler <https://twitter.com/blueyed>

+ 54 - 0
desktop/core/ext-py/pytest-django-3.10.0/LICENSE

@@ -0,0 +1,54 @@
+pytest-django is released under the BSD (3-clause) license
+----------------------------------------------------------
+Copyright (c) 2015-2018, pytest-django authors (see AUTHORS file)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * The names of its contributors may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+This version of pytest-django is a fork of pytest_django created by Ben Firshman.
+---------------------------------------------------------------------------------
+Copyright (c) 2009, Ben Firshman
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * The names of its contributors may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 15 - 0
desktop/core/ext-py/pytest-django-3.10.0/MANIFEST.in

@@ -0,0 +1,15 @@
+include AUTHORS
+include README.rst
+include LICENSE
+
+# Include tests for downstream testing (https://github.com/pytest-dev/pytest-django/issues/290).
+recursive-include tests *.py *.txt
+recursive-include pytest_django_test *.json *.py *.txt
+
+recursive-exclude .git *
+recursive-exclude .tox *
+recursive-exclude bin *
+recursive-exclude include *
+recursive-exclude lib *
+recursive-exclude share *
+recursive-exclude src *

+ 28 - 0
desktop/core/ext-py/pytest-django-3.10.0/Makefile

@@ -0,0 +1,28 @@
+.PHONY: docs test clean isort
+
+VENV:=build/venv
+
+export DJANGO_SETTINGS_MODULE?=pytest_django_test.settings_sqlite_file
+
+testenv: $(VENV)/bin/pytest
+
+test: $(VENV)/bin/pytest
+	$(VENV)/bin/pip install -e .
+	$(VENV)/bin/py.test
+
+$(VENV)/bin/python $(VENV)/bin/pip:
+	virtualenv $(VENV)
+
+$(VENV)/bin/pytest: $(VENV)/bin/python requirements.txt
+	$(VENV)/bin/pip install -Ur requirements.txt
+	touch $@
+
+docs:
+	tox -e docs
+
+# See setup.cfg for configuration.
+isort:
+	find pytest_django tests -name '*.py' -exec isort {} +
+
+clean:
+	rm -rf bin include/ lib/ man/ pytest_django.egg-info/ build/

+ 104 - 0
desktop/core/ext-py/pytest-django-3.10.0/PKG-INFO

@@ -0,0 +1,104 @@
+Metadata-Version: 2.1
+Name: pytest-django
+Version: 3.10.0
+Summary: A Django plugin for pytest.
+Home-page: https://pytest-django.readthedocs.io/
+Author: Andreas Pelme
+Author-email: andreas@pelme.se
+Maintainer: Andreas Pelme
+Maintainer-email: andreas@pelme.se
+License: BSD-3-Clause
+Project-URL: Source, https://github.com/pytest-dev/pytest-django
+Project-URL: Changelog, https://pytest-django.readthedocs.io/en/latest/changelog.html
+Description: .. image:: https://img.shields.io/pypi/v/pytest-django.svg?style=flat
+            :alt: PyPI Version
+            :target: https://pypi.python.org/pypi/pytest-django
+        
+        .. image:: https://img.shields.io/pypi/pyversions/pytest-django.svg
+            :alt: Supported Python versions
+            :target: https://pypi.python.org/pypi/pytest-django
+        
+        .. image:: https://travis-ci.org/pytest-dev/pytest-django.svg?branch=master
+            :alt: Build Status
+            :target: https://travis-ci.org/pytest-dev/pytest-django
+        
+        .. image:: https://img.shields.io/codecov/c/github/pytest-dev/pytest-django.svg?style=flat
+            :alt: Coverage
+            :target: https://codecov.io/gh/pytest-dev/pytest-django
+        
+        Welcome to pytest-django!
+        =========================
+        
+        pytest-django allows you to test your Django project/applications with the
+        `pytest testing tool <https://pytest.org/>`_.
+        
+        * `Quick start / tutorial
+          <https://pytest-django.readthedocs.io/en/latest/tutorial.html>`_
+        * `Changelog <https://pytest-django.readthedocs.io/en/latest/changelog.html>`_
+        * Full documentation: https://pytest-django.readthedocs.io/en/latest/
+        * `Contribution docs
+          <https://pytest-django.readthedocs.io/en/latest/contributing.html>`_
+        * Version compatibility:
+        
+          * Django: 1.8-1.11, 2.0-2.2,
+            and latest master branch (compatible at the time of each release)
+          * Python: CPython 2.7, 3.4-3.7 or PyPy 2, 3
+          * pytest: >=3.6
+        
+        * Licence: BSD
+        * Project maintainers: Andreas Pelme, Floris Bruynooghe and Daniel Hahler
+        * `All contributors <https://github.com/pytest-dev/pytest-django/contributors>`_
+        * GitHub repository: https://github.com/pytest-dev/pytest-django
+        * `Issue tracker <http://github.com/pytest-dev/pytest-django/issues>`_
+        * `Python Package Index (PyPI) <https://pypi.python.org/pypi/pytest-django/>`_
+        
+        Install pytest-django
+        ---------------------
+        
+        ::
+        
+            pip install pytest-django
+        
+        Why would I use this instead of Django's `manage.py test` command?
+        ------------------------------------------------------------------
+        
+        Running your test suite with pytest-django allows you to tap into the features
+        that are already present in pytest. Here are some advantages:
+        
+        * `Manage test dependencies with pytest fixtures. <https://pytest.org/en/latest/fixture.html>`_
+        * Less boilerplate tests: no need to import unittest, create a subclass with methods. Write tests as regular functions.
+        * Database re-use: no need to re-create the test database for every test run.
+        * Run tests in multiple processes for increased speed (with the pytest-xdist plugin).
+        * Make use of other `pytest plugins <https://pytest.org/en/latest/plugins.html>`_.
+        * Works with both worlds: Existing unittest-style TestCase's still work without any modifications.
+        
+        See the `pytest documentation <https://pytest.org/en/latest/>`_ for more information on pytest itself.
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Framework :: Django
+Classifier: Framework :: Django :: 1.8
+Classifier: Framework :: Django :: 1.9
+Classifier: Framework :: Django :: 1.10
+Classifier: Framework :: Django :: 1.11
+Classifier: Framework :: Django :: 2.0
+Classifier: Framework :: Django :: 2.1
+Classifier: Framework :: Django :: 2.2
+Classifier: Framework :: Django :: 3.0
+Classifier: Framework :: Django :: 3.1
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Software Development :: Testing
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
+Provides-Extra: docs
+Provides-Extra: testing

+ 63 - 0
desktop/core/ext-py/pytest-django-3.10.0/README.rst

@@ -0,0 +1,63 @@
+.. image:: https://img.shields.io/pypi/v/pytest-django.svg?style=flat
+    :alt: PyPI Version
+    :target: https://pypi.python.org/pypi/pytest-django
+
+.. image:: https://img.shields.io/pypi/pyversions/pytest-django.svg
+    :alt: Supported Python versions
+    :target: https://pypi.python.org/pypi/pytest-django
+
+.. image:: https://travis-ci.org/pytest-dev/pytest-django.svg?branch=master
+    :alt: Build Status
+    :target: https://travis-ci.org/pytest-dev/pytest-django
+
+.. image:: https://img.shields.io/codecov/c/github/pytest-dev/pytest-django.svg?style=flat
+    :alt: Coverage
+    :target: https://codecov.io/gh/pytest-dev/pytest-django
+
+Welcome to pytest-django!
+=========================
+
+pytest-django allows you to test your Django project/applications with the
+`pytest testing tool <https://pytest.org/>`_.
+
+* `Quick start / tutorial
+  <https://pytest-django.readthedocs.io/en/latest/tutorial.html>`_
+* `Changelog <https://pytest-django.readthedocs.io/en/latest/changelog.html>`_
+* Full documentation: https://pytest-django.readthedocs.io/en/latest/
+* `Contribution docs
+  <https://pytest-django.readthedocs.io/en/latest/contributing.html>`_
+* Version compatibility:
+
+  * Django: 1.8-1.11, 2.0-2.2,
+    and latest master branch (compatible at the time of each release)
+  * Python: CPython 2.7, 3.4-3.7 or PyPy 2, 3
+  * pytest: >=3.6
+
+* Licence: BSD
+* Project maintainers: Andreas Pelme, Floris Bruynooghe and Daniel Hahler
+* `All contributors <https://github.com/pytest-dev/pytest-django/contributors>`_
+* GitHub repository: https://github.com/pytest-dev/pytest-django
+* `Issue tracker <http://github.com/pytest-dev/pytest-django/issues>`_
+* `Python Package Index (PyPI) <https://pypi.python.org/pypi/pytest-django/>`_
+
+Install pytest-django
+---------------------
+
+::
+
+    pip install pytest-django
+
+Why would I use this instead of Django's `manage.py test` command?
+------------------------------------------------------------------
+
+Running your test suite with pytest-django allows you to tap into the features
+that are already present in pytest. Here are some advantages:
+
+* `Manage test dependencies with pytest fixtures. <https://pytest.org/en/latest/fixture.html>`_
+* Less boilerplate tests: no need to import unittest, create a subclass with methods. Write tests as regular functions.
+* Database re-use: no need to re-create the test database for every test run.
+* Run tests in multiple processes for increased speed (with the pytest-xdist plugin).
+* Make use of other `pytest plugins <https://pytest.org/en/latest/plugins.html>`_.
+* Works with both worlds: Existing unittest-style TestCase's still work without any modifications.
+
+See the `pytest documentation <https://pytest.org/en/latest/>`_ for more information on pytest itself.

+ 6 - 0
desktop/core/ext-py/pytest-django-3.10.0/codecov.yml

@@ -0,0 +1,6 @@
+coverage:
+  status:
+    project: true
+    patch: true
+    changes: true
+comment: false

+ 155 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/Makefile

@@ -0,0 +1,155 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+ifndef SPHINXBUILD
+SPHINXBUILD   = ../bin/sphinx-build
+endif
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pytest-django.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pytest-django.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/pytest-django"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pytest-django"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."

+ 6 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/_ext/pytestdocs.py

@@ -0,0 +1,6 @@
+def setup(app):
+    app.add_crossref_type(
+        directivename="fixture",
+        rolename="fixture",
+        indextemplate="pair: %s; fixture",
+    )

+ 727 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/changelog.rst

@@ -0,0 +1,727 @@
+Changelog
+=========
+
+v3.10.0 (2020-08-25)
+--------------------
+
+Improvements
+^^^^^^^^^^^^
+
+* Officialy support Django 3.1
+
+* Preliminary supoprt for upcoming Django 3.2
+
+* Support for pytest-xdist 2.0
+
+
+Misc
+^^^^
+
+* Fix running pytest-django's own tests against pytest 6.0 (#855)
+
+
+v3.9.0 (2020-03-31)
+-------------------
+
+Improvements
+^^^^^^^^^^^^
+
+* Improve test ordering with Django test classes (#830)
+
+* Remove import of pkg_resources for parsing pytest version (performance) (#826)
+
+Bugfixes
+^^^^^^^^
+
+* Work around unittest issue with pytest 5.4.{0,1} (#825)
+
+* Don't break --failed-first when re-ordering tests (#819, #820)
+
+* pytest_addoption: use `group.addoption` (#833)
+
+Misc
+^^^^
+
+* Remove Django version from --nomigrations heading (#822)
+
+* docs: changelog: prefix headers with v for permalink anchors
+
+* changelog: add custom/fixed anchor for last version
+
+* setup.py: add Changelog to project_urls
+
+
+v3.8.0 (2020-01-14)
+--------------------
+
+Improvements
+^^^^^^^^^^^^
+
+* Make Django's assertion helpers available in pytest_django.asserts (#709).
+
+* Report django-configurations setting (#791)
+
+
+v3.7.0 (2019-11-09)
+-------------------
+
+Bugfixes
+^^^^^^^^
+
+* Monkeypatch pytest to not use ``TestCase.debug`` with unittests, instead
+  of patching it into Django (#782).
+
+* Work around pytest crashing due to ``pytest.fail`` being used from within the
+  DB blocker, and pytest trying to display an object representation involving
+  DB access (#781).  pytest-django uses a ``RuntimeError`` now instead.
+
+
+v3.6.0 (2019-10-17)
+-------------------
+
+Features
+^^^^^^^^
+
+* Rename test databases when running parallel Tox (#678, #680)
+
+Bugfixes
+^^^^^^^^
+
+* Django unittests: restore "debug" function (#769, #771)
+
+Misc
+^^^^
+
+* Improve/harden internal tests / infrastructure.
+
+
+v3.5.1 (2019-06-29)
+-------------------
+
+Bugfixes
+^^^^^^^^
+
+* Fix compatibility with pytest 5.x (#751)
+
+v3.5.0 (2019-06-03)
+-------------------
+
+Features
+^^^^^^^^
+
+* Run tests in the same order as Django (#223)
+
+* Use verbosity=0 with disabled migrations (#729, #730)
+
+Bugfixes
+^^^^^^^^
+
+* django_db_setup: warn instead of crash with teardown errors (#726)
+
+Misc
+^^^^
+* tests: fix test_sqlite_database_renamed (#739, #741)
+
+* tests/conftest.py: move import of db_helpers (#737)
+
+* Cleanup/improve coverage, mainly with tests (#706)
+
+* Slightly revisit unittest handling (#740)
+
+
+v3.4.8 (2019-02-26)
+-------------------
+
+Bugfixes
+^^^^^^^^
+
+* Fix DB renaming fixture for Multi-DB environment with SQLite (#679)
+
+v3.4.7 (2019-02-03)
+-------------------
+
+Bugfixes
+^^^^^^^^
+
+* Fix disabling/handling of unittest methods with pytest 4.2+ (#700)
+
+v3.4.6 (2019-02-01)
+-------------------
+
+Bugfixes
+^^^^^^^^
+
+* django_find_project: add cwd as fallback always (#690)
+
+Misc
+^^^^
+
+* Enable tests for Django 2.2 and add classifier (#693)
+* Disallow pytest 4.2.0 in ``install_requires`` (#697)
+
+v3.4.5 (2019-01-07)
+-------------------
+
+Bugfixes
+^^^^^^^^
+
+* Use ``request.config`` instead of ``pytest.config`` (#677)
+* :fixture:`admin_user`: handle "email" username_field (#676)
+
+Misc
+^^^^
+
+* Minor doc fixes (#674)
+* tests: fix for pytest 4 (#675)
+
+v3.4.4 (2018-11-13)
+-------------------
+
+Bugfixes
+^^^^^^^^
+
+* Refine the django.conf module check to see if the settings really are
+  configured (#668).
+* Avoid crash after OSError during Django path detection (#664).
+
+Features
+^^^^^^^^
+
+* Add parameter info to fixture assert_num_queries to display additional message on failure (#663).
+
+Docs
+^^^^
+
+* Improve doc for django_assert_num_queries/django_assert_max_num_queries.
+* Add warning about sqlite specific snippet + fix typos (#666).
+
+Misc
+^^^^
+
+* MANIFEST.in: include tests for downstream distros (#653).
+* Ensure that the LICENSE file is included in wheels (#665).
+* Run black on source.
+
+
+v3.4.3 (2018-09-16)
+-------------------
+
+Bugfixes
+^^^^^^^^
+
+* Fix OSError with arguments containing ``::`` on Windows (#641).
+
+v3.4.2 (2018-08-20)
+-------------------
+
+Bugfixes
+^^^^^^^^
+
+* Changed dependency for pathlib to pathlib2 (#636).
+* Fixed code for inserting the project to sys.path with pathlib to use an
+  absolute path, regression in 3.4.0 (#637, #638).
+
+v3.4.0 (2018-08-16)
+-------------------
+
+Features
+^^^^^^^^
+
+* Added new fixture :fixture:`django_assert_max_num_queries` (#547).
+* Added support for ``connection`` and returning the wrapped context manager
+  with :fixture:`django_assert_num_queries` (#547).
+* Added support for resetting sequences via
+  :fixture:`django_db_reset_sequences` (#619).
+
+Bugfixes
+^^^^^^^^
+
+* Made sure to not call django.setup() multiple times (#629, #531).
+
+Compatibility
+^^^^^^^^^^^^^
+
+* Removed py dependency, use pathlib instead (#631).
+
+v3.3.3 (2018-07-26)
+-------------------
+
+Bug fixes
+^^^^^^^^^
+
+* Fixed registration of :py:func:`~pytest.mark.ignore_template_errors` marker,
+  which is required with ``pytest --strict`` (#609).
+* Fixed another regression with unittest (#624, #625).
+
+Docs
+^^^^
+
+* Use sphinx_rtf_theme (#621).
+* Minor fixes.
+
+v3.3.2 (2018-06-21)
+-------------------
+
+Bug fixes
+^^^^^^^^^
+
+* Fixed test for classmethod with Django TestCases again (#618,
+  introduced in #598 (3.3.0)).
+
+Compatibility
+^^^^^^^^^^^^^
+
+* Support Django 2.1 (no changes necessary) (#614).
+
+v3.3.0 (2018-06-15)
+-------------------
+
+Features
+^^^^^^^^
+
+* Added new fixtures ``django_mail_dnsname`` and ``django_mail_patch_dns``,
+  used by ``mailoutbox`` to monkeypatch the ``DNS_NAME`` used in
+  :py:mod:`django.core.mail` to improve performance and
+  reproducibility.
+
+Bug fixes
+^^^^^^^^^
+
+* Fixed test for classmethod with Django TestCases (#597, #598).
+* Fixed RemovedInPytest4Warning: MarkInfo objects are deprecated (#596, #603)
+* Fixed scope of overridden settings with live_server fixture: previously they
+  were visible to following tests (#612).
+
+Compatibility
+^^^^^^^^^^^^^
+
+* The required `pytest` version changed from >=2.9 to >=3.6.
+
+v3.2.1
+------
+
+* Fixed automatic deployment to PyPI.
+
+v3.2.0
+------
+
+Features
+^^^^^^^^
+
+* Added new fixture `django_assert_num_queries` for testing the number of
+  database queries (#387).
+* `--fail-on-template-vars` has been improved and should now return
+  full/absolute path (#470).
+* Support for setting the live server port (#500).
+* unittest: help with setUpClass not being a classmethod (#544).
+
+Bug fixes
+^^^^^^^^^
+
+* Fix --reuse-db and --create-db not working together (#411).
+* Numerous fixes in the documentation. These should not go unnoticed 🌟
+
+Compatibility
+^^^^^^^^^^^^^
+
+* Support for Django 2.0 has been added.
+* Support for Django before 1.8 has been dropped.
+
+v3.1.2
+------
+
+Bug fixes
+^^^^^^^^^
+
+* Auto clearing of ``mail.outbox`` has been re-introduced to not break
+  functionality in 3.x.x release. This means that Compatibility issues
+  mentioned in the 3.1.0 release are no longer present. Related issue:
+  `pytest-django issue <https://github.com/pytest-dev/pytest-django/issues/433>`__
+
+v3.1.1
+------
+
+Bug fixes
+^^^^^^^^^
+
+* Workaround `--pdb` interaction with Django TestCase. The issue is caused by
+  Django TestCase not implementing TestCase.debug() properly but was brought to
+  attention with recent changes in pytest 3.0.2. Related issues:
+  `pytest issue <https://github.com/pytest-dev/pytest/issues/1977>`__,
+  `Django issue <https://code.djangoproject.com/ticket/27391>`__
+
+v3.1.0
+------
+
+Features
+^^^^^^^^
+* Added new function scoped fixture ``mailoutbox`` that gives access to
+  djangos ``mail.outbox``. The will clean/empty the ``mail.outbox`` to
+  assure that no old mails are still in the outbox.
+* If ``django.contrib.sites`` is in your INSTALLED_APPS, Site cache will
+  be cleared for each test to avoid hitting the cache and cause wrong Site
+  object to be returned by ``Site.objects.get_current()``.
+
+Compatibility
+^^^^^^^^^^^^^
+* IMPORTANT: the internal autouse fixture _django_clear_outbox has been
+  removed. If you have relied on this to get an empty outbox for your
+  test, you should change tests to use the ``mailoutbox`` fixture instead.
+  See documentation of ``mailoutbox`` fixture for usage. If you try to
+  access mail.outbox directly, AssertionError will be raised. If you
+  previously relied on the old behaviour and do not want to change your
+  tests, put this in your project conftest.py::
+
+    @pytest.fixture(autouse=True)
+    def clear_outbox():
+        from django.core import mail
+        mail.outbox = []
+
+
+v3.0.0
+------
+
+Bug fixes
+^^^^^^^^^
+
+* Fix error when Django happens to be imported before pytest-django runs.
+  Thanks to Will Harris for `the bug report
+  <https://github.com/pytest-dev/pytest-django/issues/289>`__.
+
+Features
+^^^^^^^^
+* Added a new option ``--migrations`` to negate a default usage of
+  ``--nomigrations``.
+
+* The previously internal pytest-django fixture that handles database creation
+  and setup has been refactored, refined and made a public API.
+
+  This opens up more flexibility and advanced use cases to configure the test
+  database in new ways.
+
+  See :ref:`advanced-database-configuration` for more information on the new
+  fixtures and example use cases.
+
+Compatibility
+^^^^^^^^^^^^^
+* Official for the pytest 3.0.0 (2.9.2 release should work too, though). The
+  documentation is updated to mention ``pytest`` instead of ``py.test``.
+
+* Django versions 1.4, 1.5 and 1.6 is no longer supported. The supported
+  versions are now 1.7 and forward. Django master is supported as of
+  2016-08-21.
+
+* pytest-django no longer supports Python 2.6.
+
+* Specifying the ``DJANGO_TEST_LIVE_SERVER_ADDRESS`` environment variable is no
+  longer supported. Use ``DJANGO_LIVE_TEST_SERVER_ADDRESS`` instead.
+
+* Ensuring accidental database access is now stricter than before. Previously
+  database access was prevented on the cursor level. To be safer and prevent
+  more cases, it is now prevented at the connection level. If you previously
+  had tests which interacted with the databases without a database cursor, you
+  will need to mark them with the ``pytest.mark.django_db`` marker or
+  request the ``db`` fixture.
+
+* The previously undocumented internal fixtures ``_django_db_setup``,
+  ``_django_cursor_wrapper`` have been removed in favour of the new public
+  fixtures. If you previously relied on these internal fixtures, you must
+  update your code. See :ref:`advanced-database-configuration` for more
+  information on the new fixtures and example use cases.
+
+v2.9.1
+------
+
+Bug fixes
+^^^^^^^^^
+
+* Fix regression introduced in 2.9.0 that caused TestCase subclasses with
+  mixins to cause errors. Thanks MikeVL for `the bug report
+  <https://github.com/pytest-dev/pytest-django/issues/280>`__.
+
+
+v2.9.0
+------
+
+v2.9.0 focus on compatibility with Django 1.9 and master as well as pytest 2.8.1
+and Python 3.5
+
+Features
+^^^^^^^^
+* ``--fail-on-template-vars`` - fail tests for invalid variables in templates.
+  Thanks to Johannes Hoppe for idea and implementation. Thanks Daniel Hahler
+  for review and feedback.
+
+Bug fixes
+^^^^^^^^^
+* Ensure urlconf is properly reset when using @pytest.mark.urls. Thanks to
+  Sarah Bird, David Szotten, Daniel Hahler and Yannick PÉROUX for patch and
+  discussions. Fixes `issue #183
+  <https://github.com/pytest-dev/pytest-django/issues/183>`__.
+
+* Call ``setUpClass()`` in Django ``TestCase`` properly when test class is
+  inherited multiple places. Thanks to Benedikt Forchhammer for report and
+  initial test case. Fixes `issue #265
+  <https://github.com/pytest-dev/pytest-django/issues/265>`__.
+
+Compatibility
+^^^^^^^^^^^^^
+
+* Settings defined in ``pytest.ini``/``tox.ini``/``setup.cfg`` used to override
+  ``DJANGO_SETTINGS_MODULE`` defined in the environment. Previously the order was
+  undocumented. Now, instead the settings from the environment will be used
+  instead. If you previously relied on overriding the environment variable,
+  you can instead specify ``addopts = --ds=yourtestsettings`` in the ini-file
+  which will use the test settings. See `PR #199
+  <https://github.com/pytest-dev/pytest-django/pull/199>`__.
+
+* Support for Django 1.9.
+
+* Support for Django master (to be 1.10) as of 2015-10-06.
+
+* Drop support for Django 1.3. While pytest-django supports a wide range of
+  Django versions, extended for Django 1.3 was dropped in february 2013.
+
+v2.8.0
+------
+
+Features
+^^^^^^^^
+
+* pytest's verbosity is being used for Django's code to setup/teardown the test
+  database (#172).
+
+* Added a new option `--nomigrations` to avoid running Django 1.7+ migrations
+  when constructing the test database. Huge thanks to Renan Ivo for complete
+  patch, tests and documentation.
+
+Bug fixes
+^^^^^^^^^
+
+* Fixed compatibility issues related to Django 1.8's
+  `setUpClass`/`setUpTestData`. Django 1.8 is now a fully supported version.
+  Django master as of 2014-01-18 (the Django 1.9 branch) is also supported.
+
+v2.7.0
+------
+
+Features
+^^^^^^^^
+
+* New fixtures: ``admin_user``, ``django_user_model`` and
+  ``django_username_field`` (#109).
+
+* Automatic discovery of Django projects to make it easier for new users. This
+  change is slightly backward incompatible, if you encounter problems with it,
+  the old behaviour can be restored by adding this to ``pytest.ini``,
+  ``setup.cfg`` or ``tox.ini``:
+
+  .. code-block:: ini
+
+    [pytest]
+    django_find_project = false
+
+  Please see the :ref:`managing_python_path` section for more information.
+
+Bugfixes
+^^^^^^^^
+
+* Fix interaction between ``db`` and ``transaction_db`` fixtures (#126).
+
+* Fix admin client with custom user models (#124). Big thanks to Benjamin
+  Hedrich and Dmitry Dygalo for patch and tests.
+
+* Fix usage of South migrations, which were unconditionally disabled previously
+  (#22).
+
+* Fixed #119, #134: Call ``django.setup()`` in Django >=1.7 directly after
+  settings is loaded to ensure proper loading of Django applications. Thanks to
+  Ionel Cristian Mărieș, Daniel Hahler, Tymur Maryokhin, Kirill SIbirev, Paul
+  Collins, Aymeric Augustin, Jannis Leidel, Baptiste Mispelon and Anatoly
+  Bubenkoff for report, discussion and feedback.
+
+* `The `live_server`` fixture can now serve static files also for Django>=1.7
+  if the ``django.contrib.staticfiles`` app is installed. (#140).
+
+* ``DJANGO_LIVE_TEST_SERVER_ADDRESS`` environment variable is read instead
+  of ``DJANGO_TEST_LIVE_SERVER_ADDRESS``. (#140)
+
+v2.6.2
+------
+
+* Fixed a bug that caused doctests to runs. Thanks to @jjmurre for the patch
+
+* Fixed issue #88 - make sure to use SQLite in memory database when running
+  with pytest-xdist.
+
+v2.6.1
+------
+This is a bugfix/support release with no new features:
+
+* Added support for Django 1.7 beta and Django master as of 2014-04-16.
+  pytest-django is now automatically tested against the latest git master
+  version of Django.
+
+* Support for MySQL with MyISAM tables. Thanks to Zach Kanzler and Julen Ruiz
+  Aizpuru for fixing this. This fixes issue #8 #64.
+
+v2.6.0
+------
+* Experimental support for Django 1.7 / Django master as of 2014-01-19.
+
+  pytest-django is now automatically tested against the latest git version of
+  Django. The support is experimental since Django 1.7 is not yet released, but
+  the goal is to always be up to date with the latest Django master
+
+v2.5.1
+------
+Invalid release accidentally pushed to PyPI (identical to 2.6.1). Should not be
+used - use 2.6.1 or newer to avoid confusion.
+
+
+v2.5.0
+------
+* Python 2.5 compatibility dropped. py.test 2.5 dropped support for Python 2.5,
+  therefore it will be hard to properly support in pytest-django. The same
+  strategy as for pytest itself is used: No code will be changed to prevent
+  Python 2.5 from working, but it will not be actively tested.
+
+* pytest-xdist support: it is now possible to run tests in parallel. Just use
+  pytest-xdist as normal (pass -n to py.test). One database will be created for
+  each subprocess so that tests run independent from each other.
+
+v2.4.0
+------
+* Support for py.test 2.4 pytest_load_initial_conftests. This makes it possible
+  to import Django models in project conftest.py files, since pytest-django
+  will be initialized before the conftest.py is loaded.
+
+v2.3.1
+------
+* Support for Django 1.5 custom user models, thanks to Leonardo Santagada.
+
+
+v2.3.0
+------
+
+* Support for configuring settings via django-configurations. Big thanks to
+  Donald Stufft for this feature!
+
+v2.2.1
+------
+
+* Fixed an issue with the settings fixture when used in combination with
+  django-appconf. It now uses pytest's monkeypatch internally and should
+  be more robust.
+
+v2.2.0
+------
+
+* Python 3 support. pytest-django now supports Python 3.2 and 3.3 in addition
+  to 2.5-2.7. Big thanks to Rafal Stozek for making this happen!
+
+v2.1.0
+------
+
+* Django 1.5 support. pytest-django is now tested against 1.5 for Python
+  2.6-2.7. This is the first step towards Python 3 support.
+
+v2.0.1
+------
+
+* Fixed #24/#25: Make it possible to configure Django via
+  ``django.conf.settings.configure()``.
+
+* Fixed #26: Don't set DEBUG_PROPAGATE_EXCEPTIONS = True for test runs. Django
+  does not change this setting in the default test runner, so pytest-django
+  should not do it either.
+
+v2.0.0
+------
+
+This release is *backward incompatible*. The biggest change is the need
+to add the ``pytest.mark.django_db`` to tests which require database
+access.
+
+Finding such tests is generally very easy: just run your test suite, the
+tests which need database access will fail. Add ``pytestmark =
+pytest.mark.django_db`` to the module/class or decorate them with
+``@pytest.mark.django_db``.
+
+Most of the internals have been rewritten, exploiting py.test's new
+fixtures API. This release would not be possible without Floris
+Bruynooghe who did the port to the new fixture API and fixed a number of
+bugs.
+
+The tests for pytest-django itself has been greatly improved, paving the
+way for easier additions of new and exciting features in the future!
+
+* Semantic version numbers will now be used for releases, see http://semver.org/.
+
+* Do not allow database access in tests by default.  Introduce
+  ``pytest.mark.django_db`` to enable database access.
+
+* Large parts re-written using py.test's 2.3 fixtures API (issue #9).
+
+  - Fixes issue #17: Database changes made in fixtures or funcargs
+    will now be reverted as well.
+
+  - Fixes issue 21: Database teardown errors are no longer hidden.
+
+  - Fixes issue 16: Database setup and teardown for non-TestCase
+    classes works correctly.
+
+* ``pytest.urls()`` is replaced by the standard marking API and is now
+  used as ``pytest.mark.urls()``
+
+* Make the plugin behave gracefully without DJANGO_SETTINGS_MODULE
+  specified.  ``py.test`` will still work and tests needing django
+  features will skip (issue #3).
+
+* Allow specifying of ``DJANGO_SETTINGS_MODULE`` on the command line
+  (``--ds=settings``) and py.test ini configuration file as well as the
+  environment variable (issue #3).
+
+* Deprecate the ``transaction_test_case`` decorator, this is now
+  integrated with the ``django_db`` mark.
+
+v1.4
+----
+* Removed undocumented pytest.load_fixture: If you need this feature, just use
+  ``django.management.call_command('loaddata', 'foo.json')`` instead.
+* Fixed issue with RequestFactory in Django 1.3.
+
+* Fixed issue with RequestFactory in Django 1.3.
+
+v1.3
+----
+* Added ``--reuse-db`` and ``--create-db`` to allow database re-use. Many
+  thanks to `django-nose <https://github.com/jbalogh/django-nose>`__ for
+  code and inspiration for this feature.
+
+v1.2.2
+------
+* Fixed Django 1.3 compatibility.
+
+v1.2.1
+------
+* Disable database access and raise errors when using --no-db and accessing
+  the database by accident.
+
+v1.2
+----
+* Added the ``--no-db`` command line option.
+
+v1.1.1
+------
+* Flush tables after each test run with transaction_test_case instead of before.
+
+v1.1
+----
+
+* The initial release of this fork from `Ben Firshman original project
+  <http://github.com/bfirsh/pytest_django>`__
+* Added documentation
+* Uploaded to PyPI for easy installation
+* Added the ``transaction_test_case`` decorator for tests that needs real transactions
+* Added initial implementation for live server support via a funcarg (no docs yet, it might change!)

+ 58 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/conf.py

@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+import datetime
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "_ext")))
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+    'sphinx.ext.doctest',
+    'sphinx.ext.intersphinx',
+    'pytestdocs',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'pytest-django'
+copyright = u'%d, Andreas Pelme and contributors' % datetime.date.today().year
+
+exclude_patterns = ['_build']
+
+pygments_style = 'sphinx'
+
+html_theme = 'sphinx_rtd_theme'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'pytest-djangodoc'
+
+intersphinx_mapping = {
+    'python': ('https://docs.python.org/3', None),
+    'django': ('https://docs.djangoproject.com/en/dev/',
+               'https://docs.djangoproject.com/en/dev/_objects/'),
+    'pytest': ('https://docs.pytest.org/en/latest/', None),
+}
+
+
+def setup(app):
+    # Allow linking to pytest's confvals.
+    app.add_object_type(
+        "confval",
+        "pytest-confval",
+        objname="configuration value",
+        indextemplate="pair: %s; configuration value",
+    )

+ 106 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/configuring_django.rst

@@ -0,0 +1,106 @@
+.. _configuring_django_settings:
+
+Configuring Django settings
+===========================
+
+There are a couple of different ways Django settings can be provided for
+the tests.
+
+The environment variable ``DJANGO_SETTINGS_MODULE``
+---------------------------------------------------
+
+Running the tests with DJANGO_SETTINGS_MODULE defined will find the
+Django settings the same way Django does by default.
+
+Example::
+
+    $ export DJANGO_SETTINGS_MODULE=test_settings
+    $ pytest
+
+or::
+
+    $ DJANGO_SETTINGS_MODULE=test_settings pytest
+
+
+Command line option ``--ds=SETTINGS``
+-------------------------------------
+
+Example::
+
+    $ pytest --ds=test_settings
+
+
+``pytest.ini`` settings
+-----------------------
+
+Example contents of pytest.ini::
+
+    [pytest]
+    DJANGO_SETTINGS_MODULE = test_settings
+
+Order of choosing settings
+--------------------------
+
+The order of precedence is, from highest to lowest:
+
+* The command line option ``--ds``
+* The environment variable ``DJANGO_SETTINGS_MODULE``
+* The ``DJANGO_SETTINGS_MODULE`` option in the configuration file -
+  ``pytest.ini``, or other file that Pytest finds such as ``tox.ini``
+
+If you want to use the highest precedence in the configuration file, you can
+use ``addopts = --ds=yourtestsettings``.
+
+Using django-configurations
+---------------------------
+
+There is support for using `django-configurations <https://pypi.python.org/pypi/django-configurations/>`_.
+
+To do so configure the settings class using an environment variable, the
+``--dc`` flag, or ``pytest.ini`` option ``DJANGO_CONFIGURATION``.
+
+Environment Variable::
+
+    $ export DJANGO_CONFIGURATION=MySettings
+    $ pytest
+
+Command Line Option::
+
+    $ pytest --dc=MySettings
+
+INI File Contents::
+
+    [pytest]
+    DJANGO_CONFIGURATION=MySettings
+
+Using ``django.conf.settings.configure()``
+------------------------------------------
+
+Django settings can be set up by calling ``django.conf.settings.configure()``.
+
+This can be done from your project's ``conftest.py`` file::
+
+    from django.conf import settings
+
+    def pytest_configure():
+        settings.configure(DATABASES=...)
+
+Changing your app before Django gets set up
+-------------------------------------------
+
+pytest-django calls :py:func:`django.setup` automatically.  If you want to do
+anything before this, you have to create a pytest plugin and use
+the :py:func:`~_pytest.hookspec.pytest_load_initial_conftests` hook, with
+``tryfirst=True``, so that it gets run before the hook in pytest-django
+itself::
+
+    @pytest.hookimpl(tryfirst=True)
+    def pytest_load_initial_conftests(early_config, parser, args):
+        import project.app.signals
+
+        def noop(*args, **kwargs):
+            pass
+
+        project.app.signals.something = noop
+
+This plugin can then be used e.g. via ``-p`` in :pytest-confval:`addopts`.

+ 242 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/contributing.rst

@@ -0,0 +1,242 @@
+#############################
+Contributing to pytest-django
+#############################
+
+Like every open-source project, pytest-django is always looking for motivated
+individuals to contribute to its source code.  However, to ensure the highest
+code quality and keep the repository nice and tidy, everybody has to follow a
+few rules (nothing major, I promise :) )
+
+
+*********
+Community
+*********
+
+The fastest way to get feedback on contributions/bugs is usually to open an
+issue in the `issue tracker`_.
+
+Discussions also happen via IRC in #pylib on irc.freenode.org. You may also
+be interested in following `@andreaspelme`_ on Twitter.
+
+*************
+In a nutshell
+*************
+
+Here's what the contribution process looks like, in a bullet-points fashion:
+
+#. pytest-django is hosted on `GitHub`_, at
+   https://github.com/pytest-dev/pytest-django
+#. The best method to contribute back is to create an account there and fork
+   the project. You can use this fork as if it was your own project, and should
+   push your changes to it.
+#. When you feel your code is good enough for inclusion, "send us a `pull
+   request`_", by using the nice GitHub web interface.
+
+
+*****************
+Contributing Code
+*****************
+
+
+Getting the source code
+=======================
+
+- Code will be reviewed and tested by at least one core developer, preferably
+  by several. Other community members are welcome to give feedback.
+- Code *must* be tested. Your pull request should include unit-tests (that
+  cover the piece of code you're submitting, obviously).
+- Documentation should reflect your changes if relevant. There is nothing worse
+  than invalid documentation.
+- Usually, if unit tests are written, pass, and your change is relevant, then
+  your pull request will be merged.
+
+Since we're hosted on GitHub, pytest-django uses `git`_ as a version control
+system.
+
+The `GitHub help`_ is very well written and will get you started on using git
+and GitHub in a jiffy. It is an invaluable resource for newbies and oldtimers
+alike.
+
+
+Syntax and conventions
+======================
+
+We try to conform to `PEP8`_ as much as possible. A few highlights:
+
+- Indentation should be exactly 4 spaces. Not 2, not 6, not 8. **4**. Also,
+  tabs are evil.
+- We try (loosely) to keep the line length at 79 characters. Generally the rule
+  is "it should look good in a terminal-based editor" (eg vim), but we try not
+  be [Godwin's law] about it.
+
+
+Process
+=======
+
+This is how you fix a bug or add a feature:
+
+#. `fork`_ the repository on GitHub.
+#. Checkout your fork.
+#. Hack hack hack, test test test, commit commit commit, test again.
+#. Push to your fork.
+#. Open a pull request.
+
+
+Tests
+=====
+
+Having a wide and comprehensive library of unit-tests and integration tests is
+of exceeding importance. Contributing tests is widely regarded as a very
+prestigious contribution (you're making everybody's future work much easier by
+doing so). Good karma for you. Cookie points. Maybe even a beer if we meet in
+person :)
+
+Generally tests should be:
+
+- Unitary (as much as possible). I.E. should test as much as possible only on
+  one function/method/class. That's the very definition of unit tests.
+  Integration tests are also interesting obviously, but require more time to
+  maintain since they have a higher probability of breaking.
+- Short running. No hard numbers here, but if your one test doubles the time it
+  takes for everybody to run them, it's probably an indication that you're
+  doing it wrong.
+
+In a similar way to code, pull requests will be reviewed before pulling
+(obviously), and we encourage discussion via code review (everybody learns
+something this way) or in the IRC channel.
+
+Running the tests
+-----------------
+
+There is a Makefile in the repository which aids in setting up a virtualenv
+and running the tests::
+
+    $ make test
+
+You can manually create the virtualenv using::
+
+    $ make testenv
+
+This will install a virtualenv with pytest and the latest stable version of
+Django. The virtualenv can then be activated with::
+
+    $ source bin/activate
+
+Then, simply invoke pytest to run the test suite::
+
+    $ pytest --ds=pytest_django_test.settings_sqlite
+
+
+tox can be used to run the test suite under different configurations by
+invoking::
+
+    $ tox
+
+There is a huge number of unique test configurations (98 at the time of
+writing), running them all will take a long time. All valid configurations can
+be found in `tox.ini`. To test against a few of them, invoke tox with the `-e`
+flag::
+
+    $ tox -e py36-dj111-postgres,py27-dj111-mysql_innodb
+
+This will run the tests on Python 3.6/Django 1.11/PostgeSQL and Python
+2.7/Django 1.11/MySQL.
+
+
+Measuring test coverage
+-----------------------
+
+Some of the tests are executed in subprocesses. Because of that regular
+coverage measurements (using pytest-cov plugin) are not reliable.
+
+If you want to measure coverage you'll need to create .pth file as described in
+`subprocess section of coverage documentation`_. If you're using
+``setup.py develop`` you should uninstall pytest_django (using pip)
+for the time of measuring coverage.
+
+You'll also need mysql and postgres databases. There are predefined settings
+for each database in the tests directory. You may want to modify these files
+but please don't include them in your pull requests.
+
+After this short initial setup you're ready to run tests::
+
+    $ COVERAGE_PROCESS_START=`pwd`/.coveragerc COVERAGE_FILE=`pwd`/.coverage PYTHONPATH=`pwd` pytest --ds=pytest_django_test.settings_postgres
+
+You should repeat the above step for sqlite and mysql before the next step.
+This step will create a lot of ``.coverage`` files with additional suffixes for
+every process.
+
+The final step is to combine all the files created by different processes and
+generate the html coverage report::
+
+    $ coverage combine
+    $ coverage html
+
+Your coverage report is now ready in the ``htmlcov`` directory.
+
+
+Continuous integration
+----------------------
+
+`Travis`_ is used to automatically run all tests against all supported versions
+of Python, Django and different database backends.
+
+The `pytest-django Travis`_ page shows the latest test run. Travis will
+automatically pick up pull requests, test them and report the result directly
+in the pull request.
+
+**************************
+Contributing Documentation
+**************************
+
+Perhaps considered "boring" by hard-core coders, documentation is sometimes
+even more important than code! This is what brings fresh blood to a project,
+and serves as a reference for oldtimers. On top of this, documentation is the
+one area where less technical people can help most - you just need to write a
+semi-decent English. People need to understand you. We don't care about style
+or correctness.
+
+Documentation should be:
+
+- We use `Sphinx`_/`restructuredText`_. So obviously this is the format you
+  should use :) File extensions should be .rst.
+- Written in English. We can discuss how it would bring more people to the
+  project to have a Klingon translation or anything, but that's a problem we
+  will ask ourselves when we already have a good documentation in English.
+- Accessible. You should assume the reader to be moderately familiar with
+  Python and Django, but not anything else. Link to documentation of libraries
+  you use, for example, even if they are "obvious" to you (South is the first
+  example that comes to mind - it's obvious to any Django programmer, but not
+  to any newbie at all).
+  A brief description of what it does is also welcome.
+
+Pulling of documentation is pretty fast and painless. Usually somebody goes
+over your text and merges it, since there are no "breaks" and that GitHub
+parses rst files automagically it's really convenient to work with.
+
+Also, contributing to the documentation will earn you great respect from the
+core developers. You get good karma just like a test contributor, but you get
+double cookie points. Seriously. You rock.
+
+
+.. note::
+
+  This very document is based on the contributing docs of the `django CMS`_
+  project. Many thanks for allowing us to steal it!
+
+
+.. _fork: https://github.com/pytest-dev/pytest-django
+.. _issue tracker: https://github.com/pytest-dev/pytest-django/issues
+.. _Sphinx: http://sphinx.pocoo.org/
+.. _PEP8: http://www.python.org/dev/peps/pep-0008/
+.. _GitHub : http://www.github.com
+.. _GitHub help : http://help.github.com
+.. _freenode : http://freenode.net/
+.. _@andreaspelme : https://twitter.com/andreaspelme
+.. _pull request : http://help.github.com/send-pull-requests/
+.. _git : http://git-scm.com/
+.. _restructuredText: http://docutils.sourceforge.net/docs/ref/rst/introduction.html
+.. _django CMS: https://www.django-cms.org/
+.. _Travis: https://travis-ci.org/
+.. _pytest-django Travis: https://travis-ci.org/pytest-dev/pytest-django
+.. _`subprocess section of coverage documentation`: http://nedbatchelder.com/code/coverage/subprocess.html

+ 493 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/database.rst

@@ -0,0 +1,493 @@
+Database creation/re-use
+========================
+
+``pytest-django`` takes a conservative approach to enabling database
+access.  By default your tests will fail if they try to access the
+database.  Only if you explicitly request database access will this be
+allowed.  This encourages you to keep database-needing tests to a
+minimum which is a best practice since next-to-no business logic
+should be requiring the database.  Moreover it makes it very clear
+what code uses the database and catches any mistakes.
+
+Enabling database access in tests
+---------------------------------
+
+You can use `pytest marks <https://pytest.org/en/latest/mark.html>`_ to
+tell ``pytest-django`` your test needs database access::
+
+   import pytest
+
+   @pytest.mark.django_db
+   def test_my_user():
+       me = User.objects.get(username='me')
+       assert me.is_superuser
+
+It is also possible to mark all tests in a class or module at once.
+This demonstrates all the ways of marking, even though they overlap.
+Just one of these marks would have been sufficient.  See the `pytest
+documentation
+<https://pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules>`_
+for detail::
+
+   import pytest
+
+   pytestmark = pytest.mark.django_db
+
+   @pytest.mark.django_db
+   class TestUsers:
+       pytestmark = pytest.mark.django_db
+       def test_my_user(self):
+           me = User.objects.get(username='me')
+           assert me.is_superuser
+
+
+By default ``pytest-django`` will set up the Django databases the
+first time a test needs them.  Once setup the database is cached for
+used for all subsequent tests and rolls back transactions to isolate
+tests from each other.  This is the same way the standard Django
+`TestCase
+<https://docs.djangoproject.com/en/1.9/topics/testing/tools/#testcase>`_
+uses the database.  However ``pytest-django`` also caters for
+transaction test cases and allows you to keep the test databases
+configured across different test runs.
+
+
+Testing transactions
+--------------------
+
+Django itself has the ``TransactionTestCase`` which allows you to test
+transactions and will flush the database between tests to isolate
+them.  The downside of this is that these tests are much slower to
+set up due to the required flushing of the database.
+``pytest-django`` also supports this style of tests, which you can
+select using an argument to the ``django_db`` mark::
+
+   @pytest.mark.django_db(transaction=True)
+   def test_spam():
+       pass  # test relying on transactions
+
+
+Tests requiring multiple databases
+----------------------------------
+
+Currently ``pytest-django`` does not specifically support Django's
+multi-database support.
+
+You can however use normal :class:`~django.test.TestCase` instances to use its
+:ref:`django:topics-testing-advanced-multidb` support.
+In particular, if your database is configured for replication, be sure to read
+about :ref:`django:topics-testing-primaryreplica`.
+
+If you have any ideas about the best API to support multiple databases
+directly in ``pytest-django`` please get in touch, we are interested
+in eventually supporting this but unsure about simply following
+Django's approach.
+
+See `https://github.com/pytest-dev/pytest-django/pull/431` for an idea /
+discussion to approach this.
+
+``--reuse-db`` - reuse the testing database between test runs
+--------------------------------------------------------------
+Using ``--reuse-db`` will create the test database in the same way as
+``manage.py test`` usually does.
+
+However, after the test run, the test database will not be removed.
+
+The next time a test run is started with ``--reuse-db``, the database will
+instantly be re used. This will allow much faster startup time for tests.
+
+This can be especially useful when running a few tests, when there are a lot
+of database tables to set up.
+
+``--reuse-db`` will not pick up schema changes between test runs. You must run
+the tests with ``--reuse-db --create-db`` to re-create the database according
+to the new schema. Running without ``--reuse-db`` is also possible, since the
+database will automatically be re-created.
+
+
+``--create-db`` - force re creation of the test database
+--------------------------------------------------------
+When used with ``--reuse-db``, this option will re-create the database,
+regardless of whether it exists or not.
+
+Example work flow with ``--reuse-db`` and ``--create-db``.
+-----------------------------------------------------------
+A good way to use ``--reuse-db`` and ``--create-db`` can be:
+
+* Put ``--reuse-db`` in your default options (in your project's ``pytest.ini`` file)::
+
+    [pytest]
+    addopts = --reuse-db
+
+* Just run tests with ``pytest``, on the first run the test database will be
+  created. The next test run it will be reused.
+
+* When you alter your database schema, run ``pytest --create-db``, to force
+  re-creation of the test database.
+
+``--nomigrations`` - Disable Django migrations
+----------------------------------------------
+
+Using ``--nomigrations`` will disable Django migrations and create the database
+by inspecting all models. It may be faster when there are several migrations to
+run in the database setup.  You can use ``--migrations`` to force running
+migrations in case ``--nomigrations`` is used, e.g. in ``setup.cfg``.
+
+.. _advanced-database-configuration:
+
+Advanced database configuration
+-------------------------------
+
+pytest-django provides options to customize the way database is configured. The
+default database construction mostly follows Django's own test runner. You can
+however influence all parts of the database setup process to make it fit in
+projects with special requirements.
+
+This section assumes some familiarity with the Django test runner, Django
+database creation and pytest fixtures.
+
+Fixtures
+########
+
+There are some fixtures which will let you change the way the database is
+configured in your own project. These fixtures can be overridden in your own
+project by specifying a fixture with the same name and scope in ``conftest.py``.
+
+.. admonition:: Use the pytest-django source code
+
+    The default implementation of these fixtures can be found in
+    `fixtures.py <https://github.com/pytest-dev/pytest-django/blob/master/pytest_django/fixtures.py>`_.
+
+    The code is relatively short and straightforward and can provide a
+    starting point when you need to customize database setup in your own
+    project.
+
+
+django_db_setup
+"""""""""""""""
+
+.. fixture:: django_db_setup
+
+This is the top-level fixture that ensures that the test databases are created
+and available. This fixture is session scoped (it will be run once per test
+session) and is responsible for making sure the test database is available for tests
+that need it.
+
+The default implementation creates the test database by applying migrations and removes
+databases after the test run.
+
+You can override this fixture in your own ``conftest.py`` to customize how test
+databases are constructed.
+
+django_db_modify_db_settings
+""""""""""""""""""""""""""""
+
+.. fixture:: django_db_modify_db_settings
+
+This fixture allows modifying `django.conf.settings.DATABASES` just before the
+databases are configured.
+
+If you need to customize the location of your test database, this is the
+fixture you want to override.
+
+The default implementation of this fixture requests the
+:fixture:`django_db_modify_db_settings_parallel_suffix` to provide compatibility
+with pytest-xdist.
+
+This fixture is by default requested from :fixture:`django_db_setup`.
+
+django_db_modify_db_settings_parallel_suffix
+""""""""""""""""""""""""""""""""""""""""""""
+
+.. fixture:: django_db_modify_db_settings_parallel_suffix
+
+Requesting this fixture will add a suffix to the database name when the tests
+are run via `pytest-xdist`, or via `tox` in parallel mode.
+
+This fixture is by default requested from
+:fixture:`django_db_modify_db_settings`.
+
+django_db_modify_db_settings_tox_suffix
+"""""""""""""""""""""""""""""""""""""""
+
+.. fixture:: django_db_modify_db_settings_tox_suffix
+
+Requesting this fixture will add a suffix to the database name when the tests
+are run via `tox` in parallel mode.
+
+This fixture is by default requested from
+:fixture:`django_db_modify_db_settings_parallel_suffix`.
+
+django_db_modify_db_settings_xdist_suffix
+"""""""""""""""""""""""""""""""""""""""""
+
+.. fixture:: django_db_modify_db_settings_xdist_suffix
+
+Requesting this fixture will add a suffix to the database name when the tests
+are run via `pytest-xdist`.
+
+This fixture is by default requested from
+:fixture:`django_db_modify_db_settings_parallel_suffix`.
+
+django_db_use_migrations
+""""""""""""""""""""""""
+
+.. fixture:: django_db_use_migrations
+
+Returns whether or not to use migrations to create the test
+databases.
+
+The default implementation returns the value of the
+``--migrations``/``--nomigrations`` command line options.
+
+This fixture is by default requested from :fixture:`django_db_setup`.
+
+django_db_keepdb
+""""""""""""""""
+
+.. fixture:: django_db_keepdb
+
+Returns whether or not to re-use an existing database and to keep it after the
+test run.
+
+The default implementation handles the ``--reuse-db`` and ``--create-db``
+command line options.
+
+This fixture is by default requested from :fixture:`django_db_setup`.
+
+django_db_createdb
+""""""""""""""""""
+
+.. fixture:: django_db_createdb
+
+Returns whether or not the database is to be re-created before running any
+tests.
+
+This fixture is by default requested from :fixture:`django_db_setup`.
+
+django_db_blocker
+"""""""""""""""""
+
+.. fixture:: django_db_blocker
+
+.. warning::
+    It does not manage transactions and changes made to the database will not
+    be automatically restored. Using the ``pytest.mark.django_db`` marker
+    or :fixture:`db` fixture, which wraps database changes in a transaction and
+    restores the state is generally the thing you want in tests. This marker
+    can be used when you are trying to influence the way the database is
+    configured.
+
+Database access is by default not allowed. ``django_db_blocker`` is the object
+which can allow specific code paths to have access to the database. This
+fixture is used internally to implement the ``db`` fixture.
+
+
+:fixture:`django_db_blocker` can be used as a context manager to enable database
+access for the specified block::
+
+    @pytest.fixture
+    def myfixture(django_db_blocker):
+        with django_db_blocker.unblock():
+            ...  # modify something in the database
+
+You can also manage the access manually via these methods:
+
+.. py:method:: django_db_blocker.unblock()
+
+  Enable database access. Should be followed by a call to
+  :func:`~django_db_blocker.restore`.
+
+.. py:method:: django_db_blocker.block()
+
+  Disable database access. Should be followed by a call to
+  :func:`~django_db_blocker.restore`.
+
+.. py:function:: django_db_blocker.restore()
+
+  Restore the previous state of the database blocking.
+
+Examples
+########
+
+Using a template database for tests
+"""""""""""""""""""""""""""""""""""
+
+This example shows how a pre-created PostgreSQL source database can be copied
+and used for tests.
+
+Put this into ``conftest.py``::
+
+    import pytest
+    from django.db import connections
+
+    import psycopg2
+    from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
+
+
+    def run_sql(sql):
+        conn = psycopg2.connect(database='postgres')
+        conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
+        cur = conn.cursor()
+        cur.execute(sql)
+        conn.close()
+
+
+    @pytest.yield_fixture(scope='session')
+    def django_db_setup():
+        from django.conf import settings
+
+        settings.DATABASES['default']['NAME'] = 'the_copied_db'
+
+        run_sql('DROP DATABASE IF EXISTS the_copied_db')
+        run_sql('CREATE DATABASE the_copied_db TEMPLATE the_source_db')
+
+        yield
+
+        for connection in connections.all():
+            connection.close()
+
+        run_sql('DROP DATABASE the_copied_db')
+
+
+Using an existing, external database for tests
+""""""""""""""""""""""""""""""""""""""""""""""
+
+This example shows how you can connect to an existing database and use it for
+your tests. This example is trivial, you just need to disable all of
+pytest-django and Django's test database creation and point to the existing
+database. This is achieved by simply implementing a no-op
+:fixture:`django_db_setup` fixture.
+
+Put this into ``conftest.py``::
+
+    import pytest
+
+
+    @pytest.fixture(scope='session')
+    def django_db_setup():
+        settings.DATABASES['default'] = {
+            'ENGINE': 'django.db.backends.mysql',
+            'HOST': 'db.example.com',
+            'NAME': 'external_db',
+        }
+
+
+Populate the database with initial test data
+""""""""""""""""""""""""""""""""""""""""""""
+
+This example shows how you can populate the test database with test data. The
+test data will be saved in the database, i.e. it will not just be part of a
+transactions. This example uses Django's fixture loading mechanism, but it can
+be replaced with any way of loading data into the database.
+
+Notice that :fixture:`django_db_setup` is in the argument list. This may look
+odd at first, but it will make sure that the original pytest-django fixture
+is used to create the test database. When ``call_command`` is invoked, the
+test database is already prepared and configured.
+
+Put this in ``conftest.py``::
+
+    import pytest
+
+    from django.core.management import call_command
+
+    @pytest.fixture(scope='session')
+    def django_db_setup(django_db_setup, django_db_blocker):
+        with django_db_blocker.unblock():
+            call_command('loaddata', 'your_data_fixture.json')
+
+Use the same database for all xdist processes
+"""""""""""""""""""""""""""""""""""""""""""""
+
+By default, each xdist process gets its own database to run tests on. This is
+needed to have transactional tests that do not interfere with each other.
+
+If you instead want your tests to use the same database, override the
+:fixture:`django_db_modify_db_settings` to not do anything. Put this in
+``conftest.py``::
+
+    import pytest
+
+
+    @pytest.fixture(scope='session')
+    def django_db_modify_db_settings():
+        pass
+
+Randomize database sequences
+""""""""""""""""""""""""""""
+
+You can customize the test database after it has been created by extending the
+:fixture:`django_db_setup` fixture. This example shows how to give a PostgreSQL
+sequence a random starting value. This can be used to detect and prevent
+primary key id's from being hard-coded in tests.
+
+Put this in ``conftest.py``::
+
+    import random
+    import pytest
+    from django.db import connection
+
+
+    @pytest.fixture(scope='session')
+    def django_db_setup(django_db_setup, django_db_blocker):
+        with django_db_blocker.unblock():
+            cur = connection.cursor()
+            cur.execute('ALTER SEQUENCE app_model_id_seq RESTART WITH %s;',
+                        [random.randint(10000, 20000)])
+
+Create the test database from a custom SQL script
+"""""""""""""""""""""""""""""""""""""""""""""""""
+
+You can replace the :fixture:`django_db_setup` fixture and run any code in its
+place. This includes creating your database by hand by running a SQL script
+directly. This example shows sqlite3's executescript method. In a more
+general use case, you probably want to load the SQL statements from a file or
+invoke the ``psql`` or the ``mysql`` command line tool.
+
+Put this in ``conftest.py``::
+
+    import pytest
+    from django.db import connection
+
+
+    @pytest.fixture(scope='session')
+    def django_db_setup(django_db_blocker):
+        with django_db_blocker.unblock():
+            with connection.cursor() as c:
+                c.executescript('''
+                DROP TABLE IF EXISTS theapp_item;
+                CREATE TABLE theapp_item (id, name);
+                INSERT INTO theapp_item (name) VALUES ('created from a sql script');
+                ''')
+
+.. warning::
+    This snippet shows ``cursor().executescript()`` which is `sqlite` specific, for
+    other database engines this method might differ. For instance, psycopg2 uses
+    ``cursor().execute()``.
+
+
+Use a read only database
+""""""""""""""""""""""""
+
+You can replace the ordinary `django_db_setup` to completely avoid database
+creation/migrations. If you have no need for rollbacks or truncating tables,
+you can simply avoid blocking the database and use it directly. When using this
+method you must ensure that your tests do not change the database state.
+
+
+Put this in ``conftest.py``::
+
+    import pytest
+
+
+    @pytest.fixture(scope='session')
+    def django_db_setup():
+        """Avoid creating/setting up the test database"""
+        pass
+
+
+    @pytest.fixture
+    def db_access_without_rollback_and_truncate(request, django_db_setup, django_db_blocker):
+        django_db_blocker.unblock()
+        request.addfinalizer(django_db_blocker.restore)

+ 150 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/faq.rst

@@ -0,0 +1,150 @@
+FAQ
+===
+
+.. _faq-import-error:
+
+I see an error saying "could not import myproject.settings"
+-----------------------------------------------------------
+
+pytest-django tries to automatically add your project to the Python path by
+looking for a ``manage.py`` file and adding its path to the Python path.
+
+If this for some reason fails for you, you have to manage your Python paths
+explicitly. See the documentation on :ref:`managing_the_python_path_explicitly`
+for more information.
+
+How can I make sure that all my tests run with a specific locale?
+-----------------------------------------------------------------
+
+Create a `pytest fixture <https://pytest.org/en/latest/fixture.html>`_ that is
+automatically run before each test case. To run all tests with the english
+locale, put the following code in your project's `conftest.py`_ file:
+
+.. code-block:: python
+
+    from django.utils.translation import activate
+
+    @pytest.fixture(autouse=True)
+    def set_default_language():
+        activate('en')
+
+.. _conftest.py: http://docs.pytest.org/en/latest/plugins.html
+
+.. _faq-tests-not-being-picked-up:
+
+My tests are not being found. Why?
+----------------------------------
+
+By default, pytest looks for tests in files named ``test_*.py`` (note that
+this is not the same as ``test*.py``) and ``*_test.py``.  If you have your
+tests in files with other names, they will not be collected.  Note that
+Django's ``startapp`` manage command creates an ``app_dir/tests.py`` file.
+Also, it is common to put tests under ``app_dir/tests/views.py``, etc.
+
+To find those tests, create a ``pytest.ini`` file in your project root and add
+an appropriate ``python_files`` line to it:
+
+.. code-block:: ini
+
+    [pytest]
+    python_files = tests.py test_*.py *_tests.py
+
+See the `related pytest docs`_ for more details.
+
+When debugging test collection problems, the ``--collectonly`` flag and
+``-rs`` (report skipped tests) can be helpful.
+
+.. _related pytest docs:
+    http://docs.pytest.org/en/latest/example/pythoncollection.html#changing-naming-conventions
+
+Does pytest-django work with the pytest-xdist plugin?
+-----------------------------------------------------
+
+Yes. pytest-django supports running tests in parallel with pytest-xdist. Each
+process created by xdist gets its own separate database that is used for the
+tests. This ensures that each test can run independently, regardless of whether
+transactions are tested or not.
+
+.. _faq-getting-help:
+
+How can I use ``manage.py test`` with pytest-django?
+----------------------------------------------------
+
+pytest-django is designed to work with the ``pytest`` command, but if you
+really need integration with ``manage.py test``, you can create a simple
+test runner like this:
+
+.. code-block:: python
+
+    class PytestTestRunner(object):
+        """Runs pytest to discover and run tests."""
+
+        def __init__(self, verbosity=1, failfast=False, keepdb=False, **kwargs):
+            self.verbosity = verbosity
+            self.failfast = failfast
+            self.keepdb = keepdb
+
+        def run_tests(self, test_labels):
+            """Run pytest and return the exitcode.
+
+            It translates some of Django's test command option to pytest's.
+            """
+            import pytest
+
+            argv = []
+            if self.verbosity == 0:
+                argv.append('--quiet')
+            if self.verbosity == 2:
+                argv.append('--verbose')
+            if self.verbosity == 3:
+                argv.append('-vv')
+            if self.failfast:
+                argv.append('--exitfirst')
+            if self.keepdb:
+                argv.append('--reuse-db')
+
+            argv.extend(test_labels)
+            return pytest.main(argv)
+
+Add the path to this class in your Django settings:
+
+.. code-block:: python
+
+    TEST_RUNNER = 'my_project.runner.PytestTestRunner'
+
+Usage:
+
+.. code-block:: bash
+
+    ./manage.py test <django args> -- <pytest args>
+
+**Note**: the pytest-django command line options ``--ds`` and ``--dc`` are not
+compatible with this approach, you need to use the standard Django methods of
+setting the ``DJANGO_SETTINGS_MODULE``/``DJANGO_CONFIGURATION`` environmental
+variables or the ``--settings`` command line option.
+
+How can I give database access to all my tests without the `django_db` marker?
+------------------------------------------------------------------------------
+
+Create an autouse fixture and put it in ``conftest.py`` in your project root:
+
+.. code-block:: python
+
+    @pytest.fixture(autouse=True)
+    def enable_db_access_for_all_tests(db):
+        pass
+
+How/where can I get help with pytest/pytest-django?
+---------------------------------------------------
+
+Usage questions can be asked on StackOverflow with the `pytest tag`_.
+
+If you think you've found a bug or something that is wrong in the
+documentation, feel free to `open an issue on the GitHub project`_ for
+pytest-django.
+
+Direct help can be found in the #pylib IRC channel on irc.freenode.org.
+
+.. _pytest tag: http://stackoverflow.com/search?q=pytest
+.. _open an issue on the GitHub project:
+    https://github.com/pytest-dev/pytest-django/issues/

+ 393 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/helpers.rst

@@ -0,0 +1,393 @@
+.. _helpers:
+
+Django helpers
+==============
+
+Assertions
+----------
+
+All of Django's :py:class:`~django:django.test.TestCase`
+:ref:`django:assertions` are available in ``pytest_django.asserts``, e.g.
+
+::
+
+    from pytest_django.asserts import assertTemplateUsed
+
+Markers
+-------
+
+``pytest-django`` registers and uses markers.  See the pytest documentation_
+on what marks are and for notes on using_ them.
+
+.. _documentation: https://pytest.org/en/latest/mark.html
+.. _using: https://pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules
+
+
+``pytest.mark.django_db`` - request database access
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. :py:function:: pytest.mark.django_db([transaction=False, reset_sequences=False]):
+
+This is used to mark a test function as requiring the database. It
+will ensure the database is set up correctly for the test. Each test
+will run in its own transaction which will be rolled back at the end
+of the test. This behavior is the same as Django's standard
+`django.test.TestCase`_ class.
+
+In order for a test to have access to the database it must either
+be marked using the ``django_db`` mark or request one of the ``db``,
+``transactional_db`` or ``django_db_reset_sequences`` fixtures.  Otherwise the
+test will fail when trying to access the database.
+
+:type transaction: bool
+:param transaction:
+ The ``transaction`` argument will allow the test to use real transactions.
+ With ``transaction=False`` (the default when not specified), transaction
+ operations are noops during the test. This is the same behavior that
+ `django.test.TestCase`_
+ uses. When ``transaction=True``, the behavior will be the same as
+ `django.test.TransactionTestCase`_
+
+
+:type reset_sequences: bool
+:param reset_sequences:
+ The ``reset_sequences`` argument will ask to reset auto increment sequence
+ values (e.g. primary keys) before running the test.  Defaults to
+ ``False``.  Must be used together with ``transaction=True`` to have an
+ effect.  Please be aware that not all databases support this feature.
+ For details see :py:attr:`django.test.TransactionTestCase.reset_sequences`.
+
+.. note::
+
+  If you want access to the Django database *inside a fixture*
+  this marker will not help even if the function requesting your
+  fixture has this marker applied.  To access the database in a
+  fixture, the fixture itself will have to request the ``db``,
+  ``transactional_db`` or ``django_db_reset_sequences`` fixture.  See below
+  for a description of them.
+
+.. note:: Automatic usage with ``django.test.TestCase``.
+
+ Test classes that subclass `django.test.TestCase`_ will have access to
+ the database always to make them compatible with existing Django tests.
+ Test classes that subclass Python's ``unittest.TestCase`` need to have the
+ marker applied in order to access the database.
+
+.. _django.test.TestCase: https://docs.djangoproject.com/en/dev/topics/testing/overview/#testcase
+.. _django.test.TransactionTestCase: https://docs.djangoproject.com/en/dev/topics/testing/overview/#transactiontestcase
+
+
+``pytest.mark.urls`` - override the urlconf
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. py:function:: pytest.mark.urls(urls)
+
+   Specify a different ``settings.ROOT_URLCONF`` module for the marked tests.
+
+   :type urls: str
+   :param urls:
+     The urlconf module to use for the test, e.g. ``myapp.test_urls``.  This is
+     similar to Django's ``TestCase.urls`` attribute.
+
+   Example usage::
+
+     @pytest.mark.urls('myapp.test_urls')
+     def test_something(client):
+         assert 'Success!' in client.get('/some_url_defined_in_test_urls/').content
+
+
+``pytest.mark.ignore_template_errors`` - ignore invalid template variables
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. py:function:: pytest.mark.ignore_template_errors
+
+  Ignore errors when using the ``--fail-on-template-vars`` option, i.e.
+  do not cause tests to fail if your templates contain invalid variables.
+
+  This marker sets the ``string_if_invalid`` template option, or
+  the older ``settings.TEMPLATE_STRING_IF_INVALID=None`` (Django up to 1.10).
+  See :ref:`django:invalid-template-variables`.
+
+  Example usage::
+
+     @pytest.mark.ignore_template_errors
+     def test_something(client):
+         client('some-url-with-invalid-template-vars')
+
+
+Fixtures
+--------
+
+pytest-django provides some pytest fixtures to provide dependencies for tests.
+More information on fixtures is available in the `pytest documentation
+<https://pytest.org/en/latest/fixture.html>`_.
+
+
+``rf`` - ``RequestFactory``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An instance of a `django.test.RequestFactory`_
+
+.. _django.test.RequestFactory: https://docs.djangoproject.com/en/dev/topics/testing/advanced/#django.test.RequestFactory
+
+Example
+"""""""
+
+::
+
+    from myapp.views import my_view
+
+    def test_details(rf):
+        request = rf.get('/customer/details')
+        response = my_view(request)
+        assert response.status_code == 200
+
+``client`` - ``django.test.Client``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An instance of a `django.test.Client`_
+
+.. _django.test.Client: https://docs.djangoproject.com/en/dev/topics/testing/tools/#the-test-client
+
+Example
+"""""""
+
+::
+
+    def test_with_client(client):
+        response = client.get('/')
+        assert response.content == 'Foobar'
+
+To use `client` as an authenticated standard user, call its `login()` method before accessing a URL:
+
+::
+
+    def test_with_authenticated_client(client, django_user_model):
+        username = "user1"
+        password = "bar"
+        django_user_model.objects.create_user(username=username, password=password)
+        client.login(username=username, password=password)
+        response = client.get('/private')
+        assert response.content == 'Protected Area'
+
+
+``admin_client`` - ``django.test.Client`` logged in as admin
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An instance of a `django.test.Client`_, logged in as an admin user.
+
+Example
+"""""""
+
+::
+
+    def test_an_admin_view(admin_client):
+        response = admin_client.get('/admin/')
+        assert response.status_code == 200
+
+Using the `admin_client` fixture will cause the test to automatically be marked for database use (no need to specify the
+``django_db`` mark).
+
+.. fixture:: admin_user
+
+``admin_user`` - an admin user (superuser)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An instance of a superuser, with username "admin" and password "password" (in
+case there is no "admin" user yet).
+
+Using the `admin_user` fixture will cause the test to automatically be marked for database use (no need to specify the
+``django_db`` mark).
+
+
+``django_user_model``
+~~~~~~~~~~~~~~~~~~~~~
+
+A shortcut to the User model configured for use by the current Django project (aka the model referenced by
+`settings.AUTH_USER_MODEL`). Use this fixture to make pluggable apps testable regardless what User model is configured
+in the containing Django project.
+
+Example
+"""""""
+
+::
+
+    def test_new_user(django_user_model):
+        django_user_model.objects.create(username="someone", password="something")
+
+
+``django_username_field``
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This fixture extracts the field name used for the username on the user model, i.e. resolves to the current
+``settings.USERNAME_FIELD``. Use this fixture to make pluggable apps testable regardless what the username field
+is configured to be in the containing Django project.
+
+``db``
+~~~~~~~
+
+.. fixture:: db
+
+This fixture will ensure the Django database is set up.  Only
+required for fixtures that want to use the database themselves.  A
+test function should normally use the ``pytest.mark.django_db``
+mark to signal it needs the database.
+
+``transactional_db``
+~~~~~~~~~~~~~~~~~~~~
+
+This fixture can be used to request access to the database including
+transaction support.  This is only required for fixtures which need
+database access themselves.  A test function should normally use the
+``pytest.mark.django_db``  mark with ``transaction=True``.
+
+``django_db_reset_sequences``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. fixture:: django_db_reset_sequences
+
+This fixture provides the same transactional database access as
+``transactional_db``, with additional support for reset of auto increment
+sequences (if your database supports it). This is only required for
+fixtures which need database access themselves. A test function should
+normally use the ``pytest.mark.django_db`` mark with ``transaction=True`` and ``reset_sequences=True``.
+
+``live_server``
+~~~~~~~~~~~~~~~
+
+This fixture runs a live Django server in a background thread.  The
+server's URL can be retrieved using the ``live_server.url`` attribute
+or by requesting it's string value: ``unicode(live_server)``.  You can
+also directly concatenate a string to form a URL: ``live_server +
+'/foo``.
+
+.. note:: Combining database access fixtures.
+
+  When using multiple database fixtures together, only one of them is
+  used.  Their order of precedence is as follows (the last one wins):
+
+  * ``db``
+  * ``transactional_db``
+  * ``django_db_reset_sequences``
+
+  In addition, using ``live_server`` will also trigger transactional
+  database access, if not specified.
+
+``settings``
+~~~~~~~~~~~~
+
+This fixture will provide a handle on the Django settings module, and
+automatically revert any changes made to the settings (modifications, additions
+and deletions).
+
+Example
+"""""""
+
+::
+
+    def test_with_specific_settings(settings):
+        settings.USE_TZ = True
+        assert settings.USE_TZ
+
+
+.. fixture:: django_assert_num_queries
+
+``django_assert_num_queries``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. py:function:: django_assert_num_queries(num, connection=None, info=None)
+
+  :param num: expected number of queries
+  :param connection: optional non-default DB connection
+  :param str info: optional info message to display on failure
+
+This fixture allows to check for an expected number of DB queries.
+
+If the assertion failed, the executed queries can be shown by using
+the verbose command line option.
+
+It wraps `django.test.utils.CaptureQueriesContext` and yields the wrapped
+CaptureQueriesContext instance.
+
+Example usage::
+
+    def test_queries(django_assert_num_queries):
+        with django_assert_num_queries(3) as captured:
+            Item.objects.create('foo')
+            Item.objects.create('bar')
+            Item.objects.create('baz')
+
+        assert 'foo' in captured.captured_queries[0]['sql']
+
+
+.. fixture:: django_assert_max_num_queries
+
+``django_assert_max_num_queries``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. py:function:: django_assert_max_num_queries(num, connection=None, info=None)
+
+  :param num: expected maximum number of queries
+  :param connection: optional non-default DB connection
+  :param str info: optional info message to display on failure
+
+This fixture allows to check for an expected maximum number of DB queries.
+
+It is a specialized version of :fixture:`django_assert_num_queries`.
+
+Example usage::
+
+    def test_max_queries(django_assert_max_num_queries):
+        with django_assert_max_num_queries(2):
+            Item.objects.create('foo')
+            Item.objects.create('bar')
+
+
+``mailoutbox``
+~~~~~~~~~~~~~~
+
+A clean email outbox to which Django-generated emails are sent.
+
+Example
+"""""""
+
+::
+
+    from django.core import mail
+
+    def test_mail(mailoutbox):
+        mail.send_mail('subject', 'body', 'from@example.com', ['to@example.com'])
+        assert len(mailoutbox) == 1
+        m = mailoutbox[0]
+        assert m.subject == 'subject'
+        assert m.body == 'body'
+        assert m.from_email == 'from@example.com'
+        assert list(m.to) == ['to@example.com']
+
+
+This uses the ``django_mail_patch_dns`` fixture, which patches
+``DNS_NAME`` used by :py:mod:`django.core.mail` with the value from
+the ``django_mail_dnsname`` fixture, which defaults to
+"fake-tests.example.com".
+
+
+Automatic cleanup
+-----------------
+
+pytest-django provides some functionality to assure a clean and consistent environment
+during tests.
+
+Clearing of site cache
+~~~~~~~~~~~~~~~~~~~~~~
+
+If ``django.contrib.sites`` is in your INSTALLED_APPS, Site cache will
+be cleared for each test to avoid hitting the cache and causing the wrong Site
+object to be returned by ``Site.objects.get_current()``.
+
+
+Clearing of mail.outbox
+~~~~~~~~~~~~~~~~~~~~~~~
+
+``mail.outbox`` will be cleared for each pytest, to give each new test an empty
+mailbox to work with. However, it's more "pytestic" to use the ``mailoutbox`` fixture described above
+than to access ``mail.outbox``.

+ 79 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/index.rst

@@ -0,0 +1,79 @@
+===========================
+pytest-django Documentation
+===========================
+
+pytest-django is a plugin for `pytest`_ that provides a set of useful tools
+for testing `Django`_ applications and projects.
+
+.. _pytest: https://pytest.org/
+.. _Django: https://www.djangoproject.com/
+
+Quick Start
+===========
+
+.. code-block:: bash
+
+   $ pip install pytest-django
+
+Make sure ``DJANGO_SETTINGS_MODULE`` is defined (see
+:ref:`configuring_django_settings`) and make your tests discoverable
+(see :ref:`faq-tests-not-being-picked-up`):
+
+.. code-block:: ini
+
+   # -- FILE: pytest.ini (or tox.ini)
+   [pytest]
+   DJANGO_SETTINGS_MODULE = test_settings
+   # -- recommended but optional:
+   python_files = tests.py test_*.py *_tests.py
+
+Run your tests with ``pytest``:
+
+.. code-block:: bash
+
+   $ pytest
+
+Why would I use this instead of Django's manage.py test command?
+================================================================
+
+Running the test suite with pytest offers some features that are not present in Django's standard test mechanism:
+
+* Less boilerplate: no need to import unittest, create a subclass with methods. Just write tests as regular functions.
+* `Manage test dependencies with fixtures`_.
+* Run tests in multiple processes for increased speed.
+* There are a lot of other nice plugins available for pytest.
+* Easy switching: Existing unittest-style tests will still work without any modifications.
+
+See the `pytest documentation`_ for more information on pytest.
+
+.. _Manage test dependencies with fixtures: http://docs.pytest.org/en/latest/fixture.html
+.. _pytest documentation: http://docs.pytest.org/
+
+Bugs? Feature Suggestions?
+==========================
+
+Report issues and feature requests at the `GitHub issue tracker`_.
+
+.. _GitHub issue tracker: http://github.com/pytest-dev/pytest-django/issues
+
+Table of Contents
+=================
+
+.. toctree::
+   :maxdepth: 3
+
+   tutorial
+   configuring_django
+   managing_python_path
+   usage
+   database
+   helpers
+   faq
+   contributing
+   changelog
+
+Indices and Tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`

+ 190 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/make.bat

@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+	set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^<target^>` where ^<target^> is one of
+	echo.  html       to make standalone HTML files
+	echo.  dirhtml    to make HTML files named index.html in directories
+	echo.  singlehtml to make a single large HTML file
+	echo.  pickle     to make pickle files
+	echo.  json       to make JSON files
+	echo.  htmlhelp   to make HTML files and a HTML help project
+	echo.  qthelp     to make HTML files and a qthelp project
+	echo.  devhelp    to make HTML files and a Devhelp project
+	echo.  epub       to make an epub
+	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  texinfo    to make Texinfo files
+	echo.  gettext    to make PO message catalogs
+	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  linkcheck  to check all external links for integrity
+	echo.  doctest    to run all doctests embedded in the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pytest-django.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pytest-django.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "texinfo" (
+	%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+	goto end
+)
+
+if "%1" == "gettext" (
+	%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+:end

+ 83 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/managing_python_path.rst

@@ -0,0 +1,83 @@
+.. _managing_python_path:
+
+Managing the Python path
+========================
+
+pytest needs to be able to import the code in your project. Normally, when
+interacting with Django code, the interaction happens via ``manage.py``, which
+will implicilty add that directory to the Python path.
+
+However, when Python is started via the ``pytest`` command, some extra care is
+needed to have the Python path setup properly. There are two ways to handle
+this problem, described below.
+
+Automatic looking for of Django projects
+----------------------------------------
+
+By default, pytest-django tries to find Django projects by automatically
+looking for the project's ``manage.py`` file and adding its directory to the
+Python path.
+
+Looking for the ``manage.py`` file uses the same algorithm as pytest uses to
+find ``pytest.ini``, ``tox.ini`` and ``setup.cfg``: Each test root directories
+parents will be searched for ``manage.py`` files, and it will stop when the
+first file is found.
+
+If you have a custom project setup, have none or multiple ``manage.py`` files
+in your project, the automatic detection may not be correct. See
+:ref:`managing_the_python_path_explicitly` for more details on how to configure
+your environment in that case.
+
+.. _managing_the_python_path_explicitly:
+
+Managing the Python path explicitly
+-----------------------------------
+
+First, disable the automatic Django project finder. Add this to
+``pytest.ini``, ``setup.cfg`` or ``tox.ini``::
+
+    [pytest]
+    django_find_project = false
+
+
+Next, you need to make sure that your project code is available on the Python
+path. There are multiple ways to achieve this:
+
+Managing your project with virtualenv, pip and editable mode
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The easiest way to have your code available on the Python path when using
+virtualenv and pip is to have a setup.py file and install your project in
+editable mode when developing.
+
+If you don't already have a setup.py file, creating a setup.py file with this
+content will get you started::
+
+    import setuptools
+    setuptools.setup(name='myproj', version='1.0')
+
+This ``setup.py`` file is not sufficient to distribute your package to PyPI or
+more general packaging, but it should help you get started. Please refer to the
+`Python Packaging User Guide
+<https://python-packaging-user-guide.readthedocs.io/en/latest/tutorial.html#creating-your-own-project>`_
+for more information on packaging Python applications.`
+
+To install the project afterwards::
+
+    pip install --editable .
+
+Your code should then be importable from any Python application. You can also
+add this directly to your project's requirements.txt file like this::
+
+    # requirements.txt
+    -e .
+    django>=1.11
+    pytest-django
+
+
+Using pytest-pythonpath
+~~~~~~~~~~~~~~~~~~~~~~~
+
+You can also use the `pytest-pythonpath
+<https://pypi.python.org/pypi/pytest-pythonpath>`_ plugin to explicitly add paths to
+the Python path.

+ 98 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/tutorial.rst

@@ -0,0 +1,98 @@
+Getting started with pytest and pytest-django
+=============================================
+
+Introduction
+------------
+
+pytest and pytest-django are compatible with standard Django test suites and
+Nose test suites. They should be able to pick up and run existing tests without
+any or little configuration. This section describes how to get started quickly.
+
+Talks, articles and blog posts
+------------------------------
+
+ * Talk from DjangoCon Europe 2014: `pytest: helps you write better Django apps, by Andreas Pelme <https://www.youtube.com/watch?v=aaArYVh6XSM>`_
+
+ * Talk from EuroPython 2013: `Testing Django application with pytest, by Andreas Pelme <http://www.youtube.com/watch?v=aUf8Fkb7TaY>`_
+
+ * Three part blog post tutorial (part 3 mentions Django integration): `pytest: no-boilerplate testing, by Daniel Greenfeld <http://pydanny.com/pytest-no-boilerplate-testing.html>`_
+
+ * Blog post: `Django Projects to Django Apps: Converting the Unit Tests, by
+   John Costa
+   <https://www.johnmcostaiii.net/post/2013-04-21-django-projects-to-django-apps-converting-the-unit-tests/>`_.
+
+For general information and tutorials on pytest, see the `pytest tutorial page <https://pytest.org/en/latest/getting-started.html>`_.
+
+
+Step 1: Installation
+--------------------
+
+pytest-django can be obtained directly from `PyPI
+<http://pypi.python.org/pypi/pytest-django>`_, and can be installed with
+``pip``:
+
+.. code-block:: bash
+
+    pip install pytest-django
+
+Installing pytest-django will also automatically install the latest version of
+pytest. ``pytest-django`` uses ``pytest``'s plugin system and can be used right away
+after installation, there is nothing more to configure.
+
+Step 2: Point pytest to your Django settings
+--------------------------------------------
+
+You need to tell pytest which Django settings should be used for test
+runs. The easiest way to achieve this is to create a pytest configuration file
+with this information.
+
+Create a file called ``pytest.ini`` in your project root directory that
+contains:
+
+.. code-block:: ini
+
+    [pytest]
+    DJANGO_SETTINGS_MODULE = yourproject.settings
+
+You can also specify your Django settings by setting the
+``DJANGO_SETTINGS_MODULE`` environment variable or specifying the
+``--ds=yourproject.settings`` command line flag when running the tests.
+See the full documentation on :ref:`configuring_django_settings`.
+
+Optionally, also add the following line to the ``[pytest]`` section to
+instruct pytest to collect tests in Django's default app layouts, too.
+See the FAQ at :ref:`faq-tests-not-being-picked-up` for more infos.
+
+.. code-block:: ini
+
+    python_files = tests.py test_*.py *_tests.py
+
+Step 3: Run your test suite
+---------------------------
+
+Tests are invoked directly with the ``pytest`` command, instead of ``manage.py
+test``, that you might be used to:
+
+.. code-block:: bash
+
+    pytest
+
+Do you have problems with pytest not finding your code? See the FAQ
+:ref:`faq-import-error`.
+
+Next steps
+----------
+
+The :ref:`usage` section describes more ways to interact with your test suites.
+
+pytest-django also provides some :ref:`helpers` to make it easier to write
+Django tests.
+
+Consult the `pytest documentation <https://pytest.org/>`_ for more information
+on pytest itself.
+
+Stuck? Need help?
+-----------------
+
+No problem, see the FAQ on :ref:`faq-getting-help` for information on how to
+get help.

+ 56 - 0
desktop/core/ext-py/pytest-django-3.10.0/docs/usage.rst

@@ -0,0 +1,56 @@
+.. _usage:
+
+Usage and invocations
+=====================
+
+Basic usage
+-----------
+
+When using pytest-django, django-admin.py or manage.py is not used to run
+tests. This makes it possible to invoke pytest and other plugins with all its
+different options directly.
+
+Running a test suite is done by invoking the pytest command directly::
+
+    pytest
+
+Specific test files or directories can be selected by specifying the test file names directly on
+the command line::
+
+    pytest test_something.py a_directory
+
+See the `pytest documentation on Usage and invocations
+<https://pytest.org/en/latest/usage.html>`_ for more help on available parameters.
+
+Additional command line options
+-------------------------------
+
+``--fail-on-template-vars`` - fail for invalid variables in templates
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Fail tests that render templates which make use of invalid template variables.
+
+Running tests in parallel with pytest-xdist
+-------------------------------------------
+pytest-django supports running tests on multiple processes to speed up test
+suite run time. This can lead to significant speed improvements on multi
+core/multi CPU machines.
+
+This requires the pytest-xdist plugin to be available, it can usually be
+installed with::
+
+    pip install pytest-xdist
+
+You can then run the tests by running::
+
+    pytest -n <number of processes>
+
+When tests are invoked with xdist, pytest-django will create a separate test
+database for each process. Each test database will be given a suffix
+(something like "gw0", "gw1") to map to a xdist process. If your database name
+is set to "foo", the test database with xdist will be "test_foo_gw0",
+"test_foo_gw1" etc.
+
+See the full documentation on `pytest-xdist
+<https://pytest.org/en/latest/xdist.html>`_ for more information. Among other
+features, pytest-xdist can distribute/coordinate test execution on remote
+machines.

+ 0 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django/__init__.py


+ 34 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django/asserts.py

@@ -0,0 +1,34 @@
+"""
+Dynamically load all Django assertion cases and expose them for importing.
+"""
+from functools import wraps
+from django.test import (
+    TestCase, SimpleTestCase,
+    LiveServerTestCase, TransactionTestCase
+)
+
+test_case = TestCase('run')
+
+
+def _wrapper(name):
+    func = getattr(test_case, name)
+
+    @wraps(func)
+    def assertion_func(*args, **kwargs):
+        return func(*args, **kwargs)
+
+    return assertion_func
+
+
+__all__ = []
+assertions_names = set()
+assertions_names.update(
+    set(attr for attr in vars(TestCase) if attr.startswith('assert')),
+    set(attr for attr in vars(SimpleTestCase) if attr.startswith('assert')),
+    set(attr for attr in vars(LiveServerTestCase) if attr.startswith('assert')),
+    set(attr for attr in vars(TransactionTestCase) if attr.startswith('assert')),
+)
+
+for assert_func in assertions_names:
+    globals()[assert_func] = _wrapper(assert_func)
+    __all__.append(assert_func)

+ 39 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django/compat.py

@@ -0,0 +1,39 @@
+# This file cannot be imported from until Django sets up
+
+
+def _get_setup_and_teardown_databases():
+    try:
+        # Django 3.2+ has added timing capabilities that we don't really support
+        # right now. Unfortunately that new time_keeper is required.
+        from django.test.utils import NullTimeKeeper
+    except ImportError:
+        pass
+    else:
+        from django.test.utils import setup_databases, teardown_databases
+
+        def wrapped_setup_databases(*args, **kwargs):
+            return setup_databases(*args, time_keeper=NullTimeKeeper(), **kwargs)
+
+        return wrapped_setup_databases, teardown_databases
+
+    try:
+        # Django 1.11+
+        from django.test.utils import setup_databases, teardown_databases  # noqa: F401, F811
+    except ImportError:
+        pass
+    else:
+        return setup_databases, teardown_databases
+
+    # In Django prior to 1.11, teardown_databases is only available as a method on DiscoverRunner
+    from django.test.runner import setup_databases, DiscoverRunner  # noqa: F401, F811
+
+    def teardown_databases(db_cfg, verbosity):
+        DiscoverRunner(verbosity=verbosity, interactive=False).teardown_databases(
+            db_cfg
+        )
+
+    return setup_databases, teardown_databases
+
+
+setup_databases, teardown_databases = _get_setup_and_teardown_databases()
+del _get_setup_and_teardown_databases

+ 14 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django/django_compat.py

@@ -0,0 +1,14 @@
+# Note that all functions here assume django is available.  So ensure
+# this is the case before you call them.
+
+
+def is_django_unittest(request_or_item):
+    """Returns True if the request_or_item is a Django test case, otherwise False"""
+    from django.test import SimpleTestCase
+
+    cls = getattr(request_or_item, "cls", None)
+
+    if cls is None:
+        return False
+
+    return issubclass(cls, SimpleTestCase)

+ 481 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django/fixtures.py

@@ -0,0 +1,481 @@
+"""All pytest-django fixtures"""
+
+from __future__ import with_statement
+
+import os
+import warnings
+from contextlib import contextmanager
+from functools import partial
+
+import pytest
+
+from . import live_server_helper
+from .django_compat import is_django_unittest
+from .lazy_django import skip_if_no_django
+
+__all__ = [
+    "django_db_setup",
+    "db",
+    "transactional_db",
+    "django_db_reset_sequences",
+    "admin_user",
+    "django_user_model",
+    "django_username_field",
+    "client",
+    "admin_client",
+    "rf",
+    "settings",
+    "live_server",
+    "_live_server_helper",
+    "django_assert_num_queries",
+    "django_assert_max_num_queries",
+]
+
+
+@pytest.fixture(scope="session")
+def django_db_modify_db_settings_tox_suffix():
+    skip_if_no_django()
+
+    tox_environment = os.getenv("TOX_PARALLEL_ENV")
+    if tox_environment:
+        # Put a suffix like _py27-django21 on tox workers
+        _set_suffix_to_test_databases(suffix=tox_environment)
+
+
+@pytest.fixture(scope="session")
+def django_db_modify_db_settings_xdist_suffix(request):
+    skip_if_no_django()
+
+    xdist_suffix = getattr(request.config, "workerinput", {}).get("workerid")
+    if xdist_suffix:
+        # Put a suffix like _gw0, _gw1 etc on xdist processes
+        _set_suffix_to_test_databases(suffix=xdist_suffix)
+
+
+@pytest.fixture(scope="session")
+def django_db_modify_db_settings_parallel_suffix(
+    django_db_modify_db_settings_tox_suffix,
+    django_db_modify_db_settings_xdist_suffix,
+):
+    skip_if_no_django()
+
+
+@pytest.fixture(scope="session")
+def django_db_modify_db_settings(django_db_modify_db_settings_parallel_suffix):
+    skip_if_no_django()
+
+
+@pytest.fixture(scope="session")
+def django_db_use_migrations(request):
+    return not request.config.getvalue("nomigrations")
+
+
+@pytest.fixture(scope="session")
+def django_db_keepdb(request):
+    return request.config.getvalue("reuse_db")
+
+
+@pytest.fixture(scope="session")
+def django_db_createdb(request):
+    return request.config.getvalue("create_db")
+
+
+@pytest.fixture(scope="session")
+def django_db_setup(
+    request,
+    django_test_environment,
+    django_db_blocker,
+    django_db_use_migrations,
+    django_db_keepdb,
+    django_db_createdb,
+    django_db_modify_db_settings,
+):
+    """Top level fixture to ensure test databases are available"""
+    from .compat import setup_databases, teardown_databases
+
+    setup_databases_args = {}
+
+    if not django_db_use_migrations:
+        _disable_native_migrations()
+
+    if django_db_keepdb and not django_db_createdb:
+        setup_databases_args["keepdb"] = True
+
+    with django_db_blocker.unblock():
+        db_cfg = setup_databases(
+            verbosity=request.config.option.verbose,
+            interactive=False,
+            **setup_databases_args
+        )
+
+    def teardown_database():
+        with django_db_blocker.unblock():
+            try:
+                teardown_databases(db_cfg, verbosity=request.config.option.verbose)
+            except Exception as exc:
+                request.node.warn(
+                    pytest.PytestWarning(
+                        "Error when trying to teardown test databases: %r" % exc
+                    )
+                )
+
+    if not django_db_keepdb:
+        request.addfinalizer(teardown_database)
+
+
+def _django_db_fixture_helper(
+    request, django_db_blocker, transactional=False, reset_sequences=False
+):
+    if is_django_unittest(request):
+        return
+
+    if not transactional and "live_server" in request.fixturenames:
+        # Do nothing, we get called with transactional=True, too.
+        return
+
+    django_db_blocker.unblock()
+    request.addfinalizer(django_db_blocker.restore)
+
+    if transactional:
+        from django.test import TransactionTestCase as django_case
+
+        if reset_sequences:
+
+            class ResetSequenceTestCase(django_case):
+                reset_sequences = True
+
+            django_case = ResetSequenceTestCase
+    else:
+        from django.test import TestCase as django_case
+
+    test_case = django_case(methodName="__init__")
+    test_case._pre_setup()
+    request.addfinalizer(test_case._post_teardown)
+
+
+def _disable_native_migrations():
+    from django.conf import settings
+    from django.core.management.commands import migrate
+
+    from .migrations import DisableMigrations
+
+    settings.MIGRATION_MODULES = DisableMigrations()
+
+    class MigrateSilentCommand(migrate.Command):
+        def handle(self, *args, **kwargs):
+            kwargs["verbosity"] = 0
+            return super(MigrateSilentCommand, self).handle(*args, **kwargs)
+
+    migrate.Command = MigrateSilentCommand
+
+
+def _set_suffix_to_test_databases(suffix):
+    from django.conf import settings
+
+    for db_settings in settings.DATABASES.values():
+        test_name = db_settings.get("TEST", {}).get("NAME")
+
+        if not test_name:
+            if db_settings["ENGINE"] == "django.db.backends.sqlite3":
+                continue
+            test_name = "test_{}".format(db_settings["NAME"])
+
+        if test_name == ":memory:":
+            continue
+
+        db_settings.setdefault("TEST", {})
+        db_settings["TEST"]["NAME"] = "{}_{}".format(test_name, suffix)
+
+
+# ############### User visible fixtures ################
+
+
+@pytest.fixture(scope="function")
+def db(request, django_db_setup, django_db_blocker):
+    """Require a django test database.
+
+    This database will be setup with the default fixtures and will have
+    the transaction management disabled. At the end of the test the outer
+    transaction that wraps the test itself will be rolled back to undo any
+    changes to the database (in case the backend supports transactions).
+    This is more limited than the ``transactional_db`` resource but
+    faster.
+
+    If multiple database fixtures are requested, they take precedence
+    over each other in the following order (the last one wins): ``db``,
+    ``transactional_db``, ``django_db_reset_sequences``.
+    """
+    if "django_db_reset_sequences" in request.fixturenames:
+        request.getfixturevalue("django_db_reset_sequences")
+    if (
+        "transactional_db" in request.fixturenames
+        or "live_server" in request.fixturenames
+    ):
+        request.getfixturevalue("transactional_db")
+    else:
+        _django_db_fixture_helper(request, django_db_blocker, transactional=False)
+
+
+@pytest.fixture(scope="function")
+def transactional_db(request, django_db_setup, django_db_blocker):
+    """Require a django test database with transaction support.
+
+    This will re-initialise the django database for each test and is
+    thus slower than the normal ``db`` fixture.
+
+    If you want to use the database with transactions you must request
+    this resource.
+
+    If multiple database fixtures are requested, they take precedence
+    over each other in the following order (the last one wins): ``db``,
+    ``transactional_db``, ``django_db_reset_sequences``.
+    """
+    if "django_db_reset_sequences" in request.fixturenames:
+        request.getfixturevalue("django_db_reset_sequences")
+    _django_db_fixture_helper(request, django_db_blocker, transactional=True)
+
+
+@pytest.fixture(scope="function")
+def django_db_reset_sequences(request, django_db_setup, django_db_blocker):
+    """Require a transactional test database with sequence reset support.
+
+    This behaves like the ``transactional_db`` fixture, with the addition
+    of enforcing a reset of all auto increment sequences.  If the enquiring
+    test relies on such values (e.g. ids as primary keys), you should
+    request this resource to ensure they are consistent across tests.
+
+    If multiple database fixtures are requested, they take precedence
+    over each other in the following order (the last one wins): ``db``,
+    ``transactional_db``, ``django_db_reset_sequences``.
+    """
+    _django_db_fixture_helper(
+        request, django_db_blocker, transactional=True, reset_sequences=True
+    )
+
+
+@pytest.fixture()
+def client():
+    """A Django test client instance."""
+    skip_if_no_django()
+
+    from django.test.client import Client
+
+    return Client()
+
+
+@pytest.fixture()
+def django_user_model(db):
+    """The class of Django's user model."""
+    from django.contrib.auth import get_user_model
+
+    return get_user_model()
+
+
+@pytest.fixture()
+def django_username_field(django_user_model):
+    """The fieldname for the username used with Django's user model."""
+    return django_user_model.USERNAME_FIELD
+
+
+@pytest.fixture()
+def admin_user(db, django_user_model, django_username_field):
+    """A Django admin user.
+
+    This uses an existing user with username "admin", or creates a new one with
+    password "password".
+    """
+    UserModel = django_user_model
+    username_field = django_username_field
+    username = "admin@example.com" if username_field == "email" else "admin"
+
+    try:
+        user = UserModel._default_manager.get(**{username_field: username})
+    except UserModel.DoesNotExist:
+        extra_fields = {}
+        if username_field not in ("username", "email"):
+            extra_fields[username_field] = "admin"
+        user = UserModel._default_manager.create_superuser(
+            username, "admin@example.com", "password", **extra_fields
+        )
+    return user
+
+
+@pytest.fixture()
+def admin_client(db, admin_user):
+    """A Django test client logged in as an admin user."""
+    from django.test.client import Client
+
+    client = Client()
+    client.login(username=admin_user.username, password="password")
+    return client
+
+
+@pytest.fixture()
+def rf():
+    """RequestFactory instance"""
+    skip_if_no_django()
+
+    from django.test.client import RequestFactory
+
+    return RequestFactory()
+
+
+class SettingsWrapper(object):
+    _to_restore = []
+
+    def __delattr__(self, attr):
+        from django.test import override_settings
+
+        override = override_settings()
+        override.enable()
+        from django.conf import settings
+
+        delattr(settings, attr)
+
+        self._to_restore.append(override)
+
+    def __setattr__(self, attr, value):
+        from django.test import override_settings
+
+        override = override_settings(**{attr: value})
+        override.enable()
+        self._to_restore.append(override)
+
+    def __getattr__(self, item):
+        from django.conf import settings
+
+        return getattr(settings, item)
+
+    def finalize(self):
+        for override in reversed(self._to_restore):
+            override.disable()
+
+        del self._to_restore[:]
+
+
+@pytest.yield_fixture()
+def settings():
+    """A Django settings object which restores changes after the testrun"""
+    skip_if_no_django()
+
+    wrapper = SettingsWrapper()
+    yield wrapper
+    wrapper.finalize()
+
+
+@pytest.fixture(scope="session")
+def live_server(request):
+    """Run a live Django server in the background during tests
+
+    The address the server is started from is taken from the
+    --liveserver command line option or if this is not provided from
+    the DJANGO_LIVE_TEST_SERVER_ADDRESS environment variable.  If
+    neither is provided ``localhost:8081,8100-8200`` is used.  See the
+    Django documentation for its full syntax.
+
+    NOTE: If the live server needs database access to handle a request
+          your test will have to request database access.  Furthermore
+          when the tests want to see data added by the live-server (or
+          the other way around) transactional database access will be
+          needed as data inside a transaction is not shared between
+          the live server and test code.
+
+          Static assets will be automatically served when
+          ``django.contrib.staticfiles`` is available in INSTALLED_APPS.
+    """
+    skip_if_no_django()
+
+    import django
+
+    addr = request.config.getvalue("liveserver") or os.getenv(
+        "DJANGO_LIVE_TEST_SERVER_ADDRESS"
+    )
+
+    if addr and ":" in addr:
+        if django.VERSION >= (1, 11):
+            ports = addr.split(":")[1]
+            if "-" in ports or "," in ports:
+                warnings.warn(
+                    "Specifying multiple live server ports is not supported "
+                    "in Django 1.11. This will be an error in a future "
+                    "pytest-django release."
+                )
+
+    if not addr:
+        if django.VERSION < (1, 11):
+            addr = "localhost:8081,8100-8200"
+        else:
+            addr = "localhost"
+
+    server = live_server_helper.LiveServer(addr)
+    request.addfinalizer(server.stop)
+    return server
+
+
+@pytest.fixture(autouse=True, scope="function")
+def _live_server_helper(request):
+    """Helper to make live_server work, internal to pytest-django.
+
+    This helper will dynamically request the transactional_db fixture
+    for a test which uses the live_server fixture.  This allows the
+    server and test to access the database without having to mark
+    this explicitly which is handy since it is usually required and
+    matches the Django behaviour.
+
+    The separate helper is required since live_server can not request
+    transactional_db directly since it is session scoped instead of
+    function-scoped.
+
+    It will also override settings only for the duration of the test.
+    """
+    if "live_server" not in request.fixturenames:
+        return
+
+    request.getfixturevalue("transactional_db")
+
+    live_server = request.getfixturevalue("live_server")
+    live_server._live_server_modified_settings.enable()
+    request.addfinalizer(live_server._live_server_modified_settings.disable)
+
+
+@contextmanager
+def _assert_num_queries(config, num, exact=True, connection=None, info=None):
+    from django.test.utils import CaptureQueriesContext
+
+    if connection is None:
+        from django.db import connection
+
+    verbose = config.getoption("verbose") > 0
+    with CaptureQueriesContext(connection) as context:
+        yield context
+        num_performed = len(context)
+        if exact:
+            failed = num != num_performed
+        else:
+            failed = num_performed > num
+        if failed:
+            msg = "Expected to perform {} queries {}{}".format(
+                num,
+                "" if exact else "or less ",
+                "but {} done".format(
+                    num_performed == 1 and "1 was" or "%d were" % (num_performed,)
+                ),
+            )
+            if info:
+                msg += "\n{}".format(info)
+            if verbose:
+                sqls = (q["sql"] for q in context.captured_queries)
+                msg += "\n\nQueries:\n========\n\n%s" % "\n\n".join(sqls)
+            else:
+                msg += " (add -v option to show queries)"
+            pytest.fail(msg)
+
+
+@pytest.fixture(scope="function")
+def django_assert_num_queries(pytestconfig):
+    return partial(_assert_num_queries, pytestconfig)
+
+
+@pytest.fixture(scope="function")
+def django_assert_max_num_queries(pytestconfig):
+    return partial(_assert_num_queries, pytestconfig, exact=False)

+ 33 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django/lazy_django.py

@@ -0,0 +1,33 @@
+"""
+Helpers to load Django lazily when Django settings can't be configured.
+"""
+
+import os
+import sys
+
+import pytest
+
+
+def skip_if_no_django():
+    """Raises a skip exception when no Django settings are available"""
+    if not django_settings_is_configured():
+        pytest.skip("no Django settings")
+
+
+def django_settings_is_configured():
+    """Return whether the Django settings module has been configured.
+
+    This uses either the DJANGO_SETTINGS_MODULE environment variable, or the
+    configured flag in the Django settings object if django.conf has already
+    been imported.
+    """
+    ret = bool(os.environ.get("DJANGO_SETTINGS_MODULE"))
+
+    if not ret and "django.conf" in sys.modules:
+        return sys.modules["django.conf"].settings.configured
+
+    return ret
+
+
+def get_django_version():
+    return __import__("django").VERSION

+ 109 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django/live_server_helper.py

@@ -0,0 +1,109 @@
+import six
+
+
+@six.python_2_unicode_compatible
+class LiveServer(object):
+    """The liveserver fixture
+
+    This is the object that the ``live_server`` fixture returns.
+    The ``live_server`` fixture handles creation and stopping.
+    """
+
+    def __init__(self, addr):
+        import django
+        from django.db import connections
+        from django.test.testcases import LiveServerThread
+        from django.test.utils import modify_settings
+
+        connections_override = {}
+        for conn in connections.all():
+            # If using in-memory sqlite databases, pass the connections to
+            # the server thread.
+            if (
+                conn.settings_dict["ENGINE"] == "django.db.backends.sqlite3"
+                and conn.settings_dict["NAME"] == ":memory:"
+            ):
+                # Explicitly enable thread-shareability for this connection
+                conn.allow_thread_sharing = True
+                connections_override[conn.alias] = conn
+
+        liveserver_kwargs = {"connections_override": connections_override}
+        from django.conf import settings
+
+        if "django.contrib.staticfiles" in settings.INSTALLED_APPS:
+            from django.contrib.staticfiles.handlers import StaticFilesHandler
+
+            liveserver_kwargs["static_handler"] = StaticFilesHandler
+        else:
+            from django.test.testcases import _StaticFilesHandler
+
+            liveserver_kwargs["static_handler"] = _StaticFilesHandler
+
+        if django.VERSION < (1, 11):
+            host, possible_ports = parse_addr(addr)
+            self.thread = LiveServerThread(host, possible_ports, **liveserver_kwargs)
+        else:
+            try:
+                host, port = addr.split(":")
+            except ValueError:
+                host = addr
+            else:
+                liveserver_kwargs["port"] = int(port)
+            self.thread = LiveServerThread(host, **liveserver_kwargs)
+
+        self._live_server_modified_settings = modify_settings(
+            ALLOWED_HOSTS={"append": host}
+        )
+
+        self.thread.daemon = True
+        self.thread.start()
+        self.thread.is_ready.wait()
+
+        if self.thread.error:
+            raise self.thread.error
+
+    def stop(self):
+        """Stop the server"""
+        self.thread.terminate()
+        self.thread.join()
+
+    @property
+    def url(self):
+        return "http://%s:%s" % (self.thread.host, self.thread.port)
+
+    def __str__(self):
+        return self.url
+
+    def __add__(self, other):
+        return "%s%s" % (self, other)
+
+    def __repr__(self):
+        return "<LiveServer listening at %s>" % self.url
+
+
+def parse_addr(specified_address):
+    """Parse the --liveserver argument into a host/IP address and port range"""
+    # This code is based on
+    # django.test.testcases.LiveServerTestCase.setUpClass
+
+    # The specified ports may be of the form '8000-8010,8080,9200-9300'
+    # i.e. a comma-separated list of ports or ranges of ports, so we break
+    # it down into a detailed list of all possible ports.
+    possible_ports = []
+    try:
+        host, port_ranges = specified_address.split(":")
+        for port_range in port_ranges.split(","):
+            # A port range can be of either form: '8000' or '8000-8010'.
+            extremes = list(map(int, port_range.split("-")))
+            assert len(extremes) in (1, 2)
+            if len(extremes) == 1:
+                # Port range of the form '8000'
+                possible_ports.append(extremes[0])
+            else:
+                # Port range of the form '8000-8010'
+                for port in range(extremes[0], extremes[1] + 1):
+                    possible_ports.append(port)
+    except Exception:
+        raise Exception('Invalid address ("%s") for live server.' % specified_address)
+
+    return host, possible_ports

+ 16 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django/migrations.py

@@ -0,0 +1,16 @@
+# code snippet copied from https://gist.github.com/NotSqrt/5f3c76cd15e40ef62d09
+from pytest_django.lazy_django import get_django_version
+
+
+class DisableMigrations(object):
+    def __init__(self):
+        self._django_version = get_django_version()
+
+    def __contains__(self, item):
+        return True
+
+    def __getitem__(self, item):
+        if self._django_version >= (1, 9):
+            return None
+        else:
+            return "notmigrations"

+ 824 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django/plugin.py

@@ -0,0 +1,824 @@
+"""A pytest plugin which helps testing Django applications
+
+This plugin handles creating and destroying the test environment and
+test database and provides some useful text fixtures.
+"""
+
+import contextlib
+import inspect
+from functools import reduce
+import os
+import sys
+import types
+
+import pytest
+
+from .django_compat import is_django_unittest  # noqa
+from .fixtures import django_assert_num_queries  # noqa
+from .fixtures import django_assert_max_num_queries  # noqa
+from .fixtures import django_db_setup  # noqa
+from .fixtures import django_db_use_migrations  # noqa
+from .fixtures import django_db_keepdb  # noqa
+from .fixtures import django_db_createdb  # noqa
+from .fixtures import django_db_modify_db_settings  # noqa
+from .fixtures import django_db_modify_db_settings_parallel_suffix  # noqa
+from .fixtures import django_db_modify_db_settings_tox_suffix  # noqa
+from .fixtures import django_db_modify_db_settings_xdist_suffix  # noqa
+from .fixtures import _live_server_helper  # noqa
+from .fixtures import admin_client  # noqa
+from .fixtures import admin_user  # noqa
+from .fixtures import client  # noqa
+from .fixtures import db  # noqa
+from .fixtures import django_user_model  # noqa
+from .fixtures import django_username_field  # noqa
+from .fixtures import live_server  # noqa
+from .fixtures import django_db_reset_sequences  # noqa
+from .fixtures import rf  # noqa
+from .fixtures import settings  # noqa
+from .fixtures import transactional_db  # noqa
+
+from .lazy_django import django_settings_is_configured, skip_if_no_django
+
+try:
+    import pathlib
+except ImportError:
+    import pathlib2 as pathlib
+
+
+SETTINGS_MODULE_ENV = "DJANGO_SETTINGS_MODULE"
+CONFIGURATION_ENV = "DJANGO_CONFIGURATION"
+INVALID_TEMPLATE_VARS_ENV = "FAIL_INVALID_TEMPLATE_VARS"
+
+PY2 = sys.version_info[0] == 2
+
+# pytest 4.2 handles unittest setup/teardown itself via wrapping fixtures.
+_pytest_version_info = tuple(int(x) for x in pytest.__version__.split(".", 2)[:2])
+_handle_unittest_methods = _pytest_version_info < (4, 2)
+
+_report_header = []
+
+
+# ############### pytest hooks ################
+
+
+def pytest_addoption(parser):
+    group = parser.getgroup("django")
+    group.addoption(
+        "--reuse-db",
+        action="store_true",
+        dest="reuse_db",
+        default=False,
+        help="Re-use the testing database if it already exists, "
+        "and do not remove it when the test finishes.",
+    )
+    group.addoption(
+        "--create-db",
+        action="store_true",
+        dest="create_db",
+        default=False,
+        help="Re-create the database, even if it exists. This "
+        "option can be used to override --reuse-db.",
+    )
+    group.addoption(
+        "--ds",
+        action="store",
+        type=str,
+        dest="ds",
+        default=None,
+        help="Set DJANGO_SETTINGS_MODULE.",
+    )
+    group.addoption(
+        "--dc",
+        action="store",
+        type=str,
+        dest="dc",
+        default=None,
+        help="Set DJANGO_CONFIGURATION.",
+    )
+    group.addoption(
+        "--nomigrations",
+        "--no-migrations",
+        action="store_true",
+        dest="nomigrations",
+        default=False,
+        help="Disable Django migrations on test setup",
+    )
+    group.addoption(
+        "--migrations",
+        action="store_false",
+        dest="nomigrations",
+        default=False,
+        help="Enable Django migrations on test setup",
+    )
+    parser.addini(
+        CONFIGURATION_ENV, "django-configurations class to use by pytest-django."
+    )
+    group.addoption(
+        "--liveserver",
+        default=None,
+        help="Address and port for the live_server fixture.",
+    )
+    parser.addini(
+        SETTINGS_MODULE_ENV, "Django settings module to use by pytest-django."
+    )
+
+    parser.addini(
+        "django_find_project",
+        "Automatically find and add a Django project to the " "Python path.",
+        type="bool",
+        default=True,
+    )
+    group.addoption(
+        "--fail-on-template-vars",
+        action="store_true",
+        dest="itv",
+        default=False,
+        help="Fail for invalid variables in templates.",
+    )
+    parser.addini(
+        INVALID_TEMPLATE_VARS_ENV,
+        "Fail for invalid variables in templates.",
+        type="bool",
+        default=False,
+    )
+
+
+PROJECT_FOUND = (
+    "pytest-django found a Django project in %s "
+    "(it contains manage.py) and added it to the Python path.\n"
+    'If this is wrong, add "django_find_project = false" to '
+    "pytest.ini and explicitly manage your Python path."
+)
+
+PROJECT_NOT_FOUND = (
+    "pytest-django could not find a Django project "
+    "(no manage.py file could be found). You must "
+    "explicitly add your Django project to the Python path "
+    "to have it picked up."
+)
+
+PROJECT_SCAN_DISABLED = (
+    "pytest-django did not search for Django "
+    "projects since it is disabled in the configuration "
+    '("django_find_project = false")'
+)
+
+
+@contextlib.contextmanager
+def _handle_import_error(extra_message):
+    try:
+        yield
+    except ImportError as e:
+        django_msg = (e.args[0] + "\n\n") if e.args else ""
+        msg = django_msg + extra_message
+        raise ImportError(msg)
+
+
+def _add_django_project_to_path(args):
+    def is_django_project(path):
+        try:
+            return path.is_dir() and (path / "manage.py").exists()
+        except OSError:
+            return False
+
+    def arg_to_path(arg):
+        # Test classes or functions can be appended to paths separated by ::
+        arg = arg.split("::", 1)[0]
+        return pathlib.Path(arg)
+
+    def find_django_path(args):
+        args = map(str, args)
+        args = [arg_to_path(x) for x in args if not x.startswith("-")]
+
+        cwd = pathlib.Path.cwd()
+        if not args:
+            args.append(cwd)
+        elif cwd not in args:
+            args.append(cwd)
+
+        for arg in args:
+            if is_django_project(arg):
+                return arg
+            for parent in arg.parents:
+                if is_django_project(parent):
+                    return parent
+        return None
+
+    project_dir = find_django_path(args)
+    if project_dir:
+        sys.path.insert(0, str(project_dir.absolute()))
+        return PROJECT_FOUND % project_dir
+    return PROJECT_NOT_FOUND
+
+
+def _setup_django():
+    if "django" not in sys.modules:
+        return
+
+    import django.conf
+
+    # Avoid force-loading Django when settings are not properly configured.
+    if not django.conf.settings.configured:
+        return
+
+    import django.apps
+
+    if not django.apps.apps.ready:
+        django.setup()
+
+    _blocking_manager.block()
+
+
+def _get_boolean_value(x, name, default=None):
+    if x is None:
+        return default
+    if x in (True, False):
+        return x
+    possible_values = {"true": True, "false": False, "1": True, "0": False}
+    try:
+        return possible_values[x.lower()]
+    except KeyError:
+        raise ValueError(
+            "{} is not a valid value for {}. "
+            "It must be one of {}.".format(x, name, ", ".join(possible_values.keys()))
+        )
+
+
+def pytest_load_initial_conftests(early_config, parser, args):
+    # Register the marks
+    early_config.addinivalue_line(
+        "markers",
+        "django_db(transaction=False): Mark the test as using "
+        "the Django test database.  The *transaction* argument marks will "
+        "allow you to use real transactions in the test like Django's "
+        "TransactionTestCase.",
+    )
+    early_config.addinivalue_line(
+        "markers",
+        "urls(modstr): Use a different URLconf for this test, similar to "
+        "the `urls` attribute of Django's `TestCase` objects.  *modstr* is "
+        "a string specifying the module of a URL config, e.g. "
+        '"my_app.test_urls".',
+    )
+    early_config.addinivalue_line(
+        "markers",
+        "ignore_template_errors(): ignore errors from invalid template "
+        "variables (if --fail-on-template-vars is used).",
+    )
+
+    options = parser.parse_known_args(args)
+
+    if options.version or options.help:
+        return
+
+    django_find_project = _get_boolean_value(
+        early_config.getini("django_find_project"), "django_find_project"
+    )
+
+    if django_find_project:
+        _django_project_scan_outcome = _add_django_project_to_path(args)
+    else:
+        _django_project_scan_outcome = PROJECT_SCAN_DISABLED
+
+    if (
+        options.itv
+        or _get_boolean_value(
+            os.environ.get(INVALID_TEMPLATE_VARS_ENV), INVALID_TEMPLATE_VARS_ENV
+        )
+        or early_config.getini(INVALID_TEMPLATE_VARS_ENV)
+    ):
+        os.environ[INVALID_TEMPLATE_VARS_ENV] = "true"
+
+    def _get_option_with_source(option, envname):
+        if option:
+            return option, "option"
+        if envname in os.environ:
+            return os.environ[envname], "env"
+        cfgval = early_config.getini(envname)
+        if cfgval:
+            return cfgval, "ini"
+        return None, None
+
+    ds, ds_source = _get_option_with_source(options.ds, SETTINGS_MODULE_ENV)
+    dc, dc_source = _get_option_with_source(options.dc, CONFIGURATION_ENV)
+
+    if ds:
+        _report_header.append("settings: %s (from %s)" % (ds, ds_source))
+        os.environ[SETTINGS_MODULE_ENV] = ds
+
+        if dc:
+            _report_header.append("configuration: %s (from %s)" % (dc, dc_source))
+            os.environ[CONFIGURATION_ENV] = dc
+
+            # Install the django-configurations importer
+            import configurations.importer
+
+            configurations.importer.install()
+
+        # Forcefully load Django settings, throws ImportError or
+        # ImproperlyConfigured if settings cannot be loaded.
+        from django.conf import settings as dj_settings
+
+        with _handle_import_error(_django_project_scan_outcome):
+            dj_settings.DATABASES
+
+    _setup_django()
+
+
+def pytest_report_header():
+    if _report_header:
+        return ["django: " + ", ".join(_report_header)]
+
+
+@pytest.mark.trylast
+def pytest_configure():
+    # Allow Django settings to be configured in a user pytest_configure call,
+    # but make sure we call django.setup()
+    _setup_django()
+
+
+def _classmethod_is_defined_at_leaf(cls, method_name):
+    super_method = None
+
+    for base_cls in cls.__mro__[1:]:  # pragma: no branch
+        super_method = base_cls.__dict__.get(method_name)
+        if super_method is not None:
+            break
+
+    assert super_method is not None, (
+        "%s could not be found in base classes" % method_name
+    )
+
+    method = getattr(cls, method_name)
+
+    try:
+        f = method.__func__
+    except AttributeError:
+        pytest.fail("%s.%s should be a classmethod" % (cls, method_name))
+    if PY2 and not (
+        inspect.ismethod(method)
+        and inspect.isclass(method.__self__)
+        and issubclass(cls, method.__self__)
+    ):
+        pytest.fail("%s.%s should be a classmethod" % (cls, method_name))
+    return f is not super_method.__func__
+
+
+_disabled_classmethods = {}
+
+
+def _disable_class_methods(cls):
+    if cls in _disabled_classmethods:
+        return
+
+    _disabled_classmethods[cls] = (
+        # Get the classmethod object (not the resulting bound method),
+        # otherwise inheritance will be broken when restoring.
+        cls.__dict__.get("setUpClass"),
+        _classmethod_is_defined_at_leaf(cls, "setUpClass"),
+        cls.__dict__.get("tearDownClass"),
+        _classmethod_is_defined_at_leaf(cls, "tearDownClass"),
+    )
+
+    cls.setUpClass = types.MethodType(lambda cls: None, cls)
+    cls.tearDownClass = types.MethodType(lambda cls: None, cls)
+
+
+def _restore_class_methods(cls):
+    (
+        setUpClass,
+        restore_setUpClass,
+        tearDownClass,
+        restore_tearDownClass,
+    ) = _disabled_classmethods.pop(cls)
+
+    try:
+        del cls.setUpClass
+    except AttributeError:
+        raise
+
+    try:
+        del cls.tearDownClass
+    except AttributeError:
+        pass
+
+    if restore_setUpClass:
+        cls.setUpClass = setUpClass
+
+    if restore_tearDownClass:
+        cls.tearDownClass = tearDownClass
+
+
+def pytest_runtest_setup(item):
+    if _handle_unittest_methods:
+        if django_settings_is_configured() and is_django_unittest(item):
+            _disable_class_methods(item.cls)
+
+
+@pytest.hookimpl(tryfirst=True)
+def pytest_collection_modifyitems(items):
+    # If Django is not configured we don't need to bother
+    if not django_settings_is_configured():
+        return
+
+    from django.test import TestCase, TransactionTestCase
+
+    def get_order_number(test):
+        if hasattr(test, "cls") and test.cls:
+            # Beware, TestCase is a subclass of TransactionTestCase
+            if issubclass(test.cls, TestCase):
+                return 0
+            if issubclass(test.cls, TransactionTestCase):
+                return 1
+
+        marker_db = test.get_closest_marker('django_db')
+        if marker_db:
+            transaction = validate_django_db(marker_db)[0]
+            if transaction is True:
+                return 1
+        else:
+            transaction = None
+
+        fixtures = getattr(test, 'fixturenames', [])
+        if "transactional_db" in fixtures:
+            return 1
+
+        if transaction is False:
+            return 0
+        if "db" in fixtures:
+            return 0
+
+        return 2
+
+    items[:] = sorted(items, key=get_order_number)
+
+
+@pytest.fixture(autouse=True, scope="session")
+def django_test_environment(request):
+    """
+    Ensure that Django is loaded and has its testing environment setup.
+
+    XXX It is a little dodgy that this is an autouse fixture.  Perhaps
+        an email fixture should be requested in order to be able to
+        use the Django email machinery just like you need to request a
+        db fixture for access to the Django database, etc.  But
+        without duplicating a lot more of Django's test support code
+        we need to follow this model.
+    """
+    if django_settings_is_configured():
+        _setup_django()
+        from django.conf import settings as dj_settings
+        from django.test.utils import setup_test_environment, teardown_test_environment
+
+        dj_settings.DEBUG = False
+        setup_test_environment()
+        request.addfinalizer(teardown_test_environment)
+
+
+@pytest.fixture(scope="session")
+def django_db_blocker():
+    """Wrapper around Django's database access.
+
+    This object can be used to re-enable database access.  This fixture is used
+    internally in pytest-django to build the other fixtures and can be used for
+    special database handling.
+
+    The object is a context manager and provides the methods
+    .unblock()/.block() and .restore() to temporarily enable database access.
+
+    This is an advanced feature that is meant to be used to implement database
+    fixtures.
+    """
+    if not django_settings_is_configured():
+        return None
+
+    return _blocking_manager
+
+
+@pytest.fixture(autouse=True)
+def _django_db_marker(request):
+    """Implement the django_db marker, internal to pytest-django.
+
+    This will dynamically request the ``db``, ``transactional_db`` or
+    ``django_db_reset_sequences`` fixtures as required by the django_db marker.
+    """
+    marker = request.node.get_closest_marker("django_db")
+    if marker:
+        transaction, reset_sequences = validate_django_db(marker)
+        if reset_sequences:
+            request.getfixturevalue("django_db_reset_sequences")
+        elif transaction:
+            request.getfixturevalue("transactional_db")
+        else:
+            request.getfixturevalue("db")
+
+
+@pytest.fixture(autouse=True, scope="class")
+def _django_setup_unittest(request, django_db_blocker):
+    """Setup a django unittest, internal to pytest-django."""
+    if not django_settings_is_configured() or not is_django_unittest(request):
+        yield
+        return
+
+    # Fix/patch pytest.
+    # Before pytest 5.4: https://github.com/pytest-dev/pytest/issues/5991
+    # After pytest 5.4: https://github.com/pytest-dev/pytest-django/issues/824
+    from _pytest.monkeypatch import MonkeyPatch
+
+    def non_debugging_runtest(self):
+        self._testcase(result=self)
+
+    mp_debug = MonkeyPatch()
+    mp_debug.setattr("_pytest.unittest.TestCaseFunction.runtest", non_debugging_runtest)
+
+    request.getfixturevalue("django_db_setup")
+
+    cls = request.node.cls
+
+    with django_db_blocker.unblock():
+        if _handle_unittest_methods:
+            _restore_class_methods(cls)
+            cls.setUpClass()
+            _disable_class_methods(cls)
+
+            yield
+
+            _restore_class_methods(cls)
+            cls.tearDownClass()
+        else:
+            yield
+
+    if mp_debug:
+        mp_debug.undo()
+
+
+@pytest.fixture(scope="function", autouse=True)
+def _dj_autoclear_mailbox():
+    if not django_settings_is_configured():
+        return
+
+    from django.core import mail
+
+    del mail.outbox[:]
+
+
+@pytest.fixture(scope="function")
+def mailoutbox(django_mail_patch_dns, _dj_autoclear_mailbox):
+    if not django_settings_is_configured():
+        return
+
+    from django.core import mail
+
+    return mail.outbox
+
+
+@pytest.fixture(scope="function")
+def django_mail_patch_dns(monkeypatch, django_mail_dnsname):
+    from django.core import mail
+
+    monkeypatch.setattr(mail.message, "DNS_NAME", django_mail_dnsname)
+
+
+@pytest.fixture(scope="function")
+def django_mail_dnsname():
+    return "fake-tests.example.com"
+
+
+@pytest.fixture(autouse=True, scope="function")
+def _django_set_urlconf(request):
+    """Apply the @pytest.mark.urls marker, internal to pytest-django."""
+    marker = request.node.get_closest_marker("urls")
+    if marker:
+        skip_if_no_django()
+        import django.conf
+
+        try:
+            from django.urls import clear_url_caches, set_urlconf
+        except ImportError:
+            # Removed in Django 2.0
+            from django.core.urlresolvers import clear_url_caches, set_urlconf
+
+        urls = validate_urls(marker)
+        original_urlconf = django.conf.settings.ROOT_URLCONF
+        django.conf.settings.ROOT_URLCONF = urls
+        clear_url_caches()
+        set_urlconf(None)
+
+        def restore():
+            django.conf.settings.ROOT_URLCONF = original_urlconf
+            # Copy the pattern from
+            # https://github.com/django/django/blob/master/django/test/signals.py#L152
+            clear_url_caches()
+            set_urlconf(None)
+
+        request.addfinalizer(restore)
+
+
+@pytest.fixture(autouse=True, scope="session")
+def _fail_for_invalid_template_variable():
+    """Fixture that fails for invalid variables in templates.
+
+    This fixture will fail each test that uses django template rendering
+    should a template contain an invalid template variable.
+    The fail message will include the name of the invalid variable and
+    in most cases the template name.
+
+    It does not raise an exception, but fails, as the stack trace doesn't
+    offer any helpful information to debug.
+    This behavior can be switched off using the marker:
+    ``pytest.mark.ignore_template_errors``
+    """
+
+    class InvalidVarException(object):
+        """Custom handler for invalid strings in templates."""
+
+        def __init__(self):
+            self.fail = True
+
+        def __contains__(self, key):
+            """There is a test for '%s' in TEMPLATE_STRING_IF_INVALID."""
+            return key == "%s"
+
+        @staticmethod
+        def _get_origin():
+            stack = inspect.stack()
+
+            # Try to use topmost `self.origin` first (Django 1.9+, and with
+            # TEMPLATE_DEBUG)..
+            for f in stack[2:]:
+                func = f[3]
+                if func == "render":
+                    frame = f[0]
+                    try:
+                        origin = frame.f_locals["self"].origin
+                    except (AttributeError, KeyError):
+                        continue
+                    if origin is not None:
+                        return origin
+
+            from django.template import Template
+
+            # finding the ``render`` needle in the stack
+            frame = reduce(
+                lambda x, y: y[3] == "render" and "base.py" in y[1] and y or x, stack
+            )
+            # assert 0, stack
+            frame = frame[0]
+            # finding only the frame locals in all frame members
+            f_locals = reduce(
+                lambda x, y: y[0] == "f_locals" and y or x, inspect.getmembers(frame)
+            )[1]
+            # ``django.template.base.Template``
+            template = f_locals["self"]
+            if isinstance(template, Template):
+                return template.name
+
+        def __mod__(self, var):
+            """Handle TEMPLATE_STRING_IF_INVALID % var."""
+            origin = self._get_origin()
+            if origin:
+                msg = "Undefined template variable '%s' in '%s'" % (var, origin)
+            else:
+                msg = "Undefined template variable '%s'" % var
+            if self.fail:
+                pytest.fail(msg)
+            else:
+                return msg
+
+    if (
+        os.environ.get(INVALID_TEMPLATE_VARS_ENV, "false") == "true"
+        and django_settings_is_configured()
+    ):
+        from django.conf import settings as dj_settings
+
+        if dj_settings.TEMPLATES:
+            dj_settings.TEMPLATES[0]["OPTIONS"][
+                "string_if_invalid"
+            ] = InvalidVarException()
+        else:
+            dj_settings.TEMPLATE_STRING_IF_INVALID = InvalidVarException()
+
+
+@pytest.fixture(autouse=True)
+def _template_string_if_invalid_marker(request):
+    """Apply the @pytest.mark.ignore_template_errors marker,
+     internal to pytest-django."""
+    marker = request.keywords.get("ignore_template_errors", None)
+    if os.environ.get(INVALID_TEMPLATE_VARS_ENV, "false") == "true":
+        if marker and django_settings_is_configured():
+            from django.conf import settings as dj_settings
+
+            if dj_settings.TEMPLATES:
+                dj_settings.TEMPLATES[0]["OPTIONS"]["string_if_invalid"].fail = False
+            else:
+                dj_settings.TEMPLATE_STRING_IF_INVALID.fail = False
+
+
+@pytest.fixture(autouse=True, scope="function")
+def _django_clear_site_cache():
+    """Clears ``django.contrib.sites.models.SITE_CACHE`` to avoid
+    unexpected behavior with cached site objects.
+    """
+
+    if django_settings_is_configured():
+        from django.conf import settings as dj_settings
+
+        if "django.contrib.sites" in dj_settings.INSTALLED_APPS:
+            from django.contrib.sites.models import Site
+
+            Site.objects.clear_cache()
+
+
+# ############### Helper Functions ################
+
+
+class _DatabaseBlockerContextManager(object):
+    def __init__(self, db_blocker):
+        self._db_blocker = db_blocker
+
+    def __enter__(self):
+        pass
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        self._db_blocker.restore()
+
+
+class _DatabaseBlocker(object):
+    """Manager for django.db.backends.base.base.BaseDatabaseWrapper.
+
+    This is the object returned by django_db_blocker.
+    """
+
+    def __init__(self):
+        self._history = []
+        self._real_ensure_connection = None
+
+    @property
+    def _dj_db_wrapper(self):
+        from django.db.backends.base.base import BaseDatabaseWrapper
+
+        # The first time the _dj_db_wrapper is accessed, we will save a
+        # reference to the real implementation.
+        if self._real_ensure_connection is None:
+            self._real_ensure_connection = BaseDatabaseWrapper.ensure_connection
+
+        return BaseDatabaseWrapper
+
+    def _save_active_wrapper(self):
+        return self._history.append(self._dj_db_wrapper.ensure_connection)
+
+    def _blocking_wrapper(*args, **kwargs):
+        __tracebackhide__ = True
+        __tracebackhide__  # Silence pyflakes
+        raise RuntimeError(
+            "Database access not allowed, "
+            'use the "django_db" mark, or the '
+            '"db" or "transactional_db" fixtures to enable it.'
+        )
+
+    def unblock(self):
+        """Enable access to the Django database."""
+        self._save_active_wrapper()
+        self._dj_db_wrapper.ensure_connection = self._real_ensure_connection
+        return _DatabaseBlockerContextManager(self)
+
+    def block(self):
+        """Disable access to the Django database."""
+        self._save_active_wrapper()
+        self._dj_db_wrapper.ensure_connection = self._blocking_wrapper
+        return _DatabaseBlockerContextManager(self)
+
+    def restore(self):
+        self._dj_db_wrapper.ensure_connection = self._history.pop()
+
+
+_blocking_manager = _DatabaseBlocker()
+
+
+def validate_django_db(marker):
+    """Validate the django_db marker.
+
+    It checks the signature and creates the ``transaction`` and
+    ``reset_sequences`` attributes on the marker which will have the
+    correct values.
+
+    A sequence reset is only allowed when combined with a transaction.
+    """
+
+    def apifun(transaction=False, reset_sequences=False):
+        return transaction, reset_sequences
+
+    return apifun(*marker.args, **marker.kwargs)
+
+
+def validate_urls(marker):
+    """Validate the urls marker.
+
+    It checks the signature and creates the `urls` attribute on the
+    marker which will have the correct value.
+    """
+
+    def apifun(urls):
+        return urls
+
+    return apifun(*marker.args, **marker.kwargs)

+ 0 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/__init__.py


+ 0 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/__init__.py


+ 9 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/fixtures/items.json

@@ -0,0 +1,9 @@
+[
+  {
+    "pk": 1,
+    "model": "app.item",
+    "fields": {
+      "name": "Fixture item"
+    }
+  }
+]

+ 30 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/migrations/0001_initial.py

@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9a1 on 2016-06-22 04:33
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = []
+
+    operations = [
+        migrations.CreateModel(
+            name="Item",
+            fields=[
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("name", models.CharField(max_length=100)),
+            ],
+        )
+    ]

+ 0 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/migrations/__init__.py


+ 5 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/models.py

@@ -0,0 +1,5 @@
+from django.db import models
+
+
+class Item(models.Model):
+    name = models.CharField(max_length=100)

+ 1 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/static/a_file.txt

@@ -0,0 +1 @@
+bla

+ 14 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/app/views.py

@@ -0,0 +1,14 @@
+from django.http import HttpResponse
+from django.template import Template
+from django.template.context import Context
+
+from .models import Item
+
+
+def admin_required_view(request):
+    assert request.user.is_staff
+    return HttpResponse(Template("You are an admin").render(Context()))
+
+
+def item_count(request):
+    return HttpResponse("Item count: %d" % Item.objects.count())

+ 4 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/compat.py

@@ -0,0 +1,4 @@
+try:
+    from urllib2 import urlopen, HTTPError
+except ImportError:
+    from urllib.request import urlopen, HTTPError  # noqa: F401

+ 162 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/db_helpers.py

@@ -0,0 +1,162 @@
+import os
+import subprocess
+import sqlite3
+
+import pytest
+
+from django.conf import settings
+from django.utils.encoding import force_str
+
+
+# Construct names for the "inner" database used in runpytest tests
+_settings = settings.DATABASES["default"]
+
+DB_NAME = _settings["NAME"]
+TEST_DB_NAME = _settings["TEST"]["NAME"]
+
+if _settings["ENGINE"] == "django.db.backends.sqlite3" and TEST_DB_NAME is None:
+    TEST_DB_NAME = ":memory:"
+else:
+    DB_NAME += "_inner"
+
+    if TEST_DB_NAME is None:
+        # No explicit test db name was given, construct a default one
+        TEST_DB_NAME = "test_{}_inner".format(DB_NAME)
+    else:
+        # An explicit test db name was given, is that as the base name
+        TEST_DB_NAME = "{}_inner".format(TEST_DB_NAME)
+
+
+def get_db_engine():
+    return _settings["ENGINE"].split(".")[-1]
+
+
+class CmdResult(object):
+    def __init__(self, status_code, std_out, std_err):
+        self.status_code = status_code
+        self.std_out = std_out
+        self.std_err = std_err
+
+
+def run_cmd(*args):
+    r = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    stdoutdata, stderrdata = r.communicate()
+    ret = r.wait()
+    return CmdResult(ret, stdoutdata, stderrdata)
+
+
+def run_mysql(*args):
+    user = _settings.get("USER", None)
+    if user:  # pragma: no branch
+        args = ("-u", user) + tuple(args)
+    args = ("mysql",) + tuple(args)
+    return run_cmd(*args)
+
+
+def skip_if_sqlite_in_memory():
+    if (
+        _settings["ENGINE"] == "django.db.backends.sqlite3"
+        and _settings["TEST"]["NAME"] is None
+    ):
+        pytest.skip("Do not test db reuse since database does not support it")
+
+
+def _get_db_name(db_suffix=None):
+    name = TEST_DB_NAME
+    if db_suffix:
+        name = "%s_%s" % (name, db_suffix)
+    return name
+
+
+def drop_database(db_suffix=None):
+    name = _get_db_name(db_suffix)
+    db_engine = get_db_engine()
+
+    if db_engine == "postgresql_psycopg2":
+        r = run_cmd("psql", "postgres", "-c", "DROP DATABASE %s" % name)
+        assert "DROP DATABASE" in force_str(
+            r.std_out
+        ) or "does not exist" in force_str(r.std_err)
+        return
+
+    if db_engine == "mysql":
+        r = run_mysql("-e", "DROP DATABASE %s" % name)
+        assert "database doesn't exist" in force_str(r.std_err) or r.status_code == 0
+        return
+
+    assert db_engine == "sqlite3", "%s cannot be tested properly!" % db_engine
+    assert name != ":memory:", "sqlite in-memory database cannot be dropped!"
+    if os.path.exists(name):  # pragma: no branch
+        os.unlink(name)
+
+
+def db_exists(db_suffix=None):
+    name = _get_db_name(db_suffix)
+    db_engine = get_db_engine()
+
+    if db_engine == "postgresql_psycopg2":
+        r = run_cmd("psql", name, "-c", "SELECT 1")
+        return r.status_code == 0
+
+    if db_engine == "mysql":
+        r = run_mysql(name, "-e", "SELECT 1")
+        return r.status_code == 0
+
+    assert db_engine == "sqlite3", "%s cannot be tested properly!" % db_engine
+    assert TEST_DB_NAME != ":memory:", (
+        "sqlite in-memory database cannot be checked for existence!")
+    return os.path.exists(name)
+
+
+def mark_database():
+    db_engine = get_db_engine()
+
+    if db_engine == "postgresql_psycopg2":
+        r = run_cmd("psql", TEST_DB_NAME, "-c", "CREATE TABLE mark_table();")
+        assert r.status_code == 0
+        return
+
+    if db_engine == "mysql":
+        r = run_mysql(TEST_DB_NAME, "-e", "CREATE TABLE mark_table(kaka int);")
+        assert r.status_code == 0
+        return
+
+    assert db_engine == "sqlite3", "%s cannot be tested properly!" % db_engine
+    assert TEST_DB_NAME != ":memory:", (
+        "sqlite in-memory database cannot be marked!")
+
+    conn = sqlite3.connect(TEST_DB_NAME)
+    try:
+        with conn:
+            conn.execute("CREATE TABLE mark_table(kaka int);")
+    finally:  # Close the DB even if an error is raised
+        conn.close()
+
+
+def mark_exists():
+    db_engine = get_db_engine()
+
+    if db_engine == "postgresql_psycopg2":
+        r = run_cmd("psql", TEST_DB_NAME, "-c", "SELECT 1 FROM mark_table")
+
+        # When something pops out on std_out, we are good
+        return bool(r.std_out)
+
+    if db_engine == "mysql":
+        r = run_mysql(TEST_DB_NAME, "-e", "SELECT 1 FROM mark_table")
+
+        return r.status_code == 0
+
+    assert db_engine == "sqlite3", "%s cannot be tested properly!" % db_engine
+    assert TEST_DB_NAME != ":memory:", (
+        "sqlite in-memory database cannot be checked for mark!")
+
+    conn = sqlite3.connect(TEST_DB_NAME)
+    try:
+        with conn:
+            conn.execute("SELECT 1 FROM mark_table")
+            return True
+    except sqlite3.OperationalError:
+        return False
+    finally:  # Close the DB even if an error is raised
+        conn.close()

+ 34 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_base.py

@@ -0,0 +1,34 @@
+import django
+
+ROOT_URLCONF = "pytest_django_test.urls"
+INSTALLED_APPS = [
+    "django.contrib.auth",
+    "django.contrib.contenttypes",
+    "django.contrib.sessions",
+    "django.contrib.sites",
+    "pytest_django_test.app",
+]
+
+STATIC_URL = "/static/"
+SECRET_KEY = "foobar"
+
+MIDDLEWARE = [
+    "django.contrib.sessions.middleware.SessionMiddleware",
+    "django.middleware.common.CommonMiddleware",
+    "django.middleware.csrf.CsrfViewMiddleware",
+    "django.contrib.auth.middleware.AuthenticationMiddleware",
+    "django.contrib.messages.middleware.MessageMiddleware",
+]
+
+if django.VERSION < (1, 10):
+    MIDDLEWARE_CLASSES = MIDDLEWARE
+
+
+TEMPLATES = [
+    {
+        "BACKEND": "django.template.backends.django.DjangoTemplates",
+        "DIRS": [],
+        "APP_DIRS": True,
+        "OPTIONS": {},
+    }
+]

+ 11 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_mysql_innodb.py

@@ -0,0 +1,11 @@
+from .settings_base import *  # noqa: F401 F403
+
+DATABASES = {
+    "default": {
+        "ENGINE": "django.db.backends.mysql",
+        "NAME": "pytest_django_should_never_get_accessed",
+        "HOST": "localhost",
+        "USER": "root",
+        "OPTIONS": {"init_command": "SET default_storage_engine=InnoDB"},
+    }
+}

+ 11 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_mysql_myisam.py

@@ -0,0 +1,11 @@
+from .settings_base import *  # noqa: F401 F403
+
+DATABASES = {
+    "default": {
+        "ENGINE": "django.db.backends.mysql",
+        "NAME": "pytest_django_should_never_get_accessed",
+        "HOST": "localhost",
+        "USER": "root",
+        "OPTIONS": {"init_command": "SET default_storage_engine=MyISAM"},
+    }
+}

+ 19 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_postgres.py

@@ -0,0 +1,19 @@
+from .settings_base import *  # noqa: F401 F403
+
+# PyPy compatibility
+try:
+    from psycopg2ct import compat
+
+    compat.register()
+except ImportError:
+    pass
+
+
+DATABASES = {
+    "default": {
+        "ENGINE": "django.db.backends.postgresql_psycopg2",
+        "NAME": "pytest_django_should_never_get_accessed",
+        "HOST": "localhost",
+        "USER": "",
+    }
+}

+ 8 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_sqlite.py

@@ -0,0 +1,8 @@
+from .settings_base import *  # noqa: F401 F403
+
+DATABASES = {
+    "default": {
+        "ENGINE": "django.db.backends.sqlite3",
+        "NAME": "/should_not_be_accessed",
+    }
+}

+ 17 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/settings_sqlite_file.py

@@ -0,0 +1,17 @@
+import tempfile
+
+from .settings_base import *  # noqa: F401 F403
+
+# This is a SQLite configuration, which uses a file based database for
+# tests (via setting TEST_NAME / TEST['NAME']).
+
+# The name as expected / used by Django/pytest_django (tests/db_helpers.py).
+_fd, _filename = tempfile.mkstemp(prefix="test_")
+
+DATABASES = {
+    "default": {
+        "ENGINE": "django.db.backends.sqlite3",
+        "NAME": "/pytest_django_should_never_get_accessed",
+        "TEST": {"NAME": _filename},
+    }
+}

+ 8 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/urls.py

@@ -0,0 +1,8 @@
+from django.conf.urls import url
+
+from .app import views
+
+urlpatterns = [
+    url(r"^item_count/$", views.item_count),
+    url(r"^admin-required/$", views.admin_required_view),
+]

+ 6 - 0
desktop/core/ext-py/pytest-django-3.10.0/pytest_django_test/urls_overridden.py

@@ -0,0 +1,6 @@
+from django.conf.urls import url
+from django.http import HttpResponse
+
+urlpatterns = [
+    url(r"^overridden_url/$", lambda r: HttpResponse("Overridden urlconf works!"))
+]

+ 10 - 0
desktop/core/ext-py/pytest-django-3.10.0/requirements.txt

@@ -0,0 +1,10 @@
+-e .
+setuptools
+django
+django-configurations
+pytest-xdist
+tox
+wheel
+twine
+flake8
+sphinx_rtd_theme

+ 23 - 0
desktop/core/ext-py/pytest-django-3.10.0/setup.cfg

@@ -0,0 +1,23 @@
+[tool:pytest]
+addopts = --strict -ra
+django_settings_module = pytest_django_test.settings_sqlite_file
+testpaths = tests
+
+[wheel]
+universal = 1
+
+[flake8]
+ignore = W503
+max-line-length = 99
+exclude = lib/,src/,docs/,bin/
+
+[isort]
+forced_separate = tests,pytest_django,pytest_django_test
+
+[metadata]
+license_file = LICENSE
+
+[egg_info]
+tag_build = 
+tag_date = 0
+

+ 78 - 0
desktop/core/ext-py/pytest-django-3.10.0/setup.py

@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import codecs
+import os
+
+from setuptools import setup
+
+
+# Utility function to read the README file.
+# Used for the long_description.  It's nice, because now 1) we have a top level
+# README file and 2) it's easier to type in the README file than to put a raw
+# string in below ...
+def read(fname):
+    file_path = os.path.join(os.path.dirname(__file__), fname)
+    return codecs.open(file_path, encoding='utf-8').read()
+
+
+setup(
+    name='pytest-django',
+    use_scm_version=True,
+    description='A Django plugin for pytest.',
+    author='Andreas Pelme',
+    author_email='andreas@pelme.se',
+    maintainer="Andreas Pelme",
+    maintainer_email="andreas@pelme.se",
+    url='https://pytest-django.readthedocs.io/',
+    license='BSD-3-Clause',
+    packages=['pytest_django'],
+    long_description=read('README.rst'),
+    python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
+    setup_requires=['setuptools_scm>=1.11.1'],
+    install_requires=[
+        'pytest>=3.6',
+        'pathlib2;python_version<"3.4"',
+    ],
+    extras_require={
+        'docs': [
+            'sphinx',
+            'sphinx_rtd_theme',
+        ],
+        'testing': [
+            'Django',
+            'django-configurations>=2.0',
+            'six',
+        ],
+    },
+    classifiers=['Development Status :: 5 - Production/Stable',
+                 'Framework :: Django',
+                 'Framework :: Django :: 1.8',
+                 'Framework :: Django :: 1.9',
+                 'Framework :: Django :: 1.10',
+                 'Framework :: Django :: 1.11',
+                 'Framework :: Django :: 2.0',
+                 'Framework :: Django :: 2.1',
+                 'Framework :: Django :: 2.2',
+                 'Framework :: Django :: 3.0',
+                 'Framework :: Django :: 3.1',
+                 'Intended Audience :: Developers',
+                 'License :: OSI Approved :: BSD License',
+                 'Operating System :: OS Independent',
+                 'Programming Language :: Python',
+                 'Programming Language :: Python :: 2.7',
+                 'Programming Language :: Python :: 3.4',
+                 'Programming Language :: Python :: 3.5',
+                 'Programming Language :: Python :: 3.6',
+                 'Programming Language :: Python :: 3.7',
+                 'Programming Language :: Python :: 3.8',
+                 'Programming Language :: Python :: Implementation :: CPython',
+                 'Programming Language :: Python :: Implementation :: PyPy',
+                 'Topic :: Software Development :: Testing',
+                 ],
+    project_urls={
+        'Source': 'https://github.com/pytest-dev/pytest-django',
+        'Changelog': 'https://pytest-django.readthedocs.io/en/latest/changelog.html',
+    },
+    # the following makes a plugin available to pytest
+    entry_points={'pytest11': ['django = pytest_django.plugin']})

+ 165 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/conftest.py

@@ -0,0 +1,165 @@
+import copy
+import shutil
+from textwrap import dedent
+
+import pytest
+import six
+from django.conf import settings
+
+try:
+    import pathlib
+except ImportError:
+    import pathlib2 as pathlib
+
+pytest_plugins = "pytester"
+
+REPOSITORY_ROOT = pathlib.Path(__file__).parent
+
+
+def pytest_configure(config):
+    config.addinivalue_line(
+        "markers", "django_project: options for the django_testdir fixture"
+    )
+
+
+def _marker_apifun(extra_settings="", create_manage_py=False, project_root=None):
+    return {
+        "extra_settings": extra_settings,
+        "create_manage_py": create_manage_py,
+        "project_root": project_root,
+    }
+
+
+@pytest.fixture
+def testdir(testdir, monkeypatch):
+    monkeypatch.delenv("PYTEST_ADDOPTS", raising=False)
+    return testdir
+
+
+@pytest.fixture(scope="function")
+def django_testdir(request, testdir, monkeypatch):
+    from pytest_django_test.db_helpers import DB_NAME, TEST_DB_NAME
+
+    marker = request.node.get_closest_marker("django_project")
+
+    options = _marker_apifun(**(marker.kwargs if marker else {}))
+
+    if hasattr(request.node.cls, "db_settings"):
+        db_settings = request.node.cls.db_settings
+    else:
+        db_settings = copy.deepcopy(settings.DATABASES)
+        db_settings["default"]["NAME"] = DB_NAME
+        db_settings["default"]["TEST"]["NAME"] = TEST_DB_NAME
+
+    test_settings = (
+        dedent(
+            """
+        import django
+
+        # Pypy compatibility
+        try:
+            from psycopg2ct import compat
+        except ImportError:
+            pass
+        else:
+            compat.register()
+
+        DATABASES = %(db_settings)s
+
+        INSTALLED_APPS = [
+            'django.contrib.auth',
+            'django.contrib.contenttypes',
+            'tpkg.app',
+        ]
+        SECRET_KEY = 'foobar'
+
+        MIDDLEWARE = [
+            'django.contrib.sessions.middleware.SessionMiddleware',
+            'django.middleware.common.CommonMiddleware',
+            'django.middleware.csrf.CsrfViewMiddleware',
+            'django.contrib.auth.middleware.AuthenticationMiddleware',
+            'django.contrib.messages.middleware.MessageMiddleware',
+        ]
+
+        if django.VERSION < (1, 10):
+            MIDDLEWARE_CLASSES = MIDDLEWARE
+
+        TEMPLATES = [
+            {
+                'BACKEND': 'django.template.backends.django.DjangoTemplates',
+                'DIRS': [],
+                'APP_DIRS': True,
+                'OPTIONS': {},
+            },
+        ]
+
+        %(extra_settings)s
+    """
+        )
+        % {
+            "db_settings": repr(db_settings),
+            "extra_settings": dedent(options["extra_settings"]),
+        }
+    )
+
+    if options["project_root"]:
+        project_root = testdir.mkdir(options["project_root"])
+    else:
+        project_root = testdir.tmpdir
+
+    tpkg_path = project_root.mkdir("tpkg")
+
+    if options["create_manage_py"]:
+        project_root.ensure("manage.py")
+
+    tpkg_path.ensure("__init__.py")
+
+    app_source = REPOSITORY_ROOT / "../pytest_django_test/app"
+    test_app_path = tpkg_path.join("app")
+
+    # Copy the test app to make it available in the new test run
+    shutil.copytree(six.text_type(app_source), six.text_type(test_app_path))
+    tpkg_path.join("the_settings.py").write(test_settings)
+
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "tpkg.the_settings")
+
+    def create_test_module(test_code, filename="test_the_test.py"):
+        r = tpkg_path.join(filename)
+        r.write(dedent(test_code), ensure=True)
+        return r
+
+    def create_app_file(code, filename):
+        r = test_app_path.join(filename)
+        r.write(dedent(code), ensure=True)
+        return r
+
+    testdir.create_test_module = create_test_module
+    testdir.create_app_file = create_app_file
+    testdir.project_root = project_root
+
+    testdir.makeini(
+        """
+        [pytest]
+        addopts = --strict
+        console_output_style=classic
+    """
+    )
+
+    return testdir
+
+
+@pytest.fixture
+def django_testdir_initial(django_testdir):
+    """A django_testdir fixture which provides initial_data."""
+    django_testdir.project_root.join("tpkg/app/migrations").remove()
+    django_testdir.makefile(
+        ".json",
+        initial_data="""
+        [{
+            "pk": 1,
+            "model": "app.item",
+            "fields": { "name": "mark_initial_data" }
+        }]""",
+    )
+
+    return django_testdir

+ 56 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_asserts.py

@@ -0,0 +1,56 @@
+"""
+Tests the dynamic loading of all Django assertion cases.
+"""
+import inspect
+
+import pytest
+import pytest_django
+
+from pytest_django.asserts import __all__ as asserts_all
+
+
+def _get_actual_assertions_names():
+    """
+    Returns list with names of all assertion helpers in Django.
+    """
+    from django.test import TestCase as DjangoTestCase
+    from unittest import TestCase as DefaultTestCase
+
+    obj = DjangoTestCase('run')
+
+    def is_assert(func):
+        return func.startswith('assert') and '_' not in func
+
+    base_methods = [name for name, member in
+                    inspect.getmembers(DefaultTestCase)
+                    if is_assert(name)]
+
+    return [name for name, member in inspect.getmembers(obj)
+            if is_assert(name) and name not in base_methods]
+
+
+def test_django_asserts_available():
+    django_assertions = _get_actual_assertions_names()
+    expected_assertions = asserts_all
+    assert set(django_assertions) == set(expected_assertions)
+
+    for name in expected_assertions:
+        assert hasattr(pytest_django.asserts, name)
+
+
+@pytest.mark.django_db
+def test_sanity():
+    from django.http import HttpResponse
+    from pytest_django.asserts import assertContains, assertNumQueries
+
+    response = HttpResponse('My response')
+
+    assertContains(response, 'My response')
+    with pytest.raises(AssertionError):
+        assertContains(response, 'Not my response')
+
+    assertNumQueries(0, lambda: 1 + 1)
+    with assertNumQueries(0):
+        pass
+
+    assert assertContains.__doc__

+ 296 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_database.py

@@ -0,0 +1,296 @@
+from __future__ import with_statement
+
+import pytest
+from django.db import connection
+from django.test.testcases import connections_support_transactions
+
+from pytest_django_test.app.models import Item
+
+
+def db_supports_reset_sequences():
+    """Return if the current db engine supports `reset_sequences`."""
+    return (
+        connection.features.supports_transactions
+        and connection.features.supports_sequence_reset
+    )
+
+
+def test_noaccess():
+    with pytest.raises(RuntimeError):
+        Item.objects.create(name="spam")
+    with pytest.raises(RuntimeError):
+        Item.objects.count()
+
+
+@pytest.fixture
+def noaccess():
+    with pytest.raises(RuntimeError):
+        Item.objects.create(name="spam")
+    with pytest.raises(RuntimeError):
+        Item.objects.count()
+
+
+def test_noaccess_fixture(noaccess):
+    # Setup will fail if this test needs to fail
+    pass
+
+
+@pytest.fixture
+def non_zero_sequences_counter(db):
+    """Ensure that the db's internal sequence counter is > 1.
+
+    This is used to test the `reset_sequences` feature.
+    """
+    item_1 = Item.objects.create(name="item_1")
+    item_2 = Item.objects.create(name="item_2")
+    item_1.delete()
+    item_2.delete()
+
+
+class TestDatabaseFixtures:
+    """Tests for the different database fixtures."""
+
+    @pytest.fixture(params=["db", "transactional_db", "django_db_reset_sequences"])
+    def all_dbs(self, request):
+        if request.param == "django_db_reset_sequences":
+            return request.getfixturevalue("django_db_reset_sequences")
+        elif request.param == "transactional_db":
+            return request.getfixturevalue("transactional_db")
+        elif request.param == "db":
+            return request.getfixturevalue("db")
+
+    def test_access(self, all_dbs):
+        Item.objects.create(name="spam")
+
+    def test_clean_db(self, all_dbs):
+        # Relies on the order: test_access created an object
+        assert Item.objects.count() == 0
+
+    def test_transactions_disabled(self, db):
+        if not connections_support_transactions():
+            pytest.skip("transactions required for this test")
+
+        assert connection.in_atomic_block
+
+    def test_transactions_enabled(self, transactional_db):
+        if not connections_support_transactions():
+            pytest.skip("transactions required for this test")
+
+        assert not connection.in_atomic_block
+
+    def test_transactions_enabled_via_reset_seq(self, django_db_reset_sequences):
+        if not connections_support_transactions():
+            pytest.skip("transactions required for this test")
+
+        assert not connection.in_atomic_block
+
+    def test_django_db_reset_sequences_fixture(
+        self, db, django_testdir, non_zero_sequences_counter
+    ):
+
+        if not db_supports_reset_sequences():
+            pytest.skip(
+                "transactions and reset_sequences must be supported "
+                "by the database to run this test"
+            )
+
+        # The test runs on a database that already contains objects, so its
+        # id counter is > 1. We check for the ids of newly created objects.
+        django_testdir.create_test_module(
+            """
+            import pytest
+            from .app.models import Item
+
+            def test_django_db_reset_sequences_requested(
+                    django_db_reset_sequences):
+                item = Item.objects.create(name='new_item')
+                assert item.id == 1
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-v", "--reuse-db")
+        result.stdout.fnmatch_lines(
+            ["*test_django_db_reset_sequences_requested PASSED*"]
+        )
+
+    @pytest.fixture
+    def mydb(self, all_dbs):
+        # This fixture must be able to access the database
+        Item.objects.create(name="spam")
+
+    def test_mydb(self, mydb):
+        if not connections_support_transactions():
+            pytest.skip("transactions required for this test")
+
+        # Check the fixture had access to the db
+        item = Item.objects.get(name="spam")
+        assert item
+
+    def test_fixture_clean(self, all_dbs):
+        # Relies on the order: test_mydb created an object
+        # See https://github.com/pytest-dev/pytest-django/issues/17
+        assert Item.objects.count() == 0
+
+    @pytest.fixture
+    def fin(self, request, all_dbs):
+        # This finalizer must be able to access the database
+        request.addfinalizer(lambda: Item.objects.create(name="spam"))
+
+    def test_fin(self, fin):
+        # Check finalizer has db access (teardown will fail if not)
+        pass
+
+
+class TestDatabaseFixturesAllOrder:
+    @pytest.fixture
+    def fixture_with_db(self, db):
+        Item.objects.create(name="spam")
+
+    @pytest.fixture
+    def fixture_with_transdb(self, transactional_db):
+        Item.objects.create(name="spam")
+
+    @pytest.fixture
+    def fixture_with_reset_sequences(self, django_db_reset_sequences):
+        Item.objects.create(name="spam")
+
+    def test_trans(self, fixture_with_transdb):
+        pass
+
+    def test_db(self, fixture_with_db):
+        pass
+
+    def test_db_trans(self, fixture_with_db, fixture_with_transdb):
+        pass
+
+    def test_trans_db(self, fixture_with_transdb, fixture_with_db):
+        pass
+
+    def test_reset_sequences(
+        self, fixture_with_reset_sequences, fixture_with_transdb, fixture_with_db
+    ):
+        pass
+
+
+class TestDatabaseMarker:
+    "Tests for the django_db marker."
+
+    @pytest.mark.django_db
+    def test_access(self):
+        Item.objects.create(name="spam")
+
+    @pytest.mark.django_db
+    def test_clean_db(self):
+        # Relies on the order: test_access created an object.
+        assert Item.objects.count() == 0
+
+    @pytest.mark.django_db
+    def test_transactions_disabled(self):
+        if not connections_support_transactions():
+            pytest.skip("transactions required for this test")
+
+        assert connection.in_atomic_block
+
+    @pytest.mark.django_db(transaction=False)
+    def test_transactions_disabled_explicit(self):
+        if not connections_support_transactions():
+            pytest.skip("transactions required for this test")
+
+        assert connection.in_atomic_block
+
+    @pytest.mark.django_db(transaction=True)
+    def test_transactions_enabled(self):
+        if not connections_support_transactions():
+            pytest.skip("transactions required for this test")
+
+        assert not connection.in_atomic_block
+
+    @pytest.mark.django_db
+    def test_reset_sequences_disabled(self, request):
+        marker = request.node.get_closest_marker("django_db")
+        assert not marker.kwargs
+
+    @pytest.mark.django_db(reset_sequences=True)
+    def test_reset_sequences_enabled(self, request):
+        marker = request.node.get_closest_marker("django_db")
+        assert marker.kwargs["reset_sequences"]
+
+
+def test_unittest_interaction(django_testdir):
+    "Test that (non-Django) unittests cannot access the DB."
+
+    django_testdir.create_test_module(
+        """
+        import pytest
+        import unittest
+        from .app.models import Item
+
+        class TestCase_setupClass(unittest.TestCase):
+            @classmethod
+            def setUpClass(cls):
+                Item.objects.create(name='foo')
+
+            def test_db_access_1(self):
+                Item.objects.count() == 1
+
+        class TestCase_setUp(unittest.TestCase):
+            @classmethod
+            def setUp(cls):
+                Item.objects.create(name='foo')
+
+            def test_db_access_2(self):
+                Item.objects.count() == 1
+
+        class TestCase(unittest.TestCase):
+            def test_db_access_3(self):
+                Item.objects.count() == 1
+    """
+    )
+
+    result = django_testdir.runpytest_subprocess("-v", "--reuse-db")
+    result.stdout.fnmatch_lines(
+        [
+            "*test_db_access_1 ERROR*",
+            "*test_db_access_2 FAILED*",
+            "*test_db_access_3 FAILED*",
+            "*ERROR at setup of TestCase_setupClass.test_db_access_1*",
+            '*RuntimeError: Database access not allowed, use the "django_db" mark, '
+            'or the "db" or "transactional_db" fixtures to enable it.',
+        ]
+    )
+
+
+class Test_database_blocking:
+    def test_db_access_in_conftest(self, django_testdir):
+        """Make sure database access in conftest module is prohibited."""
+
+        django_testdir.makeconftest(
+            """
+            from tpkg.app.models import Item
+            Item.objects.get()
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-v")
+        result.stderr.fnmatch_lines(
+            [
+                '*RuntimeError: Database access not allowed, use the "django_db" mark, '
+                'or the "db" or "transactional_db" fixtures to enable it.*'
+            ]
+        )
+
+    def test_db_access_in_test_module(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            from tpkg.app.models import Item
+            Item.objects.get()
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-v")
+        result.stdout.fnmatch_lines(
+            [
+                '*RuntimeError: Database access not allowed, use the "django_db" mark, '
+                'or the "db" or "transactional_db" fixtures to enable it.'
+            ]
+        )

+ 27 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_db_access_in_repr.py

@@ -0,0 +1,27 @@
+def test_db_access_with_repr_in_report(django_testdir):
+    django_testdir.create_test_module(
+        """
+        import pytest
+
+        from .app.models import Item
+
+        def test_via_db_blocker(django_db_setup, django_db_blocker):
+            with django_db_blocker.unblock():
+                Item.objects.get(name='This one is not there')
+
+        def test_via_db_fixture(db):
+            Item.objects.get(name='This one is not there')
+    """
+    )
+
+    result = django_testdir.runpytest_subprocess("--tb=auto")
+    result.stdout.fnmatch_lines([
+        "tpkg/test_the_test.py FF",
+        "E   *DoesNotExist: Item matching query does not exist.",
+        "tpkg/test_the_test.py:8: ",
+        'self = *RuntimeError*Database access not allowed*',
+        "E   *DoesNotExist: Item matching query does not exist.",
+        "* 2 failed in *",
+    ])
+    assert "INTERNALERROR" not in str(result.stdout) + str(result.stderr)
+    assert result.ret == 1

+ 564 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_db_setup.py

@@ -0,0 +1,564 @@
+import pytest
+
+from pytest_django.lazy_django import get_django_version
+from pytest_django_test.db_helpers import (
+    db_exists,
+    drop_database,
+    mark_database,
+    mark_exists,
+    skip_if_sqlite_in_memory,
+)
+
+
+def test_db_reuse_simple(django_testdir):
+    "A test for all backends to check that `--reuse-db` works."
+    django_testdir.create_test_module(
+        """
+        import pytest
+
+        from .app.models import Item
+
+        @pytest.mark.django_db
+        def test_db_can_be_accessed():
+            assert Item.objects.count() == 0
+    """
+    )
+
+    result = django_testdir.runpytest_subprocess("-v", "--reuse-db")
+    assert result.ret == 0
+    result.stdout.fnmatch_lines(["*test_db_can_be_accessed PASSED*"])
+
+
+def test_db_order(django_testdir):
+    """Test order in which tests are being executed."""
+
+    django_testdir.create_test_module('''
+        from unittest import TestCase
+        import pytest
+        from django.test import SimpleTestCase, TestCase as DjangoTestCase, TransactionTestCase
+
+        from .app.models import Item
+
+        @pytest.mark.django_db(transaction=True)
+        def test_run_second_decorator():
+            pass
+
+        def test_run_second_fixture(transactional_db):
+            pass
+
+        def test_run_first_fixture(db):
+            pass
+
+        @pytest.mark.django_db
+        def test_run_first_decorator():
+            pass
+
+        class MyTestCase(TestCase):
+            def test_run_last_test_case(self):
+                pass
+
+        class MySimpleTestCase(SimpleTestCase):
+            def test_run_last_simple_test_case(self):
+                pass
+
+        class MyDjangoTestCase(DjangoTestCase):
+            def test_run_first_django_test_case(self):
+                pass
+
+        class MyTransactionTestCase(TransactionTestCase):
+            def test_run_second_transaction_test_case(self):
+                pass
+    ''')
+    result = django_testdir.runpytest_subprocess('-v', '-s')
+    assert result.ret == 0
+    result.stdout.fnmatch_lines([
+        "*test_run_first_fixture*",
+        "*test_run_first_decorator*",
+        "*test_run_first_django_test_case*",
+        "*test_run_second_decorator*",
+        "*test_run_second_fixture*",
+        "*test_run_second_transaction_test_case*",
+        "*test_run_last_test_case*",
+        "*test_run_last_simple_test_case*",
+    ])
+
+
+def test_db_reuse(django_testdir):
+    """
+    Test the re-use db functionality.
+    """
+    skip_if_sqlite_in_memory()
+
+    django_testdir.create_test_module(
+        """
+        import pytest
+
+        from .app.models import Item
+
+        @pytest.mark.django_db
+        def test_db_can_be_accessed():
+            assert Item.objects.count() == 0
+    """
+    )
+
+    # Use --create-db on the first run to make sure we are not just re-using a
+    # database from another test run
+    drop_database()
+    assert not db_exists()
+
+    # Do not pass in --create-db to make sure it is created when it
+    # does not exist
+    result_first = django_testdir.runpytest_subprocess("-v", "--reuse-db")
+    assert result_first.ret == 0
+
+    result_first.stdout.fnmatch_lines(["*test_db_can_be_accessed PASSED*"])
+
+    assert not mark_exists()
+    mark_database()
+    assert mark_exists()
+
+    result_second = django_testdir.runpytest_subprocess("-v", "--reuse-db")
+    assert result_second.ret == 0
+    result_second.stdout.fnmatch_lines(["*test_db_can_be_accessed PASSED*"])
+
+    # Make sure the database has not been re-created
+    assert mark_exists()
+
+    result_third = django_testdir.runpytest_subprocess(
+        "-v", "--reuse-db", "--create-db"
+    )
+    assert result_third.ret == 0
+    result_third.stdout.fnmatch_lines(["*test_db_can_be_accessed PASSED*"])
+
+    # Make sure the database has been re-created and the mark is gone
+    assert db_exists()
+    assert not mark_exists()
+
+
+class TestSqlite:
+
+    db_settings = {
+        "default": {
+            "ENGINE": "django.db.backends.sqlite3",
+            "NAME": "db_name",
+            "TEST": {"NAME": "test_custom_db_name"},
+        }
+    }
+
+    def test_sqlite_test_name_used(self, django_testdir):
+
+        django_testdir.create_test_module(
+            """
+            import pytest
+            from django.db import connections
+            from django import VERSION
+
+            @pytest.mark.django_db
+            def test_a():
+                (conn, ) = connections.all()
+
+                assert conn.vendor == 'sqlite'
+                print(conn.settings_dict)
+                assert conn.settings_dict['NAME'] == 'test_custom_db_name'
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("--tb=short", "-v")
+        assert result.ret == 0
+        result.stdout.fnmatch_lines(["*test_a*PASSED*"])
+
+
+def test_xdist_with_reuse(django_testdir):
+    pytest.importorskip("xdist")
+    skip_if_sqlite_in_memory()
+
+    drop_database("gw0")
+    drop_database("gw1")
+    assert not db_exists("gw0")
+    assert not db_exists("gw1")
+
+    django_testdir.create_test_module(
+        """
+        import pytest
+
+        from .app.models import Item
+
+        def _check(settings):
+            # Make sure that the database name looks correct
+            db_name = settings.DATABASES['default']['NAME']
+            assert db_name.endswith('_gw0') or db_name.endswith('_gw1')
+
+            assert Item.objects.count() == 0
+            Item.objects.create(name='foo')
+            assert Item.objects.count() == 1
+
+
+        @pytest.mark.django_db
+        def test_a(settings):
+            _check(settings)
+
+
+        @pytest.mark.django_db
+        def test_b(settings):
+            _check(settings)
+
+        @pytest.mark.django_db
+        def test_c(settings):
+            _check(settings)
+
+        @pytest.mark.django_db
+        def test_d(settings):
+            _check(settings)
+    """
+    )
+
+    result = django_testdir.runpytest_subprocess("-vv", "-n2", "-s", "--reuse-db")
+    assert result.ret == 0
+    result.stdout.fnmatch_lines(["*PASSED*test_a*"])
+    result.stdout.fnmatch_lines(["*PASSED*test_b*"])
+    result.stdout.fnmatch_lines(["*PASSED*test_c*"])
+    result.stdout.fnmatch_lines(["*PASSED*test_d*"])
+
+    assert db_exists("gw0")
+    assert db_exists("gw1")
+
+    result = django_testdir.runpytest_subprocess("-vv", "-n2", "-s", "--reuse-db")
+    assert result.ret == 0
+    result.stdout.fnmatch_lines(["*PASSED*test_a*"])
+    result.stdout.fnmatch_lines(["*PASSED*test_b*"])
+    result.stdout.fnmatch_lines(["*PASSED*test_c*"])
+    result.stdout.fnmatch_lines(["*PASSED*test_d*"])
+
+    result = django_testdir.runpytest_subprocess(
+        "-vv", "-n2", "-s", "--reuse-db", "--create-db"
+    )
+    assert result.ret == 0
+    result.stdout.fnmatch_lines(["*PASSED*test_a*"])
+    result.stdout.fnmatch_lines(["*PASSED*test_b*"])
+    result.stdout.fnmatch_lines(["*PASSED*test_c*"])
+    result.stdout.fnmatch_lines(["*PASSED*test_d*"])
+
+    # Cleanup.
+    drop_database("gw0")
+    drop_database("gw1")
+
+
+class TestSqliteWithXdist:
+
+    db_settings = {
+        "default": {
+            "ENGINE": "django.db.backends.sqlite3",
+            "NAME": "/tmp/should-not-be-used",
+        }
+    }
+
+    def test_sqlite_in_memory_used(self, django_testdir):
+        pytest.importorskip("xdist")
+
+        django_testdir.create_test_module(
+            """
+            import pytest
+            from django.db import connections
+
+            @pytest.mark.django_db
+            def test_a():
+                (conn, ) = connections.all()
+
+                assert conn.vendor == 'sqlite'
+                db_name = conn.creation._get_test_db_name()
+                assert 'file:memorydb' in db_name or db_name == ':memory:'
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("--tb=short", "-vv", "-n1")
+        assert result.ret == 0
+        result.stdout.fnmatch_lines(["*PASSED*test_a*"])
+
+
+class TestSqliteWithMultipleDbsAndXdist:
+
+    db_settings = {
+        "default": {
+            "ENGINE": "django.db.backends.sqlite3",
+            "NAME": "/tmp/should-not-be-used",
+        },
+        "db2": {
+            "ENGINE": "django.db.backends.sqlite3",
+            "NAME": "db_name",
+            "TEST": {"NAME": "test_custom_db_name"},
+        }
+    }
+
+    def test_sqlite_database_renamed(self, django_testdir):
+        pytest.importorskip("xdist")
+
+        django_testdir.create_test_module(
+            """
+            import pytest
+            from django.db import connections
+
+            @pytest.mark.django_db
+            def test_a():
+                (conn_db2, conn_default) = sorted(
+                    connections.all(),
+                    key=lambda conn: conn.alias,
+                )
+
+                assert conn_default.vendor == 'sqlite'
+                db_name = conn_default.creation._get_test_db_name()
+
+                # can_share_in_memory_db was removed in Django 2.1, and
+                # used in _get_test_db_name before.
+                if getattr(conn_default.features, "can_share_in_memory_db", True):
+                    assert 'file:memorydb' in db_name
+                else:
+                    assert db_name == ":memory:"
+
+                assert conn_db2.vendor == 'sqlite'
+                db_name = conn_db2.creation._get_test_db_name()
+                assert db_name.startswith('test_custom_db_name_gw')
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("--tb=short", "-vv", "-n1")
+        assert result.ret == 0
+        result.stdout.fnmatch_lines(["*PASSED*test_a*"])
+
+
+class TestSqliteWithTox:
+
+    db_settings = {
+        "default": {
+            "ENGINE": "django.db.backends.sqlite3",
+            "NAME": "db_name",
+            "TEST": {"NAME": "test_custom_db_name"},
+        }
+    }
+
+    def test_db_with_tox_suffix(self, django_testdir, monkeypatch):
+        "A test to check that Tox DB suffix works when running in parallel."
+        monkeypatch.setenv("TOX_PARALLEL_ENV", "py37-django22")
+
+        django_testdir.create_test_module(
+            """
+            import pytest
+            from django.db import connections
+
+            @pytest.mark.django_db
+            def test_inner():
+
+                (conn, ) = connections.all()
+
+                assert conn.vendor == 'sqlite'
+                db_name = conn.creation._get_test_db_name()
+                assert db_name == 'test_custom_db_name_py37-django22'
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("--tb=short", "-vv")
+        assert result.ret == 0
+        result.stdout.fnmatch_lines(["*test_inner*PASSED*"])
+
+    def test_db_with_empty_tox_suffix(self, django_testdir, monkeypatch):
+        "A test to check that Tox DB suffix is not used when suffix would be empty."
+        monkeypatch.setenv("TOX_PARALLEL_ENV", "")
+
+        django_testdir.create_test_module(
+            """
+            import pytest
+            from django.db import connections
+
+            @pytest.mark.django_db
+            def test_inner():
+
+                (conn,) = connections.all()
+
+                assert conn.vendor == 'sqlite'
+                db_name = conn.creation._get_test_db_name()
+                assert db_name == 'test_custom_db_name'
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("--tb=short", "-vv")
+        assert result.ret == 0
+        result.stdout.fnmatch_lines(["*test_inner*PASSED*"])
+
+
+class TestSqliteWithToxAndXdist:
+
+    db_settings = {
+        "default": {
+            "ENGINE": "django.db.backends.sqlite3",
+            "NAME": "db_name",
+            "TEST": {"NAME": "test_custom_db_name"},
+        }
+    }
+
+    def test_db_with_tox_suffix(self, django_testdir, monkeypatch):
+        "A test to check that both Tox and xdist suffixes work together."
+        pytest.importorskip("xdist")
+        monkeypatch.setenv("TOX_PARALLEL_ENV", "py37-django22")
+
+        django_testdir.create_test_module(
+            """
+            import pytest
+            from django.db import connections
+
+            @pytest.mark.django_db
+            def test_inner():
+
+                (conn, ) = connections.all()
+
+                assert conn.vendor == 'sqlite'
+                db_name = conn.creation._get_test_db_name()
+                assert db_name.startswith('test_custom_db_name_py37-django22_gw')
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("--tb=short", "-vv", "-n1")
+        assert result.ret == 0
+        result.stdout.fnmatch_lines(["*PASSED*test_inner*"])
+
+
+class TestSqliteInMemoryWithXdist:
+
+    db_settings = {
+        "default": {
+            "ENGINE": "django.db.backends.sqlite3",
+            "NAME": ":memory:",
+            "TEST": {"NAME": ":memory:"},
+        }
+    }
+
+    def test_sqlite_in_memory_used(self, django_testdir):
+        pytest.importorskip("xdist")
+
+        django_testdir.create_test_module(
+            """
+            import pytest
+            from django.db import connections
+
+            @pytest.mark.django_db
+            def test_a():
+                (conn, ) = connections.all()
+
+                assert conn.vendor == 'sqlite'
+                db_name = conn.creation._get_test_db_name()
+                assert 'file:memorydb' in db_name or db_name == ':memory:'
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("--tb=short", "-vv", "-n1")
+        assert result.ret == 0
+        result.stdout.fnmatch_lines(["*PASSED*test_a*"])
+
+
+@pytest.mark.skipif(
+    get_django_version() >= (1, 9),
+    reason=(
+        "Django 1.9 requires migration and has no concept of initial data fixtures"
+    ),
+)
+def test_initial_data(django_testdir_initial):
+    """Test that initial data gets loaded."""
+    django_testdir_initial.create_test_module(
+        """
+        import pytest
+
+        from .app.models import Item
+
+        @pytest.mark.django_db
+        def test_inner():
+            assert [x.name for x in Item.objects.all()] \
+                == ["mark_initial_data"]
+    """
+    )
+
+    result = django_testdir_initial.runpytest_subprocess("--tb=short", "-v")
+    assert result.ret == 0
+    result.stdout.fnmatch_lines(["*test_inner*PASSED*"])
+
+
+class TestNativeMigrations(object):
+    """ Tests for Django Migrations """
+
+    def test_no_migrations(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            import pytest
+
+            @pytest.mark.django_db
+            def test_inner_migrations():
+                from .app.models import Item
+                Item.objects.create()
+        """
+        )
+
+        migration_file = django_testdir.project_root.join(
+            "tpkg/app/migrations/0001_initial.py"
+        )
+        assert migration_file.isfile()
+        migration_file.write(
+            'raise Exception("This should not get imported.")', ensure=True
+        )
+
+        result = django_testdir.runpytest_subprocess(
+            "--nomigrations", "--tb=short", "-vv", "-s",
+        )
+        assert result.ret == 0
+        assert "Operations to perform:" not in result.stdout.str()
+        result.stdout.fnmatch_lines(["*= 1 passed in *"])
+
+    def test_migrations_run(self, django_testdir):
+        testdir = django_testdir
+        testdir.create_test_module(
+            """
+            import pytest
+
+            @pytest.mark.django_db
+            def test_inner_migrations():
+                from .app.models import Item
+                Item.objects.create()
+            """
+        )
+
+        testdir.create_app_file(
+            """
+            from django.db import migrations, models
+
+            def print_it(apps, schema_editor):
+                print("mark_migrations_run")
+
+            class Migration(migrations.Migration):
+
+                dependencies = []
+
+                operations = [
+                    migrations.CreateModel(
+                        name='Item',
+                        fields=[
+                            ('id', models.AutoField(serialize=False,
+                                                    auto_created=True,
+                                                    primary_key=True)),
+                            ('name', models.CharField(max_length=100)),
+                        ],
+                        options={
+                        },
+                        bases=(models.Model,),
+                    ),
+                    migrations.RunPython(
+                        print_it,
+                    ),
+                ]
+            """,
+            "migrations/0001_initial.py",
+        )
+        result = testdir.runpytest_subprocess("--tb=short", "-v", "-s")
+        assert result.ret == 0
+        result.stdout.fnmatch_lines(["*mark_migrations_run*"])
+
+        result = testdir.runpytest_subprocess(
+            "--no-migrations", "--migrations", "--tb=short", "-v", "-s"
+        )
+        assert result.ret == 0
+        result.stdout.fnmatch_lines(["*mark_migrations_run*"])

+ 140 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_django_configurations.py

@@ -0,0 +1,140 @@
+"""Tests which check the various ways you can set DJANGO_SETTINGS_MODULE
+
+If these tests fail you probably forgot to install django-configurations.
+"""
+import pytest
+
+pytest.importorskip("configurations")
+
+
+BARE_SETTINGS = """
+from configurations import Configuration
+
+class MySettings(Configuration):
+    # At least one database must be configured
+    DATABASES = {
+        'default': {
+            'ENGINE': 'django.db.backends.sqlite3',
+            'NAME': ':memory:'
+        },
+    }
+
+    SECRET_KEY = 'foobar'
+"""
+
+
+def test_dc_env(testdir, monkeypatch):
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "tpkg.settings_env")
+    monkeypatch.setenv("DJANGO_CONFIGURATION", "MySettings")
+
+    pkg = testdir.mkpydir("tpkg")
+    settings = pkg.join("settings_env.py")
+    settings.write(BARE_SETTINGS)
+    testdir.makepyfile(
+        """
+        import os
+
+        def test_settings():
+            assert os.environ['DJANGO_SETTINGS_MODULE'] == 'tpkg.settings_env'
+            assert os.environ['DJANGO_CONFIGURATION'] == 'MySettings'
+    """
+    )
+    result = testdir.runpytest_subprocess()
+    result.stdout.fnmatch_lines([
+        'django: settings: tpkg.settings_env (from env), configuration: MySettings (from env)',
+        "* 1 passed in*",
+    ])
+    assert result.ret == 0
+
+
+def test_dc_env_overrides_ini(testdir, monkeypatch):
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "tpkg.settings_env")
+    monkeypatch.setenv("DJANGO_CONFIGURATION", "MySettings")
+
+    testdir.makeini(
+        """
+       [pytest]
+       DJANGO_SETTINGS_MODULE = DO_NOT_USE_ini
+       DJANGO_CONFIGURATION = DO_NOT_USE_ini
+    """
+    )
+    pkg = testdir.mkpydir("tpkg")
+    settings = pkg.join("settings_env.py")
+    settings.write(BARE_SETTINGS)
+    testdir.makepyfile(
+        """
+        import os
+
+        def test_ds():
+            assert os.environ['DJANGO_SETTINGS_MODULE'] == 'tpkg.settings_env'
+            assert os.environ['DJANGO_CONFIGURATION'] == 'MySettings'
+    """
+    )
+    result = testdir.runpytest_subprocess()
+    result.stdout.fnmatch_lines([
+        'django: settings: tpkg.settings_env (from env), configuration: MySettings (from env)',
+        "* 1 passed in*",
+    ])
+    assert result.ret == 0
+
+
+def test_dc_ini(testdir, monkeypatch):
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+
+    testdir.makeini(
+        """
+       [pytest]
+       DJANGO_SETTINGS_MODULE = tpkg.settings_ini
+       DJANGO_CONFIGURATION = MySettings
+    """
+    )
+    pkg = testdir.mkpydir("tpkg")
+    settings = pkg.join("settings_ini.py")
+    settings.write(BARE_SETTINGS)
+    testdir.makepyfile(
+        """
+        import os
+
+        def test_ds():
+            assert os.environ['DJANGO_SETTINGS_MODULE'] == 'tpkg.settings_ini'
+            assert os.environ['DJANGO_CONFIGURATION'] == 'MySettings'
+    """
+    )
+    result = testdir.runpytest_subprocess()
+    result.stdout.fnmatch_lines([
+        'django: settings: tpkg.settings_ini (from ini), configuration: MySettings (from ini)',
+        "* 1 passed in*",
+    ])
+    assert result.ret == 0
+
+
+def test_dc_option(testdir, monkeypatch):
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "DO_NOT_USE_env")
+    monkeypatch.setenv("DJANGO_CONFIGURATION", "DO_NOT_USE_env")
+
+    testdir.makeini(
+        """
+       [pytest]
+       DJANGO_SETTINGS_MODULE = DO_NOT_USE_ini
+       DJANGO_CONFIGURATION = DO_NOT_USE_ini
+    """
+    )
+    pkg = testdir.mkpydir("tpkg")
+    settings = pkg.join("settings_opt.py")
+    settings.write(BARE_SETTINGS)
+    testdir.makepyfile(
+        """
+        import os
+
+        def test_ds():
+            assert os.environ['DJANGO_SETTINGS_MODULE'] == 'tpkg.settings_opt'
+            assert os.environ['DJANGO_CONFIGURATION'] == 'MySettings'
+    """
+    )
+    result = testdir.runpytest_subprocess("--ds=tpkg.settings_opt", "--dc=MySettings")
+    result.stdout.fnmatch_lines([
+        'django: settings: tpkg.settings_opt (from option),'
+        ' configuration: MySettings (from option)',
+        "* 1 passed in*",
+    ])
+    assert result.ret == 0

+ 452 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_django_settings_module.py

@@ -0,0 +1,452 @@
+"""Tests which check the various ways you can set DJANGO_SETTINGS_MODULE
+
+If these tests fail you probably forgot to run "python setup.py develop".
+"""
+
+import django
+import pytest
+
+
+BARE_SETTINGS = """
+# At least one database must be configured
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': ':memory:'
+    },
+}
+SECRET_KEY = 'foobar'
+"""
+
+
+def test_ds_ini(testdir, monkeypatch):
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+    testdir.makeini(
+        """
+       [pytest]
+       DJANGO_SETTINGS_MODULE = tpkg.settings_ini
+    """
+    )
+    pkg = testdir.mkpydir("tpkg")
+    pkg.join("settings_ini.py").write(BARE_SETTINGS)
+    testdir.makepyfile(
+        """
+        import os
+
+        def test_ds():
+            assert os.environ['DJANGO_SETTINGS_MODULE'] == 'tpkg.settings_ini'
+    """
+    )
+    result = testdir.runpytest_subprocess()
+    result.stdout.fnmatch_lines([
+        "django: settings: tpkg.settings_ini (from ini)",
+        "*= 1 passed in *",
+    ])
+    assert result.ret == 0
+
+
+def test_ds_env(testdir, monkeypatch):
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "tpkg.settings_env")
+    pkg = testdir.mkpydir("tpkg")
+    settings = pkg.join("settings_env.py")
+    settings.write(BARE_SETTINGS)
+    testdir.makepyfile(
+        """
+        import os
+
+        def test_settings():
+            assert os.environ['DJANGO_SETTINGS_MODULE'] == 'tpkg.settings_env'
+    """
+    )
+    result = testdir.runpytest_subprocess()
+    result.stdout.fnmatch_lines([
+        "django: settings: tpkg.settings_env (from env)",
+        "*= 1 passed in *",
+    ])
+
+
+def test_ds_option(testdir, monkeypatch):
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "DO_NOT_USE_env")
+    testdir.makeini(
+        """
+       [pytest]
+       DJANGO_SETTINGS_MODULE = DO_NOT_USE_ini
+    """
+    )
+    pkg = testdir.mkpydir("tpkg")
+    settings = pkg.join("settings_opt.py")
+    settings.write(BARE_SETTINGS)
+    testdir.makepyfile(
+        """
+        import os
+
+        def test_ds():
+            assert os.environ['DJANGO_SETTINGS_MODULE'] == 'tpkg.settings_opt'
+    """
+    )
+    result = testdir.runpytest_subprocess("--ds=tpkg.settings_opt")
+    result.stdout.fnmatch_lines([
+        "django: settings: tpkg.settings_opt (from option)",
+        "*= 1 passed in *",
+    ])
+
+
+def test_ds_env_override_ini(testdir, monkeypatch):
+    "DSM env should override ini."
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "tpkg.settings_env")
+    testdir.makeini(
+        """\
+       [pytest]
+       DJANGO_SETTINGS_MODULE = DO_NOT_USE_ini
+    """
+    )
+    pkg = testdir.mkpydir("tpkg")
+    settings = pkg.join("settings_env.py")
+    settings.write(BARE_SETTINGS)
+    testdir.makepyfile(
+        """
+        import os
+
+        def test_ds():
+            assert os.environ['DJANGO_SETTINGS_MODULE'] == 'tpkg.settings_env'
+    """
+    )
+    result = testdir.runpytest_subprocess()
+    assert result.parseoutcomes()["passed"] == 1
+    assert result.ret == 0
+
+
+def test_ds_non_existent(testdir, monkeypatch):
+    """
+    Make sure we do not fail with INTERNALERROR if an incorrect
+    DJANGO_SETTINGS_MODULE is given.
+    """
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "DOES_NOT_EXIST")
+    testdir.makepyfile("def test_ds(): pass")
+    result = testdir.runpytest_subprocess()
+    result.stderr.fnmatch_lines(["*ImportError:*DOES_NOT_EXIST*"])
+    assert result.ret != 0
+
+
+def test_ds_after_user_conftest(testdir, monkeypatch):
+    """
+    Test that the settings module can be imported, after pytest has adjusted
+    the sys.path.
+    """
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "settings_after_conftest")
+    testdir.makepyfile("def test_ds(): pass")
+    testdir.makepyfile(settings_after_conftest="SECRET_KEY='secret'")
+    # testdir.makeconftest("import sys; print(sys.path)")
+    result = testdir.runpytest_subprocess("-v")
+    result.stdout.fnmatch_lines(["* 1 passed in*"])
+    assert result.ret == 0
+
+
+def test_ds_in_pytest_configure(testdir, monkeypatch):
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+    pkg = testdir.mkpydir("tpkg")
+    settings = pkg.join("settings_ds.py")
+    settings.write(BARE_SETTINGS)
+    testdir.makeconftest(
+        """
+        import os
+
+        from django.conf import settings
+
+        def pytest_configure():
+            if not settings.configured:
+                os.environ.setdefault('DJANGO_SETTINGS_MODULE',
+                                      'tpkg.settings_ds')
+    """
+    )
+
+    testdir.makepyfile(
+        """
+        def test_anything():
+            pass
+    """
+    )
+
+    r = testdir.runpytest_subprocess()
+    assert r.parseoutcomes()["passed"] == 1
+    assert r.ret == 0
+
+
+def test_django_settings_configure(testdir, monkeypatch):
+    """
+    Make sure Django can be configured without setting
+    DJANGO_SETTINGS_MODULE altogether, relying on calling
+    django.conf.settings.configure() and then invoking pytest.
+    """
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+
+    p = testdir.makepyfile(
+        run="""
+            from django.conf import settings
+            settings.configure(SECRET_KEY='set from settings.configure()',
+                               DATABASES={'default': {
+                                   'ENGINE': 'django.db.backends.sqlite3',
+                                   'NAME': ':memory:'
+                               }},
+                               INSTALLED_APPS=['django.contrib.auth',
+                                               'django.contrib.contenttypes',])
+
+            import pytest
+
+            pytest.main()
+    """
+    )
+
+    testdir.makepyfile(
+        """
+        import pytest
+
+        from django.conf import settings
+        from django.test.client import RequestFactory
+        from django.test import TestCase
+        from django.contrib.auth.models import User
+
+        def test_access_to_setting():
+            assert settings.SECRET_KEY == 'set from settings.configure()'
+
+        # This test requires Django to be properly configured to be run
+        def test_rf(rf):
+            assert isinstance(rf, RequestFactory)
+
+        # This tests that pytest-django actually configures the database
+        # according to the settings above
+        class ATestCase(TestCase):
+            def test_user_count(self):
+                assert User.objects.count() == 0
+
+        @pytest.mark.django_db
+        def test_user_count():
+            assert User.objects.count() == 0
+
+    """
+    )
+    result = testdir.runpython(p)
+    result.stdout.fnmatch_lines(["* 4 passed in*"])
+
+
+def test_settings_in_hook(testdir, monkeypatch):
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+    testdir.makeconftest(
+        """
+        from django.conf import settings
+
+        def pytest_configure():
+            settings.configure(SECRET_KEY='set from pytest_configure',
+                               DATABASES={'default': {
+                                   'ENGINE': 'django.db.backends.sqlite3',
+                                   'NAME': ':memory:'}},
+                               INSTALLED_APPS=['django.contrib.auth',
+                                               'django.contrib.contenttypes',])
+    """
+    )
+    testdir.makepyfile(
+        """
+        import pytest
+        from django.conf import settings
+        from django.contrib.auth.models import User
+
+        def test_access_to_setting():
+            assert settings.SECRET_KEY == 'set from pytest_configure'
+
+        @pytest.mark.django_db
+        def test_user_count():
+            assert User.objects.count() == 0
+    """
+    )
+    r = testdir.runpytest_subprocess()
+    assert r.ret == 0
+
+
+def test_django_not_loaded_without_settings(testdir, monkeypatch):
+    """
+    Make sure Django is not imported at all if no Django settings is specified.
+    """
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+    testdir.makepyfile(
+        """
+        import sys
+        def test_settings():
+            assert 'django' not in sys.modules
+    """
+    )
+    result = testdir.runpytest_subprocess()
+    result.stdout.fnmatch_lines(["* 1 passed in*"])
+    assert result.ret == 0
+
+
+def test_debug_false(testdir, monkeypatch):
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+    testdir.makeconftest(
+        """
+        from django.conf import settings
+
+        def pytest_configure():
+            settings.configure(SECRET_KEY='set from pytest_configure',
+                               DEBUG=True,
+                               DATABASES={'default': {
+                                   'ENGINE': 'django.db.backends.sqlite3',
+                                   'NAME': ':memory:'}},
+                               INSTALLED_APPS=['django.contrib.auth',
+                                               'django.contrib.contenttypes',])
+    """
+    )
+
+    testdir.makepyfile(
+        """
+        from django.conf import settings
+        def test_debug_is_false():
+            assert settings.DEBUG is False
+    """
+    )
+
+    r = testdir.runpytest_subprocess()
+    assert r.ret == 0
+
+
+@pytest.mark.skipif(
+    not hasattr(django, "setup"),
+    reason="This Django version does not support app loading",
+)
+@pytest.mark.django_project(
+    extra_settings="""
+    INSTALLED_APPS = [
+        'tpkg.app.apps.TestApp',
+    ]
+"""
+)
+def test_django_setup_sequence(django_testdir):
+    django_testdir.create_app_file(
+        """
+        from django.apps import apps, AppConfig
+
+
+        class TestApp(AppConfig):
+            name = 'tpkg.app'
+
+            def ready(self):
+                try:
+                    populating = apps.loading
+                except AttributeError:  # Django < 2.0
+                    populating = apps._lock.locked()
+                print('READY(): populating=%r' % populating)
+        """,
+        "apps.py",
+    )
+
+    django_testdir.create_app_file(
+        """
+        from django.apps import apps
+
+        try:
+            populating = apps.loading
+        except AttributeError:  # Django < 2.0
+            populating = apps._lock.locked()
+
+        print('IMPORT: populating=%r,ready=%r' % (populating, apps.ready))
+        SOME_THING = 1234
+        """,
+        "models.py",
+    )
+
+    django_testdir.create_app_file("", "__init__.py")
+    django_testdir.makepyfile(
+        """
+        from django.apps import apps
+        from tpkg.app.models import SOME_THING
+
+        def test_anything():
+            try:
+                populating = apps.loading
+            except AttributeError:  # Django < 2.0
+                populating = apps._lock.locked()
+
+            print('TEST: populating=%r,ready=%r' % (populating, apps.ready))
+        """
+    )
+
+    result = django_testdir.runpytest_subprocess("-s", "--tb=line")
+    result.stdout.fnmatch_lines(["*IMPORT: populating=True,ready=False*"])
+    result.stdout.fnmatch_lines(["*READY(): populating=True*"])
+    if django.VERSION < (2, 0):
+        result.stdout.fnmatch_lines(["*TEST: populating=False,ready=True*"])
+    else:
+        result.stdout.fnmatch_lines(["*TEST: populating=True,ready=True*"])
+    assert result.ret == 0
+
+
+def test_no_ds_but_django_imported(testdir, monkeypatch):
+    """pytest-django should not bail out, if "django" has been imported
+    somewhere, e.g. via pytest-splinter."""
+
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+
+    testdir.makepyfile(
+        """
+        import os
+        import django
+
+        from pytest_django.lazy_django import django_settings_is_configured
+
+        def test_django_settings_is_configured():
+            assert django_settings_is_configured() is False
+
+        def test_env():
+            assert 'DJANGO_SETTINGS_MODULE' not in os.environ
+
+        def test_cfg(pytestconfig):
+            assert pytestconfig.option.ds is None
+    """
+    )
+    r = testdir.runpytest_subprocess("-s")
+    assert r.ret == 0
+
+
+def test_no_ds_but_django_conf_imported(testdir, monkeypatch):
+    """pytest-django should not bail out, if "django.conf" has been imported
+    somewhere, e.g. via hypothesis (#599)."""
+
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+
+    testdir.makepyfile(
+        """
+        import os
+        import sys
+
+        # line copied from hypothesis/extras/django.py
+        from django.conf import settings as django_settings
+
+        # Don't let pytest poke into this object, generating a
+        # django.core.exceptions.ImproperlyConfigured
+        del django_settings
+
+        from pytest_django.lazy_django import django_settings_is_configured
+
+        def test_django_settings_is_configured():
+            assert django_settings_is_configured() is False
+
+        def test_django_conf_is_imported():
+            assert 'django.conf' in sys.modules
+
+        def test_env():
+            assert 'DJANGO_SETTINGS_MODULE' not in os.environ
+
+        def test_cfg(pytestconfig):
+            assert pytestconfig.option.ds is None
+    """
+    )
+    r = testdir.runpytest_subprocess("-s")
+    assert r.ret == 0
+
+
+def test_no_django_settings_but_django_imported(testdir, monkeypatch):
+    """Make sure we do not crash when Django happens to be imported, but
+    settings is not properly configured"""
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+    testdir.makeconftest("import django")
+    r = testdir.runpytest_subprocess("--help")
+    assert r.ret == 0

+ 4 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_doctest.txt

@@ -0,0 +1,4 @@
+This doctest should run without problems with pytest.
+
+>>> print('works')
+works

+ 327 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_environment.py

@@ -0,0 +1,327 @@
+from __future__ import with_statement
+
+import os
+
+import pytest
+from django.contrib.sites.models import Site
+from django.contrib.sites import models as site_models
+from django.core import mail
+from django.db import connection
+from django.test import TestCase
+from pytest_django.lazy_django import get_django_version
+
+from pytest_django_test.app.models import Item
+
+
+# It doesn't matter which order all the _again methods are run, we just need
+# to check the environment remains constant.
+# This is possible with some of the testdir magic, but this is the lazy way
+# to do it.
+
+
+@pytest.mark.parametrize("subject", ["subject1", "subject2"])
+def test_autoclear_mailbox(subject):
+    assert len(mail.outbox) == 0
+    mail.send_mail(subject, "body", "from@example.com", ["to@example.com"])
+    assert len(mail.outbox) == 1
+
+    m = mail.outbox[0]
+    assert m.subject == subject
+    assert m.body == "body"
+    assert m.from_email == "from@example.com"
+    assert m.to == ["to@example.com"]
+
+
+class TestDirectAccessWorksForDjangoTestCase(TestCase):
+    def _do_test(self):
+        assert len(mail.outbox) == 0
+        mail.send_mail("subject", "body", "from@example.com", ["to@example.com"])
+        assert len(mail.outbox) == 1
+
+    def test_one(self):
+        self._do_test()
+
+    def test_two(self):
+        self._do_test()
+
+
+@pytest.mark.django_project(
+    extra_settings="""
+    TEMPLATE_LOADERS = (
+        'django.template.loaders.filesystem.Loader',
+        'django.template.loaders.app_directories.Loader',
+    )
+    ROOT_URLCONF = 'tpkg.app.urls'
+    """
+)
+def test_invalid_template_variable(django_testdir):
+    django_testdir.create_app_file(
+        """
+        from django.conf.urls import url
+
+        from tpkg.app import views
+
+        urlpatterns = [url(r'invalid_template/', views.invalid_template)]
+        """,
+        "urls.py",
+    )
+    django_testdir.create_app_file(
+        """
+        from django.shortcuts import render
+
+
+        def invalid_template(request):
+            return render(request, 'invalid_template.html', {})
+        """,
+        "views.py",
+    )
+    django_testdir.create_app_file(
+        "<div>{{ invalid_var }}</div>", "templates/invalid_template_base.html"
+    )
+    django_testdir.create_app_file(
+        "{% include 'invalid_template_base.html' %}", "templates/invalid_template.html"
+    )
+    django_testdir.create_test_module(
+        """
+        import pytest
+
+        def test_for_invalid_template(client):
+            client.get('/invalid_template/')
+
+        @pytest.mark.ignore_template_errors
+        def test_ignore(client):
+            client.get('/invalid_template/')
+        """
+    )
+    result = django_testdir.runpytest_subprocess("-s", "--fail-on-template-vars")
+
+    if get_django_version() >= (1, 9):
+        origin = "'*/tpkg/app/templates/invalid_template_base.html'"
+    else:
+        origin = "'invalid_template.html'"
+    result.stdout.fnmatch_lines_random(
+        [
+            "tpkg/test_the_test.py F.*",
+            "E * Failed: Undefined template variable 'invalid_var' in {}".format(
+                origin
+            ),
+        ]
+    )
+
+
+@pytest.mark.django_project(
+    extra_settings="""
+    TEMPLATE_LOADERS = (
+        'django.template.loaders.filesystem.Loader',
+        'django.template.loaders.app_directories.Loader',
+    )
+    ROOT_URLCONF = 'tpkg.app.urls'
+    """
+)
+def test_invalid_template_with_default_if_none(django_testdir):
+    django_testdir.create_app_file(
+        """
+            <div>{{ data.empty|default:'d' }}</div>
+            <div>{{ data.none|default:'d' }}</div>
+            <div>{{ data.empty|default_if_none:'d' }}</div>
+            <div>{{ data.none|default_if_none:'d' }}</div>
+            <div>{{ data.missing|default_if_none:'d' }}</div>
+        """,
+        "templates/the_template.html",
+    )
+    django_testdir.create_test_module(
+        """
+        def test_for_invalid_template():
+            from django.shortcuts import render
+
+
+            render(
+                request=None,
+                template_name='the_template.html',
+                context={'data': {'empty': '', 'none': None}},
+            )
+        """
+    )
+    result = django_testdir.runpytest_subprocess("--fail-on-template-vars")
+    result.stdout.fnmatch_lines(
+        [
+            "tpkg/test_the_test.py F",
+            "E * Failed: Undefined template variable 'data.missing' in *the_template.html'",
+        ]
+    )
+
+
+@pytest.mark.django_project(
+    extra_settings="""
+    TEMPLATE_LOADERS = (
+        'django.template.loaders.filesystem.Loader',
+        'django.template.loaders.app_directories.Loader',
+    )
+    ROOT_URLCONF = 'tpkg.app.urls'
+    """
+)
+def test_invalid_template_variable_opt_in(django_testdir):
+    django_testdir.create_app_file(
+        """
+        from django.conf.urls import url
+
+        from tpkg.app import views
+
+        urlpatterns = [url(r'invalid_template/', views.invalid_template)]
+        """,
+        "urls.py",
+    )
+    django_testdir.create_app_file(
+        """
+        from django.shortcuts import render
+
+
+        def invalid_template(request):
+            return render(request, 'invalid_template.html', {})
+        """,
+        "views.py",
+    )
+    django_testdir.create_app_file(
+        "<div>{{ invalid_var }}</div>", "templates/invalid_template.html"
+    )
+    django_testdir.create_test_module(
+        """
+        import pytest
+
+        def test_for_invalid_template(client):
+            client.get('/invalid_template/')
+
+        @pytest.mark.ignore_template_errors
+        def test_ignore(client):
+            client.get('/invalid_template/')
+        """
+    )
+    result = django_testdir.runpytest_subprocess("-s")
+    result.stdout.fnmatch_lines_random(["tpkg/test_the_test.py ..*"])
+
+
+@pytest.mark.django_db
+def test_database_rollback():
+    assert Item.objects.count() == 0
+    Item.objects.create(name="blah")
+    assert Item.objects.count() == 1
+
+
+@pytest.mark.django_db
+def test_database_rollback_again():
+    test_database_rollback()
+
+
+@pytest.mark.django_db
+def test_database_name():
+    dirname, name = os.path.split(connection.settings_dict["NAME"])
+    assert "file:memorydb" in name or name == ":memory:" or name.startswith("test_")
+
+
+def test_database_noaccess():
+    with pytest.raises(RuntimeError):
+        Item.objects.count()
+
+
+class TestrunnerVerbosity:
+    """Test that Django's code to setup and teardown the databases uses
+    pytest's verbosity level."""
+
+    @pytest.fixture
+    def testdir(self, django_testdir):
+        print("testdir")
+        django_testdir.create_test_module(
+            """
+            import pytest
+
+            @pytest.mark.django_db
+            def test_inner_testrunner():
+                pass
+            """
+        )
+        return django_testdir
+
+    def test_default(self, testdir):
+        """Not verbose by default."""
+        result = testdir.runpytest_subprocess("-s")
+        result.stdout.fnmatch_lines(["tpkg/test_the_test.py .*"])
+
+    def test_vq_verbosity_0(self, testdir):
+        """-v and -q results in verbosity 0."""
+        result = testdir.runpytest_subprocess("-s", "-v", "-q")
+        result.stdout.fnmatch_lines(["tpkg/test_the_test.py .*"])
+
+    def test_verbose_with_v(self, testdir):
+        """Verbose output with '-v'."""
+        result = testdir.runpytest_subprocess("-s", "-v")
+        result.stdout.fnmatch_lines_random(["tpkg/test_the_test.py:*", "*PASSED*"])
+        if get_django_version() >= (2, 2):
+            result.stderr.fnmatch_lines(
+                ["*Destroying test database for alias 'default'*"]
+            )
+        else:
+            result.stdout.fnmatch_lines(
+                ["*Destroying test database for alias 'default'...*"]
+            )
+
+    def test_more_verbose_with_vv(self, testdir):
+        """More verbose output with '-v -v'."""
+        result = testdir.runpytest_subprocess("-s", "-v", "-v")
+        result.stdout.fnmatch_lines_random(
+            [
+                "tpkg/test_the_test.py:*",
+                "*Operations to perform:*",
+                "*Apply all migrations:*",
+                "*PASSED*",
+            ]
+        )
+        if get_django_version() >= (2, 2):
+            result.stderr.fnmatch_lines(
+                [
+                    "*Creating test database for alias*",
+                    "*Destroying test database for alias 'default'*",
+                ]
+            )
+        else:
+            result.stdout.fnmatch_lines(
+                [
+                    "*Creating test database for alias*",
+                    "*Destroying test database for alias 'default'*",
+                ]
+            )
+
+    def test_more_verbose_with_vv_and_reusedb(self, testdir):
+        """More verbose output with '-v -v', and --create-db."""
+        result = testdir.runpytest_subprocess("-s", "-v", "-v", "--create-db")
+        result.stdout.fnmatch_lines(["tpkg/test_the_test.py:*", "*PASSED*"])
+        if get_django_version() >= (2, 2):
+            result.stderr.fnmatch_lines(["*Creating test database for alias*"])
+            assert (
+                "*Destroying test database for alias 'default' ('*')...*"
+                not in result.stderr.str()
+            )
+        else:
+            result.stdout.fnmatch_lines(["*Creating test database for alias*"])
+            assert (
+                "*Destroying test database for alias 'default' ('*')...*"
+                not in result.stdout.str()
+            )
+
+
+@pytest.mark.django_db
+@pytest.mark.parametrize("site_name", ["site1", "site2"])
+def test_clear_site_cache(site_name, rf, monkeypatch):
+    request = rf.get("/")
+    monkeypatch.setattr(request, "get_host", lambda: "foo.com")
+    Site.objects.create(domain="foo.com", name=site_name)
+    assert Site.objects.get_current(request=request).name == site_name
+
+
+@pytest.mark.django_db
+@pytest.mark.parametrize("site_name", ["site1", "site2"])
+def test_clear_site_cache_check_site_cache_size(site_name, settings):
+    assert len(site_models.SITE_CACHE) == 0
+    site = Site.objects.create(domain="foo.com", name=site_name)
+    settings.SITE_ID = site.id
+    assert Site.objects.get_current() == site
+    assert len(site_models.SITE_CACHE) == 1

+ 718 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_fixtures.py

@@ -0,0 +1,718 @@
+"""Tests for user-visible fixtures.
+
+Not quite all fixtures are tested here, the db and transactional_db
+fixtures are tested in test_database.
+"""
+
+from __future__ import with_statement
+
+import socket
+from contextlib import contextmanager
+
+import pytest
+from django.conf import settings as real_settings
+from django.core import mail
+from django.db import connection, transaction
+from django.test.client import Client, RequestFactory
+from django.test.testcases import connections_support_transactions
+from django.utils.encoding import force_str
+
+from pytest_django.lazy_django import get_django_version
+from pytest_django_test.app.models import Item
+from pytest_django_test.compat import HTTPError, urlopen
+
+
+@contextmanager
+def nonverbose_config(config):
+    """Ensure that pytest's config.option.verbose is <= 0."""
+    if config.option.verbose <= 0:
+        yield
+    else:
+        saved = config.option.verbose
+        config.option.verbose = 0
+        yield
+        config.option.verbose = saved
+
+
+def test_client(client):
+    assert isinstance(client, Client)
+
+
+@pytest.mark.django_db
+def test_admin_client(admin_client):
+    assert isinstance(admin_client, Client)
+    resp = admin_client.get("/admin-required/")
+    assert force_str(resp.content) == "You are an admin"
+
+
+def test_admin_client_no_db_marker(admin_client):
+    assert isinstance(admin_client, Client)
+    resp = admin_client.get("/admin-required/")
+    assert force_str(resp.content) == "You are an admin"
+
+
+@pytest.mark.django_db
+def test_admin_user(admin_user, django_user_model):
+    assert isinstance(admin_user, django_user_model)
+
+
+def test_admin_user_no_db_marker(admin_user, django_user_model):
+    assert isinstance(admin_user, django_user_model)
+
+
+def test_rf(rf):
+    assert isinstance(rf, RequestFactory)
+
+
+@pytest.mark.django_db
+def test_django_assert_num_queries_db(request, django_assert_num_queries):
+    with nonverbose_config(request.config):
+        with django_assert_num_queries(3):
+            Item.objects.create(name="foo")
+            Item.objects.create(name="bar")
+            Item.objects.create(name="baz")
+
+        with pytest.raises(pytest.fail.Exception) as excinfo:
+            with django_assert_num_queries(2) as captured:
+                Item.objects.create(name="quux")
+        assert excinfo.value.args == (
+            "Expected to perform 2 queries but 1 was done "
+            "(add -v option to show queries)",
+        )
+        assert len(captured.captured_queries) == 1
+
+
+@pytest.mark.django_db
+def test_django_assert_max_num_queries_db(request, django_assert_max_num_queries):
+    with nonverbose_config(request.config):
+        with django_assert_max_num_queries(2):
+            Item.objects.create(name="1-foo")
+            Item.objects.create(name="2-bar")
+
+        with pytest.raises(pytest.fail.Exception) as excinfo:
+            with django_assert_max_num_queries(2) as captured:
+                Item.objects.create(name="1-foo")
+                Item.objects.create(name="2-bar")
+                Item.objects.create(name="3-quux")
+
+        assert excinfo.value.args == (
+            "Expected to perform 2 queries or less but 3 were done "
+            "(add -v option to show queries)",
+        )
+        assert len(captured.captured_queries) == 3
+        assert "1-foo" in captured.captured_queries[0]["sql"]
+
+
+@pytest.mark.django_db(transaction=True)
+def test_django_assert_num_queries_transactional_db(
+    request, transactional_db, django_assert_num_queries
+):
+    with nonverbose_config(request.config):
+        with transaction.atomic():
+            with django_assert_num_queries(3):
+                Item.objects.create(name="foo")
+                Item.objects.create(name="bar")
+                Item.objects.create(name="baz")
+
+            with pytest.raises(pytest.fail.Exception):
+                with django_assert_num_queries(2):
+                    Item.objects.create(name="quux")
+
+
+def test_django_assert_num_queries_output(django_testdir):
+    django_testdir.create_test_module(
+        """
+        from django.contrib.contenttypes.models import ContentType
+        import pytest
+
+        @pytest.mark.django_db
+        def test_queries(django_assert_num_queries):
+            with django_assert_num_queries(1):
+                list(ContentType.objects.all())
+                ContentType.objects.count()
+    """
+    )
+    result = django_testdir.runpytest_subprocess("--tb=short")
+    result.stdout.fnmatch_lines(["*Expected to perform 1 queries but 2 were done*"])
+    assert result.ret == 1
+
+
+def test_django_assert_num_queries_output_verbose(django_testdir):
+    django_testdir.create_test_module(
+        """
+        from django.contrib.contenttypes.models import ContentType
+        import pytest
+
+        @pytest.mark.django_db
+        def test_queries(django_assert_num_queries):
+            with django_assert_num_queries(11):
+                list(ContentType.objects.all())
+                ContentType.objects.count()
+    """
+    )
+    result = django_testdir.runpytest_subprocess("--tb=short", "-v")
+    result.stdout.fnmatch_lines(
+        ["*Expected to perform 11 queries but 2 were done*", "*Queries:*", "*========*"]
+    )
+    assert result.ret == 1
+
+
+@pytest.mark.django_db
+def test_django_assert_num_queries_db_connection(django_assert_num_queries):
+    from django.db import connection
+
+    with django_assert_num_queries(1, connection=connection):
+        Item.objects.create(name="foo")
+
+    with django_assert_num_queries(1, connection=None):
+        Item.objects.create(name="foo")
+
+    with pytest.raises(AttributeError):
+        with django_assert_num_queries(1, connection=False):
+            pass
+
+
+@pytest.mark.django_db
+def test_django_assert_num_queries_output_info(django_testdir):
+    django_testdir.create_test_module(
+        """
+        from django.contrib.contenttypes.models import ContentType
+        import pytest
+
+        @pytest.mark.django_db
+        def test_queries(django_assert_num_queries):
+            with django_assert_num_queries(
+                num=2,
+                info="Expected: 1 for select all, 1 for count"
+            ):
+                list(ContentType.objects.all())
+                ContentType.objects.count()
+                ContentType.objects.first()  # additional wrong query
+    """
+    )
+    result = django_testdir.runpytest_subprocess("--tb=short", "-v")
+    result.stdout.fnmatch_lines(
+        [
+            "*Expected to perform 2 queries but 3 were done*",
+            "*Expected: 1 for select all, 1 for count*",
+            "*Queries:*",
+            "*========*",
+        ]
+    )
+    assert result.ret == 1
+
+
+class TestSettings:
+    """Tests for the settings fixture, order matters"""
+
+    def test_modify_existing(self, settings):
+        assert settings.SECRET_KEY == "foobar"
+        assert real_settings.SECRET_KEY == "foobar"
+        settings.SECRET_KEY = "spam"
+        assert settings.SECRET_KEY == "spam"
+        assert real_settings.SECRET_KEY == "spam"
+
+    def test_modify_existing_again(self, settings):
+        assert settings.SECRET_KEY == "foobar"
+        assert real_settings.SECRET_KEY == "foobar"
+
+    def test_new(self, settings):
+        assert not hasattr(settings, "SPAM")
+        assert not hasattr(real_settings, "SPAM")
+        settings.SPAM = "ham"
+        assert settings.SPAM == "ham"
+        assert real_settings.SPAM == "ham"
+
+    def test_new_again(self, settings):
+        assert not hasattr(settings, "SPAM")
+        assert not hasattr(real_settings, "SPAM")
+
+    def test_deleted(self, settings):
+        assert hasattr(settings, "SECRET_KEY")
+        assert hasattr(real_settings, "SECRET_KEY")
+        del settings.SECRET_KEY
+        assert not hasattr(settings, "SECRET_KEY")
+        assert not hasattr(real_settings, "SECRET_KEY")
+
+    def test_deleted_again(self, settings):
+        assert hasattr(settings, "SECRET_KEY")
+        assert hasattr(real_settings, "SECRET_KEY")
+
+    def test_signals(self, settings):
+        result = []
+
+        def assert_signal(signal, sender, setting, value, enter):
+            result.append((setting, value, enter))
+
+        from django.test.signals import setting_changed
+
+        setting_changed.connect(assert_signal)
+
+        result = []
+        settings.SECRET_KEY = "change 1"
+        settings.SECRET_KEY = "change 2"
+        assert result == [
+            ("SECRET_KEY", "change 1", True),
+            ("SECRET_KEY", "change 2", True),
+        ]
+
+        result = []
+        settings.FOOBAR = "abc123"
+        assert sorted(result) == [("FOOBAR", "abc123", True)]
+
+    def test_modification_signal(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            import pytest
+
+            from django.conf import settings
+            from django.test.signals import setting_changed
+
+
+            @pytest.fixture(autouse=True, scope='session')
+            def settings_change_printer():
+                def receiver(sender, **kwargs):
+                    fmt_dict = {'actual_value': getattr(settings, kwargs['setting'],
+                                                        '<<does not exist>>')}
+                    fmt_dict.update(kwargs)
+
+                    print('Setting changed: '
+                          'enter=%(enter)s,setting=%(setting)s,'
+                          'value=%(value)s,actual_value=%(actual_value)s'
+                          % fmt_dict)
+
+                setting_changed.connect(receiver, weak=False)
+
+
+            def test_set(settings):
+                settings.SECRET_KEY = 'change 1'
+                settings.SECRET_KEY = 'change 2'
+
+
+            def test_set_non_existent(settings):
+                settings.FOOBAR = 'abc123'
+         """
+        )
+
+        result = django_testdir.runpytest_subprocess("--tb=short", "-v", "-s")
+
+        # test_set
+        result.stdout.fnmatch_lines(
+            [
+                "*Setting changed: enter=True,setting=SECRET_KEY,value=change 1*",
+                "*Setting changed: enter=True,setting=SECRET_KEY,value=change 2*",
+                "*Setting changed: enter=False,setting=SECRET_KEY,value=change 1*",
+                "*Setting changed: enter=False,setting=SECRET_KEY,value=foobar*",
+            ]
+        )
+
+        result.stdout.fnmatch_lines(
+            [
+                "*Setting changed: enter=True,setting=FOOBAR,value=abc123*",
+                (
+                    "*Setting changed: enter=False,setting=FOOBAR,value=None,"
+                    "actual_value=<<does not exist>>*"
+                ),
+            ]
+        )
+
+
+class TestLiveServer:
+    def test_settings_before(self):
+        from django.conf import settings
+
+        assert (
+            "%s.%s" % (settings.__class__.__module__, settings.__class__.__name__)
+            == "django.conf.Settings"
+        )
+        TestLiveServer._test_settings_before_run = True
+
+    def test_url(self, live_server):
+        assert live_server.url == force_str(live_server)
+
+    def test_change_settings(self, live_server, settings):
+        assert live_server.url == force_str(live_server)
+
+    def test_settings_restored(self):
+        """Ensure that settings are restored after test_settings_before."""
+        import django
+        from django.conf import settings
+
+        assert TestLiveServer._test_settings_before_run is True
+        assert (
+            "%s.%s" % (settings.__class__.__module__, settings.__class__.__name__)
+            == "django.conf.Settings"
+        )
+        if django.VERSION >= (1, 11):
+            assert settings.ALLOWED_HOSTS == ["testserver"]
+        else:
+            assert settings.ALLOWED_HOSTS == ["*"]
+
+    def test_transactions(self, live_server):
+        if not connections_support_transactions():
+            pytest.skip("transactions required for this test")
+
+        assert not connection.in_atomic_block
+
+    def test_db_changes_visibility(self, live_server):
+        response_data = urlopen(live_server + "/item_count/").read()
+        assert force_str(response_data) == "Item count: 0"
+        Item.objects.create(name="foo")
+        response_data = urlopen(live_server + "/item_count/").read()
+        assert force_str(response_data) == "Item count: 1"
+
+    def test_fixture_db(self, db, live_server):
+        Item.objects.create(name="foo")
+        response_data = urlopen(live_server + "/item_count/").read()
+        assert force_str(response_data) == "Item count: 1"
+
+    def test_fixture_transactional_db(self, transactional_db, live_server):
+        Item.objects.create(name="foo")
+        response_data = urlopen(live_server + "/item_count/").read()
+        assert force_str(response_data) == "Item count: 1"
+
+    @pytest.fixture
+    def item(self):
+        # This has not requested database access explicitly, but the
+        # live_server fixture auto-uses the transactional_db fixture.
+        Item.objects.create(name="foo")
+
+    def test_item(self, item, live_server):
+        pass
+
+    @pytest.fixture
+    def item_db(self, db):
+        return Item.objects.create(name="foo")
+
+    def test_item_db(self, item_db, live_server):
+        response_data = urlopen(live_server + "/item_count/").read()
+        assert force_str(response_data) == "Item count: 1"
+
+    @pytest.fixture
+    def item_transactional_db(self, transactional_db):
+        return Item.objects.create(name="foo")
+
+    def test_item_transactional_db(self, item_transactional_db, live_server):
+        response_data = urlopen(live_server + "/item_count/").read()
+        assert force_str(response_data) == "Item count: 1"
+
+    @pytest.mark.django_project(
+        extra_settings="""
+        INSTALLED_APPS = [
+            'django.contrib.auth',
+            'django.contrib.contenttypes',
+            'django.contrib.sessions',
+            'django.contrib.sites',
+            'django.contrib.staticfiles',
+            'tpkg.app',
+        ]
+
+        STATIC_URL = '/static/'
+        """
+    )
+    def test_serve_static_with_staticfiles_app(self, django_testdir, settings):
+        """
+        LiveServer always serves statics with ``django.contrib.staticfiles``
+        handler.
+        """
+        django_testdir.create_test_module(
+            """
+            from django.utils.encoding import force_str
+
+            try:
+                from urllib2 import urlopen
+            except ImportError:
+                from urllib.request import urlopen
+
+            class TestLiveServer:
+                def test_a(self, live_server, settings):
+                    assert ('django.contrib.staticfiles'
+                            in settings.INSTALLED_APPS)
+                    response_data = urlopen(
+                        live_server + '/static/a_file.txt').read()
+                    assert force_str(response_data) == 'bla\\n'
+            """
+        )
+        result = django_testdir.runpytest_subprocess("--tb=short", "-v")
+        result.stdout.fnmatch_lines(["*test_a*PASSED*"])
+        assert result.ret == 0
+
+    def test_serve_static_dj17_without_staticfiles_app(self, live_server, settings):
+        """
+        Because ``django.contrib.staticfiles`` is not installed
+        LiveServer can not serve statics with django >= 1.7 .
+        """
+        with pytest.raises(HTTPError):
+            urlopen(live_server + "/static/a_file.txt").read()
+
+    @pytest.mark.skipif(
+        get_django_version() < (1, 11), reason="Django >= 1.11 required"
+    )
+    def test_specified_port_range_error_message_django_111(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+        def test_with_live_server(live_server):
+            pass
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("--liveserver=localhost:1234-2345")
+        result.stdout.fnmatch_lines(
+            [
+                "*Specifying multiple live server ports is not supported in Django 1.11. This "
+                "will be an error in a future pytest-django release.*"
+            ]
+        )
+
+    @pytest.mark.skipif(
+        get_django_version() < (1, 11, 2), reason="Django >= 1.11.2 required"
+    )
+    def test_specified_port_django_111(self, django_testdir):
+        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        try:
+            sock.bind(("", 0))
+            __, port = sock.getsockname()
+        finally:
+            sock.close()
+
+        django_testdir.create_test_module(
+            """
+        def test_with_live_server(live_server):
+            assert live_server.port == %d
+        """
+            % port
+        )
+
+        django_testdir.runpytest_subprocess("--liveserver=localhost:%s" % port)
+
+
+@pytest.mark.parametrize("username_field", ("email", "identifier"))
+@pytest.mark.django_project(
+    extra_settings="""
+    AUTH_USER_MODEL = 'app.MyCustomUser'
+    INSTALLED_APPS = [
+        'django.contrib.auth',
+        'django.contrib.contenttypes',
+        'django.contrib.sessions',
+        'django.contrib.sites',
+        'tpkg.app',
+    ]
+    ROOT_URLCONF = 'tpkg.app.urls'
+    """
+)
+def test_custom_user_model(django_testdir, username_field):
+    django_testdir.create_app_file(
+        """
+        from django.contrib.auth.models import AbstractUser
+        from django.db import models
+
+        class MyCustomUser(AbstractUser):
+            identifier = models.CharField(unique=True, max_length=100)
+
+            USERNAME_FIELD = '%s'
+        """
+        % (username_field),
+        "models.py",
+    )
+    django_testdir.create_app_file(
+        """
+        from tpkg.app import views
+
+        try:
+            from django.urls import path
+        except ImportError:
+            from django.conf.urls import url
+
+            urlpatterns = [url(r'admin-required/', views.admin_required_view)]
+        else:
+            urlpatterns = [path('admin-required/', views.admin_required_view)]
+        """,
+        "urls.py",
+    )
+    django_testdir.create_app_file(
+        """
+        from django.http import HttpResponse
+        from django.template import Template
+        from django.template.context import Context
+
+
+        def admin_required_view(request):
+            assert request.user.is_staff
+            return HttpResponse(Template('You are an admin').render(Context()))
+        """,
+        "views.py",
+    )
+    django_testdir.makepyfile(
+        """
+        from django.utils.encoding import force_str
+        from tpkg.app.models import MyCustomUser
+
+        def test_custom_user_model(admin_client):
+            resp = admin_client.get('/admin-required/')
+            assert force_str(resp.content) == 'You are an admin'
+        """
+    )
+
+    django_testdir.create_app_file("", "migrations/__init__.py")
+    django_testdir.create_app_file(
+        """
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import django.utils.timezone
+import django.core.validators
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('auth', '0001_initial'),
+        ('app', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='MyCustomUser',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('password', models.CharField(max_length=128, verbose_name='password')),
+                ('last_login', models.DateTimeField(null=True, verbose_name='last login', blank=True)),
+                ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+                ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, max_length=30, validators=[django.core.validators.RegexValidator(r'^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.', 'invalid')], help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, verbose_name='username')),
+                ('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)),
+                ('last_name', models.CharField(max_length=30, verbose_name='last name', blank=True)),
+                ('email', models.EmailField(max_length=254, verbose_name='email address', blank=True)),
+                ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
+                ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
+                ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
+                ('identifier', models.CharField(unique=True, max_length=100)),
+                ('groups', models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Group', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', verbose_name='groups')),
+                ('user_permissions', models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Permission', blank=True, help_text='Specific permissions for this user.', verbose_name='user permissions')),
+            ],
+            options={
+                'abstract': False,
+                'verbose_name': 'user',
+                'verbose_name_plural': 'users',
+            },
+            bases=None,
+        ),
+    ]
+        """,  # noqa: E501
+        "migrations/0002_custom_user_model.py",
+    )
+
+    result = django_testdir.runpytest_subprocess("-s")
+    result.stdout.fnmatch_lines(["* 1 passed in*"])
+    assert result.ret == 0
+
+
+class Test_django_db_blocker:
+    @pytest.mark.django_db
+    def test_block_manually(self, django_db_blocker):
+        try:
+            django_db_blocker.block()
+            with pytest.raises(RuntimeError):
+                Item.objects.exists()
+        finally:
+            django_db_blocker.restore()
+
+    @pytest.mark.django_db
+    def test_block_with_block(self, django_db_blocker):
+        with django_db_blocker.block():
+            with pytest.raises(RuntimeError):
+                Item.objects.exists()
+
+    def test_unblock_manually(self, django_db_blocker):
+        try:
+            django_db_blocker.unblock()
+            Item.objects.exists()
+        finally:
+            django_db_blocker.restore()
+
+    def test_unblock_with_block(self, django_db_blocker):
+        with django_db_blocker.unblock():
+            Item.objects.exists()
+
+
+def test_mail(mailoutbox):
+    assert (
+        mailoutbox is mail.outbox
+    )  # check that mail.outbox and fixture value is same object
+    assert len(mailoutbox) == 0
+    mail.send_mail("subject", "body", "from@example.com", ["to@example.com"])
+    assert len(mailoutbox) == 1
+    m = mailoutbox[0]
+    assert m.subject == "subject"
+    assert m.body == "body"
+    assert m.from_email == "from@example.com"
+    assert list(m.to) == ["to@example.com"]
+
+
+def test_mail_again(mailoutbox):
+    test_mail(mailoutbox)
+
+
+def test_mail_message_uses_mocked_DNS_NAME(mailoutbox):
+    mail.send_mail("subject", "body", "from@example.com", ["to@example.com"])
+    m = mailoutbox[0]
+    message = m.message()
+    assert message["Message-ID"].endswith("@fake-tests.example.com>")
+
+
+def test_mail_message_uses_django_mail_dnsname_fixture(django_testdir):
+    django_testdir.create_test_module(
+        """
+        from django.core import mail
+        import pytest
+
+        @pytest.fixture
+        def django_mail_dnsname():
+            return 'from.django_mail_dnsname'
+
+        def test_mailbox_inner(mailoutbox):
+            mail.send_mail('subject', 'body', 'from@example.com',
+                           ['to@example.com'])
+            m = mailoutbox[0]
+            message = m.message()
+            assert message['Message-ID'].endswith('@from.django_mail_dnsname>')
+    """
+    )
+    result = django_testdir.runpytest_subprocess("--tb=short", "-v")
+    result.stdout.fnmatch_lines(["*test_mailbox_inner*PASSED*"])
+    assert result.ret == 0
+
+
+def test_mail_message_dns_patching_can_be_skipped(django_testdir):
+    django_testdir.create_test_module(
+        """
+        from django.core import mail
+        import pytest
+
+        @pytest.fixture
+        def django_mail_dnsname():
+            raise Exception('should not get called')
+
+        @pytest.fixture
+        def django_mail_patch_dns():
+            print('\\ndjango_mail_dnsname_mark')
+
+        def test_mailbox_inner(mailoutbox, monkeypatch):
+            def mocked_make_msgid(*args, **kwargs):
+                mocked_make_msgid.called += [(args, kwargs)]
+            mocked_make_msgid.called = []
+
+            monkeypatch.setattr(mail.message, 'make_msgid', mocked_make_msgid)
+            mail.send_mail('subject', 'body', 'from@example.com',
+                           ['to@example.com'])
+            m = mailoutbox[0]
+            assert len(mocked_make_msgid.called) == 1
+
+            assert mocked_make_msgid.called[0][1]['domain'] is mail.DNS_NAME
+    """
+    )
+    result = django_testdir.runpytest_subprocess("--tb=short", "-vv", "-s")
+    result.stdout.fnmatch_lines(
+        ["*test_mailbox_inner*", "django_mail_dnsname_mark", "PASSED*"]
+    )
+    assert result.ret == 0

+ 60 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_initialization.py

@@ -0,0 +1,60 @@
+from textwrap import dedent
+
+
+def test_django_setup_order_and_uniqueness(django_testdir, monkeypatch):
+    """
+    The django.setup() function shall not be called multiple times by
+    pytest-django, since it resets logging conf each time.
+    """
+    django_testdir.makeconftest(
+        """
+        import django.apps
+        assert django.apps.apps.ready
+        from tpkg.app.models import Item
+
+        print("conftest")
+        def pytest_configure():
+            import django
+            print("pytest_configure: conftest")
+            django.setup = lambda: SHOULD_NOT_GET_CALLED
+    """
+    )
+
+    django_testdir.project_root.join("tpkg", "plugin.py").write(
+        dedent(
+            """
+        import pytest
+        import django.apps
+        assert not django.apps.apps.ready
+
+        print("plugin")
+        def pytest_configure():
+            assert django.apps.apps.ready
+            from tpkg.app.models import Item
+            print("pytest_configure: plugin")
+
+        @pytest.hookimpl(tryfirst=True)
+        def pytest_load_initial_conftests(early_config, parser, args):
+            print("pytest_load_initial_conftests")
+            assert not django.apps.apps.ready
+    """
+        )
+    )
+    django_testdir.makepyfile(
+        """
+        def test_ds():
+            pass
+    """
+    )
+    result = django_testdir.runpytest_subprocess("-s", "-p", "tpkg.plugin")
+    result.stdout.fnmatch_lines(
+        [
+            "plugin",
+            "pytest_load_initial_conftests",
+            "conftest",
+            "pytest_configure: conftest",
+            "pytest_configure: plugin",
+            "* 1 passed in*",
+        ]
+    )
+    assert result.ret == 0

+ 142 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_manage_py_scan.py

@@ -0,0 +1,142 @@
+import pytest
+
+
+@pytest.mark.django_project(project_root="django_project_root", create_manage_py=True)
+def test_django_project_found(django_testdir):
+    # XXX: Important: Do not chdir() to django_project_root since runpytest_subprocess
+    # will call "python /path/to/pytest.py", which will impliclity add cwd to
+    # the path. By instead calling "python /path/to/pytest.py
+    # django_project_root", we avoid impliclity adding the project to sys.path
+    # This matches the behaviour when pytest is called directly as an
+    # executable (cwd is not added to the Python path)
+
+    django_testdir.create_test_module(
+        """
+    def test_foobar():
+        assert 1 + 1 == 2
+    """
+    )
+
+    result = django_testdir.runpytest_subprocess("django_project_root")
+    assert result.ret == 0
+
+    outcomes = result.parseoutcomes()
+    assert outcomes["passed"] == 1
+
+
+@pytest.mark.django_project(project_root="django_project_root", create_manage_py=True)
+def test_django_project_found_with_k(django_testdir, monkeypatch):
+    """Test that cwd is checked as fallback with non-args via '-k foo'."""
+    testfile = django_testdir.create_test_module(
+        """
+    def test_foobar():
+        assert True
+    """,
+        "sub/test_in_sub.py",
+    )
+
+    monkeypatch.chdir(testfile.dirname)
+    result = django_testdir.runpytest_subprocess("-k", "test_foobar")
+    assert result.ret == 0
+
+    outcomes = result.parseoutcomes()
+    assert outcomes["passed"] == 1
+
+
+@pytest.mark.django_project(project_root="django_project_root", create_manage_py=True)
+def test_django_project_found_with_k_and_cwd(django_testdir, monkeypatch):
+    """Cover cwd not used as fallback if present already in args."""
+    testfile = django_testdir.create_test_module(
+        """
+    def test_foobar():
+        assert True
+    """,
+        "sub/test_in_sub.py",
+    )
+
+    monkeypatch.chdir(testfile.dirname)
+    result = django_testdir.runpytest_subprocess(testfile.dirname, "-k", "test_foobar")
+    assert result.ret == 0
+
+    outcomes = result.parseoutcomes()
+    assert outcomes["passed"] == 1
+
+
+@pytest.mark.django_project(project_root="django_project_root", create_manage_py=True)
+def test_django_project_found_absolute(django_testdir, monkeypatch):
+    """This only tests that "." is added as an absolute path (#637)."""
+    django_testdir.create_test_module(
+        """
+    def test_dot_not_in_syspath():
+        import sys
+        assert '.' not in sys.path[:5]
+    """
+    )
+    monkeypatch.chdir("django_project_root")
+    # NOTE: the "." here is important to test for an absolute path being used.
+    result = django_testdir.runpytest_subprocess("-s", ".")
+    assert result.ret == 0
+
+    outcomes = result.parseoutcomes()
+    assert outcomes["passed"] == 1
+
+
+@pytest.mark.django_project(project_root="django_project_root", create_manage_py=True)
+def test_django_project_found_invalid_settings(django_testdir, monkeypatch):
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "DOES_NOT_EXIST")
+
+    result = django_testdir.runpytest_subprocess("django_project_root")
+    assert result.ret != 0
+
+    result.stderr.fnmatch_lines(["*ImportError:*DOES_NOT_EXIST*"])
+    result.stderr.fnmatch_lines(["*pytest-django found a Django project*"])
+
+
+def test_django_project_scan_disabled_invalid_settings(django_testdir, monkeypatch):
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "DOES_NOT_EXIST")
+
+    django_testdir.makeini(
+        """
+    [pytest]
+    django_find_project = false
+    """
+    )
+
+    result = django_testdir.runpytest_subprocess("django_project_root")
+    assert result.ret != 0
+
+    result.stderr.fnmatch_lines(["*ImportError*DOES_NOT_EXIST*"])
+    result.stderr.fnmatch_lines(
+        ["*pytest-django did not search for " "Django projects*"]
+    )
+
+
+@pytest.mark.django_project(project_root="django_project_root", create_manage_py=True)
+def test_django_project_found_invalid_settings_version(django_testdir, monkeypatch):
+    """Invalid DSM should not cause an error with --help or --version."""
+    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "DOES_NOT_EXIST")
+
+    result = django_testdir.runpytest_subprocess("django_project_root", "--version", "--version")
+    assert result.ret == 0
+    result.stderr.fnmatch_lines(["*This is pytest version*"])
+
+    result = django_testdir.runpytest_subprocess("django_project_root", "--help")
+    assert result.ret == 0
+    result.stdout.fnmatch_lines(["*usage:*"])
+
+
+@pytest.mark.django_project(project_root="django_project_root", create_manage_py=True)
+def test_runs_without_error_on_long_args(django_testdir):
+    django_testdir.create_test_module(
+        """
+    def test_this_is_a_long_message_which_caused_a_bug_when_scanning_for_manage_py_12346712341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234112341234112451234123412341234123412341234123412341234123412341234123412341234123412341234123412341234():
+        assert 1 + 1 == 2
+        """  # noqa: E501
+    )
+
+    result = django_testdir.runpytest_subprocess(
+        "-k",
+        "this_is_a_long_message_which_caused_a_bug_when_scanning_for_manage_py_12346712341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234112341234112451234123412341234123412341234123412341234123412341234123412341234123412341234123412341234",  # noqa: E501
+        "django_project_root",
+    )
+    assert result.ret == 0

+ 497 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_unittest.py

@@ -0,0 +1,497 @@
+import pytest
+from django.test import TestCase
+
+from pytest_django.plugin import _pytest_version_info
+from pytest_django_test.app.models import Item
+
+
+class TestFixtures(TestCase):
+    fixtures = ["items"]
+
+    def test_fixtures(self):
+        assert Item.objects.count() == 1
+        assert Item.objects.get().name == "Fixture item"
+
+    def test_fixtures_again(self):
+        """Ensure fixtures are only loaded once."""
+        self.test_fixtures()
+
+
+class TestSetup(TestCase):
+    def setUp(self):
+        """setUp should be called after starting a transaction"""
+        assert Item.objects.count() == 0
+        Item.objects.create(name="Some item")
+        Item.objects.create(name="Some item again")
+
+    def test_count(self):
+        self.assertEqual(Item.objects.count(), 2)
+        assert Item.objects.count() == 2
+        Item.objects.create(name="Foo")
+        self.assertEqual(Item.objects.count(), 3)
+
+    def test_count_again(self):
+        self.test_count()
+
+    def tearDown(self):
+        """tearDown should be called before rolling back the database"""
+        assert Item.objects.count() == 3
+
+
+class TestFixturesWithSetup(TestCase):
+    fixtures = ["items"]
+
+    def setUp(self):
+        assert Item.objects.count() == 1
+        Item.objects.create(name="Some item")
+
+    def test_count(self):
+        assert Item.objects.count() == 2
+        Item.objects.create(name="Some item again")
+
+    def test_count_again(self):
+        self.test_count()
+
+    def tearDown(self):
+        assert Item.objects.count() == 3
+
+
+def test_sole_test(django_testdir):
+    """
+    Make sure the database is configured when only Django TestCase classes
+    are collected, without the django_db marker.
+
+    Also ensures that the DB is available after a failure (#824).
+    """
+    django_testdir.create_test_module(
+        """
+        import os
+
+        from django.test import TestCase
+        from django.conf import settings
+
+        from .app.models import Item
+
+        class TestFoo(TestCase):
+            def test_foo(self):
+                # Make sure we are actually using the test database
+                _, db_name = os.path.split(settings.DATABASES['default']['NAME'])
+                assert db_name.startswith('test_') or db_name == ':memory:' \\
+                    or 'file:memorydb' in db_name
+
+                # Make sure it is usable
+                assert Item.objects.count() == 0
+
+                assert 0, "trigger_error"
+
+        class TestBar(TestCase):
+            def test_bar(self):
+                assert Item.objects.count() == 0
+    """
+    )
+
+    result = django_testdir.runpytest_subprocess("-v")
+    result.stdout.fnmatch_lines(
+        [
+            "*::test_foo FAILED",
+            "*::test_bar PASSED",
+            '>       assert 0, "trigger_error"',
+            "E       AssertionError: trigger_error",
+            "E       assert 0",
+            "*= 1 failed, 1 passed in *",
+        ]
+    )
+    assert result.ret == 1
+
+
+class TestUnittestMethods:
+    "Test that setup/teardown methods of unittests are being called."
+
+    def test_django(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            from django.test import TestCase
+
+            class TestFoo(TestCase):
+                @classmethod
+                def setUpClass(self):
+                    print('\\nCALLED: setUpClass')
+
+                def setUp(self):
+                    print('\\nCALLED: setUp')
+
+                def tearDown(self):
+                    print('\\nCALLED: tearDown')
+
+                @classmethod
+                def tearDownClass(self):
+                    print('\\nCALLED: tearDownClass')
+
+                def test_pass(self):
+                    pass
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-v", "-s")
+        result.stdout.fnmatch_lines(
+            [
+                "CALLED: setUpClass",
+                "CALLED: setUp",
+                "CALLED: tearDown",
+                "PASSED*",
+                "CALLED: tearDownClass",
+            ]
+        )
+        assert result.ret == 0
+
+    def test_setUpClass_not_being_a_classmethod(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            from django.test import TestCase
+
+            class TestFoo(TestCase):
+                def setUpClass(self):
+                    pass
+
+                def test_pass(self):
+                    pass
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-v", "-s")
+        expected_lines = [
+            "* ERROR at setup of TestFoo.test_pass *",
+        ]
+        if _pytest_version_info < (4, 2):
+            expected_lines += [
+                "E *Failed: <class 'tpkg.test_the_test.TestFoo'>.setUpClass should be a classmethod",  # noqa:E501
+            ]
+        else:
+            expected_lines += [
+                "E * TypeError: *",
+            ]
+
+        result.stdout.fnmatch_lines(expected_lines)
+        assert result.ret == 1
+
+    def test_setUpClass_multiple_subclasses(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            from django.test import TestCase
+
+
+            class TestFoo(TestCase):
+                @classmethod
+                def setUpClass(cls):
+                    super(TestFoo, cls).setUpClass()
+
+                def test_shared(self):
+                    pass
+
+
+            class TestBar(TestFoo):
+                def test_bar1(self):
+                    pass
+
+
+            class TestBar2(TestFoo):
+                def test_bar21(self):
+                    pass
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-v")
+        result.stdout.fnmatch_lines(
+            [
+                "*TestFoo::test_shared PASSED*",
+                "*TestBar::test_bar1 PASSED*",
+                "*TestBar::test_shared PASSED*",
+                "*TestBar2::test_bar21 PASSED*",
+                "*TestBar2::test_shared PASSED*",
+            ]
+        )
+        assert result.ret == 0
+
+    def test_setUpClass_mixin(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            from django.test import TestCase
+
+            class TheMixin(object):
+                @classmethod
+                def setUpClass(cls):
+                    super(TheMixin, cls).setUpClass()
+
+
+            class TestFoo(TheMixin, TestCase):
+                def test_foo(self):
+                    pass
+
+
+            class TestBar(TheMixin, TestCase):
+                def test_bar(self):
+                    pass
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-v")
+        result.stdout.fnmatch_lines(
+            ["*TestFoo::test_foo PASSED*", "*TestBar::test_bar PASSED*"]
+        )
+        assert result.ret == 0
+
+    def test_setUpClass_skip(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            from django.test import TestCase
+            import pytest
+
+
+            class TestFoo(TestCase):
+                @classmethod
+                def setUpClass(cls):
+                    if cls is TestFoo:
+                        raise pytest.skip("Skip base class")
+                    super(TestFoo, cls).setUpClass()
+
+                def test_shared(self):
+                    pass
+
+
+            class TestBar(TestFoo):
+                def test_bar1(self):
+                    pass
+
+
+            class TestBar2(TestFoo):
+                def test_bar21(self):
+                    pass
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-v")
+        result.stdout.fnmatch_lines(
+            [
+                "*TestFoo::test_shared SKIPPED*",
+                "*TestBar::test_bar1 PASSED*",
+                "*TestBar::test_shared PASSED*",
+                "*TestBar2::test_bar21 PASSED*",
+                "*TestBar2::test_shared PASSED*",
+            ]
+        )
+        assert result.ret == 0
+
+    def test_multi_inheritance_setUpClass(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            from django.test import TestCase
+
+            # Using a mixin is a regression test, see #280 for more details:
+            # https://github.com/pytest-dev/pytest-django/issues/280
+
+            class SomeMixin(object):
+                pass
+
+            class TestA(SomeMixin, TestCase):
+                expected_state = ['A']
+                state = []
+
+                @classmethod
+                def setUpClass(cls):
+                    super(TestA, cls).setUpClass()
+                    cls.state.append('A')
+
+                @classmethod
+                def tearDownClass(cls):
+                    assert cls.state.pop() == 'A'
+                    super(TestA, cls).tearDownClass()
+
+                def test_a(self):
+                    assert self.state == self.expected_state
+
+            class TestB(TestA):
+                expected_state = ['A', 'B']
+
+                @classmethod
+                def setUpClass(cls):
+                    super(TestB, cls).setUpClass()
+                    cls.state.append('B')
+
+                @classmethod
+                def tearDownClass(cls):
+                    assert cls.state.pop() == 'B'
+                    super(TestB, cls).tearDownClass()
+
+                def test_b(self):
+                    assert self.state == self.expected_state
+
+            class TestC(TestB):
+                expected_state = ['A', 'B', 'C']
+
+                @classmethod
+                def setUpClass(cls):
+                    super(TestC, cls).setUpClass()
+                    cls.state.append('C')
+
+                @classmethod
+                def tearDownClass(cls):
+                    assert cls.state.pop() == 'C'
+                    super(TestC, cls).tearDownClass()
+
+                def test_c(self):
+                    assert self.state == self.expected_state
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-vvvv", "-s")
+        assert result.parseoutcomes()["passed"] == 6
+        assert result.ret == 0
+
+    def test_unittest(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            from unittest import TestCase
+
+            class TestFoo(TestCase):
+                @classmethod
+                def setUpClass(self):
+                    print('\\nCALLED: setUpClass')
+
+                def setUp(self):
+                    print('\\nCALLED: setUp')
+
+                def tearDown(self):
+                    print('\\nCALLED: tearDown')
+
+                @classmethod
+                def tearDownClass(self):
+                    print('\\nCALLED: tearDownClass')
+
+                def test_pass(self):
+                    pass
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-v", "-s")
+        result.stdout.fnmatch_lines(
+            [
+                "CALLED: setUpClass",
+                "CALLED: setUp",
+                "CALLED: tearDown",
+                "PASSED*",
+                "CALLED: tearDownClass",
+            ]
+        )
+        assert result.ret == 0
+
+    def test_setUpClass_leaf_but_not_in_dunder_dict(self, django_testdir):
+        django_testdir.create_test_module(
+            """
+            from django.test import testcases
+
+            class CMSTestCase(testcases.TestCase):
+                pass
+
+            class FooBarTestCase(testcases.TestCase):
+
+                @classmethod
+                def setUpClass(cls):
+                    print('FooBarTestCase.setUpClass')
+                    super(FooBarTestCase, cls).setUpClass()
+
+            class TestContact(CMSTestCase, FooBarTestCase):
+
+                def test_noop(self):
+                    print('test_noop')
+        """
+        )
+
+        result = django_testdir.runpytest_subprocess("-q", "-s")
+        result.stdout.fnmatch_lines(
+            ["*FooBarTestCase.setUpClass*", "*test_noop*", "1 passed in*"]
+        )
+        assert result.ret == 0
+
+
+class TestCaseWithDbFixture(TestCase):
+    pytestmark = pytest.mark.usefixtures("db")
+
+    def test_simple(self):
+        # We only want to check setup/teardown does not conflict
+        assert 1
+
+
+class TestCaseWithTrDbFixture(TestCase):
+    pytestmark = pytest.mark.usefixtures("transactional_db")
+
+    def test_simple(self):
+        # We only want to check setup/teardown does not conflict
+        assert 1
+
+
+def test_pdb_enabled(django_testdir):
+    """
+    Make sure the database is flushed and tests are isolated when
+    using the --pdb option.
+
+    See issue #405 for details:
+    https://github.com/pytest-dev/pytest-django/issues/405
+    """
+
+    django_testdir.create_test_module(
+        '''
+        import os
+
+        from django.test import TestCase
+        from django.conf import settings
+
+        from .app.models import Item
+
+        class TestPDBIsolation(TestCase):
+            def setUp(self):
+                """setUp should be called after starting a transaction"""
+                assert Item.objects.count() == 0
+                Item.objects.create(name='Some item')
+                Item.objects.create(name='Some item again')
+
+            def test_count(self):
+                self.assertEqual(Item.objects.count(), 2)
+                assert Item.objects.count() == 2
+                Item.objects.create(name='Foo')
+                self.assertEqual(Item.objects.count(), 3)
+
+            def test_count_again(self):
+                self.test_count()
+
+            def tearDown(self):
+                """tearDown should be called before rolling back the database"""
+                assert Item.objects.count() == 3
+
+    '''
+    )
+
+    result = django_testdir.runpytest_subprocess("-v", "--pdb")
+    assert result.ret == 0
+
+
+def test_debug_not_used(django_testdir):
+    django_testdir.create_test_module(
+        """
+        from django.test import TestCase
+
+        pre_setup_count = 0
+
+
+        class TestClass1(TestCase):
+
+            def debug(self):
+                assert 0, "should not be called"
+
+            def test_method(self):
+                pass
+    """
+    )
+
+    result = django_testdir.runpytest_subprocess("--pdb")
+    result.stdout.fnmatch_lines(["*= 1 passed in *"])
+    assert result.ret == 0

+ 103 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_urls.py

@@ -0,0 +1,103 @@
+import pytest
+from django.conf import settings
+from django.utils.encoding import force_str
+
+
+@pytest.mark.urls("pytest_django_test.urls_overridden")
+def test_urls():
+    try:
+        from django.urls import is_valid_path
+    except ImportError:
+        from django.core.urlresolvers import is_valid_path
+    assert settings.ROOT_URLCONF == "pytest_django_test.urls_overridden"
+    assert is_valid_path("/overridden_url/")
+
+
+@pytest.mark.urls("pytest_django_test.urls_overridden")
+def test_urls_client(client):
+    response = client.get("/overridden_url/")
+    assert force_str(response.content) == "Overridden urlconf works!"
+
+
+def test_urls_cache_is_cleared(testdir):
+    testdir.makepyfile(
+        myurls="""
+        from django.conf.urls import url
+
+        def fake_view(request):
+            pass
+
+        urlpatterns = [url(r'first/$', fake_view, name='first')]
+    """
+    )
+
+    testdir.makepyfile(
+        """
+        try:
+            from django.urls import reverse, NoReverseMatch
+        except ImportError:  # Django < 2.0
+            from django.core.urlresolvers import reverse, NoReverseMatch
+        import pytest
+
+        @pytest.mark.urls('myurls')
+        def test_something():
+            reverse('first')
+
+
+        def test_something_else():
+            with pytest.raises(NoReverseMatch):
+                reverse('first')
+
+    """
+    )
+
+    result = testdir.runpytest_subprocess()
+    assert result.ret == 0
+
+
+def test_urls_cache_is_cleared_and_new_urls_can_be_assigned(testdir):
+    testdir.makepyfile(
+        myurls="""
+        from django.conf.urls import url
+
+        def fake_view(request):
+            pass
+
+        urlpatterns = [url(r'first/$', fake_view, name='first')]
+    """
+    )
+
+    testdir.makepyfile(
+        myurls2="""
+        from django.conf.urls import url
+
+        def fake_view(request):
+            pass
+
+        urlpatterns = [url(r'second/$', fake_view, name='second')]
+    """
+    )
+
+    testdir.makepyfile(
+        """
+        try:
+            from django.urls import reverse, NoReverseMatch
+        except ImportError:  # Django < 2.0
+            from django.core.urlresolvers import reverse, NoReverseMatch
+        import pytest
+
+        @pytest.mark.urls('myurls')
+        def test_something():
+            reverse('first')
+
+        @pytest.mark.urls('myurls2')
+        def test_something_else():
+            with pytest.raises(NoReverseMatch):
+                reverse('first')
+
+            reverse('second')
+    """
+    )
+
+    result = testdir.runpytest_subprocess()
+    assert result.ret == 0

+ 117 - 0
desktop/core/ext-py/pytest-django-3.10.0/tests/test_without_django_loaded.py

@@ -0,0 +1,117 @@
+import pytest
+
+
+@pytest.fixture
+def no_ds(monkeypatch):
+    """Ensure DJANGO_SETTINGS_MODULE is unset"""
+    monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
+
+
+pytestmark = pytest.mark.usefixtures("no_ds")
+
+
+def test_no_ds(testdir):
+    testdir.makepyfile(
+        """
+        import os
+
+        def test_env():
+            assert 'DJANGO_SETTINGS_MODULE' not in os.environ
+
+        def test_cfg(pytestconfig):
+            assert pytestconfig.option.ds is None
+    """
+    )
+    r = testdir.runpytest_subprocess()
+    assert r.ret == 0
+
+
+def test_database(testdir):
+    testdir.makepyfile(
+        """
+        import pytest
+
+        @pytest.mark.django_db
+        def test_mark():
+            assert 0
+
+        @pytest.mark.django_db(transaction=True)
+        def test_mark_trans():
+            assert 0
+
+        def test_db(db):
+            assert 0
+
+        def test_transactional_db(transactional_db):
+            assert 0
+    """
+    )
+    r = testdir.runpytest_subprocess()
+    assert r.ret == 0
+    r.stdout.fnmatch_lines(["*4 skipped*"])
+
+
+def test_client(testdir):
+    testdir.makepyfile(
+        """
+        def test_client(client):
+            assert 0
+
+        def test_admin_client(admin_client):
+            assert 0
+    """
+    )
+    r = testdir.runpytest_subprocess()
+    assert r.ret == 0
+    r.stdout.fnmatch_lines(["*2 skipped*"])
+
+
+def test_rf(testdir):
+    testdir.makepyfile(
+        """
+        def test_rf(rf):
+            assert 0
+    """
+    )
+    r = testdir.runpytest_subprocess()
+    assert r.ret == 0
+    r.stdout.fnmatch_lines(["*1 skipped*"])
+
+
+def test_settings(testdir):
+    testdir.makepyfile(
+        """
+        def test_settings(settings):
+            assert 0
+    """
+    )
+    r = testdir.runpytest_subprocess()
+    assert r.ret == 0
+    r.stdout.fnmatch_lines(["*1 skipped*"])
+
+
+def test_live_server(testdir):
+    testdir.makepyfile(
+        """
+        def test_live_server(live_server):
+            assert 0
+    """
+    )
+    r = testdir.runpytest_subprocess()
+    assert r.ret == 0
+    r.stdout.fnmatch_lines(["*1 skipped*"])
+
+
+def test_urls_mark(testdir):
+    testdir.makepyfile(
+        """
+        import pytest
+
+        @pytest.mark.urls('foo.bar')
+        def test_urls():
+            assert 0
+    """
+    )
+    r = testdir.runpytest_subprocess()
+    assert r.ret == 0
+    r.stdout.fnmatch_lines(["*1 skipped*"])

+ 88 - 0
desktop/core/ext-py/pytest-django-3.10.0/tox.ini

@@ -0,0 +1,88 @@
+[tox]
+envlist =
+    py37-dj{31,30,22,21,20,111}-postgres
+    py36-dj{31,30,22,21,20,111,110,19,18}-postgres
+    py35-dj{22,21,20,111,110,19,18}-postgres
+    py34-dj{20,111,110}-postgres
+    py27-dj{111,110}-{mysql_innodb,mysql_myisam,postgres}
+    py27-dj{111,110,19,18}-postgres
+    checkqa
+
+[testenv]
+extras = testing
+deps =
+    djmaster: https://github.com/django/django/archive/master.tar.gz
+    dj31: Django>=3.1rc1,<3.2
+    dj30: Django>=3.0,<3.1
+    dj22: Django>=2.2,<2.3
+    dj21: Django>=2.1,<2.2
+    dj20: Django>=2.0,<2.1
+    dj111: Django>=1.11,<1.12
+    dj110: Django>=1.10,<1.11
+    dj19: Django>=1.9,<1.10
+    dj18: Django>=1.8,<1.9
+
+    mysql_myisam: mysqlclient==1.4.2.post1
+    mysql_innodb: mysqlclient==1.4.2.post1
+
+    postgres: psycopg2-binary
+    coverage: coverage-enable-subprocess
+
+    pytest41: pytest>=4.1,<4.2
+    pytest41: attrs==17.4.0
+    pytest53: pytest>=5.3,<5.4
+    xdist: pytest-xdist>=1.15
+
+setenv =
+    PYTHONPATH = {toxinidir}:{env:PYTHONPATH:}
+
+    mysql_innodb: DJANGO_SETTINGS_MODULE=pytest_django_test.settings_mysql_innodb
+    mysql_myisam: DJANGO_SETTINGS_MODULE=pytest_django_test.settings_mysql_myisam
+    postgres:     DJANGO_SETTINGS_MODULE=pytest_django_test.settings_postgres
+    sqlite:       DJANGO_SETTINGS_MODULE=pytest_django_test.settings_sqlite
+    sqlite_file:  DJANGO_SETTINGS_MODULE=pytest_django_test.settings_sqlite_file
+
+    coverage: PYTESTDJANGO_TEST_RUNNER=coverage run -m pytest
+    coverage: COVERAGE_PROCESS_START={toxinidir}/.coveragerc
+    coverage: COVERAGE_FILE={toxinidir}/.coverage
+    coverage: PYTESTDJANGO_COVERAGE_SRC={toxinidir}/
+
+passenv = PYTEST_ADDOPTS TERM
+usedevelop = True
+commands =
+    coverage: coverage erase
+    {env:PYTESTDJANGO_TEST_RUNNER:pytest} {posargs:tests}
+    coverage: coverage combine
+    coverage: coverage report
+    coverage: coverage xml
+
+[testenv:checkqa]
+extras =
+deps =
+    flake8
+commands =
+    flake8 --version
+    flake8 --statistics {posargs:pytest_django pytest_django_test tests}
+
+[testenv:doc8]
+extras =
+basepython = python3.6
+skip_install = true
+deps =
+    sphinx
+    doc8
+commands =
+    doc8 docs/
+
+[testenv:docs]
+deps =
+extras = docs
+commands = sphinx-build -n -W -b html -d docs/_build/doctrees docs docs/_build/html
+
+[testenv:readme]
+extras =
+basepython = python3.5
+deps =
+    readme_renderer
+commands =
+    python setup.py check -r -s