Skip to content

Commit f43c1f7

Browse files
author
Dean Troyer
committed
Defer client imports
So we really weren't deferring the loading of client libs dadgummit, do that for real where possible. This shaves a couple of tenths off the static import times. Also defer as much import-time procesing as possible. This is a little ugly in api.auth but this also eliminates import of the auth plugins until they are needed. Change-Id: Ia11d4b9cf98231d37449103fc29101dc17afb009
1 parent e60bf28 commit f43c1f7

5 files changed

Lines changed: 73 additions & 39 deletions

File tree

‎openstackclient/api/auth.py‎

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,37 +27,57 @@
2727

2828
LOG = logging.getLogger(__name__)
2929

30-
3130
# Initialize the list of Authentication plugins early in order
3231
# to get the command-line options
33-
PLUGIN_LIST = stevedore.ExtensionManager(
34-
base.PLUGIN_NAMESPACE,
35-
invoke_on_load=False,
36-
propagate_map_exceptions=True,
37-
)
32+
PLUGIN_LIST = None
3833

39-
# Get the command line options so the help action has them available
34+
# List of plugin command line options
4035
OPTIONS_LIST = {}
41-
for plugin in PLUGIN_LIST:
42-
for o in plugin.plugin.get_options():
43-
os_name = o.dest.lower().replace('_', '-')
44-
os_env_name = 'OS_' + os_name.upper().replace('-', '_')
45-
OPTIONS_LIST.setdefault(os_name, {'env': os_env_name, 'help': ''})
46-
# TODO(mhu) simplistic approach, would be better to only add
47-
# help texts if they vary from one auth plugin to another
48-
# also the text rendering is ugly in the CLI ...
49-
OPTIONS_LIST[os_name]['help'] += 'With %s: %s\n' % (
50-
plugin.name,
51-
o.help,
36+
37+
38+
def get_plugin_list():
39+
"""Gather plugin list and cache it"""
40+
41+
global PLUGIN_LIST
42+
43+
if PLUGIN_LIST is None:
44+
PLUGIN_LIST = stevedore.ExtensionManager(
45+
base.PLUGIN_NAMESPACE,
46+
invoke_on_load=False,
47+
propagate_map_exceptions=True,
5248
)
49+
return PLUGIN_LIST
50+
51+
52+
def get_options_list():
53+
"""Gather plugin options so the help action has them available"""
54+
55+
global OPTIONS_LIST
56+
57+
if not OPTIONS_LIST:
58+
for plugin in get_plugin_list():
59+
for o in plugin.plugin.get_options():
60+
os_name = o.dest.lower().replace('_', '-')
61+
os_env_name = 'OS_' + os_name.upper().replace('-', '_')
62+
OPTIONS_LIST.setdefault(
63+
os_name, {'env': os_env_name, 'help': ''},
64+
)
65+
# TODO(mhu) simplistic approach, would be better to only add
66+
# help texts if they vary from one auth plugin to another
67+
# also the text rendering is ugly in the CLI ...
68+
OPTIONS_LIST[os_name]['help'] += 'With %s: %s\n' % (
69+
plugin.name,
70+
o.help,
71+
)
72+
return OPTIONS_LIST
5373

5474

5575
def select_auth_plugin(options):
5676
"""Pick an auth plugin based on --os-auth-type or other options"""
5777

5878
auth_plugin_name = None
5979

60-
if options.os_auth_type in [plugin.name for plugin in PLUGIN_LIST]:
80+
if options.os_auth_type in [plugin.name for plugin in get_plugin_list()]:
6181
# A direct plugin name was given, use it
6282
return options.os_auth_type
6383

@@ -113,7 +133,7 @@ def build_auth_params(auth_plugin_name, cmd_options):
113133
else:
114134
LOG.debug('no auth_type')
115135
# delay the plugin choice, grab every option
116-
plugin_options = set([o.replace('-', '_') for o in OPTIONS_LIST])
136+
plugin_options = set([o.replace('-', '_') for o in get_options_list()])
117137
for option in plugin_options:
118138
option_name = 'os_' + option
119139
LOG.debug('fetching option %s' % option_name)
@@ -147,7 +167,7 @@ def build_auth_plugins_option_parser(parser):
147167
authentication plugin.
148168
149169
"""
150-
available_plugins = [plugin.name for plugin in PLUGIN_LIST]
170+
available_plugins = [plugin.name for plugin in get_plugin_list()]
151171
parser.add_argument(
152172
'--os-auth-type',
153173
metavar='<auth-type>',
@@ -169,7 +189,7 @@ def build_auth_plugins_option_parser(parser):
169189
default=utils.env('OS_TENANT_ID')
170190
),
171191
}
172-
for o in OPTIONS_LIST:
192+
for o in get_options_list():
173193
# remove allusion to tenants from v2.0 API
174194
if 'tenant' not in o:
175195
parser.add_argument(

‎openstackclient/compute/client.py‎

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,6 @@
1515

1616
import logging
1717

18-
from novaclient import client as nova_client
19-
from novaclient import extension
20-
21-
try:
22-
from novaclient.v2.contrib import list_extensions
23-
except ImportError:
24-
from novaclient.v1_1.contrib import list_extensions
25-
2618
from openstackclient.common import utils
2719

2820
LOG = logging.getLogger(__name__)
@@ -34,6 +26,15 @@
3426

3527
def make_client(instance):
3628
"""Returns a compute service client."""
29+
30+
# Defer client imports until we actually need them
31+
from novaclient import client as nova_client
32+
from novaclient import extension
33+
try:
34+
from novaclient.v2.contrib import list_extensions
35+
except ImportError:
36+
from novaclient.v1_1.contrib import list_extensions
37+
3738
compute_client = nova_client.get_client_class(
3839
instance._api_version[API_NAME],
3940
)

‎openstackclient/tests/common/test_clientmanager.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
SERVICE_CATALOG = service_catalog.ServiceCatalogV2(AUTH_REF)
3535

3636

37+
# This is deferred in api.auth but we need it here...
38+
auth.get_options_list()
39+
40+
3741
class Container(object):
3842
attr = clientmanager.ClientCache(lambda x: object())
3943

‎openstackclient/tests/volume/test_find_resource.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
from openstackclient.volume import client # noqa
2525

2626

27+
# Monkey patch for v1 cinderclient
28+
# NOTE(dtroyer): Do here because openstackclient.volume.client
29+
# doesn't do it until the client object is created now.
30+
volumes.Volume.NAME_ATTR = 'display_name'
31+
volume_snapshots.Snapshot.NAME_ATTR = 'display_name'
32+
33+
2734
ID = '1after909'
2835
NAME = 'PhilSpector'
2936

‎openstackclient/volume/client.py‎

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,8 @@
1515

1616
import logging
1717

18-
from cinderclient import extension
19-
from cinderclient.v1.contrib import list_extensions
20-
from cinderclient.v1 import volume_snapshots
21-
from cinderclient.v1 import volumes
22-
2318
from openstackclient.common import utils
2419

25-
# Monkey patch for v1 cinderclient
26-
volumes.Volume.NAME_ATTR = 'display_name'
27-
volume_snapshots.Snapshot.NAME_ATTR = 'display_name'
28-
2920
LOG = logging.getLogger(__name__)
3021

3122
DEFAULT_VOLUME_API_VERSION = '1'
@@ -38,6 +29,17 @@
3829

3930
def make_client(instance):
4031
"""Returns a volume service client."""
32+
33+
# Defer client imports until we actually need them
34+
from cinderclient import extension
35+
from cinderclient.v1.contrib import list_extensions
36+
from cinderclient.v1 import volume_snapshots
37+
from cinderclient.v1 import volumes
38+
39+
# Monkey patch for v1 cinderclient
40+
volumes.Volume.NAME_ATTR = 'display_name'
41+
volume_snapshots.Snapshot.NAME_ATTR = 'display_name'
42+
4143
volume_client = utils.get_client_class(
4244
API_NAME,
4345
instance._api_version[API_NAME],

0 commit comments

Comments
 (0)