Sfoglia il codice sorgente

Adds tox.ini and fixes issues

Fixes pep8 and py27 issues.

Co-Authored-By: Gabriel Samfira <gsamfira@cloudbasesolutions.com>
Claudiu Belu 8 anni fa
parent
commit
87000159e1
45 ha cambiato i file con 188 aggiunte e 128 eliminazioni
  1. 7 0
      .testr.conf
  2. 4 3
      coriolis/api/__init__.py
  3. 1 2
      coriolis/api/middleware/auth.py
  4. 1 1
      coriolis/api/middleware/fault.py
  5. 1 1
      coriolis/api/v1/endpoint_actions.py
  6. 1 1
      coriolis/api/v1/endpoint_instances.py
  7. 1 1
      coriolis/api/v1/endpoint_networks.py
  8. 3 4
      coriolis/api/v1/endpoints.py
  9. 3 4
      coriolis/api/v1/migrations.py
  10. 2 2
      coriolis/api/v1/replica_tasks_executions.py
  11. 2 3
      coriolis/api/v1/replicas.py
  12. 3 3
      coriolis/api/v1/router.py
  13. 6 1
      coriolis/api/wsgi.py
  14. 5 0
      coriolis/cmd/__init__.py
  15. 4 7
      coriolis/cmd/api.py
  16. 5 8
      coriolis/cmd/conductor.py
  17. 5 8
      coriolis/cmd/worker.py
  18. 1 0
      coriolis/db/api.py
  19. 3 3
      coriolis/db/sqlalchemy/models.py
  20. 8 1
      coriolis/exception.py
  21. 1 1
      coriolis/keystone.py
  22. 4 4
      coriolis/migrations/manager.py
  23. 1 1
      coriolis/osmorphing/manager.py
  24. 0 1
      coriolis/osmorphing/openwrt.py
  25. 3 3
      coriolis/osmorphing/osmount/base.py
  26. 15 6
      coriolis/osmorphing/osmount/windows.py
  27. 1 1
      coriolis/osmorphing/redhat.py
  28. 2 2
      coriolis/osmorphing/suse.py
  29. 2 2
      coriolis/osmorphing/windows.py
  30. 11 7
      coriolis/providers/base.py
  31. 1 1
      coriolis/qemu_reader.py
  32. 6 6
      coriolis/schemas.py
  33. 5 7
      coriolis/schemas_exceptions.py
  34. 1 3
      coriolis/tasks/base.py
  35. 6 6
      coriolis/tasks/migration_tasks.py
  36. 2 2
      coriolis/tasks/replica_tasks.py
  37. 2 2
      coriolis/tests/providers/base.py
  38. 1 1
      coriolis/tests/test_base.py
  39. 3 3
      coriolis/tests/test_schemas.py
  40. 3 3
      coriolis/tests/testutils.py
  41. 6 7
      coriolis/utils.py
  42. 5 4
      coriolis/worker/rpc/server.py
  43. 2 2
      setup.py
  44. 2 0
      test-requirements.txt
  45. 37 0
      tox.ini

+ 7 - 0
.testr.conf

@@ -0,0 +1,7 @@
+[DEFAULT]
+test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
+             OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
+             OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
+             ${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
+test_id_option=--load-list $IDFILE
+test_list_option=--list

+ 4 - 3
coriolis/api/__init__.py

@@ -18,14 +18,15 @@
 WSGI middleware for OpenStack API controllers.
 WSGI middleware for OpenStack API controllers.
 """
 """
 
 
-from oslo_log import log as logging
-from oslo_service import wsgi as base_wsgi
 from paste import urlmap
 from paste import urlmap
 import routes
 import routes
 
 
+from oslo_log import log as logging
+from oslo_service import wsgi as base_wsgi
+
 from coriolis.api import wsgi
 from coriolis.api import wsgi
 from coriolis import exception
 from coriolis import exception
-from coriolis.i18n import _, _LW
+from coriolis.i18n import _, _LW  # noqa
 
 
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)

+ 1 - 2
coriolis/api/middleware/auth.py

@@ -1,11 +1,10 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-import webob
-
 from oslo_log import log as logging
 from oslo_log import log as logging
 from oslo_middleware import request_id
 from oslo_middleware import request_id
 from oslo_serialization import jsonutils
 from oslo_serialization import jsonutils
+import webob
 
 
 from coriolis.api import wsgi
 from coriolis.api import wsgi
 from coriolis import context
 from coriolis import context

+ 1 - 1
coriolis/api/middleware/fault.py

@@ -21,7 +21,7 @@ import webob.exc
 
 
 from coriolis.api import wsgi
 from coriolis.api import wsgi
 from coriolis import exception
 from coriolis import exception
-from coriolis.i18n import _, _LE, _LI
+from coriolis.i18n import _, _LE, _LI  # noqa
 from coriolis import utils
 from coriolis import utils
 
 
 
 

+ 1 - 1
coriolis/api/v1/endpoint_actions.py

@@ -4,8 +4,8 @@
 from webob import exc
 from webob import exc
 
 
 from coriolis.api import wsgi as api_wsgi
 from coriolis.api import wsgi as api_wsgi
-from coriolis import exception
 from coriolis.endpoints import api
 from coriolis.endpoints import api
+from coriolis import exception
 
 
 
 
 class EndpointActionsController(api_wsgi.Controller):
 class EndpointActionsController(api_wsgi.Controller):

+ 1 - 1
coriolis/api/v1/endpoint_instances.py

@@ -4,8 +4,8 @@
 from oslo_log import log as logging
 from oslo_log import log as logging
 
 
 from coriolis.api import common
 from coriolis.api import common
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import endpoint_instance_view
 from coriolis.api.v1.views import endpoint_instance_view
+from coriolis.api import wsgi as api_wsgi
 from coriolis.endpoint_instances import api
 from coriolis.endpoint_instances import api
 from coriolis import utils
 from coriolis import utils
 
 

+ 1 - 1
coriolis/api/v1/endpoint_networks.py

