mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-11-03 20:38:59 +00:00 
			
		
		
		
	* Consistently use spaces in rest-api-templates/asterisk_processor.py. * Exclude third-party from docs/full-en_US.xml. * Add docs/full-en_US.xml to .gitignore. * Use list() to convert python3 view. * Use python3 print function. * Replace cmp() with equivalent equation. * Replace reference to out of scope subtype variable with name parameter. * Use unescaping triple bracket notation in mustache templates where needed. This causes behavior of Python2 to be maintained when using Python3. * Fix references to has_websocket / is_websocket in res_ari_resource.c.mustache. * Update calculation of has_websocket to use any(). * Use unicode mode for writing output file in transform.py. * Replace 'from swagger_model import *' with explicit import of required symbols. I have not tested spandspflow2pcap.py or voicemailpwcheck.py, only the print syntax has been fixed. Change-Id: If5c5b556a2800d41a3e2cfef080ac2e151178c33
		
			
				
	
	
		
			766 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			766 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
 | 
						|
# Asterisk -- An open source telephony toolkit.
 | 
						|
#
 | 
						|
# Copyright (C) 2013, Digium, Inc.
 | 
						|
#
 | 
						|
# David M. Lee, II <dlee@digium.com>
 | 
						|
#
 | 
						|
# See http://www.asterisk.org for more information about
 | 
						|
# the Asterisk project. Please do not directly contact
 | 
						|
# any of the maintainers of this project for assistance;
 | 
						|
# the project provides a web site, mailing lists and IRC
 | 
						|
# channels for your use.
 | 
						|
#
 | 
						|
# This program is free software, distributed under the terms of
 | 
						|
# the GNU General Public License Version 2. See the LICENSE file
 | 
						|
# at the top of the source tree.
 | 
						|
#
 | 
						|
 | 
						|
"""Swagger data model objects.
 | 
						|
 | 
						|
These objects should map directly to the Swagger api-docs, without a lot of
 | 
						|
additional fields. In the process of translation, it should also validate the
 | 
						|
model for consistency against the Swagger spec (i.e., fail if fields are
 | 
						|
missing, or have incorrect values).
 | 
						|
 | 
						|
See https://github.com/wordnik/swagger-core/wiki/API-Declaration for the spec.
 | 
						|
"""
 | 
						|
 | 
						|
from __future__ import print_function
 | 
						|
import json
 | 
						|
import os.path
 | 
						|
import pprint
 | 
						|
import re
 | 
						|
import sys
 | 
						|
import traceback
 | 
						|
 | 
						|
# We don't fully support Swagger 1.2, but we need it for subtyping
 | 
						|
SWAGGER_VERSIONS = ["1.1", "1.2"]
 | 
						|
 | 
						|
SWAGGER_PRIMITIVES = [
 | 
						|
    'void',
 | 
						|
    'string',
 | 
						|
    'boolean',
 | 
						|
    'number',
 | 
						|
    'int',
 | 
						|
    'long',
 | 
						|
    'double',
 | 
						|
    'float',
 | 
						|
    'Date',
 | 
						|
]
 | 
						|
 | 
						|
 | 
						|
class Stringify(object):
 | 
						|
    """Simple mix-in to make the repr of the model classes more meaningful.
 | 
						|
    """
 | 
						|
    def __repr__(self):
 | 
						|
        return "%s(%s)" % (self.__class__, pprint.saferepr(self.__dict__))
 | 
						|
 | 
						|
 | 
						|
def compare_versions(lhs, rhs):
 | 
						|
    '''Performs a lexicographical comparison between two version numbers.
 | 
						|
 | 
						|
    This properly handles simple major.minor.whatever.sure.why.not version
 | 
						|
    numbers, but fails miserably if there's any letters in there.
 | 
						|
 | 
						|
    For reference:
 | 
						|
      1.0 == 1.0
 | 
						|
      1.0 < 1.0.1
 | 
						|
      1.2 < 1.10
 | 
						|
 | 
						|
    @param lhs Left hand side of the comparison
 | 
						|
    @param rhs Right hand side of the comparison
 | 
						|
    @return  < 0 if lhs  < rhs
 | 
						|
    @return == 0 if lhs == rhs
 | 
						|
    @return  > 0 if lhs  > rhs
 | 
						|
    '''
 | 
						|
    lhs = [int(v) for v in lhs.split('.')]
 | 
						|
    rhs = [int(v) for v in rhs.split('.')]
 | 
						|
    return (lhs > rhs) - (lhs < rhs)
 | 
						|
 | 
						|
 | 
						|
