-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Json skeleton #963
Merged
Merged
Json skeleton #963
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
48d9b4e
Add support for use of input JSON skeletons
kyleknap b6d164a
Add unit test for input JSON skeleton feature
kyleknap 3549e70
Added integration test for json skeleton feature
kyleknap 210686c
Clean up the input json skeleton code
kyleknap f841371
Update JSON code based on feedback
kyleknap eb66503
Add generate skeleton integ test
jamesls ecc2a0d
Accepts input shape of None
kyleknap 9a0898b
Fix arguments with no required setters
kyleknap 2610ed2
Unit and integration test pass for json skeleton
kyleknap 7db6e6a
Refactor the clidriver event system
kyleknap a16c878
Updated the travis yml for unittest2
kyleknap eed1362
Updated CHANGELOG
kyleknap File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Copyright 2014 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. | ||
from awscli.arguments import CustomArgument | ||
|
||
|
||
class OverrideRequiredArgsArgument(CustomArgument): | ||
"""An argument that if specified makes all other arguments not required | ||
By not required, it refers to not having an error thrown when the | ||
parser does not find an argument that is required on the command line. | ||
To obtain this argument's property of ignoring required arguments, | ||
subclass from this class and fill out the ``ARG_DATA`` parameter as | ||
described below. Note this class is really only useful for subclassing. | ||
""" | ||
|
||
# ``ARG_DATA`` follows the same format as a member of ``ARG_TABLE`` in | ||
# ``BasicCommand`` class as specified in | ||
# ``awscli/customizations/commands.py``. | ||
# | ||
# For example, an ``ARG_DATA`` variable would be filled out as: | ||
# | ||
# ARG_DATA = | ||
# {'name': 'my-argument', | ||
# 'help_text': 'This is argument ensures the argument is specified' | ||
# 'no other arguments are required'} | ||
ARG_DATA = {'name': 'no-required-args'} | ||
|
||
def __init__(self, session): | ||
self._session = session | ||
self._register_argument_action() | ||
super(OverrideRequiredArgsArgument, self).__init__(**self.ARG_DATA) | ||
|
||
def _register_argument_action(self): | ||
self._session.register('before-building-argument-table-parser', | ||
self.override_required_args) | ||
|
||
def override_required_args(self, argument_table, args, **kwargs): | ||
name_in_cmdline = '--' + self.name | ||
# Set all ``Argument`` objects in ``argument_table`` to not required | ||
# if this argument's name is present in the command line. | ||
if name_in_cmdline in args: | ||
for arg_name in argument_table.keys(): | ||
argument_table[arg_name].required = False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# Copyright 2014 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. | ||
import json | ||
|
||
from awscli.paramfile import get_paramfile | ||
from awscli.argprocess import ParamError | ||
from awscli.customizations.arguments import OverrideRequiredArgsArgument | ||
|
||
|
||
def register_cli_input_json(cli): | ||
cli.register('building-argument-table', add_cli_input_json) | ||
|
||
|
||
def add_cli_input_json(operation, argument_table, **kwargs): | ||
# This argument cannot support operations with streaming output which | ||
# is designated by the argument name `outfile`. | ||
if 'outfile' not in argument_table: | ||
cli_input_json_argument = CliInputJSONArgument(operation) | ||
cli_input_json_argument.add_to_arg_table(argument_table) | ||
|
||
|
||
class CliInputJSONArgument(OverrideRequiredArgsArgument): | ||
"""This argument inputs a JSON string as the entire input for a command. | ||
|
||
Ideally, the value to this argument should be a filled out JSON file | ||
generated by ``--generate-cli-skeleton``. The items in the JSON string | ||
will not clobber other arguments entered into the command line. | ||
""" | ||
ARG_DATA = { | ||
'name': 'cli-input-json', | ||
'help_text': 'Performs service operation based on the JSON string ' | ||
'provided. The JSON string follows the format provided ' | ||
'by ``--generate-cli-skeleton``. If other arguments are ' | ||
'provided on the command line, it will not clobber their ' | ||
'values.' | ||
} | ||
|
||
def __init__(self, operation_object): | ||
self._operation_object = operation_object | ||
super(CliInputJSONArgument, self).__init__( | ||
self._operation_object.session) | ||
|
||
def _register_argument_action(self): | ||
self._operation_object.session.register( | ||
'calling-command', self.add_to_call_parameters) | ||
super(CliInputJSONArgument, self)._register_argument_action() | ||
|
||
def add_to_call_parameters(self, call_parameters, parsed_args, | ||
parsed_globals, **kwargs): | ||
|
||
# Check if ``--cli-input-json`` was specified in the command line. | ||
input_json = getattr(parsed_args, 'cli_input_json', None) | ||
if input_json is not None: | ||
# Retrieve the JSON from the file if needed. | ||
retrieved_json = get_paramfile(input_json) | ||
# Nothing was retrieved from the file. So assume the argument | ||
# is already a JSON string. | ||
if retrieved_json is None: | ||
retrieved_json = input_json | ||
try: | ||
# Try to load the JSON string into a python dictionary | ||
input_data = json.loads(retrieved_json) | ||
except ValueError as e: | ||
raise ParamError( | ||
self.name, "Invalid JSON: %s\nJSON received: %s" | ||
% (e, retrieved_json)) | ||
# Add the members from the input JSON to the call parameters. | ||
self._update_call_parameters(call_parameters, input_data) | ||
|
||
def _update_call_parameters(self, call_parameters, input_data): | ||
for input_key in input_data.keys(): | ||
# Only add the values to ``call_parameters`` if not already | ||
# present. | ||
if input_key not in call_parameters: | ||
call_parameters[input_key] = input_data[input_key] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# Copyright 2014 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. | ||
import json | ||
import sys | ||
|
||
from botocore.utils import ArgumentGenerator | ||
|
||
from awscli.customizations.arguments import OverrideRequiredArgsArgument | ||
|
||
|
||
def register_generate_cli_skeleton(cli): | ||
cli.register('building-argument-table', add_generate_skeleton) | ||
|
||
|
||
def add_generate_skeleton(operation, argument_table, **kwargs): | ||
# This argument cannot support operations with streaming output which | ||
# is designated by the argument name `outfile`. | ||
if 'outfile' not in argument_table: | ||
generate_cli_skeleton_argument = GenerateCliSkeletonArgument(operation) | ||
generate_cli_skeleton_argument.add_to_arg_table(argument_table) | ||
|
||
|
||
class GenerateCliSkeletonArgument(OverrideRequiredArgsArgument): | ||
"""This argument writes a generated JSON skeleton to stdout | ||
The argument, if present in the command line, will prevent the intended | ||
command from taking place. Instead, it will generate a JSON skeleton and | ||
print it to standard output. This JSON skeleton then can be filled out | ||
and can be used as input to ``--input-cli-json`` in order to run the | ||
command with the filled out JSON skeleton. | ||
""" | ||
ARG_DATA = { | ||
'name': 'generate-cli-skeleton', | ||
'help_text': 'Prints a sample input JSON to standard output. Note the ' | ||
'specified operation is not run if this argument is ' | ||
'specified. The sample input can be used as an argument ' | ||
'for ``--cli-input-json``.', | ||
'action': 'store_true', | ||
'group_name': 'generate_cli_skeleton' | ||
} | ||
|
||
def __init__(self, operation_object): | ||
self._operation_object = operation_object | ||
super(GenerateCliSkeletonArgument, self).__init__( | ||
self._operation_object.session) | ||
|
||
def _register_argument_action(self): | ||
self._operation_object.session.register( | ||
'calling-command.*', self.generate_json_skeleton) | ||
super(GenerateCliSkeletonArgument, self)._register_argument_action() | ||
|
||
def generate_json_skeleton(self, call_parameters, parsed_args, | ||
parsed_globals, **kwargs): | ||
|
||
# Only perform the method if the ``--generate-cli-skeleton`` was | ||
# included in the command line. | ||
if getattr(parsed_args, 'generate_cli_skeleton', False): | ||
|
||
# Obtain the model of the operation | ||
operation_model = self._operation_object.model | ||
|
||
# Generate the skeleton based on the ``input_shape``. | ||
argument_generator = ArgumentGenerator() | ||
operation_input_shape = operation_model.input_shape | ||
# If the ``input_shape`` is ``None``, generate an empty | ||
# dictionary. | ||
if operation_input_shape is None: | ||
skeleton = {} | ||
else: | ||
skeleton = argument_generator.generate_skeleton( | ||
operation_input_shape) | ||
|
||
# Write the generated skeleton to standard output. | ||
sys.stdout.write(json.dumps(skeleton, indent=4)) | ||
sys.stdout.write('\n') | ||
# This is the return code | ||
return 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually for input_shapes of
None
, we should probably just emit an empty dictionary because that can used withcli-input-json
to round trip.