Skip to content

Instantly share code, notes, and snippets.

@logc
Last active March 8, 2017 09:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save logc/2793a4e35d663ba1baf278d7a2e15a39 to your computer and use it in GitHub Desktop.
Save logc/2793a4e35d663ba1baf278d7a2e15a39 to your computer and use it in GitHub Desktop.
Python packages with Sphinx & Github pages
#!/usr/bin/env bash
pkg_name=$1
pkg_root=$PWD/${pkg_name}
doc_root=${pkg_root}/docs/_build/html
hostname=`hostname`
year=`date '+%Y'`
version='0.1.0'
mkdir -p ${pkg_root}/${pkg_name}
mkdir -p ${pkg_root}/test
cat << EOF > ${pkg_root}/setup.py
from setuptools import setup
setup(name='$pkg_name',
version='$version',
author='$USER',
author_email='$USER@$hostname',
entry_points={
'console_scripts': [
'${pkg_name} = ${pkg_name}.main:run'
]
},
test_suite='nose.collector'
)
EOF
touch ${pkg_root}/${pkg_name}/__init__.py
cat <<EOF > ${pkg_root}/${pkg_name}/main.py
"""
This module holds entry points of the ${pkg_name} package
"""
def run():
"""Main console entry point"""
print "Hello, ${pkg_name}"
if __name__ == '__main__':
main()
EOF
cat <<EOF > ${pkg_root}/test/test_main.py
def test_main():
assert 1 == 2, "Fix this test"
EOF
cat << EOF > ${pkg_root}/README.md
$pkg_name
=========
# Installation
This is a Python setuptools package. Use this command:
$ python setup.py install
# Usage
Please refer to the documentation
# License
See LICENSE.txt
EOF
cat << EOF > ${pkg_root}/LICENSE.txt
MIT License
Copyright (c) $year $USER
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
EOF
cat << EOF > ${pkg_root}/requirements.txt
nose
sphinx
EOF
cat << EOF > ${pkg_root}/.gitignore
.Python
/bin/
/include/
/lib/
pip-selfcheck.json
EOF
pip --quiet install virtualenv
virtualenv --quiet ${pkg_root}
source ${pkg_root}/bin/activate
pip --quiet install -r ${pkg_root}/requirements.txt
git init --quiet ${pkg_root}
sphinx-quickstart --quiet \
--project=${pkg_name} \
--author=$USER \
-v $version \
--ext-autodoc \
--no-batchfile \
${pkg_root}/docs
cd ${pkg_root}
git add --all .
git commit --quiet -m "Initial commit"
git checkout --orphan gh-pages
git checkout master
mkdir -p ${doc_root}
git worktree add -b gh-pages ${doc_root}
cd ${doc_root}
git rm -rf .
git commit --quiet -m "Remove sources from documentation root"
cd ${pkg_root}
sed -i -e "s/# import os/import os/" docs/conf.py
sed -i -e "s/# import sys/import sys/" docs/conf.py
# Notice we insert the **parent directory**
sed -i -e "s/# sys.path.insert(0, os.path.abspath('.'))/sys.path.insert(0, os.path.abspath('..'))/" docs/conf.py
sphinx-apidoc -o docs/ ${pkg_name}
sed -i -e '12 a\
\ \ \ modules' docs/index.rst
cd docs/
make html
cd ${doc_root}
touch .nojekyll
git add --all .
git commit --quiet -m "Start HTML documentation"
@logc
Copy link
Author

logc commented Mar 7, 2017

Usage example

Package creation

bash-3.2$ pypkg world
Creating file /tmp/world/docs/conf.py.
Creating file /tmp/world/docs/index.rst.
Creating file /tmp/world/docs/Makefile.

Finished: An initial directory structure has been created.

You should now populate your master file /tmp/world/docs/index.rst and create other documentation
source files. Use the Makefile to build the docs, like so:
   make builder
where "builder" is one of the supported builders, e.g. html, latex or linkcheck.

