Keystoneclient didn't provide translated messages. With this
change, the messages are marked for translation.

DocImpact

Implements: blueprint keystoneclient-i18n

Change-Id: I85263a71671a1dffed524185266e6bb7ae559630
This commit is contained in:
Brant Knudson 2014-10-27 10:54:48 -05:00 committed by Jamie Lennox
parent 3b766c5143
commit fece74ca3e
33 changed files with 293 additions and 186 deletions

View File

@ -25,6 +25,7 @@ import logging
import re
from keystoneclient import exceptions
from keystoneclient.i18n import _, _LI, _LW
from keystoneclient import utils
@ -65,7 +66,7 @@ def get_version_data(session, url, authenticated=None):
pass
err_text = resp.text[:50] + '...' if len(resp.text) > 50 else resp.text
msg = 'Invalid Response - Bad version data returned: %s' % err_text
msg = _('Invalid Response - Bad version data returned: %s') % err_text
raise exceptions.DiscoveryFailure(msg)
@ -99,7 +100,7 @@ def normalize_version_number(version):
except Exception:
pass
raise TypeError('Invalid version specified: %s' % version)
raise TypeError(_('Invalid version specified: %s') % version)
def version_match(required, candidate):
@ -159,8 +160,8 @@ class Discover(object):
try:
status = v['status']
except KeyError:
_LOGGER.warning('Skipping over invalid version data. '
'No stability status in version.')
_LOGGER.warning(_LW('Skipping over invalid version data. '
'No stability status in version.'))
continue
status = status.lower()
@ -198,13 +199,14 @@ class Discover(object):
try:
version_str = v['id']
except KeyError:
_LOGGER.info('Skipping invalid version data. Missing ID.')
_LOGGER.info(_LI('Skipping invalid version data. Missing ID.'))
continue
try:
links = v['links']
except KeyError:
_LOGGER.info('Skipping invalid version data. Missing links')
_LOGGER.info(
_LI('Skipping invalid version data. Missing links'))
continue
version_number = normalize_version_number(version_str)
@ -214,15 +216,15 @@ class Discover(object):
rel = link['rel']
url = link['href']
except (KeyError, TypeError):
_LOGGER.info('Skipping invalid version link. '
'Missing link URL or relationship.')
_LOGGER.info(_LI('Skipping invalid version link. '
'Missing link URL or relationship.'))
continue
if rel.lower() == 'self':
break
else:
_LOGGER.info('Skipping invalid version data. '
'Missing link to endpoint.')
_LOGGER.info(_LI('Skipping invalid version data. '
'Missing link to endpoint.'))
continue
versions.append({'version': version_number,

View File

@ -19,6 +19,7 @@ import datetime
from oslo.utils import timeutils
from keystoneclient.i18n import _
from keystoneclient import service_catalog
@ -63,7 +64,7 @@ class AccessInfo(dict):
else:
auth_ref = AccessInfoV2(**kwargs)
else:
raise NotImplementedError('Unrecognized auth response')
raise NotImplementedError(_('Unrecognized auth response'))
else:
auth_ref = AccessInfoV2(**kwargs)

View File

@ -17,6 +17,8 @@ import six
import stevedore
from keystoneclient import exceptions
from keystoneclient.i18n import _
# NOTE(jamielennox): The AUTH_INTERFACE is a special value that can be
# requested from get_endpoint. If a plugin receives this as the value of
@ -40,7 +42,7 @@ def get_plugin_class(name):
name=name,
invoke_on_load=False)
except RuntimeError:
msg = 'The plugin %s could not be found' % name
msg = _('The plugin %s could not be found') % name
raise exceptions.NoMatchingPlugin(msg)
return mgr.driver

View File

@ -19,6 +19,7 @@ import six
from keystoneclient import _discover
from keystoneclient.auth import base
from keystoneclient import exceptions
from keystoneclient.i18n import _LW
from keystoneclient import utils
LOG = logging.getLogger(__name__)
@ -181,9 +182,9 @@ class BaseIdentityPlugin(base.BaseAuthPlugin):
return self.auth_url
if not service_type:
LOG.warn('Plugin cannot return an endpoint without knowing the '
'service type that is required. Add service_type to '
'endpoint filtering data.')
LOG.warn(_LW('Plugin cannot return an endpoint without knowing '
'the service type that is required. Add service_type '
'to endpoint filtering data.'))
return None
if not interface:
@ -216,8 +217,9 @@ class BaseIdentityPlugin(base.BaseAuthPlugin):
# NOTE(jamielennox): Again if we can't contact the server we fall
# back to just returning the URL from the catalog. This may not be
# the best default but we need it for now.
LOG.warn('Failed to contact the endpoint at %s for discovery. '
'Fallback to using that endpoint as the base url.', url)
LOG.warn(_LW('Failed to contact the endpoint at %s for discovery. '
'Fallback to using that endpoint as the base url.'),
url)
else:
url = disc.url_for(version)

View File

@ -20,6 +20,8 @@ import six.moves.urllib.parse as urlparse
from keystoneclient import _discover
from keystoneclient.auth.identity import base
from keystoneclient import exceptions
from keystoneclient.i18n import _, _LW
LOG = logging.getLogger(__name__)
@ -127,9 +129,9 @@ class BaseGenericPlugin(base.BaseIdentityPlugin):
except (exceptions.DiscoveryFailure,
exceptions.HTTPError,
exceptions.ConnectionError):
LOG.warn('Discovering versions from the identity service failed '
'when creating the password plugin. Attempting to '
'determine version from URL.')
LOG.warn(_LW('Discovering versions from the identity service '
'failed when creating the password plugin. '
'Attempting to determine version from URL.'))
url_parts = urlparse.urlparse(self.auth_url)
path = url_parts.path.lower()
@ -163,7 +165,7 @@ class BaseGenericPlugin(base.BaseIdentityPlugin):
return plugin
# so there were no URLs that i could use for auth of any version.
msg = 'Could not determine a suitable URL for the plugin'
msg = _('Could not determine a suitable URL for the plugin')
raise exceptions.DiscoveryFailure(msg)
def get_auth_ref(self, session, **kwargs):

View File

@ -19,6 +19,7 @@ import six
from keystoneclient import access
from keystoneclient.auth.identity import base
from keystoneclient import exceptions
from keystoneclient.i18n import _
from keystoneclient import utils
_logger = logging.getLogger(__name__)
@ -84,18 +85,17 @@ class Auth(base.BaseIdentityPlugin):
ident[name] = auth_data
if not ident:
raise exceptions.AuthorizationFailure('Authentication method '
'required (e.g. password)')
raise exceptions.AuthorizationFailure(
_('Authentication method required (e.g. password)'))
mutual_exclusion = [bool(self.domain_id or self.domain_name),
bool(self.project_id or self.project_name),
bool(self.trust_id)]
if sum(mutual_exclusion) > 1:
raise exceptions.AuthorizationFailure('Authentication cannot be '
'scoped to multiple '
'targets. Pick one of: '
'project, domain or trust')
raise exceptions.AuthorizationFailure(
_('Authentication cannot be scoped to multiple targets. Pick '
'one of: project, domain or trust'))
if self.domain_id:
body['auth']['scope'] = {'domain': {'id': self.domain_id}}
@ -165,7 +165,7 @@ class AuthMethod(object):
setattr(self, param, kwargs.pop(param, None))
if kwargs:
msg = "Unexpected Attributes: %s" % ", ".join(kwargs.keys())
msg = _("Unexpected Attributes: %s") % ", ".join(kwargs.keys())
raise AttributeError(msg)
@classmethod

View File

@ -27,6 +27,7 @@ from six.moves import urllib
from keystoneclient import auth
from keystoneclient import exceptions
from keystoneclient.i18n import _
from keystoneclient.openstack.common.apiclient import base
@ -219,7 +220,7 @@ class Manager(object):
management=management,
**kwargs)
except KeyError:
raise exceptions.ClientException("Invalid update method: %s"
raise exceptions.ClientException(_("Invalid update method: %s")
% method)
# PUT requests may not return a body
if body:
@ -244,7 +245,8 @@ class ManagerWithFind(Manager):
num = len(rl)
if num == 0:
msg = "No %s matching %s." % (self.resource_class.__name__, kwargs)
msg = _("No %(name)s matching %(kwargs)s.") % {
'name': self.resource_class.__name__, 'kwargs': kwargs}
raise exceptions.NotFound(404, msg)
elif num > 1:
raise exceptions.NoUniqueMatch
@ -395,7 +397,8 @@ class CrudManager(Manager):
num = len(rl)
if num == 0:
msg = "No %s matching %s." % (self.resource_class.__name__, kwargs)
msg = _("No %(name)s matching %(kwargs)s.") % {
'name': self.resource_class.__name__, 'kwargs': kwargs}
raise exceptions.NotFound(404, msg)
elif num > 1:
raise exceptions.NoUniqueMatch

View File

@ -28,6 +28,7 @@ import zlib
import six
from keystoneclient import exceptions
from keystoneclient.i18n import _, _LE, _LW
subprocess = None
@ -73,8 +74,9 @@ def _check_files_accessible(files):
except IOError as e:
# Catching IOError means there is an issue with
# the given file.
err = ('Hit OSError in _process_communicate_handle_oserror()\n'
'Likely due to %s: %s') % (try_file, e.strerror)
err = _('Hit OSError in _process_communicate_handle_oserror()\n'
'Likely due to %(file)s: %(error)s') % {'file': try_file,
'error': e.strerror}
# Emulate openssl behavior, which returns with code 2 when
# access to a file failed:
@ -122,8 +124,9 @@ def _encoding_for_form(inform):
elif inform == PKIZ_CMS_FORM:
encoding = 'hex'
else:
raise ValueError('"inform" must be either %s or %s' %
(PKI_ASN1_FORM, PKIZ_CMS_FORM))
raise ValueError(
_('"inform" must be one of: %s') % ','.join((PKI_ASN1_FORM,
PKIZ_CMS_FORM)))
return encoding
@ -296,8 +299,8 @@ def is_asn1_token(token):
def is_ans1_token(token):
"""Deprecated. Use is_asn1_token() instead."""
LOG.warning('The function is_ans1_token() is deprecated, '
'use is_asn1_token() instead.')
LOG.warning(_LW('The function is_ans1_token() is deprecated, '
'use is_asn1_token() instead.'))
return is_asn1_token(token)
@ -344,13 +347,13 @@ def cms_sign_data(data_to_sign, signing_cert_file_name, signing_key_file_name,
process, data, (signing_cert_file_name, signing_key_file_name))
if retcode or ('Error' in err):
LOG.error('Signing error: %s', err)
LOG.error(_LE('Signing error: %s'), err)
if retcode == 3:
LOG.error('Signing error: Unable to load certificate - '
'ensure you have configured PKI with '
'"keystone-manage pki_setup"')
LOG.error(_LE('Signing error: Unable to load certificate - '
'ensure you have configured PKI with '
'"keystone-manage pki_setup"'))
else:
LOG.error('Signing error: %s', err)
LOG.error(_LE('Signing error: %s'), err)
raise subprocess.CalledProcessError(retcode, 'openssl')
if outform == PKI_ASN1_FORM:
return output.decode('utf-8')

View File

@ -20,6 +20,7 @@ from six.moves import urllib
from keystoneclient import access
from keystoneclient.auth.identity import v3
from keystoneclient import exceptions
from keystoneclient.i18n import _
class _BaseSAMLPlugin(v3.AuthConstructor):
@ -30,7 +31,7 @@ class _BaseSAMLPlugin(v3.AuthConstructor):
@staticmethod
def _first(_list):
if len(_list) != 1:
raise IndexError("Only single element list is acceptable")
raise IndexError(_("Only single element list is acceptable"))
return _list[0]
@staticmethod
@ -80,8 +81,8 @@ class Saml2UnscopedTokenAuthMethod(v3.AuthMethod):
_method_parameters = []
def get_auth_data(self, session, auth, headers, **kwargs):
raise exceptions.MethodNotImplemented(('This method should never '
'be called'))
raise exceptions.MethodNotImplemented(_('This method should never '
'be called'))
class Saml2UnscopedToken(_BaseSAMLPlugin):
@ -211,9 +212,9 @@ class Saml2UnscopedToken(_BaseSAMLPlugin):
authenticated=False)
# prepare error message and raise an exception.
msg = ("Consumer URLs from Service Provider %(service_provider)s "
"%(sp_consumer_url)s and Identity Provider "
"%(identity_provider)s %(idp_consumer_url)s are not equal")
msg = _("Consumer URLs from Service Provider %(service_provider)s "
"%(sp_consumer_url)s and Identity Provider "
"%(identity_provider)s %(idp_consumer_url)s are not equal")
msg = msg % {
'service_provider': self.token_url,
'sp_consumer_url': sp_response_consumer_url,
@ -257,8 +258,8 @@ class Saml2UnscopedToken(_BaseSAMLPlugin):
try:
self.saml2_authn_request = etree.XML(sp_response.content)
except etree.XMLSyntaxError as e:
msg = ("SAML2: Error parsing XML returned "
"from Service Provider, reason: %s" % e)
msg = _("SAML2: Error parsing XML returned "
"from Service Provider, reason: %s") % e
raise exceptions.AuthorizationFailure(msg)
relay_state = self.saml2_authn_request.xpath(
@ -288,8 +289,8 @@ class Saml2UnscopedToken(_BaseSAMLPlugin):
try:
self.saml2_idp_authn_response = etree.XML(idp_response.content)
except etree.XMLSyntaxError as e:
msg = ("SAML2: Error parsing XML returned "
"from Identity Provider, reason: %s" % e)
msg = _("SAML2: Error parsing XML returned "
"from Identity Provider, reason: %s") % e
raise exceptions.AuthorizationFailure(msg)
idp_response_consumer_url = self.saml2_idp_authn_response.xpath(
@ -736,8 +737,8 @@ class ADFSUnscopedToken(_BaseSAMLPlugin):
except exceptions.InternalServerError as e:
reason = _get_failure(e)
raise exceptions.AuthorizationFailure(reason)
msg = ("Error parsing XML returned from "
"the ADFS Identity Provider, reason: %s")
msg = _("Error parsing XML returned from "
"the ADFS Identity Provider, reason: %s")
self.adfs_token = self.str_to_xml(response.content, msg)
def _prepare_sp_request(self):
@ -803,8 +804,9 @@ class ADFSUnscopedToken(_BaseSAMLPlugin):
"""
if self._cookies(session) is False:
raise exceptions.AuthorizationFailure(
"Session object doesn't contain a cookie, therefore you are "
"not allowed to enter the Identity Provider's protected area.")
_("Session object doesn't contain a cookie, therefore you are "
"not allowed to enter the Identity Provider's protected "
"area."))
self.authenticated_response = session.get(self.token_url,
authenticated=False)
@ -883,4 +885,4 @@ class Saml2ScopedToken(v3.Token):
super(Saml2ScopedToken, self).__init__(auth_url, token, **kwargs)
if not (self.project_id or self.domain_id):
raise exceptions.ValidationError(
'Neither project nor domain specified')
_('Neither project nor domain specified'))

View File

@ -24,6 +24,8 @@ import re
import six
from six.moves import urllib
from keystoneclient.i18n import _
class Ec2Signer(object):
"""Utility class which adds allows a request to be signed with an AWS style
@ -91,10 +93,10 @@ class Ec2Signer(object):
credentials['body_hash'])
if signature_version is not None:
raise Exception('Unknown signature version: %s' %
raise Exception(_('Unknown signature version: %s') %
signature_version)
else:
raise Exception('Unexpected signature format')
raise Exception(_('Unexpected signature format'))
@staticmethod
def _get_utf8_value(value):
@ -257,7 +259,7 @@ class Ec2Signer(object):
credential_date = credential_split[1]
param_date = date_param()
if not param_date.startswith(credential_date):
raise Exception('Request date mismatch error')
raise Exception(_('Request date mismatch error'))
# Create the string to sign
# http://docs.aws.amazon.com/general/latest/gr/

View File

@ -16,6 +16,7 @@ import six
from keystoneclient import _discover
from keystoneclient import exceptions
from keystoneclient.i18n import _
from keystoneclient import session as client_session
from keystoneclient import utils
from keystoneclient.v2_0 import client as v2_client
@ -122,9 +123,9 @@ class Discover(_discover.Discover):
url = auth_url
if not url:
raise exceptions.DiscoveryFailure('Not enough information to '
'determine URL. Provide either '
'auth_url or endpoint')
raise exceptions.DiscoveryFailure(
_('Not enough information to determine URL. Provide either '
'auth_url or endpoint'))
self._client_kwargs = kwargs
super(Discover, self).__init__(session, url,
@ -213,10 +214,11 @@ class Discover(_discover.Discover):
version_data = all_versions[-1]
if not version_data:
msg = 'Could not find a suitable endpoint'
msg = _('Could not find a suitable endpoint')
if version:
msg += ' for client version: %s' % str(version)
msg = _('Could not find a suitable endpoint for client '
'version: %s') % str(version)
raise exceptions.VersionNotAvailable(msg)
@ -228,7 +230,7 @@ class Discover(_discover.Discover):
client_class = _CLIENT_VERSIONS[version_data['version'][0]]
except KeyError:
version = '.'.join(str(v) for v in version_data['version'])
msg = 'No client available for version: %s' % version
msg = _('No client available for version: %s') % version
raise exceptions.DiscoveryFailure(msg)
# kwargs should take priority over stored kwargs.

View File

@ -16,6 +16,7 @@
Exception definitions.
"""
from keystoneclient.i18n import _
from keystoneclient.openstack.common.apiclient.exceptions import * # noqa
# NOTE(akurilin): This alias should be left here to support backwards
@ -31,7 +32,7 @@ class CertificateConfigError(Exception):
"""Error reading the certificate."""
def __init__(self, output):
self.output = output
msg = 'Unable to load certificate.'
msg = _('Unable to load certificate.')
super(CertificateConfigError, self).__init__(msg)
@ -39,7 +40,7 @@ class CMSError(Exception):
"""Error reading the certificate."""
def __init__(self, output):
self.output = output
msg = 'Unable to sign or verify data.'
msg = _('Unable to sign or verify data.')
super(CMSError, self).__init__(msg)

View File

@ -19,6 +19,7 @@ from six.moves.urllib import parse as urlparse
from keystoneclient import exceptions
from keystoneclient import httpclient
from keystoneclient.i18n import _
_logger = logging.getLogger(__name__)
@ -94,7 +95,7 @@ class Client(httpclient.HTTPClient):
try:
results = {}
if 'version' in body:
results['message'] = "Keystone found at %s" % url
results['message'] = _("Keystone found at %s") % url
version = body['version']
# Stable/diablo incorrect format
id, status, version_url = (
@ -105,7 +106,7 @@ class Client(httpclient.HTTPClient):
return results
elif 'versions' in body:
# Correct format
results['message'] = "Keystone found at %s" % url
results['message'] = _("Keystone found at %s") % url
for version in body['versions']['values']:
id, status, version_url = (
self._get_version_info(version, url))
@ -114,8 +115,8 @@ class Client(httpclient.HTTPClient):
"url": version_url}
return results
else:
results['message'] = ("Unrecognized response from %s"
% url)
results['message'] = (
_("Unrecognized response from %s") % url)
return results
except KeyError:
raise exceptions.AuthorizationFailure()
@ -159,7 +160,7 @@ class Client(httpclient.HTTPClient):
extensions = body['extensions']
else:
return dict(message=(
'Unrecognized extensions response from %s' % url))
_('Unrecognized extensions response from %s') % url))
return dict(self._get_extension_info(e) for e in extensions)
elif resp.status_code == 305:

View File

@ -16,6 +16,7 @@
import six
from keystoneclient.generic import client
from keystoneclient.i18n import _
from keystoneclient import utils
@ -37,13 +38,14 @@ def do_discover(cs, args):
print(versions['message'])
for key, version in six.iteritems(versions):
if key != 'message':
print(" - supports version %s (%s) here %s" %
(version['id'], version['status'], version['url']))
print(_(" - supports version %(id)s (%(status)s) here "
"%(url)s") %
version)
extensions = cs.discover_extensions(version['url'])
if extensions:
for key, extension in six.iteritems(extensions):
if key != 'message':
print(" - and %s: %s" %
(key, extension))
print(_(" - and %(key)s: %(extension)s") %
{'key': key, 'extension': extension})
else:
print("No Keystone-compatible endpoint found")
print(_("No Keystone-compatible endpoint found"))

View File

@ -55,6 +55,7 @@ from keystoneclient import access
from keystoneclient.auth import base
from keystoneclient import baseclient
from keystoneclient import exceptions
from keystoneclient.i18n import _, _LI, _LW
from keystoneclient import session as client_session
from keystoneclient import utils
@ -265,7 +266,7 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
# keyring setup
if use_keyring and keyring is None:
_logger.warning('Failed to load keyring modules.')
_logger.warning(_LW('Failed to load keyring modules.'))
self.use_keyring = use_keyring and keyring is not None
self.force_new_token = force_new_token
self.stale_duration = stale_duration or access.STALE_TOKEN_DURATION
@ -476,7 +477,8 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
auth_ref = None
except Exception as e:
auth_ref = None
_logger.warning('Unable to retrieve token from keyring %s', e)
_logger.warning(
_LW('Unable to retrieve token from keyring %s'), e)
return (keyring_key, auth_ref)
def store_auth_ref_into_keyring(self, keyring_key):
@ -489,7 +491,8 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
keyring_key,
pickle.dumps(self.auth_ref))
except Exception as e:
_logger.warning("Failed to store token into keyring %s", e)
_logger.warning(
_LW("Failed to store token into keyring %s"), e)
def _process_management_url(self, region_name):
try:
@ -511,14 +514,14 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
if self.auth_ref.project_scoped:
if not self.auth_ref.tenant_id:
raise exceptions.AuthorizationFailure(
"Token didn't provide tenant_id")
_("Token didn't provide tenant_id"))
self._process_management_url(region_name)
self.project_name = self.auth_ref.tenant_name
self.project_id = self.auth_ref.tenant_id
if not self.auth_ref.user_id:
raise exceptions.AuthorizationFailure(
"Token didn't provide user_id")
_("Token didn't provide user_id"))
self.user_id = self.auth_ref.user_id
@ -620,10 +623,11 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
try:
return self.request(url, method, **kwargs)
except exceptions.MissingAuthPlugin:
_logger.info('Cannot get authenticated endpoint without an '
'auth plugin')
_logger.info(_LI('Cannot get authenticated endpoint without an '
'auth plugin'))
raise exceptions.AuthorizationFailure(
'Current authorization does not have a known management url')
_('Current authorization does not have a known management '
'url'))
def get(self, url, **kwargs):
return self._cs_request(url, 'GET', **kwargs)
@ -656,7 +660,7 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
try:
var_name = self.deprecated_session_variables[name]
except KeyError:
raise AttributeError("Unknown Attribute: %s" % name)
raise AttributeError(_("Unknown Attribute: %s") % name)
return getattr(self.session, var_name or name)

37
keystoneclient/i18n.py Normal file
View File

@ -0,0 +1,37 @@
# Copyright 2014 IBM Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""oslo.i18n integration module.
See http://docs.openstack.org/developer/oslo.i18n/usage.html .
"""
from oslo import i18n
_translators = i18n.TranslatorFactory(domain='keystoneclient')
# The primary translation function using the well-known name "_"
_ = _translators.primary
# Translators for log levels.
#
# The abbreviated names are meant to reflect the usual use of a short
# name like '_'. The "L" is for "log" and the other letter comes from
# the level.
_LI = _translators.log_info
_LW = _translators.log_warning
_LE = _translators.log_error
_LC = _translators.log_critical

View File

@ -21,6 +21,7 @@ import abc
import six
from keystoneclient import exceptions
from keystoneclient.i18n import _
from keystoneclient import utils
@ -36,7 +37,7 @@ class ServiceCatalog(object):
elif ServiceCatalogV2.is_valid(resource_dict):
return ServiceCatalogV2(resource_dict, region_name)
else:
raise NotImplementedError('Unrecognized auth response')
raise NotImplementedError(_('Unrecognized auth response'))
def __init__(self, region_name=None):
self._region_name = region_name
@ -208,7 +209,7 @@ class ServiceCatalog(object):
"""
if not self.get_data():
raise exceptions.EmptyCatalog('The service catalog is empty.')
raise exceptions.EmptyCatalog(_('The service catalog is empty.'))
urls = self.get_urls(attr=attr,
filter_value=filter_value,
@ -222,12 +223,30 @@ class ServiceCatalog(object):
except Exception:
pass
msg = '%s endpoint for %s service' % (endpoint_type, service_type)
if service_name:
msg += ' named %s' % service_name
if region_name:
msg += ' in %s region' % region_name
msg += ' not found'
if service_name and region_name:
msg = (_('%(endpoint_type)s endpoint for %(service_type)s service '
'named %(service_name)s in %(region_name)s region not '
'found') %
{'endpoint_type': endpoint_type,
'service_type': service_type, 'service_name': service_name,
'region_name': region_name})
elif service_name:
msg = (_('%(endpoint_type)s endpoint for %(service_type)s service '
'named %(service_name)s not found') %
{'endpoint_type': endpoint_type,
'service_type': service_type,
'service_name': service_name})
elif region_name:
msg = (_('%(endpoint_type)s endpoint for %(service_type)s service '
'in %(region_name)s region not found') %
{'endpoint_type': endpoint_type,
'service_type': service_type, 'region_name': region_name})
else:
msg = (_('%(endpoint_type)s endpoint for %(service_type)s service '
'not found') %
{'endpoint_type': endpoint_type,
'service_type': service_type})
raise exceptions.EndpointNotFound(msg)
@abc.abstractmethod

View File

@ -25,6 +25,7 @@ import six
from six.moves import urllib
from keystoneclient import exceptions
from keystoneclient.i18n import _, _LI, _LW
from keystoneclient import utils
osprofiler_web = importutils.try_import("osprofiler.web")
@ -40,10 +41,10 @@ def _positive_non_zero_float(argument_value):
try:
value = float(argument_value)
except ValueError:
msg = "%s must be a float" % argument_value
msg = _("%s must be a float") % argument_value
raise argparse.ArgumentTypeError(msg)
if value <= 0:
msg = "%s must be greater than 0" % argument_value
msg = _("%s must be greater than 0") % argument_value
raise argparse.ArgumentTypeError(msg)
return value
@ -274,7 +275,7 @@ class Session(object):
token = self.get_token(auth)
if not token:
raise exceptions.AuthorizationFailure("No token Available")
raise exceptions.AuthorizationFailure(_("No token Available"))
headers['X-Auth-Token'] = token
@ -372,20 +373,20 @@ class Session(object):
try:
resp = self.session.request(method, url, **kwargs)
except requests.exceptions.SSLError:
msg = 'SSL exception connecting to %s' % url
msg = _('SSL exception connecting to %s') % url
raise exceptions.SSLError(msg)
except requests.exceptions.Timeout:
msg = 'Request to %s timed out' % url
msg = _('Request to %s timed out') % url
raise exceptions.RequestTimeout(msg)
except requests.exceptions.ConnectionError:
msg = 'Unable to establish connection to %s' % url
msg = _('Unable to establish connection to %s') % url
raise exceptions.ConnectionRefused(msg)
except (exceptions.RequestTimeout, exceptions.ConnectionRefused) as e:
if connect_retries <= 0:
raise
_logger.info('Failure: %s. Retrying in %.1fs.',
e, connect_retry_delay)
_logger.info(_LI('Failure: %(e)s. Retrying in %(delay).1fs.'),
{'e': e, 'delay': connect_retry_delay})
time.sleep(connect_retry_delay)
return self._send_request(
@ -411,8 +412,8 @@ class Session(object):
try:
location = resp.headers['location']
except KeyError:
_logger.warn("Failed to redirect request to %s as new "
"location was not provided.", resp.url)
_logger.warn(_LW("Failed to redirect request to %s as new "
"location was not provided."), resp.url)
else:
# NOTE(jamielennox): We don't pass through connect_retry_delay.
# This request actually worked so we can reset the delay count.
@ -508,13 +509,13 @@ class Session(object):
auth = self.auth
if not auth:
raise exceptions.MissingAuthPlugin("Token Required")
raise exceptions.MissingAuthPlugin(_("Token Required"))
try:
return auth.get_token(self)
except exceptions.HttpError as exc:
raise exceptions.AuthorizationFailure("Authentication failure: "
"%s" % exc)
raise exceptions.AuthorizationFailure(
_("Authentication failure: %s") % exc)
def get_endpoint(self, auth=None, **kwargs):
"""Get an endpoint as provided by the auth plugin.
@ -531,8 +532,9 @@ class Session(object):
auth = self.auth
if not auth:
raise exceptions.MissingAuthPlugin('An auth plugin is required to '
'determine the endpoint URL.')
raise exceptions.MissingAuthPlugin(
_('An auth plugin is required to determine the endpoint '
'URL.'))
return auth.get_endpoint(self, **kwargs)
@ -543,7 +545,7 @@ class Session(object):
auth = self.auth
if not auth:
msg = 'Auth plugin not available to invalidate'
msg = _('Auth plugin not available to invalidate')
raise exceptions.MissingAuthPlugin(msg)
return auth.invalidate()

View File

@ -18,6 +18,7 @@ import logging
from keystoneclient.auth.identity import v2 as v2_auth
from keystoneclient import exceptions
from keystoneclient import httpclient
from keystoneclient.i18n import _
from keystoneclient.v2_0 import ec2
from keystoneclient.v2_0 import endpoints
from keystoneclient.v2_0 import extensions
@ -163,7 +164,7 @@ class Client(httpclient.HTTPClient):
"""
try:
if auth_url is None:
raise ValueError("Cannot authenticate without an auth_url")
raise ValueError(_("Cannot authenticate without an auth_url"))
new_kwargs = {'trust_id': trust_id,
'tenant_id': project_id or tenant_id,
@ -175,7 +176,7 @@ class Client(httpclient.HTTPClient):
plugin = v2_auth.Password(auth_url, username, password,
**new_kwargs)
else:
msg = 'A username and password or token is required.'
msg = _('A username and password or token is required.')
raise exceptions.AuthorizationFailure(msg)
return plugin.get_auth_ref(self.session)
@ -183,8 +184,9 @@ class Client(httpclient.HTTPClient):
_logger.debug("Authorization Failed.")
raise
except exceptions.EndpointNotFound:
msg = 'There was no suitable authentication url for this request'
msg = (
_('There was no suitable authentication url for this request'))
raise exceptions.AuthorizationFailure(msg)
except Exception as e:
raise exceptions.AuthorizationFailure("Authorization Failed: "
"%s" % e)
raise exceptions.AuthorizationFailure(
_("Authorization Failed: %s") % e)

View File

@ -29,6 +29,7 @@ import sys
from oslo.utils import strutils
import six
from keystoneclient.i18n import _
from keystoneclient import utils
from keystoneclient.v2_0 import client
@ -38,9 +39,9 @@ ASK_FOR_PASSWORD = object()
def require_service_catalog(f):
msg = ('Configuration error: Client configured to run without a service '
'catalog. Run the client using --os-auth-url or OS_AUTH_URL, '
'instead of --os-endpoint or OS_SERVICE_ENDPOINT, for example.')
msg = _('Configuration error: Client configured to run without a service '
'catalog. Run the client using --os-auth-url or OS_AUTH_URL, '
'instead of --os-endpoint or OS_SERVICE_ENDPOINT, for example.')
def wrapped(kc, args):
if not kc.has_service_catalog():
@ -121,15 +122,15 @@ def do_user_update(kc, args):
kwargs['enabled'] = strutils.bool_from_string(args.enabled)
if not len(kwargs):
print("User not updated, no arguments present.")
print(_("User not updated, no arguments present."))
return
user = utils.find_resource(kc.users, args.user)
try:
kc.users.update(user, **kwargs)
print('User has been updated.')
print(_('User has been updated.'))
except Exception as e:
print('Unable to update user: %s' % e)
print(_('Unable to update user: %s') % e)
@utils.arg('--pass', metavar='<password>', dest='passwd', required=False,
@ -141,8 +142,8 @@ def do_user_password_update(kc, args):
user = utils.find_resource(kc.users, args.user)
new_passwd = args.passwd or utils.prompt_for_password()
if new_passwd is None:
msg = ("\nPlease specify password using the --pass option "
"or using the prompt")
msg = (_("\nPlease specify password using the --pass option "
"or using the prompt"))
sys.exit(msg)
kc.users.update_password(user, new_passwd)
@ -163,20 +164,20 @@ def do_password_update(kc, args):
if args.currentpasswd is not None:
currentpasswd = args.currentpasswd
if currentpasswd is None:
currentpasswd = getpass.getpass('Current Password: ')
currentpasswd = getpass.getpass(_('Current Password: '))
newpasswd = args.newpasswd
while newpasswd is None:
passwd1 = getpass.getpass('New Password: ')
passwd2 = getpass.getpass('Repeat New Password: ')
passwd1 = getpass.getpass(_('New Password: '))
passwd2 = getpass.getpass(_('Repeat New Password: '))
if passwd1 == passwd2:
newpasswd = passwd1
kc.users.update_own_password(currentpasswd, newpasswd)
if args.os_password != newpasswd:
print("You should update the password you are using to authenticate "
"to match your new password")
print(_("You should update the password you are using to authenticate "
"to match your new password"))
@utils.arg('user', metavar='<user>', help='Name or ID of user to delete.')
@ -234,7 +235,7 @@ def do_tenant_update(kc, args):
kwargs.update({'enabled': strutils.bool_from_string(args.enabled)})
if kwargs == {}:
print("Tenant not updated, no arguments present.")
print(_("Tenant not updated, no arguments present."))
return
tenant.update(**kwargs)
@ -450,9 +451,9 @@ def do_ec2_credentials_delete(kc, args):
args.user_id = kc.auth_user_id
try:
kc.ec2.delete(args.user_id, args.access)
print('Credential has been deleted.')
print(_('Credential has been deleted.'))
except Exception as e:
print('Unable to delete credential: %s' % e)
print(_('Unable to delete credential: %s') % e)
@utils.arg('--service', metavar='<service-type>', default=None,
@ -463,7 +464,7 @@ def do_catalog(kc, args):
endpoints = kc.service_catalog.get_endpoints(service_type=args.service)
for (service, service_endpoints) in six.iteritems(endpoints):
if len(service_endpoints) > 0:
print("Service: %s" % service)
print(_("Service: %s") % service)
for ep in service_endpoints:
utils.print_dict(ep)
@ -489,7 +490,7 @@ def do_endpoint_get(kc, args):
if args.attr and args.value:
kwargs.update({'attr': args.attr, 'filter_value': args.value})
elif args.attr or args.value:
print('Both --attr and --value required.')
print(_('Both --attr and --value required.'))
return
url = kc.service_catalog.url_for(**kwargs)
@ -531,9 +532,9 @@ def do_endpoint_delete(kc, args):
"""Delete a service endpoint."""
try:
kc.endpoints.delete(args.id)
print('Endpoint has been deleted.')
print(_('Endpoint has been deleted.'))
except Exception:
print('Unable to delete endpoint.')
print(_('Unable to delete endpoint.'))
@utils.arg('--wrap', metavar='<integer>', default=0,

View File

@ -13,6 +13,7 @@
from keystoneclient import auth
from keystoneclient import base
from keystoneclient import exceptions
from keystoneclient.i18n import _
from keystoneclient import utils
@ -45,7 +46,8 @@ class TokenManager(base.Manager):
params = {"auth": {"passwordCredentials": {"username": username,
"password": password}}}
else:
raise ValueError('A username and password or token is required.')
raise ValueError(
_('A username and password or token is required.'))
if tenant_id:
params['auth']['tenantId'] = tenant_id
elif tenant_name:

View File

@ -20,6 +20,7 @@ from oslo.serialization import jsonutils
from keystoneclient.auth.identity import v3 as v3_auth
from keystoneclient import exceptions
from keystoneclient import httpclient
from keystoneclient.i18n import _
from keystoneclient.v3.contrib import endpoint_filter
from keystoneclient.v3.contrib import endpoint_policy
from keystoneclient.v3.contrib import federation
@ -203,7 +204,7 @@ EndpointPolicyManager`
if self.auth_ref.domain_scoped:
if not self.auth_ref.domain_id:
raise exceptions.AuthorizationFailure(
"Token didn't provide domain_id")
_("Token didn't provide domain_id"))
self._process_management_url(kwargs.get('region_name'))
self.domain_name = self.auth_ref.domain_name
self.domain_id = self.auth_ref.domain_id
@ -235,7 +236,7 @@ EndpointPolicyManager`
"""
try:
if auth_url is None:
raise ValueError("Cannot authenticate without an auth_url")
raise ValueError(_("Cannot authenticate without an auth_url"))
auth_methods = []
@ -251,7 +252,7 @@ EndpointPolicyManager`
auth_methods.append(m)
if not auth_methods:
msg = 'A user and password or token is required.'
msg = _('A user and password or token is required.')
raise exceptions.AuthorizationFailure(msg)
plugin = v3_auth.Auth(auth_url, auth_methods,
@ -268,8 +269,9 @@ EndpointPolicyManager`
_logger.debug('Authorization failed.')
raise
except exceptions.EndpointNotFound:
msg = 'There was no suitable authentication url for this request'
msg = _('There was no suitable authentication url for this'
' request')
raise exceptions.AuthorizationFailure(msg)
except Exception as e:
raise exceptions.AuthorizationFailure('Authorization failed: '
'%s' % e)
raise exceptions.AuthorizationFailure(
_('Authorization failed: %s') % e)

View File

@ -14,6 +14,7 @@
from keystoneclient import base
from keystoneclient import exceptions
from keystoneclient.i18n import _
class EndpointFilterManager(base.Manager):
@ -31,7 +32,7 @@ class EndpointFilterManager(base.Manager):
elif endpoint_id:
api_path = '/endpoints/%s/projects' % (endpoint_id)
else:
msg = 'Must specify a project, an endpoint, or both'
msg = _('Must specify a project, an endpoint, or both')
raise exceptions.ValidationError(msg)
return self.OS_EP_FILTER_EXT + api_path
@ -39,7 +40,7 @@ class EndpointFilterManager(base.Manager):
def add_endpoint_to_project(self, project, endpoint):
"""Create a project-endpoint association."""
if not (project and endpoint):
raise ValueError('project and endpoint are required')
raise ValueError(_('project and endpoint are required'))
base_url = self._build_base_url(project=project,
endpoint=endpoint)
@ -48,7 +49,7 @@ class EndpointFilterManager(base.Manager):
def delete_endpoint_from_project(self, project, endpoint):
"""Remove a project-endpoint association."""
if not (project and endpoint):
raise ValueError('project and endpoint are required')
raise ValueError(_('project and endpoint are required'))
base_url = self._build_base_url(project=project,
endpoint=endpoint)
@ -57,7 +58,7 @@ class EndpointFilterManager(base.Manager):
def check_endpoint_in_project(self, project, endpoint):
"""Checks if project-endpoint association exist."""
if not (project and endpoint):
raise ValueError('project and endpoint are required')
raise ValueError(_('project and endpoint are required'))
base_url = self._build_base_url(project=project,
endpoint=endpoint)
@ -66,7 +67,7 @@ class EndpointFilterManager(base.Manager):
def list_endpoints_for_project(self, project):
"""List all endpoints for a given project."""
if not project:
raise ValueError('project is required')
raise ValueError(_('project is required'))
base_url = self._build_base_url(project=project)
return super(EndpointFilterManager, self)._list(
@ -77,7 +78,7 @@ class EndpointFilterManager(base.Manager):
def list_projects_for_endpoint(self, endpoint):
"""List all projects for a given endpoint."""
if not endpoint:
raise ValueError('endpoint is required')
raise ValueError(_('endpoint is required'))
base_url = self._build_base_url(endpoint=endpoint)
return super(EndpointFilterManager, self)._list(

View File

@ -13,6 +13,7 @@
# under the License.
from keystoneclient import base
from keystoneclient.i18n import _
from keystoneclient.v3 import policies
@ -24,7 +25,7 @@ class EndpointPolicyManager(base.Manager):
def _act_on_policy_association_for_endpoint(
self, policy, endpoint, action):
if not (policy and endpoint):
raise ValueError('policy and endpoint are required')
raise ValueError(_('policy and endpoint are required'))
policy_id = base.getid(policy)
endpoint_id = base.getid(endpoint)
@ -52,7 +53,7 @@ class EndpointPolicyManager(base.Manager):
def _act_on_policy_association_for_service(self, policy, service, action):
if not (policy and service):
raise ValueError('policy and service are required')
raise ValueError(_('policy and service are required'))
policy_id = base.getid(policy)
service_id = base.getid(service)
@ -81,7 +82,7 @@ class EndpointPolicyManager(base.Manager):
def _act_on_policy_association_for_region_and_service(
self, policy, region, service, action):
if not (policy and region and service):
raise ValueError('policy, region and service are required')
raise ValueError(_('policy, region and service are required'))
policy_id = base.getid(policy)
region_id = base.getid(region)
@ -121,7 +122,7 @@ class EndpointPolicyManager(base.Manager):
"""
if not endpoint:
raise ValueError('endpoint is required')
raise ValueError(_('endpoint is required'))
endpoint_id = base.getid(endpoint)
url = ('/endpoints/%(endpoint_id)s/%(ext_name)s/policy') % {
@ -141,7 +142,7 @@ class EndpointPolicyManager(base.Manager):
"""
if not policy:
raise ValueError('policy is required')
raise ValueError(_('policy is required'))
policy_id = base.getid(policy)
url = ('/policies/%(policy_id)s/%(ext_name)s/endpoints') % {

View File

@ -11,6 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from keystoneclient.i18n import _
from keystoneclient.v3.contrib.oauth1 import access_tokens
from keystoneclient.v3.contrib.oauth1 import consumers
from keystoneclient.v3.contrib.oauth1 import request_tokens
@ -59,6 +60,6 @@ class OAuthManagerOptionalImportProxy(object):
def __getattribute__(self, name):
if name in ('access_tokens', 'consumers', 'request_tokens'):
raise NotImplementedError(
'To use %r oauthlib must be installed' % name)
_('To use %r oauthlib must be installed') % name)
return super(OAuthManagerOptionalImportProxy,
self).__getattribute__(name)

View File

@ -14,6 +14,7 @@ from oslo.utils import timeutils
from keystoneclient import base
from keystoneclient import exceptions
from keystoneclient.i18n import _
class Trust(base.Resource):
@ -75,8 +76,8 @@ class TrustManager(base.CrudManager):
**kwargs)
def update(self):
raise exceptions.MethodNotImplemented('Update not supported'
' for trusts')
raise exceptions.MethodNotImplemented(
_('Update not supported for trusts'))
def list(self, trustee_user=None, trustor_user=None, **kwargs):
"""List Trusts."""

View File

@ -15,6 +15,7 @@
# under the License.
from keystoneclient import base
from keystoneclient.i18n import _
from keystoneclient import utils
@ -46,7 +47,7 @@ class CredentialManager(base.CrudManager):
return data
else:
raise ValueError(
"Credential requires blob to be specified")
_("Credential requires blob to be specified"))
@utils.positional(1, enforcement=utils.positional.WARN)
def create(self, user, type, blob=None, data=None, project=None, **kwargs):

View File

@ -16,6 +16,7 @@
from keystoneclient import base
from keystoneclient import exceptions
from keystoneclient.i18n import _
from keystoneclient import utils
@ -45,7 +46,7 @@ class EndpointManager(base.CrudManager):
def _validate_interface(self, interface):
if interface is not None and interface not in VALID_INTERFACES:
msg = '"interface" must be one of: %s'
msg = _('"interface" must be one of: %s')
msg = msg % ', '.join(VALID_INTERFACES)
raise exceptions.ValidationError(msg)

View File

@ -12,6 +12,7 @@
from keystoneclient import base
from keystoneclient import exceptions
from keystoneclient.i18n import _
class RoleAssignment(base.Resource):
@ -37,12 +38,12 @@ class RoleAssignmentManager(base.CrudManager):
def _check_not_user_and_group(self, user, group):
if user and group:
msg = 'Specify either a user or group, not both'
msg = _('Specify either a user or group, not both')
raise exceptions.ValidationError(msg)
def _check_not_domain_and_project(self, domain, project):
if domain and project:
msg = 'Specify either a domain or project, not both'
msg = _('Specify either a domain or project, not both')
raise exceptions.ValidationError(msg)
def list(self, user=None, group=None, project=None, domain=None, role=None,
@ -87,25 +88,25 @@ class RoleAssignmentManager(base.CrudManager):
return super(RoleAssignmentManager, self).list(**query_params)
def create(self, **kwargs):
raise exceptions.MethodNotImplemented('Create not supported for'
' role assignments')
raise exceptions.MethodNotImplemented(
_('Create not supported for role assignments'))
def update(self, **kwargs):
raise exceptions.MethodNotImplemented('Update not supported for'
' role assignments')
raise exceptions.MethodNotImplemented(
_('Update not supported for role assignments'))
def get(self, **kwargs):
raise exceptions.MethodNotImplemented('Get not supported for'
' role assignments')
raise exceptions.MethodNotImplemented(
_('Get not supported for role assignments'))
def find(self, **kwargs):
raise exceptions.MethodNotImplemented('Find not supported for'
' role assignments')
raise exceptions.MethodNotImplemented(
_('Find not supported for role assignments'))
def put(self, **kwargs):
raise exceptions.MethodNotImplemented('Put not supported for'
' role assignments')
raise exceptions.MethodNotImplemented(
_('Put not supported for role assignments'))
def delete(self, **kwargs):
raise exceptions.MethodNotImplemented('Delete not supported for'
' role assignments')
raise exceptions.MethodNotImplemented(
_('Delete not supported for role assignments'))

View File

@ -16,6 +16,7 @@
from keystoneclient import base
from keystoneclient import exceptions
from keystoneclient.i18n import _
from keystoneclient import utils
@ -59,18 +60,18 @@ class RoleManager(base.CrudManager):
def _require_domain_xor_project(self, domain, project):
if domain and project:
msg = 'Specify either a domain or project, not both'
msg = _('Specify either a domain or project, not both')
raise exceptions.ValidationError(msg)
elif not (domain or project):
msg = 'Must specify either a domain or project'
msg = _('Must specify either a domain or project')
raise exceptions.ValidationError(msg)
def _require_user_xor_group(self, user, group):
if user and group:
msg = 'Specify either a user or group, not both'
msg = _('Specify either a user or group, not both')
raise exceptions.ValidationError(msg)
elif not (user or group):
msg = 'Must specify either a user or group'
msg = _('Must specify either a user or group')
raise exceptions.ValidationError(msg)
@utils.positional(1, enforcement=utils.positional.WARN)

View File

@ -18,6 +18,7 @@ import logging
from keystoneclient import base
from keystoneclient import exceptions
from keystoneclient.i18n import _, _LW
from keystoneclient import utils
LOG = logging.getLogger(__name__)
@ -41,7 +42,7 @@ class UserManager(base.CrudManager):
def _require_user_and_group(self, user, group):
if not (user and group):
msg = 'Specify both a user and a group'
msg = _('Specify both a user and a group')
raise exceptions.ValidationError(msg)
@utils.positional(1, enforcement=utils.positional.WARN)
@ -58,8 +59,8 @@ class UserManager(base.CrudManager):
will be used.
"""
if project:
LOG.warning("The project argument is deprecated, "
"use default_project instead.")
LOG.warning(_LW("The project argument is deprecated, "
"use default_project instead."))
default_project_id = base.getid(default_project) or base.getid(project)
user_data = base.filter_none(name=name,
domain_id=base.getid(domain),
@ -92,8 +93,8 @@ class UserManager(base.CrudManager):
will be used.
"""
if project:
LOG.warning("The project argument is deprecated, "
"use default_project instead.")
LOG.warning(_LW("The project argument is deprecated, "
"use default_project instead."))
default_project_id = base.getid(default_project) or base.getid(project)
if group:
base_url = '/groups/%s' % base.getid(group)
@ -124,8 +125,8 @@ class UserManager(base.CrudManager):
will be used.
"""
if project:
LOG.warning("The project argument is deprecated, "
"use default_project instead.")
LOG.warning(_LW("The project argument is deprecated, "
"use default_project instead."))
default_project_id = base.getid(default_project) or base.getid(project)
user_data = base.filter_none(name=name,
domain_id=base.getid(domain),
@ -145,11 +146,11 @@ class UserManager(base.CrudManager):
def update_password(self, old_password, new_password):
"""Update the password for the user the token belongs to."""
if not (old_password and new_password):
msg = 'Specify both the current password and a new password'
msg = _('Specify both the current password and a new password')
raise exceptions.ValidationError(msg)
if old_password == new_password:
msg = 'Old password and new password must be different.'
msg = _('Old password and new password must be different.')
raise exceptions.ValidationError(msg)
params = {'user': {'password': new_password,

View File

@ -9,6 +9,7 @@ Babel>=1.3
iso8601>=0.1.9
netaddr>=0.7.12
oslo.config>=1.4.0 # Apache-2.0
oslo.i18n>=1.0.0 # Apache-2.0
oslo.serialization>=1.0.0 # Apache-2.0
oslo.utils>=1.0.0 # Apache-2.0
PrettyTable>=0.7,<0.8

View File

@ -45,3 +45,6 @@ exclude = .venv,.tox,dist,doc,*egg,build,*openstack/common*
commands=
python setup.py build_sphinx
[hacking]
import_exceptions =
keystoneclient.i18n