Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1f23a57
sdk input sanitization initial commit
mredolatti Jul 4, 2018
b669189
added ImpressionListener to Python sdk
Aug 2, 2018
ad05c39
removed previous bulk listener handler and updated previous tests
Aug 2, 2018
8780aa0
added documentation for redis sentinel support and simple redis
Aug 28, 2018
6302817
updated documentation
Aug 28, 2018
86ad3b4
updated documentation to use setup already configured
Aug 28, 2018
35aedd6
merged with dev and fixed tests
Sep 3, 2018
57eea97
added tests for IL
Sep 5, 2018
4fa5c2f
removed unnecesary mocked fields
Sep 5, 2018
1b64db3
updated logic to wrap il in sdk
Sep 6, 2018
3dfbe0d
added small fix when IL is null
Sep 6, 2018
2b2b25d
added more unit tests-
Sep 6, 2018
7067790
added documentation in Detailed-README for IL
Sep 7, 2018
c1cf23e
fixed typo
Sep 7, 2018
334a9f9
fixed readme
Sep 7, 2018
a3342c2
improved description for IL
Sep 7, 2018
420107c
improvements in code
Sep 10, 2018
34c0b1d
fixed issue for python 2
Sep 11, 2018
1ff1ab3
fixed typo
Sep 11, 2018
6764a40
removed old impression_listener handler from uwsgi
Sep 14, 2018
b659858
Merge branch 'master' of github.com:splitio/python-client into improv…
mredolatti Sep 18, 2018
6f94d6b
added input validation logic
Sep 19, 2018
9e6c38c
added pull request template
Sep 19, 2018
cedbd77
improvements
Sep 19, 2018
0a0b6d0
code improvements
Sep 19, 2018
ce299b4
removed unnecesary check
Sep 19, 2018
566df6e
removed commented lines and bare exception linter
Sep 20, 2018
3b3b98a
Merge pull request #96 from splitio/feature/DocumentationRedisSentinel
mmelograno Sep 20, 2018
659fd8b
merged with development
Sep 20, 2018
42e4d76
Merge pull request #98 from splitio/feature/ImpressionListener
mmelograno Sep 20, 2018
0852444
merged with development
Sep 20, 2018
cc2bb45
Merge pull request #99 from splitio/improvement/inputSanitization
mmelograno Sep 20, 2018
c5c350a
fixed track with null value and updated version
Sep 21, 2018
2ccb523
Merge pull request #100 from splitio/improvement/inputSanitization
mmelograno Sep 24, 2018
77a74f1
fixed issue on exception
Sep 24, 2018
1d3a5aa
Merge pull request #101 from splitio/fix/HotFixInputSanitization
mmelograno Sep 24, 2018
690a2e5
fixes for tests and code improvement on input_validator
Sep 25, 2018
1595816
refactored validation names
Sep 25, 2018
c551f7d
updated changes regarding new version
Sep 25, 2018
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
15 changes: 15 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Python SDK