class ParsingContext(object):
 | 
						|
    """Context information for parsing.
 | 
						|
 | 
						|
    This object is immutable. To change contexts (like adding an item to the
 | 
						|
    stack), use the next() and next_stack() functions to build a new one.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, swagger_version, stack):
 | 
						|
        self.__swagger_version = swagger_version
 | 
						|
        self.__stack = stack
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "ParsingContext(swagger_version=%s, stack=%s)" % (
 | 
						|
            self.swagger_version, self.stack)
 | 
						|
 | 
						|
    def get_swagger_version(self):
 | 
						|
        return self.__swagger_version
 | 
						|
 | 
						|
    def get_stack(self):
 | 
						|
        return self.__stack
 | 
						|
 | 
						|
    swagger_version = property(get_swagger_version)
 | 
						|
 | 
						|
    stack = property(get_stack)
 | 
						|
 | 
						|
    def version_less_than(self, ver):
 | 
						|
        return compare_versions(self.swagger_version, ver) < 0
 | 
						|
 | 
						|
    def next_stack(self, json, id_field):
 | 
						|
        """Returns a new item pushed to the stack.
 | 
						|
 | 
						|
        @param json: Current JSON object.
 | 
						|
        @param id_field: Field identifying this object.
 | 
						|
        @return New context with additional item in the stack.
 | 
						|
        """
 | 
						|
        if not id_field in json:
 | 
						|
            raise SwaggerError("Missing id_field: %s" % id_field, self)
 | 
						|
        new_stack = self.stack + ['%s=%s' % (id_field, str(json[id_field]))]
 | 
						|
        return ParsingContext(self.swagger_version, new_stack)
 | 
						|
 | 
						|
    def next(self, version=None, stack=None):
 | 
						|
        if version is None:
 | 
						|
            version = self.version
 | 
						|
        if stack is None:
 | 
						|
            stack = self.stack
 | 
						|
        return ParsingContext(version, stack)
 | 
						|
 | 
						|
 | 
						|
class SwaggerError(Exception):
 | 
						|
    """Raised when an error is encountered mapping the JSON objects into the
 | 
						|
    model.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, msg, context, cause=None):
 | 
						|
        """Ctor.
 | 
						|
 | 
						|
        @param msg: String message for the error.
 | 
						|
        @param context: ParsingContext object
 | 
						|
        @param cause: Optional exception that caused this one.
 | 
						|
        """
 | 
						|
        super(Exception, self).__init__(msg, context, cause)
 | 
						|
 | 
						|
 | 
						|
class SwaggerPostProcessor(object):
 | 
						|
    """Post processing interface for model objects. This processor can add
 | 
						|
    fields to model objects for additional information to use in the
 | 
						|
    templates.
 | 
						|
    """
 | 
						|
    def process_resource_api(self, resource_api, context):
 | 
						|
        """Post process a ResourceApi object.
 | 
						|
 | 
						|
        @param resource_api: ResourceApi object.
 | 
						|
        @param context: Current context in the API.
 | 
						|
        """
 | 
						|
        pass
 | 
						|
 | 
						|
    def process_api(self, api, context):
 | 
						|
        """Post process an Api object.
 | 
						|
 | 
						|
        @param api: Api object.
 | 
						|
        @param context: Current context in the API.
 | 
						|
        """
 | 
						|
        pass
 | 
						|
 | 
						|
    def process_operation(self, operation, context):
 | 
						|
        """Post process a Operation object.
 | 
						|
 | 
						|
        @param operation: Operation object.
 | 
						|
        @param context: Current context in the API.
 | 
						|
        """
 | 
						|
        pass
 | 
						|
 | 
						|
    def process_parameter(self, parameter, context):
 | 
						|
        """Post process a Parameter object.
 | 
						|
 | 
						|
        @param parameter: Parameter object.
 | 
						|
        @param context: Current context in the API.
 | 
						|
        """
 | 
						|
        pass
 | 
						|
 | 
						|
    def process_model(self, model, context):
 | 
						|
        """Post process a Model object.
 | 
						|
 | 
						|
        @param model: Model object.
 | 
						|
        @param context: Current context in the API.
 | 
						|
        """
 | 
						|
        pass
 | 
						|
 | 
						|
    def process_property(self, property, context):
 | 
						|
        """Post process a Property object.
 | 
						|
 | 
						|
        @param property: Property object.
 | 
						|
        @param context: Current context in the API.
 | 
						|
        """
 | 
						|
        pass
 | 
						|
 | 
						|
    def process_type(self, swagger_type, context):
 | 
						|
        """Post process a SwaggerType object.
 | 
						|
 | 
						|
        @param swagger_type: ResourceListing object.
 | 
						|
        @param context: Current context in the API.
 | 
						|
        """
 | 
						|
        pass
 | 
						|
 | 
						|
    def process_resource_listing(self, resource_listing, context):
 | 
						|
        """Post process the overall ResourceListing object.
 | 
						|
 | 
						|
        @param resource_listing: ResourceListing object.
 | 
						|
        @param context: Current context in the API.
 | 
						|
        """
 | 
						|
        pass
 | 
						|
 | 
						|
 | 
						|
