示例#1
0
    def test_decorate_view(self):
        def myfunction():
            pass

        meth = "POST"
        decorated = decorate_view(myfunction, {}, meth)
        self.assertEqual(decorated.__name__, "{0}__{1}".format(func_name(myfunction), meth))
示例#2
0
def register_service_views(config, service):
    """Register the routes of the given service into the pyramid router.

    :param config: the pyramid configuration object that will be populated.
    :param service: the service object containing the definitions
    """
    services = config.registry.setdefault("cornice_services", {})
    services[service.path] = service

    # keep track of the registered routes
    registered_routes = []

    # register the fallback view, which takes care of returning good error
    # messages to the user-agent
    for method, view, args in service.definitions:

        args = dict(args)  # make a copy of the dict to not modify it
        args["request_method"] = method

        decorated_view = decorate_view(view, dict(args), method)
        for item in ("filters", "validators", "schema", "klass"):
            if item in args:
                del args[item]

        # if acl is present, then convert it to a "factory"
        if "acl" in args:
            args["factory"] = make_route_factory(args.pop("acl"))

        route_args = {}
        if "factory" in args:
            route_args["factory"] = args.pop("factory")

        # register the route name with the path if it's not already done
        if service.path not in registered_routes:
            config.add_route(service.path, service.path, **route_args)
            config.add_view(view=get_fallback_view(service), route_name=service.path)
            registered_routes.append(service.path)

        # loop on the accept fields: we need to build custom predicate if
        # callables were passed
        if "accept" in args:
            for accept in to_list(args.pop("accept", ())):
                predicates = args.get("custom_predicates", [])
                if callable(accept):
                    predicate_checker = functools.partial(match_accept_header, accept)
                    predicates.append(predicate_checker)
                    args["custom_predicates"] = predicates
                else:
                    # otherwise it means that it is a "standard" accept,
                    # so add it as such.
                    args["accept"] = accept

                # We register multiple times the same view with different
                # accept / custom_predicates arguments
                config.add_view(view=decorated_view, route_name=service.path, **args)
        else:
            # it is a simple view, we don't need to loop on the definitions
            # and just add it one time.
            config.add_view(view=decorated_view, route_name=service.path, **args)
示例#3
0
    def test_decorate_view(self):
        def myfunction():
            pass

        meth = 'POST'
        decorated = decorate_view(myfunction, {}, meth)
        self.assertEqual(decorated.__name__, "{0}__{1}".format(
            func_name(myfunction), meth))
示例#4
0
    def test_decorate_view_acl(self):

        args = {'acl': 'dummy_permission', 'klass': DummyAPI}

        decorated_view = decorate_view('collection_get', args, 'GET')
        dummy_request = DummyRequest()
        ret = decorated_view(dummy_request)
        self.assertEqual(ret, ['douggy', 'rusty'])
        self.assertEqual(dummy_request, DummyAPI.last_request)
        self.assertIsNone(DummyAPI.last_context)
示例#5
0
    def test_decorate_view_factory(self):

        args = {"factory": u"TheFactoryMethodCalledByPyramid", "klass": DummyAPI}

        decorated_view = decorate_view("collection_get", args, "GET")
        dummy_request = DummyRequest()
        ret = decorated_view(dummy_request)
        self.assertEqual(ret, ["douggy", "rusty"])
        self.assertEqual(dummy_request, DummyAPI.last_request)
        self.assertEqual(dummy_request.context, DummyAPI.last_context)
示例#6
0
    def test_decorate_view_acl(self):

        args = {"acl": "dummy_permission", "klass": DummyAPI}

        decorated_view = decorate_view("collection_get", args, "GET")
        dummy_request = DummyRequest()
        ret = decorated_view(dummy_request)
        self.assertEqual(ret, ["douggy", "rusty"])
        self.assertEqual(dummy_request, DummyAPI.last_request)
        self.assertIsNone(DummyAPI.last_context)
示例#7
0
    def test_decorate_view_factory(self):

        args = {'factory': u'TheFactoryMethodCalledByPyramid',
                'klass': DummyAPI}

        decorated_view = decorate_view('collection_get', args, 'GET')
        dummy_request = DummyRequest()
        ret = decorated_view(dummy_request)
        self.assertEqual(ret, ['douggy', 'rusty'])
        self.assertEqual(dummy_request, DummyAPI.last_request)
        self.assertEqual(dummy_request.context, DummyAPI.last_context)
