initial version

This commit is contained in:
Artur Maciag 2017-09-21 12:51:37 +01:00
parent e3d831c005
commit 553b7228b1
27 changed files with 1138 additions and 2 deletions

2
MANIFEST.in Normal file
View file

@ -0,0 +1,2 @@
include requirements.txt
include requirements_dev.txt

View file

@ -1,2 +0,0 @@
# openapi-core
OpenAPI core

24
README.rst Normal file
View file

@ -0,0 +1,24 @@
openapi-core
************
Openapi-core is a Python library that adds client-side and server-side support
for the `OpenAPI Specification v3.0.0 <github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md>`__.
Installation
============
Recommended way (via pip):
::
$ pip install openapi-core
Alternatively you can download the code and install from the repository:
.. code-block:: bash
$ pip install -e git+https://github.com/p1c2u/openapi-core.git#egg=openapi_core
Related projects
================
* `openapi-spec-validator <https://github.com/p1c2u/openapi-spec-validator>`__

10
openapi_core/__init__.py Normal file
View file

@ -0,0 +1,10 @@
"""OpenAPI core module"""
from openapi_core.shortcuts import create_spec
__author__ = 'Artur Maciąg'
__email__ = 'maciag.artur@gmail.com'
__version__ = '0.0.1'
__url__ = 'https://github.com/p1c2u/openapi-core'
__license__ = 'BSD 3-Clause License'
__all__ = ['create_spec', ]

View file

@ -0,0 +1,17 @@
"""OpenAPI core exceptions module"""
class OpenAPIError(Exception):
pass
class OpenAPIMappingError(OpenAPIError):
pass
class MissingParameterError(OpenAPIMappingError):
pass
class InvalidContentTypeError(OpenAPIMappingError):
pass

View file

@ -0,0 +1,37 @@
"""OpenAPI core mediaTypes module"""
from six import iteritems
from openapi_core.schemas import SchemaFactory
class MediaType(object):
"""Represents an OpenAPI MediaType."""
def __init__(self, content_type, schema=None):
self.content_type = content_type
self.schema = schema
def unmarshal(self, value):
if not self.schema:
return value
return self.schema.unmarshal(value)
class MediaTypeGenerator(object):
def __init__(self, dereferencer):
self.dereferencer = dereferencer
def generate(self, content):
for content_type, media_type in iteritems(content):
schema_spec = media_type.get('schema')
schema = None
if schema_spec:
schema = self._create_schema(schema_spec)
yield content_type, MediaType(content_type, schema)
def _create_schema(self, schema_spec):
return SchemaFactory(self.dereferencer).create(schema_spec)

View file

@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
"""OpenAPI core operations module"""
import logging
from six import iteritems
from openapi_core.parameters import ParametersGenerator
from openapi_core.request_bodies import RequestBodyFactory
log = logging.getLogger(__name__)
class Operation(object):
"""Represents an OpenAPI Operation."""
def __init__(
self, http_method, path_name, parameters, request_body=None,
deprecated=False, operation_id=None):
self.http_method = http_method
self.path_name = path_name
self.parameters = dict(parameters)
self.request_body = request_body
self.deprecated = deprecated
self.operation_id = operation_id
def __getitem__(self, name):
return self.parameters[name]
class OperationsGenerator(object):
"""Represents an OpenAPI Operation in a service."""
def __init__(self, dereferencer):
self.dereferencer = dereferencer
def generate(self, path_name, path):
path_deref = self.dereferencer.dereference(path)
for http_method, operation in iteritems(path_deref):
if http_method.startswith('x-') or http_method == 'parameters':
continue
operation_deref = self.dereferencer.dereference(operation)
deprecated = operation_deref.get('deprecated', False)
parameters_list = operation_deref.get('parameters', [])
parameters = self._generate_parameters(parameters_list)
request_body = None
if 'requestBody' in operation_deref:
request_body_spec = operation_deref.get('requestBody')
request_body = self._create_request_body(request_body_spec)
yield (
http_method,
Operation(
http_method, path_name, list(parameters),
request_body=request_body, deprecated=deprecated,
),
)
def _generate_parameters(self, parameters):
return ParametersGenerator(self.dereferencer).generate(parameters)
def _create_request_body(self, request_body_spec):
return RequestBodyFactory(self.dereferencer).create(request_body_spec)

