Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
1b23d0f
full refactor
mredolatti Apr 12, 2019
5b8b7ab
add configurations to split model
mredolatti Apr 12, 2019
94a941b
return configurations from evaluator
mredolatti Apr 12, 2019
66f5d29
update clients & input validator to work with new methods *_with_config
mredolatti Apr 12, 2019
2fea2db
more tests & redis
mredolatti Apr 15, 2019
7dd4d03
reorder tasks
mredolatti Apr 15, 2019
a37bdee
add localhost support for dynamic configs
mredolatti Apr 16, 2019
48ab64c
improve logging
mredolatti Apr 16, 2019
385ee2a
docstring cleanup
mredolatti Apr 16, 2019
ebabec2
fix input validation log interpolation
mredolatti Apr 17, 2019
f2ed31a
input validation for factory instantiation
mredolatti Apr 17, 2019
d0e58cb
factory ready methods
mredolatti Apr 17, 2019
5eba7d0
Merge branch 'full_refactor' of github.com:splitio/python-client into…
mredolatti Apr 17, 2019
27d9cc2
Merge branch 'feature/dynamic-configs-splitchanges' of github.com:spl…
mredolatti Apr 17, 2019
9eaaa02
merge with latest changes in refactor
mredolatti Apr 17, 2019
db630c2
Merge pull request #130 from splitio/feature/dynamic-configs-splitcha…
mredolatti Apr 17, 2019
ca9ddc2
Merge pull request #131 from splitio/feature/dynamic-configs-evaluator
mredolatti Apr 17, 2019
137072e
Merge pull request #132 from splitio/feature/dynamic-configs-client
mredolatti Apr 17, 2019
1b17f6b
Merge branch 'full_refactor' of github.com:splitio/python-client into…
mredolatti Apr 17, 2019
a959773
fix yaml/legacy selection and test it
mredolatti Apr 17, 2019
1daeb1d
add e2e tests for localhost yaml file
mredolatti Apr 17, 2019
a57e7ec
add `configs` in testview
mredolatti Apr 17, 2019
3f2c0e3
Merge pull request #133 from splitio/feature/dynamic-config-localhost
mredolatti Apr 17, 2019
70044ac
Merge branch 'full_refactor' of github.com:splitio/python-client into…
mredolatti Apr 17, 2019
2fc3c7a
Merge pull request #134 from splitio/feature/dynamic-configs-splitview
mredolatti Apr 17, 2019
e1fc0a2
more e2e tests
mredolatti Apr 22, 2019
56e6bca
remove unnecessary print
mredolatti Apr 22, 2019
0a45113
update e2e tests
mredolatti Apr 22, 2019
527b0f3
fix tests in py3
mredolatti Apr 23, 2019
cd33c26
forward config to metadata builder
mredolatti Apr 23, 2019
e7b7b81
Merge pull request #135 from splitio/feature/dynamic-configs-splitview
mredolatti Apr 23, 2019
72bd9b1
fix impression listener. move to utils.raise_from
mredolatti Apr 23, 2019
0f1033d
reorganize exceptions
mredolatti Apr 23, 2019
3a8d4ac
conver mget result to list of strings
mredolatti Apr 23, 2019
add69ec
fix track issue in redis, fix tests
mredolatti Apr 23, 2019
81ee307
look for sentinels as well when guessing operation mode
mredolatti Apr 23, 2019
7b06c62
use a pool in uwsgi mode as well to increase segment fetching throughput
mredolatti Apr 23, 2019
605908b
more uwsgi optimizations
mredolatti Apr 23, 2019
4723b9f
start the pool
mredolatti Apr 23, 2019
04b1995
fix segment fetching in uwsgi mode
mredolatti Apr 23, 2019
9d3157c
do not fail when removing nonexistant split in uwsgi. Keep tasks goin…
mredolatti Apr 23, 2019
8b08be6
Merge pull request #129 from splitio/full_refactor
mredolatti Apr 24, 2019
9895591
Merge branch 'master' of github.com:splitio/python-client into develo…
mredolatti Apr 24, 2019
18ec7ce
update travis config
mredolatti Apr 24, 2019
eeec9ae
fix travis.yml
mredolatti Apr 24, 2019
ddbb852
remove old legacy test
mredolatti Apr 24, 2019
d6c87a0
tests in verbose mode
mredolatti Apr 24, 2019
7a7596e
add a method to build metadata headers
mredolatti Apr 24, 2019
88e2e00
Added python 3.6
Apr 24, 2019
3f59ce1
bump version & update changes.txt
mredolatti Apr 24, 2019
e91e795
Merge branch 'development' of github.com:splitio/python-client into d…
mredolatti Apr 24, 2019
cd2f4b2
wait for factory to be ready in localhost tests
mredolatti Apr 24, 2019
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
3 changes: 2 additions & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
* Bullet 2

