Skip to content

Commit 85b2b7d

Browse files
committed
Add llbase.llrest.get(), post(), put(), delete()
1 parent 0ff1251 commit 85b2b7d

File tree

2 files changed

+104
-10
lines changed

2 files changed

+104
-10
lines changed

debian/changelog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
llbase (1.2.11) unstable; urgency=low
2+
3+
* Added llrest.get(), post(), put(), delete()
4+
5+
-- Nat Goodspeed <[email protected]> Wed, 07 Jul 2021 14:01:32 -0400
6+
17
llbase (1.2.10) unstable; urgency=low
28

39
* Added llrest.RESTService(cookie_policy)

llbase/llrest.py

Lines changed: 98 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,11 @@ def set_content_type_header(self, session):
196196
def encode(self, data):
197197
return ElementTree.tostring(data)
198198

199-
class RESTService(object):
199+
class _RESTService(object):
200200
"""
201+
The _RESTService base class provides most of the implementation for
202+
RESTService. The RESTService subclass adds some parameter validation.
203+
201204
Implements a simple wrapper for calling a REST interface that returns
202205
either llsd or json, with optional authentication.
203206
@@ -230,6 +233,11 @@ class RESTService(object):
230233
undesired dependency between that module and the calling script.
231234
"""
232235

236+
# describe __init__() params; used by _resolve_args()
237+
init_params = ('name', 'baseurl', 'codec', 'authenticated',
238+
'username', 'password', 'proxy_hostport', 'cert', 'basepath',
239+
'cookie_policy')
240+
233241
def __init__(self, name, baseurl, codec=RESTEncoding.LLSD, authenticated=True,
234242
username=None, password=None, proxy_hostport=None, cert=None, basepath='',
235243
cookie_policy=None, **session_params):
@@ -382,15 +390,6 @@ def _url(self, basepath, path, method, path_param='path', basepath_param='basepa
382390
383391
basepath_param is the name of method's parameter passed to us as basepath.
384392
"""
385-
# Since caller accepts both 'basepath' and 'path', both are typically
386-
# optional arguments -- though 'path' is usually first so its caller
387-
# need not explicitly pass it as a keyword argument. But its caller
388-
# MUST pass one or the other.
389-
if not (basepath or path):
390-
# When you fail to pass a non-optional parameter, the interpreter
391-
# raises TypeError. Treat this similarly.
392-
raise TypeError("{}() requires either {} or {}"
393-
.format(method, path_param, basepath_param))
394393
# if self.baseurl is None, use empty string instead
395394
baseurl = self.baseurl or ""
396395
if basepath:
@@ -667,6 +666,26 @@ def temp_codec(self, codec):
667666
finally:
668667
self.set_codec(prev)
669668

669+
class RESTService(_RESTService):
670+
# We want the following validation for a consumer-instantiated
671+
# RESTService, just not for _RESTService instances implicitly constructed
672+
# by _resolve_args()
673+
def _url(self, basepath, path, method, path_param='path', basepath_param='basepath'):
674+
# Since caller accepts both 'basepath' and 'path', both are typically
675+
# optional arguments -- though 'path' is usually first so its caller
676+
# need not explicitly pass it as a keyword argument. But its caller
677+
# MUST pass one or the other.
678+
if not (basepath or path):
679+
# When you fail to pass a non-optional parameter, the interpreter
680+
# raises TypeError. Treat this similarly.
681+
raise TypeError("{}() requires either {} or {}"
682+
.format(method, path_param, basepath_param))
683+
684+
# we have one or the other, pass to base-class method
685+
return super(RESTService, self)._url(
686+
basepath=basepath, path=path, method=method,
687+
path_param=path_param, basepath_param=basepath_param)
688+
670689
class _OldTLS(requests.adapters.HTTPAdapter):
671690
"""
672691
Helper for RESTService.enable_old_tls(), derived from
@@ -709,3 +728,72 @@ class SimpleRESTService(RESTService):
709728
"""
710729
def __init__(self, name, baseurl, *args, **kwds):
711730
RESTService.__init__(self, name, baseurl, authenticated=False, *args, **kwds)
731+
732+
733+
# convenience functions for simple one-shot use cases
734+
def get(url, **kwds):
735+
"""
736+
url is the target URL; everything else must be keyword arguments
737+
738+
RESTService.__init__() keywords are passed to RESTService constructor;
739+
the rest are passed to requests.get()
740+
"""
741+
svc, kwds = _resolve_args('get', url, kwds)
742+
return svc.get(query='', basepath='', **kwds)
743+
744+
def post(url, **kwds):
745+
"""
746+
url is the target URL; everything else must be keyword arguments
747+
748+
RESTService.__init__() keywords are passed to RESTService constructor;
749+
data (if passed) is encoded according to the RESTService codec;
750+
the rest are passed to requests.post()
751+
"""
752+
svc, kwds = _resolve_args('post', url, kwds)
753+
return svc.post(path='', basepath='', **kwds)
754+
755+
def put(url, **kwds):
756+
"""
757+
url is the target URL; everything else must be keyword arguments
758+
759+
RESTService.__init__() keywords are passed to RESTService constructor;
760+
data (if passed) is encoded according to the RESTService codec;
761+
the rest are passed to requests.put()
762+
"""
763+
svc, kwds = _resolve_args('put', url, kwds)
764+
return svc.put(path='', basepath='', **kwds)
765+
766+
def delete(url, **kwds):
767+
"""
768+
url is the target URL; everything else must be keyword arguments
769+
770+
RESTService.__init__() keywords are passed to RESTService constructor;
771+
the rest are passed to requests.delete()
772+
"""
773+
svc, kwds = _resolve_args('delete', url, kwds)
774+
return svc.delete(path='', basepath='', **kwds)
775+
776+
def _resolve_args(func, url, kwds):
777+
"""
778+
Given a dict of **kwds, split them into _RESTService constructor params
779+
versus anything else, which we assume to be extra keywords to pass to
780+
'func'.
781+
782+
Return (_RESTService instance, remaining kwds).
783+
"""
784+
# _RESTService.init_params includes the first two parameters, name and
785+
# baseurl, to simplify maintenance. But since we pass those explicitly
786+
# here, remove from the set of keywords we recognize.
787+
init_params = set(_RESTService.init_params[2:])
788+
init_kwds = {}
789+
func_kwds = {}
790+
for key, value in kwds.items():
791+
if key in init_params:
792+
dest_kwds = init_kwds
793+
else:
794+
dest_kwds = func_kwds
795+
dest_kwds[key] = value
796+
return (_RESTService(name='temp ' + func, baseurl=url, **init_kwds),
797+
func_kwds)
798+
799+

0 commit comments

Comments
 (0)