diff --git a/.travis.yml b/.travis.yml index 90df19d..90f4769 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,8 @@ -language: python +language: minimal -services: - - redis-server +install: + - docker-compose build -python: - - "2.7" - -install: python setup.py develop - -script: make test +script: + - docker-compose up -d + - docker-compose exec python make diff --git a/bin/test b/bin/test new file mode 100755 index 0000000..7c79b19 --- /dev/null +++ b/bin/test @@ -0,0 +1,7 @@ +#!/bin/bash +if [[ "$@" ]] +then + exec docker-compose exec python python setup.py nosetests --where "$@" +else + exec docker-compose exec python python setup.py nosetests +fi diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..84459e1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3' + +services: + + python: + image: python:3 + command: sleep infinity + working_dir: /src + volumes: + - .:/src + + redis: + image: redis diff --git a/gutter/client/__init__.py b/gutter/client/__init__.py index c79b1fe..be881d9 100644 --- a/gutter/client/__init__.py +++ b/gutter/client/__init__.py @@ -8,5 +8,5 @@ try: VERSION = __import__('pkg_resources').get_distribution('gutter').version -except Exception, e: +except Exception: VERSION = 'unknown' diff --git a/gutter/client/arguments/__init__.py b/gutter/client/arguments/__init__.py index b898fb5..94691c9 100644 --- a/gutter/client/arguments/__init__.py +++ b/gutter/client/arguments/__init__.py @@ -1,7 +1,8 @@ from functools import partial -from base import Container, argument # noqa -import variables +from . import variables +from .base import Container, argument # noqa + Value = partial(argument, variables.Value) Boolean = partial(argument, variables.Boolean) diff --git a/gutter/client/arguments/base.py b/gutter/client/arguments/base.py index 1388c78..abb7b5f 100644 --- a/gutter/client/arguments/base.py +++ b/gutter/client/arguments/base.py @@ -1,5 +1,3 @@ -from types import NoneType - class classproperty(object): @@ -13,7 +11,7 @@ def __get__(self, instance, owner): class argument(object): def __init__(self, variable, getter): - if issubclass(type(getter), basestring): + if issubclass(type(getter), str): self.getter = lambda self: getattr(self.input, getter) else: self.getter = getter @@ -51,7 +49,7 @@ class Container(object): the specified input. """ - COMPATIBLE_TYPE = NoneType + COMPATIBLE_TYPE = type(None) def __init__(self, inpt): self.input = inpt diff --git a/gutter/client/models.py b/gutter/client/models.py index 954b9b1..d755143 100644 --- a/gutter/client/models.py +++ b/gutter/client/models.py @@ -12,7 +12,6 @@ import threading from collections import defaultdict from functools import partial -from itertools import ifilter # External Libraries from gutter.client import signals @@ -187,7 +186,7 @@ def enabled_for(self, inpt): return signal_decorated(result) def enabled_for_all(self, *inpts): - foo = ifilter( + foo = filter( lambda x: x is not None, (self.enabled_for(inpt) for inpt in inpts) ) @@ -407,7 +406,7 @@ def __init__( if namespace is None: namespace = self.default_namespace - elif isinstance(namespace, basestring): + elif isinstance(namespace, str): namespace = [namespace] self.storage = storage @@ -437,7 +436,7 @@ def switches(self): List of all switches currently registered. """ results = [ - switch for name, switch in self.storage.iteritems() + switch for name, switch in self.storage.items() if name.startswith(self.__joined_namespace) ] diff --git a/gutter/client/operators/comparable.py b/gutter/client/operators/comparable.py index cd59ffc..b843ef0 100644 --- a/gutter/client/operators/comparable.py +++ b/gutter/client/operators/comparable.py @@ -24,7 +24,10 @@ class Between(Base): arguments = ('lower_limit', 'upper_limit') def applies_to(self, argument): - return argument > self.lower_limit and argument < self.upper_limit + try: + return argument > self.lower_limit and argument < self.upper_limit + except TypeError: + return False def __str__(self): return 'between "%s" and "%s"' % (self.lower_limit, self.upper_limit) diff --git a/setup.py b/setup.py index 31ed838..cf899ac 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ from setuptools import setup tests_require = [ - 'nose', 'exam', 'mock', 'nose-performance', 'django', 'redis', 'unittest2' + 'nose', 'exam', 'mock', 'nose-performance', 'django==1.7', 'redis', 'unittest2' ] setup_requires = [] @@ -36,7 +36,7 @@ packages=find_packages(exclude=["tests"]), zip_safe=False, install_requires=[ - 'durabledict>=0.9.0', + 'durabledict==0.9.4', 'jsonpickle', 'werkzeug', ], diff --git a/tests/test_integration.py b/tests/test_integration.py index 4843c26..85de008 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -424,7 +424,7 @@ def test_concent_with_different_arguments(self): class TestIntegrationWithRedis(TestIntegration): @fixture def redis(self): - return Redis(db=15) + return Redis(host='redis', db=15) @after def flush_redis(self): diff --git a/tests/test_models.py b/tests/test_models.py index c24ca93..7821020 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -471,7 +471,7 @@ def test_update_tells_manager_to_register_with_switch_updated_signal(self): @mock.patch('gutter.client.signals.switch_updated') def test_update_calls_the_switch_updateed_signal(self, signal): self.manager.update(self.switch) - signal.call.assert_call_once() + signal.call.assert_called_once_with(self.switch) def test_manager_resets_switch_dirty_tracking(self): self.manager.update(self.switch) diff --git a/tests/test_operators.py b/tests/test_operators.py index cd244e3..435111f 100644 --- a/tests/test_operators.py +++ b/tests/test_operators.py @@ -120,6 +120,8 @@ def test_applies_to_if_between_lower_and_upper_bound(self): ok_(self.operator.applies_to(2)) ok_(self.operator.applies_to(99)) ok_(self.operator.applies_to(100) is False) + + def test_applies_to_if_wrong_type(self): ok_(self.operator.applies_to('steve') is False) def test_applies_to_works_with_any_comparable(self): @@ -269,7 +271,7 @@ def __nonzero__(self): def successful_runs(self, number): runs = map(self.operator.applies_to, range(1000)) - return len(filter(bool, runs)) + return len(list(filter(bool, runs))) class PercentageTest(PercentTest, unittest2.TestCase): diff --git a/tests/test_registry.py b/tests/test_registry.py index f85f22f..df601dd 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -15,7 +15,7 @@ from gutter.client import registry def all_operators_in(module): - for _, obj in vars(module).iteritems(): + for _, obj in vars(module).items(): try: if issubclass(obj, Base) and obj is not Base: yield obj diff --git a/tests/test_signals.py b/tests/test_signals.py index 749b788..f83c3fd 100644 --- a/tests/test_signals.py +++ b/tests/test_signals.py @@ -25,7 +25,7 @@ def test_connect_raises_exceptiion_if_argument_is_not_callable(self): def tests_callback_called_when_signal_is_called(self): self.signal_with_callback.call() - self.callback.assert_called_once() + self.callback.assert_called_once_with() def test_signal_passes_args_along_to_callback(self): self.signal_with_callback.call(1, 2.0, kw='args') diff --git a/tests/test_singleton.py b/tests/test_singleton.py index 28a6464..e261176 100644 --- a/tests/test_singleton.py +++ b/tests/test_singleton.py @@ -1,6 +1,7 @@ +import mock import unittest2 +from importlib import reload from nose.tools import * -import mock from gutter.client.settings import manager import gutter.client.models @@ -63,4 +64,4 @@ def test_can_change_settings_before_importing(self): def test_uses_default_manager_if_set(self): manager.default = mock.sentinel.default_manager reload(gutter.client.singleton) - eq_(gutter.client.singleton.gutter, mock.sentinel.default_manager) \ No newline at end of file + eq_(gutter.client.singleton.gutter, mock.sentinel.default_manager)