0

I have to create a decorator that has parameters, and uses those parameters to modify a function also with parameters. This is a general question of how to decorate any function with parameters with additional parameters, but for my specific case, I need it for Django RQ, to determine based on an environment variable whether to use an asynchronous queue that is activated through a decorator.

There is a function in Django RQ called django_rq.job that I use like this (it requires args and kwargs):

@django_rq.job('default', timeout=3600, result_ttl=86400)
def upload_missing_documents_s3(batches, projects, uuid_val):
   pass

# A simpler example:
@django_rq.job('default', timeout=3600, result_ttl=86400)
def sample(content):
    file = open("temp/sample.txt", "w+")
    file.write(content)
    file.close()

I need to essentially create a decorator that will take a boolean value and return either the modified function (with a job) or the unmodified function (no job). But I can't seem to figure it out, because there are two sets of parameters. I tried something like this:

#My attempt, I don't think it works...
def conditional_django_job(function_name, *args, **kwargs):
    if settings.NO_QUEUE:
        return function_name
    else:
        return django_rq.job("default", None, *args, **kwargs)(function_name)

@conditional_django_job('default', timeout=3600, result_ttl=86400)
def sample(content):
    file = open("temp/sample.txt", "w+")
    file.write(content)
    file.close()

I also tried with an inner function, but I can't seem to get it right. How do I implement a decorator with parameters that decorates a function?

I tried looking at this SO question but it didn't seem to have an example where both the decorator and the function have parameters: How to make function decorators and chain them together?

Thank you!

Jonathan Ma
  • 556
  • 6
  • 20

1 Answers1

1

Hm, I think I got it after some time. Crazy how writing out a question can help answer that question.

I think this is the solution:

def conditional_django_job(*args, **kwargs):
    def real_decorator(func):
        try:
            if settings.NO_QUEUE:
                print("Returning ordinary func")
                return func
            else:
                print("Returning queued func")
                return django_rq.job(*args, **kwargs)(func)
        except:
            print("Put NO_QUEUE boolean in env variable. Returning ordinary func")
            return func
    return real_decorator
Jonathan Ma
  • 556
  • 6
  • 20