jython-nailgun-eclipse

Automatically generated description.

Jython startup time, nailgun and eclipse (WIP)

Being frustrated about Jython startup time that leads to running unittest rarely, I decided to investigate ways to improve it.

Unfortunately, there’s not much you can do about it:

The suggestion is to run JVM once and reuse that instance. Nailgun helps to achieve it. Playing a little with it I came up with the idea of extending PyDev with an ability to use Nailgun.

Extending PyDev

After reading developer instructions I went ahead and forked the Pydev repository. After importing eclipse projects into a new workspace, adding some breakpoints and running Eclipse in the debug mode I found a place where Jython’s command line is constructed: it is a getCommandLine method of org.python.pydev.debug.ui.launching.PythonRunnerConfig.

The plan has emerged:

  • Run nailgun server
  • Setup classpath
  • Run the script

Since nailgun server should be started only once, I can do it manually for now.

TODO:

  • start nailgun server by pydev (restart on demand)
  • stop: ng-stop

PYTHONPATH

First I need to provide a proper PYTHONPATH environment variable. Since in Jython PYTHONPATH contains classpath, I can just setup class path. To do that Nailgun provides ng-cp class:

./ng ng-cp space delimited classpath folders

Run the script

To run the script you must specify the jython main class and a path to a script as an argument:

./ng org.python.util.jython path/to/script

or you can use the -c option for inline scripts:

./ng org.python.util.jython -c "inline script"

Module reloading

Now our script run pretty fast. But the problem is that imported modules are not reloaded when you change them. I.e. if a module is already in sys.modules, import does nothing.

There are a few articles that attempt to solve this problem:

There are two approaches to make module be reloaded:

  • delete it from sys.modules and wait for the next import
  • use the built-in function reload.

I’ve choosen the second one, since it’s more obvious and simple.

It is not enough to just reload one module. You must also reload all its dependants. E.g. if you have such two modules:

# dependency.py
name = __name__


# dependant.py
from dependency import name

And you change dependency.name, you must reload not only the dependency, but also the dependant.

To do that we’ll build the dependency tree.

Since we want to reload only changed modules, we should save modules timestamps.

  • (hook on save action, make hook on import, save modified timestamp )
  • ValueError: (‘unsupported operand type’, op) when using re.compile
    • Never reload sre_constants module!

https://github.com/Vanuan/module_reloader

An option to call reloader script was added to Eclipse.

TODO:

  • Unload module when file is deleted
  • Unload module when import is commented out
  • Run as Jython unit-test won’t work

Environment, current working directory and arguments.

Unfortunately, Jython doesn’t reinitialize command line arguments, working directory and enviroment when run multiple times in the same JVM. This is good (simultaneous runs won’t rewrite any system field, modules are not unloaded). And this is bad (subsequent runs won’t change argv and cwd).

We need to keep modules loaded just once, but update these:

  • environment

  • current working directory

  • arguments

  • Jython cwd and arguments should be forcefully reinitialized!

TODO: jython reloader, option to Eclipse

The result

Known limitations and TODOs

File not found - /opt/jython/jython-2.5.3/Lib/site.py (Too many open files) fixed. (close file after find_module) File modification timestamp is 1 sec precision

Still I need to

  • embed nailgun binaries to pydev
  • deal with debugging in some way
  • impossible to stop script