Skip to content

Commit 0cf4d23

Browse files
authored
Merge pull request #173 from splitio/fix/deps
fix dependencies
2 parents d16d21b + 602571d commit 0cf4d23

File tree

6 files changed

+80
-54
lines changed

6 files changed

+80
-54
lines changed

LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright 2018 Split Software, Co.
1+
Copyright © 2020 Split Software, Inc.
22

33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.

setup.py

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,57 @@
11
"""Setup module."""
22
#!/usr/bin/env python
33

4-
from setuptools import setup, find_packages
54
from os import path
5+
from setuptools import setup, find_packages
66

7-
tests_require = [
7+
TESTS_REQUIRES = [
88
'flake8',
9-
'pytest',
9+
'pytest<=4.6', # for deprecated python versions: https://docs.pytest.org/en/latest/py27-py34-deprecation.html
1010
'pytest-mock',
1111
'coverage',
1212
'pytest-cov',
1313
'mock;python_version<"3"'
1414
]
15-
install_requires = [
15+
16+
INSTALL_REQUIRES = [
1617
'requests>=2.9.1',
1718
'pyyaml>=5.1',
1819
'future>=0.15.2',
1920
'docopt>=0.6.2',
21+
'six>=1.10.0',
2022
'enum34;python_version<"3.4"',
21-
'six>=1.10.0;python_version<"3"',
2223
'futures>=3.0.5;python_version<"3"'
2324
]
2425

2526
with open(path.join(path.abspath(path.dirname(__file__)),
2627
'splitio', 'version.py')) as f:
27-
exec(f.read())
28+
exec(f.read()) # pylint: disable=exec-used
2829

29-
setup(name='splitio_client',
30-
version=__version__, # noqa
31-
description='Split.io Python Client',
32-
author='Patricio Echague, Sebastian Arrubia',
33-
author_email='pato@split.io, sebastian@split.io',
34-
url='https://github.com/splitio/python-client',
35-
download_url=('https://github.com/splitio/python-client/tarball/' +
36-
__version__),
37-
license='Apache License 2.0',
38-
install_requires=install_requires,
39-
tests_require=tests_require,
40-
extras_require={
41-
'test': tests_require,
42-
'redis': ['redis>=2.10.5'],
43-
'uwsgi': ['uwsgi>=2.0.0'],
44-
'cpphash': ['mmh3cffi>=0.1.4']
45-
},
46-
setup_requires=['pytest-runner'],
47-
classifiers=[
48-
'Development Status :: 3 - Alpha',
49-
'Environment :: Console',
50-
'Intended Audience :: Developers',
51-
'Programming Language :: Python',
52-
'Programming Language :: Python :: 2',
53-
'Programming Language :: Python :: 3',
54-
'Topic :: Software Development :: Libraries'
55-
],
56-
packages=find_packages())
30+
setup(
31+
name='splitio_client',
32+
version=__version__, # pylint: disable=undefined-variable
33+
description='Split.io Python Client',
34+
author='Patricio Echague, Sebastian Arrubia',
35+
author_email='pato@split.io, sebastian@split.io',
36+
url='https://github.com/splitio/python-client',
37+
download_url=('https://github.com/splitio/python-client/tarball/' + __version__), # pylint: disable=undefined-variable
38+
license='Apache License 2.0',
39+
install_requires=INSTALL_REQUIRES,
40+
tests_require=TESTS_REQUIRES,
41+
extras_require={
42+
'test': TESTS_REQUIRES,
43+
'redis': ['redis>=2.10.5'],
44+
'uwsgi': ['uwsgi>=2.0.0'],
45+
'cpphash': ['mmh3cffi>=0.1.4']
46+
},
47+
setup_requires=['pytest-runner'],
48+
classifiers=[
49+
'Environment :: Console',
50+
'Intended Audience :: Developers',
51+
'Programming Language :: Python',
52+
'Programming Language :: Python :: 2',
53+
'Programming Language :: Python :: 3',
54+
'Topic :: Software Development :: Libraries'
55+
],
56+
packages=find_packages()
57+
)

splitio/client/factory.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ def _build_in_memory_factory(api_key, config, sdk_url=None, events_url=None): #
246246
timeout=cfg.get('connectionTimeout')
247247
)
248248

249-
sdk_metadata = util.get_metadata(config)
249+
sdk_metadata = util.get_metadata(cfg)
250250
apis = {
251251
'splits': SplitsAPI(http_client, api_key),
252252
'segments': SegmentsAPI(http_client, api_key),
@@ -348,8 +348,8 @@ def _build_redis_factory(api_key, config):
348348
"""Build and return a split factory with redis-based storage."""
349349
cfg = DEFAULT_CONFIG.copy()
350350
cfg.update(config)
351-
sdk_metadata = util.get_metadata(config)
352-
redis_adapter = redis.build(config)
351+
sdk_metadata = util.get_metadata(cfg)
352+
redis_adapter = redis.build(cfg)
353353
storages = {
354354
'splits': RedisSplitStorage(redis_adapter),
355355
'segments': RedisSegmentStorage(redis_adapter),

splitio/storage/adapters/cache_trait.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def __init__(
5151
):
5252
"""Class constructor."""
5353
self._data = {}
54-
self._lock = threading.RLock()
54+
self._lock = threading.Lock()
5555
self._max_age_seconds = max_age_seconds
5656
self._max_size = max_size
5757
self._lru = None
@@ -109,26 +109,31 @@ def _bubble_up(self, node):
109109
if node is None:
110110
return None
111111

112+
# First item, just set lru & mru
113+
if not self._data:
114+
self._lru = node
115+
self._mru = node
116+
return node
117+
118+
# MRU, just return it
119+
if node is self._mru:
120+
return node
121+
122+
# LRU, update pointer and end-of-list
123+
if node is self._lru:
124+
self._lru = node.next
125+
self._lru.previous = None
126+
112127
if node.previous is not None:
113128
node.previous.next = node.next
114-
115129
if node.next is not None:
116130
node.next.previous = node.previous
117131

118-
if self._lru == node:
119-
if node.next is not None: #only update lru pointer if there are more than 1 elements.
120-
self._lru = node.next
121-
122-
if not self._data:
123-
# if there are no items, set the LRU to this node
124-
self._lru = node
125-
else:
126-
# if there is at least one item, update the MRU chain
127-
self._mru.next = node
128-
129-
node.next = None
130132
node.previous = self._mru
133+
node.previous.next = node
134+
node.next = None
131135
self._mru = node
136+
132137
return node
133138

134139
def _rollover(self):
@@ -137,13 +142,14 @@ def _rollover(self):
137142
next_item = self._lru.next
138143
del self._data[self._lru.key]
139144
self._lru = next_item
145+
self._lru.previous = None
140146

141147
def __str__(self):
142148
"""User friendly representation of cache."""
143149
nodes = []
144150
node = self._mru
145151
while node is not None:
146-
nodes.append('<%s: %s> -->' % (node.key, node.value))
152+
nodes.append('\t<%s: %s> -->' % (node.key, node.value))
147153
node = node.previous
148154
return '<MRU>\n' + '\n'.join(nodes) + '\n<LRU>'
149155

splitio/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '8.1.7'
1+
__version__ = '8.1.8'

tests/storage/adapters/test_cache_trait.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Cache testing module."""
22
#pylint: disable=protected-access,no-self-use,line-too-long
33
import time
4+
from random import choice
45

56
import pytest
67

@@ -55,6 +56,9 @@ def test_lru_behaviour(self, mocker):
5556
assert 'some' not in cache._data
5657
assert len(cache._data) == 5
5758
assert cache._lru.key == 'some_other'
59+
for node in cache._data.values():
60+
if node != cache._mru:
61+
assert node.next is not None
5862

5963
# `some_other` should be the next key to be evicted.
6064
# if we issue a get call for it, it should be marked as the MRU,
@@ -64,6 +68,21 @@ def test_lru_behaviour(self, mocker):
6468
assert cache._mru.key == 'some_other'
6569
assert cache._lru.key == 'another'
6670

71+
def test_intensive_usage_behavior(self, mocker):
72+
"""Test fetches with random repeated strings."""
73+
user_func = mocker.Mock()
74+
user_func.side_effect = lambda *p, **kw: len(p[0])
75+
key_func = mocker.Mock()
76+
key_func.side_effect = lambda *p, **kw: p[0]
77+
cache = cache_trait.LocalMemoryCache(key_func, user_func, 1, 5)
78+
79+
strings = ['a', 'bb', 'ccc', 'dddd', 'eeeee', 'ffffff', 'ggggggg', 'hhhhhhhh',
80+
'jjjjjjjjj', 'kkkkkkkkkk']
81+
for _ in range(0, 100000):
82+
chosen = choice(strings)
83+
assert cache.get(chosen) == len(chosen)
84+
assert cache._lru is not None
85+
6786
def test_expiration_behaviour(self, mocker):
6887
"""Test time expiration works as expected."""
6988
user_func = mocker.Mock()

0 commit comments

Comments
 (0)