@@ -3,8 +3,8 @@
 
 
 from oslo_log import log as logging
 from oslo_log import log as logging
 
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import endpoint_network_view
 from coriolis.api.v1.views import endpoint_network_view
+from coriolis.api import wsgi as api_wsgi
 from coriolis.endpoint_networks import api
 from coriolis.endpoint_networks import api
 from coriolis import utils
 from coriolis import utils
 
 

+ 3 - 4
coriolis/api/v1/endpoints.py

@@ -1,14 +1,13 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-from webob import exc
-
 from oslo_log import log as logging
 from oslo_log import log as logging
+from webob import exc
 
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import endpoint_view
 from coriolis.api.v1.views import endpoint_view
-from coriolis import exception
+from coriolis.api import wsgi as api_wsgi
 from coriolis.endpoints import api
 from coriolis.endpoints import api
+from coriolis import exception
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 

+ 3 - 4
coriolis/api/v1/migrations.py

@@ -1,12 +1,11 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-from webob import exc
-
 from oslo_log import log as logging
 from oslo_log import log as logging
+from webob import exc
 
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import migration_view
 from coriolis.api.v1.views import migration_view
+from coriolis.api import wsgi as api_wsgi
 from coriolis import exception
 from coriolis import exception
 from coriolis.migrations import api
 from coriolis.migrations import api
 
 
@@ -57,7 +56,7 @@ class MigrationController(api_wsgi.Controller):
             raise exception.InvalidInput(msg)
             raise exception.InvalidInput(msg)
 
 
     def create(self, req, body):
     def create(self, req, body):
-        # TODO: validate body
+        # TODO(alexpilotti): validate body
         migration_body = body.get("migration", {})
         migration_body = body.get("migration", {})
         context = req.environ['coriolis.context']
         context = req.environ['coriolis.context']
 
 

+ 2 - 2
coriolis/api/v1/replica_tasks_executions.py

@@ -3,8 +3,8 @@
 
 
 from webob import exc
 from webob import exc
 
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import replica_tasks_execution_view
 from coriolis.api.v1.views import replica_tasks_execution_view
+from coriolis.api import wsgi as api_wsgi
 from coriolis import exception
 from coriolis import exception
 from coriolis.replica_tasks_executions import api
 from coriolis.replica_tasks_executions import api
 
 
@@ -35,7 +35,7 @@ class ReplicaTasksExecutionController(api_wsgi.Controller):
                 include_tasks=True))
                 include_tasks=True))
 
 
     def create(self, req, replica_id, body):
     def create(self, req, replica_id, body):
-        # TODO: validate body
+        # TODO(alexpilotti): validate body
 
 
         execution_body = body.get("execution", {})
         execution_body = body.get("execution", {})
         shutdown_instances = execution_body.get("shutdown_instances", False)
         shutdown_instances = execution_body.get("shutdown_instances", False)

+ 2 - 3
coriolis/api/v1/replicas.py

@@ -1,12 +1,11 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-from webob import exc
-
 from oslo_log import log as logging
 from oslo_log import log as logging
+from webob import exc
 
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import replica_view
 from coriolis.api.v1.views import replica_view
+from coriolis.api import wsgi as api_wsgi
 from coriolis import exception
 from coriolis import exception
 from coriolis.replicas import api
 from coriolis.replicas import api
 
 

+ 3 - 3
coriolis/api/v1/router.py

@@ -5,16 +5,16 @@ from oslo_log import log as logging
 
 
 from coriolis import api
 from coriolis import api
 from coriolis.api.v1 import endpoint_actions
 from coriolis.api.v1 import endpoint_actions
-from coriolis.api.v1 import endpoints
 from coriolis.api.v1 import endpoint_instances
 from coriolis.api.v1 import endpoint_instances
 from coriolis.api.v1 import endpoint_networks
 from coriolis.api.v1 import endpoint_networks
-from coriolis.api.v1 import migrations
+from coriolis.api.v1 import endpoints
 from coriolis.api.v1 import migration_actions
 from coriolis.api.v1 import migration_actions
+from coriolis.api.v1 import migrations
 from coriolis.api.v1 import provider_schemas
 from coriolis.api.v1 import provider_schemas
 from coriolis.api.v1 import providers
 from coriolis.api.v1 import providers
 from coriolis.api.v1 import replica_actions
 from coriolis.api.v1 import replica_actions
-from coriolis.api.v1 import replica_tasks_executions
 from coriolis.api.v1 import replica_tasks_execution_actions
 from coriolis.api.v1 import replica_tasks_execution_actions
+from coriolis.api.v1 import replica_tasks_executions
 from coriolis.api.v1 import replicas
 from coriolis.api.v1 import replicas
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)

+ 6 - 1
coriolis/api/wsgi.py

@@ -23,10 +23,11 @@ from oslo_serialization import jsonutils
 from oslo_utils import excutils
 from oslo_utils import excutils
 import six
 import six
 import webob
 import webob
+import webob.dec
 
 
 from coriolis import exception
 from coriolis import exception
 from coriolis import i18n
 from coriolis import i18n
-from coriolis.i18n import _, _LE, _LI
+from coriolis.i18n import _, _LE, _LI  # noqa
 
 
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
@@ -319,6 +320,7 @@ class Request(webob.Request):
 
 
 class Middleware(Application):
 class Middleware(Application):
     """Base WSGI middleware.
     """Base WSGI middleware.
+
     These classes require an application to be
     These classes require an application to be
     initialized that will be called next.  By default the middleware will
     initialized that will be called next.  By default the middleware will
     simply call its wrapped app, or you can override __call__ to customize its
     simply call its wrapped app, or you can override __call__ to customize its
@@ -328,6 +330,7 @@ class Middleware(Application):
     @classmethod
     @classmethod
     def factory(cls, global_config, **local_config):
     def factory(cls, global_config, **local_config):
         """Used for paste app factories in paste.deploy config files.
         """Used for paste app factories in paste.deploy config files.
+
         Any local configuration (that is, values under the [filter:APPNAME]
         Any local configuration (that is, values under the [filter:APPNAME]
         section of the paste config) will be passed into the `__init__` method
         section of the paste config) will be passed into the `__init__` method
         as kwargs.
         as kwargs.
@@ -350,6 +353,7 @@ class Middleware(Application):
 
 
     def process_request(self, req):
     def process_request(self, req):
         """Called on each request.
         """Called on each request.
+
         If this returns None, the next application down the stack will be
         If this returns None, the next application down the stack will be
         executed. If it returns a response then that response will be returned
         executed. If it returns a response then that response will be returned
         and execution will stop here.
         and execution will stop here.
@@ -1250,6 +1254,7 @@ def _set_request_id_header(req, headers):
 
 
 def _check_string_length(value, name, min_length=0, max_length=None):
 def _check_string_length(value, name, min_length=0, max_length=None):
     """Check the length of specified string.
     """Check the length of specified string.
+
     :param value: the value of the string
     :param value: the value of the string
     :param name: the name of the string
     :param name: the name of the string
     :param min_length: the min_length of the string
     :param min_length: the min_length of the string

+ 5 - 0
coriolis/cmd/__init__.py

@@ -0,0 +1,5 @@
+# Copyright 2017 Cloudbase Solutions Srl
+# All Rights Reserved.
+
+import eventlet
+eventlet.monkey_patch()

+ 4 - 7
coriolis/cmd/api.py

@@ -1,15 +1,12 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-import eventlet
-eventlet.monkey_patch()
+import sys
 
 
-import sys # noqa
+from oslo_config import cfg
 
 
-from coriolis import service # noqa
-from coriolis import utils # noqa
-
-from oslo_config import cfg # noqa
+from coriolis import service
+from coriolis import utils
 
 
 CONF = cfg.CONF
 CONF = cfg.CONF
 
 

+ 5 - 8
coriolis/cmd/conductor.py

@@ -1,16 +1,13 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-import eventlet
-eventlet.monkey_patch()
+import sys
 
 
-import sys # noqa
+from oslo_config import cfg
 
 
-from oslo_config import cfg # noqa
-
-from coriolis.conductor.rpc import server as rpc_server # noqa
-from coriolis import service # noqa
-from coriolis import utils # noqa
+from coriolis.conductor.rpc import server as rpc_server
+from coriolis import service
+from coriolis import utils
 
 
 CONF = cfg.CONF
 CONF = cfg.CONF
 
 

+ 5 - 8
coriolis/cmd/worker.py

@@ -1,16 +1,13 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-import eventlet
-eventlet.monkey_patch()
+import sys
 
 
-import sys # noqa
+from oslo_config import cfg
 
 
-from oslo_config import cfg # noqa
-
-from coriolis.worker.rpc import server as rpc_server # noqa
-from coriolis import service # noqa
-from coriolis import utils # noqa
+from coriolis import service
+from coriolis import utils
+from coriolis.worker.rpc import server as rpc_server
 
 
 CONF = cfg.CONF
 CONF = cfg.CONF
 
 

+ 1 - 0
coriolis/db/api.py

@@ -48,6 +48,7 @@ def _model_query(context, *args):
 
 
 def _soft_delete_aware_query(context, *args, **kwargs):
 def _soft_delete_aware_query(context, *args, **kwargs):
     """Query helper that accounts for context's `show_deleted` field.
     """Query helper that accounts for context's `show_deleted` field.
+
     :param show_deleted: if True, overrides context's show_deleted field.
     :param show_deleted: if True, overrides context's show_deleted field.
     """
     """
     query = _model_query(context, *args)
     query = _model_query(context, *args)

+ 3 - 3
coriolis/db/sqlalchemy/models.py

@@ -60,10 +60,10 @@ class Task(BASE, models.TimestampMixin, models.SoftDeleteMixin,
     exception_details = sqlalchemy.Column(sqlalchemy.Text, nullable=True)
     exception_details = sqlalchemy.Column(sqlalchemy.Text, nullable=True)
     depends_on = sqlalchemy.Column(types.List, nullable=True)
     depends_on = sqlalchemy.Column(types.List, nullable=True)
     on_error = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False)
     on_error = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False)
-    # TODO: Add soft delete filter
+    # TODO(alexpilotti): Add soft delete filter
     events = orm.relationship(TaskEvent, cascade="all,delete",
     events = orm.relationship(TaskEvent, cascade="all,delete",
                               backref=orm.backref('task'))
                               backref=orm.backref('task'))
-    # TODO: Add soft delete filter
+    # TODO(alexpilotti): Add soft delete filter
     progress_updates = orm.relationship(TaskProgressUpdate,
     progress_updates = orm.relationship(TaskProgressUpdate,
                                         cascade="all,delete",
                                         cascade="all,delete",
                                         backref=orm.backref('task'))
                                         backref=orm.backref('task'))
@@ -79,7 +79,7 @@ class TasksExecution(BASE, models.TimestampMixin, models.ModelBase,
     action_id = sqlalchemy.Column(
     action_id = sqlalchemy.Column(
         sqlalchemy.String(36),
         sqlalchemy.String(36),
         sqlalchemy.ForeignKey('base_transfer_action.base_id'), nullable=False)
         sqlalchemy.ForeignKey('base_transfer_action.base_id'), nullable=False)
-    # TODO: Add soft delete filter
+    # TODO(alexpilotti): Add soft delete filter
     tasks = orm.relationship(Task, cascade="all,delete",
     tasks = orm.relationship(Task, cascade="all,delete",
                              backref=orm.backref('execution'))
                              backref=orm.backref('execution'))
     status = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)
     status = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)

+ 8 - 1
coriolis/exception.py

@@ -24,7 +24,7 @@ import webob.exc
 from webob.util import status_generic_reasons
 from webob.util import status_generic_reasons
 from webob.util import status_reasons
 from webob.util import status_reasons
 
 
-from coriolis.i18n import _, _LE
+from coriolis.i18n import _, _LE  # noqa
 
 
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
@@ -306,3 +306,10 @@ class SchemaValidationException(CoriolisException):
 
 
 class QEMUException(Exception):
 class QEMUException(Exception):
     pass
     pass
