Package: asyncio-requests
Async HTTP / SOAP / FTP Request LibraryThis library provides the functionality to make async API calls via HTTP / SOAP / FTP protocols via a config.Installationpip install asyncio-requestsHTTPUses aiohttp internallyHas an inbuilt circuit breakerCurrently supports infinite nested depth of pre and post processorsRetry FunctionalityExceptions can be contributed in the utilities, and you can use your own exceptions in the circuit breaker config as well.Direct File Upload functionality.Params -ParamData TypeOptional/RequiredHelpurlStrRequiredURL to be hitdataDictOptionaldata to be sent. It can be dict or str. If dict, it will be dumped via ujson.dumps methodauthauth objectOptionalAuth param is expected to be an auth object of your choice which is accepted by aiohttp. Eg - aiohttp.BasicAuth(username, password)protocolStrRequired(HTTP/HTTPS/SOAP/FTP)pre_processor_configDictOptionalpre processor indicates an action (file download/api call or anything) to be done before making the actual API call.Takes async callable object which is executed before making the actual API call - RequiredParams dictionary where key is parameter to the callable object passed in pre processor and values is parameter valueThe callable object/function can be used from the utilities folder which is contributed by all or your own function address.You can nest the whole API. Eg - you can pass the address of asyncio_requests.request function too. The response will be a nested one. (Explained via example down)post_processor_configDictOptionalpost processor indicates an action (file download or delete file or api call or anything) to be done post making the actual API call.function: Takes async callable object/function address which is executed after making request - RequiredParams: Takes dictionary where key is parameter to the callable object/function passed in pre-processor and values is parameter valuesimilar to pre-processor, difference being this is executed after making an API call.Eg - if you want to send the data of a file in the API call and the file needs to be downloaded. You can have a file download pre-processor function and have a file deletion post processor function.protocol_infoDictRequiredrequest_type - Str. Required. GET/PUT/POST/PATCH/DELETE/OPTIONStimeout -      Int. Optional. Default HTTP timeout is 15 seconds. Can be overridden if specified.certificate -  Tuple(str, str)  Optional. Used for SSL certificates and expected in the format Tuple('certificate path', 'certificate key path')verify_ssl -   Boolean. Optional. SSL is enabled by defaultcookies -      Str. Optionalheaders -      Dict. Requiredtrace_config - List[tracer_callable_object] Optional. default tracer is aiohttp.TraceConfig() - Optionalhttp_file_upload_config: Dict use this only if you want to send file in request. If you use this config then only file will be sent in request - Optionallocal_filepath: machine file path for file to be sent in requestfile_key: The key in which the file data is to be sentserialization: serializer callable object. Optional. If you want to use any json serializer then you can pass here default is ujson.dumps.circuit_breaker_config - Dict - Optionalmaximum_failures - Int. Optional. maximum failures you want to allow for request default is 5timeout - Int Optional. seconds timeout you want to keep for request default is 60 secondsretry_config - Dict - Optionalname - Str requiredallowed_retries - Int. Required this is for how many retries you want to performretriable_exceptions - List[]. Optional. list of exception types indicating which exceptions can cause a retry. If None every exception is considered retriableabortable_exceptions - List[]. Optional. list of exception types indicating which exceptions should abort failsafe run immediately and be propagated out of failsafe. If None, no exception is considered abortable.on_retries_exhausted - callable object. Optional. callable/function_address which will be invoked on retry exhausted eventon_failed_attempt - callable object. Optional. callable/function_address that will be invoked on a failed attempt eventon_abort - callable object. Optional. callable that will be invoked on an abort eventdelay - Int Optional. seconds of delay between retries default is 0.max_delay - Int Optional. seconds of max delay between retries default 0jitter: Boolean Optional. False when you want to keep the wait between calls constant else TrueDefaults -By default, circuit breaker is not enabled and is activated only if provided with its config.By default, retry is not enabled and is activated only if provided with its config.Default Request tracer is enabled which provides the traces of the whole request wrt data chunks, dns cache hit etc.In case of user specific request tracer, a list of request tracer objects is expected which will override the default tracer.Default serialization is via ujson and can be overwritten by specifying oneSSL is enabled by defaultHow to UseDesign the http request payload as per below formatMock url -https://api.fyndx1.de/masquerader/v1/aio-request-test/postis live and open for use.importaiohttpfromasyncio_requests.asyncio_requestimportrequestawaitrequest(url="URL FOR REQUEST",# str <Required>data={"key":"val"}or"",# Data to be sent in body as dict or str,auth=aiohttp.BasicAuth('username','password'),# This auth object is to be made by the user itself as there are n number of# auth mechanisms to add to. Eg - auth=aiohttp.BasicAuth(username, password). Its an Optional field.protocol="REQUEST PROTOCOL",# str <Required> (HTTP/HTTPS)protocol_info={"request_type":"GET",# str <Required>"timeout":15,# int <Optional> Default - 15"certificate":('',''),# Tuple(str, str) <Optional>,"verify_ssl":True,# Boolean <Optional>,"cookies":"",# str <Optional>,"headers":{},# dict <Optional>,"http_file_upload_config":{# optional Include only if you want call api with file. If this is included api body will have only file"local_filepath":"required",# File path to be sent"file_key":"required",# File to be sent on which key in request body"file_upload_chunk_size":"optional"# size of stream if streaming upload is required# After making API if you want to delete file then add value as True default is false.},"http_file_download_config":{"download_filepath":"required"# In case file downloads, location to which file is stored"file_download_chunk_size":"optional"# chunk size of a stream.}"circuit_breaker_config":{# Optional"maximum_failures":int,# Optional Failures allowed"timeout":int,# Optional time in seconds"retry_config":{# Optional Include this if you want retry API calls if failed on first time"name":str,# Required Any name"allowed_retries":int,# Required number of retries you want to make"retriable_exceptions":[<callableobject>]# Optional"abortable_exceptions":[<callableobject>]# Optional"on_retries_exhausted":<callableobject>,# Optional callable that will be invoked on a retries exhausted event,"on_failed_attempt":<callableobject>,# Optional callable that will be invoked on a failed attempt event,"on_abort":<callableobject>,# Optional callable that will be invoked on an abort event,"delay":int,# seconds of delay between retries Optional default 0,"max_delay":int,# seconds of max delay between retries Optional default 0,"jitter":bool# Boolean Optional,}}},pre_processor_config={# Optional"function":<callableobject>,# Required function that you want to call before http call"params":{# Optional"param1":"value1"# Params you want to pass in function}},post_processor_config={# Optional"function":<callableobject>,# Required function that you want to call after http call"params":{"param1":"value1"# Params you want to pass in function}})Basic HTTP POST callfromasyncio_requests.asyncio_requestimportrequestresult=awaitrequest(url="https://api.fyndx1.de/masquerader/v1/aio-request-test/post",data={"first_name":"Joy","last_name":"Pandey","gender":"M"},protocol="HTTPS",protocol_info={"request_type":"POST"})### Response"""{'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post','payload': {'first_name': 'Joy','last_name': 'Pandey','gender': 'M'},'external_call_request_time': '2022-02-17 17:25:03.930531+05:30','text': '','error_message': '','api_response': {'status_code': 200,'headers': {'Date': 'Thu, 17 Feb 2022 11:55:04 GMT','Content-Type': 'application/json','Content-Length': '57','Connection': 'keep-alive','X-Fynd-Trace-Id': '78ca02ff444ae5855e856c5f3d769364'},'cookies': {},'content': b'{"method": "POST", "status": true, "error_message": null}','text': '{"method": "POST", "status": true, "error_message": null}','json': {'method': 'POST','status': True,'error_message': None},'request_tracer': [{'on_request_start': 287753.868594354,'is_redirect': False,'on_connection_create_start': 0.0002811980084516108,'on_dns_cache_miss': 0.002910615992732346,'on_dns_resolvehost_start': 0.0029266909696161747,'on_dns_resolvehost_end': 0.04894679499557242,'on_connection_create_end': 0.15098483895417303,'on_request_chunk_sent': 0.15202936198329553,'on_request_end': 0.2799108889885247}]}}"""API call with circuit breaker and custom exceptionsfromasyncio_requests.asyncio_requestimportrequestclassHTTPRequestFailedException(Exception):passclassCustomException(Exception):passdefretry_exhausted_actions():print("All retries exhausted. API call failed.")defrequest_attempt_failed_actions():print("API call failed.")defrequest_abort_actions():print("API call aborted")result=awaitrequest(url="https://api.fyndx1.de/masquerader/v1/aio-request-test/post",data={"first_name":"Joy","last_name":"Pandey","gender":"M"},protocol="HTTPS",protocol_info={"request_type":"POST","circuit_breaker_config":{"maximum_failures":5,"timeout":15,"retry_config":{"name":"retry_masquerader","allowed_retries":5,"retriable_exceptions":[HTTPRequestFailedException],"abortable_exceptions":[CustomException],"on_retries_exhausted":retry_exhausted_actions,"on_failed_attempt":request_attempt_failed_actions,"on_abort":request_abort_actions,"delay":5,"max_delay":300,"jitter":True}}})### Value of result"""{'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post','payload': {'first_name': 'Joy','last_name': 'Pandey','gender': 'M'},'external_call_request_time': '2022-02-18 12:57:20.762713+05:30','text': '','error_message': '','api_response': {'status_code': 200,'headers': {'Date': 'Fri, 18 Feb 2022 07:27:21 GMT','Content-Type': 'application/json','Content-Length': '57','Connection': 'keep-alive','X-Fynd-Trace-Id': '390cd5e9f4b1f179d5d711ca7bc83ec3'},'cookies': {},'content': b'{"method": "POST", "status": true, "error_message": null}','text': '{"method": "POST", "status": true, "error_message": null}','json': {'method': 'POST','status': True,'error_message': None},'request_tracer': [{'on_request_start': 352622.180567606,'is_redirect': False,'on_connection_create_start': 0.0009668020065873861,'on_dns_cache_miss': 0.07304156001191586,'on_dns_resolvehost_start': 0.07307461701566353,'on_dns_resolvehost_end': 0.31564718199661,'on_connection_create_end': 0.5526716759777628,'on_request_chunk_sent': 0.5531467269756831,'on_request_end': 0.6851100819767453}]}}"""API with pre and post processor enabled with circuit breaker and retries.fromasyncio_requests.asyncio_requestimportrequestfromtypingimportDict,Textasyncdefmake_request_payload(response:Dict,first_name:Text,last_name:Text,gender:Text):response["payload"]={"first_name":first_name,"last_name":last_name,"gender":gender}asyncdefprint_response_recieved_from_api(response:Dict,text:Text):print(f"{text}{response['api_response']}")result=awaitrequest(url="https://api.fyndx1.de/masquerader/v1/aio-request-test/post",protocol="HTTPS",protocol_info={"request_type":"POST","circuit_breaker_config":{"timeout":150,"retry_config":{"name":"api_retry","allowed_retries":4}}},pre_processor_config={"function":make_request_payload,"params":{"first_name":"Joy","last_name":"Pandey","gender":"M"}},post_processor_config={"function":print_response_recieved_from_api,"params":{"text":"Response received from API: "}})### Response### The pre and post processor keys have no values in response since they were just print statements. Had they been API calls, the value would have been different.### The print statements will be printed in the shell if run but won't have its resemblence in the response."""{'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post','payload': {'first_name': 'Joy','last_name': 'Pandey','gender': 'M'},'external_call_request_time': '2022-02-17 17:33:35.508376+05:30','text': '','error_message': '','pre_processor_response': None,'api_response': {'status_code': 200,'headers': {'Date': 'Thu, 17 Feb 2022 12:03:35 GMT','Content-Type': 'application/json','Content-Length': '57','Connection': 'keep-alive','X-Fynd-Trace-Id': '8903eeb30ed218385631d3b52d04b38e'},'cookies': {},'content': b'{"method": "POST", "status": true, "error_message": null}','text': '{"method": "POST", "status": true, "error_message": null}','json': {'method': 'POST','status': True,'error_message': None},'request_tracer': [{'on_request_start': 288265.446420053,'is_redirect': False,'on_connection_create_start': 0.00028238497907295823,'on_dns_cache_miss': 0.0028724189614877105,'on_dns_resolvehost_start': 0.002888173970859498,'on_dns_resolvehost_end': 0.09302646096330136,'on_connection_create_end': 0.2075990799930878,'on_request_chunk_sent': 0.20890663599129766,'on_request_end': 0.319920428970363}]},'post_processor_response': None}"""Having separate API call in pre-processor.This is usually the case wherein we want to report some data before making the actual API callfromasyncio_requests.asyncio_requestimportrequestresult=awaitrequest(url="https://api.fyndx1.de/masquerader/v1/aio-request-test/post",data={"first_name":"Joy","last_name":"Pandey","gender":"M"},protocol="HTTPS",protocol_info={"request_type":"POST"},pre_processor_config={"function":request,"async_enabled":True,"params":{"url":"https://api.fyndx1.de/masquerader/v1/aio-request-test/post","data":{"first_name":"Joy","last_name":"Pandey","Gender":"M"},"protocol":"HTTP","protocol_info":{"request_type":"POST"}}})### Value of result"""{'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post','payload': {'first_name': 'Joy','last_name': 'Pandey','gender': 'M'},'external_call_request_time': '2022-02-18 13:26:35.575362+05:30','text': '','error_message': '','pre_processor_response': {'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post','payload': {'first_name': 'Joy','last_name': 'Pandey','Gender': 'M'},'external_call_request_time': '2022-02-18 13:26:35.575469+05:30','text': '','error_message': '','api_response': {'status_code': 200,'headers': {'Date': 'Fri, 18 Feb 2022 07:56:36 GMT','Content-Type': 'application/json','Content-Length': '57','Connection': 'keep-alive','X-Fynd-Trace-Id': 'ae2703a4c82e8f917c53faded0688717'},'cookies': {},'content': b'{"method": "POST", "status": true, "error_message": null}','text': '{"method": "POST", "status": true, "error_message": null}','json': {'method': 'POST','status': True,'error_message': None},'request_tracer': [{'on_request_start': 354376.993160197,'is_redirect': False,'on_connection_create_start': 0.00041024398524314165,'on_dns_cache_miss': 0.004407248983625323,'on_dns_resolvehost_start': 0.0044287089840509,'on_dns_resolvehost_end': 0.32443026901455596,'on_connection_create_end': 0.44923901598667726,'on_request_chunk_sent': 0.449799319030717,'on_request_end': 0.5300842020078562}]}},'api_response': {'status_code': 200,'headers': {'Date': 'Fri, 18 Feb 2022 07:56:36 GMT','Content-Type': 'application/json','Content-Length': '57','Connection': 'keep-alive','X-Fynd-Trace-Id': 'ddb370fbf58999c359fe384b547446c9'},'cookies': {},'content': b'{"method": "POST", "status": true, "error_message": null}','text': '{"method": "POST", "status": true, "error_message": null}','json': {'method': 'POST','status': True,'error_message': None},'request_tracer': [{'on_request_start': 354377.524928869,'is_redirect': False,'on_connection_create_start': 0.000421632023062557,'on_dns_cache_miss': 0.00067474803654477,'on_dns_resolvehost_start': 0.0006999420002102852,'on_dns_resolvehost_end': 0.002583371999207884,'on_connection_create_end': 0.09995210904162377,'on_request_chunk_sent': 0.10060718702152371,'on_request_end': 0.2261603070073761}]}}"""API call with nested pre and post processorsHere the pre processor(parent) has another pre-processor(child) within it.The response will include all the nested responses in the same fashion as that of the config setThe actual flow would be (child pre-processor -> parent pre-processor -> main API call -> parent post-processor -> child post processor)response format will be this way -parent pre-processor response
        child pre processor response
            child's child pre preprocesor response
                infinite nesting...
    
    main api call response
    
    parent post-processor response
        child post processor response
            child's child post preprocesor response
                infinite nesting...fromasyncio_requests.asyncio_requestimportrequestasyncdeftest_fun(*args,**kwargs):return{"text":"final res"}result=awaitrequest(url="https://api.fyndx1.de/masquerader/v1/aio-request-test/post",data={"first_name":"Joy","last_name":"Pandey","Gender":"M"},protocol="HTTP",protocol_info={"request_type":"POST","circuit_breaker_config":{"timeout":150,"retry_config":{"name":"asdf","allowed_retries":1}}},pre_processor_config={"function":request,"async_enabled":True,"params":{"url":"https://api.fyndx1.de/masquerader/v1/aio-request-test/post","data":{"first_name":"Joy","last_name":"Pandey","Gender":"M"},"protocol":"HTTP","protocol_info":{"request_type":"POST","circuit_breaker_config":{"retry_config":{"name":"asdf","allowed_retries":5}},},"pre_processor_config":{"function":test_fun,"async_enabled":True,"params":{"url":"https://api.fyndx1.de/masquerader/v1/aio-request-test/post","data":{"first_name":"Joy","last_name":"Pandey","Gender":"M"},"protocol":"HTTP","protocol_info":{"request_type":"POST","circuit_breaker_config":{"retry_config":{"name":"asdf","allowed_retries":5}},}}}}},post_processor_config={"function":request,"async_enabled":True,"params":{"url":"https://api.fyndx1.de/masquerader/v1/aio-request-test/post","data":{"first_name":"Joy","last_name":"Pandey","Gender":"M"},"protocol":"HTTP","protocol_info":{"request_type":"POST","circuit_breaker_config":{"retry_config":{"name":"asdf","allowed_retries":5}},},"post_processor_config":{"function":test_fun,"async_enabled":True,"params":{"url":"https://api.fyndx1.de/masquerader/v1/aio-request-test/post","data":{"first_name":"Joy","last_name":"Pandey","Gender":"M"},"protocol":"HTTP","protocol_info":{"request_type":"POST","circuit_breaker_config":{"retry_config":{"name":"asdf","allowed_retries":5}},}}}}})### Response"""{'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post','payload': {'first_name': 'Joy','last_name': 'Pandey','Gender': 'M'},'external_call_request_time': '2022-02-17 17:22:01.383304+05:30','text': '','error_message': '','pre_processor_response': {'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post','payload': {'first_name': 'Joy','last_name': 'Pandey','Gender': 'M'},'external_call_request_time': '2022-02-17 17:22:01.383358+05:30','text': '','error_message': '','pre_processor_response': {'text': 'final res'},'api_response': {'status_code': 200,'headers': {'Date': 'Thu, 17 Feb 2022 11:52:01 GMT','Content-Type': 'application/json','Content-Length': '57','Connection': 'keep-alive','X-Fynd-Trace-Id': 'b1a3111270067ae160eeaf9971b04cc5'},'cookies': {},'content': b'{"method": "POST", "status": true, "error_message": null}','text': '{"method": "POST", "status": true, "error_message": null}','json': {'method': 'POST','status': True,'error_message': None},'request_tracer': [{'on_request_start': 287571.321608293,'is_redirect': False,'on_connection_create_start': 0.00031328899785876274,'on_dns_cache_miss': 0.0029667950002476573,'on_dns_resolvehost_start': 0.0029829980339854956,'on_dns_resolvehost_end': 0.0064852479845285416,'on_connection_create_end': 0.08529951400123537,'on_request_chunk_sent': 0.0858444279874675,'on_request_end': 0.1671372150303796}]}},'api_response': {'status_code': 200,'headers': {'Date': 'Thu, 17 Feb 2022 11:52:01 GMT','Content-Type': 'application/json','Content-Length': '57','Connection': 'keep-alive','X-Fynd-Trace-Id': '3340481533a6511b15952cabb4c144bb'},'cookies': {},'content': b'{"method": "POST", "status": true, "error_message": null}','text': '{"method": "POST", "status": true, "error_message": null}','json': {'method': 'POST','status': True,'error_message': None},'request_tracer': [{'on_request_start': 287571.490459029,'is_redirect': False,'on_connection_create_start': 0.0006432340014725924,'on_dns_cache_miss': 0.00104641099460423,'on_dns_resolvehost_start': 0.001091104990337044,'on_dns_resolvehost_end': 0.0037200640072114766,'on_connection_create_end': 0.10335264401510358,'on_request_chunk_sent': 0.10410607699304819,'on_request_end': 0.18950222100829706}]},'post_processor_response': {'url': 'https://api.fyndx1.de/masquerader/v1/aio-request-test/post','payload': {'first_name': 'Joy','last_name': 'Pandey','Gender': 'M'},'external_call_request_time': '2022-02-17 17:22:01.743288+05:30','text': '','error_message': '','api_response': {'status_code': 200,'headers': {'Date': 'Thu, 17 Feb 2022 11:52:02 GMT','Content-Type': 'application/json','Content-Length': '57','Connection': 'keep-alive','X-Fynd-Trace-Id': 'a0304896aabbc394894d442fa27a5c3e'},'cookies': {},'content': b'{"method": "POST", "status": true, "error_message": null}','text': '{"method": "POST", "status": true, "error_message": null}','json': {'method': 'POST','status': True,'error_message': None},'request_tracer': [{'on_request_start': 287571.681455504,'is_redirect': False,'on_connection_create_start': 0.00041248503839597106,'on_dns_cache_miss': 0.0006613450241275132,'on_dns_resolvehost_start': 0.0006853759987279773,'on_dns_resolvehost_end': 0.0024919320130720735,'on_connection_create_end': 0.08381915499921888,'on_request_chunk_sent': 0.08448734600096941,'on_request_end': 0.5899507160065696}]},'post_processor_response': {'text': 'final res'}}}"""API call to send a fileHere we are downloading a file in the pre-processor. If the file is already present in the system then you can avoid that pre-processor and directly mention the file address in the local_file_path variable.The file can be downloaded by using the existing pre processor function in the utilities.The Utilities dir has a function that supports file download via url/aws s3.The Utilities dir also has a function to delete a file. If you want to delete teh file post making the API call, use this in the post processor.If you have some other way around to download the file, just pass that function address in the pre processor and include the file address in the local_file_path variable.fromasyncio_requests.asyncio_requestimportrequestfromasyncio_requests.utils.http_file_upload_configimportdownload_file_from_url,delete_local_file_pathlocal_file_path="/tmp/test.pdf"result=awaitrequest(url="http://localhost:5000/api/v1/test/aio-request-files",protocol="HTTPS",protocol_info={"request_type":"POST","http_file_upload_config":{"local_filepath":local_file_path,"file_key":"file"}},pre_processor_config={"function":download_file_from_url,"params":{"file_download_path":"https://didukhn.github.io/homepage/assets/img/photo.jpg","local_filepath":local_file_path}},post_processor_config={"function":delete_local_file_path,"params":{"local_filepath":local_file_path}})### Response"""{'url': 'http://localhost:5000/api/v1/test/aio-request-files','payload': {},'external_call_request_time': '2022-02-17 17:13:03.231826+05:30','text': '','error_message': '','pre_processor_response': None,'api_response': {'status_code': 200,'headers': {'Connection': 'close','Content-Length': '29','Content-Type': 'application/json'},'cookies': {},'content': b'{"success":true,"message":""}','text': '{"success":true,"message":""}','json': {'success': True,'message': ''},'request_tracer': [{'on_request_start': 287033.4935145,'is_redirect': False,'on_connection_create_start': 0.0021707930136471987,'on_dns_cache_miss': 0.002449413004796952,'on_dns_resolvehost_start': 0.002480961033143103,'on_dns_resolvehost_end': 0.003233974042814225,'on_connection_create_end': 0.0042467640014365315,'on_request_chunk_sent': 0.0064254660392180085,'on_request_end': 0.1773580180015415}]},'post_processor_response': None}"""Utilities IncludedDownload a file from AWS S3Download a file from public urlDelete a local file on systemFTPUses aioftp internally to implement FTP/FTPS.Added functionality of circuit breaker, pre and post processor configs same as http.Can Leverage all the ftp commands provided by aioftp library.By Default used FTP protocol can use FTPS if ssl config is enabled.How to use.importaiohttpfromasyncio_requests.asyncio_requestimportrequestawaitrequest(url="Server Ip",# Ip/url or ftp server <Required>auth=aiohttp.BasicAuth('username','password'),# The username and ip of the ftp server, to be sent as aiohttp.BasicAuth object <Required>protocol="FTP",# str <Required> (FTP)protocol_info={"port":21,# default is 21 <Optional>"command":"download",# generic ftp commands like download, upload, remove <Required>"server_path":"/tmp/temp.pdf",# path from where to get/remove or upload file on server."client_path":"",# path where file is downloaded/uploaded to. <optional>"timeout":30# <Optional>"verify_ssl":False# default is False <Optional>"certificate"""# required if verify_ssl is True"circuit_breaker_config":{# Optional"maximum_failures":int,# Optional Failures allowed"timeout":int,# Optional time in seconds"retry_config":{# Optional Include this if you want retry calls if failed on first time"name":str,# Required Any name"allowed_retries":int,# Required number of retries you want to make"retriable_exceptions":[<callableobject>]# Optional"abortable_exceptions":[<callableobject>]# Optional"on_retries_exhausted":<callableobject>,# Optional callable that will be invoked on a retries exhausted event,"on_failed_attempt":<callableobject>,# Optional callable that will be invoked on a failed attempt event,"on_abort":<callableobject>,# Optional callable that will be invoked on an abort event,"delay":int,# seconds of delay between retries Optional default 0,"max_delay":int,# seconds of max delay between retries Optional default 0,"jitter":bool# Boolean Optional,}}},pre_processor_config={# Optional"function":<callableobject>,# Required function that you want to call before ftp call"params":{# Optional"param1":"value1"# Params you want to pass in function}},post_processor_config={# Optional"function":<callableobject>,# Required function that you want to call after ftp call"params":{"param1":"value1"# Params you want to pass in function}})Sample FTP Call.importaiohttpfromasyncio_requests.asyncio_requestimportrequestfromasyncio_requests.utils.http_file_upload_configimportdownload_file_from_urllocal_path="/tmp/temp.png"awaitrequest(url="localhost",auth=aiohttp.BasicAuth("use","pswd"),protocol="FTP",protocol_info={"port":21,"command":"upload","server_path":"/home/resources/logo.png","client_path":local_path,"circuit_breaker_config":{"timeout":150,"retry_config":{"name":"api_retry","allowed_retries":4}}},pre_processor_config={"function":download_file_from_s3,"params":{"file_download_path":"https://[bucket_name].s3.amazonaws.com/logo.png","local_filepath":local_path}})## Resonse"""{'api_response': True,'error_message': '','external_call_request_time': '2022-05-13 19:07:35.775706+05:30','file': '/home/resources/logo.png','file_stats': {'modify': '20220513190700','size': '29304','type': 'file','unix.group': '1000','unix.links': '1','unix.mode': 436,'unix.owner': '1000'},'mode': 'upload','payload': {'success': True},'pre_processor_response': None,'text': '','url': 'localhost'}"""SOAP(upcoming)Generating Distribution Archivespython3-mpipinstall--upgradesetuptoolswheel
python3setup.pysdistbdist_wheelThis command should output a lot of text and once completed should generate two files in thedistdirectory.Open Source contributionYou can add utilities that can be used by others.Eg - Contributing a function that accepts certain params and downloads a file via AWS S3.
This function can be used by other developers in the pre/post processor to download the file before or after making the API call.Make sure to add the utility in the utilities section in the readme wrt protocol.Generating New Tags/ReleaseCheck the code with flake8, mypy, bandit, pytest before submitting a PRUpdate version insetup.pyUpdate version indocs/source/conf.pyUpdate version in README.md sectionSend a PR, and after it gets merged to master create a tag from master in the formatvX.YX- Major Release (Breaking Changes)Y- Minor ReleaseTo know more about the developer, here's a quote to find him out -Anton died so we could live