View file

@ -0,0 +1,59 @@
"""OpenAPI core parameters module"""
import logging
from openapi_core.schemas import SchemaFactory
log = logging.getLogger(__name__)
class Parameter(object):
"""Represents an OpenAPI operation Parameter."""
def __init__(
self, name, location, schema=None, default=None,
required=False, deprecated=False, allow_empty_value=False,
items=None, collection_format=None):
self.name = name
self.location = location
self.schema = schema
self.default = default
self.required = required
self.deprecated = deprecated
self.allow_empty_value = allow_empty_value
self.items = items
self.collection_format = collection_format
def unmarshal(self, value):
if not self.schema:
return value
return self.schema.unmarshal(value)
class ParametersGenerator(object):
def __init__(self, dereferencer):
self.dereferencer = dereferencer
def generate(self, paramters):
for parameter in paramters:
parameter_deref = self.dereferencer.dereference(parameter)
default = parameter_deref.get('default')
required = parameter_deref.get('required', False)
schema_spec = parameter_deref.get('schema', None)
schema = None
if schema_spec:
schema = self._create_schema(schema_spec)
yield (
parameter_deref['name'],
Parameter(
parameter_deref['name'], parameter_deref['in'],
schema=schema, default=default, required=required,
),
)
def _create_schema(self, schema_spec):
return SchemaFactory(self.dereferencer).create(schema_spec)

30
openapi_core/paths.py Normal file
View file

@ -0,0 +1,30 @@
"""OpenAPI core paths module"""
from six import iteritems
from openapi_core.operations import OperationsGenerator
class Path(object):
"""Represents an OpenAPI Path."""
def __init__(self, name, operations):
self.name = name
self.operations = dict(operations)
def __getitem__(self, http_method):
return self.operations[http_method]
class PathsGenerator(object):
def __init__(self, dereferencer):
self.dereferencer = dereferencer
def generate(self, paths):
paths_deref = self.dereferencer.dereference(paths)
for path_name, path in iteritems(paths_deref):
operations = self._generate_operations(path_name, path)
yield path_name, Path(path_name, list(operations))
def _generate_operations(self, path_name, path):
return OperationsGenerator(self.dereferencer).generate(path_name, path)

View file

@ -0,0 +1,30 @@
"""OpenAPI core requestBodies module"""
from openapi_core.media_types import MediaTypeGenerator
class RequestBody(object):
"""Represents an OpenAPI RequestBody."""
def __init__(self, content, required=False):
self.content = dict(content)
self.required = required
def __getitem__(self, content_type):
return self.content[content_type]
class RequestBodyFactory(object):
def __init__(self, dereferencer):
self.dereferencer = dereferencer
def create(self, request_body_spec):
request_body_deref = self.dereferencer.dereference(
request_body_spec)
content = request_body_deref['content']
media_types = self._generate_media_types(content)
required = request_body_deref.get('required', False)
return RequestBody(media_types, required=required)
def _generate_media_types(self, content):
return MediaTypeGenerator(self.dereferencer).generate(content)

113
openapi_core/schemas.py Normal file
View file

