@@ -137,10 +137,6 @@ class AmbiguousReferenceException(ValueError):
137137 """Thrown when the name used to fetch an entity matches more than one entity."""
138138 pass
139139
140- class EntityDeletedException (Exception ):
141- """Thrown when the entity that has been referred to has been deleted."""
142- pass
143-
144140class InvalidNameException (Exception ):
145141 """Thrown when the specified name contains characters that are not allowed
146142 in Splunk entity names."""
@@ -209,8 +205,8 @@ def _load_atom_entries(response):
209205 entries = r .feed .get ('entry' , None )
210206 if entries is None : return None
211207 return entries if isinstance (entries , list ) else [entries ]
212- # This rigamarole is because the jobs endpoint doesn't
213- # returned an entry inside a feed, it just returns and entry .
208+ # The jobs endpoint doesn't returns a bare <entry> element
209+ # instead of an < entry> element inside a < feed> element .
214210 else :
215211 entries = r .get ('entry' , None )
216212 if entries is None : return None
@@ -549,9 +545,8 @@ def roles(self):
549545 return Roles (self )
550546
551547 def search (self , query , ** kwargs ):
552- """Runs a oneshot synchronous search using a search query and any
553- optional arguments you provide. A oneshot search doesn't create a search
554- job and ID, but rather it returns the search results once completed.
548+ """Runs a search using a search query and any optional arguments you
549+ provide, and returns a `Job` object representing the search.
555550
556551 :param query: A search query.
557552 :type query: ``string``
@@ -576,6 +571,8 @@ def search(self, query, **kwargs):
576571 search.
577572
578573 :type kwargs: ``dict``
574+ :rtype: class:`Job`
575+ :returns: An object representing the created job.
579576 """
580577 return self .jobs .create (query , ** kwargs )
581578
@@ -882,17 +879,14 @@ def __getitem__(self, key):
882879 def _load_atom_entry (self , response ):
883880 elem = _load_atom (response , XNAME_ENTRY )
884881 if isinstance (elem , list ):
885- return [ x . entry for x in elem ]
882+ raise AmbiguousReferenceException ( "Fetch from server returned multiple entries for name %s." % self . name )
886883 else :
887884 return elem .entry
888885
889886 # Load the entity state record from the given response
890887 def _load_state (self , response ):
891888 entry = self ._load_atom_entry (response )
892- if isinstance (entry , list ):
893- raise AmbiguousReferenceException ("Fetch from server returned multiple entries for name %s." % self .name )
894- else :
895- return _parse_atom_entry (entry )
889+ return _parse_atom_entry (entry )
896890
897891 def _run_method (self , path_segment , ** kwargs ):
898892 """Run a method and return the content Record from the returned XML.
@@ -911,24 +905,26 @@ def _run_method(self, path_segment, **kwargs):
911905 def _proper_namespace (self , owner = None , app = None , sharing = None ):
912906 """Produce a namespace sans wildcards for use in entity requests.
913907
914- This method handles the case of two entities with the same name in different namespaces
915- showing up due to wildcards in the service 's namespace. We replace the wildcards with the
916- namespace of the entity we want .
908+ This method tries to fill in the fields of the namespace which are `None`
909+ or wildcard (`'-'`) from the entity 's namespace. If that fails, it uses
910+ the service's namespace .
917911
918912 :param owner:
919913 :param app:
920914 :param sharing:
921915 :return:
922916 """
923- if owner is None and app is None and sharing is None and \
924- (self .service .namespace .owner == '-' or self .service .namespace .app == '-' ):
925- # If no namespace is specified and there are wildcards in the service's namespace,
926- # we need to use the entity's namespace to avoid name collisions.
927- if 'access' in self ._state :
928- owner = self ._state .access .owner
929- app = self ._state .access .app
930- sharing = self ._state .access .sharing
931- return (owner , app , sharing )
917+ if owner is None and app is None and sharing is None : # No namespace provided
918+ if self ._state is not None and 'access' in self ._state :
919+ return (self ._state .access .owner ,
920+ self ._state .access .app ,
921+ self ._state .access .sharing )
922+ else :
923+ return (self .service .namespace ['owner' ],
924+ self .service .namespace ['app' ],
925+ self .service .namespace ['sharing' ])
926+ else :
927+ return (owner ,app ,sharing )
932928
933929 def delete (self ):
934930 owner , app , sharing = self ._proper_namespace ()
@@ -966,13 +962,7 @@ def refresh(self, state=None):
966962 if state is not None :
967963 self ._state = state
968964 else :
969- try :
970- raw_state = self .read ()
971- except HTTPError , he :
972- if he .status == 404 :
973- raise EntityDeletedException ("Entity %s was already deleted" % self .name )
974- raw_state ['links' ] = dict ([(k , urllib .unquote (v )) for k ,v in raw_state ['links' ].iteritems ()])
975- self ._state = raw_state
965+ self ._state = self .read ()
976966 return self
977967
978968 @property
@@ -1043,6 +1033,12 @@ def read(self):
10431033 """Reads the current state of the entity from the server."""
10441034 response = self .get ()
10451035 results = self ._load_state (response )
1036+ # In lower layers of the SDK, we end up trying to URL encode
1037+ # text to be dispatched via HTTP. However, these links are already
1038+ # URL encoded when they arrive, and we need to mark them as such.
1039+ unquoted_links = dict ([(k , UrlEncoded (v , skip_encode = True ))
1040+ for k ,v in results ['links' ].iteritems ()])
1041+ results ['links' ] = unquoted_links
10461042 return results
10471043
10481044 def reload (self ):
0 commit comments