o `^@sdZeZgdZddlmZddlmZddlm Z m Z zddl m Z m Z mZmZmZWneyGddl m Z m Z mZddlmZmZYnwdd lZejdd krXeZeZneZeZdd lmZdd lmZdd lm Z ddl!m"Z"m#Z#ddl$m%Z%ddl&m'Z'e(Z)GdddZ*GdddZ+Gddde+ZGdddeZ,GdddeZ-GdddeZ.Gddde+Z/Gdd d eZ0Gd!d"d"eZ1Gd#d$d$e1Z2Gd%d&d&eZ3d S)'z)Common support for web service resources.) CollectionCollectionWithKeyBasedLookupEntryNamedOperationResource ServiceRoot)Message)BytesIO)dumpsloads)urljoinurlparseparse_qsunquote urlencode)r r r)rrN)URI)r) __version__)Browser RestfulHttp)DatetimeJSONEncoder) HTTPErrorc@s*eZdZdZddZd ddZddZdS) HeaderDictionaryaA dictionary that bridges httplib2's and wadllib's expectations. httplib2 expects all header dictionary access to give lowercase header names. wadllib expects to access the header exactly as it's specified in the WADL file, which means the official HTTP header name. This class transforms keys to lowercase before doing a lookup on the underlying dictionary. That way wadllib can pass in the official header name and httplib2 will get the lowercased name. cCs ||_dSN)wrapped_dictionary)selfrr=/usr/lib/python3/dist-packages/lazr/restfulclient/resource.py__init__Is zHeaderDictionary.__init__NcCs|j|Sz2Retrieve a value, converting the key to lowercase.)rgetlower)rkeydefaultrrrr LszHeaderDictionary.getcCs ||t}|turt||Sr)r missingKeyError)rr"valuerrr __getitem__Ps zHeaderDictionary.__getitem__r)__name__ __module__ __qualname____doc__rr r'rrrrr>s   rc@s$eZdZdZdZddZddZdS) RestfulBasez=Base class for classes that know about lazr.restful services.application/jsoncCs8i}|D]\}}t|tr|j}||||<q|Sr)items isinstancer self_link_get_external_param_name)r dictionarynew_dictionaryr"r&rrr_transform_resources_to_links]s  z)RestfulBase._transform_resources_to_linkscC|S)aTurn a lazr.restful name into something to be sent over HTTP. For resources this may involve sticking '_link' or '_collection_link' on the end of the parameter name. For arguments to named operations, the parameter name is returned as is. rr param_namerrrr1esz$RestfulBase._get_external_param_nameN)r(r)r*r+JSON_MEDIA_TYPEr4r1rrrrr,Xs  r,c@seZdZdZddZeZeZeZe ddZ e ddZ e dd Z e d d Z e d d Ze ZddZddZddZddZe    d'ddZd(ddZddZdd Zd!d"Zd#d$Zd%d&ZdS))rz+Base class for lazr.restful HTTP resources.cCs$|dur|}||jd<||jd<dS)z5Initialize with respect to a wadllib Resource object.N_root_wadl_resource)__dict__rroot wadl_resourcerrrrss zResource.__init__cC ||jS)z,Name the collections this resource links to.)_get_parameter_namesFIND_COLLECTIONSrrrrlp_collections zResource.lp_collectionscCr?)z(Name the entries this resource links to.)r@ FIND_ENTRIESrBrrr lp_entriesrDzResource.lp_entriescCr?)z'Name this resource's scalar attributes.)r@FIND_ATTRIBUTESrBrrr lp_attributesrDzResource.lp_attributescCsg}|jjD]E}|j}|dkr|jddg}n|dkr9dD]}|j|}|dur2|}nq ||j}|D]}|jdkrJ||j nq;q|S)z.Name all of this resource's custom operations.r queryplainpost)!application/x-www-form-urlencodedmultipart/form-dataNws.op) r: method_iternamer!requestparamsget_representation_definitionresolve_definitionappend fixed_value)rnamesmethodrPrR media_type definitionparamrrr lp_operationss,     zResource.lp_operationscCs||j|j|jS)z;A hook into dir() that returns web service-derived members.)r@rArErGrBrrr __members__s zResource.__members__cGsg}|j|jD]@}|j}|j}|dkr?|dur?|jr?|dr0|j|vr/||ddq |j |vr>||ddq |j |vrI||q |S)z2Retrieve some subset of the resource's parameters.r0N_collection_linki) r: parametersr8rPlink can_followendswithrArUrErG)rkindsrW parameterrPrarrrr@s(    zResource._get_parameter_namescCs||duS)z8Does this resource have a parameter with the given name?N)r1r6rrrlp_has_parameterszResource.lp_has_parameterc Cs|dD]6}|j||}|dur_sz*Resource.lp_values_for..N)r:rir8optionslen)rr7rerrrr lp_values_forYs zResource.lp_values_forcCs*dD]}||}|j|r|SqdS)z>What's this parameter's name in the underlying representation?)rgr^N)r:ri)rr7rmrPrrrr1bs  z!Resource._get_external_param_namecCs|jjdurJ|jj|j}t|tr|d}t|}t|t r;|d}|dur;||jj kr;|jj |}|j |j_ |jj||jdd|jd<dSdS)z5Make sure this resource has a representation fetched.Nutf-8resource_type_linkFr}r:)r:r{r9rr r/ binary_typedecoder dictrv_wadlget_resource_typetagrxr8r;)rr{ type_linkr~rrrrhjs$      zResource._ensure_representationcCs ||k S)zInequality operator.rrotherrrr__ne__s zResource.__ne__)Nr-TNNNN)r(r)r*r+robjectrArErGpropertyrCrFrHr\r] __methods__r@rfrnrs classmethodrlrrrr1rhrrrrrrpsB      $ 4   rc@seZdZdZeddZdS) ScalarValuez.A resource representing a single scalar value.cCs||jjS)zReturn the scalar value.)rhr:r{rBrrrr&szScalarValue.valueN)r(r)r*r+rr&rrrrrsrc@s2eZdZdZd ddZddZdd Zd d ZdS) HostedFilezAA resource representing a file managed by a lazr.restful service.rNcCs|dvr t||||Std)z5Open the file on the server for read or write access.)rw'Invalid mode. Supported modes are: r, w)HostedFileBuffer ValueError)rmode content_typefilenamerrropenszHostedFile.opencCs|jj|jjdS)z Delete the file from the server.N)r9rdeleter:urlrBrrrrzHostedFile.deletecGsgS)z4HostedFile objects define no web service parameters.r)rrdrrrr@zHostedFile._get_parameter_namescCs|duo |jj|jjkS)aEquality comparison. Two hosted files are the same if they have the same URL. There is no need to check the contents because the only way to retrieve or modify the hosted file contents is to open a filehandle, which goes direct to the server. N)r:rrrrr__eq__s zHostedFile.__eq__)rNN)r(r)r*r+rrr@rrrrrrs   rcsVeZdZdZeedZdddddejffdd Z e ddZ d d Z d d Z ZS) rzEntry point to the service. Subclass this for a service-specific client. :ivar credentials: The credentials instance used to access Launchpad. )rrNrc s|dur|ddkr|d7}|t|7}|ddkr|d7}t||_||_||_t||||||j||_|j|j|_ |j d} | |j | d} t t|d| dS)zRoot access to a lazr.restful API. :param credentials: The credentials used to access the service. :param service_root: The URL to the root of the web service. :type service_root: string Nrt/rr-)strr _root_uri_base_client_name credentialsr _user_agentrget_wadl_applicationrget_resource_by_pathrxr superrr) r authorizer service_rootcachetimeout proxy_infoversionbase_client_name max_retries root_resource bound_root __class__rrrs&      zServiceRoot.__init__cCspdt}|jdkr|jd|d}t}||d<|jdur4|jj}t|D] }||}|||dq&|dS)aThe value for the User-Agent header. This will be something like: launchpadlib 1.6.1, lazr.restfulclient 1.0.0; application=apport That is, a string describing lazr.restfulclient and an optional custom client built on top, and parameters containing any authorization-specific information that identifies the user agent (such as the application name). zlazr.restfulclient %srz ()z User-AgentN)rrrruser_agent_paramssorted set_param)r base_portionmessagerr"r&rrrrs   zServiceRoot._user_agentcCst||||Sr)r)rrrrrrrr httpFactoryszServiceRoot.httpFactorycCst|}|jdkr|dddkr|dd}t|j|}|j|}t|tr/| d}zt |}Wn t yBt d|w|d}|durRt d||j j |}t|j j ||j}|j|j ||d d d S) zLoad a resource given its URL.rNrrz!%s doesn't serve a JSON document.rz+Couldn't determine the resource type of %s.r-Fr)r schemerrrUrr r/rrr rr9rr WadlResourcerrl)rrparseddocumentr{rr~r>rrrloads0          zServiceRoot.load)r(r)r*r+rrrwr MAX_RETRIESrrrrr __classcell__rrrrrs! rc@s8eZdZdZddZddZddZdd Zd d Zd S) rz=A class for a named operation to be invoked with GET or POST.cCs||_||_||_dS)z/Initialize with respect to a WADL Method objectN)r=rz wadl_method)rr=rzrrrrrs zNamedOperation.__init__cOs|t|dkr td|jj}||}|jj}|dvr|j}n|d}|dur-|d}|dus5Jd||j j }t dd |D}| D]\}} ||vrYt | td ||<qI|dvrl|jjdi|} d } i} n|j} |jjdi|\} } d | i} |jjj| | || d \}}|jdkr|| ||S|dkr|jdkr|d} |jj| \}}n|j || ||S)z)Invoke the method and process the result.rz(Method must be called with keyword args.)r headrrMNrLzYA POST named operation must define a multipart or form-urlencoded request representation.cSs*g|]}|jdkst|jdkr|jqS)binaryr)typerrrP)rr[rrrr5s  z+NamedOperation.__call__..)ryrz Content-type) extra_headersrK-locationr)r TypeErrorrrPr4rQrorSrRrzr:setr.r rbuild_request_urlbuild_representationr=r_requestupperstatus_handle_201_responser_handle_200_response)rargskwargs http_methodrQrRrZsend_as_is_paramsr"r&rin_representationrrYresponsecontentrrr__call__ s\         zNamedOperation.__call__cCsL|jjt|}|d}|j}|jj|j \}}t |j|||dS)z5Handle the creation of a new resource by fetching it.Location content-type) rrrxrrirkr=rrrrrl)rrrr wadl_responsewadl_parameterr>rrrrbs z#NamedOperation._handle_201_responsec Cs|d}|jj}||}|dur&||jkr$t|tr |d}t|S|St|tr0|d}t|}|dur:|Sd|vrYd|vrY|d}|jj |d}t |jj ||j } n | }t |jj ||j } tj|j| ||d|dS)z)Process the return value of an operation.rNrr0rF)r}ru)rrrSr8r/rrr r=rrrrrTrrl) rrrrrresponse_definitionrurr~r>rrrrpsF         z#NamedOperation._handle_200_responsecCr5)z/Named operation parameter names are sent as is.rr6rrrr1rz'NamedOperation._get_external_param_nameN) r(r)r*r+rrrrr1rrrrrsB 6rcsjeZdZdZfddZddZddZdd Zfd d Zd d Z ddZ dfdd Z ddZ Z S)rzBA class for an entry-type resource that can be updated with PATCH.cs2tt|||i|jd<tt|||dS)N_dirty_attributes)rrrr;r<rrrrs zEntry.__init__cCsdt|jj|jfS)z:Return the WADL resource type and the URL to the resource.z <%s at %s>)rrfragmentr0rBrrr__repr__szEntry.__repr__cCs|jjt|jS)zDelete the resource.)r9rrrr0rBrrr lp_deleteszEntry.lp_deletecCs|jS)zReturn the URL to the resource.)r0rBrrr__str__z Entry.__str__cs,|dkr||jvr|j|Stt||S)z-Try to retrive a parameter of the given name.r)rrrr)rrPrrrrs  zEntry.__getattr__cCs,||std|jj|f||j|<dS)z$Set the parameter of the given name.z!'%s' object has no attribute '%s'N)rfrrr(r)rrPr&rrr __setattr__s  zEntry.__setattr__cCs,|duo|j|jko|j|jko|j|jkS)zEquality operator. Two entries are the same if their self_link and http_etag attributes are the same, and if their dirty attribute dicts contain the same values. N)r0 http_etagrrrrrrs   z Entry.__eq__Ncs,t|dd}tt||||jdS)rrN)getattrrrrrclear)rrrrrrrs zEntry.lp_refreshcCs||j}i}t|dd}|dur||d<|jjt|j||\}}|jdkr0| |d|j |d}|jdkr[||j kr]t |t rM|d}t|}||j_||j_dSdSdS) zSave changes to the entry.rNzIf-Matchrrrr)r4rrr9rpatchrr0rrrr8r/rrr r:r{rY)rr{rrrrrnew_representationrrrlp_saves*       z Entry.lp_saver)r(r)r*r+rrrrrrrrrrrrrrrs   rcsPeZdZdZfddZddZddZdd Zd d Zd d Z ddZ Z S)rz4A collection-type resource that supports pagination.cstt|||dS)zCreate a collection object.N)rrrr<rrrrrzCollection.__init__cCs,|j}t|tr |St|tr|jStd)znThe number of items in the collection. :return: length of the collection :rtype: int z collection size is not available) total_sizer/intrr&r)rrrrr__len__s   zCollection.__len__ccsx||jj} ||diD]}|Vq|d}|dur$dS|jjt|}t|t r7| d}t |}q )zqIterate over the items in the collection. :return: iterator :rtype: sequence of `Entry` Tentriesnext_collection_linkNr) rhr:r{_convert_dicts_to_entriesr r9rrr/rrr )r current_pagerz next_linknext_getrrr__iter__$s     zCollection.__iter__cCsDt|tr ||S|t||d}t|dkrtd|dS)acLook up a slice, or a subordinate resource by index. To discourage situations where a lazr.restful client fetches all of an enormous list, all collection slices must have a definitive end point. For performance reasons, all collection slices must be indexed from the start of the list rather than the end. rzlist index out of ranger)r/slice _get_slicer IndexError)rr" found_slicerrrr'8s  zCollection.__getitem__cCs|jpd}|j}|dkrtd|dkrtd|jj}|dur<|t|dkr<|d}t|}|||}|d}n d}g}||jjd|}||} | t|} | dkr|dur|j j |} t | t rl| d} t| } | d} || d| 7}| t|} | d}|durn|durt| }| dkr| |kr||d | }| dkr|dus[|jdur|dd|j}d d ||DS) z!Retrieve a slice of a collection.rz6Collection slices must have a nonnegative start point.z>Collection slices must have a definite, nonnegative end point.Nrrzws.startrzws.sizecSsg|]}|qSrr)rrzrrrrsz)Collection._get_slice..)startstoprr:r{rr _with_url_query_variable_setrr9rr/rrr stepr )rrrrexisting_representation entry_pagefirst_page_size entry_dictspage_url desired_size more_neededpage_getr{current_page_entriesrrrrJsV          zCollection._get_sliceccs\|D](}|d}|d}|jj}||}t|jj||j}t|j|||jdVqdS)aConvert dictionaries describing entries to Entry objects. The dictionaries come from the 'entries' field of the JSON dictionary you get when you GET a page of a collection. Each dictionary is the same as you'd get if you sent a GET request to the corresponding entry resource. So each of these dictionaries can be treated as a preprocessed representation of an entry resource, and turned into an Entry instance. :yield: A sequence of Entry instances. r0rFN) r: applicationrrrrrlr9r8)rr entry_dict resource_urlrwadl_applicationr~rzrrrr s"  z$Collection._convert_dicts_to_entriescCsBt|}|jdur i}nt|j}t|||<t|d|_t|S)z1A helper method to set a query variable in a URL.NT)rrIrrr)rrvariable new_valueurirRrrrrs    z'Collection._with_url_query_variable_set) r(r)r*r+rrr r'rr rrrrrrr s Urcs4eZdZdZfddZddZdZddZZS) rzA collection-type resource that supports key-based lookup. This collection can be sliced, but any single index passed into __getitem__ will be treated as a custom lookup key. c st|tr tt||Sz||}Wn tytdw|dur(t|||}z| W|St yJ}z |j j dkrEt|d}~ww)z8Look up a slice, or a subordinate resource by unique ID.unsubscriptable objectN) r/rrrr'_get_url_from_idNotImplementedErrorrr%rhrrr)rr"r shim_resourceerrrr's&    z(CollectionWithKeyBasedLookup.__getitem__c Csz||}Wn tytdw|durt||jdur.d}t|jjjd|j}n3z|jj |}t |t r@| d}t|}Wnty\}z |jjdkrWt|d}~ww|d}t|jj||}|j|j||ddS) z=Retrieve a member from this collection without looking it up.r&N#rr'rF)r{r})r(r)rr collection_ofr r9r markup_urlrr r/rrr rrrr%rrl)rr"rr{rurl_geterrorrzrrrrs:       z%CollectionWithKeyBasedLookup.__call__NcCst)z2Transform the unique ID of an object into its URL.)r))rr"rrrr(rz-CollectionWithKeyBasedLookup._get_url_from_id) r(r)r*r+r'rr-r(rrrrrrs  0rc@s*eZdZdZd ddZddZddZdS) rz8The contents of a file hosted by a lazr.restful service.Nc Cs|jj|_|dkrB|durtd|durtd|jjj|jdd\}}|d}|d}|d}t|d } t| d d }n|d kr[d }|durPtd|durXtdd}ntd||_ ||_ ||_ ||_ ||_ t||dS)Nrz8Files opened for read access can't specify content_type.z4Files opened for read access can't specify filename.T)return_responserz last-modifiedzcontent-locationrrtrrz8Files opened for write access must specify content_type.z4Files opened for write access must specify filename.r)r:rrr9rr r rsplit hosted_filerrr last_modifiedr r) rr4rrrrr&r5content_locationpathrrrrs8    zHostedFileBuffer.__init__cCsD|jdkrd|j}|jjj|j||jd|it |dS)Nrzattachment; filename="%s"zContent-Disposition) rrr4r9rputrgetvaluerr close)r dispositionrrrr:Bs     zHostedFileBuffer.closecCst||dSr)r write)rbrrrr<JszHostedFileBuffer.writer)r(r)r*r+rr:r<rrrrrs  ( r)4r+r __metaclass____all__ email.messagerior jsonr r urllib.parser r rrr ImportErrorurllibsys version_infor text_typebytesrunicodelazr.urirwadllib.applicationrrlazr.restfulclientrlazr.restfulclient._browserrrlazr.restfulclient._jsonrlazr.restfulclient.errorsrrr$rr,rrrrrrrrrrrrsP         c`:T