
    ˑc$F                       d Z ddlmZ ddlZddlZddlZddlmZ ddlZddl	Z	ddl
mZmZ ddlmZ ddlmZ  e	j        e          ZdZej                            e          r
eej        d	<   d
ZdZdZdZddddddddZ G d d          ZdLdZ	 dMdNd"ZdOd&Z dPd)Z!dQd,Z"dRd/Z#ed0ed1d2Z$dSd5Z%dTd7Z&dUd9Z'dVd;Z(dWd?Z)dXdBZ*dYdGZ+dZdJZ,d[dKZ-dS )\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)AnyIterable)
SoapClient)SimpleXMLElementz/etc/ssl/ca-debianSSL_CERT_DIRz(https://bugs.debian.org/cgi-bin/soap.cgizDebbugs/SOAP/V1zhttps://bugs.debian.org/i                       )criticalgraveserious	importantnormalminorwishlistc                  Z    e Zd ZdZddZddZdd	Zdd
ZddZddZ	ddZ
ddZddZdS )	Bugreporta  Represents 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
    returnNonec                j    |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  d S N )selfs    5/usr/lib/python3/dist-packages/debianbts/debianbts.py__init__zBugreport.__init__r   s     "&&!#    strc                x    d                     d | j                                        D                       }|dz   S )N
c              3  *   K   | ]\  }}| d | V  dS )z: Nr   ).0keyvalues      r    	<genexpr>z$Bugreport.__str__.<locals>.<genexpr>   sE       
 
",#use
 
 
 
 
 
r"   )join__dict__items)r   ss     r    __str__zBugreport.__str__   sJ    II 
 
040C0C0E0E
 
 
 
 
 4xr"   otherboolc                V    |                                  |                                 k     S )a  Compare 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_valuer   r0   s     r    __lt__zBugreport.__lt__   s%        5#3#3#5#555r"   c                .    |                      |           S r   )__gt__r5   s     r    __le__zBugreport.__le__       ;;u%%%%r"   c                V    |                                  |                                 k    S r   r3   r5   s     r    r8   zBugreport.__gt__   s#      5#3#3#5#555r"   c                .    |                      |           S r   )r6   r5   s     r    __ge__zBugreport.__ge__   r:   r"   objectc                    t          |t                    st          S |                                 |                                k    S r   )
isinstancer   NotImplementedr4   r5   s     r    __eq__zBugreport.__eq__   s;    %++ 	"!!  E$4$4$6$666r"   c                f    t          |t                    st          S |                     |           S r   )r@   r   rA   rB   r5   s     r    __ne__zBugreport.__ne__   s/    %++ 	"!!;;u%%%%r"   intc                \    | j         rd}n| j        rd}nd}|t          | j                 z  }|S )Nr   
      )archiveddone
SEVERITIESseverity)r   vals     r    r4   zBugreport._get_value   sA    = 	CCY 	CC Cz$-((
r"   N)r   r   )r   r#   )r0   r   r   r1   )r0   r>   r   r1   )r   rE   )__name__
__module____qualname____doc__r!   r/   r6   r9   r8   r=   rB   rD   r4   r   r"   r    r   r   6   s        9 9v   D   6 6 6 6$& & & &6 6 6 6& & & &7 7 7 7
& & & &
     r"   r   nrs!int | list[int] | tuple[int, ...]r   list[Bugreport]c                   t          | t          t          f          s| g}nt          |           }t                      }g }t	          dt          |          t                    D ]}|||t          z            }t          d          }t          d||           |	                    d|          } |d          
                                pg D ]>}|
                                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

    r   z<get_status></get_status>arg0
get_status	s-gensym3r   )r@   listtuple_build_soap_clientrangelen
BATCH_SIZEr   _build_int_array_elcallchildrenappend_parse_status)
rR   numberssoap_clientbugsislice_	method_elreplybug_item_elbug_els
             r    rW   rW      s   ( cD%=)) %s)) %&&KD1c'llJ// 	/ 	/1z>)* %%@AA	FIv666  y99 5--6688>B 	/ 	/K ))++A.FKKf--....	/ Kr"   emailr#   tags"None | list[str] | tuple[str, ...]dict[str, list[int]]c                   |g }t          d| g|R  } |d          }i }|                                                    d          }|rk|j        dk    r`|                                pg D ]H}t           |d                    } |d          }d |                                pg D             ||<   InP|                                pg D ]9}|                                }d	 |                                pg D             ||<   :|S )
a3  Get 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_usertagrX   xsi:typezapachens:Mapr(   r)   c                ,    g | ]}t          |          S r   rE   r'   bugs     r    
<listcomp>zget_usertag.<locals>.<listcomp>      LLLCHHLLLr"   c                ,    g | ]}t          |          S r   ru   rv   s     r    rx   zget_usertag.<locals>.<listcomp>  ry   r"   )_soap_client_call
attributesgetr)   ra   r#   get_name)	rm   rn   rj   map_elmapping	type_attr
usertag_eltag
buglist_els	            r    rr   rr      sG   & |mU:T:::EU;FG
 !!##''
