SickGear/lib/encodingKludge.py

163 lines
4.9 KiB
Python
Raw Normal View History

#
# This file is part of SickGear.
#
# SickGear is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SickGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
import os
import logging
import locale
import sys
from six import iteritems, moves, PY2, text_type, string_types
logger = logging.getLogger('encodingKludge')
logger.addHandler(logging.NullHandler())
# noinspection PyUnreachableCode
if False:
# noinspection PyUnresolvedReferences
from typing import AnyStr
SYS_ENCODING = None
EXIT_BAD_ENCODING = None
def set_sys_encoding():
# type: (...) -> (bool, AnyStr)
"""Set system encoding
:return: The encoding that is set
"""
should_exit = False
try:
locale.setlocale(locale.LC_ALL, '')
except (locale.Error, IOError):
pass
try:
sys_encoding = locale.getpreferredencoding()
except (locale.Error, IOError):
sys_encoding = None
# For OSes that are poorly configured I'll just randomly force UTF-8
if not sys_encoding or sys_encoding in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
sys_encoding = 'UTF-8'
if not hasattr(sys, 'setdefaultencoding'):
moves.reload_module(sys)
if PY2:
try:
# On non-unicode builds this raises an AttributeError,
# if encoding type is not valid it throws a LookupError
# noinspection PyUnresolvedReferences
sys.setdefaultencoding(sys_encoding)
except (BaseException, Exception):
should_exit = True
return should_exit, sys_encoding
if None is EXIT_BAD_ENCODING:
EXIT_BAD_ENCODING, SYS_ENCODING = set_sys_encoding()
# This module tries to deal with the apparently random behavior of python when dealing with unicode <-> utf-8
# encodings. It tries to just use unicode, but if that fails then it tries forcing it to utf-8. Any functions
# which return something should always return unicode.
# noinspection PyCompatibility,PyPep8Naming
def fixStupidEncodings(x, silent=False):
if not PY2:
return x
if str == type(x):
try:
return x.decode(SYS_ENCODING)
except UnicodeDecodeError:
logger.error(u"Unable to decode value: " + repr(x))
elif text_type == type(x):
return x
else:
msg = u"Unknown value passed in, ignoring it: " + str(type(x)) + " (" + repr(x) + ":" + repr(type(x)) + ")"
if silent:
logger.debug(msg)
else:
logger.error(msg)
# noinspection PyCompatibility,PyPep8Naming
def fixOutEncoding(x):
if PY2 and isinstance(x, string_types):
return fixStupidEncodings(x)
return x
# noinspection PyCompatibility,PyPep8Naming
def fixListEncodings(x):
if not PY2 or type(x) not in (list, tuple):
return x
return filter(lambda i: None is not i, map(fixOutEncoding, x))
# noinspection PyCompatibility,PyPep8Naming
def callPeopleStupid(x):
if not PY2:
return x
try:
return x.encode(SYS_ENCODING)
except UnicodeEncodeError:
logger.error(u'Your data is being corrupted by a bad locale/encoding setting.'
u' Report this error in IRC please: %s, %s' % (repr(x), SYS_ENCODING))
return x.encode(SYS_ENCODING, 'ignore')
# noinspection PyCompatibility,PyPep8Naming
def fixParaLists(x):
if PY2 and list == type(x):
return [callPeopleStupid(a) if type(a) in (str, text_type) else a for a in x]
return x
# noinspection PyCompatibility
def win_encode_unicode(x):
if PY2 and isinstance(x, str):
try:
# noinspection PyUnresolvedReferences
return x.decode('UTF-8')
except UnicodeDecodeError:
pass
return x
# noinspection PyCompatibility
def ek(func, *args, **kwargs):
if not PY2:
return func(*args, **kwargs)
if 'nt' == os.name:
# convert all str parameter values to unicode
args = tuple([x if not isinstance(x, str) else win_encode_unicode(x) for x in args])
# iteritems can stay, since this code will not run on py3
kwargs = {k: x if not isinstance(x, str) else win_encode_unicode(x) for k, x in iteritems(kwargs)}
result = func(*args, **kwargs)
else:
result = func(*[callPeopleStupid(x) if type(x) in (str, text_type)
else fixParaLists(x) for x in args], **kwargs)
if type(result) in (list, tuple):
return fixListEncodings(result)
elif type(result) == str:
return fixStupidEncodings(result)
return result