support the new CLI in py2 *and* py3

This commit is contained in:
Ryan Petrello
2019-08-19 17:59:49 -04:00
parent 2cdd007ed0
commit 80b4102aa9
21 changed files with 154 additions and 52 deletions

View File

@@ -6,6 +6,7 @@ import yaml
from requests.exceptions import ConnectionError, SSLError
from .client import CLI
from awxkit.utils import to_str
from awxkit.exceptions import Unauthorized, Common
from awxkit.cli.utils import cprint
@@ -46,7 +47,14 @@ def run(stdout=sys.stdout, stderr=sys.stderr, argv=[]):
if cli.get_config('format') == 'json':
json.dump(e.msg, sys.stdout)
elif cli.get_config('format') == 'yaml':
sys.stdout.write(yaml.dump(e.msg))
sys.stdout.write(to_str(
yaml.safe_dump(
e.msg,
default_flow_style=False,
encoding='utf-8',
allow_unicode=True
)
))
sys.exit(1)
except Exception as e:
if cli.verbose:

View File

@@ -1,9 +1,12 @@
from __future__ import print_function
import logging
import os
import pkg_resources
import sys
from requests.exceptions import RequestException
import six
from .custom import handle_custom_actions
from .format import (add_authentication_arguments,
@@ -160,10 +163,18 @@ class CLI(object):
changed=self.original_action in ('modify', 'create')
)
if formatted:
print(formatted, file=self.stdout)
print(utils.to_str(formatted), file=self.stdout)
else:
self.parser.print_help()
if six.PY2 and not self.help:
# Unfortunately, argparse behavior between py2 and py3
# changed in a notable way when required subparsers
# have invalid (or missing) arguments specified
# see: https://github.com/python/cpython/commit/f97c59aaba2d93e48cbc6d25f7ff9f9c87f8d0b2
print('\nargument resource: invalid choice')
raise SystemExit(2)
def parse_action(self, page, from_sphinx=False):
"""Perform an HTTP OPTIONS request

View File

@@ -1,3 +1,5 @@
from six import with_metaclass
from .stdout import monitor, monitor_workflow
from .utils import CustomRegistryMeta, color_enabled
@@ -17,7 +19,7 @@ class CustomActionRegistryMeta(CustomRegistryMeta):
return ' '.join([self.resource, self.action])
class CustomAction(object, metaclass=CustomActionRegistryMeta):
class CustomAction(with_metaclass(CustomActionRegistryMeta)):
"""Base class for defining a custom action for a resource."""
def __init__(self, page):

View File

@@ -1,6 +1,7 @@
import json
from distutils.util import strtobool
import six
import yaml
from awxkit.cli.utils import colored
@@ -79,7 +80,7 @@ def add_output_formatting_arguments(parser, env):
def format_response(response, fmt='json', filter='.', changed=False):
if response is None:
return # HTTP 204
if isinstance(response, str):
if isinstance(response, six.text_type):
return response
if 'results' in response.__dict__:
@@ -113,7 +114,7 @@ def format_jq(output, fmt):
results = []
for x in jq.jq(fmt).transform(output, multiple_output=True):
if x not in (None, ''):
if isinstance(x, str):
if isinstance(x, six.text_type):
results.append(x)
else:
results.append(json.dumps(x))
@@ -126,9 +127,11 @@ def format_json(output, fmt):
def format_yaml(output, fmt):
output = json.loads(json.dumps(output))
return yaml.dump(
return yaml.safe_dump(
output,
default_flow_style=False
default_flow_style=False,
encoding='utf-8',
allow_unicode=True
)

View File

@@ -1,5 +1,7 @@
import os
from six import PY3, with_metaclass
from awxkit import api, config
from awxkit.api.pages import Page
from awxkit.cli.format import format_response, add_authentication_arguments
@@ -40,7 +42,7 @@ DEPRECATED_RESOURCES_REVERSE = dict(
)
class CustomCommand(object, metaclass=CustomRegistryMeta):
class CustomCommand(with_metaclass(CustomRegistryMeta)):
"""Base class for implementing custom commands.
Custom commands represent static code which should run - they are
@@ -121,15 +123,28 @@ def parse_resource(client, skip_deprecated=False):
if k in ('dashboard',):
# the Dashboard API is deprecated and not supported
continue
aliases = []
if not skip_deprecated:
# argparse aliases are *only* supported in Python3 (not 2.7)
kwargs = {}
if not skip_deprecated and PY3:
if k in DEPRECATED_RESOURCES:
aliases = [DEPRECATED_RESOURCES[k]]
kwargs['aliases'] = [DEPRECATED_RESOURCES[k]]
client.subparsers[k] = subparsers.add_parser(
k, help='', aliases=aliases
k, help='', **kwargs
)
resource = client.parser.parse_known_args()[0].resource
try:
resource = client.parser.parse_known_args()[0].resource
except SystemExit:
if PY3:
raise
else:
# Unfortunately, argparse behavior between py2 and py3
# changed in a notable way when required subparsers
# have invalid (or missing) arguments specified
# see: https://github.com/python/cpython/commit/f97c59aaba2d93e48cbc6d25f7ff9f9c87f8d0b2
# In py2, this raises a SystemExit; which we want to _ignore_
resource = None
if resource in DEPRECATED_RESOURCES.values():
client.argv[
client.argv.index(resource)

View File

@@ -1,8 +1,12 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import sys
import time
from .utils import cprint, color_enabled, STATUS_COLORS
from awxkit.utils import to_str
def monitor_workflow(response, session, print_stdout=True, timeout=None,
@@ -25,6 +29,7 @@ def monitor_workflow(response, session, print_stdout=True, timeout=None,
sys.stdout.write('\x1b[2K')
for result in results:
result['name'] = to_str(result['name'])
if print_stdout:
print('{id} - {name} '.format(**result), end='')
status = result['status']
@@ -39,7 +44,7 @@ def monitor_workflow(response, session, print_stdout=True, timeout=None,
cprint('------Starting Standard Out Stream------', 'red')
if print_stdout:
print('Launching {}...'.format(get().json.name))
print('Launching {}...'.format(to_str(get().json.name)))
started = time.time()
seen = set()
@@ -84,7 +89,7 @@ def monitor(response, session, print_stdout=True, timeout=None, interval=.25):
# skip it for now and wait until the prior lines arrive and are
# printed
continue
stdout = result.get('stdout')
stdout = to_str(result.get('stdout'))
if stdout and print_stdout:
print(stdout)
next_line = result['end_line']

View File

@@ -1,3 +1,5 @@
from __future__ import print_function
from argparse import ArgumentParser
import os
import sys