One of my new years resolutions is to make Jython more friendly to new developers. One way to do that is to write up some notes on bits of Jython that are particularly mysterious to newcomers. I've boldly titled this post "Jython dev notes part I" to push myself to create more than one of these :)
It should be noted that I'm not shying away from making these notes highly technical - but I'm happy to edit them to make them more manageable later. Hopefully if I write enough of these up they can make up the beginnings of an advanced dev guide for Jython.
Recently I was asked how the Jython exposer works. The Jython exposer is the code that exposes the types that are written in Java as Python types in the Jython interpreter. It does this by rewriting the .class files during build time and adding the special methods that are seen at runtime. The augmented .class files end up in the build/exposed/ directory, and are ultimately built into the jython.jar distribution file. You can run the exposer from the Jython source like so:
ant expose
The exposer reads through each of the classes listed in CoreExposed.include and rewrites each of them. The rewritten classes get new methods generated for the Jython runtime to use as Python classes and methods. The exposer finds the code that it needs to operate on by finding Java annotations that have been defined for this purpose. An example is the easiest way to explain:
The string type in Python is called "str" and is implemented in Jython by src/org/python/core/PyString.java -- at the top of PyString.java is:
@ExposedType(name = "str", doc = BuiltinDocs.str_doc)
Which tells the exposer to expose PyString.java as the "str" type and take its "__doc__" attribute from BuiltinDocs.str_doc. Note that there currently appears to be a bug that str.__doc__ ends up as None right now, but it will show up if you run:
>>> help(str)
Further down in the source of PyString.java:
@ExposedNew
static PyObject str_new(PyNewWrapper new_, boolean init, PyType subtype, ...
Exposes the str_new Java method as the Python str __new__ method. (The __new__ method is a special class level method that acts as a str factory).
Next we'll look at some examples of ExposedMethod, which is the most common annotation that the exposer uses. ExposedMethod exposes general methods for Python classes.
@ExposedMethod(doc = BuiltinDocs.str___len___doc)
final int str___len__() {
The above code exposes the __len__ method, which is how the str method will respond to a call to the builtin len() function. Since the object itself is the only argument, the ExposedMethod annotation only needs a doc.
@ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.str___eq___doc)
final PyObject str___eq__(PyObject other) {
The above exposes the __eq__ method. MethodType.Binary indicates that this is a binary method that will take 2 arguments. The exposer has special handling for common types like this.
@ExposedMethod(defaults = {"null", "-1"}, doc = BuiltinDocs.str_split_doc)
final PyList str_split(String sep, int maxsplit) {
The above implements the split method of str, which takes 2 optional arguments. the "defaults" attribute assigns default values to the optional arguments.
There is much more to the exposer, but unfortunately the code is the only real documentation other than this post at this time. The source for the exposer engine is in:
src/org/python/expose/
And the source for the generator and ant task are here:
src/org/python/expose/generate/
View comments