No activity today, make something!
tiddlyweb Python Namespace Packages for TiddlyWeb

20160313184307 cdent  

Mature TiddlyWeb plugins need to be packaged so they can be indexed by pypi and installed via pip. At base this is relatively straightforward, put some stuff in a directory, make a setup.py, register the package, package up a source distribution, tell PyPI about it.

This is okay if you have a good name for your package, but what about packages, like plugins for TiddlyWeb, which have names which are only meaningful in their use context? You can't just use the name of the module, otherwise you end up with namespace collisions, trouble finding stuff, and associated beasts of chaos.

Thankfully distutils, setuptools, pip, etc conspire to support a notion called namespace_packages which can solve this issue. Unfortunately using the feature is not exceptionally well documented. I (@cdent) found getting started a bit frustrating, until I sort of cracked the nut. Here's some info for reference.

First some prerequisites:

  1. You need setuptools
  2. You need a username and password on PyPi.
  3. Some understanding of how to make a Python package distribution. Here's one tutorial: Use setup.py to Deploy Your Python App with Style.
  4. Some understanding of Python packages.

That tutorial includes a section about using namespace_packages under the heading "Multiple Distributions, One (Virtual) Package". That "Virtual" is key: if you wish to use namespace packages there must be no real distribution which occupies the namespace. In the example of tiddlywebplugins, you can have tiddlywebplugins.static and tiddlywebplugins.utils distributions which are members of the tiddlywebplugins namespace, but you must not have a tiddlywebplugins distribution. If you do, the packages which are supposed to occupy the virtual namespace will not be found. The upshot of this is that if you already have a package out there using a name that you want to use as a namespace, you will need to rename the existing package (this is why the old tiddlywebplugins package is now tiddlywebplugins.utils.

Packaging a Plugin

So say you have a TiddlyWeb plugin called foobar.py sitting in a directory somewhere. You've determined that it is a happy little plugin and the world would benefit if it could be installed easily. You've heard of the tiddlywebplugins namespace and you'd like to join the party. Here's what you do.

  • In that directory make a tiddlywebplugins directory.
  • Edit tiddlywebplugins/__init__.py to include just this line:

    __import__("pkg_resources").declare_namespace(__name__
    
  • Move foobar.py into the tiddlywebplugins directory.

  • Create a setup.py (in the original directory) that includes at least:
     from setuptools import setup, find_packages

     setup(
         version = '0.1',
         namespace_packages = ['tiddlywebplugins'],
         name = 'tiddlywebplugins.foobar',
         description = 'A TiddlyWeb plugin for foobaring the fritz.',
         install_requires = ['setuptools', 'tiddlyweb'],
         )
  • Do not import from the tiddlywebplugins package in setup.py. This will make installs struggle or fail later.
  • Learn enough about distribution to register the package and upload it. The links above point to enough documentation to figure that part out. If you can't be bothered to read that documentation then you shouldn't be distributing packages. We wouldn't want you aol-ing all over PyPi.
  • When you want to use your foobar plugin in a TiddlyWeb instance or application refer to it as tiddlywebplugins.foobar.

A github repository called pluginmaker has been created which captures all the necessaries for creating a plugin in the tiddlywebplugins namespace.