Compare commits

...

109 commits

Author SHA1 Message Date
dependabot[bot]
2a3b69b700 chore(deps-dev): bump sphinx from 7.4.7 to 8.1.3
Some checks are pending
test / test-matrix (5.2, 3.10) (push) Waiting to run
test / test-matrix (5.2, 3.11) (push) Waiting to run
test / test-matrix (5.2, 3.12) (push) Waiting to run
test / test-matrix (5.2, 3.13) (push) Waiting to run
test / test-matrix (6.0, 3.12) (push) Waiting to run
test / test-matrix (6.0, 3.13) (push) Waiting to run
Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 7.4.7 to 8.1.3.
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/v8.1.3/CHANGES.rst)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v7.4.7...v8.1.3)

---
updated-dependencies:
- dependency-name: sphinx
  dependency-version: 8.1.3
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 17:46:14 -07:00
Mike
cb06860cce chore: release 1.8.2 2026-05-22 17:29:32 -07:00
dependabot[bot]
64919e34ee
chore(deps-dev): bump tomlkit from 0.13.3 to 0.15.0 (#863)
Bumps [tomlkit](https://github.com/python-poetry/tomlkit) from 0.13.3 to 0.15.0.
- [Release notes](https://github.com/python-poetry/tomlkit/releases)
- [Changelog](https://github.com/python-poetry/tomlkit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python-poetry/tomlkit/compare/0.13.3...0.15.0)

---
updated-dependencies:
- dependency-name: tomlkit
  dependency-version: 0.15.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 00:26:25 +00:00
dependabot[bot]
a0ca28d696
chore(deps-dev): bump sphinx-rtd-theme from 3.0.2 to 3.1.0 (#862)
Bumps [sphinx-rtd-theme](https://github.com/readthedocs/sphinx_rtd_theme) from 3.0.2 to 3.1.0.
- [Changelog](https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/changelog.rst)
- [Commits](https://github.com/readthedocs/sphinx_rtd_theme/compare/3.0.2...3.1.0)

---
updated-dependencies:
- dependency-name: sphinx-rtd-theme
  dependency-version: 3.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 00:26:13 +00:00
dependabot[bot]
d890d0e0e3 ci(deps): bump the github-actions group with 2 updates
Bumps the github-actions group with 2 updates: [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) and [codecov/codecov-action](https://github.com/codecov/codecov-action).


Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](https://github.com/dependabot/fetch-metadata/compare/v2...v3)

Updates `codecov/codecov-action` from 5 to 6.0.0
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: codecov/codecov-action
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 17:23:41 -07:00
dependabot[bot]
ef986ea0de chore(deps-dev): bump the test-dependencies group across 1 directory with 3 updates
Bumps the test-dependencies group with 3 updates in the / directory: [mypy](https://github.com/python/mypy), [pytest-django](https://github.com/pytest-dev/pytest-django) and [doc8](https://github.com/pycqa/doc8).


Updates `mypy` from 1.18.2 to 2.1.0
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.18.2...v2.1.0)

Updates `pytest-django` from 4.11.1 to 4.12.0
- [Release notes](https://github.com/pytest-dev/pytest-django/releases)
- [Changelog](https://github.com/pytest-dev/pytest-django/blob/main/docs/changelog.rst)
- [Commits](https://github.com/pytest-dev/pytest-django/compare/v4.11.1...v4.12.0)

Updates `doc8` from 1.1.2 to 2.0.0
- [Release notes](https://github.com/pycqa/doc8/releases)
- [Commits](https://github.com/pycqa/doc8/compare/v1.1.2...v2.0.0)

---
updated-dependencies:
- dependency-name: doc8
  dependency-version: 2.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: test-dependencies
- dependency-name: mypy
  dependency-version: 2.1.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: test-dependencies
- dependency-name: pytest-django
  dependency-version: 4.12.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: test-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 17:23:29 -07:00
dependabot[bot]
54c91fa628
chore(deps-dev): bump m2r2 from 0.3.1 to 0.3.4 (#861)
Bumps [m2r2](https://github.com/crossnox/m2r2) from 0.3.1 to 0.3.4.
- [Changelog](https://github.com/CrossNox/m2r2/blob/development/CHANGES.md)
- [Commits](https://github.com/crossnox/m2r2/compare/v0.3.1...v0.3.4)

---
updated-dependencies:
- dependency-name: m2r2
  dependency-version: 0.3.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 00:17:50 +00:00
Mike
8ab3dcc623 ci: improve Dependabot automation 2026-05-22 17:10:22 -07:00
dependabot[bot]
62766371fd chore(deps-dev): bump cryptography from 45.0.3 to 46.0.7
Bumps [cryptography](https://github.com/pyca/cryptography) from 45.0.3 to 46.0.7.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/45.0.3...46.0.7)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 46.0.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:59:12 -07:00
dependabot[bot]
5369886635 chore(deps-dev): bump marshmallow from 4.0.0 to 4.1.2
Bumps [marshmallow](https://github.com/marshmallow-code/marshmallow) from 4.0.0 to 4.1.2.
- [Changelog](https://github.com/marshmallow-code/marshmallow/blob/dev/CHANGELOG.rst)
- [Commits](https://github.com/marshmallow-code/marshmallow/compare/4.0.0...4.1.2)

---
updated-dependencies:
- dependency-name: marshmallow
  dependency-version: 4.1.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:57:25 -07:00
dependabot[bot]
4e45c4b271 chore(deps-dev): bump filelock from 3.16.1 to 3.20.3
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.16.1 to 3.20.3.
- [Release notes](https://github.com/tox-dev/py-filelock/releases)
- [Changelog](https://github.com/tox-dev/filelock/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/py-filelock/compare/3.16.1...3.20.3)

---
updated-dependencies:
- dependency-name: filelock
  dependency-version: 3.20.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:57:09 -07:00
dependabot[bot]
63451dc9c4 chore(deps): bump sqlparse from 0.5.3 to 0.5.4
Bumps [sqlparse](https://github.com/andialbrecht/sqlparse) from 0.5.3 to 0.5.4.
- [Changelog](https://github.com/andialbrecht/sqlparse/blob/master/CHANGELOG)
- [Commits](https://github.com/andialbrecht/sqlparse/compare/0.5.3...0.5.4)

---
updated-dependencies:
- dependency-name: sqlparse
  dependency-version: 0.5.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:56:57 -07:00
dependabot[bot]
c6f2f8a4dc chore(deps-dev): bump idna from 3.10 to 3.15
Bumps [idna](https://github.com/kjd/idna) from 3.10 to 3.15.
- [Release notes](https://github.com/kjd/idna/releases)
- [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.md)
- [Commits](https://github.com/kjd/idna/compare/v3.10...v3.15)

---
updated-dependencies:
- dependency-name: idna
  dependency-version: '3.15'
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:56:15 -07:00
dependabot[bot]
f9152b1546 chore(deps-dev): bump urllib3 from 2.5.0 to 2.7.0
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.5.0 to 2.7.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.5.0...2.7.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.7.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:55:03 -07:00
dependabot[bot]
0ae11e15db chore(deps-dev): bump pygments from 2.19.1 to 2.20.0
Bumps [pygments](https://github.com/pygments/pygments) from 2.19.1 to 2.20.0.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](https://github.com/pygments/pygments/compare/2.19.1...2.20.0)

---
updated-dependencies:
- dependency-name: pygments
  dependency-version: 2.20.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:49:04 -07:00
dependabot[bot]
7d69f84932 chore(deps-dev): bump authlib from 1.6.0 to 1.6.12
Bumps [authlib](https://github.com/authlib/authlib) from 1.6.0 to 1.6.12.
- [Release notes](https://github.com/authlib/authlib/releases)
- [Changelog](https://github.com/authlib/authlib/blob/1.6.12/docs/changelog.rst)
- [Commits](https://github.com/authlib/authlib/compare/v1.6.0...1.6.12)

---
updated-dependencies:
- dependency-name: authlib
  dependency-version: 1.6.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:48:46 -07:00
dependabot[bot]
a9da53b96f chore(deps-dev): bump mistune from 0.8.4 to 3.2.1
Bumps [mistune](https://github.com/lepture/mistune) from 0.8.4 to 3.2.1.
- [Release notes](https://github.com/lepture/mistune/releases)
- [Changelog](https://github.com/lepture/mistune/blob/main/docs/changes.rst)
- [Commits](https://github.com/lepture/mistune/compare/v0.8.4...v3.2.1)

---
updated-dependencies:
- dependency-name: mistune
  dependency-version: 3.2.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:48:24 -07:00
dependabot[bot]
ca213de35a chore(deps): bump actions/checkout from 4 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:48:07 -07:00
dependabot[bot]
2e564999c0 chore(deps-dev): bump ruff from 0.12.2 to 0.15.14
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.12.2 to 0.15.14.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.12.2...0.15.14)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.14.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:47:54 -07:00
dependabot[bot]
bed0162587 chore(deps-dev): bump hypothesis from 6.135.26 to 6.152.9
Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.135.26 to 6.152.9.
- [Release notes](https://github.com/HypothesisWorks/hypothesis/releases)
- [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.135.26...hypothesis-python-6.152.9)

---
updated-dependencies:
- dependency-name: hypothesis
  dependency-version: 6.141.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:47:40 -07:00
dependabot[bot]
c8549fa59f chore(deps-dev): bump safety from 3.5.2 to 3.7.0
Bumps [safety](https://github.com/pyupio/safety) from 3.5.2 to 3.7.0.
- [Release notes](https://github.com/pyupio/safety/releases)
- [Changelog](https://github.com/pyupio/safety/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyupio/safety/compare/3.5.2...3.7.0)

---
updated-dependencies:
- dependency-name: safety
  dependency-version: 3.6.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:47:27 -07:00
dependabot[bot]
9099bce0c8 chore(deps-dev): bump requests from 2.32.4 to 2.33.0
Bumps [requests](https://github.com/psf/requests) from 2.32.4 to 2.33.0.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.32.4...v2.33.0)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.33.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:34:08 -07:00
Mike
15f1d3de3b chore: update ruff ignore rules for PLC0415, PT030, PLW0108 2026-05-22 16:26:04 -07:00
Mike
8339249381 refactor: move non-circular deferred imports to top-level, noqa circular ones 2026-05-22 16:26:04 -07:00
Mike
39b4a46cb8 fix: replace Optional[X] type hints with X | None (UP045) 2026-05-22 16:26:04 -07:00
dependabot[bot]
72ede7357b chore(deps-dev): bump mypy from 1.16.1 to 1.18.2
Bumps [mypy](https://github.com/python/mypy) from 1.16.1 to 1.18.2.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.16.1...v1.18.2)

---
updated-dependencies:
- dependency-name: mypy
  dependency-version: 1.18.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:14:48 -07:00
dependabot[bot]
d174c2be02 chore(deps-dev): bump pytest-randomly from 3.16.0 to 4.1.0
Bumps [pytest-randomly](https://github.com/pytest-dev/pytest-randomly) from 3.16.0 to 4.1.0.
- [Changelog](https://github.com/pytest-dev/pytest-randomly/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-randomly/compare/3.16.0...4.1.0)

---
updated-dependencies:
- dependency-name: pytest-randomly
  dependency-version: 4.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:14:32 -07:00
pre-commit-ci[bot]
7968e99369 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2026-05-22 16:13:54 -07:00
pre-commit-ci[bot]
0d266687ad [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v5.0.0 → v6.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v5.0.0...v6.0.0)
- [github.com/astral-sh/ruff-pre-commit: v0.11.12 → v0.15.13](https://github.com/astral-sh/ruff-pre-commit/compare/v0.11.12...v0.15.13)
2026-05-22 16:13:54 -07:00
Mike
881289aee9 ci: bump django to 5.2 2026-05-22 16:11:04 -07:00
dependabot[bot]
853682c08f chore(deps-dev): bump nltk from 3.9.1 to 3.9.4
Bumps [nltk](https://github.com/nltk/nltk) from 3.9.1 to 3.9.4.
- [Changelog](https://github.com/nltk/nltk/blob/develop/ChangeLog)
- [Commits](https://github.com/nltk/nltk/compare/3.9.1...3.9.4)

---
updated-dependencies:
- dependency-name: nltk
  dependency-version: 3.9.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:07:45 -07:00
dependabot[bot]
ae5d7dd15c chore(deps-dev): bump pytest from 8.4.2 to 9.0.3
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.4.2 to 9.0.3.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.4.2...9.0.3)

---
updated-dependencies:
- dependency-name: pytest
  dependency-version: 9.0.3
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 16:07:30 -07:00
Mike
1559ff79fb fix(lint): fix en dash lint errors 2026-05-22 16:02:14 -07:00
dependabot[bot]
9c04f3e300 chore(deps-dev): bump pytest-cov from 6.2.1 to 7.1.0
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 6.2.1 to 7.1.0.
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v6.2.1...v7.1.0)

---
updated-dependencies:
- dependency-name: pytest-cov
  dependency-version: 7.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 15:59:18 -07:00
dependabot[bot]
fee490a599 chore(deps): bump actions/cache from 4 to 5
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 15:51:16 -07:00
dependabot[bot]
17e913ae36 chore(deps-dev): bump pytest from 8.4.1 to 8.4.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.4.1 to 8.4.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.4.1...8.4.2)

---
updated-dependencies:
- dependency-name: pytest
  dependency-version: 8.4.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 15:50:23 -07:00
dependabot[bot]
22c140908a chore(deps): bump actions/setup-python from 5 to 6
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 15:49:55 -07:00
Mike
917599d16a ci: only trigger test workflow on push to master to avoid duplicate runs on PRs 2026-05-22 15:48:27 -07:00
Mike
16b0930195 fix: replace deprecated check kwarg with condition in CheckConstraint 2026-05-22 15:48:27 -07:00
Mike
1f46bb9d15 fix(queryset): guard against Q children in is_eav_and_leaf (#634) 2026-05-22 15:48:27 -07:00
Mike
ccab2c4162 chore: drop EOL Django/Python versions, add Django 6.0 support 2026-05-22 15:37:52 -07:00
dependabot[bot]
d941373d34 chore(deps-dev): bump hypothesis from 6.135.24 to 6.135.26
Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.135.24 to 6.135.26.
- [Release notes](https://github.com/HypothesisWorks/hypothesis/releases)
- [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.135.24...hypothesis-python-6.135.26)

---
updated-dependencies:
- dependency-name: hypothesis
  dependency-version: 6.135.26
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-06 20:56:28 -07:00
dependabot[bot]
8b70e6afec chore(deps-dev): bump hypothesis from 6.133.0 to 6.135.24
Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.133.0 to 6.135.24.
- [Release notes](https://github.com/HypothesisWorks/hypothesis/releases)
- [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.133.0...hypothesis-python-6.135.24)

---
updated-dependencies:
- dependency-name: hypothesis
  dependency-version: 6.135.24
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-05 12:25:44 -07:00
dependabot[bot]
5248498008 chore(deps-dev): bump ruff from 0.11.12 to 0.12.2
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.11.12 to 0.12.2.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.11.12...0.12.2)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.12.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-04 15:42:50 -07:00
dependabot[bot]
ce5f58dc50 chore(deps-dev): bump urllib3 from 2.4.0 to 2.5.0
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.5.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-04 15:42:41 -07:00
dependabot[bot]
f42a53bcaf chore(deps-dev): bump pytest from 8.3.5 to 8.4.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.3.5 to 8.4.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.5...8.4.1)

---
updated-dependencies:
- dependency-name: pytest
  dependency-version: 8.4.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-04 15:42:34 -07:00
dependabot[bot]
32e20994f1 chore(deps-dev): bump mypy from 1.16.0 to 1.16.1
Bumps [mypy](https://github.com/python/mypy) from 1.16.0 to 1.16.1.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.16.0...v1.16.1)

---
updated-dependencies:
- dependency-name: mypy
  dependency-version: 1.16.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-04 15:37:03 -07:00
dependabot[bot]
ec9a5b413d chore(deps-dev): bump safety from 3.5.1 to 3.5.2
Bumps [safety](https://github.com/pyupio/safety) from 3.5.1 to 3.5.2.
- [Release notes](https://github.com/pyupio/safety/releases)
- [Changelog](https://github.com/pyupio/safety/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyupio/safety/compare/3.5.1...3.5.2)

---
updated-dependencies:
- dependency-name: safety
  dependency-version: 3.5.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-04 15:36:53 -07:00
dependabot[bot]
dcc643ff81 chore(deps-dev): bump pytest-cov from 5.0.0 to 6.2.1
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 5.0.0 to 6.2.1.
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v5.0.0...v6.2.1)

---
updated-dependencies:
- dependency-name: pytest-cov
  dependency-version: 6.2.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-04 15:36:40 -07:00
dependabot[bot]
88d367f924 chore(deps): bump django from 4.2.21 to 4.2.23
Bumps [django](https://github.com/django/django) from 4.2.21 to 4.2.23.
- [Commits](https://github.com/django/django/compare/4.2.21...4.2.23)

---
updated-dependencies:
- dependency-name: django
  dependency-version: 4.2.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-04 15:10:34 -07:00
dependabot[bot]
f7aeed0b14 chore(deps-dev): bump requests from 2.32.3 to 2.32.4
Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-04 15:10:21 -07:00
dependabot[bot]
a32e94adb6 chore(deps-dev): bump tomlkit from 0.13.2 to 0.13.3
Bumps [tomlkit](https://github.com/sdispater/tomlkit) from 0.13.2 to 0.13.3.
- [Release notes](https://github.com/sdispater/tomlkit/releases)
- [Changelog](https://github.com/python-poetry/tomlkit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sdispater/tomlkit/compare/0.13.2...0.13.3)

---
updated-dependencies:
- dependency-name: tomlkit
  dependency-version: 0.13.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-04 15:10:11 -07:00
Mike
794c71c7a6 chore: release 1.8.1 2025-06-02 10:46:04 -07:00
pre-commit-ci[bot]
8dd92753d6 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.11.11 → v0.11.12](https://github.com/astral-sh/ruff-pre-commit/compare/v0.11.11...v0.11.12)
2025-06-02 10:36:16 -07:00
pre-commit-ci[bot]
539f0003a1 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.11.8 → v0.11.11](https://github.com/astral-sh/ruff-pre-commit/compare/v0.11.8...v0.11.11)
2025-06-02 09:09:58 -07:00
Mike
dc371db44f chore(deps): update downstream dependencies 2025-06-02 09:08:01 -07:00
Mike
24c1de89fa ci(workflow): update Python and Django version matrix for tests 2025-06-02 08:57:36 -07:00
Mike
3e5841af10 chore(deps): update python and django version requirements 2025-06-02 08:57:18 -07:00
dependabot[bot]
dc49b53c82 chore(deps-dev): bump m2r2 from 0.3.3.post2 to 0.3.4
Bumps [m2r2](https://github.com/crossnox/m2r2) from 0.3.3.post2 to 0.3.4.
- [Changelog](https://github.com/CrossNox/m2r2/blob/development/CHANGES.md)
- [Commits](https://github.com/crossnox/m2r2/compare/v0.3.3.post2...v0.3.4)

---
updated-dependencies:
- dependency-name: m2r2
  dependency-version: 0.3.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 14:45:08 -07:00
dependabot[bot]
f193bd41cd chore(deps-dev): bump ruff from 0.9.7 to 0.11.8
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.9.7 to 0.11.8.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.7...0.11.8)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.11.8
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 14:26:54 -07:00
dependabot[bot]
f7f3d59b30 chore(deps-dev): bump jinja2 from 3.1.5 to 3.1.6
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.5 to 3.1.6.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.5...3.1.6)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 14:18:04 -07:00
pre-commit-ci[bot]
439fa5046f [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.9.7 → v0.11.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.9.7...v0.11.8)
2025-05-05 14:17:56 -07:00
dependabot[bot]
fe6db896bd chore(deps-dev): bump pytest from 8.3.4 to 8.3.5
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.3.4 to 8.3.5.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.4...8.3.5)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 14:17:44 -07:00
Mike
682cf61840 ci: improve test workflow configuration
- Prevent test workflow from running on tag pushes to avoid
  duplicate runs during releases
- Rename job from "build" to "test-matrix" for clarity
2025-02-24 19:22:03 -08:00
Mike
7e572801b0 ci: update PyPI publish action to use recommended tag 2025-02-24 19:15:02 -08:00
Mike
a38a6b9f5c chore: release 1.8.0 2025-02-24 19:01:08 -08:00
wolfmetr
2b9b9d7aa7 Fix for issue #648: Ensure choices are valid (value, label) tuples to avoid 'not enough values to unpack' error
(cherry picked from commit 30e8873b10db560b845f23697e00d20c42d7a989)
2025-02-24 18:53:50 -08:00
pre-commit-ci[bot]
f6b3cf0865 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.9.6 → v0.9.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.9.6...v0.9.7)
2025-02-24 18:27:00 -08:00
dependabot[bot]
041b19a1d2 chore(deps-dev): bump ruff from 0.9.6 to 0.9.7
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.9.6 to 0.9.7.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.6...0.9.7)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 18:26:49 -08:00
dependabot[bot]
e789a0dcd3 chore(deps-dev): bump safety from 3.2.14 to 3.3.0
Bumps [safety](https://github.com/pyupio/safety) from 3.2.14 to 3.3.0.
- [Release notes](https://github.com/pyupio/safety/releases)
- [Changelog](https://github.com/pyupio/safety/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyupio/safety/compare/3.2.14...3.3.0)

---
updated-dependencies:
- dependency-name: safety
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 18:26:40 -08:00
Mike
fafe528ea5 feat(models): add database constraints to Value model 2025-02-24 18:26:28 -08:00
Mike
4deda2abc5 refactor: move Sequence import to type-checking block
- Fix Ruff TC003 linting error
2025-02-13 09:09:40 -08:00
pre-commit-ci[bot]
28c67b3d04 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-02-13 09:09:40 -08:00
pre-commit-ci[bot]
449ddc9248 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.7.3 → v0.9.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.3...v0.9.6)
2025-02-13 09:09:40 -08:00
Mike
a95f2a1c33 style(lint): apply ruff formatting rules with defined target-version 2025-02-13 07:40:43 -08:00
Mike
996512b04c chore(ruff): set python target version to 3.8 2025-02-13 07:39:22 -08:00
dependabot[bot]
73755c4fdf chore(deps-dev): bump ruff from 0.9.5 to 0.9.6
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.9.5 to 0.9.6.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.5...0.9.6)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-13 07:27:44 -08:00
dependabot[bot]
579a1e0fc7 chore(deps-dev): bump pytest-django from 4.9.0 to 4.10.0
Bumps [pytest-django](https://github.com/pytest-dev/pytest-django) from 4.9.0 to 4.10.0.
- [Release notes](https://github.com/pytest-dev/pytest-django/releases)
- [Changelog](https://github.com/pytest-dev/pytest-django/blob/main/docs/changelog.rst)
- [Commits](https://github.com/pytest-dev/pytest-django/compare/v4.9.0...v4.10.0)

---
updated-dependencies:
- dependency-name: pytest-django
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-13 07:27:31 -08:00
dependabot[bot]
b160b38309 chore(deps-dev): bump ruff from 0.8.0 to 0.9.5
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.8.0 to 0.9.5.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.8.0...0.9.5)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-09 13:25:33 -08:00
dependabot[bot]
436edd5492 chore(deps): bump django from 4.2.16 to 4.2.19
Bumps [django](https://github.com/django/django) from 4.2.16 to 4.2.19.
- [Commits](https://github.com/django/django/compare/4.2.16...4.2.19)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-08 08:46:37 -08:00
dependabot[bot]
9261d518da chore(deps-dev): bump jinja2 from 3.1.4 to 3.1.5
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.4...3.1.5)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-08 08:30:09 -08:00
Mike
18148c2b97 pin Poetry to 1.8.4 2025-02-08 08:25:33 -08:00
dependabot[bot]
eca5995616 chore(deps-dev): bump mypy from 1.13.0 to 1.14.1
Bumps [mypy](https://github.com/python/mypy) from 1.13.0 to 1.14.1.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.13.0...v1.14.1)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-08 08:17:47 -08:00
dependabot[bot]
1125887ba9 chore(deps-dev): bump safety from 3.2.11 to 3.2.14
Bumps [safety](https://github.com/pyupio/safety) from 3.2.11 to 3.2.14.
- [Release notes](https://github.com/pyupio/safety/releases)
- [Changelog](https://github.com/pyupio/safety/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyupio/safety/compare/3.2.11...3.2.14)

---
updated-dependencies:
- dependency-name: safety
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-08 08:17:41 -08:00
dependabot[bot]
9c68743af8 chore(deps-dev): bump pytest from 8.3.3 to 8.3.4
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.3.3 to 8.3.4.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.3...8.3.4)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-08 08:17:34 -08:00
dependabot[bot]
6c44ba988a chore(deps-dev): bump ruff from 0.7.3 to 0.8.0
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.7.3 to 0.8.0.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.7.3...0.8.0)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-27 11:24:33 -08:00
dependabot[bot]
75708e3fbb chore(deps): bump codecov/codecov-action from 3 to 5
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 5.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v3...v5)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-27 11:24:25 -08:00
dependabot[bot]
34862ed30a chore(deps-dev): bump sphinx-rtd-theme from 3.0.1 to 3.0.2
Bumps [sphinx-rtd-theme](https://github.com/readthedocs/sphinx_rtd_theme) from 3.0.1 to 3.0.2.
- [Changelog](https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/changelog.rst)
- [Commits](https://github.com/readthedocs/sphinx_rtd_theme/compare/3.0.1...3.0.2)

---
updated-dependencies:
- dependency-name: sphinx-rtd-theme
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-27 11:24:16 -08:00
dependabot[bot]
abd93a44a1 chore(deps-dev): bump safety from 3.2.10 to 3.2.11
Bumps [safety](https://github.com/pyupio/safety) from 3.2.10 to 3.2.11.
- [Release notes](https://github.com/pyupio/safety/releases)
- [Changelog](https://github.com/pyupio/safety/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyupio/safety/compare/3.2.10...3.2.11)

---
updated-dependencies:
- dependency-name: safety
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-27 11:24:09 -08:00
dependabot[bot]
835717bd27 chore(deps-dev): bump ruff from 0.6.8 to 0.7.3
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.8 to 0.7.3.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.6.8...0.7.3)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-11 15:39:32 -08:00
dependabot[bot]
3a7d8eec63 chore(deps-dev): bump safety from 3.2.8 to 3.2.10
Bumps [safety](https://github.com/pyupio/safety) from 3.2.8 to 3.2.10.
- [Release notes](https://github.com/pyupio/safety/releases)
- [Changelog](https://github.com/pyupio/safety/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyupio/safety/compare/3.2.8...3.2.10)

---
updated-dependencies:
- dependency-name: safety
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-11 14:09:02 -08:00
dependabot[bot]
fef15f0ba6 chore(deps-dev): bump mypy from 1.11.2 to 1.13.0
Bumps [mypy](https://github.com/python/mypy) from 1.11.2 to 1.13.0.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.11.2...v1.13.0)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-11 14:08:55 -08:00
dependabot[bot]
ae73962bb2 chore(deps-dev): bump sphinx-rtd-theme from 2.0.0 to 3.0.1
Bumps [sphinx-rtd-theme](https://github.com/readthedocs/sphinx_rtd_theme) from 2.0.0 to 3.0.1.
- [Changelog](https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/changelog.rst)
- [Commits](https://github.com/readthedocs/sphinx_rtd_theme/compare/2.0.0...3.0.1)

---
updated-dependencies:
- dependency-name: sphinx-rtd-theme
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-11 14:08:48 -08:00
dependabot[bot]
70fceedda0 chore(deps-dev): bump hypothesis from 6.112.2 to 6.113.0
Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.112.2 to 6.113.0.
- [Release notes](https://github.com/HypothesisWorks/hypothesis/releases)
- [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.112.2...hypothesis-python-6.113.0)

---
updated-dependencies:
- dependency-name: hypothesis
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-11 14:08:39 -08:00
pre-commit-ci[bot]
39c3540592 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.6.0 → v5.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.6.0...v5.0.0)
- [github.com/astral-sh/ruff-pre-commit: v0.6.8 → v0.7.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.8...v0.7.3)
2024-11-11 14:08:26 -08:00
dependabot[bot]
6c3c7f39e8 chore(deps-dev): bump hypothesis from 6.112.1 to 6.112.2
Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.112.1 to 6.112.2.
- [Release notes](https://github.com/HypothesisWorks/hypothesis/releases)
- [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.112.1...hypothesis-python-6.112.2)

---
updated-dependencies:
- dependency-name: hypothesis
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-03 17:24:32 -07:00
dependabot[bot]
a47b1b05e0 chore(deps-dev): bump safety from 3.2.7 to 3.2.8
Bumps [safety](https://github.com/pyupio/safety) from 3.2.7 to 3.2.8.
- [Release notes](https://github.com/pyupio/safety/releases)
- [Changelog](https://github.com/pyupio/safety/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyupio/safety/compare/3.2.7...3.2.8)

---
updated-dependencies:
- dependency-name: safety
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-03 17:24:26 -07:00
dependabot[bot]
b276cb3e35 chore(deps-dev): bump ruff from 0.6.5 to 0.6.8
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.5 to 0.6.8.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.6.5...0.6.8)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-03 17:24:18 -07:00
pre-commit-ci[bot]
5a1d7546f4 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.6.5 → v0.6.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.5...v0.6.8)
2024-10-03 17:24:10 -07:00
dependabot[bot]
dc2cd2dff5 chore(deps-dev): bump ruff from 0.6.3 to 0.6.5
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.3 to 0.6.5.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.6.3...0.6.5)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-19 08:56:06 -07:00
dependabot[bot]
0e27224106 chore(deps-dev): bump hypothesis from 6.111.2 to 6.112.1
Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.111.2 to 6.112.1.
- [Release notes](https://github.com/HypothesisWorks/hypothesis/releases)
- [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.111.2...hypothesis-python-6.112.1)

---
updated-dependencies:
- dependency-name: hypothesis
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-19 08:56:00 -07:00
dependabot[bot]
305740e2e6 chore(deps-dev): bump pytest from 8.3.2 to 8.3.3
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.3.2 to 8.3.3.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.2...8.3.3)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-19 08:55:53 -07:00
pre-commit-ci[bot]
d281ff97c2 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.6.3 → v0.6.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.3...v0.6.5)
2024-09-19 08:55:44 -07:00
dependabot[bot]
e17778b522 chore(deps): bump django from 4.2.15 to 4.2.16
Bumps [django](https://github.com/django/django) from 4.2.15 to 4.2.16.
- [Commits](https://github.com/django/django/compare/4.2.15...4.2.16)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-19 08:55:36 -07:00
dependabot[bot]
0f218add0b chore(deps-dev): bump cryptography from 42.0.8 to 43.0.1
Bumps [cryptography](https://github.com/pyca/cryptography) from 42.0.8 to 43.0.1.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/42.0.8...43.0.1)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-03 18:18:12 -07:00
dependabot[bot]
f07e2d0506 chore(deps-dev): bump pytest-django from 4.8.0 to 4.9.0
Bumps [pytest-django](https://github.com/pytest-dev/pytest-django) from 4.8.0 to 4.9.0.
- [Release notes](https://github.com/pytest-dev/pytest-django/releases)
- [Changelog](https://github.com/pytest-dev/pytest-django/blob/main/docs/changelog.rst)
- [Commits](https://github.com/pytest-dev/pytest-django/compare/v4.8.0...v4.9.0)

---
updated-dependencies:
- dependency-name: pytest-django
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-03 17:29:39 -07:00
dependabot[bot]
0d82d5ab5a chore(deps-dev): bump doc8 from 1.1.1 to 1.1.2
Bumps [doc8](https://github.com/pycqa/doc8) from 1.1.1 to 1.1.2.
- [Release notes](https://github.com/pycqa/doc8/releases)
- [Commits](https://github.com/pycqa/doc8/compare/v1.1.1...v1.1.2)

---
updated-dependencies:
- dependency-name: doc8
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-03 17:29:31 -07:00
Mike
d0b531f7be chore: release 1.7.1 2024-09-01 21:30:59 -07:00
Mike
8f18d5e7e2 fix(attribute): restore backward compatibility for invalid slugs
Replace ValidationError with a warning when creating Attributes with invalid slugs. This change allows existing code to continue functioning while alerting users to potential issues.
2024-09-01 21:26:45 -07:00
26 changed files with 2382 additions and 1003 deletions

View file

@ -1,15 +1,38 @@
version: 2
updates:
- package-ecosystem: pip
directory: "/"
schedule:
interval: daily
time: "02:00"
open-pull-requests-limit: 10
- package-ecosystem: pip
directory: "/"
schedule:
interval: daily
time: "02:00"
cooldown:
default-days: 7
open-pull-requests-limit: 10
groups:
test-dependencies:
patterns:
- "pytest*"
- "mypy"
- "ruff"
- "hypothesis"
- "safety"
- "doc8"
commit-message:
prefix: "chore"
include: "scope"
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
time: "02:00"
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
time: "02:00"
cooldown:
default-days: 7
open-pull-requests-limit: 10
groups:
github-actions:
patterns:
- "*"
commit-message:
prefix: "ci"
include: "scope"

View file

@ -0,0 +1,25 @@
name: Dependabot auto-merge
on: pull_request
permissions:
contents: write
pull-requests: write
jobs:
auto-merge:
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]'
steps:
- name: Fetch Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v3
- name: Auto-merge patch and minor updates
if: |
steps.metadata.outputs.update-type == 'version-update:semver-patch' ||
steps.metadata.outputs.update-type == 'version-update:semver-minor'
run: gh pr merge --auto --squash "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -11,12 +11,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: 3.8
@ -32,7 +32,7 @@ jobs:
- name: Upload packages to Jazzband
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@master
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: jazzband
password: ${{ secrets.JAZZBAND_RELEASE_KEY }}

View file

@ -1,43 +1,45 @@
# https://docs.djangoproject.com/en/stable/faq/install/#what-python-version-can-i-use-with-django
name: test
"on": [push, pull_request, workflow_dispatch]
"on":
push:
branches:
- master
pull_request:
workflow_dispatch:
jobs:
build:
test-matrix:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
django-version: ["4.2", "5.0", "5.1"]
python-version: ['3.10', '3.11', '3.12', '3.13']
django-version: ['5.2', '6.0']
exclude:
# Exclude Python 3.8 and 3.9 with Django 5.0
- python-version: '3.8'
django-version: '5.0'
- python-version: '3.9'
django-version: '5.0'
# Exclude Python 3.8 and 3.9 with Django 5.1
- python-version: '3.8'
django-version: '5.1'
- python-version: '3.9'
django-version: '5.1'
# Django 6.0 requires Python 3.12+
- python-version: '3.10'
django-version: '6.0'
- python-version: '3.11'
django-version: '6.0'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.8.4
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true
- name: Set up cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: .venv
key: venv-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
@ -55,6 +57,6 @@ jobs:
poetry run pip check
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v6
with:
file: ./coverage.xml
files: ./coverage.xml

View file

@ -1,7 +1,7 @@
# See https://pre-commit.com for more information
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@ -11,7 +11,7 @@ repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.3
rev: v0.15.13
hooks:
# Run the linter.
- id: ruff
@ -24,4 +24,4 @@ repos:
hooks:
- id: check-migrations-created
args: [--manage-path=manage.py]
additional_dependencies: [django==4.1]
additional_dependencies: [django==5.2]

View file

@ -2,12 +2,47 @@
We follow [Semantic Versions](https://semver.org/) starting at the `0.14.0` release.
## v1.7.0 (2024-09-01)
## 1.8.2 (2026-05-22)
## What's Changed
### Bug Fixes
- Fixed `TypeError: 'Q' object is not subscriptable` when combining EAV filters with negated Q objects by @Dresdn in https://github.com/jazzband/django-eav2/pull/846
### Compatibility
- Added Django 6.0 support
- Dropped support for EOL Django versions — minimum is now Django 5.2
- Dropped support for EOL Python versions — minimum is now Python 3.10
## 1.8.1 (2025-06-02)
## What's Changed
- Added support for Django 5.2
- Updated dependencies to their latest versions
## 1.8.0 (2025-02-24)
## What's Changed
- Add database constraints to Value model for data integrity by @Dresdn in https://github.com/jazzband/django-eav2/pull/706
- Fix for issue #648: Ensure choices are valid (value, label) tuples by @altimore in https://github.com/jazzband/django-eav2/pull/707
## 1.7.1 (2024-09-01)
## What's Changed
* Restore backward compatibility for Attribute creation with invalid slugs by @Dresdn in https://github.com/jazzband/django-eav2/pull/639
## 1.7.0 (2024-09-01)
### What's Changed
- Enhance slug validation for Python identifier compliance
- Migrate to ruff
- Drop support for Django 3.2
- Add support for Django 5.1
## 1.6.1 (2024-06-23)

View file

@ -1,10 +1,10 @@
def register(model_cls, config_cls=None):
from eav.registry import Registry
from eav.registry import Registry # noqa: PLC0415
Registry.register(model_cls, config_cls)
def unregister(model_cls):
from eav.registry import Registry
from eav.registry import Registry # noqa: PLC0415
Registry.unregister(model_cls)

View file

@ -2,7 +2,7 @@
from __future__ import annotations
from typing import Any, ClassVar, Dict, List, Sequence, Union
from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Union
from django.contrib import admin
from django.contrib.admin.options import InlineModelAdmin, ModelAdmin
@ -11,6 +11,9 @@ from django.utils.safestring import mark_safe
from eav.models import Attribute, EnumGroup, EnumValue, Value
if TYPE_CHECKING:
from collections.abc import Sequence
_FIELDSET_TYPE = List[Union[str, Dict[str, Any]]] # type: ignore[misc]
some_attribute = ClassVar[Dict[str, str]]

View file

@ -3,6 +3,10 @@ This module contains pure wrapper functions used as decorators.
Functions in this module should be simple and not involve complex logic.
"""
from django.db.models import Model
from eav import register
def register_eav(**kwargs):
"""
@ -13,9 +17,6 @@ def register_eav(**kwargs):
class Author(models.Model):
pass
"""
from django.db.models import Model
from eav import register
def _model_eav_wrapper(model_class):
if not issubclass(model_class, Model):

View file

@ -107,7 +107,7 @@ class BaseDynamicEntityForm(ModelForm):
if datatype == attribute.TYPE_ENUM:
values = attribute.get_choices().values_list("id", "value")
choices = ["", "-----", *list(values)]
choices = [("", ""), ("-----", "-----"), *list(values)]
defaults.update({"choices": choices})
if value:

View file

@ -86,7 +86,7 @@ class ValueManager(models.Manager):
Returns:
Value: The instance matching the provided keys.
"""
from eav.models import Attribute
from eav.models import Attribute # noqa: PLC0415
attribute = Attribute.objects.get(name=attribute[0], slug=attribute[1])

View file

@ -0,0 +1,54 @@
from django.db import migrations, models
class Migration(migrations.Migration):
"""
Add uniqueness and integrity constraints to the Value model.
This migration adds database-level constraints to ensure:
1. Each entity (identified by UUID) can have only one value per attribute
2. Each entity (identified by integer ID) can have only one value per attribute
3. Each value must use either entity_id OR entity_uuid, never both or neither
These constraints ensure data integrity by preventing duplicate attribute values
for the same entity and enforcing the XOR relationship between the two types of
entity identification (integer ID vs UUID).
"""
dependencies = [
("eav", "0011_update_defaults_and_meta"),
]
operations = [
migrations.AddConstraint(
model_name="value",
constraint=models.UniqueConstraint(
fields=("entity_ct", "attribute", "entity_uuid"),
name="unique_entity_uuid_per_attribute",
),
),
migrations.AddConstraint(
model_name="value",
constraint=models.UniqueConstraint(
fields=("entity_ct", "attribute", "entity_id"),
name="unique_entity_id_per_attribute",
),
),
migrations.AddConstraint(
model_name="value",
constraint=models.CheckConstraint(
condition=models.Q(
models.Q(
("entity_id__isnull", False),
("entity_uuid__isnull", True),
),
models.Q(
("entity_id__isnull", True),
("entity_uuid__isnull", False),
),
_connector="OR",
),
name="ensure_entity_id_xor_entity_uuid",
),
),
]

View file

@ -17,9 +17,9 @@ from .value import Value
__all__ = [
"Attribute",
"EAVModelMeta",
"Entity",
"EnumGroup",
"EnumValue",
"Value",
"Entity",
"EAVModelMeta",
]

View file

@ -1,8 +1,7 @@
# ruff: noqa: UP007
from __future__ import annotations
from typing import TYPE_CHECKING, Optional
import warnings
from typing import TYPE_CHECKING
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
@ -164,7 +163,7 @@ class Attribute(models.Model):
:meth:`~eav.registry.EavConfig.get_attributes` method of that entity's config.
"""
enum_group: ForeignKey[Optional[EnumGroup]] = ForeignKey(
enum_group: ForeignKey[EnumGroup | None] = ForeignKey(
"eav.EnumGroup",
on_delete=models.PROTECT,
blank=True,
@ -311,13 +310,10 @@ class Attribute(models.Model):
super().clean_fields(exclude=exclude)
if not self.slug.isidentifier():
raise ValidationError(
{
"slug": _(
"Slug must be a valid Python identifier (no spaces, "
+ "special characters, or leading digits).",
),
},
warnings.warn(
f"Slug '{self.slug}' is not a valid Python identifier. "
+ "Consider updating it.",
stacklevel=3,
)
def get_choices(self):

View file

@ -1,7 +1,6 @@
# ruff: noqa: UP007
from __future__ import annotations
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, ClassVar
from django.contrib.contenttypes import fields as generic
from django.contrib.contenttypes.models import ContentType
@ -137,7 +136,7 @@ class Value(models.Model):
verbose_name=_("Value JSON"),
)
value_enum: ForeignKey[Optional[EnumValue]] = ForeignKey(
value_enum: ForeignKey[EnumValue | None] = ForeignKey(
"eav.EnumValue",
blank=True,
null=True,
@ -173,21 +172,39 @@ class Value(models.Model):
verbose_name = _("Value")
verbose_name_plural = _("Values")
constraints: ClassVar[list[models.Constraint]] = [
models.UniqueConstraint(
fields=["entity_ct", "attribute", "entity_uuid"],
name="unique_entity_uuid_per_attribute",
),
models.UniqueConstraint(
fields=["entity_ct", "attribute", "entity_id"],
name="unique_entity_id_per_attribute",
),
models.CheckConstraint(
condition=(
models.Q(entity_id__isnull=False, entity_uuid__isnull=True)
| models.Q(entity_id__isnull=True, entity_uuid__isnull=False)
),
name="ensure_entity_id_xor_entity_uuid",
),
]
def __str__(self) -> str:
"""String representation of a Value."""
entity = self.entity_pk_uuid if self.entity_uuid else self.entity_pk_int
return f'{self.attribute.name}: "{self.value}" ({entity})'
def __repr__(self) -> str:
"""Representation of Value object."""
entity = self.entity_pk_uuid if self.entity_uuid else self.entity_pk_int
return f'{self.attribute.name}: "{self.value}" ({entity})'
def save(self, *args, **kwargs):
"""Validate and save this value."""
self.full_clean()
super().save(*args, **kwargs)
def __repr__(self) -> str:
"""Representation of Value object."""
entity = self.entity_pk_uuid if self.entity_uuid else self.entity_pk_int
return f'{self.attribute.name}: "{self.value}" ({entity})'
def natural_key(self) -> tuple[tuple[str, str], int, str]:
"""
Retrieve the natural key for the Value instance.

View file

@ -12,11 +12,27 @@ Q-expressions need to be rewritten for two reasons:
city_values = Value.objects.filter(value__text__startswith='New')
Supplier.objects.filter(eav_values__in=city_values)
For details see: :func:`eav_filter`.
2. To ensure that Q-expression tree is compiled to valid SQL.
For details see: :func:`rewrite_q_expr`.
.. note:: EAV negation limitation
Because EAV values are stored as individual rows in a shared table,
using ``~Q(eav__attr=value)`` inside ``.filter()`` negates at the
**row** level rather than the **entity** level. This can produce
unexpected results: an entity that has *other* EAV rows not matching
the negation will still appear in the result set.
The correct way to express "entities where attr A = x AND attr B ≠ y"
is to chain ``.exclude()`` instead::
# Wrong - row-level negation, may return unexpected results
MyModel.objects.filter(Q(eav__a=x) & ~Q(eav__b=y))
# Correct - entity-level negation
MyModel.objects.filter(eav__a=x).exclude(eav__b=y)
"""
from functools import wraps
@ -44,6 +60,7 @@ def is_eav_and_leaf(expr, gr_name):
return (
getattr(expr, "connector", None) == "AND"
and len(expr.children) == 1
and isinstance(expr.children[0], tuple)
and expr.children[0][0] in ["pk__in", f"{gr_name}__in"]
)

View file

@ -83,7 +83,7 @@ def validate_enum(value):
Raises ``ValidationError`` unless *value* is a saved
:class:`~eav.models.EnumValue` model instance.
"""
from eav.models import EnumValue
from eav.models import EnumValue # noqa: PLC0415
if isinstance(value, EnumValue) and not value.pk:
raise ValidationError(_("EnumValue has not been saved yet"))

View file

@ -3,6 +3,15 @@
import os
import sys
try:
from django.core import management
except ImportError as err:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?",
) from err
def main() -> None:
"""
@ -14,16 +23,6 @@ def main() -> None:
3. Executes any given command
"""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings")
try:
from django.core import management
except ImportError as err:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?",
) from err
management.execute_from_command_line(sys.argv)

2497
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,12 @@
[build-system]
requires = ["poetry-core"]
requires = ["poetry-core>=1.9"]
build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "django-eav2"
description = "Entity-Attribute-Value storage for Django"
version = "1.7.0"
version = "1.8.2"
license = "GNU Lesser General Public License (LGPL), Version 3"
packages = [
{ include = "eav" }
@ -37,17 +37,15 @@ classifiers = [
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"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",
"Programming Language :: Python :: 3.13",
"Topic :: Database",
"Topic :: Software Development :: Libraries :: Python Modules",
"Framework :: Django",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.0",
"Framework :: Django :: 5.1",
"Framework :: Django :: 5.2",
"Framework :: Django :: 6.0",
]
[tool.semantic_release]
@ -60,36 +58,37 @@ upload_to_release = false
build_command = "pip install poetry && poetry build"
[tool.poetry.dependencies]
python = "^3.8"
django = ">=4.2,<5.2"
python = "^3.10"
django = ">=5.2"
[tool.poetry.group.test.dependencies]
mypy = "^1.6"
ruff = "^0.6.3"
mypy = ">=1.6,<3.0"
ruff = ">=0.6.3,<0.16.0"
safety = ">=2.3,<4.0"
pytest = ">=7.4.3,<9.0.0"
pytest-cov = ">=4.1,<6.0"
pytest-randomly = "^3.15"
pytest = ">=7.4.3,<10.0.0"
pytest-cov = ">=4.1,<8.0"
pytest-randomly = ">=3.15,<5.0"
pytest-django = "^4.5.2"
hypothesis = "^6.87.1"
doc8 = ">=0.11.2,<1.2.0"
doc8 = ">=0.11.2,<2.1.0"
[tool.poetry.group.docs]
optional = true
[tool.poetry.group.docs.dependencies]
sphinx = ">=5.0,<8.0"
sphinx-rtd-theme = ">=1.3,<3.0"
sphinx = ">=5.0,<9.0"
sphinx-rtd-theme = ">=1.3,<4.0"
sphinx-autodoc-typehints = ">=1.19.5,<3.0.0"
m2r2 = "^0.3"
tomlkit = ">=0.13.0,<0.14"
tomlkit = ">=0.13.0,<0.16"
[tool.ruff]
line-length = 88
target-version = "py38"
[tool.ruff.lint]
select = ["ALL"]
@ -122,8 +121,10 @@ allow-multiline = false
"tests/*" = [
"INP001", # "Add an __init__.py"
"PLR2004", # "Magic value used in comparison"
"PLW0108", # "Lambda may be unnecessary" - used with assertRaises
"PT009", # "Use a regular assert instead of unittest-style"
"PT027", # "Use pytest.raises instead of unittest-style"
"PT030", # "pytest.warns match parameter" - broad warnings intentional in tests
"S101", # "Use of assert detected"
"SLF001" # "Private member accessed"
]

View file

@ -101,7 +101,7 @@ class Encounter(TestBase):
patient = models.ForeignKey(Patient, on_delete=models.PROTECT)
def __str__(self):
return "%s: encounter num %d" % (self.patient, self.num)
return f"{self.patient}: encounter num {self.num}"
def __repr__(self):
return self.name

View file

@ -167,8 +167,15 @@ class TestAttributeModel(django.TestCase):
@pytest.mark.django_db
def test_attribute_create_with_invalid_slug():
with pytest.raises(ValidationError):
def test_attribute_create_with_invalid_slug() -> None:
"""
Test that creating an Attribute with an invalid slug raises a UserWarning.
This test ensures that when an Attribute is created with a slug that is not
a valid Python identifier, a UserWarning is raised. The warning should
indicate that the slug is invalid and suggest updating it.
"""
with pytest.warns(UserWarning):
Attribute.objects.create(
name="Test Attribute",
slug="123-invalid",

View file

@ -211,3 +211,41 @@ def test_entity_admin_form_no_attributes(patient):
# 3 for 'name', 'email', 'example'
assert total_fields == expected_fields
@pytest.mark.django_db
def test_dynamic_form_renders_enum_choices():
"""
Test that enum choices render correctly in BaseDynamicEntityForm.
This test verifies the fix for issue #648 where enum choices weren't
rendering correctly in Django 4.2.17 due to QuerySet unpacking issues.
"""
# Setup
eav.register(Patient)
# Create enum values and group
female = EnumValue.objects.create(value="Female")
male = EnumValue.objects.create(value="Male")
gender_group = EnumGroup.objects.create(name="Gender")
gender_group.values.add(female, male)
Attribute.objects.create(
name="gender",
datatype=Attribute.TYPE_ENUM,
enum_group=gender_group,
)
# Create a patient
patient = Patient.objects.create(name="Test Patient")
# Initialize the dynamic form
form = PatientDynamicForm(instance=patient)
# Test rendering - should not raise any exceptions
rendered_form = form.as_p()
# Verify the form rendered and contains the enum choices
assert 'name="gender"' in rendered_form
assert f'value="{female.pk}">{female.value}' in rendered_form
assert f'value="{male.pk}">{male.value}' in rendered_form

View file

@ -32,9 +32,9 @@ def test_generate_slug_uniqueness() -> None:
generated_slugs: dict[str, str] = {}
for input_str in inputs:
slug = generate_slug(input_str)
assert (
slug not in generated_slugs.values()
), f"Duplicate slug '{slug}' generated for input '{input_str}'"
assert slug not in generated_slugs.values(), (
f"Duplicate slug '{slug}' generated for input '{input_str}'"
)
generated_slugs[input_str] = slug
assert len(generated_slugs) == len(

View file

@ -407,3 +407,148 @@ class Queries(TestCase):
# Assert that the expected patient is returned
self.assertEqual(len(patients), 1)
self.assertEqual(patients[0].name, "Anne")
def test_filter_eav_and_negated_non_eav_field(self) -> None:
"""
Regression test for #634: EAV Q combined with a negated non-EAV Q.
Q(eav__attr=val) & ~Q(non_eav_field=val) raised:
TypeError: 'Q' object is not subscriptable
"""
self.init_data()
# fever=yes → Cyrill, Eugene; name≠"Bob" excludes nobody here
p = Patient.objects.filter(Q(eav__fever=self.yes) & ~Q(name="Bob"))
assert p.count() == 2
assert set(p.values_list("name", flat=True)) == {"Cyrill", "Eugene"}
def test_filter_negated_non_eav_field_and_eav(self) -> None:
"""
Regression test for #634: negated non-EAV Q combined with an EAV Q
(operand order reversed from the previous test).
~Q(non_eav_field=val) & Q(eav__attr=val) raised:
TypeError: 'Q' object is not subscriptable
"""
self.init_data()
# Same expectation as above; order of operands should not matter.
p = Patient.objects.filter(~Q(name="Bob") & Q(eav__fever=self.yes))
assert p.count() == 2
assert set(p.values_list("name", flat=True)) == {"Cyrill", "Eugene"}
def test_filter_eav_and_negated_eav_field(self) -> None:
"""
Regression test for #634: EAV Q combined with a negated EAV Q.
Q(eav__attr1=val) & ~Q(eav__attr2=val) raised:
TypeError: 'Q' object is not subscriptable
Note: negating an EAV filter inside filter() has known SQL JOIN
semantics limitations. Because each EAV attribute is stored as a
separate row in the values table, the negation operates on individual
rows rather than on entities. This means a patient with both a
fever=no value AND a city='Nice' value will still be included because
their fever=no row passes the NOT city='Nice' row-level check.
The primary purpose of this test is to verify no TypeError is raised.
"""
self.init_data()
# fever=no → Anne, Bob, Daniel
# ~city='Nice' does NOT reliably exclude Daniel due to EAV row semantics
p = Patient.objects.filter(Q(eav__fever=self.no) & ~Q(eav__city="Nice"))
# At minimum, the EAV-only patients (no city='Nice') must be present
names = set(p.values_list("name", flat=True))
assert {"Anne", "Bob"}.issubset(names)
# Result is bounded by the fever=no set
assert names.issubset({"Anne", "Bob", "Daniel"})
def test_filter_solo_negated_eav_field(self) -> None:
"""
~Q(eav__attr=val) as the sole argument should work correctly.
This produces entity-level exclusion because there are no other EAV
JOIN conditions to interfere: entities with no matching value row are
simply absent from the JOIN, so NOT eav_values__in correctly excludes
entities that DO have that value row.
"""
self.init_data()
# age != 3 → Bob (15), Cyrill (15), Eugene (2)
p = Patient.objects.filter(~Q(eav__age=3))
assert p.count() == 3
assert set(p.values_list("name", flat=True)) == {"Bob", "Cyrill", "Eugene"}
def test_filter_or_eav_and_non_eav_no_duplicates(self) -> None:
"""
OR between an EAV Q and a non-EAV Q must not return duplicate rows.
When an EAV condition is used in OR with a non-EAV condition, the EAV
side remains as a JOIN condition (it cannot be merged via rewrite_q_expr
because there is only one EAV leaf). This JOIN can produce multiple rows
per entity. Results should be distinct.
This is a known limitation: callers should use .distinct() when mixing
EAV and non-EAV conditions in OR.
"""
self.init_data()
# fever=yes → Cyrill, Eugene; name='Bob' → Bob
p = Patient.objects.filter(Q(eav__fever=self.yes) | Q(name="Bob"))
# Correct distinct count is 3; without distinct() duplicates may appear
assert p.distinct().count() == 3
assert set(p.distinct().values_list("name", flat=True)) == {
"Bob",
"Cyrill",
"Eugene",
}
def test_q_object_not_mutated_by_filter(self) -> None:
"""
Q objects passed to filter() must not be mutated.
expand_q_filters() rewrites Q children in-place. If the original Q
object is mutated, reusing it in a second query will operate on the
already-expanded (internal) form and may produce incorrect results or
errors.
This test documents the current behaviour (mutation occurs) so that
any future fix is captured as a regression guard.
"""
self.init_data()
q = Q(eav__fever=self.yes)
original_children = list(q.children) # [('eav__fever', <EnumValue>)]
Patient.objects.filter(q)
# Document current (broken) behaviour: children are mutated.
# When this is fixed, change the assertion to assertEqual.
assert q.children != original_children, (
"Q mutation is fixed - update this test to assert no mutation"
)
def test_negated_eav_field_workaround_chained_exclude(self) -> None:
"""
Documents the correct way to express "EAV attr A = x AND EAV attr B != y".
Because EAV values are stored one-per-row, using ~Q() inside filter()
negates at the *row* level, not the *entity* level. The correct
approach is to chain .exclude() which operates at the entity level::
# WRONG - may return entities that should be excluded
Patient.objects.filter(Q(eav__fever=no) & ~Q(eav__city="Nice"))
# CORRECT - exclude() works at entity level
Patient.objects.filter(eav__fever=no).exclude(eav__city="Nice")
# or equivalently:
Patient.objects.filter(Q(eav__fever=no)).exclude(Q(eav__city="Nice"))
"""
self.init_data()
# fever=no → Anne, Bob, Daniel; chained exclude removes Daniel
p_chained = Patient.objects.filter(eav__fever=self.no).exclude(
eav__city="Nice",
)
assert p_chained.count() == 2
assert set(p_chained.values_list("name", flat=True)) == {"Anne", "Bob"}
# Q-based form of the same thing
p_q = Patient.objects.filter(Q(eav__fever=self.no)).exclude(
Q(eav__city="Nice"),
)
assert p_q.count() == 2
assert set(p_q.values_list("name", flat=True)) == {"Anne", "Bob"}

319
tests/test_value.py Normal file
View file

@ -0,0 +1,319 @@
import pytest
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.db import IntegrityError
from eav.models import Attribute, Value
from test_project.models import Doctor, Patient
@pytest.fixture
def patient_ct() -> ContentType:
"""Return the content type for the Patient model."""
return ContentType.objects.get_for_model(Patient)
@pytest.fixture
def doctor_ct() -> ContentType:
"""Return the content type for the Doctor model."""
# We use Doctor model for UUID tests since it already uses UUID as primary key
return ContentType.objects.get_for_model(Doctor)
@pytest.fixture
def attribute() -> Attribute:
"""Create and return a test attribute."""
return Attribute.objects.create(
name="test_attribute",
datatype="text",
)
@pytest.fixture
def patient() -> Patient:
"""Create and return a patient with integer PK."""
# Patient model uses auto-incrementing integer primary keys
return Patient.objects.create(name="Patient with Int PK")
@pytest.fixture
def doctor() -> Doctor:
"""Create and return a doctor with UUID PK."""
# Doctor model uses UUID primary keys, ideal for testing entity_uuid constraints
return Doctor.objects.create(name="Doctor with UUID PK")
class TestValueModelValidation:
"""Test Value model Python-level validation (via full_clean in save)."""
@pytest.mark.django_db
def test_unique_entity_id_validation(
self,
patient_ct: ContentType,
attribute: Attribute,
patient: Patient,
) -> None:
"""
Test that model validation prevents duplicate entity_id values.
The model's save() method calls full_clean() which should detect the
duplicate before it hits the database constraint.
"""
# Create first value - this should succeed
Value.objects.create(
entity_ct=patient_ct,
entity_id=patient.id,
attribute=attribute,
value_text="First value",
)
# Try to create a second value with the same entity_ct, attribute, and entity_id
# This should fail with ValidationError from full_clean()
with pytest.raises(ValidationError) as excinfo:
Value.objects.create(
entity_ct=patient_ct,
entity_id=patient.id,
attribute=attribute,
value_text="Second value",
)
# Verify the error message indicates uniqueness violation
assert "already exists" in str(excinfo.value)
@pytest.mark.django_db
def test_unique_entity_uuid_validation(
self,
doctor_ct: ContentType,
attribute: Attribute,
doctor: Doctor,
) -> None:
"""
Test that model validation prevents duplicate entity_uuid values.
The model's full_clean() should detect the duplicate before it hits
the database constraint.
"""
# Create first value with UUID - this should succeed
Value.objects.create(
entity_ct=doctor_ct,
entity_uuid=doctor.id,
attribute=attribute,
value_text="First UUID value",
)
# Try to create a second value with the same entity_ct,
# attribute, and entity_uuid
with pytest.raises(ValidationError) as excinfo:
Value.objects.create(
entity_ct=doctor_ct,
entity_uuid=doctor.id,
attribute=attribute,
value_text="Second UUID value",
)
# Verify the error message indicates uniqueness violation
assert "already exists" in str(excinfo.value)
@pytest.mark.django_db
def test_entity_id_xor_entity_uuid_validation(
self,
patient_ct: ContentType,
attribute: Attribute,
patient: Patient,
doctor: Doctor,
) -> None:
"""
Test that model validation enforces XOR between entity_id and entity_uuid.
The model's full_clean() should detect if both or neither field is provided.
"""
# Try to create with both ID types
with pytest.raises(ValidationError):
Value.objects.create(
entity_ct=patient_ct,
entity_id=patient.id,
entity_uuid=doctor.id,
attribute=attribute,
value_text="Both IDs provided",
)
# Try to create with neither ID type
with pytest.raises(ValidationError):
Value.objects.create(
entity_ct=patient_ct,
entity_id=None,
entity_uuid=None,
attribute=attribute,
value_text="No IDs provided",
)
class TestValueDatabaseConstraints:
"""
Test Value model database constraints when bypassing model validation.
These tests use bulk_create() which bypasses the save() method and its
full_clean() validation, allowing us to test the database constraints directly.
"""
@pytest.mark.django_db
def test_unique_entity_id_constraint(
self,
patient_ct: ContentType,
attribute: Attribute,
patient: Patient,
) -> None:
"""
Test that database constraints prevent duplicate entity_id values.
Even when bypassing model validation with bulk_create, the database
constraint should still prevent duplicates.
"""
# Create first value - this should succeed
Value.objects.create(
entity_ct=patient_ct,
entity_id=patient.id,
attribute=attribute,
value_text="First value",
)
# Try to bulk create a duplicate value, bypassing model validation
with pytest.raises(IntegrityError):
Value.objects.bulk_create(
[
Value(
entity_ct=patient_ct,
entity_id=patient.id,
attribute=attribute,
value_text="Second value",
),
],
)
@pytest.mark.django_db
def test_unique_entity_uuid_constraint(
self,
doctor_ct: ContentType,
attribute: Attribute,
doctor: Doctor,
) -> None:
"""
Test that database constraints prevent duplicate entity_uuid values.
Even when bypassing model validation, the database constraint should
still prevent duplicates.
"""
# Create first value with UUID - this should succeed
Value.objects.create(
entity_ct=doctor_ct,
entity_uuid=doctor.id,
attribute=attribute,
value_text="First UUID value",
)
# Try to bulk create a duplicate value, bypassing model validation
with pytest.raises(IntegrityError):
Value.objects.bulk_create(
[
Value(
entity_ct=doctor_ct,
entity_uuid=doctor.id,
attribute=attribute,
value_text="Second UUID value",
),
],
)
@pytest.mark.django_db
def test_entity_id_and_entity_uuid_constraint(
self,
patient_ct: ContentType,
attribute: Attribute,
patient: Patient,
doctor: Doctor,
) -> None:
"""
Test that database constraints prevent having both entity_id and entity_uuid.
Even when bypassing model validation, the database constraint should
prevent having both fields set.
"""
# Try to bulk create with both ID types
with pytest.raises(IntegrityError):
Value.objects.bulk_create(
[
Value(
entity_ct=patient_ct,
entity_id=patient.id,
entity_uuid=doctor.id,
attribute=attribute,
value_text="Both IDs provided",
),
],
)
@pytest.mark.django_db
def test_neither_entity_id_nor_entity_uuid_constraint(
self,
patient_ct: ContentType,
attribute: Attribute,
) -> None:
"""
Test that database constraints prevent having neither entity_id nor entity_uuid.
Even when bypassing model validation, the database constraint should
prevent having neither field set.
"""
# Try to bulk create with neither ID type
with pytest.raises(IntegrityError):
Value.objects.bulk_create(
[
Value(
entity_ct=patient_ct,
entity_id=None,
entity_uuid=None,
attribute=attribute,
value_text="No IDs provided",
),
],
)
@pytest.mark.django_db
def test_happy_path_constraints(
self,
patient_ct: ContentType,
doctor_ct: ContentType,
attribute: Attribute,
patient: Patient,
doctor: Doctor,
) -> None:
"""
Test that valid values pass both database constraints.
Values with either entity_id or entity_uuid (but not both) should be accepted.
"""
# Test with entity_id using bulk_create
values = Value.objects.bulk_create(
[
Value(
entity_ct=patient_ct,
entity_id=patient.id,
attribute=attribute,
value_text="Integer ID bulk created",
),
],
)
assert len(values) == 1
# Test with entity_uuid using bulk_create
values = Value.objects.bulk_create(
[
Value(
entity_ct=doctor_ct,
entity_uuid=doctor.id,
attribute=attribute,
value_text="UUID bulk created",
),
],
)
assert len(values) == 1