2727except ImportError :
2828 JSONDecodeError = ValueError
2929
30+ from .errors import *
31+ from ._internal import ApplicationV2 , BasicAuthenticatedServer , _format_date_param
32+
3033__version__ = "2.3.0"
3134
3235logger = logging .getLogger ("nexmo" )
3336
3437
35- class Error (Exception ):
36- pass
37-
38-
39- class ClientError (Error ):
40- pass
41-
42-
43- class ServerError (Error ):
44- pass
45-
46-
47- class AuthenticationError (ClientError ):
48- pass
49-
50-
5138class Client :
39+ """
40+ Create a Client object to start making calls to Nexmo APIs.
41+
42+ Most methods corresponding to Nexmo API calls are on this class itself,
43+ although newer APIs are under namespaces like :attr:`Client.application_v2`.
44+
45+ The credentials you provide when instantiating a Client determine which
46+ methods can be called. Consult the `Nexmo API docs <https://developer.nexmo.com/api/>`_ for details of the
47+ authentication used by the APIs you wish to use, and instantiate your
48+ Client with the appropriate credentials.
49+
50+ :param str key: Your Nexmo API key
51+ :param str secret: Your Nexmo API secret.
52+ :param str signature_secret: Your Nexmo API signature secret.
53+ You may need to have this enabled by Nexmo support. It is only used for SMS authentication.
54+ :param str signature_method:
55+ The encryption method used for signature encryption. This must match the method
56+ configured in the Nexmo Dashboard. We recommend `sha256` or `sha512`.
57+ This should be one of `md5`, `sha1`, `sha256`, or `sha512` if using HMAC digests.
58+ If you want to use a simple MD5 hash, leave this as `None`.
59+ :param str application_id: Your application ID if calling methods which use JWT authentication.
60+ :param str private_key: Your private key if calling methods which use JWT authentication.
61+ This should either be a str containing the key in its PEM form, or a path to a private key file.
62+ :param str app_name: This optional value is added to the user-agent header
63+ provided by this library and can be used by Nexmo to track your app statistics.
64+ :param str app_name: This optional value is added to the user-agent header
65+ provided by this library and can be used by Nexmo to track your app statistics.
66+ """
67+
5268 def __init__ (
5369 self ,
5470 key = None ,
@@ -71,7 +87,7 @@ def __init__(
7187 "NEXMO_SIGNATURE_METHOD" , None
7288 )
7389
74- if signature_method in {"md5" , "sha1" , "sha256" , "sha512" }:
90+ if self . signature_method in {"md5" , "sha1" , "sha256" , "sha512" }:
7591 self .signature_method = getattr (hashlib , signature_method )
7692
7793 self .application_id = application_id
@@ -99,6 +115,14 @@ def __init__(
99115
100116 self .auth_params = {}
101117
118+ api_server = BasicAuthenticatedServer (
119+ "https://api.nexmo.com" ,
120+ user_agent = user_agent ,
121+ api_key = self .api_key ,
122+ api_secret = self .api_secret ,
123+ )
124+ self .application_v2 = ApplicationV2 (api_server )
125+
102126 def auth (self , params = None , ** kwargs ):
103127 self .auth_params = params or kwargs
104128
@@ -297,25 +321,50 @@ def request_number_insight(self, params=None, **kwargs):
297321 return self .post (self .host , "/ni/json" , params or kwargs )
298322
299323 def get_applications (self , params = None , ** kwargs ):
324+ warnings .warn (
325+ "nexmo.Client#get_applications is deprecated (use methods from #application_v2 instead)" ,
326+ DeprecationWarning ,
327+ stacklevel = 2 ,
328+ )
300329 return self .get (self .api_host , "/v1/applications" , params or kwargs )
301330
302331 def get_application (self , application_id ):
332+ warnings .warn (
333+ "nexmo.Client#get_application is deprecated (use methods from #application_v2 instead)" ,
334+ DeprecationWarning ,
335+ stacklevel = 2 ,
336+ )
303337 return self .get (
304338 self .api_host ,
305339 "/v1/applications/{application_id}" .format (application_id = application_id ),
306340 )
307341
308342 def create_application (self , params = None , ** kwargs ):
343+ warnings .warn (
344+ "nexmo.Client#create_application is deprecated (use methods from #application_v2 instead)" ,
345+ DeprecationWarning ,
346+ stacklevel = 2 ,
347+ )
309348 return self .post (self .api_host , "/v1/applications" , params or kwargs )
310349
311350 def update_application (self , application_id , params = None , ** kwargs ):
351+ warnings .warn (
352+ "nexmo.Client#update_application is deprecated (use methods from #application_v2 instead)" ,
353+ DeprecationWarning ,
354+ stacklevel = 2 ,
355+ )
312356 return self .put (
313357 self .api_host ,
314358 "/v1/applications/{application_id}" .format (application_id = application_id ),
315359 params or kwargs ,
316360 )
317361
318362 def delete_application (self , application_id ):
363+ warnings .warn (
364+ "nexmo.Client#delete_application is deprecated (use methods from #application_v2 instead)" ,
365+ DeprecationWarning ,
366+ stacklevel = 2 ,
367+ )
319368 return self .delete (
320369 self .api_host ,
321370 "/v1/applications/{application_id}" .format (application_id = application_id ),
@@ -447,6 +496,12 @@ def get(self, host, request_uri, params=None, header_auth=False):
447496 return self .parse (host , requests .get (uri , params = params , headers = headers ))
448497
449498 def post (self , host , request_uri , params , header_auth = False ):
499+ """
500+ Post form-encoded data to `request_uri`.
501+
502+ Auth is either key/secret added to the post data, or basic auth,
503+ if `header_auth` is True.
504+ """
450505 uri = "https://{host}{request_uri}" .format (host = host , request_uri = request_uri )
451506 headers = self .headers
452507 if header_auth :
@@ -464,6 +519,9 @@ def post(self, host, request_uri, params, header_auth=False):
464519 return self .parse (host , requests .post (uri , data = params , headers = headers ))
465520
466521 def _post_json (self , host , request_uri , json ):
522+ """
523+ Post json to `request_uri`, using basic auth.
524+ """
467525 uri = "https://{host}{request_uri}" .format (host = host , request_uri = request_uri )
468526 auth = base64 .b64encode (
469527 (
@@ -480,12 +538,24 @@ def _post_json(self, host, request_uri, json):
480538 )
481539 return self .parse (host , requests .post (uri , headers = headers , json = json ))
482540
483- def put (self , host , request_uri , params ):
541+ def put (self , host , request_uri , params , header_auth = False ):
484542 uri = "https://{host}{request_uri}" .format (host = host , request_uri = request_uri )
485543
486- params = dict (params , api_key = self .api_key , api_secret = self .api_secret )
487- logger .debug ("PUT to %r with params %r" , uri , params )
488- return self .parse (host , requests .put (uri , json = params , headers = self .headers ))
544+ headers = self .headers
545+ if header_auth :
546+ h = base64 .b64encode (
547+ (
548+ "{api_key}:{api_secret}" .format (
549+ api_key = self .api_key , api_secret = self .api_secret
550+ ).encode ("utf-8" )
551+ )
552+ ).decode ("ascii" )
553+ # Must create a new headers dict here, otherwise we'd be mutating `self.headers`:
554+ headers = dict (headers or {}, Authorization = "Basic {hash}" .format (hash = h ))
555+ else :
556+ params = dict (params , api_key = self .api_key , api_secret = self .api_secret )
557+ logger .debug ("PUT to %r with params %r, headers %r" , uri , params , headers )
558+ return self .parse (host , requests .put (uri , json = params , headers = headers ))
489559
490560 def delete (self , host , request_uri , header_auth = False ):
491561 uri = "https://{host}{request_uri}" .format (host = host , request_uri = request_uri )
@@ -500,6 +570,7 @@ def delete(self, host, request_uri, header_auth=False):
500570 ).encode ("utf-8" )
501571 )
502572 ).decode ("ascii" )
573+ # Must create a new headers dict here, otherwise we'd be mutating `self.headers`:
503574 headers = dict (headers or {}, Authorization = "Basic {hash}" .format (hash = h ))
504575 else :
505576 params = {"api_key" : self .api_key , "api_secret" : self .api_secret }
@@ -600,19 +671,3 @@ def generate_application_jwt(self, when=None):
600671 payload .setdefault ("jti" , str (uuid4 ()))
601672
602673 return jwt .encode (payload , self .private_key , algorithm = "RS256" )
603-
604-
605- def _format_date_param (params , key , format = "%Y-%m-%d %H:%M:%S" ):
606- """
607- Utility function to convert datetime values to strings.
608-
609- If the value is already a str, or is not in the dict, no change is made.
610-
611- :param params: A `dict` of params that may contain a `datetime` value.
612- :param key: The datetime value to be converted to a `str`
613- :param format: The `strftime` format to be used to format the date. The default value is '%Y-%m-%d %H:%M:%S'
614- """
615- if key in params :
616- param = params [key ]
617- if hasattr (param , "strftime" ):
618- params [key ] = param .strftime (format )
0 commit comments