Reputation: 1501
I am trying to make a python package which I want to install using pip install .
locally. The package name is listed in pip freeze
but import <package>
results in an error No module named <package>
. Also the site-packages folder does only contain a dist-info folder. find_packages()
is able to find packages. What am I missing?
import io
import os
import sys
from shutil import rmtree
from setuptools import find_packages, setup, Command
# Package meta-data.
NAME = '<package>'
DESCRIPTION = 'description'
URL = ''
EMAIL = 'email'
AUTHOR = 'name'
# What packages are required for this module to be executed?
REQUIRED = [
# 'requests', 'maya', 'records',
]
# The rest you shouldn't have to touch too much :)
# ------------------------------------------------
# Except, perhaps the License and Trove Classifiers!
# If you do change the License, remember to change the Trove Classifier for that!
here = os.path.abspath(os.path.dirname(__file__))
# Where the magic happens:
setup(
name=NAME,
#version=about['__version__'],
description=DESCRIPTION,
# long_description=long_description,
author=AUTHOR,
author_email=EMAIL,
url=URL,
packages=find_packages(),
# If your package is a single module, use this instead of 'packages':
# py_modules=['mypackage'],
# entry_points={
# 'console_scripts': ['mycli=mymodule:cli'],
# },
install_requires=REQUIRED,
include_package_data=True,
license='MIT',
classifiers=[
# Trove classifiers
# Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy'
],
)
Upvotes: 120
Views: 56246
Reputation: 35
I had this problem just now, and the issue was that I was referring to non-existent modules from an old pyproject.toml file that I had copied over to this new package in the [project.optional-dependencies]. So if you just get the dist-info folder created upon installation but not the actual package folder, check the pyproject.toml folder for errors, and specifically check to make sure that [project.optional-dependencies] does not list any modules that do not exist in your package.
Upvotes: 0
Reputation: 524
update 2024: the recommended way is to use pyproject.toml
instead of setup.py
now.It was introduced introduced by PEP 517 and PEP 518 .
you can find the difference between both approaches here
All you need to do is to make sure that you have empty __init__.py
in the root directory of your module and all subdirectories. You will also need to create pyproject.toml
file like the one below,
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[metadata]
name = "project"
version = "0.0.1"
[tool.setuptools.packages]
find = {} # Scan the project directory with the default parameters
[project]
name = "project"
version = "0.0.1"
authors = [
{ name="your_name", email="your_email" },
]
description = "Sample project "
readme = "README.md"
requires-python = ">=3.8"
great article explaining the setup here
Upvotes: 0
Reputation: 325
Make certain that your src
files are in example_package_YOUR_USERNAME_HERE
(this is the example package name that is used in the docs) and not in src
. Errantly putting the files in src
can have the effect described in the question.
Reference: https://packaging.python.org/en/latest/tutorials/packaging-projects/
The package should be set up like this:
packaging_tutorial/
└── src/
└── example_package_YOUR_USERNAME_HERE/
├── __init__.py
└── example.py
Upvotes: 3
Reputation: 79
I had the same problem, and updating setuptools
helped:
python3 -m pip install --upgrade pip setuptools wheel
After that, reinstall the package, and it should work fine :)
Upvotes: 4
Reputation: 2037
For me, I noticed something weird if you do this:
# Not in the setup.py directory
python /path/to/folder/setup.py bdist_wheel
It will only install the .dist-info folder in your site-packages folder when you install the wheel.
However, if you do this:
cd /path/to/folder \
&& python setup.py bdist_wheel
The wheel will include all your files.
Upvotes: 1
Reputation: 66261
Since the question has become quite popular, here are the diagnosis steps to go through when you're missing files after installation. Imagine having an example project with the following structure:
root
├── spam
│ ├── __init__.py
│ ├── data.txt
│ ├── eggs.py
│ └── fizz
│ ├── __init__.py
│ └── buzz.py
├── bacon.py
└── setup.py
Now I run pip install .
, check that the package is installed:
$ pip list
Package Version
---------- -------
mypkg 0.1
pip 19.0.1
setuptools 40.6.3
wheel 0.32.3
but see neither spam
, nor spam/eggs.py
nor bacon.py
nor spam/fizz/buzz.py
in the list of files belonging to the installed package:
$ pip show -f mypkg
Name: mypkg
Version: 0.1
...
Files:
mypkg-0.1.dist-info/DESCRIPTION.rst
mypkg-0.1.dist-info/INSTALLER
mypkg-0.1.dist-info/METADATA
mypkg-0.1.dist-info/RECORD
mypkg-0.1.dist-info/WHEEL
mypkg-0.1.dist-info/metadata.json
mypkg-0.1.dist-info/top_level.txt
So what to do now?
Unless told not to do so, pip
will always try to build a wheel file and install your package from it. We can inspect the log for the wheel build process if reinstalling in the verbose mode. First step is to uninstall the package:
$ pip uninstall -y mypkg
...
then install it again, but now with an additional argument:
$ pip install . -vvv
...
Now if I inspect the log:
$ pip install . -vvv | grep 'adding'
adding 'mypkg-0.1.dist-info/METADATA'
adding 'mypkg-0.1.dist-info/WHEEL'
adding 'mypkg-0.1.dist-info/top_level.txt'
adding 'mypkg-0.1.dist-info/RECORD'
I notice that no files from the spam
directory or bacon.py
are mentioned anywhere. This means they were simply not included in the wheel file and hence not installed by pip
. The most common error sources are:
packages
argumentVerify you have passed the packages
argument to the setup function. Check that you have mentioned all of the packages that should be installed. Subpackages will not be collected automatically if only the parent package is mentioned! For example, in the setup script
from setuptools import setup
setup(
name='mypkg',
version='0.1',
packages=['spam']
)
spam
will be installed, but not spam.fizz
because it is a package itself and must be mentioned explicitly. Fixing it:
from setuptools import setup
setup(
name='mypkg',
version='0.1',
packages=['spam', 'spam.fizz']
)
If you have lots of packages, use setuptools.find_packages
to automate the process:
from setuptools import find_packages, setup
setup(
name='mypkg',
version='0.1',
packages=find_packages() # will return a list ['spam', 'spam.fizz']
)
In case you are missing a module:
py_modules
argumentIn the above examples, I will be missing bacon.py
after installation since it doesn't belong to any package. I have to provide its module name in the separate argument py_modules
:
from setuptools import find_packages, setup
setup(
name='mypkg',
version='0.1',
packages=find_packages(),
py_modules=['bacon']
)
package_data
argumentI have all the source code files in place now, but the data.txt
file is still not installed. Data files located under package directories should be added via the package_data
argument. Fixing the above setup script:
from setuptools import find_packages, setup
setup(
name='mypkg',
version='0.1',
packages=find_packages(),
package_data={'spam': ['data.txt']},
py_modules=['bacon']
)
Don't be tempted to use the data_files
argument. Place the data files under a package and configure package_data
instead.
If I now reinstall the package, I will notice all of the files are added to the wheel:
$ pip install . -vvv | grep 'adding'
adding 'bacon.py'
adding 'spam/__init__.py'
adding 'spam/data.txt'
adding 'spam/eggs.py'
adding 'spam/fizz/__init__.py'
adding 'spam/fizz/buzz.py'
adding 'mypkg-0.1.dist-info/METADATA'
adding 'mypkg-0.1.dist-info/WHEEL'
adding 'mypkg-0.1.dist-info/top_level.txt'
adding 'mypkg-0.1.dist-info/RECORD'
They will also be visible in the list of files belonging to mypkg
:
$ pip show -f mypkg
Name: mypkg
Version: 0.1
...
Files:
__pycache__/bacon.cpython-36.pyc
bacon.py
mypkg-0.1.dist-info/INSTALLER
mypkg-0.1.dist-info/METADATA
mypkg-0.1.dist-info/RECORD
mypkg-0.1.dist-info/WHEEL
mypkg-0.1.dist-info/top_level.txt
spam/__init__.py
spam/__pycache__/__init__.cpython-36.pyc
spam/__pycache__/eggs.cpython-36.pyc
spam/data.txt
spam/eggs.py
spam/fizz/__init__.py
spam/fizz/__pycache__/__init__.cpython-36.pyc
spam/fizz/__pycache__/buzz.cpython-36.pyc
spam/fizz/buzz.py
Upvotes: 158
Reputation: 354
If you are on Windows 10+, one way you could make sure that you had all the correct installations was to click start in the bottom left-hand corner and search cmd.exe and right-click on "Command Prompt" (Make sure you choose "Run as Administrator"). Type "cd path to your Python 3.X installation
". You can find this path in File Explorer (go to the folder where Python is installed) and then at the top. Copy this, and put it in where I wrote above path to your Python 3.X installation
. Once you do that and click enter, type "python -m pip install package
" (package
signifies the package you would like to install). Your Python program should now work perfectly.
Upvotes: 0