diff --git a/.drone.yml b/.drone.yml index 9d7c769d8c..c4fd423e94 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,9 +1,9 @@ -image: python2.7 +image: python:all env: - POSTGRESQL_URI=postgresql://postgres@127.0.0.1:5432/ - MYSQL_URI=mysql://root@127.0.0.1:3306/ script: - pip install tox - - tox -e "py27-{sqlite,postgresql}" + - tox -e "{py27,py33,py34,py35}-{sqlite,postgresql}" --skip-missing-interpreters services: - postgres diff --git a/CHANGELOG b/CHANGELOG index 433e0a9902..0c30d5b5b0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Add Python3 support + Version 3.8.0 - 2015-11-02 * Bug fixes (see mercurial logs for details) diff --git a/account.py b/account.py index da88600248..0033ff37f1 100644 --- a/account.py +++ b/account.py @@ -5,10 +5,10 @@ from trytond.model import fields from trytond.pyson import Eval __all__ = ['Configuration'] -__metaclass__ = PoolMeta class Configuration: + __metaclass__ = PoolMeta __name__ = 'account.configuration' sepa_mandate_sequence = fields.Property(fields.Many2One('ir.sequence', 'SEPA Mandate Sequence', domain=[ diff --git a/party.py b/party.py index 944635efee..68365143cb 100644 --- a/party.py +++ b/party.py @@ -3,11 +3,11 @@ from trytond.pool import PoolMeta from trytond.model import fields -__metaclass__ = PoolMeta __all__ = ['Party'] class Party: + __metaclass__ = PoolMeta __name__ = 'party.party' sepa_creditor_identifier = fields.Char('SEPA Creditor Identifier', size=35) sepa_creditor_identifier_used = fields.Function(fields.Char( diff --git a/payment.py b/payment.py index e9c505827c..b178bed8cb 100644 --- a/payment.py +++ b/payment.py @@ -22,12 +22,29 @@ from trytond.modules.company import CompanyReport from .sepa_handler import CAMT054 -__metaclass__ = PoolMeta __all__ = ['Journal', 'Group', 'Payment', 'Mandate', 'Message', 'MandateReport'] +# XXX fix: https://genshi.edgewall.org/ticket/582 +from genshi.template.astutil import ASTCodeGenerator, ASTTransformer +if not hasattr(ASTCodeGenerator, 'visit_NameConstant'): + def visit_NameConstant(self, node): + if node.value is None: + self._write('None') + elif node.value is True: + self._write('True') + elif node.value is False: + self._write('False') + else: + raise Exception("Unknown NameConstant %r" % (node.value,)) + ASTCodeGenerator.visit_NameConstant = visit_NameConstant +if not hasattr(ASTTransformer, 'visit_NameConstant'): + # Re-use visit_Name because _clone is deleted + ASTTransformer.visit_NameConstant = ASTTransformer.visit_Name + class Journal: + __metaclass__ = PoolMeta __name__ = 'account.payment.journal' company_party = fields.Function(fields.Many2One('party.party', 'Company Party'), 'on_change_with_company_party') @@ -116,6 +133,7 @@ loader = genshi.template.TemplateLoader( class Group: + __metaclass__ = PoolMeta __name__ = 'account.payment.group' sepa_messages = fields.One2Many('account.payment.sepa.message', 'origin', 'SEPA Messages', readonly=True, @@ -203,6 +221,7 @@ class Group: class Payment: + __metaclass__ = PoolMeta __name__ = 'account.payment' sepa_mandate = fields.Many2One('account.payment.sepa.mandate', 'Mandate', diff --git a/setup.py b/setup.py index 9add3dc8a7..34cbd6dfa4 100644 --- a/setup.py +++ b/setup.py @@ -5,11 +5,17 @@ from setuptools import setup import re import os -import ConfigParser +import io +try: + from configparser import ConfigParser +except ImportError: + from ConfigParser import ConfigParser def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read() + return io.open( + os.path.join(os.path.dirname(__file__), fname), + 'r', encoding='utf-8').read() def get_require_version(name): @@ -21,7 +27,7 @@ def get_require_version(name): major_version, minor_version + 1) return require -config = ConfigParser.ConfigParser() +config = ConfigParser() config.readfp(open('tryton.cfg')) info = dict(config.items('tryton')) for key in ('depends', 'extras_depend', 'xml'): @@ -47,7 +53,12 @@ for dep in info.get('depends', []): requires.append(get_require_version('trytond_%s' % dep)) requires.append(get_require_version('trytond')) -tests_require = ['mock'] +tests_require = [] +try: + from unittest import mock + mock.__version__ +except ImportError: + tests_require.append('mock') setup(name=name, version=version, @@ -91,6 +102,9 @@ setup(name=name, 'Natural Language :: Spanish', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Office/Business', @@ -106,4 +120,5 @@ setup(name=name, test_suite='tests', test_loader='trytond.test_loader:Loader', tests_require=tests_require, + use_2to3=True, ) diff --git a/tests/test_account_payment_sepa.py b/tests/test_account_payment_sepa.py index b448e6960f..8a615b0de3 100644 --- a/tests/test_account_payment_sepa.py +++ b/tests/test_account_payment_sepa.py @@ -4,9 +4,12 @@ import os import unittest from lxml import etree from decimal import Decimal -from io import BytesIO +from io import BytesIO, open -from mock import Mock, patch +try: + from unittest.mock import Mock, patch +except ImportError: + from mock import Mock, patch import trytond.tests.test_tryton from trytond.tests.test_tryton import ModuleTestCase, with_transaction @@ -349,7 +352,7 @@ class AccountPaymentSepaTestCase(ModuleTestCase): message_file = os.path.join(os.path.dirname(__file__), '%s.xml' % flavor) - message = open(message_file).read() + message = open(message_file, 'rb').read() namespace = Message.get_namespace(message) self.assertEqual(namespace, 'urn:iso:std:iso:20022:tech:xsd:%s' % flavor) diff --git a/tox.ini b/tox.ini index e9d2876444..e2a064851d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,10 @@ [tox] -envlist = py27-{sqlite,postgresql,mysql},pypy-{sqlite,postgresql} +envlist = {py27,py33,py34,py35}-{sqlite,postgresql,mysql},pypy-{sqlite,postgresql} [testenv] commands = {envpython} setup.py test deps = - py27-postgresql: psycopg2 >= 2.0 + {py27,py33,py34,py35}-postgresql: psycopg2 >= 2.0 pypy-postgresql: psycopg2cffi >= 2.5 mysql: MySQL-python setenv =