mirror of
https://github.com/ansible/awx.git
synced 2026-02-25 06:56:00 -03:30
Merge pull request #4516 from ryanpetrello/py2
support the new CLI in py2 *and* py3 Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
2
Makefile
2
Makefile
@@ -376,7 +376,7 @@ test:
|
|||||||
. $(VENV_BASE)/awx/bin/activate; \
|
. $(VENV_BASE)/awx/bin/activate; \
|
||||||
fi; \
|
fi; \
|
||||||
PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider -n auto $(TEST_DIRS)
|
PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider -n auto $(TEST_DIRS)
|
||||||
cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3
|
cd awxkit && $(VENV_BASE)/awx/bin/tox -re py2,py3
|
||||||
awx-manage check_migrations --dry-run --check -n 'vNNN_missing_migration_file'
|
awx-manage check_migrations --dry-run --check -n 'vNNN_missing_migration_file'
|
||||||
|
|
||||||
test_unit:
|
test_unit:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from .api import pages, client, resources # NOQA
|
from awxkit.api import pages, client, resources # NOQA
|
||||||
from .config import config # NOQA
|
from awxkit.config import config # NOQA
|
||||||
from . import awx # NOQA
|
from awxkit import awx # NOQA
|
||||||
from .ws import WSClient # NOQA
|
from awxkit.ws import WSClient # NOQA
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
from awxkit.utils import poll_until
|
from awxkit.utils import poll_until
|
||||||
|
|
||||||
|
|
||||||
@@ -43,7 +45,7 @@ class HasStatus(object):
|
|||||||
return self.wait_until_status(self.started_statuses, interval=interval, timeout=timeout)
|
return self.wait_until_status(self.started_statuses, interval=interval, timeout=timeout)
|
||||||
|
|
||||||
def assert_status(self, status_list, msg=None):
|
def assert_status(self, status_list, msg=None):
|
||||||
if isinstance(status_list, str):
|
if isinstance(status_list, six.text_type):
|
||||||
status_list = [status_list]
|
status_list = [status_list]
|
||||||
if self.status in status_list:
|
if self.status in status_list:
|
||||||
# include corner cases in is_successful logic
|
# include corner cases in is_successful logic
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import http.client
|
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from requests import Response
|
from requests import Response
|
||||||
|
import six
|
||||||
|
from six.moves import http_client as http
|
||||||
|
|
||||||
from awxkit.utils import (
|
from awxkit.utils import (
|
||||||
PseudoNamespace,
|
PseudoNamespace,
|
||||||
@@ -12,7 +13,8 @@ from awxkit.utils import (
|
|||||||
are_same_endpoint,
|
are_same_endpoint,
|
||||||
super_dir_set,
|
super_dir_set,
|
||||||
suppress,
|
suppress,
|
||||||
is_list_or_tuple
|
is_list_or_tuple,
|
||||||
|
to_str
|
||||||
)
|
)
|
||||||
from awxkit.api.client import Connection
|
from awxkit.api.client import Connection
|
||||||
from awxkit.api.registry import URLRegistry
|
from awxkit.api.registry import URLRegistry
|
||||||
@@ -167,7 +169,11 @@ class Page(object):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, raw):
|
def from_json(cls, raw):
|
||||||
resp = Response()
|
resp = Response()
|
||||||
resp._content = bytes(json.dumps(raw), 'utf-8')
|
data = json.dumps(raw)
|
||||||
|
if six.PY3:
|
||||||
|
resp._content = bytes(data, 'utf-8')
|
||||||
|
else:
|
||||||
|
resp._content = data
|
||||||
resp.encoding = 'utf-8'
|
resp.encoding = 'utf-8'
|
||||||
resp.status_code = 200
|
resp.status_code = 200
|
||||||
return cls(r=resp)
|
return cls(r=resp)
|
||||||
@@ -199,16 +205,16 @@ class Page(object):
|
|||||||
"Unable to parse JSON response ({0.status_code}): {1} - '{2}'".format(response, e, text))
|
"Unable to parse JSON response ({0.status_code}): {1} - '{2}'".format(response, e, text))
|
||||||
|
|
||||||
exc_str = "%s (%s) received" % (
|
exc_str = "%s (%s) received" % (
|
||||||
http.client.responses[response.status_code], response.status_code)
|
http.responses[response.status_code], response.status_code)
|
||||||
|
|
||||||
exception = exception_from_status_code(response.status_code)
|
exception = exception_from_status_code(response.status_code)
|
||||||
if exception:
|
if exception:
|
||||||
raise exception(exc_str, data)
|
raise exception(exc_str, data)
|
||||||
|
|
||||||
if response.status_code in (
|
if response.status_code in (
|
||||||
http.client.OK,
|
http.OK,
|
||||||
http.client.CREATED,
|
http.CREATED,
|
||||||
http.client.ACCEPTED):
|
http.ACCEPTED):
|
||||||
|
|
||||||
# Not all JSON responses include a URL. Grab it from the request
|
# Not all JSON responses include a URL. Grab it from the request
|
||||||
# object, if needed.
|
# object, if needed.
|
||||||
@@ -235,7 +241,7 @@ class Page(object):
|
|||||||
r=response,
|
r=response,
|
||||||
ds=ds)
|
ds=ds)
|
||||||
|
|
||||||
elif response.status_code == http.client.FORBIDDEN:
|
elif response.status_code == http.FORBIDDEN:
|
||||||
if is_license_invalid(response):
|
if is_license_invalid(response):
|
||||||
raise exc.LicenseInvalid(exc_str, data)
|
raise exc.LicenseInvalid(exc_str, data)
|
||||||
elif is_license_exceeded(response):
|
elif is_license_exceeded(response):
|
||||||
@@ -243,7 +249,7 @@ class Page(object):
|
|||||||
else:
|
else:
|
||||||
raise exc.Forbidden(exc_str, data)
|
raise exc.Forbidden(exc_str, data)
|
||||||
|
|
||||||
elif response.status_code == http.client.BAD_REQUEST:
|
elif response.status_code == http.BAD_REQUEST:
|
||||||
if is_license_invalid(response):
|
if is_license_invalid(response):
|
||||||
raise exc.LicenseInvalid(exc_str, data)
|
raise exc.LicenseInvalid(exc_str, data)
|
||||||
if is_duplicate_error(response):
|
if is_duplicate_error(response):
|
||||||
@@ -314,14 +320,14 @@ class Page(object):
|
|||||||
return page_cls(self.connection, endpoint=endpoint).get(**kw)
|
return page_cls(self.connection, endpoint=endpoint).get(**kw)
|
||||||
|
|
||||||
|
|
||||||
_exception_map = {http.client.NO_CONTENT: exc.NoContent,
|
_exception_map = {http.NO_CONTENT: exc.NoContent,
|
||||||
http.client.NOT_FOUND: exc.NotFound,
|
http.NOT_FOUND: exc.NotFound,
|
||||||
http.client.INTERNAL_SERVER_ERROR: exc.InternalServerError,
|
http.INTERNAL_SERVER_ERROR: exc.InternalServerError,
|
||||||
http.client.BAD_GATEWAY: exc.BadGateway,
|
http.BAD_GATEWAY: exc.BadGateway,
|
||||||
http.client.METHOD_NOT_ALLOWED: exc.MethodNotAllowed,
|
http.METHOD_NOT_ALLOWED: exc.MethodNotAllowed,
|
||||||
http.client.UNAUTHORIZED: exc.Unauthorized,
|
http.UNAUTHORIZED: exc.Unauthorized,
|
||||||
http.client.PAYMENT_REQUIRED: exc.PaymentRequired,
|
http.PAYMENT_REQUIRED: exc.PaymentRequired,
|
||||||
http.client.CONFLICT: exc.Conflict}
|
http.CONFLICT: exc.Conflict}
|
||||||
|
|
||||||
|
|
||||||
def exception_from_status_code(status_code):
|
def exception_from_status_code(status_code):
|
||||||
@@ -376,10 +382,10 @@ class PageList(object):
|
|||||||
class TentativePage(str):
|
class TentativePage(str):
|
||||||
|
|
||||||
def __new__(cls, endpoint, connection):
|
def __new__(cls, endpoint, connection):
|
||||||
return super(TentativePage, cls).__new__(cls, endpoint)
|
return super(TentativePage, cls).__new__(cls, to_str(endpoint))
|
||||||
|
|
||||||
def __init__(self, endpoint, connection):
|
def __init__(self, endpoint, connection):
|
||||||
self.endpoint = endpoint
|
self.endpoint = to_str(endpoint)
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
|
|
||||||
def _create(self):
|
def _create(self):
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import yaml
|
|||||||
from requests.exceptions import ConnectionError, SSLError
|
from requests.exceptions import ConnectionError, SSLError
|
||||||
|
|
||||||
from .client import CLI
|
from .client import CLI
|
||||||
|
from awxkit.utils import to_str
|
||||||
from awxkit.exceptions import Unauthorized, Common
|
from awxkit.exceptions import Unauthorized, Common
|
||||||
from awxkit.cli.utils import cprint
|
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':
|
if cli.get_config('format') == 'json':
|
||||||
json.dump(e.msg, sys.stdout)
|
json.dump(e.msg, sys.stdout)
|
||||||
elif cli.get_config('format') == 'yaml':
|
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)
|
sys.exit(1)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if cli.verbose:
|
if cli.verbose:
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from requests.exceptions import RequestException
|
from requests.exceptions import RequestException
|
||||||
|
import six
|
||||||
|
|
||||||
from .custom import handle_custom_actions
|
from .custom import handle_custom_actions
|
||||||
from .format import (add_authentication_arguments,
|
from .format import (add_authentication_arguments,
|
||||||
@@ -160,10 +163,18 @@ class CLI(object):
|
|||||||
changed=self.original_action in ('modify', 'create')
|
changed=self.original_action in ('modify', 'create')
|
||||||
)
|
)
|
||||||
if formatted:
|
if formatted:
|
||||||
print(formatted, file=self.stdout)
|
print(utils.to_str(formatted), file=self.stdout)
|
||||||
else:
|
else:
|
||||||
self.parser.print_help()
|
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):
|
def parse_action(self, page, from_sphinx=False):
|
||||||
"""Perform an HTTP OPTIONS request
|
"""Perform an HTTP OPTIONS request
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from six import with_metaclass
|
||||||
|
|
||||||
from .stdout import monitor, monitor_workflow
|
from .stdout import monitor, monitor_workflow
|
||||||
from .utils import CustomRegistryMeta, color_enabled
|
from .utils import CustomRegistryMeta, color_enabled
|
||||||
|
|
||||||
@@ -17,7 +19,7 @@ class CustomActionRegistryMeta(CustomRegistryMeta):
|
|||||||
return ' '.join([self.resource, self.action])
|
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."""
|
"""Base class for defining a custom action for a resource."""
|
||||||
|
|
||||||
def __init__(self, page):
|
def __init__(self, page):
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
from distutils.util import strtobool
|
from distutils.util import strtobool
|
||||||
|
|
||||||
|
import six
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from awxkit.cli.utils import colored
|
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):
|
def format_response(response, fmt='json', filter='.', changed=False):
|
||||||
if response is None:
|
if response is None:
|
||||||
return # HTTP 204
|
return # HTTP 204
|
||||||
if isinstance(response, str):
|
if isinstance(response, six.text_type):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
if 'results' in response.__dict__:
|
if 'results' in response.__dict__:
|
||||||
@@ -113,7 +114,7 @@ def format_jq(output, fmt):
|
|||||||
results = []
|
results = []
|
||||||
for x in jq.jq(fmt).transform(output, multiple_output=True):
|
for x in jq.jq(fmt).transform(output, multiple_output=True):
|
||||||
if x not in (None, ''):
|
if x not in (None, ''):
|
||||||
if isinstance(x, str):
|
if isinstance(x, six.text_type):
|
||||||
results.append(x)
|
results.append(x)
|
||||||
else:
|
else:
|
||||||
results.append(json.dumps(x))
|
results.append(json.dumps(x))
|
||||||
@@ -126,9 +127,11 @@ def format_json(output, fmt):
|
|||||||
|
|
||||||
def format_yaml(output, fmt):
|
def format_yaml(output, fmt):
|
||||||
output = json.loads(json.dumps(output))
|
output = json.loads(json.dumps(output))
|
||||||
return yaml.dump(
|
return yaml.safe_dump(
|
||||||
output,
|
output,
|
||||||
default_flow_style=False
|
default_flow_style=False,
|
||||||
|
encoding='utf-8',
|
||||||
|
allow_unicode=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
from six import PY3, with_metaclass
|
||||||
|
|
||||||
from awxkit import api, config
|
from awxkit import api, config
|
||||||
from awxkit.api.pages import Page
|
from awxkit.api.pages import Page
|
||||||
from awxkit.cli.format import format_response, add_authentication_arguments
|
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.
|
"""Base class for implementing custom commands.
|
||||||
|
|
||||||
Custom commands represent static code which should run - they are
|
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',):
|
if k in ('dashboard',):
|
||||||
# the Dashboard API is deprecated and not supported
|
# the Dashboard API is deprecated and not supported
|
||||||
continue
|
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:
|
if k in DEPRECATED_RESOURCES:
|
||||||
aliases = [DEPRECATED_RESOURCES[k]]
|
kwargs['aliases'] = [DEPRECATED_RESOURCES[k]]
|
||||||
client.subparsers[k] = subparsers.add_parser(
|
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():
|
if resource in DEPRECATED_RESOURCES.values():
|
||||||
client.argv[
|
client.argv[
|
||||||
client.argv.index(resource)
|
client.argv.index(resource)
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from .utils import cprint, color_enabled, STATUS_COLORS
|
from .utils import cprint, color_enabled, STATUS_COLORS
|
||||||
|
from awxkit.utils import to_str
|
||||||
|
|
||||||
|
|
||||||
def monitor_workflow(response, session, print_stdout=True, timeout=None,
|
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')
|
sys.stdout.write('\x1b[2K')
|
||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
|
result['name'] = to_str(result['name'])
|
||||||
if print_stdout:
|
if print_stdout:
|
||||||
print(' ↳ {id} - {name} '.format(**result), end='')
|
print(' ↳ {id} - {name} '.format(**result), end='')
|
||||||
status = result['status']
|
status = result['status']
|
||||||
@@ -39,7 +44,7 @@ def monitor_workflow(response, session, print_stdout=True, timeout=None,
|
|||||||
cprint('------Starting Standard Out Stream------', 'red')
|
cprint('------Starting Standard Out Stream------', 'red')
|
||||||
|
|
||||||
if print_stdout:
|
if print_stdout:
|
||||||
print('Launching {}...'.format(get().json.name))
|
print('Launching {}...'.format(to_str(get().json.name)))
|
||||||
|
|
||||||
started = time.time()
|
started = time.time()
|
||||||
seen = set()
|
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
|
# skip it for now and wait until the prior lines arrive and are
|
||||||
# printed
|
# printed
|
||||||
continue
|
continue
|
||||||
stdout = result.get('stdout')
|
stdout = to_str(result.get('stdout'))
|
||||||
if stdout and print_stdout:
|
if stdout and print_stdout:
|
||||||
print(stdout)
|
print(stdout)
|
||||||
next_line = result['end_line']
|
next_line = result['end_line']
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import sys
|
|||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import six
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from awxkit.words import words
|
from awxkit.words import words
|
||||||
@@ -132,7 +133,7 @@ class PseudoNamespace(dict):
|
|||||||
|
|
||||||
|
|
||||||
def is_relative_endpoint(candidate):
|
def is_relative_endpoint(candidate):
|
||||||
return isinstance(candidate, (str,)) and candidate.startswith('/api/')
|
return isinstance(candidate, (six.text_type,)) and candidate.startswith('/api/')
|
||||||
|
|
||||||
|
|
||||||
def is_class_or_instance(obj, cls):
|
def is_class_or_instance(obj, cls):
|
||||||
@@ -320,6 +321,22 @@ def update_payload(payload, fields, kwargs):
|
|||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def to_str(obj):
|
||||||
|
if six.PY3:
|
||||||
|
if isinstance(obj, bytes):
|
||||||
|
return obj.decode('utf-8')
|
||||||
|
return obj
|
||||||
|
if not isinstance(obj, six.text_type):
|
||||||
|
try:
|
||||||
|
return str(obj)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
try:
|
||||||
|
obj = six.text_type(obj, 'utf8')
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
obj = obj.decode('latin1')
|
||||||
|
return obj.encode('utf8')
|
||||||
|
|
||||||
|
|
||||||
def to_bool(obj):
|
def to_bool(obj):
|
||||||
if isinstance(obj, (str,)):
|
if isinstance(obj, (str,)):
|
||||||
return obj.lower() not in ('false', 'off', 'no', 'n', '0', '')
|
return obj.lower() not in ('false', 'off', 'no', 'n', '0', '')
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
from queue import Queue, Empty
|
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
import logging
|
import logging
|
||||||
import atexit
|
import atexit
|
||||||
import json
|
import json
|
||||||
import ssl
|
import ssl
|
||||||
import urllib.parse
|
|
||||||
|
from six.moves.queue import Queue, Empty
|
||||||
|
from six.moves.urllib.parse import urlparse
|
||||||
|
|
||||||
from awxkit.config import config
|
from awxkit.config import config
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ class WSClient(object):
|
|||||||
import websocket
|
import websocket
|
||||||
|
|
||||||
if not hostname:
|
if not hostname:
|
||||||
result = urllib.parse.urlparse(config.base_url)
|
result = urlparse(config.base_url)
|
||||||
secure = result.scheme == 'https'
|
secure = result.scheme == 'https'
|
||||||
port = result.port
|
port = result.port
|
||||||
if port is None:
|
if port is None:
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
PyYAML
|
PyYAML
|
||||||
requests
|
requests
|
||||||
|
six
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ setup(
|
|||||||
},
|
},
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
install_requires=requirements,
|
install_requires=requirements,
|
||||||
python_requires=">= 3.5",
|
python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*",
|
||||||
extras_require={
|
extras_require={
|
||||||
'formatting': ['jq', 'tabulate'],
|
'formatting': ['jq', 'tabulate'],
|
||||||
'websockets': ['websocket-client>0.54.0'],
|
'websockets': ['websocket-client>0.54.0'],
|
||||||
|
|||||||
@@ -50,8 +50,14 @@ def test_list_resources(capfd, resource):
|
|||||||
cli.parse_args(['awx {}'.format(resource)])
|
cli.parse_args(['awx {}'.format(resource)])
|
||||||
cli.connect()
|
cli.connect()
|
||||||
|
|
||||||
cli.parse_resource()
|
try:
|
||||||
out, err = capfd.readouterr()
|
cli.parse_resource()
|
||||||
|
out, err = capfd.readouterr()
|
||||||
|
except SystemExit:
|
||||||
|
# python2 argparse raises SystemExit for invalid/missing required args,
|
||||||
|
# py3 doesn't
|
||||||
|
_, out = capfd.readouterr()
|
||||||
|
|
||||||
assert "usage:" in out
|
assert "usage:" in out
|
||||||
for snippet in (
|
for snippet in (
|
||||||
'--conf.host https://example.awx.org]',
|
'--conf.host https://example.awx.org]',
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
import unittest
|
import unittest
|
||||||
from io import StringIO
|
try:
|
||||||
|
from StringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from requests import Response
|
from requests import Response
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
from unittest.mock import patch
|
try:
|
||||||
|
from unittest.mock import patch
|
||||||
|
except ImportError:
|
||||||
|
from mock import patch
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
from unittest import mock
|
try:
|
||||||
|
from unittest import mock
|
||||||
|
except ImportError:
|
||||||
|
import mock
|
||||||
import pytest
|
import pytest
|
||||||
|
import six
|
||||||
|
|
||||||
from awxkit import utils
|
from awxkit import utils
|
||||||
from awxkit import exceptions as exc
|
from awxkit import exceptions as exc
|
||||||
@@ -73,11 +78,19 @@ def test_load_invalid_json_or_yaml(inp):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('non_ascii', [True, False])
|
@pytest.mark.parametrize('non_ascii', [True, False])
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.version_info < (3, 6),
|
||||||
|
reason='this is only intended to be used in py3, not the CLI'
|
||||||
|
)
|
||||||
def test_random_titles_are_unicode(non_ascii):
|
def test_random_titles_are_unicode(non_ascii):
|
||||||
assert isinstance(utils.random_title(non_ascii=non_ascii), str)
|
assert isinstance(utils.random_title(non_ascii=non_ascii), six.text_type)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('non_ascii', [True, False])
|
@pytest.mark.parametrize('non_ascii', [True, False])
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.version_info < (3, 6),
|
||||||
|
reason='this is only intended to be used in py3, not the CLI'
|
||||||
|
)
|
||||||
def test_random_titles_generates_correct_characters(non_ascii):
|
def test_random_titles_generates_correct_characters(non_ascii):
|
||||||
title = utils.random_title(non_ascii=non_ascii)
|
title = utils.random_title(non_ascii=non_ascii)
|
||||||
if non_ascii:
|
if non_ascii:
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from unittest.mock import patch
|
try:
|
||||||
|
from unittest.mock import patch
|
||||||
|
except ImportError:
|
||||||
|
from mock import patch
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from awxkit.ws import WSClient
|
from awxkit.ws import WSClient
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ setenv =
|
|||||||
deps =
|
deps =
|
||||||
websocket-client
|
websocket-client
|
||||||
coverage
|
coverage
|
||||||
|
mock
|
||||||
pytest
|
pytest
|
||||||
pytest-mock
|
pytest-mock
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user