## How to test new changes?
*
* python setup.py test to test everythin
* pytest <SPECIFIC_FILE> to test a file in particular (requires pytest, pytest-cov & pytest-mock to be installed)

## Extra Notes
* Bullet 1
Expand Down
30 changes: 2 additions & 28 deletions splitio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,5 @@
unicode_literals

from splitio.client.factory import get_factory
#from .factories import get_factory # noqa
#from .key import Key # noqa
#from .version import __version__ # noqa
#
#__all__ = ('api', 'brokers', 'cache', 'clients', 'matchers', 'segments',
# 'settings', 'splits', 'splitters', 'transformers', 'treatments',
# 'version', 'factories', 'manager')
#
#
## Functions defined to maintain compatibility with previous sdk versions.
## ======================================================================
##
## This functions are not supposed to be used directly, factory method should be
## called instead, but since they were previously exposed, they're re-added here
## as helper function so that if someone was using we don't break their code.
#
#def get_client(apikey, **kwargs):
# from .clients import Client
# from .brokers import get_self_refreshing_broker
# broker = get_self_refreshing_broker(apikey, **kwargs)
# return Client(broker)
#
#
#def get_redis_client(apikey, **kwargs):
# from .clients import Client
# from .brokers import get_redis_broker
# broker = get_redis_broker(apikey, **kwargs)
# return Client(broker)
from splitio.client.key import Key
from splitio.version import __version__
9 changes: 1 addition & 8 deletions splitio/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,12 @@
class APIException(Exception):
"""Exception to raise when an API call fails."""

def __init__(self, custom_message, status_code=None, original_exception=None):
def __init__(self, custom_message, status_code=None):
"""Constructor."""
Exception.__init__(self, custom_message)
self._status_code = status_code if status_code else -1
self._custom_message = custom_message
self._original_exception = original_exception

@property
def status_code(self):
"""Return HTTP status code."""
return self._status_code

@property
def custom_message(self):
"""Return custom message."""
return self._custom_message
63 changes: 33 additions & 30 deletions splitio/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from __future__ import division

from collections import namedtuple

from six import raise_from
import requests

HttpResponse = namedtuple('HttpResponse', ['status_code', 'body'])
Expand All @@ -10,28 +12,14 @@
class HttpClientException(Exception):
"""HTTP Client exception."""

def __init__(self, custom_message, original_exception=None):
def __init__(self, message):
"""
Class constructor.

:param message: Information on why this exception happened.
:type message: str
:param original_exception: Original exception being caught if any.
:type original_exception: Exception.
"""
Exception.__init__(self, custom_message)
self._custom_message = custom_message
self._original_exception = original_exception

@property
def custom_message(self):
"""Return custom message."""
return self._custom_message

@property
def original_exception(self):
"""Return original exception."""
return self._original_exception
Exception.__init__(self, message)