@ -0,0 +1,113 @@
"""OpenAPI core schemas module"""
import logging
from distutils.util import strtobool
from collections import defaultdict
from json import loads
from six import iteritems
log = logging.getLogger(__name__)
DEFAULT_CAST_CALLABLE_GETTER = {
'integer': int,
'number': float,
'boolean': lambda x: bool(strtobool(x)),
'object': loads,
}
class Schema(object):
"""Represents an OpenAPI Schema."""
def __init__(
self, schema_type, properties=None, items=None, spec_format=None,
required=False):
self.type = schema_type
self.properties = properties and dict(properties) or {}
self.items = items
self.format = spec_format
self.required = required
def __getitem__(self, name):
return self.properties[name]
def get_cast_mapping(self):
mapping = DEFAULT_CAST_CALLABLE_GETTER.copy()
if self.items:
mapping.update({
'array': lambda x: list(map(self.items.unmarshal, x)),
})
return defaultdict(lambda: lambda x: x, mapping)
def cast(self, value):
"""Cast value to schema type"""
if value is None:
return None
cast_mapping = self.get_cast_mapping()
if self.type in cast_mapping and value == '':
return None
cast_callable = cast_mapping[self.type]
try:
return cast_callable(value)
except ValueError:
log.warning(
"Failed to cast value of %s to %s", value, self.type,
)
return value
def unmarshal(self, value):
"""Unmarshal parameter from the value."""
casted = self.cast(value)
if casted is None and not self.required:
return None
return casted
class PropertiesGenerator(object):
def __init__(self, dereferencer):
self.dereferencer = dereferencer
def generate(self, properties):
for property_name, schema_spec in iteritems(properties):
schema = self._create_schema(schema_spec)
yield property_name, schema
def _create_schema(self, schema_spec):
return SchemaFactory(self.dereferencer).create(schema_spec)
class SchemaFactory(object):
def __init__(self, dereferencer):
self.dereferencer = dereferencer
def create(self, schema_spec):
schema_deref = self.dereferencer.dereference(schema_spec)
schema_type = schema_deref['type']
required = schema_deref.get('required', False)
properties_spec = schema_deref.get('properties', None)
items_spec = schema_deref.get('items', None)
properties = None
if properties_spec:
properties = self._generate_properties(properties_spec)
items = None
if items_spec:
items = self._create_items(items_spec)
return Schema(
schema_type, properties=properties, items=items, required=required)
def _generate_properties(self, properties_spec):
return PropertiesGenerator(self.dereferencer).generate(properties_spec)
def _create_items(self, items_spec):
return SchemaFactory(self.dereferencer).create(items_spec)

14
openapi_core/shortcuts.py Normal file
View file

@ -0,0 +1,14 @@
"""OpenAPI core shortcuts module"""
from jsonschema.validators import RefResolver
from openapi_spec_validator.validators import Dereferencer
from openapi_spec_validator import default_handlers
from openapi_core.specs import SpecFactory
def create_spec(spec_dict, spec_url=''):
spec_resolver = RefResolver(
spec_url, spec_dict, handlers=default_handlers)
dereferencer = Dereferencer(spec_resolver)
spec_factory = SpecFactory(dereferencer)
return spec_factory.create(spec_dict, spec_url=spec_url)

60
openapi_core/specs.py Normal file
View file

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
"""OpenAPI core specs module"""
import logging
from functools import partialmethod
from openapi_spec_validator import openapi_v3_spec_validator
from openapi_core.paths import PathsGenerator
log = logging.getLogger(__name__)
class Spec(object):
"""Represents an OpenAPI Specification for a service."""
def __init__(self, servers=None, paths=None):
self.servers = servers or []
self.paths = paths and dict(paths) or {}
def __getitem__(self, path_name):
return self.paths[path_name]
def get_server_url(self, index=0):
return self.servers[index]['url']
def get_operation(self, path_pattern, http_method):
return self.paths[path_pattern].operations[http_method]
# operations shortcuts
get = partialmethod(get_operation, http_method='get')
put = partialmethod(get_operation, http_method='put')
post = partialmethod(get_operation, http_method='post')
delete = partialmethod(get_operation, http_method='delete')
options = partialmethod(get_operation, http_method='options')
head = partialmethod(get_operation, http_method='head')
patch = partialmethod(get_operation, http_method='patch')
class SpecFactory(object):
def __init__(self, dereferencer, config=None):
self.dereferencer = dereferencer
self.config = config or {}
def create(self, spec_dict, spec_url=''):
if self.config.get('validate_spec', True):
openapi_v3_spec_validator.validate(spec_dict, spec_url=spec_url)
spec_dict_deref = self.dereferencer.dereference(spec_dict)
servers = spec_dict_deref.get('servers', [])
paths = spec_dict_deref.get('paths', [])
paths = self._generate_paths(paths)
return Spec(servers=servers, paths=list(paths))
def _generate_paths(self, paths):
return PathsGenerator(self.dereferencer).generate(paths)

101
openapi_core/wrappers.py Normal file
View file

