diff --git a/mypy/semanal.py b/mypy/semanal.py index 4f0c9793f4d8..d9fe795326dd 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -1483,7 +1483,9 @@ def visit_import_all(self, i: ImportAll) -> None: self.add_submodules_to_parent_modules(i_id, True) for name, node in m.names.items(): node = self.normalize_type_alias(node, i) - if not name.startswith('_') and node.module_public: + # if '__all__' exists, all nodes not included have had module_public set to + # False, and we can skip checking '_' because it's been explicitly included. + if node.module_public and (not name.startswith('_') or '__all__' in m.names): existing_symbol = self.globals.get(name) if existing_symbol: # Import can redefine a variable. They get special treatment. diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 8f212b27a7ad..546010eb7f2a 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -427,6 +427,25 @@ __all__ = [u'a', u'b', u'c'] [out] +[case testUnderscoreExportedValuesInImportAll] +import typing +from m import * +_ = a +_ = _b +_ = __c__ +_ = ___d +_ = e +_ = f # E: Name 'f' is not defined +_ = _g # E: Name '_g' is not defined +[file m.py] +__all__ = ['a'] +__all__ += ('_b',) +__all__.append('__c__') +__all__.extend(('___d', 'e')) + +a = _b = __c__ = ___d = e = f = _g = 1 +[builtins fixtures/module_all.pyi] + [case testEllipsisInitializerInStubFileWithType] import m m.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")