Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getAttachments only works for 2+ attachments #160

Closed
ElBarto221 opened this issue May 12, 2022 · 10 comments
Closed

getAttachments only works for 2+ attachments #160

ElBarto221 opened this issue May 12, 2022 · 10 comments

Comments

@ElBarto221
Copy link

Trying to fetch the attachments from a workitem with only one attachment results in

AttributeError: 'str' object has no attribute 'get'

Root cause seems to be this code line:

if isinstance(entries, OrderedDict):

If I change this to

if isinstance(entries, dict)

it works.

@dixudx
Copy link
Owner

dixudx commented May 12, 2022

Please help submit a PR. Thanks for your contribution.

@dixudx
Copy link
Owner

dixudx commented May 12, 2022

Actually OrderedDict is supposed to work.

@ElBarto221 Would you please help take more tests on this change? We need to make sure the new change works.

@ElBarto221
Copy link
Author

@dixudx Sure, what do you need me to test? Also, I just realized now that I got the getAttachments method to work, how do I get the actual attachment content?

@ElBarto221
Copy link
Author

Btw, we are using EWM 7.0.1 with form-based authentication.

@ElBarto221
Copy link
Author

Here's the stacktrace for OrderedDict - please note that the line numbers are shifted due to my debugging:


AttributeError Traceback (most recent call last)
Input In [6], in <cell line: 3>()
1 wk = rtcClient.getWorkitem(683480)
----> 3 attachments = wk.getAttachments()

File ~\Anaconda3\envs\rtc2jira\lib\site-packages\rtcclient\workitem.py:816, in Workitem.getAttachments(self)
813 attachment_tag = ("rtc_cm:com.ibm.team.workitem.linktype."
814 "attachment.attachment")
815 self.log.info("attachment_tag = %s", attachment_tag)
--> 816 return (self.rtc_obj._get_paged_resources(
817 "Attachment",
818 workitem_id=self.identifier,
819 customized_attr=attachment_tag,
820 page_size="10"))

File ~\Anaconda3\envs\rtc2jira\lib\site-packages\rtcclient\client.py:1441, in RTCClient._get_paged_resources(self, resource_name, projectarea_id, workitem_id, customized_attr, page_size, archived, returned_properties, filter_rule)
1436 # iterate all the entries
1437 with Pool() as p:
1438 resources_list = list(
1439 filter(
1440 None,
-> 1441 p.starmap(self._handle_resource_entry,
1442 [(resource_name, entry, pa_url, archived,
1443 filter_rule) for entry in entries])))
1445 # find the next page
1446 url_next = raw_data.get('oslc_cm:Collection').get('@oslc_cm:next')

File ~\Anaconda3\envs\rtc2jira\lib\multiprocessing\pool.py:372, in Pool.starmap(self, func, iterable, chunksize)
366 def starmap(self, func, iterable, chunksize=None):
367 '''
368 Like map() method but the elements of the iterable are expected to
369 be iterables as well and will be unpacked as arguments. Hence
370 func and (a, b) becomes func(a, b).
371 '''
--> 372 return self._map_async(func, iterable, starmapstar, chunksize).get()

File ~\Anaconda3\envs\rtc2jira\lib\multiprocessing\pool.py:771, in ApplyResult.get(self, timeout)
769 return self._value
770 else:
--> 771 raise self._value

File ~\Anaconda3\envs\rtc2jira\lib\multiprocessing\pool.py:125, in worker(inqueue, outqueue, initializer, initargs, maxtasks, wrap_exception)
123 job, i, func, args, kwds = task
124 try:
--> 125 result = (True, func(*args, **kwds))
126 except Exception as e:
127 if wrap_exception and func is not _helper_reraises_exception:

File ~\Anaconda3\envs\rtc2jira\lib\multiprocessing\pool.py:51, in starmapstar(args)
50 def starmapstar(args):
---> 51 return list(itertools.starmap(args[0], args[1]))

File ~\Anaconda3\envs\rtc2jira\lib\site-packages\rtcclient\client.py:1505, in RTCClient._handle_resource_entry(self, resource_name, entry, projectarea_url, archived, filter_rule)
1502 except AttributeError:
1503 pass
-> 1505 entry_archived = entry.get("rtc_cm:archived")
1506 if (entry_archived is not None and
1507 eval(entry_archived.capitalize()) != archived):
1508 return None

AttributeError: 'str' object has no attribute 'get

@dixudx
Copy link
Owner

dixudx commented May 12, 2022

Also, I just realized now that I got the getAttachments method to work, how do I get the actual attachment content?

>>> import pprint
# print the field alias
>>> pprint.pprint(myattachment.field_alias, width=1)

You will see all the attribute list, where you can find the content.

@ElBarto221
Copy link
Author

I tried this

wk.getAttachments()[0]["content"].get('@rdf:resource')

but it only gives me the URL. How can I then download the actual attachment content? If I try

rtcClient.get(attachments[0]["content"].get('@rdf:resource'))

it results in

ExpatError Traceback (most recent call last)
File ~\Anaconda3\envs\rtc2jira\lib\site-packages\rtcclient\utils.py:32, in token_expire_handler..wrapper(*args, **kwargs)
31 resp = func(*args, **kwargs)
---> 32 xmltodict.parse(resp.content)
33 return resp

File ~\Anaconda3\envs\rtc2jira\lib\site-packages\xmltodict.py:378, in parse(xml_input, encoding, expat, process_namespaces, namespace_separator, disable_entities, process_comments, **kwargs)
377 else:
--> 378 parser.Parse(xml_input, True)
379 return handler.item

ExpatError: not well-formed (invalid token): line 17, column 78

During handling of the above exception, another exception occurred:

TypeError Traceback (most recent call last)
Input In [12], in <cell line: 1>()
----> 1 print(rtcClient.get(attachments[0]["content"].get('@Rdf:resource')))

File ~\Anaconda3\envs\rtc2jira\lib\site-packages\rtcclient\utils.py:38, in token_expire_handler..wrapper(*args, **kwargs)
35 if "invalid token" in str(excp):
36 # expires
37 try:
---> 38 rtc_obj.relogin()
39 except RTCException:
40 raise RTCException("Relogin Failed: "
41 "Invalid username or password")

File ~\Anaconda3\envs\rtc2jira\lib\site-packages\rtcclient\client.py:111, in RTCClient.relogin(self)
106 def relogin(self):
107 """Relogin the RTC Server/Jazz when the token expires
108
109 """
--> 111 self.log.info("Cookie expires. Relogin to get a new cookie.")
112 self.headers = None
113 self.headers = self._get_headers()

TypeError: 'tuple' object is not callable

@dixudx
Copy link
Owner

dixudx commented Jul 18, 2022

If so, please use dict instead of OrderedDict.

#fixme: if isinstance(entries, OrderedDict):
if isinstance(entries, dict):

@dixudx
Copy link
Owner

dixudx commented Jul 24, 2022

@ElBarto221 I found this was due to the dependency xmltodict.

xmltodict 0.13.0 is buggy. xref martinblech/xmltodict#297

Please stick to older 0.12.0 version. pip install -U xmltodict==0.12.0.

@dixudx
Copy link
Owner

dixudx commented Mar 24, 2023

Please stick to older 0.12.0 version. pip install -U xmltodict==0.12.0

This has been fixed in #164.

Close it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants