I have a Python package called cmdline. I use setuptools to define a console entry point. I would like to put this entry point inside a cli submodule, but I get an error when I try to run the installed script.
My project layout looks like this.
setup.py
cmdline/
__init__.py
cli/
__init__.py
main.py
The setup.py looks like this.
from setuptools import setup
setup(
name='cmdline',
version='1.0.0',
packages=['cmdline'],
url='',
license='',
author='W.P. McNeill',
author_email='',
description='',
entry_points={
'console_scripts': ['cmdline=cmdline.cli.main:main'],
}
)
The main.py file looks like this.
def main():
print("Hello, world")
if __name__ == "__main__":
main()
Both __init__.py files are empty.
If I install this with python setup.py install and then try to run the console script, I get an error.
> cmdline
Traceback (most recent call last):
File "//anaconda/envs/cmdline/bin/cmdline", line 9, in <module>
load_entry_point('cmdline==1.0.0', 'console_scripts', 'cmdline')()
File "build/bdist.macosx-10.5-x86_64/egg/pkg_resources/__init__.py", line 542, in load_entry_point
File "build/bdist.macosx-10.5-x86_64/egg/pkg_resources/__init__.py", line 2569, in load_entry_point
File "build/bdist.macosx-10.5-x86_64/egg/pkg_resources/__init__.py", line 2229, in load
File "build/bdist.macosx-10.5-x86_64/egg/pkg_resources/__init__.py", line 2235, in resolve
ImportError: No module named cli.main
If, however, I install it via a softlink with python setup.py develop it works.
> cmdline
Hello, world
It also works if I don't use a cli submodule and just have main.py at the top level of the project.
How can I make the submodule configuration work?
Your setup.py doesn't include the cmdline.cli subpackage, only the cmdline package will be included. setuptools does not recursively add all subpackages, you need to explicitly specify all packages, or use the find_packages() function to do so:
from setuptools import setup, find_packages
setup(
name='cmdline',
version='1.0.0',
packages=find_packages(),
# or:
# packages=['cmdline', 'cmdline.cli']
url='',
license='',
author='W.P. McNeill',
author_email='',
description='',
entry_points={
'console_scripts': ['cmdline=cmdline.cli.main:main'],
}
)
After that, the cmdline.cli package will be installed and the entry point should be resolveable.
Related
I am trying to create a module using setuptools. I installed setuptools and wrote a small piece of code as TestFunction.py:
def function(test):
print(test);
function("hello World")
and created a setup.py file with the below instruction:
from setuptools import setup
setup(
name='TestFunction.py',
version='1.0',
description='this is a python distribution',
py_module=['TestFunction'],)
Now i am running python3 setup.py sdist and getting the below error. My os is ubuntu 18. Much appreciated.
Original exception was:
Traceback (most recent call last):
File "setup.py", line 1, in <module>
from setuptools import setup, find_packages
File "/home/jeet/.local/lib/python3.6/site-packages/setuptools/__init__.py", line 6, in <module>
import distutils.core
File "/usr/lib/python3.6/distutils/core.py", line 16, in <module>
from distutils.dist import Distribution
File "/usr/lib/python3.6/distutils/dist.py", line 18, in <module>
from distutils.fancy_getopt import FancyGetopt, translate_longopt
File "/usr/lib/python3.6/distutils/fancy_getopt.py", line 373, in <module>
WS_TRANS = {ord(_wschar) : ' ' for _wschar in string.whitespace}
AttributeError: module 'string' has no attribute 'whitespace'
It seems you have a file string.py that isn't a module from the standard library but your own module or script. Rename it so it doesn't overshadow the standard module; don't forget to remove string.pyc file; for python 3.6 it's in __pycache__ directory.
I changed your code because you have an indentation formatting error. Rest of your code works fine.
copy and try this:
test_module.py
def function1(test):
print(test);
setup.py
from setuptools import setup
setup(
name='test_module.py',
version='1.0',
description='this is a python distribution',
py_module=['test_module'],)
usage:
python setup.py install
use your function:
from test_module import function1
function1("hello stackoverflow")
output:
hello stackoverflow
In some cases setup.py needs to import some extra modules, e.g.:
from setuptools import setup
import foo
setup(
# e.g. a keyword uses `foo`
version=foo.generate_version()
)
If foo is not installed, the execution of setup.py will fail because of ImportError.
I have tried to use setup_requires, e.g. setup_requires=['foo'], but it doesn’t help.
So how to specify this kind of dependencies?
pyproject.toml allows to specify custom build tooling:
[build-system]
requires = [..., foo, ...]
build-backend = "setuptools.build_meta"
Dependencies needed in setup.py cannot be specified in the very setup.py. You have to install them before running python setup.py:
pip install -r requirements.txt
python setup.py install
I have thought out a trick — call pip to install the dependencies in setup.py
import pip
pip.main(['install', 'foo', 'bar']) # call pip to install them
# Now I can import foo & bar
import foo, bar
from setuptools import setup
setup(
...
)
Like #Tosha answered, pyproject.toml is your friend.
Here is an example from my project which uses jinja2:
setup.py: # Simplified - removed all actual code
import jinja2
from setuptools import setup
setup(name='test')
Building with: python -m build --wheel will break:
* Creating venv isolated environment...
* Installing packages in isolated environment... (setuptools >= 40.8.0, wheel)
* Getting dependencies for wheel...
Traceback (most recent call last):
File "/tmp/venv/lib/python3.6/site-packages/pep517/in_process/_in_process.py", line 363, in <module>
main()
File "/tmp/venv/lib/python3.6/site-packages/pep517/in_process/_in_process.py", line 345, in main
json_out['return_val'] = hook(**hook_input['kwargs'])
File "/tmp/venv/lib/python3.6/site-packages/pep517/in_process/_in_process.py", line 130, in get_requires_for_buil
d_wheel
return hook(config_settings)
File "/tmp/build-env-4zi79uth/lib/python3.6/site-packages/setuptools/build_meta.py", line 163, in get_requires_fo
r_build_wheel
config_settings, requirements=['wheel'])
File "/tmp/build-env-4zi79uth/lib/python3.6/site-packages/setuptools/build_meta.py", line 143, in _get_build_requ
ires
self.run_setup()
File "/tmp/build-env-4zi79uth/lib/python3.6/site-packages/setuptools/build_meta.py", line 268, in run_setup
self).run_setup(setup_script=setup_script)
File "/tmp/build-env-4zi79uth/lib/python3.6/site-packages/setuptools/build_meta.py", line 158, in run_setup
exec(compile(code, __file__, 'exec'), locals())
File "setup.py", line 1, in <module>
import jinja2
ModuleNotFoundError: No module named 'jinja2'
ERROR Backend subproccess exited when trying to invoke get_requires_for_build_wheel
However, adding a pyproject.toml:
[build-system]
requires = [
"setuptools",
"jinja2",
]
fixes the issue
Note I'm including also setuptools as a requirement. Omitting it will also break
I have similar problem, that I want to getting version of installer from yaml file, so I need to parse it and getting version from it.
I use following script as answer:
#!/usr/bin/env python
from setuptools import setup
import yaml
def find_version():
with open('meta/main.yml') as meta_main:
return yaml.load(meta_main)['version']
setup(name='sample',
version=find_version(),
packages=[],
setup_requires=['pyyaml'])
I found that setup method has setup_requires parameter, that you can specify setup dependencies. As mentioned in setuptools doccumentation, projects listed in setup_requires will NOT be automatically installed on the system where the setup script is being run. If you want them to be installed, as well as being available when the setup script is run, you should add them to install_requires and setup_requires.
Let me know if you have any other problem.
I am trying to build a program called dnsrep in Python, I am using setuptools so that I can call the dnsrep module without using the command python dnsrep. The setup.py script I wrote is given below:
from setuptools import setup, find_packages
setup(
name='dnsrep',
version='0.1',
description='Program that gives a reputation score to url\'s\n.',
entry_points = {
'console_scripts': ['dnsrep = dnsrep:main']
},
zip_safe=True,
)
I install the module by using the command:
python setup.py install
My module gets registered but when I run it I get the error:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.7/bin/dnsrep", line 9, in <module>
load_entry_point('dnsrep==0.1', 'console_scripts', 'dnsrep')()
File "build/bdist.macosx-10.6-intel/egg/pkg_resources/__init__.py", line 521, in load_entry_point
File "build/bdist.macosx-10.6-intel/egg/pkg_resources/__init__.py", line 2632, in load_entry_point
File "build/bdist.macosx-10.6-intel/egg/pkg_resources/__init__.py", line 2312, in load
File "build/bdist.macosx-10.6-intel/egg/pkg_resources/__init__.py", line 2318, in resolve
ImportError: No module named dnsrep
You have to install your python script, before you can call it via your defined entry point
This is my dummy project:
dnsrep/
├── dnsrep.py
└── setup.py
This is how setup.py looks like:
from setuptools import setup
setup(
name='dnsrep',
version='0.1',
description='Program that gives a reputation score to url\'s\n.',
py_modules=['dnsrep'],
entry_points = {
'console_scripts': ['dnsrep = dnsrep:main']
},
zip_safe=True,
)
Note the argument py_modules=['dnsrep'], which installs dnsrep.py as a new module.
Finally, this is my dummy implementation of dnsrep.py:
from __future__ import print_function
def main():
print("Hey, it works!")
After installing, everything works as expected and $ dnsrep prints: Hey, it works!
My package has a entry point defined in it's setup.py:
# -*- coding: utf-8 -*-
from setuptools import setup
setup(
name='fbuildbot',
version='0.1',
...
entry_points={
'console_scripts': [
'create = create:main',
],
},
install_requires=[
"cookiecutter",
],
)
Thing is, If I do python setup.py develop, I can run the command just fine, but if I do install it with python setup.py install the install procedure runs correctly but the console script fails with ImportError:
Traceback (most recent call last):
File "/home/matias/.venvs/fbuild/bin/create", line 8, in <module>
load_entry_point('fbuildbot==0.1', 'console_scripts', 'create')()
File "/home/matias/.venvs/fbuild/local/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg/pkg_resources.py", line 318, in load_entry_point
File "/home/matias/.venvs/fbuild/local/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg/pkg_resources.py", line 2221, in load_entry_point
File "/home/matias/.venvs/fbuild/local/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg/pkg_resources.py", line 1954, in load
ImportError: No module named create
Clearly it's failing to setup the package correctly on the pythonpath. I thought it was because I have the script barely at the top level. So I tried adding wrapping it all in a package, moving all important parts to a inner module and changing the setup.py accordingly:
# -*- coding: utf-8 -*-
from setuptools import setup
setup(
name='fbuildbot',
version='0.1',
description="Buildbot configuration generator for fbuild",
...
packages=['fbuildbot', ],
entry_points={
'console_scripts': [
'create = fbuildbot.create:main',
],
},
install_requires=[
"cookiecutter",
],
)
But it fails with the same message (with updated path, obviously).
Clearly I'm doing something wrong here. What could it be?
The problem is in your packages argument. You only specify:
packages=['fbuildbot', ],
not
packages=['fbuildbot', 'fbuildbot.create'],
so your setup is not actually installing the "create" module. Makes sense that it could not be found.
I would recommend the find_packages utility
from setuptools import setup, find_packages
setup(
...
packages=find_packages(),
entry_points={
'console_scripts': [
'create = fbuildbot.create:main',
],
},
...
)
which will handle all of it for you.
My console_scripts/entry_points are not working in "develop" mode install and produce a traceback saying ImportError cannot load the module containing the entry points. Need help understanding how entry_points figure out which module to load and what paths to setup and stuff. Help fixing my error.
I have a setup.py script that has some entry points as follows
entry_points = {'console_scripts':[
'pyjampiler=pyjs.pyjampiler:Builder',
'pyjscompile=pyjs.translator:main',
'pyjsbuild=pyjs.browser:build_script',
]}
my code is organized as
workspace/
setup.py
pyjs/
src/
pyjs/
browser.py
My setup.py makes use of packages and package_dir arguments to setup() in setup.py to make sure the pyjs package gets picked up from pyjs/src/pyjs and so a regular install produces the following console scripts containing the following and it runs fine. it is able to load the module and call the entry point fine.
sys.exit(
load_entry_point('pyjs==0.8.1', 'console_scripts', 'pyjsbuild')()
)
But when I install and run it in development as "python setup.py develop", the install goes fine and I see the egg.lnk files getting created. but executing the console script causes the following errors
localhost:pyjs sarvi$ lpython/bin/pyjsbuild
Traceback (most recent call last):
File "lpython/bin/pyjsbuild", line 8, in <module>
load_entry_point('pyjs==0.8.1', 'console_scripts', 'pyjsbuild')()
File "/Users/sarvi/Workspace/pyjs/lpython/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg/pkg_resources.py", line 318, in load_entry_point
File "/Users/sarvi/Workspace/pyjs/lpython/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg/pkg_resources.py", line 2221, in load_entry_point
File "/Users/sarvi/Workspace/pyjs/lpython/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg/pkg_resources.py", line 1954, in load
ImportError: No module named browser
I suspect it has something to do with sys.path and the directory structure in the development sources. How can I get this to work in "develop" mode install?