33I MY_66 //++1r 	M 	MJjj''((C#G,,JLL
0C0C0E0E0KLLLGCLL	M
 !//++1r 	M 	MJ%%''CLL
0C0C0E0E0KLLLGCLLNr"   nrrE   >list[dict[str, str | list[Any] | int | email.message.Message]]c                   t          d|           } |d          }g }|                                D ]}i }t           |d                    }t           |d                    }t           |d                    }g }	t          j                            t          j        j                  }
|
	                    |
                                           |
	                    d           |
	                    |
                                           |
                                }||||	|d}|                    |           |S )	a  Get 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:Arrayheaderbodymsg_num)policys   

)r   r   r   attachmentsmessage)r{   ra   _parse_string_elrE   rm   
feedparserBytesFeedParserr   SMTPfeedencodecloserb   )r   rj   items_elbuglogs	buglog_elbuglogr   r   r   r   mail_parserr   s               r    r   r   !  sN   . mR00Eu_%%HG&&((  	KM!))H"5"566		& 1 122ii	**++!#&66<$ 7 
 
 	)))!!!'''##%% &
 
 	vNr"   amount	list[int]c                x    t          d|           } |d          }d |                                pg D             S )a9  Returns 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_bugsr   c                ,    g | ]}t          |          S r   ru   r'   item_els     r    rx   znewest_bugs.<locals>.<listcomp>j      BBBWCLLBBBr"   )r{   ra   )r   rj   r   s      r    r   r   W  sG    " mV44Eu_%%HBB(9(9(;(;(ArBBBBr"   kwargsstr | int | list[int]c                    g }|                                  D ]\  }}|                    ||g           t          d          }t          |          D ][\  }}dt	          |          z   }t          |t          t          f          rt          |||           E|	                    ||           \t                      }|                    d|          }	 |	d          }
d |
                                pg D             S )a  Get 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]

    z<get_bugs></get_bugs>argget_bugsr   c                ,    g | ]}t          |          S r   ru   r   s     r    rx   zget_bugs.<locals>.<listcomp>  r   r"   )r-   extendr   	enumerater#   r@   rY   rZ   r_   marshallr[   r`   ra   )r   argskvri   arg_nkvarg_namere   rj   r   s              r    r   r   m  s   P D  1QF
 !!899It__ - -	r3u::%b4-(( 	-)R8888x,,,,$&&KZ33Eu_%%HBB(9(9(;(;(ArBBBBr"   rl   r   c           
     v   t                      }dD ])}t          ||t           | |                               *t          j        t           | d                              |_        t          j        t           | d                              |_        d t           | d                    	                                D             |_
        t           | d                    |_        |j        rt           | d                    nd|_        t           | d                    |_        t           | d	                    |_        t!           | d
                    |_        d t           | d                    	                                D             |_        d t           | d                    	                                D             |_        d t           | d                    	                                D             |_        d  | d                                          pg D             |_        d  | d                                          pg D             |_        d t           | d                    	                    d          D             }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

    )
originatorsubjectmsgidpackagerL   ownersummarylocationsourcepending	forwardeddatelog_modifiedc                    g | ]}|S r   r   )r'   r   s     r    rx   z!_parse_status.<locals>.<listcomp>  s    ;;;;;;r"   rn   rJ   NrI   
unarchivedbug_numc                ,    g | ]}t          |          S r   ru   r'   rg   s     r    rx   z!_parse_status.<locals>.<listcomp>  s    HHHc!ffHHHr"   
mergedwithc                ,    g | ]}t          |          S r   ru   r   s     r    rx   z!_parse_status.<locals>.<listcomp>  s    FFFSVVFFFr"   	blockedbyc                ,    g | ]}t          |          S r   ru   r   s     r    rx   z!_parse_status.<locals>.<listcomp>  s    @@@Q#a&&@@@r"   blocksc                ,    g | ]}t          |          S r   r#   r'   els     r    rx   z!_parse_status.<locals>.<listcomp>  +       B  r"   found_versionsc                ,    g | ]}t          |          S r   r   r   s     r    rx   z!_parse_status.<locals>.<listcomp>  r   r"   fixed_versionsc                    g | ]}||S r   r   )r'   _fs     r    rx   z!_parse_status.<locals>.<listcomp>  s    DDDbDrDDDr"   affects,c                6    g | ]}|                                 S r   )strip)r'   as     r    rx   z!_parse_status.<locals>.<listcomp>  s     ...17799...r"   )r   setattrr   r   utcfromtimestampfloatr   r   r#   splitrn   _parse_boolrJ   done_byrI   r   rE   r   r   r   r   ra   r   r   r   )rl   rw   fieldr   s       r    rc   rc     s    ++C = = 	U,VVE]];;<<<<(vvf~~)>)>??CH0vvn7M7M1N1NOOC;;s66&>>2288::;;;CH66&>>**CH69hH"66&>>222DCKvvj1122CL !5!566CNffY''((CKHHc&&*>*>&?&?&E&E&G&GHHHCNFFS)<)<%=%=%C%C%E%EFFFCM@@#ffX&6&6"7"7"="="?"?@@@CJ  &!122;;==C  C  &!122;;==C  C EDCy 1 12288==DDDG..g...CK Jr"    soap)r   action	namespacesoap_ns	proxy_argr   c                    | t           d<   dS )zSet proxy for SOAP client.

    You must use this method after import to set the proxy.

    Parameters
    ----------
    proxy_arg

    proxyN_soap_client_kwargs)r   s    r    set_soap_proxyr     s     $-   r"   urlc                    | t           d<   dS )zSet location URL for SOAP client

    You may use this method after import to override the default URL.

    Parameters
    ----------
    url
        default URL

    r   Nr   )r   s    r    set_soap_locationr     s     '*
###r"   dict[str, str]c                     t           S )zlReturns SOAP client kwargs.

    Returns
    -------
    dict[str, str]
        the SOAP client kwargs

    r   r   r"   r    get_soap_client_kwargsr     s
     r"   r   c                 $    t          di t          S )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   )r   r   r   r"   r    r[   r[     s     ,,+,,,r"   r   Iterable[Any]list[tuple[str, Any]]c                     g }t          |           D ],\  }}|                    dt          |          z   |f           -|S )aq  Convert 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   )r   rb   r#   )r   	soap_argsr   r   s       r    _convert_soap_method_argsr   (  sO    * Ioo 4 4
s%#e**,c23333r"   method_namer   c                V    t                      }t          | } t          ||           | S )zWrapper to call SoapClient method

    Parameters
    ----------
    method_name
        the method name
    *args

    Returns
    -------
    Any

    )r[   r   getattr)r   r   re   r   s       r    r{   r{   C  s0     %&&K)40I,7;,,i88r"   el_nameparentlist_	list[Any]c                T   |                     |           }|                    dd           |                    dd           |                    ddt          |          dd           |D ];}|                     d	t          |                    }|                    dd
           <|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/rs   r   zsoapenc:arrayTypezxsd:int[d]itemzxsd:int)	add_childadd_attributer]   r#   )r   r   r   r   r  r   s         r    r_   r_   W  s    * 
		'	"	"BD   Z111(*DSZZ*D*D*D*DEEE 5 5,,vs4yy11j)4444Ir"   r   r1   c                L    t          |           }|                                dvS )zParse a boolean value from a XML element.

    Parameters
    ----------
    el
        the element to parse

    Returns
    -------
    bool
        the parsed value

    )r   0)r#   r   )r   r)   s     r    r   r   x  s"     GGE{{}}	))r"   c                    t          |           }|                                                     d          }|r6|j        dk    r+t	          j        |          }|                    dd          }|S )zRead a string element, maybe encoded in base64.

    Parameters
    ----------
    el
        the element to parse

    Returns
    -------
    str
        the parsed value

    rs   zxsd:base64Binaryzutf-8replace)errors)r#   r|   r}   r)   base64	b64decodedecode)r   r)   el_typetmps       r    r   r     si     GGEmmoo!!*--G 67=$666u%%

79
55Lr"   )rR   rS   r   rT   r   )rm   r#   rn   ro   r   rp   )r   rE   r   r   )r   rE   r   r   )r   r   r   r   )rl   r   r   r   )r   r#   r   r   )r   r#   r   r   )r   r   )r   r   )r   r   r   r   )r   r#   r   r   r   r   )r   r#   r   r   r   r   r   r   )r   r   r   r1   )r   r   r   r#   ).rQ   
__future__r   r	  email.feedparserrm   email.policyr   osloggingtypingr   r   pysimplesoap.clientr   pysimplesoap.simplexmlr   	getLoggerrN   loggerca_pathpathisdirenvironURLNSBTS_URLr^   rK   r   rW   rr   r   r   r   rc   r   r   r   r   r[   r   r{   r_   r   r   r   r"   r    <module>r     s    # " " " " "                				                  * * * * * * 3 3 3 3 3 3 
	8	$	$ 7== )!(BJ~
 1
$
  
T T T T T T T Tn' ' ' 'X 04' ' ' ' 'T3 3 3 3lC C C C,:C :C :C :Cz= = = =B 	  
- 
- 
- 
-* * * *	 	 	 	- - - -   69 9 9 9(   B* * * *$     r"   