66from .blob import unpack
77from . import DataJointError
88from . import key as PRIMARY_KEY
9+ import warnings
910
1011
1112def update_dict (d1 , d2 ):
@@ -37,9 +38,15 @@ def _initialize_behavior(self):
3738 @property
3839 def squeeze (self ):
3940 """
41+ DEPRECATED
42+
4043 Changes the state of the fetch object to squeeze the returned values as much as possible.
4144 :return: a copy of the fetch object
4245 """
46+
47+ warnings .warn ('Use of `squeeze` on `fetch` object is deprecated. Please use `squeeze=True` keyword arguments '
48+ 'in the call to `fetch`/`keys` instead' , stacklevel = 2 )
49+
4350 ret = self .copy ()
4451 ret .ext_behavior ['squeeze' ] = True
4552 return ret
@@ -60,6 +67,9 @@ def _prepare_attributes(item):
6067 raise DataJointError ("Index must be a sequence or a string." )
6168 return item , attributes
6269
70+ def __len__ (self ):
71+ return len (self ._relation )
72+
6373
6474
6575
@@ -76,6 +86,8 @@ def _initialize_behavior(self):
7686
7787 def order_by (self , * args ):
7888 """
89+ DEPRECATED
90+
7991 Changes the state of the fetch object to order the results by a particular attribute.
8092 The commands are handed down to mysql.
8193 :param args: the attributes to sort by. If DESC is passed after the name, then the order is descending.
@@ -85,6 +97,8 @@ def order_by(self, *args):
8597 >>> my_relation.fetch.order_by('language', 'name DESC')
8698
8799 """
100+ warnings .warn ('Use of `order_by` on `fetch` object is deprecated. Please use `order_by` keyword arguments in '
101+ 'the call to `fetch`/`keys` instead' , stacklevel = 2 )
88102 self = Fetch (self )
89103 if len (args ) > 0 :
90104 self .sql_behavior ['order_by' ] = args
@@ -93,71 +107,104 @@ def order_by(self, *args):
93107 @property
94108 def as_dict (self ):
95109 """
110+ DEPRECATED
111+
96112 Changes the state of the fetch object to return dictionaries.
97113 :return: a copy of the fetch object
98114 Example:
99115
100116 >>> my_relation.fetch.as_dict()
101117
102118 """
119+ warnings .warn ('Use of `as_dict` on `fetch` object is deprecated. Please use `as_dict` keyword arguments in the '
120+ 'call to `fetch`/`keys` instead' , stacklevel = 2 )
103121 ret = Fetch (self )
104122 ret .sql_behavior ['as_dict' ] = True
105123 return ret
106124
107125 def limit (self , limit ):
108126 """
127+ DEPRECATED
128+
109129 Limits the number of items fetched.
110130
111131 :param limit: limit on the number of items
112132 :return: a copy of the fetch object
113133 """
134+ warnings .warn ('Use of `limit` on `fetch` object is deprecated. Please use `limit` keyword arguments in '
135+ 'the call to `fetch`/`keys` instead' , stacklevel = 2 )
114136 ret = Fetch (self )
115137 ret .sql_behavior ['limit' ] = limit
116138 return ret
117139
118140 def offset (self , offset ):
119141 """
142+ DEPRECATED
143+
120144 Offsets the number of itms fetched. Needs to be applied with limit.
121145
122146 :param offset: offset
123147 :return: a copy of the fetch object
124148 """
149+
150+ warnings .warn ('Use of `offset` on `fetch` object is deprecated. Please use `offset` keyword arguments in '
151+ 'the call to `fetch`/`keys` instead' , stacklevel = 2 )
125152 ret = Fetch (self )
126153 if ret .sql_behavior ['limit' ] is None :
127154 warnings .warn ('You should supply a limit together with an offset,' )
128155 ret .sql_behavior ['offset' ] = offset
129156 return ret
130157
131- def __call__ (self , ** kwargs ):
158+ def __call__ (self , * attrs , * *kwargs ):
132159 """
133160 Fetches the relation from the database table into an np.array and unpacks blob attributes.
134161
162+ :param attrs: OPTIONAL. one or more attributes to fetch. If not provided, the call will return
163+ all attributes of this relation. If provided, returns tuples with an entry for each attribute.
135164 :param offset: the number of tuples to skip in the returned result
136165 :param limit: the maximum number of tuples to return
137166 :param order_by: the list of attributes to order the results. No ordering should be assumed if order_by=None.
138167 :param as_dict: returns a list of dictionaries instead of a record array
139168 :return: the contents of the relation in the form of a structured numpy.array
140169 """
170+ # if 'order_by' passed in a string, make into list
171+ if isinstance (kwargs .get ('order_by' ), str ):
172+ kwargs ['order_by' ] = [kwargs ['order_by' ]]
173+
141174 sql_behavior = update_dict (self .sql_behavior , kwargs )
142175 ext_behavior = update_dict (self .ext_behavior , kwargs )
176+ total_behavior = dict (sql_behavior )
177+ total_behavior .update (ext_behavior )
143178
144179 unpack_ = partial (unpack , squeeze = ext_behavior ['squeeze' ])
145180
146181 if sql_behavior ['limit' ] is None and sql_behavior ['offset' ] is not None :
147182 warnings .warn ('Offset set, but no limit. Setting limit to a large number. '
148183 'Consider setting a limit explicitly.' )
149184 sql_behavior ['limit' ] = 2 * len (self ._relation )
150- cur = self ._relation .cursor (** sql_behavior )
151- heading = self ._relation .heading
152- if sql_behavior ['as_dict' ]:
153- ret = [OrderedDict ((name , unpack_ (d [name ]) if heading [name ].is_blob else d [name ])
154- for name in heading .names )
155- for d in cur .fetchall ()]
156- else :
157- ret = list (cur .fetchall ())
158- ret = np .array (ret , dtype = heading .as_dtype )
159- for blob_name in heading .blobs :
160- ret [blob_name ] = list (map (unpack_ , ret [blob_name ]))
185+
186+ if len (attrs ) == 0 : # fetch all attributes
187+ cur = self ._relation .cursor (** sql_behavior )
188+ heading = self ._relation .heading
189+ if sql_behavior ['as_dict' ]:
190+ ret = [OrderedDict ((name , unpack_ (d [name ]) if heading [name ].is_blob else d [name ])
191+ for name in heading .names )
192+ for d in cur .fetchall ()]
193+ else :
194+ ret = list (cur .fetchall ())
195+ ret = np .array (ret , dtype = heading .as_dtype )
196+ for blob_name in heading .blobs :
197+ ret [blob_name ] = list (map (unpack_ , ret [blob_name ]))
198+
199+ else : # if list of attributes provided
200+ single_output = len (attrs ) == 1
201+ attributes = [a for a in attrs if a is not PRIMARY_KEY ]
202+ result = self ._relation .proj (* attributes ).fetch (** total_behavior )
203+ return_values = [
204+ list (to_dicts (result [self ._relation .primary_key ]))
205+ if attribute is PRIMARY_KEY else result [attribute ]
206+ for attribute in attrs ]
207+ ret = return_values [0 ] if single_output else return_values
161208
162209 return ret
163210
@@ -193,6 +240,8 @@ def keys(self, **kwargs):
193240
194241 def __getitem__ (self , item ):
195242 """
243+ DEPRECATED
244+
196245 Fetch attributes as separate outputs.
197246 datajoint.key is a special value that requests the entire primary key
198247 :return: tuple with an entry for each element of item
@@ -201,6 +250,10 @@ def __getitem__(self, item):
201250 >>> a, b = relation['a', 'b']
202251 >>> a, b, key = relation['a', 'b', datajoint.key]
203252 """
253+
254+ warnings .warn ('Use of `rel.fetch[a, b]` notation is deprecated. Please use `rel.fetch(a, b) for equivalent '
255+ 'result' , stacklevel = 2 )
256+
204257 behavior = dict (self .sql_behavior )
205258 behavior .update (self .ext_behavior )
206259
@@ -222,8 +275,7 @@ def __repr__(self):
222275 ["\t {key}:\t {value}" .format (key = k , value = str (v )) for k , v in behavior .items () if v is not None ])
223276 return repr_str
224277
225- def __len__ (self ):
226- return len (self ._relation )
278+
227279
228280
229281class Fetch1 (FetchBase , Callable ):
@@ -233,28 +285,44 @@ class Fetch1(FetchBase, Callable):
233285 :param relation: relation the fetch object fetches data from
234286 """
235287
236- def __call__ (self , ** kwargs ):
288+ def __call__ (self , * attrs , * *kwargs ):
237289 """
238290 This version of fetch is called when self is expected to contain exactly one tuple.
239291 :return: the one tuple in the relation in the form of a dict
240292 """
241293 heading = self ._relation .heading
242294
243- #sql_behavior = update_dict(self.sql_behavior, kwargs)
295+ # sql_behavior = update_dict(self.sql_behavior, kwargs)
244296 ext_behavior = update_dict (self .ext_behavior , kwargs )
245297
246298 unpack_ = partial (unpack , squeeze = ext_behavior ['squeeze' ])
247299
300+ if len (attrs ) == 0 : # fetch all attributes
301+ cur = self ._relation .cursor (as_dict = True )
302+ ret = cur .fetchone ()
303+ if not ret or cur .fetchone ():
304+ raise DataJointError ('fetch1 should only be used for relations with exactly one tuple' )
305+ ret = OrderedDict ((name , unpack_ (ret [name ]) if heading [name ].is_blob else ret [name ])
306+ for name in heading .names )
307+ else :
308+ single_output = len (attrs ) == 1
309+ attributes = [a for a in attrs if a is not PRIMARY_KEY ]
310+ result = self ._relation .proj (* attributes ).fetch (** ext_behavior )
311+ if len (result ) != 1 :
312+ raise DataJointError ('fetch1 should only return one tuple. %d tuples were found' % len (result ))
313+ return_values = tuple (
314+ next (to_dicts (result [self ._relation .primary_key ]))
315+ if attribute is PRIMARY_KEY else result [attribute ][0 ]
316+ for attribute in attrs )
317+ ret = return_values [0 ] if single_output else return_values
318+
248319
249- cur = self ._relation .cursor (as_dict = True )
250- ret = cur .fetchone ()
251- if not ret or cur .fetchone ():
252- raise DataJointError ('fetch1 should only be used for relations with exactly one tuple' )
253- return OrderedDict ((name , unpack_ (ret [name ]) if heading [name ].is_blob else ret [name ])
254- for name in heading .names )
320+ return ret
255321
256322 def __getitem__ (self , item ):
257323 """
324+ DEPRECATED
325+
258326 Fetch attributes as separate outputs.
259327 datajoint.key is a special value that requests the entire primary key
260328 :return: tuple with an entry for each element of item
@@ -265,10 +333,13 @@ def __getitem__(self, item):
265333 >>> a, b, key = relation['a', 'b', datajoint.key]
266334
267335 """
336+ warnings .warn ('Use of `rel.fetch[a, b]` notation is deprecated. Please use `rel.fetch(a, b) for equivalent '
337+ 'result' , stacklevel = 2 )
338+
268339 behavior = dict (self .sql_behavior )
269340 behavior .update (self .ext_behavior )
270341
271- single_output = isinstance (item , str ) or item is PRIMARY_KEY or isinstance ( item , int )
342+ single_output = isinstance (item , str ) or item is PRIMARY_KEY
272343 item , attributes = self ._prepare_attributes (item )
273344 result = self ._relation .proj (* attributes ).fetch (** behavior )
274345 if len (result ) != 1 :
0 commit comments