ˑc$FdZddlmZddlZddlZddlZddlmZddlZddl Z ddl m Z m Z ddl mZddlmZe jeZdZejer eejd <d Zd Zd Zd ZddddddddZGddZdLdZ dMdNd"ZdOd&Z dPd)Z!dQd,Z"dRd/Z#ed0ed1d2Z$dSd5Z%dTd7Z&dUd9Z'dVd;Z(dWd?Z)dXdBZ*dYdGZ+dZdJZ,d[dKZ-dS)\z Query Debian's Bug Tracking System (BTS). This module provides a layer between Python and Debian's BTS. It provides methods to query the BTS using the BTS' SOAP interface, and the Bugreport class which represents a bugreport from the BTS. ) annotationsN)datetime)AnyIterable) SoapClient)SimpleXMLElementz/etc/ssl/ca-debian SSL_CERT_DIRz(https://bugs.debian.org/cgi-bin/soap.cgizDebbugs/SOAP/V1zhttps://bugs.debian.org/i)criticalgraveserious importantnormalminorwishlistcZeZdZdZddZddZdd Zdd Zdd Zdd Z ddZ ddZ ddZ dS) BugreportaRepresents a bugreport from Debian's Bug Tracking System. A bugreport object provides all attributes provided by the SOAP interface. Most of the attributes are strings, the others are marked. Attributes ---------- bug_num : int The bugnumber severity : str Severity of the bugreport tags : list[str] Tags of the bugreport subject : str The subject/title of the bugreport originator : str Submitter of the bugreport mergedwith : list[int] List of bugnumbers this bug was merged with package : str Package of the bugreport source : str Source package of the bugreport date : datetime Date of bug creation log_modified : datetime Date of update of the bugreport done : boolean Is the bug fixed or not done_by : str | None Name and Email or None archived : bool Is the bug archived or not unarchived : bool Was the bug unarchived or not fixed_versions : list[str] List of versions, can be empty even if bug is fixed found_versions : list[str] List of version numbers where bug was found forwarded : str A URL or email address blocks: list[int] List of bugnumbers this bug blocks blockedby : list[int] List of bugnumbers which block this bug pending : str Either 'pending' or 'done' msgid : str Message ID of the bugreport owner : str Who took responsibility for fixing this bug location : str Either 'db-h' or 'archive' affects : list[str] List of Packagenames summary : str Arbitrary text returnNonecj|||||||||||||||||||||||||dSN)selfs 5/usr/lib/python3/dist-packages/debianbts/debianbts.py__init__zBugreport.__init__rs           "   & &  !    #     strcxdd|jD}|dzS)N c3*K|]\}}|d|VdS)z: Nr).0keyvalues r z$Bugreport.__str__..sE  ",#us  e        r")join__dict__items)rss r __str__zBugreport.__str__sJ II  04 0C0C0E0E     4xr"otherboolcV||kS)aCompare a bugreport with another. The more open and urgent a bug is, the greater the bug is: outstanding > resolved > archived critical > grave > serious > important > normal > minor > wishlist. Openness always beats urgency, eg an archived bug is *always* smaller than an outstanding bug. This sorting is useful for displaying bugreports in a list and sorting them in a useful way.  _get_valuerr0s r __lt__zBugreport.__lt__s%   5#3#3#5#555r"c.|| Sr)__gt__r5s r __le__zBugreport.__le__;;u%%%%r"cV||kSrr3r5s r r8zBugreport.__gt__s#  5#3#3#5#555r"c.|| Sr)r6r5s r __ge__zBugreport.__ge__r:r"objectct|tstS||kSr) isinstancerNotImplementedr4r5s r __eq__zBugreport.__eq__s;%++ "! !  E$4$4$6$666r"cft|tstS|| Sr)r@rrArBr5s r __ne__zBugreport.__ne__s/%++ "! !;;u%%%%r"intc\|jrd}n |jrd}nd}|t|jz }|S)Nr )archiveddone SEVERITIESseverity)rvals r r4zBugreport._get_valuesA = CC Y CCC z$-(( r"N)rr)rr#)r0rrr1)r0r>rr1)rrE) __name__ __module__ __qualname____doc__r!r/r6r9r8r=rBrDr4rr"r rr6s99vD 6666$&&&&6666&&&&7777 &&&&      r"rnrs!int | list[int] | tuple[int, ...]rlist[Bugreport]ct|ttfs|g}nt|}t}g}t dt |t D]}|||t z}td}td||| d|}|d pgD]>}| d} | t| ?|S)a Returns a list of Bugreport objects. Given a list of bug numbers this method returns a list of Bugreport objects. Parameters ---------- nrs The bugnumbers Returns ------- list[Bugreport] list of Bugreport objects rzarg0 get_status s-gensym3r) r@listtuple_build_soap_clientrangelen BATCH_SIZEr_build_int_array_elcallchildrenappend _parse_status) rRnumbers soap_clientbugsislice_ method_elreply bug_item_elbug_els r rWrWs( cD%= ) )%s))%&&K D 1c'llJ / / / /1z>)*%%@AA FIv666  y99 5--6688>B / /K ))++A.F KK f-- . . . . / Kr"emailr#tags"None | list[str] | tuple[str, ...]dict[str, list[int]]c |g}td|g|R}|d}i}|d}|rk|jdkr`|pgD]H}t |d}|d}d|pgD||<InP|pgD]9}|}d |pgD||<:|S) a3Get buglists by usertags. Parameters ---------- email tags If tags are given the dictionary is limited to the matching tags, if no tags are given all available tags are returned. Returns ------- dict[str, list[int]] a mapping of usertag -> buglist N get_usertagrXxsi:typez apachens:Mapr(r)c,g|]}t|SrrEr'bugs r zget_usertag..LLLCHHLLLr"c,g|]}t|Srrurvs r rxzget_usertag..ryr")_soap_client_call attributesgetr)rar#get_name) rmrnrjmap_elmapping type_attr usertag_eltag buglist_els r rrrrsG& | mU :T : : :E U;  FG !!##'' 33IMY_66 //++1r M MJjj''((C#G,,JLL 0C0C0E0E0KLLLGCLL M !//++1r M MJ%%''CLL 0C0C0E0E0KLLLGCLL Nr"nrrE>list[dict[str, str | list[Any] | int | email.message.Message]]ctd|}|d}g}|D]}i}t|d}t|d}t|d}g} tjtjj} | | | d| | | } |||| | d}| ||S) aGet Buglogs. A buglog is a dictionary with the following mappings: * "header" => string * "body" => string * "attachments" => list * "msg_num" => int * "message" => email.message.Message Parameters ---------- nr the bugnumber Returns ------- list[dict[str, str | list[Any] | int | email.message.Message]] list of buglogs get_bug_log soapenc:Arrayheaderbodymsg_num)policys )rrr attachmentsmessage) r{ra_parse_string_elrErm feedparserBytesFeedParserrSMTPfeedencodecloserb) rrjitems_elbuglogs buglog_elbuglogrrrr mail_parserrs r rr!sN. mR 0 0Eu_%%HG&&(( KM!))H"5"566 & 1 122ii **++!# &66<$7   )))!!!'''##%%&    v Nr"amount list[int]cxtd|}|d}d|pgDS)a9Returns the newest bugs. This method can be used to query the BTS for the n newest bugs. Parameters ---------- amount the number of desired bugs. E.g. if `amount` is 10 the method will return the 10 latest bugs. Returns ------- list[int] the bugnumbers newest_bugsrc,g|]}t|Srrur'item_els r rxznewest_bugs..j B B BWCLL B B Br")r{ra)rrjrs r rrWsG" mV 4 4Eu_%%H B B(9(9(;(;(Ar B B BBr"kwargsstr | int | list[int]c g}|D]\}}|||gtd}t|D][\}}dt |z}t |t tfrt|||E| ||\t}| d|} | d} d| pgDS)aGet list of bugs matching certain criteria. The conditions are defined by the keyword arguments. Arguments --------- kwargs Possible keywords are: * "package": bugs for the given package * "submitter": bugs from the submitter * "maint": bugs belonging to a maintainer * "src": bugs belonging to a source package * "severity": bugs with a certain severity * "status": can be either "done", "forwarded", or "open" * "tag": see http://www.debian.org/Bugs/Developer#tags for available tags * "owner": bugs which are assigned to `owner` * "bugs": takes single int or list of bugnumbers, filters the list according to given criteria * "correspondent": bugs where `correspondent` has sent a mail to * "archive": takes a string: "0" (unarchived), "1" (archived) or "both" (un- and archived). if omitted, only returns un-archived bugs. Returns ------- list[int] the bugnumbers Examples -------- >>> get_bugs(package='gtk-qt-engine', severity='normal') [12345, 23456] zargget_bugsrc,g|]}t|Srrurs r rxzget_bugs..rr") r-extendr enumerater#r@rYrZr_marshallr[r`ra) rargskvriarg_nkvarg_namererjrs r rrmsP D 1 QF !!899It__-- r3u::% b4- ( ( - )R 8 8 8 8   x , , , ,$&&K   Z 3 3Eu_%%H B B(9(9(;(;(Ar B B BBr"rlrc vt}dD])}t||t||*tjt |d|_tjt |d|_dt|d D|_ t|d|_ |j rt|dnd|_ t|d|_t|d |_t!|d |_d t|d  D|_d t|d D|_dt|d D|_d|dpgD|_d|dpgD|_dt|d dD}d|D|_|S)zReturn a bugreport object from a given status xml element Parameters ---------- bug_el a status XML element Returns ------- Bugreport a Bugreport object ) originatorsubjectmsgidpackagerLownersummarylocationsourcepending forwardeddate log_modifiedcg|]}|Srr)r'rs r rxz!_parse_status..s;;;;;;r"rnrJNrI unarchivedbug_numc,g|]}t|Srrur'rgs r rxz!_parse_status..sHHHc!ffHHHr" mergedwithc,g|]}t|Srrurs r rxz!_parse_status..sFFFSVVFFFr" blockedbyc,g|]}t|Srrurs r rxz!_parse_status..s@@@Q#a&&@@@r"blocksc,g|]}t|Srr#r'els r rxz!_parse_status..+Br"found_versionsc,g|]}t|Srrrs r rxz!_parse_status..rr"fixed_versionscg|]}||Srr)r'_fs r rxz!_parse_status..sDDDbDrDDDr"affects,c6g|]}|Sr)strip)r'as r rxz!_parse_status..s ...17799...r")rsetattrrrutcfromtimestampfloatrrr#splitrn _parse_boolrJdone_byrIrrErrrrrarrr)rlrwfieldrs r rcrcs ++C  = = U,VVE]];;<<<<(vvf~~)>)>??CH0vvn7M7M1N1NOOC;;s66&>>2288::;;;CH66&>>**CH69hH"66&>>222DCKvvj1122CL  !5!566CNffY''((CKHHc&&*>*>&?&?&E&E&G&GHHHCNFFS )<)<%=%=%C%C%E%EFFFCM@@#ffX&6&6"7"7"="="?"?@@@CJ &!122;;==CC &!122;;==CCEDCy 1 12288==DDDG..g...CK Jr"soap)raction namespacesoap_ns proxy_argrc|td<dS)zSet proxy for SOAP client. You must use this method after import to set the proxy. Parameters ---------- proxy_arg proxyN_soap_client_kwargs)rs r set_soap_proxyrs$-   r"urlc|td<dS)zSet location URL for SOAP client You may use this method after import to override the default URL. Parameters ---------- url default URL rNr)rs r set_soap_locationrs'* ###r"dict[str, str]ctS)zlReturns SOAP client kwargs. Returns ------- dict[str, str] the SOAP client kwargs rrr"r get_soap_client_kwargsr s  r"rc$tditS)zFactory method that creates a SoapClient. For thread-safety we create SoapClients on demand instead of using a module-level one. Returns ------- SoapClient a SoapClient instance r)rrrr"r r[r[s  , ,+ , ,,r"r Iterable[Any]list[tuple[str, Any]]cg}t|D],\}}|dt|z|f-|S)aqConvert arguments to be consumed by a SoapClient method Parameters ---------- *args any argument Returns ------- list[tuple[str, Any]] the converted arguments Examples -------- Soap client required a list of named arguments: >>> _convert_soap_method_args('a', 1) [('arg0', 'a'), ('arg1', 1)] r)rrbr#)r soap_argsrrs r _convert_soap_method_argsr(sO*Ioo44 s%#e**,c23333 r" method_namercVt}t|}t|||S)zWrapper to call SoapClient method Parameters ---------- method_name the method name *args Returns ------- Any )r[rgetattr)rrrers r r{r{Cs0%&&K)40I ,7; , ,i 88r"el_nameparentlist_ list[Any]cT||}|dd|dd|ddt|dd|D];}|d t|}|dd <|S) zBuild Array as child of parent. More specifically: Build a soapenc:Array made of ints called `el_name` as a child of `parent`. Parameters ---------- el_name parent list Returns ------- SimpleXMLElement z xmlns:soapencz)http://schemas.xmlsoap.org/soap/encoding/rsrzsoapenc:arrayTypezxsd:int[d]itemzxsd:int) add_child add_attributer]r#)rrrrrrs r r_r_Ws*   ' " "BDZ111(*DSZZ*D*D*D*DEEE55,,vs4yy11j)4444 Ir"rr1cLt|}|dvS)zParse a boolean value from a XML element. Parameters ---------- el the element to parse Returns ------- bool the parsed value )r0)r#r)rr)s r rrxs" GGE{{}} ))r"ct|}|d}|r6|jdkr+t j|}|dd}|S)zRead a string element, maybe encoded in base64. Parameters ---------- el the element to parse Returns ------- str the parsed value rszxsd:base64Binaryzutf-8replace)errors)r#r|r}r)base64 b64decodedecode)rr)el_typetmps r rrsi GGEmmoo!!*--G67=$666u%% 79 55 Lr")rRrSrrTr)rmr#rnrorrp)rrErr)rrErr)rrrr)rlrrr)rr#rr)rr#rr)rr)rr)rrrr)rr#rrrr)rr#rrrrrr)rrrr1)rrrr#).rQ __future__rr email.feedparserrm email.policyrosloggingtypingrrpysimplesoap.clientrpysimplesoap.simplexmlr getLoggerrNloggerca_pathpathisdirenvironURLNSBTS_URLr^rKrrWrrrrrrcrrrrr[rr{r_rrrr"r rs#"""""   ******333333  8 $ $ 7==)!(BJ~ 1 $     TTTTTTTTn''''X04'''''T3333lCCCC,:C:C:C:Cz====B  - - - - * * * *     - - - -69999(B****$r"