Skip to content

Commit 950816a

Browse files
committed
updated pacakging pages.
1 parent f69ce1c commit 950816a

File tree

4 files changed

+81
-37
lines changed

4 files changed

+81
-37
lines changed

source/exercises/mailroom/mailroom-pkg.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The first step is to re-structure your code into separate files:
2020

2121
You should have all this pretty distinct after having refactored for the unit testing. If not, this is a good time to do it!
2222

23-
In addition to those three, you will want to write a top-level script file (probably called ``mailroom.py``) that does little but import the ui code and run a ``main()`` function. It should look something like this:
23+
In addition to those three, you will want to write a top-level script file (perhaps called ``mailman.py``) that does little but import the ui code and run a ``main()`` function. It should look something like this:
2424

2525
.. code-block:: python
2626
@@ -32,6 +32,8 @@ In addition to those three, you will want to write a top-level script file (prob
3232
3333
Yes, that's it! This has the advantage of keeping the top-level script really simple, as it has to get put somewhere else and it can keep the "real" code in the package where it belongs.
3434

35+
.. note:: Be careful here -- it is important not to call your top-level script the same thing as your package, in this case ``mailroom.py``. If you do, than when installed, python will find the script, rather than the package, when you do ``import mailroom``. You can call it ``mailroom`` without the Python, but that may confuse Windows.
36+
3537

3638
Making the Package
3739
------------------
@@ -49,7 +51,7 @@ Put all these in a python package structure, something like this::
4951
test_model.py
5052
test_cli.py
5153
bin
52-
mailroom.py
54+
mailman.py
5355

5456
You will need to import the logic code from model.py in the cli code in order to use it. You can wait until you learn about mocking to write the code in test_cli.py (so you can leave that out)
5557

@@ -63,6 +65,8 @@ To get the script installed you have two options. I prefer the more straightforw
6365

6466
But if you want to get fancy, you can use ``setuptools``'s `entry points <http://python-packaging.readthedocs.io/en/latest/command-line-scripts.html#the-console-scripts-entry-point>`_
6567

68+
.. note:: On Unix systems, including the Mac, the simple ``scripts`` keyword argument method works well and is simple. But it may not work as well on Windows -- it relies in your script being named ``something.py`` and that Windows is configured to run all files with ``.py`` extensions. Not all windows systems are set up this way. But the "entry points" method builds a little exe file to call your script, so it's more reliable.
69+
6670

6771
Including data files
6872
--------------------

source/exercises/packaging/capitalize/cap_script.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
"""
44
A really simple script just to demonstrate packaging
55
"""
6-
7-
import sys, os
8-
import capital_mod
96
import main
107

11-
128
if __name__ == "__main__":
139
main.main()

source/exercises/trigrams/test_trigrams.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ def test_make_sentence():
119119
as it is supposed to be random, this tests for things other than
120120
the actual results.
121121
122+
Which means that it does NOT test everything! This test could pass
123+
with a very broken make_sentence function. So you should probably
124+
add a few more things to this test.
125+
122126
NOTE that this test relies on the build_trigram() function, so it
123127
will fail if that doesn't work.
124128
"""

source/modules/Packaging.rst

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,10 @@ Widely used by the scipy community:
331331
(lots of hard to build stuff that needs to work together...)
332332

333333
* Anaconda (https://store.continuum.io/cshop/anaconda/) and `miniconda <https://docs.conda.io/en/latest/miniconda.html>`_
334+
334335
* ActivePython (http://www.activestate.com/activepython)
335336

336-
Anaconda has seen a LOT of growth recently -- it's based on the open-source conda packaging system, and provides both a commercial curated set of packages, and a community-developed collection of packages known as conda-forge:
337+
Conda has seen a LOT of growth in the last few years -- it's based on the open-source conda packaging system, and provides both a commercial curated set of packages, and a community-developed collection of packages known as conda-forge:
337338

338339
https://conda-forge.org/
339340

@@ -548,7 +549,7 @@ You can find some additional notes here: :ref:`virtualenv_section`
548549
Building Your Own Package
549550
=========================
550551

551-
The term "package" is overloaded in Python. AS defined above, it means a collection of python modules. But it often is used to refer to not just the modules themselves, but the whole collection, with documentation and tests, bundled up and installable on other systems.
552+
The term "package" is overloaded in Python. As defined above, it means a collection of python modules. But it often is used to refer to not just the modules themselves, but the whole collection, with documentation and tests, bundled up and installable on other systems.
552553

553554
Here are the very basics of what you need to know to make your own package.
554555

@@ -567,7 +568,7 @@ structured package eases development.
567568

568569

569570
What is a Package?
570-
--------------------
571+
------------------
571572

572573
**A collection of modules**
573574

@@ -583,28 +584,29 @@ What is a Package?
583584

584585

585586
Python packaging tools:
586-
------------------------
587+
-----------------------
587588

588589
The ``distutils``::
589590

590591
from distutils.core import setup
591592

592593
Getting klunky, hard to extend, maybe destined for deprecation...
593594

594-
But it gets the job done -- and it does it well for the simple cases.
595+
You really need to use ``setuptools`` these days, which fortunatly has a similar API: ::
595596

596-
``setuptools``: for extra features
597+
from setuptools import setup
597598

598599
``pip``: for installing packages
599600

600601
``wheel``: for binary distributions
601602

602-
These last three are pretty much the standard now -- very well maintained by:
603+
These are pretty much the standard now -- very well maintained by:
603604

604605
"The Python Packaging Authority" -- `PaPA <https://www.pypa.io/en/latest/>`_
605606

606607
This all continues to change quickly, see that site for up to date information.
607608

609+
608610
Where do I go to figure this out?
609611
---------------------------------
610612

@@ -684,8 +686,9 @@ Basic Package Structure:
684686

685687
(http://docutils.sourceforge.net/rst.html)
686688

687-
``setup.py``: distutils script for building/installing package.
689+
(those are all "metadata" critical if you are distributing to the world -- not so much for your own use)
688690

691+
``setup.py``: ``distutils``/``setuptools`` script for building/installing the package.
689692

690693
``bin/``: This is where you put top-level scripts
691694

@@ -697,30 +700,33 @@ Basic Package Structure:
697700

698701
``test/``: your unit tests. Options here:
699702

700-
Put it inside the package -- supports ::
703+
Put it inside the package -- this results in the tests getting isntalled with the package, so they can be run after installation, with::
701704

702705
$ pip install package_name
703706
>> import package_name.test
704707
>> package_name.test.runall()
705708

706-
Or keep it at the top level.
709+
or ::
710+
711+
$ pytest --pyargs package_name
712+
713+
714+
Or, if you have a lot of tests, and do not want the entire set installed with the package, you can keep it at the top level.
707715

708716
Some notes on that: `Where to put Tests <http://pythonchb.github.io/PythonTopics/where_to_put_tests.html>`_
709717

710718

711719
The ``setup.py`` File
712-
----------------------
720+
---------------------
713721

714-
Your ``setup.py`` file is what describes your package, and tells the distutils how to package, build, and install it
722+
Your ``setup.py`` file is what describes your package, and tells the setuptools how to package, build, and install it
715723

716724
It is python code, so you can add anything custom you need to it.
717725

718726
But in the simple case, it is essentially declarative.
719727

720-
721728
``http://docs.python.org/3/distutils/``
722729

723-
724730
An example:
725731
...........
726732

@@ -729,12 +735,15 @@ An example:
729735
from setuptools import setup
730736
731737
setup(
738+
# the critical stuff
732739
name='PackageName',
740+
packages=['package_name', 'package_name.test'],
741+
scripts=['bin/script1','bin/script2'],
742+
743+
# the good to have stuff: particularly if you are distributing it
733744
version='0.1.0',
734745
author='An Awesome Coder',
735746
author_email='[email protected]',
736-
packages=['package_name', 'package_name.test'],
737-
scripts=['bin/script1','bin/script2'],
738747
url='http://pypi.python.org/pypi/PackageName/',
739748
license='LICENSE.txt',
740749
description='An awesome package that does something',
@@ -745,6 +754,7 @@ An example:
745754
],
746755
)
747756
757+
748758
``setup.cfg``
749759
--------------
750760

@@ -770,7 +780,7 @@ Note that an option spelled ``--foo-bar`` on the command-line is spelled f``foo_
770780
Running ``setup.py``
771781
--------------------
772782

773-
With a ``setup.py`` script defined, setuptools can do a lot:
783+
With a ``setup.py`` script defined, setuptools, along with pip, can do a lot:
774784

775785
* builds a source distribution (a tar archive of all the files needed to build and install the package)::
776786

@@ -790,6 +800,12 @@ With a ``setup.py`` script defined, setuptools can do a lot:
790800

791801
python setup.py install
792802

803+
or::
804+
805+
pip install .
806+
807+
(the dot means "this directory" -- pip will look in the current dir for a ``setup.py`` file)
808+
793809
* install in "develop" or "editable" mode::
794810

795811
python setup.py develop
@@ -798,6 +814,7 @@ or::
798814

799815
pip install -e .
800816

817+
.. note:: setuptools can be used by itself to build and install packages. But over the years, pip has evolved to a more "modern" way of doing things. When you install from source with pip -- it is using setuptools to do the work, but it changes things around, and installs things in a more modern, up to date, and compatible way. For much use, you won't notice the difference, but it setuptools still has some old crufty ways of doing things, so it's better to use pip as a front end as much as possible.
801818

802819
setuptools
803820
-----------
@@ -816,17 +833,18 @@ This buys you a bunch of additional functionality:
816833
* **develop mode**
817834
* a LOT more
818835

836+
In fact, virtually all python packages use setuptools these days, and there is currently discussion of deprecating distutils, and making setuptools "official". So you really want to use it.
837+
819838
http://pythonhosted.org//setuptools/
820839

821840
wheels
822-
-------
841+
------
823842

824843
Wheels are a binary format for packages.
825844

826845
http://wheel.readthedocs.org/en/latest/
827846

828-
Pretty simple, essentially a zip archive of all the stuff that gets put
829-
in ``site-packages``.
847+
Pretty simple, essentially a zip archive of all the stuff that gets installed, i.e. put in ``site-packages``.
830848

831849
Can be just pure python or binary with compiled extensions
832850

@@ -836,17 +854,9 @@ Building a wheel::
836854

837855
python setup.py bdist_wheel
838856

839-
Create a set of wheels (a wheelhouse)::
840-
841-
# Build a directory of wheels for pyramid and all its dependencies
842-
pip wheel --wheel-dir=/tmp/wheelhouse pyramid
843-
844-
# Install from cached wheels
845-
pip install --use-wheel --no-index --find-links=/tmp/wheelhouse pyramid
846-
847857
``pip install packagename`` will find wheels for Windows and OS-X and "manylinux"
848858

849-
``pip install --no-use-wheel`` avoids that.
859+
``pip install --no-use-wheel`` avoids that, and forces a source install.
850860

851861
manylinux
852862
---------
@@ -876,7 +886,6 @@ To upload your package to PyPi::
876886

877887
python setup.py sdist bdist_wheel upload
878888

879-
880889
http://docs.python.org/2/distutils/packageindex.html
881890

882891
NOTE: only do this if you really want to share your package with the world!
@@ -885,7 +894,7 @@ NOTE: only do this if you really want to share your package with the world!
885894
Under Development
886895
------------------
887896

888-
Develop mode is *really* *really* nice::
897+
Develop mode (or "editable install") is *really* *really* nice::
889898

890899
$ python setup.py develop
891900

@@ -1127,6 +1136,36 @@ To use pkg_resources, you include the files with ``package_data`` in setup.py bu
11271136
11281137
http://setuptools.readthedocs.io/en/latest/pkg_resources.html#resourcemanager-api
11291138

1139+
Command line scripts
1140+
--------------------
1141+
1142+
The "easy" and traditional way to isntall command line scripts is with the ``scripts`` keyword argument to the ``setup()`` command::
1143+
1144+
1145+
setup(...
1146+
...
1147+
scripts = ["bin/a_script.py"]
1148+
...
1149+
)
1150+
1151+
This works well on Unix systems (including the mac), but is not as reliable on Windows. All it really does is put a slightly altered copy of the script on PATH -- so it will work if it is named with the ``.py`` extension and the system is set up to run ``.py`` files.
1152+
1153+
entry points
1154+
............
1155+
1156+
A more complicated, but better maintained and robust way is to use setuptools "entry points". Entry points can provide a number of functions, but one of them is to make console scripts. Also an argument to ``setup()``, It is done like so::
1157+
1158+
setup(
1159+
...
1160+
entry_points = {
1161+
'console_scripts': ['script_name=package_name.module_name:main'],
1162+
}
1163+
...
1164+
)
1165+
1166+
What this does is tell setuptools to make a little wrapper program called "script_name" that will start up python, and run the function called ``main`` in the package.module module.
1167+
1168+
11301169
Getting Started With a New Package
11311170
----------------------------------
11321171

@@ -1147,6 +1186,7 @@ or use "Cookie Cutter":
11471186
https://cookiecutter.readthedocs.io/en/latest/
11481187

11491188

1189+
11501190
LAB: A Small Example Package
11511191
----------------------------
11521192

0 commit comments

Comments
 (0)