Update oslo-incubator dependencies

Our version of oslo.log is conflicting with the one in Horizon.

Change-Id: I1f0eba6555367c20d1d356371f71b8823ad096a2
This commit is contained in:
Kirill Izotov 2014-04-23 16:22:38 +07:00
parent e6d5aee483
commit f403e29d5c
8 changed files with 124 additions and 114 deletions

View File

@ -1,2 +1,17 @@
#
# 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.
import six import six
six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox')) six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))

View File

@ -30,6 +30,7 @@ import six
from six.moves.urllib import parse from six.moves.urllib import parse
from mistralclient.openstack.common.apiclient import exceptions from mistralclient.openstack.common.apiclient import exceptions
from mistralclient.openstack.common.gettextutils import _
from mistralclient.openstack.common import strutils from mistralclient.openstack.common import strutils
@ -219,7 +220,10 @@ class ManagerWithFind(BaseManager):
matches = self.findall(**kwargs) matches = self.findall(**kwargs)
num_matches = len(matches) num_matches = len(matches)
if num_matches == 0: if num_matches == 0:
msg = "No %s matching %s." % (self.resource_class.__name__, kwargs) msg = _("No %(name)s matching %(args)s.") % {
'name': self.resource_class.__name__,
'args': kwargs
}
raise exceptions.NotFound(msg) raise exceptions.NotFound(msg)
elif num_matches > 1: elif num_matches > 1:
raise exceptions.NoUniqueMatch() raise exceptions.NoUniqueMatch()
@ -373,7 +377,10 @@ class CrudManager(BaseManager):
num = len(rl) num = len(rl)
if num == 0: if num == 0:
msg = "No %s matching %s." % (self.resource_class.__name__, kwargs) msg = _("No %(name)s matching %(args)s.") % {
'name': self.resource_class.__name__,
'args': kwargs
}
raise exceptions.NotFound(404, msg) raise exceptions.NotFound(404, msg)
elif num > 1: elif num > 1:
raise exceptions.NoUniqueMatch raise exceptions.NoUniqueMatch
@ -457,17 +464,22 @@ class Resource(object):
def __getattr__(self, k): def __getattr__(self, k):
if k not in self.__dict__: if k not in self.__dict__:
#NOTE(bcwaldon): disallow lazy-loading if already loaded once #NOTE(bcwaldon): disallow lazy-loading if already loaded once
if not self.is_loaded: if not self.is_loaded():
self._get() self.get()
return self.__getattr__(k) return self.__getattr__(k)
raise AttributeError(k) raise AttributeError(k)
else: else:
return self.__dict__[k] return self.__dict__[k]
def _get(self): def get(self):
# set _loaded first ... so if we have to bail, we know we tried. """Support for lazy loading details.
self._loaded = True
Some clients, such as novaclient have the option to lazy load the
details, details which can be loaded with this function.
"""
# set_loaded() first ... so if we have to bail, we know we tried.
self.set_loaded(True)
if not hasattr(self.manager, 'get'): if not hasattr(self.manager, 'get'):
return return
@ -485,9 +497,11 @@ class Resource(object):
return self.id == other.id return self.id == other.id
return self._info == other._info return self._info == other._info
@property
def is_loaded(self): def is_loaded(self):
return self._loaded return self._loaded
def set_loaded(self, val):
self._loaded = val
def to_dict(self): def to_dict(self):
return copy.deepcopy(self._info) return copy.deepcopy(self._info)

View File

@ -36,6 +36,7 @@ except ImportError:
import requests import requests
from mistralclient.openstack.common.apiclient import exceptions from mistralclient.openstack.common.apiclient import exceptions
from mistralclient.openstack.common.gettextutils import _
from mistralclient.openstack.common import importutils from mistralclient.openstack.common import importutils
@ -228,7 +229,7 @@ class HTTPClient(object):
**filter_args) **filter_args)
if not (token and endpoint): if not (token and endpoint):
raise exceptions.AuthorizationFailure( raise exceptions.AuthorizationFailure(
"Cannot find endpoint or token for request") _("Cannot find endpoint or token for request"))
old_token_endpoint = (token, endpoint) old_token_endpoint = (token, endpoint)
kwargs.setdefault("headers", {})["X-Auth-Token"] = token kwargs.setdefault("headers", {})["X-Auth-Token"] = token
@ -351,8 +352,12 @@ class BaseClient(object):
try: try:
client_path = version_map[str(version)] client_path = version_map[str(version)]
except (KeyError, ValueError): except (KeyError, ValueError):
msg = "Invalid %s client version '%s'. must be one of: %s" % ( msg = _("Invalid %(api_name)s client version '%(version)s'. "
(api_name, version, ', '.join(version_map.keys()))) "Must be one of: %(version_map)s") % {
'api_name': api_name,
'version': version,
'version_map': ', '.join(version_map.keys())
}
raise exceptions.UnsupportedVersion(msg) raise exceptions.UnsupportedVersion(msg)
return importutils.import_class(client_path) return importutils.import_class(client_path)

View File

@ -25,6 +25,8 @@ import sys
import six import six
from mistralclient.openstack.common.gettextutils import _
class ClientException(Exception): class ClientException(Exception):
"""The base exception class for all exceptions this library raises. """The base exception class for all exceptions this library raises.
@ -36,7 +38,7 @@ class MissingArgs(ClientException):
"""Supplied arguments are not sufficient for calling a function.""" """Supplied arguments are not sufficient for calling a function."""
def __init__(self, missing): def __init__(self, missing):
self.missing = missing self.missing = missing
msg = "Missing argument(s): %s" % ", ".join(missing) msg = _("Missing arguments: %s") % ", ".join(missing)
super(MissingArgs, self).__init__(msg) super(MissingArgs, self).__init__(msg)
@ -69,7 +71,7 @@ class AuthPluginOptionsMissing(AuthorizationFailure):
"""Auth plugin misses some options.""" """Auth plugin misses some options."""
def __init__(self, opt_names): def __init__(self, opt_names):
super(AuthPluginOptionsMissing, self).__init__( super(AuthPluginOptionsMissing, self).__init__(
"Authentication failed. Missing options: %s" % _("Authentication failed. Missing options: %s") %
", ".join(opt_names)) ", ".join(opt_names))
self.opt_names = opt_names self.opt_names = opt_names
@ -78,7 +80,7 @@ class AuthSystemNotFound(AuthorizationFailure):
"""User has specified a AuthSystem that is not installed.""" """User has specified a AuthSystem that is not installed."""
def __init__(self, auth_system): def __init__(self, auth_system):
super(AuthSystemNotFound, self).__init__( super(AuthSystemNotFound, self).__init__(
"AuthSystemNotFound: %s" % repr(auth_system)) _("AuthSystemNotFound: %s") % repr(auth_system))
self.auth_system = auth_system self.auth_system = auth_system
@ -101,7 +103,7 @@ class AmbiguousEndpoints(EndpointException):
"""Found more than one matching endpoint in Service Catalog.""" """Found more than one matching endpoint in Service Catalog."""
def __init__(self, endpoints=None): def __init__(self, endpoints=None):
super(AmbiguousEndpoints, self).__init__( super(AmbiguousEndpoints, self).__init__(
"AmbiguousEndpoints: %s" % repr(endpoints)) _("AmbiguousEndpoints: %s") % repr(endpoints))
self.endpoints = endpoints self.endpoints = endpoints
@ -109,7 +111,7 @@ class HttpError(ClientException):
"""The base exception class for all HTTP exceptions. """The base exception class for all HTTP exceptions.
""" """
http_status = 0 http_status = 0
message = "HTTP Error" message = _("HTTP Error")
def __init__(self, message=None, details=None, def __init__(self, message=None, details=None,
response=None, request_id=None, response=None, request_id=None,
@ -129,7 +131,7 @@ class HttpError(ClientException):
class HTTPRedirection(HttpError): class HTTPRedirection(HttpError):
"""HTTP Redirection.""" """HTTP Redirection."""
message = "HTTP Redirection" message = _("HTTP Redirection")
class HTTPClientError(HttpError): class HTTPClientError(HttpError):
@ -137,7 +139,7 @@ class HTTPClientError(HttpError):
Exception for cases in which the client seems to have erred. Exception for cases in which the client seems to have erred.
""" """
message = "HTTP Client Error" message = _("HTTP Client Error")
class HttpServerError(HttpError): class HttpServerError(HttpError):
@ -146,7 +148,7 @@ class HttpServerError(HttpError):
Exception for cases in which the server is aware that it has Exception for cases in which the server is aware that it has
erred or is incapable of performing the request. erred or is incapable of performing the request.
""" """
message = "HTTP Server Error" message = _("HTTP Server Error")
class MultipleChoices(HTTPRedirection): class MultipleChoices(HTTPRedirection):
@ -156,7 +158,7 @@ class MultipleChoices(HTTPRedirection):
""" """
http_status = 300 http_status = 300
message = "Multiple Choices" message = _("Multiple Choices")
class BadRequest(HTTPClientError): class BadRequest(HTTPClientError):
@ -165,7 +167,7 @@ class BadRequest(HTTPClientError):
The request cannot be fulfilled due to bad syntax. The request cannot be fulfilled due to bad syntax.
""" """
http_status = 400 http_status = 400
message = "Bad Request" message = _("Bad Request")
class Unauthorized(HTTPClientError): class Unauthorized(HTTPClientError):
@ -175,7 +177,7 @@ class Unauthorized(HTTPClientError):
is required and has failed or has not yet been provided. is required and has failed or has not yet been provided.
""" """
http_status = 401 http_status = 401
message = "Unauthorized" message = _("Unauthorized")
class PaymentRequired(HTTPClientError): class PaymentRequired(HTTPClientError):
@ -184,7 +186,7 @@ class PaymentRequired(HTTPClientError):
Reserved for future use. Reserved for future use.
""" """
http_status = 402 http_status = 402
message = "Payment Required" message = _("Payment Required")
class Forbidden(HTTPClientError): class Forbidden(HTTPClientError):
@ -194,7 +196,7 @@ class Forbidden(HTTPClientError):
to it. to it.
""" """
http_status = 403 http_status = 403
message = "Forbidden" message = _("Forbidden")
class NotFound(HTTPClientError): class NotFound(HTTPClientError):
@ -204,7 +206,7 @@ class NotFound(HTTPClientError):
in the future. in the future.
""" """
http_status = 404 http_status = 404
message = "Not Found" message = _("Not Found")
class MethodNotAllowed(HTTPClientError): class MethodNotAllowed(HTTPClientError):
@ -214,7 +216,7 @@ class MethodNotAllowed(HTTPClientError):
by that resource. by that resource.
""" """
http_status = 405 http_status = 405
message = "Method Not Allowed" message = _("Method Not Allowed")
class NotAcceptable(HTTPClientError): class NotAcceptable(HTTPClientError):
@ -224,7 +226,7 @@ class NotAcceptable(HTTPClientError):
acceptable according to the Accept headers sent in the request. acceptable according to the Accept headers sent in the request.
""" """
http_status = 406 http_status = 406
message = "Not Acceptable" message = _("Not Acceptable")
class ProxyAuthenticationRequired(HTTPClientError): class ProxyAuthenticationRequired(HTTPClientError):
@ -233,7 +235,7 @@ class ProxyAuthenticationRequired(HTTPClientError):
The client must first authenticate itself with the proxy. The client must first authenticate itself with the proxy.
""" """
http_status = 407 http_status = 407
message = "Proxy Authentication Required" message = _("Proxy Authentication Required")
class RequestTimeout(HTTPClientError): class RequestTimeout(HTTPClientError):
@ -242,7 +244,7 @@ class RequestTimeout(HTTPClientError):
The server timed out waiting for the request. The server timed out waiting for the request.
""" """
http_status = 408 http_status = 408
message = "Request Timeout" message = _("Request Timeout")
class Conflict(HTTPClientError): class Conflict(HTTPClientError):
@ -252,7 +254,7 @@ class Conflict(HTTPClientError):
in the request, such as an edit conflict. in the request, such as an edit conflict.
""" """
http_status = 409 http_status = 409
message = "Conflict" message = _("Conflict")
class Gone(HTTPClientError): class Gone(HTTPClientError):
@ -262,7 +264,7 @@ class Gone(HTTPClientError):
not be available again. not be available again.
""" """
http_status = 410 http_status = 410
message = "Gone" message = _("Gone")
class LengthRequired(HTTPClientError): class LengthRequired(HTTPClientError):
@ -272,7 +274,7 @@ class LengthRequired(HTTPClientError):
required by the requested resource. required by the requested resource.
""" """
http_status = 411 http_status = 411
message = "Length Required" message = _("Length Required")
class PreconditionFailed(HTTPClientError): class PreconditionFailed(HTTPClientError):
@ -282,7 +284,7 @@ class PreconditionFailed(HTTPClientError):
put on the request. put on the request.
""" """
http_status = 412 http_status = 412
message = "Precondition Failed" message = _("Precondition Failed")
class RequestEntityTooLarge(HTTPClientError): class RequestEntityTooLarge(HTTPClientError):
@ -291,7 +293,7 @@ class RequestEntityTooLarge(HTTPClientError):
The request is larger than the server is willing or able to process. The request is larger than the server is willing or able to process.
""" """
http_status = 413 http_status = 413
message = "Request Entity Too Large" message = _("Request Entity Too Large")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
try: try:
@ -308,7 +310,7 @@ class RequestUriTooLong(HTTPClientError):
The URI provided was too long for the server to process. The URI provided was too long for the server to process.
""" """
http_status = 414 http_status = 414
message = "Request-URI Too Long" message = _("Request-URI Too Long")
class UnsupportedMediaType(HTTPClientError): class UnsupportedMediaType(HTTPClientError):
@ -318,7 +320,7 @@ class UnsupportedMediaType(HTTPClientError):
not support. not support.
""" """
http_status = 415 http_status = 415
message = "Unsupported Media Type" message = _("Unsupported Media Type")
class RequestedRangeNotSatisfiable(HTTPClientError): class RequestedRangeNotSatisfiable(HTTPClientError):
@ -328,7 +330,7 @@ class RequestedRangeNotSatisfiable(HTTPClientError):
supply that portion. supply that portion.
""" """
http_status = 416 http_status = 416
message = "Requested Range Not Satisfiable" message = _("Requested Range Not Satisfiable")
class ExpectationFailed(HTTPClientError): class ExpectationFailed(HTTPClientError):
@ -337,7 +339,7 @@ class ExpectationFailed(HTTPClientError):
The server cannot meet the requirements of the Expect request-header field. The server cannot meet the requirements of the Expect request-header field.
""" """
http_status = 417 http_status = 417
message = "Expectation Failed" message = _("Expectation Failed")
class UnprocessableEntity(HTTPClientError): class UnprocessableEntity(HTTPClientError):
@ -347,7 +349,7 @@ class UnprocessableEntity(HTTPClientError):
errors. errors.
""" """
http_status = 422 http_status = 422
message = "Unprocessable Entity" message = _("Unprocessable Entity")
class InternalServerError(HttpServerError): class InternalServerError(HttpServerError):
@ -356,7 +358,7 @@ class InternalServerError(HttpServerError):
A generic error message, given when no more specific message is suitable. A generic error message, given when no more specific message is suitable.
""" """
http_status = 500 http_status = 500
message = "Internal Server Error" message = _("Internal Server Error")
# NotImplemented is a python keyword. # NotImplemented is a python keyword.
@ -367,7 +369,7 @@ class HttpNotImplemented(HttpServerError):
the ability to fulfill the request. the ability to fulfill the request.
""" """
http_status = 501 http_status = 501
message = "Not Implemented" message = _("Not Implemented")
class BadGateway(HttpServerError): class BadGateway(HttpServerError):
@ -377,7 +379,7 @@ class BadGateway(HttpServerError):
response from the upstream server. response from the upstream server.
""" """
http_status = 502 http_status = 502
message = "Bad Gateway" message = _("Bad Gateway")
class ServiceUnavailable(HttpServerError): class ServiceUnavailable(HttpServerError):
@ -386,7 +388,7 @@ class ServiceUnavailable(HttpServerError):
The server is currently unavailable. The server is currently unavailable.
""" """
http_status = 503 http_status = 503
message = "Service Unavailable" message = _("Service Unavailable")
class GatewayTimeout(HttpServerError): class GatewayTimeout(HttpServerError):
@ -396,7 +398,7 @@ class GatewayTimeout(HttpServerError):
response from the upstream server. response from the upstream server.
""" """
http_status = 504 http_status = 504
message = "Gateway Timeout" message = _("Gateway Timeout")
class HttpVersionNotSupported(HttpServerError): class HttpVersionNotSupported(HttpServerError):
@ -405,7 +407,7 @@ class HttpVersionNotSupported(HttpServerError):
The server does not support the HTTP protocol version used in the request. The server does not support the HTTP protocol version used in the request.
""" """
http_status = 505 http_status = 505
message = "HTTP Version Not Supported" message = _("HTTP Version Not Supported")
# _code_map contains all the classes that have http_status attribute. # _code_map contains all the classes that have http_status attribute.
@ -423,12 +425,17 @@ def from_response(response, method, url):
:param method: HTTP method used for request :param method: HTTP method used for request
:param url: URL used for request :param url: URL used for request
""" """
req_id = response.headers.get("x-openstack-request-id")
#NOTE(hdd) true for older versions of nova and cinder
if not req_id:
req_id = response.headers.get("x-compute-request-id")
kwargs = { kwargs = {
"http_status": response.status_code, "http_status": response.status_code,
"response": response, "response": response,
"method": method, "method": method,
"url": url, "url": url,
"request_id": response.headers.get("x-compute-request-id"), "request_id": req_id,
} }
if "retry-after" in response.headers: if "retry-after" in response.headers:
kwargs["retry_after"] = response.headers["retry-after"] kwargs["retry_after"] = response.headers["retry-after"]

View File

@ -28,7 +28,6 @@ import gettext
import locale import locale
from logging import handlers from logging import handlers
import os import os
import re
from babel import localedata from babel import localedata
import six import six
@ -248,47 +247,22 @@ class Message(six.text_type):
if other is None: if other is None:
params = (other,) params = (other,)
elif isinstance(other, dict): elif isinstance(other, dict):
params = self._trim_dictionary_parameters(other) # Merge the dictionaries
# Copy each item in case one does not support deep copy.
params = {}
if isinstance(self.params, dict):
for key, val in self.params.items():
params[key] = self._copy_param(val)
for key, val in other.items():
params[key] = self._copy_param(val)
else: else:
params = self._copy_param(other) params = self._copy_param(other)
return params return params
def _trim_dictionary_parameters(self, dict_param):
"""Return a dict that only has matching entries in the msgid."""
# NOTE(luisg): Here we trim down the dictionary passed as parameters
# to avoid carrying a lot of unnecessary weight around in the message
# object, for example if someone passes in Message() % locals() but
# only some params are used, and additionally we prevent errors for
# non-deepcopyable objects by unicoding() them.
# Look for %(param) keys in msgid;
# Skip %% and deal with the case where % is first character on the line
keys = re.findall('(?:[^%]|^)?%\((\w*)\)[a-z]', self.msgid)
# If we don't find any %(param) keys but have a %s
if not keys and re.findall('(?:[^%]|^)%[a-z]', self.msgid):
# Apparently the full dictionary is the parameter
params = self._copy_param(dict_param)
else:
params = {}
# Save our existing parameters as defaults to protect
# ourselves from losing values if we are called through an
# (erroneous) chain that builds a valid Message with
# arguments, and then does something like "msg % kwds"
# where kwds is an empty dictionary.
src = {}
if isinstance(self.params, dict):
src.update(self.params)
src.update(dict_param)
for key in keys:
params[key] = self._copy_param(src[key])
return params
def _copy_param(self, param): def _copy_param(self, param):
try: try:
return copy.deepcopy(param) return copy.deepcopy(param)
except TypeError: except Exception:
# Fallback to casting to unicode this will handle the # Fallback to casting to unicode this will handle the
# python code-like objects that can't be deep-copied # python code-like objects that can't be deep-copied
return six.text_type(param) return six.text_type(param)
@ -300,13 +274,14 @@ class Message(six.text_type):
def __radd__(self, other): def __radd__(self, other):
return self.__add__(other) return self.__add__(other)
def __str__(self): if six.PY2:
# NOTE(luisg): Logging in python 2.6 tries to str() log records, def __str__(self):
# and it expects specifically a UnicodeError in order to proceed. # NOTE(luisg): Logging in python 2.6 tries to str() log records,
msg = _('Message objects do not support str() because they may ' # and it expects specifically a UnicodeError in order to proceed.
'contain non-ascii characters. ' msg = _('Message objects do not support str() because they may '
'Please use unicode() or translate() instead.') 'contain non-ascii characters. '
raise UnicodeError(msg) 'Please use unicode() or translate() instead.')
raise UnicodeError(msg)
def get_available_languages(domain): def get_available_languages(domain):

View File

@ -36,17 +36,9 @@ import functools
import inspect import inspect
import itertools import itertools
import json import json
try:
import xmlrpclib
except ImportError:
# NOTE(jaypipes): xmlrpclib was renamed to xmlrpc.client in Python3
# however the function and object call signatures
# remained the same. This whole try/except block should
# be removed and replaced with a call to six.moves once
# six 1.4.2 is released. See http://bit.ly/1bqrVzu
import xmlrpc.client as xmlrpclib
import six import six
import six.moves.xmlrpc_client as xmlrpclib
from mistralclient.openstack.common import gettextutils from mistralclient.openstack.common import gettextutils
from mistralclient.openstack.common import importutils from mistralclient.openstack.common import importutils

View File

@ -163,6 +163,7 @@ log_opts = [
'qpid=WARN', 'qpid=WARN',
'sqlalchemy=WARN', 'sqlalchemy=WARN',
'suds=INFO', 'suds=INFO',
'oslo.messaging=INFO',
'iso8601=WARN', 'iso8601=WARN',
'requests.packages.urllib3.connectionpool=WARN' 'requests.packages.urllib3.connectionpool=WARN'
], ],
@ -495,10 +496,16 @@ def _find_facility_from_conf():
class RFCSysLogHandler(logging.handlers.SysLogHandler): class RFCSysLogHandler(logging.handlers.SysLogHandler):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.binary_name = _get_binary_name() self.binary_name = _get_binary_name()
super(RFCSysLogHandler, self).__init__(*args, **kwargs) # Do not use super() unless type(logging.handlers.SysLogHandler)
# is 'type' (Python 2.7).
# Use old style calls, if the type is 'classobj' (Python 2.6)
logging.handlers.SysLogHandler.__init__(self, *args, **kwargs)
def format(self, record): def format(self, record):
msg = super(RFCSysLogHandler, self).format(record) # Do not use super() unless type(logging.handlers.SysLogHandler)
# is 'type' (Python 2.7).
# Use old style calls, if the type is 'classobj' (Python 2.6)
msg = logging.handlers.SysLogHandler.format(self, record)
msg = self.binary_name + ' ' + msg msg = self.binary_name + ' ' + msg
return msg return msg
@ -650,7 +657,7 @@ class ContextFormatter(logging.Formatter):
# NOTE(sdague): default the fancier formatting params # NOTE(sdague): default the fancier formatting params
# to an empty string so we don't throw an exception if # to an empty string so we don't throw an exception if
# they get used # they get used
for key in ('instance', 'color'): for key in ('instance', 'color', 'user_identity'):
if key not in record.__dict__: if key not in record.__dict__:
record.__dict__[key] = '' record.__dict__[key] = ''

View File

@ -98,7 +98,8 @@ def bool_from_string(subject, strict=False, default=False):
def safe_decode(text, incoming=None, errors='strict'): def safe_decode(text, incoming=None, errors='strict'):
"""Decodes incoming str using `incoming` if they're not already unicode. """Decodes incoming text/bytes string using `incoming` if they're not
already unicode.
:param incoming: Text's current encoding :param incoming: Text's current encoding
:param errors: Errors handling policy. See here for valid :param errors: Errors handling policy. See here for valid
@ -107,7 +108,7 @@ def safe_decode(text, incoming=None, errors='strict'):
representation of it. representation of it.
:raises TypeError: If text is not an instance of str :raises TypeError: If text is not an instance of str
""" """
if not isinstance(text, six.string_types): if not isinstance(text, (six.string_types, six.binary_type)):
raise TypeError("%s can't be decoded" % type(text)) raise TypeError("%s can't be decoded" % type(text))
if isinstance(text, six.text_type): if isinstance(text, six.text_type):
@ -137,7 +138,7 @@ def safe_decode(text, incoming=None, errors='strict'):
def safe_encode(text, incoming=None, def safe_encode(text, incoming=None,
encoding='utf-8', errors='strict'): encoding='utf-8', errors='strict'):
"""Encodes incoming str/unicode using `encoding`. """Encodes incoming text/bytes string using `encoding`.
If incoming is not specified, text is expected to be encoded with If incoming is not specified, text is expected to be encoded with
current python's default encoding. (`sys.getdefaultencoding`) current python's default encoding. (`sys.getdefaultencoding`)
@ -150,7 +151,7 @@ def safe_encode(text, incoming=None,
representation of it. representation of it.
:raises TypeError: If text is not an instance of str :raises TypeError: If text is not an instance of str
""" """
if not isinstance(text, six.string_types): if not isinstance(text, (six.string_types, six.binary_type)):
raise TypeError("%s can't be encoded" % type(text)) raise TypeError("%s can't be encoded" % type(text))
if not incoming: if not incoming:
@ -158,19 +159,13 @@ def safe_encode(text, incoming=None,
sys.getdefaultencoding()) sys.getdefaultencoding())
if isinstance(text, six.text_type): if isinstance(text, six.text_type):
if six.PY3: return text.encode(encoding, errors)
return text.encode(encoding, errors).decode(incoming)
else:
return text.encode(encoding, errors)
elif text and encoding != incoming: elif text and encoding != incoming:
# Decode text before encoding it with `encoding` # Decode text before encoding it with `encoding`
text = safe_decode(text, incoming, errors) text = safe_decode(text, incoming, errors)
if six.PY3: return text.encode(encoding, errors)
return text.encode(encoding, errors).decode(incoming) else:
else: return text
return text.encode(encoding, errors)
return text
def string_to_bytes(text, unit_system='IEC', return_int=False): def string_to_bytes(text, unit_system='IEC', return_int=False):