@ -0,0 +1,101 @@
"""OpenAPI core wrappers module"""
from six import iteritems
from openapi_core.exceptions import (
OpenAPIMappingError, MissingParameterError, InvalidContentTypeError,
)
SPEC_LOCATION_TO_REQUEST_LOCATION_MAPPING = {
'path': 'view_args',
'query': 'args',
'headers': 'headers',
'cookies': 'cookies',
}
class RequestParameters(dict):
valid_locations = ['path', 'query', 'headers', 'cookies']
def __getitem__(self, location):
self.validate_location(location)
return self.setdefault(location, {})
def __setitem__(self, location, value):
raise NotImplementedError
@classmethod
def validate_location(cls, location):
if location not in cls.valid_locations:
raise OpenAPIMappingError(
"Unknown parameter location: {0}".format(str(location)))
class RequestParametersFactory(object):
def __init__(self, attr_mapping=SPEC_LOCATION_TO_REQUEST_LOCATION_MAPPING):
self.attr_mapping = attr_mapping
def create(self, request, spec):
operation = spec.get_operation(request.path_pattern, request.method)
params = RequestParameters()
for param_name, param in iteritems(operation.parameters):
try:
value = self._unmarshal_param(request, param)
except MissingParameterError:
if param.required:
raise
continue
params[param.location][param_name] = value
return params
def _unmarshal_param(self, request, param):
request_location = self.attr_mapping[param.location]
request_attr = getattr(request, request_location)
try:
raw_value = request_attr[param.name]
except KeyError:
raise MissingParameterError(
"Missing required `{0}` parameter".format(param.name))
return param.unmarshal(raw_value)
class RequestBodyFactory(object):
def create(self, request, spec):
operation = spec.get_operation(request.path_pattern, request.method)
try:
media_type = operation.request_body[request.content_type]
except KeyError:
raise InvalidContentTypeError(
"Invalid Content-Type `{0}`".format(request.content_type))
return media_type.unmarshal(request.data)
class BaseOpenAPIRequest(object):
path = NotImplemented
path_pattern = NotImplemented
method = NotImplemented
args = NotImplemented
view_args = NotImplemented
headers = NotImplemented
cookies = NotImplemented
data = NotImplemented
content_type = NotImplemented
def get_parameters(self, spec):
return RequestParametersFactory().create(self, spec)
def get_body(self, spec):
return RequestBodyFactory().create(self, spec)

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
openapi-spec-validator
six

5
requirements_dev.txt Normal file
View file

@ -0,0 +1,5 @@
mock
pytest
pytest-pep8
pytest-flakes
pytest-cov

81
setup.py Normal file
View file

@ -0,0 +1,81 @@
"""OpenAPI core setup module"""
import os
import re
import sys
from setuptools import setup, find_packages
from setuptools.command.test import test as TestCommand
def read_requirements(filename):
"""Open a requirements file and return list of its lines."""
contents = read_file(filename).strip('\n')
return contents.split('\n') if contents else []
def read_file(filename):
"""Open and a file, read it and return its contents."""
path = os.path.join(os.path.dirname(__file__), filename)
with open(path) as f:
return f.read()
def get_metadata(init_file):
"""Read metadata from a given file and return a dictionary of them"""
return dict(re.findall("__([a-z]+)__ = '([^']+)'", init_file))
class PyTest(TestCommand):
"""Command to run unit tests after in-place build."""
def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = [
'-sv',
'--pep8',
'--flakes',
'--junitxml', 'reports/junit.xml',
'--cov', 'openapi_core',
'--cov-report', 'term-missing',
'--cov-report', 'xml:reports/coverage.xml',
]
self.test_suite = True
def run_tests(self):
# Importing here, `cause outside the eggs aren't loaded.
import pytest
errno = pytest.main(self.test_args)
sys.exit(errno)
init_path = os.path.join('openapi_core', '__init__.py')
init_py = read_file(init_path)
metadata = get_metadata(init_py)
setup(
name='openapi-core',
version=metadata['version'],
author=metadata['author'],
author_email=metadata['email'],
url=metadata['url'],
long_description=read_file("README.rst"),
packages=find_packages(include=('openapi_core*',)),
include_package_data=True,
classifiers=[
"Development Status :: 3 - Alpha",
'Intended Audience :: Developers',
"Topic :: Software Development :: Libraries :: Python Modules",
"Operating System :: OS Independent",
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Topic :: Software Development :: Libraries',
],
install_requires=read_requirements('requirements.txt'),
tests_require=read_requirements('requirements_dev.txt'),
cmdclass={'test': PyTest},
zip_safe=False,
)

