I’m writing a simple Python script to reach out to a remote Tryton using the default jsonrpclib. I’m able to reach Tryton and execute the login, but the script fails on the result.
TypeError: Response is not a dict.
Indeed the response is an array with two elements: [<user_id>, <session_id>]. However, the JSON-RPC spec defines a response object https://www.jsonrpc.org/specification which says that there should be a JSON object with a member called result.
Is there a reason why Tryton doesn’t follow the JSON-RPC spec for the login?
I have in the header Content-Type: 'application/json-rpc', modified it to Content-Type: 'application/json' but same result. So I digged through the request flow to see where something did go wrong. And finally found it!
In trytond: 10426538d63f trytond/protocols/jsonrpc.py there should be an exact match of request keys. However I have an extra key 'jsonrpc' in the set, so the if statement yields wrong and I got the just the result back. I added 'jsonrpc' to the dict and from then on, it worked.
According to the JSON-RPC specification, the member ‘jsonrpc’ tells the server which version of the specification is used.
But now the client fails. Can the if statement be rewritten so that it only checks if id, method and params exists in the parsed_keys and just ignore the rest?
When everything is working, I don’t see any problem to share the script. But I first need to clean it up before I can share it. To much sensitive data and at the moment the whole script is a mess.
But it is not in version 1.0 which is the one implemented.
No the goal is to be sure it is a JSON-RPC request. So it must match exactly. Once version 2.0 is supported we should update the test to allow optional ‘jsonrpc’ key.
I would rather see a “snippets” category where people can put their small solutions to different problems. Not everybody fully understands what Tryton is capable of.
But for now, Here is a very very basic script in Python3 which can connect to a Tryton server version 4.8, 5.0 or 5.2 (tested with the demo server)
WARNING! Use at your own risk.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from jsonrpclib import Server as ServerProxy
import jsonrpclib
import json
import base64
# Tryton server connection settings
HOST = 'http://demo4.8.tryton.org'
PORT = '8000'
DB = 'demo4.8'
USER = 'admin'
PASSWORD = 'admin'
class Tryton(object):
def __init__(self, url):
self.server = ServerProxy(url, verbose=0, version=1.0, history=None)
try:
result = self.server.common.db.login(
USER,
{'password': PASSWORD}, 'en_US')
session = ':'.join(map(str, [USER] + result))
auth = base64.b64encode(session.encode())
self.headers = {'AUTHORIZATION' : 'Session ' + auth.decode('utf-8'),
'CONNECTION' : 'keep-alive'
}
with self.server._additional_headers(self.headers) as loggedinClient:
self.pref = loggedinClient.model.res.user.get_preferences(True,{})
print('Connection to Tryton succesfull')
except IOError as msg:
print('Connection to Tryton failed! %s', msg)
raise
def execute(self, method, *args):
args += (self.pref,)
try:
with self.server._additional_headers(self.headers) as loggedinClient:
return getattr(loggedinClient, method)(*args)
except TypeError:
a = json.loads(jsonrpclib.history.response)
print('Execution failed! %s: %s', a['error'][0], a['error'][1])
raise TypeError('%s: %s' % (a['error'][0], a['error'][1]))
def logout(self):
with self.server._additional_headers(self.headers) as loggedinClient:
loggedinClient.common.db.logout()
if __name__ == "__main__":
print('Connect to Tryton')
# connect to tryton and login
tryton = Tryton("%s:%s/%s/" % (HOST, PORT, DB))
# get some data from Tryton. Check the documentation on
# http://docs.tryton.org/projects/server/en/latest/ref/models/models.html
# how to get or send data to Tryton
for sale_order in tryton.execute('model.sale.sale.search_read',
[], 0, 50, None, ['reference', 'number', 'party', 'lines']):
print(sale_order)
print('Log out from Tryton')
tryton.logout()
When working with dates and datetimes, you’re out of luck here. The Tryton JsonRPC encoder and decorder have to be used.