Pylons / pyramid_routehelper

Pyramid Route and View Handler Helpers
Other
10 stars 2 forks source link

Weirdness in config.add_route or zope.configuration #2

Open heshiming opened 13 years ago

heshiming commented 13 years ago

I'm playing with the current revision of pyramid_routehelper. Though all tests are okay, it can't be used in pyramid yet.

Currently, for each config.add_resource('proj.handlers.controllers:Controllers', 'controller', 'controllers'), it'll generate two sets of zope configuration conflict. Stack trace is as below:

Traceback (most recent call last):
  File "/env/bin/paster", line 8, in 
    load_entry_point('PasteScript==1.7.3', 'console_scripts', 'paster')()
  File "/env/lib/python2.6/site-packages/paste/script/command.py", line 84, in run
    invoke(command, command_name, options, args[1:])
...
  File "/env/lib/python2.6/site-packages/pyramid/config.py", line 491, in commit
    self._ctx.execute_actions()
  File "/env/lib/python2.6/site-packages/zope/configuration/config.py", line 620, in execute_actions
    for action in resolveConflicts(self.actions):
  File "/env/lib/python2.6/site-packages/zope/configuration/config.py", line 1527, in resolveConflicts
    raise ConfigurationConflictError(conflicts)
zope.configuration.config.ConfigurationConflictError: Conflicting configuration actions
  For: ('route', 'controller', False, None, None, None, None, None)
    ('/proj/handlers/__init__.py', 13, 'includeme', "config.add_resource('proj.handlers.controllers:Controllers', 'controller', 'controllers')")
    ('/proj/handlers/__init__.py', 13, 'includeme', "config.add_resource('proj.handlers.controllers:Controllers', 'controller', 'controllers')")
    ('/proj/handlers/__init__.py', 13, 'includeme', "config.add_resource('proj.handlers.controllers:Controllers', 'controller', 'controllers')")
  For: ('route', 'controllers', False, None, None, None, None, None)
    ('/proj/handlers/__init__.py', 13, 'includeme', "config.add_resource('proj.handlers.controllers:Controllers', 'controller', 'controllers')")
    ('/proj/handlers/__init__.py', 13, 'includeme', "config.add_resource('proj.handlers.controllers:Controllers', 'controller', 'controllers')")

Digging down, I discovered that because the create/index urls are the same /controllers, Configurator treated them as duplicates. The same happened with update/delete/show with url form /controllers/{id}.

I've been trying to get it working, so I changed add_route_and_view a little bit:

def add_route_and_view(self, action, route_name, path, request_method='any'):
    if request_method != 'any':
        request_method = request_method.upper()
    else:
        request_method = None

    for format_kwargs in action_kwargs.get(action, {}).get('formatted', []):
        format = format_kwargs.pop('format')
        self.add_route("%s_formatted_%s" % (format, route_name),
                       "%s.%s" % (path, format), request_method=request_method, **kwargs)
        self.add_view(view=handler, attr=format_kwargs.pop('attr'), request_method=request_method,
                      route_name = "%s_formatted_%s" % (format, route_name), **format_kwargs)

    self.add_route(route_name, path, request_method=request_method, **kwargs)
    self.add_view(view=handler, attr=action, route_name=route_name, request_method=request_method, **action_kwargs.get(action, {}).get('default', {}))
    if request_method in ['PUT', 'DELETE']:
        self.add_route(route_name + '_fallback', path, request_method='POST', request_param=('_method=' + request_method), **kwargs)
        self.add_view(view=handler, attr=action, route_name=route_name + '_fallback', request_method='POST', request_param=('_method=' + request_method), **action_kwargs.get(action, {}).get('default', {}))

I added request_method=request_method to add_route. Zope no longer treats the route as duplicates, and the app is up and running. Later on I discovered route matching is top-down, so I moved the format section up because otherwise .format will be a part of id. And I tried to simulate PUT/DELETE using '_method' in forms which is seen in Pylons 1.0.

It almost worked except for one thing, it didn't pass the test. The 3 failed tests are test_delete_member, test_post_collection, test_put_member. I checked, all these 3 requests failed with HTTP 404 error. If I enable route dispatch debugging in my app, I can see Pyramid complaining about no route to /controllers/id when doing POST (or PUT or DELETE, it wasn't the fault of my form emulation code).

I couldn't figure out a reason for this. Zope Configurator seemed to be only able to correctly find the route, when no request_method is specified. Yet, without request_method, there will be duplicates. Have I overlooked something simple here?

I'm dying to get this working and I'm happy to help in this project anyway I can.

heshiming commented 13 years ago

I've corrected this issue in my own fork: https://github.com/heshiming/pyramid_routehelper .