biblio.py 0.55 release (sanity)

You can find the latest release of biblio.py here.

v0.55 (sanity), bkarak:
* FIXED: ~/.biblio.py/repositories file is now created correctly, when you run the program for the first time
* ADDED: pdf storage support

	Now biblio.py automatically find and adds to each bibtex entry pdf file that contain the actual document.
	The pdf file is stored in a folder with the bib file's name, in the same directory. For example, the file '/home/bkarak/foo.bib'
	should contain the pdf files in '/home/bkarak/foo'. The pdf file should have as filename the entry's key.

	The generated entry will look like:

	@techreport{GRSH00,
	 Title = {Rules of Thumb in Data Engineering},
	 Year = {2000},
	 Author = {Jim Gray and Prashant Shenoy},
	 Institution = {Microsoft Research, Advanced Technology Division},
	 Filename = {[...]/bibliography/reading/2009/june-2009.bib},
	 pdf-file = {[...]/bibliography/reading/2009/june-2009/grsh00.pdf},}
* REMOVED: Optik library removed

Slice and Dice

Lets have a look at the following example:

bkarak@linux-uho3:~> python
Python 2.6 (r26:66714, Feb  3 2009, 20:52:03)
[GCC 4.3.2 [gcc-4_3-branch revision 141291]] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = [1,2,3,4,5,6,7,8,9,10]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a[1:]
[2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a[1:].extend(a[:2])
>>> a[1:] + a[:2]
[2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2]

I am trying to concatenate two slices from a python list, using the extend method.

“| extend(…)
| L.extend(iterable) — extend list by appending elements from the iterable”

Why this does not work? … the list concatenation works fine with the “+” operator.

Multiple Inheritance in Python 2.5

I always liked python. It is a rather gentle language with many functional and Object-Oriented characteristics. I was always complaining about python’s Object-Oriented support, and i have a principle as a developer: “If you cannot implement something, do not offer it as a feature”.

Python violates this principle, because it allows developers to use multiple inheritance on a class but does not implement it correctly. Consider the following example:

class ParentOne:
	def __init__(self):
		print "Parent One says: Hello my child!"
		self.i = 1

	def methodOne(self):
		print self.i

class ParentTwo:
	def __init__(self):
		print "Parent Two says: Hello my child"

class Child(ParentOne, ParentTwo):
	def __init__(self):
		print "Child Says: hello"

We have three classes, ParentOne, ParentTwo, and Child. The class Child inherits ParentOne and ParentTwo.

Normally each parent class should be initialised when the child class is initialised through a specified initialisation scheme. Python just do not initialise the parent classes. For example, if we create an instance of the class Child

c = Child()

… we will see in our screen the following output:

bkarak$ python example.py
Child Says: hello

As we can see the __init__ method (aka the constructor) for each parent class is never executed. OOppss.

So, if the ParentOne init method declares a field named “i” (instance field) and the child tries to execute the method, we will end up with the following result:

bkarak$ python example.py
Child Says: hello
Traceback (most recent call last):
  File "example.py", line 20, in 
    c.methodOne()
  File "example.py", line 9, in methodOne
    print self.i
AttributeError: Child instance has no attribute 'i'

Ouch. This fact narrows down the usability of multiple inheritance to simple concatenation of methods with static methods. Really nicely done.

My advice is: “Avoid it, because you are not going to enjoy it”.

I do not really know if something is better implemented in Python 3.0. I will check it and write about it in the distant future.

ArgsDispatcher

I really hate GUI programming. Lucky me, i develop mostly command-line applications.

The problem is always the same. Command-line applications take arguments, and that arguments need to be parsed. I used various methods to do the job; i tried to use getopt (which i found BAD) and some other libraries.

During the development of biblio.py, i devised the following solution to create a very simplistic command-line parser.

The actual command-line scheme of biblio.py is:

biblio.py [command] [args]

An example:

biblio.py search software

To parse such simple arguments you typically need an if-else if pattern:

if sys.argv[1] == 'arg1':
	# do something here
elif sys.argv[1] == 'arg2':
	# do something there
elif sys.arg[1] == 'arg3':
	# etc ...

Hm … that is not very good piece of code, and not very scalable either. To avoid all these, i proposed the following solution:

class ArgsDispatcher:
       def __init__(self, args):
                self.__args = args

       def doHelp(self):
                # print the online help

       def doFoo(self):
                # is the 'foo' argument actual implementation

# the program starts here
def main():
	# initialise the dispatcher and execute
	cdisp = ArgsDispatcher(sys.argv[2:])
	try:
		getattr(adisp,"do" + sys.argv[1].title())()
	except (AttributeError, IndexError):
		adisp.doHelp()

# call the main function
if __name__ == '__main__':
	main()

The solution is simple; reflectively the main function calls the implementation of each argument (after initialising ArgsDispatcher). The implemented method follows the pattern do[argument] e.g. help is implemented by doHelp.

Bibliography

Doing my PhD for the last 4 years … i have a big collection of articles (have not read them all :-p … but lots of them):

Macintosh:monitor bkarak$ biblio.py count
Processed [...]/reading/2008/july-2008.bib ... found 22 entries
Processed [...]/reading/papers/toplas-survey.bib ... found 12 entries
Processed [...]/reading/papers/fire.bib ... found 61 entries
Processed [...]/reading/2008/august-2008.bib ... found 7 entries
Processed [...]/reading/papers/bkarak-publications.bib ... found 17 entries
Processed [...]/reading/2008/october-2008.bib ... found 25 entries
Processed [...]/reading/2008/september-2008.bib ... found 11 entries
Processed [...]/reading/papers/dsl-biblio.bib ... found 81 entries
Processed [...]/reading/3rdparty/yannis.bib ... found 61 entries
Processed [...]/reading/2008/may-2008.bib ... found 5 entries
Processed [...]/reading/papers/dsl-biblio2.bib ... found 19 entries
Processed [...]/reading/papers/full.bib ... found 507 entries
Processed [...]/reading/papers/ecoop08.bib ... found 40 entries
Processed [...]/reading/2008/april-2008.bib ... found 4 entries
Processed [...]/reading/papers/dds.bib ... found 277 entries
Processed [...]/reading/2008/june-2008.bib ... found 10 entries
Processed [...]/reading/2008/march-2008.bib ... found 13 entries

Total: 1172 entries in 17 files