diff --git a/doc/ext/apidoc.py b/doc/ext/apidoc.py index fc5db88..98ef11f 100644 --- a/doc/ext/apidoc.py +++ b/doc/ext/apidoc.py @@ -31,12 +31,19 @@ def run_apidoc(app): return run_already = True - package_dir = path.abspath(path.join(app.srcdir, '..', '..', - 'osc_lib')) + package_dir = path.abspath(path.join(app.srcdir, '..', '..', 'osc_lib')) source_dir = path.join(app.srcdir, 'api') - apidoc.main(['apidoc', package_dir, '-f', - '-H', 'osc-lib Modules', - '-o', source_dir]) + apidoc.main( + [ + 'apidoc', + package_dir, + '-f', + '-H', + 'osc-lib Modules', + '-o', + source_dir, + ] + ) def setup(app): diff --git a/doc/source/conf.py b/doc/source/conf.py index ea40269..11c47e3 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -17,21 +17,24 @@ import sys # NOTE(blk-u): Path for our Sphinx extension, remove when # https://launchpad.net/bugs/1260495 is fixed. -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +sys.path.insert( + 0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +) # -- General configuration ---------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.todo', - 'openstackdocstheme', - 'sphinxcontrib.apidoc', - ] +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.todo', + 'openstackdocstheme', + 'sphinxcontrib.apidoc', +] # openstackdocstheme options openstackdocs_repo_name = 'openstack/osc-lib' @@ -39,13 +42,13 @@ openstackdocs_auto_name = False openstackdocs_use_storyboard = True # Add any paths that contain templates here, relative to this directory. -#templates_path = ['_templates'] +# templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' @@ -55,13 +58,13 @@ project = 'OpenStackClient CLI Base' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -69,18 +72,18 @@ exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'native' @@ -93,76 +96,76 @@ modindex_common_prefix = ['osc_lib.'] # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -#html_theme_path = ["."] -#html_theme = '_theme' +# html_theme_path = ["."] +# html_theme = '_theme' html_theme = 'openstackdocs' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] +# html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'OpenStackCommandLineClientdoc' @@ -171,54 +174,55 @@ htmlhelp_basename = 'OpenStackCommandLineClientdoc' # -- Options for LaTeX output ------------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]) # . latex_documents = [ - ('index', 'OpenStackCommandLineClient.tex', - 'OpenStack Command Line Client Documentation', - 'OpenStack'), + ( + 'index', + 'OpenStackCommandLineClient.tex', + 'OpenStack Command Line Client Documentation', + 'OpenStack', + ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output ------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -#man_pages = [] +# man_pages = [] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ----------------------------------------------- @@ -227,21 +231,25 @@ latex_documents = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'OpenStackCommandLineClient', - 'OpenStack Command Line Client Documentation', - 'OpenStack', 'OpenStackCommandLineClient', - 'One line description of project.', - 'Miscellaneous'), + ( + 'index', + 'OpenStackCommandLineClient', + 'OpenStack Command Line Client Documentation', + 'OpenStack', + 'OpenStackCommandLineClient', + 'One line description of project.', + 'Miscellaneous', + ), ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # -- Options for sphinxcontrib.apidoc ---------------------------------------- diff --git a/osc_lib/api/api.py b/osc_lib/api/api.py index cbb62fb..467b6f9 100644 --- a/osc_lib/api/api.py +++ b/osc_lib/api/api.py @@ -42,11 +42,7 @@ class BaseAPI(object): HEADER_NAME = "OpenStack-API-Version" def __init__( - self, - session=None, - service_type=None, - endpoint=None, - **kwargs + self, session=None, service_type=None, endpoint=None, **kwargs ): """Base object that contains some common API objects and methods @@ -140,13 +136,7 @@ class BaseAPI(object): # The basic action methods all take a Session and return dict/lists - def create( - self, - url, - session=None, - method=None, - **params - ): + def create(self, url, session=None, method=None, **params): """Create a new resource :param string url: @@ -166,12 +156,7 @@ class BaseAPI(object): except json.JSONDecodeError: return ret - def delete( - self, - url, - session=None, - **params - ): + def delete(self, url, session=None, **params): """Delete a resource :param string url: @@ -292,9 +277,7 @@ class BaseAPI(object): if len(data) > 1: msg = _("Multiple %(resource)s exist with %(attr)s='%(value)s'") raise exceptions.CommandError( - msg % {'resource': resource, - 'attr': attr, - 'value': value} + msg % {'resource': resource, 'attr': attr, 'value': value} ) # Search by id @@ -304,17 +287,10 @@ class BaseAPI(object): return data[0] msg = _("No %(resource)s with a %(attr)s or ID of '%(value)s' found") raise exceptions.CommandError( - msg % {'resource': resource, - 'attr': attr, - 'value': value} + msg % {'resource': resource, 'attr': attr, 'value': value} ) - def find_bulk( - self, - path, - headers=None, - **kwargs - ): + def find_bulk(self, path, headers=None, **kwargs): """Bulk load and filter locally :param string path: @@ -342,11 +318,7 @@ class BaseAPI(object): return ret - def find_one( - self, - path, - **kwargs - ): + def find_one(self, path, **kwargs): """Find a resource by name or ID :param string path: @@ -390,7 +362,8 @@ class BaseAPI(object): try: ret = self._request( - 'GET', "/%s/%s" % (path, value), + 'GET', + "/%s/%s" % (path, value), headers=headers, ).json() if isinstance(ret, dict): @@ -404,11 +377,7 @@ class BaseAPI(object): if attr: kwargs = {attr: value} try: - ret = self.find_one( - path, - headers=headers, - **kwargs - ) + ret = self.find_one(path, headers=headers, **kwargs) except ( exceptions.NotFound, ksa_exceptions.NotFound, diff --git a/osc_lib/api/auth.py b/osc_lib/api/auth.py index 3963d0f..b671443 100644 --- a/osc_lib/api/auth.py +++ b/osc_lib/api/auth.py @@ -53,7 +53,8 @@ def get_options_list(): os_name = o.name.lower().replace('_', '-') os_env_name = 'OS_' + os_name.upper().replace('-', '_') OPTIONS_LIST.setdefault( - os_name, {'env': os_env_name, 'help': ''}, + os_name, + {'env': os_env_name, 'help': ''}, ) # TODO(mhu) simplistic approach, would be better to only add # help texts if they vary from one auth plugin to another @@ -67,19 +68,23 @@ def get_options_list(): def check_valid_authorization_options(options, auth_plugin_name): """Validate authorization options, and provide helpful error messages.""" - if (options.auth.get('project_id') and not - options.auth.get('domain_id') and not - options.auth.get('domain_name') and not - options.auth.get('project_name') and not - options.auth.get('tenant_id') and not - options.auth.get('tenant_name')): - raise exc.CommandError(_( - 'Missing parameter(s): ' - 'Set either a project or a domain scope, but not both. Set a ' - 'project scope with --os-project-name, OS_PROJECT_NAME, or ' - 'auth.project_name. Alternatively, set a domain scope with ' - '--os-domain-name, OS_DOMAIN_NAME or auth.domain_name.' - )) + if ( + options.auth.get('project_id') + and not options.auth.get('domain_id') + and not options.auth.get('domain_name') + and not options.auth.get('project_name') + and not options.auth.get('tenant_id') + and not options.auth.get('tenant_name') + ): + raise exc.CommandError( + _( + 'Missing parameter(s): ' + 'Set either a project or a domain scope, but not both. Set a ' + 'project scope with --os-project-name, OS_PROJECT_NAME, or ' + 'auth.project_name. Alternatively, set a domain scope with ' + '--os-domain-name, OS_DOMAIN_NAME or auth.domain_name.' + ) + ) def check_valid_authentication_options(options, auth_plugin_name): @@ -102,31 +107,34 @@ def check_valid_authentication_options(options, auth_plugin_name): # when no auth params are passed in, user advised to use os-cloud if not options.auth and auth_plugin_name != 'none': - msgs.append(_( - 'Set a cloud-name with --os-cloud or OS_CLOUD' - )) + msgs.append(_('Set a cloud-name with --os-cloud or OS_CLOUD')) else: - if ('password' in plugin_opts and not - (options.auth.get('username') or options.auth.get('user_id'))): - msgs.append(_( - 'Set a username with --os-username, OS_USERNAME,' - ' or auth.username' - ' or set a user-id with --os-user-id, OS_USER_ID,' - ' or auth.user_id' - )) + if 'password' in plugin_opts and not ( + options.auth.get('username') or options.auth.get('user_id') + ): + msgs.append( + _( + 'Set a username with --os-username, OS_USERNAME,' + ' or auth.username' + ' or set a user-id with --os-user-id, OS_USER_ID,' + ' or auth.user_id' + ) + ) if 'auth_url' in plugin_opts and not options.auth.get('auth_url'): - msgs.append(_( - 'Set an authentication URL, with --os-auth-url,' - ' OS_AUTH_URL or auth.auth_url' - )) + msgs.append( + _( + 'Set an authentication URL, with --os-auth-url,' + ' OS_AUTH_URL or auth.auth_url' + ) + ) if 'url' in plugin_opts and not options.auth.get('url'): - msgs.append(_( - 'Set a service URL, with --os-url, OS_URL or auth.url' - )) + msgs.append( + _('Set a service URL, with --os-url, OS_URL or auth.url') + ) if 'token' in plugin_opts and not options.auth.get('token'): - msgs.append(_( - 'Set a token with --os-token, OS_TOKEN or auth.token' - )) + msgs.append( + _('Set a token with --os-token, OS_TOKEN or auth.token') + ) if msgs: raise exc.CommandError( @@ -147,20 +155,21 @@ def build_auth_plugins_option_parser(parser): metavar='', dest='auth_type', default=utils.env('OS_AUTH_TYPE'), - help=_('Select an authentication type. Available types: %s.' - ' Default: selected based on --os-username/--os-token' - ' (Env: OS_AUTH_TYPE)') % ', '.join(available_plugins), - choices=available_plugins + help=_( + 'Select an authentication type. Available types: %s.' + ' Default: selected based on --os-username/--os-token' + ' (Env: OS_AUTH_TYPE)' + ) + % ', '.join(available_plugins), + choices=available_plugins, ) # Maintain compatibility with old tenant env vars envs = { 'OS_PROJECT_NAME': utils.env( - 'OS_PROJECT_NAME', - default=utils.env('OS_TENANT_NAME') + 'OS_PROJECT_NAME', default=utils.env('OS_TENANT_NAME') ), 'OS_PROJECT_ID': utils.env( - 'OS_PROJECT_ID', - default=utils.env('OS_TENANT_ID') + 'OS_PROJECT_ID', default=utils.env('OS_TENANT_ID') ), } for o in get_options_list(): @@ -174,7 +183,8 @@ def build_auth_plugins_option_parser(parser): OPTIONS_LIST[o]['env'], utils.env(OPTIONS_LIST[o]['env']), ), - help=_('%(help)s\n(Env: %(env)s)') % { + help=_('%(help)s\n(Env: %(env)s)') + % { 'help': OPTIONS_LIST[o]['help'], 'env': OPTIONS_LIST[o]['env'], }, @@ -196,10 +206,14 @@ def build_auth_plugins_option_parser(parser): return parser -def get_keystone2keystone_auth(local_auth, service_provider, - project_id=None, project_name=None, - project_domain_id=None, - project_domain_name=None): +def get_keystone2keystone_auth( + local_auth, + service_provider, + project_id=None, + project_name=None, + project_domain_id=None, + project_domain_name=None, +): """Return Keystone 2 Keystone authentication for service provider. :param local_auth: authentication to use with the local Keystone @@ -210,9 +224,11 @@ def get_keystone2keystone_auth(local_auth, service_provider, :param project_domain_name: name of domain to in the service provider :return: Keystone2Keystone auth object for service provider """ - return k2k.Keystone2Keystone(local_auth, - service_provider, - project_id=project_id, - project_name=project_name, - project_domain_id=project_domain_id, - project_domain_name=project_domain_name) + return k2k.Keystone2Keystone( + local_auth, + service_provider, + project_id=project_id, + project_name=project_name, + project_domain_id=project_domain_id, + project_domain_name=project_domain_name, + ) diff --git a/osc_lib/api/utils.py b/osc_lib/api/utils.py index 6407cd4..4204307 100644 --- a/osc_lib/api/utils.py +++ b/osc_lib/api/utils.py @@ -60,8 +60,11 @@ def simple_filter( if attr in d: # Searching data fields search_value = d[attr] - elif (property_field and property_field in d and - isinstance(d[property_field], dict)): + elif ( + property_field + and property_field in d + and isinstance(d[property_field], dict) + ): # Searching a properties field - do this separately because # we don't want to fail over to checking the fields if a # property name is given. diff --git a/osc_lib/cli/client_config.py b/osc_lib/cli/client_config.py index bc05f89..154a14c 100644 --- a/osc_lib/cli/client_config.py +++ b/osc_lib/cli/client_config.py @@ -26,7 +26,6 @@ LOG = logging.getLogger(__name__) # Sublcass OpenStackConfig in order to munge config values # before auth plugins are loaded class OSC_Config(config.OpenStackConfig): - def _auth_select_default_plugin(self, config): """Select a default plugin based on supplied arguments @@ -66,7 +65,7 @@ class OSC_Config(config.OpenStackConfig): Migrated from auth.build_auth_params() """ - if ('auth_type' in config and config['auth_type'].startswith("v2")): + if 'auth_type' in config and config['auth_type'].startswith("v2"): if 'project_id' in config['auth']: config['auth']['tenant_id'] = config['auth']['project_id'] if 'project_name' in config['auth']: @@ -82,8 +81,9 @@ class OSC_Config(config.OpenStackConfig): # NOTE(hieulq): If USER_DOMAIN_NAME, USER_DOMAIN_ID, PROJECT_DOMAIN_ID # or PROJECT_DOMAIN_NAME is present and API_VERSION is 2.0, then # ignore all domain related configs. - if (str(config.get('identity_api_version', '')).startswith('2') and - config.get('auth_type').endswith('password')): + if str(config.get('identity_api_version', '')).startswith( + '2' + ) and config.get('auth_type').endswith('password'): domain_props = [ 'project_domain_id', 'project_domain_name', @@ -95,12 +95,14 @@ class OSC_Config(config.OpenStackConfig): if config.get('cloud'): LOG.warning( "Ignoring domain related config %s for %s" - "because identity API version is 2.0" % ( - prop, config['cloud'])) + "because identity API version is 2.0" + % (prop, config['cloud']) + ) else: LOG.warning( "Ignoring domain related config %s because" - " identity API version is 2.0" % prop) + " identity API version is 2.0" % prop + ) return config def _auth_default_domain(self, config): @@ -115,17 +117,18 @@ class OSC_Config(config.OpenStackConfig): # TODO(mordred): This is a usability improvement that's broadly useful # We should port it back up into os-client-config. default_domain = config.get('default_domain', None) - if (identity_version == '3' and - not auth_type.startswith('v2') and - default_domain): - + if ( + identity_version == '3' + and not auth_type.startswith('v2') + and default_domain + ): # NOTE(stevemar): If PROJECT_DOMAIN_ID or PROJECT_DOMAIN_NAME is # present, then do not change the behaviour. Otherwise, set the # PROJECT_DOMAIN_ID to 'OS_DEFAULT_DOMAIN' for better usability. if ( - auth_type in ("password", "v3password", "v3totp") and - not config['auth'].get('project_domain_id') and - not config['auth'].get('project_domain_name') + auth_type in ("password", "v3password", "v3totp") + and not config['auth'].get('project_domain_id') + and not config['auth'].get('project_domain_name') ): config['auth']['project_domain_id'] = default_domain @@ -136,9 +139,9 @@ class OSC_Config(config.OpenStackConfig): # TODO(dtroyer): Move this to os-client-config after the plugin has # been loaded so we can check directly if the options are accepted. if ( - auth_type in ("password", "v3password", "v3totp") and - not config['auth'].get('user_domain_id') and - not config['auth'].get('user_domain_name') + auth_type in ("password", "v3password", "v3totp") + and not config['auth'].get('user_domain_id') + and not config['auth'].get('user_domain_name') ): config['auth']['user_domain_id'] = default_domain return config @@ -156,8 +159,9 @@ class OSC_Config(config.OpenStackConfig): config = self._auth_default_domain(config) if LOG.isEnabledFor(logging.DEBUG): - LOG.debug("auth_config_hook(): %s", - strutils.mask_password(str(config))) + LOG.debug( + "auth_config_hook(): %s", strutils.mask_password(str(config)) + ) return config def _validate_auth(self, config, loader, fixed_argparse=None): @@ -176,7 +180,8 @@ class OSC_Config(config.OpenStackConfig): winning_value = self._find_winning_auth_value(p_opt, config) if not winning_value: winning_value = self._find_winning_auth_value( - p_opt, config['auth']) + p_opt, config['auth'] + ) # if the plugin tells us that this value is required # then error if it's doesn't exist now @@ -184,7 +189,8 @@ class OSC_Config(config.OpenStackConfig): msgs.append( 'Missing value {auth_key}' ' required for auth plugin {plugin}'.format( - auth_key=p_opt.name, plugin=config.get('auth_type'), + auth_key=p_opt.name, + plugin=config.get('auth_type'), ) ) @@ -198,17 +204,18 @@ class OSC_Config(config.OpenStackConfig): # Prefer the plugin configuration dest value if the value's key # is marked as depreciated. if p_opt.dest is None: - config['auth'][p_opt.name.replace('-', '_')] = ( - winning_value) + config['auth'][ + p_opt.name.replace('-', '_') + ] = winning_value else: config['auth'][p_opt.dest] = winning_value # See if this needs a prompting if ( - 'prompt' in vars(p_opt) and - p_opt.prompt is not None and - p_opt.dest not in config['auth'] and - self._pw_callback is not None + 'prompt' in vars(p_opt) + and p_opt.prompt is not None + and p_opt.dest not in config['auth'] + and self._pw_callback is not None ): # Defer these until we know all required opts are present prompt_options.append(p_opt) diff --git a/osc_lib/cli/identity.py b/osc_lib/cli/identity.py index e352371..2f2a5cb 100644 --- a/osc_lib/cli/identity.py +++ b/osc_lib/cli/identity.py @@ -25,14 +25,16 @@ def add_project_owner_option_to_parser(parser): parser.add_argument( '--project', metavar='', - help=_("Owner's project (name or ID)") + help=_("Owner's project (name or ID)"), ) parser.add_argument( '--project-domain', metavar='', - help=_('Domain the project belongs to (name or ID). ' - 'This can be used in case collisions between project names ' - 'exist.'), + help=_( + 'Domain the project belongs to (name or ID). ' + 'This can be used in case collisions between project names ' + 'exist.' + ), ) @@ -55,14 +57,15 @@ def find_project(sdk_connection, name_or_id, domain_name_or_id=None): """ try: if domain_name_or_id: - domain = sdk_connection.identity.find_domain(domain_name_or_id, - ignore_missing=False) + domain = sdk_connection.identity.find_domain( + domain_name_or_id, ignore_missing=False + ) domain_id = domain.id else: domain_id = None - return sdk_connection.identity.find_project(name_or_id, - ignore_missing=False, - domain_id=domain_id) + return sdk_connection.identity.find_project( + name_or_id, ignore_missing=False, domain_id=domain_id + ) # NOTE: OpenStack SDK raises HttpException for 403 response code. # There is no specific exception class at now, so we need to catch # HttpException and check the status code. diff --git a/osc_lib/cli/parseractions.py b/osc_lib/cli/parseractions.py index 688a8e5..3c97c35 100644 --- a/osc_lib/cli/parseractions.py +++ b/osc_lib/cli/parseractions.py @@ -84,8 +84,15 @@ class MultiKeyValueAction(argparse.Action): And comma(',') and equal('=') may not be used in the key or value. """ - def __init__(self, option_strings, dest, nargs=None, - required_keys=None, optional_keys=None, **kwargs): + def __init__( + self, + option_strings, + dest, + nargs=None, + required_keys=None, + optional_keys=None, + **kwargs + ): """Initialize the action object, and parse customized options Required keys and optional keys can be specified when initializing @@ -99,8 +106,9 @@ class MultiKeyValueAction(argparse.Action): msg = _("Parameter 'nargs' is not allowed, but got %s") raise ValueError(msg % nargs) - super(MultiKeyValueAction, self).__init__(option_strings, - dest, **kwargs) + super(MultiKeyValueAction, self).__init__( + option_strings, dest, **kwargs + ) # required_keys: A list of keys that is required. None by default. if required_keys and not isinstance(required_keys, list): @@ -128,10 +136,13 @@ class MultiKeyValueAction(argparse.Action): "Invalid keys %(invalid_keys)s specified.\n" "Valid keys are: %(valid_keys)s" ) - raise argparse.ArgumentTypeError(msg % { - 'invalid_keys': ', '.join(invalid_keys), - 'valid_keys': ', '.join(valid_keys), - }) + raise argparse.ArgumentTypeError( + msg + % { + 'invalid_keys': ', '.join(invalid_keys), + 'valid_keys': ', '.join(valid_keys), + } + ) if self.required_keys: missing_keys = [k for k in self.required_keys if k not in keys] @@ -140,10 +151,13 @@ class MultiKeyValueAction(argparse.Action): "Missing required keys %(missing_keys)s.\n" "Required keys are: %(required_keys)s" ) - raise argparse.ArgumentTypeError(msg % { - 'missing_keys': ', '.join(missing_keys), - 'required_keys': ', '.join(self.required_keys), - }) + raise argparse.ArgumentTypeError( + msg + % { + 'missing_keys': ', '.join(missing_keys), + 'required_keys': ', '.join(self.required_keys), + } + ) def __call__(self, parser, namespace, values, metavar=None): # Make sure we have an empty list rather than None @@ -245,10 +259,14 @@ class RangeAction(argparse.Action): setattr(namespace, self.dest, (int(range[0]), int(range[1]))) else: msg = _("Invalid range, %(min)s is not less than %(max)s") - raise argparse.ArgumentError(self, msg % { - 'min': range[0], - 'max': range[1], - }) + raise argparse.ArgumentError( + self, + msg + % { + 'min': range[0], + 'max': range[1], + }, + ) else: # Too many values msg = _("Invalid range, too many values") diff --git a/osc_lib/clientmanager.py b/osc_lib/clientmanager.py index b779ee4..2389495 100644 --- a/osc_lib/clientmanager.py +++ b/osc_lib/clientmanager.py @@ -18,7 +18,7 @@ import copy import logging -from openstack.config import loader as config # noqa +from openstack.config import loader as config # noqa from openstack import connection from oslo_utils import strutils @@ -145,13 +145,16 @@ class ClientManager(object): # Horrible hack alert...must handle prompt for null password if # password auth is requested. - if (self.auth_plugin_name.endswith('password') and - not self._cli_options.auth.get('password')): + if self.auth_plugin_name.endswith( + 'password' + ) and not self._cli_options.auth.get('password'): self._cli_options.auth['password'] = self._pw_callback() LOG.info('Using auth plugin: %s', self.auth_plugin_name) - LOG.debug('Using parameters %s', - strutils.mask_password(self._cli_options.auth)) + LOG.debug( + 'Using parameters %s', + strutils.mask_password(self._cli_options.auth), + ) self.auth = self._cli_options.get_auth() if self._cli_options.service_provider: @@ -161,7 +164,7 @@ class ClientManager(object): self._cli_options.remote_project_id, self._cli_options.remote_project_name, self._cli_options.remote_project_domain_id, - self._cli_options.remote_project_domain_name + self._cli_options.remote_project_domain_name, ) self.session = self._cli_options.get_session() @@ -193,8 +196,10 @@ class ClientManager(object): @property def auth_ref(self): """Dereference will trigger an auth if it hasn't already""" - if (not self._auth_required or - self._cli_options.config['auth_type'] == 'none'): + if ( + not self._auth_required + or self._cli_options.config['auth_type'] == 'none' + ): # Forcibly skip auth if we know we do not need it return None if not self._auth_ref: @@ -230,8 +235,9 @@ class ClientManager(object): LOG.debug("No service catalog") return service_available - def get_endpoint_for_service_type(self, service_type, region_name=None, - interface='public'): + def get_endpoint_for_service_type( + self, service_type, region_name=None, interface='public' + ): """Return the endpoint URL for the service type.""" # Overrides take priority unconditionally override = self._override_for(service_type) diff --git a/osc_lib/command/command.py b/osc_lib/command/command.py index bc3719e..1a3b112 100644 --- a/osc_lib/command/command.py +++ b/osc_lib/command/command.py @@ -24,25 +24,26 @@ from osc_lib.i18n import _ class CommandMeta(abc.ABCMeta): - def __new__(mcs, name, bases, cls_dict): if 'log' not in cls_dict: cls_dict['log'] = logging.getLogger( - cls_dict['__module__'] + '.' + name) + cls_dict['__module__'] + '.' + name + ) return super(CommandMeta, mcs).__new__(mcs, name, bases, cls_dict) class Command(command.Command, metaclass=CommandMeta): - def run(self, parsed_args): self.log.debug('run(%s)', parsed_args) return super(Command, self).run(parsed_args) def validate_os_beta_command_enabled(self): if not self.app.options.os_beta_command: - msg = _('Caution: This is a beta command and subject to ' - 'change. Use global option --os-beta-command ' - 'to enable this command.') + msg = _( + 'Caution: This is a beta command and subject to ' + 'change. Use global option --os-beta-command ' + 'to enable this command.' + ) raise exceptions.CommandError(msg) def deprecated_option_warning(self, old_option, new_option): diff --git a/osc_lib/command/commandmanager.py b/osc_lib/command/commandmanager.py index 5530f3a..4042efc 100644 --- a/osc_lib/command/commandmanager.py +++ b/osc_lib/command/commandmanager.py @@ -18,4 +18,5 @@ import cliff.commandmanager class CommandManager(cliff.commandmanager.CommandManager): """Noop subclass for transition purposes.""" + pass diff --git a/osc_lib/exceptions.py b/osc_lib/exceptions.py index 4373cee..156b22c 100644 --- a/osc_lib/exceptions.py +++ b/osc_lib/exceptions.py @@ -26,6 +26,7 @@ class AuthorizationFailure(Exception): class PluginAttributeError(Exception): """A plugin threw an AttributeError while being lazily loaded.""" + # This *must not* inherit from AttributeError; # that would defeat the whole purpose. pass @@ -33,21 +34,25 @@ class PluginAttributeError(Exception): class NoTokenLookupException(Exception): """This does not support looking up endpoints from an existing token.""" + pass class EndpointNotFound(Exception): """Could not find Service or Region in Service Catalog.""" + pass class UnsupportedVersion(Exception): """The user is trying to use an unsupported version of the API""" + pass class InvalidValue(Exception): """An argument value is not valid: wrong type, out of range, etc""" + message = "Supplied value is not valid" @@ -68,36 +73,42 @@ class ClientException(Exception): class BadRequest(ClientException): """HTTP 400 - Bad request: you sent some malformed data.""" + http_status = 400 message = "Bad request" class Unauthorized(ClientException): """HTTP 401 - Unauthorized: bad credentials.""" + http_status = 401 message = "Unauthorized" class Forbidden(ClientException): """HTTP 403 - Forbidden: not authorized to access to this resource.""" + http_status = 403 message = "Forbidden" class NotFound(ClientException): """HTTP 404 - Not found""" + http_status = 404 message = "Not found" class Conflict(ClientException): """HTTP 409 - Conflict""" + http_status = 409 message = "Conflict" class OverLimit(ClientException): """HTTP 413 - Over limit: reached the API limits for this time period.""" + http_status = 413 message = "Over limit" @@ -105,6 +116,7 @@ class OverLimit(ClientException): # NotImplemented is a python keyword. class HTTPNotImplemented(ClientException): """HTTP 501 - Not Implemented: server does not support this operation.""" + http_status = 501 message = "Not Implemented" @@ -115,11 +127,14 @@ class HTTPNotImplemented(ClientException): # for c in ClientException.__subclasses__()) # # Instead, we have to hardcode it: -_code_map = dict((c.http_status, c) for c in [ - BadRequest, - Unauthorized, - Forbidden, - NotFound, - OverLimit, - HTTPNotImplemented -]) +_code_map = dict( + (c.http_status, c) + for c in [ + BadRequest, + Unauthorized, + Forbidden, + NotFound, + OverLimit, + HTTPNotImplemented, + ] +) diff --git a/osc_lib/logs.py b/osc_lib/logs.py index 8671555..bc6b08e 100644 --- a/osc_lib/logs.py +++ b/osc_lib/logs.py @@ -81,8 +81,10 @@ def set_warning_filter(log_level): class _FileFormatter(logging.Formatter): """Customize the logging format for logging handler""" + _LOG_MESSAGE_BEGIN = ( - '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s ') + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s ' + ) _LOG_MESSAGE_CONTEXT = '[%(cloud)s %(username)s %(project)s] ' _LOG_MESSAGE_END = '%(message)s' _LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S' @@ -102,16 +104,17 @@ class _FileFormatter(logging.Formatter): 'username': config.auth.get('username', ''), } if context: - self.fmt = (self._LOG_MESSAGE_BEGIN + - (self._LOG_MESSAGE_CONTEXT % context) + - self._LOG_MESSAGE_END) + self.fmt = ( + self._LOG_MESSAGE_BEGIN + + (self._LOG_MESSAGE_CONTEXT % context) + + self._LOG_MESSAGE_END + ) else: self.fmt = self._LOG_MESSAGE_BEGIN + self._LOG_MESSAGE_END logging.Formatter.__init__(self, self.fmt, self._LOG_DATE_FORMAT) class LogConfigurator(object): - _CONSOLE_MESSAGE_FORMAT = '%(message)s' def __init__(self, options): @@ -183,7 +186,7 @@ class LogConfigurator(object): for k in logconfig.keys(): level = log_level_from_string(logconfig[k]) logging.getLogger(k).setLevel(level) - if (highest_level < level): + if highest_level < level: highest_level = level self.console_logger.setLevel(highest_level) if self.file_logger: diff --git a/osc_lib/shell.py b/osc_lib/shell.py index 5d673d3..6c79318 100644 --- a/osc_lib/shell.py +++ b/osc_lib/shell.py @@ -63,29 +63,32 @@ def prompt_for_password(prompt=None): pass # No password because we did't have a tty or nothing was entered if not pw: - raise exc.CommandError(_("No password entered, or found via" - " --os-password or OS_PASSWORD"),) + raise exc.CommandError( + _( + "No password entered, or found via" + " --os-password or OS_PASSWORD" + ), + ) return pw class OpenStackShell(app.App): - CONSOLE_MESSAGE_FORMAT = '%(levelname)s: %(name)s %(message)s' log = logging.getLogger(__name__) timing_data = [] def __init__( - self, - description=None, - version=None, - command_manager=None, - stdin=None, - stdout=None, - stderr=None, - interactive_app_factory=None, - deferred_help=False, + self, + description=None, + version=None, + command_manager=None, + stdin=None, + stdout=None, + stderr=None, + interactive_app_factory=None, + deferred_help=False, ): # Patch command.Command to add a default auth_required = True command.Command.auth_required = True @@ -163,10 +166,14 @@ class OpenStackShell(app.App): # bigger than most big default one (CRITICAL) or something like # that (PROFILE = 60 for instance), but not sure we need it here. self.log.warning("Trace ID: %s" % trace_id) - self.log.warning("Short trace ID " - "for OpenTracing-based drivers: %s" % short_id) - self.log.warning("Display trace data with command:\n" - "osprofiler trace show --html %s " % trace_id) + self.log.warning( + "Short trace ID " + "for OpenTracing-based drivers: %s" % short_id + ) + self.log.warning( + "Display trace data with command:\n" + "osprofiler trace show --html %s " % trace_id + ) def run_subcommand(self, argv): self.init_profile() @@ -186,8 +193,8 @@ class OpenStackShell(app.App): def build_option_parser(self, description, version): parser = super(OpenStackShell, self).build_option_parser( - description, - version) + description, version + ) # service token auth argument parser.add_argument( @@ -243,11 +250,11 @@ class OpenStackShell(app.App): '--os-default-domain', metavar='', dest='default_domain', - default=utils.env( - 'OS_DEFAULT_DOMAIN', - default=DEFAULT_DOMAIN), - help=_('Default domain ID, default=%s. ' - '(Env: OS_DEFAULT_DOMAIN)') % DEFAULT_DOMAIN, + default=utils.env('OS_DEFAULT_DOMAIN', default=DEFAULT_DOMAIN), + help=_( + 'Default domain ID, default=%s. ' '(Env: OS_DEFAULT_DOMAIN)' + ) + % DEFAULT_DOMAIN, ) parser.add_argument( '--os-interface', @@ -258,18 +265,23 @@ class OpenStackShell(app.App): # config key 'interface' will be ignored. Use OSC_Config's ctor # option 'override_defaults' below instead. default=utils.env('OS_INTERFACE'), - help=_('Select an interface type.' - ' Valid interface types: [admin, public, internal].' - ' default=%s, (Env: OS_INTERFACE)') % DEFAULT_INTERFACE, + help=_( + 'Select an interface type.' + ' Valid interface types: [admin, public, internal].' + ' default=%s, (Env: OS_INTERFACE)' + ) + % DEFAULT_INTERFACE, ) parser.add_argument( '--os-service-provider', metavar='', dest='service_provider', default=utils.env('OS_SERVICE_PROVIDER'), - help=_('Authenticate with and perform the command on a service' - ' provider using Keystone-to-keystone federation. Must' - ' also specify the remote project option.') + help=_( + 'Authenticate with and perform the command on a service' + ' provider using Keystone-to-keystone federation. Must' + ' also specify the remote project option.' + ), ) remote_project_group = parser.add_mutually_exclusive_group() remote_project_group.add_argument( @@ -277,16 +289,20 @@ class OpenStackShell(app.App): metavar='', dest='remote_project_name', default=utils.env('OS_REMOTE_PROJECT_NAME'), - help=_('Project name when authenticating to a service provider' - ' if using Keystone-to-Keystone federation.') + help=_( + 'Project name when authenticating to a service provider' + ' if using Keystone-to-Keystone federation.' + ), ) remote_project_group.add_argument( '--os-remote-project-id', metavar='', dest='remote_project_id', default=utils.env('OS_REMOTE_PROJECT_ID'), - help=_('Project ID when authenticating to a service provider' - ' if using Keystone-to-Keystone federation.') + help=_( + 'Project ID when authenticating to a service provider' + ' if using Keystone-to-Keystone federation.' + ), ) remote_project_domain_group = parser.add_mutually_exclusive_group() remote_project_domain_group.add_argument( @@ -294,18 +310,22 @@ class OpenStackShell(app.App): metavar='', dest='remote_project_domain_name', default=utils.env('OS_REMOTE_PROJECT_DOMAIN_NAME'), - help=_('Domain name of the project when authenticating to a' - ' service provider if using Keystone-to-Keystone' - ' federation.') + help=_( + 'Domain name of the project when authenticating to a' + ' service provider if using Keystone-to-Keystone' + ' federation.' + ), ) remote_project_domain_group.add_argument( '--os-remote-project-domain-id', metavar='', dest='remote_project_domain_id', default=utils.env('OS_REMOTE_PROJECT_DOMAIN_ID'), - help=_('Domain ID of the project when authenticating to a' - ' service provider if using Keystone-to-Keystone' - ' federation.') + help=_( + 'Domain ID of the project when authenticating to a' + ' service provider if using Keystone-to-Keystone' + ' federation.' + ), ) parser.add_argument( '--timing', @@ -345,6 +365,7 @@ class OpenStackShell(app.App): * ClientManager """ + def _final_defaults(self): # Set the default plugin to None # NOTE(dtroyer): This is here to set up for setting it to a default @@ -396,10 +417,11 @@ class OpenStackShell(app.App): # Parent __init__ parses argv into self.options super(OpenStackShell, self).initialize_app(argv) - self.log.info("START with options: %s", - strutils.mask_password(" ".join(self.command_options))) - self.log.debug("options: %s", - strutils.mask_password(self.options)) + self.log.info( + "START with options: %s", + strutils.mask_password(" ".join(self.command_options)), + ) + self.log.debug("options: %s", strutils.mask_password(self.options)) # Callout for stuff between superclass init and o-c-c self._final_defaults() @@ -434,8 +456,9 @@ class OpenStackShell(app.App): self.log_configurator.configure(self.cloud) self.dump_stack_trace = self.log_configurator.dump_trace self.log.debug("defaults: %s", self.cloud_config.defaults) - self.log.debug("cloud cfg: %s", - strutils.mask_password(self.cloud.config)) + self.log.debug( + "cloud cfg: %s", strutils.mask_password(self.cloud.config) + ) # Callout for stuff between o-c-c and ClientManager # self._initialize_app_2(self.options) @@ -489,8 +512,9 @@ class OpenStackShell(app.App): # let the command decide whether we need a scoped token self.client_manager.validate_scope() # Trigger the Identity client to initialize - self.client_manager.session.auth.auth_ref = \ + self.client_manager.session.auth.auth_ref = ( self.client_manager.auth_ref + ) return def clean_up(self, cmd, result, err): @@ -518,8 +542,10 @@ class OpenStackShell(app.App): # If anything other than prettytable is specified, force csv format = 'table' # Check the formatter used in the actual command - if hasattr(cmd, 'formatter') \ - and cmd.formatter != cmd._formatter_plugins['table'].obj: + if ( + hasattr(cmd, 'formatter') + and cmd.formatter != cmd._formatter_plugins['table'].obj + ): format = 'csv' sys.stdout.write('\n') diff --git a/osc_lib/tests/api/fakes.py b/osc_lib/tests/api/fakes.py index 72be212..dcc4d1b 100644 --- a/osc_lib/tests/api/fakes.py +++ b/osc_lib/tests/api/fakes.py @@ -47,7 +47,6 @@ LIST_BODY = { class TestSession(utils.TestCase): - BASE_URL = 'https://api.example.com:1234/test' def setUp(self): diff --git a/osc_lib/tests/api/test_api.py b/osc_lib/tests/api/test_api.py index b574ebc..da1f5b0 100644 --- a/osc_lib/tests/api/test_api.py +++ b/osc_lib/tests/api/test_api.py @@ -22,7 +22,6 @@ from osc_lib.tests.api import fakes as api_fakes class TestBaseAPIDefault(api_fakes.TestSession): - def setUp(self): super(TestBaseAPIDefault, self).setUp() self.api = api.BaseAPI() @@ -89,7 +88,6 @@ class TestBaseAPIDefault(api_fakes.TestSession): class TestBaseAPIEndpointArg(api_fakes.TestSession): - def test_baseapi_endpoint_no_endpoint(self): x_api = api.BaseAPI( session=self.sess, @@ -187,7 +185,6 @@ class TestBaseAPIEndpointArg(api_fakes.TestSession): class TestBaseAPIArgs(api_fakes.TestSession): - def setUp(self): super(TestBaseAPIArgs, self).setUp() self.api = api.BaseAPI( @@ -222,7 +219,6 @@ class TestBaseAPIArgs(api_fakes.TestSession): class TestBaseAPICreate(api_fakes.TestSession): - def setUp(self): super(TestBaseAPICreate, self).setUp() self.api = api.BaseAPI( @@ -261,7 +257,6 @@ class TestBaseAPICreate(api_fakes.TestSession): class TestBaseAPIFind(api_fakes.TestSession): - def setUp(self): super(TestBaseAPIFind, self).setUp() self.api = api.BaseAPI( @@ -283,14 +278,9 @@ class TestBaseAPIFind(api_fakes.TestSession): self.BASE_URL + '/qaz/1', status_code=404, ) - self.assertRaises( - exceptions.NotFound, - self.api.find, - 'qaz', - '1') + self.assertRaises(exceptions.NotFound, self.api.find, 'qaz', '1') def test_baseapi_find_attr_by_id(self): - # All first requests (by name) will fail in this test self.requests_mock.register_uri( 'GET', @@ -382,7 +372,6 @@ class TestBaseAPIFind(api_fakes.TestSession): self.assertEqual(api_fakes.RESP_ITEM_1, ret) def test_baseapi_find_attr_path_resource(self): - # Test resource different than path self.requests_mock.register_uri( 'GET', @@ -462,7 +451,6 @@ class TestBaseAPIFind(api_fakes.TestSession): class TestBaseAPIList(api_fakes.TestSession): - def setUp(self): super(TestBaseAPIList, self).setUp() self.api = api.BaseAPI( diff --git a/osc_lib/tests/api/test_utils.py b/osc_lib/tests/api/test_utils.py index 8b6d587..b54af7d 100644 --- a/osc_lib/tests/api/test_utils.py +++ b/osc_lib/tests/api/test_utils.py @@ -37,8 +37,7 @@ class TestBaseAPIFilter(api_fakes.TestSession): ] def test_simple_filter_none(self): - output = api_utils.simple_filter( - ) + output = api_utils.simple_filter() self.assertIsNone(output) def test_simple_filter_no_attr(self): diff --git a/osc_lib/tests/cli/test_client_config.py b/osc_lib/tests/cli/test_client_config.py index 1beb959..a59a797 100644 --- a/osc_lib/tests/cli/test_client_config.py +++ b/osc_lib/tests/cli/test_client_config.py @@ -16,7 +16,6 @@ from osc_lib.tests import utils class TestOSCConfig(utils.TestCase): - def setUp(self): super(TestOSCConfig, self).setUp() @@ -209,7 +208,7 @@ class TestOSCConfig(utils.TestCase): 'username': 'fred', 'project_id': 'id', 'project_domain_id': 'proj', - 'user_domain_id': 'use' + 'user_domain_id': 'use', }, } ret_config = self.cloud._auth_default_domain(config) diff --git a/osc_lib/tests/cli/test_format_columns.py b/osc_lib/tests/cli/test_format_columns.py index 267b1bc..3541c49 100644 --- a/osc_lib/tests/cli/test_format_columns.py +++ b/osc_lib/tests/cli/test_format_columns.py @@ -20,7 +20,6 @@ from osc_lib.tests import utils class TestDictColumn(utils.TestCase): - def test_dict_column(self): data = { 'key1': 'value1', @@ -42,7 +41,6 @@ class TestDictColumn(utils.TestCase): class TestDictListColumn(utils.TestCase): - def test_dict_list_column(self): data = { 'public': ['2001:db8::8', '172.24.4.6'], @@ -67,7 +65,6 @@ class TestDictListColumn(utils.TestCase): class TestListColumn(utils.TestCase): - def test_list_column(self): data = [ 'key1', @@ -87,7 +84,6 @@ class TestListColumn(utils.TestCase): class TestListDictColumn(utils.TestCase): - def test_list_dict_column(self): data = [ {'key1': 'value1'}, @@ -112,7 +108,6 @@ class TestListDictColumn(utils.TestCase): class TestSizeColumn(utils.TestCase): - def test_size_column(self): content = 1576395005 col = format_columns.SizeColumn(content) diff --git a/osc_lib/tests/cli/test_identity.py b/osc_lib/tests/cli/test_identity.py index fa5e802..77b140d 100644 --- a/osc_lib/tests/cli/test_identity.py +++ b/osc_lib/tests/cli/test_identity.py @@ -22,12 +22,12 @@ from osc_lib.tests import utils as test_utils class IdentityUtilsTestCase(test_utils.TestCase): - def test_add_project_owner_option_to_parser(self): parser = argparse.ArgumentParser() cli_identity.add_project_owner_option_to_parser(parser) - parsed_args = parser.parse_args(['--project', 'project1', - '--project-domain', 'domain1']) + parsed_args = parser.parse_args( + ['--project', 'project1', '--project-domain', 'domain1'] + ) self.assertEqual('project1', parsed_args.project) self.assertEqual('domain1', parsed_args.project_domain) @@ -39,7 +39,8 @@ class IdentityUtilsTestCase(test_utils.TestCase): ret = cli_identity.find_project(sdk_connection, 'project1') self.assertEqual(mock.sentinel.project1, ret) sdk_find_project.assert_called_once_with( - 'project1', ignore_missing=False, domain_id=None) + 'project1', ignore_missing=False, domain_id=None + ) def test_find_project_with_domain(self): domain1 = mock.Mock() @@ -54,9 +55,11 @@ class IdentityUtilsTestCase(test_utils.TestCase): ret = cli_identity.find_project(sdk_connection, 'project1', 'domain1') self.assertEqual(mock.sentinel.project1, ret) sdk_find_domain.assert_called_once_with( - 'domain1', ignore_missing=False) + 'domain1', ignore_missing=False + ) sdk_find_project.assert_called_once_with( - 'project1', ignore_missing=False, domain_id='id-domain1') + 'project1', ignore_missing=False, domain_id='id-domain1' + ) def test_find_project_with_forbidden_exception(self): sdk_connection = mock.Mock() diff --git a/osc_lib/tests/cli/test_parseractions.py b/osc_lib/tests/cli/test_parseractions.py index 7e4dc2a..5f8ceaa 100644 --- a/osc_lib/tests/cli/test_parseractions.py +++ b/osc_lib/tests/cli/test_parseractions.py @@ -20,7 +20,6 @@ from osc_lib.tests import utils class TestKeyValueAction(utils.TestCase): - def setUp(self): super(TestKeyValueAction, self).setUp() @@ -33,15 +32,20 @@ class TestKeyValueAction(utils.TestCase): action=parseractions.KeyValueAction, default={'green': '20%', 'format': '#rgb'}, help='Property to store for this volume ' - '(repeat option to set multiple properties)', + '(repeat option to set multiple properties)', ) def test_good_values(self): - results = self.parser.parse_args([ - '--property', 'red=', - '--property', 'green=100%', - '--property', 'blue=50%', - ]) + results = self.parser.parse_args( + [ + '--property', + 'red=', + '--property', + 'green=100%', + '--property', + 'blue=50%', + ] + ) actual = getattr(results, 'property', {}) # All should pass through unmolested @@ -50,17 +54,26 @@ class TestKeyValueAction(utils.TestCase): def test_error_values(self): data_list = [ - ['--property', 'red', ], - ['--property', '=', ], - ['--property', '=red', ] + [ + '--property', + 'red', + ], + [ + '--property', + '=', + ], + [ + '--property', + '=red', + ], ] for data in data_list: - self.assertRaises(argparse.ArgumentTypeError, - self.parser.parse_args, data) + self.assertRaises( + argparse.ArgumentTypeError, self.parser.parse_args, data + ) class TestKeyValueAppendAction(utils.TestCase): - def setUp(self): super(TestKeyValueAppendAction, self).setUp() @@ -72,16 +85,21 @@ class TestKeyValueAppendAction(utils.TestCase): metavar='', action=parseractions.KeyValueAppendAction, help='Arbitrary key/value pairs to be sent to the scheduler for ' - 'custom use', + 'custom use', ) def test_good_values(self): print(self.parser._get_optional_actions()) - results = self.parser.parse_args([ - '--hint', 'same_host=a0cf03a5-d921-4877-bb5c-86d26cf818e1', - '--hint', 'same_host=8c19174f-4220-44f0-824a-cd1eeef10287', - '--hint', 'query=[>=,$free_ram_mb,1024]', - ]) + results = self.parser.parse_args( + [ + '--hint', + 'same_host=a0cf03a5-d921-4877-bb5c-86d26cf818e1', + '--hint', + 'same_host=8c19174f-4220-44f0-824a-cd1eeef10287', + '--hint', + 'query=[>=,$free_ram_mb,1024]', + ] + ) actual = getattr(results, 'hint', {}) expect = { @@ -97,17 +115,26 @@ class TestKeyValueAppendAction(utils.TestCase): def test_error_values(self): data_list = [ - ['--hint', 'red', ], - ['--hint', '=', ], - ['--hint', '=red', ] + [ + '--hint', + 'red', + ], + [ + '--hint', + '=', + ], + [ + '--hint', + '=red', + ], ] for data in data_list: - self.assertRaises(argparse.ArgumentTypeError, - self.parser.parse_args, data) + self.assertRaises( + argparse.ArgumentTypeError, self.parser.parse_args, data + ) class TestMultiKeyValueAction(utils.TestCase): - def setUp(self): super(TestMultiKeyValueAction, self).setUp() @@ -122,14 +149,18 @@ class TestMultiKeyValueAction(utils.TestCase): default=None, required_keys=['req1', 'req2'], optional_keys=['opt1', 'opt2'], - help='Test' + help='Test', ) def test_good_values(self): - results = self.parser.parse_args([ - '--test', 'req1=aaa,req2=bbb', - '--test', 'req1=,req2=', - ]) + results = self.parser.parse_args( + [ + '--test', + 'req1=aaa,req2=bbb', + '--test', + 'req1=,req2=', + ] + ) actual = getattr(results, 'test', []) expect = [ @@ -147,13 +178,17 @@ class TestMultiKeyValueAction(utils.TestCase): default=None, required_keys=[], optional_keys=[], - help='Test' + help='Test', ) - results = self.parser.parse_args([ - '--test-empty', 'req1=aaa,req2=bbb', - '--test-empty', 'req1=,req2=', - ]) + results = self.parser.parse_args( + [ + '--test-empty', + 'req1=aaa,req2=bbb', + '--test-empty', + 'req1=,req2=', + ] + ) actual = getattr(results, 'test_empty', []) expect = [ @@ -164,21 +199,32 @@ class TestMultiKeyValueAction(utils.TestCase): def test_error_values_with_comma(self): data_list = [ - ['--test', 'mmm,nnn=zzz', ], - ['--test', 'nnn=zzz,=', ], - ['--test', 'nnn=zzz,=zzz', ] + [ + '--test', + 'mmm,nnn=zzz', + ], + [ + '--test', + 'nnn=zzz,=', + ], + [ + '--test', + 'nnn=zzz,=zzz', + ], ] for data in data_list: - self.assertRaises(argparse.ArgumentTypeError, - self.parser.parse_args, data) + self.assertRaises( + argparse.ArgumentTypeError, self.parser.parse_args, data + ) def test_error_values_without_comma(self): self.assertRaises( argparse.ArgumentTypeError, self.parser.parse_args, [ - '--test', 'mmmnnn', - ] + '--test', + 'mmmnnn', + ], ) def test_missing_key(self): @@ -186,8 +232,9 @@ class TestMultiKeyValueAction(utils.TestCase): argparse.ArgumentTypeError, self.parser.parse_args, [ - '--test', 'req2=ddd', - ] + '--test', + 'req2=ddd', + ], ) def test_invalid_key(self): @@ -195,8 +242,9 @@ class TestMultiKeyValueAction(utils.TestCase): argparse.ArgumentTypeError, self.parser.parse_args, [ - '--test', 'req1=aaa,req2=bbb,aaa=req1', - ] + '--test', + 'req1=aaa,req2=bbb,aaa=req1', + ], ) def test_required_keys_not_list(self): @@ -210,7 +258,7 @@ class TestMultiKeyValueAction(utils.TestCase): default=None, required_keys={'aaa': 'bbb'}, optional_keys=['opt1', 'opt2'], - help='Test' + help='Test', ) def test_optional_keys_not_list(self): @@ -224,12 +272,11 @@ class TestMultiKeyValueAction(utils.TestCase): default=None, required_keys=['req1', 'req2'], optional_keys={'aaa': 'bbb'}, - help='Test' + help='Test', ) class TestMultiKeyValueCommaAction(utils.TestCase): - def setUp(self): super(TestMultiKeyValueCommaAction, self).setUp() self.parser = argparse.ArgumentParser() @@ -247,28 +294,38 @@ class TestMultiKeyValueCommaAction(utils.TestCase): ) def test_mkvca_required(self): - results = self.parser.parse_args([ - '--test', 'req1=aaa,bbb', - ]) + results = self.parser.parse_args( + [ + '--test', + 'req1=aaa,bbb', + ] + ) actual = getattr(results, 'test', []) expect = [ {'req1': 'aaa,bbb'}, ] self.assertCountEqual(expect, actual) - results = self.parser.parse_args([ - '--test', 'req1=', - ]) + results = self.parser.parse_args( + [ + '--test', + 'req1=', + ] + ) actual = getattr(results, 'test', []) expect = [ {'req1': ''}, ] self.assertCountEqual(expect, actual) - results = self.parser.parse_args([ - '--test', 'req1=aaa,bbb', - '--test', 'req1=', - ]) + results = self.parser.parse_args( + [ + '--test', + 'req1=aaa,bbb', + '--test', + 'req1=', + ] + ) actual = getattr(results, 'test', []) expect = [ {'req1': 'aaa,bbb'}, @@ -277,19 +334,26 @@ class TestMultiKeyValueCommaAction(utils.TestCase): self.assertCountEqual(expect, actual) def test_mkvca_optional(self): - results = self.parser.parse_args([ - '--test', 'req1=aaa,bbb', - ]) + results = self.parser.parse_args( + [ + '--test', + 'req1=aaa,bbb', + ] + ) actual = getattr(results, 'test', []) expect = [ {'req1': 'aaa,bbb'}, ] self.assertCountEqual(expect, actual) - results = self.parser.parse_args([ - '--test', 'req1=aaa,bbb', - '--test', 'req1=,opt2=ccc', - ]) + results = self.parser.parse_args( + [ + '--test', + 'req1=aaa,bbb', + '--test', + 'req1=,opt2=ccc', + ] + ) actual = getattr(results, 'test', []) expect = [ {'req1': 'aaa,bbb'}, @@ -298,10 +362,14 @@ class TestMultiKeyValueCommaAction(utils.TestCase): self.assertCountEqual(expect, actual) try: - results = self.parser.parse_args([ - '--test', 'req1=aaa,bbb', - '--test', 'opt2=ccc', - ]) + results = self.parser.parse_args( + [ + '--test', + 'req1=aaa,bbb', + '--test', + 'opt2=ccc', + ] + ) self.fail('ArgumentTypeError should be raised') except argparse.ArgumentTypeError as e: self.assertEqual( @@ -310,14 +378,19 @@ class TestMultiKeyValueCommaAction(utils.TestCase): ) def test_mkvca_multiples(self): - results = self.parser.parse_args([ - '--test', 'req1=aaa,bbb,opt2=ccc', - ]) + results = self.parser.parse_args( + [ + '--test', + 'req1=aaa,bbb,opt2=ccc', + ] + ) actual = getattr(results, 'test', []) - expect = [{ - 'req1': 'aaa,bbb', - 'opt2': 'ccc', - }] + expect = [ + { + 'req1': 'aaa,bbb', + 'opt2': 'ccc', + } + ] self.assertCountEqual(expect, actual) def test_mkvca_no_required_optional(self): @@ -332,18 +405,24 @@ class TestMultiKeyValueCommaAction(utils.TestCase): help='Test', ) - results = self.parser.parse_args([ - '--test-empty', 'req1=aaa,bbb', - ]) + results = self.parser.parse_args( + [ + '--test-empty', + 'req1=aaa,bbb', + ] + ) actual = getattr(results, 'test_empty', []) expect = [ {'req1': 'aaa,bbb'}, ] self.assertCountEqual(expect, actual) - results = self.parser.parse_args([ - '--test-empty', 'xyz=aaa,bbb', - ]) + results = self.parser.parse_args( + [ + '--test-empty', + 'xyz=aaa,bbb', + ] + ) actual = getattr(results, 'test_empty', []) expect = [ @@ -353,9 +432,12 @@ class TestMultiKeyValueCommaAction(utils.TestCase): def test_mkvca_invalid_key(self): try: - self.parser.parse_args([ - '--test', 'req1=aaa,bbb=', - ]) + self.parser.parse_args( + [ + '--test', + 'req1=aaa,bbb=', + ] + ) self.fail('ArgumentTypeError should be raised') except argparse.ArgumentTypeError as e: self.assertIn( @@ -364,9 +446,12 @@ class TestMultiKeyValueCommaAction(utils.TestCase): ) try: - self.parser.parse_args([ - '--test', 'nnn=aaa', - ]) + self.parser.parse_args( + [ + '--test', + 'nnn=aaa', + ] + ) self.fail('ArgumentTypeError should be raised') except argparse.ArgumentTypeError as e: self.assertIn( @@ -376,9 +461,12 @@ class TestMultiKeyValueCommaAction(utils.TestCase): def test_mkvca_value_no_key(self): try: - self.parser.parse_args([ - '--test', 'req1=aaa,=bbb', - ]) + self.parser.parse_args( + [ + '--test', + 'req1=aaa,=bbb', + ] + ) self.fail('ArgumentTypeError should be raised') except argparse.ArgumentTypeError as e: self.assertEqual( @@ -386,9 +474,12 @@ class TestMultiKeyValueCommaAction(utils.TestCase): str(e), ) try: - self.parser.parse_args([ - '--test', '=nnn', - ]) + self.parser.parse_args( + [ + '--test', + '=nnn', + ] + ) self.fail('ArgumentTypeError should be raised') except argparse.ArgumentTypeError as e: self.assertEqual( @@ -397,9 +488,12 @@ class TestMultiKeyValueCommaAction(utils.TestCase): ) try: - self.parser.parse_args([ - '--test', 'nnn', - ]) + self.parser.parse_args( + [ + '--test', + 'nnn', + ] + ) self.fail('ArgumentTypeError should be raised') except argparse.ArgumentTypeError as e: self.assertIn( @@ -437,7 +531,6 @@ class TestMultiKeyValueCommaAction(utils.TestCase): class TestNonNegativeAction(utils.TestCase): - def setUp(self): super(TestNonNegativeAction, self).setUp() @@ -455,21 +548,17 @@ class TestNonNegativeAction(utils.TestCase): self.assertRaises( argparse.ArgumentTypeError, self.parser.parse_args, - "--foo -1".split() + "--foo -1".split(), ) def test_zero_values(self): - results = self.parser.parse_args( - '--foo 0'.split() - ) + results = self.parser.parse_args('--foo 0'.split()) actual = getattr(results, 'foo', None) self.assertEqual(actual, 0) def test_positive_values(self): - results = self.parser.parse_args( - '--foo 1'.split() - ) + results = self.parser.parse_args('--foo 1'.split()) actual = getattr(results, 'foo', None) self.assertEqual(actual, 1) diff --git a/osc_lib/tests/command/test_command.py b/osc_lib/tests/command/test_command.py index 59d9efd..533ec07 100644 --- a/osc_lib/tests/command/test_command.py +++ b/osc_lib/tests/command/test_command.py @@ -21,13 +21,11 @@ from osc_lib.tests import utils as test_utils class FakeCommand(command.Command): - def take_action(self, parsed_args): pass class TestCommand(test_utils.TestCase): - def test_command_has_logger(self): cmd = FakeCommand(mock.Mock(), mock.Mock()) self.assertTrue(hasattr(cmd, 'log')) diff --git a/osc_lib/tests/command/test_timing.py b/osc_lib/tests/command/test_timing.py index c140f01..be35936 100644 --- a/osc_lib/tests/command/test_timing.py +++ b/osc_lib/tests/command/test_timing.py @@ -28,14 +28,12 @@ timing_elapsed = 0.872809 class FakeGenericClient(object): - def __init__(self, **kwargs): self.auth_token = kwargs['token'] self.management_url = kwargs['endpoint'] class TestTiming(utils.TestCommand): - columns = ( 'URL', 'Seconds', @@ -71,16 +69,23 @@ class TestTiming(utils.TestCommand): self.assertEqual(self.columns, columns) datalist = [ - ('Total', 0.0,) + ( + 'Total', + 0.0, + ) ] self.assertEqual(datalist, data) def test_timing_list(self): - self.app.timing_data = [session.RequestTiming( - method=timing_method, - url=timing_url, - elapsed=datetime.timedelta(microseconds=timing_elapsed * 1000000), - )] + self.app.timing_data = [ + session.RequestTiming( + method=timing_method, + url=timing_url, + elapsed=datetime.timedelta( + microseconds=timing_elapsed * 1000000 + ), + ) + ] arglist = [] verifylist = [] diff --git a/osc_lib/tests/fakes.py b/osc_lib/tests/fakes.py index ebd529c..ae5616b 100644 --- a/osc_lib/tests/fakes.py +++ b/osc_lib/tests/fakes.py @@ -32,8 +32,7 @@ VERSION = "3" SERVICE_PROVIDER_ID = "bob" -TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN, - user_name=USERNAME) +TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN, user_name=USERNAME) _s = TEST_RESPONSE_DICT.add_service('identity', name='keystone') _s.add_endpoint(AUTH_URL + ':5000/v2.0') _s = TEST_RESPONSE_DICT.add_service('network', name='neutron') @@ -54,8 +53,10 @@ TEST_VERSIONS = fixture.DiscoveryList(href=AUTH_URL) def to_unicode_dict(catalog_dict): """Converts dict to unicode dict""" if isinstance(catalog_dict, dict): - return {to_unicode_dict(key): to_unicode_dict(value) - for key, value in catalog_dict.items()} + return { + to_unicode_dict(key): to_unicode_dict(value) + for key, value in catalog_dict.items() + } elif isinstance(catalog_dict, list): return [to_unicode_dict(element) for element in catalog_dict] elif isinstance(catalog_dict, str): @@ -65,7 +66,6 @@ def to_unicode_dict(catalog_dict): class FakeStdout(object): - def __init__(self): self.content = [] @@ -80,7 +80,6 @@ class FakeStdout(object): class FakeLog(object): - def __init__(self): self.messages = {} @@ -101,7 +100,6 @@ class FakeLog(object): class FakeApp(object): - def __init__(self, _stdout, _log): self.stdout = _stdout self.client_manager = None @@ -118,7 +116,6 @@ class FakeOptions(object): class FakeClientManager(object): - def __init__(self): self.compute = None self.identity = None @@ -143,7 +140,6 @@ class FakeClientManager(object): class FakeModule(object): - def __init__(self, name, version): self.name = name self.__version__ = version @@ -153,7 +149,6 @@ class FakeModule(object): class FakeResource(object): - def __init__(self, manager=None, info=None, loaded=False, methods=None): """Set attributes and methods for a resource. @@ -177,7 +172,7 @@ class FakeResource(object): self._loaded = loaded def _add_details(self, info): - for (k, v) in info.items(): + for k, v in info.items(): setattr(self, k, v) def _add_methods(self, methods): @@ -188,13 +183,14 @@ class FakeResource(object): @value. When users access the attribute with (), @value will be returned, which looks like a function call. """ - for (name, ret) in methods.items(): + for name, ret in methods.items(): method = mock.MagicMock(return_value=ret) setattr(self, name, method) def __repr__(self): - reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and - k != 'manager') + reprkeys = sorted( + k for k in self.__dict__.keys() if k[0] != '_' and k != 'manager' + ) info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) return "<%s %s>" % (self.__class__.__name__, info) diff --git a/osc_lib/tests/test_clientmanager.py b/osc_lib/tests/test_clientmanager.py index a97bb48..98ff264 100644 --- a/osc_lib/tests/test_clientmanager.py +++ b/osc_lib/tests/test_clientmanager.py @@ -41,7 +41,7 @@ AUTH_DICT = { 'auth_url': fakes.AUTH_URL, 'username': fakes.USERNAME, 'password': fakes.PASSWORD, - 'project_name': fakes.PROJECT_NAME + 'project_name': fakes.PROJECT_NAME, } @@ -58,7 +58,6 @@ class Container(object): class TestClientCache(utils.TestCase): - def test_singleton(self): # NOTE(dtroyer): Verify that the ClientCache descriptor only invokes # the factory one time and always returns the same value after that. @@ -67,14 +66,14 @@ class TestClientCache(utils.TestCase): def test_attribute_error_propagates(self): c = Container() - err = self.assertRaises(exc.PluginAttributeError, - getattr, c, 'buggy_attr') + err = self.assertRaises( + exc.PluginAttributeError, getattr, c, 'buggy_attr' + ) self.assertNotIsInstance(err, AttributeError) self.assertEqual("'Container' object has no attribute 'foo'", str(err)) class TestClientManager(utils.TestClientManager): - def test_client_manager_none(self): none_auth = { 'endpoint': fakes.AUTH_URL, @@ -268,10 +267,12 @@ class TestClientManager(utils.TestClientManager): ) auth_args = copy.deepcopy(self.default_password_auth) - auth_args.update({ - 'user_domain_name': 'default', - 'project_domain_name': 'default', - }) + auth_args.update( + { + 'user_domain_name': 'default', + 'project_domain_name': 'default', + } + ) self._make_clientmanager( auth_args=auth_args, identity_api_version='3', @@ -292,10 +293,12 @@ class TestClientManager(utils.TestClientManager): # Use v3 auth args auth_args = copy.deepcopy(self.default_password_auth) - auth_args.update({ - 'user_domain_name': 'default', - 'project_domain_name': 'default', - }) + auth_args.update( + { + 'user_domain_name': 'default', + 'project_domain_name': 'default', + } + ) self._make_clientmanager( auth_args=auth_args, identity_api_version='3', @@ -303,9 +306,11 @@ class TestClientManager(utils.TestClientManager): auth_args = copy.deepcopy(self.default_password_auth) auth_args.pop('username') - auth_args.update({ - 'user_id': fakes.USER_ID, - }) + auth_args.update( + { + 'user_id': fakes.USER_ID, + } + ) self._make_clientmanager( auth_args=auth_args, identity_api_version='3', @@ -342,12 +347,14 @@ class TestClientManager(utils.TestClientManager): loader = loading.get_plugin_loader('password') auth_plugin = loader.load_from_options(**AUTH_DICT) cli_options = defaults.get_defaults() - cli_options.update({ - 'auth_type': 'password', - 'auth': AUTH_DICT, - 'interface': fakes.INTERFACE, - 'region_name': fakes.REGION_NAME, - }) + cli_options.update( + { + 'auth_type': 'password', + 'auth': AUTH_DICT, + 'interface': fakes.INTERFACE, + 'region_name': fakes.REGION_NAME, + } + ) client_manager = self._clientmanager_class()( cli_options=cloud_config.CloudConfig( name='t1', @@ -372,10 +379,12 @@ class TestClientManager(utils.TestClientManager): def test_client_manager_endpoint_disabled(self): auth_args = copy.deepcopy(self.default_password_auth) - auth_args.update({ - 'user_domain_name': 'default', - 'project_domain_name': 'default', - }) + auth_args.update( + { + 'user_domain_name': 'default', + 'project_domain_name': 'default', + } + ) # v3 fake doesn't have network endpoint client_manager = self._make_clientmanager( auth_args=auth_args, @@ -389,14 +398,16 @@ class TestClientManager(utils.TestClientManager): loader = loading.get_plugin_loader('password') auth_plugin = loader.load_from_options(**AUTH_DICT) cli_options = defaults.get_defaults() - cli_options.update({ - 'auth_type': 'password', - 'auth': AUTH_DICT, - 'interface': fakes.INTERFACE, - 'region_name': fakes.REGION_NAME, - 'service_provider': fakes.SERVICE_PROVIDER_ID, - 'remote_project_id': fakes.PROJECT_ID - }) + cli_options.update( + { + 'auth_type': 'password', + 'auth': AUTH_DICT, + 'interface': fakes.INTERFACE, + 'region_name': fakes.REGION_NAME, + 'service_provider': fakes.SERVICE_PROVIDER_ID, + 'remote_project_id': fakes.PROJECT_ID, + } + ) client_manager = self._clientmanager_class()( cli_options=cloud_config.CloudConfig( name='t1', @@ -425,27 +436,31 @@ class TestClientManager(utils.TestClientManager): auth_plugin_name='none', ) self.assertIsNone( - client_manager.get_endpoint_for_service_type('compute')) + client_manager.get_endpoint_for_service_type('compute') + ) def test_client_manager_endpoint_override(self): # test token auth client_manager = self._make_clientmanager( auth_args={}, - config_args={'compute_endpoint_override': 'http://example.com', - 'foo_bar_endpoint_override': 'http://example2.com'}, + config_args={ + 'compute_endpoint_override': 'http://example.com', + 'foo_bar_endpoint_override': 'http://example2.com', + }, auth_plugin_name='none', ) self.assertEqual( 'http://example.com', - client_manager.get_endpoint_for_service_type('compute')) + client_manager.get_endpoint_for_service_type('compute'), + ) self.assertEqual( 'http://example2.com', - client_manager.get_endpoint_for_service_type('foo-bar')) + client_manager.get_endpoint_for_service_type('foo-bar'), + ) self.assertTrue(client_manager.is_service_available('compute')) class TestClientManagerSDK(utils.TestClientManager): - def test_client_manager_connection(self): client_manager = self._make_clientmanager( auth_required=True, diff --git a/osc_lib/tests/test_logs.py b/osc_lib/tests/test_logs.py index 3c19569..5a5c2af 100644 --- a/osc_lib/tests/test_logs.py +++ b/osc_lib/tests/test_logs.py @@ -19,7 +19,6 @@ from osc_lib.tests import utils class TestContext(utils.TestCase): - def test_log_level_from_options(self): opts = mock.Mock() opts.verbose_level = 0 @@ -66,35 +65,47 @@ class TestContext(utils.TestCase): class TestFileFormatter(utils.TestCase): - def test_nothing(self): formatter = logs._FileFormatter() - self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s %(message)s'), formatter.fmt) + self.assertEqual( + ( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' + '%(name)s %(message)s' + ), + formatter.fmt, + ) def test_options(self): class Opts(object): cloud = 'cloudy' os_project_name = 'projecty' username = 'usernamey' + options = Opts() formatter = logs._FileFormatter(options=options) - self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s [cloudy usernamey projecty] %(message)s'), - formatter.fmt) + self.assertEqual( + ( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' + '%(name)s [cloudy usernamey projecty] %(message)s' + ), + formatter.fmt, + ) def test_config(self): config = mock.Mock() config.config = {'cloud': 'cloudy'} config.auth = {'project_name': 'projecty', 'username': 'usernamey'} formatter = logs._FileFormatter(config=config) - self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s [cloudy usernamey projecty] %(message)s'), - formatter.fmt) + self.assertEqual( + ( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' + '%(name)s [cloudy usernamey projecty] %(message)s' + ), + formatter.fmt, + ) class TestLogConfigurator(utils.TestCase): - def setUp(self): super(TestLogConfigurator, self).setUp() self.options = mock.Mock() @@ -117,7 +128,8 @@ class TestLogConfigurator(utils.TestCase): self.requests_log, self.cliff_log, self.stevedore_log, - self.iso8601_log] + self.iso8601_log, + ] @mock.patch('logging.StreamHandler') @mock.patch('logging.getLogger') @@ -186,7 +198,8 @@ class TestLogConfigurator(utils.TestCase): cloud_config.config = { 'log_file': config_log, 'verbose_level': 1, - 'log_level': 'info'} + 'log_level': 'info', + } file_logger = mock.Mock() file_logger.setFormatter = mock.Mock() file_logger.setLevel = mock.Mock() diff --git a/osc_lib/tests/test_shell.py b/osc_lib/tests/test_shell.py index a75c8fa..0442cd6 100644 --- a/osc_lib/tests/test_shell.py +++ b/osc_lib/tests/test_shell.py @@ -113,7 +113,7 @@ global_options = { '--os-default-domain': (DEFAULT_DOMAIN_NAME, True, True), '--os-cacert': ('/dev/null', True, True), '--timing': (True, True, False), - '--os-interface': (DEFAULT_INTERFACE, True, True) + '--os-interface': (DEFAULT_INTERFACE, True, True), } if shell.osprofiler_profiler: global_options['--os-profile'] = ('SECRET_KEY', True, True) @@ -138,8 +138,8 @@ class TestShellArgV(utils.TestShell): """ with mock.patch( - "osc_lib.shell.OpenStackShell.run", - self.app, + "osc_lib.shell.OpenStackShell.run", + self.app, ): # Ensure type gets through unmolested through shell.main() argv = sys.argv @@ -220,8 +220,8 @@ class TestShellCli(utils.TestShell): def test_shell_args_no_options(self): _shell = utils.make_shell() with mock.patch( - "osc_lib.shell.OpenStackShell.initialize_app", - self.app, + "osc_lib.shell.OpenStackShell.initialize_app", + self.app, ): utils.fake_execute(_shell, "list user") self.app.assert_called_with(["list", "user"]) @@ -306,8 +306,7 @@ class TestShellCli(utils.TestShell): # --os-cert and --os-key utils.fake_execute( - _shell, - "--os-cert mycert --os-key mickey module list" + _shell, "--os-cert mycert --os-key mickey module list" ) self.assertEqual('mycert', _shell.options.cert) self.assertEqual('mickey', _shell.options.key) diff --git a/osc_lib/tests/utils/__init__.py b/osc_lib/tests/utils/__init__.py index ef1ea8d..2664e07 100644 --- a/osc_lib/tests/utils/__init__.py +++ b/osc_lib/tests/utils/__init__.py @@ -86,17 +86,20 @@ class ParserException(Exception): class TestCase(testtools.TestCase): - def setUp(self): testtools.TestCase.setUp(self) - if (os.environ.get("OS_STDOUT_CAPTURE") == "True" or - os.environ.get("OS_STDOUT_CAPTURE") == "1"): + if ( + os.environ.get("OS_STDOUT_CAPTURE") == "True" + or os.environ.get("OS_STDOUT_CAPTURE") == "1" + ): stdout = self.useFixture(fixtures.StringStream("stdout")).stream self.useFixture(fixtures.MonkeyPatch("sys.stdout", stdout)) - if (os.environ.get("OS_STDERR_CAPTURE") == "True" or - os.environ.get("OS_STDERR_CAPTURE") == "1"): + if ( + os.environ.get("OS_STDERR_CAPTURE") == "True" + or os.environ.get("OS_STDERR_CAPTURE") == "1" + ): stderr = self.useFixture(fixtures.StringStream("stderr")).stream self.useFixture(fixtures.MonkeyPatch("sys.stderr", stderr)) @@ -162,10 +165,13 @@ class TestCommand(TestCase): for col_expected, col_actual in zip(expected, actual): if isinstance(col_expected, cliff_columns.FormattableColumn): self.assertIsInstance(col_actual, col_expected.__class__) - self.assertEqual(col_expected.human_readable(), - col_actual.human_readable()) - self.assertEqual(col_expected.machine_readable(), - col_actual.machine_readable()) + self.assertEqual( + col_expected.human_readable(), col_actual.human_readable() + ) + self.assertEqual( + col_expected.machine_readable(), + col_actual.machine_readable(), + ) else: self.assertEqual(col_expected, col_actual) @@ -201,18 +207,24 @@ class TestClientManager(TestCase): # fake v2password token retrieval self.stub_auth(json=fakes.TEST_RESPONSE_DICT) # fake token and token_endpoint retrieval - self.stub_auth(json=fakes.TEST_RESPONSE_DICT, - url='/'.join([fakes.AUTH_URL, 'v2.0/tokens'])) + self.stub_auth( + json=fakes.TEST_RESPONSE_DICT, + url='/'.join([fakes.AUTH_URL, 'v2.0/tokens']), + ) # fake v3password token retrieval - self.stub_auth(json=fakes.TEST_RESPONSE_DICT_V3, - url='/'.join([fakes.AUTH_URL, 'v3/auth/tokens'])) + self.stub_auth( + json=fakes.TEST_RESPONSE_DICT_V3, + url='/'.join([fakes.AUTH_URL, 'v3/auth/tokens']), + ) # fake password token retrieval - self.stub_auth(json=fakes.TEST_RESPONSE_DICT_V3, - url='/'.join([fakes.AUTH_URL, 'auth/tokens'])) + self.stub_auth( + json=fakes.TEST_RESPONSE_DICT_V3, + url='/'.join([fakes.AUTH_URL, 'auth/tokens']), + ) # fake password version endpoint discovery - self.stub_auth(json=fakes.TEST_VERSIONS, - url=fakes.AUTH_URL, - verb='GET') + self.stub_auth( + json=fakes.TEST_VERSIONS, url=fakes.AUTH_URL, verb='GET' + ) # Mock the auth plugin self.auth_mock = mock.Mock() @@ -250,7 +262,6 @@ class TestClientManager(TestCase): auth_plugin_name=None, auth_required=None, ): - if identity_api_version is None: identity_api_version = '2.0' if auth_plugin_name is None: @@ -267,13 +278,15 @@ class TestClientManager(TestCase): auth_dict = auth_args cli_options = defaults.get_defaults() - cli_options.update({ - 'auth_type': auth_plugin_name, - 'auth': auth_dict, - 'interface': fakes.INTERFACE, - 'region_name': fakes.REGION_NAME, - # 'workflow_api_version': '2', - }) + cli_options.update( + { + 'auth_type': auth_plugin_name, + 'auth': auth_dict, + 'interface': fakes.INTERFACE, + 'region_name': fakes.REGION_NAME, + # 'workflow_api_version': '2', + } + ) if config_args is not None: cli_options.update(config_args) @@ -302,7 +315,6 @@ class TestClientManager(TestCase): class TestShell(TestCase): - # Full name of the OpenStackShell class to test (cliff.app.App subclass) shell_class_name = "osc_lib.shell.OpenStackShell" @@ -325,8 +337,8 @@ class TestShell(TestCase): """ with mock.patch( - self.shell_class_name + ".initialize_app", - self.app, + self.shell_class_name + ".initialize_app", + self.app, ): _shell = make_shell(shell_class=self.shell_class) _cmd = cmd_options + " module list" @@ -352,8 +364,8 @@ class TestShell(TestCase): cloud.config = {} self.occ_get_one = mock.Mock(return_value=cloud) with mock.patch( - "openstack.config.loader.OpenStackConfig.get_one", - self.occ_get_one, + "openstack.config.loader.OpenStackConfig.get_one", + self.occ_get_one, ): _shell = make_shell(shell_class=self.shell_class) _cmd = cmd_options + " module list" diff --git a/osc_lib/tests/utils/test_columns.py b/osc_lib/tests/utils/test_columns.py index 6bbf925..ee6de68 100644 --- a/osc_lib/tests/utils/test_columns.py +++ b/osc_lib/tests/utils/test_columns.py @@ -16,7 +16,6 @@ from osc_lib.utils import columns as column_utils class TestColumnUtils(test_utils.TestCase): - def test_get_column_definitions(self): attr_map = ( ('id', 'ID', column_utils.LIST_BOTH), @@ -25,7 +24,8 @@ class TestColumnUtils(test_utils.TestCase): ('summary', 'Summary', column_utils.LIST_SHORT_ONLY), ) headers, columns = column_utils.get_column_definitions( - attr_map, long_listing=False) + attr_map, long_listing=False + ) self.assertEqual(['id', 'name', 'summary'], columns) self.assertEqual(['ID', 'Name', 'Summary'], headers) @@ -37,7 +37,8 @@ class TestColumnUtils(test_utils.TestCase): ('summary', 'Summary', column_utils.LIST_SHORT_ONLY), ) headers, columns = column_utils.get_column_definitions( - attr_map, long_listing=True) + attr_map, long_listing=True + ) self.assertEqual(['id', 'tenant_id', 'name'], columns) self.assertEqual(['ID', 'Project', 'Name'], headers) diff --git a/osc_lib/tests/utils/test_tags.py b/osc_lib/tests/utils/test_tags.py index 7737c47..6f6769b 100644 --- a/osc_lib/tests/utils/test_tags.py +++ b/osc_lib/tests/utils/test_tags.py @@ -26,15 +26,22 @@ def help_enhancer(_h): class TestTags(test_utils.TestCase): - def test_add_tag_filtering_option_to_parser(self): parser = argparse.ArgumentParser() tags.add_tag_filtering_option_to_parser(parser, 'test') - parsed_args = parser.parse_args(['--tags', 'tag1,tag2', - '--any-tags', 'tag4', - '--not-tags', 'tag5', - '--not-any-tags', 'tag6']) + parsed_args = parser.parse_args( + [ + '--tags', + 'tag1,tag2', + '--any-tags', + 'tag4', + '--not-tags', + 'tag5', + '--not-any-tags', + 'tag6', + ] + ) actual = getattr(parsed_args, 'tags', []) expected = ['tag1', 'tag2'] @@ -56,12 +63,24 @@ class TestTags(test_utils.TestCase): parser = argparse.ArgumentParser() tags.add_tag_filtering_option_to_parser(parser, 'test') - parsed_args = parser.parse_args(['--tags', 'tag1,tag2', - '--any-tags', 'tag4', - '--not-tags', 'tag5', - '--not-any-tags', 'tag6']) - expected = {'tags': 'tag1,tag2', 'any_tags': 'tag4', - 'not_tags': 'tag5', 'not_any_tags': 'tag6'} + parsed_args = parser.parse_args( + [ + '--tags', + 'tag1,tag2', + '--any-tags', + 'tag4', + '--not-tags', + 'tag5', + '--not-any-tags', + 'tag6', + ] + ) + expected = { + 'tags': 'tag1,tag2', + 'any_tags': 'tag4', + 'not_tags': 'tag5', + 'not_any_tags': 'tag6', + } args = {} tags.get_tag_filtering_args(parsed_args, args) self.assertEqual(expected, args) @@ -71,8 +90,9 @@ class TestTags(test_utils.TestCase): tags.add_tag_option_to_parser_for_create(parser, 'test') # Test that --tag and --no-tag are mutually exclusive - self.assertRaises(SystemExit, parser.parse_args, - ['--tag', 'tag1', '--no-tag']) + self.assertRaises( + SystemExit, parser.parse_args, ['--tag', 'tag1', '--no-tag'] + ) parsed_args = parser.parse_args(['--tag', 'tag1']) actual = getattr(parsed_args, 'tags', []) @@ -103,8 +123,9 @@ class TestTags(test_utils.TestCase): tags.add_tag_option_to_parser_for_unset(parser, 'test') # Test that --tag and --all-tag are mutually exclusive - self.assertRaises(SystemExit, parser.parse_args, - ['--tag', 'tag1', '--all-tag']) + self.assertRaises( + SystemExit, parser.parse_args, ['--tag', 'tag1', '--all-tag'] + ) parsed_args = parser.parse_args(['--tag', 'tag1']) actual = getattr(parsed_args, 'tags', []) @@ -127,7 +148,8 @@ class TestTags(test_utils.TestCase): mock_obj.tags = None tags.update_tags_for_set(mock_client, mock_obj, mock_parsed_args) mock_client.set_tags.assert_called_once_with( - mock_obj, list(mock_parsed_args.tags)) + mock_obj, list(mock_parsed_args.tags) + ) # no-tag False path mock_client.set_tags.reset_mock() @@ -136,8 +158,7 @@ class TestTags(test_utils.TestCase): mock_obj.tags = ['tag2'] expected_list = ['tag1', 'tag2'] tags.update_tags_for_set(mock_client, mock_obj, mock_parsed_args) - mock_client.set_tags.assert_called_once_with( - mock_obj, expected_list) + mock_client.set_tags.assert_called_once_with(mock_obj, expected_list) # no new tags path mock_client.set_tags.reset_mock() @@ -164,8 +185,7 @@ class TestTags(test_utils.TestCase): mock_parsed_args.all_tag = True mock_parsed_args.tags = None tags.update_tags_for_unset(mock_client, mock_obj, mock_parsed_args) - mock_client.set_tags.assert_called_once_with( - mock_obj, []) + mock_client.set_tags.assert_called_once_with(mock_obj, []) # Remove one tag mock_client.set_tags.reset_mock() @@ -173,12 +193,10 @@ class TestTags(test_utils.TestCase): mock_parsed_args.all_tag = False mock_parsed_args.tags = ['tag2'] tags.update_tags_for_unset(mock_client, mock_obj, mock_parsed_args) - mock_client.set_tags.assert_called_once_with( - mock_obj, ['tag1']) + mock_client.set_tags.assert_called_once_with(mock_obj, ['tag1']) class TestTagHelps(test_utils.TestCase): - def _test_tag_method_help(self, meth, exp_normal, exp_enhanced): """Vet the help text of the options added by the tag filtering helpers. @@ -241,7 +259,8 @@ usage: run.py [-h] [--tags [,,...]] [--any-tags [,,...]] --not-any-tags [,,...] )sgat fo tsil detarapes-ammoC( )s(gat nevig yna evah hcihw tset edulcxE -""") +""", + ) def test_add_tag_option_to_parser_for_create(self): self._test_tag_method_help( @@ -263,7 +282,8 @@ usage: run.py [-h] [--tag | --no-tag] --tag )sgat elpitlum tes ot noitpo taeper( tset eht ot dedda eb ot gaT --no-tag tset eht htiw detaicossa sgat oN -""") +""", + ) def test_add_tag_option_to_parser_for_set(self): self._test_tag_method_help( @@ -287,7 +307,8 @@ usage: run.py [-h] [--tag ] [--no-tag] gaT --no-tag sgat tnerruc etirwrevo ot gat-on-- dna gat-- htob yficepS .tset eht htiw detaicossa sgat raelC -""") +""", + ) def test_add_tag_option_to_parser_for_unset(self): self._test_tag_method_help( @@ -309,4 +330,5 @@ usage: run.py [-h] [--tag | --all-tag] --tag )sgat elpitlum evomer ot noitpo taeper( tset eht morf devomer eb ot gaT --all-tag tset eht htiw detaicossa sgat lla raelC -""") +""", + ) diff --git a/osc_lib/tests/utils/test_utils.py b/osc_lib/tests/utils/test_utils.py index 82b8b46..01b6f02 100644 --- a/osc_lib/tests/utils/test_utils.py +++ b/osc_lib/tests/utils/test_utils.py @@ -31,7 +31,6 @@ DROWSSAP = "dr0w$$aP" class FakeOddballResource(fakes.FakeResource): - def get(self, attr): """get() is needed for utils.find_resource()""" if attr == 'id': @@ -43,7 +42,6 @@ class FakeOddballResource(fakes.FakeResource): class TestUtils(test_utils.TestCase): - def _get_test_items(self): item1 = {'a': 1, 'b': 2} item2 = {'a': 1, 'b': 3} @@ -130,18 +128,18 @@ class TestUtils(test_utils.TestCase): mock_stdin = mock.Mock() mock_stdin.isatty = mock.Mock() mock_stdin.isatty.return_value = False - self.assertRaises(exceptions.CommandError, - utils.get_password, - mock_stdin) + self.assertRaises( + exceptions.CommandError, utils.get_password, mock_stdin + ) def test_get_password_cntrl_d(self): with mock.patch("getpass.getpass", side_effect=EOFError()): mock_stdin = mock.Mock() mock_stdin.isatty = mock.Mock() mock_stdin.isatty.return_value = True - self.assertRaises(exceptions.CommandError, - utils.get_password, - mock_stdin) + self.assertRaises( + exceptions.CommandError, utils.get_password, mock_stdin + ) def test_sort_items_with_one_key(self): items = self._get_test_items() @@ -187,16 +185,16 @@ class TestUtils(test_utils.TestCase): def test_sort_items_with_invalid_key(self): items = self._get_test_items() sort_str = 'c' - self.assertRaises(exceptions.CommandError, - utils.sort_items, - items, sort_str) + self.assertRaises( + exceptions.CommandError, utils.sort_items, items, sort_str + ) def test_sort_items_with_invalid_direction(self): items = self._get_test_items() sort_str = 'a:bad_dir' - self.assertRaises(exceptions.CommandError, - utils.sort_items, - items, sort_str) + self.assertRaises( + exceptions.CommandError, utils.sort_items, items, sort_str + ) def test_sort_items_with_different_type_exception(self): item1 = {'a': 2} @@ -216,8 +214,9 @@ class TestUtils(test_utils.TestCase): sort_str = 'a' sort_type = int expect_items = [item3, item4, item1, item2] - self.assertEqual(expect_items, utils.sort_items(items, sort_str, - sort_type)) + self.assertEqual( + expect_items, utils.sort_items(items, sort_str, sort_type) + ) def test_sort_items_with_different_type_str(self): item1 = {'a': 'a'} @@ -228,21 +227,22 @@ class TestUtils(test_utils.TestCase): sort_str = 'a' sort_type = str expect_items = [item3, item2, item1, item4] - self.assertEqual(expect_items, utils.sort_items(items, sort_str, - sort_type)) + self.assertEqual( + expect_items, utils.sort_items(items, sort_str, sort_type) + ) @mock.patch.object(time, 'sleep') def test_wait_for_delete_ok(self, mock_sleep): # Tests the normal flow that the resource is deleted with a 404 coming # back on the 2nd iteration of the wait loop. resource = mock.MagicMock(status='ACTIVE', progress=None) - mock_get = mock.Mock(side_effect=[resource, - exceptions.NotFound(404)]) + mock_get = mock.Mock(side_effect=[resource, exceptions.NotFound(404)]) manager = mock.MagicMock(get=mock_get) res_id = str(uuid.uuid4()) callback = mock.Mock() - self.assertTrue(utils.wait_for_delete(manager, res_id, - callback=callback)) + self.assertTrue( + utils.wait_for_delete(manager, res_id, callback=callback) + ) mock_sleep.assert_called_once_with(5) callback.assert_called_once_with(0) @@ -253,8 +253,9 @@ class TestUtils(test_utils.TestCase): mock_get = mock.Mock(return_value=resource) manager = mock.MagicMock(get=mock_get) res_id = str(uuid.uuid4()) - self.assertFalse(utils.wait_for_delete(manager, res_id, sleep_time=1, - timeout=1)) + self.assertFalse( + utils.wait_for_delete(manager, res_id, sleep_time=1, timeout=1) + ) mock_sleep.assert_called_once_with(1) @mock.patch.object(time, 'sleep') @@ -274,9 +275,14 @@ class TestUtils(test_utils.TestCase): mock_get = mock.Mock(return_value=resource) manager = mock.MagicMock(get=mock_get) res_id = str(uuid.uuid4()) - self.assertFalse(utils.wait_for_delete(manager, res_id, - status_field='my_status', - error_status=['failed'])) + self.assertFalse( + utils.wait_for_delete( + manager, + res_id, + status_field='my_status', + error_status=['failed'], + ) + ) mock_sleep.assert_not_called() @mock.patch.object(time, 'sleep') @@ -285,8 +291,11 @@ class TestUtils(test_utils.TestCase): mock_get = mock.Mock(side_effect=Exception) manager = mock.MagicMock(get=mock_get) res_id = str(uuid.uuid4()) - self.assertTrue(utils.wait_for_delete(manager, res_id, - exception_name=['Exception'])) + self.assertTrue( + utils.wait_for_delete( + manager, res_id, exception_name=['Exception'] + ) + ) mock_sleep.assert_not_called() @mock.patch.object(time, 'sleep') @@ -295,7 +304,12 @@ class TestUtils(test_utils.TestCase): resource = mock.MagicMock(status='ACTIVE') status_f = mock.Mock(return_value=resource) res_id = str(uuid.uuid4()) - self.assertTrue(utils.wait_for_status(status_f, res_id,)) + self.assertTrue( + utils.wait_for_status( + status_f, + res_id, + ) + ) mock_sleep.assert_not_called() @mock.patch.object(time, 'sleep') @@ -304,9 +318,14 @@ class TestUtils(test_utils.TestCase): resource = mock.MagicMock(my_status='COMPLETE') status_f = mock.Mock(return_value=resource) res_id = str(uuid.uuid4()) - self.assertTrue(utils.wait_for_status(status_f, res_id, - status_field='my_status', - success_status=['complete'])) + self.assertTrue( + utils.wait_for_status( + status_f, + res_id, + status_field='my_status', + success_status=['complete'], + ) + ) mock_sleep.assert_not_called() @mock.patch.object(time, 'sleep') @@ -324,14 +343,20 @@ class TestUtils(test_utils.TestCase): resource = mock.MagicMock(my_status='FAILED') status_f = mock.Mock(return_value=resource) res_id = str(uuid.uuid4()) - self.assertFalse(utils.wait_for_status(status_f, res_id, - status_field='my_status', - error_status=['failed'])) + self.assertFalse( + utils.wait_for_status( + status_f, + res_id, + status_field='my_status', + error_status=['failed'], + ) + ) mock_sleep.assert_not_called() def test_build_kwargs_dict_value_set(self): - self.assertEqual({'arg_bla': 'bla'}, - utils.build_kwargs_dict('arg_bla', 'bla')) + self.assertEqual( + {'arg_bla': 'bla'}, utils.build_kwargs_dict('arg_bla', 'bla') + ) def test_build_kwargs_dict_value_None(self): self.assertEqual({}, utils.build_kwargs_dict('arg_bla', None)) @@ -349,21 +374,17 @@ class TestUtils(test_utils.TestCase): self.assertEqual("999", utils.format_size(999)) self.assertEqual("100K", utils.format_size(100000)) self.assertEqual("2M", utils.format_size(2000000)) - self.assertEqual( - "16.4M", utils.format_size(16361280) - ) - self.assertEqual( - "1.6G", utils.format_size(1576395005) - ) + self.assertEqual("16.4M", utils.format_size(16361280)) + self.assertEqual("1.6G", utils.format_size(1576395005)) self.assertEqual("0", utils.format_size(None)) def test_backward_compat_col_lister(self): fake_col_headers = ['ID', 'Name', 'Size'] columns = ['Display Name'] column_map = {'Display Name': 'Name'} - results = utils.backward_compat_col_lister(fake_col_headers, - columns, - column_map) + results = utils.backward_compat_col_lister( + fake_col_headers, columns, column_map + ) self.assertIsInstance(results, list) self.assertIn('Display Name', results) self.assertNotIn('Name', results) @@ -374,9 +395,9 @@ class TestUtils(test_utils.TestCase): fake_col_headers = ['ID', 'Name', 'Size'] columns = [] column_map = {'Display Name': 'Name'} - results = utils.backward_compat_col_lister(fake_col_headers, - columns, - column_map) + results = utils.backward_compat_col_lister( + fake_col_headers, columns, column_map + ) self.assertIsInstance(results, list) self.assertNotIn('Display Name', results) self.assertIn('Name', results) @@ -387,9 +408,9 @@ class TestUtils(test_utils.TestCase): fake_col_headers = ('ID', 'Name', 'Size') columns = ['Display Name'] column_map = {'Display Name': 'Name'} - results = utils.backward_compat_col_lister(fake_col_headers, - columns, - column_map) + results = utils.backward_compat_col_lister( + fake_col_headers, columns, column_map + ) self.assertIsInstance(results, list) self.assertIn('Display Name', results) self.assertNotIn('Name', results) @@ -397,14 +418,16 @@ class TestUtils(test_utils.TestCase): self.assertIn('Size', results) def test_backward_compat_col_showone(self): - fake_object = {'id': 'fake-id', - 'name': 'fake-name', - 'size': 'fake-size'} + fake_object = { + 'id': 'fake-id', + 'name': 'fake-name', + 'size': 'fake-size', + } columns = ['display_name'] column_map = {'display_name': 'name'} - results = utils.backward_compat_col_showone(fake_object, - columns, - column_map) + results = utils.backward_compat_col_showone( + fake_object, columns, column_map + ) self.assertIsInstance(results, dict) self.assertIn('display_name', results) self.assertIn('id', results) @@ -412,14 +435,16 @@ class TestUtils(test_utils.TestCase): self.assertIn('size', results) def test_backward_compat_col_showone_no_specify_column(self): - fake_object = {'id': 'fake-id', - 'name': 'fake-name', - 'size': 'fake-size'} + fake_object = { + 'id': 'fake-id', + 'name': 'fake-name', + 'size': 'fake-size', + } columns = [] column_map = {'display_name': 'name'} - results = utils.backward_compat_col_showone(fake_object, - columns, - column_map) + results = utils.backward_compat_col_showone( + fake_object, columns, column_map + ) self.assertIsInstance(results, dict) self.assertNotIn('display_name', results) self.assertIn('id', results) @@ -429,8 +454,9 @@ class TestUtils(test_utils.TestCase): def _test_get_item_properties_with_formatter(self, formatters): names = ('id', 'attr') item = fakes.FakeResource(info={'id': 'fake-id', 'attr': ['a', 'b']}) - res_id, res_attr = utils.get_item_properties(item, names, - formatters=formatters) + res_id, res_attr = utils.get_item_properties( + item, names, formatters=formatters + ) self.assertEqual('fake-id', res_id) return res_attr @@ -447,8 +473,9 @@ class TestUtils(test_utils.TestCase): def _test_get_dict_properties_with_formatter(self, formatters): names = ('id', 'attr') item = {'id': 'fake-id', 'attr': ['a', 'b']} - res_id, res_attr = utils.get_dict_properties(item, names, - formatters=formatters) + res_id, res_attr = utils.get_dict_properties( + item, names, formatters=formatters + ) self.assertEqual('fake-id', res_id) return res_attr @@ -462,14 +489,16 @@ class TestUtils(test_utils.TestCase): res_attr = self._test_get_dict_properties_with_formatter(formatters) self.assertIsInstance(res_attr, format_columns.ListColumn) - def _test_calculate_header_and_attrs(self, parsed_args_columns, - expected_headers, expected_attrs): + def _test_calculate_header_and_attrs( + self, parsed_args_columns, expected_headers, expected_attrs + ): column_headers = ('ID', 'Name', 'Fixed IP Addresses') columns = ('id', 'name', 'fixed_ips') parsed_args = mock.Mock() parsed_args.columns = parsed_args_columns ret_headers, ret_attrs = utils.calculate_header_and_attrs( - column_headers, columns, parsed_args) + column_headers, columns, parsed_args + ) self.assertEqual(expected_headers, ret_headers) self.assertEqual(expected_attrs, ret_attrs) if parsed_args_columns: @@ -481,25 +510,27 @@ class TestUtils(test_utils.TestCase): self._test_calculate_header_and_attrs( [], ('ID', 'Name', 'Fixed IP Addresses'), - ('id', 'name', 'fixed_ips')) + ('id', 'name', 'fixed_ips'), + ) def test_calculate_header_and_attrs_with_known_columns(self): self._test_calculate_header_and_attrs( - ['Name', 'ID'], - ['Name', 'ID'], - ['name', 'id']) + ['Name', 'ID'], ['Name', 'ID'], ['name', 'id'] + ) def test_calculate_header_and_attrs_with_unknown_columns(self): self._test_calculate_header_and_attrs( ['Name', 'ID', 'device_id'], ['Name', 'ID', 'device_id'], - ['name', 'id', 'device_id']) + ['name', 'id', 'device_id'], + ) def test_calculate_header_and_attrs_with_attrname_columns(self): self._test_calculate_header_and_attrs( ['name', 'id', 'device_id'], ['Name', 'ID', 'device_id'], - ['name', 'id', 'device_id']) + ['name', 'id', 'device_id'], + ) def test_subtest(self): for i in range(3): @@ -512,7 +543,6 @@ class NoUniqueMatch(Exception): class TestFindResource(test_utils.TestCase): - def setUp(self): super(TestFindResource, self).setUp() self.name = 'legos' @@ -572,36 +602,39 @@ class TestFindResource(test_utils.TestCase): self.manager.find = mock.Mock( side_effect=exceptions.NotFound(404, "2") ) - result = self.assertRaises(exceptions.CommandError, - utils.find_resource, - self.manager, - self.name) - self.assertEqual("No lego with a name or ID of 'legos' exists.", - str(result)) + result = self.assertRaises( + exceptions.CommandError, + utils.find_resource, + self.manager, + self.name, + ) + self.assertEqual( + "No lego with a name or ID of 'legos' exists.", str(result) + ) self.manager.get.assert_called_with(self.name) self.manager.find.assert_called_with(name=self.name) def test_find_resource_list_forbidden(self): self.manager.get = mock.Mock(side_effect=Exception('Boom!')) self.manager.find = mock.Mock(side_effect=Exception('Boom!')) - self.manager.list = mock.Mock( - side_effect=exceptions.Forbidden(403) + self.manager.list = mock.Mock(side_effect=exceptions.Forbidden(403)) + self.assertRaises( + exceptions.Forbidden, utils.find_resource, self.manager, self.name ) - self.assertRaises(exceptions.Forbidden, - utils.find_resource, - self.manager, - self.name) self.manager.list.assert_called_with() def test_find_resource_find_no_unique(self): self.manager.get = mock.Mock(side_effect=Exception('Boom!')) self.manager.find = mock.Mock(side_effect=NoUniqueMatch()) - result = self.assertRaises(exceptions.CommandError, - utils.find_resource, - self.manager, - self.name) - self.assertEqual("More than one lego exists with the name 'legos'.", - str(result)) + result = self.assertRaises( + exceptions.CommandError, + utils.find_resource, + self.manager, + self.name, + ) + self.assertEqual( + "More than one lego exists with the name 'legos'.", str(result) + ) self.manager.get.assert_called_with(self.name) self.manager.find.assert_called_with(name=self.name) @@ -620,7 +653,9 @@ class TestFindResource(test_utils.TestCase): loaded=True, ) self.manager.list = mock.Mock( - return_value=[silly_resource, ], + return_value=[ + silly_resource, + ], ) result = utils.find_resource(self.manager, self.name) self.assertEqual(silly_resource, result) @@ -637,12 +672,13 @@ class TestFindResource(test_utils.TestCase): ) ) self.manager.list = mock.Mock(return_value=[]) - result = self.assertRaises(exceptions.CommandError, - utils.find_resource, - self.manager, - self.name) - self.assertEqual("Could not find resource legos", - str(result)) + result = self.assertRaises( + exceptions.CommandError, + utils.find_resource, + self.manager, + self.name, + ) + self.assertEqual("Could not find resource legos", str(result)) self.manager.get.assert_called_with(self.name) self.manager.find.assert_called_with(name=self.name) @@ -665,34 +701,39 @@ class TestFindResource(test_utils.TestCase): {'id': 'abcde', 'name': self.name}, loaded=True, ) - self.manager.list = mock.Mock(return_value=[silly_resource, - silly_resource_same]) - result = self.assertRaises(exceptions.CommandError, - utils.find_resource, - self.manager, - self.name) - self.assertEqual("More than one resource exists " - "with the name or ID 'legos'.", str(result)) + self.manager.list = mock.Mock( + return_value=[silly_resource, silly_resource_same] + ) + result = self.assertRaises( + exceptions.CommandError, + utils.find_resource, + self.manager, + self.name, + ) + self.assertEqual( + "More than one resource exists " "with the name or ID 'legos'.", + str(result), + ) self.manager.get.assert_called_with(self.name) self.manager.find.assert_called_with(name=self.name) def test_format_dict(self): expected = "a='b', c='d', e='f'" - self.assertEqual(expected, - utils.format_dict({'a': 'b', 'c': 'd', 'e': 'f'})) - self.assertEqual(expected, - utils.format_dict({'e': 'f', 'c': 'd', 'a': 'b'})) + self.assertEqual( + expected, utils.format_dict({'a': 'b', 'c': 'd', 'e': 'f'}) + ) + self.assertEqual( + expected, utils.format_dict({'e': 'f', 'c': 'd', 'a': 'b'}) + ) self.assertIsNone(utils.format_dict(None)) def test_format_dict_recursive(self): expected = "a='b', c.1='d', c.2=''" self.assertEqual( - expected, - utils.format_dict({'a': 'b', 'c': {'1': 'd', '2': ''}}) + expected, utils.format_dict({'a': 'b', 'c': {'1': 'd', '2': ''}}) ) self.assertEqual( - expected, - utils.format_dict({'c': {'1': 'd', '2': ''}, 'a': 'b'}) + expected, utils.format_dict({'c': {'1': 'd', '2': ''}, 'a': 'b'}) ) self.assertIsNone(utils.format_dict(None)) @@ -710,7 +751,7 @@ class TestFindResource(test_utils.TestCase): 'b2': 'D', }, } - ) + ), ) self.assertEqual( expected, @@ -725,45 +766,64 @@ class TestFindResource(test_utils.TestCase): }, 'a1': 'A', } - ) + ), ) def test_format_dict_of_list(self): expected = "a=a1, a2; b=b1, b2; c=c1, c2; e=" - self.assertEqual(expected, - utils.format_dict_of_list({'a': ['a2', 'a1'], - 'b': ['b2', 'b1'], - 'c': ['c1', 'c2'], - 'd': None, - 'e': []}) - ) - self.assertEqual(expected, - utils.format_dict_of_list({'c': ['c1', 'c2'], - 'a': ['a2', 'a1'], - 'b': ['b2', 'b1'], - 'e': []}) - ) + self.assertEqual( + expected, + utils.format_dict_of_list( + { + 'a': ['a2', 'a1'], + 'b': ['b2', 'b1'], + 'c': ['c1', 'c2'], + 'd': None, + 'e': [], + } + ), + ) + self.assertEqual( + expected, + utils.format_dict_of_list( + { + 'c': ['c1', 'c2'], + 'a': ['a2', 'a1'], + 'b': ['b2', 'b1'], + 'e': [], + } + ), + ) self.assertIsNone(utils.format_dict_of_list(None)) def test_format_dict_of_list_with_separator(self): expected = "a=a1, a2\nb=b1, b2\nc=c1, c2\ne=" - self.assertEqual(expected, - utils.format_dict_of_list({'a': ['a2', 'a1'], - 'b': ['b2', 'b1'], - 'c': ['c1', 'c2'], - 'd': None, - 'e': []}, - separator='\n') - ) - self.assertEqual(expected, - utils.format_dict_of_list({'c': ['c1', 'c2'], - 'a': ['a2', 'a1'], - 'b': ['b2', 'b1'], - 'e': []}, - separator='\n') - ) - self.assertIsNone(utils.format_dict_of_list(None, - separator='\n')) + self.assertEqual( + expected, + utils.format_dict_of_list( + { + 'a': ['a2', 'a1'], + 'b': ['b2', 'b1'], + 'c': ['c1', 'c2'], + 'd': None, + 'e': [], + }, + separator='\n', + ), + ) + self.assertEqual( + expected, + utils.format_dict_of_list( + { + 'c': ['c1', 'c2'], + 'a': ['a2', 'a1'], + 'b': ['b2', 'b1'], + 'e': [], + }, + separator='\n', + ), + ) + self.assertIsNone(utils.format_dict_of_list(None, separator='\n')) def test_format_list(self): expected = 'a, b, c' @@ -790,35 +850,43 @@ class TestFindResource(test_utils.TestCase): class TestAssertItemEqual(test_utils.TestCommand): - def test_assert_normal_item(self): expected = ['a', 'b', 'c'] actual = ['a', 'b', 'c'] self.assertItemEqual(expected, actual) def test_assert_item_with_formattable_columns(self): - expected = [format_columns.DictColumn({'a': 1, 'b': 2}), - format_columns.ListColumn(['x', 'y', 'z'])] - actual = [format_columns.DictColumn({'a': 1, 'b': 2}), - format_columns.ListColumn(['x', 'y', 'z'])] + expected = [ + format_columns.DictColumn({'a': 1, 'b': 2}), + format_columns.ListColumn(['x', 'y', 'z']), + ] + actual = [ + format_columns.DictColumn({'a': 1, 'b': 2}), + format_columns.ListColumn(['x', 'y', 'z']), + ] self.assertItemEqual(expected, actual) def test_assert_item_different_length(self): expected = ['a', 'b', 'c'] actual = ['a', 'b'] - self.assertRaises(AssertionError, - self.assertItemEqual, expected, actual) + self.assertRaises( + AssertionError, self.assertItemEqual, expected, actual + ) def test_assert_item_formattable_columns_vs_legacy_formatter(self): - expected = [format_columns.DictColumn({'a': 1, 'b': 2}), - format_columns.ListColumn(['x', 'y', 'z'])] - actual = [utils.format_dict({'a': 1, 'b': 2}), - utils.format_list(['x', 'y', 'z'])] - self.assertRaises(AssertionError, - self.assertItemEqual, expected, actual) + expected = [ + format_columns.DictColumn({'a': 1, 'b': 2}), + format_columns.ListColumn(['x', 'y', 'z']), + ] + actual = [ + utils.format_dict({'a': 1, 'b': 2}), + utils.format_list(['x', 'y', 'z']), + ] + self.assertRaises( + AssertionError, self.assertItemEqual, expected, actual + ) def test_assert_item_different_formattable_columns(self): - class ExceptionColumn(cliff_columns.FormattableColumn): def human_readable(self): raise Exception('always fail') @@ -828,63 +896,80 @@ class TestAssertItemEqual(test_utils.TestCommand): # AssertionError is a subclass of Exception # so raising AssertionError ensures ExceptionColumn.human_readable() # is not called. - self.assertRaises(AssertionError, - self.assertItemEqual, expected, actual) + self.assertRaises( + AssertionError, self.assertItemEqual, expected, actual + ) def test_assert_list_item(self): expected = [ ['a', 'b', 'c'], - [format_columns.DictColumn({'a': 1, 'b': 2}), - format_columns.ListColumn(['x', 'y', 'z'])] + [ + format_columns.DictColumn({'a': 1, 'b': 2}), + format_columns.ListColumn(['x', 'y', 'z']), + ], ] actual = [ ['a', 'b', 'c'], - [format_columns.DictColumn({'a': 1, 'b': 2}), - format_columns.ListColumn(['x', 'y', 'z'])] + [ + format_columns.DictColumn({'a': 1, 'b': 2}), + format_columns.ListColumn(['x', 'y', 'z']), + ], ] self.assertListItemEqual(expected, actual) class TestSDKUtils(test_utils.TestCase): - def setUp(self): super(TestSDKUtils, self).setUp() def _test_get_osc_show_columns_for_sdk_resource( - self, sdk_resource, column_map, - expected_display_columns, expected_attr_columns): - display_columns, attr_columns = \ - utils.get_osc_show_columns_for_sdk_resource( - sdk_resource, column_map) + self, + sdk_resource, + column_map, + expected_display_columns, + expected_attr_columns, + ): + ( + display_columns, + attr_columns, + ) = utils.get_osc_show_columns_for_sdk_resource( + sdk_resource, column_map + ) self.assertEqual(expected_display_columns, display_columns) self.assertEqual(expected_attr_columns, attr_columns) def test_get_osc_show_columns_for_sdk_resource_empty(self): self._test_get_osc_show_columns_for_sdk_resource( - {}, {}, tuple(), tuple()) + {}, {}, tuple(), tuple() + ) def test_get_osc_show_columns_for_sdk_resource_empty_map(self): self._test_get_osc_show_columns_for_sdk_resource( - {'foo': 'foo1'}, {}, - ('foo',), ('foo',)) + {'foo': 'foo1'}, {}, ('foo',), ('foo',) + ) def test_get_osc_show_columns_for_sdk_resource_empty_data(self): self._test_get_osc_show_columns_for_sdk_resource( - {}, {'foo': 'foo_map'}, - ('foo_map',), ('foo_map',)) + {}, {'foo': 'foo_map'}, ('foo_map',), ('foo_map',) + ) def test_get_osc_show_columns_for_sdk_resource_map(self): self._test_get_osc_show_columns_for_sdk_resource( - {'foo': 'foo1'}, {'foo': 'foo_map'}, - ('foo_map',), ('foo',)) + {'foo': 'foo1'}, {'foo': 'foo_map'}, ('foo_map',), ('foo',) + ) def test_get_osc_show_columns_for_sdk_resource_map_dup(self): self._test_get_osc_show_columns_for_sdk_resource( - {'foo': 'foo1', 'foo_map': 'foo1'}, {'foo': 'foo_map'}, - ('foo_map',), ('foo',)) + {'foo': 'foo1', 'foo_map': 'foo1'}, + {'foo': 'foo_map'}, + ('foo_map',), + ('foo',), + ) def test_get_osc_show_columns_for_sdk_resource_map_full(self): self._test_get_osc_show_columns_for_sdk_resource( {'foo': 'foo1', 'bar': 'bar1'}, {'foo': 'foo_map', 'new': 'bar'}, - ('bar', 'foo_map'), ('bar', 'foo')) + ('bar', 'foo_map'), + ('bar', 'foo'), + ) diff --git a/osc_lib/utils/__init__.py b/osc_lib/utils/__init__.py index 75bf4d3..90cb6f3 100644 --- a/osc_lib/utils/__init__.py +++ b/osc_lib/utils/__init__.py @@ -53,11 +53,13 @@ def backward_compat_col_lister(column_headers, columns, column_map): column_headers = list(column_headers) for old_col, new_col in column_map.items(): if old_col in columns: - LOG.warning(_('The column "%(old_column)s" was deprecated, ' - 'please use "%(new_column)s" replace.') % { - 'old_column': old_col, - 'new_column': new_col} - ) + LOG.warning( + _( + 'The column "%(old_column)s" was deprecated, ' + 'please use "%(new_column)s" replace.' + ) + % {'old_column': old_col, 'new_column': new_col} + ) if new_col in column_headers: column_headers[column_headers.index(new_col)] = old_col return column_headers @@ -81,11 +83,13 @@ def backward_compat_col_showone(show_object, columns, column_map): show_object = copy.deepcopy(show_object) for old_col, new_col in column_map.items(): if old_col in columns: - LOG.warning(_('The column "%(old_column)s" was deprecated, ' - 'please use "%(new_column)s" replace.') % { - 'old_column': old_col, - 'new_column': new_col} - ) + LOG.warning( + _( + 'The column "%(old_column)s" was deprecated, ' + 'please use "%(new_column)s" replace.' + ) + % {'old_column': old_col, 'new_column': new_col} + ) if new_col in show_object: show_object.update({old_col: show_object.pop(new_col)}) return show_object @@ -118,11 +122,13 @@ def calculate_header_and_attrs(column_headers, attrs, parsed_args): """ if parsed_args.columns: header_attr_map = dict(zip(column_headers, attrs)) - expected_attrs = [header_attr_map.get(c, c) - for c in parsed_args.columns] + expected_attrs = [ + header_attr_map.get(c, c) for c in parsed_args.columns + ] attr_header_map = dict(zip(attrs, column_headers)) - expected_headers = [attr_header_map.get(c, c) - for c in parsed_args.columns] + expected_headers = [ + attr_header_map.get(c, c) for c in parsed_args.columns + ] # If attribute name is used in parsed_args.columns # convert it into display names because cliff expects # name in parsed_args.columns and name in column_headers matches. @@ -215,9 +221,11 @@ def find_resource(manager, name_or_id, **kwargs): # Eventually this should be pulled from a common set # of client exceptions. except Exception as ex: - if (type(ex).__name__ == 'NotFound' or - type(ex).__name__ == 'HTTPNotFound' or - type(ex).__name__ == 'TypeError'): + if ( + type(ex).__name__ == 'NotFound' + or type(ex).__name__ == 'HTTPNotFound' + or type(ex).__name__ == 'TypeError' + ): pass else: raise @@ -246,21 +254,25 @@ def find_resource(manager, name_or_id, **kwargs): # of client exceptions. except Exception as ex: if type(ex).__name__ == 'NotFound': - msg = _( - "No %(resource)s with a name or ID of '%(id)s' exists." + msg = _("No %(resource)s with a name or ID of '%(id)s' exists.") + raise exceptions.CommandError( + msg + % { + 'resource': manager.resource_class.__name__.lower(), + 'id': name_or_id, + } ) - raise exceptions.CommandError(msg % { - 'resource': manager.resource_class.__name__.lower(), - 'id': name_or_id, - }) if type(ex).__name__ == 'NoUniqueMatch': msg = _( "More than one %(resource)s exists with the name '%(id)s'." ) - raise exceptions.CommandError(msg % { - 'resource': manager.resource_class.__name__.lower(), - 'id': name_or_id, - }) + raise exceptions.CommandError( + msg + % { + 'resource': manager.resource_class.__name__.lower(), + 'id': name_or_id, + } + ) else: pass @@ -268,8 +280,10 @@ def find_resource(manager, name_or_id, **kwargs): # to find a matching name or ID. count = 0 for resource in manager.list(): - if (resource.get('id') == name_or_id or - resource.get('name') == name_or_id): + if ( + resource.get('id') == name_or_id + or resource.get('name') == name_or_id + ): count += 1 _resource = resource if count == 0: @@ -403,17 +417,21 @@ def get_client_class(api_name, version, version_map): try: client_path = version_map[str(version)] except (KeyError, ValueError): - sorted_versions = sorted(version_map.keys(), - key=lambda s: list(map(int, s.split('.')))) + sorted_versions = sorted( + version_map.keys(), key=lambda s: list(map(int, s.split('.'))) + ) msg = _( "Invalid %(api_name)s client version '%(version)s'. " "must be one of: %(version_map)s" ) - raise exceptions.UnsupportedVersion(msg % { - 'api_name': api_name, - 'version': version, - 'version_map': ', '.join(sorted_versions), - }) + raise exceptions.UnsupportedVersion( + msg + % { + 'api_name': api_name, + 'version': version, + 'version_map': ', '.join(sorted_versions), + } + ) return importutils.import_class(client_path) @@ -443,16 +461,15 @@ def get_dict_properties(item, fields, mixed_case_fields=None, formatters=None): if field in formatters: formatter = formatters[field] # columns must be either a subclass of FormattableColumn - if ( - isinstance(formatter, type) and - issubclass(formatter, cliff_columns.FormattableColumn) + if isinstance(formatter, type) and issubclass( + formatter, cliff_columns.FormattableColumn ): data = formatter(data) # or a partial wrapping one (to allow us to pass extra parameters) elif ( - isinstance(formatter, functools.partial) and - isinstance(formatter.func, type) and - issubclass(formatter.func, cliff_columns.FormattableColumn) + isinstance(formatter, functools.partial) + and isinstance(formatter.func, type) + and issubclass(formatter.func, cliff_columns.FormattableColumn) ): data = formatter(data) # otherwise it's probably a legacy-style function @@ -461,7 +478,8 @@ def get_dict_properties(item, fields, mixed_case_fields=None, formatters=None): 'The usage of formatter functions is now discouraged. ' 'Consider using cliff.columns.FormattableColumn instead. ' 'See reviews linked with bug 1687955 for more detail.', - category=DeprecationWarning) + category=DeprecationWarning, + ) if data is not None: data = formatter(data) else: @@ -520,15 +538,17 @@ def get_item_properties(item, fields, mixed_case_fields=None, formatters=None): data = getattr(item, field_name, '') if field in formatters: formatter = formatters[field] - if (isinstance(formatter, type) and issubclass( - formatter, cliff_columns.FormattableColumn)): + if isinstance(formatter, type) and issubclass( + formatter, cliff_columns.FormattableColumn + ): data = formatter(data) elif callable(formatter): warnings.warn( 'The usage of formatter functions is now discouraged. ' 'Consider using cliff.columns.FormattableColumn instead. ' 'See reviews linked with bug 1687955 for more detail.', - category=DeprecationWarning) + category=DeprecationWarning, + ) if data is not None: data = formatter(data) else: @@ -561,8 +581,11 @@ def get_password(stdin, prompt=None, confirm=True): def is_ascii(string): try: - (string.decode('ascii') if isinstance(string, bytes) - else string.encode('ascii')) + ( + string.decode('ascii') + if isinstance(string, bytes) + else string.encode('ascii') + ) return True except (UnicodeEncodeError, UnicodeDecodeError): return False @@ -607,10 +630,13 @@ def sort_items(items, sort_str, sort_type=None): "'%(direction)s' is not a valid sort direction for " "sort key %(sort_key)s, use 'asc' or 'desc' instead" ) - raise exceptions.CommandError(msg % { - 'direction': direction, - 'sort_key': sort_key, - }) + raise exceptions.CommandError( + msg + % { + 'direction': direction, + 'sort_key': sort_key, + } + ) if direction == 'desc': reverse = True @@ -632,14 +658,16 @@ def sort_items(items, sort_str, sort_type=None): return items -def wait_for_delete(manager, - res_id, - status_field='status', - error_status=['error'], - exception_name=['NotFound'], - sleep_time=5, - timeout=300, - callback=None): +def wait_for_delete( + manager, + res_id, + status_field='status', + error_status=['error'], + exception_name=['NotFound'], + sleep_time=5, + timeout=300, + callback=None, +): """Wait for resource deletion :param manager: the manager from which we can get the resource @@ -683,13 +711,15 @@ def wait_for_delete(manager, return False -def wait_for_status(status_f, - res_id, - status_field='status', - success_status=['active'], - error_status=['error'], - sleep_time=5, - callback=None): +def wait_for_status( + status_f, + res_id, + status_field='status', + success_status=['active'], + error_status=['error'], + sleep_time=5, + callback=None, +): """Wait for status change on a resource during a long-running operation :param status_f: a status function that takes a single id argument @@ -718,9 +748,7 @@ def wait_for_status(status_f, def get_osc_show_columns_for_sdk_resource( - sdk_resource, - osc_column_map, - invisible_columns=None + sdk_resource, osc_column_map, invisible_columns=None ): """Get and filter the display and attribute columns for an SDK resource. @@ -740,7 +768,8 @@ def get_osc_show_columns_for_sdk_resource( # 100% sdk compatible. Unless we introduce SDK test/fake resources we # should check presence of the specific method resource_dict = sdk_resource.to_dict( - body=True, headers=False, ignore_none=False) + body=True, headers=False, ignore_none=False + ) else: # We might land here with not a real SDK Resource (during the # transition period). diff --git a/osc_lib/utils/columns.py b/osc_lib/utils/columns.py index 98fc2ae..2aaa526 100644 --- a/osc_lib/utils/columns.py +++ b/osc_lib/utils/columns.py @@ -44,15 +44,29 @@ def get_column_definitions(attr_map, long_listing): """ if long_listing: - headers = [hdr for col, hdr, listing_mode in attr_map - if listing_mode in (LIST_BOTH, LIST_LONG_ONLY)] - columns = [col for col, hdr, listing_mode in attr_map - if listing_mode in (LIST_BOTH, LIST_LONG_ONLY)] + headers = [ + hdr + for col, hdr, listing_mode in attr_map + if listing_mode in (LIST_BOTH, LIST_LONG_ONLY) + ] + columns = [ + col + for col, hdr, listing_mode in attr_map + if listing_mode in (LIST_BOTH, LIST_LONG_ONLY) + ] else: - headers = [hdr for col, hdr, listing_mode in attr_map if listing_mode - if listing_mode in (LIST_BOTH, LIST_SHORT_ONLY)] - columns = [col for col, hdr, listing_mode in attr_map if listing_mode - if listing_mode in (LIST_BOTH, LIST_SHORT_ONLY)] + headers = [ + hdr + for col, hdr, listing_mode in attr_map + if listing_mode + if listing_mode in (LIST_BOTH, LIST_SHORT_ONLY) + ] + columns = [ + col + for col, hdr, listing_mode in attr_map + if listing_mode + if listing_mode in (LIST_BOTH, LIST_SHORT_ONLY) + ] return headers, columns @@ -92,8 +106,8 @@ def get_columns(item, attr_map=None): attr_map = attr_map or tuple([]) _attr_map_dict = dict((col, hdr) for col, hdr, listing_mode in attr_map) - columns = [(column, _attr_map_dict.get(column, column)) - for column in item.keys()] + columns = [ + (column, _attr_map_dict.get(column, column)) for column in item.keys() + ] columns = sorted(columns, key=operator.itemgetter(1)) - return (tuple(col[0] for col in columns), - tuple(col[1] for col in columns)) + return (tuple(col[0] for col in columns), tuple(col[1] for col in columns)) diff --git a/osc_lib/utils/tags.py b/osc_lib/utils/tags.py index eb67945..634642f 100644 --- a/osc_lib/utils/tags.py +++ b/osc_lib/utils/tags.py @@ -17,13 +17,13 @@ from osc_lib.i18n import _ class _CommaListAction(argparse.Action): - def __call__(self, parser, namespace, values, option_string=None): setattr(namespace, self.dest, values.split(',')) def add_tag_filtering_option_to_parser( - parser, resource_name, enhance_help=lambda _h: _h): + parser, resource_name, enhance_help=lambda _h: _h +): """Add tag filtering options to a parser. :param parser: argparse.Argument parser object. @@ -39,32 +39,48 @@ def add_tag_filtering_option_to_parser( metavar='[,,...]', action=_CommaListAction, help=enhance_help( - _('List %s which have all given tag(s) ' - '(Comma-separated list of tags)') % resource_name) + _( + 'List %s which have all given tag(s) ' + '(Comma-separated list of tags)' + ) + % resource_name + ), ) parser.add_argument( '--any-tags', metavar='[,,...]', action=_CommaListAction, help=enhance_help( - _('List %s which have any given tag(s) ' - '(Comma-separated list of tags)') % resource_name) + _( + 'List %s which have any given tag(s) ' + '(Comma-separated list of tags)' + ) + % resource_name + ), ) parser.add_argument( '--not-tags', metavar='[,,...]', action=_CommaListAction, help=enhance_help( - _('Exclude %s which have all given tag(s) ' - '(Comma-separated list of tags)') % resource_name) + _( + 'Exclude %s which have all given tag(s) ' + '(Comma-separated list of tags)' + ) + % resource_name + ), ) parser.add_argument( '--not-any-tags', metavar='[,,...]', action=_CommaListAction, help=enhance_help( - _('Exclude %s which have any given tag(s) ' - '(Comma-separated list of tags)') % resource_name) + _( + 'Exclude %s which have any given tag(s) ' + '(Comma-separated list of tags)' + ) + % resource_name + ), ) @@ -88,7 +104,8 @@ def get_tag_filtering_args(parsed_args, args): def add_tag_option_to_parser_for_create( - parser, resource_name, enhance_help=lambda _h: _h): + parser, resource_name, enhance_help=lambda _h: _h +): """Add tag options to a parser for create commands. :param parser: argparse.Argument parser object. @@ -106,18 +123,23 @@ def add_tag_option_to_parser_for_create( dest='tags', metavar='', help=enhance_help( - _("Tag to be added to the %s " - "(repeat option to set multiple tags)") % resource_name) + _( + "Tag to be added to the %s " + "(repeat option to set multiple tags)" + ) + % resource_name + ), ) tag_group.add_argument( '--no-tag', action='store_true', - help=enhance_help(_("No tags associated with the %s") % resource_name) + help=enhance_help(_("No tags associated with the %s") % resource_name), ) def add_tag_option_to_parser_for_set( - parser, resource_name, enhance_help=lambda _h: _h): + parser, resource_name, enhance_help=lambda _h: _h +): """Add tag options to a parser for set commands. :param parser: argparse.Argument parser object. @@ -134,20 +156,29 @@ def add_tag_option_to_parser_for_set( dest='tags', metavar='', help=enhance_help( - _("Tag to be added to the %s " - "(repeat option to set multiple tags)") % resource_name) + _( + "Tag to be added to the %s " + "(repeat option to set multiple tags)" + ) + % resource_name + ), ) parser.add_argument( '--no-tag', action='store_true', help=enhance_help( - _("Clear tags associated with the %s. Specify both " - "--tag and --no-tag to overwrite current tags") % resource_name) + _( + "Clear tags associated with the %s. Specify both " + "--tag and --no-tag to overwrite current tags" + ) + % resource_name + ), ) def add_tag_option_to_parser_for_unset( - parser, resource_name, enhance_help=lambda _h: _h): + parser, resource_name, enhance_help=lambda _h: _h +): """Add tag options to a parser for set commands. :param parser: argparse.Argument parser object. @@ -165,13 +196,20 @@ def add_tag_option_to_parser_for_unset( dest='tags', metavar='', help=enhance_help( - _("Tag to be removed from the %s " - "(repeat option to remove multiple tags)") % resource_name)) + _( + "Tag to be removed from the %s " + "(repeat option to remove multiple tags)" + ) + % resource_name + ), + ) tag_group.add_argument( '--all-tag', action='store_true', help=enhance_help( - _("Clear all tags associated with the %s") % resource_name)) + _("Clear all tags associated with the %s") % resource_name + ), + ) def update_tags_for_set(client, obj, parsed_args): diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py index a1703e0..ce28215 100644 --- a/releasenotes/source/conf.py +++ b/releasenotes/source/conf.py @@ -32,6 +32,7 @@ # -- General configuration ------------------------------------------------ from sphinx.util import logging + # According to the discussion in # https://github.com/sphinx-doc/sphinx/issues/10112 this may be applied as a # dirty hack until the issue with replacing extlinks is resolved @@ -248,10 +249,8 @@ htmlhelp_basename = 'OSC_LIBReleaseNotesdoc' latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # 'preamble': '', } @@ -259,12 +258,14 @@ latex_elements = { # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). -latex_documents = [( - 'index', - 'OSC_LIBReleaseNotes.tex', - 'osc-lib Release Notes Documentation', - 'osc-lib Developers', - 'manual'), +latex_documents = [ + ( + 'index', + 'OSC_LIBReleaseNotes.tex', + 'osc-lib Release Notes Documentation', + 'osc-lib Developers', + 'manual', + ), ] # The name of an image file (relative to this directory) to place at the top of @@ -298,13 +299,15 @@ latex_documents = [( # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [( - 'index', - 'osc_libreleasenotes', - 'osc-lib Release Notes Documentation', - ['osc-lib Developers'], - 1, -)] +man_pages = [ + ( + 'index', + 'osc_libreleasenotes', + 'osc-lib Release Notes Documentation', + ['osc-lib Developers'], + 1, + ) +] # If true, show URL addresses after external links. # @@ -316,15 +319,17 @@ man_pages = [( # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) -texinfo_documents = [( - 'index', - 'OSC_LIBReleaseNotes', - 'osc-lib Release Notes Documentation', - 'osc-lib Developers', - 'OSC_LIBReleaseNotes', - 'Common base library for OpenStackClient plugins.', - 'Miscellaneous', -)] +texinfo_documents = [ + ( + 'index', + 'OSC_LIBReleaseNotes', + 'osc-lib Release Notes Documentation', + 'osc-lib Developers', + 'OSC_LIBReleaseNotes', + 'Common base library for OpenStackClient plugins.', + 'Miscellaneous', + ) +] # Documents to append as an appendix to all manuals. # diff --git a/setup.py b/setup.py index cd35c3c..481505b 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,4 @@ import setuptools -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) +setuptools.setup(setup_requires=['pbr>=2.0.0'], pbr=True) diff --git a/tox.ini b/tox.ini index f59bca0..07b72ab 100644 --- a/tox.ini +++ b/tox.ini @@ -62,9 +62,17 @@ commands = [flake8] show-source = True exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools -# If 'ignore' is not set there are default errors and warnings that are set -# Doc: http://flake8.readthedocs.org/en/latest/config.html#default -ignore = W504 +# The following are ignored on purpose. It's not super worth it to fix them. +# However, if you feel strongly about it, patches will be accepted to fix them +# if they fix ALL of the occurances of one and only one of them. +# E203 Black will put spaces after colons in list comprehensions +# E501 Black takes care of line length for us +# H238 New Style Classes are the default in Python3 +# H301 Black will put commas after imports that can't fit on one line +# H4 Are about docstrings and there's just a huge pile of pre-existing issues. +# W503 Is supposed to be off by default but in the latest pycodestyle isn't. +# Also, both openstacksdk and Donald Knuth disagree with the rule. Line +# breaks should occur before the binary operator for readability. +ignore = E203, E501, H301, H238, H4, W503 import-order-style = pep8 application-import-names = osc_lib -filename = *.py