Skip to content

Commit ed1f1c4

Browse files
author
Daniel Kopka
committed
[SYNPYTH-9] examples
1 parent 6181599 commit ed1f1c4

File tree

2 files changed

+167
-23
lines changed

2 files changed

+167
-23
lines changed

docs/source/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,5 @@
104104
# texinfo_domain_indices = True
105105
# texinfo_show_urls = 'footnote'
106106
# texinfo_no_detailmenu = False
107+
108+
autodoc_member_order = 'bysource'

syncano/models/manager.py

Lines changed: 165 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)