class HttpClient(object):
Expand All @@ -44,12 +32,12 @@ def __init__(self, timeout=None, sdk_url=None, events_url=None):
"""
Class constructor.

:param timeout: How many milliseconds to wait until the server responds.
:type timeout: int
:param sdk_url: Optional alternative sdk URL.
:type sdk_url: str
:param events_url: Optional alternative events URL.
:type events_url: str
:param timeout: How many milliseconds to wait until the server responds.
:type timeout: int
"""
self._timeout = timeout / 1000 if timeout else None # Convert ms to seconds.
self._urls = {
Expand All @@ -71,24 +59,38 @@ def _build_url(self, server, path):
"""
return self._urls[server] + path

@staticmethod
def _build_basic_headers(apikey):
"""
Build basic headers with auth.

:param apikey: API token used to identify backend calls.
:type apikey: str
"""
return {
'Content-Type': 'application/json',
'Authorization': "Bearer %s" % apikey
}

def get(self, server, path, apikey, query=None, extra_headers=None): #pylint: disable=too-many-arguments
"""
Issue a get request.

:param server: Whether the request is for SDK server or Events server.
:typee server: str
:param path: path to append to the host url.
:type path: str
:param apikey: api token.
:type apikey: str
:param query: Query string passed as dictionary.
:type query: dict
:param extra_headers: key/value pairs of possible extra headers.
:type extra_headers: dict

:return: Tuple of status_code & response text
:rtype: HttpResponse
"""
headers = {
'Content-Type': 'application/json',
'Authorization': "Bearer %s" % apikey
}
headers = self._build_basic_headers(apikey)

if extra_headers is not None:
headers.update(extra_headers)
Expand All @@ -101,29 +103,30 @@ def get(self, server, path, apikey, query=None, extra_headers=None): #pylint: d
timeout=self._timeout
)
return HttpResponse(response.status_code, response.text)
except Exception as exc:
raise HttpClientException('requests library is throwing exceptions', exc)
except Exception as exc: #pylint: disable=broad-except
raise_from(HttpClientException('requests library is throwing exceptions'), exc)

def post(self, server, path, apikey, body, query=None, extra_headers=None): #pylint: disable=too-many-arguments
"""
Issue a POST request.

:param server: Whether the request is for SDK server or Events server.
:typee server: str
:param path: path to append to the host url.
:type path: str
:param apikey: api token.
:type apikey: str
:param body: body sent in the request.
:type body: str
:param query: Query string passed as dictionary.
:type query: dict
:param extra_headers: key/value pairs of possible extra headers.
:type extra_headers: dict

:return: Tuple of status_code & response text
:rtype: HttpResponse
"""
headers = {
'Content-Type': 'application/json',
'Authorization': "Bearer %s" % apikey
}
headers = self._build_basic_headers(apikey)

if extra_headers is not None:
headers.update(extra_headers)
Expand All @@ -137,5 +140,5 @@ def post(self, server, path, apikey, body, query=None, extra_headers=None): #py
timeout=self._timeout
)
return HttpResponse(response.status_code, response.text)
except Exception as exc:
raise HttpClientException('requests library is throwing exceptions', exc)
except Exception as exc: #pylint: disable=broad-except
raise_from(HttpClientException('requests library is throwing exceptions'), exc)
14 changes: 10 additions & 4 deletions splitio/api/events.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
"""Events API module."""
import logging

from six import raise_from

from splitio.api import APIException
from splitio.api.client import HttpClientException

Expand All @@ -11,10 +14,12 @@ def __init__(self, http_client, apikey, sdk_metadata):
"""
Class constructor.

:param client: HTTP Client responsble for issuing calls to the backend.
:type client: HttpClient
:param http_client: HTTP Client responsble for issuing calls to the backend.
:type http_client: HttpClient
:param apikey: User apikey token.
:type apikey: string
:param sdk_metadata: SDK version & machine name & IP.
:type sdk_metadata: splitio.client.util.SdkMetadata
"""
self._logger = logging.getLogger(self.__class__.__name__)
self._client = http_client
Expand Down Expand Up @@ -69,5 +74,6 @@ def flush_events(self, events):
if not 200 <= response.status_code < 300:
raise APIException(response.body, response.status_code)
except HttpClientException as exc:
self._logger.debug('Error flushing events: ', exc_info=True)
raise APIException(exc.custom_message, original_exception=exc.original_exception)
self._logger.error('Http client is throwing exceptions')
self._logger.debug('Error: ', exc_info=True)
raise_from(APIException('Events not flushed properly.'), exc)
8 changes: 6 additions & 2 deletions splitio/api/impressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import logging
from itertools import groupby

from six import raise_from

from splitio.api import APIException
from splitio.api.client import HttpClientException

Expand Down Expand Up @@ -78,5 +81,6 @@ def flush_impressions(self, impressions):
if not 200 <= response.status_code < 300:
raise APIException(response.body, response.status_code)
except HttpClientException as exc:
self._logger.debug('Error flushing events: ', exc_info=True)
raise APIException(exc.custom_message, original_exception=exc.original_exception)
self._logger.error('Http client is throwing exceptions')
self._logger.debug('Error: ', exc_info=True)
raise_from(APIException('Impressions not flushed properly.'), exc)
8 changes: 6 additions & 2 deletions splitio/api/segments.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import json
import logging

from six import raise_from

from splitio.api import APIException
from splitio.api.client import HttpClientException

Expand Down Expand Up @@ -47,5 +50,6 @@ def fetch_segment(self, segment_name, change_number):
else:
raise APIException(response.body, response.status_code)
except HttpClientException as exc:
self._logger.debug('Error flushing events: ', exc_info=True)
raise APIException(exc.custom_message, original_exception=exc.original_exception)
self._logger.error('Http client is throwing exceptions')
self._logger.debug('Error: ', exc_info=True)
raise_from(APIException('Segments not fetched properly.'), exc)
8 changes: 6 additions & 2 deletions splitio/api/splits.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import logging
import json

from six import raise_from

from splitio.api import APIException
from splitio.api.client import HttpClientException

Expand Down Expand Up @@ -44,5 +47,6 @@ def fetch_splits(self, change_number):
else:
raise APIException(response.body, response.status_code)
except HttpClientException as exc:
self._logger.debug('Error flushing events: ', exc_info=True)
raise APIException(exc.custom_message, original_exception=exc.original_exception)
self._logger.error('Http client is throwing exceptions')
self._logger.debug('Error: ', exc_info=True)
raise_from(APIException('Splits not fetched correctly.'), exc)
13 changes: 9 additions & 4 deletions splitio/api/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ def flush_latencies(self, latencies):
if not 200 <= response.status_code < 300:
raise APIException(response.body, response.status_code)
except HttpClientException as exc:
raise APIException(exc.custom_message, original_exception=exc.original_exception)
self._logger.error('Http client is throwing exceptions')
self._logger.debug('Error: ', exc_info=True)
six.raise_from(APIException('Latencies not flushed correctly.'), exc)

@staticmethod
def _build_gauges(gauges):
Expand Down Expand Up @@ -94,7 +96,9 @@ def flush_gauges(self, gauges):
if not 200 <= response.status_code < 300:
raise APIException(response.body, response.status_code)
except HttpClientException as exc:
raise APIException(exc.custom_message, original_exception=exc.original_exception)
self._logger.error('Http client is throwing exceptions')
self._logger.debug('Error: ', exc_info=True)
six.raise_from(APIException('Gauges not flushed correctly.'), exc)

@staticmethod
def _build_counters(counters):
Expand Down Expand Up @@ -128,5 +132,6 @@ def flush_counters(self, counters):
if not 200 <= response.status_code < 300:
raise APIException(response.body, response.status_code)
except HttpClientException as exc:
self._logger.debug('Error flushing events: ', exc_info=True)
raise APIException(exc.custom_message, original_exception=exc.original_exception)
self._logger.error('Http client is throwing exceptions')
self._logger.debug('Error: ', exc_info=True)
six.raise_from(APIException('Counters not flushed correctly.'), exc)
5 changes: 5 additions & 0 deletions splitio/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ def destroy(self):
"""
self._factory.destroy()

@property
def ready(self):
"""Return whether the SDK initialization has finished."""
return self._factory.ready

@property
def destroyed(self):
"""Return whether the factory holding this client has been destroyed."""
Expand Down
Loading