示例#8
0
    def test_decorate_resource_view(self):
        class MyResource(object):
            def __init__(self, **kwargs):
                pass

            def myview(self):
                pass

        meth = "POST"
        decorated = decorate_view(_UnboundView(MyResource, "myview"), {}, meth)
        self.assertEqual(decorated.__name__, "{0}__{1}".format(func_name(MyResource.myview), meth))
示例#9
0
    def test_decorate_view_factory(self):

        args = {'factory': u'TheFactoryMethodCalledByPyramid',
                'klass': DummyAPI}

        decorated_view = decorate_view('collection_get', args, 'GET')
        dummy_request = DummyRequest()
        ret = decorated_view(dummy_request)
        self.assertEqual(ret, ['douggy', 'rusty'])
        self.assertEqual(dummy_request, DummyAPI.last_request)
        self.assertEqual(dummy_request.context, DummyAPI.last_context)
示例#10
0
    def test_decorate_view_acl(self):

        args = {'acl': 'dummy_permission',
                'klass': DummyAPI}

        decorated_view = decorate_view('collection_get', args, 'GET')
        dummy_request = DummyRequest()
        ret = decorated_view(dummy_request)
        self.assertEqual(ret, ['douggy', 'rusty'])
        self.assertEqual(dummy_request, DummyAPI.last_request)
        self.assertIsNone(DummyAPI.last_context)
示例#11
0
    def test_decorate_resource_view(self):
        class MyResource(object):
            def __init__(self, **kwargs):
                pass

            def myview(self):
                pass

        meth = 'POST'
        decorated = decorate_view(_UnboundView(MyResource, 'myview'), {}, meth)
        self.assertEqual(decorated.__name__, "{0}__{1}".format(
            func_name(MyResource.myview), meth))
示例#12
0
def register_service_views(config, service):
    """Register the routes of the given service into the pyramid router.

    :param config: the pyramid configuration object that will be populated.
    :param service: the service object containing the definitions
    """
    route_name = service.name
    existing_route = service.pyramid_route
    prefix = config.route_prefix or ''
    services = config.registry.cornice_services
    if existing_route:
        route_name = existing_route
        services[prefix + '__cornice' + existing_route] = service
    else:
        services[prefix + service.path] = service

    # before doing anything else, register a view for the OPTIONS method
    # if we need to
    if service.cors_enabled and 'OPTIONS' not in service.defined_methods:
        service.add_view('options', view=get_cors_preflight_view(service),
                         permission=NO_PERMISSION_REQUIRED)

    # register the fallback view, which takes care of returning good error
    # messages to the user-agent
    cors_validator = get_cors_validator(service)

    # Cornice-specific arguments that pyramid does not know about
    cornice_parameters = ('filters', 'validators', 'schema', 'klass',
                          'error_handler') + CORS_PARAMETERS

    # 1. register route

    route_args = {}

    if hasattr(service, 'factory'):
        route_args['factory'] = service.factory

    routes = config.get_predlist('route')
    for predicate in routes.sorter.names:
        # Do not let the custom predicates handle validation of Header Accept,
        # which will pass it through to pyramid. It is handled by
        # _fallback_view(), because it allows callable.
        if predicate == 'accept':
            continue

        if hasattr(service, predicate):
            route_args[predicate] = getattr(service, predicate)

    # register route when not using exiting pyramid routes
    if not existing_route:
        config.add_route(route_name, service.path, **route_args)

    # 2. register view(s)

    for method, view, args in service.definitions:

        args = copy.copy(args)  # make a copy of the dict to not modify it
        # Deepcopy only the params we're possibly passing on to pyramid
        # (Some of those in cornice_parameters, e.g. ``schema``, may contain
        # unpickleable values.)
        for item in args:
            if item not in cornice_parameters:
                args[item] = copy.deepcopy(args[item])

        args['request_method'] = method

        if service.cors_enabled:
            args['validators'].insert(0, cors_validator)

        decorated_view = decorate_view(view, dict(args), method, route_args)

        for item in cornice_parameters:
            if item in args:
                del args[item]

        # filter predicates defined on Resource
        route_predicates = config.get_predlist('route').sorter.names
        view_predicates = config.get_predlist('view').sorter.names
        for pred in set(route_predicates).difference(view_predicates):
            if pred in args:
                args.pop(pred)

        # pop and compute predicates which get passed through to Pyramid 1:1

        predicate_definitions = _pop_complex_predicates(args)

        if predicate_definitions:
            empty_contenttype = [({'kind': 'content_type', 'value': ''},)]
            for predicate_list in predicate_definitions + empty_contenttype:
                args = dict(args)  # make a copy of the dict to not modify it

                # prepare view args by evaluating complex predicates
                _mungle_view_args(args, predicate_list)

                # We register the same view multiple times with different
                # accept / content_type / custom_predicates arguments
                config.add_view(view=decorated_view, route_name=route_name,
                                **args)

        else:
            # it is a simple view, we don't need to loop on the definitions
            # and just add it one time.
            config.add_view(view=decorated_view, route_name=route_name,
                            **args)

    if service.definitions:
        # Add the fallback view last
        config.add_view(view=get_fallback_view(service),
                        route_name=route_name,
                        permission=NO_PERMISSION_REQUIRED,
                        require_csrf=False)
示例#13
0
def register_service_views(config, service):
    """Register the routes of the given service into the pyramid router.

    :param config: the pyramid configuration object that will be populated.
    :param service: the service object containing the definitions
    """
    services = config.registry.setdefault('cornice_services', {})
    services[service.path] = service

    # keep track of the registered routes
    registered_routes = []

    # before doing anything else, register a view for the OPTIONS method
    # if we need to
    if service.cors_enabled and 'OPTIONS' not in service.defined_methods:
        service.add_view('options', view=get_cors_preflight_view(service))

    # register the fallback view, which takes care of returning good error
    # messages to the user-agent
    cors_validator = get_cors_validator(service)

    for method, view, args in service.definitions:

        args = copy.deepcopy(args)  # make a copy of the dict to not modify it
        args['request_method'] = method

        if service.cors_enabled:
            args['validators'].insert(0, cors_validator)

        decorated_view = decorate_view(view, dict(args), method)

        for item in ('filters', 'validators', 'schema', 'klass',
                     'error_handler') + CORS_PARAMETERS:
            if item in args:
                del args[item]

        # if acl is present, then convert it to a "factory"
        if 'acl' in args:
            args["factory"] = make_route_factory(args.pop('acl'))


        # 1. register route

        route_args = {}
        if 'factory' in args:
            route_args['factory'] = args.pop('factory')

        # register the route name with the path if it's not already done
        if service.path not in registered_routes:
            config.add_route(service.name, service.path, **route_args)
            config.add_view(view=get_fallback_view(service),
                            route_name=service.name)
            registered_routes.append(service.path)
            config.commit()


        # 2. register view(s)

        # pop and compute predicates which get passed through to Pyramid 1:1
        predicate_definitions = _pop_complex_predicates(args)

        if predicate_definitions:
            for predicate_list in predicate_definitions:
                args = dict(args)  # make a copy of the dict to not modify it

                # prepare view args by evaluating complex predicates
                _mungle_view_args(args, predicate_list)

                # We register the same view multiple times with different
                # accept / content_type / custom_predicates arguments
                config.add_view(view=decorated_view, route_name=service.name,
                            **args)

        else:
            # it is a simple view, we don't need to loop on the definitions
            # and just add it one time.
            config.add_view(view=decorated_view, route_name=service.name,
                            **args)

        config.commit()
