简体   繁体   中英

passing function into a class and using it as a decorator of class methods

first I created some user management functions I want to use everywhere, and bound them to cherrypy, thinking I could import cherrypy elsewhere and they would be there. Other functions seem to import fine this way, when not used as decorators.

from user import validuser
cherrypy.validuser = validuser
del validuser

that didn't work, so next I tried passing the function into the class that is a section of my cherrypy site ( /analyze ) from the top level class of pages:

class Root:
    analyze = Analyze(cherrypy.validuser) #maps to /analyze

And in the Analyze class, I referred to them. This works for normal functions but not for decorators. why not?

class Analyze:

    def __init__(self, validuser):
        self.validuser = validuser

    @cherrypy.expose
    @self.validuser(['uid'])
    def index(self, **kw):        
        return analysis_panel.pick_data_sets(user_id=kw['uid'])

I'm stuck. How can I pass functions in and use them as decorators. I'd rather not wrap my functions like this:

    return self.validuser(analysis_panel.pick_data_sets(user_id=kw['uid']),['uid'])

thanks.

ADDED/EDITED: here's what the decorator is doing, because as a separate issue, I don't think it is properly adding user_id into the kwargs

def validuser(old_function, fetch=['uid']):
    def new_function(*args, **kw):
        "... do stuff. decide is USER is logged in. return USER id or -1 ..."
        if USER != -1 and 'uid' in fetch:
            kw['uid'] = user_data['fc_uid']
        return old_function(*args, **kw)
    return new_function

only the kwargs that were passed in appear in the kwargs for the new_function. Anything I try to add isn't there. (what I'm doing appears to work here How can I pass a variable in a decorator to function's argument in a decorated function? )

The proper way in CherryPy to handle a situation like this is to have a tool and to enable that tool on the parts of your site that require authentication. Consider first creating this user-auth tool:

@cherrypy.tools.register('before_handler')
def validate_user():
    if USER == -1:
        return
    cherrypy.request.uid = user_data['fc_uid']

Note that the 'register' decorator was added in CherryPy 5.5.0 .

Then, wherever you wish to validate the user, either decorate the handler with the tool:

class Analyze:

    @cherrypy.expose
    @cherrypy.tools.validate_user()
    def index(self):
        return analysis_panel.pick_data_sets(user_id=cherrypy.request.uid)

Or in your cherrypy config, enable that tool:

config = {
    '/analyze': {
        'tools.validate_user.on': True,
    },
}

The function/method is defined in the class, it doesn't make sense to decorate it with an instance variable because it won't be the same decorator for each instance.

You may consider using a property to create the decorated method when it is accessed:

@property
def index(self):
    @cherrypy.expose
    @self.validuser(['uid'])
    def wrapped_index(**kw):
        return analysis_panel.pick_data_sets(user_id=kw['uid'])
    return wrapped_index

You may also consider trying to apply lru_cache to save the method for each instance but I'm not sure how to apply that with the property.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM