Using setuptools to package your Python app
In our previous post, we made a Hello World! app to get us started with
Click. You might have noticed though that we needed to do
python hello-world.py
to run it. Since we're building CLI
apps, that's just not cool and it's not how CLI apps work anyway. We
need to be able to run a single command, something like:
(venv) $ hello
Hello World!
That's where setuptools
comes in. Setuptools helps us bundle our script so we can install it and
run it like an app ($ hello
), instead of like a script
($ python hello-world.py
).
Setuptools is a collection of enhancements to the Python distutils that allow developers to more easily build and distribute Python packages, especially ones that have dependencies on other packages. - Docs
The first thing we'll need to do is add a new file to our project and
call it setup.py
. We'll also rename
hello-world.py
to helloworld.py
(remove the
dash). I'll explain why this is necessary when we get to the
setup()
section. Our project structure should now look like
this:
hello-world-cli
|- helloworld.py # renamed from hello-world.py
|- setup.py # new file
In the helloworld.py
, remove the if __name__ =
'[[main]{.underline}]{.underline}':= section. The code should now look
like this:
import click
@click.command()
def hello():
click.echo('Hello World!')
In the setup.py
file, add this code:
from setuptools import setup
setup(
name='hello-world-cli',
py_modules=['helloworld'],
install_requires=[
'Click',
],
entry_points='''
[console_scripts]
hello=helloworld:hello
''',
)
Let's examine what each line of code does.
from setuptools import setup
We need to import setup
from setuptools
in
order to use it.
Next, we call the setup()
function and pass in a number of
parameters:
name='hello-world-cli'
This'll be the name of our CLI app.
py_modules=['helloworld']
This tells the setup()
where to find our main module to
execute. Our main file here is helloworld.py
so we set
helloworld
as the module. We can keep it that simple since
we only have one file for now, but as our app grows we'll replace
py_modules
with packages=find_packages()
. More
on that later.
install_requires=['Click']
Our app has Click as a dependancy, so it needs to be installed for it to
work. setup()
needs to know about this so it can include it
as it packages our project. install_requires
accepts a list
of values, so if we had more dependencies, we would list all of them
here.
entry_points='''
[console_scripts]
hello=helloworld:hello
'''
This is the part that saves us the hassle of having to run the app with
python ...
everytime, and enables us to just execute
hello
to run it.
It's important to note that if we maintained our previous name
(hello-world.py
), the setup
would have failed
at entry_points
. This is because python module names
shouldn't have dashes.
We can now install our app in our environment and run it. To install it, run:
(venv) $ pip install --editable .
Then execute the created command:
(venv) $ hello
Hello World!