@@ -125,7 +125,16 @@ def __getitem__(self, k):
125125
126126 def create (self , ** kwargs ):
127127 """
128- A convenience method for creating an object and saving it all in one step.
128+ A convenience method for creating an object and saving it all in one step. Thus::
129+
130+ instance = Instance.please.create(name='test-one', description='description')
131+
132+ and::
133+
134+ instance = Instance(name='test-one', description='description')
135+ instance.save()
136+
137+ are equivalent.
129138 """
130139 attrs = kwargs .copy ()
131140 attrs .update (self .properties )
@@ -139,83 +148,180 @@ def bulk_create(self, objects):
139148 """
140149 Creates many new instances based on provided list of objects.
141150
151+ Usage::
152+
153+ objects = [{'name': 'test-one'}, {'name': 'test-two'}]
154+ instances = Instance.please.bulk_create(objects)
155+
142156 .. warning::
143- This method is not meant to be used with large datasets .
157+ This method is not meant to be used with large data sets .
144158 """
145159 return [self .create (** o ) for o in objects ]
146160
147161 @clone
148162 def get (self , * args , ** kwargs ):
149- """Returns the object matching the given lookup parameters."""
163+ """
164+ Returns the object matching the given lookup parameters.
165+
166+ Usage::
167+
168+ instance = Instance.please.get('test-one')
169+ instance = Instance.please.get(name='test-one')
170+ """
150171 self .method = 'GET'
151172 self .endpoint = 'detail'
152173 self ._filter (* args , ** kwargs )
153174 return self .request ()
154175
155176 def detail (self , * args , ** kwargs ):
156- """Wrapper around ``get`` method."""
177+ """
178+ Wrapper around ``get`` method.
179+
180+ Usage::
181+
182+ instance = Instance.please.detail('test-one')
183+ instance = Instance.please.detail(name='test-one')
184+ """
157185 return self .get (* args , ** kwargs )
158186
159187 def get_or_create (self , * args , ** kwargs ):
160- """A convenience method for looking up an object with the given
161- lookup parameters, creating one if necessary."""
188+ """
189+ A convenience method for looking up an object with the given
190+ lookup parameters, creating one if necessary.
191+
192+ Returns a tuple of **(object, created)**, where **object** is the retrieved or
193+ **created** object and created is a boolean specifying whether a new object was created.
194+
195+ This is meant as a shortcut to boilerplatish code. For example::
196+
197+ try:
198+ instance = Instance.please.get(name='test-one')
199+ except Instance.DoesNotExist:
200+ instance = Instance(name='test-one', description='test')
201+ instance.save()
202+
203+ The above example can be rewritten using **get_or_create()** like so::
204+
205+ instance, created = Instance.please.get_or_create(name='test-one', defaults={'description': 'test'})
206+ """
162207 defaults = deepcopy (kwargs .pop ('defaults' , {}))
163208 try :
164209 instance = self .get (* args , ** kwargs )
165210 except self .model .DoesNotExist :
166211 defaults .update (kwargs )
167212 instance = self .create (** defaults )
168- return instance
213+ created = True
214+ else :
215+ created = False
216+ return instance , created
169217
170218 @clone
171219 def delete (self , * args , ** kwargs ):
172- """Removes single instance based on provided arguments."""
220+ """
221+ Removes single instance based on provided arguments.
222+
223+ Usage::
224+
225+ instance = Instance.please.delete('test-one')
226+ instance = Instance.please.delete(name='test-one')
227+ """
173228 self .method = 'DELETE'
174229 self .endpoint = 'detail'
175230 self ._filter (* args , ** kwargs )
176231 return self .request ()
177232
178233 @clone
179234 def update (self , * args , ** kwargs ):
180- """Updates single instance based on provided arguments."""
235+ """
236+ Updates single instance based on provided arguments.
237+ The **data** is a dictionary of (field, value) pairs used to update the object.
238+
239+ Usage::
240+
241+ instance = Instance.please.update('test-one', data={'description': 'new one'})
242+ instance = Instance.please.update(name='test-one', data={'description': 'new one'})
243+ """
181244 self .method = 'PUT'
182245 self .endpoint = 'detail'
183- self .data = kwargs .pop ('data ' )
246+ self .data = kwargs .pop ('defaults ' )
184247 self ._filter (* args , ** kwargs )
185248 return self .request ()
186249
187- def update_or_create (self , * args , ** kwargs ):
250+ def update_or_create (self , defaults = None , ** kwargs ):
188251 """
189252 A convenience method for updating an object with the given parameters, creating a new one if necessary.
190253 The ``defaults`` is a dictionary of (field, value) pairs used to update the object.
254+
255+ Returns a tuple of **(object, created)**, where object is the created or updated object and created
256+ is a boolean specifying whether a new object was created.
257+
258+ The **update_or_create** method tries to fetch an object from Syncano API based on the given kwargs.
259+ If a match is found, it updates the fields passed in the defaults dictionary.
260+
261+ This is meant as a shortcut to boilerplatish code. For example::
262+
263+ try:
264+ instance = Instance.please.update(name='test-one', data=updated_values)
265+ except Instance.DoesNotExist:
266+ updated_values.update({'name': 'test-one'})
267+ instance = Instance(**updated_values)
268+ instance.save()
269+
270+ This pattern gets quite unwieldy as the number of fields in a model goes up.
271+ The above example can be rewritten using **update_or_create()** like so::
272+
273+ instance, created = Instance.please.update_or_create(name='test-one',
274+ defaults=updated_values)
191275 """
192- defaults = deepcopy (kwargs . get ( ' defaults' , {}) )
276+ defaults = deepcopy (defaults or {} )
193277 try :
194- instance = self .update (* args , * *kwargs )
278+ instance = self .update (** kwargs )
195279 except self .model .DoesNotExist :
196280 defaults .update (kwargs )
197281 instance = self .create (** defaults )
198- return instance
282+ created = True
283+ else :
284+ created = False
285+ return instance , created
199286
200287 # List actions
201288
202289 @clone
203290 def all (self , * args , ** kwargs ):
204- """Returns a copy of the current ``Manager`` with limit removed."""
291+ """
292+ Returns a copy of the current ``Manager`` with limit removed.
293+
294+ Usage::
295+
296+ instances = Instance.please.all()
297+ """
205298 self ._limit = None
206299 return self .list (* args , ** kwargs )
207300
208301 @clone
209302 def list (self , * args , ** kwargs ):
210- """Returns a copy of the current ``Manager`` containing objects that match the given lookup parameters."""
303+ """
304+ Returns a copy of the current ``Manager`` containing objects that match the given lookup parameters.
305+
306+ Usage::
307+ instance = Instance.please.list()
308+ classes = Class.please.list(instance_name='test-one')
309+ """
211310 self .method = 'GET'
212311 self .endpoint = 'list'
213312 self ._filter (* args , ** kwargs )
214313 return self
215314
216315 @clone
217316 def first (self , * args , ** kwargs ):
218- """Returns the first object matched by the lookup parameters or None, if there is no matching object."""
317+ """
318+ Returns the first object matched by the lookup parameters or None, if there is no matching object.
319+
320+ Usage::
321+
322+ instance = Instance.please.first()
323+ classes = Class.please.first(instance_name='test-one')
324+ """
219325 try :
220326 self ._limit = 1
221327 return self .list (* args , ** kwargs )[0 ]
@@ -224,7 +330,13 @@ def first(self, *args, **kwargs):
224330
225331 @clone
226332 def page_size (self , value ):
227- """Sets page size."""
333+ """
334+ Sets page size.
335+
336+ Usage::
337+
338+ instances = Instance.please.page_size(20).all()
339+ """
228340 if not value or not isinstance (value , six .integer_types ):
229341 raise SyncanoValueError ('page_size value needs to be an int.' )
230342
@@ -233,7 +345,14 @@ def page_size(self, value):
233345
234346 @clone
235347 def limit (self , value ):
236- """Sets limit of returned objects."""
348+ """
349+ Sets limit of returned objects.
350+
351+ Usage::
352+
353+ instances = Instance.please.list().limit(10)
354+ classes = Class.please.list(instance_name='test-one').limit(10)
355+ """
237356 if not value or not isinstance (value , six .integer_types ):
238357 raise SyncanoValueError ('Limit value needs to be an int.' )
239358
@@ -242,7 +361,13 @@ def limit(self, value):
242361
243362 @clone
244363 def order_by (self , field ):
245- """Sets order of returned objects."""
364+ """
365+ Sets order of returned objects.
366+
367+ Usage::
368+
369+ instances = Instance.please.order_by('name')
370+ """
246371 if not field or not isinstance (field , six .string_types ):
247372 raise SyncanoValueError ('Order by field needs to be a string.' )
248373
@@ -251,13 +376,23 @@ def order_by(self, field):
251376
252377 @clone
253378 def raw (self ):
254- """Disables serialization. ``request`` method will return raw Python types."""
379+ """
380+ Disables serialization. ``request`` method will return raw Python types.
381+
382+ Usage::
383+
384+ >>> instances = Instance.please.list().raw()
385+ >>> instances
386+ [{'description': 'new one', 'name': 'test-one'...}...]
387+ """
255388 self ._serialize = False
256389 return self
257390
258391 @clone
259392 def using (self , connection ):
260- """Connection juggling."""
393+ """
394+ Connection juggling.
395+ """
261396 # ConnectionMixin will validate this
262397 self .connection = connection
263398 return self
@@ -390,7 +525,7 @@ def create(self, **kwargs):
390525
391526 return instance
392527
393- def serialize (self , data ):
528+ def serialize (self , data , model = None ):
394529 model = self .get_class_model (self .properties )
395530 return super (ObjectManager , self ).serialize (data , model )
396531
@@ -421,6 +556,13 @@ def get_class_schema(self, properties):
421556
422557 @clone
423558 def filter (self , ** kwargs ):
559+ """
560+ Special method just for data object :class:`~syncano.models.base.Object` model.
561+
562+ Usage::
563+
564+ objects = Object.please.list('instance-name', 'class-name').filter(henryk__gte='hello')
565+ """
424566 query = {}
425567 model = self .get_class_model (self .properties )
426568
0 commit comments