ModuleNotFoundError using setup.py

Question:

I use python click package and setuptools to create a simple command line.
And I work in a pipenv virtualenv.

My working directory is like this:

jkt/scripts/app.py

And my setup.py is like this:

from setuptools import setup, find_packages

setup(

  name='jkt',
  version='0.1',
  packages=find_packages(),
  include_package_data=True,
  entry_points='''
      [console_scripts]
      jktool=jkt.scripts.app:my_function 
  ''',

)

Then I run the command
pip install --editable .

And run jktool to execute my_function but I get the error:

ModuleNotFoundError No module named ‘jkt’.

But when the app.py in jkt directory I can run my function

setup(
    name='app',
    version='0.1',
    py_modules=['app'],
    entry_points='''
        [console_scripts]
        app=app:jktools
    ''',
)

After I run pip install -e . I can use app command to run my function.

Asked By: Saluton

||

Answers:

As I mentioned, I can’t reproduce your error (Python 3.7 with modern pip seems to work just fine), but there are a couple things that could potentially be going wrong on older versions.

Since it doesn’t look like you put __init__.py files in your subdirectories, find_packages doesn’t actually find any packages at all (python3 -c 'from setuptools import find_packages; print(find_packages()) prints the empty list, []). You can fix this in one of three ways:

  1. Create empty __init__.py files to explicitly mark those folders as package folders; on a UNIX-like system, touch jkt/__init__.py and touch jkt/scripts/__init__.py is enough to create them
  2. Python 3.3+ only: (also requires modern setuptools so pip install --upgrade setuptools might be necessary) Replace your use of find_packages with find_namespace_packages (which recognizes Python 3 era implicit namespace packages).
  3. Just get rid of find_packages entirely and list the packages directly, e.g. replace packages=find_packages(), with packages=['jkt', 'jkt.scripts'],

Options #2 only works on Python 3.3+, so if your package is intended to work on older versions of Python, go with option #1 or #3.

Answered By: ShadowRanger
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.