如何编写装饰器并返回经过身份验证的对象

时间:2016-01-20 21:09:52

标签: python python-2.7 python-3.x jira

我正在编写自动化脚本,通过jira python库向Jira添加一些bug。

我在一个文件中有我的用户名和密码,我想确保每次调用一个函数(添加/修改一个bug)都会被验证。

基本上我想写一个装饰器。但是这个装饰器将返回一个jira对象,每个函数都应该使用它。以下是我要写的函数。

def return_authed_jira():
    options = {'server': 'https://jira.xxxxyyzzz.com'}
    authed_jira = JIRA(options,  basic_auth=('my_uname', my_passwd))
    return authed_jira

有没有办法可以使用装饰器来做到这一点。再说一遍,我知道如果不使用装饰器我可以做到不同,但我想用装饰器做这件事。

我自己尝试过编写它,但我见过的大多数示例都没有返回对象。

这就是我的尝试。

def authenticate(func):

    def authenticate_and_call(*args, **kwargs):

        options = {'server': 'https://jira.xxxxxxx.com', 'verify': False}
        jira = JIRA(options)
        if not jira.current_user() == 'uname':
            options = {'server': 'https://jira.xxxxxx.com', 'verify': False}
            jira = JIRA(options, basic_auth=('uname', passwd))
            args.append(jira)
        return func(*args, **kwargs)
    return authenticate_and_call

这里我试图附加jira对象,但这不起作用。

这是我想要的。将jira对象添加到args不会使函数轻松访问。这与登录装饰器类似,如果您尝试访问需要用户登录的页面,则将装饰器添加到服务页面的功能中。

@authenticate
def create_new_jira_bug(jira_fields):

    new_issue = jira.create_issue(jira_fields)
    print new_issue.id

以下是Blckknght回答问题并做出一些修改后的新代码。

def authenticate(func):

    def authenticate_and_call(*args, **kwargs):

        options = {'server': 'https://jira.xyz.com', 'verify': False}
        jira = JIRA(options)
        if not jira.current_user() == 'uname':
            options = {'server': 'https://jira.xyz.com', 'verify': False}
            jira = JIRA(options, basic_auth=(uname, password))
        return func(*args, jira=jira, **kwargs)
    return authenticate_and_call

@authenticate
def list_projects():

    my_issue = jira.issue('MYKEY-1289')
    print (my_issue.raw.get('fields'))

list_projects()

以下是我没有将jira添加到list_projects函数时得到的错误

Traceback (most recent call last):
  File "C:/testjira.py", line 44, in <module>
    list_projects()
  File "C:testjira.py", line 33, in authenticate_and_call
    return func(*args, jira=jira, **kwargs)
TypeError: list_projects() takes no arguments (1 given)

我的问题是我必须将jira对象传递给调用装饰器之前的函数,否则我会收到此错误。有替代方案吗?它可以正常使用下面的代码。我试图得到一个解释,为什么我必须在定义函数时传递对象,当我在调用函数时不必传递该对象。

@authenticate
def list_projects(jira):

    my_issue = jira.issue('MYKEY-1289')
    print (my_issue.raw.get('fields'))

list_projects()

1 个答案:

答案 0 :(得分:1)

你不能appendargs,因为它是一个元组,而不是一个列表。要添加值,您需要创建一个值为concatenated的新元组:

args = args + (jira,)

注意(jira,)末尾的逗号,必须使它成为1元组,而不是简单的括号表达式。

您还需要设置要装饰的函数以期望jira参数:

@authenticate
def create_new_jira_bug(jira_fields, jira): # expects jira arg from decorator
    new_issue = jira.create_issue(jira_fields)
    print new_issue.id

请注意,我没有为jira提供默认值。您的当前代码仅在某些时候将jira参数添加到args,如果jira是必需参数,则该参数不起作用。总是从装饰器中传入它可能更有意义。

为装饰器调用添加关键字参数可能更自然,而不是额外的位置参数。这将要求您正在装饰的所有函数对装饰器传递的jira对象使用相同的名称,但它不会干扰它们对其他关键字参数的处理。将位置参数添加到现有的末尾(正如您当前所做的那样)可能会使用关键字参数来中断调用。以下是使用关键字的装饰器的外观:

def authenticate(func):
    def authenticate_and_call(*args, **kwargs):
        options = {'server': 'https://jira.xxxxxxx.com', 'verify': False}

        jira = JIRA(options)
        if not jira.current_user() == 'uname':
            jira = JIRA(options, basic_auth=('uname', passwd))

        return func(*args, jira=jira, **kwargs)

    return authenticate_and_call

这将适用于上述功能,但不会干扰如下调用:

 create_new_jira_bug(jira_fields={"foo": "bar"})