Pylint: False positive E0611/E0401 (No Name / Unable to Import)

Created on 17 Oct 2017  路  3Comments  路  Source: PyCQA/pylint

In my code I have the following imports:

import email
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText

And further in the code:

        output = u''.join(
            txt.decode(enc or 'iso8859-1') if isinstance(txt, bytes) else txt
            for txt, enc in email.Header.decode_header(word)
        )

and

email.Encoders.encode_base64(out_message_attachment)

When I run Pylint over this file, I get the following errors:

[E0611] maileater/models.py:4:0 : No name 'MIMEBase' in module 'email'
[E0401] maileater/models.py:4:0 : Unable to import 'email.MIMEBase'
[E0611] maileater/models.py:5:0 : No name 'MIMEMultipart' in module 'email'
[E0401] maileater/models.py:5:0 : Unable to import 'email.MIMEMultipart'
[E0611] maileater/models.py:6:0 : No name 'MIMEText' in module 'email'
[E0401] maileater/models.py:6:0 : Unable to import 'email.MIMEText'
[E1101] maileater/models.py:55:28 : Module 'email' has no 'Header' member
[E1101] maileater/models.py:527:8 : Module 'email' has no 'Encoders' member

However, all of these members are in fact in the email module:

$ ipython
Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
Type "copyright", "credits" or "license" for more information.

IPython 4.0.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: from email import MIMEBase, MIMEMultipart, MIMEText, Header, Encoders

In [2]: 
Do you really want to exit ([y]/n)? y

pylint --version output

pylint 1.7.4, 
astroid 1.5.3
Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
[GCC 5.4.0 20160609]

All of this is happening in a virtualenv, and of course, that virtualenv is active for both the Pylint and the iPython run.

bug

Most helpful comment

from email.MIMEMultipart import MIMEMultipart
Is the correct import for Python 2.x.

According to the Python 3 examples in the documentation, you need:

from email.mime.multipart import MIMEMultipart

All 3 comments

from email.MIMEMultipart import MIMEMultipart
Is the correct import for Python 2.x.

According to the Python 3 examples in the documentation, you need:

from email.mime.multipart import MIMEMultipart

The module seems to be doing some "weird" stuff, which might explain a bit.

In the __init__.py in the email library's root folder, we see the following:

_MIMENAMES = [
    # email.MIME<old name> -> email.mime.<new name is lowercased old name>
    'Audio',
    'Base',
    'Image',
    'Message',
    'Multipart',
    'NonMultipart',
    'Text',
    ]

# skipping some code

import email.mime
for _name in _MIMENAMES:
    importer = LazyImporter('mime.' + _name.lower())
    sys.modules['email.MIME' + _name] = importer
    setattr(sys.modules['email'], 'MIME' + _name, importer)
    setattr(sys.modules['email.mime'], _name, importer)

with the LazyImporter being defined as:

# Lazy loading to provide name mapping from new-style names (PEP 8 compatible
# email 4.0 module names), to old-style names (email 3.0 module names).
import sys

class LazyImporter(object):
    def __init__(self, module_name):
        self.__name__ = 'email.' + module_name

    def __getattr__(self, name):
        __import__(self.__name__)
        mod = sys.modules[self.__name__]
        self.__dict__.update(mod.__dict__)
        return getattr(mod, name)

@selinium your suggestion works on Python 2 as well. For now I'm going to solve it like that. Thanks for your input, which prompted me to dig a little deeper.

Given the weird stuff the email module is doing, I think it's safe to assume that we're not going to support this particular use case.

Was this page helpful?
0 / 5 - 0 ratings