Skip to content

Commit cf2abf1

Browse files
authored
Merge pull request #1449 from quantopian/getitem-is-not-getattr
MAINT: remove __getitem__ as alias of __getattr__
2 parents 393aa06 + a3e869e commit cf2abf1

File tree

6 files changed

+163
-80
lines changed

6 files changed

+163
-80
lines changed

tests/test_algorithm.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,9 +1448,10 @@ def before_trading_start(context, data):
14481448
assert (context.hd_portfolio.__dict__[k]
14491449
== bts_portfolio.__dict__[k])
14501450
record(pos_value=bts_portfolio.positions_value)
1451-
record(pos_amount=bts_portfolio.positions[sid(3)]['amount'])
1452-
record(last_sale_price=bts_portfolio.positions[sid(3)]
1453-
['last_sale_price'])
1451+
record(pos_amount=bts_portfolio.positions[sid(3)].amount)
1452+
record(
1453+
last_sale_price=bts_portfolio.positions[sid(3)].last_sale_price
1454+
)
14541455
def handle_data(context, data):
14551456
if not context.ordered:
14561457
order(sid(3), 1)

tests/test_perf_tracking.py

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -111,26 +111,26 @@ def check_account(account,
111111
# so net and gross leverage are equal.
112112

113113
np.testing.assert_allclose(settled_cash,
114-
account['settled_cash'], rtol=1e-3)
114+
account.settled_cash, rtol=1e-3)
115115
np.testing.assert_allclose(equity_with_loan,
116-
account['equity_with_loan'], rtol=1e-3)
116+
account.equity_with_loan, rtol=1e-3)
117117
np.testing.assert_allclose(total_positions_value,
118-
account['total_positions_value'], rtol=1e-3)
118+
account.total_positions_value, rtol=1e-3)
119119
np.testing.assert_allclose(total_positions_exposure,
120-
account['total_positions_exposure'], rtol=1e-3)
120+
account.total_positions_exposure, rtol=1e-3)
121121
np.testing.assert_allclose(regt_equity,
122-
account['regt_equity'], rtol=1e-3)
122+
account.regt_equity, rtol=1e-3)
123123
np.testing.assert_allclose(available_funds,
124-
account['available_funds'], rtol=1e-3)
124+
account.available_funds, rtol=1e-3)
125125
np.testing.assert_allclose(excess_liquidity,
126-
account['excess_liquidity'], rtol=1e-3)
126+
account.excess_liquidity, rtol=1e-3)
127127
np.testing.assert_allclose(cushion,
128-
account['cushion'], rtol=1e-3)
129-
np.testing.assert_allclose(leverage, account['leverage'], rtol=1e-3)
128+
account.cushion, rtol=1e-3)
129+
np.testing.assert_allclose(leverage, account.leverage, rtol=1e-3)
130130
np.testing.assert_allclose(net_leverage,
131-
account['net_leverage'], rtol=1e-3)
131+
account.net_leverage, rtol=1e-3)
132132
np.testing.assert_allclose(net_liquidation,
133-
account['net_liquidation'], rtol=1e-3)
133+
account.net_liquidation, rtol=1e-3)
134134

135135

136136
def create_txn(asset, dt, price, amount):
@@ -368,28 +368,28 @@ def test_split_long_position(self):
368368

