28
28
_LINKS_ATTRIBUTE = '_dynamic_links'
29
29
_LINKS_BASE_URL = 'https://firebasedynamiclinks.googleapis.com/v1/'
30
30
31
+ _UNKNOWN_ERROR = 'unknown-error'
32
+
31
33
PLATFORM_DESKTOP = 'desktop'
32
34
PLATFORM_IOS = 'ios'
33
35
PLATFORM_ANDROID = 'android'
@@ -50,41 +52,42 @@ def get_link_stats(short_link, stat_options, app=None):
50
52
app: A Firebase ``App instance`` (optional). (If missing uses default app.)
51
53
52
54
Returns:
53
- LinkStats: An ``LinkStats`` object. (containing an array of ``EventStats``)
55
+ LinkStats: A ``LinkStats`` object. (containing an array of ``EventStats``)
54
56
55
57
Raises:
56
58
ValueError: If any of the arguments are invalid.
57
- url must start with the protocol "http"
58
- stat_options should have a field with duration_days > 0
59
+ short_link must start with the "https" protocol.
60
+ stat_options should have duration_days > 0.
59
61
"""
60
62
return _get_link_service (app ).get_stats (short_link , stat_options )
61
63
62
64
def _get_link_service (app ):
63
- """Returns an _LinksService instance for an App.
65
+ """Returns an _DynamicLinksService instance for an App.
64
66
65
- If the App already has a _LinksService associated with it, simply returns
66
- it. Otherwise creates a new _LinksService , and adds it to the App before
67
+ If the App already has a _DynamicLinksService associated with it, simply returns
68
+ it. Otherwise creates a new _DynamicLinksService , and adds it to the App before
67
69
returning it.
68
70
69
71
Args:
70
72
app: A Firebase App instance (or None to use the default App).
71
73
72
74
Returns:
73
- _LinksService : An `_LinksService ` for the specified App instance.
75
+ _DynamicLinksService : An `_DynamicLinksService ` for the specified App instance.
74
76
75
77
Raises:
76
78
ValueError: If the app argument is invalid.
77
79
"""
78
- return _utils .get_app_service (app , _LINKS_ATTRIBUTE , _LinksService )
80
+ return _utils .get_app_service (app , _LINKS_ATTRIBUTE , _DynamicLinksService )
79
81
80
82
81
83
class LinkStats (object ):
82
- """The ``LinkStats`` object is returned by get_link_stats, it contains a list of ``EventStats``"""
84
+ """The ``LinkStats`` object is returned by get_link_stats, it contains a list of
85
+ ``EventStats``"""
83
86
def __init__ (self , event_stats ):
84
87
if not isinstance (event_stats , (list , tuple )):
85
88
raise ValueError ('Invalid data argument: {0}. Must be a list or tuple'
86
89
.format (event_stats ))
87
- if event_stats and not isinstance (event_stats [ 0 ] , EventStats ):
90
+ if not all ( isinstance (es , EventStats ) for es in event_stats ):
88
91
raise ValueError ('Invalid data argument: elements of event stats must be' +
89
92
' "EventStats", found{}' .format (type (event_stats [0 ])))
90
93
self ._stats = event_stats
@@ -117,28 +120,22 @@ class EventStats(object):
117
120
118
121
def __init__ (self , platform , event , count ):
119
122
"""Create new instance of EventStats(platform, event, count)"""
120
- if isinstance (platform , six .string_types ) and platform in self ._platforms .keys ():
121
- raise ValueError (('Raw string "{}" detected. Use a dynamic_links.PLATFORM_* constant' +
122
- ' or the make_from_strings() method.' ).format (platform ))
123
123
if not isinstance (platform , six .string_types ) or platform not in self ._platforms .values ():
124
- raise ValueError ('platform {}, not recognized ' .format (platform ))
124
+ raise ValueError ('Invalid Platform value "{}". ' .format (platform ))
125
125
self ._platform = platform
126
126
127
- if isinstance (event , six .string_types ) and event in self ._event_types .keys ():
128
- raise ValueError (('Raw string {} detected. Use one of the dynamic_links.EVENT_TYPES_' +
129
- ' constants, or the make_from_strings() method.' ).format (event ))
130
127
if not isinstance (event , six .string_types ) or event not in self ._event_types .values ():
131
- raise ValueError ('event_type {}, not recognized ' .format (event ))
128
+ raise ValueError ('Invalid Event Type value "{}". ' .format (event ))
132
129
self ._event = event
133
130
134
131
if not isinstance (count , int ) or isinstance (count , bool ) or count < 0 :
135
132
raise ValueError ('Count: {} must be a non negative int' .format (count ))
136
133
self ._count = count
137
134
138
135
@classmethod
139
- def make_from_strings (cls , platform , event , count ):
140
- """make_from_strings creates an EventStat object given the appropriate constants. e.g:
141
- make_from_strings (platform=PLATFORM_DESKTOP, event=EVENT_TYPE_REDIRECT, count=4)"""
136
+ def _make_from_strings (cls , platform , event , count ):
137
+ """_make_from_strings creates an EventStat object given the appropriate constants. e.g:
138
+ _make_from_strings (platform=PLATFORM_DESKTOP, event=EVENT_TYPE_REDIRECT, count=4)"""
142
139
return EventStats (cls ._platforms [platform ],
143
140
cls ._event_types [event ],
144
141
int (count ))
@@ -158,22 +155,19 @@ def count(self):
158
155
159
156
class StatOptions (object ):
160
157
def __init__ (self , duration_days ):
161
- self .duration_days = duration_days
162
-
163
- @property
164
- def duration_days (self ):
165
- return self ._duration_days
166
-
167
- @duration_days .setter
168
- def duration_days (self , duration_days ):
169
158
if (isinstance (duration_days , bool )
170
159
or not isinstance (duration_days , int )
171
160
or duration_days < 1 ):
172
161
raise ValueError ('duration_days must be positive integer (got {})'
173
162
.format (duration_days ))
174
163
self ._duration_days = duration_days
175
164
176
- class _LinksService (object ):
165
+ @property
166
+ def duration_days (self ):
167
+ return self ._duration_days
168
+
169
+
170
+ class _DynamicLinksService (object ):
177
171
"""Provides methods for the Firebase dynamic links interaction"""
178
172
179
173
INTERNAL_ERROR = 'internal-error'
@@ -188,9 +182,7 @@ def __init__(self, app):
188
182
def _format_request_string (self , short_link , options ):
189
183
days = options .duration_days
190
184
# Complaints about the named second argument needed to replace "/"
191
- #pylint: disable=redundant-keyword-arg
192
- url_quoted = urllib .parse .quote (short_link , safe = '' )
193
- #pylint: enable=redundant-keyword-arg
185
+ url_quoted = urllib .parse .quote (short_link , safe = '' ) #pylint: disable=redundant-keyword-arg
194
186
return self ._request_string .format (url_quoted , days )
195
187
196
188
def get_stats (self , short_link , stat_options ):
@@ -203,13 +195,12 @@ def get_stats(self, short_link, stat_options):
203
195
204
196
request_string = self ._format_request_string (short_link , stat_options )
205
197
try :
206
- resp = self ._client .body ('get' , request_string )
198
+ resp = self ._client .body ('get' , request_string , timeout = self . _timeout )
207
199
except requests .exceptions .RequestException as error :
208
-
209
200
self ._handle_error (error )
210
201
else :
211
- link_event_stats_dict = resp .get ('linkEventStats' , [])
212
- event_stats = [EventStats .make_from_strings (** es ) for es in link_event_stats_dict ]
202
+ link_event_stats = resp .get ('linkEventStats' , [])
203
+ event_stats = [EventStats ._make_from_strings (** es ) for es in link_event_stats ]
213
204
return LinkStats (event_stats )
214
205
215
206
def _handle_error (self , error ):
@@ -225,7 +216,7 @@ def _handle_error(self, error):
225
216
except ValueError :
226
217
pass
227
218
error_details = data .get ('error' , {})
228
- code = error_details .get ('code' , 'undefined error code' )
219
+ code = error_details .get ('code' , _UNKNOWN_ERROR )
229
220
msg = error_details .get ('message' )
230
221
if not msg :
231
222
msg = 'Unexpected HTTP response with status: {0}; body: {1}' .format (
0 commit comments