diff --git a/.travis.yml b/.travis.yml index 95f2843f..cccbaad8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,11 +7,15 @@ stages: if: tag IS present python: - '2.7' -- '3.5' - '3.6' - '3.7' +env: +- DJANGO=1.8 +- DJANGO=1.9 +- DJANGO=1.10 +- DJANGO=1.11 install: pip install tox coveralls -script: tox -e $(echo py$TRAVIS_PYTHON_VERSION | tr -d .) +script: tox -e $(echo py$TRAVIS_PYTHON_VERSION | tr -d .)-django$DJANGO after_success: coveralls jobs: include: diff --git a/README.rst b/README.rst index 6a99f906..cc405e03 100644 --- a/README.rst +++ b/README.rst @@ -53,8 +53,8 @@ For our example, let's look at an example for a ``Calculator`` resource: import os import rpyc from django.db import models - from rotest.management import base_resource from rotest.management.models import resource_data + from rotest.management import base_resource class CalculatorData(resource_data.ResourceData): diff --git a/appveyor.yml b/appveyor.yml index 77017e9f..ccb1c7c8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,8 @@ environment: matrix: - - TOXENV: "py27" - - TOXENV: "py35" - - TOXENV: "py36" - - TOXENV: "py37" + - TOXENV: "py27-django1.11" + - TOXENV: "py36-django1.11" + - TOXENV: "py37-django1.11" build: off diff --git a/docs/conf.py b/docs/conf.py index fc84feea..d99c94e0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,6 +31,13 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. from __future__ import absolute_import + +import os +import django + +os.environ['DJANGO_SETTINGS_MODULE'] = "rotest.common.django_utils.settings" +django.setup() + extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon'] diff --git a/requirements.txt b/requirements.txt index eaa2fd67..0e8a02eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,61 +1,73 @@ -astroid==1.6.5 -atomicwrites==1.2.1 -attrdict==2.0.0 -attrs==18.2.0 +astroid==1.6.6 +atomicwrites==1.3.0 +attrdict==2.0.1 +attrs==19.1.0 backports.functools-lru-cache==1.5 backports.shutil-get-terminal-size==1.0.0 basicstruct==1.0.3 -certifi==2018.11.29 +cached-property==1.5.1 +certifi==2019.6.16 chardet==3.0.4 colorama==0.4.1 -configparser==3.5.0 -coverage==4.5.2 -decorator==4.3.0 -Django==1.8.19 +configparser==3.7.4 +contextlib2==0.5.5 +coverage==4.5.3 +decorator==4.4.0 +Django==1.11.21 +docutils==0.14 +entrypoints==0.3 enum34==1.1.6 -flake8==3.6.0 +flake8==3.7.7 funcsigs==1.0.2 functools32==3.2.3.post2 future==0.17.1 futures==3.2.0 idna==2.8 -ipdb==0.11 -ipdbugger==2.0.3 +importlib-metadata==0.18 +ipdb==0.12 +ipdbugger==2.5.0 ipython==5.8.0 ipython-genutils==0.2.0 -jsonschema==2.6.0 -lazy-object-proxy==1.3.1 +isort==4.3.21 +jsonschema==3.0.1 +lazy-object-proxy==1.4.1 mccabe==0.6.1 -mock==2.0.0 +mock==3.0.5 more-itertools==5.0.0 -pathlib2==2.3.3 -pbr==5.1.1 -pexpect==4.6.0 +packaging==19.0 +pathlib2==2.3.4 +pexpect==4.7.0 pickleshare==0.7.5 -pluggy==0.8.1 -prompt-toolkit==1.0.15 -psutil==5.4.8 +pluggy==0.12.0 +prompt-toolkit==1.0.16 +psutil==5.6.3 ptyprocess==0.6.0 -py==1.7.0 -pycodestyle==2.4.0 -pyfakefs==3.5.6 -pyflakes==2.0.0 -Pygments==2.3.1 +py==1.8.0 +pycodestyle==2.5.0 +pyfakefs==3.5.8 +pyflakes==2.1.1 +Pygments==2.4.2 pylint==1.9.4 -pytest==4.1.1 -pytest-cov==2.6.1 -pytest-django==3.4.5 -PyYAML==3.13 -requests==2.21.0 -scandir==1.9.0 +pyparsing==2.4.0 +pyrsistent==0.15.2 +pytest==4.6.3 +pytest-cov==2.7.1 +pytest-django==3.5.0 +pytz==2019.1 +PyYAML==5.1.1 +requests==2.22.0 +scandir==1.10.0 simplegeneric==0.8.1 singledispatch==3.4.0.3 six==1.12.0 -swaggapi==0.6.5 +statistics==1.0.3.5 +swaggapi==0.6.7 termcolor==1.1.0 traitlets==4.3.2 -urllib3==1.24.1 +typing==3.7.4 +urllib3==1.25.3 wcwidth==0.1.7 -wrapt==1.11.0 +wrapt==1.11.2 xlrd==1.2.0 xlwt==1.3.0 +zipp==0.5.1 diff --git a/setup.py b/setup.py index acd15f64..7da8d3c5 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from setuptools import setup, find_packages -__version__ = "7.6.0" +__version__ = "7.7.0" result_handlers = [ "db = rotest.core.result.handlers.db_handler:DBHandler", @@ -34,7 +34,7 @@ url="https://github.com/gregoil/rotest", keywords="testing system django unittest", install_requires=[ - 'django>=1.8,<1.9', + 'django>=1.8,<2.0', 'py', 'ipdbugger>=2.5', 'xlwt', @@ -46,7 +46,7 @@ 'jsonschema', 'basicstruct', 'future', - 'swaggapi>=0.6.5', + 'swaggapi>=0.6.7', 'cached_property', ], extras_require={ @@ -63,7 +63,7 @@ "pylint", ] }, - python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*", + python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*", entry_points={ "console_scripts": [ "rotest = rotest.cli.main:main" @@ -83,9 +83,13 @@ 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Framework :: Django', + 'Framework :: Django :: 1.8', + 'Framework :: Django :: 1.9', + 'Framework :: Django :: 1.10', + 'Framework :: Django :: 1.11', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX', 'Operating System :: Unix', diff --git a/src/rotest/api/resource_control/release_resources.py b/src/rotest/api/resource_control/release_resources.py index fba0c44a..0a827874 100644 --- a/src/rotest/api/resource_control/release_resources.py +++ b/src/rotest/api/resource_control/release_resources.py @@ -9,7 +9,7 @@ from swaggapi.api.builder.server.exceptions import BadRequest from swaggapi.api.builder.server.request import DjangoRequestView -from rotest.management import ResourceData +from rotest.management.models import ResourceData from rotest.management.common.utils import get_username from rotest.common.django_utils.common import get_sub_model from rotest.api.common.models import ReleaseResourcesParamsModel diff --git a/src/rotest/api/urls.py b/src/rotest/api/urls.py index e5d0e35b..16274397 100644 --- a/src/rotest/api/urls.py +++ b/src/rotest/api/urls.py @@ -1,7 +1,6 @@ """URLs of all the django views.""" # pylint: disable=unused-argument, no-self-use from __future__ import absolute_import -from django.conf.urls import patterns from swaggapi.build import Swagger from swaggapi.api.openapi.models import Info, License, Tag @@ -65,4 +64,4 @@ swagger = Swagger(info, mount_url="api", requests=requests, tags=tags) -urlpatterns = patterns("", *swagger.get_django_urls()) +urlpatterns = swagger.get_django_urls() diff --git a/src/rotest/cli/client.py b/src/rotest/cli/client.py index 1626b03f..adf3b335 100644 --- a/src/rotest/cli/client.py +++ b/src/rotest/cli/client.py @@ -39,7 +39,7 @@ Specify resources to request by attributes, e.g. '-r res1.group=QA,res2.comment=CI'. """ -# pylint: disable=unused-argument,cell-var-from-loop +# pylint: disable=unused-argument,cell-var-from-loop,wrong-import-position # pylint: disable=too-many-arguments,too-many-locals,redefined-builtin from __future__ import print_function from __future__ import absolute_import @@ -53,7 +53,9 @@ import pkg_resources from attrdict import AttrDict -from rotest.core import TestSuite +django.setup() # noqa + +from rotest.core.suite import TestSuite from rotest.common import core_log from rotest.core.filter import match_tags from rotest.core.utils.common import print_test_hierarchy @@ -201,8 +203,6 @@ def main(*tests): Args: *tests: either suites or tests to be run. """ - django.setup() - parser = create_client_options_parser() arguments = parser.parse_args() diff --git a/src/rotest/cli/discover.py b/src/rotest/cli/discover.py index 6d047732..7f273694 100644 --- a/src/rotest/cli/discover.py +++ b/src/rotest/cli/discover.py @@ -8,7 +8,8 @@ import py from rotest.common import core_log -from rotest.core import TestCase, TestFlow +from rotest.core.case import TestCase +from rotest.core.flow import TestFlow from rotest.common.config import DISCOVERER_BLACKLIST diff --git a/src/rotest/cli/main.py b/src/rotest/cli/main.py index 1790549f..ab8671ae 100644 --- a/src/rotest/cli/main.py +++ b/src/rotest/cli/main.py @@ -1,7 +1,11 @@ #!/usr/bin/env python +# pylint: disable=wrong-import-position from __future__ import absolute_import import sys +import django +django.setup() # noqa + from rotest.cli.client import main as run from rotest.cli.server import start_server from rotest.management.utils.shell import main as shell diff --git a/src/rotest/common/django_utils/settings.py b/src/rotest/common/django_utils/settings.py index 7dfca2a5..790dc223 100644 --- a/src/rotest/common/django_utils/settings.py +++ b/src/rotest/common/django_utils/settings.py @@ -27,6 +27,9 @@ 'HOST': '', 'PORT': '', 'TEST_NAME': 'test_rotest_db', + 'TEST': { + 'NAME': 'test_rotest_db' + } }, } diff --git a/src/rotest/core/__init__.py b/src/rotest/core/__init__.py index 91c84789..c69247b4 100644 --- a/src/rotest/core/__init__.py +++ b/src/rotest/core/__init__.py @@ -1,10 +1,43 @@ -from .case import TestCase -from .block import TestBlock -from .suite import TestSuite -from .abstract_test import request -from .flow import TestFlow, create_flow -from .flow_component import (MODE_CRITICAL, MODE_FINALLY, MODE_OPTIONAL, - Pipe, BlockInput, BlockOutput) -from .result.monitor.monitor import (AbstractMonitor, AbstractResourceMonitor, - require_attr, skip_if_case, skip_if_flow, - skip_if_block, skip_if_not_main) +# pylint: disable=too-many-locals +from django.apps import AppConfig + + +class CoreConfig(AppConfig): + name = "rotest.core" + + def ready(self): + from .case import TestCase + from .flow import TestFlow, create_flow + from .block import TestBlock + from .suite import TestSuite + from .abstract_test import request + from .flow_component import (MODE_CRITICAL, MODE_FINALLY, MODE_OPTIONAL, + Pipe, BlockInput, BlockOutput) + from .result.monitor.monitor import (AbstractMonitor, + AbstractResourceMonitor, + require_attr, skip_if_case, + skip_if_flow, + skip_if_block, skip_if_not_main) + import rotest + rotest.core.TestCase = TestCase + rotest.core.TestFlow = TestFlow + rotest.core.create_flow = create_flow + rotest.core.TestBlock = TestBlock + rotest.core.TestSuite = TestSuite + rotest.core.request = request + rotest.core.MODE_CRITICAL = MODE_CRITICAL + rotest.core.MODE_FINALLY = MODE_FINALLY + rotest.core.MODE_OPTIONAL = MODE_OPTIONAL + rotest.core.Pipe = Pipe + rotest.core.BlockInput = BlockInput + rotest.core.BlockOutput = BlockOutput + rotest.core.AbstractMonitor = AbstractMonitor + rotest.core.AbstractResourceMonitor = AbstractResourceMonitor + rotest.core.require_attr = require_attr + rotest.core.skip_if_case = skip_if_case + rotest.core.skip_if_flow = skip_if_flow + rotest.core.skip_if_block = skip_if_block + rotest.core.skip_if_not_main = skip_if_not_main + + +default_app_config = "rotest.core.CoreConfig" diff --git a/src/rotest/core/abstract_test.py b/src/rotest/core/abstract_test.py index 39d06f35..a4abed78 100644 --- a/src/rotest/core/abstract_test.py +++ b/src/rotest/core/abstract_test.py @@ -420,6 +420,7 @@ def addSuccess(self, msg): def create_expect_method(method_name): original_assert = getattr(unittest.TestCase, method_name) + @wraps(original_assert) def extended_assert(self, *args, **kwargs): success_msg = kwargs.pop("success_msg", None) diff --git a/src/rotest/core/result/handlers/remote_db_handler.py b/src/rotest/core/result/handlers/remote_db_handler.py index 8fabc40f..17fccf08 100644 --- a/src/rotest/core/result/handlers/remote_db_handler.py +++ b/src/rotest/core/result/handlers/remote_db_handler.py @@ -1,7 +1,7 @@ """Remote database result handler.""" from __future__ import absolute_import -from rotest.core import TestCase +from rotest.core.case import TestCase from rotest.core.models.case_data import TestOutcome from rotest.management.client.result_client import ClientResultManager from rotest.core.result.handlers.abstract_handler import AbstractResultHandler diff --git a/src/rotest/core/result/handlers/signature_handler.py b/src/rotest/core/result/handlers/signature_handler.py index 18fbfd9f..f9a40a1d 100644 --- a/src/rotest/core/result/handlers/signature_handler.py +++ b/src/rotest/core/result/handlers/signature_handler.py @@ -1,7 +1,7 @@ """Known issues result handler.""" from __future__ import absolute_import -from rotest.core import skip_if_not_main +from rotest.core.result.monitor.monitor import skip_if_not_main from rotest.core.result.handlers.stream.base_handler import BaseStreamHandler from rotest.management.client.signatures_client import ClientSignatureManager diff --git a/src/rotest/core/runner.py b/src/rotest/core/runner.py index b532b803..f9c19470 100644 --- a/src/rotest/core/runner.py +++ b/src/rotest/core/runner.py @@ -13,9 +13,13 @@ from rotest.common.utils import get_class_fields from rotest.core.runners.base_runner import BaseTestRunner from rotest.management.base_resource import ResourceRequest -from rotest.core import TestCase, TestFlow, TestBlock, TestSuite from rotest.core.runners.multiprocess.manager.runner import MultiprocessRunner +from .case import TestCase +from .flow import TestFlow +from .block import TestBlock +from .suite import TestSuite + LAST_RUN_INDEX = -1 MINIMUM_TIMES_TO_RUN = 1 FILE_FOLDER = os.path.dirname(__file__) diff --git a/src/rotest/core/runners/multiprocess/worker/process.py b/src/rotest/core/runners/multiprocess/worker/process.py index 842a749f..2de6b6a0 100644 --- a/src/rotest/core/runners/multiprocess/worker/process.py +++ b/src/rotest/core/runners/multiprocess/worker/process.py @@ -1,12 +1,15 @@ """Multiprocess worker process.""" -# pylint: disable=invalid-name,too-many-arguments +# pylint: disable=invalid-name,too-many-arguments,wrong-import-position # pylint: disable=too-many-locals,too-many-instance-attributes from __future__ import absolute_import from multiprocessing import Process +import django import psutil from six.moves import queue +django.setup() # noqa + from rotest.common import core_log from rotest.core.runners.multiprocess.worker.runner import WorkerRunner from rotest.core.runners.multiprocess.common import (get_item_by_id, diff --git a/src/rotest/management/__init__.py b/src/rotest/management/__init__.py index c7fcd9b3..d5ce12d6 100644 --- a/src/rotest/management/__init__.py +++ b/src/rotest/management/__init__.py @@ -1,4 +1,19 @@ -from __future__ import absolute_import -from .models import ResourceData, DataPointer -from .client.manager import ClientResourceManager -from .base_resource import BaseResource, ResourceRequest +from django.apps import AppConfig + + +class ManagementConfig(AppConfig): + name = "rotest.management" + + def ready(self): + from .models import ResourceData + from .client.manager import ClientResourceManager + from .base_resource import BaseResource, ResourceRequest + + import rotest + rotest.management.ResourceData = ResourceData + rotest.management.ClientResourceManager = ClientResourceManager + rotest.management.BaseResource = BaseResource + rotest.management.ResourceRequest = ResourceRequest + + +default_app_config = "rotest.management.ManagementConfig" diff --git a/src/rotest/management/base_resource.py b/src/rotest/management/base_resource.py index 22ab0016..41812d02 100644 --- a/src/rotest/management/base_resource.py +++ b/src/rotest/management/base_resource.py @@ -16,14 +16,20 @@ from attrdict import AttrDict from future.utils import iteritems from future.builtins import zip, object -from django.db.models.fields.related import \ - ReverseSingleRelatedObjectDescriptor from rotest.common import core_log from rotest.common.config import ROTEST_WORK_DIR from rotest.common.utils import get_work_dir, get_class_fields from rotest.management.models.resource_data import ResourceData, DataPointer +try: + from django.db.models.fields.related_descriptors import \ + ForwardManyToOneDescriptor + +except ImportError: + from django.db.models.fields.related import \ + ReverseSingleRelatedObjectDescriptor as ForwardManyToOneDescriptor + class ResourceRequest(object): """Holds the data for a resource request. @@ -157,7 +163,7 @@ class fields, where the 'data' attribute in the declaration points actual_kwargs['config'] = self.config actual_kwargs['base_work_dir'] = self.work_dir for key, value in six.iteritems(sub_request.kwargs): - if isinstance(value, ReverseSingleRelatedObjectDescriptor): + if isinstance(value, ForwardManyToOneDescriptor): actual_kwargs[key] = getattr(self.data, value.field.name) elif isinstance(value, DataPointer): diff --git a/src/rotest/management/common/resource_descriptor.py b/src/rotest/management/common/resource_descriptor.py index 2070cf25..0ae2a87a 100644 --- a/src/rotest/management/common/resource_descriptor.py +++ b/src/rotest/management/common/resource_descriptor.py @@ -6,7 +6,7 @@ import six from future.builtins import object -from rotest.management import ResourceData +from rotest.management.models import ResourceData from rotest.management.common.errors import ResourceBuildError from rotest.management.common.utils import (TYPE_NAME, PROPERTIES, diff --git a/tests/integration/playground.py b/tests/integration/playground.py index 9a997ab3..707d07a1 100644 --- a/tests/integration/playground.py +++ b/tests/integration/playground.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, print_function -from rotest import main +from rotest.cli.client import main from rotest.core import TestBlock, TestFlow diff --git a/tox.ini b/tox.ini index d32d2d7b..1e0c9773 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = validate_requirements - py27,py35,py36,py37 + py{27,36,37}-django{1.8,1.9,1.10,1.11} docs [testenv] @@ -10,10 +10,15 @@ extras = dev passenv = ROTEST_WORK_DIR basepython = py27: python2.7 - py35: python3.5 py36: python3.6 py37: python3.7 +deps = + django1.8: Django>=1.8,<1.9 + django1.9: Django>=1.9,<1.10 + django1.10: Django>=1.10,<1.11 + django1.11: Django>=1.11,<2.0 + commands = flake8 setup.py src/rotest/ tests/ pylint setup.py src/rotest/ tests/