diff --git a/sphinx/config.py b/sphinx/config.py index 0374df977..36a5b862a 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -16,8 +16,8 @@ from os import path from sphinx.errors import ConfigError from sphinx.locale import l_ -from sphinx.util.osutil import make_filename, fs_encoding -from sphinx.util.pycompat import bytes, b, convert_with_2to3 +from sphinx.util.osutil import make_filename +from sphinx.util.pycompat import bytes, b, execfile_ nonascii_re = re.compile(b(r'[\x80-\xff]')) @@ -219,27 +219,8 @@ class Config(object): # we promise to have the config dir as current dir while the # config file is executed os.chdir(dirname) - # get config source -- 'b' is a no-op under 2.x, while 'U' is - # ignored under 3.x (but 3.x compile() accepts \r\n newlines) - f = open(filename, 'rbU') try: - source = f.read() - finally: - f.close() - try: - # compile to a code object, handle syntax errors - config_file_enc = config_file.encode(fs_encoding) - try: - code = compile(source, config_file_enc, 'exec') - except SyntaxError: - if convert_with_2to3: - # maybe the file uses 2.x syntax; try to refactor to - # 3.x syntax using 2to3 - source = convert_with_2to3(config_file) - code = compile(source, config_file_enc, 'exec') - else: - raise - exec code in config + execfile_(filename, config) except SyntaxError, err: raise ConfigError(CONFIG_SYNTAX_ERROR % err) finally: diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index b373c5049..e4e4acc2a 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -64,6 +64,35 @@ else: return s.encode('ascii', 'backslashreplace') +def execfile_(filepath, _globals): + from sphinx.util.osutil import fs_encoding + # get config source -- 'b' is a no-op under 2.x, while 'U' is + # ignored under 3.x (but 3.x compile() accepts \r\n newlines) + f = open(filepath, 'rbU') + try: + source = f.read() + finally: + f.close() + + # py25,py26,py31 accept only LF eol instead of CRLF + if sys.version_info[:2] in ((2, 5), (2, 6), (3, 1)): + source = source.replace(b('\r\n'), b('\n')) + + # compile to a code object, handle syntax errors + filepath_enc = filepath.encode(fs_encoding) + try: + code = compile(source, filepath_enc, 'exec') + except SyntaxError: + if convert_with_2to3: + # maybe the file uses 2.x syntax; try to refactor to + # 3.x syntax using 2to3 + source = convert_with_2to3(filepath) + code = compile(source, filepath_enc, 'exec') + else: + raise + exec code in _globals + + try: from html import escape as htmlescape except ImportError: diff --git a/tests/test_config.py b/tests/test_config.py index 69858a200..84a3b4b77 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -16,6 +16,7 @@ from util import * import sphinx from sphinx.config import Config from sphinx.errors import ExtensionError, ConfigError, VersionRequirementError +from sphinx.util.pycompat import b @with_app(confoverrides={'master_doc': 'master', 'nonexisting_value': 'True', @@ -113,3 +114,14 @@ def test_errors_warnings(dir): def test_needs_sphinx(): raises(VersionRequirementError, TestApp, confoverrides={'needs_sphinx': '9.9'}) + + +@with_tempdir +def test_config_eol(tmpdir): + # test config file's eol patterns: LF, CRLF + configfile = tmpdir / 'conf.py' + for eol in ('\n', '\r\n'): + configfile.write_bytes(b('project = "spam"' + eol)) + cfg = Config(tmpdir, 'conf.py', {}, None) + cfg.init_values() + assert cfg.project == u'spam' diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index ff1f75684..69839da9e 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -16,6 +16,7 @@ from util import * from sphinx import quickstart as qs from sphinx.util.console import nocolor, coloron +from sphinx.util.pycompat import execfile_ def setup_module(): nocolor() @@ -110,12 +111,7 @@ def test_quickstart_defaults(tempdir): conffile = tempdir / 'conf.py' assert conffile.isfile() ns = {} - f = open(conffile, 'rbU') - try: - code = compile(f.read(), conffile, 'exec') - finally: - f.close() - exec code in ns + execfile_(conffile, ns) assert ns['extensions'] == [] assert ns['templates_path'] == ['_templates'] assert ns['source_suffix'] == '.rst' @@ -170,12 +166,7 @@ def test_quickstart_all_answers(tempdir): conffile = tempdir / 'source' / 'conf.py' assert conffile.isfile() ns = {} - f = open(conffile, 'rbU') - try: - code = compile(f.read(), conffile, 'exec') - finally: - f.close() - exec code in ns + execfile_(conffile, ns) assert ns['extensions'] == ['sphinx.ext.autodoc', 'sphinx.ext.doctest'] assert ns['templates_path'] == ['.templates'] assert ns['source_suffix'] == '.txt'