Skip to content

Commit 1cea422

Browse files
authored
Merge pull request #124 from CiscoDevNet/v1.x
v1.5
2 parents 704904a + 30c080a commit 1cea422

File tree

8 files changed

+202
-70
lines changed

8 files changed

+202
-70
lines changed

docs/user/api.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,14 @@ Exceptions
324324
Warnings
325325
========
326326

327+
.. autoexception:: webexteamssdkWarning()
328+
:show-inheritance:
329+
:members:
330+
331+
.. autoexception:: ApiWarning()
332+
:show-inheritance:
333+
:members:
334+
327335
.. autoexception:: RateLimitWarning()
328336
:show-inheritance:
329337
:members:

webexteamssdk/__init__.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@
3333
import logging
3434

3535
import webexteamssdk.models.cards as cards
36-
from ._metadata import *
37-
from ._version import get_versions
36+
from ._metadata import (
37+
__author__, __author_email__, __copyright__, __description__,
38+
__download_url__, __license__, __title__, __url__, __version__,
39+
)
3840
from .api import WebexTeamsAPI
3941
from .exceptions import (
40-
AccessTokenError, ApiError, MalformedResponse, RateLimitError,
41-
RateLimitWarning, webexteamssdkException,
42+
AccessTokenError, ApiError, ApiWarning, MalformedResponse, RateLimitError,
43+
RateLimitWarning, webexteamssdkException, webexteamssdkWarning,
4244
)
4345
from .models.dictionary import dict_data_factory
4446
from .models.immutable import (
@@ -50,10 +52,6 @@
5052
from .utils import WebexTeamsDateTime
5153

5254

53-
__version__ = get_versions()['version']
54-
del get_versions
55-
56-
5755
# Initialize Package Logging
5856
logger = logging.getLogger(__name__)
5957
logger.addHandler(logging.NullHandler())

webexteamssdk/_metadata.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
SOFTWARE.
2323
"""
2424

25-
2625
__title__ = 'webexteamssdk'
2726
__description__ = 'Community-developed Python SDK for the Webex Teams APIs'
2827
__url__ = 'https://github.com/CiscoDevNet/webexteamssdk'
@@ -31,3 +30,11 @@
3130
__author_email__ = '[email protected]'
3231
__copyright__ = "Copyright (c) 2016-2019 Cisco Systems, Inc."
3332
__license__ = "MIT"
33+
34+
35+
# Only import the ._version module and compute the version when this module is
36+
# imported.
37+
if __name__ == "webexteamssdk._metadata":
38+
from ._version import get_versions
39+
__version__ = get_versions()['version']
40+
del get_versions

webexteamssdk/api/__init__.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
from .team_memberships import TeamMembershipsAPI
4949
from .teams import TeamsAPI
5050
from .webhooks import WebhooksAPI
51+
import os
5152

5253

5354
class WebexTeamsAPI(object):
@@ -69,7 +70,9 @@ def __init__(self, access_token=None, base_url=DEFAULT_BASE_URL,
6970
client_secret=None,
7071
oauth_code=None,
7172
redirect_uri=None,
72-
proxies=None):
73+
proxies=None,
74+
be_geo_id=None,
75+
caller=None):
7376
"""Create a new WebexTeamsAPI object.
7477
7578
An access token must be used when interacting with the Webex Teams API.
@@ -113,6 +116,12 @@ def __init__(self, access_token=None, base_url=DEFAULT_BASE_URL,
113116
OAuth process.
114117
proxies(dict): Dictionary of proxies passed on to the requests
115118
session.
119+
be_geo_id(basestring): Optional partner identifier for API usage
120+
tracking. Defaults to checking for a BE_GEO_ID environment
121+
variable.
122+
caller(basestring): Optional identifier for API usage tracking.
123+
Defaults to checking for a WEBEX_PYTHON_SDK_CALLER environment
124+
variable.
116125
117126
Returns:
118127
WebexTeamsAPI: A new WebexTeamsAPI object.
@@ -132,6 +141,8 @@ def __init__(self, access_token=None, base_url=DEFAULT_BASE_URL,
132141
check_type(oauth_code, basestring, optional=True)
133142
check_type(redirect_uri, basestring, optional=True)
134143
check_type(proxies, dict, optional=True)
144+
check_type(be_geo_id, basestring, optional=True)
145+
check_type(caller, basestring, optional=True)
135146

136147
access_token = access_token or WEBEX_TEAMS_ACCESS_TOKEN
137148

@@ -151,6 +162,10 @@ def __init__(self, access_token=None, base_url=DEFAULT_BASE_URL,
151162
redirect_uri=redirect_uri
152163
).access_token
153164

165+
# Set optional API metrics tracking variables from env vars if there
166+
be_geo_id = be_geo_id or os.environ.get('BE_GEO_ID')
167+
caller = caller or os.environ.get('WEBEX_PYTHON_SDK_CALLER')
168+
154169
# If an access token hasn't been provided as a parameter, environment
155170
# variable, or obtained via an OAuth exchange raise an error.
156171
if not access_token:
@@ -169,7 +184,9 @@ def __init__(self, access_token=None, base_url=DEFAULT_BASE_URL,
169184
base_url=base_url,
170185
single_request_timeout=single_request_timeout,
171186
wait_on_rate_limit=wait_on_rate_limit,
172-
proxies=proxies
187+
proxies=proxies,
188+
be_geo_id=be_geo_id,
189+
caller=caller
173190
)
174191

175192
# API wrappers

webexteamssdk/exceptions.py

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ class webexteamssdkException(Exception):
4646
pass
4747

4848

49+
class webexteamssdkWarning(webexteamssdkException, Warning):
50+
"""Base class for all webexteamssdk warnings."""
51+
pass
52+
53+
4954
class AccessTokenError(webexteamssdkException):
5055
"""Raised when an incorrect Webex Teams Access Token has been provided."""
5156
pass
@@ -73,6 +78,9 @@ def __init__(self, response):
7378
self.status = self.response.reason
7479
"""The HTTP status from the API response."""
7580

81+
self.description = RESPONSE_CODES.get(self.status_code)
82+
"""A description of the HTTP Response Code from the API docs."""
83+
7684
self.details = None
7785
"""The parsed JSON details from the API response."""
7886
if "application/json" in \
@@ -85,24 +93,40 @@ def __init__(self, response):
8593
self.message = self.details.get("message") if self.details else None
8694
"""The error message from the parsed API response."""
8795

88-
self.description = RESPONSE_CODES.get(self.status_code)
89-
"""A description of the HTTP Response Code from the API docs."""
96+
self.tracking_id = (
97+
self.details.get("trackingId") if self.details else None
98+
or self.response.headers.get("trackingId")
99+
)
100+
"""The Webex Tracking ID from the response."""
90101

91-
super(ApiError, self).__init__(
92-
"[{status_code}]{status} - {message}".format(
102+
self.error_message = (
103+
"[{status_code}]{status} - {detail}{tracking_id}".format(
93104
status_code=self.status_code,
94105
status=" " + self.status if self.status else "",
95-
message=self.message or self.description or "Unknown Error",
106+
detail=self.message or self.description or "Unknown Error",
107+
tracking_id=" [Tracking ID: " + self.tracking_id + "]"
108+
if self.tracking_id else "",
96109
)
97110
)
98111

112+
super(ApiError, self).__init__(self.error_message)
113+
99114
def __repr__(self):
100-
return "<{exception_name} [{status_code}]>".format(
115+
return "<{exception_name} [{status_code}]{status}>".format(
101116
exception_name=self.__class__.__name__,
102117
status_code=self.status_code,
118+
status=" " + self.status if self.status else "",
103119
)
104120

105121

122+
class ApiWarning(webexteamssdkWarning, ApiError):
123+
"""Warnings raised from API responses received from the Webex APIs.
124+
125+
Several data attributes are available for inspection.
126+
"""
127+
pass
128+
129+
106130
class RateLimitError(ApiError):
107131
"""Webex Teams Rate-Limit exceeded Error.
108132
@@ -125,26 +149,13 @@ def __init__(self, response):
125149
super(RateLimitError, self).__init__(response)
126150

127151

128-
class RateLimitWarning(UserWarning):
152+
class RateLimitWarning(ApiWarning, RateLimitError):
129153
"""Webex Teams rate-limit exceeded warning.
130154
131155
Raised when a rate-limit exceeded message is received and the request will
132156
be retried.
133157
"""
134-
135-
def __init__(self, response):
136-
assert isinstance(response, requests.Response)
137-
138-
# Extended warning attributes
139-
self.retry_after = max(1, int(response.headers.get('Retry-After', 15)))
140-
"""The `Retry-After` time period (in seconds) provided by Webex Teams.
141-
142-
Defaults to 15 seconds if the response `Retry-After` header isn't
143-
present in the response headers, and defaults to a minimum wait time of
144-
1 second if Webex Teams returns a `Retry-After` header of 0 seconds.
145-
"""
146-
147-
super(RateLimitWarning, self).__init__()
158+
pass
148159

149160

150161
class MalformedResponse(webexteamssdkException):

webexteamssdk/models/cards/actions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ def __init__(self, data=None, title=None, iconURL=None):
4949
self.iconURL = iconURL
5050

5151
super().__init__(
52-
serializable_properties=['data'],
53-
simple_properties=['title', 'iconURL', 'type'],
52+
serializable_properties=[],
53+
simple_properties=['data', 'title', 'iconURL', 'type'],
5454
)
5555

5656

webexteamssdk/models/cards/adaptive_card_component.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"""
2424

2525
import json
26+
import enum
2627

2728

2829
class AdaptiveCardComponent:
@@ -63,7 +64,10 @@ def to_dict(self):
6364
property_value = getattr(self, property_name, None)
6465

6566
if property_value is not None:
66-
serialized_data[property_name] = str(property_value)
67+
if isinstance(property_value, enum.Enum):
68+
property_value = str(property_value)
69+
70+
serialized_data[property_name] = property_value
6771

6872
# Recursively serialize sub-components
6973
for property_name in self.serializable_properties:

0 commit comments

Comments
 (0)