## Tickets covered:
* [SDKS-{TICKET}](https://splitio.atlassian.net/browse/SDKS-{TICKET})

## What did you accomplish?
* Bullet 1
* Bullet 2

## How to test new changes?
*

## Extra Notes
* Bullet 1
* Bullet 2
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var/
*.egg-info/
.installed.cfg
*.egg
venv/
.vscode

# PyInstaller
Expand Down
3 changes: 3 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
6.1.0 (Sep 25, 2018)
- Add custom impression listener feature.
- Input Sanitization for track, get_treatment and split.
6.0.0 (Aug 29, 2018)
- Add support for redis sentinel
- UWSGI performance boost (breaking change)
Expand Down
114 changes: 114 additions & 0 deletions Detailed-README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,120 @@ The following snippet shows you how to create a basic client using the default c
'SOME_TREATMENT'
```

## Logging
Split SDK uses logging module from Python.

### Logging sample
```python
import logging
logging.basicConfig(level=logging.DEBUG)
```

## Cache
Split SDK depends on the popular [redis-py](https://github.com/andymccurdy/redis-py) library.

### Cache Adapter
The redis-py library is supported as the python interface to the Redis key-value store. This library uses a connection pool to manage connections to a Redis server. For further information about how to configure the ```redis-py``` client, please take a look on [redis-py official docs](https://github.com/andymccurdy/redis-py)

For ```redis``` and their dependencies such as ```jsonpickle``` you can use ```pip``` running the command ```pip install splitio_client[redis,cpphash]==5.5.0```

#### Provided redis-py connection - sample code
```python
#Default imports
from __future__ import print_function

import sys

from splitio import get_factory
from splitio.exceptions import TimeoutException

# redis-py options
'''The options below, will be loaded as:
r = redis.StrictRedis(host='localhost', port=6379, db=0, prefix='')
'''
config = {
'redisDb' : 0,
'redisHost' : 'localhost',
'redisPosrt': 6379,
'redisPrefix': ''
}

# Create the Split Client instance.
try:
factory = get_factory('API_KEY', config=config)
split = factory.client()
except TimeoutException:
sys.exit()
```

#### Provided redis-py connection - sample code for Sentinel Support
```python
#Default imports
from __future__ import print_function

import sys

from splitio import get_factory
from splitio.exceptions import TimeoutException

# redis-py options
'''
The options below, will be loaded as:
sentinel = Sentinel(redisSentinels, { db: redisDb, socket_timeout: redisSocketTimeout })
master = sentinel.master_for(redisMasterService)
'''
config = {
'redisDb': 0,
'redisPrefix': '',
'redisSentinels': [('IP', PORT), ('IP', PORT), ('IP', PORT)],
'redisMasterService': 'SERVICE_MASTER_NAME',
'redisSocketTimeout': 3
}

# Create the Split Client instance.
try:
factory = get_factory('API_KEY', config=config)
split = factory.client()
except TimeoutException:
sys.exit()
```

## Impression Listener
Split SDKs send impression data back to Split servers periodically and as a result of evaluating splits. In order to additionally send this information to a location of your choice, you could define and attach an Impression Listener. For that purpose, SDK's options have a parameter called `impressionListener` where an implementation of `ImpressionListener` could be added. This implementation **must** define the `log_impression` method and it will receive data in the following schema:

| Name | Type | Description |
| --- | --- | --- |
| impression | Impression | Impression object that has the feature_name, treatment result, label, etc. |
| attributes | Array | A list of attributes passed by the client. |
| instance-id | String | Corresponds to the IP of the machine where the SDK is running. |
| sdk-language-version | String | Indicates the version of the sdk. In this case the language will be python plus the version of it. |

### Implementing custom Impression Listener
Below you could find an example of how implement a custom Impression Listener:
```python
# Import ImpressionListener interface
from splitio.impressions import ImpressionListener

# Implementation Sample for a Custom Impression Listener
class CustomImpressionListener(ImpressionListener)
{
def log_impression(self, data):
# Custom behavior
}
```

### Attaching custom Impression Listener
```python
factory = get_factory(
'YOUR_API_KEY',
config={
# ...
'impressionListener': CustomImpressionListener()
},
# ...
)
split = factory.client()

## Additional information

You can get more information on how to use this package in the included documentation.
2 changes: 1 addition & 1 deletion splitio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
unicode_literals

from .factories import get_factory # noqa
from .clients import Key # noqa
from .key import Key # noqa
from .version import __version__ # noqa

__all__ = ('api', 'brokers', 'cache', 'clients', 'matchers', 'segments',
Expand Down
26 changes: 13 additions & 13 deletions splitio/brokers.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ class BaseBroker(object):

__metaclass__ = abc.ABCMeta

def __init__(self):
def __init__(self, config=None):
"""
Class constructor, only sets up the logger
"""
self._logger = logging.getLogger(self.__class__.__name__)
self._destroyed = False
self._config = config

def fetch_feature(self, name):
"""
Expand Down Expand Up @@ -120,7 +121,7 @@ def destroy(self):
pass

class JSONFileBroker(BaseBroker):
def __init__(self, segment_changes_file_name, split_changes_file_name):
def __init__(self, config, segment_changes_file_name, split_changes_file_name):
"""
A Broker implementation that uses responses from the segmentChanges and
splitChanges resources to provide access to splits. It is intended to be
Expand All @@ -133,7 +134,7 @@ def __init__(self, segment_changes_file_name, split_changes_file_name):
splitChanges response
:type split_changes_file_name: str
"""
super(JSONFileBroker, self).__init__()
super(JSONFileBroker, self).__init__(config)
self._segment_changes_file_name = segment_changes_file_name
self._split_changes_file_name = split_changes_file_name
self._split_fetcher = self._build_split_fetcher()
Expand Down Expand Up @@ -310,7 +311,6 @@ def _build_treatment_log(self):
self._sdk_api,
max_count=self._max_impressions_log_size,
interval=self._impressions_interval,
listener=self._impression_listener
)
return AsyncTreatmentLog(self_updating_treatment_log)

Expand Down Expand Up @@ -388,7 +388,7 @@ class LocalhostEventStorage(object):
def log(self, event):
pass

def __init__(self, split_definition_file_name=None, auto_refresh_period=2):
def __init__(self, config, split_definition_file_name=None, auto_refresh_period=2):
"""
A broker implementation that builds its configuration from a split
definition file. By default the definition is taken from $HOME/.split
Expand All @@ -398,7 +398,7 @@ def __init__(self, split_definition_file_name=None, auto_refresh_period=2):
:param auto_refresh_period: Number of seconds between split refresh calls
:type auto_refresh_period: int
"""
super(LocalhostBroker, self).__init__()
super(LocalhostBroker, self).__init__(config)

if split_definition_file_name is None:
self._split_definition_file_name = os.path.join(
Expand Down Expand Up @@ -503,11 +503,11 @@ def destroy(self):


class RedisBroker(BaseBroker):
def __init__(self, redis):
def __init__(self, redis, config):
"""A Broker implementation that uses Redis as its backend.
:param redis: A redis broker
:type redis: StrctRedis"""
super(RedisBroker, self).__init__()
super(RedisBroker, self).__init__(config)

split_cache = RedisSplitCache(redis)
split_fetcher = CacheBasedSplitFetcher(split_cache)
Expand Down Expand Up @@ -571,7 +571,7 @@ def __init__(self, uwsgi, config=None):
:param config: The configuration dictionary
:type config: dict
"""
super(UWSGIBroker, self).__init__()
super(UWSGIBroker, self).__init__(config)

split_cache = UWSGISplitCache(uwsgi)
split_fetcher = CacheBasedSplitFetcher(split_cache)
Expand Down Expand Up @@ -712,7 +712,7 @@ def get_self_refreshing_broker(api_key, **kwargs):
)

if api_key == 'localhost':
return LocalhostBroker(**kwargs)
return LocalhostBroker(config, **kwargs)

return SelfRefreshingBroker(
api_key,
Expand Down Expand Up @@ -776,11 +776,11 @@ def get_redis_broker(api_key, **kwargs):
api_key, config, _, _ = _init_config(api_key, **kwargs)

if api_key == 'localhost':
return LocalhostBroker(**kwargs)
return LocalhostBroker(config, **kwargs)

redis = get_redis(config)

redis_broker = RedisBroker(redis)
redis_broker = RedisBroker(redis, config)

return redis_broker

Expand Down Expand Up @@ -836,7 +836,7 @@ def get_uwsgi_broker(api_key, **kwargs):
api_key, config, _, _ = _init_config(api_key, **kwargs)

if api_key == 'localhost':
return LocalhostBroker(**kwargs)
return LocalhostBroker(config, **kwargs)

uwsgi = get_uwsgi()
uwsgi_broker = UWSGIBroker(uwsgi, config)
Expand Down
Loading