View file

@ -0,0 +1,30 @@
from os import path
import pytest
from six.moves.urllib import request
from yaml import safe_load
def spec_from_file(spec_file):
directory = path.abspath(path.dirname(__file__))
path_full = path.join(directory, spec_file)
with open(path_full) as fh:
return safe_load(fh)
def spec_from_url(spec_url):
content = request.urlopen(spec_url)
return safe_load(content)
class Factory(dict):
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
@pytest.fixture(scope='session')
def factory():
return Factory(
spec_from_file=spec_from_file,
spec_from_url=spec_from_url,
)

View file

@ -0,0 +1 @@
openapi: "3.0.0"

View file

@ -0,0 +1,134 @@
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: true
schema:
type: integer
format: int32
- name: ids
in: query
description: Filter pets with Ids
schema:
type: array
items:
type: integer
format: int32
responses:
'200':
description: An paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Create a pet
operationId: createPets
tags:
- pets
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PetCreate'
responses:
'201':
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: integer
format: int64
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
Pet:
type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
PetCreate:
type: object
required:
- name
properties:
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: "#/components/schemas/Pet"
Error:
type: object
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View file

@ -0,0 +1,19 @@
import pytest
from jsonschema.exceptions import ValidationError
from openapi_core.shortcuts import create_spec
class TestEmpty(object):
@pytest.fixture
def spec_dict(self, factory):
return factory.spec_from_file("data/v3.0/empty.yaml")
@pytest.fixture
def spec(self, spec_dict):
return create_spec(spec_dict)
def test_raises_on_invalid(self, spec_dict):
with pytest.raises(ValidationError):
create_spec(spec_dict)

View file

@ -0,0 +1,201 @@
import json
import pytest
from six import iteritems
from openapi_core.exceptions import (
MissingParameterError, InvalidContentTypeError,
)
from openapi_core.media_types import MediaType
from openapi_core.operations import Operation
from openapi_core.paths import Path
from openapi_core.request_bodies import RequestBody
from openapi_core.schemas import Schema
from openapi_core.shortcuts import create_spec
from openapi_core.wrappers import BaseOpenAPIRequest
class RequestMock(BaseOpenAPIRequest):
def __init__(
self, method, path, path_pattern=None, args=None, view_args=None,
headers=None, cookies=None, data=None,
content_type='application/json'):
self.path = path
self.path_pattern = path_pattern or path
self.method = method
self.args = args or {}
self.view_args = view_args or {}
self.headers = headers or {}
self.cookies = cookies or {}
self.data = data or ''
self.content_type = content_type
class TestPetstore(object):
@pytest.fixture
def spec_dict(self, factory):
return factory.spec_from_file("data/v3.0/petstore.yaml")
@pytest.fixture
def spec(self, spec_dict):
return create_spec(spec_dict)
def test_spec(self, spec, spec_dict):
assert spec.servers == spec_dict['servers']
assert spec.get_server_url() == spec_dict['servers'][0]['url']
for path_name, path in iteritems(spec.paths):
assert type(path) == Path
assert path.name == path_name
for http_method, operation in iteritems(path.operations):
assert type(operation) == Operation
assert operation.path_name == path_name
assert operation.http_method == http_method
operation_spec = spec_dict['paths'][path_name][http_method]
request_body_spec = operation_spec.get('requestBody')
assert bool(request_body_spec) == bool(operation.request_body)
if not request_body_spec:
continue
assert type(operation.request_body) == RequestBody
assert bool(operation.request_body.required) ==\
request_body_spec.get('required', False)
for content_type, media_type in iteritems(
operation.request_body.content):
assert type(media_type) == MediaType
assert media_type.content_type == content_type
content_spec = request_body_spec['content'][content_type]
schema_spec = content_spec.get('schema')
assert bool(schema_spec) == bool(media_type.schema)
if not schema_spec:
continue
# @todo: test with defererence
if '$ref' in schema_spec:
continue
assert type(media_type.schema) == Schema
assert media_type.schema.type == schema_spec['type']
assert media_type.schema.required == schema_spec.get(
'required', False)
def test_get_pets(self, spec):
query_params = {
'limit': '20',
'ids': ['12', '13'],
}
request = RequestMock('get', '/pets', args=query_params)
parameters = request.get_parameters(spec)
assert parameters == {
'query': {
'limit': 20,
'ids': [12, 13],
}
}
def test_get_pets_raises_missing_required_param(self, spec):
request = RequestMock('get', '/pets')
with pytest.raises(MissingParameterError):
request.get_parameters(spec)
def test_get_pets_failed_to_cast(self, spec):
query_params = {
'limit': 'non_integer_value',
}
request = RequestMock('get', '/pets', args=query_params)
parameters = request.get_parameters(spec)
assert parameters == {
'query': {
'limit': 'non_integer_value',
}
}
def test_get_pets_empty_value(self, spec):
query_params = {
'limit': '',
}
request = RequestMock('get', '/pets', args=query_params)
parameters = request.get_parameters(spec)
assert parameters == {
'query': {
'limit': None,
}
}
def test_get_pets_none_value(self, spec):
query_params = {
'limit': None,
}
request = RequestMock('get', '/pets', args=query_params)
parameters = request.get_parameters(spec)
assert parameters == {
'query': {
'limit': None,
}
}
def test_post_pets(self, spec):
data_json = {
'name': 'Cat',
'tag': 'cats',
}
data = json.dumps(data_json)
request = RequestMock('post', '/pets', data=data)
body = request.get_body(spec)
assert body == data_json
def test_post_pets_raises_invalid_content_type(self, spec):
data_json = {
'name': 'Cat',
'tag': 'cats',
}
data = json.dumps(data_json)
request = RequestMock(
'post', '/pets', data=data, content_type='text/html')
with pytest.raises(InvalidContentTypeError):
request.get_body(spec)
def test_get_pet(self, spec):
view_args = {
'petId': '1',
}
request = RequestMock(
'get', '/pets/1', path_pattern='/pets/{petId}',
view_args=view_args,
)
parameters = request.get_parameters(spec)
assert parameters == {
'path': {
'petId': 1,
}
}

