Skip to content

Commit c4393d4

Browse files
authored
Fixed a bug where aliased Python submodule imports referred to the top-level module rather than the submodule (#533)
1 parent f4505db commit c4393d4

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
* Fixed a bug where the Basilisp AST nodes for return values of `deftype` members could be marked as _statements_ rather than _expressions_, resulting in an incorrect `nil` return (#523)
1414
* Fixed a bug where `defonce` would throw a Python SyntaxError due to a superfluous `global` statement in the generated Python (#525)
1515
* Fixed a bug where Basilisp would throw an exception when comparing seqs by `=` to non-seqable values (#530)
16+
* Fixed a bug where aliased Python submodule imports referred to the top-level module rather than the submodule (#533)
1617

1718
## [v0.1.dev13] - 2020-03-16
1819
### Added

src/basilisp/lang/compiler/generator.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,8 @@ def _var_ns_as_python_sym(name: str) -> str:
548548
_COERCE_SEQ_FN_NAME = _load_attr(f"{_RUNTIME_ALIAS}.to_seq")
549549
_BASILISP_FN_FN_NAME = _load_attr(f"{_RUNTIME_ALIAS}._basilisp_fn")
550550
_FN_WITH_ATTRS_FN_NAME = _load_attr(f"{_RUNTIME_ALIAS}._with_attrs")
551+
_BUILTINS_IMPORT_FN_NAME = _load_attr("builtins.__import__")
552+
_IMPORTLIB_IMPORT_MODULE_FN_NAME = _load_attr("importlib.import_module")
551553
_PY_CLASSMETHOD_FN_NAME = _load_attr("classmethod")
552554
_PY_PROPERTY_FN_NAME = _load_attr("property")
553555
_PY_STATICMETHOD_FN_NAME = _load_attr("staticmethod")
@@ -1586,18 +1588,23 @@ def _import_to_py_ast(_: GeneratorContext, node: Import) -> GeneratedPyAST:
15861588
deps: List[ast.AST] = []
15871589
for alias in node.aliases:
15881590
safe_name = munge(alias.name)
1589-
py_import_alias = (
1590-
munge(alias.alias)
1591-
if alias.alias is not None
1592-
else safe_name.split(".", maxsplit=1)[0]
1593-
)
1591+
1592+
# Always use builtins.__import__ and assign to the first name component
1593+
# if there's no alias. Otherwise, we could potentially overwrite a parent
1594+
# import if parent and child are both imported:
1595+
# (import* collections collections.abc)
1596+
if alias.alias is not None:
1597+
py_import_alias = munge(alias.alias)
1598+
import_func = _IMPORTLIB_IMPORT_MODULE_FN_NAME
1599+
else:
1600+
py_import_alias = safe_name.split(".", maxsplit=1)[0]
1601+
import_func = _BUILTINS_IMPORT_FN_NAME
1602+
15941603
deps.append(
15951604
ast.Assign(
15961605
targets=[ast.Name(id=py_import_alias, ctx=ast.Store())],
15971606
value=ast.Call(
1598-
func=_load_attr("builtins.__import__"),
1599-
args=[ast.Constant(safe_name)],
1600-
keywords=[],
1607+
func=import_func, args=[ast.Constant(safe_name)], keywords=[],
16011608
),
16021609
)
16031610
)

tests/basilisp/compiler_test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,11 @@ def test_nested_imports_visible_with_parent(self, lcompile: CompileFn):
20832083
"""
20842084
)
20852085

2086+
def test_aliased_nested_import_refers_to_child(self, lcompile: CompileFn):
2087+
import os.path
2088+
2089+
assert os.path.exists is lcompile("(import [os.path :as path]) path/exists")
2090+
20862091

20872092
class TestInvoke:
20882093
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)