Commit 599c3405 authored by Haoyu Bai's avatar Haoyu Bai Committed by Robert Bradshaw

T542 relative import

parent f8b6ad84
...@@ -1735,14 +1735,20 @@ class BackquoteNode(ExprNode): ...@@ -1735,14 +1735,20 @@ class BackquoteNode(ExprNode):
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
class ImportNode(ExprNode): class ImportNode(ExprNode):
# Used as part of import statement implementation. # Used as part of import statement implementation.
# Implements result = # 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 # 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 type = py_object_type
...@@ -1765,10 +1771,11 @@ class ImportNode(ExprNode): ...@@ -1765,10 +1771,11 @@ class ImportNode(ExprNode):
else: else:
name_list_code = "0" name_list_code = "0"
code.putln( code.putln(
"%s = __Pyx_Import(%s, %s); %s" % ( "%s = __Pyx_Import(%s, %s, %d); %s" % (
self.result(), self.result(),
self.module_name.py_result(), self.module_name.py_result(),
name_list_code, name_list_code,
self.level,
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
...@@ -7659,10 +7666,10 @@ static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { ...@@ -7659,10 +7666,10 @@ static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
import_utility_code = UtilityCode( import_utility_code = UtilityCode(
proto = """ proto = """
static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, long level); /*proto*/
""", """,
impl = """ 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 *py_import = 0;
PyObject *empty_list = 0; PyObject *empty_list = 0;
PyObject *module = 0; PyObject *module = 0;
...@@ -7686,8 +7693,23 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) { ...@@ -7686,8 +7693,23 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
empty_dict = PyDict_New(); empty_dict = PyDict_New();
if (!empty_dict) if (!empty_dict)
goto bad; 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, module = PyObject_CallFunctionObjArgs(py_import,
name, global_dict, empty_dict, list, NULL); name, global_dict, empty_dict, list, NULL);
#endif
bad: bad:
Py_XDECREF(empty_list); Py_XDECREF(empty_list);
Py_XDECREF(py_import); Py_XDECREF(py_import);
......
...@@ -1189,6 +1189,8 @@ def p_raise_statement(s): ...@@ -1189,6 +1189,8 @@ def p_raise_statement(s):
return Nodes.ReraiseStatNode(pos) return Nodes.ReraiseStatNode(pos)
def p_import_statement(s): 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') # s.sy in ('import', 'cimport')
pos = s.position() pos = s.position()
kind = s.sy kind = s.sy
...@@ -1216,6 +1218,7 @@ def p_import_statement(s): ...@@ -1216,6 +1218,7 @@ def p_import_statement(s):
rhs = ExprNodes.ImportNode(pos, rhs = ExprNodes.ImportNode(pos,
module_name = ExprNodes.IdentifierStringNode( module_name = ExprNodes.IdentifierStringNode(
pos, value = dotted_name), pos, value = dotted_name),
level = level,
name_list = name_list)) name_list = name_list))
stats.append(stat) stats.append(stat)
return Nodes.StatListNode(pos, stats = stats) return Nodes.StatListNode(pos, stats = stats)
...@@ -1224,6 +1227,22 @@ def p_from_import_statement(s, first_statement = 0): ...@@ -1224,6 +1227,22 @@ def p_from_import_statement(s, first_statement = 0):
# s.sy == 'from' # s.sy == 'from'
pos = s.position() pos = s.position()
s.next() s.next()
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, _) = \ (dotted_name_pos, _, dotted_name, _) = \
p_dotted_name(s, as_allowed = 0) p_dotted_name(s, as_allowed = 0)
if s.sy in ('import', 'cimport'): if s.sy in ('import', 'cimport'):
...@@ -1231,6 +1250,7 @@ def p_from_import_statement(s, first_statement = 0): ...@@ -1231,6 +1250,7 @@ def p_from_import_statement(s, first_statement = 0):
s.next() s.next()
else: else:
s.error("Expected 'import' or 'cimport'") s.error("Expected 'import' or 'cimport'")
is_cimport = kind == 'cimport' is_cimport = kind == 'cimport'
is_parenthesized = False is_parenthesized = False
if s.sy == '*': if s.sy == '*':
...@@ -1252,6 +1272,8 @@ def p_from_import_statement(s, first_statement = 0): ...@@ -1252,6 +1272,8 @@ def p_from_import_statement(s, first_statement = 0):
if dotted_name == '__future__': if dotted_name == '__future__':
if not first_statement: if not first_statement:
s.error("from __future__ imports must occur at the beginning of the file") s.error("from __future__ imports must occur at the beginning of the file")
elif level is not None:
s.error("invalid syntax")
else: else:
for (name_pos, name, as_name, kind) in imported_names: for (name_pos, name, as_name, kind) in imported_names:
if name == "braces": if name == "braces":
...@@ -1285,6 +1307,7 @@ def p_from_import_statement(s, first_statement = 0): ...@@ -1285,6 +1307,7 @@ def p_from_import_statement(s, first_statement = 0):
return Nodes.FromImportStatNode(pos, return Nodes.FromImportStatNode(pos,
module = ExprNodes.ImportNode(dotted_name_pos, module = ExprNodes.ImportNode(dotted_name_pos,
module_name = ExprNodes.IdentifierStringNode(pos, value = dotted_name), module_name = ExprNodes.IdentifierStringNode(pos, value = dotted_name),
level = level,
name_list = import_list), name_list = import_list),
items = items) items = items)
......
...@@ -93,6 +93,7 @@ VER_DEP_MODULES = { ...@@ -93,6 +93,7 @@ VER_DEP_MODULES = {
]), ]),
(2,5) : (operator.lt, lambda x: x in ['run.any', (2,5) : (operator.lt, lambda x: x in ['run.any',
'run.all', 'run.all',
'run.relativeimport_T542',
]), ]),
(2,6) : (operator.lt, lambda x: x in ['run.print_function', (2,6) : (operator.lt, lambda x: x in ['run.print_function',
'run.cython3', 'run.cython3',
......
...@@ -4,4 +4,12 @@ def f(): ...@@ -4,4 +4,12 @@ def f():
from spam import eggs from spam import eggs
from spam.morespam import bacon, eggs, ham from spam.morespam import bacon, eggs, ham
from spam import eggs as ova 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(): ...@@ -61,16 +61,16 @@ def typed_imports():
cdef type t cdef type t
from sys import maxunicode from sys import maxunicode
print maxunicode == sys.maxunicode print(maxunicode == sys.maxunicode)
from types import ModuleType as t from types import ModuleType as t
print t is types.ModuleType print(t is types.ModuleType)
try: try:
from sys import version_info as maxunicode from sys import version_info as maxunicode
except TypeError, e: except TypeError, e:
print e print(e)
try: try:
from sys import maxunicode as t from sys import maxunicode as t
except TypeError, e: 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