class AllowableRange(Stringify):
 | 
						|
    """Model of a allowableValues of type RANGE
 | 
						|
 | 
						|
    See https://github.com/wordnik/swagger-core/wiki/datatypes#complex-types
 | 
						|
    """
 | 
						|
    def __init__(self, min_value, max_value):
 | 
						|
        self.min_value = min_value
 | 
						|
        self.max_value = max_value
 | 
						|
 | 
						|
    def to_wiki(self):
 | 
						|
        return "Allowed range: Min: {0}; Max: {1}".format(self.min_value, self.max_value)
 | 
						|
 | 
						|
 | 
						|
class AllowableList(Stringify):
 | 
						|
    """Model of a allowableValues of type LIST
 | 
						|
 | 
						|
    See https://github.com/wordnik/swagger-core/wiki/datatypes#complex-types
 | 
						|
    """
 | 
						|
    def __init__(self, values):
 | 
						|
        self.values = values
 | 
						|
 | 
						|
    def to_wiki(self):
 | 
						|
        return "Allowed values: {0}".format(", ".join(self.values))
 | 
						|
 | 
						|
 | 
						|
def load_allowable_values(json, context):
 | 
						|
    """Parse a JSON allowableValues object.
 | 
						|
 | 
						|
    This returns None, AllowableList or AllowableRange, depending on the
 | 
						|
    valueType in the JSON. If the valueType is not recognized, a SwaggerError
 | 
						|
    is raised.
 | 
						|
    """
 | 
						|
    if not json:
 | 
						|
        return None
 | 
						|
 | 
						|
    if not 'valueType' in json:
 | 
						|
        raise SwaggerError("Missing valueType field", context)
 | 
						|
 | 
						|
    value_type = json['valueType']
 | 
						|
 | 
						|
    if value_type == 'RANGE':
 | 
						|
        if not 'min' in json and not 'max' in json:
 | 
						|
            raise SwaggerError("Missing fields min/max", context)
 | 
						|
        return AllowableRange(json.get('min'), json.get('max'))
 | 
						|
    if value_type == 'LIST':
 | 
						|
        if not 'values' in json:
 | 
						|
            raise SwaggerError("Missing field values", context)
 | 
						|
        return AllowableList(json['values'])
 | 
						|
    raise SwaggerError("Unkown valueType %s" % value_type, context)
 | 
						|
 | 
						|
 | 
						|
class Parameter(Stringify):
 | 
						|
    """Model of an operation's parameter.
 | 
						|
 | 
						|
    See https://github.com/wordnik/swagger-core/wiki/parameters
 | 
						|
    """
 | 
						|
 | 
						|
    required_fields = ['name', 'paramType', 'dataType']
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.param_type = None
 | 
						|
        self.name = None
 | 
						|
        self.description = None
 | 
						|
        self.data_type = None
 | 
						|
        self.required = None
 | 
						|
        self.allowable_values = None
 | 
						|
        self.allow_multiple = None
 | 
						|
 | 
						|
    def load(self, parameter_json, processor, context):
 | 
						|
        context = context.next_stack(parameter_json, 'name')
 | 
						|
        validate_required_fields(parameter_json, self.required_fields, context)
 | 
						|
        self.name = parameter_json.get('name')
 | 
						|
        self.param_type = parameter_json.get('paramType')
 | 
						|
        self.description = parameter_json.get('description') or ''
 | 
						|
        self.data_type = parameter_json.get('dataType')
 | 
						|
        self.required = parameter_json.get('required') or False
 | 
						|
        self.default_value = parameter_json.get('defaultValue')
 | 
						|
        self.allowable_values = load_allowable_values(
 | 
						|
            parameter_json.get('allowableValues'), context)
 | 
						|
        self.allow_multiple = parameter_json.get('allowMultiple') or False
 | 
						|
        processor.process_parameter(self, context)
 | 
						|
        if parameter_json.get('allowedValues'):
 | 
						|
            raise SwaggerError(
 | 
						|
                "Field 'allowedValues' invalid; use 'allowableValues'",
 | 
						|
                context)
 | 
						|
        return self
 | 
						|
 | 
						|
    def is_type(self, other_type):
 | 
						|
        return self.param_type == other_type
 | 
						|
 | 
						|
 | 
						|
