【问题标题】:PyRal getAttachmentPyRal 获取附件
【发布时间】:2018-04-23 15:31:52
【问题描述】:

我有一个相当简单的用例,但我不理解收到的错误消息。

我正在使用 requests 和 pyral 模块,pyral (http://pyral.readthedocs.io/en/latest/interface.html#) 实际上只是 Rally 的 Restful api 的包装器。我的目标是从 Rally(CA 产品)UserStory 中获取文件(附件)并将其存储到本地文件系统中。

对于上下文,这是我的环境设置(验证 Rally 并创建一个对象)。我显然已经删除了身份验证信息。

from pyral import Rally, rallyWorkset

options = [arg for arg in sys.argv[1:] if arg.startswith('--')]
args = [arg for arg in sys.argv[1:] if arg not in options]
server, user, password, apikey, workspace, project = rallyWorkset(options)
rally = Rally(server='rally1.rallydev.com', 
user='**********', password='***********', 
          apikey="**************",
          workspace='**************', project='**************',
          server_ping=False)

之后,我只获得了一个用户故事的响应对象(请参阅 US845 的查询),我这样做只是为了简化问题。

r = rally.get('UserStory', fetch = True, projectScopeDown=True, query = 'FormattedID = US845')

然后我使用内置迭代器从 RallyRESTResponse 对象中获取用户故事。

us = r.next()

从那里感觉我应该能够轻松地使用接受工件(我们)和文件名(附件名称)的 getAttachment() 方法。我可以使用 getAttachmentNames(us) 返回附件名称列表。当我尝试类似的事情时,问题就出现了

attachment_names = rally.getAttachmentNames(us) #get attachments for this UserStory
attachment_file = rally.getAttachment(us, attachment_names[0]) #Try to get the first attachment 

返回这样的错误

Traceback (most recent call last):

File "<ipython-input-81-a4a342a59c5a>", line 1, in <module>
attachment_file = rally.getAttachment(us, attachment_names[0])

File "C:\Miniconda3\lib\site-packages\pyral\restapi.py", line 1700, in getAttachment
att.Content = base64.decodebytes(att_content.Content)  # maybe further txfm to Unicode ?

File "C:\Miniconda3\lib\base64.py", line 552, in decodebytes
_input_type_check(s)

File "C:\Miniconda3\lib\base64.py", line 520, in _input_type_check
raise TypeError(msg) from err

TypeError: expected bytes-like object, not str

如果我尝试使用,我会收到类似的错误

test_obj = rally.getAttachments(us)

返回如下错误:

Traceback (most recent call last):

File "<ipython-input-82-06a8cd525177>", line 1, in <module>
rally.getAttachments(us)

File "C:\Miniconda3\lib\site-packages\pyral\restapi.py", line 1721, in getAttachments
attachments = [self.getAttachment(artifact, attachment_name) for attachment_name in attachment_names]

File "C:\Miniconda3\lib\site-packages\pyral\restapi.py", line 1721, in <listcomp>
attachments = [self.getAttachment(artifact, attachment_name) for attachment_name in attachment_names]

File "C:\Miniconda3\lib\site-packages\pyral\restapi.py", line 1700, in getAttachment
att.Content = base64.decodebytes(att_content.Content)  # maybe further txfm to Unicode ?

File "C:\Miniconda3\lib\base64.py", line 552, in decodebytes
_input_type_check(s)

File "C:\Miniconda3\lib\base64.py", line 520, in _input_type_check
raise TypeError(msg) from err

TypeError: expected bytes-like object, not str

似乎我从根本上误解了这种方法所需的参数?有没有人能够成功地做到这一点?对于它的价值,我使用 addAttachment() 方法和上面类似的工作流程没有任何问题。我尝试使用 bytes() 方法将文件名(字符串)转换为 utf-8,但这没有帮助。

我也在 pyral 源代码中查看了这个示例,但在尝试执行该示例时收到完全相同的错误。

https://github.com/klehman-rally/pyral/blob/master/examples/get_attachments.py

【问题讨论】:

    标签: python web-services encode rally pyral


    【解决方案1】:

    看起来像 restapi.py 脚本中的问题 - base64 库中没有 decodebytes 方法:

    att.Content = base64.decodebytes(att_content.Content)
    

    所有可用的方法都在以下位置进行了描述: RFC 3548: Base16, Base32, Base64 Data Encodings 因此,解决方法是在restapi.py 中用base64.b64decode 替换decodebytes。至少,它对我有用。

    例如Mac OS X 上的位置:

    /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pyral/restapi.py
    

    【讨论】:

    • 我没想到问题可能出在模块本身而不是我 :)。感谢您的验证!我已经在 GitHub 上提交了一个问题。
    • 我也可以在 Python 2.7 和 Python 3.6 上使用 base64.b64decode(比我必须检查 Python 版本的解决方案更好)。
    • @sc305495 仅供参考,我已经创建了 Pyral 的一个分支,并纠正了该错误 (github.com/jfthuong/RallyRestToolkitForPython)。
    • @Jean-FrancoisT。谢谢,大帮助!对于提取 excel 文档(或任何文档)并将其存储在文件系统上,您有什么建议吗?我尝试使用 pickle.dump(.Content, , pickle.HIGHEST_PROTOCOL),但也许这是错误的方法?
    • 没关系:)。一个简单的 output = open('test.xlsx', 'wb) output.write(attachment_file.Content) 就可以了。再次感谢您的帮助!
    【解决方案2】:

    我已使用以下代码获取所有附件,因为 getAttachments 未按预期工作。它将在当前目录中创建一个同名的文件。

    import sys
    import string
    import base64
    from pyral import rallyWorkset, Rally,RallyRESTResponse
    
    rally = Rally(server, user=USER_NAME, password=PASSWORD, workspace=workspace, project=project)
    criterion = 'FormattedID = US57844'
    response = rally.get('HierarchicalRequirement',  query=criterion, order="FormattedID",pagesize=200, limit=400, projectScopeDown=True)
    
    artifact = response.next()
    context, augments = rally.contextHelper.identifyContext()
    for att in artifact.Attachments:
        resp = rally._getResourceByOID(context, 'AttachmentContent', att.Content.oid, project=None)
        if resp.status_code not in [200, 201, 202]:
            break
        res = RallyRESTResponse(rally.session, context, "AttachmentContent.x", resp, "full", 1)
        if res.errors or res.resultCount != 1:
            print("breaking the for loop")
        att_content = res.next()
        cont = att_content.Content
        x = base64.b64decode(cont)
        output = open(att.Name, 'wb') 
        output.write(x)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-02
      • 2017-10-23
      • 1970-01-01
      • 2011-10-11
      • 1970-01-01
      • 2015-04-15
      相关资源
      最近更新 更多