Klein routers share too much state between class- and instance-level copies
A use-case to set the stage:
I want to generalize my approach to handle_errors and sub-routes. This means I want to do something like:
@attr.s
class RootAPI:
remoteErrorHandlerConfig = attr.ib()
router = Klein()
@router.route("/subroute", branch=True)
def subroute(self, request):
domainObject = SubAPI()
subRouter = domainObject.router
subRouter.handle_errors(Exception)(
lambda other, request, failure: self.errorHandler(request, failure)
)
return subRouter.resource()
Then I want to test this thing.
The problem is that SubAPI.router, another Klein object, shares mutable state with all other instance router objects, due to this code. Rather than doing k._error_handlers = self._error_handlers[:], we do k._error_handlers = self._error_handlers.
Perhaps the existing state-sharing behavior has to be preserved for compatibility, but:
- the attributes aren't exposed as settable via a constructor, so I can't create a new
Kleinmyself - the construction of the URL map is class-scope, so there's no way to pull in the work the
@routedecorator does without re-writing it completely myself - some of these attributes are (inconsistently!) private, which means even if I had a constructor where I could pass them, I can't retrieve the thing I want to pass.
There should be some way to derive a bound Klein object from an existing Klein object which doesn't share state and can be configured on a per-instance basis, so that my dependency-injected remoteErrorHandlerConfig can be passed along.
I feel like your use case needs a little more use-y-ness…
Indeed.
⌘Enter is just too inviting a key combination, so I posted this bug way too early. Does the updated summary make sense?
I've run into some interesting oddness when using multiple routers in one app, and found the class/instance copy stuff and the weak references use to make some CONFUSION happen that I couldn't understand, but I left with an impression that makes your title seem correct to me. :-)
Aha! Had to reload to see it. OK cool.
cc @euresti