Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This SDK is designed to work with Split, the platform for controlled rollouts, w
[![Twitter Follow](https://img.shields.io/twitter/follow/splitsoftware.svg?style=social&label=Follow&maxAge=1529000)](https://twitter.com/intent/follow?screen_name=splitsoftware)

## Compatibility
This SDK is compatible with **Python 2.7 and higher**.
This SDK is compatible with **Python 3 and higher**.

## Getting started
Below is a simple example that describes the instantiation and most basic usage of our SDK:
Expand Down
2 changes: 1 addition & 1 deletion doc/source/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This project provides Python programs access to the `Split.io <http://split.io/>
Installation and Requirements
-----------------------------

``splitio_client`` supports both Python 2 (2.7 or later) and Python 3 (3.3 or later). Stable versions can be installed from `PyPI <https://pypi.python.org>`_ using pip: ::
``splitio_client`` supports Python 3 (3.3 or later). Stable versions can be installed from `PyPI <https://pypi.python.org>`_ using pip: ::

pip install splitio_client

Expand Down
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@

TESTS_REQUIRES = [
'flake8',
'pytest<=4.6', # for deprecated python versions: https://docs.pytest.org/en/latest/py27-py34-deprecation.html
'pytest-mock==2.0.0',
'pytest>=6.2.3',
'pytest-mock>=3.5.1',
'coverage',
'pytest-cov',
'mock;python_version<"3"'
]

INSTALL_REQUIRES = [
Expand Down
40 changes: 5 additions & 35 deletions splitio/push/sse.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
"""Low-level SSE Client."""
import logging
import socket
import sys
from collections import namedtuple

try: # try to import python3 names. fallback to python2
from http.client import HTTPConnection, HTTPSConnection
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
from httplib import HTTPConnection, HTTPSConnection
from http.client import HTTPConnection, HTTPSConnection
from urllib.parse import urlparse


_LOGGER = logging.getLogger(__name__)
Expand All @@ -23,30 +17,6 @@


__ENDING_CHARS = set(['\n', ''])
def __httpresponse_readline_py2(response):
"""
Hacky `readline` implementation to be used with chunked transfers in python2.

This makes syscalls in a loop, so not particularly efficient. Migrate to py3 now!

:param response: HTTPConnection's response after a .request() call
:type response: httplib.HTTPResponse

:returns: a string with the read line
:rtype: str
"""
buf = []
while True:
read = response.read(1)
buf.append(read)
if read in __ENDING_CHARS:
break

return ''.join(buf)


_http_response_readline = (__httpresponse_readline_py2 if sys.version_info.major <= 2 #pylint:disable=invalid-name
else lambda response: response.readline())


class EventBuilder(object):
Expand Down Expand Up @@ -105,7 +75,7 @@ def _read_events(self):
response = self._conn.getresponse()
event_builder = EventBuilder()
while True:
line = _http_response_readline(response)
line = response.readline()
if line is None or len(line) <= 0: # connection ended
break
elif line.startswith(b':'): # comment. Skip
Expand All @@ -118,7 +88,7 @@ def _read_events(self):
event_builder = EventBuilder()
else:
event_builder.process_line(line)
except Exception: #pylint:disable=broad-except
except Exception: # pylint:disable=broad-except
_LOGGER.debug('sse connection ended.')
_LOGGER.debug('stack trace: ', exc_info=True)
finally:
Expand All @@ -127,7 +97,7 @@ def _read_events(self):

return self._shutdown_requested

def start(self, url, extra_headers=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): #pylint:disable=protected-access
def start(self, url, extra_headers=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): # pylint:disable=protected-access
"""
Connect and start listening for events.

Expand Down
8 changes: 1 addition & 7 deletions splitio/storage/adapters/redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,7 @@ def add_prefix(self, k):
"""
Add a prefix to the contents of k.

'k' may be:
- a single key (of type string or unicode in python2, or type string
in python 3. In which case we simple add a prefix with a dot.
- a list, in which the prefix is applied to element.
If no user prefix is stored, the key/list of keys will be returned as is

:param k: single (string) or list of (list) keys.
:param k: single (string).
:returns: Key(s) with prefix if applicable
"""
if self._prefix:
Expand Down
8 changes: 3 additions & 5 deletions splitio/util/decorators.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
"""Misc decorators."""
import sys
from abc import abstractmethod

from abc import abstractmethod, abstractproperty

def abstract_property(func):
"""
Python2/3 compatible abstract property decorator.
Abstract property decorator.

:param func: method to decorate
:type func: callable

:returns: decorated function
:rtype: callable
"""
return (property(abstractmethod(func)) if sys.version_info > (3, 3)
else abstractproperty(func))
return property(abstractmethod(func))
15 changes: 5 additions & 10 deletions splitio/util/threadutil.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
"""Threading utilities."""
from inspect import isclass
import threading


# python2 workaround
_EventClass = threading.Event if isclass(threading.Event) else threading._Event #pylint:disable=protected-access,invalid-name
from threading import Event, Condition


class EventGroup(object):
"""EventGroup that can be waited with an OR condition."""

class Event(_EventClass): #pylint:disable=too-few-public-methods
class Event(Event): # pylint:disable=too-few-public-methods
"""Threading event meant to be used in an group."""

def __init__(self, shared_condition):
Expand All @@ -20,18 +15,18 @@ def __init__(self, shared_condition):
:param shared_condition: shared condition varaible.
:type shared_condition: threading.Condition
"""
_EventClass.__init__(self)
Event.__init__(self)
self._shared_cond = shared_condition

def set(self):
"""Set the event."""
_EventClass.set(self)
Event.set(self)
with self._shared_cond:
self._shared_cond.notify()

def __init__(self):
"""Construct an event group."""
self._cond = threading.Condition()
self._cond = Condition()

def make_event(self):
"""
Expand Down
6 changes: 1 addition & 5 deletions tests/integration/test_streaming_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@
from queue import Queue
from splitio.client.factory import get_factory
from tests.helpers.mockserver import SSEMockServer, SplitMockServer

try: # try to import python3 names. fallback to python2
from urllib.parse import parse_qs
except ImportError:
from urlparse import parse_qs
from urllib.parse import parse_qs


class StreamingIntegrationTests(object):
Expand Down
1 change: 0 additions & 1 deletion tests/storage/test_redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,6 @@ def test_add_events(self, mocker):
}
}) for e in events]

# To deal with python2 & 3 differences in hashing/order when dumping json.
list_of_raw_json_strings_called = adapter.rpush.mock_calls[0][1][1:]
list_of_events_called = [json.loads(event) for event in list_of_raw_json_strings_called]
list_of_events_sent = [json.loads(event) for event in list_of_raw_events]
Expand Down