John Vandenberg has uploaded a new change for review.
https://gerrit.wikimedia.org/r/291155
Change subject: Add PyPy builds
......................................................................
Add PyPy builds
- unicodedata2 and lunatic-python are not PyPy compatible
Change-Id: Ide8bcef49499d7f3bb7bcbf00bde3d42936e5672
---
M .travis.yml
M pywikibot/__init__.py
M requirements.txt
M setup.py
M tests/api_tests.py
M tests/bot_tests.py
M tests/i18n_tests.py
M tests/pwb_tests.py
M tests/script_tests.py
M tests/tools_tests.py
M tox.ini
11 files changed, 156 insertions(+), 13 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/pywikibot/core
refs/changes/55/291155/1
diff --git a/.travis.yml b/.travis.yml
index a0186ad..332e6a0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,6 +5,7 @@
sudo: false
python:
+ - 'pypy'
- '2.7'
- '3.3'
- '3.4'
@@ -30,10 +31,27 @@
# Instead install requests in the before_script step below.
- if [[ "$PYSETUP_TEST_EXTRAS" != '1' ]]; then rm requirements.txt ; fi
+ # PyPy `pwb` based tests fail under plain unittest, but work under pytest
+ - if [[ "$TRAVIS_PYTHON_VERSION" = "pypy" ]]; then USE_PYTEST=1; fi
+
# When the env variable USE_NOSE or USE_PYTEST is set, the appropriate
# tool is used, else PYTEST is taken as the default
- - if [[ "$PYSETUP_TEST_EXTRAS" != '1' && "$USE_NOSE" != '1' && "$USE_PYTEST"
!= '1' ]]; then
- export USE_PYTEST=1 ;
+ - |
+ if [[ "$USE_NOSE" != '1' && "$USE_PYTEST" != '1' ]]; then
+ if [[ "$NO_NET" == '1' ]]; then
+ export USE_PYTEST=1
+ elif [[ "$PYSETUP_TEST_EXTRAS" != '1' ]]; then
+ export USE_PYTEST=1
+ fi
+ fi
+
+ - if [[ -z "$FAMILY" ]]; then FAMILY=test; fi
+ - if [[ -z "$LANGUAGE" ]]; then LANGUAGE=test; fi
+
+ - |
+ if [[ "$NO_NET" == '1' ]]; then
+ echo "Running no tests requiring network access"
+ echo "(however generate_family_file uses network)"
fi
- if [[ "$SITE_ONLY" == '1' ]]; then
@@ -48,12 +66,29 @@
export PYWIKIBOT2_TEST_WRITE_FAIL=1 ;
fi
+ # Set the default pypy version to be 2.6.1
+ - if [[ "$PYPY_VERSION" != '' ]]; then PYPY_VERSION=2.6.1; fi
+
+ - | # Based on Vlad Frolov's MIT licensed
https://github.com/travis-ci/travis-ci/issues/5027#issuecomment-170939193
+ if [[ "$TRAVIS_PYTHON_VERSION" = "pypy" && "$PYPY_VERSION" != 'default'
]]; then
+ export PYENV_ROOT="$HOME/.pyenv"
+ if [[ -f "$PYENV_ROOT/bin/pyenv" ]]; then
+ pushd "$PYENV_ROOT" && git pull && popd
+ else
+ rm -rf "$PYENV_ROOT" && git clone --depth 1
https://github.com/yyuu/pyenv.git "$PYENV_ROOT"
+ fi
+ "$PYENV_ROOT/bin/pyenv" install --skip-existing "pypy-$PYPY_VERSION"
+ virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python"
"$HOME/virtualenvs/pypy-$PYPY_VERSION"
+ source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate"
+ python --version
+ fi
+
before_script:
- pip install -r dev-requirements.txt
script:
# Install security packages for requests to support HTTPS in site_detect
- - if [[ "$PYSETUP_TEST_EXTRAS" != '1' ]]; then
+ - if [[ "$PYSETUP_TEST_EXTRAS" != '1' && "$NO_NET" != '1' ]]; then
pip install mwoauth -r requests-requirements.txt ;
fi
@@ -100,12 +135,17 @@
nosetests --version ;
if [[ "$SITE_ONLY" == "1" ]]; then
python setup.py nosetests --tests tests --verbosity=2 -a
"family=$FAMILY,code=$LANGUAGE" --with-trim --with-coverage --cover-package=. ;
+ elif [[ "$NO_NET" == "1" ]]; then
+ python setup.py nosetests --tests tests --verbosity=2 -a "!net"
--with-trim --with-coverage --cover-package=. ;
else
python setup.py nosetests --tests tests --verbosity=2 --with-trim
--with-coverage --cover-package=. ;
fi ;
elif [[ "$USE_PYTEST" == "1" ]]; then
+ py.test --version ;
if [[ "$SITE_ONLY" == "1" ]]; then
python setup.py pytest --addopts="-vvv -s --timeout=$TEST_TIMEOUT
--cov=. -a \"family=='$FAMILY' and code=='$LANGUAGE'\"" ;
+ elif [[ "$NO_NET" == "1" ]]; then
+ python setup.py pytest --addopts="-vvv -s --timeout=$TEST_TIMEOUT
--cov=. -a \"not net\"" ;
else
python setup.py pytest --addopts="-vvv -s --timeout=$TEST_TIMEOUT
--cov=." ;
fi
@@ -134,6 +174,14 @@
matrix:
include:
+ # Test the Ubuntu precise pypy (2.5) without network
+ - python: 'pypy'
+ env: PYPY_VERSION=default NO_NET=1 USE_PYTEST=1
+ - python: 'pypy'
+ env: PYPY_VERSION=default NO_NET=1 USE_NOSE=1
+ # Test the Ubuntu precise pypy (2.5) with network; fails with T136382
+ - python: 'pypy'
+ env: PYPY_VERSION=default
- python: '2.7_with_system_site_packages' # equivalent to virtualenv:
system_site_packages: true
env: LANGUAGE=he FAMILY=wikivoyage DIST=precise-sudo
PYWIKIBOT2_TEST_NO_RC=1
dist: precise
@@ -174,6 +222,16 @@
env: LANGUAGE=ar FAMILY=wiktionary PYWIKIBOT2_TEST_NO_RC=1
- python: '2.6'
env: LANGUAGE=wikidata FAMILY=wikidata SITE_ONLY=1
+ # Test no-net flag
+ - python: '2.6'
+ env: NO_NET=1
+ - python: 'pypy'
+ env: PYPY_VERSION=5.0.1 PYSETUP_TEST_EXTRAS=1 NO_NET=1
+ # https://travis-ci.org/jayvdb/pywikibot-core/jobs/133171601 - strange
errors on py.test
+ - python: 'pypy'
+ env: PYPY_VERSION=4.0.1 PYSETUP_TEST_EXTRAS=1
+ - python: 'pypy'
+ env: PYPY_VERSION=5.1.1 PYSETUP_TEST_EXTRAS=1
notifications:
email:
diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py
index c80c9e1..d04bdd1 100644
--- a/pywikibot/__init__.py
+++ b/pywikibot/__init__.py
@@ -130,6 +130,12 @@
deprecated = redirect_func(__deprecated)
deprecate_arg = redirect_func(__deprecate_arg)
+try:
+ sys.pypy_version_info
+ PYPY = True
+except AttributeError:
+ PYPY = False
+
class Timestamp(datetime.datetime):
@@ -155,6 +161,16 @@
mediawikiTSFormat = "%Y%m%d%H%M%S"
ISO8601Format = "%Y-%m-%dT%H:%M:%SZ"
+ if PYPY:
+ def replace(self, *args, **kwargs):
+ obj = super(Timestamp, self).replace(*args, **kwargs)
+ return self.__class__(
+ year=obj.year, month=obj.month, day=obj.day,
+ hour=obj.hour, minute=obj.minute, second=obj.second,
+ microsecond=obj.microsecond,
+ tzinfo=obj.tzinfo,
+ )
+
def clone(self):
"""Clone this instance."""
return self.replace(microsecond=self.microsecond)
diff --git a/requirements.txt b/requirements.txt
index 9b4400a..7ba4be6 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -30,7 +30,7 @@
ipaddr>=2.1.10 ; python_version < '3'
-unicodedata2>=7.0.0-2 ; python_version < '3'
+unicodedata2>=7.0.0-2 ; python_version < '3' and
platform_python_implementation != 'PyPy'
# OAuth support
# mwoauth 0.2.4 is needed because it supports getting identity information
diff --git a/setup.py b/setup.py
index c880ec4..2fd8a02 100644
--- a/setup.py
+++ b/setup.py
@@ -25,6 +25,12 @@
PY2 = (PYTHON_VERSION[0] == 2)
PY26 = (PYTHON_VERSION < (2, 7))
+try:
+ sys.pypy_version_info
+ PYPY = True
+except AttributeError:
+ PYPY = False
+
versions_required_message = """
Pywikibot not available on:
%s
@@ -72,6 +78,10 @@
extra_deps.update({
'csv': [csv_dep],
'MySQL': ['oursql'],
+ })
+
+if PY2 and not PYPY:
+ extra_deps.update({
'unicode7': ['unicodedata2>=7.0.0-2'],
})
@@ -93,7 +103,7 @@
'flickrapi>=1.4.5,<2' if PY26 else 'flickrapi')
# lunatic-python is only available for Linux
-if sys.platform.startswith('linux'):
+if sys.platform.startswith('linux') and not PYPY:
script_deps['script_wui.py'] = [irc_dep, 'lunatic-python', 'crontab']
# The main pywin32 repository contains a Python 2 only setup.py with a small
@@ -187,6 +197,10 @@
else:
test_deps += ['six']
+# Before commencing unit tests, clear the last exception
+if PY2:
+ sys.exc_clear()
+
from setuptools import setup, find_packages
name = 'pywikibot'
diff --git a/tests/api_tests.py b/tests/api_tests.py
index 3e3e61a..b2d179f 100644
--- a/tests/api_tests.py
+++ b/tests/api_tests.py
@@ -624,7 +624,7 @@
"""Test setting the limit to not a number."""
with self.assertRaisesRegex(
ValueError,
- "invalid literal for int\(\) with base 10: 'test'"):
+ "invalid literal for int\(\) with base 10: u?'test'"):
self.gen.set_maximum_items('test')
def test_limit_equal_total(self):
diff --git a/tests/bot_tests.py b/tests/bot_tests.py
index c95b9d5..82f6e6f 100644
--- a/tests/bot_tests.py
+++ b/tests/bot_tests.py
@@ -83,6 +83,9 @@
super(FakeSaveBotTestCase, self).setUp()
self.assert_saves = getattr(self, 'default_assert_saves', 1)
self.save_called = 0
+ # Ensure that exceptions outside the test do not break these tests
+ if PY2:
+ sys.exc_clear()
def tearDown(self):
"""Tear down by asserting the counters."""
@@ -160,6 +163,7 @@
"""Get tests which are executed on exit."""
def exit():
exc = sys.exc_info()[0]
+ tb = sys.exc_info()[2]
if exc is AssertionError:
# When an AssertionError happened we shouldn't do these
# assertions as they are invalid anyway and hide the actual
@@ -170,6 +174,10 @@
if exception:
self.assertIs(exc, exception)
else:
+ if exc:
+ print('saw exception')
+ import traceback
+ print(traceback.format_tb(tb))
self.assertIsNone(exc)
self.assertRaises(StopIteration, next, self._page_iter)
return exit
diff --git a/tests/i18n_tests.py b/tests/i18n_tests.py
index 22fd9b0..139c1b4 100644
--- a/tests/i18n_tests.py
+++ b/tests/i18n_tests.py
@@ -300,9 +300,9 @@
def testMultipleNonNumbers(self):
"""Test error handling for multiple non-numbers."""
- with self.assertRaisesRegex(ValueError, "invalid literal for int\(\)
with base 10: 'drei'"):
+ with self.assertRaisesRegex(ValueError, "invalid literal for int\(\)
with base 10: u?'drei'"):
i18n.twntranslate('de', 'test-multiple-plurals', ["drei", "1", 1])
- with self.assertRaisesRegex(ValueError, "invalid literal for int\(\)
with base 10: 'elf'"):
+ with self.assertRaisesRegex(ValueError, "invalid literal for int\(\)
with base 10: u?'elf'"):
i18n.twntranslate('de', 'test-multiple-plurals',
{'action': u'Ändere', 'line': "elf", 'page': 2})
diff --git a/tests/pwb_tests.py b/tests/pwb_tests.py
index 94535f3..185cca5 100644
--- a/tests/pwb_tests.py
+++ b/tests/pwb_tests.py
@@ -21,6 +21,12 @@
from tests.utils import execute, execute_pwb
from tests.aspects import unittest, PwbTestCase
+try:
+ sys.pypy_version_info
+ PYPY = True
+except AttributeError:
+ PYPY = False
+
join_pwb_tests_path = create_path_func(join_tests_path, 'pwb')
@@ -57,6 +63,8 @@
Make sure the environment is not contaminated, and is the same as
the environment we get when directly running a script.
"""
+ if PYPY:
+ raise unittest.SkipTest('Fails on PyPy, dumping secure env vars')
self._do_check('print_env')
def test_locals(self):
diff --git a/tests/script_tests.py b/tests/script_tests.py
index 5837e98..c2cd614 100644
--- a/tests/script_tests.py
+++ b/tests/script_tests.py
@@ -25,6 +25,12 @@
archive_path = join_root_path('scripts', 'archive')
+try:
+ sys.pypy_version_info
+ PYPY = True
+except AttributeError:
+ PYPY = False
+
if PY2:
TK_IMPORT = 'Tkinter'
else:
@@ -97,6 +103,10 @@
set(['login']) -
set(unrunnable_script_list)))
+if PYPY:
+ unrunnable_script_list = script_list
+
+
script_input = {
'catall': 'q\n', # q for quit
'editarticle': 'Test page\n',
diff --git a/tests/tools_tests.py b/tests/tools_tests.py
index 71f6b63..6b5e1e4 100644
--- a/tests/tools_tests.py
+++ b/tests/tools_tests.py
@@ -14,6 +14,7 @@
import inspect
import os.path
import subprocess
+import sys
import tempfile
import warnings
@@ -24,6 +25,12 @@
unittest, require_modules, DeprecationTestCase, TestCase, MetaTestCaseClass
)
from tests.utils import expected_failure_if, add_metaclass
+
+try:
+ sys.pypy_version_info
+ PYPY = True
+except AttributeError:
+ PYPY = False
class ContextManagerWrapperTestCase(TestCase):
@@ -538,9 +545,9 @@
deduper = tools.filter_unique(self.strs, container=deduped, key=hash)
self._test_dedup_str(deduped, deduper, hash)
- @expected_failure_if(not tools.PY2)
+ @expected_failure_if(not tools.PY2 or PYPY)
def test_str_id(self):
- """Test str using id as key fails on Python 3."""
+ """Test str using id as key fails on Python 3 and PyPy 2."""
# str in Python 3 behave like objects.
deduped = set()
deduper = tools.filter_unique(self.strs, container=deduped, key=id)
diff --git a/tox.ini b/tox.ini
index eb77d65..fcf1718 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,13 +3,13 @@
minversion = 1.7.2
skipsdist = True
skip_missing_interpreters = True
-envlist = flake8,pyflakes-{py26,py3,pypy},doctest-{py27,py34},py26,py27,py34
+envlist =
flake8,pyflakes-{py26,py3,pypy},doctest-{py27,py34},py26,py27,py34,nose-pypy,pytest-pypy
[tox:jenkins]
# Override default for WM Jenkins
# Others are run in their own individual jobs on WM Jenkins
# Wikimedia Jenkins does not have Python 2.6
-envlist = flake8,pyflakes-{py3,pypy}
+envlist = flake8,pyflakes-{py3,pypy},nose-pypy,pytest-pypy
[params]
doctest_skip = --ignore-files=(gui\.py|botirc\.py|rcstream\.py)
@@ -79,12 +79,34 @@
commands =
python -W error::UserWarning -m generate_user_files -family:test
-lang:test -v
nosetests --version
- nosetests --with-detecthttp -v -a '!net' tests
+ nosetests --with-detecthttp -v --attr '!net' tests
deps =
nose
nose-detecthttp>=0.1.3
six
+[testenv:nose-pypy]
+basepython = pypy
+commands =
+ python -W error::UserWarning -m generate_user_files -family:test
-lang:test -v
+ nosetests --version
+ nosetests --with-detecthttp -v --eval-attr 'not net' tests
+deps =
+ nose
+ nose-detecthttp>=0.1.3
+ six
+
+[testenv:pytest-pypy]
+basepython = pypy
+commands =
+ python -W error::UserWarning -m generate_user_files -family:test
-lang:test -v
+ pytest --version
+ pytest -vv -a 'not net'
+deps =
+ pytest
+ pytest-attrib
+ six
+
[testenv:doctest]
commands =
python -W error::UserWarning -m generate_user_files -family:test
-lang:test -v
--
To view, visit https://gerrit.wikimedia.org/r/291155
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ide8bcef49499d7f3bb7bcbf00bde3d42936e5672
Gerrit-PatchSet: 1
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: John Vandenberg <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits