def generate(package): doc = [] with mock_import.mock_import([package]): for resource_class, parents in packages.iter_resource_classes(package): resource_path = common.url_join( *([parent.path for parent in parents] + [resource_class.path()])) for route in resource_class.iter_route_methods(): arguments = [] for name, arg in six.iteritems(route.spec.args_info): argument = { 'name': route.keyword_map.get(name, name), 'type': arg.type_name, 'doc': arg.doc, } if isinstance(arg, (_args.KeywordArg, _args.OptionalArg)): argument['default'] = arg.default arguments.append(argument) doc.append({ 'name': route.__name__, 'arguments': arguments, 'method': route.method, 'path': common.url_join(resource_path, route.path), 'success_status': route.success_code, 'doc': route.spec.doc, 'cli_command': _build_cli_command(parents, resource_class, route) }) return doc
def _add_resources(self, package): with mock_import.mock_import([package]): for resource_class, parents in packages.iter_resource_classes(package): cur = self._resources for parent in parents: cur = cur.setdefault(parent, {}) cur.setdefault("", []).append(resource_class)
def add_resources(self, node, resource_package, **resource_params): """ :param node: a resource node to add package resources to :param resource_package: resources package """ bad_definition = False for resource_class, parents in packages.iter_resource_classes(resource_package): prefix = '/'.join([parent.path for parent in parents]) node = node.get_node([parent.name for parent in parents]) node.add(resource_class.name(), resource_class) resource = resource_class(**resource_params) try: self._add_route_methods(resource, prefix) except exceptions.BadResourceDefinition: bad_definition = True try: self._add_sink_methods(resource, prefix) except exceptions.BadResourceDefinition: bad_definition = True if bad_definition: raise exceptions.BadResourceDefinition('Bad definition of resource, see log for errors.')
def add_resources(self, node, resource_package, **resource_params): """ :param node: a resource node to add package resources to :param resource_package: resources package """ bad_definition = False for resource_class, parents in packages.iter_resource_classes( resource_package): prefix = '/'.join([parent.path for parent in parents]) node = node.get_node([parent.name for parent in parents]) node.add(resource_class.name(), resource_class) resource = resource_class(**resource_params) try: self._add_route_methods(resource, prefix) except exceptions.BadResourceDefinition: bad_definition = True try: self._add_sink_methods(resource, prefix) except exceptions.BadResourceDefinition: bad_definition = True if bad_definition: raise exceptions.BadResourceDefinition( 'Bad definition of resource, see log for errors.')
def verify_doc(package, method_verifier=None, argument_verifier=None, verification_exceptions=None): """Verify API documentation. :param method_verifier: a function that gets a single Method object (see above) and returns a list of errors as strings (if found). these strings are prefixed by the method identifier and added to any other errors that are found here. :param argument_verifier: a function that gets a single Argument object (see above) and returns a list of errors as strings (if found). these strings are prefixed by the argument identifier and added to any other errors that are found here. :param list verification_exceptions: a list of ExceptedMethods and ExceptedArguments to ignore by verify_doc (similar to #noqa for pep8) """ verification_exceptions = verification_exceptions or set() errors = [] with mock_import.mock_import([package]): for resource_class, _ in packages.iter_resource_classes(package): for route in resource_class.iter_route_methods(): if route.dest is not None: continue identifier = '%s.%s' % (resource_class.__name__, route.func.__name__) if ExceptedMethod( resource_class.__name__, route.func.__name__) in verification_exceptions: continue method = Method(name=route.func.__name__, doc=strip_escaped_newlines(route.spec.doc), class_name=resource_class.__name__, method=route.method, returns=route.spec.returns, returns_doc=route.spec.returns.doc if route.spec.returns else '', success_code=route.success_code) errors.extend( _verify_method(identifier, method, method_verifier)) default_dict = _func_default_dict(route) for name, arg in six.iteritems(route.spec.args_info): if name.startswith('_'): continue if ExceptedArgument(resource_class.__name__, route.func.__name__, route.keyword_map.get( name, name)) in verification_exceptions: continue default = default_dict.get(name, NO_DEFAULT) argument = Argument(name=route.keyword_map.get(name, name), class_name=resource_class.__name__, doc=strip_escaped_newlines(arg.doc), method_name=route.func.__name__, type_name=arg.type_name, default=default, has_default=default is not NO_DEFAULT) errors.extend( _verify_argument(identifier, argument, argument_verifier)) return errors
def generate_swagger(package): doc = OrderedDict( swagger='2.0', info={ 'title': package, 'version': '1.0.0', } ) paths = defaultdict(dict) definitions = {} with mock_import.mock_import([package]): for resource_class, parents in packages.iter_resource_classes(package): resource_path = common.url_join(*([parent.path for parent in parents] + [resource_class.path()])) for route in resource_class.iter_route_methods(): path = '/' + common.url_join(resource_path, route.path) path_vars = PATH_VARIABLE.findall(path) method = route.method.lower() # classify params by source: path, query or body params = defaultdict(dict) for name, arg in six.iteritems(route.spec.args_info): if name.startswith('_'): continue if name in path_vars: params['path'][name] = arg elif method in ['get']: params['query'][name] = arg elif method in ['post', 'put', 'patch']: params['body'][name] = arg parameters = [] # add all path params for name, arg in six.iteritems(params['path']): parameters.append(_generate_param_dict(route, name, arg, 'path', True)) # add all query params for name, arg in six.iteritems(params['query']): required = not isinstance(arg, (_args.KeywordArg, _args.OptionalArg)) parameters.append(_generate_param_dict(route, name, arg, 'query', required)) # add body param if needed properties = {} required = [] for name, arg in six.iteritems(params['body']): prop_name = route.keyword_map.get(name, name) properties[prop_name] = { 'type': SWAGGER_TYPES.get(arg.type_name, "string"), 'description': arg.doc or "", } if not isinstance(arg, (_args.KeywordArg, _args.OptionalArg)): required.append(prop_name) operation_id = _build_operation_id(parents, resource_class, route) if len(properties) > 0: param_name = operation_id + '_object' param = { 'name': param_name, 'in': 'body', 'schema': { '$ref': '#/definitions/' + param_name, } } parameters.append(param) definitions[param_name] = dict(type='object', properties=properties) if len(required) > 1: definitions[param_name]['required'] = required operation = { 'description': route.spec.doc or '', 'parameters': parameters, 'responses': { route.success_code: { 'description': 'default response' } } } paths[path][method] = operation doc['paths'] = paths doc['definitions'] = definitions return doc