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
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())
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;
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);
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
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)
# 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 == '*':
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":
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)
]),
(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',
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)
--- /dev/null
+from spam import *
+from ...spam.foo import *
+from . import *
+from ... import *
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)
--- /dev/null
+# 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
+"""
--- /dev/null
+from distutils import core, version
+__package__ = 'distutils.core' # fool Python we are in distutils
+from . import *
+
+__doc__ = """
+>>> core.setup == setup
+True
+"""