+
+
+if six.PY2:
+    class ConnectionRefusedError(OSError):
+        pass
+else:
+    ConnectionRefusedError = six.moves.builtins.ConnectionRefusedError

+ 1 - 1
coriolis/keystone.py

@@ -101,7 +101,7 @@ def delete_trust(ctxt):
 def create_keystone_session(ctxt, connection_info={}):
 def create_keystone_session(ctxt, connection_info={}):
     allow_untrusted = connection_info.get(
     allow_untrusted = connection_info.get(
         "allow_untrusted", CONF.keystone.allow_untrusted)
         "allow_untrusted", CONF.keystone.allow_untrusted)
-    # TODO: add "ca_cert" to connection_info
+    # TODO(alexpilotti): add "ca_cert" to connection_info
     verify = not allow_untrusted
     verify = not allow_untrusted
 
 
     username = connection_info.get("username")
     username = connection_info.get("username")

+ 4 - 4
coriolis/migrations/manager.py

@@ -1,16 +1,16 @@
 # Copyright 2017 Cloudbase Solutions Srl
 # Copyright 2017 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-import eventlet
 import gc
 import gc
 import sys
 import sys
 
 
+import eventlet
 from oslo_log import log as logging
 from oslo_log import log as logging
 from oslo_utils import units
 from oslo_utils import units
 
 
 from coriolis import events
 from coriolis import events
-from coriolis import qemu_reader
 from coriolis.providers import backup_writers
 from coriolis.providers import backup_writers
+from coriolis import qemu_reader
 from coriolis import utils
 from coriolis import utils
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
@@ -64,7 +64,7 @@ def _copy_wrapper(job_args):
 
 
 
 
 def copy_disk_data(target_conn_info, volumes_info, event_handler):
 def copy_disk_data(target_conn_info, volumes_info, event_handler):
-    # TODO (gsamfira): the disk image should be an URI that can either be local
+    # TODO(gsamfira): the disk image should be an URI that can either be local
     # (file://) or remote (https://, ftp://, smb://, nfs:// etc).
     # (file://) or remote (https://, ftp://, smb://, nfs:// etc).
     # This must happen if we are to implement multi-worker scenarios.
     # This must happen if we are to implement multi-worker scenarios.
     # In such cases, it is not guaranteed that the disk sync task
     # In such cases, it is not guaranteed that the disk sync task
@@ -92,7 +92,7 @@ def copy_disk_data(target_conn_info, volumes_info, event_handler):
     job_data = [(vol, disk_image_reader, backup_writer, event_manager)
     job_data = [(vol, disk_image_reader, backup_writer, event_manager)
                 for vol in volumes_info]
                 for vol in volumes_info]
     for result, disk_id, error in pool.imap(_copy_wrapper, job_data):
     for result, disk_id, error in pool.imap(_copy_wrapper, job_data):
-        # TODO (gsamfira): There is no use in letting the other disks finish
+        # TODO(gsamfira): There is no use in letting the other disks finish
         # sync-ing as we don't save the state of the disk sync anywhere (yet).
         # sync-ing as we don't save the state of the disk sync anywhere (yet).
         # When/If we ever do add this info to the database, keep track of
         # When/If we ever do add this info to the database, keep track of
         # failures, and allow any other paralel sync to finish
         # failures, and allow any other paralel sync to finish

+ 1 - 1
coriolis/osmorphing/manager.py

@@ -4,8 +4,8 @@
 from oslo_config import cfg
 from oslo_config import cfg
 from oslo_log import log as logging
 from oslo_log import log as logging
 
 
-from coriolis import exception
 from coriolis import events
 from coriolis import events
+from coriolis import exception
 from coriolis.osmorphing.osmount import factory as osmount_factory
 from coriolis.osmorphing.osmount import factory as osmount_factory
 
 
 proxy_opts = [
 proxy_opts = [

+ 0 - 1
coriolis/osmorphing/openwrt.py

@@ -28,4 +28,3 @@ class BaseOpenWRTMorphingTools(base.BaseLinuxOSMorphingTools):
 
 
     def set_net_config(self, nics_info, dhcp):
     def set_net_config(self, nics_info, dhcp):
         pass
         pass
-

+ 3 - 3
coriolis/osmorphing/osmount/base.py

@@ -184,15 +184,15 @@ class BaseLinuxOSMountTools(BaseSSHOSMountTools):
             self._exec_cmd('sudo mount %s %s' % (dev_path, tmp_dir))
             self._exec_cmd('sudo mount %s %s' % (dev_path, tmp_dir))
             dirs = self._exec_cmd('ls %s' % tmp_dir).decode().split('\n')
             dirs = self._exec_cmd('ls %s' % tmp_dir).decode().split('\n')
 
 
-            # TODO: better ways to check for a linux root?
+            # TODO(alexpilotti): better ways to check for a linux root?
             if (not os_root_dir and 'etc' in dirs and 'bin' in dirs and
             if (not os_root_dir and 'etc' in dirs and 'bin' in dirs and
                     'sbin' in dirs):
                     'sbin' in dirs):
                 os_root_dir = tmp_dir
                 os_root_dir = tmp_dir
                 os_root_device = dev_path
                 os_root_device = dev_path
                 LOG.info("OS root device: %s", dev_path)
                 LOG.info("OS root device: %s", dev_path)
-            # TODO: better ways to check for a linux boot dir?
+            # TODO(alexpilotti): better ways to check for a linux boot dir?
             else:
             else:
-                # TODO: better ways to check for a linux boot dir?
+                # TODO(alexpilotti): better ways to check for a linux boot dir?
                 if not boot_dev_path and ('grub' in dirs or 'grub2' in dirs):
                 if not boot_dev_path and ('grub' in dirs or 'grub2' in dirs):
                     # Needs to be remounted under os_root_dir
                     # Needs to be remounted under os_root_dir
                     boot_dev_path = dev_path
                     boot_dev_path = dev_path

+ 15 - 6
coriolis/osmorphing/osmount/windows.py

@@ -58,8 +58,11 @@ class WindowsMountTools(base.BaseOSMountTools):
             "Update-HostStorageCache", ignore_stdout=True)
             "Update-HostStorageCache", ignore_stdout=True)
 
 
     def _run_diskpart_script(self, script):
     def _run_diskpart_script(self, script):
