summaryrefslogtreecommitdiff
path: root/docs/setuptools.rst
diff options
context:
space:
mode:
authorArmin Ronacher <armin.ronacher@active-4.com>2014-08-12 22:50:21 +0200
committerArmin Ronacher <armin.ronacher@active-4.com>2014-08-12 22:50:21 +0200
commit61b6ffa13f3d1b471847c57b44bf0c5ac29c0244 (patch)
tree02b2432f3d716b1b795215d5359b071926a8adb1 /docs/setuptools.rst
parenta4d02ff64c328e7a7693b8d8dbeecfed1c704f6f (diff)
downloadclick-61b6ffa13f3d1b471847c57b44bf0c5ac29c0244.tar.gz
Rewrote the setuptools documentation.
Diffstat (limited to 'docs/setuptools.rst')
-rw-r--r--docs/setuptools.rst110
1 files changed, 83 insertions, 27 deletions
diff --git a/docs/setuptools.rst b/docs/setuptools.rst
index 1f4a8ac..7dfa591 100644
--- a/docs/setuptools.rst
+++ b/docs/setuptools.rst
@@ -1,33 +1,54 @@
.. _setuptools-integration:
-Usage with Setuptools
-=====================
+Setuptools Integration
+======================
When writing command line utilities, it's recommended to write them as
modules that are distributed with setuptools instead of using Unix
-shebangs. There are many reasons for this.
-
-The first one is that setuptools automatically generates executable
-wrappers for Windows so your command line utilities work on Windows too.
-
-The second reason is that setuptools scripts work with virtualenv on Unix
-without the virtualenv having to be activated. This is a very useful
-concept which allows you to bundle your scripts with all requirements into
-a virtualenv.
+shebangs.
+
+Why would you want to do that? There are a bunch of reasons:
+
+1. One of the problems with the traditional approach is that the first
+ module the Python interpreter loads has an incorrect name. This might
+ sound like a small issue but it has quite significant implications.
+
+ The first module is not called by it's actual name, but the
+ interpreter renames it to ``__main__``. While that is a perfectly
+ valid name it means that if another piece of code wants to import from
+ that module it will trigger the import a second time under it's real
+ name and all the sudden your code is imported twice.
+
+2. Not on all platforms are things that easy to execute. On Linux and OS
+ X you can add a comment to the beginning of the file (``#/usr/bin/env
+ python``) and your script works like an executable (assuming it has
+ the executable bit set). This however does not work on Windows.
+ While on Windows you can associate interpreters with file extensions
+ (like having everything ending in ``.py`` execute through the Python
+ interpreter) you will then run into issues if you want to use the
+ script in a virtualenv.
+
+ In fact running a script in a virtualenv is an issue with OS X and
+ Linux as well. With the traditional approach you need to have the
+ whole virtualenv activated so that the correct Python interpreter is
+ used. Not very user friendly.
+
+3. The main trick only works if the script is a Python module. If your
+ application grows too large and you want to start using a package you
+ will run into issues.
Introduction
------------
-To bundle your script with setuptools, all you need is the script in a Python
-package and a ``setup.py`` file.
+To bundle your script with setuptools, all you need is the script in a
+Python package and a ``setup.py`` file.
Imagine this directory structure::
- yourpackage/
- cli.py
+ yourscript.py
setup.py
-Contents of ``cli.py``:
+Contents of ``yourscript.py``:
.. click:example::
@@ -40,27 +61,26 @@ Contents of ``cli.py``:
Contents of ``setup.py``::
- from setuptools import setup, find_packages
+ from setuptools import setup
setup(
- name='yourpackage',
+ name='yourscript',
version='0.1',
- packages=find_packages(),
- include_package_data=True,
+ py_modules=['yourscript'],
install_requires=[
'Click',
],
entry_points='''
[console_scripts]
- yourscript=yourpackage.cli:cli
+ yourscript=yourscript:cli
''',
)
-The magic is in the ``entry_points`` parameter. Below ``console_scripts``,
-each line identifies one console script. The first part before the equals
-sign (``=``) is the name of the script that should be generated, the second
-part is the import path followed by a colon (``:``) with the Click
-command.
+The magic is in the ``entry_points`` parameter. Below
+``console_scripts``, each line identifies one console script. The first
+part before the equals sign (``=``) is the name of the script that should
+be generated, the second part is the import path followed by a colon
+(``:``) with the Click command.
That's it.
@@ -78,4 +98,40 @@ Afterwards, your command should be available:
.. click:run::
- invoke(cli, prog_name='yourscript', prog_prefix='')
+ invoke(cli, prog_name='yourscript')
+
+Scripts in Packages
+-------------------
+
+If your script is growing and you want to switch over to your script being
+contained in a Python package the changes necessary are minimal. Let's
+assume your directory structure changed to this::
+
+ yourpackage/
+ main.py
+ utils.py
+ scripts/
+ yourscript.py
+
+In this case instead of using ``py_modules`` in your ``setup.py`` file you
+can use ``packages`` and the automatic package finding support of
+setuptools. In addition to that it's also recommended to include other
+package data.
+
+These would be the modified contents of ``setup.py``::
+
+ from setuptools import setup, find_packages
+
+ setup(
+ name='yourpackage',
+ version='0.1',
+ packages=find_packages(),
+ include_package_data=True,
+ install_requires=[
+ 'Click',
+ ],
+ entry_points='''
+ [console_scripts]
+ yourscript=yourpackage.scripts.yourscript:cli
+ ''',
+ )