eric7/E5Network/E5XmlRpcClient.py

branch
eric7
changeset 8312
800c432b34c8
parent 8268
6b8128e0c9d1
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2015 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a xmlrpc client for Qt.
8 """
9
10 import xmlrpc.client as xmlrpc
11
12 from PyQt5.QtCore import Qt, QObject, QUrl, QByteArray, QEventLoop
13 from PyQt5.QtGui import QGuiApplication, QCursor
14 from PyQt5.QtNetwork import (
15 QNetworkAccessManager, QNetworkRequest, QNetworkReply
16 )
17
18 from E5Network.E5NetworkProxyFactory import proxyAuthenticationRequired
19 try:
20 from E5Network.E5SslErrorHandler import E5SslErrorHandler, E5SslErrorState
21 SSL_AVAILABLE = True
22 except ImportError:
23 SSL_AVAILABLE = False
24
25
26 class E5XmlRpcClient(QObject):
27 """
28 Class implementing a xmlrpc client for Qt.
29 """
30 def __init__(self, url, parent=None):
31 """
32 Constructor
33
34 @param url xmlrpc handler URL (string or QUrl)
35 @param parent parent object (QObject)
36 """
37 super().__init__(parent)
38
39 # attributes for the network objects
40 self.__networkManager = QNetworkAccessManager(self)
41 self.__networkManager.proxyAuthenticationRequired.connect(
42 proxyAuthenticationRequired)
43 self.__networkManager.finished.connect(self.__replyFinished)
44 if SSL_AVAILABLE:
45 self.__sslErrorHandler = E5SslErrorHandler(self)
46 self.__networkManager.sslErrors.connect(self.__sslErrors)
47
48 self.__callmap = {}
49
50 self.__request = QNetworkRequest(QUrl(url))
51 self.__request.setRawHeader(b"User-Agent", b"E5XmlRpcClient/1.0")
52 self.__request.setHeader(
53 QNetworkRequest.KnownHeaders.ContentTypeHeader, "text/xml")
54
55 def setUrl(self, url):
56 """
57 Public slot to set the xmlrpc handler URL.
58
59 @param url xmlrpc handler URL (string or QUrl)
60 """
61 url = QUrl(url)
62 if url.isValid():
63 self.__request.setUrl(url)
64
65 def call(self, method, args, responseCallback, errorCallback):
66 """
67 Public method to call the remote server.
68
69 @param method name of the remote method to be called (string)
70 @param args tuple of method arguments (tuple)
71 @param responseCallback method to be called with the returned
72 result as a tuple (function)
73 @param errorCallback method to be called in case of an error
74 with error code and error string (function)
75 @exception TypeError raised to indicate an illegal 'args' parameter
76 type
77 """
78 if not isinstance(args, tuple):
79 raise TypeError("argument 'args' must be tuple")
80
81 QGuiApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
82 QGuiApplication.processEvents(
83 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents)
84
85 data = xmlrpc.dumps(args, method).encode("utf-8")
86 reply = self.__networkManager.post(
87 self.__request, QByteArray(data))
88 self.__callmap[reply] = (responseCallback, errorCallback)
89
90 def abort(self):
91 """
92 Public method to abort all calls.
93 """
94 for reply in list(self.__callmap):
95 if reply.isRunning():
96 reply.abort()
97
98 def __sslErrors(self, reply, errors):
99 """
100 Private slot to handle SSL errors.
101
102 @param reply reference to the reply object (QNetworkReply)
103 @param errors list of SSL errors (list of QSslError)
104 """
105 QGuiApplication.restoreOverrideCursor()
106 QGuiApplication.processEvents(
107 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents)
108
109 ignored = self.__sslErrorHandler.sslErrorsReply(reply, errors)[0]
110 if ignored == E5SslErrorState.NOT_IGNORED and reply in self.__callmap:
111 self.__callmap[reply][1](xmlrpc.TRANSPORT_ERROR, self.tr(
112 "SSL Error"))
113
114 def __replyFinished(self, reply):
115 """
116 Private slot handling the receipt of a reply.
117
118 @param reply reference to the finished reply (QNetworkReply)
119 """
120 if reply not in self.__callmap:
121 return
122
123 QGuiApplication.restoreOverrideCursor()
124 QGuiApplication.processEvents(
125 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents)
126
127 if reply.error() != QNetworkReply.NetworkError.NoError:
128 self.__callmap[reply][1](xmlrpc.TRANSPORT_ERROR,
129 reply.errorString())
130 else:
131 data = bytes(reply.readAll()).decode("utf-8")
132 try:
133 data = xmlrpc.loads(data)[0]
134 self.__callmap[reply][0](data)
135 except xmlrpc.Fault as fault:
136 self.__callmap[reply][1](fault.faultCode, fault.faultString)
137
138 reply.deleteLater()
139 del self.__callmap[reply]

eric ide

mercurial