Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cython
Commits
c97860d3
Commit
c97860d3
authored
Feb 23, 2019
by
Stefan Behnel
Committed by
GitHub
Feb 23, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2859 from cython/faster_absolute_reimports
Faster absolute reimports
parents
dad0100c
96879038
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
211 additions
and
50 deletions
+211
-50
CHANGES.rst
CHANGES.rst
+3
-0
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+34
-17
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+2
-6
Cython/Utility/ImportExport.c
Cython/Utility/ImportExport.c
+156
-22
tests/run/importas.pyx
tests/run/importas.pyx
+10
-0
tests/run/reimport_from_package.srctree
tests/run/reimport_from_package.srctree
+4
-4
tests/run/relativeimport_T542.srctree
tests/run/relativeimport_T542.srctree
+2
-1
No files found.
CHANGES.rst
View file @
c97860d3
...
...
@@ -8,6 +8,9 @@ Cython Changelog
Features
added
--------------
*
Reimports
of
already
imported
modules
are
substantially
faster
.
(
Github
issue
#
2854
)
*
The
``
volatile
``
C
modifier
is
supported
in
Cython
code
.
Patch
by
Jeroen
Demeyer
.
(
Github
issue
#
1667
)
...
...
Cython/Compiler/ExprNodes.py
View file @
c97860d3
...
...
@@ -2527,44 +2527,61 @@ class ImportNode(ExprNode):
# relative to the current module.
# None: decide the level according to language level and
# directives
# get_top_level_module int true: return top-level module, false: return imported module
# module_names TupleNode the separate names of the module and submodules, or None
type
=
py_object_type
module_names
=
None
get_top_level_module
=
False
is_temp
=
True
subexprs
=
[
'module_name'
,
'name_list'
]
subexprs
=
[
'module_name'
,
'name_list'
,
'module_names'
]
def
analyse_types
(
self
,
env
):
if
self
.
level
is
None
:
if
(
env
.
directives
[
'py2_import'
]
or
# For modules in packages, and without 'absolute_import' enabled, try relative (Py2) import first.
if
env
.
global_scope
().
parent_module
and
(
env
.
directives
[
'py2_import'
]
or
Future
.
absolute_import
not
in
env
.
global_scope
().
context
.
future_directives
):
self
.
level
=
-
1
else
:
self
.
level
=
0
module_name
=
self
.
module_name
.
analyse_types
(
env
)
self
.
module_name
=
module_name
.
coerce_to_pyobject
(
env
)
assert
self
.
module_name
.
is_string_literal
if
self
.
name_list
:
name_list
=
self
.
name_list
.
analyse_types
(
env
)
self
.
name_list
=
name_list
.
coerce_to_pyobject
(
env
)
self
.
is_temp
=
1
elif
'.'
in
self
.
module_name
.
value
:
self
.
module_names
=
TupleNode
(
self
.
module_name
.
pos
,
args
=
[
IdentifierStringNode
(
self
.
module_name
.
pos
,
value
=
part
,
constant_result
=
part
)
for
part
in
map
(
StringEncoding
.
EncodedString
,
self
.
module_name
.
value
.
split
(
'.'
))
]).
analyse_types
(
env
)
return
self
gil_message
=
"Python import"
def
generate_result_code
(
self
,
code
):
if
self
.
name_list
:
name_list_code
=
self
.
name_list
.
py_result
()
assert
self
.
module_name
.
is_string_literal
module_name
=
self
.
module_name
.
value
if
self
.
level
==
0
and
not
self
.
name_list
and
not
self
.
get_top_level_module
:
if
self
.
module_names
:
assert
self
.
module_names
.
is_literal
# make sure we create the tuple only once
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"ImportDottedModule"
,
"ImportExport.c"
))
import_code
=
"__Pyx_ImportDottedModule(%s, %s)"
%
(
self
.
module_name
.
py_result
(),
self
.
module_names
.
py_result
()
if
self
.
module_names
else
'NULL'
,
)
else
:
name_list_code
=
"0"
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"Import"
,
"ImportExport.c"
))
import_code
=
"__Pyx_Import(%s, %s, %d)"
%
(
self
.
module_name
.
py_result
(),
name_list_code
,
self
.
name_list
.
py_result
()
if
self
.
name_list
else
'0'
,
self
.
level
)
if
(
self
.
level
<=
0
and
self
.
module_name
.
is_string_literal
and
self
.
module_name
.
value
in
utility_code_for_imports
):
helper_func
,
code_name
,
code_file
=
utility_code_for_imports
[
self
.
module_name
.
value
]
if
self
.
level
<=
0
and
module_name
in
utility_code_for_imports
:
helper_func
,
code_name
,
code_file
=
utility_code_for_imports
[
module_name
]
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
code_name
,
code_file
))
import_code
=
'%s(%s)'
%
(
helper_func
,
import_code
)
...
...
Cython/Compiler/Parsing.py
View file @
c97860d3
...
...
@@ -1675,11 +1675,6 @@ def p_import_statement(s):
as_name
=
as_name
,
is_absolute
=
is_absolute
)
else
:
if
as_name
and
"."
in
dotted_name
:
name_list
=
ExprNodes
.
ListNode
(
pos
,
args
=
[
ExprNodes
.
IdentifierStringNode
(
pos
,
value
=
s
.
context
.
intern_ustring
(
"*"
))])
else
:
name_list
=
None
stat
=
Nodes
.
SingleAssignmentNode
(
pos
,
lhs
=
ExprNodes
.
NameNode
(
pos
,
name
=
as_name
or
target_name
),
...
...
@@ -1687,7 +1682,8 @@ def p_import_statement(s):
pos
,
module_name
=
ExprNodes
.
IdentifierStringNode
(
pos
,
value
=
dotted_name
),
level
=
0
if
is_absolute
else
None
,
name_list
=
name_list
))
get_top_level_module
=
'.'
in
dotted_name
and
as_name
is
None
,
name_list
=
None
))
stats
.
append
(
stat
)
return
Nodes
.
StatListNode
(
pos
,
stats
=
stats
)
...
...
Cython/Utility/ImportExport.c
View file @
c97860d3
...
...
@@ -9,6 +9,147 @@
#endif
/////////////// ImportDottedModule.proto ///////////////
static
PyObject
*
__Pyx_ImportDottedModule
(
PyObject
*
name
,
PyObject
*
parts_tuple
);
/*proto*/
/////////////// ImportDottedModule ///////////////
//@requires: Import
#if PY_MAJOR_VERSION >= 3
static
PyObject
*
__Pyx__ImportDottedModule_Error
(
PyObject
*
name
,
PyObject
*
parts_tuple
,
Py_ssize_t
count
)
{
PyObject
*
partial_name
=
NULL
,
*
slice
=
NULL
,
*
sep
=
NULL
;
if
(
unlikely
(
PyErr_Occurred
()))
{
PyErr_Clear
();
}
if
(
likely
(
PyTuple_GET_SIZE
(
parts_tuple
)
==
count
))
{
partial_name
=
name
;
}
else
{
PyObject
*
sep
;
PyObject
*
slice
=
PySequence_GetSlice
(
parts_tuple
,
0
,
count
);
if
(
unlikely
(
!
slice
))
goto
bad
;
sep
=
PyUnicode_FromStringAndSize
(
"."
,
1
);
if
(
unlikely
(
!
sep
))
goto
bad
;
partial_name
=
PyUnicode_Join
(
sep
,
slice
);
}
PyErr_Format
(
#if PY_MAJOR_VERSION < 3
PyExc_ImportError
,
"No module named '%s'"
,
PyString_AS_STRING
(
partial_name
));
#else
#if PY_VERSION_HEX >= 0x030600B1
PyExc_ModuleNotFoundError
,
#else
PyExc_ImportError
,
#endif
"No module named '%U'"
,
partial_name
);
#endif
bad:
Py_XDECREF
(
sep
);
Py_XDECREF
(
slice
);
Py_XDECREF
(
partial_name
);
return
NULL
;
}
#endif
#if PY_MAJOR_VERSION >= 3
static
PyObject
*
__Pyx__ImportDottedModule_Lookup
(
PyObject
*
name
)
{
PyObject
*
imported_module
;
#if PY_VERSION_HEX < 0x030700A1
PyObject
*
modules
=
PyImport_GetModuleDict
();
if
(
unlikely
(
!
modules
))
return
NULL
;
imported_module
=
__Pyx_PyDict_GetItemStr
(
modules
,
name
);
Py_XINCREF
(
imported_module
);
#else
imported_module
=
PyImport_GetModule
(
name
);
#endif
return
imported_module
;
}
#endif
static
PyObject
*
__Pyx__ImportDottedModule
(
PyObject
*
name
,
CYTHON_UNUSED
PyObject
*
parts_tuple
)
{
#if PY_MAJOR_VERSION < 3
PyObject
*
module
,
*
from_list
,
*
star
=
PYIDENT
(
"*"
);
from_list
=
PyList_New
(
1
);
if
(
unlikely
(
!
from_list
))
return
NULL
;
Py_INCREF
(
star
);
PyList_SET_ITEM
(
from_list
,
0
,
star
);
module
=
__Pyx_Import
(
name
,
from_list
,
0
);
Py_DECREF
(
from_list
);
return
module
;
#else
Py_ssize_t
i
,
nparts
;
PyObject
*
imported_module
;
PyObject
*
module
=
__Pyx_Import
(
name
,
NULL
,
0
);
if
(
!
parts_tuple
||
unlikely
(
!
module
))
return
module
;
// Look up module in sys.modules, which is safer than the attribute lookups below.
imported_module
=
__Pyx__ImportDottedModule_Lookup
(
name
);
if
(
likely
(
imported_module
))
{
Py_DECREF
(
module
);
return
imported_module
;
}
PyErr_Clear
();
nparts
=
PyTuple_GET_SIZE
(
parts_tuple
);
for
(
i
=
1
;
i
<
nparts
&&
module
;
i
++
)
{
PyObject
*
part
,
*
submodule
;
#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
part
=
PyTuple_GET_ITEM
(
parts_tuple
,
i
);
#else
part
=
PySequence_ITEM
(
parts_tuple
,
i
);
#endif
submodule
=
__Pyx_PyObject_GetAttrStrNoError
(
module
,
part
);
#if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS)
Py_DECREF
(
part
);
#endif
Py_DECREF
(
module
);
module
=
submodule
;
}
if
(
likely
(
module
))
return
module
;
return
__Pyx__ImportDottedModule_Error
(
name
,
parts_tuple
,
i
);
#endif
}
static
PyObject
*
__Pyx_ImportDottedModule
(
PyObject
*
name
,
PyObject
*
parts_tuple
)
{
#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030400B1
PyObject
*
module
=
__Pyx__ImportDottedModule_Lookup
(
name
);
if
(
likely
(
module
))
{
// CPython guards against thread-concurrent initialisation in importlib.
// In this case, we let PyImport_ImportModuleLevelObject() handle the locking.
PyObject
*
spec
=
__Pyx_PyObject_GetAttrStrNoError
(
module
,
PYIDENT
(
"__spec__"
));
if
(
likely
(
spec
))
{
PyObject
*
unsafe
=
__Pyx_PyObject_GetAttrStrNoError
(
spec
,
PYIDENT
(
"_initializing"
));
if
(
likely
(
!
unsafe
||
!
__Pyx_PyObject_IsTrue
(
unsafe
)))
{
Py_DECREF
(
spec
);
spec
=
NULL
;
}
Py_XDECREF
(
unsafe
);
}
if
(
likely
(
!
spec
))
{
// Not in initialisation phase => use modules as is.
PyErr_Clear
();
return
module
;
}
Py_DECREF
(
spec
);
Py_DECREF
(
module
);
}
else
if
(
PyErr_Occurred
())
{
PyErr_Clear
();
}
#endif
return
__Pyx__ImportDottedModule
(
name
,
parts_tuple
);
}
/////////////// Import.proto ///////////////
static
PyObject
*
__Pyx_Import
(
PyObject
*
name
,
PyObject
*
from_list
,
int
level
);
/*proto*/
...
...
@@ -18,30 +159,23 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); /
//@substitute: naming
static
PyObject
*
__Pyx_Import
(
PyObject
*
name
,
PyObject
*
from_list
,
int
level
)
{
PyObject
*
empty_list
=
0
;
PyObject
*
module
=
0
;
PyObject
*
global_dict
=
0
;
PyObject
*
empty_dict
=
0
;
PyObject
*
list
;
PyObject
*
empty_list
=
0
;
#if PY_MAJOR_VERSION < 3
PyObject
*
py_import
;
py_import
=
__Pyx_PyObject_GetAttrStr
(
$
builtins_cname
,
PYIDENT
(
"__import__"
));
if
(
!
py_import
)
if
(
unlikely
(
!
py_import
)
)
goto
bad
;
#endif
if
(
from_list
)
list
=
from_list
;
else
{
if
(
!
from_list
)
{
empty_list
=
PyList_New
(
0
);
if
(
!
empty_list
)
if
(
unlikely
(
!
empty_list
)
)
goto
bad
;
list
=
empty_list
;
from_
list
=
empty_list
;
}
global_dict
=
PyModule_GetDict
(
$
module_cname
);
if
(
!
global_dict
)
goto
bad
;
#endif
empty_dict
=
PyDict_New
();
if
(
!
empty_dict
)
if
(
unlikely
(
!
empty_dict
)
)
goto
bad
;
{
#if PY_MAJOR_VERSION >= 3
...
...
@@ -49,9 +183,9 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
if
(
strchr
(
__Pyx_MODULE_NAME
,
'.'
))
{
/* try package relative import first */
module
=
PyImport_ImportModuleLevelObject
(
name
,
global_dict
,
empty_dict
,
list
,
1
);
if
(
!
module
)
{
if
(
!
PyErr_ExceptionMatches
(
PyExc_ImportError
))
name
,
$
moddict_cname
,
empty_dict
,
from_
list
,
1
);
if
(
unlikely
(
!
module
)
)
{
if
(
unlikely
(
!
PyErr_ExceptionMatches
(
PyExc_ImportError
)
))
goto
bad
;
PyErr_Clear
();
}
...
...
@@ -62,23 +196,23 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
if
(
!
module
)
{
#if PY_MAJOR_VERSION < 3
PyObject
*
py_level
=
PyInt_FromLong
(
level
);
if
(
!
py_level
)
if
(
unlikely
(
!
py_level
)
)
goto
bad
;
module
=
PyObject_CallFunctionObjArgs
(
py_import
,
name
,
global_dict
,
empty_dict
,
list
,
py_level
,
(
PyObject
*
)
NULL
);
name
,
$
moddict_cname
,
empty_dict
,
from_
list
,
py_level
,
(
PyObject
*
)
NULL
);
Py_DECREF
(
py_level
);
#else
module
=
PyImport_ImportModuleLevelObject
(
name
,
global_dict
,
empty_dict
,
list
,
level
);
name
,
$
moddict_cname
,
empty_dict
,
from_
list
,
level
);
#endif
}
}
bad:
Py_XDECREF
(
empty_dict
);
Py_XDECREF
(
empty_list
);
#if PY_MAJOR_VERSION < 3
Py_XDECREF
(
py_import
);
#endif
Py_XDECREF
(
empty_list
);
Py_XDECREF
(
empty_dict
);
return
module
;
}
...
...
tests/run/importas.pyx
View file @
c97860d3
# mode: run
# tag: all_language_levels
__doc__
=
u"""
>>> try: sys
... except NameError: pass
... else: print("sys was defined!")
>>> try: distutils
... except NameError: pass
... else: print("distutils was defined!")
>>> import sys as sous
>>> import distutils.core as corey
>>> from copy import deepcopy as copey
...
...
tests/run/reimport_from_package.srctree
View file @
c97860d3
...
...
@@ -17,8 +17,8 @@ setup(
import sys
import a
assert a in sys.modules.values(),
list
(sys.modules)
assert sys.modules['a'] is a,
list
(sys.modules)
assert a in sys.modules.values(),
sorted
(sys.modules)
assert sys.modules['a'] is a,
sorted
(sys.modules)
from atest.package import module
...
...
@@ -33,8 +33,8 @@ assert 'atest.package.module' in sys.modules
import a
import atest.package.module as module
assert module in sys.modules.values(),
list
(sys.modules)
assert sys.modules['atest.package.module'] is module,
list
(sys.modules)
assert module in sys.modules.values(),
sorted
(sys.modules)
assert sys.modules['atest.package.module'] is module,
sorted
(sys.modules)
if sys.version_info >= (3, 5):
from . import pymodule
...
...
tests/run/relativeimport_T542.srctree
View file @
c97860d3
...
...
@@ -26,7 +26,8 @@ try:
except ImportError:
pass
else:
assert False, "absolute import succeeded"
import sys
assert False, "absolute import succeeded: %s" % sorted(sys.modules)
import relimport.a
import relimport.bmod
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment