Skip to content

Commit 0b13988

Browse files
committed
Merge branch 'release-0.0.5'
2 parents 596f623 + 2190b6b commit 0b13988

19 files changed

+873
-66
lines changed

CHANGELOG.rst

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
Changelog
22
=========
33

4+
0.0.5 - 2014-12-09
5+
------------------
6+
7+
* feature: Add support for batch actions on collections.
8+
(`issue 32 <https://github.com/boto/boto3/pull/32>`__)
9+
* feature: Update to Botocore 0.78.0
10+
11+
* Add support for Amazon Simple Queue Service purge queue which allows
12+
users to delete the messages in their queue.
13+
* Add AWS OpsWorks support for registering and assigning existing Amazon
14+
EC2 instances and on-premises servers.
15+
* Fix issue with expired signatures when retrying failed requests
16+
(`botocore issue 399 <https://github.com/boto/botocore/pull/399>`__)
17+
* Port Route53 resource ID customizations from AWS CLI to Botocore.
18+
(`botocore issue 398 <https://github.com/boto/botocore/pull/398>`__)
19+
* Fix handling of blob type serialization for JSON services.
20+
(`botocore issue 397 <https://github.com/boto/botocore/pull/397>`__)
21+
422
0.0.4 - 2014-12-04
523
------------------
624

@@ -16,7 +34,7 @@ Changelog
1634
* Add support for updating the comment of a Route53 hosted zone.
1735
* Fix base64 serialization for JSON protocol services.
1836
* Fix issue where certain timestamps were not being accepted as valid input
19-
(`botocore issue 389 <https://github.com/boto/botocore/pull/389>`__)
37+
(`botocore issue 389 <https://github.com/boto/botocore/pull/389>`__)
2038

2139
* feature: Update `Amazon EC2 <http://aws.amazon.com/ec2/>`_ resource model.
2240
* feature: Support `belongsTo` resource reference as well as `path`

boto3/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818

1919
__author__ = 'Amazon Web Services'
20-
__version__ = '0.0.4'
20+
__version__ = '0.0.5'
2121

2222

2323
# The default Boto3 session; autoloaded when needed.

boto3/docs.py

+136-12
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,32 @@ def py_type_name(type_name):
6161
}.get(type_name, type_name)
6262

6363

