Anatomy of a Pinax Reusable App

The Pinax team has built a lot of reusable Django apps over the years. We have begun settling on certain patterns to make our apps more consistent. In this post we’d like to share with you the different aspects of what we are doing and why.

We maintain an app template that we base new apps off of and are in the process of updating older apps to comply with. This template is called pinax-starter-app and is the best place to start in walking through how we build apps.

We can break down this application template into the following areas:

  • Common Files
  • Continuous Integration
  • Documentation
  • Packaging
  • Pinax Namespace

Common Files

We (should) have a common set of files in all our projects. By having them in the template we can ensure that we don’t forget to create them or copy them over from another project.

  • CONTRIBUTING.md - the document that provides guidance when submitting pull requests on preferences for how to work with our code base
  • .gitignore - common things like .pyc that we want to make sure don’t get committed to the repo
  • AUTHORS - a file that lists all the contributors to the project
  • LICENSE - a copy of the MIT license that we apply to all our open source
  • README.rst - both a README for the app template as well as a template to be used on the new app once you create it

Continuous Integration

Code quality is a big priority of the Pinax team. Not only do we want to keep quality high from the perspective of bugs, but we want the code to be beautiful, clean, and consistant.

We lean heavily on Travis CI to automate the checking of the code on every commit pushed and every pull request sent to us. We run tests, we lint the code, and we send coverage reports to Coveralls so we can keep an eye on test coverage.

  • tox.ini - is what controls our testing matrix, we validate our app against several versions of Python and Django
  • .travis.yml - the configuration that tells Travis CI what to do
  • runtests.py - a script that bootstraps the Django environment in order to test the Django app
  • setup.py - has a parameter, test_suite="runtests.runtests", that tells python setup.py test what to run
  • .coveragerc - has configuration for running coverage on Travis
  • pinax/app_name/tests/ - serves as the basis to write tests for the application

By providing a new app with all this infrastructure setup and ready to go, we at least get linting of the code from the first commit pushed to an open repo as we have Travis CI setup to work for any repo it finds on the Pinax organziation that has a .travis.yml file.

But it’s also dead simple to just add some tests and they’ll get run since all you have to do is literally just starting writing tests.

Documentation

We have recently switched from using Sphinx to MkDocs. Both are supported on Read The Docs where all our docs are hosted but Markdown is just more natural when authoring content and setup/configuration for MkDocs is simpler and quicker to get going with.

  • docs/ - is the start of the documentation
  • mkdocs.yml - configuration for MkDocs

Both of these are setup to just make getting going with writing documentation easy and to get the infrastruction bits out of the way.

Packaging

Packaging is another infrastructure piece that we had done a lot of different ways in the past and was always evolving. It likely will continue to evolve but hopefully those changes will be reflected in this template and our projects kept reconciled to it.

  • MANIFEST.in - what files should we always include in the package
  • setup.py - we have had lots more complicated setup files in the past but this being short and sweet seems to fit the bill lately

We used to specify the version number in the package’s __init__.py and then import it into the setup.py. But we have found specifying the version number in the setup.py and using pkg_resources to pull it out of the package for anything that needs to read the version at run time to be a better alternative:

# pinax/app_name/__init__.py
import pkg_resources
__version__ = pkg_resources.get_distribution("pinax-{{ app_name }}").version

Pinax Namespace

Lastly, you might have noticed that we have started namespacing Pinax apps. Not all of them. Some, like django-user-accounts will remain top level for historical reasons, but most apps will be rolled under the pinax.* namespace.

The main reason for doing this is so we can use more functional names that will likely have collisions with other applications in the ecosystem. For example, we currently have this problem with django-stripe-payments and the code living in a payments namespace. There have been some requests from folks who are using other packages with the same namespace making them incompatible to live side by side. Having this package live at pinax.payments will solve that, in addition signal to the developer that this app is designed to work well with other Pinax ecosystem applications.

Another reason for this change is that Eldarion is donating a lot of its open source to Pinax. Eldarion had a history of naming his open source applications with Greek names. There has been a lot of feedback that this makes things hard to discover. So we have renamed packages as they have been donated, for instance, biblion to pinax-blog.

Tags

pinax-blog django-user-accounts django-stripe-payments biblion pinax-starter-app