# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['django_tools',
 'django_tools.admin_tools',
 'django_tools.auto_update_cache',
 'django_tools.cache',
 'django_tools.debug',
 'django_tools.fields',
 'django_tools.file_storage',
 'django_tools.filemanager',
 'django_tools.fixture_tools',
 'django_tools.local_sync_cache',
 'django_tools.log_utils',
 'django_tools.mail',
 'django_tools.management',
 'django_tools.management.commands',
 'django_tools.middlewares',
 'django_tools.model_version_protect',
 'django_tools.model_version_protect.tests',
 'django_tools.parler_utils',
 'django_tools.playwright',
 'django_tools.selenium',
 'django_tools.serve_media_app',
 'django_tools.serve_media_app.migrations',
 'django_tools.serve_media_app.tests',
 'django_tools.serve_media_app.views',
 'django_tools.template',
 'django_tools.unittest_utils',
 'django_tools.utils',
 'django_tools.views',
 'django_tools_test_project',
 'django_tools_test_project.django_tools_test_app',
 'django_tools_test_project.django_tools_test_app.migrations',
 'django_tools_test_project.settings',
 'django_tools_test_project.tests']

package_data = \
{'': ['*'],
 'django_tools': ['templates/tagging_addon/*'],
 'django_tools.model_version_protect': ['templates/model_version_protect/*'],
 'django_tools_test_project.django_tools_test_app': ['templates/*']}

install_requires = \
['bleach', 'bx_py_utils', 'django', 'icdiff', 'pprintpp']

entry_points = \
{'console_scripts': ['dev_server = '
                     'django_tools_test_project.manage:start_test_server',
                     'django_tools_selenium = django_tools.selenium.cli:main',
                     'publish = django_tools.publish:publish',
                     'update_rst_readme = django_tools.publish:update_readme']}

