diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 8faf1a2f..00000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,74 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ "main" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "main" ] - schedule: - - cron: '39 4 * * 2' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'python' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:${{matrix.language}}" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2f966adc..ca736986 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] env: PYTHON: ${{ matrix.python-version }} steps: @@ -28,7 +28,7 @@ jobs: python -m pip install --upgrade pip pip install tox - name: Run tox targets for ${{ matrix.python-version }} - run: tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) + run: tox run -f py$(echo ${{ matrix.python-version }} | tr -d . | cut -f 1 -d '-') - name: Upload coverage report uses: codecov/codecov-action@v4 with: @@ -43,10 +43,10 @@ jobs: tox-env: ["black", "lint", "docs"] steps: - uses: actions/checkout@v2 - - name: Set up Python 3.9 + - name: Set up Python 3.10 uses: actions/setup-python@v2 with: - python-version: 3.9 + python-version: "3.10" - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 997afe3f..fa503604 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -3,7 +3,7 @@ version: 2 build: os: "ubuntu-22.04" tools: - python: "3.9" + python: "3.10" sphinx: configuration: docs/conf.py diff --git a/AUTHORS b/AUTHORS index 7f4a8237..d421d5e6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -15,6 +15,7 @@ David Guillot, for Contexte David Vogt Felix Viernickel Greg Aker +Humayun Ahmad Jamie Bliss Jason Housley Jeppe Fihl-Pearson diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c3c7720..07cd7d8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Note that in line with [Django REST framework policy](https://www.django-rest-framework.org/topics/release-notes/), any parts of the framework not mentioned in the documentation should generally be considered private API, and may be subject to change. +## [7.1.0] - 2024-10-25 + +### Fixed + +* Handled zero as a valid ID for resource (regression since 6.1.0) +* Ensured that patching a To-Many relationship with the `RelationshipView` correctly raises request error when passing in `None`. + For emptying a To-Many relationship an empty array should be used as per [JSON:API spec](https://jsonapi.org/format/#crud-updating-to-many-relationships) + +### Added + +* Added support for Django 5.1 +* Added support for Python 3.13 + +### Deprecated + +* Deprecated built-in support for generating OpenAPI schema. Use [drf-spectacular-json-api](https://github.com/jokiefer/drf-spectacular-json-api/) instead. + ## [7.0.2] - 2024-06-28 ### Fixed diff --git a/README.rst b/README.rst index fd340af6..0c9b842f 100644 --- a/README.rst +++ b/README.rst @@ -92,8 +92,8 @@ As a Django REST framework JSON:API (short DJA) we are trying to address followi Requirements ------------ -1. Python (3.8, 3.9, 3.10, 3.11, 3.12) -2. Django (4.2, 5.0) +1. Python (3.8, 3.9, 3.10, 3.11, 3.12, 3.13) +2. Django (4.2, 5.0, 5.1) 3. Django REST framework (3.14, 3.15) We **highly** recommend and only officially support the latest patch release of each Python, Django and REST framework series. diff --git a/docs/getting-started.md b/docs/getting-started.md index fd70c79a..a7de353a 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -51,8 +51,8 @@ like the following: ## Requirements -1. Python (3.8, 3.9, 3.10, 3.11, 3.12) -2. Django (4.2, 5.0) +1. Python (3.8, 3.9, 3.10, 3.11, 3.12, 3.13) +2. Django (4.2, 5.0, 5.1) 3. Django REST framework (3.14, 3.15) We **highly** recommend and only officially support the latest patch release of each Python, Django and REST framework series. diff --git a/docs/usage.md b/docs/usage.md index a50a97f7..1a2cb195 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -31,7 +31,6 @@ REST_FRAMEWORK = { 'rest_framework_json_api.renderers.BrowsableAPIRenderer' ), 'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata', - 'DEFAULT_SCHEMA_CLASS': 'rest_framework_json_api.schemas.openapi.AutoSchema', 'DEFAULT_FILTER_BACKENDS': ( 'rest_framework_json_api.filters.QueryParameterValidationFilter', 'rest_framework_json_api.filters.OrderingFilter', @@ -1062,6 +1061,20 @@ DRF has a [OAS schema functionality](https://www.django-rest-framework.org/api-g DJA extends DRF's schema support to generate an OAS schema in the JSON:API format. +--- + +**Deprecation notice:** + +REST framework's built-in support for generating OpenAPI schemas is +**deprecated** in favor of 3rd party packages that can provide this +functionality instead. Therefore we have also deprecated the schema support in +Django REST framework JSON:API. The built-in support will be retired over the +next releases. + +As a full-fledged replacement, we recommend the [drf-spectacular-json-api] package. + +--- + ### AutoSchema Settings In order to produce an OAS schema that properly represents the JSON:API structure @@ -1187,3 +1200,8 @@ We aim to make creating third party packages as easy as possible, whilst keeping To submit new content, [open an issue](https://github.com/django-json-api/django-rest-framework-json-api/issues/new/choose) or [create a pull request](https://github.com/django-json-api/django-rest-framework-json-api/compare). * [drf-yasg-json-api](https://github.com/glowka/drf-yasg-json-api) - Automated generation of Swagger/OpenAPI 2.0 from Django REST framework JSON:API endpoints. +* [drf-spectacular-json-api] - OpenAPI 3 schema generator for Django REST framework JSON:API based on drf-spectacular. + + + +[drf-spectacular-json-api]: https://github.com/jokiefer/drf-spectacular-json-api/ diff --git a/example/tests/test_openapi.py b/example/tests/test_openapi.py index 2333dd6a..fa2f9c73 100644 --- a/example/tests/test_openapi.py +++ b/example/tests/test_openapi.py @@ -1,6 +1,7 @@ # largely based on DRF's test_openapi import json +import pytest from django.test import RequestFactory, override_settings from django.urls import re_path from rest_framework.request import Request @@ -9,6 +10,8 @@ from example import views +pytestmark = pytest.mark.filterwarnings("ignore:Built-in support") + def create_request(path): factory = RequestFactory() diff --git a/example/tests/test_views.py b/example/tests/test_views.py index ad3fe124..47d4adb1 100644 --- a/example/tests/test_views.py +++ b/example/tests/test_views.py @@ -2,6 +2,7 @@ from django.test import RequestFactory, override_settings from django.utils import timezone +from rest_framework import status from rest_framework.exceptions import NotFound from rest_framework.request import Request from rest_framework.reverse import reverse @@ -174,16 +175,30 @@ def test_patch_one_to_many_relationship(self): response = self.client.get(url) assert response.data == request_data["data"] - def test_patch_one_to_many_relaitonship_with_none(self): + def test_patch_one_to_many_relaitonship_with_empty(self): url = f"/blogs/{self.first_entry.id}/relationships/entry_set" - request_data = {"data": None} + + request_data = {"data": []} response = self.client.patch(url, data=request_data) - assert response.status_code == 200, response.content.decode() + assert response.status_code == status.HTTP_200_OK assert response.data == [] response = self.client.get(url) assert response.data == [] + def test_patch_one_to_many_relaitonship_with_none(self): + """ + None for a to many relationship is invalid and should return a request error. + + see https://jsonapi.org/format/#crud-updating-to-many-relationships + """ + + url = f"/blogs/{self.first_entry.id}/relationships/entry_set" + + request_data = {"data": None} + response = self.client.patch(url, data=request_data) + assert response.status_code == status.HTTP_400_BAD_REQUEST + def test_patch_many_to_many_relationship(self): url = f"/entries/{self.first_entry.id}/relationships/authors" request_data = { diff --git a/requirements/requirements-codestyle.txt b/requirements/requirements-codestyle.txt index 4c270607..f5e5e92c 100644 --- a/requirements/requirements-codestyle.txt +++ b/requirements/requirements-codestyle.txt @@ -1,5 +1,5 @@ -black==24.4.2 -flake8==7.0.0 -flake8-bugbear==24.4.26 +black==24.10.0 +flake8==7.1.1 +flake8-bugbear==24.8.19 flake8-isort==6.1.1 isort==5.13.2 diff --git a/requirements/requirements-documentation.txt b/requirements/requirements-documentation.txt index 13a66219..aa120a8e 100644 --- a/requirements/requirements-documentation.txt +++ b/requirements/requirements-documentation.txt @@ -1,3 +1,3 @@ recommonmark==0.7.1 -Sphinx==7.3.7 -sphinx_rtd_theme==2.0.0 +Sphinx==8.1.3 +sphinx_rtd_theme==3.0.1 diff --git a/requirements/requirements-optionals.txt b/requirements/requirements-optionals.txt index efc82a58..589636e6 100644 --- a/requirements/requirements-optionals.txt +++ b/requirements/requirements-optionals.txt @@ -1,7 +1,7 @@ -django-filter==24.2 +django-filter==24.3 # once next version has been released (>3.1.0) this # should be set to pinned version again # see https://github.com/django-polymorphic/django-polymorphic/pull/541 django-polymorphic@git+https://github.com/django-polymorphic/django-polymorphic@master # pyup: ignore -pyyaml==6.0.1 +pyyaml==6.0.2 uritemplate==4.1.1 diff --git a/requirements/requirements-packaging.txt b/requirements/requirements-packaging.txt index 489eeb83..e957043a 100644 --- a/requirements/requirements-packaging.txt +++ b/requirements/requirements-packaging.txt @@ -1 +1 @@ -twine==5.0.0 +twine==5.1.1 diff --git a/requirements/requirements-testing.txt b/requirements/requirements-testing.txt index 1dfa20d4..b56d8185 100644 --- a/requirements/requirements-testing.txt +++ b/requirements/requirements-testing.txt @@ -1,7 +1,7 @@ -factory-boy==3.3.0 -Faker==25.0.1 -pytest==8.2.0 +factory-boy==3.3.1 +Faker==30.6.0 +pytest==8.3.3 pytest-cov==5.0.0 -pytest-django==4.8.0 +pytest-django==4.9.0 pytest-factoryboy==2.7.0 -syrupy==4.6.1 +syrupy==4.7.2 diff --git a/rest_framework_json_api/__init__.py b/rest_framework_json_api/__init__.py index 3008837c..a69daa9f 100644 --- a/rest_framework_json_api/__init__.py +++ b/rest_framework_json_api/__init__.py @@ -1,5 +1,5 @@ __title__ = "djangorestframework-jsonapi" -__version__ = "7.0.2" +__version__ = "7.1.0" __author__ = "" __license__ = "BSD" __copyright__ = "" diff --git a/rest_framework_json_api/parsers.py b/rest_framework_json_api/parsers.py index a0a2aeb2..8940c653 100644 --- a/rest_framework_json_api/parsers.py +++ b/rest_framework_json_api/parsers.py @@ -98,7 +98,7 @@ def parse_data(self, result, parser_context): "Received data contains one or more malformed JSON:API " "Resource Identifier Object(s)" ) - elif not (data.get("id") and data.get("type")): + elif isinstance(data, dict) and not (data.get("id") and data.get("type")): raise ParseError( "Received data is not a valid JSON:API Resource Identifier Object" ) diff --git a/rest_framework_json_api/schemas/openapi.py b/rest_framework_json_api/schemas/openapi.py index b44ce7a4..6892e991 100644 --- a/rest_framework_json_api/schemas/openapi.py +++ b/rest_framework_json_api/schemas/openapi.py @@ -423,6 +423,16 @@ def get_operation(self, path, method): - collections - special handling for POST, PATCH, DELETE """ + + warnings.warn( + DeprecationWarning( + "Built-in support for generating OpenAPI schema is deprecated. " + "Use drf-spectacular-json-api instead see " + "https://github.com/jokiefer/drf-spectacular-json-api/" + ), + stacklevel=2, + ) + operation = {} operation["operationId"] = self.get_operation_id(path, method) operation["description"] = self.get_description(path, method) diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py index e12080ac..805f5f09 100644 --- a/rest_framework_json_api/utils.py +++ b/rest_framework_json_api/utils.py @@ -307,13 +307,11 @@ def get_resource_type_from_serializer(serializer): def get_resource_id(resource_instance, resource): """Returns the resource identifier for a given instance (`id` takes priority over `pk`).""" if resource and "id" in resource: - return resource["id"] and encoding.force_str(resource["id"]) or None + _id = resource["id"] + return encoding.force_str(_id) if _id is not None else None if resource_instance: - return ( - hasattr(resource_instance, "pk") - and encoding.force_str(resource_instance.pk) - or None - ) + pk = getattr(resource_instance, "pk", None) + return encoding.force_str(pk) if pk is not None else None return None diff --git a/setup.py b/setup.py index 95d5ca0b..652ab85b 100755 --- a/setup.py +++ b/setup.py @@ -91,6 +91,7 @@ def get_package_data(package): "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tests/test_utils.py b/tests/test_utils.py index 4e103ae2..a3beb12e 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -403,6 +403,13 @@ class SerializerWithoutResourceName(serializers.Serializer): (None, {"id": 11}, "11"), (object(), {"pk": 11}, None), (BasicModel(id=6), {"id": 11}, "11"), + (BasicModel(id=0), None, "0"), + (None, {"id": 0}, "0"), + ( + BasicModel(id=0), + {"id": 0}, + "0", + ), ], ) def test_get_resource_id(resource_instance, resource, expected): diff --git a/tox.ini b/tox.ini index 68646fb4..a2accaad 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,8 @@ [tox] envlist = py{38,39,310,311,312}-django42-drf{314,315,master}, - py{310,311,312}-django50-drf{314,315,master}, + py{310,311,312}-django{50,51}-drf{314,315,master}, + py313-django51-drf{master}, black, docs, lint @@ -10,6 +11,7 @@ envlist = deps = django42: Django>=4.2,<4.3 django50: Django>=5.0,<5.1 + django51: Django>=5.1,<5.2 drf314: djangorestframework>=3.14,<3.15 drf315: djangorestframework>=3.15,<3.16 drfmaster: https://github.com/encode/django-rest-framework/archive/master.zip @@ -24,13 +26,13 @@ commands = pytest --cov --no-cov-on-fail --cov-report xml {posargs} [testenv:black] -basepython = python3.9 +basepython = python3.10 deps = -rrequirements/requirements-codestyle.txt commands = black --check . [testenv:lint] -basepython = python3.9 +basepython = python3.10 deps = -rrequirements/requirements-codestyle.txt -rrequirements/requirements-testing.txt @@ -39,15 +41,9 @@ commands = flake8 [testenv:docs] # keep in sync with .readthedocs.yml -basepython = python3.9 +basepython = python3.10 deps = -rrequirements/requirements-optionals.txt -rrequirements/requirements-documentation.txt commands = sphinx-build -W -b html -d docs/_build/doctrees docs docs/_build/html - -[testenv:py{38,39,310,311,312}-django42-drfmaster] -ignore_outcome = true - -[testenv:py{310,311,312}-django50-drfmaster] -ignore_outcome = true pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy