From f46626e2f22012d4d649114c61fad20d80afda64 Mon Sep 17 00:00:00 2001 From: cnotbohm Date: Wed, 4 Mar 2026 21:15:52 +0000 Subject: [PATCH 1/3] update to poetry --- .github/workflows/action.yml | 76 ---- .github/workflows/publish.yml | 89 +++++ .github/workflows/python-version-tests.yml | 70 ++++ AUTHORS.md | 13 + AUTHORS.rst | 13 - CHANGELOG.md | 75 ++++ CHANGELOG.rst | 74 ---- MANIFEST.in | 2 +- Makefile | 32 ++ README.md | 47 +++ README.rst | 58 --- build.sh | 9 - lint.sh | 25 -- poetry.lock | 434 +++++++++++++++++++++ pyproject.toml | 41 ++ setup.py | 99 ----- tests/run_tests.py | 58 +++ 17 files changed, 860 insertions(+), 355 deletions(-) delete mode 100644 .github/workflows/action.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/python-version-tests.yml create mode 100644 AUTHORS.md delete mode 100644 AUTHORS.rst create mode 100644 CHANGELOG.md delete mode 100644 CHANGELOG.rst create mode 100644 Makefile create mode 100644 README.md delete mode 100644 README.rst delete mode 100755 build.sh delete mode 100755 lint.sh create mode 100644 poetry.lock create mode 100644 pyproject.toml delete mode 100755 setup.py create mode 100644 tests/run_tests.py diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml deleted file mode 100644 index 84128c0..0000000 --- a/.github/workflows/action.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Python package - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - test: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - django-version: ['3.2', '4.0', '4.1', '4.2', '5.0'] - services: - postgres: - image: postgres:12 - ports: - - 5432:5432 - options: >- - --health-cmd=pg_isready - --health-interval=10s - --health-timeout=5s - --health-retries=5 - env: - POSTGRES_DB: testdb - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - mysql: - image: mysql:8 - ports: - - 3306:3306 - options: >- - --health-cmd="mysqladmin ping" - --health-interval=10s - --health-timeout=5s - --health-retries=5 - env: - MYSQL_USER: travis - MYSQL_PASSWORD: travis - MYSQL_ALLOW_EMPTY_PASSWORD: true - MYSQL_DATABASE: test_testdb - steps: - - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - name: Test versions Python ${{ matrix.python-version }} Django ${{ matrix.django-version }} - shell: bash - run: | - if [[ "${{ matrix.python-version }}" == "3.8" && "${{ matrix.django-version }}" == "5.0" ]]; then - echo "Skipping unsupported Python/Django combination" - exit 0 - elif [[ "${{ matrix.python-version }}" == "3.9" && "${{ matrix.django-version }}" == "5.0" ]]; then - echo "Skipping unsupported Python/Django combination" - exit 0 - elif [[ "${{ matrix.python-version }}" == "3.11" && ( "${{ matrix.django-version }}" == "3.2" || "${{ matrix.django-version }}" == "4.0" ) ]]; then - echo "Skipping unsupported Python/Django combination" - exit 0 - elif [[ "${{ matrix.python-version }}" == "3.12" && ( "${{ matrix.django-version }}" == "3.2" || "${{ matrix.django-version }}" == "4.0" || "${{ matrix.django-version }}" == "4.1" ) ]]; then - echo "Skipping unsupported Python/Django combination" - exit 0 - fi - - pip install Django==${{ matrix.django-version }} mysqlclient psycopg2 - pip install flake8 pylint pytest pytest-django - - if [[ "${{ matrix.python-version }}" == "3.12" ]]; then - pip install setuptools - fi - - pip install -e . - python setup.py test - ./lint.sh \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..9887549 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,89 @@ +name: Client Build, Publish, and Release + +on: + workflow_dispatch: + inputs: + tag: + description: "Release tag (for example: 1.1.1)" + required: true + type: string + release_name: + description: "Release name (defaults to tag if empty)" + required: false + default: "" + type: string + prerelease: + description: "Mark as prerelease" + required: true + default: false + type: boolean + +jobs: + build: + name: Build package distributions + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install Poetry + run: | + make poetry + - name: Install dependencies + run: | + make install-build + - name: Build package + run: | + make build + - name: Upload dist artifacts + uses: actions/upload-artifact@v4 + with: + name: python-dist + path: dist/* + if-no-files-found: error + + pypi-publish: + name: Upload release to public PyPI + runs-on: ubuntu-latest + needs: build + environment: + name: pypi + url: https://pypi.org/p/django-livefield + permissions: + id-token: write + steps: + - name: Download dist artifacts + uses: actions/download-artifact@v4 + with: + name: python-dist + path: dist + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + create-github-release: + name: Create GitHub release + runs-on: ubuntu-latest + needs: + - pypi-publish + permissions: + contents: write + steps: + - name: Download dist artifacts + uses: actions/download-artifact@v4 + with: + name: python-dist + path: dist + - name: Create release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ inputs.tag }} + name: ${{ inputs.release_name || inputs.tag }} + target_commitish: ${{ github.sha }} + prerelease: ${{ inputs.prerelease }} + generate_release_notes: true + files: dist/* diff --git a/.github/workflows/python-version-tests.yml b/.github/workflows/python-version-tests.yml new file mode 100644 index 0000000..35bc4ac --- /dev/null +++ b/.github/workflows/python-version-tests.yml @@ -0,0 +1,70 @@ +name: Python Version Tests + +on: + push: + branches: ["master"] + pull_request: + branches: ["master"] + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + django-version: ['3.2', '4.0', '4.1', '4.2', '5.0'] + services: + postgres: + image: postgres:12 + ports: + - 5432:5432 + options: >- + --health-cmd=pg_isready + --health-interval=10s + --health-timeout=5s + --health-retries=5 + env: + POSTGRES_DB: testdb + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + mysql: + image: mysql:8 + ports: + - 3306:3306 + options: >- + --health-cmd="mysqladmin ping" + --health-interval=10s + --health-timeout=5s + --health-retries=5 + env: + MYSQL_USER: travis + MYSQL_PASSWORD: travis + MYSQL_ALLOW_EMPTY_PASSWORD: true + MYSQL_DATABASE: test_testdb + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install Poetry + run: | + make poetry + - name: Install dependencies + run: | + make install-build + - name: Pin Django version + run: | + poetry run pip install "Django==${{ matrix.django-version }}" + - name: Lint with flake8 and pylint + run: | + make lint + - name: Test with custom bootstrap runner + run: | + make test diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..43d023f --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,13 @@ +Developed and maintained by [Hearsay Social, Inc.](http://hearsaysocial.com). + +## Contributors + +- [Adam DePue](http://github.com/adepue) +- [Akshay Shah](http://github.com/akshayjshah) +- [Cordelia Notbohm](http://github.com/cnotbohm) +- [John Lynn](http://github.com/jlynn) +- [Dylan Verheul](http://github.com/dyve) +- [Grant McConnaughey](http://github.com/grantmcconnaughey) +- [Luke Burden](http://github.com/lukeburden) +- [James Addison](http://github.com/jaddison) +- [Krisztian Csizmazia](http://github.com/csizmaziakiki) diff --git a/AUTHORS.rst b/AUTHORS.rst deleted file mode 100644 index d8e22d2..0000000 --- a/AUTHORS.rst +++ /dev/null @@ -1,13 +0,0 @@ -Developed and maintained by `Hearsay Social, Inc. -`_. - -Contributors -============ -| `Adam DePue `_ -| `Akshay Shah `_ -| `John Lynn `_ -| `Dylan Verheul `_ -| `Grant McConnaughey `_ -| `Luke Burden `_ -| `James Addison `_ -| `Krisztian Csizmazia `_ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4f391a3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,75 @@ +# Changelog + +## 4.2.0 +- Migrate to Poetry for building and publishing + +## 4.1.0 + +- Add support for Python 3.12 +- Add support for Django 5.0 + +## 4.0.0 + +- Add support for Python 3.8 - 3.11 +- Add support for Django 4.1 and 4.2 +- Remove support for old Django versions +- Remove support for old Python versions + +## 3.3.0 + +- Django 3.x support +- switch to BooleanField as base (Django 4.x deprecation) + +## 3.2.1 + +- Fix rST formatting in this file to pass PyPI rendering check + +## 3.2.0 (Not released) + +- Support Django 2.2 +- Support Python 3.7 +- Fix metadata to remove deprecated Django versions +- Expand travis tests for versions and database engines +- Remove obsolete pylint suppressions +- Thanks to [@shurph](https://github.com/shurph) for the above! + +## 3.1.0 + +- Fix [deprecation of context param for Field.from_db_value](https://code.djangoproject.com/ticket/28370) +- Support for Django 2.1 (Thanks [@lukeburden](https://github.com/lukeburden) +- Switch tests suite to use pytest +- Remove pylint-django plugin, no longer needed + +## 3.0.0 + +- Add support for Python 3.6 +- Add support for Django 2.0 +- Remove support for Python 3.4 +- Remove support for old Django versions +- Remove GIS + +## 2.5.0 (Not released) + +- Added official Python 3 support. +- Re-added support for Django 1.8. Now supports Django 1.8 and 1.9. + +## 2.4.0 (2016-02-11) + +- Drop support for Django 1.8 +- Add number of affected rows for delete methods (hard_delete, soft_delete, delete). Note: Django 1.9+ only. + +## 2.1.0 (2014-09-04) + +- Add support for Django 1.7. + +## 2.0.0 (2014-07-13) + +- Renamed top-level namespace to `livefield`. +- Restructured internally to match Django convention. +- Added GIS support. +- Added South support. + +## 1.0.0 (2014-02-14) + +- Initial release. +- Separated existing code from main application repository. diff --git a/CHANGELOG.rst b/CHANGELOG.rst deleted file mode 100644 index 8a6f3ae..0000000 --- a/CHANGELOG.rst +++ /dev/null @@ -1,74 +0,0 @@ -Changelog -========= - -4.1.0 --------------------- - - Add support for Python 3.12 - - Add support for Django 5.0 - -4.0.0 --------------------- - - Add support for Python 3.8 - 3.11 - - Add support for Django 4.1 and 4.2 - - Remove support for old Django versions - - Remove support for old Python versions - -3.3.0 --------------------- - - Django 3.x support - - switch to BooleanField as base (Django 4.x deprecation) - -3.2.1 --------------------- - - Fix rST formatting in this file to pass PyPI rendering check - -3.2.0 (Not released) --------------------- - - Support Django 2.2 - - Support Python 3.7 - - Fix metadata to remove deprecated Django versions - - Expand travis tests for versions and database engines - - Remove obsolete pylint suppressions - - Thanks to [@shurph](https://github.com/shurph) for the above! - -3.1.0 --------------------- - - Fix [deprecation of context param for Field.from_db_value](https://code.djangoproject.com/ticket/28370) - - Support for Django 2.1 (Thanks [@lukeburden](https://github.com/lukeburden) - - Switch tests suite to use pytest - - Remove pylint-django plugin, no longer needed - -3.0.0 --------------------- - - Add support for Python 3.6 - - Add support for Django 2.0 - - Remove support for Python 3.4 - - Remove support for old Django versions - - Remove GIS - - -2.5.0 (Not released) --------------------- - - Added official Python 3 support. - - Re-added support for Django 1.8. Now supports Django 1.8 and 1.9. - -2.4.0 (2016-02-11) --------------------- - - Drop support for Django 1.8 - - Add number of affected rows for delete methods (hard_delete, soft_delete, delete). Note: Django 1.9+ only. - -2.1.0 (2014-09-04) --------------------- - - Add support for Django 1.7. - -2.0.0 (2014-07-13) --------------------- - - Renamed top-level namespace to ``livefield``. - - Restructured internally to match Django convention. - - Added GIS support. - - Added South support. - -1.0.0 (2014-02-14) --------------------- - - Initial release. - - Separated existing code from main application repository. diff --git a/MANIFEST.in b/MANIFEST.in index 98c429d..b9c7b4a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1 @@ -include *.rst LICENSE.txt +include *.md LICENSE.txt diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..60fdd5b --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +REPO = $(shell git rev-parse --show-toplevel) +POETRY = poetry + +install-build: + ${POETRY} install --only=main + +install-dev: + ${POETRY} install + +poetry: + curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.8.4 python3 - + poetry cache clear pypi --all + poetry config virtualenvs.in-project true + +quickstart: poetry install-dev + +quickstart-build: poetry install-build + +clean: + # Delete all .pyc and .pyo files. + find ${REPO} \( -name "*~" -o -name "*.py[co]" -o -name ".#*" -o -name "#*#" \) -exec rm -f '{}' + + rm -rf build dist src/django_livefield.egg-info django_livefield.egg-info + +lint: clean + ${POETRY} run flake8 --config=${REPO}/setup.cfg ${REPO}/src/livefield/ ${REPO}/tests/ + ${POETRY} run pylint --rcfile=${REPO}/pylint.rc ${REPO}/src/livefield/ ${REPO}/tests/ + +test: clean + ${POETRY} run python ${REPO}/tests/run_tests.py + +build: + ${POETRY} build diff --git a/README.md b/README.md new file mode 100644 index 0000000..3fd12a9 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# django-livefield + +## About + +A Django field that enables convenient soft-deletion. For Python 3.8+ and Django 3.2+ + +## Installation + +Simple: `pip install django-livefield`. + +## Example Usage + +```python +>>> from django.db import models +>>> from livefield import LiveField, LiveManager +>>> +>>> +>>> class Person(models.Model): +... name = models.CharField() +... live = LiveField() +... +... objects = LiveManager() +... all_objects = LiveManager(include_soft_deleted=True) +... +... class Meta: +... unique_together = ('name', 'live') +... +... def delete(self, using=None): +... self.live = False +... self.save(using=using) +... +>>> john = Person.objects.create(name='John Cleese') +>>> doppelganger = Person(name='John Cleese') +>>> doppelganger.save() # Raises an IntegrityError +>>> john.delete() +>>> doppelganger.save() # Succeeds! +``` + +## License + +MIT. See LICENSE.txt for details. + +## Contributing + +Pull requests welcome! To save everyone some hassle, please open an issue first so we can discuss your proposed change. + +In your PR, be sure to add your name to AUTHORS.md and include some tests for your spiffy new functionality. CI will green-light your build once it passes the unit tests (`make test`) and our linters (`make lint`). diff --git a/README.rst b/README.rst deleted file mode 100644 index 22de83e..0000000 --- a/README.rst +++ /dev/null @@ -1,58 +0,0 @@ -================ -django-livefield -================ - -===== -About -===== -A Django field that enables convenient soft-deletion. For Python 2.7/3.3+ and Django 1.8+ - -============ -Installation -============ -Simple: ``pip install django-livefield``. - -============= -Example Usage -============= -.. code:: python - - >>> from django.db import models - >>> from livefield import LiveField, LiveManager - >>> - >>> - >>> class Person(models.Model): - ... name = models.CharField() - ... live = LiveField() - ... - ... objects = LiveManager() - ... all_objects = LiveManager(include_soft_deleted=True) - ... - ... class Meta: - ... unique_together = ('name', 'live') - ... - ... def delete(self, using=None): - ... self.live = False - ... self.save(using=using) - ... - >>> john = Person.objects.create(name='John Cleese') - >>> doppelganger = Person(name='John Cleese') - >>> doppelganger.save() # Raises an IntegrityError - >>> john.delete() - >>> doppelganger.save() # Succeeds! - -======= -License -======= -MIT. See LICENSE.txt for details. - -============ -Contributing -============ -Pull requests welcome! To save everyone some hassle, please open an -issue first so we can discuss your proposed change. - -In your PR, be sure to add your name to AUTHORS.txt and include some -tests for your spiffy new functionality. CI will green-light your -build once it passes the unit tests (``./setup.py test``) and our -linters (``./lint.sh``). diff --git a/build.sh b/build.sh deleted file mode 100755 index f0fb26c..0000000 --- a/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env sh - -# Safer to update these separately. -pip install -U "setuptools" -pip install -U "wheel" -pip install -U "pip" - -./setup.py sdist -./setup.py bdist_wheel diff --git a/lint.sh b/lint.sh deleted file mode 100755 index cb06e9f..0000000 --- a/lint.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env sh - -flake8 tests src setup.py -if [ $? -ne 0 ]; then - echo "Flake8 linting failed." - exit 1 -fi - -pylint --rcfile=pylint.rc src/livefield -if [ $? -ne 0 ]; then - echo "PyLint found errors in src/." - exit 1 -fi - -pylint --rcfile=pylint.rc tests -if [ $? -ne 0 ]; then - echo "PyLint found errors in test/." - exit 1 -fi - -pylint --rcfile=pylint.rc setup.py -if [ $? -ne 0 ]; then - echo "PyLint found errors in setup.py." - exit 1 -fi diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..2fec3da --- /dev/null +++ b/poetry.lock @@ -0,0 +1,434 @@ +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. + +[[package]] +name = "asgiref" +version = "3.8.1" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.8" +files = [ + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + +[[package]] +name = "astroid" +version = "3.2.4" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "astroid-3.2.4-py3-none-any.whl", hash = "sha256:413658a61eeca6202a59231abb473f932038fbcbf1666587f66d482083413a25"}, + {file = "astroid-3.2.4.tar.gz", hash = "sha256:0e14202810b30da1b735827f78f5157be2bbd4a7a59b7707ca0bfc2fb4c0063a"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "backports-zoneinfo" +version = "0.2.1" +description = "Backport of the standard library zoneinfo module" +optional = false +python-versions = ">=3.6" +files = [ + {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"}, +] + +[package.extras] +tzdata = ["tzdata"] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "dill" +version = "0.4.0" +description = "serialize all of Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049"}, + {file = "dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] + +[[package]] +name = "dill" +version = "0.4.1" +description = "serialize all of Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d"}, + {file = "dill-0.4.1.tar.gz", hash = "sha256:423092df4182177d4d8ba8290c8a5b640c66ab35ec7da59ccfa00f6fa3eea5fa"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] + +[[package]] +name = "django" +version = "4.2.29" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +optional = false +python-versions = ">=3.8" +files = [ + {file = "django-4.2.29-py3-none-any.whl", hash = "sha256:074d7c4d2808050e528388bda442bd491f06def4df4fe863f27066851bba010c"}, + {file = "django-4.2.29.tar.gz", hash = "sha256:86d91bc8086569c8d08f9c55888b583a921ac1f95ed3bdc7d5659d4709542014"}, +] + +[package.dependencies] +asgiref = ">=3.6.0,<4" +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +argon2 = ["argon2-cffi (>=19.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "flake8" +version = "5.0.4" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, + {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.9.0,<2.10.0" +pyflakes = ">=2.5.0,<2.6.0" + +[[package]] +name = "iniconfig" +version = "2.1.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.8" +files = [ + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, +] + +[[package]] +name = "isort" +version = "5.13.2" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[package.extras] +colors = ["colorama (>=0.4.6)"] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "packaging" +version = "26.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, + {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pycodestyle" +version = "2.9.1" +description = "Python style guide checker" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, + {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, +] + +[[package]] +name = "pyflakes" +version = "2.5.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, + {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, +] + +[[package]] +name = "pylint" +version = "3.2.7" +description = "python code static checker" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "pylint-3.2.7-py3-none-any.whl", hash = "sha256:02f4aedeac91be69fb3b4bea997ce580a4ac68ce58b89eaefeaf06749df73f4b"}, + {file = "pylint-3.2.7.tar.gz", hash = "sha256:1b7a721b575eaeaa7d39db076b6e7743c993ea44f57979127c517c6c572c803e"}, +] + +[package.dependencies] +astroid = ">=3.2.4,<=3.3.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = [ + {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, +] +isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.10.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pytest" +version = "8.3.5" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, + {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-django" +version = "4.11.1" +description = "A Django plugin for pytest." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest_django-4.11.1-py3-none-any.whl", hash = "sha256:1b63773f648aa3d8541000c26929c1ea63934be1cfa674c76436966d73fe6a10"}, + {file = "pytest_django-4.11.1.tar.gz", hash = "sha256:a949141a1ee103cb0e7a20f1451d355f83f5e4a5d07bdd4dcfdd1fd0ff227991"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx", "sphinx_rtd_theme"] +testing = ["Django", "django-configurations (>=2.0)"] + +[[package]] +name = "sqlparse" +version = "0.5.5" +description = "A non-validating SQL parser." +optional = false +python-versions = ">=3.8" +files = [ + {file = "sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba"}, + {file = "sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e"}, +] + +[package.extras] +dev = ["build"] +doc = ["sphinx"] + +[[package]] +name = "tomli" +version = "2.4.0" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, + {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576"}, + {file = "tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a"}, + {file = "tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa"}, + {file = "tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51"}, + {file = "tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729"}, + {file = "tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da"}, + {file = "tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f"}, + {file = "tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86"}, + {file = "tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87"}, + {file = "tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8"}, + {file = "tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776"}, + {file = "tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475"}, + {file = "tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b"}, + {file = "tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087"}, + {file = "tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd"}, + {file = "tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4"}, + {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"}, + {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"}, +] + +[[package]] +name = "tomlkit" +version = "0.13.3" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0"}, + {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, +] + +[[package]] +name = "typing-extensions" +version = "4.13.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, + {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, +] + +[[package]] +name = "tzdata" +version = "2025.3" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1"}, + {file = "tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7"}, +] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8,<4.0" +content-hash = "ea6184e707c4482a8a229cb3b59dcf3bab7a478b55e9ac303565ad4d719a0deb" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b19c60b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,41 @@ +[tool.poetry] +name = "django-livefield" +version = "4.2.0" +description = "Convenient soft-deletion support for Django models" +authors = ["Hearsay Social "] +license = "MIT" +readme = "README.md" +keywords = ["python", "django", "soft-delete"] +packages = [ + { include = "livefield", from = "src" } +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Framework :: Django :: 3.2", + "Framework :: Django :: 4.0", + "Framework :: Django :: 4.1", + "Framework :: Django :: 4.2", + "Framework :: Django :: 5.0", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" +] + +[tool.poetry.urls] +"Github Repo" = "https://github.com/hearsaycorp/django-livefield" + +[tool.poetry.dependencies] +python = ">=3.8,<4.0" +Django = ">=3.2,<5.1" + +[tool.poetry.group.dev.dependencies] +flake8 = "*" +pylint = "*" +pytest = "*" +pytest-django = "*" + +[build-system] +requires = ["poetry-core>=1.1.0"] +build-backend = "poetry.core.masonry.api" diff --git a/setup.py b/setup.py deleted file mode 100755 index afa77af..0000000 --- a/setup.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python - -import multiprocessing # noqa -import os -import sys - -from setuptools import setup, find_packages -from setuptools.command.test import test as TestCommand - - -tests_require = ( - 'pytest', - 'pytest-django' -) - - -install_requires = ( - 'Django>=3.2,<5.1', -) - - -class DjangoTest(TestCommand): - DIRNAME = os.path.dirname(__file__) - APPS = ('tests',) - - def finalize_options(self): - TestCommand.finalize_options(self) - self.test_args = [] - self.test_suite = True - - def run_tests(self): - from django.conf import settings - - db_engine = os.environ.get('DJANGO_DB_ENGINE', 'sqlite') - if db_engine == 'mysql': - db_settings = { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': os.environ['DJANGO_DB_NAME'], - 'USER': os.environ['DJANGO_DB_USER'], - } - elif db_engine == 'postgres': - db_settings = { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': os.environ['DJANGO_DB_NAME'], - 'USER': os.environ['DJANGO_DB_USER'], - } - elif db_engine == 'sqlite': - db_settings = { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(self.DIRNAME, 'database.db'), - } - else: - raise ValueError("Unknown DB engine: %s" % db_engine) - - # Common settings. - settings.configure( - DEBUG=True, - DATABASES={'default': db_settings}, - CACHES={'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}}, - INSTALLED_APPS=self.APPS) - - import django - import pytest - django.setup() - sys.exit(pytest.main(["tests/"])) - - -setup( - name='django-livefield', - version='4.1.0', - description='Convenient soft-deletion support for Django models', - long_description=( - open('README.rst').read() + '\n\n' + - open('CHANGELOG.rst').read() + '\n\n' + - open('AUTHORS.rst').read()), - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Framework :: Django :: 3.2', - 'Framework :: Django :: 4.0', - 'Framework :: Django :: 4.1', - 'Framework :: Django :: 4.2', - 'Framework :: Django :: 5.0', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - ], - keywords='python django soft-delete', - url='https://github.com/hearsaycorp/django-livefield', - author='Hearsay Social', - author_email='opensource@hearsaysocial.com', - license='MIT', - package_dir={'': 'src'}, - packages=find_packages('src'), - install_requires=install_requires, - tests_require=tests_require, - cmdclass={'test': DjangoTest}, -) diff --git a/tests/run_tests.py b/tests/run_tests.py new file mode 100644 index 0000000..b9cb2b4 --- /dev/null +++ b/tests/run_tests.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +import os +import sys + + +REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +SRC_ROOT = os.path.join(REPO_ROOT, "src") +APPS = ("tests",) + + +def _db_settings(): + db_engine = os.environ.get("DJANGO_DB_ENGINE", "sqlite") + if db_engine == "mysql": + return { + "ENGINE": "django.db.backends.mysql", + "NAME": os.environ["DJANGO_DB_NAME"], + "USER": os.environ["DJANGO_DB_USER"], + } + if db_engine == "postgres": + return { + "ENGINE": "django.db.backends.postgresql", + "NAME": os.environ["DJANGO_DB_NAME"], + "USER": os.environ["DJANGO_DB_USER"], + } + if db_engine == "sqlite": + return { + "ENGINE": "django.db.backends.sqlite3", + "NAME": os.path.join(REPO_ROOT, "database.db"), + } + + raise ValueError(f"Unknown DB engine: {db_engine}") + + +def main(): + if REPO_ROOT not in sys.path: + sys.path.insert(0, REPO_ROOT) + if SRC_ROOT not in sys.path: + sys.path.insert(0, SRC_ROOT) + + from django.conf import settings + + if not settings.configured: + settings.configure( + DEBUG=True, + DATABASES={"default": _db_settings()}, + CACHES={"default": {"BACKEND": "django.core.cache.backends.dummy.DummyCache"}}, + INSTALLED_APPS=APPS, + ) + + import django + import pytest + + django.setup() + return pytest.main(["tests/"]) + + +if __name__ == "__main__": + sys.exit(main()) From 9ac602574d387b536e064a73f5c91b2d3a17b73a Mon Sep 17 00:00:00 2001 From: cnotbohm Date: Wed, 4 Mar 2026 21:22:55 +0000 Subject: [PATCH 2/3] fix test action --- .github/workflows/python-version-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-version-tests.yml b/.github/workflows/python-version-tests.yml index 35bc4ac..4d44ac8 100644 --- a/.github/workflows/python-version-tests.yml +++ b/.github/workflows/python-version-tests.yml @@ -58,7 +58,7 @@ jobs: make poetry - name: Install dependencies run: | - make install-build + make install-dev - name: Pin Django version run: | poetry run pip install "Django==${{ matrix.django-version }}" From 5621781bba19bde3ef3f7ee6fe034ffff356fa01 Mon Sep 17 00:00:00 2001 From: cnotbohm Date: Wed, 4 Mar 2026 21:33:43 +0000 Subject: [PATCH 3/3] skip the pairs we were skipping before --- .github/workflows/python-version-tests.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/python-version-tests.yml b/.github/workflows/python-version-tests.yml index 4d44ac8..3acddc0 100644 --- a/.github/workflows/python-version-tests.yml +++ b/.github/workflows/python-version-tests.yml @@ -18,6 +18,21 @@ jobs: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] django-version: ['3.2', '4.0', '4.1', '4.2', '5.0'] + exclude: + - python-version: '3.8' + django-version: '5.0' + - python-version: '3.9' + django-version: '5.0' + - python-version: '3.11' + django-version: '3.2' + - python-version: '3.11' + django-version: '4.0' + - python-version: '3.12' + django-version: '3.2' + - python-version: '3.12' + django-version: '4.0' + - python-version: '3.12' + django-version: '4.1' services: postgres: image: postgres:12