setup_kwargs = {
    'name': 'django-tools',
    'version': '0.54.0rc1',
    'description': 'miscellaneous tools for Django based projects',
    'long_description': '|django-tools|\n\n.. |django-tools| image:: https://raw.githubusercontent.com/jedie/django-tools/master/logo/logo.svg\n\nMiscellaneous tools for django.\n\nLook also at the siblings project: `django-cms-tools <https://github.com/jedie/django-cms-tools>`_ (Tools/helpers around Django-CMS).\n\n+-----------------------------------+-----------------------------------------------+\n| |PyPi|                            | `https://pypi.python.org/pypi/django-tools/`_ |\n+-----------------------------------+-----------------------------------------------+\n| |Build Status on github|          | `github.com/jedie/django-tools/actions`_      |\n+-----------------------------------+-----------------------------------------------+\n| |Coverage Status on codecov.io|   | `codecov.io/gh/jedie/django-tools`_           |\n+-----------------------------------+-----------------------------------------------+\n| |Coverage Status on coveralls.io| | `coveralls.io/r/jedie/django-tools`_          |\n+-----------------------------------+-----------------------------------------------+\n\n.. |PyPi| image:: https://img.shields.io/pypi/v/django-tools?label=django-tools%20%40%20PyPi\n.. _https://pypi.python.org/pypi/django-tools/: https://pypi.python.org/pypi/django-tools/\n.. |Build Status on github| image:: https://github.com/jedie/django-tools/workflows/test/badge.svg?branch=main\n.. _github.com/jedie/django-tools/actions: https://github.com/jedie/django-tools/actions\n.. |Coverage Status on codecov.io| image:: https://codecov.io/gh/jedie/django-tools/branch/main/graph/badge.svg\n.. _codecov.io/gh/jedie/django-tools: https://codecov.io/gh/jedie/django-tools\n.. |Coverage Status on coveralls.io| image:: https://coveralls.io/repos/jedie/django-tools/badge.svg\n.. _coveralls.io/r/jedie/django-tools: https://coveralls.io/r/jedie/django-tools\n\n|Python Versions|\n|License|\n\n.. |Python Versions| image:: https://img.shields.io/pypi/pyversions/django-tools\n.. |License| image:: https://img.shields.io/pypi/l/django-tools\n\n(Logo contributed by `@reallinfo <https://github.com/reallinfo>`_ see `#16 <https://github.com/jedie/django-tools/pull/16>`_)\n\n-------\ntry-out\n-------\n\ne.g.:\n\n::\n\n    ~$ git clone https://github.com/jedie/django-tools.git\n    ~$ cd django-tools/\n    ~/django-tools$ make install\n    ~/django-tools$ make\n    help                       List all commands\n    install-poetry             install or update poetry\n    install                    install django-tools via poetry\n    update                     update the sources and installation\n    lint                       Run code formatters and linter\n    fix-code-style             Fix code formatting\n    tox-listenvs               List all tox test environments\n    tox                        Run pytest via tox with all environments\n    tox-py37                   Run pytest via tox with *python v3.7*\n    tox-py38                   Run pytest via tox with *python v3.8*\n    tox-py39                   Run pytest via tox with *python v3.9*\n    pytest                     Run pytest\n    update-test-snapshot-files Update all snapshot files (by remove and recreate all snapshot files)\n    update-rst-readme          update README.rst from README.creole\n    publish                    Release new version to PyPi\n    start-dev-server           Start Django dev. server with the test project\n    playwright-install         Install test browser for Playwright tests\n    playwright-inspector       Run Playwright inspector\n    playwright-tests           Run only the Playwright tests\n\n--------------\nexisting stuff\n--------------\n\nServe User Media File\n=====================\n\nServe ``settings.MEDIA_ROOT`` files only for allowed users.\n\nSee separate README here: `django_tools/serve_media_app <https://github.com/jedie/django-tools/tree/main/django_tools/serve_media_app>`_\n\nMode Version Protect\n====================\n\nProtect a model against overwriting a newer entry with an older one, by adding a auto increment version number.\n\nSee separate README here: `django_tools/model_version_protect <https://github.com/jedie/django-tools/tree/main/django_tools/model_version_protect>`_\n\nOverwriteFileSystemStorage\n==========================\n\nA django filesystem storage that will overwrite existing files and can create backups, if content changed.\nusage:\n\n::\n\n    class ExampleModel(models.Model):\n        foo_file = models.FileField(\n            storage=OverwriteFileSystemStorage(create_backups=True)\n        )\n        bar_image = models.ImageField(\n            storage=OverwriteFileSystemStorage(create_backups=False)\n        )\n\nBackup made by appending a suffix and sequential number, e.g.:\n\n* source....: foo.bar\n\n* backup 1..: foo.bar.bak\n\n* backup 2..: foo.bar.bak0\n\n* backup 3..: foo.bar.bak1\n\nBackup files are only made if file content changed. But at least one time!\n\nDjango Logging utils\n====================\n\nPut this into your settings, e.g.:\n\n::\n\n    from django_tools.unittest_utils.logging_utils import CutPathnameLogRecordFactory, FilterAndLogWarnings\n    \n    # Filter warnings and pipe them to logging system\n    # Warnings of external packages are displayed only once and only the file path.\n    warnings.showwarning = FilterAndLogWarnings()\n    \n    # Adds \'cut_path\' attribute on log record. So \'%(cut_path)s\' can be used in log formatter.\n    logging.setLogRecordFactory(CutPathnameLogRecordFactory(max_length=50))\n    \n    LOGGING = {\n        # ...\n        \'formatters\': {\n            \'verbose\': {\n                \'format\': \'%(levelname)8s %(cut_path)s:%(lineno)-3s %(message)s\'\n            },\n        },\n        # ...\n    }\n\n(Activate warnings by, e.g.: ``export PYTHONWARNINGS=all``)\n\nThrottledAdminEmailHandler\n--------------------------\n\n`ThrottledAdminEmailHandler <https://github.com/jedie/django-tools/blob/master/django_tools/log_utils/throttle_admin_email_handler.py>`_ works similar as the origin `django.utils.log.AdminEmailHandler <https://docs.djangoproject.com/en/1.11/topics/logging/#django.utils.log.AdminEmailHandler>`_\nbut is will throttle the number of mails that can be send in a time range.\nusage e.g.:\n\n::\n\n    LOGGING = {\n        # ...\n        "handlers": {\n            "mail_admins": {\n                "level": "ERROR",\n                "class": "django_tools.log_utils.throttle_admin_email_handler.ThrottledAdminEmailHandler",\n                "formatter": "email",\n                "min_delay_sec": 20, # << -- skip mails in this time range\n            },\n            # ...\n        },\n        # ...\n    }\n\ndjango_tools.template.loader.DebugCacheLoader\n=============================================\n\nInsert template name as html comments, e.g.:\n\n::\n\n    <!-- START \'foo/bar.html\' -->\n    ...\n    <!-- END \'foo/bar.html\' -->\n\nTo use this, you must add **django_tools.template.loader.DebugCacheLoader** as template loader.\n\ne.g.: Activate it only in DEBUG mode:\n\n::\n\n    if DEBUG:\n        TEMPLATES[0]["OPTIONS"]["loaders"] = [\n            (\n                "django_tools.template.loader.DebugCacheLoader", (\n                    \'django.template.loaders.filesystem.Loader\',\n                    \'django.template.loaders.app_directories.Loader\',\n                )\n            )\n        ]\n\nsend text+html mails\n====================\n\nA helper class to send text+html mails used the django template library.\n\nYou need two template files, e.g.:\n\n* `mail_test.txt <https://github.com/jedie/django-tools/blob/master/django_tools_test_project/django_tools_test_app/templates/mail_test.txt>`_\n\n* `mail_test.html <https://github.com/jedie/django-tools/blob/master/django_tools_test_project/django_tools_test_app/templates/mail_test.html>`_\n\nYou have to specify the template file like this: ``template_base="mail_test.{ext}"``\n\nSend via Celery task:\n\n::\n\n    # settings.py\n    SEND_MAIL_CELERY_TASK_NAME="mail:send_task"\n    \n    from django_tools.mail.send_mail import SendMailCelery\n    SendMailCelery(\n        template_base="mail_test.{ext}",\n        mail_context={"foo": "first", "bar": "second"},\n        subject="Only a test",\n        recipient_list="foo@bar.tld"\n    ).send()\n\nSend without Celery:\n\n::\n\n    from django_tools.mail.send_mail import SendMail\n    SendMail(\n        template_base="mail_test.{ext}",\n        mail_context={"foo": "first", "bar": "second"},\n        subject="Only a test",\n        recipient_list="foo@bar.tld"\n    ).send()\n\nSee also the existing unittests:\n\n* `django_tools_tests/test_email.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_email.py>`_\n\nDelay tools\n===========\n\nSometimes you want to simulate when processing takes a little longer.\nThere exists ``django_tools.debug.delay.SessionDelay`` and ``django_tools.debug.delay.CacheDelay`` for this.\nThe usage will create logging entries and user messages, if user is authenticated.\n\nMore info in seperate `django_tools/debug/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/debug/README.creole>`_ file.\n\nFilemanager library\n===================\n\nLibrary for building django application like filemanager, gallery etc.\n\nmore info, read `./filemanager/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/filemanager/README.creole>`_\n\nper-site cache middleware\n=========================\n\nSimilar to `django UpdateCacheMiddleware and FetchFromCacheMiddleware <https://docs.djangoproject.com/en/1.4/topics/cache/#the-per-site-cache>`_,\nbut has some enhancements: `\'per site cache\' in ./cache/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/cache/README.creole#per-site-cache-middleware>`_\n\nsmooth cache backends\n=====================\n\nSame as django cache backends, but adds ``cache.smooth_update()`` to clears the cache smoothly depend on the current system load.\nmore info in: `\'smooth cache backends\' in ./cache/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/cache/README.creole#smooth-cache-backends>`_\n\nlocal sync cache\n================\n\nKeep a local dict in a multi-threaded environment up-to-date. Usefull for cache dicts.\nMore info, read DocString in `./local_sync_cache/local_sync_cache.py <https://github.com/jedie/django-tools/blob/master/django_tools/local_sync_cache/local_sync_cache.py>`_.\n\nthreadlocals middleware\n=======================\n\nFor getting request object anywhere, use `./middlewares/ThreadLocal.py <https://github.com/jedie/django-tools/blob/master/django_tools/middlewares/ThreadLocal.py>`_\n\nDynamic SITE_ID middleware\n==========================\n\nNote: Currently not maintained! TODO: Fix unittests for all python/django version\n\nSet settings.SITE_ID dynamically with a middleware base on the current request domain name.\nDomain name alias can be specify as a simple string or as a regular expression.\n\nmore info, read `./dynamic_site/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/dynamic_site/README.creole>`_.\n\nStackInfoStorage\n================\n\nMessage storage like LegacyFallbackStorage, except, every message would have a stack info, witch is helpful, for debugging.\nStack info would only be added, if settings DEBUG or MESSAGE_DEBUG is on.\nTo use it, put this into your settings:\n\n::\n\n    MESSAGE_STORAGE = "django_tools.utils.messages.StackInfoStorage"\n\nMore info, read DocString in `./utils/messages.py <https://github.com/jedie/django-tools/blob/master/django_tools/utils/messages.py>`_.\n\nlimit to usergroups\n===================\n\nLimit something with only one field, by selecting:\n\n* anonymous users\n\n* staff users\n\n* superusers\n\n* ..all existing user groups..\n\nMore info, read DocString in `./limit_to_usergroups.py <https://github.com/jedie/django-tools/blob/master/django_tools/limit_to_usergroups.py>`_\n\npermission helpers\n==================\n\nSee `django_tools.permissions <https://github.com/jedie/django-tools/blob/master/django_tools/permissions.py>`_\nand unittests: `django_tools_tests.test_permissions <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_permissions.py>`_\n\nform/model fields\n=================\n\n* `Directory field <https://github.com/jedie/django-tools/blob/master/django_tools/fields/directory.py>`_ - check if exist and if in a defined base path\n\n* `language code field with validator <https://github.com/jedie/django-tools/blob/master/django_tools/fields/language_code.py>`_\n\n* `Media Path field <https://github.com/jedie/django-tools/blob/master/django_tools/fields/media_path.py>`_ browse existign path to select and validate input\n\n* `sign seperated form/model field <https://github.com/jedie/django-tools/blob/master/django_tools/fields/sign_separated.py>`_ e.g. comma seperated field\n\n* `static path field <https://github.com/jedie/django-tools/blob/master/django_tools/fields/static_path.py>`_\n\n* `url field <https://github.com/jedie/django-tools/blob/master/django_tools/fields/url.py>`_ A flexible version of the original django form URLField\n\n-----------------\nunittests helpers\n-----------------\n\nSelenium Test Cases\n===================\n\nThere are Firefox and Chromium test cases, with and without django StaticLiveServerTestCase!\n\nChromium + StaticLiveServer example:\n\n::\n\n    from django_tools.selenium.chromedriver import chromium_available\n    from django_tools.selenium.django import SeleniumChromiumStaticLiveServerTestCase\n    \n    @unittest.skipUnless(chromium_available(), "Skip because Chromium is not available!")\n    class ExampleChromiumTests(SeleniumChromiumStaticLiveServerTestCase):\n        def test_admin_login_page(self):\n            self.driver.get(self.live_server_url + "/admin/login/")\n            self.assert_equal_page_title("Log in | Django site admin")\n            self.assert_in_page_source(\'<form action="/admin/login/" method="post" id="login-form">\')\n            self.assert_no_javascript_alert()\n\nFirefox + StaticLiveServer example:\n\n::\n\n    from django_tools.selenium.django import SeleniumFirefoxStaticLiveServerTestCase\n    from django_tools.selenium.geckodriver import firefox_available\n    \n    @unittest.skipUnless(firefox_available(), "Skip because Firefox is not available!")\n    class ExampleFirefoxTests(SeleniumFirefoxStaticLiveServerTestCase):\n        def test_admin_login_page(self):\n            self.driver.get(self.live_server_url + "/admin/login/")\n            self.assert_equal_page_title("Log in | Django site admin")\n            self.assert_in_page_source(\'<form action="/admin/login/" method="post" id="login-form">\')\n            self.assert_no_javascript_alert()\n\nTest cases without StaticLiveServer:\n\n::\n\n    from django_tools.selenium.chromedriver import SeleniumChromiumTestCase\n    from django_tools.selenium.geckodriver import SeleniumFirefoxTestCase\n\nSee also existing unitests here:\n\n* `/django_tools/django_tools_tests/test_unittest_selenium.py <https://github.com/jedie/django-tools/blob/master/django_tools/django_tools_tests/test_unittest_selenium.py>`_\n\nSetup Web Drivers\n-----------------\n\nSelenium test cases needs the browser and the web driver.\n\n``SeleniumChromiumTestCase`` and ``SeleniumFirefoxTestCase`` will automaticly install the web driver via `webdriver-manager <https://github.com/SergeyPirogov/webdriver_manager>`_\n\nThere is a small CLI (called ``django_tools_selenium``) to check / install the web drivers, e.g.:\n\n::\n\n    ~/django-tools$ poetry run django_tools_selenium install\n    ~/django-tools$ poetry run django_tools_selenium info\n\nMockup utils\n============\n\nCreate dummy PIL/django-filer images with Text, see:\n\n* `/django_tools/unittest_utils/mockup.py <https://github.com/jedie/django-tools/blob/master/django_tools/unittest_utils/mockup.py>`_\n\nusage/tests:\n\n* `/django_tools_tests/test_mockup.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_mockup.py>`_\n\nModel instance unittest code generator\n======================================\n\nGenerate unittest code skeletons from existing model instance. You can use this feature as django manage command or as admin action.\n\nUsage as management command, e.g.:\n\n::\n\n    $ ./manage.py generate_model_test_code auth.\n    ...\n    #\n    # pk:1 from auth.User <class \'django.contrib.auth.models.User\'>\n    #\n    user = User.objects.create(\n        password=\'pbkdf2_sha256$36000$ybRfVQDOPQ9F$jwmgc5UsqRQSXxJs/NrZeTLguieUSSZfaSZbMmC+L5w=\', # CharField, String (up to 128)\n        last_login=datetime.datetime(2018, 4, 24, 8, 27, 49, 578107, tzinfo=<UTC>), # DateTimeField, Date (with time)\n        is_superuser=True, # BooleanField, Boolean (Either True or False)\n        username=\'test\', # CharField, String (up to 150)\n        first_name=\'\', # CharField, String (up to 30)\n        last_name=\'\', # CharField, String (up to 30)\n        email=\'\', # CharField, Email address\n        is_staff=True, # BooleanField, Boolean (Either True or False)\n        is_active=True, # BooleanField, Boolean (Either True or False)\n        date_joined=datetime.datetime(2018, 3, 6, 17, 15, 50, 93136, tzinfo=<UTC>), # DateTimeField, Date (with time)\n    )\n    ...\n\ncreate users\n============\n\n`/unittest_utils/user.py <https://github.com/jedie/django-tools/blob/master/django_tools/unittest_utils/user.py>`_:\n\n* ``django_tools.unittest_utils.user.create_user()`` - create users, get_super_user\n\n* ``django_tools.unittest_utils.user.get_super_user()`` - get the first existing superuser\n\nIsolated Filesystem decorator / context manager\n===============================================\n\n`django_tools.unittest_utils.isolated_filesystem.isolated_filesystem <https://github.com/jedie/django-tools/blob/master/django_tools/unittest_utils/isolated_filesystem.py>`_ acts as either a decorator or a context manager.\nUseful to for tests that will create files/directories in current work dir, it does this:\n\n* create a new temp directory\n\n* change the current working directory to the temp directory\n\n* after exit:\n\n* Delete an entire temp directory tree\n\nusage e.g.:\n\n::\n\n    from django_tools.unittest_utils.isolated_filesystem import isolated_filesystem\n    \n    with isolated_filesystem(prefix="temp_dir_prefix"):\n        open("foo.txt", "w").write("bar")\n\nBaseUnittestCase\n================\n\n**django_tools.unittest_utils.unittest_base.BaseUnittestCase** contains some low-level assert methods:\n\n* assertEqual_dedent()\n\nNote: assert methods will be migrated to: ``django_tools.unittest_utils.assertments`` in the future!\n\n*django_tools.unittest_utils.tempdir* contains **TempDir**, a Context Manager Class:\n\n::\n\n    with TempDir(prefix="foo_") as tempfolder:\n        # create a file:\n        open(os.path.join(tempfolder, "bar"), "w").close()\n    \n    # the created temp folder was deleted with shutil.rmtree()\n\nusage/tests:\n\n* `/django_tools_tests/test_unittest_utils.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_unittest_utils.py>`_\n\nDjangoCommandMixin\n==================\n\nHelper to run shell commands. e.g.: "./manage.py cms check" in unittests.\n\nusage/tests:\n\n* `/django_tools_tests/test_unittest_django_command.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_unittest_django_command.py>`_\n\nDOM compare in unittests\n========================\n\nThe Problem:\nYou can’t easy check if e.g. some form input fields are in the response,\nbecause the form rendering use a dict for storing all html attributes.\nSo, the ordering of form field attributes are not sorted and varied.\n\nThe Solution:\nYou need to parse the response content into a DOM tree and compare nodes.\n\nWe add the great work of Gregor Müllegger at his GSoC 2011 form-rendering branch.\nYou will have the following assert methods inherit from: django_tools.unittest_utils.unittest_base.BaseTestCase\n\n* self.assertHTMLEqual() – for compare two HTML DOM trees\n\n* self.assertDOM() – for check if nodes in response or not.\n\n* self.assertContains() – Check if ond node occurs \'count’ times in response\n\nMore info and examples in `./django_tools_tests/test_dom_asserts.py <https://github.com/jedie/django-tools/blob/master/django_tools/django_tools_tests/test_dom_asserts.py>`_\n\n@set_string_if_invalid() decorator\n==================================\n\nHelper to check if there are missing template tags by set temporary ``\'string_if_invalid\'``, see: `https://docs.djangoproject.com/en/1.8/ref/templates/api/#invalid-template-variables <https://docs.djangoproject.com/en/1.8/ref/templates/api/#invalid-template-variables>`_\n\nUsage, e.g.:\n\n::\n\n    from django.test import SimpleTestCase\n    from django_tools.unittest_utils.template import TEMPLATE_INVALID_PREFIX, set_string_if_invalid\n    \n    @set_string_if_invalid()\n    class TestMyTemplate(SimpleTestCase):\n        def test_valid_tag(self):\n            response = self.client.get(\'/foo/bar/\')\n            self.assertNotIn(TEMPLATE_INVALID_PREFIX, response.content)\n\nYou can also decorate the test method ;)\n\nunittest_utils/signals.py\n=========================\n\n* ``SignalsContextManager`` connect/disconnet signal callbacks via with statement\n\nunittest_utils/assertments.py\n=============================\n\nThe file contains some common assert functions:\n\n* ``assert_startswith`` - Check if test starts with prefix.\n\n* ``assert_endswith`` - Check if text ends with suffix.\n\n* ``assert_locmem_mail_backend`` - Check if current email backend is the In-memory backend.\n\n* {{{assert_language_code() - Check if given language_code is in settings.LANGUAGES\n\n* ``assert_installed_apps()`` - Check entries in settings.INSTALLED_APPS\n\n* ``assert_is_dir`` - Check if given path is a directory\n\n* ``assert_is_file`` - Check if given path is a file\n\n* ``assert_path_not_exists`` - Check if given path doesn\'t exists\n\nSpeedup tests\n=============\n\nSpeedup test run start by disable migrations, e.g.:\n\n::\n\n    from django_tools.unittest_utils.disable_migrations import DisableMigrations\n    MIGRATION_MODULES = DisableMigrations()\n\nsmall tools\n===========\n\ndebug_csrf_failure()\n--------------------\n\nDisplay the normal debug page and not the minimal csrf debug page.\nMore info in DocString here: `django_tools/views/csrf.py <https://github.com/jedie/django-tools/blob/master/django_tools/views/csrf.py>`_\n\nimport lib helper\n-----------------\n\nadditional helper to the existing ``importlib``\nmore info in the sourcecode: `./utils/importlib.py <https://github.com/jedie/django-tools/blob/master/django_tools/utils/importlib.py>`_\n\nhttp utils\n----------\n\nPimped HttpRequest to get some more information about a request.\nMore info in DocString here: `django_tools/utils/http.py <https://github.com/jedie/django-tools/blob/master/django_tools/utils/http.py>`_\n\n@display_admin_error\n--------------------\n\nDeveloper helper to display silent errors in ModelAdmin.list_display callables.\nSee: **display_admin_error** in `decorators.py <https://github.com/jedie/django-tools/blob/master/django_tools/decorators.py>`_\n\nupgrade virtualenv\n==================\n\nA simple commandline script that calls ``pip install —-upgrade XY`` for every package thats installed in a virtualenv.\nSimply copy/symlink it into the root directory of your virtualenv and start it.\n\n**Note:** `Seems that this solution can\'t observe editables right. <https://github.com/pypa/pip/issues/319>`_\n\nTo use it, without installing django-tools:\n\n::\n\n    ~/$ cd goto/your_env\n    .../your_env/$ wget https://github.com/jedie/django-tools/raw/master/django_tools/upgrade_virtualenv.py\n    .../your_env/$ chmod +x upgrade_virtualenv.py\n    .../your_env/$ ./upgrade_virtualenv.py\n\nThis script will be obsolete, if `pip has a own upgrade command <https://github.com/pypa/pip/issues/59>`_.\n\ndjango_tools.utils.url.GetDict\n==============================\n\nSimilar to origin django.http.QueryDict but:\n\n* urlencode() doesn\'t add "=" to empty values: "?empty" instead of "?empty="\n\n* always mutable\n\n* output will be sorted (easier for tests ;)\n\nMore info, see tests: `django_tools_tests/test_utils_url.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_utils_url.py>`_\n\nSignedCookieStorage\n-------------------\n\nStore information in signed Cookies, use **django.core.signing**.\nSo the cookie data can\'t be manipulated from the client.\nSources/examples:\n\n* `/django_tools/utils/client_storage.py <https://github.com/jedie/django-tools/blob/master/django_tools/utils/client_storage.py>`_\n\n* `/django_tools_tests/test_signed_cookie.py <https://github.com/jedie/django-tools/blob/master/django_tools_tests/test_signed_cookie.py>`_\n\nPrint SQL Queries\n=================\n\nPrint the used SQL queries via context manager.\n\nusage e.g.:\n\n::\n\n    from django_tools.unittest_utils.print_sql import PrintQueries\n    \n    # e.g. use in unittests:\n    class MyTests(TestCase):\n        def test_foobar(self):\n            with PrintQueries("Create object"):\n                FooBar.objects.create("name"=foo)\n    \n    # e.g. use in views:\n    def my_view(request):\n        with PrintQueries("Create object"):\n            FooBar.objects.create("name"=foo)\n\nthe output is like:\n\n::\n\n    _______________________________________________________________________________\n     *** Create object ***\n    1 - INSERT INTO "foobar" ("name")\n        VALUES (foo)\n    -------------------------------------------------------------------------------\n\nSetRequestDebugMiddleware\n=========================\n\nmiddleware to add debug bool attribute to request object.\nMore info: `./debug/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/debug/README.creole>`_\n\nTracebackLogMiddleware\n======================\n\nPut traceback in log by call `logging.exception() <https://docs.python.org/3/library/logging.html#logging.Logger.exception>`_ on ``process_exception()``\nActivate with:\n\n::\n\n    MIDDLEWARE_CLASSES = (\n        ...\n        \'django_tools.middlewares.TracebackLogMiddleware.TracebackLogMiddleware\',\n        ...\n    )\n\nFnMatchIps() - Unix shell-style wildcards in INTERNAL_IPS / ALLOWED_HOSTS\n=========================================================================\n\nsettings.py e.g.:\n\n::\n\n    from django_tools.settings_utils import FnMatchIps\n    \n    INTERNAL_IPS = FnMatchIps(["127.0.0.1", "::1", "192.168.*.*", "10.0.*.*"])\n    ALLOWED_HOSTS = FnMatchIps(["127.0.0.1", "::1", "192.168.*.*", "10.0.*.*"])\n\nStdoutStderrBuffer()\n====================\n\nredirect stdout + stderr to a string buffer. e.g.:\n\n::\n\n    from django_tools.unittest_utils.stdout_redirect import StdoutStderrBuffer\n    \n    with StdoutStderrBuffer() as buffer:\n        print("foo")\n    output = buffer.get_output() # contains "foo\\n"\n\nManagement commands\n===================\n\npermission_info\n---------------\n\nList all permissions for one django user.\n(Needs ``\'django_tools\'`` in INSTALLED_APPS)\n\ne.g.:\n\n::\n\n    $ ./manage.py permission_info\n    No username given!\n    \n    All existing users are:\n    foo, bar, john, doe\n    \n    $ ./manage.py permission_info foo\n    All permissions for user \'test_editor\':\n    \tis_active    : yes\n    \tis_staff     : yes\n    \tis_superuser : no\n    [*] admin.add_logentry\n    [*] admin.change_logentry\n    [*] admin.delete_logentry\n    [ ] auth.add_group\n    [ ] auth.add_permission\n    [ ] auth.add_user\n    ...\n\nlogging_info\n------------\n\nShows a list of all loggers and marks which ones are configured in settings.LOGGING:\n\n::\n\n    $ ./manage.py logging_info\n\nnice_diffsettings\n-----------------\n\nSimilar to django \'diffsettings\', but used pretty-printed representation:\n\n::\n\n    $ ./manage.py nice_diffsettings\n\ndatabase_info\n-------------\n\nJust display some information about the used database and connections:\n\n::\n\n    $ ./manage.py database_info\n\nlist_models\n-----------\n\nJust list all existing models in app_label.ModelName format. Useful to use this in \'dumpdata\' etc:\n\n::\n\n    $ ./manage.py list_models\n\n..all others…\n=============\n\nThere exist many miscellaneous stuff. Look in the source, luke!\n\n------------------------------\nBackwards-incompatible changes\n------------------------------\n\nOld changes archived in git history here:\n\n* `>=v0.47 <https://github.com/jedie/django-tools/tree/v0.49.0#backwards-incompatible-changes>`_\n\n* `>=v0.35 <https://github.com/jedie/django-tools/tree/v0.35.0#backwards-incompatible-changes>`_\n\nv0.51\n=====\n\nAll Selenium helper are deprecated, please migrate to `Playwright <https://playwright.dev/python/>`_ ;)\n\nv0.50\n=====\n\nRemoved old selenium helper function, `deprecated since v0.43 <https://github.com/jedie/django-tools/tree/v0.43.0#v043>`_\n\nMake all Selenium web driver instances persistent for the complete test run session.\nThis speedup tests and fixed some bugs in Selenium.\n\nThis result in the same browser/webdriver settings for all test classes!\n\n--------------------\nDjango compatibility\n--------------------\n\n+------------------+----------------+-----------------+\n| django-tools     | django version | python          |\n+==================+================+=================+\n| >= v0.52.0       | 3.2, 4.0, 4.1  | 3.8, 3.9, 3.10  |\n+------------------+----------------+-----------------+\n| >= v0.50.0       | 2.2, 3.2, 4.0  | 3.8, 3.9, 3.10  |\n+------------------+----------------+-----------------+\n| >= v0.49.0       | 2.2, 3.1, 3.2  | 3.7, 3.8, 3.9   |\n+------------------+----------------+-----------------+\n| >= v0.47.0       | 2.2, 3.0, 3.1  | >= 3.6, pypy3   |\n+------------------+----------------+-----------------+\n| >= v0.39         | 1.11, 2.0      | 3.5, 3.6, pypy3 |\n+------------------+----------------+-----------------+\n| >= v0.38.1       | 1.8, 1.11      | 3.5, 3.6, pypy3 |\n+------------------+----------------+-----------------+\n| >= v0.38.0       | 1.8, 1.11      | 3.5, 3.6        |\n+------------------+----------------+-----------------+\n| >= v0.37.0       | 1.8, 1.11      | 3.4, 3.5        |\n+------------------+----------------+-----------------+\n| >= v0.33.0       | 1.8, 1.11      | 2.7, 3.4, 3.5   |\n+------------------+----------------+-----------------+\n| v0.30.1-v0.32.14 | 1.8, 1.9, 1.10 | 2.7, 3.4, 3.5   |\n+------------------+----------------+-----------------+\n| v0.30            | 1.8, 1.9       | 2.7, 3.4        |\n+------------------+----------------+-----------------+\n| v0.29            | 1.6 - 1.8      | 2.7, 3.4        |\n+------------------+----------------+-----------------+\n| v0.26            | <=1.6          |                 |\n+------------------+----------------+-----------------+\n| v0.25            | <=1.4          |                 |\n+------------------+----------------+-----------------+\n\n(See also combinations for `tox in pyproject.toml <https://github.com/jedie/django-tools/blob/master/pyproject.toml>`_)\n\n-------\nhistory\n-------\n\n* *dev* - `compare v0.54.0rc1...main <https://github.com/jedie/django-tools/compare/v0.54.0rc1...main>`_ \n\n    * TBC\n\n* `v0.54.0rc1 - 25.08.2022 <https://github.com/jedie/django-tools/compare/v0.53.0...v0.54.0rc1>`_ \n\n    * NEW: ``SyslogHandler`` for easy logging to ``syslog``\n\n* `v0.53.0 - 18.08.2022 <https://github.com/jedie/django-tools/compare/v0.52.0...v0.53.0>`_ \n\n    * NEW: ``MassContextManagerBase``, ``DenyStdWrite`` + Updated: ``StdoutStderrBuffer``\n\n    * Enhance ``run_testserver`` command\n\n    * Small test project setup updates\n\n* `v0.52.0 - 17.08.2022 <https://github.com/jedie/django-tools/compare/v0.51.0...v0.52.0>`_ \n\n    * Move ``run_testserver`` management command from ``django_tools_test_app`` to ``django_tools`` and polish it.\n\n    * Restrict `AlwaysLoggedInAsSuperUserMiddleware` to the admin.\n\n    * Test with Django 3.2, 4.0 and 4.1\n\n* `v0.51.0 - 26.07.2022 <https://github.com/jedie/django-tools/compare/v0.50.0...v0.51.0>`_ \n\n    * NEW: ``check_editor_config()`` to check editor config and line length in projects\n\n    * DEPRECATE all Selenium helper, please migrate to Playwright ;)\n\n    * NEW: `Playwright`_ base Unittest class and login helper\n\n* `v0.50.0 - 29.05.2022 <https://github.com/jedie/django-tools/compare/v0.49.0...v0.50.0>`_ \n\n    * Rename git "master" branch to "main"\n\n    * Use `webdriver-manager`_ to setup selenium web drivers\n\n    * CHANGE: Now all web driver instances are cached and reused for the complete test run!\n\n    * Use `darker <https://github.com/akaihola/darker>`_ for code formatting\n\n    * Update test matrix: Add Python 3.10 and Django v4.0 (remove Python 3.7 and Django 3.1)\n\n* v0.49.0 - 22.11.2021 - `compare v0.48.3...v0.49.0 <https://github.com/jedie/django-tools/compare/v0.48.3...v0.49.0>`_ \n\n    * NEW: ``VersionProtectBaseModel`` - Protect a model against overwriting a newer entry with an older one, by adding a auto increment version number.\n\n    * NEW: ``AlwaysLoggedInAsSuperUserMiddleware`` useful for local dev server run to auto login into Django Admin\n\n    * Enhance Selenium test helpers and `fix #21: Set chrome accept_languages in headless mode <https://github.com/jedie/django-tools/issues/21>`_\n\n    * Update project: Tests, code-style etc.\n\n* v0.48.3 - 20.12.2020 - `compare v0.47.2...v0.48.3 <https://github.com/jedie/django-tools/compare/v0.47.2...v0.48.3>`_ \n\n    * NEW: ``ImageDummy().in_memory_image_file()`` useful for e.g.: POST a image upload via Django\'s test client\n\n* v0.48.2 - 06.12.2020 - `compare v0.47.1...v0.48.2 <https://github.com/jedie/django-tools/compare/v0.47.1...v0.48.2>`_ \n\n    * Bugfix "Serve User Media File": Create tokens via migrations and handle if tokens not exists\n\n* v0.48.1 - 06.12.2020 - `compare v0.47.0...v0.48.1 <https://github.com/jedie/django-tools/compare/v0.47.0...v0.48.1>`_ \n\n    * Add migration file to "Serve User Media File"\n\n* v0.48.0 - 06.12.2020 - `compare v0.47.0...v0.48.0 <https://github.com/jedie/django-tools/compare/v0.47.0...v0.48.0>`_ \n\n    * NEW: "Serve User Media File" reuseable app\n\n    * NEW: django_tools.unittest_utils.signals.SignalsContextManager\n\n    * Update ``installed_apps_utils.get_filtered_apps()`` and support app config entries in ``settings.INSTALLED_APPS``\n\n* v0.47.0 - 26.11.2020 - `compare v0.46.1...v0.47.0 <https://github.com/jedie/django-tools/compare/v0.46.1...v0.47.0>`_ \n\n    * updates for newer django versions\n\n    * NEW: assert_warnings(), assert_no_warnings() and assert_in_logs()\n\n    * remove broken LoggingBuffer()\n\n    * update project setup, fix tests and pipelines\n\n* v0.46.1 - 19.02.2020 - `compare v0.46.0...v0.46.1 <https://github.com/jedie/django-tools/compare/v0.46.0...v0.46.1>`_ \n\n    * less restricted dependency specification\n\n    * NEW: ``"django_tools.middlewares.LogHeaders.LogRequestHeadersMiddleware"``\n\n    * SeleniumChromiumTestCase: set "accept_languages" and disable "headless" mode, see also: `https://github.com/jedie/django-tools/issues/21 <https://github.com/jedie/django-tools/issues/21>`_\n\n* v0.46.0 - 13.02.2020 - `compare v0.45.3...v0.46.0 <https://github.com/jedie/django-tools/compare/v0.45.3...v0.46.0>`_ \n\n    * ``dynamic_site`` was removed. Please use e.g.: `django-hosts <https://github.com/jazzband/django-hosts>`_\n\n    * modernize project setup and use ``poetry``\n\n    * remove ``lxml`` decency by using `bleach <https://github.com/mozilla/bleach>`_ for ``html_utils.html2text``\n\n    * update code and code style\n\n* v0.45.3 - 25.08.2019 - `compare v0.45.2...v0.45.3 <https://github.com/jedie/django-tools/compare/v0.45.2...v0.45.3>`_ \n\n    * Add ``excepted_exit_code`` to ``django_tools.unittest_utils.django_command.DjangoCommandMixin`` to it\'s possible to test errors in manage commands\n\n* v0.45.2 - 26.06.2019 - `compare v0.45.1...v0.45.2 <https://github.com/jedie/django-tools/compare/v0.45.1...v0.45.2>`_ \n\n    * NEW: ``django_tools.log_utils.throttle_admin_email_handler.ThrottledAdminEmailHandler``\n\n* v0.45.1 - 03.04.2019 - `compare v0.45.0...v0.45.1 <https://github.com/jedie/django-tools/compare/v0.45.0...v0.45.1>`_ \n\n    * Bugfix ValueError in ``django_tools.unittest_utils.email.print_mailbox``\n\n* v0.45.0 - 01.04.2019 - `compare v0.44.2...v0.45.0 <https://github.com/jedie/django-tools/compare/v0.44.2...v0.45.0>`_ \n\n    * NEW: ``OverwriteFileSystemStorage`` with backup functionality\n\n    * NEW: ``print_exc_plus()`` - traceback with a listing of all the local variables\n\n    * NEW: ``assert_pformat_equal`` with ``pprintpp`` and ``icdiff``\n\n    * NEW: ``assert_filenames_and_content``\n\n* v0.44.2 - 02.01.2019 - `compare v0.44.1...v0.44.2 <https://github.com/jedie/django-tools/compare/v0.44.1...v0.44.2>`_ \n\n    * Handle errors like: `https://github.com/andymccurdy/redis-py/issues/995 <https://github.com/andymccurdy/redis-py/issues/995>`_\n\n* v0.44.1 - 02.01.2019 - `compare v0.44.0...v0.44.1 <https://github.com/jedie/django-tools/compare/v0.44.0...v0.44.1>`_ \n\n    * ``LoggingBuffer``: Don\'t deactivate existing log handler, just append the buffer handler.\n\n* v0.44.0 - 13.12.2018 - `compare v0.43.2...v0.44.0 <https://github.com/jedie/django-tools/compare/v0.43.2...v0.44.0>`_ \n\n    * NEW: ``django_file = ImageDummy().create_django_file_info_image(text="")`` e.g.: for attach to ``models.ImageField()``\n\n    * Make ``mockup.ImageDummy()`` usable even if django-filer is not installed.\n\n    * ``mockup.ImageDummy()`` default image format changed from png to jpeg\n\n    * Cleanup: remove old, since v0.35 deprecated mockup image API\n\n* v0.43.2 - 11.12.2018 - `compare v0.43.1...v0.43.2 <https://github.com/jedie/django-tools/compare/v0.43.1...v0.43.2>`_ \n\n    * Bugfix Selenium refactor: Use the class with the same functionality if old usage places are used.\n\n* v0.43.1 - 11.12.2018 - `compare v0.43.0...v0.43.1 <https://github.com/jedie/django-tools/compare/v0.43.0...v0.43.1>`_ \n\n    * Bugfix: Selenium test cases: clear ``window.localStorage`` after test run\n\n* v0.43.0 - 11.12.2018 - `compare v0.42.4...v0.43.0 <https://github.com/jedie/django-tools/compare/v0.42.4...v0.43.0>`_ \n\n    * Refactor selenium helpers\n\n    * Split selenium test cases: with and without Django StaticLiveServerTestCase\n\n    * NEW: Selenium helper to access ``window.localStorage`` \n\n* v0.42.4 - 12.10.2018 - `compare v0.42.3...v0.42.4 <https://github.com/jedie/django-tools/compare/v0.42.3...v0.42.4>`_ \n\n    * Add ``request`` object to ``TestUserMixin.login()`` (needed for e.g.: django-axes auth backend)\n\n* v0.42.3 - 10.10.2018 - `compare v0.42.2...v0.42.3 <https://github.com/jedie/django-tools/compare/v0.42.2...v0.42.3>`_ \n\n    * NEW: * ``assertments.assert_is_dir``, ``assertments.assert_is_file``, ``assertments.assert_path_not_exists``\n\n* v0.42.2 - 18.09.2018 - `compare v0.42.1...v0.42.2 <https://github.com/jedie/django-tools/compare/v0.42.1...v0.42.2>`_ \n\n    * NEW: ``assert_installed_apps()`` - Check entries in settings.INSTALLED_APPS\n\n* v0.42.1 - 17.09.2018 - `compare v0.42.0...v0.42.1 <https://github.com/jedie/django-tools/compare/v0.42.0...v0.42.1>`_ \n\n    * NEW: ``django_tools.unittest_utils.assertments.assert_language_code`` - Check if given language_code is in settings.LANGUAGES\n\n* v0.42.0 - 07.09.2018 - `compare v0.41.0...v0.42.0 <https://github.com/jedie/django-tools/compare/v0.41.0...v0.42.0>`_ \n\n    * remove all celery stuff\n\n    * NEW: ``$ ./manage.py logging_info`` Shows a list of all loggers and marks which ones are configured in settings.LOGGING\n\n    * manage commands ``list_models`` and ``nice_diffsettings`` are moved from seperate apps\n\n* v0.41.0 - 28.08.2018 - `compare v0.40.6...v0.41.0 <https://github.com/jedie/django-tools/compare/v0.40.6...v0.41.0>`_ \n\n    * NEW: ``unittest_utils/assertments.py`` with some common assert functions\n\n    * Remove ``@task_always_eager()`` decorator\n\n* v0.40.6 - 28.08.2018 - `compare v0.40.5...v0.40.6 <https://github.com/jedie/django-tools/compare/v0.40.5...v0.40.6>`_ \n\n    * Bugfix ``@task_always_eager()`` decorator\n\n* v0.40.5 - 27.08.2018 - `compare v0.40.4...v0.40.5 <https://github.com/jedie/django-tools/compare/v0.40.4...v0.40.5>`_ \n\n    * Bugfix ``DjangoCommandMixin.call_manage_py()``: Use the given ``manage.py`` filename\n\n* v0.40.4 - 21.08.2018 - `compare v0.40.3...v0.40.4 <https://github.com/jedie/django-tools/compare/v0.40.3...v0.40.4>`_ \n\n    * NEW: ``django_tools.debug.delay`` to simulate longer processing time by set a delay via GET parameter (see above)\n\n* v0.40.3 - 18.07.2018 - `compare v0.40.2...v0.40.3 <https://github.com/jedie/django-tools/compare/v0.40.2...v0.40.3>`_ \n\n    * Enhance selenium test cases:\n\n        * NEW: ``assert_visible_by_id()``\n\n        * NEW: ``assert_clickable_by_id()``\n\n        * NEW: ``assert_clickable_by_xpath()``\n\n        * add ``desired_capabilities`` to firefox and chrome test cases\n\n        * enable logging in chrome test case\n\n        * NEW: ``assert_in_browser_log()`` in chrome test case\n\n* v0.40.2 - 04.07.2018 - `compare v0.40.1...v0.40.2 <https://github.com/jedie/django-tools/compare/v0.40.1...v0.40.2>`_ \n\n    * Bugfix selenium Test Case if driver is None\n\n    * Bugfix django compatibility\n\n* v0.40.1 - 28.06.2018 - `compare v0.40.0...v0.40.1 <https://github.com/jedie/django-tools/compare/v0.40.0...v0.40.1>`_ \n\n    * Bugfix selenium test case if executable can\'t be found.\n\n* v0.40.0 - 15.06.2018 - `compare v0.39.6...v0.40.0 <https://github.com/jedie/django-tools/compare/v0.39.6...v0.40.0>`_ \n\n    * NEW: selenium chrome and firefox test cases in ``django_tools.unittest_utils.selenium_utils``\n\n    * Fix test project and add ``run_test_project_dev_server.sh`` for easy test\n\n    * Fixing tests\n\n* v0.39.6 - 04.05.2018 - `compare v0.39.5...v0.39.6 <https://github.com/jedie/django-tools/compare/v0.39.5...v0.39.6>`_ \n\n    * Enhance model instance unittest code generator\n\n* v0.39.5 - 24.04.2018 - `compare v0.39.4...v0.39.5 <https://github.com/jedie/django-tools/compare/v0.39.4...v0.39.5>`_ \n\n    * NEW: Model instance unittest code generator (see above)\n\n* v0.39.4 - 06.04.2018 - `compare v0.39.3...v0.39.4 <https://github.com/jedie/django-tools/compare/v0.39.3...v0.39.4>`_ \n\n    * NEW: ``django_tools.unittest_utils.logging_utils.FilterAndLogWarnings`` and ``django_tools.unittest_utils.logging_utils.CutPathnameLogRecordFactory``\n\n* v0.39.3 - 22.03.2018 - `compare v0.39.2...v0.39.3 <https://github.com/jedie/django-tools/compare/v0.39.2...v0.39.3>`_ \n\n    * ``django_tools.permissions.get_filtered_permissions`` has new keyword argument: ``exclude_actions``\n\n* v0.39.2 - 22.03.2018 - `compare v0.39.1...v0.39.2 <https://github.com/jedie/django-tools/compare/v0.39.1...v0.39.2>`_ \n\n    * NEW: ``django_tools.parler_utils.parler_fixtures.ParlerDummyGenerator``\n\n    * NEW: ``django_tools.fixture_tools.languages.iter_languages``\n\n* v0.39.1 - 19.03.2018 - `compare v0.39.0...v0.39.1 <https://github.com/jedie/django-tools/compare/v0.39.0...v0.39.1>`_ \n\n    * NEW: ``django_tools.unittest_utils.email.print_mailbox()``\n\n    * minor updates\n\n* v0.39.0 - 02.03.2018 - `compare v0.38.9...v0.39.0 <https://github.com/jedie/django-tools/compare/v0.38.9...v0.39.0>`_ \n\n    * NEW: Isolated Filesystem decorator / context manager\n\n    * Backwards-incompatible change: file renamed ``django_tools/unittest_utils/{celery.py => celery_utils.py``}\n\n    * Skip run test with Django 1.8 and run tests with Django 1.11 and 2.0\n\n* v0.38.9 - 05.02.2018 - `compare v0.38.8...v0.38.9 <https://github.com/jedie/django-tools/compare/v0.38.8...v0.38.9>`_ \n\n    * lowering log level on missing permissions from "error" to "debug"\n\n* v0.38.8 - 05.02.2018 - `compare v0.38.7...v0.38.8 <https://github.com/jedie/django-tools/compare/v0.38.7...v0.38.8>`_ \n\n    * send mail: use from celery import shared_task instead of djcelery_transactions\n\n* v0.38.7 - 15.01.2018 - `compare v0.38.6...v0.38.7 <https://github.com/jedie/django-tools/compare/v0.38.6...v0.38.7>`_ \n\n    * Add missing arguments (like "attachments", "cc" etc.) to ``django_tools.mail.send_mail.SendMailCelery``\n\n* v0.38.6 - 10.01.2018 - `compare v0.38.4...v0.38.5 <https://github.com/jedie/django-tools/compare/v0.38.4...v0.38.5>`_ \n\n    * NEW: ``./manage.py clear_cache``\n\n    * Display POST data in browser debug (``django_tools.unittest_utils.BrowserDebug.debug_response``)\n\n* v0.38.5 - 02.01.2018 - `compare v0.38.4...v0.38.5`_ \n\n    * NEW: Helper to assert django message framework output in unittests:\n\n        * ``BaseUnittestCase.get_messages()``: return a list of all messages\n\n        * ``BaseTestCase.assertMessages()``: compare messages\n\n        * ``BaseTestCase.assertResponse()``: has new keyword argument ``messages``\n\n    * NEW: ``BaseUnittestCase.assert_exception_startswith()``\n\n* v0.38.4 - 28.12.2017 - `compare v0.38.3...v0.38.4 <https://github.com/jedie/django-tools/compare/v0.38.3...v0.38.4>`_ \n\n    * Bugfix attach user group on existing user in: ``django_tools.unittest_utils.user.get_or_create_user``\n\n* v0.38.3 - 28.12.2017 - `compare v0.38.2...v0.38.3 <https://github.com/jedie/django-tools/compare/v0.38.2...v0.38.3>`_ \n\n    * Bugfix: ``unittest_utils.user.get_or_create_group`` also removes obsolete permissions, too.\n\n* v0.38.2 - 27.12.2017 - `compare v0.38.1...v0.38.2 <https://github.com/jedie/django-tools/compare/v0.38.1...v0.38.2>`_ \n\n    * NEW: ``./manage.py update_permissions``\n\n* v0.38.1 - 21.12.2017 - `compare v0.38.0...v0.38.1 <https://github.com/jedie/django-tools/compare/v0.38.0...v0.38.1>`_ \n\n    * refactor travis/tox/pytest/coverage stuff\n\n    * Tests can be run via ``python3 setup.py tox`` and/or ``python3 setup.py test``\n\n    * Test also with pypy3 on Travis CI.\n\n* v0.38.0 - 19.12.2017 - `compare v0.37.0...v0.38.0 <https://github.com/jedie/django-tools/compare/v0.37.0...v0.38.0>`_ \n\n    * NEW: ``django_tools.unittest_utils.user.get_or_create_group``\n\n    * NEW: ``django_tools.unittest_utils.user.get_or_create_user``\n\n    * NEW: ``django_tools.unittest_utils.user.get_or_create_user_and_group``\n\n    * NEW: ``BaseUnittestCase.get_admin_change_url()`` and ``BaseUnittestCase.get_admin_add_url()``\n\n    * NEW: ``BaseUnittestCase.assert_startswith()`` and ``BaseUnittestCase.assert_endswith()``\n\n* v0.37.0 - 11.12.2017 - `compare v0.36.0...v0.37.0 <https://github.com/jedie/django-tools/compare/v0.36.0...v0.37.0>`_ \n\n    * Skip official support for python v2 (remove from text matrix)\n\n    * NEW: ``./manage.py permission_info``: Display a list of all permissions for one django user\n\n    * NEW: ``django_tools.permissions.get_filtered_permissions()`` and ``django_tools.permissions.pprint_filtered_permissions()``\n\n    * ``django_tools.settings_utils.InternalIps`` was renamed to ``FnMatchIps`` and can be also used for **ALLOWED_HOSTS**\n\n    * Bugfix/Enhance permission helpers\n\n* v0.36.0 - 20.11.2017 - `compare v0.35.0...v0.36.0 <https://github.com/jedie/django-tools/compare/v0.35.0...v0.36.0>`_ \n\n    * NEW: ``./manage.py database_info``\n\n    * Bugfix: **ModelPermissionMixin**\n\n    * Dynamic Sites is no longer maintained and tests are deactivated. It\'s currently not compatible with all django versions.\n\n* v0.35.0 - 26.09.2017 - `compare v0.34.0...v0.35.0 <https://github.com/jedie/django-tools/compare/v0.34.0...v0.35.0>`_ \n\n    * CHANGE: The dummy image generation function in ``django_tools.unittest_utils.mockup`` has a new API.\n\n* v0.34.0 - 18.09.2017 - `compare v0.33.0...v0.34.0 <https://github.com/jedie/django-tools/compare/v0.33.0...v0.34.0>`_ \n\n    * CHANGE: The test usernames changed and spaces was replace with underscores e.g.: "staff test user" -> "staff_test_user"\n\n    * Bugfix in mockup.create_pil_image: Created images has wrong sizes\n\n* v0.33.0 - 11.07.2017 - `compare v0.32.14...v0.33.0 <https://github.com/jedie/django-tools/compare/v0.32.14...v0.33.0>`_ \n\n    * Run tests only against Django v1.8 TLS and v1.11 TLS\n\n    * For Django 1.11: Add support for new-style middleware - contributed by benkonrath\n\n    * NEW: ``django_tools.utils.request.create_fake_request()`` for easier create a faked request object with ``RequestFactory``\n\n    * NEW: ``django_tools.utils.html_utils.html2text()`` - Strip HTML tags with lxml Cleaner + Django \'strip_tags\'\n\n* v0.32.14 - 14.06.2017 - `compare v0.32.13...v0.32.14 <https://github.com/jedie/django-tools/compare/v0.32.13...v0.32.14>`_ \n\n    * Bugfix for Python 2: ``mock`` backport package is needed and added to ``setup.install_requires``\n\n* v0.32.13 - 24.05.2017 - `compare v0.32.12...v0.32.13 <https://github.com/jedie/django-tools/compare/v0.32.12...v0.32.13>`_ \n\n    * remove some warnings\n\n* v0.32.12 - 04.05.2017 - `compare v0.32.11...v0.32.12 <https://github.com/jedie/django-tools/compare/v0.32.11...v0.32.12>`_ \n\n    * NEW: ``self.assertIn_dedent()`` in ``django_tools.unittest_utils.unittest_base.BaseUnittestCase``\n\n* v0.32.11 - 02.05.2017 - `compare v0.32.10...v0.32.11 <https://github.com/jedie/django-tools/compare/v0.32.10...v0.32.11>`_ \n\n    * Fix PyPi package mistake (``.tar.gz`` archive contains ``.tox`` ;)\n\n* v0.32.10 - 02.05.2017 - `compare v0.32.9...v0.32.10 <https://github.com/jedie/django-tools/compare/v0.32.9...v0.32.10>`_ \n\n    * NEW: ``django_tools.mail`` to send text+html mails (see above)\n\n* v0.32.9 - 21.03.2017 - `compare v0.32.8...v0.32.9 <https://github.com/jedie/django-tools/compare/v0.32.8...v0.32.9>`_ \n\n    * Bugfix ``DebugCacheLoader`` if TemplateDoesNotExist was raised\n\n* v0.32.8 - 16.03.2017 - `compare v0.32.7...v0.32.8 <https://github.com/jedie/django-tools/compare/v0.32.7...v0.32.8>`_ \n\n    * NEW: ``django_tools.template.loader.DebugCacheLoader`` to add template name as html comments\n\n    * Change temp filename in BrowserDebug and use ``django_tools_browserdebug_`` prefix\n\n    * Bugfix in ``django_tools.middlewares.ThreadLocal.ThreadLocalMiddleware``\n\n* v0.32.7 - 10.03.2017 - `compare v0.32.6...v0.32.7 <https://github.com/jedie/django-tools/compare/v0.32.6...v0.32.7>`_ \n\n    * NEW: ``django_tools.permissions`` - helper for setup permissions\n\n    * NEW: ``/unittest_utils/user.py`` - helper for creating users (needfull in unittests)\n\n* v0.32.6 - 22.02.2017 - `compare v0.32.5...v0.32.6 <https://github.com/jedie/django-tools/compare/v0.32.5...v0.32.6>`_\n\n* ``@task_always_eager()`` decorator will set ``CELERY_EAGER_PROPAGATES_EXCEPTIONS=True``, too.\n\n* v0.32.5 - 10.02.2017 - `compare v0.32.4...v0.32.5 <https://github.com/jedie/django-tools/compare/v0.32.4...v0.32.5>`_ \n\n    * NEW: Add ``template_name`` (optional) to ``self.assertResponse()`` (check with ``assertTemplateUsed()``)\n\n* v0.32.4 - 01.02.2017 - `compare v0.32.3...v0.32.4 <https://github.com/jedie/django-tools/compare/v0.32.3...v0.32.4>`_\n\n* Fix: Set "is_active" for created test users\n\n* v0.32.3 - 25.01.2017 - `compare v0.32.2...v0.32.3 <https://github.com/jedie/django-tools/compare/v0.32.2...v0.32.3>`_ \n\n    * Fix UnicodeDecodeError in BrowserDebug\n\n    * NEW: ``@set_string_if_invalid()`` decorator\n\n    * NEW: ``@task_always_eager()`` decorator\n\n* v0.32.2 - 13.01.2017 - `compare v0.32.1...v0.32.2 <https://github.com/jedie/django-tools/compare/v0.32.1...v0.32.2>`_ \n\n    * NEW: django_tools.utils.url.GetDict\n\n* v0.32.1 - 29.12.2016 - `compare v0.32.0...v0.32.1 <https://github.com/jedie/django-tools/compare/v0.32.0...v0.32.1>`_ \n\n    * NEW: TracebackLogMiddleware\n\n* v0.32.0 - 19.12.2016 - `compare v0.31.0...v0.32.0 <https://github.com/jedie/django-tools/compare/v0.31.0...v0.32.0>`_ \n\n    * NEW: Management commands: \'nice_diffsettings\', \'list_models\'\n\n    * NEW: @display_admin_error to display silent errors in ModelAdmin.list_display callables.\n\n    * NEW: django_tools.template.render.render_template_file\n\n    * use `pytest-django <https://pypi.python.org/pypi/pytest-django>`_\n\n    * remove outdated stuff: See \'Backwards-incompatible changes\' above.\n\n* v0.31.0 - 03.11.2016 - `compare v0.30.4...v0.31.0 <https://github.com/jedie/django-tools/compare/v0.30.4...v0.31.0>`_ \n\n    * add Mockup utils to create dummy PIL/django-filer images with Text (see above)\n\n    * move tests into ``/django_tools_tests/``\n\n* v0.30.4 - 27.10.2016 - `compare v0.30.2...v0.30.4 <https://github.com/jedie/django-tools/compare/v0.30.2...v0.30.4>`_ \n\n    * add DjangoCommandMixin\n\n* v0.30.2 - 05.10.2016 - `compare v0.30.1...v0.30.2 <https://github.com/jedie/django-tools/compare/v0.30.1...v0.30.2>`_ \n\n    * Bugfix Python 2 compatibility\n\n* v0.30.1 - 26.08.2016 - `compare v0.30.0...v0.30.1 <https://github.com/jedie/django-tools/compare/v0.30.0...v0.30.1>`_ \n\n    * add: ``django_tools.unittest_utils.disable_migrations.DisableMigrations`` (see above)\n\n    * run tests also with django v1.10 and Python 3.5\n\n    * use tox\n\n* v0.30.0 - 27.04.2016 - `compare v0.29.5...v0.30.0 <https://github.com/jedie/django-tools/compare/v0.29.5...v0.30.0>`_ \n\n    * Django 1.9 and Python 3 support contributed by `naegelyd <https://github.com/jedie/django-tools/pull/9>`_\n\n* v0.29.4 and v0.29.5 - 10.08.2015 - `compare v0.29.3...v0.29.5 <https://github.com/jedie/django-tools/compare/v0.29.3...v0.29.5>`_ \n\n    * Some bugfixes for django 1.6 support\n\n* v0.29.3 - 10.08.2015 - `compare v0.29.2...v0.29.3 <https://github.com/jedie/django-tools/compare/v0.29.2...v0.29.3>`_ \n\n    * Clear ThreadLocal request atttribute after response is processed (contributed by Lucas Wiman)\n\n* v0.29.2 - 19.06.2015 - `compare v0.29.1...v0.29.2 <https://github.com/jedie/django-tools/compare/v0.29.1...v0.29.2>`_ \n\n    * Bugfix in unittest_utils.selenium_utils.selenium2fakes_response\n\n    * assertResponse used assertContains from django\n\n    * Add QueryLogMiddleware (TODO: add tests)\n\n* v0.29.1 - 17.06.2015 - `compare v0.29.0...v0.29.1 <https://github.com/jedie/django-tools/compare/v0.29.0...v0.29.1>`_ \n\n    * Bugfixes for Py2 and Py3\n\n    * add StdoutStderrBuffer()\n\n* v0.29.0 - 09.06.2015 - `compare v0.26.0...v0.29.0 <https://github.com/jedie/django-tools/compare/v0.26.0...v0.29.0>`_ \n\n    * WIP: Refactor unittests (DocTests must be updated for Py3 and more unittests must be written to cover all)\n\n    * catch more directory traversal attacks in BaseFilesystemBrowser (and merge code parts)\n\n    * Bugfix for "django.core.exceptions.AppRegistryNotReady: Models aren\'t loaded yet." if using **UpdateInfoBaseModel**\n\n    * Bugfixes in **dynamic_site** for django 1.7\n\n    * add: `django_tools.settings_utils.InternalIps <https://github.com/jedie/django-tools/blob/master/django_tools/settings_utils.py>`_\n\n* v0.28.0 - 12.02.2015 - `compare v0.26.0...v0.28.0 <https://github.com/jedie/django-tools/compare/v0.26.0...v0.28.0>`_ \n\n    * Work-a-round for import loops\n\n    * (new Version number, because of PyPi stress)\n\n* v0.26.0 - 11.02.2015 - `compare v0.25.1...v0.26.0 <https://github.com/jedie/django-tools/compare/v0.25.1...v0.26.0>`_ \n\n    * Updates for Django 1.6 and Python 3\n\n* v0.25.1 - 18.11.2013\n\n    * Bugfix: Fall back to "UTF-8" if server send no encoding info\n\n* v0.25.0 - 28.08.2012\n\n    * Rename **cache.clear()** in SmoothCacheBackends to **cache.smooth_update()**, so that reset timestamp is independ from clear the cache.\n\n* v0.24.10 - 24.08.2012\n\n    * Add **SmoothCacheBackends**: `./cache/README.creole <https://github.com/jedie/django-tools/blob/master/django_tools/cache/README.creole>`_\n\n* v0.24.9 - 24.08.2012\n\n    * Bugfix in per-site cache middleware: set inital count values to None, if counting is disabled.\n\n* v0.24.8 - 24.08.2012\n\n    * Enhanced **per-site cache middleware**: `./cache/README.creole`_\n\n    * Add **SetRequestDebugMiddleware**: `./debug/README.creole`_\n\n* v0.24.7 - 21.08.2012\n\n    * Add the **per-site cache middleware** (see above)\n\n    * Add **import lib helper**: `./utils/importlib.py`_\n\n* v0.24.6 - 21.08.2012\n\n    * Add the **filemanager library** (see above)\n\n* v0.24.5 - 06.08.2012\n\n    * Add **Print SQL Queries** context manager. (see above)\n\n* v0.24.4 - 26.07.2012\n\n    * remove date from version string, cause of side-effects e.g.: user clone the repo and has the filter not installed\n\n* v0.24.3 - 25.07.2012\n\n    * "Hardcode" the version string date attachment via `gitattribute filter script <https://github.com/jedie/python-code-snippets/tree/master/CodeSnippets/git>`_ to fix `a reported issues <https://github.com/jedie/django-tools/issues/1>`_ with `pip requirements file bug <https://github.com/pypa/pip/issues/145>`_.\n\n* v0.24.2 - 10.07.2012\n\n    * Split `UpdateInfoBaseModel() <https://github.com/jedie/django-tools/blob/master/django_tools/models.py>`_: So you can only set "createtime", "lastupdatetime" or "createby", "lastupdateby" or both types (This is backwards compatible)\n\n* v0.24.1 - 12.06.2012\n\n    * Bugfix: UsergroupsModelField() and add unittests for it\n\n    * Add "normal users" in UsergroupsModelField()\n\n    * New: Add create_user() and create_testusers() to BaseTestCase\n\n    * Add a test project for the unittests. TODO: use this for all tests\n\n* v0.24.0 - 04.06.2012\n\n    * `Don\'t use auto_now_add and auto_now in UpdateInfoBaseModel <https://github.com/jedie/django-tools/commit/a3cf1f7b2e9dbe4964306f4793c74f1782f8b2ea>`_\n\n    * Bugfix in `UsergroupsModelField <https://github.com/jedie/django-tools/blob/master/django_tools/limit_to_usergroups.py>`_\n\n* v0.23.1\n\n    * `Dynamic Site <https://github.com/jedie/django-tools/tree/main/django_tools/dynamic_site#dynamic-site-id>`_ would be only initialised if settings.USE_DYNAMIC_SITE_MIDDLEWARE = True\n\n* v0.23.0\n\n    * Use cryptographic signing tools from django 1.4 in django_tools.utils.client_storage\n\n* v0.22.0\n\n    * Add `static_path.py <https://github.com/jedie/django-tools/blob/master/django_tools/fields/static_path.py>`_ thats used settings.STATIC_ROOT.\n\n    * The old `media_path.py <https://github.com/jedie/django-tools/blob/master/django_tools/fields/media_path.py>`_ which used settings.MEDIA_ROOT is deprecated and will be removed in the future.\n\n    * auto_add_check_unique_together() can use settings.DATABASES["default"]["ENGINE"], too.\n\n* v0.21.1\n\n    * Bugfixes in `Dynamic Site`_.\n\n* v0.21.0beta\n\n    * New: site alias function\n\n    * refractory \'DynamicSiteMiddleware\' to a own app (**Backwards-incompatible change:** change your settings if you use the old DynamicSiteMiddleware.)\n\n* v0.20.1\n\n    * New: `debug_csrf_failure() <https://github.com/jedie/django-tools/blob/master/django_tools/views/csrf.py>`_ to display the normal debug page and not the minimal csrf debug page.\n\n* v0.20.0\n\n    * Add experimental `DynamicSiteMiddleware <https://github.com/jedie/django-tools/blob/master/django_tools/middlewares/DynamicSite.py>`_, please test it and give feedback.\n\n* v0.19.6\n\n    * Add some south introspection rules for LanguageCodeModelField and jQueryTagModelField\n\n    * fallback if message for anonymous user can\'t created, because django.contrib.messages middleware not used.\n\n    * Bugfix in django_tools.utils.messages.StackInfoStorage\n\n* v0.19.5\n\n    * Add `http://bugs.python.org/file22767/hp_fix.diff <http://bugs.python.org/file22767/hp_fix.diff>`_ for `https://github.com/gregmuellegger/django/issues/1 <https://github.com/gregmuellegger/django/issues/1>`_\n\n* v0.19.4\n\n    * Bugfix for PyPy in local_sync_cache get_cache_information(): sys.getsizeof() not implemented on PyPy\n\n    * Bugfix in template.filters.chmod_symbol()\n\n    * Nicer solution for template.filters.human_duration()\n\n* v0.19.3\n\n    * Add support for https in utils/http.py\n\n* v0.19.2\n\n    * Bugfix in utils/http.py timeout work-a-round\n\n* v0.19.1\n\n    * utils/http.py changes:\n\n        * Use a better solution, see:\n\n        * Add timeout and add a work-a-round for Python < 2.6\n\n* v0.19.0\n\n    * NEW: Add utils/http.py with helpers to get a webpage via http GET in unicode\n\n    * Change README from textile to creole ;)\n\n* v0.18.2\n\n    * Bugfix: Add missing template in pypi package\n\n* v0.18.0\n\n    * NEW: Add DOM compare from Gregor Müllegger GSoC work into unittest utils.\n\n* v0.17.1\n\n    * Bugfix in “limit_to_usergroups”: Make choices “lazy”: Don’t access the database in *init*\n\n* v0.17\n\n    * Add the script “upgrade_virtualenv.py”\n\n    * Add “limit_to_usergroups”\n\n    * Add “local sync cache”\n\n    * Add models.UpdateInfoBaseModel\n\n    * Update decorators.render_to\n\n    * render_to pass keyword arguments to render_to_response() (e.g.: mimetype=“text/plain”)\n\n    * new argument “skip_fail” in get_filtered_apps(): If True: raise excaption if app is not importable\n\n* v0.16.4\n\n    * Bugfix: ``get_db_prep_save() got an unexpected keyword argument \'connection’`` when save a SignSeparatedModelField()\n\n* v0.16.3\n\n    * Update BrowserDebug: Use response.templates instead of response.template and make output nicer\n\n* v0.16.2\n\n    * Merge stack info code and display better stack info on browser debug page\n\n* v0.16.1\n\n    * Update django_tools.utils.messages.StackInfoStorage for django code changes.\n\n* v0.16.0\n\n    * NEW: path model field (check if direcotry exist)\n\n* v0.15.0\n\n    * NEW: Add a flexible URL field (own validator, model- and form-field)\n\n* v0.14.1\n\n    * Bugfix: make path in MediaPathModelField relativ (remove slashes)\n\n* v0.14\n\n    * NEW: django-tagging addon: Display existing tags under a tag field\n\n* v0.13\n\n    * Bugfix UnicodeEncodeError in Browser debug\n\n* v0.12\n\n    * NEW: django_tools.utils.messages.failsafe_message\n\n* v0.11\n\n    * NEW: Store data in a secure cookie, see: utils/client_storage.py\n\n* v0.10.1\n\n    * New: Display used templates in unittest BrowserDebug\n\n    * Bugfix: catch if last usermessages exist\n\n* v0.10.0\n\n    * NEW: utils around django messages, see: /django_tools/utils/messages.py\n\n* v0.9.1\n\n    * Bugfix: database column was not created: don’t overwrite get_internal_type()\n\n* v0.9\n\n    * New: stuff in /django_tools/fields/\n\n    * see also backwards-incompatible changes, above!\n\n* v0.8.2\n\n    * New: widgets.SelectMediaPath(): Select a sub directory in settings.MEDIA_ROOT\n\n    * New: fields.SignSeparatedField()\n\n* v0.8.1\n\n    * Add “no_args” keyword argument to installed_apps_utils.get_filtered_apps()\n\n* v0.8.0\n\n    * Add model LanguageCode field and form LanguageCode field in Accept-Language header format (RFC 2616)\n\n* v0.7.0\n\n    * Add decorators.py\n\n* v0.6.0\n\n    * Add forms_utils.LimitManyToManyFields, crosspost: `http://www.djangosnippets.org/snippets/1691/ <http://www.djangosnippets.org/snippets/1691/>`_\n\n* v0.5.0\n\n    * Add template/filters.py from PyLucid v0.8.x\n\n* v0.4.0\n\n    * Add experimental “warn_invalid_template_vars”\n\n* v0.3.1\n\n    * Bugfix: Exclude the instance if it was saved in the past.\n\n* v0.3.0\n\n    * Add utils.installed_apps_utils\n\n* v0.2.0\n\n    * Add models_utils, see: `http://www.jensdiemer.de/_command/118/blog/detail/67/ <http://www.jensdiemer.de/_command/118/blog/detail/67/>`_ (de)\n\n* v0.1.0\n\n    * first version cut out from PyLucid CMS – `http://www.pylucid.org <http://www.pylucid.org>`_\n\n-----\nlinks\n-----\n\n+----------+-----------------------------------------------+\n| Homepage | `https://github.com/jedie/django-tools`_      |\n+----------+-----------------------------------------------+\n| PyPi     | `https://pypi.python.org/pypi/django-tools/`_ |\n+----------+-----------------------------------------------+\n\n.. _https://github.com/jedie/django-tools: https://github.com/jedie/django-tools\n\n--------\ndonation\n--------\n\n* `paypal.me/JensDiemer <https://www.paypal.me/JensDiemer>`_\n\n* `Flattr This! <https://flattr.com/submit/auto?uid=jedie&url=https%3A%2F%2Fgithub.com%2Fjedie%2Fdjango-tools%2F>`_\n\n* Send `Bitcoins <https://www.bitcoin.org/>`_ to `1823RZ5Md1Q2X5aSXRC5LRPcYdveCiVX6F <https://blockexplorer.com/address/1823RZ5Md1Q2X5aSXRC5LRPcYdveCiVX6F>`_\n\n------------\n\n``Note: this file is generated from README.creole 2022-08-25 02:50:56 with "python-creole"``',
    'author': 'Jens Diemer',
    'author_email': 'django-tools@jensdiemer.de',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/jedie/django-tools/',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'entry_points': entry_points,
    'python_requires': '>=3.7,<4.0.0',
}


setup(**setup_kwargs)
