Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
grumpy
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
grumpy
Commits
6ec81e81
Commit
6ec81e81
authored
Apr 07, 2017
by
Dylan Trotter
Committed by
GitHub
Apr 07, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement relative imports. (#284)
parent
7be3a9a7
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
96 additions
and
8 deletions
+96
-8
compiler/imputil.py
compiler/imputil.py
+33
-5
compiler/imputil_test.py
compiler/imputil_test.py
+63
-3
No files found.
compiler/imputil.py
View file @
6ec81e81
...
...
@@ -20,6 +20,7 @@
from
__future__
import
unicode_literals
import
collections
import
functools
import
os
from
pythonparser
import
algorithm
...
...
@@ -101,10 +102,10 @@ class Importer(algorithm.Visitor):
node
.
module
)
raise
util
.
ImportError
(
node
,
msg
)
if
node
.
module
==
'__future__'
:
if
no
t
node
.
level
and
no
de
.
module
==
'__future__'
:
return
[]
if
node
.
module
.
startswith
(
_NATIVE_MODULE_PREFIX
):
if
no
t
node
.
level
and
no
de
.
module
.
startswith
(
_NATIVE_MODULE_PREFIX
):
imp
=
Import
(
node
.
module
[
len
(
_NATIVE_MODULE_PREFIX
):],
is_native
=
True
)
for
alias
in
node
.
names
:
asname
=
alias
.
asname
or
alias
.
name
...
...
@@ -112,16 +113,29 @@ class Importer(algorithm.Visitor):
return
[
imp
]
imports
=
[]
if
not
node
.
module
:
# Import of the form 'from .. import foo, bar'. All named imports must be
# modules, not module members.
for
alias
in
node
.
names
:
imp
=
self
.
_resolve_relative_import
(
node
.
level
,
node
,
alias
.
name
)
imp
.
add_binding
(
Import
.
MODULE
,
alias
.
asname
or
alias
.
name
,
imp
.
name
.
count
(
'.'
))
imports
.
append
(
imp
)
return
imports
member_imp
=
None
for
alias
in
node
.
names
:
asname
=
alias
.
asname
or
alias
.
name
if
node
.
level
:
resolver
=
functools
.
partial
(
self
.
_resolve_relative_import
,
node
.
level
)
else
:
resolver
=
self
.
_resolve_import
try
:
imp
=
self
.
_resolve_import
(
node
,
'{}.{}'
.
format
(
node
.
module
,
alias
.
name
))
imp
=
resolver
(
node
,
'{}.{}'
.
format
(
node
.
module
,
alias
.
name
))
except
util
.
ImportError
:
# A member (not a submodule) is being imported, so bind it.
if
not
member_imp
:
member_imp
=
self
.
_resolve_import
(
node
,
node
.
module
)
member_imp
=
resolver
(
node
,
node
.
module
)
imports
.
append
(
member_imp
)
member_imp
.
add_binding
(
Import
.
MEMBER
,
asname
,
alias
.
name
)
else
:
...
...
@@ -139,6 +153,20 @@ class Importer(algorithm.Visitor):
return
Import
(
modname
)
raise
util
.
ImportError
(
node
,
'no such module: {}'
.
format
(
modname
))
def
_resolve_relative_import
(
self
,
level
,
node
,
modname
):
if
not
self
.
package_dir
:
raise
util
.
ImportError
(
node
,
'attempted relative import in non-package'
)
uplevel
=
level
-
1
if
uplevel
>
self
.
package_name
.
count
(
'.'
):
raise
util
.
ImportError
(
node
,
'attempted relative import beyond toplevel package'
)
dirname
=
os
.
path
.
normpath
(
os
.
path
.
join
(
self
.
package_dir
,
*
([
'..'
]
*
uplevel
)))
if
not
self
.
_script_exists
(
dirname
,
modname
):
raise
util
.
ImportError
(
node
,
'no such module: {}'
.
format
(
modname
))
parts
=
self
.
package_name
.
split
(
'.'
)
return
Import
(
'.'
.
join
(
parts
[:
len
(
parts
)
-
uplevel
])
+
'.'
+
modname
)
def
_script_exists
(
self
,
dirname
,
name
):
prefix
=
os
.
path
.
join
(
dirname
,
name
.
replace
(
'.'
,
os
.
sep
))
return
(
os
.
path
.
isfile
(
prefix
+
'.py'
)
or
...
...
compiler/imputil_test.py
View file @
6ec81e81
...
...
@@ -36,6 +36,10 @@ class ImportVisitorTest(unittest.TestCase):
'foo.py'
:
None
,
'qux.py'
:
None
,
'bar/'
:
{
'fred/'
:
{
'__init__.py'
:
None
,
'quux.py'
:
None
,
},
'__init__.py'
:
None
,
'baz.py'
:
None
,
'foo.py'
:
None
,
...
...
@@ -50,6 +54,12 @@ class ImportVisitorTest(unittest.TestCase):
self
.
rootdir
,
{
'src/'
:
{
'__python__/'
:
self
.
_PATH_SPEC
}})
foo_script
=
os
.
path
.
join
(
self
.
rootdir
,
'foo.py'
)
self
.
importer
=
imputil
.
Importer
(
self
.
rootdir
,
'foo'
,
foo_script
,
False
)
bar_script
=
os
.
path
.
join
(
self
.
pydir
,
'bar'
,
'__init__.py'
)
self
.
bar_importer
=
imputil
.
Importer
(
self
.
rootdir
,
'bar'
,
bar_script
,
False
)
fred_script
=
os
.
path
.
join
(
self
.
pydir
,
'bar'
,
'fred'
,
'__init__.py'
)
self
.
fred_importer
=
imputil
.
Importer
(
self
.
rootdir
,
'bar.fred'
,
fred_script
,
False
)
def
tearDown
(
self
):
shutil
.
rmtree
(
self
.
rootdir
)
...
...
@@ -82,9 +92,7 @@ class ImportVisitorTest(unittest.TestCase):
def
testImportPackageModuleRelative
(
self
):
imp
=
imputil
.
Import
(
'bar.baz'
)
imp
.
add_binding
(
imputil
.
Import
.
MODULE
,
'baz'
,
1
)
bar_script
=
os
.
path
.
join
(
self
.
pydir
,
'bar'
,
'__init__.py'
)
importer
=
imputil
.
Importer
(
self
.
rootdir
,
'bar'
,
bar_script
,
False
)
got
=
importer
.
visit
(
pythonparser
.
parse
(
'import baz'
).
body
[
0
])
got
=
self
.
bar_importer
.
visit
(
pythonparser
.
parse
(
'import baz'
).
body
[
0
])
self
.
_assert_imports_equal
([
imp
],
got
)
def
testImportPackageModuleRelativeFromSubModule
(
self
):
...
...
@@ -176,6 +184,58 @@ class ImportVisitorTest(unittest.TestCase):
imp
.
add_binding
(
imputil
.
Import
.
MEMBER
,
'foo'
,
'Printf'
)
self
.
_check_imports
(
'from __go__.fmt import Printf as foo'
,
[
imp
])
def
testRelativeImportNonPackage
(
self
):
self
.
assertRaises
(
util
.
ImportError
,
self
.
importer
.
visit
,
pythonparser
.
parse
(
'from . import bar'
).
body
[
0
])
def
testRelativeImportBeyondTopLevel
(
self
):
self
.
assertRaises
(
util
.
ImportError
,
self
.
bar_importer
.
visit
,
pythonparser
.
parse
(
'from .. import qux'
).
body
[
0
])
def
testRelativeModuleNoExist
(
self
):
self
.
assertRaises
(
util
.
ImportError
,
self
.
bar_importer
.
visit
,
pythonparser
.
parse
(
'from . import qux'
).
body
[
0
])
def
testRelativeModule
(
self
):
imp
=
imputil
.
Import
(
'bar.foo'
)
imp
.
add_binding
(
imputil
.
Import
.
MODULE
,
'foo'
,
1
)
node
=
pythonparser
.
parse
(
'from . import foo'
).
body
[
0
]
self
.
_assert_imports_equal
([
imp
],
self
.
bar_importer
.
visit
(
node
))
def
testRelativeModuleFromSubModule
(
self
):
imp
=
imputil
.
Import
(
'bar.foo'
)
imp
.
add_binding
(
imputil
.
Import
.
MODULE
,
'foo'
,
1
)
baz_script
=
os
.
path
.
join
(
self
.
pydir
,
'bar'
,
'baz.py'
)
importer
=
imputil
.
Importer
(
self
.
rootdir
,
'bar.baz'
,
baz_script
,
False
)
node
=
pythonparser
.
parse
(
'from . import foo'
).
body
[
0
]
self
.
_assert_imports_equal
([
imp
],
importer
.
visit
(
node
))
def
testRelativeModuleMember
(
self
):
imp
=
imputil
.
Import
(
'bar.foo'
)
imp
.
add_binding
(
imputil
.
Import
.
MEMBER
,
'qux'
,
'qux'
)
node
=
pythonparser
.
parse
(
'from .foo import qux'
).
body
[
0
]
self
.
_assert_imports_equal
([
imp
],
self
.
bar_importer
.
visit
(
node
))
def
testRelativeModuleMemberMixed
(
self
):
imp1
=
imputil
.
Import
(
'bar.fred'
)
imp1
.
add_binding
(
imputil
.
Import
.
MEMBER
,
'qux'
,
'qux'
)
imp2
=
imputil
.
Import
(
'bar.fred.quux'
)
imp2
.
add_binding
(
imputil
.
Import
.
MODULE
,
'quux'
,
2
)
node
=
pythonparser
.
parse
(
'from .fred import qux, quux'
).
body
[
0
]
self
.
_assert_imports_equal
([
imp1
,
imp2
],
self
.
bar_importer
.
visit
(
node
))
def
testRelativeUpLevel
(
self
):
imp
=
imputil
.
Import
(
'bar.foo'
)
imp
.
add_binding
(
imputil
.
Import
.
MODULE
,
'foo'
,
1
)
node
=
pythonparser
.
parse
(
'from .. import foo'
).
body
[
0
]
self
.
_assert_imports_equal
([
imp
],
self
.
fred_importer
.
visit
(
node
))
def
testRelativeUpLevelMember
(
self
):
imp
=
imputil
.
Import
(
'bar.foo'
)
imp
.
add_binding
(
imputil
.
Import
.
MEMBER
,
'qux'
,
'qux'
)
node
=
pythonparser
.
parse
(
'from ..foo import qux'
).
body
[
0
]
self
.
_assert_imports_equal
([
imp
],
self
.
fred_importer
.
visit
(
node
))
def
_check_imports
(
self
,
stmt
,
want
):
got
=
self
.
importer
.
visit
(
pythonparser
.
parse
(
stmt
).
body
[
0
])
self
.
_assert_imports_equal
(
want
,
got
)
...
...
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