-        """ Writes the given script data to a file and runs diskpart.exe,
-        returning the output. """
+        """Executes the given script with diskpart.exe.
+
+        Writes the given script data to a file and runs diskpart.exe,
+        returning the output.
+        """
         tempdir = self._conn.exec_ps_command("$env:TEMP")
         tempdir = self._conn.exec_ps_command("$env:TEMP")
 
 
         # NOTE: diskpart is interactive, so we must either pipe it its input
         # NOTE: diskpart is interactive, so we must either pipe it its input
@@ -72,8 +75,11 @@ class WindowsMountTools(base.BaseOSMountTools):
     def _service_disks_with_status(
     def _service_disks_with_status(
             self, status, service_script_with_id_fmt,
             self, status, service_script_with_id_fmt,
             logmsg_fmt="Operating on disk with index '%s'"):
             logmsg_fmt="Operating on disk with index '%s'"):
-        """ Uses diskpart.exe to detect all disks with the given 'status', and
-        execute the given service script after formatting the disk ID in. """
+        """Executes given service script on detected disks.
+
+        Uses diskpart.exe to detect all disks with the given 'status', and
+        execute the given service script after formatting the disk ID in.
+        """
         disk_list_script = "LIST DISK\r\nEXIT"
         disk_list_script = "LIST DISK\r\nEXIT"
 
 
         disk_entry_re = r"\s+Disk (%s)\s+%s\s+"
         disk_entry_re = r"\s+Disk (%s)\s+%s\s+"
@@ -109,8 +115,11 @@ class WindowsMountTools(base.BaseOSMountTools):
             logmsg_fmt="Clearing R/O flag on foreign disk with ID '%s'.")
             logmsg_fmt="Clearing R/O flag on foreign disk with ID '%s'.")
 
 
     def _import_foreign_disks(self):
     def _import_foreign_disks(self):
-        """ Uses diskpart.exe to import all disks which are foreign to the
-        worker. Needed when servicing installations on Dynamic Disks. """
+        """Imports foreign disks.
+
+        Uses diskpart.exe to import all disks which are foreign to the
+        worker. Needed when servicing installations on Dynamic Disks.
+        """
         # NOTE: foreign disks are not exposed via the APIs the PowerShell
         # NOTE: foreign disks are not exposed via the APIs the PowerShell
         # disk cmdlets use, thus any disk which is foreign is is likely
         # disk cmdlets use, thus any disk which is foreign is is likely
         # still RO, which is why we must change the RO attribute as well:
         # still RO, which is why we must change the RO attribute as well:

+ 1 - 1
coriolis/osmorphing/redhat.py

@@ -70,7 +70,7 @@ class BaseRedHatMorphingTools(base.BaseLinuxOSMorphingTools):
         try:
         try:
             self._exec_cmd_chroot("rpm -q systemd")
             self._exec_cmd_chroot("rpm -q systemd")
             return True
             return True
-        except:
+        except Exception:
             return False
             return False
 
 
     def _set_dhcp_net_config(self, ifcfgs_ethernet):
     def _set_dhcp_net_config(self, ifcfgs_ethernet):

+ 2 - 2
coriolis/osmorphing/suse.py

@@ -30,7 +30,7 @@ class BaseSUSEMorphingTools(base.BaseLinuxOSMorphingTools):
             return ('SUSE', release)
             return ('SUSE', release)
 
 
     def set_net_config(self, nics_info, dhcp):
     def set_net_config(self, nics_info, dhcp):
-        # TODO: add networking support
+        # TODO(alexpilotti): add networking support
         pass
         pass
 
 
     def _run_dracut(self):
     def _run_dracut(self):
@@ -50,7 +50,7 @@ class BaseSUSEMorphingTools(base.BaseLinuxOSMorphingTools):
         try:
         try:
             self._exec_cmd_chroot("rpm -q systemd")
             self._exec_cmd_chroot("rpm -q systemd")
             return True
             return True
-        except:
+        except Exception:
             return False
             return False
 
 
     def install_packages(self, package_names):
     def install_packages(self, package_names):

+ 2 - 2
coriolis/osmorphing/windows.py

@@ -1,11 +1,11 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
+from distutils import version
 import os
 import os
 import re
 import re
 import uuid
 import uuid
 
 
-from distutils import version
 from oslo_log import log as logging
 from oslo_log import log as logging
 
 
 from coriolis import exception
 from coriolis import exception
@@ -32,7 +32,7 @@ class BaseWindowsMorphingTools(base.BaseOSMorphingTools):
             LOG.debug("Exception during OS detection: %s", ex)
             LOG.debug("Exception during OS detection: %s", ex)
 
 
     def set_net_config(self, nics_info, dhcp):
     def set_net_config(self, nics_info, dhcp):
-        # TODO: implement
+        # TODO(alexpilotti): implement
         pass
         pass
 
 
     def _get_dism_path(self):
     def _get_dism_path(self):

+ 11 - 7
coriolis/providers/base.py

@@ -31,26 +31,26 @@ class BaseEndpointProvider(BaseProvider):
 
 
 
 
 class BaseEndpointInstancesProvider(BaseEndpointProvider):
 class BaseEndpointInstancesProvider(BaseEndpointProvider):
-    """ Defines operations for listing instances off of Endpoints """
+    """Defines operations for listing instances off of Endpoints."""
 
 
     @abc.abstractmethod
     @abc.abstractmethod
     def get_instances(self, ctxt, connection_info, limit=None,
     def get_instances(self, ctxt, connection_info, limit=None,
                       last_seen_id=None, instance_name_pattern=None):
                       last_seen_id=None, instance_name_pattern=None):
