Module Not Found when using pytest

Viewed 2359

I have a virtualenv that uses Python 3 and am currently using pytest for testing. I've packaged a program called "process_expiring_passwords" and import this package from my general script file called "pep.py". I've also used pip in my virtualenv to install my process_expiring_passwords package.

When I go to run my tests, however, I get the following error:

ImportError while importing test module '/home/username/projects/process-expiring-passwords/tests/test_process_expiring_passwords.py'.

Hint: make sure your test modules/packages have valid Python names.

Traceback: tests/test_process_expiring_passwords.py:3: in from process_expiring_passwords import ProcessExpiringPasswords process_expiring_passwords/process_expiring_passwords.py:16: in from process_expiring_passwords.models.ProcessExpiringPasswordsLog

\ E ModuleNotFoundError: No module named 'process_expiring_passwords.models'; 'process_expiring_passwords' is not a package

Is there a particular reason why I can use my package from my pep.py general script file while pytest is unable to find said package?

The essential parts of the code related to this issue are as follows:

pep.py:

from process_expiring_passwords.process_expiring_passwords \
    import ProcessExpiringPasswords

pep = ProcessExpiringPasswords()
pep.process()

process_expiring_passwords/process_expiring_passwords.py:

from process_expiring_passwords.models.ProcessExpiringPasswordsLog \
    import ProcessExpiringPasswordsLog

class ProcessExpiringPasswords:
    def __init__(self):
        self.example = 0
    def process():
        pepl = ProcessExpiringPasswordsLog()

process_expiring_passwords/models/ProcessExpiringPasswordsLog.py:

class ProcessExpiringPasswordsLog():
    def __init__(self):
        self.example = 0

process_expiring_passwords/setup.py:

# ref: https://github.com/pypa/sampleproject/blob/master/setup.py
# ref: http://python-packaging.readthedocs.io/en/latest/minimal.html
from setuptools import setup

setup(
    name='process_expiring_passwords',
    version='0.0.1',
    packages=find_packages(),
    description='Process expiring passwords',
    license='MIT',
    install_requires=[
        'apiclient',
        'google-api-python-client',
        'httplib2',
        'mysqlclient',
        'oauth2client',
        'requests',
        'SQLAlchemy',
    ],
)

tests/test_process_expiring_passwords.py:

from process_expiring_passwords import ProcessExpiringPasswords

def test_pep():
    pep = ProcessExpiringPasswords()
    assert pep is not None

Project structure:

process_expiring_passwords
    pep.py
    process_expiring_passwords
        __init__.py
        models
            __init__.py
            ProcessExpiringPasswordsLog.py
        process_expiring_passwords.py
        setup.py
    tests
        test_process_expiring_passwords.py

Notes:

  • Updated code example and setup.py based on feedback from Matt Messersmith.
2 Answers

Your code doesn't quite work as posted, I modified it to have the self keyword in your constructors and member functions. After that, I could get pep.py to run.

Is there a particular reason why I can use my package from my pep.py general script file while pytest is unable to find said package?

Yes, when you are in your top level process_expiring_passwords directory, you can run pep.py, because you'll be getting a "local" import of the package.

The fact that the test doens't run has little to do with pytest, and more to do with what your import statement looks like and the fact that you're not building a package:

from process_expiring_passwords import ProcessExpiringPasswords

You haven't created a package called process_expiring_passwords. You can verify this by doing python setup.py bdist_wheel (or just do sdist and unzip the tarball), unzipping the wheel, and noting that there are no packages present.

Typically, you need to install the packages python setup.py install (this plops the distributable in your site-packages), and you also have to name the packages in setup.py (find_packages() is your friend), and then your test should work (more or less) as expected.

HTH.

Following an extended conversation about this issue, here are the following steps that especially helped based on comments from @hoefling and after adding packages=find_packages(), to setup.py based on answer from @Matt Messersmith:

  1. moved setup.py to root project directory
  2. deleted __pycache__ files
  3. made imports relative in main module file

    process_expiring_passwords/process_expiring_passwords.py:

    from .models.ProcessExpiringPasswordsLog \ import ProcessExpiringPasswordsLog

  4. ran python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"

  5. removed old package line from easy-install.pth (which should be found using the resulting path from the previous step)
  6. ran pip install -e .
  7. added process_expiring_passwords to test file's import section:

    from process_expiring_passwords.process_expiring_passwords \ import ProcessExpiringPasswords

Related