class ErrorResponse(Stringify):
 | 
						|
    """Model of an error response.
 | 
						|
 | 
						|
    See https://github.com/wordnik/swagger-core/wiki/errors
 | 
						|
    """
 | 
						|
 | 
						|
    required_fields = ['code', 'reason']
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.code = None
 | 
						|
        self.reason = None
 | 
						|
 | 
						|
    def load(self, err_json, processor, context):
 | 
						|
        context = context.next_stack(err_json, 'code')
 | 
						|
        validate_required_fields(err_json, self.required_fields, context)
 | 
						|
        self.code = err_json.get('code')
 | 
						|
        self.reason = err_json.get('reason')
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
class SwaggerType(Stringify):
 | 
						|
    """Model of a data type.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.name = None
 | 
						|
        self.is_discriminator = None
 | 
						|
        self.is_list = None
 | 
						|
        self.singular_name = None
 | 
						|
        self.is_primitive = None
 | 
						|
        self.is_binary = None
 | 
						|
 | 
						|
    def load(self, type_name, processor, context):
 | 
						|
        # Some common errors
 | 
						|
        if type_name == 'integer':
 | 
						|
            raise SwaggerError("The type for integer should be 'int'", context)
 | 
						|
 | 
						|
        self.name = type_name
 | 
						|
        type_param = get_list_parameter_type(self.name)
 | 
						|
        self.is_list = type_param is not None
 | 
						|
        if self.is_list:
 | 
						|
            self.singular_name = type_param
 | 
						|
        else:
 | 
						|
            self.singular_name = self.name
 | 
						|
        self.is_primitive = self.singular_name in SWAGGER_PRIMITIVES
 | 
						|
        self.is_binary = (self.singular_name == 'binary')
 | 
						|
        processor.process_type(self, context)
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
class Operation(Stringify):
 | 
						|
    """Model of an operation on an API
 | 
						|
 | 
						|
    See https://github.com/wordnik/swagger-core/wiki/API-Declaration#apis
 | 
						|
    """
 | 
						|
 | 
						|
    required_fields = ['httpMethod', 'nickname', 'responseClass', 'summary']
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.http_method = None
 | 
						|
        self.nickname = None
 | 
						|
        self.response_class = None
 | 
						|
        self.parameters = []
 | 
						|
        self.summary = None
 | 
						|
        self.notes = None
 | 
						|
        self.error_responses = []
 | 
						|
 | 
						|
    def load(self, op_json, processor, context):
 | 
						|
        context = context.next_stack(op_json, 'nickname')
 | 
						|
        validate_required_fields(op_json, self.required_fields, context)
 | 
						|
        self.http_method = op_json.get('httpMethod')
 | 
						|
        self.nickname = op_json.get('nickname')
 | 
						|
        response_class = op_json.get('responseClass')
 | 
						|
        self.response_class = response_class and SwaggerType().load(
 | 
						|
            response_class, processor, context)
 | 
						|
 | 
						|
        # Specifying WebSocket URL's is our own extension
 | 
						|
        self.is_websocket = op_json.get('upgrade') == 'websocket'
 | 
						|
        self.is_req = not self.is_websocket
 | 
						|
 | 
						|
        if self.is_websocket:
 | 
						|
            self.websocket_protocol = op_json.get('websocketProtocol')
 | 
						|
            if self.http_method != 'GET':
 | 
						|
                raise SwaggerError(
 | 
						|
                    "upgrade: websocket is only valid on GET operations",
 | 
						|
                    context)
 | 
						|
 | 
						|
        params_json = op_json.get('parameters') or []
 | 
						|
        self.parameters = [
 | 
						|
            Parameter().load(j, processor, context) for j in params_json]
 | 
						|
        self.query_parameters = [
 | 
						|
            p for p in self.parameters if p.is_type('query')]
 | 
						|
        self.has_query_parameters = self.query_parameters and True
 | 
						|
        self.path_parameters = [
 | 
						|
            p for p in self.parameters if p.is_type('path')]
 | 
						|
        self.has_path_parameters = self.path_parameters and True
 | 
						|
        self.header_parameters = [
 | 
						|
            p for p in self.parameters if p.is_type('header')]
 | 
						|
        self.has_header_parameters = self.header_parameters and True
 | 
						|
        self.has_parameters = self.has_query_parameters or \
 | 
						|
            self.has_path_parameters or self.has_header_parameters
 | 
						|
        self.is_binary_response = self.response_class.is_binary
 | 
						|
 | 
						|
        # Body param is different, since there's at most one
 | 
						|
        self.body_parameter = [
 | 
						|
            p for p in self.parameters if p.is_type('body')]
 | 
						|
        if len(self.body_parameter) > 1:
 | 
						|
            raise SwaggerError("Cannot have more than one body param", context)
 | 
						|
        self.body_parameter = self.body_parameter and self.body_parameter[0]
 | 
						|
        self.has_body_parameter = self.body_parameter and True
 | 
						|
 | 
						|
        self.summary = op_json.get('summary')
 | 
						|
        self.notes = op_json.get('notes')
 | 
						|
        err_json = op_json.get('errorResponses') or []
 | 
						|
        self.error_responses = [
 | 
						|
            ErrorResponse().load(j, processor, context) for j in err_json]
 | 
						|
        self.has_error_responses = self.error_responses != []
 | 
						|
        processor.process_operation(self, context)
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
class Api(Stringify):
 | 
						|
    """Model of a single API in an API declaration.
 | 
						|
 | 
						|
    See https://github.com/wordnik/swagger-core/wiki/API-Declaration
 | 
						|
    """
 | 
						|
 | 
						|
    required_fields = ['path', 'operations']
 | 
						|
 | 
						|
    def __init__(self,):
 | 
						|
        self.path = None
 | 
						|
        self.description = None
 | 
						|
        self.operations = []
 | 
						|
 | 
						|
    def load(self, api_json, processor, context):
 | 
						|
        context = context.next_stack(api_json, 'path')
 | 
						|
        validate_required_fields(api_json, self.required_fields, context)
 | 
						|
        self.path = api_json.get('path')
 | 
						|
        self.description = api_json.get('description')
 | 
						|
        op_json = api_json.get('operations')
 | 
						|
        self.operations = [
 | 
						|
            Operation().load(j, processor, context) for j in op_json]
 | 
						|
        self.has_websocket = any(op.is_websocket for op in self.operations)
 | 
						|
        processor.process_api(self, context)
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
def get_list_parameter_type(type_string):
 | 
						|
    """Returns the type parameter if the given type_string is List[].
 | 
						|
 | 
						|
    @param type_string: Type string to parse
 | 
						|
    @returns Type parameter of the list, or None if not a List.
 | 
						|
    """
 | 
						|
    list_match = re.match('^List\[(.*)\]$', type_string)
 | 
						|
    return list_match and list_match.group(1)
 | 
						|
 | 
						|
 | 
						|
class Property(Stringify):
 | 
						|
    """Model of a Swagger property.
 | 
						|
 | 
						|
    See https://github.com/wordnik/swagger-core/wiki/datatypes
 | 
						|
    """
 | 
						|
 | 
						|
    required_fields = ['type']
 | 
						|
 | 
						|
    def __init__(self, name):
 | 
						|
        self.name = name
 | 
						|
        self.type = None
 | 
						|
        self.description = None
 | 
						|
        self.required = None
 | 
						|
 | 
						|
    def load(self, property_json, processor, context):
 | 
						|
        validate_required_fields(property_json, self.required_fields, context)
 | 
						|
        # Bit of a hack, but properties do not self-identify
 | 
						|
        context = context.next_stack({'name': self.name}, 'name')
 | 
						|
        self.description = property_json.get('description') or ''
 | 
						|
        self.required = property_json.get('required') or False
 | 
						|
 | 
						|
        type = property_json.get('type')
 | 
						|
        self.type = type and SwaggerType().load(type, processor, context)
 | 
						|
 | 
						|
        processor.process_property(self, context)
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
class Model(Stringify):
 | 
						|
    """Model of a Swagger model.
 | 
						|
 | 
						|
    See https://github.com/wordnik/swagger-core/wiki/datatypes
 | 
						|
    """
 | 
						|
 | 
						|
    required_fields = ['description', 'properties']
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.id = None
 | 
						|
        self.subtypes = []
 | 
						|
        self.__subtype_types = []
 | 
						|
        self.notes = None
 | 
						|
        self.description = None
 | 
						|
        self.__properties = None
 | 
						|
        self.__discriminator = None
 | 
						|
        self.__extends_type = None
 | 
						|
 | 
						|
    def load(self, id, model_json, processor, context):
 | 
						|
        context = context.next_stack(model_json, 'id')
 | 
						|
        validate_required_fields(model_json, self.required_fields, context)
 | 
						|
        # The duplication of the model's id is required by the Swagger spec.
 | 
						|
        self.id = model_json.get('id')
 | 
						|
        if id != self.id:
 | 
						|
            raise SwaggerError("Model id doesn't match name", context)
 | 
						|
        self.subtypes = model_json.get('subTypes') or []
 | 
						|
        if self.subtypes and context.version_less_than("1.2"):
 | 
						|
            raise SwaggerError("Type extension support added in Swagger 1.2",
 | 
						|
                               context)
 | 
						|
        self.description = model_json.get('description')
 | 
						|
        props = model_json.get('properties').items() or []
 | 
						|
        self.__properties = [
 | 
						|
            Property(k).load(j, processor, context) for (k, j) in props]
 | 
						|
        self.__properties = sorted(self.__properties, key=lambda p: p.name)
 | 
						|
 | 
						|
        discriminator = model_json.get('discriminator')
 | 
						|
 | 
						|
        if discriminator:
 | 
						|
            if context.version_less_than("1.2"):
 | 
						|
                raise SwaggerError("Discriminator support added in Swagger 1.2",
 | 
						|
                                   context)
 | 
						|
 | 
						|
            discr_props = [p for p in self.__properties if p.name == discriminator]
 | 
						|
            if not discr_props:
 | 
						|
                raise SwaggerError(
 | 
						|
                    "Discriminator '%s' does not name a property of '%s'" % (
 | 
						|
                        discriminator, self.id),
 | 
						|
                    context)
 | 
						|
 | 
						|
            self.__discriminator = discr_props[0]
 | 
						|
 | 
						|
        self.model_json = json.dumps(model_json,
 | 
						|
                                     indent=2, separators=(',', ': '))
 | 
						|
 | 
						|
        processor.process_model(self, context)
 | 
						|
        return self
 | 
						|
 | 
						|
    def extends(self):
 | 
						|
        return self.__extends_type and self.__extends_type.id
 | 
						|
 | 
						|
    def set_extends_type(self, extends_type):
 | 
						|
        self.__extends_type = extends_type
 | 
						|
 | 
						|
    def set_subtype_types(self, subtype_types):
 | 
						|
        self.__subtype_types = subtype_types
 | 
						|
 | 
						|
    def discriminator(self):
 | 
						|
        """Returns the discriminator, digging through base types if needed.
 | 
						|
        """
 | 
						|
        return self.__discriminator or \
 | 
						|
            self.__extends_type and self.__extends_type.discriminator()
 | 
						|
 | 
						|
    def properties(self):
 | 
						|
        base_props = []
 | 
						|
        if self.__extends_type:
 | 
						|
            base_props = self.__extends_type.properties()
 | 
						|
        return base_props + self.__properties
 | 
						|
 | 
						|
    def has_properties(self):
 | 
						|
        return len(self.properties()) > 0
 | 
						|
 | 
						|
    def all_subtypes(self):
 | 
						|
        """Returns the full list of all subtypes, including sub-subtypes.
 | 
						|
        """
 | 
						|
        res = self.__subtype_types + \
 | 
						|
              [subsubtypes for subtype in self.__subtype_types
 | 
						|
               for subsubtypes in subtype.all_subtypes()]
 | 
						|
        return sorted(res, key=lambda m: m.id)
 | 
						|
 | 
						|
    def has_subtypes(self):
 | 
						|
        """Returns True if type has any subtypes.
 | 
						|
        """
 | 
						|
        return len(self.subtypes) > 0
 | 
						|
 | 
						|
 | 
						|
class ApiDeclaration(Stringify):
 | 
						|
    """Model class for an API Declaration.
 | 
						|
 | 
						|
    See https://github.com/wordnik/swagger-core/wiki/API-Declaration
 | 
						|
    """
 | 
						|
 | 
						|
    required_fields = [
 | 
						|
        'swaggerVersion', '_author', '_copyright', 'apiVersion', 'basePath',
 | 
						|
        'resourcePath', 'apis', 'models'
 | 
						|
    ]
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.swagger_version = None
 | 
						|
        self.author = None
 | 
						|
        self.copyright = None
 | 
						|
        self.api_version = None
 | 
						|
        self.base_path = None
 | 
						|
        self.resource_path = None
 | 
						|
        self.apis = []
 | 
						|
        self.models = []
 | 
						|
 | 
						|
    def load_file(self, api_declaration_file, processor):
 | 
						|
        context = ParsingContext(None, [api_declaration_file])
 | 
						|
        try:
 | 
						|
            return self.__load_file(api_declaration_file, processor, context)
 | 
						|
        except SwaggerError:
 | 
						|
            raise
 | 
						|
        except Exception as e:
 | 
						|
            print("Error: ", traceback.format_exc(), file=sys.stderr)
 | 
						|
            raise SwaggerError(
 | 
						|
                "Error loading %s" % api_declaration_file, context, e)
 | 
						|
 | 
						|
    def __load_file(self, api_declaration_file, processor, context):
 | 
						|
        with open(api_declaration_file) as fp:
 | 
						|
            self.load(json.load(fp), processor, context)
 | 
						|
 | 
						|
        expected_resource_path = '/api-docs/' + \
 | 
						|
            os.path.basename(api_declaration_file) \
 | 
						|
            .replace(".json", ".{format}")
 | 
						|
 | 
						|
        if self.resource_path != expected_resource_path:
 | 
						|
            print("%s != %s" % (self.resource_path, expected_resource_path),
 | 
						|
                file=sys.stderr)
 | 
						|
            raise SwaggerError("resourcePath has incorrect value", context)
 | 
						|
 | 
						|
        return self
 | 
						|
 | 
						|
    def load(self, api_decl_json, processor, context):
 | 
						|
        """Loads a resource from a single Swagger resource.json file.
 | 
						|
        """
 | 
						|
        # If the version doesn't match, all bets are off.
 | 
						|
        self.swagger_version = api_decl_json.get('swaggerVersion')
 | 
						|
        context = context.next(version=self.swagger_version)
 | 
						|
        if not self.swagger_version in SWAGGER_VERSIONS:
 | 
						|
            raise SwaggerError(
 | 
						|
                "Unsupported Swagger version %s" % self.swagger_version, context)
 | 
						|
 | 
						|
        validate_required_fields(api_decl_json, self.required_fields, context)
 | 
						|
 | 
						|
        self.author = api_decl_json.get('_author')
 | 
						|
        self.copyright = api_decl_json.get('_copyright')
 | 
						|
        self.api_version = api_decl_json.get('apiVersion')
 | 
						|
        self.base_path = api_decl_json.get('basePath')
 | 
						|
        self.resource_path = api_decl_json.get('resourcePath')
 | 
						|
        self.requires_modules = api_decl_json.get('requiresModules') or []
 | 
						|
        api_json = api_decl_json.get('apis') or []
 | 
						|
        self.apis = [
 | 
						|
            Api().load(j, processor, context) for j in api_json]
 | 
						|
        paths = set()
 | 
						|
        for api in self.apis:
 | 
						|
            if api.path in paths:
 | 
						|
                raise SwaggerError("API with duplicated path: %s" % api.path, context)
 | 
						|
            paths.add(api.path)
 | 
						|
        self.has_websocket = any(api.has_websocket for api in self.apis)
 | 
						|
        models = api_decl_json.get('models').items() or []
 | 
						|
        self.models = [Model().load(id, json, processor, context)
 | 
						|
                       for (id, json) in models]
 | 
						|
        self.models = sorted(self.models, key=lambda m: m.id)
 | 
						|
        # Now link all base/extended types
 | 
						|
        model_dict = dict((m.id, m) for m in self.models)
 | 
						|
        for m in self.models:
 | 
						|
            def link_subtype(name):
 | 
						|
                res = model_dict.get(name)
 | 
						|
                if not res:
 | 
						|
                    raise SwaggerError("%s has non-existing subtype %s",
 | 
						|
                                       m.id, name)
 | 
						|
                res.set_extends_type(m)
 | 
						|
                return res;
 | 
						|
            if m.subtypes:
 | 
						|
                m.set_subtype_types([
 | 
						|
                    link_subtype(subtype) for subtype in m.subtypes])
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
class ResourceApi(Stringify):
 | 
						|
    """Model of an API listing in the resources.json file.
 | 
						|
    """
 | 
						|
 | 
						|
    required_fields = ['path', 'description']
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.path = None
 | 
						|
        self.description = None
 | 
						|
        self.api_declaration = None
 | 
						|
 | 
						|
    def load(self, api_json, processor, context):
 | 
						|
        context = context.next_stack(api_json, 'path')
 | 
						|
        validate_required_fields(api_json, self.required_fields, context)
 | 
						|
        self.path = api_json['path'].replace('{format}', 'json')
 | 
						|
        self.description = api_json['description']
 | 
						|
 | 
						|
        if not self.path or self.path[0] != '/':
 | 
						|
            raise SwaggerError("Path must start with /", context)
 | 
						|
        processor.process_resource_api(self, context)
 | 
						|
        return self
 | 
						|
 | 
						|
    def load_api_declaration(self, base_dir, processor):
 | 
						|
        self.file = (base_dir + self.path)
 | 
						|
        self.api_declaration = ApiDeclaration().load_file(self.file, processor)
 | 
						|
        processor.process_resource_api(self, [self.file])
 | 
						|
 | 
						|
 | 
						|
class ResourceListing(Stringify):
 | 
						|
    """Model of Swagger's resources.json file.
 | 
						|
    """
 | 
						|
 | 
						|
    required_fields = ['apiVersion', 'basePath', 'apis']
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self.swagger_version = None
 | 
						|
        self.api_version = None
 | 
						|
        self.base_path = None
 | 
						|
        self.apis = None
 | 
						|
 | 
						|
    def load_file(self, resource_file, processor):
 | 
						|
        context = ParsingContext(None, [resource_file])
 | 
						|
        try:
 | 
						|
            return self.__load_file(resource_file, processor, context)
 | 
						|
        except SwaggerError:
 | 
						|
            raise
 | 
						|
        except Exception as e:
 | 
						|
            print("Error: ", traceback.format_exc(), file=sys.stderr)
 | 
						|
            raise SwaggerError(
 | 
						|
                "Error loading %s" % resource_file, context, e)
 | 
						|
 | 
						|
    def __load_file(self, resource_file, processor, context):
 | 
						|
        with open(resource_file) as fp:
 | 
						|
            return self.load(json.load(fp), processor, context)
 | 
						|
 | 
						|
    def load(self, resources_json, processor, context):
 | 
						|
        # If the version doesn't match, all bets are off.
 | 
						|
        self.swagger_version = resources_json.get('swaggerVersion')
 | 
						|
        if not self.swagger_version in SWAGGER_VERSIONS:
 | 
						|
            raise SwaggerError(
 | 
						|
                "Unsupported Swagger version %s" % self.swagger_version, context)
 | 
						|
 | 
						|
        validate_required_fields(resources_json, self.required_fields, context)
 | 
						|
        self.api_version = resources_json['apiVersion']
 | 
						|
        self.base_path = resources_json['basePath']
 | 
						|
        apis_json = resources_json['apis']
 | 
						|
        self.apis = [
 | 
						|
            ResourceApi().load(j, processor, context) for j in apis_json]
 | 
						|
        processor.process_resource_listing(self, context)
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
def validate_required_fields(json, required_fields, context):
 | 
						|
    """Checks a JSON object for a set of required fields.
 | 
						|
 | 
						|
    If any required field is missing, a SwaggerError is raised.
 | 
						|
 | 
						|
    @param json: JSON object to check.
 | 
						|
    @param required_fields: List of required fields.
 | 
						|
    @param context: Current context in the API.
 | 
						|
    """
 | 
						|
    missing_fields = [f for f in required_fields if not f in json]
 | 
						|
 | 
						|
    if missing_fields:
 | 
						|
        raise SwaggerError(
 | 
						|
            "Missing fields: %s" % ', '.join(missing_fields), context)
 |