Merge lp:~submarine/ubuntu-scopes/colourlovers-set-as-wallpaper into lp:~submarine/ubuntu-scopes/colourlovers

Proposed by David Callé
Status: Merged
Approved by: Martin Mrazik
Approved revision: 29
Merged at revision: 25
Proposed branch: lp:~submarine/ubuntu-scopes/colourlovers-set-as-wallpaper
Merge into: lp:~submarine/ubuntu-scopes/colourlovers
Diff against target: 160 lines (+81/-3)
2 files modified
src/unity_colourlovers_daemon.py (+47/-1)
tests/test_colourlovers.py (+34/-2)
To merge this branch: bzr merge lp:~submarine/ubuntu-scopes/colourlovers-set-as-wallpaper
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
James Henstridge Approve
Review via email: mp+154044@code.launchpad.net

Commit message

Create preview for each result. Add set as wallpaper option when previewing a pattern.

Description of the change

Create preview for each result. Add set as wallpaper option when previewing a pattern.

To post a comment you must log in.
Revision history for this message
James Henstridge (jamesh) wrote :

A few issues:

[1]
Do you actually need the Preview.__init__() method? All it seems to be doing is chaining to the parent implementation without adding anything.

[2]
In your Preview.do_run() method, you start by assigning to a number of local variables that only get used once. It doesn't look like there is any real reason for this (e.g. code readability, or shortening long lines of code).

The preview variable is set to None, only to be assigned some other value before it is used further. Perhaps the code would be easier to read without these extra assignments?

[3]
For the path manipulation in Scope.wallpaper_action(), might it be simpler to use the Python standard library to check for the file contents and make the cache directory (i.e. os.path.isfile() and os.makedirs(..., exist_ok=True)).

[4]
In Scope.set_as_wallpaper(), you have more single-use locals. And creating a list of key strings that are then only accessed by index just makes the code more difficult to read compared to using those strings directly.

I'm also not sure what the purpose of this line is:

    gsettings.get_string(KEY[0])

At first I thought that it might be there to trigger an exception if the 'picture-uri' key didn't exist, but it seems to crash the process with unknown keys (probably a bug in the GIR data). Perhaps remove it?

[5]
Can you test this new preview code? Ideally we'd want to know that the preview is generated as expected, and that activating "wallpaper" action correctly downloads the content. You've already split the gsettings code out into a separate method, so it should be easy to stub that out for the test so you don't mess with the developer's settings.

review: Needs Fixing
Revision history for this message
David Callé (davidc3) wrote :

I think I've addressed all your concerns. Not sure about using /tmp for the wallpaper download test though.

Revision history for this message
David Callé (davidc3) wrote :

FWIW, a temp dir created with tempfile generates this error when running os.makedirs(CACHE, exist_ok=True)
"FileExistsError: [Errno 17] File exists (mode 700 != expected mode 775): '/tmp/tmpaa1fzb'"

Revision history for this message
James Henstridge (jamesh) wrote :

Looks better.

Two issues:

[1]
Rather than using a fixed temporary directory, create one with tempfile.mkdtemp() in the test's setUp() method, and delete it in tearDown() using shutil.rmtree(..., ignore_errors=True).

[2]
The test_preview() method looks a bit muddled. It appears to be calling unbound methods of the Preview class passing the Preview class itself (as opposed to an instance) as the first argument.

Isn't it possible to just call scope.create_previewer(result, metadata) to create the previewer instance? You could then call run() on it once, and then inspect the resulting preview.

With those two issues out of the way, I'd be happy for the branch to land.

review: Needs Fixing
Revision history for this message
David Callé (davidc3) wrote :

I've updated test_preview.

Regarding the temporary file: using tempfile.mkdtemp() creates a directory with the wrong permissions (unreadable by os.makedirs() in the scope). If I chmod it to the right permissions, it works fine with noestests3, but then fails in the builder. I'm not sure what is the best way to handle this.

Revision history for this message
James Henstridge (jamesh) wrote :

I had a look at this and pushed a fix to use mkdtemp(): it looks like the Python 3 version of nosetests is eating the exception due to some Python 2.x baggage, which made the cause a little less obvious. I also stubbed out the gsettings code so it should function in the testing environment.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Martin Mrazik (mrazik) wrote :

