Skip to content

Commit

Permalink
Merge branch 'release-1.10.29'
Browse files Browse the repository at this point in the history
* release-1.10.29:
  Bumping version to 1.10.29
  Update changelog based on model updates
  Remove back-compat shorthand features from new services
  Use service_name in process-cli-arg event
  Print better error when using pagination params and no paginate
  Default ec2 page size to 1000
  updated describe-scheduled-actions example
  • Loading branch information
AWS committed May 17, 2016
2 parents 5e6bff5 + 4c2bfdb commit e5ee858
Show file tree
Hide file tree
Showing 37 changed files with 821 additions and 117 deletions.
32 changes: 32 additions & 0 deletions .changes/1.10.29.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
{
"category": "``dynamodb``",
"description": "Update dynamodb command to latest version",
"type": "feature"
},
{
"category": "Shorthand",
"description": "Remove back-compat shorthand features from new services.",
"type": "bugfix"
},
{
"category": "Paginator",
"description": "Print a better error when pagination params are supplied along with no-paginate.",
"type": "bugfix"
},
{
"category": "ec2",
"description": "Sets MaxResults to default value of 1000.",
"type": "bugfix"
},
{
"category": "``workspaces``",
"description": "Update workspaces command to latest version",
"type": "feature"
},
{
"category": "``discovery``",
"description": "Update discovery command to latest version",
"type": "feature"
}
]
11 changes: 11 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@
CHANGELOG
=========

1.10.29
=======

* feature:``dynamodb``: Update dynamodb command to latest version
* bugfix:Shorthand: Remove back-compat shorthand features from new services.
* bugfix:Paginator: Print a better error when pagination params are supplied along with no-paginate.
* bugfix:ec2: Sets MaxResults to default value of 1000.
* feature:``workspaces``: Update workspaces command to latest version
* feature:``discovery``: Update discovery command to latest version


1.10.28
=======

