From 03f22a82b49a5a966aea1e034cb75112e30abf59 Mon Sep 17 00:00:00 2001 From: darius BERNARD Date: Tue, 25 Jun 2019 14:44:21 +0200 Subject: [PATCH 1/5] add unittest to upgrade coverage of used code. add functional test with a running rabbitmq and service add travis config to run these tests add tox to run test for all supported versions fix deadlock with crash during pool initalization --- .travis.yml | 24 ++++++- django_nameko/rpc.py | 88 +++++++++++++------------ tests/config.yaml | 3 + tests/services.py | 15 +++++ tests/test_rpc.py | 66 ++++++++++++++++++- tests/test_running_services.py | 114 +++++++++++++++++++++++++++++++++ tox.ini | 51 +++++++++++++++ 7 files changed, 317 insertions(+), 44 deletions(-) create mode 100644 tests/config.yaml create mode 100644 tests/services.py create mode 100644 tests/test_running_services.py create mode 100644 tox.ini diff --git a/.travis.yml b/.travis.yml index 056c055..4bdbdaf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,43 @@ sudo: false language: python +dist: xenial +services: +- docker +before_install: +- docker run -d --rm -p 15672:15672 -p 5672:5672 -p 5671:5671 --name nameko-rabbitmq nameko/nameko-rabbitmq:3.6.6 + python: - "2.7" + - "3.5" + - "3.6" + - "3.7" addons: apt_packages: - libenchant-dev +install: +- pip install tox-travis virtualenv tox python-coveralls coveralls + cache: directories: - $HOME/.cache/pip +script: +- QUIET=true tox +stages: + - test + - deploy + jobs: include: + - stage: test + after_success: + - coveralls - stage: deploy python: 2.7 - script: python2 ./setup.py test + script: skip + install: skip deploy: provider: pypi user: tranvietanh1991 diff --git a/django_nameko/rpc.py b/django_nameko/rpc.py index 2725ef0..b220168 100644 --- a/django_nameko/rpc.py +++ b/django_nameko/rpc.py @@ -54,8 +54,11 @@ def __init__(self, pool, config): self._enable_rpc_call = False def __del__(self): - if self._proxy: + + try: self._proxy.stop() + except AttributeError: + pass self._proxy = None self._rpc = None @@ -77,8 +80,8 @@ def __exit__(self, exc_type, exc_value, traceback, **kwargs): self._enable_rpc_call = False try: if exc_type == RuntimeError and ( - exc_value == "This consumer has been stopped, and can no longer be used" - or exc_value == "This consumer has been disconnected, and can no longer be used"): + str(exc_value) == "This consumer has been stopped, and can no longer be used" + or str(exc_value) == "This consumer has been disconnected, and can no longer be used"): self._pool._clear() self._pool._reload() # reload all worker self.__del__() @@ -93,8 +96,9 @@ def __exit__(self, exc_type, exc_value, traceback, **kwargs): for key in self._rpc._worker_ctx.data.keys(): del self._rpc._worker_ctx.data[key] elif len(self._rpc._worker_ctx.data) != len(self._pool.context_data) \ - or cmp(self._rpc._worker_ctx.data, self._pool.context_data) != 0: - # ensure that worker_ctx.data is revert back to original pool.context_data when exit of block + or self._rpc._worker_ctx.data != self._pool.context_data: + # ensure that worker_ctx.data is revert back to original + # pool.context_data when exit of block for key in self._rpc._worker_ctx.data.keys(): if key not in self._pool.context_data: del self._rpc._worker_ctx.data[key] @@ -159,6 +163,7 @@ def next(self, block=True, timeout=None): """ Fetch next connection. This method is thread-safe. + :rtype: ClusterRpcProxyPool.RpcContext """ return self.queue.get(block=block, timeout=timeout) @@ -208,6 +213,7 @@ def get_pool(pool_name=None): # ... with get_pool().next() as rpc: rpc.mailer.send_mail(foo='bar') + :rtype: ClusterRpcProxyPool """ global nameko_global_pools @@ -218,43 +224,40 @@ def get_pool(pool_name=None): raise ImproperlyConfigured('NAMEKO_CONFIG must be specified') NAMEKO_MULTI_POOL = [name for name in NAMEKO_CONFIG.keys() if name.islower()] # Lazy instantiation, acquire lock first to prevent dupication init - create_pool_lock.acquire() - if not nameko_global_pools: # double check inside lock is importance - if NAMEKO_MULTI_POOL: - nameko_global_pools = dict() - if 'default' not in NAMEKO_CONFIG and 'AMQP_URL' not in NAMEKO_CONFIG['default']: - raise ImproperlyConfigured( - 'NAMEKO_CONFIG must be specified and should include at least "default" config with "AMQP_URL"') - default_config = NAMEKO_CONFIG['default'] - # default_context_data = NAMEKO_CONFIG['default']['POOL'].get('CONTEXT_DATA', dict()) - # multi_context_data = getattr(settings, 'NAMEKO_MULTI_CONTEXT_DATA', dict()) - for name, _config in NAMEKO_CONFIG.items(): - # each nameko_global_pools will have different config with default config as default - if name != 'default': - # overide default config with nameko_global_pools config by merging 2 dict - pool_config = dict(mergedicts(default_config.copy(), _config)) - else: - # default nameko_global_pools - pool_config = default_config.copy() - # extract nameko_global_pools config from RpcCluster config - pool_size = pool_config.pop('POOL_SIZE', None) - pool_context_data = pool_config.pop('POOL_CONTEXT_DATA', None) - pool_timeout = pool_config.pop('POOL_TIMEOUT', 0) - # init nameko_global_pools - _pool = ClusterRpcProxyPool(pool_config, pool_size=pool_size, context_data=pool_context_data, - timeout=pool_timeout) - _pool.start() - # assign nameko_global_pools to corresponding name - nameko_global_pools[name] = _pool - else: - # single nameko_global_pools with old style configuration - if not hasattr(settings, 'NAMEKO_CONFIG') or not settings.NAMEKO_CONFIG: - raise ImproperlyConfigured( - 'NAMEKO_CONFIG must be specified and should include at least "AMQP_URL" key.') - nameko_global_pools = ClusterRpcProxyPool(settings.NAMEKO_CONFIG) - nameko_global_pools.start() # start immediately + with create_pool_lock: + if not nameko_global_pools: # double check inside lock is importance + if NAMEKO_MULTI_POOL: + nameko_global_pools = dict() + if 'default' not in NAMEKO_CONFIG or 'AMQP_URL' not in NAMEKO_CONFIG['default']: + raise ImproperlyConfigured( + 'NAMEKO_CONFIG must be specified and should include at least "default" config with "AMQP_URL"') + default_config = NAMEKO_CONFIG['default'] + # default_context_data = NAMEKO_CONFIG['default']['POOL'].get('CONTEXT_DATA', dict()) + # multi_context_data = getattr(settings, 'NAMEKO_MULTI_CONTEXT_DATA', dict()) + for name, _config in NAMEKO_CONFIG.items(): + # each nameko_global_pools will have different config with default config as default + if name != 'default': + # overide default config with nameko_global_pools config by merging 2 dict + pool_config = dict(mergedicts(default_config.copy(), _config)) + else: + # default nameko_global_pools + pool_config = default_config.copy() + # extract nameko_global_pools config from RpcCluster config + pool_size = pool_config.pop('POOL_SIZE', None) + pool_context_data = pool_config.pop('POOL_CONTEXT_DATA', None) + pool_timeout = pool_config.pop('POOL_TIMEOUT', 0) + # init nameko_global_pools + _pool = ClusterRpcProxyPool(pool_config, pool_size=pool_size, context_data=pool_context_data, + timeout=pool_timeout) + _pool.start() + # assign nameko_global_pools to corresponding name + nameko_global_pools[name] = _pool + else: + # single nameko_global_pools with old style configuration + + nameko_global_pools = ClusterRpcProxyPool(settings.NAMEKO_CONFIG) + nameko_global_pools.start() # start immediately # Finish instantiation, release lock - create_pool_lock.release() if pool_name is not None: if isinstance(nameko_global_pools, dict) is False or pool_name not in nameko_global_pools: @@ -264,7 +267,8 @@ def get_pool(pool_name=None): _pool = nameko_global_pools[pool_name] else: if isinstance(nameko_global_pools, dict): - if len(nameko_global_pools) == 0: + if len(nameko_global_pools) == 0: # pragma: nocover + # this code is unreachable, it's not passilbe to have a dict without a key in it. raise ImproperlyConfigured('NAMEKO_CONFIG must include at least 1 "default" config') _pool = nameko_global_pools.get('default', nameko_global_pools.values()[0]) else: diff --git a/tests/config.yaml b/tests/config.yaml new file mode 100644 index 0000000..c040b90 --- /dev/null +++ b/tests/config.yaml @@ -0,0 +1,3 @@ +AMQP_URI: amqp://guest:guest@localhost/ + +max_workers: 1 diff --git a/tests/services.py b/tests/services.py new file mode 100644 index 0000000..340fdec --- /dev/null +++ b/tests/services.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +import logging + +from nameko.rpc import rpc + +logger = logging.getLogger(__name__) + + +class EchoService(object): + + name = 'echo' + + @rpc + def echo(self, *attrs): + return tuple(attrs) diff --git a/tests/test_rpc.py b/tests/test_rpc.py index ce2c840..8e5c76d 100644 --- a/tests/test_rpc.py +++ b/tests/test_rpc.py @@ -1,3 +1,4 @@ +from amqp import ConnectionError from mock import patch, call from django_nameko import rpc, get_pool, destroy_pool from nose import tools @@ -59,6 +60,24 @@ def test_no_settings(): destroy_pool() +@override_settings(NAMEKO_CONFIG={'badkey': 'amqp://'}) +def test_bad_settings(): + tools.assert_raises(ImproperlyConfigured, get_pool) + destroy_pool() + + +@override_settings(NAMEKO_CONFIG={}) +def test_abd_settings(): + tools.assert_raises(ImproperlyConfigured, get_pool) + destroy_pool() + + +@override_settings(NAMEKO_CONFIG={'pool1': dict(AMQP_URL='amqp://')}) +def test_missing_default_settings(): + tools.assert_raises(ImproperlyConfigured, get_pool) + destroy_pool() + + @override_settings(NAMEKO_CONFIG=dict(AMQP_URL='amqp://'), NAMEKO_CONTEXT_DATA={"data": 123}) def test_context_data(): with patch('django_nameko.rpc.ClusterRpcProxy') as FakeClusterRpcProxy: @@ -71,6 +90,50 @@ def test_context_data(): destroy_pool() +@override_settings(NAMEKO_CONFIG=dict(AMQP_URL='amqp://')) +def test_runtime_error(): + with patch('django_nameko.rpc.ClusterRpcProxy') as FakeClusterRpcProxy: + pool = get_pool() + assert pool.queue.qsize() == 4, pool.queue.qsize() + client = pool.next() + assert pool.queue.qsize() == 3, pool.queue.qsize() + with tools.assert_raises(RuntimeError): + with pool.next(): + assert pool.queue.qsize() == 2, pool.queue.qsize() + raise RuntimeError("This consumer has been stopped, and can no longer be used") + # this has cleared all 4 proxy since runtimeerror is expected to broke them all + assert pool.queue.qsize() == 4, pool.queue.qsize + with client: + assert pool.queue.qsize() == 4, pool.queue.qsize() + client.foo.bar() + assert call().start().foo.bar() in FakeClusterRpcProxy.mock_calls + assert pool.queue.qsize() == 5, pool.queue.qsize() + + destroy_pool() + + +@override_settings(NAMEKO_CONFIG=dict(AMQP_URL='amqp://')) +def test_connection_error(): + with patch('django_nameko.rpc.ClusterRpcProxy') as FakeClusterRpcProxy: + pool = get_pool() + assert pool.queue.qsize() == 4, pool.queue.qsize() + client = pool.next() + assert pool.queue.qsize() == 3, pool.queue.qsize() + with tools.assert_raises(ConnectionError): + with pool.next(): + assert pool.queue.qsize() == 2, pool.queue.qsize + raise ConnectionError("connection closed") + assert pool.queue.qsize() == 3, pool.queue.qsize + # this has cleared all 4 proxy since runtimeerror is expected to broke them all + with client: + assert pool.queue.qsize() == 3, pool.queue.qsize() + client.foo.bar() + assert call().start().foo.bar() in FakeClusterRpcProxy.mock_calls + assert pool.queue.qsize() == 4, pool.queue.qsize() + + destroy_pool() + + @override_settings(NAMEKO_CONFIG={ 'default': { 'AMQP_URL': 'amqp://' @@ -146,6 +209,7 @@ def test_multi_pool_context_data(): destroy_pool() + @override_settings(NAMEKO_CONFIG=dict(AMQP_URL='amqp://')) def test_pool_call_rpc_out_of_with_statement(): with patch('django_nameko.rpc.ClusterRpcProxy') as FakeClusterRpcProxy: @@ -159,7 +223,7 @@ def test_pool_call_rpc_out_of_with_statement(): client.bar.foo() except AttributeError: pass - else: + else: # pragma: nocover raise AssertionError("AttributeError is expected when call rpc out of with statement") # try again inside with statement with pool.next() as client: diff --git a/tests/test_running_services.py b/tests/test_running_services.py new file mode 100644 index 0000000..a87f7e1 --- /dev/null +++ b/tests/test_running_services.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +import logging +import socket +import subprocess +import time + +import unittest + +from amqp import AccessRefused +from django.conf import settings +from django.test.utils import override_settings +from nameko.exceptions import UnknownService, MethodNotFound + +from nose import tools + +from django_nameko import get_pool, destroy_pool + +logger = logging.getLogger(__name__) + +if not settings.configured: # pragma: nocover + settings.configure() + +config = { + 'AMQP_URI': 'amqp://guest:guest@localhost', + 'TIMEOUT': 1 +} + + +class RealServiceTest(unittest.TestCase): + runner = None # type: subprocess.Popen + + @classmethod + def setUpClass(cls): + """ + run the service while in the context + :return: + """ + cls.runner = subprocess.Popen(('nameko', 'run', '--config', 'config.yaml', 'services')) + time.sleep(1) + + @classmethod + def tearDownClass(cls): + cls.runner.kill() + + def test_echo_no_rpc(self): + import services + assert services.EchoService().echo(42) == (42,) + + @override_settings(NAMEKO_CONFIG={ + 'AMQP_URI': 'amqp://guest:badpassword@localhost' + }) + def test_pool_call_bad_rabbitmq_cred(self): + with tools.assert_raises(AccessRefused): + _ = get_pool() + + destroy_pool() + + @override_settings(NAMEKO_CONFIG={ + 'AMQP_URI': 'amqp://guest:guest@localhost', + 'TIMEOUT': 1, + }) + def test_pool_call_no_service(self): + pool = get_pool() + with pool.next() as client: + tools.assert_raises(UnknownService, client.unknownservice.echo) + tools.assert_raises(MethodNotFound, client.echo.unknown_method) + + destroy_pool() + + @override_settings(NAMEKO_CONFIG={ + 'AMQP_URI': 'amqp://guest:guest@localhost:6666' + }) + def test_pool_call_no_rabbitmq_server(self): + with tools.assert_raises(socket.error): + _ = get_pool() + + destroy_pool() + + @override_settings(NAMEKO_CONFIG=config) + def test_pool_call_existing_service(self): + pool = get_pool() + with pool.next() as client: + assert client.echo.echo(42) == [42] + + # try to call RPC out of with statement + tools.assert_raises(AttributeError, lambda: client.echo.echo(42)) + # try again inside with statement + with pool.next() as client: + assert client.echo.echo(42) == [42] + + destroy_pool() + + @override_settings(NAMEKO_CONFIG=config) + def test_pool_destroy_and_recreate(self): + pool = get_pool() + with pool.next() as client: + assert client.echo.echo(42) == [42] + + destroy_pool() + pool = get_pool() + with pool.next() as client: + assert client.echo.echo(42) == [42] + + destroy_pool() + + @override_settings(NAMEKO_CONFIG=config, NAMEKO_CONTEXT_DATA={"data": 123}) + def test_error_clear_context(self): + pool = get_pool() + with tools.assert_raises(Exception): + with pool.next() as client: + client.service.method() + raise Exception("oops") + + destroy_pool() \ No newline at end of file diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..2a2335c --- /dev/null +++ b/tox.ini @@ -0,0 +1,51 @@ +# Tox (http://codespeak.net/~hpk/tox/) is a tool for running tests +# in multiple virtualenvs. This configuration file will run the +# test suite on all supported python versions. To use it, "pip install tox" +# and then run "tox" from this directory. +[flake8] +max-line-length=119 +exclude = .tox,testsettings*,docs/,bin/,include/,lib/,.git/,*/migrations/*,build/ + + + +[tox] +minversion=1.8.0 +envlist = + + py{27}-django{111}-nameko{211,212} + py{35,36,37}-django{111,20,21,22}-nameko{211,212} + isort + flake8 + +toxworkdir = {toxinidir}/.tox + +[testenv] +commands = + coverage run --source=django_nameko setup.py test + coverage report -m +deps = + coverage + django111: django >=1.11a1,<1.12 + django20: django >=2.0a1,<2.1 + django21: django >=2.1a1,<2.2 + django22: django >=2.2a1,<2.3 + nameko211: nameko >=2.11,<2.12 + nameko212: nameko >=2.12,<2.13 + + + + +[testenv:flake8] +basepython = python3 +usedevelop = false +deps = flake8 +changedir = {toxinidir} +commands = flake8 django_nameko + + +[testenv:isort] +basepython = python3 +usedevelop = false +deps = isort +changedir = {toxinidir} +commands = isort --recursive --check-only --diff django_nameko From 7debc263a83087c076b3e36fc10f776c94fbfb9c Mon Sep 17 00:00:00 2001 From: darius BERNARD Date: Tue, 25 Jun 2019 15:19:58 +0200 Subject: [PATCH 2/5] fix python3 compatiblity. fix isort and flake8 add in readme the contribution guideline (run the tests) add check for readme struct in tox -e package add classifier --- README.md | 18 ++++++++++++++++++ django_nameko/__init__.py | 4 +++- django_nameko/rpc.py | 18 ++++++++++-------- setup.py | 21 +++++++++++++++++++++ tests/__init__.py | 1 + tests/test_rpc.py | 16 +++++++++------- tests/test_running_services.py | 19 +++++++++++-------- tox.ini | 5 +++++ 8 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 tests/__init__.py diff --git a/README.md b/README.md index d08bbde..bdfdc1f 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,14 @@ Django wrapper for [Nameko] microservice framework. + +# support +tested with + +- python 2.7, 3.5, 3.6, 3.7 +- django 1.11, 2.0, 2.1, 2.2 +- nameko 2.11, 2.12 + # How to use ```python @@ -86,6 +94,16 @@ rpc.mailer.send_mail(bar='foo') ``` +# contribute + +to run the tests: +1. run a local rabbitmq +2. execute tox +```bash +docker run -d --rm -p 15672:15672 -p 5672:5672 -p 5671:5671 --name nameko-rabbitmq nameko/nameko-rabbitmq:3.6.6 +tox +``` + # Credits Thanks to guys who made an awesome [Nameko] framework. diff --git a/django_nameko/__init__.py b/django_nameko/__init__.py index 1c6923e..02d8503 100644 --- a/django_nameko/__init__.py +++ b/django_nameko/__init__.py @@ -1,4 +1,6 @@ -from rpc import ClusterRpcProxyPool, get_pool, destroy_pool +from __future__ import absolute_import, unicode_literals + +from .rpc import ClusterRpcProxyPool, destroy_pool, get_pool __all__ = [ 'ClusterRpcProxyPool', diff --git a/django_nameko/rpc.py b/django_nameko/rpc.py index b220168..84382ac 100644 --- a/django_nameko/rpc.py +++ b/django_nameko/rpc.py @@ -9,16 +9,17 @@ # from __future__ import absolute_import +import copy import logging import weakref from threading import Lock -from six.moves import xrange as xrange_six, queue as queue_six from amqp.exceptions import ConnectionError -from nameko.standalone.rpc import ClusterRpcProxy from django.conf import settings from django.core.exceptions import ImproperlyConfigured -import copy +from nameko.standalone.rpc import ClusterRpcProxy +from six.moves import queue as queue_six +from six.moves import xrange as xrange_six _logger = logging.getLogger(__name__) @@ -115,7 +116,7 @@ def __init__(self, config, pool_size=None, context_data=None, timeout=0): pool_size = getattr(settings, 'NAMEKO_POOL_SIZE', 4) if context_data is None: # keep this for compatiblity context_data = getattr(settings, 'NAMEKO_CONTEXT_DATA', None) - if timeout <= 0: # keep this for compatiblity + if timeout is None or timeout <= 0: # keep this for compatiblity timeout = getattr(settings, 'NAMEKO_TIMEOUT', None) self.config = copy.deepcopy(config) self.pool_size = pool_size @@ -146,8 +147,8 @@ def _clear(self): def _reload(self, num_of_worker=0): """ Reload into pool's queue with number of new worker - :param num_of_worker: - :return: + :param int num_of_worker: + :return: None """ if num_of_worker <= 0: num_of_worker = self.pool_size @@ -230,7 +231,8 @@ def get_pool(pool_name=None): nameko_global_pools = dict() if 'default' not in NAMEKO_CONFIG or 'AMQP_URL' not in NAMEKO_CONFIG['default']: raise ImproperlyConfigured( - 'NAMEKO_CONFIG must be specified and should include at least "default" config with "AMQP_URL"') + 'NAMEKO_CONFIG must be specified and should ' + 'include at least "default" config with "AMQP_URL"') default_config = NAMEKO_CONFIG['default'] # default_context_data = NAMEKO_CONFIG['default']['POOL'].get('CONTEXT_DATA', dict()) # multi_context_data = getattr(settings, 'NAMEKO_MULTI_CONTEXT_DATA', dict()) @@ -270,7 +272,7 @@ def get_pool(pool_name=None): if len(nameko_global_pools) == 0: # pragma: nocover # this code is unreachable, it's not passilbe to have a dict without a key in it. raise ImproperlyConfigured('NAMEKO_CONFIG must include at least 1 "default" config') - _pool = nameko_global_pools.get('default', nameko_global_pools.values()[0]) + _pool = nameko_global_pools.get('default', next(iter(nameko_global_pools.values()))) else: _pool = nameko_global_pools diff --git a/setup.py b/setup.py index 10855ab..0fb5b26 100755 --- a/setup.py +++ b/setup.py @@ -1,6 +1,11 @@ #!/usr/bin/env python2 import os +from os import path +this_directory = path.abspath(path.dirname(__file__)) +with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'django_nameko/VERSION')) as f: __version__ = f.read() @@ -10,6 +15,8 @@ name='django-nameko', version=__version__, description=' Django wrapper for nameko microservice framework.', + long_description=long_description, + long_description_content_type='text/markdown', url='http://github.com/and3rson/django-nameko', author='Andrew Dunai', author_email='andrew@dun.ai', @@ -24,4 +31,18 @@ ], test_suite='nose.collector', tests_require=['nose'], + classifiers=[ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU General Public License v3 (GPLv2)', + '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', + 'Operating System :: OS Independent', + 'Topic :: Software Development :: Libraries', + 'Topic :: Utilities', + ], ) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..40a96af --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/tests/test_rpc.py b/tests/test_rpc.py index 8e5c76d..2a87fde 100644 --- a/tests/test_rpc.py +++ b/tests/test_rpc.py @@ -1,12 +1,14 @@ +import logging + from amqp import ConnectionError -from mock import patch, call -from django_nameko import rpc, get_pool, destroy_pool -from nose import tools -from six.moves import queue as queue_six -from django.test.utils import override_settings from django.conf import settings from django.core.exceptions import ImproperlyConfigured -import logging +from django.test.utils import override_settings +from mock import call, patch +from six.moves import queue as queue_six + +from django_nameko import destroy_pool, get_pool, rpc +from nose import tools settings.configure() logger = logging.getLogger(__name__) @@ -230,4 +232,4 @@ def test_pool_call_rpc_out_of_with_statement(): client.bar.foo() assert call().start().bar.foo() in FakeClusterRpcProxy.mock_calls - destroy_pool() \ No newline at end of file + destroy_pool() diff --git a/tests/test_running_services.py b/tests/test_running_services.py index a87f7e1..704abde 100644 --- a/tests/test_running_services.py +++ b/tests/test_running_services.py @@ -1,19 +1,21 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import, unicode_literals + import logging +import os import socket import subprocess import time - import unittest from amqp import AccessRefused from django.conf import settings from django.test.utils import override_settings -from nameko.exceptions import UnknownService, MethodNotFound +from nameko.exceptions import MethodNotFound, UnknownService +from django_nameko import destroy_pool, get_pool from nose import tools - -from django_nameko import get_pool, destroy_pool +from tests.services import EchoService logger = logging.getLogger(__name__) @@ -35,7 +37,9 @@ def setUpClass(cls): run the service while in the context :return: """ - cls.runner = subprocess.Popen(('nameko', 'run', '--config', 'config.yaml', 'services')) + localdir = os.path.dirname(__file__) + config = os.path.join(localdir, 'config.yaml') + cls.runner = subprocess.Popen(('nameko', 'run', '--config', config, 'services'), cwd=localdir) time.sleep(1) @classmethod @@ -43,8 +47,7 @@ def tearDownClass(cls): cls.runner.kill() def test_echo_no_rpc(self): - import services - assert services.EchoService().echo(42) == (42,) + assert EchoService().echo(42) == (42,) @override_settings(NAMEKO_CONFIG={ 'AMQP_URI': 'amqp://guest:badpassword@localhost' @@ -111,4 +114,4 @@ def test_error_clear_context(self): client.service.method() raise Exception("oops") - destroy_pool() \ No newline at end of file + destroy_pool() diff --git a/tox.ini b/tox.ini index 2a2335c..5e1b9a0 100644 --- a/tox.ini +++ b/tox.ini @@ -33,7 +33,12 @@ deps = nameko212: nameko >=2.12,<2.13 +[testenv:package] +deps = twine +commands = + python setup.py sdist + twine check dist/* [testenv:flake8] basepython = python3 From bde9ad48a2ac09c00114e53490f9eb91c5c175f9 Mon Sep 17 00:00:00 2001 From: darius BERNARD Date: Tue, 25 Jun 2019 15:32:09 +0200 Subject: [PATCH 3/5] fix encoding error with python2 in setup.py --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 0fb5b26..5227a27 100755 --- a/setup.py +++ b/setup.py @@ -3,8 +3,8 @@ from os import path this_directory = path.abspath(path.dirname(__file__)) -with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f: - long_description = f.read() +with open(path.join(this_directory, 'README.md'), 'rb') as f: + long_description = f.read().decode('utf8') with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'django_nameko/VERSION')) as f: __version__ = f.read() From dc914a5ac793135caa5ca361ccad12e81690b39e Mon Sep 17 00:00:00 2001 From: darius BERNARD Date: Mon, 1 Jul 2019 12:20:51 +0200 Subject: [PATCH 4/5] prevent deploy from other repo (which will fail nonetheless) --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4bdbdaf..ccadc14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,8 @@ jobs: python: 2.7 script: skip install: skip + on: + repo: and3rson/django-nameko deploy: provider: pypi user: tranvietanh1991 From 8fe902fe634b49c515dfd1d2159f5b576cac0358 Mon Sep 17 00:00:00 2001 From: darius BERNARD Date: Mon, 1 Jul 2019 14:05:17 +0200 Subject: [PATCH 5/5] prevent deploy from other repo (which will fail nonetheless) fix: 1 --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ccadc14..c6f1c55 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,8 +38,7 @@ jobs: python: 2.7 script: skip install: skip - on: - repo: and3rson/django-nameko + if: repo = "and3rson/django-nameko" deploy: provider: pypi user: tranvietanh1991