Ticket #3219: xmlrpc_datetime_r28853.diff
| File xmlrpc_datetime_r28853.diff, 13.6 KB (added by chadmaine, 3 years ago) |
|---|
-
twisted/web/test/test_xmlrpc.py
6 6 Tests for XML-RPC support in L{twisted.web.xmlrpc}. 7 7 """ 8 8 9 import datetime 9 10 import xmlrpclib 10 11 11 12 from twisted.trial import unittest … … 350 351 return d 351 352 352 353 354 class XMLRPCUseDateTimeTestCase(unittest.TestCase): 355 """ 356 Test with useDateTime set to True. 353 357 358 These are not meant to be exhaustive serialization tests, since 359 L{xmlrpclib} does all of the actual serialization work. They are just 360 meant to exercise a few codepaths to make sure we are calling into 361 xmlrpclib correctly. 362 """ 363 364 def setUp(self): 365 self.p = reactor.listenTCP( 366 0, server.Site(Test(useDateTime=True)), interface="127.0.0.1") 367 self.port = self.p.getHost().port 368 369 370 def tearDown(self): 371 return self.p.stopListening() 372 373 374 def proxy(self): 375 return xmlrpc.Proxy("http://127.0.0.1:%d" % (self.port,), 376 useDateTime=True) 377 378 379 def test_deferredNone(self): 380 """ 381 Test that passing a datetime.datetime as an argument to a remote method 382 and returning a L{Deferred} which fires with datetime.datetime properly 383 passes over the network if useDateTime is set to True. 384 """ 385 dt1 = datetime.datetime(2000, 12, 28, 3, 45, 59) 386 d = self.proxy().callRemote('defer', dt1) 387 d.addCallback(self.assertEquals, dt1) 388 return d 389 390 391 def test_dictWithDatetimeValue(self): 392 """ 393 Test that return a C{dict} with datetime.datetime as a value works 394 properly. 395 """ 396 dt1 = datetime.datetime(1964, 10, 18, 3, 59, 13) 397 d = self.proxy().callRemote('defer', {'a': dt1}) 398 d.addCallback(self.assertEquals, {'a': dt1}) 399 return d 400 401 354 402 class XMLRPCTestAuthenticated(XMLRPCTestCase): 355 403 """ 356 404 Test with authenticated proxy. We run this with the same inout/ouput as -
twisted/web/xmlrpc.py
81 81 Sub-handlers for prefixed methods (e.g., system.listMethods) 82 82 can be added with putSubHandler. By default, prefixes are 83 83 separated with a '.'. Override self.separator to change this. 84 85 @ivar allowNone: Permit XML translating of Python constant None. 86 @type allowNone: C{bool} 87 88 @ivar useDateTime: Present datetime values as datetime.datetime objects? 89 Requires Python <= 2.5. 90 @type useDateTime: C{bool} 84 91 """ 85 92 86 93 # Error codes for Twisted, if they conflict with yours then … … 92 99 separator = '.' 93 100 allowedMethods = ('POST',) 94 101 95 def __init__(self, allowNone=False ):102 def __init__(self, allowNone=False, useDateTime=False): 96 103 resource.Resource.__init__(self) 97 104 self.subHandlers = {} 98 105 self.allowNone = allowNone 106 self.useDateTime = useDateTime 99 107 108 def _setUseDateTime(self, value=False): 109 if value and sys.version_info[:2] < (2, 5): 110 raise RuntimeError( 111 "useDateTime requires Python 2.5 or later.") 112 self._useDateTime = value 113 114 def _getUseDateTime(self): 115 return self._useDateTime 116 117 useDateTime = property(fget=_getUseDateTime, fset=_setUseDateTime) 118 100 119 def putSubHandler(self, prefix, handler): 101 120 self.subHandlers[prefix] = handler 102 121 … … 110 129 request.content.seek(0, 0) 111 130 request.setHeader("content-type", "text/xml") 112 131 try: 113 args, functionPath = xmlrpclib.loads(request.content.read()) 132 if self.useDateTime: 133 args, functionPath = xmlrpclib.loads(request.content.read(), 134 use_datetime=True) 135 else: 136 # Maintain backwards compatibility with Python < 2.5 137 args, functionPath = xmlrpclib.loads(request.content.read()) 114 138 except Exception, e: 115 139 f = Fault(self.FAILURE, "Can't deserialize input: %s" % (e,)) 116 140 self._cbRender(f, request) … … 203 227 To enable the methodSignature method, add a 'signature' method attribute 204 228 containing a list of lists. See methodSignature's documentation for the 205 229 format. Note the type strings should be XML-RPC types, not Python types. 230 231 @param parent: the XMLRPC server to add Introspection support to. 232 @type parent: L{XMLRPC} 206 233 """ 207 234 208 235 def __init__(self, parent): 209 236 """ 210 237 Implement Introspection support for an XMLRPC server. 211 212 @param parent: the XMLRPC server to add Introspection support to.213 238 """ 214 215 239 XMLRPC.__init__(self) 216 240 self._xmlrpc_parent = parent 217 241 … … 261 285 """ 262 286 Add Introspection support to an XMLRPC server. 263 287 264 @param xmlrpc: The xmlrpc server to add Introspection support to. 288 @param parent: the XMLRPC server to add Introspection support to. 289 @type parent: L{XMLRPC} 265 290 """ 266 291 xmlrpc.putSubHandler('system', XMLRPCIntrospection(xmlrpc)) 267 292 … … 298 323 299 324 300 325 class _QueryFactory(protocol.ClientFactory): 326 """ 327 XML-RPC Client Factory 301 328 302 deferred = None303 protocol = QueryProtocol329 @ivar path: The path portion of the URL to which to post method calls. 330 @type path: C{str} 304 331 305 def __init__(self, path, host, method, user=None, password=None, 306 allowNone=False, args=(), canceller=None): 307 """ 308 @type path: C{str} 309 @param path: The path portion of the URL to which to post method calls. 332 @ivar host: The value to use for the Host HTTP header. 333 @type host: C{str} 310 334 311 @type host: C{str}312 @param host: The value to use for the Host HTTP header.335 @ivar method: The name of the method to call. 336 @type method: C{str} 313 337 314 @type method: C{str} 315 @param method: The name of the method to call. 338 @ivar user: The username with which to authenticate with the server 339 when making calls. 340 @type user: C{str} or C{NoneType} 316 341 317 @type user: C{str} or C{NoneType}318 @param user: The username with which to authenticate with the server319 when making calls.342 @ivar password: The password with which to authenticate with the server 343 when making calls. 344 @type password: C{str} or C{NoneType} 320 345 321 @type password: C{str} or C{NoneType}322 @param password: The password with which to authenticate with the server323 when making calls.346 @ivar allowNone: allow the use of None values in parameters. It's 347 passed to the underlying xmlrpclib implementation. Default to False. 348 @type allowNone: C{bool} or C{NoneType} 324 349 325 @type allowNone: C{bool} or C{NoneType} 326 @param allowNone: allow the use of None values in parameters. It's 327 passed to the underlying xmlrpclib implementation. Default to False. 350 @ivar useDateTime: Accept datetime values as datetime.datetime objects. 351 also passed to the underlying xmlrpclib implementation. Default to 352 False. Requires Python <= 2.5. 353 @type useDateTime: C{bool} 328 354 329 @type args: C{tuple}330 @param args: the arguments to pass to the method.355 @ivar args: the arguments to pass to the method. 356 @type args: C{tuple} 331 357 332 @type canceller: C{callable} or C{NoneType} 333 @param canceller: a 1-argument callable passed to the deferred as the 334 canceller callback. 335 """ 358 @ivar canceller: a 1-argument callable passed to the deferred as the 359 canceller callback. 360 @type canceller: C{callable} or C{NoneType} 361 362 """ 363 364 deferred = None 365 protocol = QueryProtocol 366 367 def __init__(self, path, host, method, user=None, password=None, 368 allowNone=False, args=(), canceller=None, useDateTime=False): 336 369 self.path, self.host = path, host 337 370 self.user, self.password = user, password 338 371 self.payload = payloadTemplate % (method, 339 372 xmlrpclib.dumps(args, allow_none=allowNone)) 340 373 self.deferred = defer.Deferred(canceller) 374 self.useDateTime = useDateTime 341 375 376 def _setUseDateTime(self, value=False): 377 if value and sys.version_info[:2] < (2, 5): 378 raise RuntimeError( 379 "useDateTime requires Python 2.5 or later.") 380 self._useDateTime = value 381 382 def _getUseDateTime(self): 383 return self._useDateTime 384 385 useDateTime = property(fget=_getUseDateTime, fset=_setUseDateTime) 386 342 387 def parseResponse(self, contents): 343 388 if not self.deferred: 344 389 return 345 390 try: 346 response = xmlrpclib.loads(contents)[0][0] 391 if self.useDateTime: 392 response = xmlrpclib.loads(contents, 393 use_datetime=True)[0][0] 394 else: 395 # Maintain backwards compatibility with Python < 2.5 396 response = xmlrpclib.loads(contents)[0][0] 347 397 except: 348 398 deferred, self.deferred = self.deferred, None 349 399 deferred.errback(failure.Failure()) … … 373 423 Use proxy.callRemote('foobar', *args) to call remote method 374 424 'foobar' with *args. 375 425 426 @param url: The URL to which to post method calls. Calls will be made 427 over SSL if the scheme is HTTPS. If netloc contains username or 428 password information, these will be used to authenticate, as long as 429 the C{user} and C{password} arguments are not specified. 430 @type url: C{str} 431 432 @ivar user: The username with which to authenticate with the server 433 when making calls. If specified, overrides any username information 434 embedded in C{url}. If not specified, a value may be taken from 435 C{url} if present. 436 @type user: C{str} or C{NoneType} 437 438 @ivar password: The password with which to authenticate with the server 439 when making calls. If specified, overrides any password information 440 embedded in C{url}. If not specified, a value may be taken from 441 C{url} if present. 442 @type password: C{str} or C{NoneType} 443 444 @ivar allowNone: allow the use of None values in parameters. It's 445 passed to the underlying xmlrpclib implementation. Default to False. 446 @type allowNone: C{bool} or C{NoneType} 447 448 @ivar useDateTime: Accept datetime values as datetime.datetime objects. 449 also passed to the underlying xmlrpclib implementation. Default to 450 False. Requires Python <= 2.5. 451 @type useDateTime: C{bool} 452 376 453 @ivar queryFactory: object returning a factory for XML-RPC protocol. Mainly 377 454 useful for tests. 378 455 """ 379 456 queryFactory = _QueryFactory 380 457 381 def __init__(self, url, user=None, password=None, allowNone=False): 382 """ 383 @type url: C{str} 384 @param url: The URL to which to post method calls. Calls will be made 385 over SSL if the scheme is HTTPS. If netloc contains username or 386 password information, these will be used to authenticate, as long as 387 the C{user} and C{password} arguments are not specified. 388 389 @type user: C{str} or C{NoneType} 390 @param user: The username with which to authenticate with the server 391 when making calls. If specified, overrides any username information 392 embedded in C{url}. If not specified, a value may be taken from 393 C{url} if present. 394 395 @type password: C{str} or C{NoneType} 396 @param password: The password with which to authenticate with the server 397 when making calls. If specified, overrides any password information 398 embedded in C{url}. If not specified, a value may be taken from 399 C{url} if present. 400 401 @type allowNone: C{bool} or C{NoneType} 402 @param allowNone: allow the use of None values in parameters. It's 403 passed to the underlying xmlrpclib implementation. Default to False. 404 """ 458 def __init__(self, url, user=None, password=None, allowNone=False, 459 useDateTime=False): 405 460 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) 406 461 netlocParts = netloc.split('@') 407 462 if len(netlocParts) == 2: … … 428 483 if password is not None: 429 484 self.password = password 430 485 self.allowNone = allowNone 486 self.useDateTime = useDateTime 431 487 488 def _setUseDateTime(self, value=False): 489 if value and sys.version_info[:2] < (2, 5): 490 raise RuntimeError( 491 "useDateTime requires Python 2.5 or later.") 492 self._useDateTime = value 493 494 def _getUseDateTime(self): 495 return self._useDateTime 496 497 useDateTime = property(fget=_getUseDateTime, fset=_setUseDateTime) 498 432 499 def callRemote(self, method, *args): 433 500 """ 434 501 Call remote XML-RPC C{method} with given arguments. … … 447 514 connector.disconnect() 448 515 factory = self.queryFactory( 449 516 self.path, self.host, method, self.user, 450 self.password, self.allowNone, args, cancel )517 self.password, self.allowNone, args, cancel, self.useDateTime) 451 518 if self.secure: 452 519 from twisted.internet import ssl 453 520 connector = reactor.connectSSL(self.host, self.port or 443, -
twisted/web/topfiles/3219.feature
1 twisted.web.xmlrpc.XMLRPC and twisted.web.xmlrpc.Proxy now expose xmlrpclib's support of datetime.datetime objects if useDateTime is set to True.
