Commit dee6b6dd authored by Haoyu Bai's avatar Haoyu Bai Committed by Robert Bradshaw

T542 relative import

parent de4f3aa8
......@@ -1735,14 +1735,20 @@ class BackquoteNode(ExprNode):
code.put_gotref(self.py_result())
class ImportNode(ExprNode):
# Used as part of import statement implementation.
# Implements result =
# __import__(module_name, globals(), None, name_list)
# __import__(module_name, globals(), None, name_list, level)
#
# module_name StringNode dotted name of module
# module_name StringNode dotted name of module. Empty module
# name means importing the parent package accourding
# to level
# name_list ListNode or None list of names to be imported
# level int relative import level:
# -1: attempt both relative import and absolute import;
# 0: absolute import;
# >0: the number of parent directories to search
# relative to the current module.
type = py_object_type
......@@ -1765,10 +1771,11 @@ class ImportNode(ExprNode):
else:
name_list_code = "0"
code.putln(
"%s = __Pyx_Import(%s, %s); %s" % (
"%s = __Pyx_Import(%s, %s, %d); %s" % (
self.result(),
self.module_name.py_result(),
name_list_code,
self.level,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
......@@ -7659,10 +7666,10 @@ static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
import_utility_code = UtilityCode(
proto = """
static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, long level); /*proto*/
""",
impl = """
static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, long level) {
PyObject *py_import = 0;
PyObject *empty_list = 0;
PyObject *module = 0;
......@@ -7686,8 +7693,23 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
empty_dict = PyDict_New();
if (!empty_dict)
goto bad;
#if PY_VERSION_HEX >= 0x02050000
{
PyObject *py_level = PyInt_FromLong(level);
if (!py_level)
goto bad;
module = PyObject_CallFunctionObjArgs(py_import,
name, global_dict, empty_dict, list, py_level, NULL);
Py_DECREF(py_level);
}
#else
if (level>0) {
PyErr_SetString(PyExc_RuntimeError, "Relative import is not supported for Python <=2.4.");
goto bad;
}
module = PyObject_CallFunctionObjArgs(py_import,
name, global_dict, empty_dict, list, NULL);
#endif
bad:
Py_XDECREF(empty_list);
Py_XDECREF(py_import);
......
......@@ -1189,6 +1189,8 @@ def p_raise_statement(s):
return Nodes.ReraiseStatNode(pos)
def p_import_statement(s):
# will do absolute import in Py3 and try both relative and absolute in Py2.
level = 0 if s.context.language_level >= 3 else -1
# s.sy in ('import', 'cimport')
pos = s.position()
kind = s.sy
......@@ -1216,6 +1218,7 @@ def p_import_statement(s):
rhs = ExprNodes.ImportNode(pos,
module_name = ExprNodes.IdentifierStringNode(
pos, value = dotted_name),
level = level,
name_list = name_list))
stats.append(stat)
return Nodes.StatListNode(pos, stats = stats)
......@@ -1224,13 +1227,30 @@ def p_from_import_statement(s, first_statement = 0):
# s.sy == 'from'
pos = s.position()
s.next()
(dotted_name_pos, _, dotted_name, _) = \
p_dotted_name(s, as_allowed = 0)
if s.sy == '.':
# count relative import level
level = 0
while s.sy == '.':
level += 1
s.next()
else:
# will do absolute import in Py3 and try both relative and absolute in Py2.
level = 0 if s.context.language_level >= 3 else -1
if level > 0 and s.sy == 'cimport':
s.error("Relative cimport is not supported yet")
if level > 0 and s.sy == 'import':
# we are dealing with "from .. import foo, bar"
dotted_name_pos, dotted_name = s.position(), ''
else:
(dotted_name_pos, _, dotted_name, _) = \
p_dotted_name(s, as_allowed = 0)
if s.sy in ('import', 'cimport'):
kind = s.sy
s.next()
else:
s.error("Expected 'import' or 'cimport'")
is_cimport = kind == 'cimport'
is_parenthesized = False
if s.sy == '*':
......@@ -1252,6 +1272,8 @@ def p_from_import_statement(s, first_statement = 0):
if dotted_name == '__future__':
if not first_statement:
s.error("from __future__ imports must occur at the beginning of the file")
elif level is not None:
s.error("invalid syntax")
else:
for (name_pos, name, as_name, kind) in imported_names:
if name == "braces":
......@@ -1285,6 +1307,7 @@ def p_from_import_statement(s, first_statement = 0):
return Nodes.FromImportStatNode(pos,
module = ExprNodes.ImportNode(dotted_name_pos,
module_name = ExprNodes.IdentifierStringNode(pos, value = dotted_name),
level = level,
name_list = import_list),
items = items)
......
......@@ -93,6 +93,7 @@ VER_DEP_MODULES = {
]),
(2,5) : (operator.lt, lambda x: x in ['run.any',
'run.all',
'run.relativeimport_T542',
]),
(2,6) : (operator.lt, lambda x: x in ['run.print_function',
'run.cython3',
......
......@@ -4,4 +4,12 @@ def f():
from spam import eggs
from spam.morespam import bacon, eggs, ham
from spam import eggs as ova
from . import spam
from ... import spam
from .. import spam, foo
from ... import spam, foobar
from .spam import foo
from ...spam import foo, bar
from ...spam.foo import bar
from ...spam.foo import foo, bar
from ...spam.foo import (foo, bar)
from spam import *
from ...spam.foo import *
from . import *
from ... import *
......@@ -61,16 +61,16 @@ def typed_imports():
cdef type t
from sys import maxunicode
print maxunicode == sys.maxunicode
print(maxunicode == sys.maxunicode)
from types import ModuleType as t
print t is types.ModuleType
print(t is types.ModuleType)
try:
from sys import version_info as maxunicode
except TypeError, e:
print e
print(e)
try:
from sys import maxunicode as t
except TypeError, e:
print e
print(e)
# cython: language_level=3
__name__='distutils.baregg' # fool Python we are in distutils
from distutils import cmd, core, version
from .core import *
def test_relative():
"""
>>> test_relative() == (cmd, core, 'distutils.version')
True
"""
from . import cmd, core
from . import (version, core)
from .version import __name__
return cmd, core, __name__
def test_absolute():
"""
>>> test_absolute()
Traceback (most recent call last):
...
ImportError: No module named debug
"""
import debug
return
__doc__ = """
>>> setup == core.setup
True
"""
from distutils import core, version
__package__ = 'distutils.core' # fool Python we are in distutils
from . import *
__doc__ = """
>>> core.setup == setup
True
"""
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment