diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 121ac04f..7b82f668 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,68 +6,90 @@ concurrency: group: test-${{ github.head_ref }} cancel-in-progress: true -env: - PYTHONUNBUFFERED: "1" - FORCE_COLOR: "1" - jobs: - - static_tests: - name: Static Tests + ruff: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.11" - - name: Install latest pip and Hatch - run: pip install --upgrade pip hatch - - name: Lint - run: hatch run lint:all - - name: Docs - run: hatch run docs:build - - name: Build - run: hatch build + - uses: chartboost/ruff-action@v1 tests_matrix: - name: Python ${{ matrix.python-version }} runs-on: ubuntu-latest strategy: - fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: [3.8, 3.9, "3.10", 3.11, 3.12] + django-version: [3.2, 4.1, 4.2, 5.0, "main"] + exclude: + # Django 3.2 + - python-version: "3.10" + django-version: 3.2 + - python-version: 3.11 + django-version: 3.2 + - python-version: 3.12 + django-version: 3.2 - steps: - - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} + # Django 4.1 + - python-version: 3.12 + django-version: 4.1 - - name: Install GDAL binaries - run: sudo apt-get install binutils libproj-dev gdal-bin + # Django 4.2 + - python-version: 3.12 + django-version: 4.2 - - name: Install latest pip, Hatch and coveralls - run: pip install --upgrade pip hatch coveralls + # Django 5.0 + - python-version: 3.8 + django-version: 5.0 + - python-version: 3.9 + django-version: 5.0 - - name: Run tests - run: hatch run test-cov + # Django main + - python-version: 3.8 + django-version: "main" + - python-version: 3.9 + django-version: "main" - - name: Coverage combine - run: coverage combine + steps: + - uses: actions/checkout@v4 + - name: Install GDAL binaries + run: sudo apt-get install binutils libproj-dev gdal-bin + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: requirements-test.txt + - run: python -m pip install -r requirements-test.txt + - run: python -m pip install -U Django==${{ matrix.django-version }} + if: matrix.django-version != 'main' + - run: python -m pip install -U https://github.com/django/django/archive/master.tar.gz + if: matrix.django-version == 'main' + - run: python -m pip install -e . + - run: coverage run manage.py test + - run: python -m pip install -U coveralls + - name: Upload coveralls (parallel) + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_PARALLEL: true + run: coveralls --service=github - - name: Upload coveralls (parallel) - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COVERALLS_PARALLEL: true - run: coveralls --service=github + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: 'pip' + cache-dependency-path: docs/requirements.txt + - name: Install and build + run: | + python -m pip install -r docs/requirements.txt + make docs tests: if: always() runs-on: ubuntu-latest - needs: [ static_tests, tests_matrix ] + needs: [ tests_matrix, ruff, docs ] steps: - name: Check tests matrix status if: needs.tests_matrix.result != 'success' diff --git a/.readthedocs.yml b/.readthedocs.yml index 636b846f..a34d6434 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,6 +5,7 @@ build: tools: python: "3.11" commands: - - pip install -U pip hatch - - hatch run docs:build + - pip install -U pip + - pip install -U -r docs/requirements.txt + - make docs - mv docs/_build $READTHEDOCS_OUTPUT diff --git a/CHANGELOG.md b/CHANGELOG.md index 708a49c4..a4804f66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ - Drop support for Python 3.7 in test matrix (#533). - Fix support for Django 4.2 in test matrix (#533). - Pass "horizontal_field_offset_class" to child renderers (#391, #521). +- Add support for Django 5.0 (#538). +- Add support for Python 3.12 (#538). +- Revert packaging tools to setuptools, build, tox and twine (#538). ## 23.3 (2023-06-03) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 920504a8..c68dde9a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,8 +45,6 @@ Ready to contribute? Here\'s how to set up `django-bootstrap5` for local develop You will need some knowledge of git, github, and Python/Django development. Using a Python virtual environment is advised. -This project uses [Hatch](https://github.com/pypa/hatch) for environments and builds. - ### Local installation This section assumes you know about local Python versions and virtual environments. @@ -56,7 +54,7 @@ To clone the repository and install the requirements for local development: ```console git clone git://github.com/zostera/django-bootstrap5.git cd django-bootstrap5 -pip install -U pip hatch +pip install -U pip -r requirements-dev.txt pip install -e . ``` diff --git a/Makefile b/Makefile index 449eb848..72062bc2 100644 --- a/Makefile +++ b/Makefile @@ -1,35 +1,37 @@ -VERSION := $(shell hatch version) +VERSION := $(shell sed -n 's/^ *version.*=.*"\([^"]*\)".*/\1/p' pyproject.toml) .PHONY: test test: - hatch run test + coverage run manage.py test + coverage report .PHONY: tests tests: - hatch run all:test + tox .PHONY: reformat reformat: - hatch run lint:fmt + ruff format . + ruff --fix . .PHONY: lint lint: - hatch run lint:style + ruff . .PHONY: docs -docs: - hatch run docs:build +docs: clean + cd docs && sphinx-build -b html -d _build/doctrees . _build/html .PHONY: example example: - hatch run example:runserver + cd example && python manage.py runserver .PHONY: porcelain porcelain: ifeq ($(shell git status --porcelain),) @echo "Working directory is clean." else - @echo "Error - working directory is dirty. Commit those changes!"; + @echo "Error - working directory is dirty. Commit your changes."; @exit 1; endif @@ -38,17 +40,25 @@ branch: ifeq ($(shell git rev-parse --abbrev-ref HEAD),main) @echo "On branch main." else - @echo "Error - Not on branch main!" + @echo "Error - Not on branch main." @exit 1; endif .PHONY: build build: docs - rm -rf build dist src/*.egg-info - hatch build + python -m build .PHONY: publish publish: porcelain branch build - hatch publish + twine check dist/* + twine upload dist/* git tag -a v${VERSION} -m "Release ${VERSION}" git push origin --tags + +.PHONY: clean +clean: docs + rm -rf build dist src/*.egg-info .coverage* + +.PHONY: version +version: + @echo ${VERSION} diff --git a/docs/conf.py b/docs/conf.py index 00b46e05..46810fd5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,3 @@ -import importlib from datetime import datetime import tomllib @@ -7,15 +6,7 @@ pyproject = tomllib.load(f) project = pyproject["project"]["name"] -conf = {"module": project.replace("-", "_")} - -try: - conf.update(pyproject["tool"]["sphinx"]["x-conf"]) -except KeyError: - pass - -module = importlib.import_module(conf["module"]) -release = module.__version__ +release = pyproject["project"]["version"] version = ".".join(release.split(".")[:2]) author = ", ".join(author["name"] for author in pyproject["project"]["authors"]) year = datetime.now().year diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..cb2e9af4 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +sphinx>=7.2.6 +sphinx-mdinclude>=0.5.3 +furo>=2023.05.20 diff --git a/pyproject.toml b/pyproject.toml index 9fb69119..57cbc276 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] -build-backend = "hatchling.build" -requires = ["hatchling"] +build-backend = "setuptools.build_meta" +requires = ["setuptools"] [project] authors = [ @@ -13,6 +13,7 @@ classifiers = [ "Framework :: Django :: 3.2", "Framework :: Django :: 4.1", "Framework :: Django :: 4.2", + "Framework :: Django :: 5.0", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", @@ -21,20 +22,17 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Software Development :: Libraries", "Topic :: Utilities", ] -dependencies = [ - "Django>=3.2", -] +dependencies = ["Django>=3.2"] description = "Bootstrap 5 for Django" -dynamic = [ - "version", -] -license = "BSD-3-Clause" +license = {file = "LICENSE"} name = "django-bootstrap5" readme = "README.md" requires-python = ">=3.8" +version = "23.7.dev0" [project.urls] Changelog = "https://github.com/zostera/django-bootstrap5/blob/main/CHANGELOG.md" @@ -43,96 +41,6 @@ Homepage = "https://github.com/zostera/django-bootstrap5" Issues = "https://github.com/zostera/django-bootstrap5/issues" Source = "https://github.com/zostera/django-bootstrap5" -[tool.hatch.version] -path = "src/django_bootstrap5/__about__.py" - -[tool.hatch.envs.default] -dependencies = [ - "coverage[toml]>=7.2.6", - "pillow>=9.5.0", - "beautifulsoup4>=4.12.2", -] -matrix-name-format = "dj{value}" - -[tool.hatch.envs.default.scripts] -cov = [ - "test-cov", - "cov-report", -] -cov-report = [ - "- coverage combine", - "coverage report", -] -test = "python manage.py test {args:tests}" -test-cov = "coverage run manage.py test {args:tests}" - -[[tool.hatch.envs.all.matrix]] -django = ["3.2", "4.1", "4.2"] -python = ["3.8", "3.9"] - -[[tool.hatch.envs.all.matrix]] -django = ["3.2", "4.1", "4.2", "main"] -python = ["3.10"] - -[[tool.hatch.envs.all.matrix]] -django = ["4.1", "4.2", "main"] -python = ["3.11"] - -[tool.hatch.envs.all.overrides] -matrix.django.dependencies = [ - {value = "django~=3.2.0", if = ["3.2"]}, - {value = "django~=4.1.0", if = ["4.1"]}, - {value = "django~=4.2.0", if = ["4.2"]}, - {value = "django @ git+https://github.com/django/django.git", if = ["main"]}, -] - -[tool.hatch.envs.example] -dependencies = [ - "django>=3.2", -] -python = "3.11" -template = "example" - -[tool.hatch.envs.example.scripts] -runserver = [ - "cd example && python manage.py migrate && python manage.py runserver", -] - -[tool.hatch.envs.docs] -dependencies = [ - "sphinx>=7.0.1", - "sphinx-mdinclude>=0.5.3", - "furo>=2023.05.20", -] -python = "3.11" -template = "docs" - -[tool.hatch.envs.docs.scripts] -build = [ - "clean", - "cd docs && sphinx-build -b html -d _build/doctrees . _build/html", -] -clean = "rm -rf docs/_build" - -[tool.hatch.envs.lint] -dependencies = [ - "ruff>0.1", -] -detached = true - -[tool.hatch.envs.lint.scripts] -all = [ - "style", -] -fmt = [ - "ruff --fix {args:.}", - "ruff format {args:.}", - "style", -] -style = [ - "ruff {args:.}", -] - [tool.ruff] fix = false fixable = [ @@ -156,22 +64,21 @@ select = [ "UP", # pyupgrade ] src = ["src"] -target-version = "py37" +target-version = "py38" unfixable = [ "F8", # names in flake8, such as defined but unused variables ] [tool.ruff.isort] -known-first-party = ["django_bootstrap5", "app"] +known-first-party = ["django_marina", "app"] known-third-party = ["django"] [tool.coverage.run] branch = true -parallel = true -source = ["src"] +source = ["src", "tests"] [tool.coverage.paths] -package = ["src/django_bootstrap5", "*/django_bootstrap5/src/django_bootstrap5"] +package = ["src/django_marina", "*/django_marina/src/django_marina"] [tool.coverage.report] show_missing = true diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 00000000..9c8d1209 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,3 @@ +-r requirements-test.txt +-r docs/requirements.txt +twine==4.0.2 diff --git a/requirements-test.txt b/requirements-test.txt new file mode 100644 index 00000000..9a1574c5 --- /dev/null +++ b/requirements-test.txt @@ -0,0 +1,5 @@ +tox==4.11.4 +coverage==7.3.4 +ruff==0.1.9 +pillow>=10.1.0 +beautifulsoup4>=4.12.2 diff --git a/src/django_bootstrap5/__about__.py b/src/django_bootstrap5/__about__.py index fdd1c655..2c02b644 100644 --- a/src/django_bootstrap5/__about__.py +++ b/src/django_bootstrap5/__about__.py @@ -1 +1,3 @@ -__version__ = "23.4.dev0" +import importlib.metadata + +__version__ = importlib.metadata.version(__package__ or __name__) diff --git a/tests/test_bootstrap_field.py b/tests/test_bootstrap_field.py index bf5de1e2..c6377649 100644 --- a/tests/test_bootstrap_field.py +++ b/tests/test_bootstrap_field.py @@ -34,7 +34,9 @@ def test_placeholder(self): self.assertIn('placeholder="placeholdertest"', html) def test_field_class(self): - html = self.render("{% bootstrap_field form.subject field_class='field-class-test' %}", {"form": SubjectTestForm()}) + html = self.render( + "{% bootstrap_field form.subject field_class='field-class-test' %}", {"form": SubjectTestForm()} + ) self.assertIn('class="form-control field-class-test"', html) def test_xss_field(self): diff --git a/tests/test_bootstrap_field_input_checkbox.py b/tests/test_bootstrap_field_input_checkbox.py index f304b5cc..00408167 100644 --- a/tests/test_bootstrap_field_input_checkbox.py +++ b/tests/test_bootstrap_field_input_checkbox.py @@ -1,6 +1,6 @@ from django import forms -from tests.base import BootstrapTestCase +from tests.base import DJANGO_VERSION, BootstrapTestCase class CheckboxTestForm(forms.Form): @@ -24,8 +24,14 @@ def test_input_type_checkbox(self): def test_input_type_checkbox_is_invalid(self): """Test field with checkbox widget.""" + html = self.render( + "{% bootstrap_field form.test %}", + context={"form": CheckboxTestForm(data={})}, + ) + if DJANGO_VERSION >= "5": + html = html.replace(' aria-invalid="true"', "") self.assertHTMLEqual( - self.render("{% bootstrap_field form.test %}", context={"form": CheckboxTestForm(data={})}), + html, ( '