Switched to a new branch 'gh-pages'
Switched to branch 'master'
Preparing /tmp/world/docs/_build/html (identifier html)
HEAD is now at 7f484a2 Initial commit
rm '.gitignore'
rm 'LICENSE.txt'
rm 'README.md'
rm 'docs/Makefile'
rm 'docs/conf.py'
rm 'docs/index.rst'
rm 'man/man1/nosetests.1'
rm 'requirements.txt'
rm 'setup.py'
rm 'test/test_main.py'
rm 'world/__init__.py'
rm 'world/main.py'
Creating file docs/world.rst.
Creating file docs/modules.rst.
Running Sphinx v1.5.3
loading pickled environment... not yet created
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 3 source files that are out of date
updating environment: 3 added, 0 changed, 0 removed
reading sources... [100%] world
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [100%] world
generating indices... genindex py-modindex
writing additional pages... search
copying static files... done
copying extra files... done
dumping search index in English (code: en) ... done
dumping object inventory... done
build succeeded.

Build finished. The HTML pages are in _build/html.

Now there are 2 working trees in the Git repo:

  • one at the package root which points to master. Push to origin to publish source (or test) changes.
  • another one at the documentation build directory docs/_build/html. This points to gh-pages. Push to origin to publish documentation changes.

Develop the package

bash-3.2$ cd world
bash-3.2$ source bin/activate
(world) bash-3.2$ python setup.py develop
running develop
running egg_info
creating world.egg-info
writing world.egg-info/PKG-INFO
writing top-level names to world.egg-info/top_level.txt
writing dependency_links to world.egg-info/dependency_links.txt
writing entry points to world.egg-info/entry_points.txt
writing manifest file 'world.egg-info/SOURCES.txt'
reading manifest file 'world.egg-info/SOURCES.txt'
writing manifest file 'world.egg-info/SOURCES.txt'
running build_ext
Creating /private/tmp/world/lib/python2.7/site-packages/world.egg-link (link to .)
Adding world 0.1.0 to easy-install.pth file
Installing world script to /tmp/world/bin

Installed /private/tmp/world
Processing dependencies for world==0.1.0
Finished processing dependencies for world==0.1.0
(world) bash-3.2$ bin/world
Hello, world

Test the package

(world) bash-3.2$ python setup.py test
running test
running egg_info
writing world.egg-info/PKG-INFO
writing top-level names to world.egg-info/top_level.txt
writing dependency_links to world.egg-info/dependency_links.txt
writing entry points to world.egg-info/entry_points.txt
reading manifest file 'world.egg-info/SOURCES.txt'
writing manifest file 'world.egg-info/SOURCES.txt'
running build_ext
test_main.test_main ... FAIL

======================================================================
FAIL: test_main.test_main
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/world/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/private/tmp/world/test/test_main.py", line 2, in test_main
    assert 1 == 2, "Fix this test"
AssertionError: Fix this test

----------------------------------------------------------------------
Ran 1 test in 0.004s

FAILED (failures=1)
Test failed: <unittest.runner.TextTestResult run=1 errors=0 failures=1>
error: Test failed: <unittest.runner.TextTestResult run=1 errors=0 failures=1>

Document the package

(world) bash-3.2$ vim world/main.py
(world) bash-3.2$ git diff world/main.py
diff --git a/world/main.py b/world/main.py
index 78bd9d6..f17c462 100644
--- a/world/main.py
+++ b/world/main.py
@@ -5,6 +5,9 @@ def run():
     """Main console entry point"""
     print "Hello, world"

+def do():
+    """Does nothing"""
+    return None

 if __name__ == '__main__':
     main()
(world) bash-3.2$ cd docs
(world) bash-3.2$ make html
Running Sphinx v1.5.3
loading pickled environment... done
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 0 source files that are out of date
updating environment: 0 added, 1 changed, 0 removed
reading sources... [100%] world
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [100%] world
generating indices... genindex py-modindex
writing additional pages... search
copying static files... done
copying extra files... done
dumping search index in English (code: en) ... done
dumping object inventory... done
build succeeded.

Build finished. The HTML pages are in _build/html.
(world) bash-3.2$ open _build/html/index.html
(world) bash-3.2$ cd _build/html/
(world) bash-3.2$ git commit -am "Update doc"
[gh-pages 7e5ec50] Update doc
 4 files changed, 19 insertions(+), 3 deletions(-)
 rewrite searchindex.js (80%)
(world) bash-3.2$ git push

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment