I wanted to make a small self-integrated API for my PyQt5 application.
This class is a tiny chunk of the whole project:
class NyvoNetHunterRequestManager(QObject):
sending_request = pyqtSignal()
request_sent = pyqtSignal()
failed_to_send = pyqtSignal()
received_valid_response = pyqtSignal()
received_invalid_response = pyqtSignal()
def __init__(self, url: str, data: Dict, headers: Dict, method: Literal["get", "post", "put", "delete"]):
self.url = url
self.data = data
self.headers = headers
self.method = method
super(QObject, self).__init__()
def fire(self) -> str:
self.sending_request.emit()
current_method_name = self.method
try:
exec(
f"global _BACKENDRESPOND; _BACKENDRESPOND = requests.{current_method_name}(url='{self.url}', data={self.data}, headers={self.headers})"
)
global _BACKENDRESPOND
self.response = _BACKENDRESPOND
del _BACKENDRESPOND
self.request_sent.emit()
except ConnectionError:
self.failed_to_send.emit()
return
if self.response.ok:
self.received_valid_response.emit()
return self.response
self.received_invalid_response.emit()
return self.response
@property
def url(self):
return self._url
@url.setter
def url(self, _url):
if not isinstance(_url, str):
url_argument_type = type(_url).__name__
raise ValueError(f"Expected argument type passed for the parameter( url ): ( str ) | Not ( {url_argument_type}")
url_is_invalid = not is_valid_url(_url)
if url_is_invalid:
raise TypeError("That is not a valid url.")
self._url = _url
@property
def data(self):
return self._data
@data.setter
def data(self, _data):
if not isinstance(_data, dict):
data_argument_type = type(_data).__name__
raise ValueError(
f"Expected argument type passed for the parameter ( data ): ( dict ) | Not: ( {data_argument_type} )"
)
self._data = _data
@property
def headers(self):
return self._headers
@headers.setter
def headers(self, _headers):
if not isinstance(_headers, dict):
headers_argument_type = type(_headers).__name__
raise ValueError(f"Expected argument type passed for the parameter ( headers ): ( dict ) | Not: ( {headers_argument_type} )")
self._headers = _headers
@property
def method(self):
return self._method
@method.setter
def method(self, _method):
available_http_methods = ["get", "post", "put", "delete"]
if not isinstance(_method, str):
method_argument_type = type(_method).__name__
raise ValueError(f"Expected argument types passed for the parameter ( method ): ( str ) | Not: {method_argument_type}")
if not _method in available_http_methods:
raise TypeError("That is not a valid http method.")
self._method = _method
module_is_runned_directly = __name__ == "__main__"
if module_is_runned_directly:
raise DirectRunError("Database modules are not intended to run directly, they are produced for improt usage only.")
I have used the exec function because I needed the HTTP method to be passed as an argument, and I also wanted to avoid making encapsulated methods for each HTTP function.
The main idiomatic question is: Is using the exec() function in this way actually safe?
exec. It's practically never the right answer. \$\endgroup\$self.url,self.data, orself.headerscontain a'? What if one of them is equal to'); import os; os.system('malware.exe'); ('? \$\endgroup\$