Expand Down
2 changes: 1 addition & 1 deletion awscli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"""
import os

__version__ = '1.10.28'
__version__ = '1.10.29'

#
# Get our data path to be added to botocore's search path
Expand Down
74 changes: 58 additions & 16 deletions awscli/argprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from awscli.paramfile import get_paramfile, ResourceLoadingError
from awscli.paramfile import PARAMFILE_DISABLED
from awscli import shorthand
from awscli.utils import find_service_and_method_in_event_name


LOG = logging.getLogger('awscli.argprocess')
Expand Down Expand Up @@ -247,11 +248,39 @@ def _is_complex_shape(model):

class ParamShorthand(object):

def _uses_old_list_case(self, service_name, operation_name, argument_name):
"""
Determines whether a given operation for a service needs to use the
deprecated shorthand parsing case for lists of structures that only have
a single member.
"""
cases = {
'firehose': {
'put-record-batch': ['records']
},
'workspaces': {
'reboot-workspaces': ['reboot-workspace-requests'],
'rebuild-workspaces': ['rebuild-workspace-requests'],
'terminate-workspaces': ['terminate-workspace-requests']
},
'elb': {
'remove-tags': ['tags'],
'describe-instance-health': ['instances'],
'deregister-instances-from-load-balancer': ['instances'],
'register-instances-with-load-balancer': ['instances']
}
}
cases = cases.get(service_name, {}).get(operation_name, [])
return argument_name in cases


class ParamShorthandParser(ParamShorthand):

def __init__(self):
self._parser = shorthand.ShorthandParser()
self._visitor = shorthand.BackCompatVisitor()

def __call__(self, cli_argument, value, **kwargs):
def __call__(self, cli_argument, value, event_name, **kwargs):
"""Attempt to parse shorthand syntax for values.
This is intended to be hooked up as an event handler (hence the
Expand All @@ -278,16 +307,22 @@ def __call__(self, cli_argument, value, **kwargs):
be raised.
"""

if not self._should_parse_as_shorthand(cli_argument, value):
return
else:
return self._parse_as_shorthand(cli_argument, value)
service_name, operation_name = \
find_service_and_method_in_event_name(event_name)
return self._parse_as_shorthand(
cli_argument, value, service_name, operation_name)

def _parse_as_shorthand(self, cli_argument, value):
def _parse_as_shorthand(self, cli_argument, value, service_name,
operation_name):
try:
LOG.debug("Parsing param %s as shorthand",
cli_argument.cli_name)
handled_value = self._handle_special_cases(cli_argument, value)
handled_value = self._handle_special_cases(
cli_argument, value, service_name, operation_name)
if handled_value is not None:
return handled_value
if isinstance(value, list):
Expand All @@ -312,13 +347,15 @@ def _parse_as_shorthand(self, cli_argument, value):
raise ParamError(cli_argument.cli_name, str(e))
return parsed

def _handle_special_cases(self, cli_argument, value):
def _handle_special_cases(self, cli_argument, value, service_name,
operation_name):
# We need to handle a few special cases that the previous
# parser handled in order to stay backwards compatible.
model = cli_argument.argument_model
if model.type_name == 'list' and \
model.member.type_name == 'structure' and \
len(model.member.members) == 1:
model.member.type_name == 'structure' and \
len(model.member.members) == 1 and \
self._uses_old_list_case(service_name, operation_name, cli_argument.name):
# First special case is handling a list of structures
# of a single element such as:
#
Expand Down Expand Up @@ -365,7 +402,7 @@ def _should_parse_as_shorthand(self, cli_argument, value):
return _is_complex_shape(model)


class ParamShorthandDocGen(object):
class ParamShorthandDocGen(ParamShorthand):
"""Documentation generator for param shorthand syntax."""

_DONT_DOC = object()
Expand All @@ -377,7 +414,8 @@ def supports_shorthand(self, argument_model):
return _is_complex_shape(argument_model)
return False

def generate_shorthand_example(self, cli_name, argument_model):
def generate_shorthand_example(self, cli_argument, service_name,
operation_name):
"""Generate documentation for a CLI argument.
:type cli_argument: awscli.arguments.BaseCLIArgument
Expand All @@ -391,7 +429,8 @@ def generate_shorthand_example(self, cli_name, argument_model):
``argument_model``.
"""
docstring = self._handle_special_cases(cli_name, argument_model)
docstring = self._handle_special_cases(
cli_argument, service_name, operation_name)
if docstring is self._DONT_DOC:
return None
elif docstring:
Expand All @@ -401,20 +440,23 @@ def generate_shorthand_example(self, cli_name, argument_model):
# syntax.
stack = []
try:
if argument_model.type_name == 'list':
argument_model = argument_model.member
if cli_argument.argument_model.type_name == 'list':
argument_model = cli_argument.argument_model.member
return self._shorthand_docs(argument_model, stack) + ' ...'
else:
return self._shorthand_docs(argument_model, stack)
return self._shorthand_docs(cli_argument.argument_model, stack)
except TooComplexError:
return ''

def _handle_special_cases(self, cli_name, model):
def _handle_special_cases(self, cli_argument, service_name, operation_name):
model = cli_argument.argument_model
if model.type_name == 'list' and \
model.member.type_name == 'structure' and \
len(model.member.members) == 1:
len(model.member.members) == 1 and \
self._uses_old_list_case(
service_name, operation_name, cli_argument.name):
member_name = list(model.member.members)[0]
return '%s %s1 %s2 %s3' % (cli_name, member_name,
return '%s %s1 %s2 %s3' % (cli_argument.cli_name, member_name,
member_name, member_name)
elif model.type_name == 'structure' and \
len(model.members) == 1 and \
Expand Down
2 changes: 1 addition & 1 deletion awscli/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ def add_to_params(self, parameters, value):
parameters[self._serialized_name] = unpacked

def _unpack_argument(self, value):
service_name = self._operation_model.service_model.endpoint_prefix
service_name = self._operation_model.service_model.service_name
operation_name = xform_name(self._operation_model.name, '-')
override = self._emit_first_response('process-cli-arg.%s.%s' % (
service_name, operation_name), param=self.argument_model,
Expand Down
7 changes: 5 additions & 2 deletions awscli/clidocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from awscli import SCALAR_TYPES
from awscli.argprocess import ParamShorthandDocGen
from awscli.topictags import TopicTagDB
from awscli.utils import find_service_and_method_in_event_name

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -418,7 +419,9 @@ def _doc_input_structure_members(self, doc, argument_model, stack):
doc.style.new_line()
doc.write('}')

def doc_option_example(self, arg_name, help_command, **kwargs):
def doc_option_example(self, arg_name, help_command, event_name, **kwargs):
service_name, operation_name = \
find_service_and_method_in_event_name(event_name)
doc = help_command.doc
cli_argument = help_command.arg_table[arg_name]
if cli_argument.group_name in self._arg_groups:
Expand All @@ -430,7 +433,7 @@ def doc_option_example(self, arg_name, help_command, **kwargs):
docgen = ParamShorthandDocGen()
if docgen.supports_shorthand(cli_argument.argument_model):
example_shorthand_syntax = docgen.generate_shorthand_example(
cli_argument.cli_name, cli_argument.argument_model)
cli_argument, service_name, operation_name)
if example_shorthand_syntax is None:
# If the shorthand syntax returns a value of None,
# this indicates to us that there is no example
Expand Down
5 changes: 3 additions & 2 deletions awscli/clidriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,9 @@ def __call__(self, args, parsed_globals):
self._name)
self._emit(event, parsed_args=parsed_args,
parsed_globals=parsed_globals)
call_parameters = self._build_call_parameters(parsed_args,
self.arg_table)
call_parameters = self._build_call_parameters(
parsed_args, self.arg_table)

event = 'calling-command.%s.%s' % (self._parent_name,
self._name)
override = self._emit_first_non_none_response(
Expand Down
27 changes: 27 additions & 0 deletions awscli/customizations/ec2/paginate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
DEFAULT_MAX_RESULTS = 1000


def set_max_results_default(parsed_args, parsed_globals, **kwargs):
"""
In order to have EC2 return results you can paginate you need to inject
the `MaxItems` parameter. In the CLI we should be setting this by default
to avoid users having to wait exceedingly long times for the full results.
"""

# The check for page size validates that the operation is a pagination
# operation.
if parsed_globals.paginate and hasattr(parsed_args, 'page_size') and \
parsed_args.page_size is None and parsed_args.max_results is None:
parsed_args.page_size = DEFAULT_MAX_RESULTS
22 changes: 20 additions & 2 deletions awscli/customizations/paginate.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from functools import partial

from botocore import xform_name
from botocore.exceptions import DataNotFoundError
from botocore.exceptions import DataNotFoundError, PaginationError
from botocore import model

from awscli.arguments import BaseCLIArgument
Expand Down Expand Up @@ -173,7 +173,8 @@ def check_should_enable_pagination(input_tokens, shadowed_args, argument_table,
logger.debug("User has specified a manual pagination arg. "
"Automatically setting --no-paginate.")
parsed_globals.paginate = False
# Because we've now disabled pagination, there's a chance that

# Because pagination is now disabled, there's a chance that
# we were shadowing arguments. For example, we inject a
# --max-items argument in unify_paging_params(). If the
# the operation also provides its own MaxItems (which we
Expand All @@ -183,6 +184,23 @@ def check_should_enable_pagination(input_tokens, shadowed_args, argument_table,
# what we're doing here.
for key, value in shadowed_args.items():
argument_table[key] = value

if not parsed_globals.paginate:
ensure_paging_params_not_set(parsed_args, shadowed_args)


def ensure_paging_params_not_set(parsed_args, shadowed_args):
paging_params = ['starting_token', 'page_size', 'max_items']
shadowed_params = [p.replace('-', '_') for p in shadowed_args.keys()]
params_used = [p for p in paging_params if
p not in shadowed_params and getattr(parsed_args, p)]

if len(params_used) > 0:
converted_params = ', '.join(
["--" + p.replace('_', '-') for p in params_used])
raise PaginationError(
message="Cannot specify --no-paginate along with pagination "
"arguments: %s" % converted_params)


def _remove_existing_paging_arguments(argument_table, pagination_config):
Expand Down
12 changes: 9 additions & 3 deletions awscli/examples/autoscaling/describe-scheduled-actions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,17 @@ The following is example output::

{
"NextToken": "Z3M3LMPEXAMPLE",
"NotificationConfigurations": [
"ScheduledUpdateGroupActions": [
{
"MinSize": 2,
"DesiredCapacity": 4,
"AutoScalingGroupName": "my-auto-scaling-group",
"NotificationType": "autoscaling:TEST_NOTIFICATION",
"TopicARN": "arn:aws:sns:us-west-2:123456789012:my-sns-topic"
"MaxSize": 6,
"Recurrence": "30 0 1 12 0",
"ScheduledActionARN": "arn:aws:autoscaling:us-west-2:123456789012:scheduledUpdateGroupAction:8e86b655-b2e6-4410-8f29-b4f094d6871c:autoScalingGroupName/my-auto-scaling-group:scheduledActionName/my-scheduled-action",
"ScheduledActionName": "my-scheduled-action",
"StartTime": "2019-12-01T00:30:00Z",
"Time": "2019-12-01T00:30:00Z"
}
]
}
Expand Down
6 changes: 4 additions & 2 deletions awscli/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
registered with the event system.
"""
from awscli.argprocess import ParamShorthand
from awscli.argprocess import ParamShorthandParser
from awscli.argprocess import uri_param
from awscli.customizations import datapipeline
from awscli.customizations.addexamples import add_examples
Expand Down Expand Up @@ -44,6 +44,7 @@
from awscli.customizations.ec2.protocolarg import register_protocol_args
from awscli.customizations.ec2.runinstances import register_runinstances
from awscli.customizations.ec2.secgroupsimplify import register_secgroup
from awscli.customizations.ec2.paginate import set_max_results_default
from awscli.customizations.ecr import register_ecr_commands
from awscli.customizations.emr.emr import emr_initialize
from awscli.customizations.gamelift import register_gamelift_commands
Expand Down Expand Up @@ -75,7 +76,7 @@

def awscli_initialize(event_handlers):
event_handlers.register('load-cli-arg', uri_param)
param_shorthand = ParamShorthand()
param_shorthand = ParamShorthandParser()
event_handlers.register('process-cli-arg', param_shorthand)
# The s3 error mesage needs to registered before the
# generic error handler.
Expand All @@ -102,6 +103,7 @@ def awscli_initialize(event_handlers):
ec2_add_priv_launch_key)
register_parse_global_args(event_handlers)
register_pagination(event_handlers)
event_handlers.register('operation-args-parsed.ec2.*', set_max_results_default)
register_secgroup(event_handlers)
register_bundleinstance(event_handlers)
s3_plugin_initialize(event_handlers)
Expand Down

0 comments on commit e5ee858

Please sign in to comment.