369369
# Validate that the account attributes were updated.
370370
account = results[1]['account']
371-
self.assertEqual(float('inf'), account['day_trades_remaining'])
371+
self.assertEqual(float('inf'), account.day_trades_remaining)
372372
# this is a long only portfolio that is only partially invested
373373
# so net and gross leverage are equal.
374-
np.testing.assert_allclose(0.198, account['leverage'], rtol=1e-3)
375-
np.testing.assert_allclose(0.198, account['net_leverage'], rtol=1e-3)
376-
np.testing.assert_allclose(8020, account['regt_equity'], rtol=1e-3)
377-
self.assertEqual(float('inf'), account['regt_margin'])
378-
np.testing.assert_allclose(8020, account['available_funds'], rtol=1e-3)
379-
self.assertEqual(0, account['maintenance_margin_requirement'])
374+
np.testing.assert_allclose(0.198, account.leverage, rtol=1e-3)
375+
np.testing.assert_allclose(0.198, account.net_leverage, rtol=1e-3)
376+
np.testing.assert_allclose(8020, account.regt_equity, rtol=1e-3)
377+
self.assertEqual(float('inf'), account.regt_margin)
378+
np.testing.assert_allclose(8020, account.available_funds, rtol=1e-3)
379+
self.assertEqual(0, account.maintenance_margin_requirement)
380380
np.testing.assert_allclose(10000,
381-
account['equity_with_loan'], rtol=1e-3)
382-
self.assertEqual(float('inf'), account['buying_power'])
383-
self.assertEqual(0, account['initial_margin_requirement'])
384-
np.testing.assert_allclose(8020, account['excess_liquidity'],
381+
account.equity_with_loan, rtol=1e-3)
382+
self.assertEqual(float('inf'), account.buying_power)
383+
self.assertEqual(0, account.initial_margin_requirement)
384+
np.testing.assert_allclose(8020, account.excess_liquidity,
385385
rtol=1e-3)
386-
np.testing.assert_allclose(8020, account['settled_cash'], rtol=1e-3)
387-
np.testing.assert_allclose(10000, account['net_liquidation'],
386+
np.testing.assert_allclose(8020, account.settled_cash, rtol=1e-3)
387+
np.testing.assert_allclose(10000, account.net_liquidation,
388388
rtol=1e-3)
389-
np.testing.assert_allclose(0.802, account['cushion'], rtol=1e-3)
390-
np.testing.assert_allclose(1980, account['total_positions_value'],
389+
np.testing.assert_allclose(0.802, account.cushion, rtol=1e-3)
390+
np.testing.assert_allclose(1980, account.total_positions_value,
391391
rtol=1e-3)
392-
self.assertEqual(0, account['accrued_interest'])
392+
self.assertEqual(0, account.accrued_interest)
393393

394394
for i, result in enumerate(results):
395395
for perf_kind in ('daily_perf', 'cumulative_perf'):
@@ -1346,10 +1346,10 @@ def test_long_position(self):
13461346

13471347
self.assertEqual(
13481348
pp.positions[1].last_sale_price,
1349-
trades[-1]['price'],
1349+
trades[-1].price,
13501350
"last sale should be same as last trade. \
13511351
expected {exp} actual {act}".format(
1352-
exp=trades[-1]['price'],
1352+
exp=trades[-1].price,
13531353
act=pp.positions[1].last_sale_price)
13541354
)
13551355

@@ -1456,7 +1456,7 @@ def test_short_position(self):
14561456

14571457
self.assertEqual(
14581458
pp.positions[1].last_sale_price,
1459-
trades_1[-1]['price'],
1459+
trades_1[-1].price,
14601460
"last sale should be price of last trade"
14611461
)
14621462

zipline/finance/controls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,5 +394,5 @@ def validate(self,
394394
"""
395395
Fail if the leverage is greater than the allowed leverage.
396396
"""
397-
if _account['leverage'] > self.max_leverage:
397+
if _account.leverage > self.max_leverage:
398398
self.fail()

zipline/protocol.py

Lines changed: 104 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2013 Quantopian, Inc.
2+
# Copyright 2016 Quantopian, Inc.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -12,10 +12,11 @@
1212
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
15+
from warnings import warn
16+
1517
import pandas as pd
1618

1719
from .utils.enum import enum
18-
1920
from zipline._protocol import BarData # noqa
2021

2122

@@ -61,16 +62,7 @@ class Event(object):
6162

6263
def __init__(self, initial_values=None):
6364
if initial_values:
64-
self.__dict__ = initial_values
65-
66-
def __getitem__(self, name):
67-
return getattr(self, name)
68-
69-
def __setitem__(self, name, value):
70-
setattr(self, name, value)
71-
72-
def __delitem__(self, name):
73-
delattr(self, name)
65+
self.__dict__.update(initial_values)
7466

7567
def keys(self):
7668
return self.__dict__.keys()
@@ -88,8 +80,52 @@ def to_series(self, index=None):
8880
return pd.Series(self.__dict__, index=index)
8981

9082

83+
def _deprecated_getitem_method(name, attrs):
84+
"""Create a deprecated ``__getitem__`` method that tells users to use
85+
getattr instead.
86+
87+
Parameters
88+
----------
89+
name : str
90+
The name of the object in the warning message.
91+
attrs : iterable[str]
92+
The set of allowed attributes.
93+
94+
Returns
95+
-------
96+
__getitem__ : callable[any, str]
97+
The ``__getitem__`` method to put in the class dict.
98+
"""
99+
attrs = frozenset(attrs)
100+
msg = "'{0}[attr]' is deprecated, please use '{0}.attr' instead".format(
101+
name,
102+
)
103+
104+
def __getitem__(self, key):
105+
"""``__getitem__`` is deprecated, please use attribute access instead.
106+
"""
107+
warn(msg, DeprecationWarning, stacklevel=1)
108+
if key in attrs:
109+
return self.__dict__[key]
110+
raise KeyError(key)
111+
112+
return __getitem__
113+
114+
91115
class Order(Event):
92-
pass
116+
# If you are adding new attributes, don't update this set. This method
117+
# is deprecated to normal attribute access so we don't want to encourage
118+
# new usages.
119+
__getitem__ = _deprecated_getitem_method(
120+
'order', {
121+
'dt',
122+
'sid',
123+
'amount',
124+
'stop',
125+
'limit',
126+
'id',
127+
},
128+
)
93129

94130

95131
class Portfolio(object):
@@ -105,12 +141,26 @@ def __init__(self):
105141
self.start_date = None
106142
self.positions_value = 0.0
107143

108-
def __getitem__(self, key):
109-
return self.__dict__[key]
110-
111144
def __repr__(self):
112145
return "Portfolio({0})".format(self.__dict__)
113146

147+
# If you are adding new attributes, don't update this set. This method
148+
# is deprecated to normal attribute access so we don't want to encourage
149+
# new usages.
150+
__getitem__ = _deprecated_getitem_method(
151+
'portfolio', {
152+
'capital_used',
153+
'starting_cash',
154+
'portfolio_value',
155+
'pnl',
156+
'returns',
157+
'cash',
158+
'positions',
159+
'start_date',
160+
'positions_value',
161+
},
162+
)
163+
114164

115165
class Account(object):
116166
'''
@@ -139,12 +189,34 @@ def __init__(self):
139189
self.net_leverage = 0.0
140190
self.net_liquidation = 0.0
141191

142-
def __getitem__(self, key):
143-
return self.__dict__[key]
144-
145192
def __repr__(self):
146193
return "Account({0})".format(self.__dict__)
147194

195+
# If you are adding new attributes, don't update this set. This method
196+
# is deprecated to normal attribute access so we don't want to encourage
197+
# new usages.
198+
__getitem__ = _deprecated_getitem_method(
199+
'account', {
200+
'settled_cash',
201+
'accrued_interest',
202+
'buying_power',
203+
'equity_with_loan',
204+
'total_positions_value',
205+
'total_positions_exposure',
206+
'regt_equity',
207+
'regt_margin',
208+
'initial_margin_requirement',
209+
'maintenance_margin_requirement',
210+
'available_funds',
211+
'excess_liquidity',
212+
'cushion',
213+
'day_trades_remaining',
214+
'leverage',
215+
'net_leverage',
216+
'net_liquidation',
217+
},
218+
)
219+
148220

149221
class Position(object):
150222

@@ -155,12 +227,22 @@ def __init__(self, sid):
155227
self.last_sale_price = 0.0
156228
self.last_sale_date = None
157229

158-
def __getitem__(self, key):
159-
return self.__dict__[key]
160-
161230
def __repr__(self):
162231
return "Position({0})".format(self.__dict__)
163232

233+
# If you are adding new attributes, don't update this set. This method
234+
# is deprecated to normal attribute access so we don't want to encourage
235+
# new usages.
236+
__getitem__ = _deprecated_getitem_method(
237+
'position', {
238+
'sid',
239+
'amount',
240+
'cost_basis',
241+
'last_sale_price',
242+
'last_sale_date',
243+
},
244+
)
245+
164246

165247
class Positions(dict):
166248

0 commit comments

Comments
 (0)