diff --git a/.gitignore b/.gitignore index 6d7b9c17f7d3c0a133b2328a1c52005d3e39f75d..f0bd2945cc34967a44e46014a6efa62ac2c47901 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,9 @@ docs/_build/ # PyBuilder target/ +.DS_Store +.idea/ +examples/.DS_Store +examples/industrial-ai-apiserver/test.json +examples/industrial-ai-apiserver/test.yaml +pecan_swagger/.DS_Store diff --git a/API Reference.md b/API Reference.md new file mode 100644 index 0000000000000000000000000000000000000000..2169d98915a1ca931fdcde7489c908d50f23f030 --- /dev/null +++ b/API Reference.md @@ -0,0 +1,142 @@ +# Pecan Swagger API Reference + +```python +pecan_swagger.utils.swagger_build(title, version) +``` +Parameters: +- **title** (String): The title of the application. +- **version** (String): Provides the version of the application API. + +Returns: +- **Swagger Dict** + +```python +pecan_swagger.utils.add_info(s, description=None, terms_of_service=None, contact=None, license=None) +``` +Parameters: +- **s** (Swagger Dict): Swagger Dict create by swagger_build. +- **description** (String): A short description of the application. +- **terms_of_service** (String): The Terms of Service for the API. +- **contact** (Dict): The contact information for the exposed API. Key should be in "name", "url", "email" or patterned string started with "x-". Values should be string for contact. +- **license** (String): Provides the version of the application API. Key should be in "name", "url" or patterned string started with "x-". Values should be string for license. + +Returns: +- **Swagger Dict** + +```python +pecan_swagger.utils.add_external_docs(s, external_docs) +``` +Parameters: +- **s** (Swagger Dict): Swagger Dict create by swagger_build. +- **external_docs** (Dict): Allows referencing an external resource for extended documentation. Key must include "url" and should be in "description", or patterned string started with "x-". Values should be string for license. + +Returns: +- **Swagger Dict** + +```python +pecan_swagger.utils.add_host(s, host) +``` +Parameters: +- **s** (Swagger Dict): Swagger Dict create by swagger_build. +- **host** (String): The host (name or ip) serving the API. +This MUST be the host only and does not include the scheme nor sub-paths. + +Returns: +- **Swagger Dict** + +```python +pecan_swagger.utils.add_base_path(s, base_path) +``` +Parameters: +- **s** (Swagger Dict): Swagger Dict create by swagger_build. +- **base_path** (String): The base path on which the API is served, which is relative to the host. If it is not included, the API is served directly under the host. + +Returns: +- **Swagger Dict** + +```python +pecan_swagger.utils.print_json(s, output_path) +``` +Parameters: +- **s** (Swagger Dict): Swagger Dict create by swagger_build. +- **base_path** (String): Path to output the json file. + +```python +pecan_swagger.utils.print_yaml(s, output_path) +``` +Parameters: +- **s** (Swagger Dict): Swagger Dict create by swagger_build. +- **base_path** (String): Path to output the json file. + + +```python +@pecan_swagger.decorators.path(endpoint, name, parent=None) +``` +Parameters: +- **endpoint** (String): The root uri for this controller. +- **base_path** (String): The name of this path. +- **parent** (String): An optional path name to indicate a parent/child relationship between this path and another. + +```python +@pecan_swagger.decorators.response(method_name, res_code, des, schema=None) +``` +Parameters: +- **method_name** (String): The name of the method. +- **res_code** (String): The HTTP response code of this response. +- **des** (String): The description of this response. +- **schema** (String): The schema of this response. + +```python +@pecan_swagger.decorators.tags(method_name, *tags) +``` +Parameters: +- **method_name** (String): The name of the method. +- ***tags** (String): The tags of this response. + +```python +@pecan_swagger.decorators.summary(method_name, summary) +``` +Parameters: +- **method_name** (String): The name of the method. +- **summary** (String): The summary of the method. + +```python +@pecan_swagger.decorators.description(method_name, des) +``` +Parameters: +- **method_name** (String): The name of the method. +- **des** (String): The description of the method. + +```python +@pecan_swagger.decorators.operationId(method_name, oi) +``` +Parameters: +- **method_name** (String): The name of the method. +- **oi** (String): The operationId of the method. + +```python +@pecan_swagger.decorators.method(*args) +``` +Parameters: +- ***args** (String): The names of the method. + +```python +@pecan_swagger.decorators.definitions(t, *args) +``` +Parameters: +- **t** (String): The type of the definition. +- ***args** (String): The properties of the definition. + +```python +@pecan_swagger.decorators.definitions(t, *args) +``` +Parameters: +- **t** (String): The type of the definition. +- ***args** (String): The properties of the definition. + +```python +@pecan_swagger.decorators.parameter(method_name, *args) +``` +Parameters: +- **method_name** (String): The name of the method. +- ***args** (String): The parameters of the definition. \ No newline at end of file diff --git a/examples/industrial-ai-apiserver/industrialai/api/controllers/root.py b/examples/industrial-ai-apiserver/industrialai/api/controllers/root.py index 6f596a50f655c1ad932973931ac8d7a9f4aee341..6ea53d1752d720d3d565bb9f379fcc823dc382ff 100644 --- a/examples/industrial-ai-apiserver/industrialai/api/controllers/root.py +++ b/examples/industrial-ai-apiserver/industrialai/api/controllers/root.py @@ -9,6 +9,7 @@ from pecan import expose from pecan import request from pecan_swagger import decorators as swagger from wsme import types as wtypes + logger = logging.getLogger(__name__) @@ -22,6 +23,7 @@ class checkForm: pwd = wtypes.text +@swagger.definitions('object') class registryForm: account = wtypes.text pwd = wtypes.text @@ -29,14 +31,33 @@ class registryForm: mail = wtypes.text name = wtypes.text number = wtypes.text - - + check = checkForm() + + +@swagger.parameter('myself', {'in': "body", + 'name': "body", + 'description': "get user", + 'required': True, + 'schema': 'userInfo'}) +@swagger.parameter('index', {'in': "body", + 'name': "body", + 'description': "get user", + 'required': True, + 'schema': 'userInfo'}) +@swagger.parameter('test', {'in': "body", + 'name': "body", + 'description': "get user", + 'required': True, + 'schema': 'userInfo'}) +@swagger.response('myself', '401', 'fail') +@swagger.response('index', '401', 'fail') +@swagger.response('test', '200', 'test description') +@swagger.method('test', 'index', 'signin', 'pwdcheck', 'myself') @swagger.path("/", "Root") class RootController(object): - _custom_actions = { 'test': ['GET'], - 'signin':['POST'], + 'signin': ['POST'], 'pwdcheck': ['POST'], 'myself': ['POST'] } @@ -78,6 +99,7 @@ class RootController(object): "debuginfo": null } """ + @wsexpose(wtypes.text, body=logForm) def signin(self, logForm): account = logForm.account @@ -106,6 +128,7 @@ class RootController(object): "result": True True:校验通过/False:校验失败 } """ + @wsexpose(wtypes.text, body=checkForm) def pwdcheck(self, checkForm): try: @@ -132,6 +155,7 @@ class RootController(object): "phone": "12345", 手机号 } """ + @expose('json') def myself(self): token = request.cookies.get("token") diff --git a/examples/industrial-ai-apiserver/industrialai/api/controllers/v1/role.py b/examples/industrial-ai-apiserver/industrialai/api/controllers/v1/role.py index 5c3ebe50b3979dcb62499d752380fc55d3c3afc1..2f1a9d6db735e0849bd3ed07679815dd94de3e2d 100644 --- a/examples/industrial-ai-apiserver/industrialai/api/controllers/v1/role.py +++ b/examples/industrial-ai-apiserver/industrialai/api/controllers/v1/role.py @@ -12,6 +12,18 @@ class Roletest(wstypes.Base): roleId = int +@swagger.definitions('object') +class RoleItem: + title = wstypes.text + id = int + +@swagger.parameter('get_all', {'in': "body", + 'name': "body", + 'description': "get all roles", + 'required': True, + 'schema': 'RoleItem'}) +@swagger.response('get_all', '401', 'fail') +@swagger.method('test', 'get_all') @swagger.path("roles", "Role", "Root") class RoleController(RestController): _custom_actions = { diff --git a/examples/industrial-ai-apiserver/industrialai/api/controllers/v1/user.py b/examples/industrial-ai-apiserver/industrialai/api/controllers/v1/user.py index cdf98c36e83a00c12e7c3bb4cce0c4aa3a221b03..dd764b8f648f96da5f7471807e9881874eb2b8ff 100644 --- a/examples/industrial-ai-apiserver/industrialai/api/controllers/v1/user.py +++ b/examples/industrial-ai-apiserver/industrialai/api/controllers/v1/user.py @@ -5,9 +5,80 @@ from pecan import expose from pecan import request from pecan.rest import RestController from pecan_swagger import decorators as swagger - +from wsme import types as wtypes + + +@swagger.definitions('object') +class userInfo: + id = int + number = int + roleId = int + status = wtypes.text + create_at = wtypes.text + name = wtypes.text + account = wtypes.text + phone = wtypes.text + email = wtypes.text + + +@swagger.definitions('object') +class userInfoUpdate: + id = wtypes.text + enterpriseId = wtypes.text + enterpriseGroupId = wtypes.text + name = wtypes.text + + +@swagger.response('put', '401', 'fail') +@swagger.response('post', '401', 'fail') +@swagger.response('get_one', '401', 'fail') +@swagger.response('get', '401', 'fail') @swagger.response('get', '200', 'test description') -@swagger.method('get','get_one','post','put') +@swagger.parameter('get', {'name': "status", + 'in': "query", + 'description': 'Status values that need to be considered for filter', + 'required': True, + 'type': 'array', + 'items': {'type': 'string', + 'enum': ["available", "pending", "sold"], + 'default': "available"}, + 'collectionFormat': "multi"}) +@swagger.parameter('get_one', {'in': "body", + 'name': "body", + 'description': "get one user", + 'required': True, + 'schema': 'userInfo'}) +@swagger.parameter('put', {'in': "body", + 'name': "body", + 'description': "get one user", + 'required': True, + 'schema': 'userInfo'}) +@swagger.parameter('post', {'name': "userId", + 'in': "formData", + 'description': "ID of user that needs to be created", + 'required': True, + 'type': "integer", + 'format': "int64"}, + {'name': "name", + 'in': "formData", + 'description': "created name of the user", + 'required': False, + 'type': "string"}, + {'name': "status", + 'in': "formData", + 'description': "created status of the user", + 'required': False, + 'type': "string"}) +@swagger.consumes('post', 'multipart/form-data') +@swagger.produces('post', 'application/json') +@swagger.operationId('get', 'get users') +@swagger.description('get', 'get users information') +@swagger.summary('get', 'get users information') +@swagger.tags('put', 'user') +@swagger.tags('post', 'user') +@swagger.tags('get', 'user') +@swagger.tags('get_one', 'user') +@swagger.method('get', 'get_one', 'post', 'put') @swagger.path("users", "User", "Root") class UserController(RestController): """@api {get} /v1/users/?name= get_all_users diff --git a/examples/industrial-ai-apiserver/myapp-doc.py b/examples/industrial-ai-apiserver/myapp-doc.py index 3ced6b9c0d2110e5a49850c8f538b6b1246808ce..503fb8309c1f1cca49130c6205176938fc805146 100644 --- a/examples/industrial-ai-apiserver/myapp-doc.py +++ b/examples/industrial-ai-apiserver/myapp-doc.py @@ -1,4 +1,3 @@ -#!/bin/env python # import pprint import json from pecan_swagger import utils @@ -7,12 +6,19 @@ import industrialai.api.controllers.root # pp = pprint.PrettyPrinter(indent=2) # pp.pprint(utils.swagger_build('industrialai', '1.0')) # Create JSON file -s=utils.swagger_build('industrialai', - '1.0', - 'This is a This is a test project', - 'http://swagger.io/terms/', - {'email': "apiteam@swagger.io"}) -json_str = json.dumps(s, indent=4) -f = open("test.json", "w") -f.write(json_str) -f.close() +s = utils.swagger_build('industrialai', '1.0') +description = 'This is a This is a test project' +termsOfService = 'http://swagger.io/terms/' +contact = {'email': "apiteam@swagger.io"} +license = {'name': "Apache 2.0", + 'url': "http://www.apache.org/licenses/LICENSE-2.0.html"} +s = utils.add_info(s, description, termsOfService, contact, license) +externalDocs = {'description': "Find out more about Swagger", + 'url': "http://swagger.io"} +s = utils.add_external_docs(s, externalDocs) +host = "127.0.0.1" +s = utils.add_host(s, host) +basePath = "/v1" +s = utils.add_base_path(s, basePath) +output_path = "test.json" +utils.print_json(s, output_path) diff --git a/examples/industrial-ai-apiserver/pecan_swagger/decorators.py b/examples/industrial-ai-apiserver/pecan_swagger/decorators.py index a5ea799267ce4454e4aed77b9c149edf220a56ce..a9662e48e404d633bf7770d405d69ce2d1966a01 100644 --- a/examples/industrial-ai-apiserver/pecan_swagger/decorators.py +++ b/examples/industrial-ai-apiserver/pecan_swagger/decorators.py @@ -27,11 +27,10 @@ def path(endpoint, name, parent=None): c.__swag = dict(endpoint=endpoint, name=name, parent=parent) g.add_path(c) return c - return decorator -def response(method_name, res_code, des): +def response(method_name, res_code, des, schema=None): """ 获取方法的response 生成字典{response:res_code:{description:des}} @@ -39,12 +38,107 @@ def response(method_name, res_code, des): """ def decorator(m): - d = {} - d[res_code] = {'description': des} - m.__swag['method'][method_name]['response'] = d + if not hasattr(m, '__swag'): + raise Exception('You need to write a path in {} first'.format(m.__name__)) + if not 'method' in m.__swag: + raise Exception('You need to write the methods in {}'.format(m.__name__)) + if not method_name in m.__swag['method']: + raise Exception('There is no method called {} in {}'.format(method_name, m.__name__)) + if not m.__swag['method'][method_name].get('responses'): + m.__swag['method'][method_name]['responses'] = {} + if not m.__swag['method'][method_name]['responses'].get(res_code): + m.__swag['method'][method_name]['responses'][res_code] = {} + m.__swag['method'][method_name]['responses'][res_code]['description'] = des + if schema: + m.__swag['method'][method_name]['responses'][res_code]['schema'] = schema + return m + + return decorator + + +def tags(method_name, *tags): + """ + 获取方法的tags + 生成字典{tags:tag} + 并加入controller.__swag[method][method_name] + """ + + def decorator(m): + if not hasattr(m, '__swag'): + raise Exception('You need to write a path in {} first'.format(m.__name__)) + if not 'method' in m.__swag: + raise Exception('You need to write the methods in {}'.format(m.__name__)) + if not method_name in m.__swag['method']: + raise Exception('There is no method called {} in {}'.format(method_name, m.__name__)) + if not m.__swag['method'][method_name].get('tags'): + m.__swag['method'][method_name]['tags'] = [] + for i in tags: + m.__swag['method'][method_name]['tags'].append(i) + return m + + return decorator + + +def summary(method_name, summary): + """ + 获取方法的summary + 生成字典{summary:summary} + 并加入controller.__swag[method][method_name] + """ + + def decorator(m): + if not hasattr(m, '__swag'): + raise Exception('You need to write a path in {} first'.format(m.__name__)) + if not 'method' in m.__swag: + raise Exception('You need to write the methods in {}'.format(m.__name__)) + if not method_name in m.__swag['method']: + raise Exception('There is no method called {} in {}'.format(method_name, m.__name__)) + m.__swag['method'][method_name]['summary'] = summary + return m + + return decorator + + +def description(method_name, des): + """ + 获取方法的description + 生成字典{description:des} + 并加入controller.__swag[method][method_name] + """ + + def decorator(m): + if not hasattr(m, '__swag'): + raise Exception('You need to write a path in {} first'.format(m.__name__)) + if not 'method' in m.__swag: + raise Exception('You need to write the methods in {}'.format(m.__name__)) + if not method_name in m.__swag['method']: + raise Exception('There is no method called {} in {}'.format(method_name, m.__name__)) + m.__swag['method'][method_name]['description'] = des + return m + + return decorator + + +def operationId(method_name, oi): + """ + 获取方法的operationId + 生成字典{operationId:oi} + 并加入controller.__swag[method][method_name] + """ + + def decorator(m): + if not hasattr(m, '__swag'): + raise Exception('You need to write a path in {} first'.format(m.__name__)) + if not 'method' in m.__swag: + raise Exception('You need to write the methods in {}'.format(m.__name__)) + if not method_name in m.__swag['method']: + raise Exception('There is no method called {} in {}'.format(method_name, m.__name__)) + m.__swag['method'][method_name]['operationId'] = oi return m + return decorator + def method(*args): """ 获取被装饰类包含的方法 @@ -53,10 +147,93 @@ def method(*args): """ def decorator(m): + if not hasattr(m, '__swag'): + raise Exception('You need to write a path in {} first'.format(m.__name__)) d = {} for i in args: if hasattr(m, i): d[i] = {} m.__swag['method'] = d return m + + return decorator + + +def definitions(t, *args): + """ + 添加definitions到g.py中 + """ + + def decorator(m): + g.add_definitions(t, m) + return m + + return decorator + +def consumes(method_name, *consume): + """ + 获取方法的consumes + 生成字典{consumes:consumes} + 并加入controller.__swag[method][method_name] + """ + + def decorator(m): + if not hasattr(m, '__swag'): + raise Exception('You need to write a path in {} first'.format(m.__name__)) + if not 'method' in m.__swag: + raise Exception('You need to write the methods in {}'.format(m.__name__)) + if not method_name in m.__swag['method']: + raise Exception('There is no method called {} in {}'.format(method_name, m.__name__)) + if not m.__swag['method'][method_name].get('consumes'): + m.__swag['method'][method_name]['consumes'] = [] + for i in consume: + m.__swag['method'][method_name]['consumes'].append(i) + return m + + return decorator + +def produces(method_name, *pro): + """ + 获取方法的produces + 生成字典{produces:pro} + 并加入controller.__swag[method][method_name] + """ + + def decorator(m): + if not hasattr(m, '__swag'): + raise Exception('You need to write a path in {} first'.format(m.__name__)) + if not 'method' in m.__swag: + raise Exception('You need to write the methods in {}'.format(m.__name__)) + if not method_name in m.__swag['method']: + raise Exception('There is no method called {} in {}'.format(method_name, m.__name__)) + if not m.__swag['method'][method_name].get('produces'): + m.__swag['method'][method_name]['produces'] = [] + for i in pro: + m.__swag['method'][method_name]['produces'].append(i) + return m + + return decorator + +def parameter(method_name, *args): + """ + 获取方法的parameter + 生成字典{parameter:[]} + 并加入controller.__swag[method][method_name] + """ + + def decorator(m): + if not hasattr(m, '__swag'): + raise Exception('You need to write a path in {} first'.format(m.__name__)) + if not 'method' in m.__swag: + raise Exception('You need to write the methods in {}'.format(m.__name__)) + if not method_name in m.__swag['method']: + raise Exception('There is no method called {} in {}'.format(method_name, m.__name__)) + if not m.__swag['method'][method_name].get('parameters'): + m.__swag['method'][method_name]['parameters'] = [] + for i in args: + if i.get('schema'): + i['schema'] = {'$ref': '#/definitions/' + i['schema']} + m.__swag['method'][method_name]['parameters'].append(i) + return m + return decorator diff --git a/examples/industrial-ai-apiserver/pecan_swagger/g.py b/examples/industrial-ai-apiserver/pecan_swagger/g.py index b4869d13bd178bde3074567d586fcdc0cc10ba59..9085c663afd1dd7f8a35dc35e688a6b103402b5c 100644 --- a/examples/industrial-ai-apiserver/pecan_swagger/g.py +++ b/examples/industrial-ai-apiserver/pecan_swagger/g.py @@ -30,6 +30,8 @@ _all_wsme_types = wtypes.native_types + ( _definitions = {} +all_definitions = {} + def add_path(c): """adds a named controller to the hierarchy.""" @@ -77,6 +79,8 @@ def get_controller_paths(controllers, wsme_defs): if lc.get('index'): for method in get_methods_for_generic('index'): paths.append(('', (method, {}))) + spec = wsme_defs.get('index') # add wsme definitions + append_methods_for_specific('index', ('', ('get', spec))) # for REST controller for method, path in _http_methods.items(): @@ -87,11 +91,11 @@ def get_controller_paths(controllers, wsme_defs): if lc.get('get_all'): # add wsme definitions spec = wsme_defs.get('get_all') # add wsme definitions - append_methods_for_specific('get_all', ('', ('get', spec))) + append_methods_for_specific('get_all', ('get_all', ('get', spec))) if lc.get('get_one'): # add wsme definitions spec = wsme_defs.get('get_one') # add wsme definitions - append_methods_for_specific('get_one', ('', ('get', spec))) + append_methods_for_specific('get_one', ('get_one', ('get', spec))) if lc.get('_default'): append_methods_for_specific('_default', ('', ('*', {}))) @@ -272,6 +276,8 @@ def get_wsme_defs(name): if isparams and prop_dict['type'] in ['object', 'array']: prop_dict['schema'] = {'items': prop_dict['items'], 'type': prop_dict['type']} + if prop_dict['type'] == 'object': + prop_dict['schema'] = prop_dict['items'] del prop_dict['type'] del prop_dict['items'] return prop_dict @@ -307,8 +313,8 @@ def get_wsme_defs(name): # multi property schema schema_dict.update({'type': 'object'}) # properties - if 'items' not in schema_dict: - schema_dict['items'] = {'properties': {}} + if 'properties' not in schema_dict: + schema_dict['properties'] = {} prop = {key: get_wm_item_prop(obj, isparams)} # required as array of string if 'required' in prop[key] and prop[key]['required'] \ @@ -317,7 +323,7 @@ def get_wsme_defs(name): schema_dict['required'] = [] schema_dict['required'].append(key) del prop[key]['required'] - schema_dict['items']['properties'].update(prop) + schema_dict['properties'].update(prop) if schema_obj not in _all_wsme_types: if model_name not in _definitions: @@ -420,10 +426,11 @@ def get_paths(): for name in _hierarchy: fullpath = build_path(get_swag(name)) controllers = get_controllers(name) - paths = get_controller_paths(controllers, combine_defs(name)) + paths = get_controller_paths(controllers, combine_method_defs(name)) for path in paths: ptuple = (path_join(fullpath, path[0]), path[1]) pathlist.append(ptuple) + combine_all_definitions() return pathlist @@ -499,7 +506,7 @@ def get_def(name): return {} -def combine_defs(name): +def combine_method_defs(name): """合并expose和wsexpose装饰方法的definitions.""" c = _hierarchy[name] @@ -510,11 +517,101 @@ def combine_defs(name): for i in w_d: if e_d.get(i): for j in w_d[i]: - e_d[i][j]=w_d[i][j] + e_d[i][j] = w_d[i][j] else: - e_d[i]=w_d[i] + e_d[i] = w_d[i] elif w_d: return w_d else: return e_d return e_d + + +def format_type(t): + """ + 判断数据类型是否为自定义的数据类型 + """ + + def datatype_to_type_and_format(datatype): + + tf = {} + if datatype == 'uuid' or datatype == 'ipv4address' \ + or datatype == 'ipv6address' or datatype == 'date' \ + or datatype == 'time': + tf['type'] = 'string' + tf['format'] = datatype + elif datatype == 'datetime': + tf['type'] = 'string' + tf['format'] = 'date-time' + elif datatype == 'binary' or datatype == 'bytes': + # base64 encoded characters + tf['type'] = 'string' + tf['format'] = 'byte' + elif datatype == 'array' or datatype == 'boolean' \ + or datatype == 'integer' or datatype == 'string': + # no format + tf['type'] = datatype + elif datatype == 'float': + # number + tf['type'] = 'number' + tf['format'] = datatype + elif datatype == 'unicode' or datatype == 'str' \ + or datatype == 'text': + # primitive, no format + tf['type'] = 'string' + elif datatype == 'int' or datatype == 'decimal': + # primitive, no format + tf['type'] = 'integer' + elif datatype == 'bool': + # primitive, no format + tf['type'] = 'boolean' + elif datatype == 'enum': + tf['type'] = 'enum' + elif datatype == 'unset' or datatype == 'none': + tf['type'] = None + elif datatype == 'dict': + tf['type'] = 'object' + else: + tf['$ref'] = '#/definitions/' + datatype + return tf + + def conv_class_name_to_type_str(cn): + type_str = '' + if cn.endswith('Type'): + type_str = cn[:-4] + elif cn == 'str': + type_str = 'string' + else: + type_str = cn + type_str = type_str + return type_str + + def class_to_name_str(c): + return (('%s' % c).replace('<', '').replace('>', '') + .replace('class ', '').replace('\'', '') + .split(' ', 1)[0].rsplit('.', 1)[-1]) + + return datatype_to_type_and_format(conv_class_name_to_type_str(class_to_name_str(t))) + + +def add_definitions(t, m): + """将定义的类添加到all_definitions.""" + + if not all_definitions.get(m.__name__): + d = {} + d['type'] = t + d['properties'] = {} + for i, j in inspect.getmembers(m): + if not i.endswith('__'): + d['properties'][i] = format_type(j) + all_definitions[m.__name__] = d + + +def combine_all_definitions(): + """合并自定义和wsexpose解析出的definitions.""" + + for i in all_definitions: + if not _definitions.get(i): + _definitions[i] = all_definitions[i] + + return _definitions diff --git a/examples/industrial-ai-apiserver/pecan_swagger/utils.py b/examples/industrial-ai-apiserver/pecan_swagger/utils.py index 32ffa39cf351decc225f3ef526fa1244fb645b2d..57b322adb53d75a0c056ec088bb1d59013ffad34 100644 --- a/examples/industrial-ai-apiserver/pecan_swagger/utils.py +++ b/examples/industrial-ai-apiserver/pecan_swagger/utils.py @@ -1,4 +1,6 @@ from pecan_swagger import g as g +import json +import yaml """ utility function module @@ -12,20 +14,13 @@ swagger_build -- build a full swagger dictionary """ -def swagger_build(title, version, description=None, termsOfService=None, contact=None, license=None): +def swagger_build(title, version): swag = dict() swag['swagger'] = '2.0' - swag['info'] = dict(title=title, - version=version, - description=description, - termsOfService=termsOfService, - contact=contact, - license=license) + swag['info'] = dict(title=title, version=version) swag['consumes'] = [] swag['produces'] = [] swag['paths'] = {} - swag['host'] = [] - swag['basePath'] = [] swag['tags'] = [] swag['schemes'] = [] for p in g.get_paths(): @@ -34,10 +29,50 @@ def swagger_build(title, version, description=None, termsOfService=None, contact elif len(p[1]) > 0: swag['paths'][p[0]].update(_tuple_to_dict(p[1])) swag['definitions'] = g._definitions - swag['externalDocs'] = [] return swag +def print_json(s, output_path): + json_str = json.dumps(s, indent=4) + f = open(output_path, "w") + f.write(json_str) + f.close() + + +def print_yaml(s, output_path): + yaml_str = yaml.dump(s, indent=4) + f = open(output_path, "w") + f.write(yaml_str) + f.close() + + +def add_info(s, description=None, terms_of_service=None, contact=None, license=None): + if description is not None: + s['info']['description'] = description + if terms_of_service is not None: + s['info']['termsOfService'] = terms_of_service + if contact is not None: + s['info']['contact'] = contact + if license is not None: + s['info']['license'] = license + return s + + +def add_external_docs(s, external_docs): + s["externalDocs"] = external_docs + return s + + +def add_host(s, host): + s["host"] = host + return s + + +def add_base_path(s, basepath): + s["basePath"] = basepath + return s + + def _tuple_to_dict(tpl): """Convert tuple to dictionary