Simplified Unity Lens Development with Singlet

Back when I first started writing Unity lenses, I lamented the complexity required to get even the most basic Lens written and running.  I wrote in that post about wanting to hide all of that unnecessary complexity.  Well now I am happy to announce the first step towards that end: Singlet.

In optics, a “singlet” is a very simple lens.  Likewise, the Singlet project aims to produce simple Unity lenses.  Singlet targets opportunistic programmers who want to get search results into Unity with the least amount of work.  By providing a handful of Python meta classes and base classes, Singlet lets you write a basic lens with a minimal amount of fuss. It hides all of the boilerplate code necessary to interface with GObject and DBus, leaving the developer free to focus solely on the purpose of their lens.  With Singlet, the only thing a Lens author really needs to provide is a single search function.

Writing a Singlet

So what does a Singlet Lens look like?  Here is a sample of the most basic lens, which produced the screenshot above:

#! /usr/bin/python

from singlet.lens import SingleScopeLens, IconViewCategory, ListViewCategory
from singlet.utils import run_lens

class TestLens(SingleScopeLens):

    class Meta:
        name = 'test'

    cat1 = IconViewCategory("Cat One", "stock_yet")

    cat2 = ListViewCategory("Cat Two", "hint")

    def search(self, phrase, results):
        results.append('http://google.com/search?q=%s' % phrase,
                             'file',
                             self.cat1,
                             "text/html",
                             phrase, phrase, '')

        results.append('http://google.com/search?q=%s' % phrase,
                             'file',
                             self.cat2,
                             "text/html",
                             phrase, phrase, '')

if __name__ == "__main__":
    import sys
    run_lens(TestLens, sys.argv)

As you can see, there isn’t much to it.  SingleScopeLens is the first base class provided by Singlet.  It creates an inner-scope for you, and connects it to the DBus events for handling a user’s search events.  The three things you need to do, as a Lens author, is give it a name in the Meta  class, define at least one Category, and most importantly implement your custom search(self, phrase, results) method.

Going Meta

Django developers will notice a similarity between Singlet Lenses and Django Models in their use of an inner Meta class.  In fact, they work exactly the same way, though with different properties.  At a minimum, you will need to provide a name for your lens.  Everything else can either use default values, or will be extrapolated from the name.  Everything in your Meta class, plus defaults and generated values, will be accessible in <your_class>._meta later on.

Categorically easy

Again borrowing from Django Models, you add categories to your Singlet Lens by defining it in the Class’s scope itself, rather than in the  __init__ method.  One thing that I didn’t like about Categories when writing my previous lenses was that I couldn’t reference them when adding search results to the result model.  Instead you have to give the numeric index of the category.  In Singlet, the variable name you used when defining the category is converted to the numeric index for that category, so you easily reference it again when building your search results.  But don’t worry, you category objects are still available to you in <your_class>._meta.categories if you want them.

The search is on

The core functionality of a Lens is the search.  So it makes sense that the majority of your work should happen here.  Singlet will call your search method, passing in the current search phrase and an empty results model.  From there, it’s up to you to collect data from whatever source you are targeting, and start populating that results model.

You can handle the URI

Unity knows how to handle common URIs in your results, such as file:// and http:// uris.  But often times your lens isn’t going to be dealing with results that map directly to a file or website.  For those cases, you need to hook into DBus again to handle the URI of a selected result item, and return a specifically constructed GObject response.  With Singlet, all you need to do is define a handle_uri method on your Lens, and it will take care of hooking it into DBus for you.  Singlet also provides a couple of helper methods for your return value, either hide_dash_response to hide the dash after you’ve handled the URI, or update_dash_response if you want to leave it open.

Make it go

Once you’ve defined your lens, you need to be able to initialize it and run it, again using a combination of DBus and GObject.  Singlet hides all of this behind the run_lens function in singlet.utils, which you should call at the bottom of your lens file as shown in the above snippet.

Lord of the files

There’s more to getting your Lens working that just the code, you also need to specify a .lens file describing your lens to Unity, and a .service file telling dbus about it.  Singlet helps you out here too, by providing command line helpers for generating and installing these files.  Suppose the code snippet above was in a file called testlens.py, once it’s written you can run “python testlens.py make” and it will write test.lens and unity-test-lens.service into your current directory.  The data in these files comes from <your_lens>._meta, including the name, dbus information, description and icon.  After running make you can run “sudo python testlens.py install”, this will copy your code and config files to where they need to be for Unity to pick them up and run them.

