Merge lp:~niedbalski/charm-helpers/fix-lp-1311979 into lp:charm-helpers

Proposed by Jorge Niedbalski
Status: Merged
Merged at revision: 142
Proposed branch: lp:~niedbalski/charm-helpers/fix-lp-1311979
Merge into: lp:charm-helpers
Diff against target: 278 lines (+255/-0)
4 files modified
charmhelpers/contrib/python/packages.py (+76/-0)
charmhelpers/contrib/python/version.py (+18/-0)
tests/contrib/python/test_packages.py (+134/-0)
tests/contrib/python/test_version.py (+27/-0)
To merge this branch: bzr merge lp:~niedbalski/charm-helpers/fix-lp-1311979
Reviewer Review Type Date Requested Status
Marco Ceppi Approve
charmers Pending
Review via email: mp+216975@code.launchpad.net

Description of the change

- Added a new module under contrib/python for keeping common python tasks.
 - Added contrib/python/packages, exposing pip_install/pip_uninstall/pip_list/pip_install_from_requirements
 - Added contrib/python/version, exposing current_version/current_version_string

Test status:
-----------

charmhelpers.contrib.python 0 0 100%
charmhelpers.contrib.python.packages 42 3 93% 11-13
charmhelpers.contrib.python.version 6 0 100%

Also

    - Added the fetch.is_package_installed method for
      check if a package or a list of are already installed into the system
     - Added unit tests

    Tests output:
    -------------

    tests.fetch.test_fetch.FetchTest.test_is_package_installed ... ok
    tests.fetch.test_fetch.FetchTest.test_is_package_installed_not_available ... ok

To post a comment you must log in.
Revision history for this message
Marco Ceppi (marcoceppi) wrote :

LGTM +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'charmhelpers/contrib/python'
2=== added file 'charmhelpers/contrib/python/__init__.py'
3=== added file 'charmhelpers/contrib/python/packages.py'
4--- charmhelpers/contrib/python/packages.py 1970-01-01 00:00:00 +0000
5+++ charmhelpers/contrib/python/packages.py 2014-04-24 04:23:58 +0000
6@@ -0,0 +1,76 @@
7+#!/usr/bin/env python
8+# coding: utf-8
9+
10+__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"
11+
12+from charmhelpers.fetch import apt_install
13+from charmhelpers.core.hookenv import log
14+
15+try:
16+ from pip import main as pip_execute
17+except ImportError:
18+ apt_install('python-pip')
19+ from pip import main as pip_execute
20+
21+
22+def parse_options(given, available):
23+ """Given a set of options, check if available"""
24+ for key, value in given.items():
25+ if key in available:
26+ yield "--{0}={1}".format(key, value)
27+
28+
29+def pip_install_requirements(requirements, **options):
30+ """Install a requirements file """
31+ command = ["install"]
32+
33+ available_options = ('proxy', 'src', 'log', )
34+ for option in parse_options(options, available_options):
35+ command.append(option)
36+
37+ command.append("-r {0}".format(requirements))
38+ log("Installing from file: {} with options: {}".format(requirements,
39+ command))
40+ pip_execute(command)
41+
42+
43+def pip_install(package, fatal=False, **options):
44+ """Install a python package"""
45+ command = ["install"]
46+
47+ available_options = ('proxy', 'src', 'log', "index-url", )
48+ for option in parse_options(options, available_options):
49+ command.append(option)
50+
51+ if isinstance(package, list):
52+ command.extend(package)
53+ else:
54+ command.append(package)
55+
56+ log("Installing {} package with options: {}".format(package,
57+ command))
58+ pip_execute(command)
59+
60+
61+def pip_uninstall(package, **options):
62+ """Uninstall a python package"""
63+ command = ["uninstall", "-q", "-y"]
64+
65+ available_options = ('proxy', 'log', )
66+ for option in parse_options(options, available_options):
67+ command.append(option)
68+
69+ if isinstance(package, list):
70+ command.extend(package)
71+ else:
72+ command.append(package)
73+
74+ log("Uninstalling {} package with options: {}".format(package,
75+ command))
76+ pip_execute(command)
77+
78+
79+def pip_list():
80+ """Returns the list of current python installed packages
81+ """
82+ return pip_execute(["list"])
83
84=== added file 'charmhelpers/contrib/python/version.py'
85--- charmhelpers/contrib/python/version.py 1970-01-01 00:00:00 +0000
86+++ charmhelpers/contrib/python/version.py 2014-04-24 04:23:58 +0000
87@@ -0,0 +1,18 @@
88+#!/usr/bin/env python
89+# coding: utf-8
90+
91+__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"
92+
93+import sys
94+
95+
96+def current_version():
97+ """Current system python version"""
98+ return sys.version_info
99+
100+
101+def current_version_string():
102+ """Current system python version as string major.minor.micro"""
103+ return "{0}.{1}.{2}".format(sys.version_info.major,
104+ sys.version_info.minor,
105+ sys.version_info.micro)
106
107=== added directory 'tests/contrib/python'
108=== added file 'tests/contrib/python/__init__.py'
109=== added file 'tests/contrib/python/test_packages.py'
110--- tests/contrib/python/test_packages.py 1970-01-01 00:00:00 +0000
111+++ tests/contrib/python/test_packages.py 2014-04-24 04:23:58 +0000
112@@ -0,0 +1,134 @@
113+#!/usr/bin/env python
114+# coding: utf-8
115+
116+__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"
117+
118+from unittest import TestCase
119+from charmhelpers.contrib.python import packages
120+
121+import mock
122+
123+TO_PATCH = [
124+ "apt_install",
125+ "log",
126+ "pip_execute"
127+]
128+
129+
130+class PipTestCase(TestCase):
131+
132+ def setUp(self):
133+ TestCase.setUp(self)
134+ self.patch_all()
135+
136+ self.log.return_value = True
137+ self.apt_install.return_value = True
138+
139+ def patch(self, method):
140+ _m = mock.patch.object(packages, method)
141+ _mock = _m.start()
142+ self.addCleanup(_m.stop)
143+ return _mock
144+
145+ def patch_all(self):
146+ for method in TO_PATCH:
147+ setattr(self, method, self.patch(method))
148+
149+ def test_pip_install_requirements(self):
150+ """
151+ Check if pip_install_requirements works correctly
152+ """
153+ packages.pip_install_requirements("test_requirements.txt")
154+ self.pip_execute.assert_called_with(["install",
155+ "-r test_requirements.txt"])
156+
157+ packages.pip_install_requirements("test_requirements.txt",
158+ proxy="proxy_addr:8080")
159+
160+ self.pip_execute.assert_called_with(["install",
161+ "--proxy=proxy_addr:8080",
162+ "-r test_requirements.txt"])
163+
164+ packages.pip_install_requirements("test_requirements.txt",
165+ log="output.log",
166+ proxy="proxy_addr:8080")
167+
168+ self.pip_execute.assert_called_with(["install",
169+ "--log=output.log",
170+ "--proxy=proxy_addr:8080",
171+ "-r test_requirements.txt"])
172+
173+ def test_pip_install(self):
174+ """
175+ Check if pip_install works correctly with a single package
176+ """
177+ packages.pip_install("mock")
178+ self.pip_execute.assert_called_with(["install",
179+ "mock"])
180+ packages.pip_install("mock",
181+ proxy="proxy_addr:8080")
182+
183+ self.pip_execute.assert_called_with(["install",
184+ "--proxy=proxy_addr:8080",
185+ "mock"])
186+ packages.pip_install("mock",
187+ log="output.log",
188+ proxy="proxy_addr:8080")
189+
190+ self.pip_execute.assert_called_with(["install",
191+ "--log=output.log",
192+ "--proxy=proxy_addr:8080",
193+ "mock"])
194+
195+ def test_pip_install_multiple(self):
196+ """
197+ Check if pip_install works correctly with multiple packages
198+ """
199+ packages.pip_install(["mock", "nose"])
200+ self.pip_execute.assert_called_with(["install",
201+ "mock", "nose"])
202+
203+ def test_pip_uninstall(self):
204+ """
205+ Check if pip_uninstall works correctly with a single package
206+ """
207+ packages.pip_uninstall("mock")
208+ self.pip_execute.assert_called_with(["uninstall",
209+ "-q",
210+ "-y",
211+ "mock"])
212+ packages.pip_uninstall("mock",
213+ proxy="proxy_addr:8080")
214+
215+ self.pip_execute.assert_called_with(["uninstall",
216+ "-q",
217+ "-y",
218+ "--proxy=proxy_addr:8080",
219+ "mock"])
220+ packages.pip_uninstall("mock",
221+ log="output.log",
222+ proxy="proxy_addr:8080")
223+
224+ self.pip_execute.assert_called_with(["uninstall",
225+ "-q",
226+ "-y",
227+ "--log=output.log",
228+ "--proxy=proxy_addr:8080",
229+ "mock"])
230+
231+ def test_pip_uninstall_multiple(self):
232+ """
233+ Check if pip_uninstall works correctly with multiple packages
234+ """
235+ packages.pip_uninstall(["mock", "nose"])
236+ self.pip_execute.assert_called_with(["uninstall",
237+ "-q",
238+ "-y",
239+ "mock", "nose"])
240+
241+ def test_pip_list(self):
242+ """
243+ Checks if pip_list works correctly
244+ """
245+ packages.pip_list()
246+ self.pip_execute.assert_called_with(["list"])
247
248=== added file 'tests/contrib/python/test_version.py'
249--- tests/contrib/python/test_version.py 1970-01-01 00:00:00 +0000
250+++ tests/contrib/python/test_version.py 2014-04-24 04:23:58 +0000
251@@ -0,0 +1,27 @@
252+#!/usr/bin/env python
253+# coding: utf-8
254+
255+__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"
256+
257+from unittest import TestCase
258+from charmhelpers.contrib.python import version
259+
260+import sys
261+
262+
263+class VersionTestCase(TestCase):
264+
265+ def setUp(self):
266+ TestCase.setUp(self)
267+
268+ def test_current_version(self):
269+ """
270+ Check if version.current_version and version.current_version_string
271+ works correctly
272+ """
273+ self.assertEquals(version.current_version(),
274+ sys.version_info)
275+ self.assertEquals(version.current_version_string(),
276+ "{0}.{1}.{2}".format(sys.version_info.major,
277+ sys.version_info.minor,
278+ sys.version_info.micro))

Subscribers

People subscribed via source and target branches