Add pre-commit, apply ruff
Signed-off-by: Stephen Finucane <stephenfin@redhat.com> Change-Id: Iedc7653f27dbe9bb77b6d9bb03117a457e195e58
This commit is contained in:
32
.pre-commit-config.yaml
Normal file
32
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v5.0.0
|
||||||
|
hooks:
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- id: mixed-line-ending
|
||||||
|
args: ['--fix', 'lf']
|
||||||
|
exclude: '.*\.(svg)$'
|
||||||
|
- id: check-byte-order-marker
|
||||||
|
- id: check-executables-have-shebangs
|
||||||
|
- id: check-merge-conflict
|
||||||
|
- id: debug-statements
|
||||||
|
- id: check-yaml
|
||||||
|
files: .*\.(yaml|yml)$
|
||||||
|
exclude: '^zuul.d/.*$'
|
||||||
|
- repo: https://github.com/PyCQA/doc8
|
||||||
|
rev: v1.1.2
|
||||||
|
hooks:
|
||||||
|
- id: doc8
|
||||||
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
|
rev: v0.11.12
|
||||||
|
hooks:
|
||||||
|
- id: ruff-check
|
||||||
|
args: ['--fix', '--unsafe-fixes']
|
||||||
|
- id: ruff-format
|
||||||
|
- repo: https://opendev.org/openstack/hacking
|
||||||
|
rev: 7.0.0
|
||||||
|
hooks:
|
||||||
|
- id: hacking
|
||||||
|
additional_dependencies: []
|
||||||
|
exclude: '^(doc|releasenotes|tools)/.*$'
|
||||||
@@ -13,4 +13,4 @@ Pull requests submitted through GitHub will be ignored.
|
|||||||
|
|
||||||
Bugs should be filed on Launchpad, not GitHub:
|
Bugs should be filed on Launchpad, not GitHub:
|
||||||
|
|
||||||
https://bugs.launchpad.net/os-client-config
|
https://bugs.launchpad.net/os-client-config
|
||||||
|
|||||||
20
doc/source/conf.py
Executable file → Normal file
20
doc/source/conf.py
Executable file → Normal file
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
# You may obtain a copy of the License at
|
# You may obtain a copy of the License at
|
||||||
@@ -43,8 +42,8 @@ source_suffix = '.rst'
|
|||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'os-client-config'
|
project = 'os-client-config'
|
||||||
copyright = u'2015, various OpenStack developers'
|
copyright = '2015, various OpenStack developers'
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
add_function_parentheses = True
|
add_function_parentheses = True
|
||||||
@@ -66,17 +65,20 @@ pygments_style = 'native'
|
|||||||
html_theme = 'openstackdocs'
|
html_theme = 'openstackdocs'
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = '%sdoc' % project
|
htmlhelp_basename = f'{project}doc'
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title, author, documentclass
|
# (source start file, target name, title, author, documentclass
|
||||||
# [howto/manual]).
|
# [howto/manual]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('index',
|
(
|
||||||
'%s.tex' % project,
|
'index',
|
||||||
u'%s Documentation' % project,
|
f'{project}.tex',
|
||||||
u'OpenStack Foundation', 'manual'),
|
f'{project} Documentation',
|
||||||
|
'OpenStack Foundation',
|
||||||
|
'manual',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Example configuration for intersphinx: refer to the Python standard library.
|
# Example configuration for intersphinx: refer to the Python standard library.
|
||||||
#intersphinx_mapping = {'http://docs.python.org/': None}
|
# intersphinx_mapping = {'http://docs.python.org/': None}
|
||||||
|
|||||||
@@ -26,15 +26,16 @@ _config = None
|
|||||||
|
|
||||||
|
|
||||||
def get_config(
|
def get_config(
|
||||||
service_key=None, options=None,
|
service_key=None, options=None, app_name=None, app_version=None, **kwargs
|
||||||
app_name=None, app_version=None,
|
):
|
||||||
**kwargs):
|
|
||||||
load_yaml_config = kwargs.pop('load_yaml_config', True)
|
load_yaml_config = kwargs.pop('load_yaml_config', True)
|
||||||
global _config
|
global _config
|
||||||
if not _config:
|
if not _config:
|
||||||
_config = OpenStackConfig(
|
_config = OpenStackConfig(
|
||||||
load_yaml_config=load_yaml_config,
|
load_yaml_config=load_yaml_config,
|
||||||
app_name=app_name, app_version=app_version)
|
app_name=app_name,
|
||||||
|
app_version=app_version,
|
||||||
|
)
|
||||||
if options:
|
if options:
|
||||||
_config.register_argparse_arguments(options, sys.argv, service_key)
|
_config.register_argparse_arguments(options, sys.argv, service_key)
|
||||||
parsed_options = options.parse_known_args(sys.argv)
|
parsed_options = options.parse_known_args(sys.argv)
|
||||||
@@ -45,9 +46,13 @@ def get_config(
|
|||||||
|
|
||||||
|
|
||||||
def make_rest_client(
|
def make_rest_client(
|
||||||
service_key, options=None,
|
service_key,
|
||||||
app_name=None, app_version=None, version=None,
|
options=None,
|
||||||
**kwargs):
|
app_name=None,
|
||||||
|
app_version=None,
|
||||||
|
version=None,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
"""Simple wrapper function. It has almost no features.
|
"""Simple wrapper function. It has almost no features.
|
||||||
|
|
||||||
This will get you a raw requests Session Adapter that is mounted
|
This will get you a raw requests Session Adapter that is mounted
|
||||||
@@ -61,9 +66,12 @@ def make_rest_client(
|
|||||||
at OpenStack REST APIs with a properly configured keystone session.
|
at OpenStack REST APIs with a properly configured keystone session.
|
||||||
"""
|
"""
|
||||||
cloud = get_config(
|
cloud = get_config(
|
||||||
service_key=service_key, options=options,
|
service_key=service_key,
|
||||||
app_name=app_name, app_version=app_version,
|
options=options,
|
||||||
**kwargs)
|
app_name=app_name,
|
||||||
|
app_version=app_version,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
return cloud.get_session_client(service_key, version=version)
|
return cloud.get_session_client(service_key, version=version)
|
||||||
|
|
||||||
|
|
||||||
@@ -98,6 +106,7 @@ def make_sdk(options=None, **kwargs):
|
|||||||
:rtype: :class:`~openstack.connection.Connection`
|
:rtype: :class:`~openstack.connection.Connection`
|
||||||
"""
|
"""
|
||||||
from openstack import connection
|
from openstack import connection
|
||||||
|
|
||||||
cloud = get_config(options=options, **kwargs)
|
cloud = get_config(options=options, **kwargs)
|
||||||
return connection.from_config(cloud_config=cloud, options=options)
|
return connection.from_config(cloud_config=cloud, options=options)
|
||||||
|
|
||||||
@@ -110,5 +119,6 @@ def make_shade(options=None, **kwargs):
|
|||||||
:rtype: :class:`~shade.OpenStackCloud`
|
:rtype: :class:`~shade.OpenStackCloud`
|
||||||
"""
|
"""
|
||||||
import shade
|
import shade
|
||||||
|
|
||||||
cloud = get_config(options=options, **kwargs)
|
cloud = get_config(options=options, **kwargs)
|
||||||
return shade.OpenStackCloud(cloud_config=cloud, **kwargs)
|
return shade.OpenStackCloud(cloud_config=cloud, **kwargs)
|
||||||
|
|||||||
@@ -26,39 +26,35 @@ def _get_client(service_key):
|
|||||||
class_mapping = constructors.get_constructor_mapping()
|
class_mapping = constructors.get_constructor_mapping()
|
||||||
if service_key not in class_mapping:
|
if service_key not in class_mapping:
|
||||||
raise exceptions.OpenStackConfigException(
|
raise exceptions.OpenStackConfigException(
|
||||||
"Service {service_key} is unkown. Please pass in a client"
|
f"Service {service_key} is unkown. Please pass in a client"
|
||||||
" constructor or submit a patch to os-client-config".format(
|
" constructor or submit a patch to os-client-config"
|
||||||
service_key=service_key))
|
)
|
||||||
mod_name, ctr_name = class_mapping[service_key].rsplit('.', 1)
|
mod_name, ctr_name = class_mapping[service_key].rsplit('.', 1)
|
||||||
lib_name = mod_name.split('.')[0]
|
lib_name = mod_name.split('.')[0]
|
||||||
try:
|
try:
|
||||||
mod = importlib.import_module(mod_name)
|
mod = importlib.import_module(mod_name)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise exceptions.OpenStackConfigException(
|
raise exceptions.OpenStackConfigException(
|
||||||
"Client for '{service_key}' was requested, but"
|
f"Client for '{service_key}' was requested, but"
|
||||||
" {mod_name} was unable to be imported. Either import"
|
f" {mod_name} was unable to be imported. Either import"
|
||||||
" the module yourself and pass the constructor in as an argument,"
|
" the module yourself and pass the constructor in as an argument,"
|
||||||
" or perhaps you do not have python-{lib_name} installed.".format(
|
f" or perhaps you do not have python-{lib_name} installed."
|
||||||
service_key=service_key,
|
)
|
||||||
mod_name=mod_name,
|
|
||||||
lib_name=lib_name))
|
|
||||||
try:
|
try:
|
||||||
ctr = getattr(mod, ctr_name)
|
ctr = getattr(mod, ctr_name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise exceptions.OpenStackConfigException(
|
raise exceptions.OpenStackConfigException(
|
||||||
"Client for '{service_key}' was requested, but although"
|
f"Client for '{service_key}' was requested, but although"
|
||||||
" {mod_name} imported fine, the constructor at {fullname}"
|
f" {mod_name} imported fine, the constructor at {class_mapping[service_key]}"
|
||||||
" as not found. Please check your installation, we have no"
|
" as not found. Please check your installation, we have no"
|
||||||
" clue what is wrong with your computer.".format(
|
" clue what is wrong with your computer."
|
||||||
service_key=service_key,
|
)
|
||||||
mod_name=mod_name,
|
|
||||||
fullname=class_mapping[service_key]))
|
|
||||||
return ctr
|
return ctr
|
||||||
|
|
||||||
|
|
||||||
class CloudConfig(cloud_region.CloudRegion):
|
class CloudConfig(cloud_region.CloudRegion):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(CloudConfig, self).__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.log = _log.setup_logging(__name__)
|
self.log = _log.setup_logging(__name__)
|
||||||
|
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
@@ -74,8 +70,9 @@ class CloudConfig(cloud_region.CloudRegion):
|
|||||||
|
|
||||||
def insert_user_agent(self):
|
def insert_user_agent(self):
|
||||||
self._keystone_session.additional_user_agent.append(
|
self._keystone_session.additional_user_agent.append(
|
||||||
('os-client-config', os_client_config.__version__))
|
('os-client-config', os_client_config.__version__)
|
||||||
super(CloudConfig, self).insert_user_agent()
|
)
|
||||||
|
super().insert_user_agent()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def region(self):
|
def region(self):
|
||||||
@@ -88,9 +85,16 @@ class CloudConfig(cloud_region.CloudRegion):
|
|||||||
return self.get_cache_expirations()
|
return self.get_cache_expirations()
|
||||||
|
|
||||||
def get_legacy_client(
|
def get_legacy_client(
|
||||||
self, service_key, client_class=None, interface_key=None,
|
self,
|
||||||
pass_version_arg=True, version=None, min_version=None,
|
service_key,
|
||||||
max_version=None, **kwargs):
|
client_class=None,
|
||||||
|
interface_key=None,
|
||||||
|
pass_version_arg=True,
|
||||||
|
version=None,
|
||||||
|
min_version=None,
|
||||||
|
max_version=None,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
"""Return a legacy OpenStack client object for the given config.
|
"""Return a legacy OpenStack client object for the given config.
|
||||||
|
|
||||||
Most of the OpenStack python-*client libraries have the same
|
Most of the OpenStack python-*client libraries have the same
|
||||||
@@ -136,7 +140,8 @@ class CloudConfig(cloud_region.CloudRegion):
|
|||||||
interface = self.get_interface(service_key)
|
interface = self.get_interface(service_key)
|
||||||
# trigger exception on lack of service
|
# trigger exception on lack of service
|
||||||
endpoint = self.get_session_endpoint(
|
endpoint = self.get_session_endpoint(
|
||||||
service_key, min_version=min_version, max_version=max_version)
|
service_key, min_version=min_version, max_version=max_version
|
||||||
|
)
|
||||||
endpoint_override = self.get_endpoint(service_key)
|
endpoint_override = self.get_endpoint(service_key)
|
||||||
|
|
||||||
if service_key == 'object-store':
|
if service_key == 'object-store':
|
||||||
@@ -145,14 +150,17 @@ class CloudConfig(cloud_region.CloudRegion):
|
|||||||
os_options=dict(
|
os_options=dict(
|
||||||
service_type=self.get_service_type(service_key),
|
service_type=self.get_service_type(service_key),
|
||||||
object_storage_url=endpoint_override,
|
object_storage_url=endpoint_override,
|
||||||
region_name=self.region))
|
region_name=self.region,
|
||||||
|
),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
constructor_kwargs = dict(
|
constructor_kwargs = dict(
|
||||||
session=self.get_session(),
|
session=self.get_session(),
|
||||||
service_name=self.get_service_name(service_key),
|
service_name=self.get_service_name(service_key),
|
||||||
service_type=self.get_service_type(service_key),
|
service_type=self.get_service_type(service_key),
|
||||||
endpoint_override=endpoint_override,
|
endpoint_override=endpoint_override,
|
||||||
region_name=self.region)
|
region_name=self.region,
|
||||||
|
)
|
||||||
|
|
||||||
if service_key == 'image':
|
if service_key == 'image':
|
||||||
# os-client-config does not depend on glanceclient, but if
|
# os-client-config does not depend on glanceclient, but if
|
||||||
@@ -160,6 +168,7 @@ class CloudConfig(cloud_region.CloudRegion):
|
|||||||
# would need to do if they were requesting 'image' - then
|
# would need to do if they were requesting 'image' - then
|
||||||
# they necessarily have glanceclient installed
|
# they necessarily have glanceclient installed
|
||||||
from glanceclient.common import utils as glance_utils
|
from glanceclient.common import utils as glance_utils
|
||||||
|
|
||||||
endpoint, detected_version = glance_utils.strip_version(endpoint)
|
endpoint, detected_version = glance_utils.strip_version(endpoint)
|
||||||
# If the user has passed in a version, that's explicit, use it
|
# If the user has passed in a version, that's explicit, use it
|
||||||
if not version:
|
if not version:
|
||||||
@@ -176,6 +185,7 @@ class CloudConfig(cloud_region.CloudRegion):
|
|||||||
version = self.get_api_version(service_key)
|
version = self.get_api_version(service_key)
|
||||||
if not version and service_key == 'volume':
|
if not version and service_key == 'volume':
|
||||||
from cinderclient import client as cinder_client
|
from cinderclient import client as cinder_client
|
||||||
|
|
||||||
version = cinder_client.get_volume_api_from_url(endpoint)
|
version = cinder_client.get_volume_api_from_url(endpoint)
|
||||||
# Temporary workaround while we wait for python-openstackclient
|
# Temporary workaround while we wait for python-openstackclient
|
||||||
# to be able to handle 2.0 which is what neutronclient expects
|
# to be able to handle 2.0 which is what neutronclient expects
|
||||||
@@ -198,14 +208,16 @@ class CloudConfig(cloud_region.CloudRegion):
|
|||||||
constructor_kwargs['version'] = version
|
constructor_kwargs['version'] = version
|
||||||
if min_version and min_version > float(version):
|
if min_version and min_version > float(version):
|
||||||
raise exceptions.OpenStackConfigVersionException(
|
raise exceptions.OpenStackConfigVersionException(
|
||||||
"Minimum version {min_version} requested but {version}"
|
f"Minimum version {min_version} requested but {version}"
|
||||||
" found".format(min_version=min_version, version=version),
|
" found",
|
||||||
version=version)
|
version=version,
|
||||||
|
)
|
||||||
if max_version and max_version < float(version):
|
if max_version and max_version < float(version):
|
||||||
raise exceptions.OpenStackConfigVersionException(
|
raise exceptions.OpenStackConfigVersionException(
|
||||||
"Maximum version {max_version} requested but {version}"
|
f"Maximum version {max_version} requested but {version}"
|
||||||
" found".format(max_version=max_version, version=version),
|
" found",
|
||||||
version=version)
|
version=version,
|
||||||
|
)
|
||||||
if service_key == 'database':
|
if service_key == 'database':
|
||||||
# TODO(mordred) Remove when https://review.openstack.org/314032
|
# TODO(mordred) Remove when https://review.openstack.org/314032
|
||||||
# has landed and released. We're passing in a Session, but the
|
# has landed and released. We're passing in a Session, but the
|
||||||
@@ -217,8 +229,11 @@ class CloudConfig(cloud_region.CloudRegion):
|
|||||||
if not interface_key:
|
if not interface_key:
|
||||||
if service_key in ('image', 'key-manager'):
|
if service_key in ('image', 'key-manager'):
|
||||||
interface_key = 'interface'
|
interface_key = 'interface'
|
||||||
elif (service_key == 'identity'
|
elif (
|
||||||
and version and version.startswith('3')):
|
service_key == 'identity'
|
||||||
|
and version
|
||||||
|
and version.startswith('3')
|
||||||
|
):
|
||||||
interface_key = 'interface'
|
interface_key = 'interface'
|
||||||
else:
|
else:
|
||||||
interface_key = 'endpoint_type'
|
interface_key = 'endpoint_type'
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ from os_client_config import defaults
|
|||||||
|
|
||||||
|
|
||||||
class OpenStackConfig(loader.OpenStackConfig):
|
class OpenStackConfig(loader.OpenStackConfig):
|
||||||
|
|
||||||
_cloud_region_class = cloud_config.CloudConfig
|
_cloud_region_class = cloud_config.CloudConfig
|
||||||
_defaults_module = defaults
|
_defaults_module = defaults
|
||||||
|
|
||||||
@@ -59,10 +58,10 @@ if __name__ == '__main__':
|
|||||||
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
||||||
print_cloud = True
|
print_cloud = True
|
||||||
elif len(sys.argv) == 3 and (
|
elif len(sys.argv) == 3 and (
|
||||||
sys.argv[1] == cloud.name and sys.argv[2] == cloud.region):
|
sys.argv[1] == cloud.name and sys.argv[2] == cloud.region
|
||||||
|
):
|
||||||
print_cloud = True
|
print_cloud = True
|
||||||
elif len(sys.argv) == 2 and (
|
elif len(sys.argv) == 2 and (sys.argv[1] == cloud.name):
|
||||||
sys.argv[1] == cloud.name):
|
|
||||||
print_cloud = True
|
print_cloud = True
|
||||||
|
|
||||||
if print_cloud:
|
if print_cloud:
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import os
|
|||||||
import threading
|
import threading
|
||||||
|
|
||||||
_json_path = os.path.join(
|
_json_path = os.path.join(
|
||||||
os.path.dirname(os.path.realpath(__file__)), 'constructors.json')
|
os.path.dirname(os.path.realpath(__file__)), 'constructors.json'
|
||||||
|
)
|
||||||
_class_mapping = None
|
_class_mapping = None
|
||||||
_class_mapping_lock = threading.Lock()
|
_class_mapping_lock = threading.Lock()
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ def get_constructor_mapping():
|
|||||||
if _class_mapping is not None:
|
if _class_mapping is not None:
|
||||||
return _class_mapping.copy()
|
return _class_mapping.copy()
|
||||||
tmp_class_mapping = {}
|
tmp_class_mapping = {}
|
||||||
with open(_json_path, 'r') as json_file:
|
with open(_json_path) as json_file:
|
||||||
tmp_class_mapping.update(json.load(json_file))
|
tmp_class_mapping.update(json.load(json_file))
|
||||||
_class_mapping = tmp_class_mapping
|
_class_mapping = tmp_class_mapping
|
||||||
return tmp_class_mapping.copy()
|
return tmp_class_mapping.copy()
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import os
|
|||||||
from openstack.config import defaults
|
from openstack.config import defaults
|
||||||
|
|
||||||
_json_path = os.path.join(
|
_json_path = os.path.join(
|
||||||
os.path.dirname(os.path.realpath(__file__)), 'defaults.json')
|
os.path.dirname(os.path.realpath(__file__)), 'defaults.json'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_defaults():
|
def get_defaults():
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ class OpenStackConfigVersionException(OpenStackConfigException):
|
|||||||
"""A version was requested that is different than what was found."""
|
"""A version was requested that is different than what was found."""
|
||||||
|
|
||||||
def __init__(self, version):
|
def __init__(self, version):
|
||||||
super(OpenStackConfigVersionException, self).__init__()
|
super().__init__()
|
||||||
self.version = version
|
self.version = version
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Copyright 2010-2011 OpenStack Foundation
|
# Copyright 2010-2011 OpenStack Foundation
|
||||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||||
#
|
#
|
||||||
@@ -98,30 +96,37 @@ USER_CONF = {
|
|||||||
'domain_id': '6789',
|
'domain_id': '6789',
|
||||||
'project_domain_id': '123456789',
|
'project_domain_id': '123456789',
|
||||||
},
|
},
|
||||||
'networks': [{
|
'networks': [
|
||||||
'name': 'a-public',
|
{
|
||||||
'routes_externally': True,
|
'name': 'a-public',
|
||||||
'nat_source': True,
|
'routes_externally': True,
|
||||||
}, {
|
'nat_source': True,
|
||||||
'name': 'another-public',
|
},
|
||||||
'routes_externally': True,
|
{
|
||||||
'default_interface': True,
|
'name': 'another-public',
|
||||||
}, {
|
'routes_externally': True,
|
||||||
'name': 'a-private',
|
'default_interface': True,
|
||||||
'routes_externally': False,
|
},
|
||||||
}, {
|
{
|
||||||
'name': 'another-private',
|
'name': 'a-private',
|
||||||
'routes_externally': False,
|
'routes_externally': False,
|
||||||
'nat_destination': True,
|
},
|
||||||
}, {
|
{
|
||||||
'name': 'split-default',
|
'name': 'another-private',
|
||||||
'routes_externally': True,
|
'routes_externally': False,
|
||||||
'routes_ipv4_externally': False,
|
'nat_destination': True,
|
||||||
}, {
|
},
|
||||||
'name': 'split-no-default',
|
{
|
||||||
'routes_ipv6_externally': False,
|
'name': 'split-default',
|
||||||
'routes_ipv4_externally': True,
|
'routes_externally': True,
|
||||||
}],
|
'routes_ipv4_externally': False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'split-no-default',
|
||||||
|
'routes_ipv6_externally': False,
|
||||||
|
'routes_ipv4_externally': True,
|
||||||
|
},
|
||||||
|
],
|
||||||
'region_name': 'test-region',
|
'region_name': 'test-region',
|
||||||
},
|
},
|
||||||
'_test_cloud_regions': {
|
'_test_cloud_regions': {
|
||||||
@@ -136,14 +141,14 @@ USER_CONF = {
|
|||||||
'name': 'region1',
|
'name': 'region1',
|
||||||
'values': {
|
'values': {
|
||||||
'external_network': 'region1-network',
|
'external_network': 'region1-network',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'region2',
|
'name': 'region2',
|
||||||
'values': {
|
'values': {
|
||||||
'external_network': 'my-network',
|
'external_network': 'my-network',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'_test_cloud_hyphenated': {
|
'_test_cloud_hyphenated': {
|
||||||
@@ -202,7 +207,7 @@ class TestCase(base.BaseTestCase):
|
|||||||
"""Test case base class for all unit tests."""
|
"""Test case base class for all unit tests."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestCase, self).setUp()
|
super().setUp()
|
||||||
|
|
||||||
self.useFixture(fixtures.NestedTempfile())
|
self.useFixture(fixtures.NestedTempfile())
|
||||||
conf = copy.deepcopy(USER_CONF)
|
conf = copy.deepcopy(USER_CONF)
|
||||||
@@ -212,10 +217,12 @@ class TestCase(base.BaseTestCase):
|
|||||||
self.secure_yaml = _write_yaml(SECURE_CONF)
|
self.secure_yaml = _write_yaml(SECURE_CONF)
|
||||||
self.vendor_yaml = _write_yaml(VENDOR_CONF)
|
self.vendor_yaml = _write_yaml(VENDOR_CONF)
|
||||||
self.no_yaml = _write_yaml(NO_CONF)
|
self.no_yaml = _write_yaml(NO_CONF)
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
self.useFixture(
|
||||||
'os_client_config.__version__', '1.2.3'))
|
fixtures.MonkeyPatch('os_client_config.__version__', '1.2.3')
|
||||||
self.useFixture(fixtures.MonkeyPatch(
|
)
|
||||||
'openstack.version.__version__', '3.4.5'))
|
self.useFixture(
|
||||||
|
fixtures.MonkeyPatch('openstack.version.__version__', '3.4.5')
|
||||||
|
)
|
||||||
|
|
||||||
# Isolate the test runs from the environment
|
# Isolate the test runs from the environment
|
||||||
# Do this as two loops because you can't modify the dict in a loop
|
# Do this as two loops because you can't modify the dict in a loop
|
||||||
|
|||||||
@@ -34,15 +34,15 @@ fake_services_dict = {
|
|||||||
|
|
||||||
|
|
||||||
class TestCloudConfig(base.TestCase):
|
class TestCloudConfig(base.TestCase):
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_api_version')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_api_version')
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
def test_legacy_client_object_store_password(
|
def test_legacy_client_object_store_password(
|
||||||
self,
|
self,
|
||||||
mock_get_session_endpoint,
|
mock_get_session_endpoint,
|
||||||
mock_get_auth_args,
|
mock_get_auth_args,
|
||||||
mock_get_api_version):
|
mock_get_api_version,
|
||||||
|
):
|
||||||
mock_client = mock.Mock()
|
mock_client = mock.Mock()
|
||||||
mock_get_session_endpoint.return_value = 'http://swift.example.com'
|
mock_get_session_endpoint.return_value = 'http://swift.example.com'
|
||||||
mock_get_api_version.return_value = '3'
|
mock_get_api_version.return_value = '3'
|
||||||
@@ -55,7 +55,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
config_dict = defaults.get_defaults()
|
config_dict = defaults.get_defaults()
|
||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('object-store', mock_client)
|
cc.get_legacy_client('object-store', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
@@ -64,12 +65,14 @@ class TestCloudConfig(base.TestCase):
|
|||||||
'service_type': 'object-store',
|
'service_type': 'object-store',
|
||||||
'object_storage_url': None,
|
'object_storage_url': None,
|
||||||
'endpoint_type': 'public',
|
'endpoint_type': 'public',
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
def test_legacy_client_object_store_password_v2(
|
def test_legacy_client_object_store_password_v2(
|
||||||
self, mock_get_session_endpoint, mock_get_auth_args):
|
self, mock_get_session_endpoint, mock_get_auth_args
|
||||||
|
):
|
||||||
mock_client = mock.Mock()
|
mock_client = mock.Mock()
|
||||||
mock_get_session_endpoint.return_value = 'http://swift.example.com'
|
mock_get_session_endpoint.return_value = 'http://swift.example.com'
|
||||||
mock_get_auth_args.return_value = dict(
|
mock_get_auth_args.return_value = dict(
|
||||||
@@ -81,7 +84,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
config_dict = defaults.get_defaults()
|
config_dict = defaults.get_defaults()
|
||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('object-store', mock_client)
|
cc.get_legacy_client('object-store', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
@@ -90,19 +94,22 @@ class TestCloudConfig(base.TestCase):
|
|||||||
'service_type': 'object-store',
|
'service_type': 'object-store',
|
||||||
'object_storage_url': None,
|
'object_storage_url': None,
|
||||||
'endpoint_type': 'public',
|
'endpoint_type': 'public',
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
def test_legacy_client_object_store(
|
def test_legacy_client_object_store(
|
||||||
self, mock_get_session_endpoint, mock_get_auth_args):
|
self, mock_get_session_endpoint, mock_get_auth_args
|
||||||
|
):
|
||||||
mock_client = mock.Mock()
|
mock_client = mock.Mock()
|
||||||
mock_get_session_endpoint.return_value = 'http://example.com/v2'
|
mock_get_session_endpoint.return_value = 'http://example.com/v2'
|
||||||
mock_get_auth_args.return_value = {}
|
mock_get_auth_args.return_value = {}
|
||||||
config_dict = defaults.get_defaults()
|
config_dict = defaults.get_defaults()
|
||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('object-store', mock_client)
|
cc.get_legacy_client('object-store', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
@@ -111,12 +118,14 @@ class TestCloudConfig(base.TestCase):
|
|||||||
'service_type': 'object-store',
|
'service_type': 'object-store',
|
||||||
'object_storage_url': None,
|
'object_storage_url': None,
|
||||||
'endpoint_type': 'public',
|
'endpoint_type': 'public',
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
def test_legacy_client_object_store_timeout(
|
def test_legacy_client_object_store_timeout(
|
||||||
self, mock_get_session_endpoint, mock_get_auth_args):
|
self, mock_get_session_endpoint, mock_get_auth_args
|
||||||
|
):
|
||||||
mock_client = mock.Mock()
|
mock_client = mock.Mock()
|
||||||
mock_get_session_endpoint.return_value = 'http://example.com/v2'
|
mock_get_session_endpoint.return_value = 'http://example.com/v2'
|
||||||
mock_get_auth_args.return_value = {}
|
mock_get_auth_args.return_value = {}
|
||||||
@@ -124,8 +133,11 @@ class TestCloudConfig(base.TestCase):
|
|||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
config_dict['api_timeout'] = 9
|
config_dict['api_timeout'] = 9
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
name="test1", region_name="region-al", config=config_dict,
|
name="test1",
|
||||||
auth_plugin=mock.Mock())
|
region_name="region-al",
|
||||||
|
config=config_dict,
|
||||||
|
auth_plugin=mock.Mock(),
|
||||||
|
)
|
||||||
cc.get_legacy_client('object-store', mock_client)
|
cc.get_legacy_client('object-store', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
@@ -134,18 +146,19 @@ class TestCloudConfig(base.TestCase):
|
|||||||
'service_type': 'object-store',
|
'service_type': 'object-store',
|
||||||
'object_storage_url': None,
|
'object_storage_url': None,
|
||||||
'endpoint_type': 'public',
|
'endpoint_type': 'public',
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
||||||
def test_legacy_client_object_store_endpoint(
|
def test_legacy_client_object_store_endpoint(self, mock_get_auth_args):
|
||||||
self, mock_get_auth_args):
|
|
||||||
mock_client = mock.Mock()
|
mock_client = mock.Mock()
|
||||||
mock_get_auth_args.return_value = {}
|
mock_get_auth_args.return_value = {}
|
||||||
config_dict = defaults.get_defaults()
|
config_dict = defaults.get_defaults()
|
||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
config_dict['object_store_endpoint'] = 'http://example.com/swift'
|
config_dict['object_store_endpoint'] = 'http://example.com/swift'
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('object-store', mock_client)
|
cc.get_legacy_client('object-store', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
@@ -154,7 +167,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
'service_type': 'object-store',
|
'service_type': 'object-store',
|
||||||
'object_storage_url': 'http://example.com/swift',
|
'object_storage_url': 'http://example.com/swift',
|
||||||
'endpoint_type': 'public',
|
'endpoint_type': 'public',
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
def test_legacy_client_image(self, mock_get_session_endpoint):
|
def test_legacy_client_image(self, mock_get_session_endpoint):
|
||||||
@@ -163,7 +177,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
config_dict = defaults.get_defaults()
|
config_dict = defaults.get_defaults()
|
||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('image', mock_client)
|
cc.get_legacy_client('image', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
version=2.0,
|
version=2.0,
|
||||||
@@ -173,7 +188,7 @@ class TestCloudConfig(base.TestCase):
|
|||||||
interface='public',
|
interface='public',
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
# Not a typo - the config dict above overrides this
|
# Not a typo - the config dict above overrides this
|
||||||
service_type='mage'
|
service_type='mage',
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
@@ -184,7 +199,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
config_dict['image_endpoint_override'] = 'http://example.com/override'
|
config_dict['image_endpoint_override'] = 'http://example.com/override'
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('image', mock_client)
|
cc.get_legacy_client('image', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
version=2.0,
|
version=2.0,
|
||||||
@@ -194,7 +210,7 @@ class TestCloudConfig(base.TestCase):
|
|||||||
interface='public',
|
interface='public',
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
# Not a typo - the config dict above overrides this
|
# Not a typo - the config dict above overrides this
|
||||||
service_type='mage'
|
service_type='mage',
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
@@ -206,7 +222,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
# v2 endpoint was passed, 1 requested in config, endpoint wins
|
# v2 endpoint was passed, 1 requested in config, endpoint wins
|
||||||
config_dict['image_api_version'] = '1'
|
config_dict['image_api_version'] = '1'
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('image', mock_client)
|
cc.get_legacy_client('image', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
version=2.0,
|
version=2.0,
|
||||||
@@ -216,7 +233,7 @@ class TestCloudConfig(base.TestCase):
|
|||||||
interface='public',
|
interface='public',
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
# Not a typo - the config dict above overrides this
|
# Not a typo - the config dict above overrides this
|
||||||
service_type='mage'
|
service_type='mage',
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
@@ -228,7 +245,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
# Versionless endpoint, config wins
|
# Versionless endpoint, config wins
|
||||||
config_dict['image_api_version'] = '1'
|
config_dict['image_api_version'] = '1'
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('image', mock_client)
|
cc.get_legacy_client('image', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
version='1',
|
version='1',
|
||||||
@@ -238,7 +256,7 @@ class TestCloudConfig(base.TestCase):
|
|||||||
interface='public',
|
interface='public',
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
# Not a typo - the config dict above overrides this
|
# Not a typo - the config dict above overrides this
|
||||||
service_type='mage'
|
service_type='mage',
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
@@ -250,7 +268,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
# Versionless endpoint, config wins
|
# Versionless endpoint, config wins
|
||||||
config_dict['image_api_version'] = '6'
|
config_dict['image_api_version'] = '6'
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('image', mock_client, version='beef')
|
cc.get_legacy_client('image', mock_client, version='beef')
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
version='beef',
|
version='beef',
|
||||||
@@ -260,7 +279,7 @@ class TestCloudConfig(base.TestCase):
|
|||||||
interface='public',
|
interface='public',
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
# Not a typo - the config dict above overrides this
|
# Not a typo - the config dict above overrides this
|
||||||
service_type='mage'
|
service_type='mage',
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
@@ -270,7 +289,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
config_dict = defaults.get_defaults()
|
config_dict = defaults.get_defaults()
|
||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('network', mock_client)
|
cc.get_legacy_client('network', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
api_version='2.0',
|
api_version='2.0',
|
||||||
@@ -279,7 +299,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
region_name='region-al',
|
region_name='region-al',
|
||||||
service_type='network',
|
service_type='network',
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
service_name=None)
|
service_name=None,
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
def test_legacy_client_compute(self, mock_get_session_endpoint):
|
def test_legacy_client_compute(self, mock_get_session_endpoint):
|
||||||
@@ -288,7 +309,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
config_dict = defaults.get_defaults()
|
config_dict = defaults.get_defaults()
|
||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('compute', mock_client)
|
cc.get_legacy_client('compute', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
version='2',
|
version='2',
|
||||||
@@ -297,7 +319,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
region_name='region-al',
|
region_name='region-al',
|
||||||
service_type='compute',
|
service_type='compute',
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
service_name=None)
|
service_name=None,
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
def test_legacy_client_identity(self, mock_get_session_endpoint):
|
def test_legacy_client_identity(self, mock_get_session_endpoint):
|
||||||
@@ -306,7 +329,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
config_dict = defaults.get_defaults()
|
config_dict = defaults.get_defaults()
|
||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('identity', mock_client)
|
cc.get_legacy_client('identity', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
version='2.0',
|
version='2.0',
|
||||||
@@ -316,7 +340,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
region_name='region-al',
|
region_name='region-al',
|
||||||
service_type='identity',
|
service_type='identity',
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
service_name='locks')
|
service_name='locks',
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||||
def test_legacy_client_identity_v3(self, mock_get_session_endpoint):
|
def test_legacy_client_identity_v3(self, mock_get_session_endpoint):
|
||||||
@@ -326,7 +351,8 @@ class TestCloudConfig(base.TestCase):
|
|||||||
config_dict.update(fake_services_dict)
|
config_dict.update(fake_services_dict)
|
||||||
config_dict['identity_api_version'] = '3'
|
config_dict['identity_api_version'] = '3'
|
||||||
cc = cloud_config.CloudConfig(
|
cc = cloud_config.CloudConfig(
|
||||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||||
|
)
|
||||||
cc.get_legacy_client('identity', mock_client)
|
cc.get_legacy_client('identity', mock_client)
|
||||||
mock_client.assert_called_with(
|
mock_client.assert_called_with(
|
||||||
version='3',
|
version='3',
|
||||||
@@ -336,4 +362,5 @@ class TestCloudConfig(base.TestCase):
|
|||||||
region_name='region-al',
|
region_name='region-al',
|
||||||
service_type='identity',
|
service_type='identity',
|
||||||
session=mock.ANY,
|
session=mock.ANY,
|
||||||
service_name='locks')
|
service_name='locks',
|
||||||
|
)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -22,52 +22,66 @@ import fixtures
|
|||||||
|
|
||||||
|
|
||||||
class TestEnviron(base.TestCase):
|
class TestEnviron(base.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestEnviron, self).setUp()
|
super().setUp()
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('OS_AUTH_URL', 'https://example.com'))
|
fixtures.EnvironmentVariable('OS_AUTH_URL', 'https://example.com')
|
||||||
|
)
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('OS_USERNAME', 'testuser'))
|
fixtures.EnvironmentVariable('OS_USERNAME', 'testuser')
|
||||||
|
)
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('OS_PASSWORD', 'testpass'))
|
fixtures.EnvironmentVariable('OS_PASSWORD', 'testpass')
|
||||||
|
)
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('OS_PROJECT_NAME', 'testproject'))
|
fixtures.EnvironmentVariable('OS_PROJECT_NAME', 'testproject')
|
||||||
|
)
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('NOVA_PROJECT_ID', 'testnova'))
|
fixtures.EnvironmentVariable('NOVA_PROJECT_ID', 'testnova')
|
||||||
|
)
|
||||||
|
|
||||||
def test_get_one_cloud(self):
|
def test_get_one_cloud(self):
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
c = config.OpenStackConfig(
|
||||||
vendor_files=[self.vendor_yaml])
|
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||||
|
)
|
||||||
self.assertIsInstance(c.get_one_cloud(), cloud_config.CloudConfig)
|
self.assertIsInstance(c.get_one_cloud(), cloud_config.CloudConfig)
|
||||||
|
|
||||||
def test_no_fallthrough(self):
|
def test_no_fallthrough(self):
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
c = config.OpenStackConfig(
|
||||||
vendor_files=[self.vendor_yaml])
|
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||||
|
)
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exceptions.OpenStackConfigException, c.get_one_cloud, 'openstack')
|
exceptions.OpenStackConfigException, c.get_one_cloud, 'openstack'
|
||||||
|
)
|
||||||
|
|
||||||
def test_envvar_name_override(self):
|
def test_envvar_name_override(self):
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('OS_CLOUD_NAME', 'override'))
|
fixtures.EnvironmentVariable('OS_CLOUD_NAME', 'override')
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
)
|
||||||
vendor_files=[self.vendor_yaml])
|
c = config.OpenStackConfig(
|
||||||
|
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||||
|
)
|
||||||
cc = c.get_one_cloud('override')
|
cc = c.get_one_cloud('override')
|
||||||
self._assert_cloud_details(cc)
|
self._assert_cloud_details(cc)
|
||||||
|
|
||||||
def test_envvar_prefer_ipv6_override(self):
|
def test_envvar_prefer_ipv6_override(self):
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('OS_PREFER_IPV6', 'false'))
|
fixtures.EnvironmentVariable('OS_PREFER_IPV6', 'false')
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
)
|
||||||
vendor_files=[self.vendor_yaml],
|
c = config.OpenStackConfig(
|
||||||
secure_files=[self.secure_yaml])
|
config_files=[self.cloud_yaml],
|
||||||
|
vendor_files=[self.vendor_yaml],
|
||||||
|
secure_files=[self.secure_yaml],
|
||||||
|
)
|
||||||
cc = c.get_one_cloud('_test-cloud_')
|
cc = c.get_one_cloud('_test-cloud_')
|
||||||
self.assertFalse(cc.prefer_ipv6)
|
self.assertFalse(cc.prefer_ipv6)
|
||||||
|
|
||||||
def test_environ_exists(self):
|
def test_environ_exists(self):
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
c = config.OpenStackConfig(
|
||||||
vendor_files=[self.vendor_yaml],
|
config_files=[self.cloud_yaml],
|
||||||
secure_files=[self.secure_yaml])
|
vendor_files=[self.vendor_yaml],
|
||||||
|
secure_files=[self.secure_yaml],
|
||||||
|
)
|
||||||
cc = c.get_one_cloud('envvars')
|
cc = c.get_one_cloud('envvars')
|
||||||
self._assert_cloud_details(cc)
|
self._assert_cloud_details(cc)
|
||||||
self.assertNotIn('auth_url', cc.config)
|
self.assertNotIn('auth_url', cc.config)
|
||||||
@@ -80,10 +94,12 @@ class TestEnviron(base.TestCase):
|
|||||||
self._assert_cloud_details(cc)
|
self._assert_cloud_details(cc)
|
||||||
|
|
||||||
def test_environ_prefix(self):
|
def test_environ_prefix(self):
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
c = config.OpenStackConfig(
|
||||||
vendor_files=[self.vendor_yaml],
|
config_files=[self.cloud_yaml],
|
||||||
envvar_prefix='NOVA_',
|
vendor_files=[self.vendor_yaml],
|
||||||
secure_files=[self.secure_yaml])
|
envvar_prefix='NOVA_',
|
||||||
|
secure_files=[self.secure_yaml],
|
||||||
|
)
|
||||||
cc = c.get_one_cloud('envvars')
|
cc = c.get_one_cloud('envvars')
|
||||||
self._assert_cloud_details(cc)
|
self._assert_cloud_details(cc)
|
||||||
self.assertNotIn('auth_url', cc.config)
|
self.assertNotIn('auth_url', cc.config)
|
||||||
@@ -96,9 +112,11 @@ class TestEnviron(base.TestCase):
|
|||||||
self._assert_cloud_details(cc)
|
self._assert_cloud_details(cc)
|
||||||
|
|
||||||
def test_get_one_cloud_with_config_files(self):
|
def test_get_one_cloud_with_config_files(self):
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
c = config.OpenStackConfig(
|
||||||
vendor_files=[self.vendor_yaml],
|
config_files=[self.cloud_yaml],
|
||||||
secure_files=[self.secure_yaml])
|
vendor_files=[self.vendor_yaml],
|
||||||
|
secure_files=[self.secure_yaml],
|
||||||
|
)
|
||||||
self.assertIsInstance(c.cloud_config, dict)
|
self.assertIsInstance(c.cloud_config, dict)
|
||||||
self.assertIn('cache', c.cloud_config)
|
self.assertIn('cache', c.cloud_config)
|
||||||
self.assertIsInstance(c.cloud_config['cache'], dict)
|
self.assertIsInstance(c.cloud_config['cache'], dict)
|
||||||
@@ -112,40 +130,44 @@ class TestEnviron(base.TestCase):
|
|||||||
def test_config_file_override(self):
|
def test_config_file_override(self):
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable(
|
fixtures.EnvironmentVariable(
|
||||||
'OS_CLIENT_CONFIG_FILE', self.cloud_yaml))
|
'OS_CLIENT_CONFIG_FILE', self.cloud_yaml
|
||||||
c = config.OpenStackConfig(config_files=[],
|
)
|
||||||
vendor_files=[self.vendor_yaml])
|
)
|
||||||
|
c = config.OpenStackConfig(
|
||||||
|
config_files=[], vendor_files=[self.vendor_yaml]
|
||||||
|
)
|
||||||
cc = c.get_one_cloud('_test-cloud_')
|
cc = c.get_one_cloud('_test-cloud_')
|
||||||
self._assert_cloud_details(cc)
|
self._assert_cloud_details(cc)
|
||||||
|
|
||||||
|
|
||||||
class TestEnvvars(base.TestCase):
|
class TestEnvvars(base.TestCase):
|
||||||
|
|
||||||
def test_no_envvars(self):
|
def test_no_envvars(self):
|
||||||
self.useFixture(
|
self.useFixture(fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||||
fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
c = config.OpenStackConfig(
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||||
vendor_files=[self.vendor_yaml])
|
)
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exceptions.OpenStackConfigException, c.get_one_cloud, 'envvars')
|
exceptions.OpenStackConfigException, c.get_one_cloud, 'envvars'
|
||||||
|
)
|
||||||
|
|
||||||
def test_test_envvars(self):
|
def test_test_envvars(self):
|
||||||
|
self.useFixture(fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
fixtures.EnvironmentVariable('OS_STDERR_CAPTURE', 'True')
|
||||||
self.useFixture(
|
)
|
||||||
fixtures.EnvironmentVariable('OS_STDERR_CAPTURE', 'True'))
|
c = config.OpenStackConfig(
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||||
vendor_files=[self.vendor_yaml])
|
)
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exceptions.OpenStackConfigException, c.get_one_cloud, 'envvars')
|
exceptions.OpenStackConfigException, c.get_one_cloud, 'envvars'
|
||||||
|
)
|
||||||
|
|
||||||
def test_incomplete_envvars(self):
|
def test_incomplete_envvars(self):
|
||||||
self.useFixture(
|
self.useFixture(fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||||
fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'user'))
|
||||||
self.useFixture(
|
config.OpenStackConfig(
|
||||||
fixtures.EnvironmentVariable('OS_USERNAME', 'user'))
|
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||||
config.OpenStackConfig(config_files=[self.cloud_yaml],
|
)
|
||||||
vendor_files=[self.vendor_yaml])
|
|
||||||
# This is broken due to an issue that's fixed in a subsequent patch
|
# This is broken due to an issue that's fixed in a subsequent patch
|
||||||
# commenting it out in this patch to keep the patch size reasonable
|
# commenting it out in this patch to keep the patch size reasonable
|
||||||
# self.assertRaises(
|
# self.assertRaises(
|
||||||
@@ -153,33 +175,38 @@ class TestEnvvars(base.TestCase):
|
|||||||
# c.get_one_cloud, 'envvars')
|
# c.get_one_cloud, 'envvars')
|
||||||
|
|
||||||
def test_have_envvars(self):
|
def test_have_envvars(self):
|
||||||
|
self.useFixture(fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
fixtures.EnvironmentVariable('OS_AUTH_URL', 'http://example.com')
|
||||||
|
)
|
||||||
|
self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'user'))
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('OS_AUTH_URL', 'http://example.com'))
|
fixtures.EnvironmentVariable('OS_PASSWORD', 'password')
|
||||||
|
)
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('OS_USERNAME', 'user'))
|
fixtures.EnvironmentVariable('OS_PROJECT_NAME', 'project')
|
||||||
self.useFixture(
|
)
|
||||||
fixtures.EnvironmentVariable('OS_PASSWORD', 'password'))
|
c = config.OpenStackConfig(
|
||||||
self.useFixture(
|
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||||
fixtures.EnvironmentVariable('OS_PROJECT_NAME', 'project'))
|
)
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
|
||||||
vendor_files=[self.vendor_yaml])
|
|
||||||
cc = c.get_one_cloud('envvars')
|
cc = c.get_one_cloud('envvars')
|
||||||
self.assertEqual(cc.config['auth']['username'], 'user')
|
self.assertEqual(cc.config['auth']['username'], 'user')
|
||||||
|
|
||||||
def test_old_envvars(self):
|
def test_old_envvars(self):
|
||||||
|
self.useFixture(fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
fixtures.EnvironmentVariable('NOVA_AUTH_URL', 'http://example.com')
|
||||||
|
)
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable(
|
fixtures.EnvironmentVariable('NOVA_PASSWORD', 'password')
|
||||||
'NOVA_AUTH_URL', 'http://example.com'))
|
)
|
||||||
self.useFixture(
|
self.useFixture(
|
||||||
fixtures.EnvironmentVariable('NOVA_PASSWORD', 'password'))
|
fixtures.EnvironmentVariable('NOVA_PROJECT_NAME', 'project')
|
||||||
self.useFixture(
|
)
|
||||||
fixtures.EnvironmentVariable('NOVA_PROJECT_NAME', 'project'))
|
c = config.OpenStackConfig(
|
||||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
config_files=[self.cloud_yaml],
|
||||||
vendor_files=[self.vendor_yaml],
|
vendor_files=[self.vendor_yaml],
|
||||||
envvar_prefix='NOVA_')
|
envvar_prefix='NOVA_',
|
||||||
|
)
|
||||||
cc = c.get_one_cloud('envvars')
|
cc = c.get_one_cloud('envvars')
|
||||||
self.assertEqual(cc.config['auth']['username'], 'nova')
|
self.assertEqual(cc.config['auth']['username'], 'nova')
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from os_client_config.tests import base
|
|||||||
|
|
||||||
|
|
||||||
class TestImportVendors(base.TestCase):
|
class TestImportVendors(base.TestCase):
|
||||||
|
|
||||||
def test_get_profile(self):
|
def test_get_profile(self):
|
||||||
import os_client_config # noqa
|
import os_client_config # noqa
|
||||||
|
|
||||||
os_client_config.vendors.get_profile(profile_name="dummy")
|
os_client_config.vendors.get_profile(profile_name="dummy")
|
||||||
|
|||||||
@@ -19,17 +19,16 @@ from os_client_config.tests import base
|
|||||||
class TestInit(base.TestCase):
|
class TestInit(base.TestCase):
|
||||||
def test_get_config_without_arg_parser(self):
|
def test_get_config_without_arg_parser(self):
|
||||||
cloud_config = os_client_config.get_config(
|
cloud_config = os_client_config.get_config(
|
||||||
options=None, validate=False)
|
options=None, validate=False
|
||||||
|
)
|
||||||
self.assertIsInstance(
|
self.assertIsInstance(
|
||||||
cloud_config,
|
cloud_config, os_client_config.cloud_config.CloudConfig
|
||||||
os_client_config.cloud_config.CloudConfig
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_get_config_with_arg_parser(self):
|
def test_get_config_with_arg_parser(self):
|
||||||
cloud_config = os_client_config.get_config(
|
cloud_config = os_client_config.get_config(
|
||||||
options=argparse.ArgumentParser(),
|
options=argparse.ArgumentParser(), validate=False
|
||||||
validate=False)
|
)
|
||||||
self.assertIsInstance(
|
self.assertIsInstance(
|
||||||
cloud_config,
|
cloud_config, os_client_config.cloud_config.CloudConfig
|
||||||
os_client_config.cloud_config.CloudConfig
|
|
||||||
)
|
)
|
||||||
|
|||||||
14
pyproject.toml
Normal file
14
pyproject.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[tool.ruff]
|
||||||
|
line-length = 79
|
||||||
|
target-version = "py310"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
quote-style = "preserve"
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ["E4", "E7", "E9", "F", "S", "U"]
|
||||||
|
|
||||||
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"os_client_config/tests/*" = ["S"]
|
||||||
|
"tools/*" = ["S"]
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# Os-Client-Config Release Notes documentation build configuration file, created by
|
# Os-Client-Config Release Notes documentation build configuration file, created by
|
||||||
# sphinx-quickstart on Thu Nov 5 11:50:32 2015.
|
# sphinx-quickstart on Thu Nov 5 11:50:32 2015.
|
||||||
@@ -15,20 +14,17 @@
|
|||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
#sys.path.insert(0, os.path.abspath('.'))
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
# -- General configuration ------------------------------------------------
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
# 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
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = ['reno.sphinxext', 'openstackdocstheme']
|
||||||
'reno.sphinxext',
|
|
||||||
'openstackdocstheme'
|
|
||||||
]
|
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
@@ -37,14 +33,14 @@ templates_path = ['_templates']
|
|||||||
source_suffix = '.rst'
|
source_suffix = '.rst'
|
||||||
|
|
||||||
# The encoding of source files.
|
# The encoding of source files.
|
||||||
#source_encoding = 'utf-8-sig'
|
# source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'os-client-config Release Notes'
|
project = 'os-client-config Release Notes'
|
||||||
copyright = u'2015, os-client-config developers'
|
copyright = '2015, os-client-config developers'
|
||||||
|
|
||||||
# openstackdocstheme options
|
# openstackdocstheme options
|
||||||
openstackdocs_repo_name = 'openstack/os-client-config'
|
openstackdocs_repo_name = 'openstack/os-client-config'
|
||||||
@@ -60,13 +56,13 @@ release = ''
|
|||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
#language = None
|
# language = None
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to some
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
# non-false value, then it is used:
|
# non-false value, then it is used:
|
||||||
#today = ''
|
# today = ''
|
||||||
# Else, today_fmt is used as the format for a strftime call.
|
# 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
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
@@ -74,27 +70,27 @@ exclude_patterns = []
|
|||||||
|
|
||||||
# The reST default role (used for this markup: `text`) to use for all
|
# The reST default role (used for this markup: `text`) to use for all
|
||||||
# documents.
|
# documents.
|
||||||
#default_role = None
|
# default_role = None
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
# 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
|
# If true, the current module name will be prepended to all description
|
||||||
# unit titles (such as .. function::).
|
# unit titles (such as .. function::).
|
||||||
#add_module_names = True
|
# add_module_names = True
|
||||||
|
|
||||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
# output. They are ignored by default.
|
# output. They are ignored by default.
|
||||||
#show_authors = False
|
# show_authors = False
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
pygments_style = 'native'
|
pygments_style = 'native'
|
||||||
|
|
||||||
# A list of ignored prefixes for module index sorting.
|
# A list of ignored prefixes for module index sorting.
|
||||||
#modindex_common_prefix = []
|
# modindex_common_prefix = []
|
||||||
|
|
||||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||||
#keep_warnings = False
|
# keep_warnings = False
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output ----------------------------------------------
|
# -- Options for HTML output ----------------------------------------------
|
||||||
@@ -106,23 +102,23 @@ html_theme = 'openstackdocs'
|
|||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# 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
|
# further. For a list of options available for each theme, see the
|
||||||
# documentation.
|
# documentation.
|
||||||
#html_theme_options = {}
|
# html_theme_options = {}
|
||||||
|
|
||||||
# The name for this set of Sphinx documents. If None, it defaults to
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
# "<project> v<release> documentation".
|
# "<project> v<release> documentation".
|
||||||
#html_title = None
|
# html_title = None
|
||||||
|
|
||||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
# 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
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
# of the sidebar.
|
# 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
|
# 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
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
# pixels large.
|
# pixels large.
|
||||||
#html_favicon = None
|
# html_favicon = None
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# 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,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
@@ -132,48 +128,48 @@ html_static_path = ['_static']
|
|||||||
# Add any extra paths that contain custom files (such as robots.txt or
|
# Add any extra paths that contain custom files (such as robots.txt or
|
||||||
# .htaccess) here, relative to this directory. These files are copied
|
# .htaccess) here, relative to this directory. These files are copied
|
||||||
# directly to the root of the documentation.
|
# directly to the root of the documentation.
|
||||||
#html_extra_path = []
|
# html_extra_path = []
|
||||||
|
|
||||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
# using the given strftime format.
|
# 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
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
# typographically correct entities.
|
# typographically correct entities.
|
||||||
#html_use_smartypants = True
|
# html_use_smartypants = True
|
||||||
|
|
||||||
# Custom sidebar templates, maps document names to template names.
|
# 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
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
# template names.
|
# template names.
|
||||||
#html_additional_pages = {}
|
# html_additional_pages = {}
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#html_domain_indices = True
|
# html_domain_indices = True
|
||||||
|
|
||||||
# If false, no index is generated.
|
# 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.
|
# 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.
|
# 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.
|
# 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.
|
# 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
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
# contain a <link> tag referring to it. The value of this option must be the
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
# base URL from which the finished HTML is served.
|
# 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").
|
# 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.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = 'OCCReleaseNotesdoc'
|
htmlhelp_basename = 'OCCReleaseNotesdoc'
|
||||||
@@ -182,43 +178,46 @@ htmlhelp_basename = 'OCCReleaseNotesdoc'
|
|||||||
# -- Options for LaTeX output ---------------------------------------------
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
#'papersize': 'letterpaper',
|
#'papersize': 'letterpaper',
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
#'pointsize': '10pt',
|
||||||
#'pointsize': '10pt',
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#'preamble': '',
|
||||||
# Additional stuff for the LaTeX preamble.
|
|
||||||
#'preamble': '',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title,
|
# (source start file, target name, title,
|
||||||
# author, documentclass [howto, manual, or own class]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('index', 'OCCReleaseNotes.tex', u'os-client-config Release Notes Documentation',
|
(
|
||||||
u'os-client-config developers', 'manual'),
|
'index',
|
||||||
|
'OCCReleaseNotes.tex',
|
||||||
|
'os-client-config Release Notes Documentation',
|
||||||
|
'os-client-config developers',
|
||||||
|
'manual',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
# the title page.
|
# the title page.
|
||||||
#latex_logo = None
|
# latex_logo = None
|
||||||
|
|
||||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
# not chapters.
|
# not chapters.
|
||||||
#latex_use_parts = False
|
# latex_use_parts = False
|
||||||
|
|
||||||
# If true, show page references after internal links.
|
# If true, show page references after internal links.
|
||||||
#latex_show_pagerefs = False
|
# latex_show_pagerefs = False
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# 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.
|
# Documents to append as an appendix to all manuals.
|
||||||
#latex_appendices = []
|
# latex_appendices = []
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#latex_domain_indices = True
|
# latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output ---------------------------------------
|
# -- Options for manual page output ---------------------------------------
|
||||||
@@ -226,12 +225,17 @@ latex_documents = [
|
|||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [
|
||||||
('index', 'occreleasenotes', u'os-client-config Release Notes Documentation',
|
(
|
||||||
[u'os-client-config developers'], 1)
|
'index',
|
||||||
|
'occreleasenotes',
|
||||||
|
'os-client-config Release Notes Documentation',
|
||||||
|
['os-client-config developers'],
|
||||||
|
1,
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
#man_show_urls = False
|
# man_show_urls = False
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output -------------------------------------------
|
# -- Options for Texinfo output -------------------------------------------
|
||||||
@@ -240,23 +244,28 @@ man_pages = [
|
|||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('index', 'OCCReleaseNotes', u'os-client-config Release Notes Documentation',
|
(
|
||||||
u'os-client-config developers', 'OCCReleaseNotes',
|
'index',
|
||||||
'One line description of project.',
|
'OCCReleaseNotes',
|
||||||
'Miscellaneous'),
|
'os-client-config Release Notes Documentation',
|
||||||
|
'os-client-config developers',
|
||||||
|
'OCCReleaseNotes',
|
||||||
|
'One line description of project.',
|
||||||
|
'Miscellaneous',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
# Documents to append as an appendix to all manuals.
|
||||||
#texinfo_appendices = []
|
# texinfo_appendices = []
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#texinfo_domain_indices = True
|
# texinfo_domain_indices = True
|
||||||
|
|
||||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||||
#texinfo_show_urls = 'footnote'
|
# texinfo_show_urls = 'footnote'
|
||||||
|
|
||||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||||
#texinfo_no_detailmenu = False
|
# texinfo_no_detailmenu = False
|
||||||
|
|
||||||
# -- Options for Internationalization output ------------------------------
|
# -- Options for Internationalization output ------------------------------
|
||||||
locale_dirs = ['locale/']
|
locale_dirs = ['locale/']
|
||||||
|
|||||||
4
setup.py
4
setup.py
@@ -15,6 +15,4 @@
|
|||||||
|
|
||||||
import setuptools
|
import setuptools
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(setup_requires=['pbr>=2.0.0'], pbr=True)
|
||||||
setup_requires=['pbr>=2.0.0'],
|
|
||||||
pbr=True)
|
|
||||||
|
|||||||
@@ -35,8 +35,9 @@ def print_version(version):
|
|||||||
if version['status'] in ('CURRENT', 'stable'):
|
if version['status'] in ('CURRENT', 'stable'):
|
||||||
print(
|
print(
|
||||||
"\tVersion ID: {id} updated {updated}".format(
|
"\tVersion ID: {id} updated {updated}".format(
|
||||||
id=version.get('id'),
|
id=version.get('id'), updated=version.get('updated')
|
||||||
updated=version.get('updated')))
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
verbose = '-v' in sys.argv
|
verbose = '-v' in sys.argv
|
||||||
@@ -55,7 +56,7 @@ for cloud in os_client_config.OpenStackConfig().get_all_clouds():
|
|||||||
if verbose:
|
if verbose:
|
||||||
pprint.pprint(r)
|
pprint.pprint(r)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Error with {cloud}: {e}".format(cloud=cloud.name, e=str(e)))
|
print(f"Error with {cloud.name}: {str(e)}")
|
||||||
continue
|
continue
|
||||||
if 'version' in r:
|
if 'version' in r:
|
||||||
print_version(r['version'])
|
print_version(r['version'])
|
||||||
@@ -68,10 +69,11 @@ for cloud in os_client_config.OpenStackConfig().get_all_clouds():
|
|||||||
port = None
|
port = None
|
||||||
stripped = path.rsplit('/', 2)[0]
|
stripped = path.rsplit('/', 2)[0]
|
||||||
if port:
|
if port:
|
||||||
stripped = '{stripped}:{port}'.format(stripped=stripped, port=port)
|
stripped = f'{stripped}:{port}'
|
||||||
endpoint = urllib.parse.urlunsplit(
|
endpoint = urllib.parse.urlunsplit(
|
||||||
(url.scheme, url.netloc, stripped, url.params, url.query))
|
(url.scheme, url.netloc, stripped, url.params, url.query)
|
||||||
print(" also {endpoint}".format(endpoint=endpoint))
|
)
|
||||||
|
print(f" also {endpoint}")
|
||||||
try:
|
try:
|
||||||
r = c.get(endpoint).json()
|
r = c.get(endpoint).json()
|
||||||
if verbose:
|
if verbose:
|
||||||
@@ -84,6 +86,6 @@ for cloud in os_client_config.OpenStackConfig().get_all_clouds():
|
|||||||
elif 'versions' in r:
|
elif 'versions' in r:
|
||||||
print_versions(r['versions'])
|
print_versions(r['versions'])
|
||||||
else:
|
else:
|
||||||
print("\n\nUNKNOWN\n\n{r}".format(r=r))
|
print(f"\n\nUNKNOWN\n\n{r}")
|
||||||
else:
|
else:
|
||||||
print_versions(r['versions'])
|
print_versions(r['versions'])
|
||||||
|
|||||||
@@ -28,29 +28,34 @@ for cloud in os_client_config.OpenStackConfig().get_all_clouds():
|
|||||||
print(endpoint)
|
print(endpoint)
|
||||||
r = c.get(endpoint).json()
|
r = c.get(endpoint).json()
|
||||||
except Exception:
|
except Exception:
|
||||||
print("Error with %s" % cloud.name)
|
print(f"Error with {cloud.name}")
|
||||||
continue
|
continue
|
||||||
for version in r['versions']:
|
for version in r['versions']:
|
||||||
if version['status'] == 'CURRENT':
|
if version['status'] == 'CURRENT':
|
||||||
have_current = True
|
have_current = True
|
||||||
print(
|
print(
|
||||||
"\tVersion ID: {id} updated {updated}".format(
|
"\tVersion ID: {id} updated {updated}".format(
|
||||||
id=version.get('id'),
|
id=version.get('id'), updated=version.get('updated')
|
||||||
updated=version.get('updated')))
|
)
|
||||||
|
)
|
||||||
|
print("\tVersion Max: {max}".format(max=version.get('version')))
|
||||||
print(
|
print(
|
||||||
"\tVersion Max: {max}".format(max=version.get('version')))
|
"\tVersion Min: {min}".format(min=version.get('min_version'))
|
||||||
print(
|
)
|
||||||
"\tVersion Min: {min}".format(min=version.get('min_version')))
|
|
||||||
if not have_current:
|
if not have_current:
|
||||||
for version in r['versions']:
|
for version in r['versions']:
|
||||||
if version['status'] == 'SUPPORTED':
|
if version['status'] == 'SUPPORTED':
|
||||||
have_current = True
|
have_current = True
|
||||||
print(
|
print(
|
||||||
"\tVersion ID: {id} updated {updated}".format(
|
"\tVersion ID: {id} updated {updated}".format(
|
||||||
id=version.get('id'),
|
id=version.get('id'), updated=version.get('updated')
|
||||||
updated=version.get('updated')))
|
)
|
||||||
|
)
|
||||||
print(
|
print(
|
||||||
"\tVersion Max: {max}".format(max=version.get('version')))
|
"\tVersion Max: {max}".format(max=version.get('version'))
|
||||||
|
)
|
||||||
print(
|
print(
|
||||||
"\tVersion Min: {min}".format(
|
"\tVersion Min: {min}".format(
|
||||||
min=version.get('min_version')))
|
min=version.get('min_version')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|||||||
20
tox.ini
20
tox.ini
@@ -22,17 +22,13 @@ commands =
|
|||||||
stestr slowest
|
stestr slowest
|
||||||
|
|
||||||
[testenv:pep8]
|
[testenv:pep8]
|
||||||
usedevelop = false
|
description =
|
||||||
|
Run style checks.
|
||||||
skip_install = true
|
skip_install = true
|
||||||
deps =
|
deps =
|
||||||
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
|
pre-commit
|
||||||
doc8
|
|
||||||
hacking
|
|
||||||
pygments
|
|
||||||
readme
|
|
||||||
commands =
|
commands =
|
||||||
doc8 doc/source
|
pre-commit run --all-files --show-diff-on-failure
|
||||||
flake8 os_client_config
|
|
||||||
|
|
||||||
[testenv:venv]
|
[testenv:venv]
|
||||||
commands = {posargs}
|
commands = {posargs}
|
||||||
@@ -54,7 +50,7 @@ deps =
|
|||||||
-r{toxinidir}/requirements.txt
|
-r{toxinidir}/requirements.txt
|
||||||
-r{toxinidir}/doc/requirements.txt
|
-r{toxinidir}/doc/requirements.txt
|
||||||
commands =
|
commands =
|
||||||
sphinx-build -W -d doc/build/doctrees -b html doc/source/ doc/build/html
|
sphinx-build -W -d doc/build/doctrees -b html doc/source/ doc/build/html
|
||||||
|
|
||||||
[testenv:releasenotes]
|
[testenv:releasenotes]
|
||||||
skip_install = true
|
skip_install = true
|
||||||
@@ -65,6 +61,12 @@ commands =
|
|||||||
sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
|
sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
|
# We only enable the hacking (H) checks
|
||||||
|
select = H
|
||||||
|
# H301 Black will put commas after imports that can't fit on one line
|
||||||
|
# H404 Docstrings don't always start with a newline
|
||||||
|
# H405 Multiline docstrings are okay
|
||||||
|
ignore = H301,H403,H404,H405
|
||||||
show-source = True
|
show-source = True
|
||||||
builtins = _
|
builtins = _
|
||||||
exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,releasenotes/source/conf.py
|
exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,releasenotes/source/conf.py
|
||||||
|
|||||||
Reference in New Issue
Block a user