Skip to content

Commit dec4f3d

Browse files
Merge pull request pandas-dev#155 from manahl/tickstore_allow_secondary
TickStore should respect the allow_secondary flag on Arctic
2 parents b905167 + 6df008b commit dec4f3d

File tree

5 files changed

+89
-11
lines changed

5 files changed

+89
-11
lines changed

.travis.yml

+9-7
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ sudo: false
22
language: python
33
python:
44
- "2.7"
5-
- "3.4"
6-
- "3.5"
5+
- "3.4.4"
6+
- "3.5.1"
77
install:
88
- pip install --upgrade pip
9-
- pip install python-dateutil --upgrade
10-
- pip install pytz --upgrade
11-
- pip install tzlocal --upgrade
9+
- pip install python-dateutil --upgrade
10+
- pip install pytz --upgrade
11+
- pip install tzlocal --upgrade
1212
- pip install cython --upgrade
1313
- pip install pymongo --upgrade
1414
- pip install numpy --upgrade
15-
- pip install pandas --upgrade
15+
- pip install pandas --upgrade
1616
- pip install decorator --upgrade
1717
- pip install enum34 --upgrade
1818
- pip install lz4 --upgrade
@@ -24,4 +24,6 @@ install:
2424
- pip install pytest-timeout --upgrade
2525
- pip install pytest-xdist --upgrade
2626
- pip install setuptools-git --upgrade
27-
script: python setup.py test
27+
script:
28+
- pip freeze
29+
- python setup.py test

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
### 1.26
44

55
* Bugfix: Faster TickStore querying for multiple symbols simultaneously
6+
* Bugfix: TickStore.read now respects `allow_secondary=True`
67
* Bugfix: #147 Add get_info method to ChunkStore
78

89
### 1.25 (2016-05-23)

arctic/tickstore/tickstore.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import pandas as pd
1010
from pandas.core.frame import _arrays_to_mgr
1111
import pymongo
12+
from pymongo import ReadPreference
1213
from pymongo.errors import OperationFailure
1314
from six import iteritems, string_types
1415

@@ -230,7 +231,14 @@ def _symbol_query(self, symbol):
230231
query = {}
231232
return query
232233