64+
def py_default(type_name):
65+
"""
66+
Get the Python default value for a given model type, useful
67+
for generated examples.
68+
69+
>>> py_default('string')
70+
'\'string\''
71+
>>> py_default('list')
72+
'[...]'
73+
>>> py_default('unknown')
74+
'...'
75+
76+
:rtype: string
77+
"""
78+
return {
79+
'double': '123.0',
80+
'long': '123',
81+
'integer': '123',
82+
'string': "'string'",
83+
'blob': "b'bytes'",
84+
'list': '[...]',
85+
'map': '{...}',
86+
'structure': '{...}',
87+
'timestamp': 'datetime(2015, 1, 1)',
88+
}.get(type_name, '...')
89+
6490
def html_to_rst(html, indent=0, indentFirst=False):
6591
"""
6692
Use bcdoc to convert html to rst.
@@ -105,7 +131,18 @@ def docs_for(service_name):
105131

106132
print('Processing {0}-{1}'.format(service_name, service_model.api_version))
107133

134+
# The following creates an official name of 'Amazon Simple Storage
135+
# Service (S3)' our of 'Amazon Simple Storage Service' and 'Amazon S3'.
136+
# It tries to be smart, so for `Amazon DynamoDB' and 'DynamoDB' we would
137+
# get an official name of 'Amazon DynamoDB'.
108138
official_name = service_model.metadata.get('serviceFullName')
139+
short_name = service_model.metadata.get('serviceAbbreviation', '')
140+
if short_name.startswith('Amazon'):
141+
short_name = short_name[7:]
142+
if short_name.startswith('AWS'):
143+
short_name = short_name[4:]
144+
if short_name and short_name.lower() not in official_name.lower():
145+
official_name += ' ({0})'.format(short_name)
109146

110147
docs = '{0}\n{1}\n\n'.format(official_name, '=' * len(official_name))
111148

@@ -116,18 +153,47 @@ def docs_for(service_name):
116153
filename = (os.path.dirname(__file__) + '/data/resources/'
117154
'{0}-{1}.resources.json').format(service_name,
118155
service_model.api_version)
156+
# We can't use a set here because dicts aren't hashable!
157+
models = {}
119158
if os.path.exists(filename):
120159
data = json.load(open(filename))
121160
model = ResourceModel(service_name, data['service'], data['resources'])
122161

162+
for collection_model in model.collections:
163+
collection_model.parent_name = model.name
164+
models[collection_model.name] = {
165+
'type': 'collection',
166+
'model': collection_model
167+
}
168+
123169
docs += document_resource(service_name, official_name, model,
124170
service_model)
125171

172+
# First, collect all the models...
126173
for name, model in sorted(data['resources'].items(),
127174
key=lambda i:i[0]):
128175
resource_model = ResourceModel(name, model, data['resources'])
129-
docs += document_resource(service_name, official_name,
130-
resource_model, service_model)
176+
if name not in models:
177+
models[name] = {'type': 'resource', 'model': resource_model}
178+
179+
for collection_model in resource_model.collections:
180+
collection_model.parent_name = xform_name(resource_model.name)
181+
182+
cname = collection_model.name + 'CollectionManager'
183+
if cname not in models:
184+
models[cname] = {'type': 'collection',
185+
'model': collection_model}
186+
187+
# Then render them out in alphabetical order.
188+
for name, item in sorted(models.items()):
189+
model = item['model']
190+
if item['type'] == 'resource':
191+
docs += document_resource(service_name, official_name,
192+
model, service_model)
193+
elif item['type'] == 'collection':
194+
docs += document_collection(
195+
service_name, official_name, model,
196+
model.resource.model, service_model)
131197

132198
return docs
133199

@@ -169,7 +235,8 @@ def document_client(service_name, official_name, service_model):
169235
operation = service_model.operation_model(operation_name)
170236
docs += document_operation(
171237
operation, service_name,
172-
paginated=client.can_paginate(xform_name(operation_name)))
238+
paginated=client.can_paginate(xform_name(operation_name)),
239+
example_instance='client', example_response='response')
173240

174241
return docs
175242

@@ -293,16 +360,53 @@ def document_resource(service_name, official_name, resource_model,
293360
for collection in sorted(resource_model.collections,
294361
key=lambda i: i.name):
295362
docs += (' .. py:attribute:: {0}\n\n '
296-
'(:py:class:`~boto3.resources.collection.CollectionManager`)'
297-
' A collection of :py:class:`{1}.{2}` instances. This'
298-
' collection uses the :py:meth:`{3}.Client.{4}` operation'
363+
'(:py:class:`{1}.{2}CollectionManager`)'
364+
' A collection of :py:class:`{3}.{4}` instances. This'
365+
' collection uses the :py:meth:`{5}.Client.{6}` operation'
299366
' to get items.\n\n').format(
300367
xform_name(collection.name), service_name,
368+
collection.name, service_name,
301369
collection.resource.type, service_name,
302370
xform_name(collection.request.operation))
303371

304372
return docs
305373

374+
def document_collection(service_name, official_name, collection_model,
375+
resource_model, service_model):
376+
"""
377+
Generate reference documentation about a collection and any
378+
batch actions it might have.
379+
"""
380+
title = collection_model.name + 'Collection'
381+
docs = '{0}\n{1}\n\n'.format(title, '-' * len(title))
382+
docs += '.. py:class:: {0}.{1}CollectionManager()\n\n'.format(
383+
service_name, collection_model.name)
384+
docs += (' A collection of :py:class:`{0}.{1}` resources for {2}. See'
385+
' the'
386+
' :py:class:`~boto3.resources.collection.CollectionManager`'
387+
' base class for additional methods.\n\n'
388+
' This collection uses the :py:meth:`{3}.Client.{4}`'
389+
' operation to get items, and its parameters can be'
390+
' used as filters::\n\n').format(
391+
service_name, resource_model.name, official_name,
392+
service_name, xform_name(collection_model.request.operation))
393+
docs += (' for {0} in {1}.{2}.all():\n'
394+
' print({0})\n\n').format(
395+
xform_name(collection_model.resource.type),
396+
collection_model.parent_name,
397+
xform_name(collection_model.name),
398+
xform_name(collection_model.resource.type))
399+
400+
if collection_model.batch_actions:
401+
docs += (' .. rst-class:: admonition-title\n\n Batch Actions\n\n'
402+
' Batch actions provide a way to manipulate groups of'
403+
' resources in a single service operation call.\n\n')
404+
for action in sorted(collection_model.batch_actions, key=lambda i:i.name):
405+
docs += document_action(action, service_name, resource_model,
406+
service_model)
407+
408+
return docs
409+
306410
def document_action(action, service_name, resource_model, service_model,
307411
action_type='action'):
308412
"""
@@ -316,29 +420,34 @@ def document_action(action, service_name, resource_model, service_model,
316420
print('Cannot get operation ' + action.request.operation)
317421
return ''
318422

319-
ignore_params = [p.target for p in action.request.params]
423+
# Here we split because we only care about top-level parameter names
424+
ignore_params = [p.target.split('.')[0] for p in action.request.params]
320425

321426
rtype = 'dict'
322427
if action_type == 'action':
323428
description = (' This method calls'
324429
' :py:meth:`{0}.Client.{1}`.').format(
325430
service_name,
326431
xform_name(action.request.operation))
432+
example_response = 'response'
327433
if action.resource:
328434
rtype = ':py:class:`{0}.{1}`'.format(
329435
service_name, action.resource.type)
436+
example_response = xform_name(action.resource.type)
330437

331438
# Is the response plural? If so we are returning a list!
332439
if action.path and '[]' in action.path:
333440
rtype = 'list({0})'.format(rtype)
334441

335442
return document_operation(
336443
operation_model, service_name, operation_name=xform_name(action.name),
337-
description=description, ignore_params=ignore_params, rtype=rtype)
444+
description=description, ignore_params=ignore_params, rtype=rtype,
445+
example_instance=service_name, example_response=example_response)
338446

