def test_get_function_from_name_attr_error(monkeypatch): """ Test attribute error without import error on get_function_from_name. Attribute errors due to import errors are tested on test_api.test_invalid_operation_does_stop_application_to_setup """ deep_attr_mock = MagicMock() deep_attr_mock.side_effect = AttributeError monkeypatch.setattr("connexion.utils.deep_getattr", deep_attr_mock) with pytest.raises(AttributeError): utils.get_function_from_name('math.ceil')
def __init__(self, method: str, path: str, operation: dict, app_produces: list, app_security: list, security_definitions: dict, definitions: dict): """ This class uses the OperationID identify the module and function that will handle the operation From Swagger Specification: **OperationID** A friendly name for the operation. The id MUST be unique among all operations described in the API. Tools and libraries MAY use the operation id to uniquely identify an operation. :param method: HTTP method :param path: :param operation: swagger operation object """ self.method = method self.path = path self.security_definitions = security_definitions self.definitions = definitions self.operation = operation self.operation_id = operation['operationId'] # todo support definition references # todo support references to application level parameters self.parameters = operation.get('parameters', []) self.produces = operation.get('produces', app_produces) self.endpoint_name = flaskify_endpoint(self.operation_id) self.security = operation.get('security', app_security) self.__undecorated_function = get_function_from_name(self.operation_id)
def get_apikeyinfo_func(security_definition): """ :type security_definition: dict :rtype: function >>> get_apikeyinfo_func({'x-apikeyInfoFunc': 'foo.bar'}) '<function foo.bar>' """ func = (security_definition.get("x-apikeyInfoFunc") or os.environ.get('APIKEYINFO_FUNC')) if func: return get_function_from_name(func) return None
def get_bearerinfo_func(security_definition): """ :type security_definition: dict :rtype: function >>> get_bearerinfo_func({'x-bearerInfoFunc': 'foo.bar'}) '<function foo.bar>' """ func = (security_definition.get("x-bearerInfoFunc") or os.environ.get('BEARERINFO_FUNC')) if func: return get_function_from_name(func) return None
def get_scope_validate_func(security_definition): """ :type security_definition: dict :rtype: function >>> get_scope_validate_func({'x-scopeValidateFunc': 'foo.bar'}) '<function foo.bar>' """ func = (security_definition.get("x-scopeValidateFunc") or os.environ.get('SCOPEVALIDATE_FUNC')) if func: return get_function_from_name(func) return validate_scope
def main(argv=sys.argv[1:]): parser = argparse.ArgumentParser(description='Workflow Execution Service') parser.add_argument("--backend", type=str, default="wes_service.cwl_runner") parser.add_argument("--port", type=int, default=8080) parser.add_argument("--opt", type=str, action="append") args = parser.parse_args(argv) app = connexion.App(__name__) backend = utils.get_function_from_name(args.backend + ".create_backend")(args.opt) def rs(x): return getattr(backend, x) res = resource_stream(__name__, 'swagger/proto/workflow_execution_service.swagger.json') app.add_api(json.load(res), resolver=Resolver(rs)) app.run(port=args.port)
def get_tokeninfo_func(security_definition): """ :type security_definition: dict :rtype: function >>> get_tokeninfo_url({'x-tokenInfoFunc': 'foo.bar'}) '<function foo.bar>' """ token_info_func = (security_definition.get("x-tokenInfoFunc") or os.environ.get('TOKENINFO_FUNC')) if token_info_func: return get_function_from_name(token_info_func) token_info_url = (security_definition.get('x-tokenInfoUrl') or os.environ.get('TOKENINFO_URL')) if token_info_url: return functools.partial(get_tokeninfo_remote, token_info_url) return None
def __init__(self, method, path, operation, app_produces, app_security, security_definitions, definitions): """ This class uses the OperationID identify the module and function that will handle the operation From Swagger Specification: **OperationID** A friendly name for the operation. The id MUST be unique among all operations described in the API. Tools and libraries MAY use the operation id to uniquely identify an operation. :param method: HTTP method :type method: str :param path: :type path: str :param operation: swagger operation object :type operation: dict :param app_produces: list of content types the application can return by default :type app_produces: list :param app_security: list of security rules the application uses by default :type app_security: list :param security_definitions: `Security Definitions Object <https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#security-definitions-object>`_ :type security_definitions: dict :param definitions: `Definitions Object <https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#definitionsObject>`_ :type definitions: dict """ self.method = method self.path = path self.security_definitions = security_definitions self.definitions = definitions self.operation = operation self.operation_id = operation["operationId"] # todo support definition references # todo support references to application level parameters self.parameters = operation.get("parameters", []) self.produces = operation.get("produces", app_produces) self.endpoint_name = flaskify_endpoint(self.operation_id) self.security = operation.get("security", app_security) self.__undecorated_function = get_function_from_name(self.operation_id)
def call(func_str, *args, **kwargs): """Look up the function by controller.func string and call function. Function name specified as e.g.: - pcluster.cli.controllers.cluster_operations_controller.list_clusters Ignore status-codes on the command line as errors are handled through exceptions, but some functions return 202 which causes the return to be a tuple (instead of an object). Also uses the flask json-ifier to ensure data is converted the same as the API. """ query = kwargs.pop("query", None) func = get_function_from_name(func_str) ret = func(*args, **kwargs) if isinstance(ret, tuple): ret, status_code = ret if status_code >= 400: data = json.loads(encoder.JSONEncoder().encode(ret)) raise APIOperationException(data) data = json.loads(encoder.JSONEncoder().encode(ret)) return jmespath.search(query, data) if query else data
def test_get_function_from_name_no_module(): with pytest.raises(ValueError): utils.get_function_from_name('math')
def test_get_function_from_name_for_class_method(): function = utils.get_function_from_name('connexion.app.App.common_error_handler') assert function == connexion.app.App.common_error_handler
def test_get_function_from_name(): function = utils.get_function_from_name('math.ceil') assert function == math.ceil assert function(2.7) == 3
def test_get_function_from_name_for_class_method(): function = utils.get_function_from_name('connexion.FlaskApp.common_error_handler') assert function == connexion.FlaskApp.common_error_handler
spec = SpecBuilder()\ .add_spec(spec_path.joinpath("cm4.yaml")) \ .add_spec(spec_path.joinpath("vm.yaml")) \ .add_spec(spec_path.joinpath("flavor.yaml"))\ .add_spec(spec_path.joinpath("image.yaml")) options = {'swagger_path': swagger_ui_3_path} app = connexion.FlaskApp(__name__, specification_dir=spec_dir, options=options) # Inject the `controllers` namespace into `operationId`s specified in the spec # files. This allows for the (potentially many) controllers to be organized # into thier own folder and to potentially have multiple versions of the # controller classes in different folders. custom_resolver = Resolver(function_resolver=lambda fname: get_function_from_name(f"controllers.{fname}")) app.add_api(spec, resolver=custom_resolver) CORS(app.app) @app.route("/") def home(): return render_template("index.html") # Expose js, css, img static folders as if they were # root folders, not under `static/` because it's easier # than getting the JS app to rewrite all of the URLs to # include `static/`.