16
16
import logging
17
17
import warnings
18
18
from os import getenv
19
+ from typing import Union , Tuple , List , Dict , Any , Optional
19
20
20
21
import requests
21
22
from requests .adapters import HTTPAdapter , Retry , DEFAULT_RETRIES
22
23
24
+ from core .rp_issues import Issue
23
25
from ._local import set_current
24
26
from .core .rp_requests import (
25
27
HttpRequest ,
38
40
logger .addHandler (logging .NullHandler ())
39
41
40
42
41
- class RPClient ( object ) :
43
+ class RPClient :
42
44
"""Report portal client.
43
45
44
46
The class is supposed to use by Report Portal agents: both custom and
@@ -49,20 +51,44 @@ class RPClient(object):
49
51
thread to avoid request/response messing and other issues.
50
52
"""
51
53
52
- def __init__ (self ,
53
- endpoint ,
54
- project ,
55
- api_key = None ,
56
- log_batch_size = 20 ,
57
- is_skipped_an_issue = True ,
58
- verify_ssl = True ,
59
- retries = None ,
60
- max_pool_size = 50 ,
61
- launch_id = None ,
62
- http_timeout = (10 , 10 ),
63
- log_batch_payload_size = MAX_LOG_BATCH_PAYLOAD_SIZE ,
64
- mode = 'DEFAULT' ,
65
- ** kwargs ):
54
+ _log_manager : LogManager = ...
55
+ api_v1 : str = ...
56
+ api_v2 : str = ...
57
+ base_url_v1 : str = ...
58
+ base_url_v2 : str = ...
59
+ endpoint : str = ...
60
+ is_skipped_an_issue : bool = ...
61
+ launch_id : str = ...
62
+ log_batch_size : int = ...
63
+ log_batch_payload_size : int = ...
64
+ project : str = ...
65
+ api_key : str = ...
66
+ verify_ssl : Union [bool , str ] = ...
67
+ retries : int = ...
68
+ max_pool_size : int = ...
69
+ http_timeout : Union [float , Tuple [float , float ]] = ...
70
+ session : requests .Session = ...
71
+ step_reporter : StepReporter = ...
72
+ mode : str = ...
73
+ _skip_analytics : str = ...
74
+ _item_stack : List [str ] = ...
75
+
76
+ def __init__ (
77
+ self ,
78
+ endpoint : str ,
79
+ project : str ,
80
+ api_key : str = None ,
81
+ log_batch_size : int = 20 ,
82
+ is_skipped_an_issue : bool = True ,
83
+ verify_ssl : bool = True ,
84
+ retries : int = None ,
85
+ max_pool_size : int = 50 ,
86
+ launch_id : str = None ,
87
+ http_timeout : Union [float , Tuple [float , float ]] = (10 , 10 ),
88
+ log_batch_payload_size : int = MAX_LOG_BATCH_PAYLOAD_SIZE ,
89
+ mode : str = 'DEFAULT' ,
90
+ ** kwargs : Any
91
+ ) -> None :
66
92
"""Initialize required attributes.
67
93
68
94
:param endpoint: Endpoint of the report portal service
@@ -110,28 +136,28 @@ def __init__(self,
110
136
if not self .api_key :
111
137
if 'token' in kwargs :
112
138
warnings .warn (
113
- message = " Argument `token` is deprecated since 5.3.5 and "
114
- " will be subject for removing in the next major "
115
- " version. Use `api_key` argument instead." ,
139
+ message = ' Argument `token` is deprecated since 5.3.5 and '
140
+ ' will be subject for removing in the next major '
141
+ ' version. Use `api_key` argument instead.' ,
116
142
category = DeprecationWarning ,
117
143
stacklevel = 2
118
144
)
119
145
self .api_key = kwargs ['token' ]
120
146
121
147
if not self .api_key :
122
148
warnings .warn (
123
- message = " Argument `api_key` is `None` or empty string, "
124
- "that's not supposed to happen because Report "
125
- " Portal is usually requires an authorization key. "
126
- " Please check your code." ,
149
+ message = ' Argument `api_key` is `None` or empty string, '
150
+ 'that is not supposed to happen because Report '
151
+ ' Portal is usually requires an authorization key. '
152
+ ' Please check your code.' ,
127
153
category = RuntimeWarning ,
128
154
stacklevel = 2
129
155
)
130
156
131
157
self .__init_session ()
132
158
self .__init_log_manager ()
133
159
134
- def __init_session (self ):
160
+ def __init_session (self ) -> None :
135
161
retry_strategy = Retry (
136
162
total = self .retries ,
137
163
backoff_factor = 0.1 ,
@@ -148,18 +174,18 @@ def __init_session(self):
148
174
self .api_key )
149
175
self .session = session
150
176
151
- def __init_log_manager (self ):
177
+ def __init_log_manager (self ) -> None :
152
178
self ._log_manager = LogManager (
153
179
self .endpoint , self .session , self .api_v2 , self .launch_id ,
154
180
self .project , max_entry_number = self .log_batch_size ,
155
181
max_payload_size = self .log_batch_payload_size ,
156
182
verify_ssl = self .verify_ssl )
157
183
158
184
def finish_launch (self ,
159
- end_time ,
160
- status = None ,
161
- attributes = None ,
162
- ** kwargs ) :
185
+ end_time : str ,
186
+ status : str = None ,
187
+ attributes : Optional [ Union [ List , Dict ]] = None ,
188
+ ** kwargs : Any ) -> Optional [ str ] :
163
189
"""Finish launch.
164
190
165
191
:param end_time: Launch end time
@@ -169,7 +195,7 @@ def finish_launch(self,
169
195
:param attributes: Launch attributes
170
196
"""
171
197
if self .launch_id is NOT_FOUND or not self .launch_id :
172
- logger .warning (" Attempt to finish non-existent launch" )
198
+ logger .warning (' Attempt to finish non-existent launch' )
173
199
return
174
200
url = uri_join (self .base_url_v2 , 'launch' , self .launch_id , 'finish' )
175
201
request_payload = LaunchFinishRequest (
@@ -188,14 +214,14 @@ def finish_launch(self,
188
214
return response .message
189
215
190
216
def finish_test_item (self ,
191
- item_id ,
192
- end_time ,
193
- status = None ,
194
- issue = None ,
195
- attributes = None ,
196
- description = None ,
197
- retry = False ,
198
- ** kwargs ) :
217
+ item_id : str ,
218
+ end_time : str ,
219
+ status : str = None ,
220
+ issue : Optional [ Issue ] = None ,
221
+ attributes : Optional [ Union [ List , Dict ]] = None ,
222
+ description : str = None ,
223
+ retry : bool = False ,
224
+ ** kwargs : Any ) -> Optional [ str ] :
199
225
"""Finish suite/case/step/nested step item.
200
226
201
227
:param item_id: ID of the test item
@@ -212,7 +238,7 @@ def finish_test_item(self,
212
238
"True" or "False"
213
239
"""
214
240
if item_id is NOT_FOUND or not item_id :
215
- logger .warning (" Attempt to finish non-existent item" )
241
+ logger .warning (' Attempt to finish non-existent item' )
216
242
return
217
243
url = uri_join (self .base_url_v2 , 'item' , item_id )
218
244
request_payload = ItemFinishRequest (
@@ -234,7 +260,7 @@ def finish_test_item(self,
234
260
logger .debug ('response message: %s' , response .message )
235
261
return response .message
236
262
237
- def get_item_id_by_uuid (self , uuid ) :
263
+ def get_item_id_by_uuid (self , uuid : str ) -> Optional [ str ] :
238
264
"""Get test item ID by the given UUID.
239
265
240
266
:param uuid: UUID returned on the item start
@@ -245,7 +271,7 @@ def get_item_id_by_uuid(self, uuid):
245
271
verify_ssl = self .verify_ssl ).make ()
246
272
return response .id if response else None
247
273
248
- def get_launch_info (self ):
274
+ def get_launch_info (self ) -> Optional [ Dict ] :
249
275
"""Get the current launch information.
250
276
251
277
:return dict: Launch information in dictionary
@@ -268,15 +294,15 @@ def get_launch_info(self):
268
294
launch_info = {}
269
295
return launch_info
270
296
271
- def get_launch_ui_id (self ):
297
+ def get_launch_ui_id (self ) -> Optional [ Dict ] :
272
298
"""Get UI ID of the current launch.
273
299
274
300
:return: UI ID of the given launch. None if UI ID has not been found.
275
301
"""
276
302
launch_info = self .get_launch_info ()
277
303
return launch_info .get ('id' ) if launch_info else None
278
304
279
- def get_launch_ui_url (self ):
305
+ def get_launch_ui_url (self ) -> Optional [ str ] :
280
306
"""Get UI URL of the current launch.
281
307
282
308
:return: launch URL or all launches URL.
@@ -289,7 +315,7 @@ def get_launch_ui_url(self):
289
315
if not mode :
290
316
mode = self .mode
291
317
292
- launch_type = " launches" if mode .upper () == 'DEFAULT' else 'userdebug'
318
+ launch_type = ' launches' if mode .upper () == 'DEFAULT' else 'userdebug'
293
319
294
320
path = 'ui/#{project_name}/{launch_type}/all/{launch_id}' .format (
295
321
project_name = self .project .lower (), launch_type = launch_type ,
@@ -298,7 +324,7 @@ def get_launch_ui_url(self):
298
324
logger .debug ('get_launch_ui_url - ID: %s' , self .launch_id )
299
325
return url
300
326
301
- def get_project_settings (self ):
327
+ def get_project_settings (self ) -> Optional [ Dict ] :
302
328
"""Get project settings.
303
329
304
330
:return: HTTP response in dictionary
@@ -308,7 +334,8 @@ def get_project_settings(self):
308
334
verify_ssl = self .verify_ssl ).make ()
309
335
return response .json if response else None
310
336
311
- def log (self , time , message , level = None , attachment = None , item_id = None ):
337
+ def log (self , time : str , message : str , level : Optional [Union [int , str ]] = None ,
338
+ attachment : Optional [Dict ] = None , item_id : Optional [str ] = None ) -> None :
312
339
"""Send log message to the Report Portal.
313
340
314
341
:param time: Time in UTC
@@ -319,18 +346,18 @@ def log(self, time, message, level=None, attachment=None, item_id=None):
319
346
"""
320
347
self ._log_manager .log (time , message , level , attachment , item_id )
321
348
322
- def start (self ):
349
+ def start (self ) -> None :
323
350
"""Start the client."""
324
351
self ._log_manager .start ()
325
352
326
353
def start_launch (self ,
327
- name ,
328
- start_time ,
329
- description = None ,
330
- attributes = None ,
331
- rerun = False ,
332
- rerun_of = None ,
333
- ** kwargs ):
354
+ name : str ,
355
+ start_time : str ,
356
+ description : Optional [ str ] = None ,
357
+ attributes : Optional [ Union [ List , Dict ]] = None ,
358
+ rerun : bool = False ,
359
+ rerun_of : Optional [ str ] = None ,
360
+ ** kwargs ) -> Optional [ str ] :
334
361
"""Start a new launch with the given parameters.
335
362
336
363
:param name: Launch name
@@ -346,12 +373,16 @@ def start_launch(self,
346
373
# We are moving 'mode' param to the constructor, next code for the
347
374
# transition period only.
348
375
my_kwargs = dict (kwargs )
349
- if 'mode' in my_kwargs .keys ():
350
- mode = my_kwargs ['mode' ]
376
+ mode = my_kwargs .get ('mode' )
377
+ if 'mode' in my_kwargs :
378
+ warnings .warn (
379
+ message = 'Argument `mode` is deprecated since 5.2.5 and will be subject for removing in the '
380
+ 'next major version. Use `mode` argument in the class constructor instead.' ,
381
+ category = DeprecationWarning ,
382
+ stacklevel = 2
383
+ )
351
384
del my_kwargs ['mode' ]
352
- if not mode :
353
- mode = self .mode
354
- else :
385
+ if not mode :
355
386
mode = self .mode
356
387
357
388
request_payload = LaunchStartRequest (
@@ -386,18 +417,18 @@ def start_launch(self,
386
417
return self .launch_id
387
418
388
419
def start_test_item (self ,
389
- name ,
390
- start_time ,
391
- item_type ,
392
- description = None ,
393
- attributes = None ,
394
- parameters = None ,
395
- parent_item_id = None ,
396
- has_stats = True ,
397
- code_ref = None ,
398
- retry = False ,
399
- test_case_id = None ,
400
- ** kwargs ) :
420
+ name : str ,
421
+ start_time : str ,
422
+ item_type : str ,
423
+ description : Optional [ str ] = None ,
424
+ attributes : Optional [ List [ Dict ]] = None ,
425
+ parameters : Optional [ Dict ] = None ,
426
+ parent_item_id : Optional [ str ] = None ,
427
+ has_stats : bool = True ,
428
+ code_ref : Optional [ str ] = None ,
429
+ retry : bool = False ,
430
+ test_case_id : Optional [ str ] = None ,
431
+ ** _ : Any ) -> Optional [ str ] :
401
432
"""Start case/step/nested step item.
402
433
403
434
:param name: Name of the test item
@@ -419,8 +450,7 @@ def start_test_item(self,
419
450
:param test_case_id: A unique ID of the current step
420
451
"""
421
452
if parent_item_id is NOT_FOUND :
422
- logger .warning ("Attempt to start item for non-existent parent "
423
- "item" )
453
+ logger .warning ('Attempt to start item for non-existent parent item.' )
424
454
return
425
455
if parent_item_id :
426
456
url = uri_join (self .base_url_v2 , 'item' , parent_item_id )
@@ -455,11 +485,12 @@ def start_test_item(self,
455
485
str (response .json ))
456
486
return item_id
457
487
458
- def terminate (self , * args , ** kwargs ) :
488
+ def terminate (self , * _ : Any , ** __ : Any ) -> None :
459
489
"""Call this to terminate the client."""
460
490
self ._log_manager .stop ()
461
491
462
- def update_test_item (self , item_uuid , attributes = None , description = None ):
492
+ def update_test_item (self , item_uuid : str , attributes : Optional [Union [List , Dict ]] = None ,
493
+ description : Optional [str ] = None ) -> Optional [str ]:
463
494
"""Update existing test item at the Report Portal.
464
495
465
496
:param str item_uuid: Test item UUID returned on the item start
@@ -480,11 +511,11 @@ def update_test_item(self, item_uuid, attributes=None, description=None):
480
511
logger .debug ('update_test_item - Item: %s' , item_id )
481
512
return response .message
482
513
483
- def current_item (self ):
514
+ def current_item (self ) -> Optional [ str ] :
484
515
"""Retrieve the last item reported by the client."""
485
516
return self ._item_stack [- 1 ] if len (self ._item_stack ) > 0 else None
486
517
487
- def clone (self ):
518
+ def clone (self ) -> 'RPClient' :
488
519
"""Clone the client object, set current Item ID as cloned item ID.
489
520
490
521
:returns: Cloned client object
@@ -509,7 +540,7 @@ def clone(self):
509
540
cloned ._item_stack .append (current_item )
510
541
return cloned
511
542
512
- def __getstate__ (self ):
543
+ def __getstate__ (self ) -> Dict [ str , Any ] :
513
544
"""Control object pickling and return object fields as Dictionary.
514
545
515
546
:returns: object state dictionary
@@ -522,7 +553,7 @@ def __getstate__(self):
522
553
del state ['_log_manager' ]
523
554
return state
524
555
525
- def __setstate__ (self , state ) :
556
+ def __setstate__ (self , state : Dict [ str , Any ]) -> None :
526
557
"""Control object pickling, receives object state as Dictionary.
527
558
528
559
:param dict state: object state dictionary
0 commit comments