pax_global_header00006660000000000000000000000064142006432740014514gustar00rootroot0000000000000052 comment=2bafea4ba7020df11a2f2dc713085b40941fe393 django-timezone-field-5.0/000077500000000000000000000000001420064327400155335ustar00rootroot00000000000000django-timezone-field-5.0/.flake8000066400000000000000000000000511420064327400167020ustar00rootroot00000000000000[flake8] ignore=W503 max-line-length=120 django-timezone-field-5.0/.github/000077500000000000000000000000001420064327400170735ustar00rootroot00000000000000django-timezone-field-5.0/.github/workflows/000077500000000000000000000000001420064327400211305ustar00rootroot00000000000000django-timezone-field-5.0/.github/workflows/ci.yml000066400000000000000000000106701420064327400222520ustar00rootroot00000000000000name: CI on: - push - pull_request jobs: lint: runs-on: ubuntu-latest name: Lint steps: - name: Git checkout uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 - name: Install Poetry uses: snok/install-poetry@v1 with: virtualenvs-create: true virtualenvs-in-project: true - name: Load cached venv id: cached-poetry-dependencies uses: actions/cache@v2 with: path: .venv key: venv-${{ hashFiles('poetry.lock') }} - name: Install dependencies if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root - name: Lint with black run: poetry run black --check --diff . - name: Lint with flake8 run: poetry run flake8 --exclude .venv - name: Lint with isort run: poetry run isort --check --diff . - name: Lint with pylint run: poetry run pylint tests timezone_field setup.py test: runs-on: ubuntu-latest name: Test with py${{ matrix.python-version }}, dj${{ matrix.django-version }}, ${{ matrix.db-engine }} strategy: matrix: # https://docs.djangoproject.com/en/4.0/faq/install/#what-python-version-can-i-use-with-django python-version: ["3.7", "3.8", "3.9", "3.10"] django-version: ["2.2", "3.2", "4.0"] db-engine: [sqlite, postgres] exclude: - python-version: "3.10" django-version: "2.2" - python-version: "3.7" django-version: "4.0" env: PYTHON_VERSION: ${{ matrix.python-version }} DJANGO_VERSION: ${{ matrix.django-version }} DB_ENGINE: ${{ matrix.db-engine }} services: postgres: image: postgres env: POSTGRES_DB: postgres POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres ports: - 5432:5432 # Set health checks to wait until postgres has started options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - name: Git checkout uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install Poetry uses: snok/install-poetry@v1 with: virtualenvs-create: true virtualenvs-in-project: true - name: Load cached venv id: cached-poetry-dependencies uses: actions/cache@v2 with: path: .venv key: venv-py${{ matrix.python-version}}-dj${{ matrix.django-version }}-${{ hashFiles('poetry.lock') }} - name: Install dependencies if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root - name: Install django ${{ matrix.django-version }} if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: | source .venv/bin/activate pip install "Django~=${{ matrix.django-version }}" - name: Test with coverage env: POSTGRES_HOST: localhost POSTGRES_PORT: 5432 POSTGRES_DB: postgres POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres run: poetry run pytest --cov=timezone_field - name: Generate coverage report run: poetry run coverage xml - name: Upload coverage report to codecov uses: codecov/codecov-action@v2 with: env_vars: PYTHON_VERSION,DJANGO_VERSION,DB_ENGINE fail_ci_if_error: true build: runs-on: ubuntu-latest name: Build steps: - name: Git checkout uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 - name: Install Poetry uses: snok/install-poetry@v1 with: virtualenvs-create: true virtualenvs-in-project: true - name: Load cached venv id: cached-poetry-dependencies uses: actions/cache@v2 with: path: .venv key: venv-${{ hashFiles('poetry.lock') }} - name: Install dependencies if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root - name: Build with poetry run: poetry build django-timezone-field-5.0/.gitignore000066400000000000000000000000631420064327400175220ustar00rootroot00000000000000.coverage .tox *.pyc *.egg-info htmlcov build dist django-timezone-field-5.0/LICENSE.txt000066400000000000000000000024651420064327400173650ustar00rootroot00000000000000Copyright (c) 2014, Mike Fogel All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 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. django-timezone-field-5.0/README.md000066400000000000000000000213221420064327400170120ustar00rootroot00000000000000# django-timezone-field [![CI](https://github.com/mfogel/django-timezone-field/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mfogel/django-timezone-field/actions) [![codecov](https://codecov.io/gh/mfogel/django-timezone-field/branch/main/graph/badge.svg?token=Rwekzmim3l)](https://codecov.io/gh/mfogel/django-timezone-field) [![pypi downloads](https://img.shields.io/pypi/dm/django-timezone-field.svg)](https://pypi.python.org/pypi/django-timezone-field/) [![pypi python support](https://img.shields.io/pypi/pyversions/django-timezone-field.svg)](https://pypi.python.org/pypi/django-timezone-field/) [![pypi django support](https://img.shields.io/pypi/djversions/django-timezone-field.svg)](https://pypi.python.org/pypi/django-timezone-field/) A Django app providing DB, form, and REST framework fields for [`zoneinfo`](https://docs.python.org/3/library/zoneinfo.html) and [`pytz`](http://pypi.python.org/pypi/pytz/) timezone objects. ## The transition from `pytz` to `zoneinfo` Like Django, this app supports both `pytz` and `zoneinfo` objects while the community transitions away from `pytz` to `zoneinfo`. All exposed fields and functions that return a timezone object accept an optional boolean kwarg `use_pytz`. If not explicitly specified, the default value used for `use_pytz` matches Django's behavior: - Django <= 3.X: `use_pytz` defaults to `True` - Django == 4.X: `use_pytz` defaults to the value of [`django.conf.settings.USE_DEPRECATED_PYTZ`](https://docs.djangoproject.com/en/4.0/ref/settings/#use-deprecated-pytz), which itself defaults to `False` - Django >= 5.X: django plans to [drop support for `pytz` altogether](https://docs.djangoproject.com/en/4.0/releases/4.0/#zoneinfo-default-timezone-implementation), and this app will likely do the same. When switching between `pytz` and `zoneinfo`, in general a [data migration](https://docs.djangoproject.com/en/4.0/topics/migrations/#data-migrations) is _not_ needed, as both libraries recognize the same set of strings as valid timezones. Exceptions to that include if your local system has an unusual set of time zones installed, or if you are using the `Factory` timezone which `zoneinfo` recognizes but `pytz` does not. ## Examples ### Database Field ```python import zoneinfo import pytz from django.db import models from timezone_field import TimeZoneField class MyModel(models.Model): tz1 = TimeZoneField(default="Asia/Dubai") # defaults supported, in ModelForm renders like "Asia/Dubai" tz2 = TimeZoneField(choices_display="WITH_GMT_OFFSET") # in ModelForm renders like "GMT+04:00 Asia/Dubai" tz3 = TimeZoneField(use_pytz=True) # returns pytz timezone objects tz4 = TimeZoneField(use_pytz=False) # returns zoneinfo objects my_model = MyModel( tz2="America/Vancouver", # assignment of a string tz3=pytz.timezone("America/Vancouver"), # assignment of a pytz timezone tz4=zoneinfo.ZoneInfo("America/Vancouver"), # assignment of a zoneinfo ) my_model.full_clean() # validates against pytz.common_timezones by default my_model.save() # values stored in DB as strings my_model.tz3 # value returned as pytz timezone: my_model.tz4 # value returned as zoneinfo: zoneinfo.ZoneInfo(key='America/Vancouver') ``` ### Form Field ```python from django import forms from timezone_field import TimeZoneFormField class MyForm(forms.Form): tz1 = TimeZoneFormField() # renders like "Asia/Dubai" tz2 = TimeZoneFormField(choices_display="WITH_GMT_OFFSET") # renders like "GMT+04:00 Asia/Dubai" tz3 = TimeZoneFormField(use_pytz=True) # returns pytz timezone objects tz4 = TimeZoneFormField(use_pytz=False) # returns zoneinfo objects my_form = MyForm({"tz3": "Europe/Berlin", "tz4": "Europe/Berlin"}) my_form.full_clean() # validates against pytz.common_timezones by default my_form.cleaned_data["tz3"] # value returned as pytz timezone: my_form.cleaned_data["tz4"] # value returned as zoneinfo: zoneinfo.ZoneInfo(key='Europe/Berlin') ``` ### REST Framework Serializer Field ```python from rest_framework import serializers from timezone_field.rest_framework import TimeZoneSerializerField class MySerializer(serializers.Serializer): tz1 = TimeZoneSerializerField(use_pytz=True) tz2 = TimeZoneSerializerField(use_pytz=False) my_serializer = MySerializer(data={ "tz1": "America/Argentina/Buenos_Aires", "tz2": "America/Argentina/Buenos_Aires", }) my_serializer.is_valid() my_serializer.validated_data["tz1"] # my_serializer.validated_data["tz2"] # zoneinfo.ZoneInfo(key='America/Argentina/Buenos_Aires') ``` ## Installation Releases are hosted on [`pypi`](https://pypi.org/project/django-timezone-field/) and can be installed using various python packaging tools. ```bash # with poetry poetry add django-timezone-field # with pip pip install django-timezone-field ``` ## Running the tests From the repository root, with [`poetry`](https://python-poetry.org/): ```bash poetry install poetry run pytest ``` ## Changelog #### 5.0 (2022-02-08) - Add support for `zoneinfo` objects ([#79](https://github.com/mfogel/django-timezone-field/issues/79)) - Add support for django 4.0 - Remove `display_GMT_offset` kwarg (use `choices_display` instead) - Drop support for django 3.0, 3.1 - Drop support for python 3.5, 3.6 #### 4.2.3 (2022-01-13) - Fix sdist installs ([#78](https://github.com/mfogel/django-timezone-field/issues/78)) - Officially support python 3.10 #### 4.2.1 (2021-07-07) - Reinstate `TimeZoneField.default_choices` ([#76](https://github.com/mfogel/django-timezone-field/issues/76)) #### 4.2 (2021-07-07) - Officially support django 3.2, python 3.9 - Fix bug with field deconstruction ([#74](https://github.com/mfogel/django-timezone-field/issues/74)) - Housekeeping: use poetry, github actions, pytest #### 4.1.2 (2021-03-17) - Avoid `NonExistentTimeError` during DST transition ([#70](https://github.com/mfogel/django-timezone-field/issues/70)) #### 4.1.1 (2020-11-28) - Don't import `rest_framework` from package root ([#67](https://github.com/mfogel/django-timezone-field/issues/67)) #### 4.1 (2020-11-28) - Add Django REST Framework serializer field - Add new `choices_display` kwarg with supported values `WITH_GMT_OFFSET` and `STANDARD` - Deprecate `display_GMT_offset` kwarg #### 4.0 (2019-12-03) - Add support for django 3.0, python 3.8 - Drop support for django 1.11, 2.0, 2.1, python 2.7, 3.4 #### 3.1 (2019-10-02) - Officially support django 2.2 (already worked) - Add option to display TZ offsets in form field ([#46](https://github.com/mfogel/django-timezone-field/issues/46)) #### 3.0 (2018-09-15) - Support django 1.11, 2.0, 2.1 - Add support for python 3.7 - Change default human-readable timezone names to exclude underscores ([#32](https://github.com/mfogel/django-timezone-field/issues/32) & [#37](https://github.com/mfogel/django-timezone-field/issues/37)) #### 2.1 (2018-03-01) - Add support for django 1.10, 1.11 - Add support for python 3.6 - Add wheel support - Support bytes in DB fields ([#38](https://github.com/mfogel/django-timezone-field/issues/38) & [#39](https://github.com/mfogel/django-timezone-field/issues/39)) #### 2.0 (2016-01-31) - Drop support for django 1.7, add support for django 1.9 - Drop support for python 3.2, 3.3, add support for python 3.5 - Remove tests from source distribution #### 1.3 (2015-10-12) - Drop support for django 1.6, add support for django 1.8 - Various [bug fixes](https://github.com/mfogel/django-timezone-field/issues?q=milestone%3A1.3) #### 1.2 (2015-02-05) - For form field, changed default list of accepted timezones from `pytz.all_timezones` to `pytz.common_timezones`, to match DB field behavior. #### 1.1 (2014-10-05) - Django 1.7 compatibility - Added support for formatting `choices` kwarg as `[[, ], ...]`, in addition to previous format of `[[, ], ...]`. - Changed default list of accepted timezones from `pytz.all_timezones` to `pytz.common_timezones`. If you have timezones in your DB that are in `pytz.all_timezones` but not in `pytz.common_timezones`, this is a backward-incompatible change. Old behavior can be restored by specifying `choices=[(tz, tz) for tz in pytz.all_timezones]` in your model definition. #### 1.0 (2013-08-04) - Initial release as `timezone_field`. ## Credits Originally adapted from [Brian Rosner's django-timezones](https://github.com/brosner/django-timezones). Made possible thanks to the work of the [contributors](https://github.com/mfogel/django-timezone-field/graphs/contributors). django-timezone-field-5.0/poetry.lock000066400000000000000000001631631420064327400177410ustar00rootroot00000000000000[[package]] name = "asgiref" version = "3.5.0" description = "ASGI specs, helper code, and adapters" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] [[package]] name = "astroid" version = "2.9.3" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false python-versions = ">=3.6.2" [package.dependencies] lazy-object-proxy = ">=1.4.0" typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} wrapt = ">=1.11,<1.14" [[package]] name = "atomicwrites" version = "1.4.0" description = "Atomic file writes." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" version = "21.4.0" description = "Classes Without Boilerplate" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] [[package]] name = "backports.zoneinfo" version = "0.2.1" description = "Backport of the standard library zoneinfo module" category = "main" optional = false python-versions = ">=3.6" [package.extras] tzdata = ["tzdata"] [[package]] name = "black" version = "21.12b0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.6.2" [package.dependencies] click = ">=7.1.2" mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0,<1" platformdirs = ">=2" tomli = ">=0.2.6,<2.0.0" typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} typing-extensions = [ {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, ] [package.extras] colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] python2 = ["typed-ast (>=1.4.3)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "click" version = "8.0.3" description = "Composable command line interface toolkit" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" version = "0.4.4" description = "Cross-platform colored terminal text." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" version = "6.3" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] tomli = {version = "*", optional = true, markers = "extra == \"toml\""} [package.extras] toml = ["tomli"] [[package]] name = "django" version = "3.2.12" description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] asgiref = ">=3.3.2,<4" pytz = "*" sqlparse = ">=0.2.2" [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] bcrypt = ["bcrypt"] [[package]] name = "django" version = "4.0.2" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." category = "dev" optional = false python-versions = ">=3.8" [package.dependencies] asgiref = ">=3.4.1,<4" "backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} sqlparse = ">=0.2.2" tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] bcrypt = ["bcrypt"] [[package]] name = "djangorestframework" version = "3.13.1" description = "Web APIs for Django, made easy." category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] django = ">=2.2" pytz = "*" [[package]] name = "flake8" version = "4.0.1" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.8.0,<2.9.0" pyflakes = ">=2.4.0,<2.5.0" [[package]] name = "importlib-metadata" version = "4.2.0" description = "Read metadata from Python packages" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" version = "1.1.1" description = "iniconfig: brain-dead simple config-ini parsing" category = "dev" optional = false python-versions = "*" [[package]] name = "isort" version = "5.10.1" description = "A Python utility / library to sort Python imports." category = "dev" optional = false python-versions = ">=3.6.1,<4.0" [package.extras] pipfile_deprecated_finder = ["pipreqs", "requirementslib"] requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] plugins = ["setuptools"] [[package]] name = "lazy-object-proxy" version = "1.7.1" description = "A fast and thorough lazy object proxy." category = "dev" optional = false python-versions = ">=3.6" [[package]] name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" category = "dev" optional = false python-versions = "*" [[package]] name = "mypy-extensions" version = "0.4.3" description = "Experimental type system extensions for programs checked with the mypy typechecker." category = "dev" optional = false python-versions = "*" [[package]] name = "packaging" version = "21.3" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "pathspec" version = "0.9.0" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "platformdirs" version = "2.4.1" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" [package.extras] docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] [[package]] name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] [[package]] name = "psycopg2-binary" version = "2.9.3" description = "psycopg2 - Python-PostgreSQL Database Adapter" category = "dev" optional = false python-versions = ">=3.6" [[package]] name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pycodestyle" version = "2.8.0" description = "Python style guide checker" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pyflakes" version = "2.4.0" description = "passive checker of Python programs" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pylint" version = "2.12.2" description = "python code static checker" category = "dev" optional = false python-versions = ">=3.6.2" [package.dependencies] astroid = ">=2.9.0,<2.10" colorama = {version = "*", markers = "sys_platform == \"win32\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.7" platformdirs = ">=2.2.0" toml = ">=0.9.2" typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [[package]] name = "pyparsing" version = "3.0.7" description = "Python parsing module" category = "dev" optional = false python-versions = ">=3.6" [package.extras] diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" version = "6.2.5" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" py = ">=1.8.2" toml = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] [[package]] name = "pytest-cov" version = "3.0.0" description = "Pytest plugin for measuring coverage." category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] [[package]] name = "pytest-django" version = "4.5.2" description = "A Django plugin for pytest." category = "dev" optional = false python-versions = ">=3.5" [package.dependencies] pytest = ">=5.4.0" [package.extras] docs = ["sphinx", "sphinx-rtd-theme"] testing = ["django", "django-configurations (>=2.0)"] [[package]] name = "pytest-lazy-fixture" version = "0.6.3" description = "It helps to use fixtures in pytest.mark.parametrize" category = "dev" optional = false python-versions = "*" [package.dependencies] pytest = ">=3.2.5" [[package]] name = "pytest-pythonpath" version = "0.7.3" description = "pytest plugin for adding to the PYTHONPATH from command line or configs." category = "dev" optional = false python-versions = "*" [package.dependencies] pytest = ">=2.5.2" [[package]] name = "pytz" version = "2021.3" description = "World timezone definitions, modern and historical" category = "main" optional = false python-versions = "*" [[package]] name = "sqlparse" version = "0.4.2" description = "A non-validating SQL parser." category = "dev" optional = false python-versions = ">=3.5" [[package]] name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tomli" version = "1.2.3" description = "A lil' TOML parser" category = "dev" optional = false python-versions = ">=3.6" [[package]] name = "typed-ast" version = "1.5.2" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" optional = false python-versions = ">=3.6" [[package]] name = "typing-extensions" version = "4.0.1" description = "Backported and Experimental Type Hints for Python 3.6+" category = "dev" optional = false python-versions = ">=3.6" [[package]] name = "tzdata" version = "2021.5" description = "Provider of IANA time zone data" category = "dev" optional = false python-versions = ">=2" [[package]] name = "wrapt" version = "1.13.3" description = "Module for decorators, wrappers and monkey patching." category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "zipp" version = "3.7.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false python-versions = ">=3.7" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" python-versions = "^3.7" content-hash = "4f6741de28ebf27540fb76ed3dfae7ca7a2611de5ad4a36724366387454c69b8" [metadata.files] asgiref = [ {file = "asgiref-3.5.0-py3-none-any.whl", hash = "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"}, {file = "asgiref-3.5.0.tar.gz", hash = "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0"}, ] astroid = [ {file = "astroid-2.9.3-py3-none-any.whl", hash = "sha256:506daabe5edffb7e696ad82483ad0228245a9742ed7d2d8c9cdb31537decf9f6"}, {file = "astroid-2.9.3.tar.gz", hash = "sha256:1efdf4e867d4d8ba4a9f6cf9ce07cd182c4c41de77f23814feb27ca93ca9d877"}, ] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, ] "backports.zoneinfo" = [ {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, ] black = [ {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, ] click = [ {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] coverage = [ {file = "coverage-6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e8071e7d9ba9f457fc674afc3de054450be2c9b195c470147fbbc082468d8ff7"}, {file = "coverage-6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86c91c511853dfda81c2cf2360502cb72783f4b7cebabef27869f00cbe1db07d"}, {file = "coverage-6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4ce3b647bd1792d4394f5690d9df6dc035b00bcdbc5595099c01282a59ae01"}, {file = "coverage-6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a491e159294d756e7fc8462f98175e2d2225e4dbe062cca7d3e0d5a75ba6260"}, {file = "coverage-6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d008e0f67ac800b0ca04d7914b8501312c8c6c00ad8c7ba17754609fae1231a"}, {file = "coverage-6.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4578728c36de2801c1deb1c6b760d31883e62e33f33c7ba8f982e609dc95167d"}, {file = "coverage-6.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7ee317486593193e066fc5e98ac0ce712178c21529a85c07b7cb978171f25d53"}, {file = "coverage-6.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2bc85664b06ba42d14bb74d6ddf19d8bfc520cb660561d2d9ce5786ae72f71b5"}, {file = "coverage-6.3-cp310-cp310-win32.whl", hash = "sha256:27a94db5dc098c25048b0aca155f5fac674f2cf1b1736c5272ba28ead2fc267e"}, {file = "coverage-6.3-cp310-cp310-win_amd64.whl", hash = "sha256:bde4aeabc0d1b2e52c4036c54440b1ad05beeca8113f47aceb4998bb7471e2c2"}, {file = "coverage-6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7eed8459a2b81848cafb3280b39d7d49950d5f98e403677941c752e7e7ee47cb"}, {file = "coverage-6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b4285fde5286b946835a1a53bba3ad41ef74285ba9e8013e14b5ea93deaeafc"}, {file = "coverage-6.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4748349734110fd32d46ff8897b561e6300d8989a494ad5a0a2e4f0ca974fc7"}, {file = "coverage-6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:823f9325283dc9565ba0aa2d240471a93ca8999861779b2b6c7aded45b58ee0f"}, {file = "coverage-6.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fff16a30fdf57b214778eff86391301c4509e327a65b877862f7c929f10a4253"}, {file = "coverage-6.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:da1a428bdbe71f9a8c270c7baab29e9552ac9d0e0cba5e7e9a4c9ee6465d258d"}, {file = "coverage-6.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7d82c610a2e10372e128023c5baf9ce3d270f3029fe7274ff5bc2897c68f1318"}, {file = "coverage-6.3-cp37-cp37m-win32.whl", hash = "sha256:11e61c5548ecf74ea1f8b059730b049871f0e32b74f88bd0d670c20c819ad749"}, {file = "coverage-6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:8e0c3525b1a182c8ffc9bca7e56b521e0c2b8b3e82f033c8e16d6d721f1b54d6"}, {file = "coverage-6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a189036c50dcd56100746139a459f0d27540fef95b09aba03e786540b8feaa5f"}, {file = "coverage-6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:32168001f33025fd756884d56d01adebb34e6c8c0b3395ca8584cdcee9c7c9d2"}, {file = "coverage-6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5d79c9af3f410a2b5acad91258b4ae179ee9c83897eb9de69151b179b0227f5"}, {file = "coverage-6.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:85c5fc9029043cf8b07f73fbb0a7ab6d3b717510c3b5642b77058ea55d7cacde"}, {file = "coverage-6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7596aa2f2b8fa5604129cfc9a27ad9beec0a96f18078cb424d029fdd707468d"}, {file = "coverage-6.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ce443a3e6df90d692c38762f108fc4c88314bf477689f04de76b3f252e7a351c"}, {file = "coverage-6.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:012157499ec4f135fc36cd2177e3d1a1840af9b236cbe80e9a5ccfc83d912a69"}, {file = "coverage-6.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0a34d313105cdd0d3644c56df2d743fe467270d6ab93b5d4a347eb9fec8924d6"}, {file = "coverage-6.3-cp38-cp38-win32.whl", hash = "sha256:6e78b1e25e5c5695dea012be473e442f7094d066925604be20b30713dbd47f89"}, {file = "coverage-6.3-cp38-cp38-win_amd64.whl", hash = "sha256:433b99f7b0613bdcdc0b00cc3d39ed6d756797e3b078d2c43f8a38288520aec6"}, {file = "coverage-6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9ed3244b415725f08ca3bdf02ed681089fd95e9465099a21c8e2d9c5d6ca2606"}, {file = "coverage-6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab4fc4b866b279740e0d917402f0e9a08683e002f43fa408e9655818ed392196"}, {file = "coverage-6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8582e9280f8d0f38114fe95a92ae8d0790b56b099d728cc4f8a2e14b1c4a18c"}, {file = "coverage-6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c72bb4679283c6737f452eeb9b2a0e570acaef2197ad255fb20162adc80bea76"}, {file = "coverage-6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca29c352389ea27a24c79acd117abdd8a865c6eb01576b6f0990cd9a4e9c9f48"}, {file = "coverage-6.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:152cc2624381df4e4e604e21bd8e95eb8059535f7b768c1fb8b8ae0b26f47ab0"}, {file = "coverage-6.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:51372e24b1f7143ee2df6b45cff6a721f3abe93b1e506196f3ffa4155c2497f7"}, {file = "coverage-6.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:72d9d186508325a456475dd05b1756f9a204c7086b07fffb227ef8cee03b1dc2"}, {file = "coverage-6.3-cp39-cp39-win32.whl", hash = "sha256:649df3641eb351cdfd0d5533c92fc9df507b6b2bf48a7ef8c71ab63cbc7b5c3c"}, {file = "coverage-6.3-cp39-cp39-win_amd64.whl", hash = "sha256:e67ccd53da5958ea1ec833a160b96357f90859c220a00150de011b787c27b98d"}, {file = "coverage-6.3-pp36.pp37.pp38-none-any.whl", hash = "sha256:27ac7cb84538e278e07569ceaaa6f807a029dc194b1c819a9820b9bb5dbf63ab"}, {file = "coverage-6.3.tar.gz", hash = "sha256:987a84ff98a309994ca77ed3cc4b92424f824278e48e4bf7d1bb79a63cfe2099"}, ] django = [ {file = "Django-3.2.12-py3-none-any.whl", hash = "sha256:9b06c289f9ba3a8abea16c9c9505f25107809fb933676f6c891ded270039d965"}, {file = "Django-3.2.12.tar.gz", hash = "sha256:9772e6935703e59e993960832d66a614cf0233a1c5123bc6224ecc6ad69e41e2"}, {file = "Django-4.0.2-py3-none-any.whl", hash = "sha256:996495c58bff749232426c88726d8cd38d24c94d7c1d80835aafffa9bc52985a"}, {file = "Django-4.0.2.tar.gz", hash = "sha256:110fb58fb12eca59e072ad59fc42d771cd642dd7a2f2416582aa9da7a8ef954a"}, ] djangorestframework = [ {file = "djangorestframework-3.13.1-py3-none-any.whl", hash = "sha256:24c4bf58ed7e85d1fe4ba250ab2da926d263cd57d64b03e8dcef0ac683f8b1aa"}, {file = "djangorestframework-3.13.1.tar.gz", hash = "sha256:0c33407ce23acc68eca2a6e46424b008c9c02eceb8cf18581921d0092bc1f2ee"}, ] flake8 = [ {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, ] importlib-metadata = [ {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] lazy-object-proxy = [ {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"}, {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"}, {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"}, {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"}, {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"}, {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"}, {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"}, {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"}, {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"}, {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"}, {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"}, {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"}, {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"}, {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"}, {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"}, {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"}, {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"}, {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"}, {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"}, {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"}, {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"}, {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"}, {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"}, {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"}, {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"}, {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"}, {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"}, {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"}, {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"}, {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"}, {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"}, {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"}, {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"}, {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"}, {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"}, {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] pathspec = [ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, ] platformdirs = [ {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"}, {file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"}, ] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] psycopg2-binary = [ {file = "psycopg2-binary-2.9.3.tar.gz", hash = "sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:539b28661b71da7c0e428692438efbcd048ca21ea81af618d845e06ebfd29478"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e82d38390a03da28c7985b394ec3f56873174e2c88130e6966cb1c946508e65"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57804fc02ca3ce0dbfbef35c4b3a4a774da66d66ea20f4bda601294ad2ea6092"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:083a55275f09a62b8ca4902dd11f4b33075b743cf0d360419e2051a8a5d5ff76"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:0a29729145aaaf1ad8bafe663131890e2111f13416b60e460dae0a96af5905c9"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a79d622f5206d695d7824cbf609a4f5b88ea6d6dab5f7c147fc6d333a8787e4"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:090f3348c0ab2cceb6dfbe6bf721ef61262ddf518cd6cc6ecc7d334996d64efa"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a9e1f75f96ea388fbcef36c70640c4efbe4650658f3d6a2967b4cc70e907352e"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c3ae8e75eb7160851e59adc77b3a19a976e50622e44fd4fd47b8b18208189d42"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-win32.whl", hash = "sha256:7b1e9b80afca7b7a386ef087db614faebbf8839b7f4db5eb107d0f1a53225029"}, {file = "psycopg2_binary-2.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:8b344adbb9a862de0c635f4f0425b7958bf5a4b927c8594e6e8d261775796d53"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:e847774f8ffd5b398a75bc1c18fbb56564cda3d629fe68fd81971fece2d3c67e"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68641a34023d306be959101b345732360fc2ea4938982309b786f7be1b43a4a1"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3303f8807f342641851578ee7ed1f3efc9802d00a6f83c101d21c608cb864460"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_24_aarch64.whl", hash = "sha256:e3699852e22aa68c10de06524a3721ade969abf382da95884e6a10ff798f9281"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_24_ppc64le.whl", hash = "sha256:526ea0378246d9b080148f2d6681229f4b5964543c170dd10bf4faaab6e0d27f"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:b1c8068513f5b158cf7e29c43a77eb34b407db29aca749d3eb9293ee0d3103ca"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:15803fa813ea05bef089fa78835118b5434204f3a17cb9f1e5dbfd0b9deea5af"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:152f09f57417b831418304c7f30d727dc83a12761627bb826951692cc6491e57"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:404224e5fef3b193f892abdbf8961ce20e0b6642886cfe1fe1923f41aaa75c9d"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-win32.whl", hash = "sha256:1f6b813106a3abdf7b03640d36e24669234120c72e91d5cbaeb87c5f7c36c65b"}, {file = "psycopg2_binary-2.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:2d872e3c9d5d075a2e104540965a1cf898b52274a5923936e5bfddb58c59c7c2"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:10bb90fb4d523a2aa67773d4ff2b833ec00857f5912bafcfd5f5414e45280fb1"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a52ecab70af13e899f7847b3e074eeb16ebac5615665db33bce8a1009cf33"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a29b3ca4ec9defec6d42bf5feb36bb5817ba3c0230dd83b4edf4bf02684cd0ae"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:12b11322ea00ad8db8c46f18b7dfc47ae215e4df55b46c67a94b4effbaec7094"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:53293533fcbb94c202b7c800a12c873cfe24599656b341f56e71dd2b557be063"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c381bda330ddf2fccbafab789d83ebc6c53db126e4383e73794c74eedce855ef"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d29409b625a143649d03d0fd7b57e4b92e0ecad9726ba682244b73be91d2fdb"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:183a517a3a63503f70f808b58bfbf962f23d73b6dccddae5aa56152ef2bcb232"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:15c4e4cfa45f5a60599d9cec5f46cd7b1b29d86a6390ec23e8eebaae84e64554"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:adf20d9a67e0b6393eac162eb81fb10bc9130a80540f4df7e7355c2dd4af9fba"}, {file = "psycopg2_binary-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:2f9ffd643bc7349eeb664eba8864d9e01f057880f510e4681ba40a6532f93c71"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:def68d7c21984b0f8218e8a15d514f714d96904265164f75f8d3a70f9c295667"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dffc08ca91c9ac09008870c9eb77b00a46b3378719584059c034b8945e26b272"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:280b0bb5cbfe8039205c7981cceb006156a675362a00fe29b16fbc264e242834"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:af9813db73395fb1fc211bac696faea4ca9ef53f32dc0cfa27e4e7cf766dcf24"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:63638d875be8c2784cfc952c9ac34e2b50e43f9f0a0660b65e2a87d656b3116c"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ffb7a888a047696e7f8240d649b43fb3644f14f0ee229077e7f6b9f9081635bd"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c9d5450c566c80c396b7402895c4369a410cab5a82707b11aee1e624da7d004"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:d1c1b569ecafe3a69380a94e6ae09a4789bbb23666f3d3a08d06bbd2451f5ef1"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8fc53f9af09426a61db9ba357865c77f26076d48669f2e1bb24d85a22fb52307"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-win32.whl", hash = "sha256:6472a178e291b59e7f16ab49ec8b4f3bdada0a879c68d3817ff0963e722a82ce"}, {file = "psycopg2_binary-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:35168209c9d51b145e459e05c31a9eaeffa9a6b0fd61689b48e07464ffd1a83e"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:47133f3f872faf28c1e87d4357220e809dfd3fa7c64295a4a148bcd1e6e34ec9"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91920527dea30175cc02a1099f331aa8c1ba39bf8b7762b7b56cbf54bc5cce42"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887dd9aac71765ac0d0bac1d0d4b4f2c99d5f5c1382d8b770404f0f3d0ce8a39"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:1f14c8b0942714eb3c74e1e71700cbbcb415acbc311c730370e70c578a44a25c"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:7af0dd86ddb2f8af5da57a976d27cd2cd15510518d582b478fbb2292428710b4"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93cd1967a18aa0edd4b95b1dfd554cf15af657cb606280996d393dadc88c3c35"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bda845b664bb6c91446ca9609fc69f7db6c334ec5e4adc87571c34e4f47b7ddb"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:01310cf4cf26db9aea5158c217caa92d291f0500051a6469ac52166e1a16f5b7"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99485cab9ba0fa9b84f1f9e1fef106f44a46ef6afdeec8885e0b88d0772b49e8"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-win32.whl", hash = "sha256:46f0e0a6b5fa5851bbd9ab1bc805eef362d3a230fbdfbc209f4a236d0a7a990d"}, {file = "psycopg2_binary-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:accfe7e982411da3178ec690baaceaad3c278652998b2c45828aaac66cd8285f"}, ] py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] pycodestyle = [ {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, ] pyflakes = [ {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, ] pylint = [ {file = "pylint-2.12.2-py3-none-any.whl", hash = "sha256:daabda3f7ed9d1c60f52d563b1b854632fd90035bcf01443e234d3dc794e3b74"}, {file = "pylint-2.12.2.tar.gz", hash = "sha256:9d945a73640e1fec07ee34b42f5669b770c759acd536ec7b16d7e4b87a9c9ff9"}, ] pyparsing = [ {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, ] pytest = [ {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] pytest-cov = [ {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, ] pytest-django = [ {file = "pytest-django-4.5.2.tar.gz", hash = "sha256:d9076f759bb7c36939dbdd5ae6633c18edfc2902d1a69fdbefd2426b970ce6c2"}, {file = "pytest_django-4.5.2-py3-none-any.whl", hash = "sha256:c60834861933773109334fe5a53e83d1ef4828f2203a1d6a0fa9972f4f75ab3e"}, ] pytest-lazy-fixture = [ {file = "pytest-lazy-fixture-0.6.3.tar.gz", hash = "sha256:0e7d0c7f74ba33e6e80905e9bfd81f9d15ef9a790de97993e34213deb5ad10ac"}, {file = "pytest_lazy_fixture-0.6.3-py3-none-any.whl", hash = "sha256:e0b379f38299ff27a653f03eaa69b08a6fd4484e46fd1c9907d984b9f9daeda6"}, ] pytest-pythonpath = [ {file = "pytest-pythonpath-0.7.3.tar.gz", hash = "sha256:63fc546ace7d2c845c1ee289e8f7a6362c2b6bae497d10c716e58e253e801d62"}, ] pytz = [ {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, ] sqlparse = [ {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"}, {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"}, ] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] tomli = [ {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, ] typed-ast = [ {file = "typed_ast-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266"}, {file = "typed_ast-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596"}, {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985"}, {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76"}, {file = "typed_ast-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a"}, {file = "typed_ast-1.5.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837"}, {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78"}, {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e"}, {file = "typed_ast-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d"}, {file = "typed_ast-1.5.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd"}, {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88"}, {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7"}, {file = "typed_ast-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30"}, {file = "typed_ast-1.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4"}, {file = "typed_ast-1.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca"}, {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb"}, {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b"}, {file = "typed_ast-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7"}, {file = "typed_ast-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098"}, {file = "typed_ast-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344"}, {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e"}, {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e"}, {file = "typed_ast-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5"}, {file = "typed_ast-1.5.2.tar.gz", hash = "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27"}, ] typing-extensions = [ {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, ] tzdata = [ {file = "tzdata-2021.5-py2.py3-none-any.whl", hash = "sha256:3eee491e22ebfe1e5cfcc97a4137cd70f092ce59144d81f8924a844de05ba8f5"}, {file = "tzdata-2021.5.tar.gz", hash = "sha256:68dbe41afd01b867894bbdfd54fa03f468cfa4f0086bfb4adcd8de8f24f3ee21"}, ] wrapt = [ {file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"}, {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"}, {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"}, {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"}, {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"}, {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"}, {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"}, {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"}, {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"}, {file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"}, {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"}, {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"}, {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"}, {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"}, {file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"}, {file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"}, {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"}, {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"}, {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"}, {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"}, {file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"}, {file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"}, {file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"}, {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"}, {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"}, {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"}, {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"}, {file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"}, {file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"}, {file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"}, {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"}, {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"}, {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"}, {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"}, {file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"}, {file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"}, {file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"}, {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"}, {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"}, {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"}, {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"}, {file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"}, {file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"}, {file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"}, {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"}, {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"}, {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"}, {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"}, {file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"}, {file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"}, {file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"}, ] zipp = [ {file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"}, {file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"}, ] django-timezone-field-5.0/pyproject.toml000066400000000000000000000032051420064327400204470ustar00rootroot00000000000000[build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" [tool.black] line-length = 120 [tool.coverage.run] relative_files = true [tool.isort] profile = "black" line_length = 120 [tool.poetry] name = "django-timezone-field" version = "5.0" description = "A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects." license = "BSD-2-Clause" authors = ["Mike Fogel "] readme = "README.md" repository = "https://github.com/mfogel/django-timezone-field/" classifiers = [ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: Django", "Framework :: Django :: 2.2", "Framework :: Django :: 3.2", "Framework :: Django :: 4.0", "Intended Audience :: Developers", "Operating System :: OS Independent", "Topic :: Utilities", ] packages = [ { include = "timezone_field" }, ] [tool.poetry.dependencies] python = "^3.7" pytz = "*" "backports.zoneinfo" = { version = "^0.2.1", python = "<3.9" } [tool.poetry.dev-dependencies] coverage = {extras = ["toml"], version = "^6.2"} Django = [ { version = "^2.2 || ^3.2", python = "~3.7" }, { version = "^2.2 || ^3.2 || ^4.0", python = "^3.8" }, ] djangorestframework = "^3.13.1" flake8 = "^4.0.1" psycopg2-binary = "^2.9.3" pytest = "^6.2.5" pytest-django = "^4.5.2" pytest-pythonpath = "^0.7.3" pytest-lazy-fixture = "^0.6.3" pytest-cov = "^3.0.0" black = "^21.12b0" isort = "^5.10.1" pylint = "^2.12.2" [tool.pylint.'MESSAGES CONTROL'] max-line-length = 120 disable = "C, R, redefined-outer-name" [tool.pytest.ini_options] DJANGO_SETTINGS_MODULE = "tests.settings" django-timezone-field-5.0/tests/000077500000000000000000000000001420064327400166755ustar00rootroot00000000000000django-timezone-field-5.0/tests/__init__.py000066400000000000000000000000001420064327400207740ustar00rootroot00000000000000django-timezone-field-5.0/tests/conftest.py000066400000000000000000000066421420064327400211040ustar00rootroot00000000000000import pytest import pytz from django import forms from django.db import models from timezone_field import TimeZoneField from timezone_field.compat import ZoneInfo USA_TZS = [ "US/Alaska", "US/Arizona", "US/Central", "US/Eastern", "US/Hawaii", "US/Mountain", "US/Pacific", ] class _TZModel(models.Model): tz = TimeZoneField(use_pytz=True) tz_opt = TimeZoneField(blank=True, use_pytz=True) tz_opt_default = TimeZoneField(blank=True, default="America/Los_Angeles", use_pytz=True) class _ZIModel(models.Model): tz = TimeZoneField(use_pytz=False) tz_opt = TimeZoneField(blank=True, use_pytz=False) tz_opt_default = TimeZoneField(blank=True, default="America/Los_Angeles", use_pytz=False) class _TZModelChoice(models.Model): tz_superset = TimeZoneField( choices=[(tz, tz) for tz in pytz.all_timezones], blank=True, use_pytz=True, ) tz_subset = TimeZoneField( choices=[(tz, tz) for tz in USA_TZS], blank=True, use_pytz=True, ) class _ZIModelChoice(models.Model): tz_superset = TimeZoneField( choices=[(tz, tz) for tz in pytz.all_timezones], blank=True, use_pytz=False, ) tz_subset = TimeZoneField( choices=[(tz, tz) for tz in USA_TZS], blank=True, use_pytz=False, ) class _TZModelOldChoiceFormat(models.Model): tz_superset = TimeZoneField( choices=[(pytz.timezone(tz), tz) for tz in pytz.all_timezones], blank=True, use_pytz=True, ) tz_subset = TimeZoneField( choices=[(pytz.timezone(tz), tz) for tz in USA_TZS], blank=True, use_pytz=True, ) class _ZIModelOldChoiceFormat(models.Model): tz_superset = TimeZoneField( choices=[(ZoneInfo(tz), tz) for tz in pytz.all_timezones], blank=True, use_pytz=False, ) tz_subset = TimeZoneField( choices=[(ZoneInfo(tz), tz) for tz in USA_TZS], blank=True, use_pytz=False, ) class _TZModelForm(forms.ModelForm): class Meta: model = _TZModel fields = "__all__" class _ZIModelForm(forms.ModelForm): class Meta: model = _ZIModel fields = "__all__" @pytest.fixture(params=[True, False]) def use_pytz(request): yield request.param @pytest.fixture def tz_func(use_pytz): yield pytz.timezone if use_pytz else ZoneInfo @pytest.fixture def Model(use_pytz): yield _TZModel if use_pytz else _ZIModel @pytest.fixture def ModelChoice(use_pytz): yield _TZModelChoice if use_pytz else _ZIModelChoice @pytest.fixture def ModelOldChoiceFormat(use_pytz): yield _TZModelOldChoiceFormat if use_pytz else _ZIModelOldChoiceFormat @pytest.fixture def ModelForm(use_pytz): yield _TZModelForm if use_pytz else _ZIModelForm @pytest.fixture def pst(): yield "America/Los_Angeles" @pytest.fixture def pst_tz(use_pytz, pst): yield (pytz.timezone(pst) if use_pytz else ZoneInfo(pst)) # pytz.tzinfo.DstTzInfo @pytest.fixture def gmt(): yield "GMT" @pytest.fixture def gmt_tz(use_pytz, gmt): yield (pytz.timezone(gmt) if use_pytz else ZoneInfo(gmt)) # pytz.tzinfo.StaticTzInfo @pytest.fixture def utc(): yield "UTC" @pytest.fixture def utc_tz(use_pytz, utc): yield (pytz.timezone(utc) if use_pytz else ZoneInfo(utc)) # pytz.utc singleton @pytest.fixture def uncommon_tz(): yield "Singapore" @pytest.fixture def invalid_tz(): yield "foobar" django-timezone-field-5.0/tests/models.py000066400000000000000000000000331420064327400205260ustar00rootroot00000000000000# intentionally left blank django-timezone-field-5.0/tests/settings.py000066400000000000000000000047211420064327400211130ustar00rootroot00000000000000""" Django settings for tests project. For more information on this file, see https://docs.djangoproject.com/en/1.7/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.7/ref/settings/ """ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = "unused" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True TEMPLATE_DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = ( "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "tests", "rest_framework", ) MIDDLEWARE_CLASSES = ( "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.auth.middleware.SessionAuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ) WSGI_APPLICATION = "tests.wsgi.application" # Database # https://docs.djangoproject.com/en/1.7/ref/settings/#databases db_engine = os.environ.get("DB_ENGINE", "sqlite") if db_engine == "sqlite": DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", }, } if db_engine == "postgres": DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql_psycopg2", "HOST": os.environ.get("POSTGRES_HOST"), "PORT": os.environ.get("POSTGRES_PORT", 5432), "NAME": os.environ.get("POSTGRES_DB", "timezone_field_tests"), "USER": os.environ.get("POSTGRES_USER", "postgres"), "PASSWORD": os.environ.get("POSTGRES_PASSWORD"), }, } # Internationalization # https://docs.djangoproject.com/en/1.7/topics/i18n/ LANGUAGE_CODE = "en-us" TIME_ZONE = "UTC" USE_I18N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.7/howto/static-files/ STATIC_URL = "/static/" DEFAULT_AUTO_FIELD = "django.db.models.AutoField" django-timezone-field-5.0/tests/test_choices.py000066400000000000000000000101221420064327400217170ustar00rootroot00000000000000from datetime import datetime import pytest import pytz from timezone_field.choices import standard, with_gmt_offset @pytest.fixture def tzs1(): # test timezones out of order, but they should appear in order in result. # avoiding an timezones that go through a Daylight Savings change here yield [ "Asia/Kathmandu", # 45 min off the hour "Asia/Kolkata", # 30 min off the hour "America/Argentina/Buenos_Aires", # on the hour "Asia/Qatar", # on the hour ] @pytest.fixture def tzs2(): # test timezones out of order, but they should appear in order in result. yield [ "Europe/London", "Canada/Newfoundland", # 30 min off the hour "America/Los_Angeles", # on the hour "America/Santiago", # southern hemisphere ] @pytest.fixture def tzs3_names(): yield [ "America/Los_Angeles", "Europe/London", "America/Argentina/Buenos_Aires", ] @pytest.fixture def tzs3_standard_displays(): yield [ "America/Los Angeles", "Europe/London", "America/Argentina/Buenos Aires", ] def test_with_gmt_offset_using_timezone_names(tzs1, use_pytz): assert with_gmt_offset(tzs1, use_pytz=use_pytz) == [ ("America/Argentina/Buenos_Aires", "GMT-03:00 America/Argentina/Buenos Aires"), ("Asia/Qatar", "GMT+03:00 Asia/Qatar"), ("Asia/Kolkata", "GMT+05:30 Asia/Kolkata"), ("Asia/Kathmandu", "GMT+05:45 Asia/Kathmandu"), ] def test_with_gmt_offset_using_timezone_objects(tzs1, use_pytz, tz_func): tz_objects = [tz_func(name) for name in tzs1] assert with_gmt_offset(tz_objects, use_pytz=use_pytz) == [ ( tz_func("America/Argentina/Buenos_Aires"), "GMT-03:00 America/Argentina/Buenos Aires", ), (tz_func("Asia/Qatar"), "GMT+03:00 Asia/Qatar"), (tz_func("Asia/Kolkata"), "GMT+05:30 Asia/Kolkata"), (tz_func("Asia/Kathmandu"), "GMT+05:45 Asia/Kathmandu"), ] def test_with_gmt_offset_in_northern_summer(tzs2, use_pytz): now = datetime(2020, 7, 15, tzinfo=pytz.utc) assert with_gmt_offset(tzs2, now=now, use_pytz=use_pytz) == [ ("America/Los_Angeles", "GMT-07:00 America/Los Angeles"), ("America/Santiago", "GMT-04:00 America/Santiago"), ("Canada/Newfoundland", "GMT-02:30 Canada/Newfoundland"), ("Europe/London", "GMT+01:00 Europe/London"), ] def test_with_gmt_offset_in_northern_winter(tzs2, use_pytz): now = datetime(2020, 1, 15, tzinfo=pytz.utc) assert with_gmt_offset(tzs2, now=now, use_pytz=use_pytz) == [ ("America/Los_Angeles", "GMT-08:00 America/Los Angeles"), ("Canada/Newfoundland", "GMT-03:30 Canada/Newfoundland"), ("America/Santiago", "GMT-03:00 America/Santiago"), ("Europe/London", "GMT+00:00 Europe/London"), ] def test_with_gmt_offset_transition_forward(use_pytz): tz_names = ["Europe/London"] before = datetime(2021, 3, 28, 0, 59, 59, 999999, tzinfo=pytz.utc) after = datetime(2021, 3, 28, 1, 0, 0, 0, tzinfo=pytz.utc) assert with_gmt_offset(tz_names, now=before, use_pytz=use_pytz) == [("Europe/London", "GMT+00:00 Europe/London")] assert with_gmt_offset(tz_names, now=after, use_pytz=use_pytz) == [("Europe/London", "GMT+01:00 Europe/London")] def test_with_gmt_offset_transition_backward(use_pytz): tz_names = ["Europe/London"] before = datetime(2021, 10, 31, 0, 59, 59, 999999, tzinfo=pytz.utc) after = datetime(2021, 10, 31, 1, 0, 0, 0, tzinfo=pytz.utc) assert with_gmt_offset(tz_names, now=before, use_pytz=use_pytz) == [("Europe/London", "GMT+01:00 Europe/London")] assert with_gmt_offset(tz_names, now=after, use_pytz=use_pytz) == [("Europe/London", "GMT+00:00 Europe/London")] def test_standard_using_timezone_names(tzs3_names, tzs3_standard_displays): assert standard(tzs3_names) == list(zip(tzs3_names, tzs3_standard_displays)) def test_standard_using_timezone_objects(tzs3_names, tzs3_standard_displays, tz_func): tzs3_objects = [tz_func(tz) for tz in tzs3_names] assert standard(tzs3_objects) == list(zip(tzs3_objects, tzs3_standard_displays)) django-timezone-field-5.0/tests/test_choices_display_option.py000066400000000000000000000215531420064327400250460ustar00rootroot00000000000000import pytest import pytz from django import forms from django.db import models from timezone_field import TimeZoneField, TimeZoneFormField common_tz_names = tuple(tz for tz in pytz.common_timezones) @pytest.fixture def common_tz_objects(tz_func): yield tuple(tz_func(tz) for tz in pytz.common_timezones) class _ZIChoicesDisplayForm(forms.Form): limited_tzs = [ "Asia/Tokyo", "Asia/Dubai", "America/Argentina/Buenos_Aires", "Africa/Nairobi", ] limited_choices = [(tz, tz) for tz in limited_tzs] tz_none = TimeZoneFormField(use_pytz=False) tz_standard = TimeZoneFormField(choices_display="STANDARD", use_pytz=False) tz_with_gmt_offset = TimeZoneFormField(choices_display="WITH_GMT_OFFSET", use_pytz=False) tz_limited_none = TimeZoneFormField(choices=limited_choices, use_pytz=False) tz_limited_standard = TimeZoneFormField( choices=limited_choices, choices_display="STANDARD", use_pytz=False, ) tz_limited_with_gmt_offset = TimeZoneFormField( choices=limited_choices, choices_display="WITH_GMT_OFFSET", use_pytz=False, ) class _TZChoicesDisplayForm(forms.Form): limited_tzs = [ "Asia/Tokyo", "Asia/Dubai", "America/Argentina/Buenos_Aires", "Africa/Nairobi", ] limited_choices = [(tz, tz) for tz in limited_tzs] tz_none = TimeZoneFormField(use_pytz=True) tz_standard = TimeZoneFormField(choices_display="STANDARD", use_pytz=True) tz_with_gmt_offset = TimeZoneFormField(choices_display="WITH_GMT_OFFSET", use_pytz=True) tz_limited_none = TimeZoneFormField(choices=limited_choices, use_pytz=True) tz_limited_standard = TimeZoneFormField( choices=limited_choices, choices_display="STANDARD", use_pytz=True, ) tz_limited_with_gmt_offset = TimeZoneFormField( choices=limited_choices, choices_display="WITH_GMT_OFFSET", use_pytz=True, ) class _ZIChoicesDisplayModel(models.Model): limited_tzs = [ "Asia/Tokyo", "Asia/Dubai", "America/Argentina/Buenos_Aires", "Africa/Nairobi", ] limited_choices = [(tz, tz) for tz in limited_tzs] tz_none = TimeZoneField(use_pytz=False) tz_standard = TimeZoneField(choices_display="STANDARD", use_pytz=False) tz_with_gmt_offset = TimeZoneField(choices_display="WITH_GMT_OFFSET", use_pytz=False) tz_limited_none = TimeZoneField(choices=limited_choices, use_pytz=False) tz_limited_standard = TimeZoneField( choices=limited_choices, choices_display="STANDARD", use_pytz=False, ) tz_limited_with_gmt_offset = TimeZoneField( choices=limited_choices, choices_display="WITH_GMT_OFFSET", use_pytz=False, ) class _TZChoicesDisplayModel(models.Model): limited_tzs = [ "Asia/Tokyo", "Asia/Dubai", "America/Argentina/Buenos_Aires", "Africa/Nairobi", ] limited_choices = [(tz, tz) for tz in limited_tzs] tz_none = TimeZoneField(use_pytz=True) tz_standard = TimeZoneField(choices_display="STANDARD", use_pytz=True) tz_with_gmt_offset = TimeZoneField(choices_display="WITH_GMT_OFFSET", use_pytz=True) tz_limited_none = TimeZoneField(choices=limited_choices, use_pytz=True) tz_limited_standard = TimeZoneField( choices=limited_choices, choices_display="STANDARD", use_pytz=True, ) tz_limited_with_gmt_offset = TimeZoneField( choices=limited_choices, choices_display="WITH_GMT_OFFSET", use_pytz=True, ) @pytest.fixture def ChoicesDisplayForm(use_pytz): yield _TZChoicesDisplayForm if use_pytz else _ZIChoicesDisplayForm @pytest.fixture def ChoicesDisplayModel(use_pytz): yield _TZChoicesDisplayModel if use_pytz else _ZIChoicesDisplayModel @pytest.fixture def ChoicesDisplayModelForm(ChoicesDisplayModel): class _ChoicesDisplayModelForm(forms.ModelForm): class Meta: model = ChoicesDisplayModel fields = "__all__" yield _ChoicesDisplayModelForm def test_db_field_invalid_choices_display(use_pytz): with pytest.raises(ValueError): TimeZoneField(choices_display="invalid", use_pytz=use_pytz) def test_form_field_invalid_choices_display(use_pytz): with pytest.raises(ValueError): TimeZoneFormField(choices_display="invalid", use_pytz=use_pytz) def test_form_field_none(ChoicesDisplayForm): form = ChoicesDisplayForm() values, displays = zip(*form.fields["tz_none"].choices) assert values == common_tz_names assert displays[values.index("America/Los_Angeles")] == "America/Los Angeles" assert displays[values.index("Asia/Kolkata")] == "Asia/Kolkata" def test_form_field_standard(ChoicesDisplayForm): form = ChoicesDisplayForm() assert form.fields["tz_standard"].choices == form.fields["tz_none"].choices def test_form_field_with_gmt_offset(ChoicesDisplayForm): form = ChoicesDisplayForm() values, displays = zip(*form.fields["tz_with_gmt_offset"].choices) assert values != common_tz_names assert sorted(values) == sorted(common_tz_names) assert displays[values.index("America/Argentina/Buenos_Aires")] == "GMT-03:00 America/Argentina/Buenos Aires" assert displays[values.index("Europe/Moscow")] == "GMT+03:00 Europe/Moscow" def test_form_field_limited_none(ChoicesDisplayForm): form = ChoicesDisplayForm() assert form.fields["tz_limited_none"].choices == [ ("Asia/Tokyo", "Asia/Tokyo"), ("Asia/Dubai", "Asia/Dubai"), ("America/Argentina/Buenos_Aires", "America/Argentina/Buenos_Aires"), ("Africa/Nairobi", "Africa/Nairobi"), ] def test_form_field_limited_standard(ChoicesDisplayForm): form = ChoicesDisplayForm() assert form.fields["tz_limited_standard"].choices == [ ("Asia/Tokyo", "Asia/Tokyo"), ("Asia/Dubai", "Asia/Dubai"), ("America/Argentina/Buenos_Aires", "America/Argentina/Buenos Aires"), ("Africa/Nairobi", "Africa/Nairobi"), ] def test_form_field_limited_with_gmt_offset(ChoicesDisplayForm): form = ChoicesDisplayForm() assert form.fields["tz_limited_with_gmt_offset"].choices == [ ("America/Argentina/Buenos_Aires", "GMT-03:00 America/Argentina/Buenos Aires"), ("Africa/Nairobi", "GMT+03:00 Africa/Nairobi"), ("Asia/Dubai", "GMT+04:00 Asia/Dubai"), ("Asia/Tokyo", "GMT+09:00 Asia/Tokyo"), ] def test_model_form_field_none(ChoicesDisplayModelForm, tz_func, common_tz_objects): form = ChoicesDisplayModelForm() values, displays = zip(*form.fields["tz_none"].choices) assert values == ("",) + common_tz_objects assert displays[values.index(tz_func("America/Los_Angeles"))] == "America/Los Angeles" assert displays[values.index(tz_func("Asia/Kolkata"))] == "Asia/Kolkata" def test_model_form_field_standard(ChoicesDisplayModelForm): form = ChoicesDisplayModelForm() assert form.fields["tz_standard"].choices == form.fields["tz_none"].choices def test_model_form_field_with_gmt_offset(ChoicesDisplayModelForm, tz_func, common_tz_objects): form = ChoicesDisplayModelForm() values, displays = zip(*form.fields["tz_with_gmt_offset"].choices) assert values != common_tz_objects assert sorted(str(v) for v in values) == sorted([""] + [str(tz) for tz in common_tz_objects]) assert ( displays[values.index(tz_func("America/Argentina/Buenos_Aires"))] == "GMT-03:00 America/Argentina/Buenos Aires" ) assert displays[values.index(tz_func("Europe/Moscow"))] == "GMT+03:00 Europe/Moscow" def test_model_form_field_limited_none(ChoicesDisplayModelForm, tz_func): form = ChoicesDisplayModelForm() assert form.fields["tz_limited_none"].choices == [ ("", "---------"), (tz_func("Asia/Tokyo"), "Asia/Tokyo"), (tz_func("Asia/Dubai"), "Asia/Dubai"), (tz_func("America/Argentina/Buenos_Aires"), "America/Argentina/Buenos_Aires"), (tz_func("Africa/Nairobi"), "Africa/Nairobi"), ] def test_moel_form_field_limited_standard(ChoicesDisplayModelForm, tz_func): form = ChoicesDisplayModelForm() assert form.fields["tz_limited_standard"].choices == [ ("", "---------"), (tz_func("Asia/Tokyo"), "Asia/Tokyo"), (tz_func("Asia/Dubai"), "Asia/Dubai"), (tz_func("America/Argentina/Buenos_Aires"), "America/Argentina/Buenos Aires"), (tz_func("Africa/Nairobi"), "Africa/Nairobi"), ] def test_model_form_field_limited_with_gmt_offset(ChoicesDisplayModelForm, tz_func): form = ChoicesDisplayModelForm() assert form.fields["tz_limited_with_gmt_offset"].choices == [ ("", "---------"), ( tz_func("America/Argentina/Buenos_Aires"), "GMT-03:00 America/Argentina/Buenos Aires", ), (tz_func("Africa/Nairobi"), "GMT+03:00 Africa/Nairobi"), (tz_func("Asia/Dubai"), "GMT+04:00 Asia/Dubai"), (tz_func("Asia/Tokyo"), "GMT+09:00 Asia/Tokyo"), ] django-timezone-field-5.0/tests/test_deconstruct.py000066400000000000000000000136411420064327400226500ustar00rootroot00000000000000import pytest import pytz from django.db.migrations.writer import MigrationWriter from timezone_field import TimeZoneField from timezone_field.compat import ZoneInfo test_fields = [ TimeZoneField(), TimeZoneField(default="UTC"), TimeZoneField(max_length=42), TimeZoneField(use_pytz=True), TimeZoneField(use_pytz=False), TimeZoneField(choices=[("US/Pacific", "US/Pacific"), ("US/Eastern", "US/Eastern")]), TimeZoneField(choices=[(b"US/Pacific", b"US/Pacific"), (b"US/Eastern", b"US/Eastern")]), TimeZoneField( choices=[(pytz.timezone("US/Pacific"), "US/Pacific"), (pytz.timezone("US/Eastern"), "US/Eastern")], use_pytz=True, ), TimeZoneField( choices=[(ZoneInfo("US/Pacific"), "US/Pacific"), (ZoneInfo("US/Eastern"), "US/Eastern")], use_pytz=False, ), ] @pytest.mark.parametrize("field", test_fields) def test_deconstruct(field): _name, _path, args, kwargs = field.deconstruct() new_field = TimeZoneField(*args, **kwargs) assert field.max_length == new_field.max_length assert field.choices == new_field.choices @pytest.mark.parametrize("field", test_fields) def test_full_serialization(field): # ensure the values passed to kwarg arguments can be serialized # the recommended 'deconstruct' testing by django docs doesn't cut it # https://docs.djangoproject.com/en/1.7/howto/custom-model-fields/#field-deconstruction # replicates https://github.com/mfogel/django-timezone-field/issues/12 MigrationWriter.serialize(field) # should not throw def test_from_db_value(use_pytz): """ Verify that the field can handle data coming back as bytes from the db. """ field = TimeZoneField(use_pytz=use_pytz) utc = pytz.UTC if use_pytz else ZoneInfo("UTC") value = field.from_db_value(b"UTC", None, None) assert utc == value def test_default_kwargs_not_frozen(): """ Ensure the deconstructed representation of the field does not contain kwargs if they match the default. Don't want to bloat everyone's migration files. """ field = TimeZoneField() _name, _path, _args, kwargs = field.deconstruct() assert "choices" not in kwargs assert "max_length" not in kwargs def test_specifying_defaults_not_frozen(): """ If someone's matched the default values with their kwarg args, we shouldn't bothering freezing those (excluding the use_pytz, which changes with your django version). """ field = TimeZoneField(max_length=63) _name, _path, _args, kwargs = field.deconstruct() assert "max_length" not in kwargs choices = [(tz, tz.replace("_", " ")) for tz in pytz.common_timezones] field = TimeZoneField(choices=choices) _name, _path, _args, kwargs = field.deconstruct() assert "choices" not in kwargs choices = [(pytz.timezone(tz), tz.replace("_", " ")) for tz in pytz.common_timezones] field = TimeZoneField(choices=choices, use_pytz=True) _name, _path, _args, kwargs = field.deconstruct() assert "choices" not in kwargs choices = [(ZoneInfo(tz), tz.replace("_", " ")) for tz in pytz.common_timezones] field = TimeZoneField(choices=choices, use_pytz=False) _name, _path, _args, kwargs = field.deconstruct() assert "choices" not in kwargs @pytest.mark.parametrize( "choices, use_pytz", [ [ [("US/Pacific", "US/Pacific"), ("US/Eastern", "US/Eastern")], None, ], [ [(pytz.timezone("US/Pacific"), "US/Pacific"), (pytz.timezone("US/Eastern"), "US/Eastern")], True, ], [ [(ZoneInfo("US/Pacific"), "US/Pacific"), (ZoneInfo("US/Eastern"), "US/Eastern")], False, ], ], ) def test_deconstruct_when_using_choices(choices, use_pytz): field = TimeZoneField(choices=choices, use_pytz=use_pytz) _name, _path, _args, kwargs = field.deconstruct() assert kwargs == { **{ "choices": [ ("US/Pacific", "US/Pacific"), ("US/Eastern", "US/Eastern"), ] }, **({"use_pytz": use_pytz} if use_pytz is not None else {}), } @pytest.mark.parametrize( "choices_display, expected_kwargs", [ [None, {}], ["STANDARD", {"choices_display": "STANDARD"}], ["WITH_GMT_OFFSET", {"choices_display": "WITH_GMT_OFFSET"}], ], ) def test_deconstruct_when_using_choices_display(choices_display, expected_kwargs): field = TimeZoneField(choices_display=choices_display) _name, _path, _args, kwargs = field.deconstruct() assert kwargs == expected_kwargs @pytest.mark.parametrize( "choices, choices_display, expected_kwargs", [ [ [["US/Pacific", "West Coast Time"]], None, {"choices": [("US/Pacific", "West Coast Time")]}, ], [ [["US/Pacific", "West Coast Time"]], "STANDARD", {"choices": [("US/Pacific", "")], "choices_display": "STANDARD"}, ], [ [["US/Pacific", "West Coast Time"]], "WITH_GMT_OFFSET", {"choices": [("US/Pacific", "")], "choices_display": "WITH_GMT_OFFSET"}, ], [ [[tz, "ignored"] for tz in pytz.common_timezones], "WITH_GMT_OFFSET", {"choices_display": "WITH_GMT_OFFSET"}, ], ], ) def test_deconstruct_when_using_choices_and_choices_display(choices, choices_display, expected_kwargs): field = TimeZoneField(choices=choices, choices_display=choices_display) _name, _path, _args, kwargs = field.deconstruct() assert kwargs == expected_kwargs @pytest.mark.parametrize( "use_pytz, expected_kwargs", [ [None, {}], [True, {"use_pytz": True}], [False, {"use_pytz": False}], ], ) def test_deconstruct_when_using_use_pytz(use_pytz, expected_kwargs): field = TimeZoneField(use_pytz=use_pytz) _name, _path, _args, kwargs = field.deconstruct() assert kwargs == expected_kwargs django-timezone-field-5.0/tests/test_field.py000066400000000000000000000067001420064327400213740ustar00rootroot00000000000000import pytest from django.core.exceptions import ValidationError from pytest_lazyfixture import lazy_fixture from timezone_field import TimeZoneField @pytest.mark.django_db @pytest.mark.parametrize( "input_tz, output_tz", [ [lazy_fixture("pst"), lazy_fixture("pst_tz")], [lazy_fixture("pst_tz"), lazy_fixture("pst_tz")], [lazy_fixture("gmt"), lazy_fixture("gmt_tz")], [lazy_fixture("gmt_tz"), lazy_fixture("gmt_tz")], [lazy_fixture("utc"), lazy_fixture("utc_tz")], [lazy_fixture("utc_tz"), lazy_fixture("utc_tz")], ], ) def test_valid_dst_tz(Model, input_tz, output_tz): m = Model.objects.create(tz=input_tz, tz_opt=input_tz, tz_opt_default=input_tz) m.full_clean() m = Model.objects.get(pk=m.pk) assert m.tz == output_tz assert m.tz_opt == output_tz assert m.tz_opt_default == output_tz @pytest.mark.django_db def test_valid_default_values(Model, utc_tz, pst_tz): m = Model.objects.create(tz=utc_tz) m.full_clean() m = Model.objects.get(pk=m.pk) assert m.tz_opt is None assert m.tz_opt_default == pst_tz def test_valid_default_values_without_saving_to_db(Model, utc_tz, pst_tz): m = Model(tz=utc_tz) m.full_clean() assert m.tz_opt is None assert m.tz_opt_default == pst_tz @pytest.mark.django_db @pytest.mark.parametrize("tz_opt", ["", None]) def test_valid_blank(Model, pst, tz_opt): m = Model.objects.create(tz=pst, tz_opt=tz_opt) m.full_clean() m = Model.objects.get(pk=m.pk) assert m.tz_opt is None @pytest.mark.django_db @pytest.mark.parametrize("filter_tz", [lazy_fixture("pst"), lazy_fixture("pst_tz")]) def test_string_value_lookup(Model, pst, filter_tz): Model.objects.create(tz=pst) qs = Model.objects.filter(tz=filter_tz) assert qs.count() == 1 @pytest.mark.parametrize("tz", [None, "", "not-a-tz", 4, object()]) def test_invalid_input(Model, tz): m = Model(tz=tz) with pytest.raises(ValidationError): m.full_clean() def test_three_positional_args_does_not_throw(): TimeZoneField("a verbose name", "a name", True) def test_four_positional_args_throws(): with pytest.raises(ValueError): TimeZoneField("a verbose name", "a name", True, 42) def test_default_human_readable_choices_dont_have_underscores(Model, pst_tz): m = Model(tz=pst_tz) assert m.get_tz_display() == "America/Los Angeles" @pytest.mark.django_db def test_with_limited_choices_valid_choice(ModelChoice, pst, pst_tz): ModelChoice.objects.create(tz_superset=pst, tz_subset=pst) m = ModelChoice.objects.get() assert m.tz_superset == pst_tz assert m.tz_subset == pst_tz @pytest.mark.parametrize("kwargs", [{"tz_superset": "not a tz"}, {"tz_subset": "Europe/Brussels"}]) def test_with_limited_choices_invalid_choice(ModelChoice, kwargs): m = ModelChoice(**kwargs) with pytest.raises(ValidationError): m.full_clean() @pytest.mark.django_db def test_with_limited_choices_old_format_valid_choice(ModelOldChoiceFormat, pst, pst_tz): ModelOldChoiceFormat.objects.create(tz_superset=pst, tz_subset=pst) m = ModelOldChoiceFormat.objects.get() assert m.tz_superset == pst_tz assert m.tz_subset == pst_tz @pytest.mark.parametrize("kwargs", [{"tz_superset": "not a tz"}, {"tz_subset": "Europe/Brussels"}]) def test_with_limited_choices_old_format_invalid_choice(ModelOldChoiceFormat, kwargs): m = ModelOldChoiceFormat(**kwargs) with pytest.raises(ValidationError): m.full_clean() django-timezone-field-5.0/tests/test_form_field.py000066400000000000000000000035731420064327400224240ustar00rootroot00000000000000import pytest import pytz from django import forms from pytest_lazyfixture import lazy_fixture from timezone_field import TimeZoneFormField @pytest.fixture def Form(use_pytz): class _Form(forms.Form): tz = TimeZoneFormField(use_pytz=use_pytz) tz_opt = TimeZoneFormField(required=False, use_pytz=use_pytz) yield _Form @pytest.fixture def FormInvalidChoice(use_pytz, invalid_tz): class _FormInvalidChoice(forms.Form): tz = TimeZoneFormField( choices=([(tz, tz) for tz in pytz.all_timezones] + [(invalid_tz, pytz.utc)]), use_pytz=use_pytz ) yield _FormInvalidChoice def test_form_valid1(Form, pst, pst_tz): form = Form({"tz": pst}) assert form.is_valid() assert form.cleaned_data["tz"] == pst_tz assert form.cleaned_data["tz_opt"] is None def test_form_valid2(Form, gmt, gmt_tz, utc, utc_tz): form = Form({"tz": gmt, "tz_opt": utc}) assert form.is_valid() assert form.cleaned_data["tz"] == gmt_tz assert form.cleaned_data["tz_opt"] == utc_tz @pytest.mark.parametrize( "tz, tz_invalid_choice", [ [lazy_fixture("invalid_tz"), None], [None, lazy_fixture("invalid_tz")], [lazy_fixture("uncommon_tz"), None], ], ) def test_form_invalid(Form, tz, tz_invalid_choice): form = Form({"tz": tz, "tz_invalid_choice": tz_invalid_choice}) assert not form.is_valid() def test_form_default_human_readable_choices_dont_have_underscores(Form): form = Form() for choice in form.fields["tz"].choices: assert "_" not in choice[1] def test_form_invalid_choice_valid(FormInvalidChoice, pst, pst_tz): form = FormInvalidChoice({"tz": pst}) assert form.is_valid() assert form.cleaned_data["tz"] == pst_tz def test_form_invalid_chocie_invalid_choice(FormInvalidChoice, invalid_tz): form = FormInvalidChoice({"tz": invalid_tz}) assert not form.is_valid() django-timezone-field-5.0/tests/test_model_form_field.py000066400000000000000000000032401420064327400235730ustar00rootroot00000000000000import pytest from pytest_lazyfixture import lazy_fixture @pytest.mark.django_db def test_valid_with_defaults(Model, ModelForm, pst_tz, gmt, gmt_tz): # seems there should be a better way to get a form's default values...? # http://stackoverflow.com/questions/7399490/ data = dict((field_name, field.initial) for field_name, field in ModelForm().fields.items()) data.update({"tz": gmt}) form = ModelForm(data=data) assert form.is_valid() form.save() assert Model.objects.count() == 1 m = Model.objects.get() assert m.tz == gmt_tz assert m.tz_opt is None assert m.tz_opt_default == pst_tz @pytest.mark.django_db def test_valid_specify_all(Model, ModelForm, utc, pst, gmt, utc_tz, gmt_tz, pst_tz): form = ModelForm( { "tz": utc, "tz_opt": pst, "tz_opt_default": gmt, } ) assert form.is_valid() form.save() assert Model.objects.count() == 1 m = Model.objects.get() assert m.tz == utc_tz assert m.tz_opt == pst_tz assert m.tz_opt_default == gmt_tz @pytest.mark.parametrize( "tz, error_keyword", [ [None, "required"], [lazy_fixture("invalid_tz"), "choice"], [lazy_fixture("uncommon_tz"), "choice"], ], ) def test_invalid_not_blank(ModelForm, tz, error_keyword): form = ModelForm({"tz": tz}) assert not form.is_valid() assert any(error_keyword in e for e in form.errors["tz"]) def test_default_human_readable_choices_dont_have_underscores(ModelForm, pst_tz): form = ModelForm() pst_choice = [c for c in form.fields["tz"].choices if c[0] == pst_tz] assert pst_choice[0][1] == "America/Los Angeles" django-timezone-field-5.0/tests/test_serializer_field.py000066400000000000000000000021651420064327400236260ustar00rootroot00000000000000import pytest from rest_framework import serializers from timezone_field.rest_framework import TimeZoneSerializerField @pytest.fixture def TimeZoneSerializer(use_pytz): class _TimeZoneSerializer(serializers.Serializer): # pylint: disable=abstract-method tz = TimeZoneSerializerField(use_pytz=use_pytz) yield _TimeZoneSerializer def test_invalid_str(TimeZoneSerializer, invalid_tz): serializer = TimeZoneSerializer(data={"tz": invalid_tz}) assert not serializer.is_valid() def test_valid(TimeZoneSerializer, pst, pst_tz): serializer = TimeZoneSerializer(data={"tz": pst}) assert serializer.is_valid() assert serializer.validated_data["tz"] == pst_tz def test_valid_representation(TimeZoneSerializer, pst): serializer = TimeZoneSerializer(data={"tz": pst}) assert serializer.is_valid() assert serializer.data["tz"] == pst def test_valid_with_timezone_object(TimeZoneSerializer, pst, pst_tz): serializer = TimeZoneSerializer(data={"tz": pst_tz}) assert serializer.is_valid() assert serializer.data["tz"] == pst assert serializer.validated_data["tz"] == pst_tz django-timezone-field-5.0/tests/test_utils.py000066400000000000000000000012751420064327400214530ustar00rootroot00000000000000import warnings import pytest from django import VERSION from timezone_field.utils import use_pytz_default def test_use_pytz_default_USE_DEPRECATED_PYTZ_unset(): assert use_pytz_default() is (VERSION < (4, 0)) @pytest.mark.skipif(VERSION[0] != 4, reason="settings.USE_DEPRECATED_PYTZ exists only in django 4.x") @pytest.mark.parametrize("value", [True, False]) def test_use_pytz_default_USE_DEPRECATED_PYTZ_set(settings, value): from django.utils.deprecation import RemovedInDjango50Warning with warnings.catch_warnings(): warnings.simplefilter("ignore", category=RemovedInDjango50Warning) settings.USE_DEPRECATED_PYTZ = value assert use_pytz_default() is value django-timezone-field-5.0/timezone_field/000077500000000000000000000000001420064327400205305ustar00rootroot00000000000000django-timezone-field-5.0/timezone_field/__init__.py000066400000000000000000000002511420064327400226370ustar00rootroot00000000000000from timezone_field.fields import TimeZoneField from timezone_field.forms import TimeZoneFormField __version__ = "5.0" __all__ = ["TimeZoneField", "TimeZoneFormField"] django-timezone-field-5.0/timezone_field/choices.py000066400000000000000000000033041420064327400225170ustar00rootroot00000000000000import datetime import pytz from timezone_field.compat import ZoneInfo from timezone_field.utils import use_pytz_default def standard(timezones): """ Given a list of timezones (either strings of timezone objects), return a list of choices with * values equal to what was passed in * display strings as the timezone name without underscores """ choices = [] for tz in timezones: tz_str = str(tz) choices.append((tz, tz_str.replace("_", " "))) return choices def with_gmt_offset(timezones, now=None, use_pytz=None): """ Given a list of timezones (either strings of timezone objects), return a list of choices with * values equal to what was passed in * display strings formated with GMT offsets and without underscores. For example: "GMT-05:00 America/New York" * sorted by their timezone offset """ use_pytz = use_pytz_default() if use_pytz is None else use_pytz if use_pytz: utc = pytz.utc timezone_func = pytz.timezone else: utc = ZoneInfo("UTC") timezone_func = ZoneInfo now = now or datetime.datetime.now(utc) _choices = [] for tz in timezones: tz_str = str(tz) now_tz = now.astimezone(timezone_func(tz_str)) delta = now_tz.replace(tzinfo=utc) - now display = "GMT{sign}{gmt_diff} {timezone}".format( sign="+" if delta == abs(delta) else "-", gmt_diff=str(abs(delta)).zfill(8)[:-3], timezone=tz_str.replace("_", " "), ) _choices.append((delta, tz, display)) _choices.sort(key=lambda x: x[0]) choices = [(one, two) for zero, one, two in _choices] return choices django-timezone-field-5.0/timezone_field/compat.py000066400000000000000000000003041420064327400223620ustar00rootroot00000000000000try: from zoneinfo import ZoneInfo, ZoneInfoNotFoundError # pylint: disable=unused-import except ImportError: from backports.zoneinfo import ZoneInfo, ZoneInfoNotFoundError # noqa: F401 django-timezone-field-5.0/timezone_field/fields.py000066400000000000000000000155611420064327400223600ustar00rootroot00000000000000import pytz from django.core.exceptions import ValidationError from django.db import models from django.utils.encoding import force_str from timezone_field.choices import standard, with_gmt_offset from timezone_field.compat import ZoneInfo, ZoneInfoNotFoundError from timezone_field.utils import is_pytz_instance, use_pytz_default class TimeZoneField(models.Field): """ Provides database store for pytz timezone objects. Valid inputs: * any instance of pytz.tzinfo.DstTzInfo or pytz.tzinfo.StaticTzInfo * the pytz.UTC singleton * any string that validates against pytz.common_timezones. pytz will be used to build a timezone object from the string. * None and the empty string both represent 'no timezone' Valid outputs: * None * instances of pytz.tzinfo.DstTzInfo and pytz.tzinfo.StaticTzInfo * the pytz.UTC singleton Blank values are stored in the DB as the empty string. Timezones are stored in their string representation. The `choices` kwarg can be specified as a list of either [, ] or [, ]. Internally, it is stored as [, ]. """ description = "A timezone object" # NOTE: these defaults are excluded from migrations. If these are changed, # existing migration files will need to be accomodated. default_max_length = 63 default_pytz_tzs = [pytz.timezone(tz) for tz in pytz.common_timezones] default_zoneinfo_tzs = [ZoneInfo(tz) for tz in pytz.common_timezones] def __init__(self, *args, **kwargs): # allow some use of positional args up until the args we customize # https://github.com/mfogel/django-timezone-field/issues/42 # https://github.com/django/django/blob/1.11.11/django/db/models/fields/__init__.py#L145 if len(args) > 3: raise ValueError("Cannot specify max_length by positional arg") kwargs.setdefault("max_length", self.default_max_length) self.use_pytz_explicit = kwargs.pop("use_pytz", None) self.use_pytz = self.use_pytz_explicit if self.use_pytz_explicit is not None else use_pytz_default() self.default_tzs = self.default_pytz_tzs if self.use_pytz else self.default_zoneinfo_tzs if "choices" in kwargs: values, displays = zip(*kwargs["choices"]) # Choices can be specified in two forms: either # [, ] or [, ] # # The [, ] format is the one we actually # store the choices in memory because of # https://github.com/mfogel/django-timezone-field/issues/24 # # The [, ] format is supported because since django # can't deconstruct pytz.timezone objects, migration files must # use an alternate format. Representing the timezones as strings # is the obvious choice. if self.use_pytz and not is_pytz_instance(values[0]): values = [pytz.timezone(v) for v in values] elif not self.use_pytz and not isinstance(values[0], ZoneInfo): # using force_str b/c of https://github.com/mfogel/django-timezone-field/issues/38 values = [ZoneInfo(force_str(v)) for v in values] else: values = self.default_tzs displays = None self.choices_display = kwargs.pop("choices_display", None) if self.choices_display == "WITH_GMT_OFFSET": choices = with_gmt_offset(values, use_pytz=self.use_pytz) elif self.choices_display == "STANDARD": choices = standard(values) elif self.choices_display is None: choices = zip(values, displays) if displays else standard(values) else: raise ValueError(f"Unrecognized value for kwarg 'choices_display' of '{self.choices_display}'") kwargs["choices"] = choices super().__init__(*args, **kwargs) def validate(self, value, model_instance): if (self.use_pytz and not is_pytz_instance(value)) or (not self.use_pytz and not isinstance(value, ZoneInfo)): raise ValidationError(f"'{value}' is not a pytz timezone object") super().validate(value, model_instance) def deconstruct(self): name, path, args, kwargs = super().deconstruct() if kwargs.get("max_length") == self.default_max_length: del kwargs["max_length"] if self.use_pytz_explicit is not None: kwargs["use_pytz"] = self.use_pytz_explicit if self.choices_display is not None: kwargs["choices_display"] = self.choices_display choices = kwargs["choices"] if self.choices_display is None: if choices == standard(self.default_tzs): kwargs.pop("choices") else: values, _ = zip(*choices) if sorted(values, key=str) == sorted(self.default_tzs, key=str): kwargs.pop("choices") else: kwargs["choices"] = [(value, "") for value in values] # django can't decontruct pytz objects, so transform choices # to [, ] format for writing out to the migration if "choices" in kwargs: kwargs["choices"] = [(str(tz), n) for tz, n in kwargs["choices"]] return name, path, args, kwargs def get_internal_type(self): return "CharField" def get_default(self): # allow defaults to be still specified as strings. Allows for easy # serialization into migration files value = super().get_default() return self._get_python_and_db_repr(value)[0] def from_db_value(self, value, *_args): "Convert to pytz timezone object" return self._get_python_and_db_repr(value)[0] def to_python(self, value): "Convert to pytz timezone object" return self._get_python_and_db_repr(value)[0] def get_prep_value(self, value): "Convert to string describing a valid pytz timezone object" return self._get_python_and_db_repr(value)[1] def _get_python_and_db_repr(self, value): "Returns a tuple of (python representation, db representation)" if value is None or value == "": return (None, "") if self.use_pytz: if is_pytz_instance(value): return (value, value.zone) try: return (pytz.timezone(force_str(value)), force_str(value)) except pytz.UnknownTimeZoneError: pass else: if isinstance(value, ZoneInfo): return (value, value.key) try: # using force_str b/c of https://github.com/mfogel/django-timezone-field/issues/38 return (ZoneInfo(force_str(value)), force_str(value)) except ZoneInfoNotFoundError: pass raise ValidationError(f"Invalid timezone '{value}'") django-timezone-field-5.0/timezone_field/forms.py000066400000000000000000000032201420064327400222250ustar00rootroot00000000000000import pytz from django import forms from django.core.exceptions import ValidationError from timezone_field.choices import standard, with_gmt_offset from timezone_field.compat import ZoneInfo, ZoneInfoNotFoundError from timezone_field.utils import use_pytz_default def coerce_to_pytz(val): try: return pytz.timezone(val) except pytz.UnknownTimeZoneError as err: raise ValidationError(f"Unknown time zone: '{val}'") from err def coerce_to_zoneinfo(val): try: return ZoneInfo(val) except ZoneInfoNotFoundError as err: raise ValidationError(f"Unknown time zone: '{val}'") from err class TimeZoneFormField(forms.TypedChoiceField): def __init__(self, *args, **kwargs): self.use_pytz = kwargs.pop("use_pytz", use_pytz_default()) kwargs.setdefault("coerce", coerce_to_pytz if self.use_pytz else coerce_to_zoneinfo) kwargs.setdefault("empty_value", None) if "choices" in kwargs: values, displays = zip(*kwargs["choices"]) else: values = pytz.common_timezones displays = None choices_display = kwargs.pop("choices_display", None) if choices_display == "WITH_GMT_OFFSET": choices = with_gmt_offset(values, use_pytz=self.use_pytz) elif choices_display == "STANDARD": choices = standard(values) elif choices_display is None: choices = zip(values, displays) if displays else standard(values) else: raise ValueError(f"Unrecognized value for kwarg 'choices_display' of '{choices_display}'") kwargs["choices"] = choices super().__init__(*args, **kwargs) django-timezone-field-5.0/timezone_field/models.py000066400000000000000000000000331420064327400223610ustar00rootroot00000000000000# intentionally left blank django-timezone-field-5.0/timezone_field/rest_framework.py000066400000000000000000000017451420064327400241430ustar00rootroot00000000000000import pytz from django.utils.encoding import force_str from django.utils.translation import gettext_lazy as _ from rest_framework.fields import Field from timezone_field.compat import ZoneInfo, ZoneInfoNotFoundError from timezone_field.utils import use_pytz_default class TimeZoneSerializerField(Field): default_error_messages = { "invalid": _("A valid timezone is required."), } def __init__(self, *args, **kwargs): self.use_pytz = kwargs.pop("use_pytz", use_pytz_default()) super().__init__(*args, **kwargs) def to_internal_value(self, data): if self.use_pytz: try: return pytz.timezone(force_str(data)) except pytz.UnknownTimeZoneError: self.fail("invalid") else: try: return ZoneInfo(force_str(data)) except ZoneInfoNotFoundError: self.fail("invalid") def to_representation(self, value): return str(value) django-timezone-field-5.0/timezone_field/utils.py000066400000000000000000000003731420064327400222450ustar00rootroot00000000000000import pytz from django import VERSION, conf def is_pytz_instance(value): return value is pytz.UTC or isinstance(value, pytz.tzinfo.BaseTzInfo) def use_pytz_default(): return getattr(conf.settings, "USE_DEPRECATED_PYTZ", VERSION < (4, 0))