Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 9 additions & 35 deletions docs/api-guide/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,48 +265,22 @@ For example...

### Live tests

With careful usage both the `RequestsClient` and the `CoreAPIClient` provide
the ability to write test cases that can run either in development, or be run
directly against your staging server or production environment.

With careful usage the `RequestsClient` provides the ability to write tests
that exercise your API views in a more end-to-end fashion than `APIClient`,
while still running entirely in-process against your local Django application.

Note that `RequestsClient` mounts a WSGI adapter and does not perform real
network I/O. It cannot be used to send HTTP requests to remote services such
as staging or production servers. For live tests against a deployed service,
you should instead use a plain `requests.Session` (or similar HTTP client)
configured with the appropriate base URL and authentication.
Using this style to create basic tests of a few core pieces of functionality is
a powerful way to validate your live service. Doing so may require some careful
attention to setup and teardown to ensure that the tests run in a way that they
do not directly affect customer data.

---

## CoreAPIClient

The CoreAPIClient allows you to interact with your API using the Python
`coreapi` client library.

# Fetch the API schema
client = CoreAPIClient()
schema = client.get('http://testserver/schema/')

# Create a new organization
params = {'name': 'MegaCorp', 'status': 'active'}
client.action(schema, ['organizations', 'create'], params)

# Ensure that the organization exists in the listing
data = client.action(schema, ['organizations', 'list'])
assert(len(data) == 1)
assert(data == [{'name': 'MegaCorp', 'status': 'active'}])

### Headers & Authentication

Custom headers and authentication may be used with `CoreAPIClient` in a
similar way as with `RequestsClient`.

from requests.auth import HTTPBasicAuth

client = CoreAPIClient()
client.session.auth = HTTPBasicAuth('user', 'pass')
client.session.headers.update({'x-test': 'true'})

---

## API Test cases

REST framework includes the following test case classes, that mirror the existing [Django's test case classes][provided_test_case_classes], but use `APIClient` instead of Django's default `Client`.
Expand Down
6 changes: 3 additions & 3 deletions docs/api-guide/views.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,16 +202,16 @@ decorator. For example:
from rest_framework.schemas import AutoSchema

class CustomAutoSchema(AutoSchema):
def get_link(self, path, method, base_url):
def get_operation(self, path, method):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain a bit about the rename?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The from rest_framework.schemas import AutoSchema now resolve to rest_framework.schemas.openapi.AutoSchema instead of rest_framework.schemas.coreapi.AutoSchema.

The get_link method from the Core API version doesn't exist in the Open API variant, but the get_operation is the equivalent: it collects paths, filters and pagination parameters for the API schema. The CoreAPI version was returning a coreapi.Link object while the Open API returns a dict following the schema Open API expects.

So it's not really a rename, it's more of an API difference between the 2 AutoSchema variants.

# override view introspection here...

@api_view(['GET'])
@schema(CustomAutoSchema())
def view(request):
return Response({"message": "Hello for today! See you tomorrow!"})

This decorator takes a single `AutoSchema` instance, an `AutoSchema` subclass
instance or `ManualSchema` instance as described in the [Schemas documentation][schemas].
This decorator takes a single `AutoSchema` instance or an `AutoSchema` subclass
instance as described in the [Schemas documentation][schemas].
You may pass `None` in order to exclude the view from schema generation.

@api_view(['GET'])
Expand Down
8 changes: 2 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ dev = [
]
test = [
"importlib-metadata<9.0",

# Pytest for running the tests.
"pytest==9.*",
"pytest-cov==7.*",
Expand All @@ -63,8 +62,6 @@ docs = [
]
optional = [
# Optional packages which may be used with REST framework.
"coreapi==2.3.3",
"coreschema==0.0.4",
"django-filter",
"django-guardian>=2.4.0,<3.4",
"inflection==0.5.1",
Expand All @@ -73,8 +70,8 @@ optional = [
"psycopg[binary]>=3.1.8",
"pygments>=2.17,<2.20",
"pyyaml>=5.3.1,<6.1",
# setuptools is needed for coreapi (imports pkg_resources)
"setuptools<82",
"requests",
"uritemplate",
]
django42 = [ "django>=4.2,<5.0" ]
django50 = [ "django>=5.0,<5.1" ]
Expand Down Expand Up @@ -120,7 +117,6 @@ keep_full_version = true
addopts = "--tb=short --strict-markers -ra"
testpaths = [ "tests" ]
filterwarnings = [
"ignore:CoreAPI compatibility is deprecated*:rest_framework.RemovedInDRF318Warning",
"ignore:'cgi' is deprecated:DeprecationWarning",
]

Expand Down
4 changes: 0 additions & 4 deletions rest_framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,3 @@
# Default datetime input and output formats
ISO_8601 = 'iso-8601'
DJANGO_DURATION_FORMAT = 'django'


class RemovedInDRF318Warning(DeprecationWarning):
pass
28 changes: 0 additions & 28 deletions rest_framework/authtoken/views.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
from rest_framework import parsers, renderers
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.serializers import AuthTokenSerializer
from rest_framework.compat import coreapi, coreschema
from rest_framework.response import Response
from rest_framework.schemas import ManualSchema
from rest_framework.schemas import coreapi as coreapi_schema
from rest_framework.views import APIView


Expand All @@ -15,31 +12,6 @@ class ObtainAuthToken(APIView):
renderer_classes = (renderers.JSONRenderer,)
serializer_class = AuthTokenSerializer

if coreapi_schema.is_enabled():
schema = ManualSchema(
fields=[
coreapi.Field(
name="username",
required=True,
location='form',
schema=coreschema.String(
title="Username",
description="Valid username for authentication",
),
),
coreapi.Field(
name="password",
required=True,
location='form',
schema=coreschema.String(
title="Password",
description="Valid password for authentication",
),
),
],
encoding="application/json",
)

def get_serializer_context(self):
return {
'request': self.request,
Expand Down
15 changes: 1 addition & 14 deletions rest_framework/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,13 @@ def unicode_http_header(value):
postgres_fields = None


# coreapi is required for CoreAPI schema generation
try:
import coreapi
except ImportError:
coreapi = None

# uritemplate is required for OpenAPI and CoreAPI schema generation
# uritemplate is required for OpenAPI schema generation
try:
import uritemplate
except ImportError:
uritemplate = None


# coreschema is optional
try:
import coreschema
except ImportError:
coreschema = None


# pyyaml is optional
try:
import yaml
Expand Down
88 changes: 0 additions & 88 deletions rest_framework/documentation.py

This file was deleted.

44 changes: 0 additions & 44 deletions rest_framework/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
returned by list views.
"""
import operator
import warnings
from functools import reduce

from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured
Expand All @@ -14,8 +13,6 @@
from django.utils.text import smart_split, unescape_string_literal
from django.utils.translation import gettext_lazy as _

from rest_framework import RemovedInDRF318Warning
from rest_framework.compat import coreapi, coreschema
from rest_framework.fields import CharField
from rest_framework.settings import api_settings

Expand Down Expand Up @@ -48,13 +45,6 @@ def filter_queryset(self, request, queryset, view):
"""
raise NotImplementedError(".filter_queryset() must be overridden.")

def get_schema_fields(self, view):
assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`'
if coreapi is not None:
warnings.warn('CoreAPI compatibility is deprecated and will be removed in DRF 3.18', RemovedInDRF318Warning)
assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`'
return []

def get_schema_operation_parameters(self, view):
return []

Expand Down Expand Up @@ -186,23 +176,6 @@ def to_html(self, request, queryset, view):
template = loader.get_template(self.template)
return template.render(context)

def get_schema_fields(self, view):
assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`'
if coreapi is not None:
warnings.warn('CoreAPI compatibility is deprecated and will be removed in DRF 3.18', RemovedInDRF318Warning)
assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`'
return [
coreapi.Field(
name=self.search_param,
required=False,
location='query',
schema=coreschema.String(
title=force_str(self.search_title),
description=force_str(self.search_description)
)
)
]

def get_schema_operation_parameters(self, view):
return [
{
Expand Down Expand Up @@ -352,23 +325,6 @@ def to_html(self, request, queryset, view):
context = self.get_template_context(request, queryset, view)
return template.render(context)

def get_schema_fields(self, view):
assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`'
if coreapi is not None:
warnings.warn('CoreAPI compatibility is deprecated and will be removed in DRF 3.18', RemovedInDRF318Warning)
assert coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`'
return [
coreapi.Field(
name=self.ordering_param,
required=False,
location='query',
schema=coreschema.String(
title=force_str(self.ordering_title),
description=force_str(self.ordering_description)
)
)
]

def get_schema_operation_parameters(self, view):
return [
{
Expand Down
Loading