I’ve developed several Python projects in the distant past, and after recently releasing rsnappush and following it up with release 1.1, I’ve researched and learned several new methodologies that Python developers need to be aware of.
A quick preface, though: I only write code for Linux platforms, so compatibility with Windows platforms doesn’t engage me at all. I therefore go with the simplest route for a Linux-only distribution.
setup.py changes: use setuptools
Back in the day Python developers relied on the distutils package, but now setuptools is recommended.
Manpages
I like manpages, and in general, Linux developers like them too. They are
predictably found, and follow consistent format that works well for
reference purposes. I’m a fan of using markdown as the base format,
and then let conversion tools work from there. I considered using
pandoc
, but it wasn’t specific enough for creating manpages.
My Preferred Tool: ronn
ronn is a great, simple tool for
converting markdown into manpages, and has nice manpage-specific
markups. For distributing Python command line tools, I’m a fan of
having the github-popularized README.md
to be the source for
documentation. In order to use ronn
automatically and get the
manpages installed with right permissions, below is the setup.py
boilerplate you can re-use. It’s unfortunate that Python doesn’t have
better built-in support for distributing manpages in packages.
# setup.py boilerplate
import os
import setuptools
import subprocess
import setuptools.command.sdist
import setuptools.command.install
from distutils import log
manpage = 'rsnappush.1'
def run(cmd):
log.info("calling " + ' '.join(cmd))
subprocess.run(cmd, check=True)
# run ronn with every sdist, converting README.md into manpage
class my_sdist(setuptools.command.sdist.sdist):
def run(self):
cmd = ["ronn", "--roff", "README.md"]
run(cmd)
cmd = ["mv", "README.1", manpage]
run(cmd)
super().run()
# make the manpage world-readable
class my_install(setuptools.command.install.install):
def run(self):
os.umask(0o002)
run(['chmod', '-R', 'a+rX', 'rsnappush.egg-info'])
stat = os.stat(manpage)
os.chmod(manpage, stat.st_mode | 0o444)
super().run()
# enter the right hooks for setuptools
setuptools.setup(...,
data_files=[('share/man/man1/', [manpage])],
cmdclass = {'sdist': my_sdist,
'install': my_install,
},
)
More uses for README.md
setup.py
, in its call to setuptools.setup()
, sets
long_description
. Make your life easy and just have it read
README.md
:
# More setup.py boilerplate
with open("README.md", "r") as fh:
long_description = fh.read()
setuptools.setup(...
long_description = long_description,
...
)
Licenses: Mozilla Public License
I did a little more research on Open Source License, and have decided to switch rsnappush from the Eclipse Public License (EPL) to the Mozilla Public License 2.0 (MPL). It’s basically a middle-ground between the BSD and LGPL license. The MPL is very similar to the EPL, but more popular. They basically are both simple copyleft licenses, with no linking rules. The main difference that I could pick out is that the MPL also has a built-in permission that the user can re-license the code as the LGPL if they choose. You can do this with the EPL but I’d have to include an extra clause. I don’t want that extra step.
I plan on using the MPL for much of the new open source code I write.