-
Projects
- Qimo 4 Kids
- Read Feeder
- Tomboy PasteBinIt!
- Ubuntu Developer Summit
- Ubuntu LoCo Directory
-
Recent Posts
- Multi-monitor support coming to the Ubuntu greeter
- Learn Ubuntu Development in just 3 days!
- Looking for Quickly template help
- Singlet, part 0.2
- Let’s chat about Unity
Recent Comments
- Michael Hall on The Science of Atheism
- Alan Berends on The Science of Atheism
- Michael Hall on The Science of Atheism
- Alan Berends on The Science of Atheism
- Tory on Singlet, part 0.2
Archives
- January 2012
- December 2011
- November 2011
- October 2011
- September 2011
- August 2011
- July 2011
- June 2011
- May 2011
- April 2011
- March 2011
- February 2011
- November 2010
- June 2010
- May 2010
- April 2010
- January 2010
Categories
- Events
- Food
- LoCo
- Meetups
- OpenSource
- Politics
- Programming
- Projects
- Religion
- School
- Science
- Uncategorized
- Work
Meta
- Log in
- Entries RSS
- Comments RSS
- WordPress.org
Singlet, part 0.2
I’ve finally had a little extra time to get back to working on Singlet. There’s been a lot of progress since the first iteration. To start with, Singlet had to be upgraded to work with the new Lens API introduced when Unity 5.0 landed in the Precise repos. Luckily the Singlet API didn’t need to change, so any Singlet lenses written for Oneiric and Unity 4 will only need the latest Singlet to work in Precise.
The more exciting development, though, is that Singlet 0.2 introduces an API for Scopes. This means you can write Lenses that support external scopes from other authors, as well as external Scopes for existing lenses. They don’t both need to be based on Singlet either, you can write a Singlet scope for the Music Lens if you wanted to, and non-Singlet scopes can be written for your Singlet lens. They don’t even have to be in Python.
In order to make the Scope API, I chose to convert my previous LoCo Teams Portal lens into a generic Community lens and separate LoCo Teams scope. The Lens itself ends up being about as simple as can be:
from singlet.lens import Lens, IconViewCategory, ListViewCategory
class CommunityLens(Lens):
class Meta:
name = 'community'
description = 'Ubuntu Community Lens'
search_hint = 'Search the Ubuntu Community'
icon = 'community.svg'
category_order = ['teams', 'news', 'events', 'meetings']
teams = IconViewCategory("Teams", 'ubuntu-logo')
news = ListViewCategory("News", 'news-feed')
events = ListViewCategory("Events", 'calendar')
meetings = ListViewCategory("Meetings", 'applications-chat')
As you can see, it’s really nothing more that some meta-data and the categories. All the real work happens in the scope:
class LocoTeamsScope(Scope):
class Meta:
name = 'locoteams'
search_hint = 'Search LoCo Teams'
search_on_blank = True
lens = 'community'
categories = ['teams', 'news', 'events', 'meetings']
def __init__(self, *args, **kargs):
super(LocoTeamsScope, self).__init__(*args, **kargs)
self._ltp = locodir.LocoDirectory()
self.lpusername = None
if os.path.exists(os.path.expanduser('~/.bazaar/bazaar.conf')):
try:
import configparser
except ImportError:
import ConfigParser as configparser
bzrconf = configparser.ConfigParser()
bzrconf.read(os.path.expanduser('~/.bazaar/bazaar.conf'))
try:
self.lpusername = bzrconf.get('DEFAULT', 'launchpad_username')
except configparser.NoOptionError:
pass
def search(self, search, model, cancellable):
I left out the actual search code, because it’s rather long and most of it isn’t important when talking about Singlet itself. Just like the Lens API, a Singlet Scope uses an inner Meta class for meta-data. The most important fields here are the ‘lens’ and ‘categories’ variables. The ‘lens’ tells Singlet the name of the lens your scope is for. Singlet uses this to build DBus names and paths, and also to know where to install your scope. The ‘categories’ list will let you define a result item’s category using a descriptive name, rather than an integer.
model.append('loco.ubuntu.com/events/%s/%s/detail/' % (team['lp_name'], tevent['id']),
team['mugshot_url'],
self.lens.events,
"text/html",
tevent['name'],
'%s\n%s' % (tevent['date_begin'], tevent['description']), '')
It’s important that the order of the categories in the Scope’s Meta matches the order of categories defined in the Lens you are targeting, since in the end it’s still just the position number that’s being passed back to the Dash.
After all this, I still had a little bit of time left in the day. And what good is supporting external scopes if you only have one anyway? So I spent 30 minutes creating another scope, one that will read from the Ubuntu Planet news feed:
The next step is to add some proper packaging to get these into the Ubuntu Software Center, but you impatient users can get them either from their respective bzr branches, or try the preliminary packages from the One Hundred Scopes PPA.
13 Responses to Singlet, part 0.2
Great work Michael. Thank you!
Pingback: Looking for Quickly template help | Michael Hall's Blog
Pingback: Learn Ubuntu Development in just 3 days! | Michael Hall's Blog
I am trying to make a websearch lens and google scope with the latest singlet, I’m using Ubuntu 11.10, is Unity 5 required for this version? Or does the latest version still support Unity 4 as well?
I’d hate to have to use singlet 1 and have to make it as a SingleScopeLens until Precise is finished…
However if it does support Unity 4, the error I’m getting when I use ‘setsid unity’ is this:
WARN 2012-02-06 02:06:14 unity.glib.dbusproxy GLibDBusProxy.cpp:269 Calling method failed: GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such interface `com.canonical.Unity.Lens’ on object at path /unity/singlet/lens/web_search
And if I use ‘sudo python web_search’ I get this:
(process:2504): libunity-DEBUG: unity-scope-factory.vala:57: Searching for Scopes in /usr/share/unity/lenses/web_search
(process:2504): libunity-DEBUG: unity-scope-factory.vala:102: Successfully loaded /usr/share/unity/lenses/web_search/google.scope: unity.singlet.lens.web_search.google | /unity/singlet/lens/web_search/google
(process:2504): libunity-DEBUG: unity-scope-proxy-remote.vala:115: Scope vanished: unity.singlet.lens.web_search.google
(process:2504): libunity-DEBUG: unity-scope-proxy-remote.vala:105: Scope appeared: unity.singlet.lens.web_search.google
(process:2504): libunity-WARNING **: unity-scope-proxy-remote.vala:97: Unable to connect to Scope (/unity/singlet/lens/web_search/google @ unity.singlet.lens.web_search.google): GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such interface `com.canonical.Unity.Scope’ on object at path /unity/singlet/lens/web_search/google
(process:2504): libunity-WARNING **: unity-scope-proxy-remote.vala:97: Unable to connect to Scope (/unity/singlet/lens/web_search/google @ unity.singlet.lens.web_search.google): GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such interface `com.canonical.Unity.Scope’ on object at path /unity/singlet/lens/web_search/google
(process:2504): libunity-DEBUG: unity-scope-proxy-remote.vala:115: Scope vanished: unity.singlet.lens.web_search.google
The DBus info is all correct in the .service, .lens, and .scope files
The latest Singlet only works on Unity 5 (Ubuntu 12.04)
OK, thanks, I guess I’ll write a SingleScopeLens for now then…
OK, I got my scope working using singlet 0.1, well sort of, but the search results are not showing up, also, I installed your test lens from singlet 0.1, and it has the same problem, it acts like it works, but no results show up, all lenses I installed via softwtare center are working fine. When you type in the search the circle is spinning as if it’s searching, then it stops spinning, but nothing shows.
I should also note that when I run setsid unity in a terminal, and then try to use the singlets, there are no error messages, the singlets are displaying the same info as all the working lenses.
I’m running Ubuntu 11.10 with Unity 4.28.0
On another note, I realized that at least with singlet 0.1, you can not use any special characters in the name, I was using web-search and the ‘-’ was causing it to fail, as would ‘_’, I had to use websearch as the name, don’t know why it does this, but it does.
Can you run the lens script from the command line, and see if you get any errors? I’ve seen this happen when the search code itself throws an error.
It doesn’t throw any errors, it just says it’s searching for scopes, also, I used my searching data in a test python program and it gets all the data correctly.
Is your source code available somewhere I could look at it?
Also, like I wrote earlier the test lens included in singlet does the same thing.
I’ll post it here:
import sys, urllib, json
from singlet.lens import SingleScopeLens, ListViewCategory
from singlet.utils import run_lens
class WebSearchLens(SingleScopeLens):
class Meta:
name = “websearch”
description = “Search the web”
search_hint = “Search Google and Wikipedia”
icon = “websearch.svg”
search_on_blank = True
webcrawler = ListViewCategory(‘Web Crawler’, ‘webcrawler.svg’)
wiki = ListViewCategory(‘Wiki’, ‘file’)
def search(self, search, model):
if len(search) == 0:
model.append(‘google.com/',
“/usr/share/unity/lenses/websearch/webcrawler.svg”,
self.webcrawler,
“text/html”,
‘Google Home Page’)
else:
##format search string into url#
query = urllib.urlencode({‘q’: search})
url = “ajax.googleapis.com/ajax/services/search/web?v=1.0&rsz=large&%s” % query
##open and read the url, convert to Python object#
search_results = urllib.urlopen(url).read()
data = json.loads(search_results)['responseData']
##retrieve desired info from data#
for item in data['results']:
title = item['titleNoFormatting']
url = item['url']
description = item['content']
model.append(url,
“/usr/share/unity/lenses/websearch/webcrawler.svg”,
self.webcrawler,
“text/html”,
title, description)
if __name__ == “__main__”:
run_lens(WebSearchLens, sys.argv)
And don’t worry, my indentation was all correct, the comment just removed it