示例#14
0
def register_service_views(config, service):
    """Register the routes of the given service into the pyramid router.

    :param config: the pyramid configuration object that will be populated.
    :param service: the service object containing the definitions
    """
    route_name = service.name
    services = config.registry.cornice_services
    prefix = config.route_prefix or ''
    services[prefix + service.path] = service

    # before doing anything else, register a view for the OPTIONS method
    # if we need to
    if service.cors_enabled and 'OPTIONS' not in service.defined_methods:
        service.add_view('options', view=get_cors_preflight_view(service),
                         permission=NO_PERMISSION_REQUIRED)

    # register the fallback view, which takes care of returning good error
    # messages to the user-agent
    cors_validator = get_cors_validator(service)

    # Cornice-specific arguments that pyramid does not know about
    cornice_parameters = ('filters', 'validators', 'schema', 'klass',
                          'error_handler', 'deserializer') + CORS_PARAMETERS

    # 1. register route

    route_args = {}

    if hasattr(service, 'acl'):
        route_args['factory'] = make_route_factory(service.acl)

    elif hasattr(service, 'factory'):
        route_args['factory'] = service.factory

    if hasattr(service, 'traverse'):
        route_args['traverse'] = service.traverse

    config.add_route(route_name, service.path, **route_args)

    # 2. register view(s)

    for method, view, args in service.definitions:

        args = copy.copy(args)  # make a copy of the dict to not modify it
        # Deepcopy only the params we're possibly passing on to pyramid
        # (Some of those in cornice_parameters, e.g. ``schema``, may contain
        # unpickleable values.)
        for item in args:
            if item not in cornice_parameters:
                args[item] = copy.deepcopy(args[item])

        args['request_method'] = method

        if service.cors_enabled:
            args['validators'].insert(0, cors_validator)

        decorated_view = decorate_view(view, dict(args), method)

        for item in cornice_parameters:
            if item in args:
                del args[item]

        # These attributes are used in routes not views
        deprecated_attrs = ['acl', 'factory', 'traverse']
        for attr in deprecated_attrs:
            if attr in args:
                args.pop(attr)

        # pop and compute predicates which get passed through to Pyramid 1:1

        predicate_definitions = _pop_complex_predicates(args)

        if predicate_definitions:
            for predicate_list in predicate_definitions:
                args = dict(args)  # make a copy of the dict to not modify it

                # prepare view args by evaluating complex predicates
                _mungle_view_args(args, predicate_list)

                # We register the same view multiple times with different
                # accept / content_type / custom_predicates arguments
                config.add_view(view=decorated_view, route_name=route_name,
                                **args)

        else:
            # it is a simple view, we don't need to loop on the definitions
            # and just add it one time.
            config.add_view(view=decorated_view, route_name=route_name,
                            **args)

        config.commit()

    if service.definitions:
        # Add the fallback view last
        config.add_view(view=get_fallback_view(service),
                        route_name=route_name,
                        permission=NO_PERMISSION_REQUIRED)
        config.commit()
示例#15
0
def register_service_views(config, service):
    """Register the routes of the given service into the pyramid router.

    :param config: the pyramid configuration object that will be populated.
    :param service: the service object containing the definitions
    """
    services = config.registry.setdefault('cornice_services', {})
    services[service.path] = service

    # keep track of the registered routes
    registered_routes = []

    # before doing anything else, register a view for the OPTIONS method
    # if we need to
    if service.cors_enabled and 'OPTIONS' not in service.defined_methods:
        service.add_view('options', view=get_cors_preflight_view(service))

    # register the fallback view, which takes care of returning good error
    # messages to the user-agent
    cors_validator = get_cors_validator(service)
    cors_filter = get_cors_filter(service)

    for method, view, args in service.definitions:

        args = copy.deepcopy(args)  # make a copy of the dict to not modify it
        args['request_method'] = method

        if service.cors_enabled:
            args['validators'].insert(0, cors_validator)
            args['filters'].append(cors_filter)

        decorated_view = decorate_view(view, dict(args), method)

        for item in ('filters', 'validators', 'schema', 'klass',
                     'error_handler') + CORS_PARAMETERS:
            if item in args:
                del args[item]

        # if acl is present, then convert it to a "factory"
        if 'acl' in args:
            args["factory"] = make_route_factory(args.pop('acl'))

        route_args = {}
        if 'factory' in args:
            route_args['factory'] = args.pop('factory')

        # register the route name with the path if it's not already done
        if service.path not in registered_routes:
            config.add_route(service.path, service.path, **route_args)
            config.add_view(view=get_fallback_view(service),
                            route_name=service.path)
            registered_routes.append(service.path)

        # loop on the accept fields: we need to build custom predicate if
        # callables were passed
        if 'accept' in args:
            for accept in to_list(args.pop('accept', ())):
                predicates = args.get('custom_predicates', [])
                if callable(accept):
                    predicate_checker = functools.partial(match_accept_header,
                                                          accept)
                    predicates.append(predicate_checker)
                    args['custom_predicates'] = predicates
                else:
                    # otherwise it means that it is a "standard" accept,
                    # so add it as such.
                    args['accept'] = accept

                # We register multiple times the same view with different
                # accept / custom_predicates arguments
                config.add_view(view=decorated_view, route_name=service.path,
                                **args)
        else:
            # it is a simple view, we don't need to loop on the definitions
            # and just add it one time.
            config.add_view(view=decorated_view, route_name=service.path,
                            **args)
示例#16
0
def register_service_views(config, service):
    """Register the routes of the given service into the pyramid router.

    :param config: the pyramid configuration object that will be populated.
    :param service: the service object containing the definitions
    """
    services = config.registry.setdefault('cornice_services', {})
    services[service.path] = service

    # keep track of the registered routes
    registered_routes = []

    # register the fallback view, which takes care of returning good error
    # messages to the user-agent
    for method, view, args in service.definitions:

        args = dict(args)  # make a copy of the dict to not modify it
        args['request_method'] = method

        decorated_view = decorate_view(view, dict(args), method)
        for item in ('filters', 'validators', 'schema', 'klass',
                     'error_handler'):
            if item in args:
                del args[item]

        # if acl is present, then convert it to a "factory"
        if 'acl' in args:
            args["factory"] = make_route_factory(args.pop('acl'))

        route_args = {}
        if 'factory' in args:
            route_args['factory'] = args.pop('factory')

        # register the route name with the path if it's not already done
        if service.path not in registered_routes:
            config.add_route(service.path, service.path, **route_args)
            config.add_view(view=get_fallback_view(service),
                            route_name=service.path)
            registered_routes.append(service.path)

        # loop on the accept fields: we need to build custom predicate if
        # callables were passed
        if 'accept' in args:
            for accept in to_list(args.pop('accept', ())):
                predicates = args.get('custom_predicates', [])
                if callable(accept):
                    predicate_checker = functools.partial(match_accept_header,
                                                          accept)
                    predicates.append(predicate_checker)
                    args['custom_predicates'] = predicates
                else:
                    # otherwise it means that it is a "standard" accept,
                    # so add it as such.
                    args['accept'] = accept

                # We register multiple times the same view with different
                # accept / custom_predicates arguments
                config.add_view(view=decorated_view, route_name=service.path,
                                **args)
        else:
            # it is a simple view, we don't need to loop on the definitions
            # and just add it one time.
            config.add_view(view=decorated_view, route_name=service.path,
                            **args)
示例#17
0
def register_service_views(config, service):
    """Register the routes of the given service into the pyramid router.

    :param config: the pyramid configuration object that will be populated.
    :param service: the service object containing the definitions
    """
    services = config.registry.setdefault('cornice_services', {})
    prefix = config.route_prefix or ''
    services[prefix + service.path] = service

    # keep track of the registered routes
    registered_routes = []

    # before doing anything else, register a view for the OPTIONS method
    # if we need to
    if service.cors_enabled and 'OPTIONS' not in service.defined_methods:
        service.add_view('options', view=get_cors_preflight_view(service))

    # register the fallback view, which takes care of returning good error
    # messages to the user-agent
    cors_validator = get_cors_validator(service)

    # Cornice-specific arguments that pyramid does not know about
    cornice_parameters = ('filters', 'validators', 'schema', 'klass',
                          'error_handler', 'deserializer') + CORS_PARAMETERS

    for method, view, args in service.definitions:

        args = copy.copy(args)  # make a copy of the dict to not modify it
        # Deepcopy only the params we're possibly passing on to pyramid
        # (Some of those in cornice_parameters, e.g. ``schema``, may contain
        # unpickleable values.)
        for item in args:
            if item not in cornice_parameters:
                args[item] = copy.deepcopy(args[item])

        args['request_method'] = method

        if service.cors_enabled:
            args['validators'].insert(0, cors_validator)

        decorated_view = decorate_view(view, dict(args), method)

        for item in cornice_parameters:
            if item in args:
                del args[item]

        # if acl is present, then convert it to a "factory"
        if 'acl' in args:
            args["factory"] = make_route_factory(args.pop('acl'))

        # 1. register route
        route_args = {}
        if 'factory' in args:
            route_args['factory'] = args.pop('factory')

        if 'traverse' in args:
            route_args['traverse'] = args.pop('traverse')

        # register the route name with the path if it's not already done
        if service.path not in registered_routes:
            config.add_route(service.name, service.path, **route_args)
            config.add_view(view=get_fallback_view(service),
                            route_name=service.name)
            registered_routes.append(service.path)
            config.commit()

        # 2. register view(s)
        # pop and compute predicates which get passed through to Pyramid 1:1

        predicate_definitions = _pop_complex_predicates(args)

        if predicate_definitions:
            for predicate_list in predicate_definitions:
                args = dict(args)  # make a copy of the dict to not modify it

                # prepare view args by evaluating complex predicates
                _mungle_view_args(args, predicate_list)

                # We register the same view multiple times with different
                # accept / content_type / custom_predicates arguments
                config.add_view(view=decorated_view,
                                route_name=service.name,
                                **args)

        else:
            # it is a simple view, we don't need to loop on the definitions
            # and just add it one time.
            config.add_view(view=decorated_view,
                            route_name=service.name,
                            **args)

        config.commit()
示例#18
0
def register_service_views(config, service):
    """Register the routes of the given service into the pyramid router.

    :param config: the pyramid configuration object that will be populated.
    :param service: the service object containing the definitions
    """
    route_name = service.name
    services = config.registry.cornice_services
    prefix = config.route_prefix or ''
    services[prefix + service.path] = service

    # before doing anything else, register a view for the OPTIONS method
    # if we need to
    if service.cors_enabled and 'OPTIONS' not in service.defined_methods:
        service.add_view('options',
                         view=get_cors_preflight_view(service),
                         permission=NO_PERMISSION_REQUIRED)

    # register the fallback view, which takes care of returning good error
    # messages to the user-agent
    cors_validator = get_cors_validator(service)

    # Cornice-specific arguments that pyramid does not know about
    cornice_parameters = ('filters', 'validators', 'schema', 'klass',
                          'error_handler', 'deserializer') + CORS_PARAMETERS

    # 1. register route

    route_args = {}

    if hasattr(service, 'acl'):
        route_args['factory'] = make_route_factory(service.acl)

    elif hasattr(service, 'factory'):
        route_args['factory'] = service.factory

    if hasattr(service, 'traverse'):
        route_args['traverse'] = service.traverse

    routes = config.get_predlist('route')
    for predicate in routes.sorter.names:
        if hasattr(service, predicate):
            route_args[predicate] = getattr(service, predicate)

    config.add_route(route_name, service.path, **route_args)

    # 2. register view(s)

    for method, view, args in service.definitions:

        args = copy.copy(args)  # make a copy of the dict to not modify it
        # Deepcopy only the params we're possibly passing on to pyramid
        # (Some of those in cornice_parameters, e.g. ``schema``, may contain
        # unpickleable values.)
        for item in args:
            if item not in cornice_parameters:
                args[item] = copy.deepcopy(args[item])

        args['request_method'] = method

        if service.cors_enabled:
            args['validators'].insert(0, cors_validator)

        decorated_view = decorate_view(view, dict(args), method)

        for item in cornice_parameters:
            if item in args:
                del args[item]

        # These attributes are used in routes not views
        deprecated_attrs = ['acl', 'factory', 'traverse']
        for attr in deprecated_attrs:
            if attr in args:
                args.pop(attr)

        # filter predicates defined on Resource
        route_predicates = config.get_predlist('route').sorter.names
        view_predicates = config.get_predlist('view').sorter.names
        for pred in set(route_predicates).difference(view_predicates):
            if pred in args:
                args.pop(pred)

        # pop and compute predicates which get passed through to Pyramid 1:1

        predicate_definitions = _pop_complex_predicates(args)

        if predicate_definitions:
            for predicate_list in predicate_definitions:
                args = dict(args)  # make a copy of the dict to not modify it

                # prepare view args by evaluating complex predicates
                _mungle_view_args(args, predicate_list)

                # We register the same view multiple times with different
                # accept / content_type / custom_predicates arguments
                config.add_view(view=decorated_view,
                                route_name=route_name,
                                **args)

        else:
            # it is a simple view, we don't need to loop on the definitions
            # and just add it one time.
            config.add_view(view=decorated_view, route_name=route_name, **args)

        config.commit()

    if service.definitions:
        # Add the fallback view last
        config.add_view(view=get_fallback_view(service),
                        route_name=route_name,
                        permission=NO_PERMISSION_REQUIRED)
        config.commit()