More to come

You can get the current Singlet code by branching lp:singlet.  I will be working on getting it built and available via PyPi and a PPA in the near future, but for now just having it on your PYTHONPATH is enough to get started using it.  Just be aware that if you make/install a Singlet lens, you need to make the Singlet package available on Unity’s PYTHONPATH as well or it won’t be able to run.  I’ve already converted my Dictionary Lens to use Singlet, and will work on others while I grow the collection of Singlet base classes.  If anybody has a common yet simple use case they would like me to target, please leave a description in the comments.

This entry was posted in OpenSource, Programming, Work and tagged , , , , , , . Bookmark the permalink.

34 Responses to Simplified Unity Lens Development with Singlet

  1. Frederik says:

    Hi Michael,

    this is great news! I am currently also running a project that aims to create a new lens (a contacts lens), and we too thought about simplifying the process. We went for a different route in that we first created a basic lens that can be managed using quickly, so that this handles packaging the lens. We thought about pushing this further, by creating a real lens template for quickly, which allows to create new lenses with ease, provides a sensible way of running the lens code from the source directory without installing it, etc.

    I can imagine these two approaches blending nicely into each other: What about a quickly template that makes use of Singlet? Hide the complexity of the code and provide helpers for packaging etc.

    Since we are currently busy completing our lens, I guess this could only be a medium term goal for us. But if anybody is interested in taking what we got with regard to quickly, and build something usable from it, we are more than willing to collaborate.

  2. Alan Bell says:

    this is great! One thing I would like to see is some sensible means of connecting to authenticated data sources, I have a number of internal systems that need a login before they will let me search them and I can see quite a few public web data sources that either need a login or can return better data if you are logged in (like Amazon returning recommended stuff for you). Some kind of gnome-keyring integration maybe?

    • Michael Hall says:

      You can probably access the gnome-keyring/seahorse data from within a lens. I’m not sure if they would be capable of storing things like OAuth tokens, or if they’re just username and password. Getting the information into it is another story.

    • Martin Owens says:

      A user/access/desktop cookie type system you say? Why I wrote one of them years ago ;-)

  3. Some initial packaging: lp:~andrewsomething/singlet/packaging

    • Michael Hall says:

      Thanks for the branch, but debuild is failing on it. Ping me (mhall119 on freenode) when you have a minute.

      Thanks.

      • Ya, that’s because there is no real orig.tar. You can tar up the unreleased code, or just you bzr build-deb’s –split option which automatically creates an .orig.tar.gz from a full source branch.

        bzr bd –split

        • Michael Hall says:

          Awesome, thanks so much. I’m taking just the ./debian/ folder from your branch and putting it in lp:~singlet-developers/singlet/pkg-oneiric, because I like to keep the source and packaging files separate.

          Also, your debian/watch files references bzr-grep, is that intentional or leftover from a copy/paste?

          • Ya. I guess I did a cat ~/development/bzr-grep/debian/watch | sed s/bzr\-grep/singlet/ > watch instead ofcat ~/development/bzr-grep/debian/watch | sed s/bzr\-grep/singlet/g > watch

  4. Your work is so awesome! Like Frederik said, my first thought when I was reading your post was: what if this work was integrated in Quickly?!

    Well, that would be too perfect! I worked with quickly and i love it; also i have some ideas to do with this lens concept. So, if this two excellent things where the joined, I would very very happy.

    Frederik, what do we need to do to have this things done?

    Best Regards,
    Claudio Novais.

    • Michael Hall says:

      You’ll be happy to know that discussion of integrating with Quickly are already underway, I’ll have more to report on that soon (there will be more blog postings on lenses over the next few months).

  5. Michael Nirza says:

    Hey I’m new to the linux programing like total noob to be honest and was wondering if it were possible to create a lens that searches a site like Ch131.com that doesn’t have a search function on it the only reason im asking is cause well to be honest i have no idea how to even get started if you could email back at NirzaMichael@gmail.com

  6. Pingback: Links for January 3rd through January 5th | michael-mccracken.net

  7. stefan says:

    I had your dictionary lens installed (and it worked great!) and two of my own lenses which I had written with singlet. Now today they no longer show up. I’m not sure if there was a unity update yesterday, so I thought you might know: Are you aware of unity changes (unity 4.28.0) which are incompatible with singlet?

  8. Grzegorz Lachowski says:

    Hi there!
    I was trying to develop a custom Unity lens (pidgin buddy lens) using this tutorial http://saravananthirumuruganathan.wordpress.com/2011/08/05/tutorial-on-writing-ubuntu-lensesplaces-in-python/, but then I have found your project and thought I’ll try it out. Great job! I have a problem with running the test lens (Unity 4.28). I run python testlens.py make and it created lens and service files. Is it possible to test it without installing it with ‘install’ argument? Also even if I installed it, it was not available (only 4 standard lenses appeared) on the dash. Any thoughts?
    With regards,
    Grzegorz

    • Grzegorz Lachowski says:

      I figured it out after looking into your dictionary lens. I was missing the ‘setsid unity’ command. Anyway, singlet is awesome!

  9. Very cool. I can’t wait to try it out.

    Just wondering, would you be interested in submitting a tutorial for Singlet & lens writing to Ubuntu app developer site?

    • Michael Hall says:

      We’ll see about a tutorial, I’m going to be working with didrocks next week to integrate singlet and quickly, so it may no longer be a separate project.

  10. Pingback: Quick Team Update | jonobacon@home

  11. Pingback: Singlet, part 0.2 | Michael Hall's Blog

  12. Pingback: Singlet + Quickly: Better, Faster, Simpler | Michael Hall's Blog

  13. Pingback: Singlet – Schnelles Erzeugen von Unity Linsen | Softwareperlen

  14. Pingback: Remember The Milk Lens for Ubuntu | thealarmclocksixam

  15. Andrew King says:

    I’m using your project in something I’m trying to put on PPA. Do you have a donate link through pledgie or otherwise?

  16. mauricio says:

    Hi, i’m having a problem, I follow these instructions
    http://developer.ubuntu.com/2012/04/how-to-create-a-wikipedia-unity-lens-for-ubuntu/

    But, I just can’t change the icon that is on the dash (the scope icon), so i really will apreciate your help with this.

    How to change an icon?

  17. Tory says:

    I am trying to make a single scope lens using the latest singlet in Ubuntu 12.04, I am having problems troubleshooting, when I run ‘setsid unity’ in a terminal, and press SUPER to open the dash, first of all, I can see my lens icon on the bottom, but it just sits for a little while, then it just says my lens times out, specifically:

    WARN 2012-05-17 19:37:10 unity.glib.dbusproxy GLibDBusProxy.cpp:182 Unable to connect to proxy: Error calling StartServiceByName for Unity.Singlet.Lens.DuckDuckGo: Timeout was reached

    OK, now is it possible that this is happening because my actual python file is having errors? When you run setsid unity and try to use the lens will it throw the python errors in that terminal as it does when you run a file with ./myfile.py ?

    If not, I need to know how to troubleshoot my python file to make sure it’s working.

    Another thing, I had to make the .lens and .service files myself because the commands make and install aren’t working, I just manually put the files in the correct locations.

    • Tory says:

      Well, I kinda found my own answer, I didn’t realize you could start the python daemon from the terminal after setsid unity. However I did end up just writing the daemon the old way, without singlet. Singlet and Quickly are really cool, but for some reason I can never really get them to work, but at least I have my first version of a DuckDuckGo websearch lens, now I need to find out how/where to upload it. I would like to add it to something like the scopes packagers ppa rather than starting my own ppa.

  18. Pingback: My App Developer Showdown Entry | Michael Hall

  19. matthias says:

    hello and 4 first:

    Great Work :D

    So:

    I wanna create an kde netbook “search and launch menu” like lense and will ask you, if you can help me with write it. I have no experience with programming and phyton and learn very quick and easy :D

    Hnn, i wanna create this 4 first, cuz the idea behind is great and will be get in a new linux <3

    So, maybe u will help me with introducion or something like that :D

    See ya soon;

    Matthias ( Vienna )

    Shalok Shalom
    Will U help me ?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>