@@ -195,6 +195,10 @@ class RequestFlaskResponse:
195
195
"""
196
196
197
197
def __init__ (self , response ):
198
+ """Constructor parameter
199
+
200
+ - ``response`` from request.
201
+ """
198
202
199
203
self ._response = response
200
204
self .status_code = response .status_code
@@ -214,6 +218,11 @@ class Client:
214
218
"""Common class for flask authenticated testing."""
215
219
216
220
def __init__ (self , auth : Authenticator , default_login : str | None = None ):
221
+ """Constructor parameters.
222
+
223
+ - ``auth`` authenticator
224
+ - ``default_login`` if not ``login`` is set.
225
+ """
217
226
self ._auth = auth
218
227
self ._default_login = default_login
219
228
@@ -260,18 +269,23 @@ def request(self, method: str, path: str, status: int|None = None, auth: str|Non
260
269
return res
261
270
262
271
def get (self , path , ** kwargs ):
272
+ """HTTP GET request."""
263
273
return self .request ("GET" , path , ** kwargs )
264
274
265
275
def post (self , path , ** kwargs ):
276
+ """HTTP POST request."""
266
277
return self .request ("POST" , path , ** kwargs )
267
278
268
279
def put (self , path , ** kwargs ):
280
+ """HTTP PUT request."""
269
281
return self .request ("PUT" , path , ** kwargs )
270
282
271
283
def patch (self , path , ** kwargs ):
284
+ """HTTP PATCH request."""
272
285
return self .request ("PATCH" , path , ** kwargs )
273
286
274
287
def delete (self , path , ** kwargs ):
288
+ """HTTP DELETE request."""
275
289
return self .request ("DELETE" , path , ** kwargs )
276
290
277
291
def check (self , method : str , path : str , status : int , content : str | None = None , ** kwargs ):
@@ -291,6 +305,7 @@ def check(self, method: str, path: str, status: int, content: str|None = None, *
291
305
# get HTTP response
292
306
res = self .request (method , path , status = status , ** kwargs )
293
307
308
+ # check contents
294
309
if content is not None :
295
310
if not re .search (content , res .text , re .DOTALL ): # pragma: no cover
296
311
log .error (f"cannot find { content } in { res .text } " )
@@ -303,15 +318,23 @@ class RequestClient(Client):
303
318
"""Request-based test provider."""
304
319
305
320
def __init__ (self , auth : Authenticator , base_url : str , default_login = None ):
321
+ """Constructor parameters.
322
+
323
+ - ``auth`` authenticator
324
+ - ``base_url`` target server
325
+ - ``default_login`` if not ``login`` is set.
326
+ """
306
327
super ().__init__ (auth , default_login )
307
328
self ._base_url = base_url
308
329
# reuse connections, otherwise it is too slow…
309
330
from requests import Session
310
331
self ._requests = Session ()
311
332
312
333
def _request (self , method : str , path : str , ** kwargs ):
313
- # ensure file upload compatibility
334
+ """Actual request handling."""
335
+
314
336
if "data" in kwargs :
337
+ # "data" to "files" parameter transfer
315
338
data = kwargs ["data" ]
316
339
files : dict [str , Any ] = {}
317
340
for name , whatever in data .items ():
@@ -324,39 +347,50 @@ def _request(self, method: str, path: str, **kwargs):
324
347
files [name ] = (file_name , file_handle , file_type )
325
348
else :
326
349
pass
327
- # complete "data" to "files" parameter transfer
328
350
for name in files :
329
351
del data [name ]
330
352
assert "files" not in kwargs
331
353
kwargs ["files" ] = files
332
354
# sanity
333
355
assert not (files and "json" in kwargs ), "cannot mix file upload and json?"
356
+
334
357
res = self ._requests .request (method , self ._base_url + path , ** kwargs )
358
+
335
359
return RequestFlaskResponse (res )
336
360
337
361
338
362
class FlaskClient (Client ):
339
363
"""Flask-based test provider."""
340
364
341
365
def __init__ (self , auth : Authenticator , client , default_login = None ):
366
+ """Constructor parameters.
367
+
368
+ - ``auth`` authenticator
369
+ - ``client`` Flask ``test_client``
370
+ - ``default_login`` if not ``login`` is set.
371
+ """
342
372
super ().__init__ (auth , default_login )
343
373
self ._client = client
344
374
345
375
def _request (self , method : str , path : str , ** kwargs ):
376
+ """Actual request handling."""
346
377
return self ._client .open (method = method , path = path , ** kwargs )
347
378
348
379
349
380
@pytest .fixture
350
381
def ft_authenticator ():
351
382
"""Pytest Fixture: ft_authenticator."""
383
+
352
384
level = os .environ .get ("FLASK_TESTER_LOG_LEVEL" , "NOTSET" )
353
385
log .setLevel (logging .DEBUG if level == "DEBUG" else
354
386
logging .INFO if level == "INFO" else
355
387
logging .WARNING if level == "WARNING" else
356
388
logging .ERROR if level == "ERROR" else
357
389
logging .CRITICAL if level == "CRITICAL" else
358
390
logging .NOTSET )
391
+
359
392
allow = os .environ .get ("FLASK_TESTER_ALLOW" , "bearer basic param" ).split (" " )
393
+
360
394
# per-scheme parameters, must be consistent with FSA configuration
361
395
user = os .environ .get ("FLASK_TESTER_USER" , "USER" )
362
396
pwd = os .environ .get ("FLASK_TESTER_PASS" , "PASS" )
@@ -365,18 +399,23 @@ def ft_authenticator():
365
399
header = os .environ .get ("FLASK_TESTER_HEADER" , "Auth" )
366
400
cookie = os .environ .get ("FLASK_TESTER_COOKIE" , "auth" )
367
401
tparam = os .environ .get ("FLASK_TESTER_TPARAM" , "AUTH" )
402
+
368
403
# create authenticator, possibly with initial credentials
369
404
auth = Authenticator (allow , user = user , pwd = pwd , login = login , bearer = bearer , header = header , cookie = cookie , tparam = tparam )
405
+
370
406
if "FLASK_TESTER_AUTH" in os .environ :
371
407
auth .setPasses (os .environ ["FLASK_TESTER_AUTH" ].split ("," ))
408
+
372
409
yield auth
373
410
374
411
375
412
@pytest .fixture
376
413
def ft_client (ft_authenticator ):
377
414
"""Pytest Fixture: ft_client."""
415
+
378
416
default_login = os .environ .get ("FLASK_TESTER_DEFAULT" , None )
379
417
client : Client
418
+
380
419
if "FLASK_TESTER_URL" in os .environ : # pragma: no cover
381
420
app_url = os .environ ["FLASK_TESTER_URL" ]
382
421
client = RequestClient (ft_authenticator , app_url , default_login )
@@ -392,4 +431,5 @@ def ft_client(ft_authenticator):
392
431
client = FlaskClient (ft_authenticator , app .test_client (), default_login )
393
432
else : # pragma: no cover
394
433
raise FlaskTesterError ("no Flask application to test" )
434
+
395
435
yield client
0 commit comments