66from .blob import unpack
77from . import DataJointError
88from . import key as PRIMARY_KEY
9+ import warnings
910
1011
1112def update_dict (d1 , d2 ):
@@ -25,9 +26,13 @@ def __init__(self, arg):
2526
2627 def copy (self ):
2728 """
29+ DEPRECATED
30+
2831 Creates and returns a copy of this object
2932 :return: copy FetchBase derivatives
3033 """
34+ warnings .warn ('Use of `copy` on `fetch` object is deprecated' , stacklevel = 2 )
35+
3136 return self .__class__ (self )
3237
3338 def _initialize_behavior (self ):
@@ -37,9 +42,15 @@ def _initialize_behavior(self):
3742 @property
3843 def squeeze (self ):
3944 """
45+ DEPRECATED
46+
4047 Changes the state of the fetch object to squeeze the returned values as much as possible.
4148 :return: a copy of the fetch object
4249 """
50+
51+ warnings .warn ('Use of `squeeze` on `fetch` object is deprecated. Please use `squeeze=True` keyword arguments '
52+ 'in the call to `fetch`/`keys` instead' , stacklevel = 2 )
53+
4354 ret = self .copy ()
4455 ret .ext_behavior ['squeeze' ] = True
4556 return ret
@@ -60,6 +71,9 @@ def _prepare_attributes(item):
6071 raise DataJointError ("Index must be a sequence or a string." )
6172 return item , attributes
6273
74+ def __len__ (self ):
75+ return len (self ._relation )
76+
6377
6478
6579
@@ -76,6 +90,8 @@ def _initialize_behavior(self):
7690
7791 def order_by (self , * args ):
7892 """
93+ DEPRECATED
94+
7995 Changes the state of the fetch object to order the results by a particular attribute.
8096 The commands are handed down to mysql.
8197 :param args: the attributes to sort by. If DESC is passed after the name, then the order is descending.
@@ -85,6 +101,8 @@ def order_by(self, *args):
85101 >>> my_relation.fetch.order_by('language', 'name DESC')
86102
87103 """
104+ warnings .warn ('Use of `order_by` on `fetch` object is deprecated. Please use `order_by` keyword arguments in '
105+ 'the call to `fetch`/`keys` instead' , stacklevel = 2 )
88106 self = Fetch (self )
89107 if len (args ) > 0 :
90108 self .sql_behavior ['order_by' ] = args
@@ -93,71 +111,103 @@ def order_by(self, *args):
93111 @property
94112 def as_dict (self ):
95113 """
114+ DEPRECATED
115+
96116 Changes the state of the fetch object to return dictionaries.
97117 :return: a copy of the fetch object
98118 Example:
99119
100120 >>> my_relation.fetch.as_dict()
101121
102122 """
123+ warnings .warn ('Use of `as_dict` on `fetch` object is deprecated. Please use `as_dict` keyword arguments in the '
124+ 'call to `fetch`/`keys` instead' , stacklevel = 2 )
103125 ret = Fetch (self )
104126 ret .sql_behavior ['as_dict' ] = True
105127 return ret
106128
107129 def limit (self , limit ):
108130 """
131+ DEPRECATED
132+
109133 Limits the number of items fetched.
110134
111135 :param limit: limit on the number of items
112136 :return: a copy of the fetch object
113137 """
138+ warnings .warn ('Use of `limit` on `fetch` object is deprecated. Please use `limit` keyword arguments in '
139+ 'the call to `fetch`/`keys` instead' , stacklevel = 2 )
114140 ret = Fetch (self )
115141 ret .sql_behavior ['limit' ] = limit
116142 return ret
117143
118144 def offset (self , offset ):
119145 """
146+ DEPRECATED
147+
120148 Offsets the number of itms fetched. Needs to be applied with limit.
121149
122150 :param offset: offset
123151 :return: a copy of the fetch object
124152 """
153+
154+ warnings .warn ('Use of `offset` on `fetch` object is deprecated. Please use `offset` keyword arguments in '
155+ 'the call to `fetch`/`keys` instead' , stacklevel = 2 )
125156 ret = Fetch (self )
126157 if ret .sql_behavior ['limit' ] is None :
127158 warnings .warn ('You should supply a limit together with an offset,' )
128159 ret .sql_behavior ['offset' ] = offset
129160 return ret
130161
131- def __call__ (self , ** kwargs ):
162+ def __call__ (self , * attrs , * *kwargs ):
132163 """
133164 Fetches the relation from the database table into an np.array and unpacks blob attributes.
134165
166+ :param attrs: OPTIONAL. one or more attributes to fetch. If not provided, the call will return
167+ all attributes of this relation. If provided, returns tuples with an entry for each attribute.
135168 :param offset: the number of tuples to skip in the returned result
136169 :param limit: the maximum number of tuples to return
137170 :param order_by: the list of attributes to order the results. No ordering should be assumed if order_by=None.
138171 :param as_dict: returns a list of dictionaries instead of a record array
139172 :return: the contents of the relation in the form of a structured numpy.array
140173 """
174+ # if 'order_by' passed in a string, make into list
175+ if isinstance (kwargs .get ('order_by' ), str ):
176+ kwargs ['order_by' ] = [kwargs ['order_by' ]]
177+
141178 sql_behavior = update_dict (self .sql_behavior , kwargs )
142179 ext_behavior = update_dict (self .ext_behavior , kwargs )
180+ total_behavior = dict (sql_behavior )
181+ total_behavior .update (ext_behavior )
143182
144183 unpack_ = partial (unpack , squeeze = ext_behavior ['squeeze' ])
145184
146185 if sql_behavior ['limit' ] is None and sql_behavior ['offset' ] is not None :
147186 warnings .warn ('Offset set, but no limit. Setting limit to a large number. '
148187 'Consider setting a limit explicitly.' )
149188 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 ]))
189+
190+ if len (attrs ) == 0 : # fetch all attributes
191+ cur = self ._relation .cursor (** sql_behavior )
192+ heading = self ._relation .heading
193+ if sql_behavior ['as_dict' ]:
194+ ret = [OrderedDict ((name , unpack_ (d [name ]) if heading [name ].is_blob else d [name ])
195+ for name in heading .names )
196+ for d in cur .fetchall ()]
197+ else :
198+ ret = list (cur .fetchall ())
199+ ret = np .array (ret , dtype = heading .as_dtype )
200+ for blob_name in heading .blobs :
201+ ret [blob_name ] = list (map (unpack_ , ret [blob_name ]))
202+
203+ else : # if list of attributes provided
204+ attributes = [a for a in attrs if a is not PRIMARY_KEY ]
205+ result = self ._relation .proj (* attributes ).fetch (** total_behavior )
206+ return_values = [
207+ list (to_dicts (result [self ._relation .primary_key ]))
208+ if attribute is PRIMARY_KEY else result [attribute ]
209+ for attribute in attrs ]
210+ ret = return_values [0 ] if len (attrs ) == 1 else return_values
161211
162212 return ret
163213
@@ -193,6 +243,8 @@ def keys(self, **kwargs):
193243
194244 def __getitem__ (self , item ):
195245 """
246+ DEPRECATED
247+
196248 Fetch attributes as separate outputs.
197249 datajoint.key is a special value that requests the entire primary key
198250 :return: tuple with an entry for each element of item
@@ -201,6 +253,10 @@ def __getitem__(self, item):
201253 >>> a, b = relation['a', 'b']
202254 >>> a, b, key = relation['a', 'b', datajoint.key]
203255 """
256+
257+ warnings .warn ('Use of `rel.fetch[a, b]` notation is deprecated. Please use `rel.fetch(a, b) for equivalent '
258+ 'result' , stacklevel = 2 )
259+
204260 behavior = dict (self .sql_behavior )
205261 behavior .update (self .ext_behavior )
206262
@@ -222,8 +278,7 @@ def __repr__(self):
222278 ["\t {key}:\t {value}" .format (key = k , value = str (v )) for k , v in behavior .items () if v is not None ])
223279 return repr_str
224280
225- def __len__ (self ):
226- return len (self ._relation )
281+
227282
228283
229284class Fetch1 (FetchBase , Callable ):
@@ -233,28 +288,43 @@ class Fetch1(FetchBase, Callable):
233288 :param relation: relation the fetch object fetches data from
234289 """
235290
236- def __call__ (self , ** kwargs ):
291+ def __call__ (self , * attrs , * *kwargs ):
237292 """
238293 This version of fetch is called when self is expected to contain exactly one tuple.
239294 :return: the one tuple in the relation in the form of a dict
240295 """
241296 heading = self ._relation .heading
242297
243- #sql_behavior = update_dict(self.sql_behavior, kwargs)
298+ # sql_behavior = update_dict(self.sql_behavior, kwargs)
244299 ext_behavior = update_dict (self .ext_behavior , kwargs )
245300
246301 unpack_ = partial (unpack , squeeze = ext_behavior ['squeeze' ])
247302
303+ if len (attrs ) == 0 : # fetch all attributes
304+ cur = self ._relation .cursor (as_dict = True )
305+ ret = cur .fetchone ()
306+ if not ret or cur .fetchone ():
307+ raise DataJointError ('fetch1 should only be used for relations with exactly one tuple' )
308+ ret = OrderedDict ((name , unpack_ (ret [name ]) if heading [name ].is_blob else ret [name ])
309+ for name in heading .names )
310+ else :
311+ attributes = [a for a in attrs if a is not PRIMARY_KEY ]
312+ result = self ._relation .proj (* attributes ).fetch (** ext_behavior )
313+ if len (result ) != 1 :
314+ raise DataJointError ('fetch1 should only return one tuple. %d tuples were found' % len (result ))
315+ return_values = tuple (
316+ next (to_dicts (result [self ._relation .primary_key ]))
317+ if attribute is PRIMARY_KEY else result [attribute ][0 ]
318+ for attribute in attrs )
319+ ret = return_values [0 ] if len (attrs ) == 1 else return_values
320+
248321
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 )
322+ return ret
255323
256324 def __getitem__ (self , item ):
257325 """
326+ DEPRECATED
327+
258328 Fetch attributes as separate outputs.
259329 datajoint.key is a special value that requests the entire primary key
260330 :return: tuple with an entry for each element of item
@@ -265,10 +335,13 @@ def __getitem__(self, item):
265335 >>> a, b, key = relation['a', 'b', datajoint.key]
266336
267337 """
338+ warnings .warn ('Use of `rel.fetch[a, b]` notation is deprecated. Please use `rel.fetch(a, b) for equivalent '
339+ 'result' , stacklevel = 2 )
340+
268341 behavior = dict (self .sql_behavior )
269342 behavior .update (self .ext_behavior )
270343
271- single_output = isinstance (item , str ) or item is PRIMARY_KEY or isinstance ( item , int )
344+ single_output = isinstance (item , str ) or item is PRIMARY_KEY
272345 item , attributes = self ._prepare_attributes (item )
273346 result = self ._relation .proj (* attributes ).fetch (** behavior )
274347 if len (result ) != 1 :
0 commit comments