summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2011-09-19 09:03:07 +0200
committerGeorg Brandl <georg@python.org>2011-09-19 09:03:07 +0200
commit0a9c4d641f1c1f9f6e9ec0ec1fc10f22c4e57e99 (patch)
treea8f2d9cbefc14fb1c01e31fcc22833f8e08c0bc0
parentc1e0adeed0bb2288a147e922e8a88f5663a69f48 (diff)
downloadsphinx-0a9c4d641f1c1f9f6e9ec0ec1fc10f22c4e57e99.tar.gz
Fix #705: read module source in ModuleAnalyzer in binary mode, decode afterwards.
-rw-r--r--sphinx/pycode/__init__.py23
-rw-r--r--sphinx/util/pycompat.py6
2 files changed, 21 insertions, 8 deletions
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index ab87e61d..ac840750 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -10,13 +10,12 @@
"""
from os import path
-from cStringIO import StringIO
from sphinx.errors import PycodeError
from sphinx.pycode import nodes
from sphinx.pycode.pgen2 import driver, token, tokenize, parse, literals
from sphinx.util import get_module_source, detect_encoding
-from sphinx.util.pycompat import next
+from sphinx.util.pycompat import next, StringIO, BytesIO, TextIOWrapper
from sphinx.util.docstrings import prepare_docstring, prepare_commentdoc
@@ -170,14 +169,16 @@ class ModuleAnalyzer(object):
@classmethod
def for_string(cls, string, modname, srcname='<string>'):
- return cls(StringIO(string), modname, srcname)
+ if isinstance(string, bytes):
+ return cls(BytesIO(string), modname, srcname)
+ return cls(StringIO(string), modname, srcname, decoded=True)
@classmethod
def for_file(cls, filename, modname):
if ('file', filename) in cls.cache:
return cls.cache['file', filename]
try:
- fileobj = open(filename, 'r')
+ fileobj = open(filename, 'rb')
except Exception, err:
raise PycodeError('error opening %r' % filename, err)
obj = cls(fileobj, modname, filename)
@@ -204,7 +205,7 @@ class ModuleAnalyzer(object):
cls.cache['module', modname] = obj
return obj
- def __init__(self, source, modname, srcname):
+ def __init__(self, source, modname, srcname, decoded=False):
# name of the module
self.modname = modname
# name of the source file
@@ -214,9 +215,15 @@ class ModuleAnalyzer(object):
# cache the source code as well
pos = self.source.tell()
- self.encoding = detect_encoding(self.source.readline)
- self.code = self.source.read()
- self.source.seek(pos)
+ if not decoded:
+ self.encoding = detect_encoding(self.source.readline)
+ self.code = self.source.read().decode(self.encoding)
+ self.source.seek(pos)
+ self.source = TextIOWrapper(self.source, self.encoding)
+ else:
+ self.encoding = None
+ self.code = self.source.read()
+ self.source.seek(pos)
# will be filled by tokenize()
self.tokens = None
diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py
index a95c9332..375f6920 100644
--- a/sphinx/util/pycompat.py
+++ b/sphinx/util/pycompat.py
@@ -25,6 +25,8 @@ if sys.version_info >= (3, 0):
bytes = bytes
# prefix for Unicode strings
u = ''
+ # StringIO/BytesIO classes
+ from io import StringIO, BytesIO, TextIOWrapper
# support for running 2to3 over config files
def convert_with_2to3(filepath):
from lib2to3.refactor import RefactoringTool, get_fixers_from_package
@@ -48,8 +50,12 @@ else:
b = str
bytes = str
u = 'u'
+ from StringIO import StringIO
+ BytesIO = StringIO
# no need to refactor on 2.x versions
convert_with_2to3 = None
+ def TextIOWrapper(stream, encoding):
+ return codecs.lookup(encoding or 'ascii')[2](stream)
# ------------------------------------------------------------------------------