Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage DuplicateComponentNameError apispec error. #138

Merged
merged 1 commit into from
Mar 21, 2019
Merged
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
2 changes: 1 addition & 1 deletion hapic/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from hapic.hapic import Hapic
from hapic.data import HapicData
from hapic.hapic import Hapic
from hapic.infos import __version__

# To make a default hapic instance, must determine processor
Expand Down
20 changes: 12 additions & 8 deletions hapic/doc/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from apispec import APISpec
from apispec import BasePlugin
from apispec.exceptions import DuplicateComponentNameError
import yaml

from hapic.context import ContextInterface
Expand Down Expand Up @@ -319,14 +320,17 @@ def get_doc(
schema_usages.append(SchemaUsage(error_schema))

for schema_usage in set(schema_usages):
spec.components.schema(
main_plugin.schema_name_resolver(
schema_usage.schema,
**schema_usage.plugin_name_resolver_kwargs,
),
schema=schema_usage.schema,
**schema_usage.plugin_helper_kwargs,
)
try:
spec.components.schema(
main_plugin.schema_name_resolver(
schema_usage.schema,
**schema_usage.plugin_name_resolver_kwargs,
),
schema=schema_usage.schema,
**schema_usage.plugin_helper_kwargs,
)
except DuplicateComponentNameError:
pass # Already registered schema
buxx marked this conversation as resolved.
Show resolved Hide resolved

# add views
for controller in controllers:
Expand Down
2 changes: 1 addition & 1 deletion hapic/error/serpyco.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# coding: utf-8
import dataclasses
import typing

import dataclasses
from hapic.error.main import DefaultErrorBuilder
from hapic.processor.main import ProcessValidationError
from hapic.type import TYPE_SCHEMA
Expand Down
4 changes: 3 additions & 1 deletion hapic/ext/aiohttp/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,9 @@ def add_view(
http_method: str,
view_func: typing.Callable[..., typing.Any],
) -> None:
self.app.router.add_routes([web.route(http_method, path=route, handler=view_func)])
self.app.router.add_routes(
[web.route(http_method, path=route, handler=view_func)]
)

def serve_directory(self, route_prefix: str, directory_path: str) -> None:
self.app.router.add_static(route_prefix, path=directory_path)
Expand Down
2 changes: 1 addition & 1 deletion hapic/processor/marshmallow.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import typing

from apispec import BasePlugin
from apispec_marshmallow_advanced import MarshmallowAdvancedPlugin
from apispec_marshmallow_advanced.common import generate_schema_name
from apispec_marshmallow_advanced.common import (
schema_class_resolver as schema_class_resolver_
)

from apispec_marshmallow_advanced import MarshmallowAdvancedPlugin
from hapic.doc.schema import SchemaUsage
from hapic.error.main import ErrorBuilderInterface
from hapic.error.marshmallow import MarshmallowDefaultErrorBuilder
Expand Down
56 changes: 44 additions & 12 deletions tests/func/fake_api/test_fake_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,25 @@ def test_func__test_fake_api_doc_ok__all_framework(context):
doc["definitions"]["AboutResponseSchema"]
== SWAGGER_DOC_API["definitions"]["AboutResponseSchema"]
)
assert (
doc["definitions"]["ListsUserSchema"]
== SWAGGER_DOC_API["definitions"]["ListsUserSchema"]
)

# FIXME BS 2019-02-04: With irregularity,
# apispec.ext.marshmallow.common.get_unique_schema_name increment counter
# on UserSchema_without_email_address_first_name_last_name . See #136
try:
assert (
"#/definitions/UserSchema_without_email_address_first_name_last_name"
== doc["definitions"]["ListsUserSchema"]["properties"]["items"][
"items"
]["$ref"]
)
except AssertionError:
assert (
"#/definitions/UserSchema_without_email_address_first_name_last_name1"
== doc["definitions"]["ListsUserSchema"]["properties"]["items"][
"items"
]["$ref"]
)

assert (
doc["definitions"]["NoContentSchema"]
== SWAGGER_DOC_API["definitions"]["NoContentSchema"]
Expand All @@ -212,11 +227,28 @@ def test_func__test_fake_api_doc_ok__all_framework(context):
doc["definitions"]["UserSchema_without_id"]
== SWAGGER_DOC_API["definitions"]["UserSchema_without_id"]
)
assert (
doc["definitions"][
"UserSchema_without_email_address_first_name_last_name"
]
== SWAGGER_DOC_API["definitions"][
"UserSchema_without_email_address_first_name_last_name"
]
)

# FIXME BS 2019-02-04: With irregularity,
# apispec.ext.marshmallow.common.get_unique_schema_name increment counter
# on UserSchema_without_email_address_first_name_last_name . See #136
if (
"UserSchema_without_email_address_first_name_last_name1"
in doc["definitions"]
):
assert (
doc["definitions"][
"UserSchema_without_email_address_first_name_last_name1"
]
== SWAGGER_DOC_API["definitions"][
"UserSchema_without_email_address_first_name_last_name"
]
)
else:
assert (
doc["definitions"][
"UserSchema_without_email_address_first_name_last_name"
]
== SWAGGER_DOC_API["definitions"][
"UserSchema_without_email_address_first_name_last_name"
]
)
26 changes: 26 additions & 0 deletions tests/func/test_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -883,3 +883,29 @@ def my_controller():
assert schema_field["maxLength"] == 5
assert schema_field["minLength"] == 5
assert schema_field["enum"] == ["01000", "11111"]

def test_func__schema_with_many__ok__with_exclude(self):
hapic = Hapic(processor_class=MarshmallowProcessor)
# TODO BS 20171113: Make this test non-bottle
app = bottle.Bottle()
hapic.set_context(MyContext(app=app))

class MySchema(marshmallow.Schema):
first_name = marshmallow.fields.String(required=True)
last_name = marshmallow.fields.String(required=False)

@hapic.with_api_doc()
@hapic.output_body(MySchema(many=True, exclude=("last_name",)))
def my_controller(hapic_data=None):
pass

app.route("/", method="GET", callback=my_controller)
doc = hapic.generate_doc()

assert {
"MySchema_without_last_name": {
"type": "object",
"properties": {"first_name": {"type": "string"}},
"required": ["first_name"],
}
} == doc["definitions"]
3 changes: 2 additions & 1 deletion tests/func/test_doc_serpyco.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# coding: utf-8
import dataclasses

import bottle

import dataclasses
from hapic import Hapic
from hapic.error.serpyco import SerpycoDefaultErrorBuilder
from hapic.ext.bottle import BottleContext
Expand Down