Extending Kate with Python

So there I am, a confirmed Kate user, and now I need to find my way around a codebase of over 100,000 files using GNU ID utils. The rather crude answer for Kate 3 was to write a wrapper around the lid(1) utility and the DCOP scripting interface of Kate, all driven from the built-in Konsole. The result was clunky but somewhat usable. But Kate 3? In 2010? Because the version of KDE on our primary development environment is the venerable KDE 3.3!

Eventually though, I decide the time had come for something a little nicer, and the answer seemed to lie in Kate 4 and scripting, except that the Javascript API didn’t seem to offer a way to get to the ID database. That had me stumped for a while until I came across Pâté, which allowed Kate 4 to be extended in Python. Sadly, it was unmaintained and there things stalled until, inexorably, I got to the point where the itch needed scratching.

That most basic driver of Open Source usually comes with strings attached, like the need to find a way to work in a new codebase, and with a new team of hackers. Plus, in the this case, the minor issue of being pretty much a Python newbie. Luckily it turns out that Kate has one of the most responsive teams I’ve encountered, the Pâté code seemed reasonably tractable, and the Python C API solidly documented. What could possibly go wrong? :-) Not that much, because we now have:

  • A Kate plugin based on Pâté
  • A Python debugger console Pâté plugin
  • And oh yes, an ID file integration Pâté plugin

The Kate plugin has a configuration page that allows individual Python plugins to be enabled or disabled, and if need be, system installed plugins to be overridden. Like the original Pâté, Python plugins can hook into Kate’s menus and shortcuts. Unlike the original, this version:

  • Allows Python plugins to supply Kate configuration pages just like native Kate plugins
  • Uses Python pickling to save configuration data, so arbitrary Python objects can be part of a plugin’s configuration
  • Provides for reloading Python plugins, which is really handy when writing new plugins
  • Supported threaded Python
  • Provides direct access to the documentation for Python plugins (though if anybody can figure out how to be information for variables, as well as classes and function, that would be wonderful!)
  • The sample Console and ID plugins try to show a selection of techniques

But help is always welcome to do better (How *should* i18n be done? What might Python 3 involve? What about some decent developer docs?). Any takers or clues much appreciated!

17 thoughts on “Extending Kate with Python”

  1. This is fantastic! I’m especially looking forward to using the Python debugger console. Very nice, thank you!

  2. Great work.. I was looking forward for a new Pate plugin for Kate 4.
    Is this work already available somewhere? I’d like to test it out and possibly replace my Eclipse+PyDev env :)

      1. thanks a lot for the answer..
        I’m already playing with git sources but I cannot find any ‘playground subfolder’ option in the CMakeLists.txt file. What I missing? Any hint?

        1. If you have 4.9, the code is in kate/playground/pate, and you need to uncomment the entry for playground in kate/CMakeLists.txt.

          If you have master following the 4.9 branch, the code is in kate/kate/plugins/pate, and it is part of the build by default as Dominik said.

  3. Nice to see! I can’t wait to use it.

    Is there a reason Kate isn’t just using Kross to provide general scripting support, instead of having to create separate interfaces for each language?

    1. Actually, the reason is very simple: For Kate Part scripting, we want a thin layer that especially works well for indenters and small helper scripts.

      On Kate Application level, the long term goal is indeed to use Kross, but this won’t happen as long as no one does the work. In this case, we have Python experts who ported a long existing plugin from KDE 3 to KDE 4, so we have people who do the work. I myself find it really cool to have this excellent python support, especially since there is a huge python community which may write very useful tools for Kate!

      It of course would be awesome if you implemented the Kross interface :-)

  4. Shaheed: By the way, are you going to the KDE conference starting on this Friday? This would be awesome! Several other Kate developers will be there, too :-)

  5. The Python builtin `dir’ function returns a Python list of supported function calls and properties/fields as Python strings (names) of any object . Similarly `type’ returns the Python type name of an object.

    So for example dir(dir) returns a list with “magic” methods, one of which is the ‘__call__’ method which is a sure sign of a function/method, similarly type(dir) returns ‘builtin_function_or_method’…

    1. And one of the properties often returned by a `dir’ call is ‘__doc__’, which returns the Python doc string. So in Python you could have a function like this:

      def printDoc(obj):
      if obj.__doc__ !=None:
      print(obj.__doc__)

      1. You don’t even need that much. Something that is equal to False (an empty string, any other empty object, 0, or None) is treated as False for if statements (or any other Boolean test), so you can just do

        def printDoc(obj):
        if obj.__doc__:
        print(obj.__doc__)

        Or, if you want to be more robust and allow for objects that don’t have a __doc__ attribute, you can use:

        def printDoc(obj):
        if getattr(obj,’__doc__’,”):
        print(obj.__doc__)

        This causes getattr to return the contents of obj.__doc__ if obj has a __doc__ attribute, otherwise it returns an empty string. If either obj.__doc__ is empty or doesn’t exist, the if test sees that as False and so does not execute the print line

        1. Thanks for the replies, but the problem is a tad more subtle than that :-(.

          Basically, if you (a) enable the Pate plugin, (b) open its configuration settings, and (c) click on the second tab, you’ll see some HTML formatted documentation for each plugin, extracted from __doc__ etc. So far so good.

          The problem is that the generated doc omits the annotation for variables. All you get is the variable name and its value. For example, look at lines 325 to 327 here:

          https://projects.kde.org/projects/kde/kde-baseapps/kate/repository/revisions/master/entry/kate/plugins/pate/src/kate/__init__.py

          There are several such important variables, but without the doc it is not obvious what they are for. I could have changed them to functions but did not want to break backwards compatibility for the existing plugins.

          1. So if you cannot add it to the C++ code, you could still write a Python class which will wrap the actual instance and intercepts calls to __getattribute__ and __setattr__. Throw in some filtering and you can effectively divert the “control flow”: normally you redirect to the wrapped instance, except for a few special items which you pull out of the wrapper class (notably any __getattribute__ calls for access to the wrapped variable from inside your wrapper class). Throw in some docs in your wrapper class, and with filtering it will look like you have proper docs on your opaque C++ objects.

            Of course this is a bit of an awful hack, but it will work.

          2. @johan

            See the previously linked file, line 151 for what the current code does using pydoc. I’m too lazy to try to rebuild all that, so I am rather hoping for a magic bullet…

Leave a Reply