Skip to content

Commit

Permalink
Merge pull request #760 from Samweli/dev_migrate_qgsnetwork
Browse files Browse the repository at this point in the history
Migration to QgsNetworkAccessManager
  • Loading branch information
azvoleff committed Mar 1, 2023
2 parents 5983097 + 220fdd5 commit 759d130
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 140 deletions.
204 changes: 130 additions & 74 deletions LDMP/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
email : [email protected]
***************************************************************************/
"""
import io
import sys
import typing

from future import standard_library

standard_library.install_aliases()
Expand All @@ -20,9 +24,19 @@
import requests
import backoff

from qgis.core import QgsApplication, QgsTask
from qgis.PyQt import QtCore, QtWidgets
from dateutil import tz
from qgis.core import (
QgsApplication,
QgsTask,
QgsNetworkAccessManager,
QgsApplication,
QgsSettings,
QgsNetworkReplyContent,
)
from qgis.PyQt import QtCore, QtWidgets, QtNetwork

from qgis.utils import iface
from qgis.gui import QgsAuthConfigSelect

from . import auth, conf
from .logger import log
Expand All @@ -42,59 +56,110 @@ def tr(message):
class RequestTask(QgsTask):
def __init__(self, description, url, method, payload, headers, timeout=30):
super().__init__(description, QgsTask.CanCancel)

self.description = description
self.url = url
self.method = method
self.payload = payload
self.headers = headers

self.timeout = timeout
self.headers = headers or {}
self.exception = None
self.resp = None

def run(self):
try:
if self.method == "get":
self.resp = requests.get(
self.url,
json=self.payload,
headers=self.headers,
timeout=self.timeout,
settings = QgsSettings()
auth_id = settings.value("trendsearth/auth")

qurl = QtCore.QUrl(self.url)

network_manager = QgsNetworkAccessManager().instance()
network_manager.setTimeout(600000)

network_request = QtNetwork.QNetworkRequest(qurl)
auth_manager = QgsApplication.authManager()
auth_added, _ = auth_manager.updateNetworkRequest(network_request, auth_id)

network_request.setHeader(
QtNetwork.QNetworkRequest.ContentTypeHeader, "application/json"
)

if len(self.headers) > 0:
network_request.setRawHeader(
QtCore.QByteArray(b"Authorization"),
QtCore.QByteArray(
bytes(self.headers.get("Authorization"), encoding="utf-8")
),
)

if self.method == "get":
self.resp = network_manager.blockingGet(network_request)

elif self.method == "post":
self.resp = requests.post(
self.url,
json=self.payload,
headers=self.headers,
timeout=self.timeout,
request_data = None
doc = QtCore.QJsonDocument({})

if self.payload is not None:
# Work around to handle QJsonDocument failing to deal with
# dictionaries that contain nested values of OrderedDict.
try:
doc = QtCore.QJsonDocument(self.payload)
except TypeError as te:
request_data = bytes(json.dumps(self.payload), encoding="utf-8")

request_data = (
doc.toJson(QtCore.QJsonDocument.Compact)
if request_data is None
else request_data
)

self.resp = network_manager.blockingPost(network_request, request_data)

elif self.method == "update":
self.resp = requests.update(
self.url,
json=self.payload,
headers=self.headers,
timeout=self.timeout,
doc = QtCore.QJsonDocument(self.payload)
request_data = doc.toJson(QtCore.QJsonDocument.Compact)

self.resp = network_manager.sendCustomRequest(
network_request, b"UPDATE", request_data
)

loop = QtCore.QEventLoop()
self.resp.finished.connect(loop.quit)
loop.exec_()

elif self.method == "delete":
self.resp = requests.delete(
self.url,
json=self.payload,
headers=self.headers,
timeout=self.timeout,
empty_payload = {}
doc = QtCore.QJsonDocument(empty_payload)
request_data = doc.toJson(QtCore.QJsonDocument.Compact)

self.resp = network_manager.sendCustomRequest(
network_request, b"DELETE", request_data
)

loop = QtCore.QEventLoop()
self.resp.finished.connect(loop.quit)
loop.exec_()

elif self.method == "patch":
self.resp = requests.patch(
self.url,
json=self.payload,
headers=self.headers,
timeout=self.timeout,
doc = QtCore.QJsonDocument(self.payload)
request_data = doc.toJson(QtCore.QJsonDocument.Compact)

self.resp = network_manager.sendCustomRequest(
network_request, b"PATCH", request_data
)

loop = QtCore.QEventLoop()
self.resp.finished.connect(loop.quit)
loop.exec_()

elif self.method == "head":
self.resp = requests.head(
self.url,
json=self.payload,
headers=self.headers,
timeout=self.timeout,
)
self.resp = network_manager.head(network_request)

loop = QtCore.QEventLoop()
self.resp.finished.connect(loop.quit)
loop.exec_()

else:
self.exception = ValueError(
"Unrecognized method: {}".format(self.method)
Expand Down Expand Up @@ -129,16 +194,10 @@ def finished(self, result):
)

if self.resp is not None:
log(f'API response from "{self.method}" request: {self.resp.status_code}')
log(f'API response from "{self.method}" request: {self.resp.error()}')
else:
log(f'API response from "{self.method}" request was None')

# if conf.settings_manager.get_value(conf.Setting.DEBUG):
# log(
# f'API response from "{self.method}" request (data): '
# f'{clean_api_response(self.resp)}'
# )


###############################################################################
# Other helper functions for api calls
Expand Down Expand Up @@ -179,24 +238,6 @@ def clean_api_response(self, resp):

return response

def get_error_status(self, resp):
try:
# JSON conversion will fail if the server didn't return a json
# response
resp = resp.json()
except ValueError:
return ("Unknown error", None)
status = resp.get("status", None)

if not status:
status = resp.get("status_code", "None")
desc = resp.get("detail", None)

if not desc:
desc = resp.get("description", "Generic error")

return (desc, status)

def login(self, authConfigId=None):
authConfig = auth.get_auth_config(
auth.TE_API_AUTH_SETUP, authConfigId=authConfigId
Expand Down Expand Up @@ -284,8 +325,10 @@ def _make_request(self, description, **kwargs):
api_task = RequestTask(description, **kwargs)
QgsApplication.taskManager().addTask(api_task)
result = api_task.waitForFinished((self.timeout + 1) * 1000)

if not result:
log("Request timed out")

return api_task.resp

def _clean_payload(self, payload):
Expand Down Expand Up @@ -331,15 +374,26 @@ def call_api(self, endpoint, method="get", payload=None, use_token=False):
headers=headers,
timeout=self.timeout,
)

else:
resp = None

if resp != None:
if resp.status_code == 200:
ret = resp.json()
if resp is not None:
status_code = resp.attribute(
QtNetwork.QNetworkRequest.HttpStatusCodeAttribute
)

if status_code == 200:
if type(resp) is QtNetwork.QNetworkReply:
ret = resp.readAll()
ret = json.load(io.BytesIO(ret))
elif type(resp) is QgsNetworkReplyContent:
ret = resp.content()
ret = json.load(io.BytesIO(ret))
else:
err_msg = "Unknown object type: {}.".format(str(resp))
log(err_msg)
else:
desc, status = self.get_error_status(resp)
desc, status = resp.error(), resp.errorString()
err_msg = "Error: {} (status {}).".format(desc, status)
log(err_msg)
"""
Expand All @@ -364,21 +418,23 @@ def get_header(self, url):
)

if resp != None:
log(f'Response from "{url}" header request: {resp.status_code}')

if resp.status_code == 200:
ret = resp.headers
status_code = resp.attribute(
QtNetwork.QNetworkRequest.HttpStatusCodeAttribute
)
if status_code == 200:
ret = resp
else:
desc, status = self.get_error_status(resp)
desc, status = resp.error(), resp.errorString()
err_msg = "Error: {} (status {}).".format(desc, status)
log(err_msg)
"""
iface.messageBar().pushCritical(
"Trends.Earth", "Error: {} (status {}).".format(desc, status)
)
"""
ret = None
else:
log("Header request failed")
ret = None

return ret
return ret

################################################################################
# Functions supporting access to individual api endpoints
Expand Down
Loading

0 comments on commit 759d130

Please sign in to comment.