I have created a class based AWS lambda function in python called requestHandler.py as below
from action_dispatcher import ActionDispatcher
class RequestHandler(ActionDispatcher):
#staticmethod
def createTemplate(event, context):
return "Hello world"
My action_dispatcher.py is as shown below.
import json
class ActionDispatcher(object):
def __call__(self, event, context, *args, **kwargs):
action = event.get('action')
handler = getattr(self, action, None)
if handler is None:
return json.loads({'status': 'error', 'code': 404, 'message':"Action {0} not found.".format(action) })
return handler(request, *args, **kwargs)
With this above setup and lambda handler as requestHandler.RequestHandler, i get error "RequestHandler() takes no arguments" in this case i create action as createTemplate. so i want to call this method from RequestHandler.
It looks to me like you are trying to call your class instead of an instance of the class. RequestHandler() will call the __init__ method to initialize an instance of the class. Since you haven't defined the method it doesn't take any arguments. To access __call__ you need to call an instance of your class.
handler = RequestHandler()
result = handler(request, context, *args, **kwargs)
You can only define a handler in python using def handler(event, context):. However, I found a package that allows you to call the handler as a class
Usage, as noted in their documentation, is as follows:
pip install aws-lambda-handler
import aws_lambda
class EchoHandler(aws_lambda.Handler):
"""Echo handler."""
def perform(self, request, **k):
"""Echo perform method."""
response = aws_lambda.Response()
response.body = self.request.event
return response
echo_handler = EchoHandler()
# `echo_handler` is now a callable function you can map your AWS Lambda function to
The solution for my problem was simple, as mentioned by jacinator, i should try with class instance.
earlier for lambda handler, i used pass class as handler, now i am passing the instance of the class as handler.
Added the line in requestHandler.py rhandler = RequestHandler()
So previously my lambda handler was like requestHandler.RequestHandler, now it has been changed to requestHandler.rhandler.
Related
1. My Requirements
The Decorator Class should use functools.wraps so it has proper introspection and organization for later.
Access to the decorated instance should be possible.
In the example below, I do it by passing a wrapped_self argument to the __call__ method.
As the title states, the Decorator Class must have parameters that you can tune for for each method.
2. An Example of What It Would Look Like
The ideal situation should look something like this:
class A():
def __init__(self):
...
#LoggerDecorator(logger_name='test.log')
def do_something(self):
...
with the Decorator Class being, so far (basic logger decorator based on a recipe coming from David Beazley's Python Cookbook):
class LoggerDecorator():
def __init__(self, func, logger_name):
wraps(func)(self)
self.logger_name = logger_name
def config_logger(self):
... # for example, uses `self.logger_name` to configure the decorator
def __call__(self, wrapped_self, *args, **kwargs):
self.config_logger()
wrapped_self.logger = self.logger
func_to_return = self.__wrapped__(wrapped_self, *args, **kwargs)
return func_to_return
def __get__(self, instance, cls):
if instance is None:
return self
else:
return types.MethodType(self, instance)
3. How Do I Fix It?
The error I'm getting refers to __init__ not recognizing a third argument apparently:
TypeError: __init__() missing 1 required positional argument: 'func'
It has been suggested to me that I should be putting func in the __call__ method. However, if I put it there as a parameter, wrapped_self isn't properly read as a parameter and I get this error:
__call__() missing 1 required positional argument: 'wrapped_self'
I've tried many things to fix this issue, including: putting wraps(func)(self) inside __call__; and many variations of this very close but not quite filling all of the requirements solution (the problem with it is that I can't seem to be able to access wrapped_self anymore).
Since you're implementing a decorator that takes parameters, the __init__ method of LoggerDecorator should take only the parameters that configures the decorator, while the __call__ method instead should become the actual decorator that returns a wrapper function:
class LoggerDecorator():
def __init__(self, logger_name):
self.logger_name = logger_name
self.config_logger()
def __call__(self, func):
#wraps(func)
def wrapper(wrapped_self, *args, **kwargs):
wrapped_self.logger = self.logger
func_to_return = func(wrapped_self, *args, **kwargs)
return func_to_return
return wrapper
from functools import wraps
class LoggerDecorator:
def __init__(self, logger):
self.logger = logger
def __call__(self, func, *args, **kwargs):
print func, args, kwargs
# do processing
return func
#LoggerDecorator('lala')
def a():
print 1
The above should work as expected. If you're planning to call the decorator using keyword arguments you can remove the logger from __init__ and use **kwargs which will return a dict of the passed keywork arguments.
I have a decorator that I use on a class method. However I would like to use the same decorator but as a wrapper instead.
For instance this is how I use the decorator:
myDecorators.py
def authenticate(method):
def authenticate_and_call(service_instance, *args, **kwargs):
print("Authentification success")
#access to service_instance is needed in the decorator
print(service_instance.config)
return method(service_instance, *args, **kwargs)
return authenticate_and_call
myClass.py
from myDecorators import authenticate
class MyService:
def __init__(self, config):
self.config = config
#authenticate #I dont want to use a decorator here
def execute(self):
print(self.config)
print("MyService is executed with authentication")
What I would like to do is something like:
service_callers.py
from myClass import MyService
from myDecorators import authenticate
#use the decorator as a wrapper
def execute_service_with_authentification():
service = MyService({"foo":"bar"})
authenticate(service.execute)(service)
execute_service_with_authentification()
This returns the following error:
File "c:\temp\test\myDecorators.py", line 4, in authenticate_and_call
return method(service_instance, *args, **kwargs)
TypeError: execute() takes exactly 1 argument (2 given)
First remove the #authenticate decorator from your MyService.execute definiton. Then when you need to use the authenticate decorator just wrap your call as: authenticate(service.execute)().
Make sure you change your decorator as well - you're not passing the first argument as self:
def authenticate(method):
def authenticate_and_call(*args, **kwargs):
print("Attempting authentication on object: {}".format(method.__self__))
return method(*args, **kwargs)
return authenticate_and_call
In a class based view, HTTP methods map to class method names. Below, defined a handler for GET requests with the get method and url called get method. My question is how did the url map to the get method?
url(r'^hello-world/$', MyView.as_view(), name='hello_world'),
class MyView(View):
def get(self, request, *args, **kwargs):
return HttpResponse("Hello, World")
The url doesn't map to the get method, it maps to the view. Its up to the request method to guide django in the right way.
If you're talking in terms of actual code, its the dispatch method on the view.
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
Why not have a look at the code.
http://ccbv.co.uk/projects/Django/1.10/django.views.generic.base/View/
You will see the as_view() method (which gets called in your urls.py) has at line 67:
return self.dispatch(request, *args, **kwargs)
The dispatch() method in turn calls get in line 85 (assuming it is a GET request):
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
I'm building a rate-limiting decorator in flask using redis stores that will recognize different limits on different endpoints. (I realize there are a number of rate-limiting decorators out there, but my use case is different enough that it made sense to roll my own.)
Basically the issue I'm having is ensuring that the keys I store in redis are class-specific. I'm using the blueprint pattern in flask, which basically works like this:
class SomeEndpoint(MethodView):
def get(self):
# Respond to get request
def post(self):
# Respond to post request
The issue here is that I want to be able to rate limit the post method of these classes without adding any additional naming conventions. In my mind the best way to do this would be something like this:
class SomeEndpoint(MethodView):
#RateLimit # Access SomeEndpoint class name
def post(self):
# Some response
but within the decorator, only the post function is in scope. How would I get back to the SomeEndpoint class given the post function? This is the basic layout of the decorator. That might be confusing, so here's a more concrete example of the decorator.
class RateLimit(object):
"""
The base decorator for app-specific rate-limiting.
"""
def __call__(self, f):
def endpoint(*args, **kwargs):
print class_backtrack(f) # Should print SomeEnpoint
return f(*args, **kwargs)
return endpoint
basically looking for what that class_backtrack function looks like. I've looked through the inspect module, but I haven't found anything that seems to accomplish this.
You can decorate the entire class instead of just the methods:
def wrap(Class, method):
def wrapper(self, *args, **kwargs):
print Class
return method(self, *args, **kwargs)
return method.__class__(wrapper, None, Class)
def rate_limit(*methods):
def decorator(Class):
for method_name in methods:
method = getattr(Class, method_name)
setattr(Class, method_name, wrap(Class, method))
return Class
return decorator
#rate_limit('post')
class SomeEndpoint(object):
def post(self):
pass
class Subclass(SomeEndpoint):
pass
a = Subclass()
a.post()
# prints <class 'SomeEndpoint'>
Is there a way to internally pass on the handling of a request from one RequestHandler subclass to another? Basically, what I would like to do is, from the get method of a RequestHandler (well, a subclass of RequestHandler), dispatch the task of handling the request to another handler (subclass of RequestHandler), whose name is determined by a value fetched from the datastore (I'm using GAE, but that is irrelevant to this problem). The code would look something like this:
class Dispatcher(RequestHandler):
def get_handler(some_id):
handler_name = get_handler_name(some_id) # fetches from datastore/etc.
return getattr(my_module, handler_name)
def get(self, some_id, *args, **kwargs):
handler = get_handler(some_id) # e.g., handler could be a HandlerA
# Not a real function, just to describe what to do:
# invokes get method of HandlerA (if handler == HandlerA)
dispatch_to_handler(handler, self, *args, **kwargs)
def post(self, some_id):
handler = get_handler(some_id)
dispatch_to_handler(....) # dispatches to post method of the handler
class HandlerA(RequestHandler):
def get(self, *args, **kwargs):
do_stuff()
def post(...):
do_post_stuff()
The big issue is that I need to somehow pass self and the positional and keyword arguments on to the other handler (HandlerA in this example), as self contains the request, response, session, authentication, and other data, which HandlerA (or whatever the handler may be) needs in order to process the request.
Try it this way:
def get(self, some_id, *args, **kwargs)
handler_cls = get_handler(some_id)
handler = handler_cls(self.request, self.response)
return handler.dispatch()