sphinx/sphinx/util/pycompat.py

165 lines
4.5 KiB
Python

# -*- coding: utf-8 -*-
"""
sphinx.util.pycompat
~~~~~~~~~~~~~~~~~~~~
Stuff for Python version compatibility.
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import sys
import codecs
import encodings
import re
try:
from types import ClassType
class_types = (type, ClassType)
except ImportError:
# Python 3
class_types = (type,)
try:
from itertools import product
except ImportError: # python < 2.6
# this code has been taken from the python documentation
def product(*args, **kwargs):
pools = map(tuple, args) * kwargs.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x + [y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
# the ubiquitous "bytes" helper function
if sys.version_info >= (3, 0):
def b(s):
return s.encode('utf-8')
else:
b = str
# Support for running 2to3 over config files
if sys.version_info < (3, 0):
# no need to refactor on 2.x versions
convert_with_2to3 = None
else:
def convert_with_2to3(filepath):
from lib2to3.refactor import RefactoringTool, get_fixers_from_package
from lib2to3.pgen2.parse import ParseError
fixers = get_fixers_from_package('lib2to3.fixes')
refactoring_tool = RefactoringTool(fixers)
source = refactoring_tool._read_python_source(filepath)[0]
try:
tree = refactoring_tool.refactor_string(source, 'conf.py')
except ParseError, err:
# do not propagate lib2to3 exceptions
lineno, offset = err.context[1]
# try to match ParseError details with SyntaxError details
raise SyntaxError(err.msg, (filepath, lineno, offset, err.value))
return unicode(tree)
try:
base_exception = BaseException
except NameError:
base_exception = Exception
try:
next = next
except NameError:
# this is on Python 2, where the method is called "next" (it is refactored
# to __next__ by 2to3, but in that case never executed)
def next(iterator):
return iterator.next()
try:
bytes = bytes
except NameError:
bytes = str
try:
any = any
all = all
except NameError:
def all(gen):
for i in gen:
if not i:
return False
return True
def any(gen):
for i in gen:
if i:
return True
return False
if sys.version_info < (2, 5):
# Python 2.4 doesn't know the utf-8-sig encoding, so deliver it here
def my_search_function(encoding):
norm_encoding = encodings.normalize_encoding(encoding)
if norm_encoding != 'utf_8_sig':
return None
return (encode, decode, StreamReader, StreamWriter)
codecs.register(my_search_function)
# begin code copied from utf_8_sig.py in Python 2.6
def encode(input, errors='strict'):
return (codecs.BOM_UTF8 +
codecs.utf_8_encode(input, errors)[0], len(input))
def decode(input, errors='strict'):
prefix = 0
if input[:3] == codecs.BOM_UTF8:
input = input[3:]
prefix = 3
(output, consumed) = codecs.utf_8_decode(input, errors, True)
return (output, consumed+prefix)
class StreamWriter(codecs.StreamWriter):
def reset(self):
codecs.StreamWriter.reset(self)
try:
del self.encode
except AttributeError:
pass
def encode(self, input, errors='strict'):
self.encode = codecs.utf_8_encode
return encode(input, errors)
class StreamReader(codecs.StreamReader):
def reset(self):
codecs.StreamReader.reset(self)
try:
del self.decode
except AttributeError:
pass
def decode(self, input, errors='strict'):
if len(input) < 3:
if codecs.BOM_UTF8.startswith(input):
# not enough data to decide if this is a BOM
# => try again on the next call
return (u"", 0)
elif input[:3] == codecs.BOM_UTF8:
self.decode = codecs.utf_8_decode
(output, consumed) = codecs.utf_8_decode(input[3:],errors)
return (output, consumed+3)
# (else) no BOM present
self.decode = codecs.utf_8_decode
return codecs.utf_8_decode(input, errors)
# end code copied from utf_8_sig.py