View file

@ -0,0 +1,20 @@
import mock
import pytest
from openapi_core.operations import Operation
class TestSchemas(object):
@pytest.fixture
def oepration(self):
parameters = {
'parameter_1': mock.sentinel.parameter_1,
'parameter_2': mock.sentinel.parameter_2,
}
return Operation('get', '/path', parameters=parameters)
@property
def test_iteritems(self, oepration):
for name in oepration.parameters.keys():
assert oepration[name] == oepration.parameters[name]

21
tests/unit/test_paths.py Normal file
View file

@ -0,0 +1,21 @@
import mock
import pytest
from openapi_core.paths import Path
class TestPaths(object):
@pytest.fixture
def path(self):
operations = {
'get': mock.sentinel.get,
'post': mock.sentinel.post,
}
return Path('/path', operations)
@property
def test_iteritems(self, path):
for http_method in path.operations.keys():
assert path[http_method] ==\
path.operations[http_method]

View file

@ -0,0 +1,21 @@
import mock
import pytest
from openapi_core.request_bodies import RequestBody
class TestRequestBodies(object):
@pytest.fixture
def request_body(self):
content = {
'application/json': mock.sentinel.application_json,
'text/csv': mock.sentinel.text_csv,
}
return RequestBody(content)
@property
def test_iteritems(self, request_body):
for content_type in request_body.content.keys():
assert request_body[content_type] ==\
request_body.content[content_type]

View file

@ -0,0 +1,20 @@
import mock
import pytest
from openapi_core.schemas import Schema
class TestSchemas(object):
@pytest.fixture
def schema(self):
properties = {
'application/json': mock.sentinel.application_json,
'text/csv': mock.sentinel.text_csv,
}
return Schema('object', properties=properties)
@property
def test_iteritems(self, schema):
for name in schema.properties.keys():
assert schema[name] == schema.properties[name]

22
tests/unit/test_specs.py Normal file
View file

@ -0,0 +1,22 @@
import mock
import pytest
from openapi_core.specs import Spec
class TestSpecs(object):
@pytest.fixture
def spec(self):
servers = []
paths = {
'get': mock.sentinel.get,
'post': mock.sentinel.post,
}
return Spec(servers, paths)
@property
def test_iteritems(self, spec):
for path_name in spec.paths.keys():
assert spec[path_name] ==\
spec.paths[path_name]