11import logging
22import time
3+ import requests
4+ import typing
5+ if typing .TYPE_CHECKING :
6+ from helpscout import HelpScout
7+ from collections .abc import Generator
8+ from typing import Self
39
410from functools import partial
5- try : # Python 3
6- from urllib .parse import urljoin
7- except ImportError : # Python 2
8- from urlparse import urljoin
9-
10- import requests
11+ from urllib .parse import urljoin
1112
1213from helpscout .exceptions import (HelpScoutException ,
1314 HelpScoutAuthenticationException ,
2223
2324class HelpScout :
2425
25- def __init__ (self , app_id , app_secret ,
26- base_url = 'https://api.helpscout.net/v2/' ,
27- sleep_on_rate_limit_exceeded = True ,
28- rate_limit_sleep = 10 ):
26+ def __init__ (self , app_id : str , app_secret : str ,
27+ base_url : str = 'https://api.helpscout.net/v2/' ,
28+ sleep_on_rate_limit_exceeded : bool = True ,
29+ rate_limit_sleep : int = 10 ):
2930 """Help Scout API v2 client wrapper.
3031
3132 The app credentials are created on the My App section in your profile.
@@ -40,7 +41,7 @@ def __init__(self, app_id, app_secret,
4041 The application secret.
4142 base_url: str
4243 The API's base url.
43- sleep_on_rate_limit_exceeded: Boolean
44+ sleep_on_rate_limit_exceeded: bool
4445 True to sleep and retry on rate limits exceeded.
4546 Otherwise raises an HelpScoutRateLimitExceededException exception.
4647 rate_limit_sleep: int
@@ -54,7 +55,7 @@ def __init__(self, app_id, app_secret,
5455 self .rate_limit_sleep = rate_limit_sleep
5556 self .access_token = None
5657
57- def __getattr__ (self , endpoint ) :
58+ def __getattr__ (self , endpoint : str ) -> 'HelpScoutEndpointRequester' :
5859 """Returns a request to hit the API in a nicer way. E.g.:
5960 > client = HelpScout(app_id='asdasd', app_secret='1021')
6061 > client.conversations.get()
@@ -76,19 +77,18 @@ def __getattr__(self, endpoint):
7677 """
7778 return HelpScoutEndpointRequester (self , endpoint , False )
7879
79- def get_objects (self , endpoint , resource_id = None , params = None ,
80- specific_resource = False ):
80+ def get_objects (self , endpoint :str , resource_id :int | str | None = None , params :dict | str | None = None , specific_resource :bool = False ) -> HelpScoutObject | list [HelpScoutObject ]:
8181 """Returns the objects from the endpoint filtering by the parameters.
8282
8383 Parameters
8484 ----------
8585 endpoint: str
8686 One of the endpoints in the API. E.g.: conversations, mailboxes.
87- resource_id: int or str or None
87+ resource_id: int | str | None
8888 The id of the resource in the endpoint to query.
8989 E.g.: in "GET /v2/conversations/123 HTTP/1.1" the id would be 123.
9090 If None is provided, nothing will be done
91- params: dict or str or None
91+ params: dict | str | None
9292 Dictionary with the parameters to send to the url.
9393 Or the parameters already un url format.
9494 specific_resource: bool
@@ -98,17 +98,17 @@ def get_objects(self, endpoint, resource_id=None, params=None,
9898
9999 Returns
100100 -------
101- [HelpScoutObject]
101+ HelpScoutObject | list [HelpScoutObject]
102102 A list of objects returned by the api.
103103 """
104104 cls = HelpScoutObject .cls (endpoint , endpoint )
105- results = cls .from_results (
105+ results : list [ HelpScoutObject ] = cls .from_results (
106106 self .hit_ (endpoint , 'get' , resource_id , params = params ))
107107 if resource_id is not None or specific_resource :
108108 return results [0 ]
109109 return results
110110
111- def hit (self , endpoint , method , resource_id = None , data = None , params = None ):
111+ def hit (self , endpoint : str , method : str , resource_id : int | str | None = None , data : dict | None = None , params : dict | str | None = None ) -> list [ dict | None ] :
112112 """Hits the api and returns all the data.
113113 If several calls are needed due to pagination, control won't be
114114 returned to the caller until all is retrieved.
@@ -120,26 +120,26 @@ def hit(self, endpoint, method, resource_id=None, data=None, params=None):
120120 method: str
121121 The http method to hit the endpoint with.
122122 One of {'get', 'post', 'put', 'patch', 'delete', 'head', 'options'}
123- resource_id: int or str or None
123+ resource_id: int | str | None
124124 The id of the resource in the endpoint to query.
125125 E.g.: in "GET /v2/conversations/123 HTTP/1.1" the id would be 123.
126126 If None is provided, nothing will be done
127- data : dict or None
127+ dict : dict | None
128128 A dictionary with the data to send to the API as json.
129- params: dict or str or None
129+ params: dict | str | None
130130 Dictionary with the parameters to send to the url.
131131 Or the parameters already un url format.
132132
133133 Returns
134134 -------
135- [dict] or [None]
136- dict : when several objects are received from the API, a list of
135+ list [dict] | list [None]
136+ list : when several objects are received from the API, a list of
137137 dictionaries with HelpScout's _embedded data will be returned
138138 None if http 201 created or 204 no content are received.
139139 """
140140 return list (self .hit_ (endpoint , method , resource_id , data , params ))
141141
142- def hit_ (self , endpoint , method , resource_id = None , data = None , params = None ):
142+ def hit_ (self , endpoint : str , method : str , resource_id : int | str | None = None , data : dict | None = None , params : dict | str | None = None ) -> Generator [ dict | None , None , None ] :
143143 """Hits the api and yields the data.
144144
145145 Parameters
@@ -149,19 +149,19 @@ def hit_(self, endpoint, method, resource_id=None, data=None, params=None):
149149 method: str
150150 The http method to hit the endpoint with.
151151 One of {'get', 'post', 'put', 'patch', 'delete', 'head', 'options'}
152- resource_id: int or str or None
152+ resource_id: int | str | None
153153 The id of the resource in the endpoint to query.
154154 E.g.: in "GET /v2/conversations/123 HTTP/1.1" the id would be 123.
155155 If None is provided, nothing will be done
156- data: dict or None
156+ data: dict | None
157157 A dictionary with the data to send to the API as json.
158- params: dict or str or None
158+ params: dict | str | None
159159 Dictionary with the parameters to send to the url.
160160 Or the parameters already un url format.
161161
162162 Yields
163163 ------
164- dict or None
164+ dict | None
165165 Dictionary with HelpScout's _embedded data.
166166 None if http 201 created or 204 no content are received.
167167 """
@@ -197,7 +197,7 @@ def hit_(self, endpoint, method, resource_id=None, data=None, params=None):
197197 else :
198198 raise HelpScoutException (r .text )
199199
200- def _results_with_pagination (self , response , method ) :
200+ def _results_with_pagination (self , response : dict , method : str ) -> Generator [ dict , None , None ] :
201201 """Requests and yields pagination results.
202202
203203 Parameters
@@ -243,8 +243,7 @@ def _results_with_pagination(self, response, method):
243243 raise HelpScoutException (r .text )
244244
245245 def _authenticate (self ):
246- """Authenticates with the API and gets a token for subsequent requests.
247- """
246+ """Authenticates with the API and gets a token for subsequent requests."""
248247 url = urljoin (self .base_url , 'oauth2/token' )
249248 data = {
250249 'grant_type' : 'client_credentials' ,
@@ -287,7 +286,7 @@ def __eq__(self, other):
287286 self .sleep_on_rate_limit_exceeded ==
288287 other .sleep_on_rate_limit_exceeded )
289288
290- def __repr__ (self ):
289+ def __repr__ (self ) -> str :
291290 """Returns the object as a string."""
292291 name = self .__class__ .__name__
293292 attrs = (
@@ -307,12 +306,12 @@ def __repr__(self):
307306
308307class HelpScoutEndpointRequester :
309308
310- def __init__ (self , client , endpoint , specific_resource ):
309+ def __init__ (self , client : HelpScout , endpoint : str , specific_resource : bool ):
311310 """Client wrapper to perform requester.get/post/put/patch/delete.
312311
313312 Parameters
314313 ----------
315- client: HelpScoutClient
314+ client: HelpScout
316315 A help scout client instance to query the API.
317316 endpoint: str
318317 One of the endpoints in the API. E.g.: conversations, mailboxes.
@@ -324,7 +323,7 @@ def __init__(self, client, endpoint, specific_resource):
324323 self .endpoint = endpoint
325324 self .specific_resource = specific_resource
326325
327- def __getattr__ (self , method ) :
326+ def __getattr__ (self , method : str ) -> 'partial | HelpScoutEndpointRequester' :
328327 """Catches http methods like get, post, patch, put and delete.
329328 Returns a subrequester when methods not named after http methods are
330329 requested, as this are considered attributes of the main object, like
@@ -359,7 +358,7 @@ def __getattr__(self, method):
359358 False ,
360359 )
361360
362- def __getitem__ (self , resource_id ) :
361+ def __getitem__ (self , resource_id : int | str ) -> 'HelpScoutEndpointRequester' :
363362 """Returns a second endpoint requester extending the endpoint to a
364363 specific resource_id or resource_name.
365364
@@ -368,7 +367,7 @@ def __getitem__(self, resource_id):
368367
369368 Parameters
370369 ----------
371- resource_id: int or str
370+ resource_id: int | str
372371 The resource id or attribute available in the API through a
373372 specific call.
374373
@@ -408,7 +407,7 @@ def __eq__(self, other):
408407 self .endpoint == other .endpoint and
409408 self .client == other .client )
410409
411- def __repr__ (self ):
410+ def __repr__ (self ) -> str :
412411 """Returns the object as a string."""
413412 name = self .__class__ .__name__
414413 return '%s(app_id="%s", endpoint="%s")' % (
0 commit comments