Category Archives: python

Python-iptables

Python-iptables is a Python project that provides bindings to the iptables C libraries in Linux. Interoperability with iptables is achieved using the iptables C libraries (libiptc, libxtables, and iptables extensions), not calling the iptables executable and parsing its output as most other iptables wrapper libraries do; this makes python-iptables faster and not prone to parsing errors, at the same time leveraging all available iptables match and target extensions without further work. If you need further information on how iptables and netfilter work, this is a great summary.

Continue reading

IndentFinder vim plugin

This is a great little python script that finds out what indentation is used in your source files. The author also provides a vim plugin, which is a life saver for anyone working with others on software projects. It prevents the complete mess that is the result of team members using their own indentation settings on source code. It analyses the text file, and provides reliable hints what indentation settings (tabs vs spaces, number of spaces etc) were used by the author. There is another plugin for the same purpose, which is basically the vimscript port of IndentFinder, but this latter is extremely slow, especially on large files (it seems vimscript was not really meant for parsing thousands of lines every time you open a file).

What I did not really like about IndentFinder was the way it invokes the python interpreter (thus increasing startup time and leaving room for errors), even if python bindings are supported in vim.  One solution could have been simply to create a vim plugin from the python source, but then this would have meant increased maintenance efforts (copying changes from the python source to the vim plugin).  Another possibility was to generate the vim plugin via setup.py from the python source.

First I added a new method to the main class in indent_finder.py:

--- a/indent_finder.py
+++ b/indent_finder.py
@@ -125,16 +125,21 @@ class IndentFinder:
         self.clear()^M
         f = open( fname )^M
         l = f.readline()^M
         while( l ):^M
             self.analyse_line( l )^M
             l = f.readline()^M
         f.close()^M
 ^M
+    def parse_buffer( self, buf ):^M
+        self.clear()^M
+        for l in buf:^M
+            self.analyse_line(l)^M
+^M
     def clear( self ):^M
         self.lines = {}^M
         for i in range(2,9): self.lines['space%d' % i] = 0^M
         for i in range(2,9): self.lines['mixed%d' % i] = 0^M
         self.lines['tab'] = 0^M
 ^M
         self.nb_processed_lines = 0^M
         self.nb_indent_hint = 0^M

It just makes it possible to call the parser with a buffer instead of a file name: vim opens the file and reads its contents into memory, thus it’s easier to pass the buffer itself to IndentFinder.

The second part is modifying setup.py to build the plugin from a fixed header, the python source and a fixed trailer. It turned out distutils is flexible enough to do this easily: you can subset the build class and do your special stuff in it. Easy:

#!/usr/bin/env python

from distutils.core import setup
from distutils.command.build import build
import os
import indent_finder

HEADER = """if exists('indent_finder') || !has('python')
	finish
endif
let indent_finder=1

python << EOS
"""

TRAILER = """EOS

augroup indent
	au!
	au BufRead *.* :py import vim
	au BufRead *.* :py fi = IndentFinder()
	au BufRead *.* :py fi.parse_buffer(vim.current.buffer)
	au BufRead *.* :py vim.command(fi.vim_output())
augroup END
"""

These are our fixed header and trailer parts. We just make sure python is supported in vim, and make IndentFinder parse the opened buffer. The result from IndentFinder is an actual vim command that adjusts indentation settings.

class build_vimscript(build):
	vimscript = "indent_finder.vim"
	pyscript = "indent_finder.py"

	def run(self):
		build.run(self) # call superclass first

		if self.is_vimscript_outdated():
			self.update_vimscript()

	def is_vimscript_outdated(self):
		pyst = os.stat(self.pyscript)
		try:
			vimst = os.stat(self.vimscript)
		except OSError:
			return True
		else:
			if pyst.st_mtime > vimst.st_mtime:
				return True
		return False

	def update_vimscript(self):
		pyf = open(self.pyscript, "r")
		vimf = open(self.vimscript, "w")

		vimf.write(HEADER)
		for line in pyf:
			vimf.write(line)
		vimf.write(TRAILER)

		vimf.close()
		pyf.close()

Here we check that the vim plugin is older than the python source of IndentFinder. If it is, then the plugin is rebuilt. Calling the superclass in our run() method makes sure the other part of the build process is handled the usual way.

setup( 	name = "Indentation Finder",
		version = indent_finder.VERSION,
		description = "Finds of check the indentation used in programming source files",
		author = "Philippe Fremy",
		author_email = "phil at freehackers dot org",
		maintainer = "Philippe Fremy",
		maintainer_email = "phil at freehackers dot org",
		license = "BSD license",
		url="http://www.freehackers.org/Indent_Finder",
		py_modules = [ "indent_finder" ],
		cmdclass={"build": build_vimscript},
		)

Here we’ve just added a new parameter to setup cmdclass tells distutils to use our class for building the package.

And that’s it. The .vim plugin is built and can be copied to
~/.vim/plugin/.