Skip to content

Commit

Permalink
Merge branch 'release-0.0.6'
Browse files Browse the repository at this point in the history
  • Loading branch information
danielgtaylor committed Dec 18, 2014
2 parents 0b13988 + bc866bb commit ff7f782
Show file tree
Hide file tree
Showing 16 changed files with 411 additions and 48 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.rst
@@ -1,6 +1,25 @@
Changelog
=========

0.0.6 - 2014-12-18
------------------

* feature:Amazon SQS: Add ``purge`` action to queue resources
* feature:Waiters: Add documentation for client and resource waiters
(`issue 44 <https://github.com/boto/boto3/pull/44>`__)
* feature:Waiters: Add support for resource waiters
(`issue 43 <https://github.com/boto/boto3/pull/43>`__)
* bugfix:Installation: Remove dependency on the unused ``six`` module
(`issue 42 <https://github.com/boto/boto3/pull/42>`__)
* feature:Botocore: Update to Botocore 0.80.0

* Update Amazon Simple Workflow Service (SWF) to the latest version
* Update AWS Storage Gateway to the latest version
* Update AWS Elastic MapReduce (EMR) to the latest version
* Update AWS Elastic Transcoder to the latest version
* Enable use of ``page_size`` for clients
(`botocore issue 408 <https://github.com/boto/botocore/pull/408>`__)

0.0.5 - 2014-12-09
------------------

Expand Down
2 changes: 1 addition & 1 deletion boto3/__init__.py
Expand Up @@ -17,7 +17,7 @@


__author__ = 'Amazon Web Services'
__version__ = '0.0.5'
__version__ = '0.0.6'


# The default Boto3 session; autoloaded when needed.
Expand Down
14 changes: 0 additions & 14 deletions boto3/compat.py

This file was deleted.