The above is my mistake. Reapproving.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/unity_colourlovers_daemon.py'
--- src/unity_colourlovers_daemon.py 2013-03-14 12:27:35 +0000
+++ src/unity_colourlovers_daemon.py 2013-03-25 06:56:20 +0000
@@ -20,6 +20,7 @@
20import urllib.request20import urllib.request
21import json21import json
22import gettext22import gettext
23import os
2324
24APP_NAME = 'unity-scope-colourlovers'25APP_NAME = 'unity-scope-colourlovers'
25LOCAL_PATH = '/usr/share/locale/'26LOCAL_PATH = '/usr/share/locale/'
@@ -27,6 +28,7 @@
27gettext.textdomain(APP_NAME)28gettext.textdomain(APP_NAME)
28_ = gettext.gettext29_ = gettext.gettext
2930
31CACHE = "%s/unity-scope-colourlovers/" % GLib.get_user_cache_dir()
30GROUP_NAME = 'com.canonical.Unity.Scope.Graphics.Colourlovers'32GROUP_NAME = 'com.canonical.Unity.Scope.Graphics.Colourlovers'
31UNIQUE_PATH = '/com/canonical/unity/scope/graphics/colourlovers'33UNIQUE_PATH = '/com/canonical/unity/scope/graphics/colourlovers'
32SEARCH_URI = "https://www.colourlovers.com/"34SEARCH_URI = "https://www.colourlovers.com/"
@@ -39,7 +41,7 @@
39DEFAULT_RESULT_MIMETYPE = 'text/html'41DEFAULT_RESULT_MIMETYPE = 'text/html'
40DEFAULT_RESULT_TYPE = Unity.ResultType.DEFAULT42DEFAULT_RESULT_TYPE = Unity.ResultType.DEFAULT
4143
42c1 = {'id' :'colours',44c1 = {'id' :'top',
43 'name' :_('Colours'),45 'name' :_('Colours'),
44 'icon' :SVG_DIR+'group-graphics.svg',46 'icon' :SVG_DIR+'group-graphics.svg',
45 'renderer':Unity.CategoryRenderer.VERTICAL_TILE}47 'renderer':Unity.CategoryRenderer.VERTICAL_TILE}
@@ -135,10 +137,26 @@
135 except Exception as error:137 except Exception as error:
136 print (error)138 print (error)
137139
140class Preview (Unity.ResultPreviewer):
141
142 def do_run(self):
143 preview = Unity.GenericPreview.new(self.result.title, '', None)
144 preview.props.subtitle = _("By ") + self.result.comment
145 preview.props.image_source_uri = self.result.icon_hint
146 icon = Gio.FileIcon.new (Gio.file_new_for_path(PROVIDER_ICON))
147 view_action = Unity.PreviewAction.new("view", _("View"), icon)
148 preview.add_action(view_action)
149 if "/patterns/" in self.result.icon_hint:
150 wallpaper_action = Unity.PreviewAction.new("wallpaper", _("Set as wallpaper"), None)
151 preview.add_action(wallpaper_action)
152 return preview
153
154
138class Scope (Unity.AbstractScope):155class Scope (Unity.AbstractScope):
139 def __init__(self):156 def __init__(self):
140 Unity.AbstractScope.__init__(self)157 Unity.AbstractScope.__init__(self)
141158
159
142 def do_get_search_hint (self):160 def do_get_search_hint (self):
143 return SEARCH_HINT161 return SEARCH_HINT
144162
@@ -186,5 +204,33 @@
186 se = MySearch (search_context)204 se = MySearch (search_context)
187 return se205 return se
188206
207 def do_create_previewer(self, result, metadata):
208 rp = Preview()
209 rp.set_scope_result(result)
210 rp.set_search_metadata(metadata)
211 return rp
212
213 def do_activate(self, result, metadata, id):
214 if id == 'wallpaper':
215 self.wallpaper_action(result.icon_hint)
216 return Unity.ActivationResponse(handled=Unity.HandledType.SHOW_DASH, goto_uri=None)
217 return Unity.ActivationResponse()
218
219 def wallpaper_action(self, image):
220 pattern_name = image.split('/')[-1]
221 local_path = os.path.join(CACHE, pattern_name)
222 if not os.path.isfile(local_path):
223 if not os.path.isdir(CACHE):
224 os.makedirs(CACHE)
225 urllib.request.urlretrieve(image, local_path)
226 self.set_as_wallpaper(local_path)
227 return
228
229 def set_as_wallpaper(self, pattern):
230 gsettings = Gio.Settings.new('org.gnome.desktop.background')
231 gsettings.set_string('picture-uri', "file://" + pattern)
232 gsettings.set_string('picture-options', "wallpaper")
233 gsettings.apply()
234
189def load_scope():235def load_scope():
190 return Scope()236 return Scope()
191237
=== added file 'tests/data/ubuntu-raptor.png'
192Binary files tests/data/ubuntu-raptor.png 1970-01-01 00:00:00 +0000 and tests/data/ubuntu-raptor.png 2013-03-25 06:56:20 +0000 differ238Binary files tests/data/ubuntu-raptor.png 1970-01-01 00:00:00 +0000 and tests/data/ubuntu-raptor.png 2013-03-25 06:56:20 +0000 differ
=== modified file 'tests/test_colourlovers.py'
--- tests/test_colourlovers.py 2013-02-18 23:17:07 +0000
+++ tests/test_colourlovers.py 2013-03-25 06:56:20 +0000
@@ -1,8 +1,13 @@
1#! /usr/bin/python31#! /usr/bin/python3
2# -*- coding: utf-8 -*-2# -*- coding: utf-8 -*-
3import imp
4import os
5import shutil
6import tempfile
7from unittest import TestCase
8
3from gi.repository import Unity9from gi.repository import Unity
4from unittest import TestCase10
5import imp
611
7class ResultSet(Unity.ResultSet):12class ResultSet(Unity.ResultSet):
8 def __init__(self):13 def __init__(self):
@@ -29,14 +34,19 @@
29 s.run()34 s.run()
30 return result_set35 return result_set
3136
37class WallpaperTestScope(Unity.AbstractScope):
38 def set_as_wallpaper(pattern):
39 return
3240
33class TestColourlovers(ScopeTestCase):41class TestColourlovers(ScopeTestCase):
34 def setUp(self):42 def setUp(self):
35 self.init_scope('src/unity_colourlovers_daemon.py')43 self.init_scope('src/unity_colourlovers_daemon.py')
44 self.cache_dir = tempfile.mkdtemp()
3645
37 def tearDown(self):46 def tearDown(self):
38 self.scope = None47 self.scope = None
39 self.scope_module = None48 self.scope_module = None
49 shutil.rmtree(self.cache_dir, ignore_errors=True)
4050
41 def test_valid_searches(self):51 def test_valid_searches(self):
42 self.scope_module.SEARCH_URI = 'file:tests/data/mock_colourlovers_pass#'52 self.scope_module.SEARCH_URI = 'file:tests/data/mock_colourlovers_pass#'
@@ -53,6 +63,28 @@
53 results.append(result_set.results[0]['icon'])63 results.append(result_set.results[0]['icon'])
54 self.assertEqual(results, expected_results)64 self.assertEqual(results, expected_results)
5565
66 def test_preview(self):
67 result = Unity.ScopeResult()
68 result.title = 'Fancy Title'
69 result.comment = 'author'
70 result.icon_hint = 'http://www.colourlovers.com/img/fancy_pattern.png'
71 scope = self.scope_module.Scope()
72 previewer = scope.create_previewer(result, Unity.SearchMetadata())
73 self.assertEqual(previewer.run().props.title, result.title)
74 self.assertEqual(previewer.run().props.subtitle, 'By '+result.comment)
75 self.assertEqual(previewer.run().props.image_source_uri, result.icon_hint)
76
77 def test_wallpaper_caching(self):
78 self.scope_module.CACHE = self.cache_dir
79 patterns = []
80 def set_as_wallpaper(pattern):
81 patterns.append(pattern)
82 self.scope.set_as_wallpaper = set_as_wallpaper
83 self.scope.wallpaper_action('file:tests/data/ubuntu-raptor.png')
84 local_path = os.path.join(self.cache_dir, 'ubuntu-raptor.png')
85 self.assertEqual(os.path.isfile(local_path), True)
86 self.assertEqual(patterns, [local_path])
87
56 def test_failing_search(self):88 def test_failing_search(self):
57 self.scope_module.SEARCH_URI = 'file:tests/data/mock_colourlovers_fail#'89 self.scope_module.SEARCH_URI = 'file:tests/data/mock_colourlovers_fail#'
58 for s in ['query']:90 for s in ['query']:

Subscribers

People subscribed via source and target branches

to all changes: