def test_field_reference_read(self): # 8.0 and 9.0 if v(self.odoo.version) < v('10'): Claim = self.odoo.env['crm.claim'] claim_id = Claim.search([])[0] # Test field containing a value self.odoo.execute( 'crm.claim', 'write', [claim_id], {'ref': 'res.partner,1'}) claim = Claim.browse(claim_id) self.assertIsInstance(claim.ref, Model) self.assertEqual(claim.ref._name, 'res.partner') self.assertEqual(claim.ref.id, 1) # Test if empty field returns False (unable to guess the model to use) self.odoo.execute( 'crm.claim', 'write', [claim_id], {'ref': None}) claim = Claim.browse(claim_id) self.assertEqual(claim.ref, False) # 10.0 else: Subscription = self.odoo.env['subscription.subscription'] fields_list = list(Subscription.fields_get([])) vals = Subscription.default_get(fields_list) vals['name'] = "ODOORPC TEST (fields.Reference)" vals['doc_source'] = 'res.partner,1' subscription_id = Subscription.create(vals) # Test field containing a value subscription = Subscription.browse(subscription_id) self.assertIsInstance(subscription.doc_source, Model) self.assertEqual(subscription.doc_source._name, 'res.partner') self.assertEqual(subscription.doc_source.id, 1)
def test_field_reference_read(self): # 8.0 and 9.0 if v(self.odoo.version) < v('10'): Claim = self.odoo.env['crm.claim'] claim_id = Claim.search([])[0] # Test field containing a value self.odoo.execute('crm.claim', 'write', [claim_id], {'ref': 'res.partner,1'}) claim = Claim.browse(claim_id) self.assertIsInstance(claim.ref, Model) self.assertEqual(claim.ref._name, 'res.partner') self.assertEqual(claim.ref.id, 1) # Test if empty field returns False (unable to guess the model to use) self.odoo.execute('crm.claim', 'write', [claim_id], {'ref': None}) claim = Claim.browse(claim_id) self.assertEqual(claim.ref, False) # 10.0 else: Subscription = self.odoo.env['subscription.subscription'] fields_list = list(Subscription.fields_get([])) vals = Subscription.default_get(fields_list) vals['name'] = "ODOORPC TEST (fields.Reference)" vals['doc_source'] = 'res.partner,1' subscription_id = Subscription.create(vals) # Test field containing a value subscription = Subscription.browse(subscription_id) self.assertIsInstance(subscription.doc_source, Model) self.assertEqual(subscription.doc_source._name, 'res.partner') self.assertEqual(subscription.doc_source.id, 1)
def test_v_cmp(self): # [(v1, v2, is_inferior), ...] versions = [ ('7.0', '6.1', False), ('6.1', '7.0', True), ('7.0alpha', '6.1', False), ('6.1beta', '7.0', True), ('6.1beta', '5.0.16', False), ('5.0.16alpha', '6.1', True), ('8.0dev-20131102-000101', '7.0-20131014-231047', False), ] for v1, v2, is_inferior in versions: result = tools.v(v1) < tools.v(v2) if is_inferior: self.assertTrue(result) else: self.assertFalse(result)
def test_exec_workflow_wrong_model(self): if tools.v(self.odoo.version)[0] >= 11: self.assertRaises(DeprecationWarning, self.odoo.exec_workflow, 'sale.order2', self.so_id, 'order_confirm') return self.assertRaises(error.RPCError, self.odoo.exec_workflow, 'sale.order2', self.so_id, 'order_confirm')
def setUp(self): LoginTestCase.setUp(self) if tools.v(self.odoo.version)[0] >= 11: # Value doesn't matter for Odoo >= 11, we only test the # DeprecationWarning exception for workflow methods self.so_id = 1 return self.product_obj = self.odoo.env['product.product'] self.partner_obj = self.odoo.env['res.partner'] self.sale_order_obj = self.odoo.env['sale.order'] self.uom_obj = self.odoo.env['product.uom'] self.p_id = self.partner_obj.create({'name': "Child 1"}) prod_vals = { 'name': "PRODUCT TEST WORKFLOW", } self.product_id = self.product_obj.create(prod_vals) sol_vals = { 'name': "TEST WORKFLOW", 'product_id': self.product_id, 'product_uom': self.uom_obj.search([])[0], } so_vals = { 'partner_id': self.p_id, 'order_line': [(0, 0, sol_vals)], } self.so_id = self.sale_order_obj.create(so_vals)
def exec_workflow(self, model, record_id, signal): """Execute the workflow `signal` on the instance having the ID `record_id` of `model`. *Python 2:* :raise: :class:`odoorpc.error.RPCError` :raise: :class:`odoorpc.error.InternalError` (if not logged) :raise: `urllib2.URLError` (connection error) *Python 3:* :raise: :class:`odoorpc.error.RPCError` :raise: :class:`odoorpc.error.InternalError` (if not logged) :raise: `urllib.error.URLError` (connection error) """ if tools.v(self.version)[0] >= 11: raise DeprecationWarning( u"Workflows have been removed in Odoo >= 11.0") self._check_logged_user() # Execute the workflow query args_to_send = [ self.env.db, self.env.uid, self._password, model, signal, record_id ] data = self.json('/jsonrpc', { 'service': 'object', 'method': 'exec_workflow', 'args': args_to_send }) return data.get('result')
def test_increased_timeout(self): # Set the timeout self.odoo.config['timeout'] = 120 # Execute a time consuming query: no exception report_name = 'web.preview_internalreport' if v(self.odoo.version)[0] < 11: report_name = 'preview.report' self.odoo.report.download(report_name, [1])
def test_exec_workflow(self): if tools.v(self.odoo.version)[0] >= 11: self.assertRaises( DeprecationWarning, self.odoo.exec_workflow, 'sale.order', self.so_id, 'order_confirm') return self.odoo.exec_workflow('sale.order', self.so_id, 'order_confirm')
def test_report_download_qweb_pdf(self): model = 'account.move' if v(self.odoo.version)[0] < 13: model = 'account.invoice' report_name = 'account.report_invoice' ids = self.odoo.env[model].search([])[:10] report = self.odoo.report.download(report_name, ids) with tempfile.TemporaryFile(mode='wb', suffix='.pdf') as file_: file_.write(report.read())
def test_report_download_pdf(self): model = 'res.company' report_name = 'web.preview_internalreport' if v(self.odoo.version)[0] < 11: report_name = 'preview.report' ids = self.odoo.env[model].search([])[:20] report = self.odoo.report.download(report_name, ids) with tempfile.TemporaryFile(mode='wb', suffix='.pdf') as file_: file_.write(report.read())
def test_reduced_timeout(self): # Set the timeout self.odoo.config['timeout'] = 0.005 # Execute a time consuming query: handle exception report_name = 'web.preview_internalreport' if v(self.odoo.version)[0] < 11: report_name = 'preview.report' self.assertRaises(socket.timeout, self.odoo.report.download, report_name, [1])
def list(self): """List available reports from the server by returning a dictionary with reports classified by data model: .. doctest:: :options: +SKIP >>> from odoorpc.tools import v >>> inv_model = 'account.move' >>> if v(VERSION) < v('13.0'): ... inv_model = 'account.invoice' >>> odoo.report.list()[inv_model] [{'name': u'Duplicates', 'report_name': u'account.account_invoice_report_duplicate_main', 'report_type': u'qweb-pdf'}, {'name': 'Invoices', 'report_type': 'qweb-pdf', 'report_name': 'account.report_invoice'}] .. doctest:: :hide: >>> from odoorpc.tools import v >>> inv_model = 'account.move' >>> if v(VERSION) < v('13.0'): ... inv_model = 'account.invoice' >>> from pprint import pprint as pp >>> any(data['report_name'] == 'account.report_invoice' ... for data in odoo.report.list()[inv_model]) True *Python 2:* :return: `list` of dictionaries :raise: `urllib2.URLError` (connection error) *Python 3:* :return: `list` of dictionaries :raise: `urllib.error.URLError` (connection error) """ report_model = 'ir.actions.report' if v(self._odoo.version)[0] < 11: report_model = 'ir.actions.report.xml' IrReport = self._odoo.env[report_model] report_ids = IrReport.search([]) reports = IrReport.read( report_ids, ['name', 'model', 'report_name', 'report_type']) result = {} for report in reports: model = report.pop('model') report.pop('id') if model not in result: result[model] = [] result[model].append(report) return result
def check_report(name): report_model = 'ir.actions.report' if v(self._odoo.version)[0] < 11: report_model = 'ir.actions.report.xml' IrReport = self._odoo.env[report_model] report_ids = IrReport.search([('report_name', '=', name)]) report_id = report_ids and report_ids[0] or False if not report_id: raise ValueError("The report '%s' does not exist." % name) return report_id
def test_reduced_timeout(self): # Set the timeout self.odoo.config['timeout'] = 0.005 # Execute a time consuming query: handle exception report_name = 'web.preview_internalreport' if v(self.odoo.version)[0] < 11: report_name = 'preview.report' self.assertRaises( socket.timeout, self.odoo.report.download, report_name, [1])
def test_report_list(self): res = self.odoo.report.list() self.assertIsInstance(res, dict) model = 'account.move' if v(self.odoo.version)[0] < 13: model = 'account.invoice' self.assertIn(model, res) self.assertTrue( any('account.report_invoice' in data['report_name'] for data in res[model]))
def test_exec_workflow(self): if tools.v(self.odoo.version)[0] >= 11: self.assertRaises( DeprecationWarning, self.odoo.exec_workflow, 'sale.order', self.so_id, 'order_confirm', ) return self.odoo.exec_workflow('sale.order', self.so_id, 'order_confirm')
def test_exec_workflow_wrong_model(self): if tools.v(self.odoo.version)[0] >= 11: self.assertRaises( DeprecationWarning, self.odoo.exec_workflow, 'sale.order2', self.so_id, 'order_confirm') return self.assertRaises( error.RPCError, self.odoo.exec_workflow, 'sale.order2', self.so_id, 'order_confirm')
def list(self): """List available reports from the server by returning a dictionary with reports classified by data model: .. doctest:: :options: +SKIP >>> odoo.report.list()['account.invoice'] [{'name': u'Duplicates', 'report_name': u'account.account_invoice_report_duplicate_main', 'report_type': u'qweb-pdf'}, {'name': 'Invoices', 'report_type': 'qweb-pdf', 'report_name': 'account.report_invoice'}] .. doctest:: :hide: >>> from pprint import pprint as pp >>> any(data['report_name'] == 'account.report_invoice' ... for data in odoo.report.list()['account.invoice']) True *Python 2:* :return: `list` of dictionaries :raise: `urllib2.URLError` (connection error) *Python 3:* :return: `list` of dictionaries :raise: `urllib.error.URLError` (connection error) """ report_model = 'ir.actions.report' if v(self._odoo.version)[0] < 11: report_model = 'ir.actions.report.xml' IrReport = self._odoo.env[report_model] report_ids = IrReport.search([]) reports = IrReport.read( report_ids, ['name', 'model', 'report_name', 'report_type']) result = {} for report in reports: model = report.pop('model') report.pop('id') if model not in result: result[model] = [] result[model].append(report) return result
def test_field_boolean_write(self): # TODO: split in several unit tests partner = self.user.partner_id if v(self.odoo.version)[0] < 13: backup = partner.customer # True partner.customer = True data = partner.read(['customer'])[0] self.assertEqual(data['customer'], True) self.assertEqual(partner.customer, True) # False partner.customer = False data = partner.read(['customer'])[0] self.assertEqual(data['customer'], False) self.assertEqual(partner.customer, False) # None partner.customer = None data = partner.read(['customer'])[0] self.assertEqual(data['customer'], False) self.assertEqual(partner.customer, False) # Restore original value partner.customer = backup data = partner.read(['customer'])[0] self.assertEqual(data['customer'], backup) self.assertEqual(partner.customer, backup) else: backup = partner.customer_rank # True partner.customer_rank = True data = partner.read(['customer_rank'])[0] self.assertEqual(data['customer_rank'], True) self.assertEqual(partner.customer_rank, True) # False partner.customer_rank = False data = partner.read(['customer_rank'])[0] self.assertEqual(data['customer_rank'], False) self.assertEqual(partner.customer_rank, False) # None partner.customer_rank = None data = partner.read(['customer_rank'])[0] self.assertEqual(data['customer_rank'], False) self.assertEqual(partner.customer_rank, False) # Restore original value partner.customer_rank = backup data = partner.read(['customer_rank'])[0] self.assertEqual(data['customer_rank'], backup) self.assertEqual(partner.customer_rank, backup)
def test_field_binary_write(self): if v(self.odoo.version)[0] < 13: backup = self.user.image jpeg_file = ( b"\xff\xd8\xff\xdb\x00\x43\x00\x03\x02\x02\x02\x02\x02\x03\x02\x02" b"\x02\x03\x03\x03\x03\x04\x06\x04\x04\x04\x04\x04\x08\x06\x06\x05" b"\x06\x09\x08\x0a\x0a\x09\x08\x09\x09\x0a\x0c\x0f\x0c\x0a\x0b\x0e" b"\x0b\x09\x09\x0d\x11\x0d\x0e\x0f\x10\x10\x11\x10\x0a\x0c\x12\x13" b"\x12\x10\x13\x0f\x10\x10\x10\xff\xc9\x00\x0b\x08\x00\x01\x00\x01" b"\x01\x01\x11\x00\xff\xcc\x00\x06\x00\x10\x10\x05\xff\xda\x00\x08" b"\x01\x01\x00\x00\x3f\x00\xd2\xcf\x20\xff\xd9" ) # https://github.com/mathiasbynens/small/blob/master/jpeg.jpg self.user.image = base64.b64encode(jpeg_file).decode('ascii') data = self.user.read(['image'])[0] decoded = base64.b64decode(data['image'].encode('ascii')) self.assertEqual(decoded, jpeg_file) # Restore original value self.user.image = backup data = self.user.read(['image'])[0] self.assertEqual(data['image'], backup) self.assertEqual(self.user.image, backup) else: backup = self.user.image_1920 jpeg_file = ( b"\xff\xd8\xff\xdb\x00\x43\x00\x03\x02\x02\x02\x02\x02\x03\x02\x02" b"\x02\x03\x03\x03\x03\x04\x06\x04\x04\x04\x04\x04\x08\x06\x06\x05" b"\x06\x09\x08\x0a\x0a\x09\x08\x09\x09\x0a\x0c\x0f\x0c\x0a\x0b\x0e" b"\x0b\x09\x09\x0d\x11\x0d\x0e\x0f\x10\x10\x11\x10\x0a\x0c\x12\x13" b"\x12\x10\x13\x0f\x10\x10\x10\xff\xc9\x00\x0b\x08\x00\x01\x00\x01" b"\x01\x01\x11\x00\xff\xcc\x00\x06\x00\x10\x10\x05\xff\xda\x00\x08" b"\x01\x01\x00\x00\x3f\x00\xd2\xcf\x20\xff\xd9" ) # https://github.com/mathiasbynens/small/blob/master/jpeg.jpg self.user.image_1920 = base64.b64encode(jpeg_file).decode('ascii') data = self.user.read(['image_1920'])[0] decoded = base64.b64decode(data['image_1920'].encode('ascii')) self.assertEqual(decoded, jpeg_file) # Restore original value self.user.image_1920 = backup data = self.user.read(['image_1920'])[0] self.assertEqual(data['image_1920'], backup) self.assertEqual(self.user.image_1920, backup)
def dump(self, password, db, format_='zip'): """Backup the `db` database. Returns the dump as a binary ZIP file containing the SQL dump file alongside the filestore directory (if any). >>> dump = odoo.db.dump('super_admin_passwd', 'prod') # doctest: +SKIP .. doctest:: :hide: >>> dump = odoo.db.dump(SUPER_PWD, DB) If you get a timeout error, increase this one before performing the request: >>> timeout_backup = odoo.config['timeout'] >>> odoo.config['timeout'] = 600 # Timeout set to 10 minutes >>> dump = odoo.db.dump('super_admin_passwd', 'prod') # doctest: +SKIP >>> odoo.config['timeout'] = timeout_backup Write it on the file system: .. doctest:: :options: +SKIP >>> with open('dump.zip', 'wb') as dump_zip: ... dump_zip.write(dump.read()) ... .. doctest:: :hide: >>> with open('dump.zip', 'wb') as dump_zip: ... fileno = dump_zip.write(dump.read()) # Python 3 ... You can manipulate the file with the `zipfile` module for instance: .. doctest:: :options: +SKIP >>> import zipfile >>> zipfile.ZipFile('dump.zip').namelist() ['dump.sql', 'filestore/ef/ef2c882a36dbe90fc1e7e28d816ad1ac1464cfbb', 'filestore/dc/dcf00aacce882bbfd117c0277e514f829b4c5bf0', ...] .. doctest:: :hide: >>> import zipfile >>> zipfile.ZipFile('dump.zip').namelist() # doctest: +NORMALIZE_WHITESPACE ['dump.sql'...'filestore/...'...] The super administrator password is required to perform this method. *Python 2:* :return: `io.BytesIO` :raise: :class:`odoorpc.error.RPCError` (access denied / wrong database) :raise: `urllib2.URLError` (connection error) *Python 3:* :return: `io.BytesIO` :raise: :class:`odoorpc.error.RPCError` (access denied / wrong database) :raise: `urllib.error.URLError` (connection error) """ args = [password, db] if v(self._odoo.version)[0] >= 9: args.append(format_) data = self._odoo.json( '/jsonrpc', {'service': 'db', 'method': 'dump', 'args': args}) # Encode to bytes forced to be compatible with Python 3.2 # (its 'base64.standard_b64decode()' function only accepts bytes) result = encode2bytes(data['result']) content = base64.standard_b64decode(result) return io.BytesIO(content)
def dump(self, password, db, format_='zip'): """Backup the `db` database. Returns the dump as a binary ZIP file containing the SQL dump file alongside the filestore directory (if any). >>> dump = odoo.db.dump('super_admin_passwd', 'prod') # doctest: +SKIP .. doctest:: :hide: >>> dump = odoo.db.dump(SUPER_PWD, DB) If you get a timeout error, increase this one before performing the request: >>> timeout_backup = odoo.config['timeout'] >>> odoo.config['timeout'] = 600 # Timeout set to 10 minutes >>> dump = odoo.db.dump('super_admin_passwd', 'prod') # doctest: +SKIP >>> odoo.config['timeout'] = timeout_backup Write it on the file system: .. doctest:: :options: +SKIP >>> with open('dump.zip', 'wb') as dump_zip: ... dump_zip.write(dump.read()) ... .. doctest:: :hide: >>> with open('dump.zip', 'wb') as dump_zip: ... fileno = dump_zip.write(dump.read()) # Python 3 ... You can manipulate the file with the `zipfile` module for instance: .. doctest:: :options: +SKIP >>> import zipfile >>> zipfile.ZipFile('dump.zip').namelist() ['dump.sql', 'filestore/ef/ef2c882a36dbe90fc1e7e28d816ad1ac1464cfbb', 'filestore/dc/dcf00aacce882bbfd117c0277e514f829b4c5bf0', ...] .. doctest:: :hide: >>> import zipfile >>> zipfile.ZipFile('dump.zip').namelist() # doctest: +NORMALIZE_WHITESPACE ['dump.sql'...'filestore/...'...] The super administrator password is required to perform this method. *Python 2:* :return: `io.BytesIO` :raise: :class:`odoorpc.error.RPCError` (access denied / wrong database) :raise: `urllib2.URLError` (connection error) *Python 3:* :return: `io.BytesIO` :raise: :class:`odoorpc.error.RPCError` (access denied / wrong database) :raise: `urllib.error.URLError` (connection error) """ args = [password, db] if v(self._odoo.version)[0] >= 9: args.append(format_) data = self._odoo.json('/jsonrpc', { 'service': 'db', 'method': 'dump', 'args': args }) # Encode to bytes forced to be compatible with Python 3.2 # (its 'base64.standard_b64decode()' function only accepts bytes) result = encode2bytes(data['result']) content = base64.standard_b64decode(result) return io.BytesIO(content)
def download(self, name, ids, datas=None, context=None): """Download a report from the server and return it as a remote file. For instance, to download the "Quotation / Order" report of sale orders identified by the IDs ``[2, 3]``: .. doctest:: :options: +SKIP >>> report = odoo.report.download('sale.report_saleorder', [2, 3]) .. doctest:: :hide: >>> report = odoo.report.download('sale.report_saleorder', [2]) Write it on the file system: .. doctest:: :options: +SKIP >>> with open('sale_orders.pdf', 'wb') as report_file: ... report_file.write(report.read()) ... .. doctest:: :hide: >>> with open('sale_orders.pdf', 'wb') as report_file: ... fileno = report_file.write(report.read()) # Python 3 ... *Python 2:* :return: `io.BytesIO` :raise: :class:`odoorpc.error.RPCError` (wrong parameters) :raise: `ValueError` (received invalid data) :raise: `urllib2.URLError` (connection error) *Python 3:* :return: `io.BytesIO` :raise: :class:`odoorpc.error.RPCError` (wrong parameters) :raise: `ValueError` (received invalid data) :raise: `urllib.error.URLError` (connection error) """ if context is None: context = self._odoo.env.context def check_report(name): report_model = 'ir.actions.report' if v(self._odoo.version)[0] < 11: report_model = 'ir.actions.report.xml' IrReport = self._odoo.env[report_model] report_ids = IrReport.search([('report_name', '=', name)]) report_id = report_ids and report_ids[0] or False if not report_id: raise ValueError("The report '%s' does not exist." % name) return report_id report_id = check_report(name) # Odoo >= 11.0 if v(self._odoo.version)[0] >= 11: IrReport = self._odoo.env['ir.actions.report'] report = IrReport.browse(report_id) if v(self._odoo.version)[0] >= 14: response = report.with_context(context)._render(ids, data=datas) else: response = report.with_context(context).render(ids, data=datas) content = response[0] # On the server the result is a bytes string, # but the RPC layer of Odoo returns it as a unicode string, # so we encode it again as bytes result = content.encode('latin1') return io.BytesIO(result) # Odoo < 11.0 else: args_to_send = [ self._odoo.env.db, self._odoo.env.uid, self._odoo._password, name, ids, datas, context, ] data = self._odoo.json( '/jsonrpc', { 'service': 'report', 'method': 'render_report', 'args': args_to_send, }, ) if 'result' not in data and not data['result'].get('result'): raise ValueError("Received invalid data.") # Encode to bytes forced to be compatible with Python 3.2 # (its 'base64.standard_b64decode()' function only accepts bytes) result = encode2bytes(data['result']['result']) content = base64.standard_b64decode(result) return io.BytesIO(content)
def test_field_binary_read(self): if v(self.odoo.version)[0] < 13: img = self.user.image else: img = self.user.image_1920 base64.b64decode(img.encode('ascii'))
def test_v_alphanumeric(self): self.assertEqual(tools.v('7.0alpha'), [7, 0])
def test_v_numeric(self): self.assertEqual(tools.v('7.0'), [7, 0])
def download(self, name, ids, datas=None, context=None): """Download a report from the server and return it as a remote file. For instance, to download the "Quotation / Order" report of sale orders identified by the IDs ``[2, 3]``: .. doctest:: >>> report = odoo.report.download('sale.report_saleorder', [2, 3]) Write it on the file system: .. doctest:: :options: +SKIP >>> with open('sale_orders.pdf', 'wb') as report_file: ... report_file.write(report.read()) ... .. doctest:: :hide: >>> with open('sale_orders.pdf', 'wb') as report_file: ... fileno = report_file.write(report.read()) # Python 3 ... *Python 2:* :return: `io.BytesIO` :raise: :class:`odoorpc.error.RPCError` (wrong parameters) :raise: `ValueError` (received invalid data) :raise: `urllib2.URLError` (connection error) *Python 3:* :return: `io.BytesIO` :raise: :class:`odoorpc.error.RPCError` (wrong parameters) :raise: `ValueError` (received invalid data) :raise: `urllib.error.URLError` (connection error) """ if context is None: context = self._odoo.env.context def check_report(name): report_model = 'ir.actions.report' if v(self._odoo.version)[0] < 11: report_model = 'ir.actions.report.xml' IrReport = self._odoo.env[report_model] report_ids = IrReport.search([('report_name', '=', name)]) report_id = report_ids and report_ids[0] or False if not report_id: raise ValueError("The report '%s' does not exist." % name) return report_id report_id = check_report(name) # Odoo >= 11.0 if v(self._odoo.version)[0] >= 11: IrReport = self._odoo.env['ir.actions.report'] report = IrReport.browse(report_id) response = report.with_context(context).render(ids, data=datas) content = response[0] # On the server the result is a bytes string, # but the RPC layer of Odoo returns it as a unicode string, # so we encode it again as bytes result = content.encode('latin1') return io.BytesIO(result) # Odoo < 11.0 else: args_to_send = [self._odoo.env.db, self._odoo.env.uid, self._odoo._password, name, ids, datas, context] data = self._odoo.json( '/jsonrpc', {'service': 'report', 'method': 'render_report', 'args': args_to_send}) if 'result' not in data and not data['result'].get('result'): raise ValueError("Received invalid data.") # Encode to bytes forced to be compatible with Python 3.2 # (its 'base64.standard_b64decode()' function only accepts bytes) result = encode2bytes(data['result']['result']) content = base64.standard_b64decode(result) return io.BytesIO(content)