35 changes: 25 additions & 10 deletions boto3/data/resources/sqs-2012-11-05.resources.json
Expand Up @@ -21,15 +21,6 @@
}
},
"hasMany": {
"DeadLetterSourceQueues": {
"request": { "operation": "ListDeadLetterSourceQueues" },
"resource": {
"type": "Queue",
"identifiers": [
{ "target": "Url", "sourceType": "responsePath", "source": "QueueUrls[]" }
]
}
},
"Queues": {
"request": { "operation": "ListQueues" },
"resource": {
Expand All @@ -45,7 +36,7 @@
"Message": {
"identifiers": [
{ "name": "QueueUrl" },
{ "name": "ReceiptHandle" }
{ "name": "ReceiptHandle", "memberName": "ReceiptHandle" }
],
"shape": "Message",
"actions": {
Expand Down Expand Up @@ -129,6 +120,14 @@
]
}
},
"Purge": {
"request": {
"operation": "PurgeQueue",
"params": [
{ "target": "QueueUrl", "sourceType": "identifier", "source": "Url" }
]
}
},
"ReceiveMessages": {
"request": {
"operation": "ReceiveMessage",
Expand Down Expand Up @@ -181,6 +180,22 @@
"subResources": {
"resources": [ "Message" ],
"identifiers": { "Url": "QueueUrl" }
},
"hasMany" : {
"DeadLetterSourceQueues": {
"request": {
"operation": "ListDeadLetterSourceQueues",
"params": [
{ "target": "QueueUrl", "sourceType": "identifier", "source": "Url" }
]
},
"resource": {
"type": "Queue",
"identifiers": [
{ "target": "Url", "sourceType": "responsePath", "source": "QueueUrls[]" }
]
}
}
}
}
}
Expand Down
106 changes: 95 additions & 11 deletions boto3/docs.py
Expand Up @@ -146,9 +146,11 @@ def docs_for(service_name):

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

docs += '.. contents:: Table of Contents\n\n'
docs += '.. contents:: Table of Contents\n :depth: 2\n\n'

docs += document_client(service_name, official_name, service_model)
docs += document_client_waiter(session, official_name, service_name,
service_model)

filename = (os.path.dirname(__file__) + '/data/resources/'
'{0}-{1}.resources.json').format(service_name,
Expand All @@ -167,7 +169,7 @@ def docs_for(service_name):
}

docs += document_resource(service_name, official_name, model,
service_model)
service_model, session)

# First, collect all the models...
for name, model in sorted(data['resources'].items(),
Expand All @@ -189,7 +191,7 @@ def docs_for(service_name):
model = item['model']
if item['type'] == 'resource':
docs += document_resource(service_name, official_name,
model, service_model)
model, service_model, session)
elif item['type'] == 'collection':
docs += document_collection(
service_name, official_name, model,
Expand Down Expand Up @@ -223,7 +225,7 @@ def document_client(service_name, official_name, service_model):
wdoc += ' .. py:method:: get_waiter(name)\n\n'
wdoc += ' Get a waiter by name. Available waiters:\n\n'
for waiter in client.waiter_names:
wdoc += ' * {0}\n'.format(waiter)
wdoc += ' * `{0}`_\n'.format(waiter)
wdoc += '\n'

waiter_included = False
Expand All @@ -240,8 +242,40 @@ def document_client(service_name, official_name, service_model):

return docs

def document_client_waiter(session, official_name, service_name,
service_model):
client = boto3.client(service_name, aws_access_key_id='dummy',
aws_secret_access_key='dummy',
region_name='us-east-1')
waiter_spec_doc = ''
if client.waiter_names:
waiter_spec_doc = 'Waiter\n------\n\n'
service_waiter_model = session.get_waiter_model(service_name)
for waiter in service_waiter_model.waiter_names:
snake_cased = xform_name(waiter)
waiter_spec_doc += '{0}\n{1}\n\n'.format(snake_cased,
'~' * len(snake_cased))
waiter_model = service_waiter_model.get_waiter(waiter)
operation_model = service_model.operation_model(
waiter_model.operation)
description = (
' This polls :py:meth:`{0}.Client.{1}` every {2} '
'seconds until a successful state is reached. An error is '
'returned after {3} failed checks.'.format(
service_name, xform_name(waiter_model.operation),
waiter_model.delay, waiter_model.max_attempts)
)
waiter_spec_doc += document_operation(
operation_model=operation_model, service_name=service_name,
operation_name='wait', rtype=None, description=description,
example_instance='client.get_waiter(\'{0}\')'.format(
snake_cased))
waiter_spec_doc += '\n'

return waiter_spec_doc

def document_resource(service_name, official_name, resource_model,
service_model):
service_model, session):
"""
Generate reference documentation from a resource model.
"""
Expand Down Expand Up @@ -369,6 +403,16 @@ def document_resource(service_name, official_name, resource_model,
collection.resource.type, service_name,
xform_name(collection.request.operation))

if resource_model.waiters:
docs += (' .. rst-class:: admonition-title\n\n Waiters\n\n'
' Waiters provide an interface to wait for a resource'
' to reach a specific state.\n\n')
service_waiter_model = session.get_waiter_model(service_name)
for waiter in sorted(resource_model.waiters,
key=lambda i: i.resource_waiter_name):
docs += document_waiter(waiter, service_name, resource_model,
service_model, service_waiter_model)

return docs

def document_collection(service_name, official_name, collection_model,
Expand Down Expand Up @@ -407,6 +451,42 @@ def document_collection(service_name, official_name, collection_model,

return docs

def document_waiter(waiter, service_name, resource_model, service_model,
service_waiter_model):
"""
Document a resource waiter, including the low-level client waiter
and parameters.
"""
try:
waiter_model = service_waiter_model.get_waiter(waiter.waiter_name)
except:
print('Cannot get waiter ' + waiter.waiter_name)
return ''

try:
operation_model = service_model.operation_model(waiter_model.operation)
except:
print('Cannot get operation ' + action.request.operation +
' for waiter ' + waiter.waiter_name)
return ''
description = (' Waits until this {0} is {1}.\n'
' This method calls ``wait()`` on'
' :py:meth:`{2}.Client.get_waiter` using `{3}`_ .').format(
resource_model.name,
xform_name(waiter.name).replace('_', ' '),
service_name,
xform_name(waiter.waiter_name))

# Here we split because we only care about top-level parameter names
ignore_params = [p.target.split('.')[0].strip('[]') for p in waiter.params]

return document_operation(
operation_model=operation_model, service_name=service_name,
operation_name=xform_name(waiter.resource_waiter_name),
description=description,
example_instance = xform_name(resource_model.name),
ignore_params=ignore_params, rtype=None)

def document_action(action, service_name, resource_model, service_model,
action_type='action'):
"""
Expand All @@ -421,7 +501,8 @@ def document_action(action, service_name, resource_model, service_model,
return ''

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

rtype = 'dict'
if action_type == 'action':
Expand All @@ -442,7 +523,8 @@ def document_action(action, service_name, resource_model, service_model,
return document_operation(
operation_model, service_name, operation_name=xform_name(action.name),
description=description, ignore_params=ignore_params, rtype=rtype,
example_instance=service_name, example_response=example_response)
example_instance=xform_name(resource_model.name),
example_response=example_response)

def document_operation(operation_model, service_name, operation_name=None,
description=None, ignore_params=None, rtype='dict',
Expand Down Expand Up @@ -497,8 +579,10 @@ def document_operation(operation_model, service_name, operation_name=None,
default = py_default(value.type_name)
dummy_params.append('{0}={1}'.format(
key, default))
docs += ' Example::\n\n {0} = {1}.{2}({3})\n\n'.format(
example_response, example_instance, operation_name,
docs += ' Example::\n\n '
if example_response is not None:
docs += '{0} = '.format(example_response)
docs += '{0}.{1}({2})\n\n'.format(example_instance, operation_name,
', '.join(dummy_params))

for key, value in params.items():
Expand All @@ -510,7 +594,7 @@ def document_operation(operation_model, service_name, operation_name=None,
docs += (' :param {0} {1}: *{2}* - {3}\n'.format(
param_type, key, required,
html_to_rst(value.documentation, indent=9)))

docs += '\n\n :rtype: {0}\n\n'.format(rtype)
if rtype is not None:
docs += '\n\n :rtype: {0}\n\n'.format(rtype)

return docs
45 changes: 45 additions & 0 deletions boto3/resources/action.py
Expand Up @@ -149,3 +149,48 @@ def __call__(self, parent, *args, **kwargs):
self._response_handler(parent, params, response))

return responses


class WaiterAction(object):
"""
A class representing a callable waiter action on a resource, for example
``s3.Bucket('foo').wait_until_bucket_exists()``.
The waiter action may construct parameters from existing resource
identifiers.
:type waiter_model: :py:class`~boto3.resources.model.Waiter`
:param waiter_model: The action waiter.
:type waiter_resource_name: string
:param waiter_resource_name: The name of the waiter action for the
resource. It usually begins with a
``wait_until_``
"""
def __init__(self, waiter_model, waiter_resource_name):
self._waiter_model = waiter_model
self._waiter_resource_name = waiter_resource_name

def __call__(self, parent, *args, **kwargs):
"""
Perform the wait operation after building operation
parameters.
:type parent: :py:class:`~boto3.resources.base.ServiceResource`
:param parent: The resource instance to which this action is attached.
"""
client_waiter_name = xform_name(self._waiter_model.waiter_name)

# First, build predefined params and then update with the
# user-supplied kwargs, which allows overriding the pre-built
# params if needed.
params = create_request_parameters(parent, self._waiter_model)
params.update(kwargs)

logger.info('Calling %s:%s with %r',
parent.meta['service_name'],
self._waiter_resource_name, params)

client = parent.meta['client']
waiter = client.get_waiter(client_waiter_name)
response = waiter.wait(**params)

logger.debug('Response: %r', response)

0 comments on commit ff7f782

Please sign in to comment.