233-
def read(self, symbol, date_range=None, columns=None, include_images=False, _target_tick_count=0):
234+
def _read_preference(self, allow_secondary):
235+
""" Return the mongo read preference given an 'allow_secondary' argument
236+
"""
237+
allow_secondary = self._allow_secondary if allow_secondary is None else allow_secondary
238+
return ReadPreference.NEAREST if allow_secondary else ReadPreference.PRIMARY
239+
240+
def read(self, symbol, date_range=None, columns=None, include_images=False, allow_secondary=None,
241+
_target_tick_count=0):
234242
"""
235243
Read data for the named symbol. Returns a VersionedItem object with
236244
a data and metdata element (as passed into write).
@@ -245,6 +253,12 @@ def read(self, symbol, date_range=None, columns=None, include_images=False, _tar
245253
Columns (fields) to return from the tickstore
246254
include_images : `bool`
247255
Should images (/snapshots) be included in the read
256+
allow_secondary : `bool` or `None`
257+
Override the default behavior for allowing reads from secondary members of a cluster:
258+
`None` : use the settings from the top-level `Arctic` object used to query this version store.
259+
`True` : allow reads from secondary members
260+
`False` : only allow reads from primary members
261+
248262
Returns
249263
-------
250264
pandas.DataFrame of data
@@ -277,7 +291,8 @@ def read(self, symbol, date_range=None, columns=None, include_images=False, _tar
277291

278292
column_dtypes = {}
279293
ticks_read = 0
280-
for b in self._collection.find(query, projection=projection).sort([(START, pymongo.ASCENDING)],):
294+
data_coll = self._collection.with_options(read_preference=self._read_preference(allow_secondary))
295+
for b in data_coll.find(query, projection=projection).sort([(START, pymongo.ASCENDING)],):
281296
data = self._read_bucket(b, column_set, column_dtypes,
282297
multiple_symbols or (columns is not None and 'SYMBOL' in columns),
283298
include_images, columns)

tests/integration/tickstore/test_ts_read.py

+41-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from datetime import datetime as dt
2-
from mock import patch
2+
from mock import patch, call
33
import numpy as np
44
from numpy.testing.utils import assert_array_equal
55
from pandas.util.testing import assert_frame_equal
66
import pandas as pd
77
from pandas.tseries.index import DatetimeIndex
8+
from pymongo import ReadPreference
89
import pytest
910
import pytz
1011

@@ -44,6 +45,44 @@ def test_read(tickstore_lib):
4445
assert tickstore_lib._collection.find_one()['c'] == 2
4546

4647

48+
def test_read_allow_secondary(tickstore_lib):
49+
data = [{'ASK': 1545.25,
50+
'ASKSIZE': 1002.0,
51+
'BID': 1545.0,
52+
'BIDSIZE': 55.0,
53+
'CUMVOL': 2187387.0,
54+
'DELETED_TIME': 0,
55+
'INSTRTYPE': 'FUT',
56+
'PRICE': 1545.0,
57+
'SIZE': 1.0,
58+
'TICK_STATUS': 0,
59+
'TRADEHIGH': 1561.75,
60+
'TRADELOW': 1537.25,
61+
'index': 1185076787070},
62+
{'CUMVOL': 354.0,
63+
'DELETED_TIME': 0,
64+
'PRICE': 1543.75,
65+
'SIZE': 354.0,
66+
'TRADEHIGH': 1543.75,
67+
'TRADELOW': 1543.75,
68+
'index': 1185141600600}]
69+
tickstore_lib.write('FEED::SYMBOL', data)
70+
71+
72+
with patch('pymongo.collection.Collection.find', side_effect=tickstore_lib._collection.find) as find:
73+
with patch('pymongo.collection.Collection.with_options', side_effect=tickstore_lib._collection.with_options) as with_options:
74+
with patch.object(tickstore_lib, '_read_preference', side_effect=tickstore_lib._read_preference) as read_pref:
75+
df = tickstore_lib.read('FEED::SYMBOL', columns=['BID', 'ASK', 'PRICE'], allow_secondary=True)
76+
assert read_pref.call_args_list == [call(True)]
77+
assert with_options.call_args_list == [call(read_preference=ReadPreference.NEAREST)]
78+
assert find.call_args_list == [call({'sy': 'FEED::SYMBOL'}, sort=[('s', 1)], projection={'s': 1, '_id': 0}),
79+
call({'sy': 'FEED::SYMBOL', 's': {'$lte': dt(2007, 8, 21, 3, 59, 47, 70000)}},
80+
projection={'sy': 1, 'cs.PRICE': 1, 'i': 1, 'cs.BID': 1, 's': 1, 'im': 1, 'v': 1, 'cs.ASK': 1})]
81+
82+
assert_array_equal(df['ASK'].values, np.array([1545.25, np.nan]))
83+
assert tickstore_lib._collection.find_one()['c'] == 2
84+
85+
4786
def test_read_symbol_as_column(tickstore_lib):
4887
data = [{'ASK': 1545.25,
4988
'index': 1185076787070},
@@ -168,7 +207,7 @@ def test_date_range(tickstore_lib):
168207
tickstore_lib._chunk_size = 3
169208
tickstore_lib.write('SYM', DUMMY_DATA)
170209

171-
with patch.object(tickstore_lib._collection, 'find', side_effect=tickstore_lib._collection.find) as f:
210+
with patch('pymongo.collection.Collection.find', side_effect=tickstore_lib._collection.find) as f:
172211
df = tickstore_lib.read('SYM', date_range=DateRange(20130101, 20130103), columns=None)
173212
assert_array_equal(df['b'].values, np.array([2., 3., 5.]))
174213
assert tickstore_lib._collection.find(f.call_args_list[-1][0][0]).count() == 1

tests/unit/tickstore/test_tickstore.py

+21
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from functools import partial
33
from mock import create_autospec, sentinel, call
44
import pytest
5+
from pymongo import ReadPreference
56
from pymongo.collection import Collection
67
import numpy as np
78
import pandas as pd
@@ -164,3 +165,23 @@ def test_tickstore_pandas_to_bucket_image():
164165
assert bucket[SYMBOL] == symbol
165166
assert bucket[IMAGE_DOC] == {IMAGE: initial_image,
166167
IMAGE_TIME: initial_image['index']}
168+
169+
170+
def test__read_preference__allow_secondary_true():
171+
self = create_autospec(TickStore)
172+
assert TickStore._read_preference(self, True) == ReadPreference.NEAREST
173+
174+
175+
def test__read_preference__allow_secondary_false():
176+
self = create_autospec(TickStore)
177+
assert TickStore._read_preference(self, False) == ReadPreference.PRIMARY
178+
179+
180+
def test__read_preference__default_true():
181+
self = create_autospec(TickStore, _allow_secondary=True)
182+
assert TickStore._read_preference(self, None) == ReadPreference.NEAREST
183+
184+
185+
def test__read_preference__default_false():
186+
self = create_autospec(TickStore, _allow_secondary=False)
187+
assert TickStore._read_preference(self, None) == ReadPreference.PRIMARY

0 commit comments

Comments
 (0)