Skip to content

Commit

Permalink
Merge pull request #42 from maticardenas/41-import-error-for-projects…
Browse files Browse the repository at this point in the history
…-without-ninja

fix: making import of ninja optional
  • Loading branch information
maticardenas committed Jun 18, 2024
2 parents a2d6691 + 3ff799c commit ebccfb1
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 30 deletions.
20 changes: 15 additions & 5 deletions openapi_tester/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@
from __future__ import annotations

import http
import logging
from typing import TYPE_CHECKING

# pylint: disable=import-error
from ninja import NinjaAPI, Router
from ninja.testing import TestClient
try:
from ninja import NinjaAPI, Router
from ninja.testing import TestClient
except ImportError:
NinjaAPI = Router = TestClient = object
logging.info("Django-Ninja is not installed.")


from rest_framework.test import APIClient

from .exceptions import APIFrameworkNotInstalledError
from .response_handler_factory import ResponseHandlerFactory
from .schema_tester import SchemaTester
from .utils import serialize_json
Expand Down Expand Up @@ -129,8 +136,11 @@ def __init__(
schema_tester: SchemaTester | None = None,
**kwargs,
) -> None:
"""Initialize ``OpenAPIClient`` instance."""
super().__init__(*args, router_or_app=router_or_app, **kwargs)
"""Initialize ``OpenAPINinjaClient`` instance."""
if not isinstance(object, TestClient):
super().__init__(*args, router_or_app=router_or_app, **kwargs)
else:
raise APIFrameworkNotInstalledError("Django-Ninja is not installed.")
self.schema_tester = schema_tester or self._schema_tester_factory()
self._ninja_path_prefix = path_prefix

