Client

Introduction

PyAMF isn’t just about the Adobe Flash Player talking to a Python backend, oh no. We have put together a client module which allows you to make AMF calls to an HTTP Gateway, whether that be PyAMF or other AMF implementations. If you come from a Adobe Flash background, this API should feel very natural to you.

Examples

The examples below are working, so feel free to try this out right now.

Basic Example

This example connects to a AMF gateway running at http://demo.pyamf.org/gateway/recordset and invokes the remote Python getLanguages method that is mapped to service.getLanguages. The result is printed on stdout.

1
2
3
4
5
6
from pyamf.remoting.client import RemotingService

client = RemotingService('http://demo.pyamf.org/gateway/recordset')
service = client.getService('service')

print service.getLanguages()

Authentication

Use setCredentials(username, password) to authenticate with an AMF client:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from pyamf.remoting.client import RemotingService

client = RemotingService('https://demo.pyamf.org/gateway/authentication')
client.setCredentials('jane', 'doe')

service = client.getService('calc')
print service.sum(85, 115) # should print 200.0

client.setCredentials('abc', 'def')
print service.sum(85, 115).description # should print Authentication Failed

Logging

Enable logging with a DEBUG level to log messages including the timestamp and level name.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from pyamf.remoting.client import RemotingService

import logging
logging.basicConfig(level=logging.DEBUG,
           format='%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s')

gateway = 'http://demo.pyamf.org/gateway/recordset'
client = RemotingService(gateway, logger=logging)
service = client.getService('service')

print service.getLanguages()

AMF Version

AMF0 is the default AMF encoding used by the client. You can force it to use AMF3 by supplying the amf_version keyword to the RemotingService. See pyamf.ENCODING_TYPES for more info.

1
2
3
4
5
6
7
8
from pyamf import AMF0, AMF3
from pyamf.remoting.client import RemotingService

gateway = 'http://demo.pyamf.org/gateway/helloworld'
client = RemotingService(gateway, amf_version=AMF3)
service = client.getService('echo')

print service("Hello AMF3 world!")

User-Agent

By default the client identifies itself with a ‘PyAMF/x.x’ user agent header. You can modify this by providing a custom user_agent keyword to your RemotingService. The example client below will be seen as ‘MyApp/0.1.0’ by the server.

1
2
3
4
5
6
7
8
from pyamf.remoting.client import RemotingService

appName = 'MyApp/0.1.0'
gateway = 'http://demo.pyamf.org/gateway/helloworld'
client = RemotingService(gateway, user_agent=appName)
service = client.getService('echo')

print service.echo('Hello World!')

Referer

The referer also provides the client a way to identify itself, similar to the user_agent in the previous example. You can modify this by providing a custom referrer keyword to your RemotingService. The example client below will be seen as ‘client.py’ by the server. The default is None.

1
2
3
4
5
6
7
8
from pyamf.remoting.client import RemotingService

appReferer = 'client.py'
gateway = 'http://demo.pyamf.org/gateway/helloworld'
client = RemotingService(gateway, referer=appReferer)
service = client.getService('echo')

print service.echo('Hello World!')

HTTP Headers

You can modify the headers of the HTTP request using this convenient API:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from pyamf.remoting.client import RemotingService

gw = RemotingService('http://demo.pyamf.org/gateway/recordset')

gw.addHTTPHeader("Accept-encoding", "gzip")
gw.addHTTPHeader('Set-Cookie', 'sessionid=QT3cUmACNeKQo5oPeM0')
gw.removeHTTPHeader('Set-Cookie')

username = 'admin'
password = 'admin'
auth = ('%s:%s' % (username, password)).encode('base64')[:-1]

gw.addHTTPHeader("Authorization", "Basic %s" % auth)

service = gw.getService('service')
print service.getLanguages()

Exception Handling

As of PyAMF 0.6, the client will now raise an appropriate error if remoting call returns an error. The default behaviour is to raise a RemotingError but this behaviour can be modified:

# service method
def type_error():
    raise TypeError('some useful message here')

And from the console:

>>> from pyamf.remoting.client import RemotingService
>>> gateway = RemotingService('http://example.org/gw')
>>> service = gateway.getService('type_error')
>>> service()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/nick/projects/pyamf/pyamf/remoting/client/__init__.py", line 121, in __call__
    return self._call(ServiceMethodProxy(self, None), *args)
  File "/Users/nick/projects/pyamf/pyamf/remoting/client/__init__.py", line 107, in _call
    response.body.raiseException()
  File "/Users/nick/projects/pyamf/pyamf/remoting/__init__.py", line 335, in raiseException
    raise get_exception_from_fault(self), self.description, None
TypeError: some useful message here

The gateway returns an error code which is mapped to an exception class. A number of built-in exceptions are automatically mapped:

  • TypeError
  • LookupError
  • KeyError
  • IndexError
  • NameError

Use pyamf.add_error_class() to add new code/class combos and pyamf.remove_error_class() to remove classes.

More

Check the API docs for more information. The source for the RecordSet example is also available.