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
1=== modified file 'src/unity_colourlovers_daemon.py'
2--- src/unity_colourlovers_daemon.py 2013-03-14 12:27:35 +0000
3+++ src/unity_colourlovers_daemon.py 2013-03-25 06:56:20 +0000
4@@ -20,6 +20,7 @@
5 import urllib.request
6 import json
7 import gettext
8+import os
9
10 APP_NAME = 'unity-scope-colourlovers'
11 LOCAL_PATH = '/usr/share/locale/'
12@@ -27,6 +28,7 @@
13 gettext.textdomain(APP_NAME)
14 _ = gettext.gettext
15
16+CACHE = "%s/unity-scope-colourlovers/" % GLib.get_user_cache_dir()
17 GROUP_NAME = 'com.canonical.Unity.Scope.Graphics.Colourlovers'
18 UNIQUE_PATH = '/com/canonical/unity/scope/graphics/colourlovers'
19 SEARCH_URI = "https://www.colourlovers.com/"
20@@ -39,7 +41,7 @@
21 DEFAULT_RESULT_MIMETYPE = 'text/html'
22 DEFAULT_RESULT_TYPE = Unity.ResultType.DEFAULT
23
24-c1 = {'id' :'colours',
25+c1 = {'id' :'top',
26 'name' :_('Colours'),
27 'icon' :SVG_DIR+'group-graphics.svg',
28 'renderer':Unity.CategoryRenderer.VERTICAL_TILE}
29@@ -135,10 +137,26 @@
30 except Exception as error:
31 print (error)
32
33+class Preview (Unity.ResultPreviewer):
34+
35+ def do_run(self):
36+ preview = Unity.GenericPreview.new(self.result.title, '', None)
37+ preview.props.subtitle = _("By ") + self.result.comment
38+ preview.props.image_source_uri = self.result.icon_hint
39+ icon = Gio.FileIcon.new (Gio.file_new_for_path(PROVIDER_ICON))
40+ view_action = Unity.PreviewAction.new("view", _("View"), icon)
41+ preview.add_action(view_action)
42+ if "/patterns/" in self.result.icon_hint:
43+ wallpaper_action = Unity.PreviewAction.new("wallpaper", _("Set as wallpaper"), None)
44+ preview.add_action(wallpaper_action)
45+ return preview
46+
47+
48 class Scope (Unity.AbstractScope):
49 def __init__(self):
50 Unity.AbstractScope.__init__(self)
51
52+
53 def do_get_search_hint (self):
54 return SEARCH_HINT
55
56@@ -186,5 +204,33 @@
57 se = MySearch (search_context)
58 return se
59
60+ def do_create_previewer(self, result, metadata):
61+ rp = Preview()
62+ rp.set_scope_result(result)
63+ rp.set_search_metadata(metadata)
64+ return rp
65+
66+ def do_activate(self, result, metadata, id):
67+ if id == 'wallpaper':
68+ self.wallpaper_action(result.icon_hint)
69+ return Unity.ActivationResponse(handled=Unity.HandledType.SHOW_DASH, goto_uri=None)
70+ return Unity.ActivationResponse()
71+
72+ def wallpaper_action(self, image):
73+ pattern_name = image.split('/')[-1]
74+ local_path = os.path.join(CACHE, pattern_name)
75+ if not os.path.isfile(local_path):
76+ if not os.path.isdir(CACHE):
77+ os.makedirs(CACHE)
78+ urllib.request.urlretrieve(image, local_path)
79+ self.set_as_wallpaper(local_path)
80+ return
81+
82+ def set_as_wallpaper(self, pattern):
83+ gsettings = Gio.Settings.new('org.gnome.desktop.background')
84+ gsettings.set_string('picture-uri', "file://" + pattern)
85+ gsettings.set_string('picture-options', "wallpaper")
86+ gsettings.apply()
87+
88 def load_scope():
89 return Scope()
90
91=== added file 'tests/data/ubuntu-raptor.png'
92Binary 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
93=== modified file 'tests/test_colourlovers.py'
94--- tests/test_colourlovers.py 2013-02-18 23:17:07 +0000
95+++ tests/test_colourlovers.py 2013-03-25 06:56:20 +0000
96@@ -1,8 +1,13 @@
97 #! /usr/bin/python3
98 # -*- coding: utf-8 -*-
99+import imp
100+import os
101+import shutil
102+import tempfile
103+from unittest import TestCase
104+
105 from gi.repository import Unity
106-from unittest import TestCase
107-import imp
108+
109
110 class ResultSet(Unity.ResultSet):
111 def __init__(self):
112@@ -29,14 +34,19 @@
113 s.run()
114 return result_set
115
116+class WallpaperTestScope(Unity.AbstractScope):
117+ def set_as_wallpaper(pattern):
118+ return
119
120 class TestColourlovers(ScopeTestCase):
121 def setUp(self):
122 self.init_scope('src/unity_colourlovers_daemon.py')
123+ self.cache_dir = tempfile.mkdtemp()
124
125 def tearDown(self):
126 self.scope = None
127 self.scope_module = None
128+ shutil.rmtree(self.cache_dir, ignore_errors=True)
129
130 def test_valid_searches(self):
131 self.scope_module.SEARCH_URI = 'file:tests/data/mock_colourlovers_pass#'
132@@ -53,6 +63,28 @@
133 results.append(result_set.results[0]['icon'])
134 self.assertEqual(results, expected_results)
135
136+ def test_preview(self):
137+ result = Unity.ScopeResult()
138+ result.title = 'Fancy Title'
139+ result.comment = 'author'
140+ result.icon_hint = 'http://www.colourlovers.com/img/fancy_pattern.png'
141+ scope = self.scope_module.Scope()
142+ previewer = scope.create_previewer(result, Unity.SearchMetadata())
143+ self.assertEqual(previewer.run().props.title, result.title)
144+ self.assertEqual(previewer.run().props.subtitle, 'By '+result.comment)
145+ self.assertEqual(previewer.run().props.image_source_uri, result.icon_hint)
146+
147+ def test_wallpaper_caching(self):
148+ self.scope_module.CACHE = self.cache_dir
149+ patterns = []
150+ def set_as_wallpaper(pattern):
151+ patterns.append(pattern)
152+ self.scope.set_as_wallpaper = set_as_wallpaper
153+ self.scope.wallpaper_action('file:tests/data/ubuntu-raptor.png')
154+ local_path = os.path.join(self.cache_dir, 'ubuntu-raptor.png')
155+ self.assertEqual(os.path.isfile(local_path), True)
156+ self.assertEqual(patterns, [local_path])
157+
158 def test_failing_search(self):
159 self.scope_module.SEARCH_URI = 'file:tests/data/mock_colourlovers_fail#'
160 for s in ['query']:

Subscribers

People subscribed via source and target branches

to all changes: