1

I observe a strange behaviour with Python 3 unittest. Following Testcase tests in function testValue a module that does not exist.

import sys
import unittest

class ModuleTest(unittest.TestCase):

    def testValue(self):
        import unknown_module
        result = unknown_module.value

        self.assertEqual(0.0, result)


if __name__ == "__main__":
    print(sys.version)
    unittest.main()

Python2 gives correctly following output:

2.7.5 (default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)]
E
======================================================================
ERROR: testValue (__main__.ModuleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\bin\WinPython-64bit-2.7.5.1\workspace\unknown_module_test.py", line 7, in testValue
    import unknown_module
ImportError: No module named unknown_module

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

But Python 3 claims an AttributeError when the unknown_module.value is referenced.

3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (Intel)]
E
======================================================================
ERROR: testValue (__main__.ModuleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "unknown_module_test.py", line 8, in testValue
    result = unknown_module.value
AttributeError: 'module' object has no attribute 'value'

----------------------------------------------------------------------
Ran 1 test in 0.016s

FAILED (errors=1)

Why doesn't throw Python 3 an ImportError as Python 2 does?

6
  • No, can't reproduce this. I just get an ImportError. What is the real name of your unknown module? Are you 100% certain that you didn't find a module added to Python 3 you did not know about? What does print(unknown_module.__file__) tell you was imported? Commented Aug 2, 2013 at 9:34
  • I think the module unknown_module exists somewhere in Python 3.3 module search path. (not in Python 2.7 module path). Commented Aug 2, 2013 at 9:37
  • @Martijn Pieters : It gives the error AttributeError: 'module' object has no attribute '__file__'. Commented Aug 2, 2013 at 9:54
  • @Holger: but there is a module object? Sounds like a built-in module in that case. What does print(unknown_module.__name__) give? Or better still, give us print(dir(unknown_module)). Commented Aug 2, 2013 at 10:54
  • @Martijn Pieters : It gives unknown_module and ['__doc__', '__initializing__', '__loader__', '__name__', '__package__', '__path__'] on the module search path. I found out that I have an empty directory unknown_module, but there is no file __init__.py in it. But this is still mandatory to declare a package in Python 3, isn't it? Commented Aug 2, 2013 at 11:21

1 Answer 1

3

You are importing an implicit namespace package. Quoting from the Python 3.3 What's New page:

Native support for package directories that don’t require __init__.py marker files and can automatically span multiple path segments (inspired by various third party approaches to namespace packages, as described in PEP 420)

and PEP 420 Implicit Namespace Packages:

If the scan completes without returning a module or package, and at least one directory was recorded, then a namespace package is created. The new namespace package:

  • Has a __path__ attribute set to an iterable of the path strings that were found and recorded during the scan.
  • Does not have a __file__ attribute.

and

Namespace packages and regular packages are very similar. The differences are:

  • Portions of namespace packages need not all come from the same directory structure, or even from the same loader. Regular packages are self-contained: all parts live in the same directory hierarchy.
  • Namespace packages have no __file__ attribute.
  • Namespace packages' __path__ attribute is a read-only iterable of strings, which is automatically updated when the parent path is modified.
  • Namespace packages have no __init__.py module.
  • Namespace packages have a different type of object for their __loader__ attribute.

Remove the unknown_module directory from your sys.path and your test will fail the way it did in earlier Python versions.

Sign up to request clarification or add additional context in comments.

2 Comments

Ok, that's new in 3.3. But, isn't that in contradiction to what is written below documentation. There it is written The init.py files are required to make Python treat the directories as containing packages. I relied on that.
It doesn't quite contradict the new namespace feature (you still need a __init__.py if the directory is not a namespace package, e.g. it contains actual modules). Yet the tutorial could do with some updating there.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.