Expand Down
8 changes: 8 additions & 0 deletions openapi_tester/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,11 @@ class UndocumentedSchemaSectionError(OpenAPISchemaError):
"""

pass


class APIFrameworkNotInstalledError(Exception):
"""
Raised when a required API framework is not installed.
"""

pass
13 changes: 4 additions & 9 deletions openapi_tester/schema_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,11 +623,8 @@ def validate_request(
"""
Verifies that an OpenAPI schema definition matches an API request body.
:param request: The HTTP request
:param case_tester: Optional Callable that checks a string's casing
:param ignore_case: Optional list of keys to ignore in case testing
:param validators: Optional list of validator functions
:param **kwargs: Request keyword arguments
:param response_handler: The HTTP response handler (can be a DRF or Ninja response)
:param test_config: Optional object with test configuration
:raises: ``openapi_tester.exceptions.DocumentationError`` for inconsistencies in the API response and schema.
``openapi_tester.exceptions.CaseError`` for case errors.
"""
Expand Down Expand Up @@ -660,10 +657,8 @@ def validate_response(
"""
Verifies that an OpenAPI schema definition matches an API response.
:param response: The HTTP response
:param case_tester: Optional Callable that checks a string's casing
:param ignore_case: Optional list of keys to ignore in case testing
:param validators: Optional list of validator functions
:param response_handler: The HTTP response handler (can be a DRF or Ninja response)
:param test_config: Optional object with test configuration
:raises: ``openapi_tester.exceptions.DocumentationError`` for inconsistencies in the API response and schema.
``openapi_tester.exceptions.CaseError`` for case errors.
"""
Expand Down
14 changes: 14 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest
from rest_framework.response import Response

import openapi_tester
from openapi_tester.response_handler import GenericRequest
from tests.schema_converter import SchemaToPythonConverter
from tests.utils import TEST_ROOT
Expand Down Expand Up @@ -98,3 +99,16 @@ def response(
return response

return response


@pytest.fixture
def users_ninja_api_schema() -> Path:
return TEST_ROOT / "schemas" / "users_django_api_schema.yaml"


@pytest.fixture
def ninja_not_installed():
former_client = openapi_tester.clients.TestClient
openapi_tester.clients.TestClient = object
yield
openapi_tester.clients.TestClient = former_client
24 changes: 22 additions & 2 deletions tests/test_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
from django.test.testcases import SimpleTestCase
from rest_framework import status

from openapi_tester.clients import OpenAPIClient
from openapi_tester.exceptions import DocumentationError, UndocumentedSchemaSectionError
from openapi_tester.clients import OpenAPIClient, OpenAPINinjaClient
from openapi_tester.exceptions import (
APIFrameworkNotInstalledError,
DocumentationError,
UndocumentedSchemaSectionError,
)
from openapi_tester.schema_tester import SchemaTester

if TYPE_CHECKING:
Expand All @@ -33,6 +37,15 @@ def test_init_schema_tester_passed():
assert client.schema_tester is schema_tester


def test_init_schema_tester_passed_ninja():
"""Ensure passed ``SchemaTester`` instance is used."""
schema_tester = SchemaTester()

client = OpenAPINinjaClient(router_or_app=None, schema_tester=schema_tester)

assert client.schema_tester is schema_tester


def test_get_request(cars_api_schema: "Path"):
schema_tester = SchemaTester(schema_file_path=str(cars_api_schema))
openapi_client = OpenAPIClient(schema_tester=schema_tester)
Expand Down Expand Up @@ -162,3 +175,10 @@ class DummyTestCase(SimpleTestCase):
test_case._pre_setup()

assert isinstance(test_case.client, OpenAPIClient)


def test_ninja_not_installed(ninja_not_installed):
OpenAPIClient()

with pytest.raises(APIFrameworkNotInstalledError):
OpenAPINinjaClient(router_or_app=None)
22 changes: 8 additions & 14 deletions tests/test_django_ninja.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,35 @@

import pytest

from openapi_tester import OpenAPIClient, SchemaTester
from openapi_tester import SchemaTester
from openapi_tester.clients import OpenAPINinjaClient
from openapi_tester.exceptions import UndocumentedSchemaSectionError
from test_project.api.ninja.api import router
from tests.utils import TEST_ROOT

if TYPE_CHECKING:
from pathlib import Path


@pytest.fixture
def users_ninja_api_schema() -> "Path":
return TEST_ROOT / "schemas" / "users_django_api_schema.yaml"


@pytest.fixture
def client(users_ninja_api_schema: "Path") -> OpenAPIClient:
def client(users_ninja_api_schema: "Path") -> OpenAPINinjaClient:
return OpenAPINinjaClient(
router_or_app=router,
path_prefix="/ninja_api/users",
schema_tester=SchemaTester(schema_file_path=str(users_ninja_api_schema)),
)


def test_get_users(client: OpenAPIClient):
def test_get_users(client: OpenAPINinjaClient):
response = client.get("/")
assert response.status_code == 200


def test_get_user(client: OpenAPIClient):
def test_get_user(client: OpenAPINinjaClient):
response = client.get("/1")
assert response.status_code == 200


def test_create_user(client: OpenAPIClient):
def test_create_user(client: OpenAPINinjaClient):
payload = {
"name": "John Doe",
"email": "john.doe@example.com",
Expand All @@ -52,7 +46,7 @@ def test_create_user(client: OpenAPIClient):
assert response.status_code == 201


def test_update_user(client: OpenAPIClient):
def test_update_user(client: OpenAPINinjaClient):
payload = {
"name": "John Doe",
"email": "john.doe@example.com",
Expand All @@ -67,14 +61,14 @@ def test_update_user(client: OpenAPIClient):
assert response.status_code == 200


def test_delete_user(client: OpenAPIClient):
def test_delete_user(client: OpenAPINinjaClient):
response = client.delete(
path="/1",
)
assert response.status_code == 204


def test_patch_user_undocumented_path(client: OpenAPIClient):
def test_patch_user_undocumented_path(client: OpenAPINinjaClient):
payload = {
"name": "John Doe",
}
Expand Down

0 comments on commit ebccfb1

Please sign in to comment.