339447
def document_operation(operation_model, service_name, operation_name=None,
340448
description=None, ignore_params=None, rtype='dict',
341-
paginated=False):
449+
paginated=False, example_instance=None,
450+
example_response=None):
342451
"""
343452
Document an operation. The description can be overridden and certain
344453
params hidden to support documenting resource actions.
@@ -361,7 +470,7 @@ def document_operation(operation_model, service_name, operation_name=None,
361470
optional_params = [k for k in params.keys() if k not in required and \
362471
k not in ignore_params]
363472
param_desc = ', '.join([
364-
', '.join(required_params),
473+
', '.join(['{0}=None'.format(k) for k in required_params]),
365474
', '.join(['{0}=None'.format(k) for k in optional_params])
366475
])
367476

@@ -379,13 +488,28 @@ def document_operation(operation_model, service_name, operation_name=None,
379488
if paginated:
380489
docs += ' This operation can be paginated.\n\n'
381490

491+
if example_instance:
492+
dummy_params = []
493+
for key, value in params.items():
494+
if key in ignore_params:
495+
continue
496+
if key in required_params:
497+
default = py_default(value.type_name)
498+
dummy_params.append('{0}={1}'.format(
499+
key, default))
500+
docs += ' Example::\n\n {0} = {1}.{2}({3})\n\n'.format(
501+
example_response, example_instance, operation_name,
502+
', '.join(dummy_params))
503+
382504
for key, value in params.items():
383505
# Skip identifiers as these are automatically set!
384506
if key in ignore_params:
385507
continue
386508
param_type = py_type_name(value.type_name)
387-
docs += (' :param {0} {1}: {2}\n'.format(
388-
param_type, key, html_to_rst(value.documentation, indent=9)))
509+
required = key in required_params and 'Required' or 'Optional'
510+
docs += (' :param {0} {1}: *{2}* - {3}\n'.format(
511+
param_type, key, required,
512+
html_to_rst(value.documentation, indent=9)))
389513

390514
docs += '\n\n :rtype: {0}\n\n'.format(rtype)
391515

0 commit comments

Comments
 (0)