-        """ Returns a list of instances """
+        """Returns a list of instances."""
         raise NotImplementedError()
         raise NotImplementedError()
 
 
     @abc.abstractmethod
     @abc.abstractmethod
     def get_instance(self, ctxt, connection_info, instance_name):
     def get_instance(self, ctxt, connection_info, instance_name):
-        """ Returns detailed info for a given instance """
+        """Returns detailed info for a given instance."""
         raise NotImplementedError()
         raise NotImplementedError()
 
 
 
 
 class BaseEndpointNetworksProvider(object, with_metaclass(abc.ABCMeta)):
 class BaseEndpointNetworksProvider(object, with_metaclass(abc.ABCMeta)):
-    """ Defines operations for endpoints networks """
+    """Defines operations for endpoints networks."""
 
 
     @abc.abstractmethod
     @abc.abstractmethod
     def get_networks(self, ctxt, connection_info, env):
     def get_networks(self, ctxt, connection_info, env):
-        """ Returns a list of networks """
+        """Returns a list of networks """
         raise NotImplementedError()
         raise NotImplementedError()
 
 
 
 
@@ -90,7 +90,9 @@ class BaseImportProvider(BaseImportInstanceProvider):
     @abc.abstractmethod
     @abc.abstractmethod
     def import_instance(self, ctxt, connection_info, target_environment,
     def import_instance(self, ctxt, connection_info, target_environment,
                         instance_name, export_info):
                         instance_name, export_info):
-        """ Imports the instance given by its name to the specified target
+        """Imports the given instance.
+
+        Imports the instance given by its name to the specified target
         environment within the destination cloud based on the provided
         environment within the destination cloud based on the provided
         connection and export info.
         connection and export info.
         """
         """
@@ -175,7 +177,9 @@ class BaseExportProvider(BaseInstanceProvider):
     @abc.abstractmethod
     @abc.abstractmethod
     def export_instance(self, ctxt, connection_info, instance_name,
     def export_instance(self, ctxt, connection_info, instance_name,
                         export_path):
                         export_path):
-        """ Exports the instance given by its name from the given source cloud
+        """Exports the given instance.
+
+         Exports the instance given by its name from the given source cloud
         to the provided export directory path using the given connection info.
         to the provided export directory path using the given connection info.
         """
         """
         pass
         pass

+ 1 - 1
coriolis/qemu_reader.py

@@ -99,7 +99,7 @@ class QEMUDiskImageReaderImpl(object):
         if ret < 0:
         if ret < 0:
             raise exception.QEMUException("blk_pread failed")
             raise exception.QEMUException("blk_pread failed")
 
 
-        return (ctypes.c_ubyte*read_size).from_address(self._buf)
+        return (ctypes.c_ubyte * read_size).from_address(self._buf)
 
 
 
 
 class QEMUDiskImageReader(object):
 class QEMUDiskImageReader(object):

+ 6 - 6
coriolis/schemas.py

@@ -1,13 +1,12 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-""" Defines various schemas used for validation throughout the project. """
+"""Defines various schemas used for validation throughout the project."""
 
 
 import json
 import json
 
 
 import jinja2
 import jinja2
 import jsonschema
 import jsonschema
-
 from oslo_log import log as logging
 from oslo_log import log as logging
 
 
 from coriolis import exception
 from coriolis import exception
@@ -29,7 +28,9 @@ _CORIOLIS_VM_NETWORK_SCHEMA_NAME = "vm_network_schema.json"
 
 
 def get_schema(package_name, schema_name,
 def get_schema(package_name, schema_name,
                schemas_directory=DEFAULT_SCHEMAS_DIRECTORY):
                schemas_directory=DEFAULT_SCHEMAS_DIRECTORY):
-    """ Loads the schema with the given 'schema_name' using jinja2 template
+    """Loads the schema using jinja2 template loading.
+
+    Loads the schema with the given 'schema_name' using jinja2 template
     loading from the provided 'package_name' under the given
     loading from the provided 'package_name' under the given
     'schemas_directory'.
     'schemas_directory'.
     """
     """
@@ -44,7 +45,7 @@ def get_schema(package_name, schema_name,
 
 
 
 
 def validate_value(val, schema):
 def validate_value(val, schema):
-    """ Simple wrapper for jsonschema.validate for usability.
+    """Simple wrapper for jsonschema.validate for usability.
 
 
     NOTE: silently passes empty schemas.
     NOTE: silently passes empty schemas.
     """
     """
@@ -59,8 +60,7 @@ def validate_value(val, schema):
 
 
 
 
 def validate_string(json_string, schema):
 def validate_string(json_string, schema):
-    """ Attempts to validate the json value provided as a string against the
-    given JSON schema.
+    """Attempts to validate the given json string against the JSON schema.
 
 
     Runs silently on success or raises an exception otherwise.
     Runs silently on success or raises an exception otherwise.
     Silently passes empty schemas.
     Silently passes empty schemas.

+ 5 - 7
coriolis/schemas_exceptions.py

@@ -1,7 +1,7 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-""" Defines a set of exceptions possible during schema loading/validation. """
+"""Defines a set of exceptions possible during schema loading/validation."""
 
 
 import jinja2
 import jinja2
 import jsonschema
 import jsonschema
@@ -10,25 +10,23 @@ from coriolis import exception
 
 
 
 
 class CoriolisSchemaException(exception.CoriolisException):
 class CoriolisSchemaException(exception.CoriolisException):
-    """ Base class for all coriolis schema handling exceptions. """
+    """Base class for all coriolis schema handling exceptions."""
     message = "Exception occured during schema validation: %(msg)s."
     message = "Exception occured during schema validation: %(msg)s."
 
 
 
 
 class CoriolisSchemaValidationError(
 class CoriolisSchemaValidationError(
         CoriolisSchemaException, jsonschema.ValidationError):
         CoriolisSchemaException, jsonschema.ValidationError):
-    """ Raised when a schema validation has failed. """
+    """Raised when a schema validation has failed."""
     message = "Failed to validate JSON schema: %(msg)s."
     message = "Failed to validate JSON schema: %(msg)s."
 
 
 
 
 class CoriolisSchemaParsingError(
 class CoriolisSchemaParsingError(
         CoriolisSchemaException, ValueError):
         CoriolisSchemaException, ValueError):
-    """ Raised when decoding of either the JSON schema or the JSON value being
-    validated occurs.
-    """
+    """Raised when decoding a JSON schema or when validating a JSON value."""
     message = "Failed to parse JSON for schema validation: %(msg)s."
     message = "Failed to parse JSON for schema validation: %(msg)s."
 
 
 
 
 class CoriolisSchemaLoadingException(
 class CoriolisSchemaLoadingException(
         CoriolisSchemaException, jinja2.TemplateNotFound):
         CoriolisSchemaException, jinja2.TemplateNotFound):
-    """ Raised when schema files are not found. """
+    """Raised when schema files are not found."""
     message = "Failed to load schema: %(msg)s."
     message = "Failed to load schema: %(msg)s."

+ 1 - 3
coriolis/tasks/base.py

@@ -3,13 +3,11 @@
 
 
 import abc
 import abc
 
 
-from coriolis import utils
-
 from oslo_config import cfg
 from oslo_config import cfg
 from oslo_log import log as logging
 from oslo_log import log as logging
-
 from six import with_metaclass
 from six import with_metaclass
 
 
+from coriolis import utils
 
 
 serialization_opts = [
 serialization_opts = [
     cfg.StrOpt('temp_keypair_password',
     cfg.StrOpt('temp_keypair_password',

+ 6 - 6
coriolis/tasks/migration_tasks.py

@@ -1,16 +1,16 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
+from oslo_log import log as logging
+
 from coriolis import constants
 from coriolis import constants
 from coriolis import events
 from coriolis import events
-from coriolis.providers import factory as providers_factory
-from coriolis import schemas
 from coriolis import exception
 from coriolis import exception
 from coriolis.migrations import manager
 from coriolis.migrations import manager
+from coriolis.providers import factory as providers_factory
+from coriolis import schemas
 from coriolis.tasks import base
 from coriolis.tasks import base
 
 
-from oslo_log import log as logging
-
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
 
 
@@ -55,7 +55,7 @@ class ImportInstanceTask(base.TaskRunner):
         task_info["origin_provider_type"] = constants.PROVIDER_TYPE_EXPORT
         task_info["origin_provider_type"] = constants.PROVIDER_TYPE_EXPORT
         task_info["destination_provider_type"] = constants.PROVIDER_TYPE_IMPORT
         task_info["destination_provider_type"] = constants.PROVIDER_TYPE_IMPORT
         # We need to retain export info until after disk sync
         # We need to retain export info until after disk sync
-        # TODO (gsamfira): remove this when we implement multi-worker, and by
+        # TODO(gsamfira): remove this when we implement multi-worker, and by
         # extension some external storage for needed resources (like swift)
         # extension some external storage for needed resources (like swift)
         task_info["retain_export_path"] = True
         task_info["retain_export_path"] = True
 
 
@@ -83,7 +83,7 @@ class DeployDiskCopyResources(base.TaskRunner):
         task_info["instance_deployment_info"][
         task_info["instance_deployment_info"][
             "disk_sync_connection_info"] = conn_info
             "disk_sync_connection_info"] = conn_info
         # We need to retain export info until after disk sync
         # We need to retain export info until after disk sync
-        # TODO (gsamfira): remove this when we implement multi-worker, and by
+        # TODO(gsamfira): remove this when we implement multi-worker, and by
         # extension some external storage for needed resources (like swift)
         # extension some external storage for needed resources (like swift)
         task_info["retain_export_path"] = True
         task_info["retain_export_path"] = True
 
 

+ 2 - 2
coriolis/tasks/replica_tasks.py

@@ -1,14 +1,14 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
+from oslo_log import log as logging
+
 from coriolis import constants
 from coriolis import constants
 from coriolis import exception
 from coriolis import exception
 from coriolis.providers import factory as providers_factory
 from coriolis.providers import factory as providers_factory
 from coriolis import schemas
 from coriolis import schemas
 from coriolis.tasks import base
 from coriolis.tasks import base
 
 
-from oslo_log import log as logging
-
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
 
 

+ 2 - 2
coriolis/tests/providers/base.py

@@ -1,9 +1,9 @@
-""" Defines base classes for all provider tests. """
+"""Defines base classes for all provider tests."""
 
 
 import mock
 import mock
 
 
-from coriolis.tests import testutils
 from coriolis.tests import test_base
 from coriolis.tests import test_base
+from coriolis.tests import testutils
 
 
 
 
 class ProvidersBaseTestCase(test_base.CoriolisBaseTestCase):
 class ProvidersBaseTestCase(test_base.CoriolisBaseTestCase):

+ 1 - 1
coriolis/tests/test_base.py

@@ -1,7 +1,7 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-""" Defines base class for all tests. """
+"""Defines base class for all tests."""
 
 
 from oslotest import base
 from oslotest import base
 
 

+ 3 - 3
coriolis/tests/test_schemas.py

@@ -2,10 +2,10 @@
 # All Rights Reserved.
 # All Rights Reserved.
 
 
 import json
 import json
-import jsonschema
-import mock
 
 
 import jinja2
 import jinja2
+import jsonschema
+import mock
 
 
 from coriolis import schemas
 from coriolis import schemas
 from coriolis.tests import test_base
 from coriolis.tests import test_base
@@ -25,7 +25,7 @@ def _get_mock_template_env():
 
 
 
 
 class SchemasTestCase(test_base.CoriolisBaseTestCase):
 class SchemasTestCase(test_base.CoriolisBaseTestCase):
-    """ Collection of tests for the Coriolis schemas package. """
+    """Collection of tests for the Coriolis schemas package."""
 
 
     def setUp(self):
     def setUp(self):
         super(SchemasTestCase, self).setUp()
         super(SchemasTestCase, self).setUp()

+ 3 - 3
coriolis/tests/testutils.py

@@ -1,13 +1,13 @@
-""" Defines general utilities for all tests. """
+"""Defines general utilities for all tests."""
 
 
 import mock
 import mock
 
 
 
 
 def identity_dec(item, *args, **kwargs):
 def identity_dec(item, *args, **kwargs):
-    """ A decorator which adds nothing to the decorated item. """
+    """A decorator which adds nothing to the decorated item."""
     return item
     return item
 
 
 
 
 def make_identity_decorator_mock():
 def make_identity_decorator_mock():
-    """ Returns a MagicMock with identity_dec as a side-effect. """
+    """Returns a MagicMock with identity_dec as a side-effect."""
     return mock.MagicMock(side_effect=identity_dec)
     return mock.MagicMock(side_effect=identity_dec)

+ 6 - 7
coriolis/utils.py

@@ -54,8 +54,9 @@ def ignore_exceptions(func):
 
 
 
 
 def get_single_result(lis):
 def get_single_result(lis):
-    """ Indexes the head of a single element list.
-    Raises a KeyError if the list is empty or its length is greater than 1.
+    """Indexes the head of a single element list.
+
+    :raises KeyError: if the list is empty or its length is greater than 1.
     """
     """
     if len(lis) == 0:
     if len(lis) == 0:
         raise KeyError("Result list is empty.")
         raise KeyError("Result list is empty.")
@@ -198,7 +199,7 @@ def _check_port_open(host, port):
         s.settimeout(1)
         s.settimeout(1)
         s.connect((host, port))
         s.connect((host, port))
         return True
         return True
-    except (ConnectionRefusedError, socket.timeout, OSError):
+    except (exception.ConnectionRefusedError, socket.timeout, OSError):
         return False
         return False
     finally:
     finally:
         s.close()
         s.close()
@@ -324,9 +325,7 @@ def to_dict(obj, max_depth=10):
 
 
 def topological_graph_sorting(items, id="id", depends_on="depends_on",
 def topological_graph_sorting(items, id="id", depends_on="depends_on",
                               sort_key=None):
                               sort_key=None):
-    """
-    Kahn's algorithm
-    """
+    """Kahn's algorithm"""
     if sort_key:
     if sort_key:
         # Sort siblings
         # Sort siblings
         items = sorted(items, key=lambda t: t[sort_key], reverse=True)
         items = sorted(items, key=lambda t: t[sort_key], reverse=True)
@@ -405,7 +404,7 @@ def quote_url(text):
 def get_url_with_credentials(url, username, password):
 def get_url_with_credentials(url, username, password):
     parts = parse.urlsplit(url)
     parts = parse.urlsplit(url)
     # Remove previous credentials if set
     # Remove previous credentials if set
-    netloc = parts.netloc[parts.netloc.find('@')+1:]
+    netloc = parts.netloc[parts.netloc.find('@') + 1:]
     netloc = "%s:%s@%s" % (
     netloc = "%s:%s@%s" % (
         quote_url(username), quote_url(password or ''), netloc)
         quote_url(username), quote_url(password or ''), netloc)
     parts = parts._replace(netloc=netloc)
     parts = parts._replace(netloc=netloc)

+ 5 - 4
coriolis/worker/rpc/server.py

@@ -1,17 +1,17 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 # All Rights Reserved.
 
 
-from logging import handlers
 import multiprocessing
 import multiprocessing
 import os
 import os
-import queue
 import shutil
 import shutil
 import signal
 import signal
 import sys
 import sys
 
 
-import psutil
+from logging import handlers
 from oslo_config import cfg
 from oslo_config import cfg
 from oslo_log import log as logging
 from oslo_log import log as logging
+import psutil
+from six.moves import queue
 
 
 from coriolis.conductor.rpc import client as rpc_conductor_client
 from coriolis.conductor.rpc import client as rpc_conductor_client
 from coriolis import constants
 from coriolis import constants
@@ -152,7 +152,8 @@ class WorkerServerEndpoint(object):
             if new_task_info:
             if new_task_info:
                 LOG.info("Task info: %s", new_task_info)
                 LOG.info("Task info: %s", new_task_info)
 
 
-            # TODO: replace the temp storage with a host independent option
+            # TODO(alexpilotti): replace the temp storage with a host
+            # independent option
             retain_export_path = new_task_info.get("retain_export_path", False)
             retain_export_path = new_task_info.get("retain_export_path", False)
             if not retain_export_path:
             if not retain_export_path:
                 del new_task_info["export_path"]
                 del new_task_info["export_path"]

+ 2 - 2
setup.py

@@ -1,7 +1,7 @@
+import os
+import platform
 import setuptools
 import setuptools
 import subprocess
 import subprocess
-import platform
-import os
 
 
 
 
 def _compile_and_install():
 def _compile_and_install():

+ 2 - 0
test-requirements.txt

@@ -1,3 +1,5 @@
 coverage
 coverage
 discover
 discover
 oslotest
 oslotest
+
+hacking>=0.12.0,<0.13 # Apache-2.0

+ 37 - 0
tox.ini

@@ -0,0 +1,37 @@
+[tox]
+minversion = 2.0
+envlist = py35,py27,pep8
+skipsdist = True
+
+[testenv]
+usedevelop = True
+whitelist_externals = rm
+install_command = pip install {opts} {packages}
+setenv =
+   VIRTUAL_ENV={envdir}
+   BRANCH_NAME=master
+   CLIENT_NAME=coriolis-core
+   DEFAULT_REPO=git@bitbucket.org:cloudbase
+   PYTHONWARNINGS=default::DeprecationWarning
+deps = -r{toxinidir}/requirements.txt
+       -r{toxinidir}/test-requirements.txt
+commands =
+  python setup.py test --slowest --testr-args='{posargs}'
+  rm -f .testrepository/times.dbm
+
+[testenv:pep8]
+commands = flake8 {posargs}
+
+[testenv:venv]
+commands = {posargs}
+
+[testenv:cover]
+commands = python setup.py test --coverage --testr-args='{posargs}'
+
+[flake8]
+# E123, E125 skipped as they are invalid PEP-8.
+
+show-source = True
+ignore = E123,E125
+builtins = _
+exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build