diff --git a/.travis.yml b/.travis.yml index 36ec7ea3..907676c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ git: matrix: include: - - python: '2.7' - python: '3.6' after_success: - bash sonar-scanner.sh diff --git a/setup.py b/setup.py index a1372a5e..6470793e 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,6 @@ 'pyyaml>=5.1', 'future>=0.15.2', 'docopt>=0.6.2', - 'six>=1.10.0', 'enum34;python_version<"3.4"', 'futures>=3.0.5;python_version<"3"' ] diff --git a/splitio/api/telemetry.py b/splitio/api/telemetry.py index edf7f22d..395c0179 100644 --- a/splitio/api/telemetry.py +++ b/splitio/api/telemetry.py @@ -1,7 +1,6 @@ """Telemetry API Module.""" import logging -import six from future.utils import raise_from from splitio.api import APIException, headers_from_metadata @@ -39,7 +38,7 @@ def _build_latencies(latencies): """ return [ {'name': name, 'latencies': latencies_list} - for name, latencies_list in six.iteritems(latencies) + for name, latencies_list in latencies.items() ] def flush_latencies(self, latencies): @@ -77,7 +76,7 @@ def _build_gauges(gauges): """ return [ {'name': name, 'value': value} - for name, value in six.iteritems(gauges) + for name, value in gauges.items() ] def flush_gauges(self, gauges): @@ -115,7 +114,7 @@ def _build_counters(counters): """ return [ {'name': name, 'delta': value} - for name, value in six.iteritems(counters) + for name, value in counters.items() ] def flush_counters(self, counters): diff --git a/splitio/client/client.py b/splitio/client/client.py index 2d9b9169..1eb7cfcc 100644 --- a/splitio/client/client.py +++ b/splitio/client/client.py @@ -4,7 +4,6 @@ import logging import time -import six from splitio.engine.evaluator import Evaluator, CONTROL from splitio.engine.splitters import Splitter from splitio.models.impressions import Impression, Label @@ -309,7 +308,7 @@ def get_treatments(self, key, features, attributes=None): """ with_config = self._make_evaluations(key, features, attributes, 'get_treatments', self._METRIC_GET_TREATMENTS) - return {feature: result[0] for (feature, result) in six.iteritems(with_config)} + return {feature: result[0] for (feature, result) in with_config.items()} def _build_impression( # pylint: disable=too-many-arguments self, diff --git a/splitio/client/input_validator.py b/splitio/client/input_validator.py index 7d9598ea..7050c63b 100644 --- a/splitio/client/input_validator.py +++ b/splitio/client/input_validator.py @@ -7,8 +7,6 @@ import re import math -import six - from splitio.api import APIException from splitio.client.key import Key from splitio.engine.evaluator import CONTROL @@ -53,7 +51,7 @@ def _check_is_string(value, name, operation): :return: The result of validation :rtype: True|False """ - if isinstance(value, six.string_types) is False: + if isinstance(value, str) is False: _LOGGER.error( '%s: you passed an invalid %s, %s must be a non-empty string.', operation, name, name @@ -121,7 +119,7 @@ def _check_can_convert(value, name, operation): :return: The result of validation :rtype: None|string """ - if isinstance(value, six.string_types): + if isinstance(value, str): return value else: # check whether if isnan and isinf are really necessary @@ -173,7 +171,7 @@ def _check_valid_object_key(key, name, operation): '%s: you passed a null %s, %s must be a non-empty string.', operation, name, name) return None - if isinstance(key, six.string_types): + if isinstance(key, str): if not _check_string_not_empty(key, name, operation): return None key_str = _check_can_convert(key, name, operation) @@ -515,8 +513,8 @@ def valid_properties(properties): valid_properties = dict() - for property, element in six.iteritems(properties): - if not isinstance(property, six.string_types): # Exclude property if is not string + for property, element in properties.items(): + if not isinstance(property, str): # Exclude property if is not string continue valid_properties[property] = None @@ -525,14 +523,14 @@ def valid_properties(properties): if element is None: continue - if not isinstance(element, six.string_types) and not isinstance(element, Number) \ + if not isinstance(element, str) and not isinstance(element, Number) \ and not isinstance(element, bool): _LOGGER.warning('Property %s is of invalid type. Setting value to None', element) element = None valid_properties[property] = element - if isinstance(element, six.string_types): + if isinstance(element, str): size += len(element) if size > MAX_PROPERTIES_LENGTH_BYTES: diff --git a/splitio/client/listener.py b/splitio/client/listener.py index 1ab61e30..7ab09e99 100644 --- a/splitio/client/listener.py +++ b/splitio/client/listener.py @@ -2,7 +2,6 @@ import abc -from six import add_metaclass from future.utils import raise_from @@ -56,8 +55,7 @@ def log_impression(self, impression, attributes=None): exc ) -@add_metaclass(abc.ABCMeta) #pylint: disable=too-few-public-methods -class ImpressionListener(object): +class ImpressionListener(object, metaclass=abc.ABCMeta): """Impression listener interface.""" @abc.abstractmethod diff --git a/splitio/engine/evaluator.py b/splitio/engine/evaluator.py index d31e94bd..489c9ba2 100644 --- a/splitio/engine/evaluator.py +++ b/splitio/engine/evaluator.py @@ -1,6 +1,5 @@ """Split evaluator module.""" import logging -import six from splitio.models.grammar.condition import ConditionType from splitio.models.impressions import Label @@ -135,7 +134,7 @@ def evaluate_features(self, features, matching_key, bucketing_key, attributes=No return { feature: self._evaluate_treatment(feature, matching_key, bucketing_key, attributes, split) - for (feature, split) in six.iteritems(self._split_storage.fetch_many(features)) + for (feature, split) in self._split_storage.fetch_many(features).items() } def _get_treatment_for_split(self, split, matching_key, bucketing_key, attributes=None): diff --git a/splitio/engine/hashfns/murmur3py.py b/splitio/engine/hashfns/murmur3py.py index 8f9028af..a768a872 100644 --- a/splitio/engine/hashfns/murmur3py.py +++ b/splitio/engine/hashfns/murmur3py.py @@ -3,9 +3,6 @@ from __future__ import absolute_import, division, print_function, \ unicode_literals -from six.moves import range - - def murmur32_py(key, seed=0x0): """ Pure python implementation of murmur32 hash. diff --git a/splitio/engine/impressions.py b/splitio/engine/impressions.py index 91b2eecf..a1184867 100644 --- a/splitio/engine/impressions.py +++ b/splitio/engine/impressions.py @@ -4,8 +4,6 @@ from collections import defaultdict, namedtuple from enum import Enum -import six - from splitio.models.impressions import Impression from splitio.engine.hashfns import murmur_128 from splitio.engine.cache.lru import SimpleLruCache @@ -151,7 +149,7 @@ def pop_all(self): self._data = defaultdict(lambda: 0) return [Counter.CountPerFeature(k.feature, k.timeframe, v) - for (k, v) in six.iteritems(old)] + for (k, v) in old.items()] class Manager(object): # pylint:disable=too-few-public-methods diff --git a/splitio/models/grammar/condition.py b/splitio/models/grammar/condition.py index 961d5f54..d7ef66a4 100644 --- a/splitio/models/grammar/condition.py +++ b/splitio/models/grammar/condition.py @@ -2,7 +2,6 @@ from enum import Enum from future.utils import python_2_unicode_compatible -import six from splitio.models.grammar import matchers from splitio.models.grammar import partitions @@ -103,7 +102,7 @@ def to_json(self): 'label': self._label, 'matcherGroup': { 'combiner': next( - (k, v) for k, v in six.iteritems(_MATCHER_COMBINERS) if v == self._combiner + (k, v) for k, v in _MATCHER_COMBINERS.items() if v == self._combiner )[0], 'matchers': [m.to_json() for m in self.matchers] }, diff --git a/splitio/models/grammar/matchers/base.py b/splitio/models/grammar/matchers/base.py index d7d818d9..0040d700 100644 --- a/splitio/models/grammar/matchers/base.py +++ b/splitio/models/grammar/matchers/base.py @@ -1,13 +1,10 @@ """Abstract matcher module.""" import abc -from six import add_metaclass - from splitio.client.key import Key -@add_metaclass(abc.ABCMeta) -class Matcher(object): +class Matcher(object, metaclass=abc.ABCMeta): """Matcher abstract class.""" def __init__(self, raw_matcher): diff --git a/splitio/models/grammar/matchers/misc.py b/splitio/models/grammar/matchers/misc.py index 335160ed..3c7b1713 100644 --- a/splitio/models/grammar/matchers/misc.py +++ b/splitio/models/grammar/matchers/misc.py @@ -4,7 +4,6 @@ import json from future.utils import python_2_unicode_compatible -from six import string_types from splitio.models.grammar.matchers.base import Matcher @@ -85,7 +84,7 @@ def _match(self, key, attributes=None, context=None): return False if isinstance(matching_data, bool): decoded = matching_data - elif isinstance(matching_data, string_types): + elif isinstance(matching_data, str): try: decoded = json.loads(matching_data.lower()) if not isinstance(decoded, bool): diff --git a/splitio/models/grammar/matchers/numeric.py b/splitio/models/grammar/matchers/numeric.py index fa63a8ea..b912ff7e 100644 --- a/splitio/models/grammar/matchers/numeric.py +++ b/splitio/models/grammar/matchers/numeric.py @@ -3,7 +3,6 @@ import logging from future.utils import python_2_unicode_compatible -from six import string_types from splitio.models.grammar.matchers.base import Matcher from splitio.models import datatypes @@ -32,7 +31,7 @@ def ensure_int(cls, data): if isinstance(data, numbers.Integral) and not isinstance(data, bool): return data - if not isinstance(data, string_types): + if not isinstance(data, str): _LOGGER.error('Cannot convert %s to int. Failing.', type(data)) return None diff --git a/splitio/models/grammar/matchers/string.py b/splitio/models/grammar/matchers/string.py index 6043bb09..80f62de9 100644 --- a/splitio/models/grammar/matchers/string.py +++ b/splitio/models/grammar/matchers/string.py @@ -6,7 +6,6 @@ import json import re from future.utils import python_2_unicode_compatible -from six import string_types from splitio.models.grammar.matchers.base import Matcher @@ -31,7 +30,7 @@ def ensure_string(cls, data): if data is None: # Failed to fetch attribute. no need to convert. return None - if isinstance(data, string_types): + if isinstance(data, str): return data _LOGGER.warning( @@ -120,7 +119,7 @@ def _match(self, key, attributes=None, context=None): matching_data = Sanitizer.ensure_string(self._get_matcher_input(key, attributes)) if matching_data is None: return False - return (isinstance(key, string_types) and + return (isinstance(key, str) and any(matching_data.startswith(s) for s in self._whitelist)) def _add_matcher_specific_properties_to_json(self): @@ -168,7 +167,7 @@ def _match(self, key, attributes=None, context=None): matching_data = Sanitizer.ensure_string(self._get_matcher_input(key, attributes)) if matching_data is None: return False - return (isinstance(key, string_types) and + return (isinstance(key, str) and any(matching_data.endswith(s) for s in self._whitelist)) def _add_matcher_specific_properties_to_json(self): @@ -216,7 +215,7 @@ def _match(self, key, attributes=None, context=None): matching_data = Sanitizer.ensure_string(self._get_matcher_input(key, attributes)) if matching_data is None: return False - return (isinstance(matching_data, string_types) and + return (isinstance(matching_data, str) and any(s in matching_data for s in self._whitelist)) def _add_matcher_specific_properties_to_json(self): diff --git a/splitio/push/parser.py b/splitio/push/parser.py index fddd0a39..9b51097a 100644 --- a/splitio/push/parser.py +++ b/splitio/push/parser.py @@ -4,7 +4,6 @@ from enum import Enum from future.utils import raise_from -from six import add_metaclass from splitio.util.decorators import abstract_property from splitio.util import utctime_ms @@ -51,12 +50,11 @@ class EventParsingException(Exception): pass -@add_metaclass(abc.ABCMeta) #pylint:disable=too-few-public-methods -class BaseEvent(object): +class BaseEvent(object, metaclass=abc.ABCMeta): """Base event that reqiures subclasses tu have a type.""" @abstract_property - def event_type(self): #pylint:disable=no-self-use + def event_type(self): # pylint:disable=no-self-use """ Return the event type. @@ -92,7 +90,7 @@ def __init__(self, code, status_code, message, href): self._timestamp = utctime_ms() @property - def event_type(self): #pylint:disable=no-self-use + def event_type(self): # pylint:disable=no-self-use """ Return the event type. @@ -160,7 +158,6 @@ def should_be_ignored(self): """ return self._code < 40000 or self._code > 49999 - def is_retryable(self): """ Return whether this error is retryable or not. @@ -176,8 +173,7 @@ def __str__(self): (self.code, self.status_code, self.message, self.href) -@add_metaclass(abc.ABCMeta) -class BaseMessage(BaseEvent): +class BaseMessage(BaseEvent, metaclass=abc.ABCMeta): """Message type event.""" def __init__(self, channel, timestamp): @@ -282,8 +278,7 @@ def __str__(self): return "Occupancy - channel=%s, publishers=%d" % (self.channel, self.publishers) -@add_metaclass(abc.ABCMeta) -class BaseUpdate(BaseMessage): +class BaseUpdate(BaseMessage, metaclass=abc.ABCMeta): """Split data update notification.""" def __init__(self, channel, timestamp, change_number): diff --git a/splitio/push/processor.py b/splitio/push/processor.py index 189e7a9a..39329b6b 100644 --- a/splitio/push/processor.py +++ b/splitio/push/processor.py @@ -2,8 +2,6 @@ from queue import Queue -from six import raise_from - from splitio.push.parser import UpdateType from splitio.push.splitworker import SplitWorker from splitio.push.segmentworker import SegmentWorker @@ -83,7 +81,7 @@ def handle(self, event): try: handle = self._handlers[event.update_type] except KeyError as exc: - raise_from('no handler for notification type: %s' % event.update_type, exc) + raise Exception('no handler for notification type: %s' % event.update_type) from exc handle(event) diff --git a/splitio/push/splitsse.py b/splitio/push/splitsse.py index 3f3236ed..e6a60324 100644 --- a/splitio/push/splitsse.py +++ b/splitio/push/splitsse.py @@ -2,7 +2,6 @@ import logging import threading from enum import Enum -import six from splitio.push.sse import SSEClient, SSE_EVENT_ERROR from splitio.util.threadutil import EventGroup @@ -75,9 +74,9 @@ def _format_channels(channels): :returns: channels as a list of strings. :rtype: list[str] """ - regular = [k for (k, v) in six.iteritems(channels) if v == ['subscribe']] + regular = [k for (k, v) in channels.items() if v == ['subscribe']] occupancy = ['[?occupancy=metrics.publishers]' + k - for (k, v) in six.iteritems(channels) + for (k, v) in channels.items() if 'channel-metadata:publishers' in v] return regular + occupancy diff --git a/splitio/push/status_tracker.py b/splitio/push/status_tracker.py index 170b3084..6acd5d95 100644 --- a/splitio/push/status_tracker.py +++ b/splitio/push/status_tracker.py @@ -1,7 +1,6 @@ """NotificationManagerKeeper implementation.""" from enum import Enum import logging -import six from splitio.push.parser import ControlType @@ -195,4 +194,4 @@ def _occupancy_ok(self): :returns: True if publisher count is enough. False otherwise :rtype: bool """ - return any(count > 0 for (chan, count) in six.iteritems(self._publishers)) + return any(count > 0 for (chan, count) in self._publishers.items()) diff --git a/splitio/recorder/recorder.py b/splitio/recorder/recorder.py index 7583e2e5..c009e1eb 100644 --- a/splitio/recorder/recorder.py +++ b/splitio/recorder/recorder.py @@ -3,14 +3,10 @@ import logging -from six import add_metaclass - - _LOGGER = logging.getLogger(__name__) -@add_metaclass(abc.ABCMeta) -class StatsRecorder(object): +class StatsRecorder(object, metaclass=abc.ABCMeta): """StatsRecorder interface.""" @abc.abstractmethod diff --git a/splitio/storage/__init__.py b/splitio/storage/__init__.py index 10f2ade3..a40bc155 100644 --- a/splitio/storage/__init__.py +++ b/splitio/storage/__init__.py @@ -3,11 +3,8 @@ import abc -from six import add_metaclass - -@add_metaclass(abc.ABCMeta) -class SplitStorage(object): +class SplitStorage(object, metaclass=abc.ABCMeta): """Split storage interface implemented as an abstract class.""" @abc.abstractmethod @@ -133,8 +130,7 @@ def kill_locally(self, split_name, default_treatment, change_number): pass -@add_metaclass(abc.ABCMeta) -class SegmentStorage(object): +class SegmentStorage(object, metaclass=abc.ABCMeta): """Segment storage interface implemented as an abstract class.""" @abc.abstractmethod @@ -213,8 +209,7 @@ def segment_contains(self, segment_name, key): pass -@add_metaclass(abc.ABCMeta) -class ImpressionStorage(object): +class ImpressionStorage(object, metaclass=abc.ABCMeta): """Impressions storage interface.""" @abc.abstractmethod @@ -245,8 +240,7 @@ def clear(self): pass -@add_metaclass(abc.ABCMeta) -class ImpressionPipelinedStorage(object): +class ImpressionPipelinedStorage(object, metaclass=abc.ABCMeta): """Impression Pipelined Storage interface.""" @abc.abstractmethod @@ -262,8 +256,7 @@ def add_impressions_to_pipe(self, impressions, pipe): pass -@add_metaclass(abc.ABCMeta) -class EventStorage(object): +class EventStorage(object, metaclass=abc.ABCMeta): """Events storage interface.""" @abc.abstractmethod @@ -294,8 +287,7 @@ def clear(self): pass -@add_metaclass(abc.ABCMeta) -class TelemetryStorage(object): +class TelemetryStorage(object, metaclass=abc.ABCMeta): """Telemetry storage interface.""" @abc.abstractmethod @@ -368,8 +360,7 @@ def clear(self): pass -@add_metaclass(abc.ABCMeta) -class TelemetryPipelinedStorage(object): +class TelemetryPipelinedStorage(object, metaclass=abc.ABCMeta): """Telemetry Pipelined Storage interface.""" @abc.abstractmethod diff --git a/splitio/storage/adapters/cache_trait.py b/splitio/storage/adapters/cache_trait.py index 840befc8..d3db3b67 100644 --- a/splitio/storage/adapters/cache_trait.py +++ b/splitio/storage/adapters/cache_trait.py @@ -4,8 +4,6 @@ import time from functools import update_wrapper -import six - DEFAULT_MAX_AGE = 5 DEFAULT_MAX_SIZE = 100 @@ -90,7 +88,7 @@ def remove_expired(self): """Remove expired elements.""" with self._lock: self._data = { - key: value for (key, value) in six.iteritems(self._data) + key: value for (key, value) in self._data.items() if not self._is_expired(value) } diff --git a/splitio/storage/adapters/redis.py b/splitio/storage/adapters/redis.py index 4052cf0c..19c3a3be 100644 --- a/splitio/storage/adapters/redis.py +++ b/splitio/storage/adapters/redis.py @@ -3,7 +3,6 @@ unicode_literals from builtins import str -from six import string_types, binary_type from future.utils import raise_from try: @@ -78,15 +77,15 @@ def add_prefix(self, k): :returns: Key(s) with prefix if applicable """ if self._prefix: - if isinstance(k, string_types): + if isinstance(k, str): return '{prefix}.{key}'.format(prefix=self._prefix, key=k) elif isinstance(k, list) and k: - if isinstance(k[0], binary_type): + if isinstance(k[0], bytes): return [ '{prefix}.{key}'.format(prefix=self._prefix, key=key.decode("utf8")) for key in k ] - elif isinstance(k[0], string_types): + elif isinstance(k[0], str): return [ '{prefix}.{key}'.format(prefix=self._prefix, key=key) for key in k @@ -109,7 +108,7 @@ def remove_prefix(self, k): :returns: prefix-less key(s) """ if self._prefix: - if isinstance(k, string_types): + if isinstance(k, str): return k[len(self._prefix)+1:] elif isinstance(k, list): return [key[len(self._prefix)+1:] for key in k] diff --git a/splitio/storage/adapters/util.py b/splitio/storage/adapters/util.py index d1dc9c19..f8602602 100644 --- a/splitio/storage/adapters/util.py +++ b/splitio/storage/adapters/util.py @@ -1,7 +1,5 @@ """Custom utilities.""" -import six - class DynamicDecorator(object): #pylint: disable=too-few-public-methods """ @@ -82,7 +80,7 @@ def __init__(self, *args, **kwargs): positional = [pos_func(*args, **kwargs) for pos_func in positional_args_lambdas] keyword = { key: func(*args, **kwargs) - for (key, func) in six.iteritems(keyword_args_lambdas) + for (key, func) in keyword_args_lambdas.items() } # call original class constructor diff --git a/splitio/storage/inmemmory.py b/splitio/storage/inmemmory.py index 344af7f3..e5fedc63 100644 --- a/splitio/storage/inmemmory.py +++ b/splitio/storage/inmemmory.py @@ -3,9 +3,9 @@ import logging import threading +import queue from collections import Counter -from six.moves import queue from splitio.models.segments import Segment from splitio.storage import SplitStorage, SegmentStorage, ImpressionStorage, EventStorage, \ TelemetryStorage diff --git a/splitio/sync/event.py b/splitio/sync/event.py index 44fc0d82..06c944b0 100644 --- a/splitio/sync/event.py +++ b/splitio/sync/event.py @@ -1,5 +1,5 @@ import logging -from six.moves import queue +import queue from splitio.api import APIException diff --git a/splitio/sync/impression.py b/splitio/sync/impression.py index a46ef2f6..51505d1c 100644 --- a/splitio/sync/impression.py +++ b/splitio/sync/impression.py @@ -1,5 +1,5 @@ import logging -from six.moves import queue +import queue from splitio.api import APIException diff --git a/splitio/sync/synchronizer.py b/splitio/sync/synchronizer.py index 5e70d84a..b27e9146 100644 --- a/splitio/sync/synchronizer.py +++ b/splitio/sync/synchronizer.py @@ -4,7 +4,6 @@ import logging import threading -from six import add_metaclass from future.utils import raise_from from splitio.api import APIException @@ -130,8 +129,7 @@ def impressions_count_task(self): return self._impressions_count_task -@add_metaclass(abc.ABCMeta) -class BaseSynchronizer(object): +class BaseSynchronizer(object, metaclass=abc.ABCMeta): """Synchronizer interface.""" @abc.abstractmethod diff --git a/splitio/sync/telemetry.py b/splitio/sync/telemetry.py index 82a64a37..f0e48613 100644 --- a/splitio/sync/telemetry.py +++ b/splitio/sync/telemetry.py @@ -1,5 +1,4 @@ import logging -from six.moves import queue from splitio.api import APIException diff --git a/splitio/tasks/events_sync.py b/splitio/tasks/events_sync.py index 4b13a351..45d426cd 100644 --- a/splitio/tasks/events_sync.py +++ b/splitio/tasks/events_sync.py @@ -4,8 +4,6 @@ import logging -from six.moves import queue -from splitio.api import APIException from splitio.tasks import BaseSynchronizationTask from splitio.tasks.util.asynctask import AsyncTask diff --git a/splitio/tasks/impressions_sync.py b/splitio/tasks/impressions_sync.py index ea9c07ca..9ffaa37b 100644 --- a/splitio/tasks/impressions_sync.py +++ b/splitio/tasks/impressions_sync.py @@ -4,8 +4,6 @@ import logging -from six.moves import queue - from splitio.tasks import BaseSynchronizationTask from splitio.tasks.util.asynctask import AsyncTask diff --git a/splitio/tasks/util/asynctask.py b/splitio/tasks/util/asynctask.py index cbeb09ac..63a9f3fc 100644 --- a/splitio/tasks/util/asynctask.py +++ b/splitio/tasks/util/asynctask.py @@ -1,8 +1,7 @@ """Asynchronous tasks that can be controlled.""" import threading import logging - -from six.moves import queue +import queue __TASK_STOP__ = 0 diff --git a/splitio/tasks/util/workerpool.py b/splitio/tasks/util/workerpool.py index ee9c13ca..32957ee6 100644 --- a/splitio/tasks/util/workerpool.py +++ b/splitio/tasks/util/workerpool.py @@ -2,7 +2,7 @@ import logging from threading import Thread, Event -from six.moves import queue +import queue _LOGGER = logging.getLogger(__name__) diff --git a/tests/engine/test_hashfns.py b/tests/engine/test_hashfns.py index c4f87592..36252fc7 100644 --- a/tests/engine/test_hashfns.py +++ b/tests/engine/test_hashfns.py @@ -5,8 +5,6 @@ import os import pytest -import six - from splitio.engine import hashfns, splitters from splitio.engine.hashfns.murmur3py import hash128_x64 as murmur3_128_py from splitio.models import splits