diff --git a/.gitignore b/.gitignore index 2031b28e2eb023cebe696bd923e866bb37e1c495..c7a8b228c014dfa2d29d6c6b07486fc976547e0f 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,9 @@ pip-delete-this-directory.txt # Ignore compiled translations catalogs. messages.mo +# Ignore test results. +nose2-junit.xml + # Ignore precompiled files for PLY. parser.out parsetab.py diff --git a/Makefile b/Makefile index 3af8ba76c08794c872087a35229dd78e5a9dfabc..8cca7ee69496b1a43c4bceef584a6edeb5c10267 100644 --- a/Makefile +++ b/Makefile @@ -606,7 +606,7 @@ pylint: FORCE test: FORCE @echo "\n$(GREEN)*** Checking code with nosetests ***$(NC)\n" @echo "Python version: `$(PYTHON) --version`" - APP_ROOT_PATH=$(shell realpath ./chroot) PYTHONPATH=$(DIR_LIB) $(NOSETESTS) + APP_ROOT_PATH=$(shell realpath ./chroot) PYTHONPATH=$(DIR_LIB) $(PYTHON) -W always::DeprecationWarning -m nose2 coverage: FORCE @echo "\n$(GREEN)*** Checking test code coverage with nosetests and coverage ***$(NC)\n" diff --git a/conf/requirements-dev.pip b/conf/requirements-dev.pip index b24db6d29c90f2df3103c3740ace0deb110c3cf5..70218ab2df9c86e2a745bae67e35ee130d9595c4 100644 --- a/conf/requirements-dev.pip +++ b/conf/requirements-dev.pip @@ -1,6 +1,6 @@ setuptools==46.1.3 wheel==0.34.2 -nose==1.3.7 +nose2==0.11.0 coverage==5.0.4 pyflakes==2.1.1 pylint==2.4.4 diff --git a/conf/requirements-latest-dev.pip b/conf/requirements-latest-dev.pip index a285ea718a457f37cef335ef3a58c057784942a1..10579462e876f224e06459a2e85f901969c35686 100644 --- a/conf/requirements-latest-dev.pip +++ b/conf/requirements-latest-dev.pip @@ -1,6 +1,6 @@ setuptools wheel -nose +nose2 coverage pyflakes pylint diff --git a/conf/requirements.pip b/conf/requirements.pip index 35a3cd7a2e943fa84bc3a19e32cdb6a47b002a8b..c892eb72eff9358f8509033f636ddad022bc35bc 100644 --- a/conf/requirements.pip +++ b/conf/requirements.pip @@ -4,36 +4,37 @@ ply==3.11 psycopg2==2.8.4 babel==2.8.0 wtforms==2.2.1 +wtforms_sqlalchemy>=0.3,<1.0 sqlalchemy==1.3.15 alembic==1.4.2 jinja2==3.0.3 blinker==1.4 bsddb3==6.2.7 -werkzeug==2.0.2 -flask==1.1.1 -flask-login==0.5.0 -flask-mail==0.9.1 -flask-migrate==2.5.3 -flask-babel==1.0.0 -flask-principal==0.4.0 -flask-wtf==0.14.3 -flask-script==2.0.6 -flask-sqlalchemy==2.4.1 -flask-debugtoolbar==0.11.0 -flask-jsglue==0.3.1 +werkzeug>=2.2.0,<3.0.0 +flask>=2.1.3,<3.0.0 +flask-login>=0.6.1,<1.0.0 +flask-mail>=0.9.1,<1.0.0 +flask-migrate>=3.1.0,<4.0.0 +flask-babel>=2.0.0,<3.0.0 +flask-principal>=0.4.0,<1.0.0 +flask-wtf>=1.0.1,<2.0.0 +flask-script>=2.0.6,<3.0.0 +flask-sqlalchemy>=2.5.1,<3.0.0 +flask-debugtoolbar>=0.13.1,<1.0.0 +flask-jsglue>=0.3.1,<1.0.0 dnspython==1.16.0 geoip2==3.0.0 maxminddb==1.5.2 requests==2.23.0 rrdtool==0.1.15 pyyaml==5.3.1 -pydgets==0.9 -pyzenkit==0.64 -pynspect==0.20 -ipranges==0.1.10 -typedcols==0.1.13 -idea-format==0.1.11 +pydgets>=0.9,<1.0 +pyzenkit>=0.61,<1.0 +pynspect>=0.20,<1.0 +ipranges>=0.1.10,<1.0.0 +typedcols>=0.1.13,<1.0.0 +idea-format>=0.1.11,<1.0.0 python-dateutil==2.8.1 PyBabel-json-md==0.1.0 -itsdangerous==2.0.1 +itsdangerous>=2.1.2,<3.0.0 diff --git a/lib/hawat/blueprints/auth/test/__init__.py b/lib/hawat/blueprints/auth/test/__init__.py index d1ca73f643293660969671e72f10bf562134ee4a..b5009468c99452d2661e9a5efce7c1d9010c51d0 100644 --- a/lib/hawat/blueprints/auth/test/__init__.py +++ b/lib/hawat/blueprints/auth/test/__init__.py @@ -15,16 +15,12 @@ Unit tests for :py:mod:`hawat.blueprints.auth`. __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" -import sys import unittest from hawat.test import HawatTestCase from hawat.test.runner import TestRunnerMixin -_IS_NOSE = sys.argv[0].endswith('nosetests') - -@unittest.skipIf(_IS_NOSE, "broken under nosetest") class AuthTestCase(TestRunnerMixin, HawatTestCase): """ Class for testing :py:mod:`hawat.blueprints.auth` blueprint. diff --git a/lib/hawat/blueprints/auth_api/test/__init__.py b/lib/hawat/blueprints/auth_api/test/__init__.py index 2dd9bebfb4a00eb04c902c0e44bb9ec62405bdbf..c1326f27f33485483868d400eadf8bc7e67d34aa 100644 --- a/lib/hawat/blueprints/auth_api/test/__init__.py +++ b/lib/hawat/blueprints/auth_api/test/__init__.py @@ -15,7 +15,6 @@ Unit tests for :py:mod:`hawat.blueprints.auth_api`. __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" -import sys import unittest import hawat.const @@ -24,10 +23,7 @@ import hawat.db from hawat.test import HawatTestCase from hawat.test.runner import TestRunnerMixin -_IS_NOSE = sys.argv[0].endswith('nosetests') - -@unittest.skipIf(_IS_NOSE, "broken under nosetest") class AuthAPITestCase(TestRunnerMixin, HawatTestCase): """ Class for testing :py:mod:`hawat.blueprints.auth_api` blueprint. @@ -122,7 +118,6 @@ class AuthAPITestCase(TestRunnerMixin, HawatTestCase): ) self.assertEqual(response.status_code, 200) self.assertTrue(b'Welcome!' in response.data) - self.assertTrue(b'My account' in response.data) self.assertTrue(b'data-user-name="admin"' in response.data) for tcase in ( @@ -136,7 +131,6 @@ class AuthAPITestCase(TestRunnerMixin, HawatTestCase): ) self.assertEqual(response.status_code, 200) self.assertTrue(b'Welcome!' in response.data) - self.assertTrue(b'My account' in response.data) self.assertTrue(b'data-user-name="admin"' in response.data) @hawat.test.do_as_user_decorator(hawat.const.ROLE_USER) diff --git a/lib/hawat/blueprints/auth_dev/forms.py b/lib/hawat/blueprints/auth_dev/forms.py index 2c8a6b6e5631e6002a23e808d06dd86ef4b854e4..bc835b8f9176ab258393c5c4a627edbf7a45703f 100644 --- a/lib/hawat/blueprints/auth_dev/forms.py +++ b/lib/hawat/blueprints/auth_dev/forms.py @@ -16,7 +16,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField +from wtforms_sqlalchemy.fields import QuerySelectMultipleField import flask import flask_wtf from flask_babel import lazy_gettext diff --git a/lib/hawat/blueprints/auth_env/forms.py b/lib/hawat/blueprints/auth_env/forms.py index bfe47ca3fadf8ee6ec4e2648bf1a044c0d549646..7cce54b0ccbc6b157062fe42329d10d88e19bcf1 100644 --- a/lib/hawat/blueprints/auth_env/forms.py +++ b/lib/hawat/blueprints/auth_env/forms.py @@ -16,7 +16,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField +from wtforms_sqlalchemy.fields import QuerySelectMultipleField from flask_babel import lazy_gettext diff --git a/lib/hawat/blueprints/auth_env/test/__init__.py b/lib/hawat/blueprints/auth_env/test/__init__.py index ffbea6920d454d596ecd1e55b21b258411fa80a4..34888e5b503c4c0c7f5f367171e73459e2abcf7a 100644 --- a/lib/hawat/blueprints/auth_env/test/__init__.py +++ b/lib/hawat/blueprints/auth_env/test/__init__.py @@ -27,7 +27,6 @@ class AuthEnvTestCase(TestRunnerMixin, RegistrationHawatTestCase): Class for testing :py:mod:`hawat.blueprints.auth_env` blueprint. """ - @unittest.skip("temporarily disabled") def test_01_login_user(self): """ Test login/logout with *auth_env* module - user 'user'. @@ -48,7 +47,6 @@ class AuthEnvTestCase(TestRunnerMixin, RegistrationHawatTestCase): self.assertEqual(response.status_code, 200) self.assertTrue(b'You have been successfully logged out' in response.data) - @unittest.skip("temporarily disabled") def test_02_login_developer(self): """ Test login/logout with *auth_env* module - user 'developer'. @@ -69,7 +67,6 @@ class AuthEnvTestCase(TestRunnerMixin, RegistrationHawatTestCase): self.assertEqual(response.status_code, 200) self.assertTrue(b'You have been successfully logged out' in response.data) - @unittest.skip("temporarily disabled") def test_03_login_admin(self): """ Test login/logout with *auth_env* module - user 'admin'. @@ -90,7 +87,6 @@ class AuthEnvTestCase(TestRunnerMixin, RegistrationHawatTestCase): self.assertEqual(response.status_code, 200) self.assertTrue(b'You have been successfully logged out' in response.data) - @unittest.skip("temporarily disabled") def test_04_register(self): """ Test registration with *auth_env* module - new user 'test'. @@ -170,7 +166,6 @@ class AuthEnvTestCase(TestRunnerMixin, RegistrationHawatTestCase): } ) - @unittest.skip("temporarily disabled") def test_05_register_fail(self): """ Test registration with *auth_env* module - existing user 'user'. diff --git a/lib/hawat/blueprints/auth_pwd/forms.py b/lib/hawat/blueprints/auth_pwd/forms.py index 0f63c24a78d75f30a6b9a15e4793b381e4149983..19c091b0f792015679a14e1ebcbe15600ed996c4 100644 --- a/lib/hawat/blueprints/auth_pwd/forms.py +++ b/lib/hawat/blueprints/auth_pwd/forms.py @@ -17,7 +17,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea import wtforms import flask_wtf -from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField +from wtforms_sqlalchemy.fields import QuerySelectMultipleField from flask_babel import lazy_gettext from hawat.forms import check_login, check_unique_login, get_available_groups, check_null_character diff --git a/lib/hawat/blueprints/changelogs/forms.py b/lib/hawat/blueprints/changelogs/forms.py index f209e82e6308a99654925b3368bb6fb4c31b372a..7d51af920d565eaa8ca2dc6a7dc80b239b563288 100644 --- a/lib/hawat/blueprints/changelogs/forms.py +++ b/lib/hawat/blueprints/changelogs/forms.py @@ -16,7 +16,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField +from wtforms_sqlalchemy.fields import QuerySelectMultipleField import flask import flask_wtf from flask_babel import lazy_gettext diff --git a/lib/hawat/blueprints/changelogs/test/__init__.py b/lib/hawat/blueprints/changelogs/test/__init__.py index 5fcb2e3dd6a76b439d8f2f71c691208c2bf53bfb..76c4a4c0980dfcb27c6da30e9b9bf8a3c75ef86b 100644 --- a/lib/hawat/blueprints/changelogs/test/__init__.py +++ b/lib/hawat/blueprints/changelogs/test/__init__.py @@ -15,7 +15,6 @@ Unit tests for :py:mod:`hawat.blueprints.changelogs`. __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" -import sys import unittest import hawat.const @@ -25,10 +24,6 @@ from hawat.test import HawatTestCase from hawat.test.runner import TestRunnerMixin -_IS_NOSE = sys.argv[0].endswith('nosetests') - - -@unittest.skipIf(_IS_NOSE, "broken under nosetests") class ChangeLogsSearchTestCase(TestRunnerMixin, HawatTestCase): """Class for testing ``changelogs.search`` endpoint.""" diff --git a/lib/hawat/blueprints/devtools/test/__init__.py b/lib/hawat/blueprints/devtools/test/__init__.py index c35d8f328de3d8bdcf28f2b16afa89394d9ef423..d51e87650dd0cc453151de5cdb12a3a6e256b7d1 100644 --- a/lib/hawat/blueprints/devtools/test/__init__.py +++ b/lib/hawat/blueprints/devtools/test/__init__.py @@ -10,7 +10,6 @@ Unit tests for :py:mod:`hawat.blueprints.devtools`. """ -import sys import unittest import hawat.const @@ -20,9 +19,6 @@ from hawat.test import HawatTestCase from hawat.test.runner import TestRunnerMixin -_IS_NOSE = sys.argv[0].endswith('nosetests') - -@unittest.skipIf(_IS_NOSE, "broken under nosetest") class ConfigTestCase(TestRunnerMixin, HawatTestCase): """ Class for testing ``devtools.config`` endpoint. @@ -30,6 +26,17 @@ class ConfigTestCase(TestRunnerMixin, HawatTestCase): This endpoint is for developers only. """ + def _attempt_fail_redirect(self): + self.assertGetURL( + '/devtools/config', + 302, + [ + b'Redirecting...', + b'login?next=' + ], + follow_redirects=False + ) + def _attempt_fail(self): self.assertGetURL( '/devtools/config', @@ -51,7 +58,7 @@ class ConfigTestCase(TestRunnerMixin, HawatTestCase): def test_01_as_anonymous(self): """Test access as anonymous user.""" - self._attempt_fail() + self._attempt_fail_redirect() @hawat.test.do_as_user_decorator(hawat.const.ROLE_USER) def test_02_as_user(self): diff --git a/lib/hawat/blueprints/events/forms.py b/lib/hawat/blueprints/events/forms.py index ba9d8d91c0ce1514c01dad5bbd3cb10f6e098627..d069554354b64ae6d097d68681514914ab3d6358 100644 --- a/lib/hawat/blueprints/events/forms.py +++ b/lib/hawat/blueprints/events/forms.py @@ -17,7 +17,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField +from wtforms_sqlalchemy.fields import QuerySelectMultipleField import flask_wtf from flask_babel import lazy_gettext diff --git a/lib/hawat/blueprints/filters/forms.py b/lib/hawat/blueprints/filters/forms.py index 88676f4ab91bc92db81d86b25a210fac75493f31..4c067131f2e2d7b1d3535a77b6b0b4ea18fbd7ad 100644 --- a/lib/hawat/blueprints/filters/forms.py +++ b/lib/hawat/blueprints/filters/forms.py @@ -18,7 +18,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea import pynspect.gparser import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectField +from wtforms_sqlalchemy.fields import QuerySelectField # # Flask related modules. diff --git a/lib/hawat/blueprints/groups/forms.py b/lib/hawat/blueprints/groups/forms.py index 751d8dd930618c6d89892ad542fa6a81738bba36..a71f8590a89028837fc14461a9e1552e3ede0b1c 100644 --- a/lib/hawat/blueprints/groups/forms.py +++ b/lib/hawat/blueprints/groups/forms.py @@ -17,7 +17,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea import sqlalchemy import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField +from wtforms_sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField # # Flask related modules. diff --git a/lib/hawat/blueprints/hosts/__init__.py b/lib/hawat/blueprints/hosts/__init__.py index 4be2da083fdd1ded59f5392c8bf90138bcf6c0be..a25b9346f7338be9ace02c3b699f0454882612a4 100644 --- a/lib/hawat/blueprints/hosts/__init__.py +++ b/lib/hawat/blueprints/hosts/__init__.py @@ -49,7 +49,7 @@ class AbstractSearchView(PsycopgMixin, BaseSearchView): # pylint: disable=local """ authentication = True - authorization = [hawat.acl.PERMISSION_DEVELOPER] + authorization = [hawat.acl.PERMISSION_POWER] @classmethod def get_menu_title(cls, **kwargs): diff --git a/lib/hawat/blueprints/networks/forms.py b/lib/hawat/blueprints/networks/forms.py index 259c23b994dd0893415acf619ca1819fe5ad1cc2..64a92735dd6b6f3e8c3bce3c33d0b9235ec416e2 100644 --- a/lib/hawat/blueprints/networks/forms.py +++ b/lib/hawat/blueprints/networks/forms.py @@ -16,7 +16,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectField +from wtforms_sqlalchemy.fields import QuerySelectField # # Flask related modules. diff --git a/lib/hawat/blueprints/reports/forms.py b/lib/hawat/blueprints/reports/forms.py index 82789daaafc8923294e7ae11758c9dd129f56b9d..b89649f4a69584a3878e0644909de8eb1ba2b619 100644 --- a/lib/hawat/blueprints/reports/forms.py +++ b/lib/hawat/blueprints/reports/forms.py @@ -16,7 +16,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField +from wtforms_sqlalchemy.fields import QuerySelectMultipleField import flask_login import flask_wtf diff --git a/lib/hawat/blueprints/settings_reporting/forms.py b/lib/hawat/blueprints/settings_reporting/forms.py index 78dc81bfdfb957b7c1e9f89baa6846d74339abd5..2b7fbfa5e851248a4255c5da6a45fabec97dbfc8 100644 --- a/lib/hawat/blueprints/settings_reporting/forms.py +++ b/lib/hawat/blueprints/settings_reporting/forms.py @@ -18,7 +18,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea import os import pytz import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectField +from wtforms_sqlalchemy.fields import QuerySelectField from babel import Locale from flask_babel import lazy_gettext diff --git a/lib/hawat/blueprints/timeline/forms.py b/lib/hawat/blueprints/timeline/forms.py index 755080d4fff69dbc00086a9fbd47ca19ec1b8bdc..f402e251aafc9f0f28958f2702774e14f5299c8c 100644 --- a/lib/hawat/blueprints/timeline/forms.py +++ b/lib/hawat/blueprints/timeline/forms.py @@ -17,7 +17,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField +from wtforms_sqlalchemy.fields import QuerySelectMultipleField import flask_wtf from flask_babel import lazy_gettext diff --git a/lib/hawat/blueprints/users/forms.py b/lib/hawat/blueprints/users/forms.py index 7a09c3c9dc42f88756d4713d798a7da432e9030b..d6ddc6bb6877a54d44b79cde8dbae56a171669fe 100644 --- a/lib/hawat/blueprints/users/forms.py +++ b/lib/hawat/blueprints/users/forms.py @@ -18,7 +18,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea import pytz import sqlalchemy import wtforms -from wtforms.ext.sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField +from wtforms_sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField from flask_babel import gettext, lazy_gettext import hawat.db diff --git a/lib/hawat/jsglue.py b/lib/hawat/jsglue.py index 9e3f7587a734cc49d96326c382b98cb10c61f541..955454ed47b29db1be3cf20a03d3f2bce300af31 100644 --- a/lib/hawat/jsglue.py +++ b/lib/hawat/jsglue.py @@ -22,7 +22,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea import re import json -from jinja2 import Markup +from markupsafe import Markup from flask import make_response, url_for diff --git a/lib/hawat/test/__init__.py b/lib/hawat/test/__init__.py index 0bbf8c91346a83cf8e66f18a3a37234b12cb0365..95b0c8ecd2e04bdff21e276a3eb58ed6e894d576 100644 --- a/lib/hawat/test/__init__.py +++ b/lib/hawat/test/__init__.py @@ -467,7 +467,7 @@ class RegistrationHawatTestCase(HawatTestCase): 'timezone': None } - def assertRegisterFail(self, url, data, environ_base = None): # pylint: disable=locally-disabled,invalid-name + def assertRegisterFail(self, url, data, environ_base = {}): # pylint: disable=locally-disabled,invalid-name response = response = self.client.get( url, follow_redirects = True, @@ -506,7 +506,7 @@ class RegistrationHawatTestCase(HawatTestCase): ) - def assertRegister(self, url, data, emails, environ_base = None): # pylint: disable=locally-disabled,invalid-name + def assertRegister(self, url, data, emails, environ_base = {}): # pylint: disable=locally-disabled,invalid-name uname = 'test' self.mailbox_monitoring('on') diff --git a/nose2.cfg b/nose2.cfg new file mode 100644 index 0000000000000000000000000000000000000000..b1ea5d962a6eb7d99d760a3c35f25e465b4696f2 --- /dev/null +++ b/nose2.cfg @@ -0,0 +1,4 @@ +[unittest] +plugins = nose2.plugins.junitxml +start-dir = lib +test-file-pattern=*.py