Merge lp:~gocept/landscape-client/py3-fs into lp:~landscape/landscape-client/trunk

Proposed by Steffen Allner
Status: Merged
Approved by: Данило Шеган
Approved revision: 970
Merged at revision: 954
Proposed branch: lp:~gocept/landscape-client/py3-fs
Merge into: lp:~landscape/landscape-client/trunk
Prerequisite: lp:~gocept/landscape-client/python3
Diff against target: 1084 lines (+272/-158)
21 files modified
landscape/broker/store.py (+2/-2)
landscape/broker/tests/test_store.py (+2/-2)
landscape/lib/fs.py (+84/-36)
landscape/lib/juju.py (+2/-2)
landscape/lib/tests/test_fs.py (+102/-39)
landscape/lib/tests/test_process.py (+4/-4)
landscape/lib/tests/test_twisted_util.py (+7/-7)
landscape/lib/vm_info.py (+4/-4)
landscape/monitor/aptpreferences.py (+4/-5)
landscape/monitor/computerinfo.py (+2/-2)
landscape/monitor/rebootrequired.py (+2/-2)
landscape/monitor/tests/test_computerinfo.py (+5/-3)
landscape/package/changer.py (+3/-3)
landscape/package/facade.py (+10/-9)
landscape/package/releaseupgrader.py (+2/-2)
landscape/package/tests/helpers.py (+5/-4)
landscape/package/tests/test_changer.py (+3/-3)
landscape/package/tests/test_facade.py (+7/-7)
landscape/package/tests/test_reporter.py (+2/-2)
landscape/sysinfo/tests/test_deployment.py (+2/-2)
landscape/tests/test_deployment.py (+18/-18)
To merge this branch: bzr merge lp:~gocept/landscape-client/py3-fs
Reviewer Review Type Date Requested Status
🤖 Landscape Builder test results Approve
Adam Collard (community) Approve
Daniel Havlik (community) Approve
Данило Шеган (community) Approve
Review via email: mp+319439@code.launchpad.net

Commit message

Split off read/create/append_file into text and binary file counterparts to serve strictly one purpose, thus clarifying the intention in each individual call.

Make rest of the code in landscape/lib/fs.py python2/3 compatible.

Description of the change

We are on the journey to get the Bytes / String story solved for Python 2/3 compatibility.

This MP considers code in the landscape.lib.fs module, which handles the reading of files. In Python 3 we can only seek at the end of a file opened in text mode, so the file has to be opened in binary mode. On the other hand, the code using `landscape.lib.fs.read_file()` is expecting a string as result, therefore we decode with the default encoding of 'utf-8'. This could be made configurable, but I did not see any usage in the code, where it might be needed.

Additionally the other methods were updated to use `open()` as context manager.

To post a comment you must log in.
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Fail
Revno: 960
Branch: lp:~gocept/landscape-client/py3-fs
Jenkins: https://ci.lscape.net/job/latch-test-precise/903/

review: Needs Fixing (test results)
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Fail
Revno: 960
Branch: lp:~gocept/landscape-client/py3-fs
Jenkins: https://ci.lscape.net/job/latch-test-xenial/1467/

review: Needs Fixing (test results)
Revision history for this message
Данило Шеган (danilo) wrote :

Just a nit about comments/docstrings, looks good.

review: Approve
lp:~gocept/landscape-client/py3-fs updated
961. By Steffen Allner

Improve docmentation.

Revision history for this message
Steffen Allner (sallner) wrote :

Thanks for the comment. Sometimes I tend to explain to verbose.

Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Fail
Revno: 961
Branch: lp:~gocept/landscape-client/py3-fs
Jenkins: https://ci.lscape.net/job/latch-test-xenial/3599/

review: Needs Fixing (test results)
Revision history for this message
Данило Шеган (danilo) wrote :

The tests don't seem to pass for either python 2 or python 3 with this change.

review: Needs Fixing
Revision history for this message
Steffen Allner (sallner) wrote :

> The tests don't seem to pass for either python 2 or python 3 with this change.

I am working on it atm. It is not so clear to me, whether read_file() should return strings or bytes. At most places where it is used, the other components are string literals ("...") in Python 2 but may be piped into structs or similar things. On the other hand, only returning bytes would require a rewrite of all places of usage. I currently think, I would leave the default on bytes and allow optional decoding for Python 3.

lp:~gocept/landscape-client/py3-fs updated
962. By Steffen Allner

Do not use context manager due to mock usage.

963. By Steffen Allner

Backmerge from trunk.

964. By Steffen Allner

Make encoding optional when creating or reading files. This allows to keep the code using strings in most places using Python 2 and 3.

965. By Steffen Allner

Use encoding when working with files in order ot get strings in Python 3.

Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Success
Revno: 965
Branch: lp:~gocept/landscape-client/py3-fs
Jenkins: https://ci.lscape.net/job/latch-test-xenial/3604/

review: Approve (test results)
Revision history for this message
Данило Шеган (danilo) wrote :

I still think we should really decode/encode unconditionally in read_file/create_file/append_file functions: they should return/take only unicode strings. A more detailed explanation is inline, but I don't think there is a way around this.

I understand that this makes it harder to do things strictly "per module", but once you update a shared helper like this one, all callsites will need to be fixed to deal with unicode too.

Note that our python2 unit tests are blocking, so without them passing, we can't land code. This will make this branch grow a bit, but I don't really see a way around it.

review: Needs Fixing
Revision history for this message
Данило Шеган (danilo) wrote :

Actually, it seems create_deb() helper in landscape/package/tests/helpers.py wants to create a binary file, but that is just a test helper, so that's easy to move away from create_file().

However, other callsites are trickier: they do want to construct binary files, and I think we should make a separate helper for them: "create_binary_file()" (mostly those that write out actual .deb files). If needed for tests, we could have a "read_binary_file()" too (which will provide symmetry too).

So my suggestion is to have separate create_binary_file() and create_text_file() helpers with their read_{binary|text}_file counterparts, with text files encoding/decoding from UTF-8, and making append_file be just append_text_file, again using UTF-8 (I doubt there is a need for append_binary_file).

Revision history for this message
Steffen Allner (sallner) wrote :

> Actually, it seems create_deb() helper in landscape/package/tests/helpers.py
> wants to create a binary file, but that is just a test helper, so that's easy
> to move away from create_file().
>
> However, other callsites are trickier: they do want to construct binary files,
> and I think we should make a separate helper for them: "create_binary_file()"
> (mostly those that write out actual .deb files). If needed for tests, we
> could have a "read_binary_file()" too (which will provide symmetry too).

Yeah it is always more complicated. That were the failures, the landscape-builder spotted first.

>
> So my suggestion is to have separate create_binary_file() and
> create_text_file() helpers with their read_{binary|text}_file counterparts,
> with text files encoding/decoding from UTF-8, and making append_file be just
> append_text_file, again using UTF-8 (I doubt there is a need for
> append_binary_file).

I am happy with the distinction of binary and text modes for these helper methods. This makes it a clear and readable option directly at the callsite.

This is almost a case, where the introduction of type annotation might be a reasonable thing.

Revision history for this message
Данило Шеган (danilo) wrote :

Right, you basically have that, it's just about making it separate methods instead of doing that with the encoding parameter.

lp:~gocept/landscape-client/py3-fs updated
966. By Steffen Allner

Explicitly offer a append_{binary|text}_file().

967. By Steffen Allner

Provide explicitly file creation in binary or test mode.

968. By Steffen Allner

Provide methods for explicitly reading in text or binary mode.

Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Success
Revno: 968
Branch: lp:~gocept/landscape-client/py3-fs
Jenkins: https://ci.lscape.net/job/latch-test-xenial/3610/

review: Approve (test results)
Revision history for this message
Steffen Allner (sallner) wrote :

I added separate functions for create, append, and read operations in binary and text mode.

Of course I needed also an append_binary_file() as on of the two modules using it, mangles with TagSection of the apt_pkg module, so there came no easier solution to my mind.

Revision history for this message
Данило Шеган (danilo) wrote :

Looks great, thanks for working on this! I just realized the error of my ways (regarding use of codecs module instead of just doing a bytes.decode() and unicode.encode()), but it's minor and not a blocker. +1

review: Approve
lp:~gocept/landscape-client/py3-fs updated
969. By Steffen Allner

Directly decode bytes and encode strings.

Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Success
Revno: 969
Branch: lp:~gocept/landscape-client/py3-fs
Jenkins: https://ci.lscape.net/job/latch-test-xenial/3612/

review: Approve (test results)
Revision history for this message
Steffen Allner (sallner) wrote :

I changed it back to a direct call and removed the import of codecs. Then this MP should be ready I think. Based on that, I will look at the MP concerning l.l.twisted_util and l.l.network.

Revision history for this message
Данило Шеган (danilo) wrote :

Looks good, thanks again! (We need two review passes, I'll ping my colleagues to get on this)

review: Approve
Revision history for this message
Данило Шеган (danilo) wrote :

Actually, one Canonical review is sufficient, we need a Gocept review too.

Revision history for this message
Daniel Havlik (nilo) wrote :

+1

review: Approve
Revision history for this message
Adam Collard (adam-collard) :
review: Approve
Revision history for this message
Данило Шеган (danilo) :
lp:~gocept/landscape-client/py3-fs updated
970. By Steffen Allner

Trim characters instead of bytes when reading in textmode.

Revision history for this message
Steffen Allner (sallner) wrote :

I changed the functionality to trimming characters in text mode.

Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Success
Revno: 970
Branch: lp:~gocept/landscape-client/py3-fs
Jenkins: https://ci.lscape.net/job/latch-test-xenial/3621/

review: Approve (test results)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'landscape/broker/store.py'
2--- landscape/broker/store.py 2017-03-06 10:38:07 +0000
3+++ landscape/broker/store.py 2017-03-14 14:46:07 +0000
4@@ -101,7 +101,7 @@
5
6 from landscape import DEFAULT_SERVER_API
7 from landscape.compat import bpickle
8-from landscape.lib.fs import create_file
9+from landscape.lib.fs import create_binary_file
10 from landscape.lib.versioning import sort_versions, is_version_higher
11
12
13@@ -372,7 +372,7 @@
14
15 filename = self._get_next_message_filename()
16 temp_path = filename + ".tmp"
17- create_file(temp_path, message_data)
18+ create_binary_file(temp_path, message_data)
19 os.rename(temp_path, filename)
20
21 if not self.accepts(message["type"]):
22
23=== modified file 'landscape/broker/tests/test_store.py'
24--- landscape/broker/tests/test_store.py 2016-08-17 20:31:48 +0000
25+++ landscape/broker/tests/test_store.py 2017-03-14 14:46:07 +0000
26@@ -280,7 +280,7 @@
27 self.store.add({"type": "data", "data": 1})
28 # We simulate it by creating a fake file which raises halfway through
29 # writing a file.
30- with mock.patch("__builtin__.open") as mock_open:
31+ with mock.patch("landscape.lib.fs.open") as mock_open:
32 mocked_file = mock_open.return_value
33 mocked_file.write.side_effect = IOError("Sorry, pal!")
34 # This kind of ensures that raising an exception is somewhat
35@@ -288,7 +288,7 @@
36 # on special exception-handling in the file-writing code.
37 self.assertRaises(
38 IOError, self.store.add, {"type": "data", "data": 2})
39- mock_open.assert_called_with(mock.ANY, "w")
40+ mock_open.assert_called_with(mock.ANY, "wb")
41 mocked_file.write.assert_called_once_with(mock.ANY)
42 self.assertEqual(self.store.get_pending_messages(),
43 [{"type": "data", "data": 1, "api": "3.2"}])
44
45=== modified file 'landscape/lib/fs.py'
46--- landscape/lib/fs.py 2013-05-28 08:48:31 +0000
47+++ landscape/lib/fs.py 2017-03-14 14:46:07 +0000
48@@ -1,50 +1,98 @@
49 """File-system utils"""
50-
51 import os
52 import time
53
54
55-def create_file(path, content):
56+from twisted.python.compat import long
57+
58+
59+def create_text_file(path, content):
60 """Create a file with the given content.
61
62- @param path: The path to the file.
63- @param content: The content to be written in the file.
64- """
65- fd = open(path, "w")
66- fd.write(content)
67- fd.close()
68-
69-
70-def append_file(path, content):
71+ The content is encoded with utf-8 before writing.
72+
73+ @param path: The path to the file.
74+ @param content: The content to be written in the file.
75+ """
76+ create_binary_file(path, content.encode("utf-8"))
77+
78+
79+def create_binary_file(path, content):
80+ """Create a file with the given binary content.
81+
82+ @param path: The path to the file.
83+ @param content: The content to be written in the file.
84+ """
85+ # XXX: Due to a very specific mock of `open()` in landscape.broker.tests.\
86+ # test_store.MessageStoreTest.test_atomic_message_writing it is hard to
87+ # write this file opening as context manager.
88+ fd = open(path, "wb")
89+ try:
90+ fd.write(content)
91+ finally:
92+ fd.close()
93+
94+
95+def append_text_file(path, content):
96 """Append a file with the given content.
97
98 The file is created, if it doesn't exist already.
99
100- @param path: The path to the file.
101- @param content: The content to be written in the file at the end.
102- """
103- fd = open(path, "a")
104- fd.write(content)
105- fd.close()
106-
107-
108-def read_file(path, limit=None):
109- """Return the content of the given file.
110-
111- @param path: The path to the file.
112- @param limit: An optional read limit. If positive, read up to that number
113- of bytes from the beginning of the file. If negative, read up to that
114- number of bytes from the end of the file.
115- @return content: The content of the file, possibly trimmed to C{limit}.
116- """
117- fd = open(path, "r")
118- if limit and os.path.getsize(path) > abs(limit):
119- whence = 0
120- if limit < 0:
121- whence = 2
122- fd.seek(limit, whence)
123- content = fd.read()
124- fd.close()
125+ The content is utf-8 encoded before it is written.
126+
127+ @param path: The path to the file.
128+ @param content: The content to be written in the file at the end.
129+ """
130+ append_binary_file(path, content.encode("utf-8"))
131+
132+
133+def append_binary_file(path, content):
134+ """Append a file with the given binary content.
135+
136+ The file is created, if it doesn't exist already.
137+
138+ @param path: The path to the file.
139+ @param content: The content to be written in the file at the end.
140+ """
141+ with open(path, "ab") as fd:
142+ fd.write(content)
143+
144+
145+def read_text_file(path, limit=None):
146+ """Return the content of the given file as string.
147+
148+ @param path: The path to the file.
149+ @param limit: An optional read limit. If positive, read up to that number
150+ of bytes from the beginning of the file. If negative, read up to that
151+ number of bytes from the end of the file.
152+ @return content: The content of the file string, possibly trimmed to
153+ C{limit}.
154+ """
155+ # Use binary mode since opening a file in text mode in Python 3 does not
156+ # allow non-zero offset seek from the end of the file.
157+ content = read_binary_file(path).decode("utf-8")
158+ if limit and len(content) > abs(limit):
159+ content = content[limit:]
160+ return content
161+
162+
163+def read_binary_file(path, limit=None):
164+ """Return the content of the given file as bytes.
165+
166+ @param path: The path to the file.
167+ @param limit: An optional read limit. If positive, read up to that number
168+ of bytes from the beginning of the file. If negative, read up to that
169+ number of bytes from the end of the file.
170+ @return content: The content of the file as bytes, possibly trimmed to
171+ C{limit}.
172+ """
173+ with open(path, "rb") as fd:
174+ if limit and os.path.getsize(path) > abs(limit):
175+ whence = 0
176+ if limit < 0:
177+ whence = 2
178+ fd.seek(limit, whence)
179+ content = fd.read()
180 return content
181
182
183
184=== modified file 'landscape/lib/juju.py'
185--- landscape/lib/juju.py 2014-09-24 08:09:55 +0000
186+++ landscape/lib/juju.py 2017-03-14 14:46:07 +0000
187@@ -2,7 +2,7 @@
188 import json
189 import logging
190
191-from landscape.lib.fs import read_file
192+from landscape.lib.fs import read_text_file
193
194
195 def get_juju_info(config):
196@@ -13,7 +13,7 @@
197 if not os.path.exists(config.juju_filename):
198 return
199
200- json_contents = read_file(config.juju_filename)
201+ json_contents = read_text_file(config.juju_filename)
202 try:
203 juju_info = json.loads(json_contents)
204 # Catch any error the json lib could throw, because we don't know or
205
206=== modified file 'landscape/lib/tests/test_fs.py'
207--- landscape/lib/tests/test_fs.py 2016-06-15 16:42:17 +0000
208+++ landscape/lib/tests/test_fs.py 2017-03-14 14:46:07 +0000
209@@ -1,44 +1,90 @@
210+# -*- coding: utf-8 -*-
211+import codecs
212 import os
213 from mock import patch
214 import time
215
216+from twisted.python.compat import long
217+
218 from landscape.tests.helpers import LandscapeTest
219
220-from landscape.lib.fs import append_file, read_file, touch_file
221+from landscape.lib.fs import append_text_file, touch_file
222+from landscape.lib.fs import read_text_file, read_binary_file
223
224
225 class ReadFileTest(LandscapeTest):
226
227- def test_read_file(self):
228+ def test_read_binary_file(self):
229 """
230- With no options L{read_file} reads the whole file passed as argument.
231+ With no options L{read_binary_file} reads the whole file passed as
232+ argument.
233 """
234 path = self.makeFile("foo")
235- self.assertEqual(read_file(path), "foo")
236+ self.assertEqual(read_binary_file(path), b"foo")
237
238- def test_read_file_with_limit(self):
239+ def test_read_binary_file_with_limit(self):
240 """
241- With a positive limit L{read_file} reads only the bytes after the
242- given limit.
243+ With a positive limit L{read_binary_file} reads only the bytes after
244+ the given limit.
245 """
246 path = self.makeFile("foo bar")
247- self.assertEqual(read_file(path, limit=3), " bar")
248-
249- def test_read_file_with_negative_limit(self):
250- """
251- With a negative limit L{read_file} reads only the tail of the file.
252- """
253- path = self.makeFile("foo bar from end")
254- self.assertEqual(read_file(path, limit=-3), "end")
255-
256- def test_read_file_with_limit_bigger_than_file(self):
257- """
258- If the limit is bigger than the file L{read_file} reads the entire
259- file.
260- """
261- path = self.makeFile("foo bar from end")
262- self.assertEqual(read_file(path, limit=100), "foo bar from end")
263- self.assertEqual(read_file(path, limit=-100), "foo bar from end")
264+ self.assertEqual(read_binary_file(path, limit=3), b" bar")
265+
266+ def test_read_binary_file_with_negative_limit(self):
267+ """
268+ With a negative limit L{read_binary_file} reads only the tail of the
269+ file.
270+ """
271+ path = self.makeFile("foo bar from end")
272+ self.assertEqual(read_binary_file(path, limit=-3), b"end")
273+
274+ def test_read_binary_file_with_limit_bigger_than_file(self):
275+ """
276+ If the limit is bigger than the file L{read_binary_file} reads the
277+ entire file.
278+ """
279+ path = self.makeFile("foo bar from end")
280+ self.assertEqual(
281+ read_binary_file(path, limit=100), b"foo bar from end")
282+ self.assertEqual(
283+ read_binary_file(path, limit=-100), b"foo bar from end")
284+
285+ def test_read_text_file(self):
286+ """
287+ With no options L{read_text_file} reads the whole file passed as
288+ argument as string decoded with utf-8.
289+ """
290+ utf8_content = codecs.encode(u"foo \N{SNOWMAN}", "utf-8")
291+ path = self.makeFile(utf8_content, mode="wb")
292+ self.assertEqual(read_text_file(path), u"foo ☃")
293+
294+ def test_read_text_file_with_limit(self):
295+ """
296+ With a positive limit L{read_text_file} returns only the characters
297+ after the first L{limit} characters as string.
298+ """
299+ utf8_content = codecs.encode(u"foo \N{SNOWMAN}", "utf-8")
300+ path = self.makeFile(utf8_content, mode="wb")
301+ self.assertEqual(read_text_file(path, limit=3), u" ☃")
302+
303+ def test_read_text_file_with_negative_limit(self):
304+ """
305+ With a negative limit L{read_text_file} reads only the tail characters
306+ of the string.
307+ """
308+ utf8_content = codecs.encode(u"foo \N{SNOWMAN} bar", "utf-8")
309+ path = self.makeFile(utf8_content, mode="wb")
310+ self.assertEqual(read_text_file(path, limit=-5), u"☃ bar")
311+
312+ def test_read_text_file_with_limit_bigger_than_file(self):
313+ """
314+ If the limit is bigger than the file L{read_text_file} reads the entire
315+ file.
316+ """
317+ utf8_content = codecs.encode(u"foo \N{SNOWMAN} bar", "utf-8")
318+ path = self.makeFile(utf8_content, mode="wb")
319+ self.assertEqual(read_text_file(path, limit=100), u"foo ☃ bar")
320+ self.assertEqual(read_text_file(path, limit=-100), u"foo ☃ bar")
321
322
323 class TouchFileTest(LandscapeTest):
324@@ -86,19 +132,36 @@
325
326 class AppendFileTest(LandscapeTest):
327
328- def test_append_existing_file(self):
329- """
330- The L{append_file} function appends contents to an existing file.
331- """
332- existing_file = self.makeFile("foo bar")
333- append_file(existing_file, " baz")
334- self.assertFileContent(existing_file, "foo bar baz")
335-
336- def test_append_no_file(self):
337- """
338- The L{append_file} function creates a new file if one doesn't
339- exist already.
340- """
341- new_file = os.path.join(self.makeDir(), "new_file")
342- append_file(new_file, "contents")
343+ def test_append_existing_text_file(self):
344+ """
345+ The L{append_text_file} function appends contents to an existing file.
346+ """
347+ existing_file = self.makeFile("foo bar")
348+ append_text_file(existing_file, " baz")
349+ self.assertFileContent(existing_file, "foo bar baz")
350+
351+ def test_append_text_no_file(self):
352+ """
353+ The L{append_text_file} function creates a new file if one doesn't
354+ exist already.
355+ """
356+ new_file = os.path.join(self.makeDir(), "new_file")
357+ append_text_file(new_file, "contents")
358+ self.assertFileContent(new_file, "contents")
359+
360+ def test_append_existing_binary_file(self):
361+ """
362+ The L{append_text_file} function appends contents to an existing file.
363+ """
364+ existing_file = self.makeFile("foo bar")
365+ append_text_file(existing_file, " baz")
366+ self.assertFileContent(existing_file, "foo bar baz")
367+
368+ def test_append_binary_no_file(self):
369+ """
370+ The L{append_text_file} function creates a new file if one doesn't
371+ exist already.
372+ """
373+ new_file = os.path.join(self.makeDir(), "new_file")
374+ append_text_file(new_file, "contents")
375 self.assertFileContent(new_file, "contents")
376
377=== modified file 'landscape/lib/tests/test_process.py'
378--- landscape/lib/tests/test_process.py 2017-03-09 10:13:30 +0000
379+++ landscape/lib/tests/test_process.py 2017-03-14 14:46:07 +0000
380@@ -5,7 +5,7 @@
381 from landscape.tests.helpers import LandscapeTest
382
383 from landscape.lib.process import calculate_pcpu, ProcessInformation
384-from landscape.lib.fs import create_file
385+from landscape.lib.fs import create_text_file
386
387
388 class ProcessInfoTest(LandscapeTest):
389@@ -25,7 +25,7 @@
390 os.mkdir(process_dir)
391
392 cmd_line = "/usr/bin/foo"
393- create_file(os.path.join(process_dir, "cmdline"), cmd_line)
394+ create_text_file(os.path.join(process_dir, "cmdline"), cmd_line)
395
396 status = "\n".join([
397 "Name: foo",
398@@ -34,11 +34,11 @@
399 "Gid: 2000",
400 "VmSize: 3000",
401 "Ignored: value"])
402- create_file(os.path.join(process_dir, "status"), status)
403+ create_text_file(os.path.join(process_dir, "status"), status)
404
405 stat_array = [str(index) for index in range(44)]
406 stat = " ".join(stat_array)
407- create_file(os.path.join(process_dir, "stat"), stat)
408+ create_text_file(os.path.join(process_dir, "stat"), stat)
409
410 @mock.patch("landscape.lib.process.detect_jiffies", return_value=1)
411 @mock.patch("os.listdir")
412
413=== modified file 'landscape/lib/tests/test_twisted_util.py'
414--- landscape/lib/tests/test_twisted_util.py 2017-01-23 12:14:33 +0000
415+++ landscape/lib/tests/test_twisted_util.py 2017-03-14 14:46:07 +0000
416@@ -3,7 +3,7 @@
417 from twisted.python.compat import _PY3
418 from unittest import skipIf
419
420-from landscape.lib.fs import create_file
421+from landscape.lib.fs import create_text_file
422 from landscape.lib.twisted_util import spawn_process
423 from landscape.tests.helpers import LandscapeTest
424
425@@ -19,7 +19,7 @@
426 """
427 The process is executed and returns the expected exit code.
428 """
429- create_file(self.command, "#!/bin/sh\nexit 2")
430+ create_text_file(self.command, "#!/bin/sh\nexit 2")
431
432 def callback(args):
433 out, err, code = args
434@@ -49,7 +49,7 @@
435 """
436 The process returns the expected standard error.
437 """
438- create_file(self.command, "#!/bin/sh\necho -n $@ >&2")
439+ create_text_file(self.command, "#!/bin/sh\necho -n $@ >&2")
440
441 def callback(args):
442 out, err, code = args
443@@ -66,7 +66,7 @@
444 If a callback for process output is provieded, it is called for every
445 line of output.
446 """
447- create_file(self.command, "#!/bin/sh\n/bin/echo -ne $@")
448+ create_text_file(self.command, "#!/bin/sh\n/bin/echo -ne $@")
449 param = r"some text\nanother line\nok, last one\n"
450 expected = ["some text", "another line", "ok, last one"]
451 lines = []
452@@ -87,7 +87,7 @@
453 """
454 If output ends with more than one newline, empty lines are preserved.
455 """
456- create_file(self.command, "#!/bin/sh\n/bin/echo -ne $@")
457+ create_text_file(self.command, "#!/bin/sh\n/bin/echo -ne $@")
458 param = r"some text\nanother line\n\n\n"
459 expected = ["some text", "another line", "", ""]
460 lines = []
461@@ -109,7 +109,7 @@
462 If output ends without a newline, the line is still passed to the
463 callback.
464 """
465- create_file(self.command, "#!/bin/sh\n/bin/echo -ne $@")
466+ create_text_file(self.command, "#!/bin/sh\n/bin/echo -ne $@")
467 param = r"some text\nanother line\nok, last one"
468 expected = ["some text", "another line", "ok, last one"]
469 lines = []
470@@ -131,7 +131,7 @@
471 """
472 Optionally C{spawn_process} accepts a C{stdin} argument.
473 """
474- create_file(self.command, "#!/bin/sh\n/bin/cat")
475+ create_text_file(self.command, "#!/bin/sh\n/bin/cat")
476
477 def callback(args):
478 out, err, code = args
479
480=== modified file 'landscape/lib/vm_info.py'
481--- landscape/lib/vm_info.py 2016-09-23 15:43:36 +0000
482+++ landscape/lib/vm_info.py 2017-03-14 14:46:07 +0000
483@@ -3,7 +3,7 @@
484 """
485 import os
486
487-from landscape.lib.fs import read_file
488+from landscape.lib.fs import read_text_file
489
490
491 def get_vm_info(root_path="/"):
492@@ -34,7 +34,7 @@
493 for filename in ("container_type", "systemd/container"):
494 path = os.path.join(run_path, filename)
495 if os.path.exists(path):
496- return read_file(path).strip()
497+ return read_text_file(path).strip()
498 return ""
499
500
501@@ -52,7 +52,7 @@
502
503 def _get_vm_by_vendor(sys_vendor_path):
504 """Return the VM type string (possibly empty) based on the vendor."""
505- vendor = read_file(sys_vendor_path).lower()
506+ vendor = read_text_file(sys_vendor_path).lower()
507 # Use lower-key string for vendors, since we do case-insentive match.
508 content_vendors_map = (
509 ("bochs", "kvm"),
510@@ -72,7 +72,7 @@
511 def _get_vm_legacy(root_path):
512 """Check if the host is virtualized looking at /proc/cpuinfo content."""
513 try:
514- cpuinfo = read_file(os.path.join(root_path, "proc/cpuinfo"))
515+ cpuinfo = read_text_file(os.path.join(root_path, "proc/cpuinfo"))
516 except (IOError, OSError):
517 return ""
518
519
520=== modified file 'landscape/monitor/aptpreferences.py'
521--- landscape/monitor/aptpreferences.py 2017-01-10 09:43:40 +0000
522+++ landscape/monitor/aptpreferences.py 2017-03-14 14:46:07 +0000
523@@ -1,8 +1,8 @@
524 import os
525
526-from twisted.python.compat import iteritems, unicode
527+from twisted.python.compat import iteritems
528
529-from landscape.lib.fs import read_file
530+from landscape.lib.fs import read_text_file
531 from landscape.constants import APT_PREFERENCES_SIZE_LIMIT
532
533 from landscape.monitor.plugin import DataWatcher
534@@ -30,11 +30,10 @@
535 simply return C{None}
536 """
537 data = {}
538- read_unicode = lambda filename: unicode(read_file(filename))
539 preferences_filename = os.path.join(self._etc_apt_directory,
540 u"preferences")
541 if os.path.exists(preferences_filename):
542- data[preferences_filename] = read_unicode(preferences_filename)
543+ data[preferences_filename] = read_text_file(preferences_filename)
544
545 preferences_directory = os.path.join(self._etc_apt_directory,
546 u"preferences.d")
547@@ -42,7 +41,7 @@
548 for entry in os.listdir(preferences_directory):
549 filename = os.path.join(preferences_directory, entry)
550 if os.path.isfile(filename):
551- data[filename] = read_unicode(filename)
552+ data[filename] = read_text_file(filename)
553
554 if data == {}:
555 return None
556
557=== modified file 'landscape/monitor/computerinfo.py'
558--- landscape/monitor/computerinfo.py 2013-10-02 15:26:21 +0000
559+++ landscape/monitor/computerinfo.py 2017-03-14 14:46:07 +0000
560@@ -3,7 +3,7 @@
561 from twisted.internet.defer import inlineCallbacks, returnValue
562
563 from landscape.lib.fetch import fetch_async
564-from landscape.lib.fs import read_file
565+from landscape.lib.fs import read_text_file
566 from landscape.lib.lsb_release import LSB_RELEASE_FILENAME, parse_lsb_release
567 from landscape.lib.cloud import fetch_ec2_meta_data
568 from landscape.lib.network import get_fqdn
569@@ -89,7 +89,7 @@
570 annotations = {}
571 if os.path.exists(self._annotations_path):
572 for key in os.listdir(self._annotations_path):
573- annotations[key] = read_file(
574+ annotations[key] = read_text_file(
575 os.path.join(self._annotations_path, key))
576
577 if annotations:
578
579=== modified file 'landscape/monitor/rebootrequired.py'
580--- landscape/monitor/rebootrequired.py 2017-03-10 12:14:46 +0000
581+++ landscape/monitor/rebootrequired.py 2017-03-14 14:46:07 +0000
582@@ -1,7 +1,7 @@
583 import os
584 import logging
585
586-from landscape.lib.fs import read_file
587+from landscape.lib.fs import read_text_file
588 from landscape.monitor.plugin import MonitorPlugin
589
590
591@@ -34,7 +34,7 @@
592 if not os.path.exists(self._packages_filename):
593 return []
594
595- lines = read_file(self._packages_filename).splitlines()
596+ lines = read_text_file(self._packages_filename).splitlines()
597 packages = set(line.strip() for line in lines if line)
598 return sorted(packages)
599
600
601=== modified file 'landscape/monitor/tests/test_computerinfo.py'
602--- landscape/monitor/tests/test_computerinfo.py 2016-06-15 20:15:44 +0000
603+++ landscape/monitor/tests/test_computerinfo.py 2017-03-14 14:46:07 +0000
604@@ -5,7 +5,7 @@
605 from twisted.internet.defer import succeed, fail, inlineCallbacks
606
607 from landscape.lib.fetch import HTTPCodeError, PyCurlError
608-from landscape.lib.fs import create_file
609+from landscape.lib.fs import create_text_file
610 from landscape.monitor.computerinfo import ComputerInfo, METADATA_RETRY_MAX
611 from landscape.tests.helpers import LandscapeTest, MonitorHelper
612
613@@ -367,8 +367,10 @@
614 """
615 annotations_dir = self.monitor.config.annotations_path
616 os.mkdir(annotations_dir)
617- create_file(os.path.join(annotations_dir, "annotation1"), "value1")
618- create_file(os.path.join(annotations_dir, "annotation2"), "value2")
619+ create_text_file(
620+ os.path.join(annotations_dir, "annotation1"), "value1")
621+ create_text_file(
622+ os.path.join(annotations_dir, "annotation2"), "value2")
623 self.mstore.set_accepted_types(["computer-info"])
624
625 plugin = ComputerInfo()
626
627=== modified file 'landscape/package/changer.py'
628--- landscape/package/changer.py 2017-01-05 09:07:23 +0000
629+++ landscape/package/changer.py 2017-03-14 14:46:07 +0000
630@@ -14,7 +14,7 @@
631 POLICY_STRICT, POLICY_ALLOW_INSTALLS, POLICY_ALLOW_ALL_CHANGES,
632 UNKNOWN_PACKAGE_DATA_TIMEOUT)
633
634-from landscape.lib.fs import create_file
635+from landscape.lib.fs import create_binary_file
636 from landscape.lib.log import log_failure
637 from landscape.package.reporter import find_reporter_command
638 from landscape.package.taskhandler import (
639@@ -172,8 +172,8 @@
640 if binaries:
641 hash_ids = {}
642 for hash, id, deb in binaries:
643- create_file(os.path.join(binaries_path, "%d.deb" % id),
644- base64.decodestring(deb))
645+ create_binary_file(os.path.join(binaries_path, "%d.deb" % id),
646+ base64.decodestring(deb))
647 hash_ids[hash] = id
648 self._store.set_hash_ids(hash_ids)
649 self._facade.add_channel_deb_dir(binaries_path)
650
651=== modified file 'landscape/package/facade.py'
652--- landscape/package/facade.py 2017-01-23 12:14:33 +0000
653+++ landscape/package/facade.py 2017-03-14 14:46:07 +0000
654@@ -25,7 +25,8 @@
655
656
657 from landscape.compat import StringIO
658-from landscape.lib.fs import append_file, create_file, read_file, touch_file
659+from landscape.lib.fs import append_text_file, create_text_file
660+from landscape.lib.fs import read_text_file, read_binary_file, touch_file
661 from landscape.package.skeleton import build_skeleton_apt
662
663
664@@ -154,10 +155,10 @@
665 self._ensure_sub_dir("var/lib/dpkg/info")
666 self._ensure_sub_dir("var/lib/dpkg/updates")
667 self._ensure_sub_dir("var/lib/dpkg/triggers")
668- create_file(os.path.join(dpkg_dir, "available"), "")
669+ create_text_file(os.path.join(dpkg_dir, "available"), "")
670 self._dpkg_status = os.path.join(dpkg_dir, "status")
671 if not os.path.exists(self._dpkg_status):
672- create_file(self._dpkg_status, "")
673+ create_text_file(self._dpkg_status, "")
674 # Apt will fail if it does not have a keyring. It does not care if
675 # the keyring is empty.
676 touch_file(os.path.join(apt_dir, "trusted.gpg"))
677@@ -279,11 +280,11 @@
678 if components:
679 sources_line += " %s" % " ".join(components)
680 if os.path.exists(sources_file_path):
681- current_content = read_file(sources_file_path).split("\n")
682+ current_content = read_text_file(sources_file_path).split("\n")
683 if sources_line in current_content:
684 return
685 sources_line += "\n"
686- append_file(sources_file_path, sources_line)
687+ append_text_file(sources_file_path, sources_line)
688
689 def add_channel_deb_dir(self, path):
690 """Add a directory with packages as a channel.
691@@ -312,7 +313,7 @@
692 packages_contents = "\n".join(
693 self.get_package_stanza(os.path.join(deb_dir, filename))
694 for filename in sorted(os.listdir(deb_dir)))
695- create_file(os.path.join(deb_dir, "Packages"), packages_contents)
696+ create_text_file(os.path.join(deb_dir, "Packages"), packages_contents)
697
698 def get_channels(self):
699 """Return a list of channels configured.
700@@ -344,7 +345,7 @@
701 deb_file.close()
702 filename = os.path.basename(deb_path)
703 size = os.path.getsize(deb_path)
704- contents = read_file(deb_path)
705+ contents = read_binary_file(deb_path)
706 md5 = hashlib.md5(contents).hexdigest()
707 sha1 = hashlib.sha1(contents).hexdigest()
708 sha256 = hashlib.sha256(contents).hexdigest()
709@@ -667,7 +668,7 @@
710 raise SystemError("dpkg didn't exit cleanly.")
711 except (apt.cache.LockFailedException, SystemError) as exception:
712 result_text = (fetch_output.getvalue()
713- + read_file(install_output_path))
714+ + read_text_file(install_output_path))
715 error = TransactionError(exception.args[0] +
716 "\n\nPackage operation log:\n" +
717 result_text)
718@@ -677,7 +678,7 @@
719 break
720 else:
721 result_text = (fetch_output.getvalue()
722- + read_file(install_output_path))
723+ + read_text_file(install_output_path))
724 break
725 if error is not None:
726 raise error
727
728=== modified file 'landscape/package/releaseupgrader.py'
729--- landscape/package/releaseupgrader.py 2017-01-23 12:14:33 +0000
730+++ landscape/package/releaseupgrader.py 2017-03-14 14:46:07 +0000
731@@ -12,7 +12,7 @@
732 from landscape.lib.fetch import url_to_filename, fetch_to_files
733 from landscape.lib.lsb_release import parse_lsb_release, LSB_RELEASE_FILENAME
734 from landscape.lib.gpg import gpg_verify
735-from landscape.lib.fs import read_file
736+from landscape.lib.fs import read_text_file
737 from landscape.package.taskhandler import (
738 PackageTaskHandlerConfiguration, PackageTaskHandler, run_task_handler)
739 from landscape.lib.twisted_util import spawn_process
740@@ -196,7 +196,7 @@
741 if not basename.endswith(".log"):
742 continue
743 filename = os.path.join(self.logs_directory, basename)
744- content = read_file(filename, - self.logs_limit)
745+ content = read_text_file(filename, - self.logs_limit)
746 buf.write("=== %s ===\n\n%s\n\n" % (basename, content))
747
748 return buf.getvalue()
749
750=== modified file 'landscape/package/tests/helpers.py'
751--- landscape/package/tests/helpers.py 2017-01-19 08:34:52 +0000
752+++ landscape/package/tests/helpers.py 2017-03-14 14:46:07 +0000
753@@ -6,7 +6,8 @@
754 import apt_inst
755 import apt_pkg
756
757-from landscape.lib.fs import append_file, create_file
758+from landscape.lib.fs import append_binary_file, append_text_file
759+from landscape.lib.fs import create_binary_file
760 from landscape.package.facade import AptFacade
761
762
763@@ -52,7 +53,7 @@
764 package_stanza = apt_pkg.rewrite_section(
765 apt_pkg.TagSection(package_stanza), apt_pkg.REWRITE_PACKAGE_ORDER,
766 control_fields.items())
767- append_file(packages_file, "\n" + package_stanza + "\n")
768+ append_binary_file(packages_file, "\n" + package_stanza + "\n")
769
770 def _add_system_package(self, name, architecture="all", version="1.0",
771 control_fields=None):
772@@ -73,7 +74,7 @@
773 lines = control.splitlines()
774 lines.insert(1, "Status: install ok installed")
775 status = "\n".join(lines)
776- append_file(self.dpkg_status, status + "\n\n")
777+ append_text_file(self.dpkg_status, status + "\n\n")
778
779 def _add_package_to_deb_dir(self, path, name, architecture="all",
780 version="1.0", description="description",
781@@ -319,7 +320,7 @@
782 """Create a Debian package in the specified C{target_dir}."""
783 path = os.path.join(target_dir, pkg_name)
784 data = base64.decodestring(pkg_data)
785- create_file(path, data)
786+ create_binary_file(path, data)
787
788
789 def create_simple_repository(target_dir):
790
791=== modified file 'landscape/package/tests/test_changer.py'
792--- landscape/package/tests/test_changer.py 2016-08-17 20:31:48 +0000
793+++ landscape/package/tests/test_changer.py 2017-03-14 14:46:07 +0000
794@@ -10,7 +10,7 @@
795
796 from mock import patch, Mock, call
797
798-from landscape.lib.fs import create_file, read_file, touch_file
799+from landscape.lib.fs import create_text_file, read_text_file, touch_file
800 from landscape.package.changer import (
801 PackageChanger, main, find_changer_command, UNKNOWN_PACKAGE_DATA_TIMEOUT,
802 SUCCESS_RESULT, DEPENDENCY_ERROR_RESULT, POLICY_ALLOW_INSTALLS,
803@@ -101,11 +101,11 @@
804 def remove_pkg2(self):
805 """Remove package name2 from its repository."""
806 packages_file = os.path.join(self.repository_dir, "Packages")
807- packages_contents = read_file(packages_file)
808+ packages_contents = read_text_file(packages_file)
809 packages_contents = "\n\n".join(
810 [stanza for stanza in packages_contents.split("\n\n")
811 if "Package: name2" not in stanza])
812- create_file(packages_file, packages_contents)
813+ create_text_file(packages_file, packages_contents)
814
815 def get_binaries_channels(self, binaries_path):
816 """Return the channels that will be used for the binaries."""
817
818=== modified file 'landscape/package/tests/test_facade.py'
819--- landscape/package/tests/test_facade.py 2017-01-10 09:43:40 +0000
820+++ landscape/package/tests/test_facade.py 2017-03-14 14:46:07 +0000
821@@ -11,7 +11,7 @@
822
823 from twisted.python.compat import unicode
824
825-from landscape.lib.fs import read_file, create_file
826+from landscape.lib.fs import read_text_file, create_text_file
827 from landscape.package.facade import (
828 TransactionError, DependencyError, ChannelError, AptFacade,
829 LandscapeInstallProgress)
830@@ -183,7 +183,7 @@
831 list_filename = (
832 self.apt_root +
833 "/etc/apt/sources.list.d/_landscape-internal-facade.list")
834- sources_contents = read_file(list_filename)
835+ sources_contents = read_text_file(list_filename)
836 self.assertEqual(
837 "deb http://example.com/ubuntu lucid\n",
838 sources_contents)
839@@ -199,7 +199,7 @@
840 list_filename = (
841 self.apt_root +
842 "/etc/apt/sources.list.d/_landscape-internal-facade.list")
843- sources_contents = read_file(list_filename)
844+ sources_contents = read_text_file(list_filename)
845 self.assertEqual(
846 "deb http://example.com/ubuntu lucid\n",
847 sources_contents)
848@@ -216,7 +216,7 @@
849 list_filename = (
850 self.apt_root +
851 "/etc/apt/sources.list.d/_landscape-internal-facade.list")
852- sources_contents = read_file(list_filename)
853+ sources_contents = read_text_file(list_filename)
854 self.assertEqual(
855 "deb http://example.com/ubuntu lucid main restricted\n",
856 sources_contents)
857@@ -265,9 +265,9 @@
858 sources_list_file = apt_pkg.config.find_file("Dir::Etc::sourcelist")
859 sources_list_d_file = os.path.join(
860 apt_pkg.config.find_dir("Dir::Etc::sourceparts"), "example.list")
861- create_file(
862+ create_text_file(
863 sources_list_file, "deb http://example1.com/ubuntu lucid main")
864- create_file(
865+ create_text_file(
866 sources_list_d_file, "deb http://example2.com/ubuntu lucid main")
867
868 self.facade.clear_channels()
869@@ -321,7 +321,7 @@
870 deb_dir = self.makeDir()
871 create_simple_repository(deb_dir)
872 self.facade.add_channel_deb_dir(deb_dir)
873- packages_contents = read_file(os.path.join(deb_dir, "Packages"))
874+ packages_contents = read_text_file(os.path.join(deb_dir, "Packages"))
875 expected_contents = "\n".join(
876 self.facade.get_package_stanza(os.path.join(deb_dir, pkg_name))
877 for pkg_name in [PKGNAME1, PKGNAME2, PKGNAME3])
878
879=== modified file 'landscape/package/tests/test_reporter.py'
880--- landscape/package/tests/test_reporter.py 2017-03-06 10:38:07 +0000
881+++ landscape/package/tests/test_reporter.py 2017-03-14 14:46:07 +0000
882@@ -8,7 +8,7 @@
883 from twisted.internet import reactor
884
885
886-from landscape.lib.fs import create_file, touch_file
887+from landscape.lib.fs import create_text_file, touch_file
888 from landscape.lib.fetch import FetchError
889 from landscape.package.store import (
890 PackageStore, UnknownHashIDRequest, FakePackageStore)
891@@ -66,7 +66,7 @@
892
893 def _clear_repository(self):
894 """Remove all packages from self.repository."""
895- create_file(self.repository_dir + "/Packages", "")
896+ create_text_file(self.repository_dir + "/Packages", "")
897
898 def set_pkg1_upgradable(self):
899 """Make it so that package "name1" is considered to be upgradable.
900
901=== modified file 'landscape/sysinfo/tests/test_deployment.py'
902--- landscape/sysinfo/tests/test_deployment.py 2016-06-16 17:00:28 +0000
903+++ landscape/sysinfo/tests/test_deployment.py 2017-03-14 14:46:07 +0000
904@@ -6,7 +6,7 @@
905
906 from twisted.internet.defer import Deferred
907
908-from landscape.lib.fs import create_file
909+from landscape.lib.fs import create_text_file
910
911 from landscape.sysinfo.deployment import (
912 SysInfoConfiguration, ALL_PLUGINS, run, setup_logging,
913@@ -51,7 +51,7 @@
914
915 def test_config_file(self):
916 filename = self.makeFile()
917- create_file(filename, "[sysinfo]\nsysinfo_plugins = TestPlugin\n")
918+ create_text_file(filename, "[sysinfo]\nsysinfo_plugins = TestPlugin\n")
919 self.configuration.load(["--config", filename, "-d", self.makeDir()])
920 plugins = self.configuration.get_plugins()
921 self.assertEqual(len(plugins), 1)
922
923=== modified file 'landscape/tests/test_deployment.py'
924--- landscape/tests/test_deployment.py 2017-01-23 12:14:33 +0000
925+++ landscape/tests/test_deployment.py 2017-03-14 14:46:07 +0000
926@@ -4,7 +4,7 @@
927 import os
928
929 from landscape.compat import StringIO
930-from landscape.lib.fs import read_file, create_file
931+from landscape.lib.fs import read_text_file, create_text_file
932
933 from landscape.deployment import (
934 BaseConfiguration, Configuration, get_versioned_persist)
935@@ -191,7 +191,7 @@
936 self.write_config_file(log_level="debug")
937 self.config.log_level = "warning"
938 self.config.write()
939- data = read_file(self.config_filename)
940+ data = read_text_file(self.config_filename)
941 self.assertConfigEqual(data, "[client]\nlog_level = warning")
942
943 def test_write_configuration_with_section(self):
944@@ -199,7 +199,7 @@
945 self.write_config_file(section_name="babble", whatever="yay")
946 self.config.whatever = "boo"
947 self.config.write()
948- data = read_file(self.config_filename)
949+ data = read_text_file(self.config_filename)
950 self.assertConfigEqual(data, "[babble]\nwhatever = boo")
951
952 def test_write_unrelated_configuration_back(self):
953@@ -214,7 +214,7 @@
954 self.config.load_configuration_file(config_filename)
955 self.config.whatever = "boo"
956 self.config.write()
957- data = read_file(config_filename)
958+ data = read_text_file(config_filename)
959 self.assertConfigEqual(
960 data,
961 "[babble]\nwhatever = boo\n\n[goojy]\nunrelated = yes")
962@@ -226,7 +226,7 @@
963 self.config.load([])
964 self.config.log_level = "warning"
965 self.config.write()
966- data = read_file(self.config_filename)
967+ data = read_text_file(self.config_filename)
968 self.assertConfigEqual(data, "[client]\nlog_level = warning\n")
969
970 def test_write_empty_list_values_instead_of_double_quotes(self):
971@@ -239,7 +239,7 @@
972 self.config.load([])
973 self.config.include_manager_plugins = ""
974 self.config.write()
975- data = read_file(self.config_filename)
976+ data = read_text_file(self.config_filename)
977 self.assertConfigEqual(data, "[client]\ninclude_manager_plugins = \n")
978
979 def test_dont_write_config_specified_default_options(self):
980@@ -250,7 +250,7 @@
981 self.write_config_file(log_level="debug")
982 self.config.log_level = "info"
983 self.config.write()
984- data = read_file(self.config_filename)
985+ data = read_text_file(self.config_filename)
986 self.assertConfigEqual(data, "[client]")
987
988 def test_dont_write_unspecified_default_options(self):
989@@ -261,7 +261,7 @@
990 self.write_config_file()
991 self.config.log_level = "info"
992 self.config.write()
993- data = read_file(self.config_filename)
994+ data = read_text_file(self.config_filename)
995 self.assertConfigEqual(data, "[client]")
996
997 def test_dont_write_client_section_default_options(self):
998@@ -272,7 +272,7 @@
999 self.write_config_file(log_level="debug")
1000 self.config.log_level = "info"
1001 self.config.write()
1002- data = read_file(self.config_filename)
1003+ data = read_text_file(self.config_filename)
1004 self.assertConfigEqual(data, "[client]")
1005
1006 def test_do_write_preexisting_default_options(self):
1007@@ -285,7 +285,7 @@
1008 self.config.load_configuration_file(config_filename)
1009 self.config.log_level = "info"
1010 self.config.write()
1011- data = read_file(config_filename)
1012+ data = read_text_file(config_filename)
1013 self.assertConfigEqual(data, "[client]\nlog_level = info\n")
1014
1015 def test_dont_delete_explicitly_set_default_options(self):
1016@@ -296,21 +296,21 @@
1017 """
1018 self.write_config_file(log_level="info")
1019 self.config.write()
1020- data = read_file(self.config_filename)
1021+ data = read_text_file(self.config_filename)
1022 self.assertConfigEqual(data, "[client]\nlog_level = info")
1023
1024 def test_dont_write_config_option(self):
1025 self.write_config_file()
1026 self.config.config = self.config_filename
1027 self.config.write()
1028- data = read_file(self.config_filename)
1029+ data = read_text_file(self.config_filename)
1030 self.assertConfigEqual(data, "[client]")
1031
1032 def test_write_command_line_options(self):
1033 self.write_config_file()
1034 self.config.load(["--log-level", "warning"])
1035 self.config.write()
1036- data = read_file(self.config_filename)
1037+ data = read_text_file(self.config_filename)
1038 self.assertConfigEqual(data, "[client]\nlog_level = warning\n")
1039
1040 def test_write_command_line_precedence(self):
1041@@ -319,7 +319,7 @@
1042 self.write_config_file(log_level="debug")
1043 self.config.load(["--log-level", "warning"])
1044 self.config.write()
1045- data = read_file(self.config_filename)
1046+ data = read_text_file(self.config_filename)
1047 self.assertConfigEqual(data, "[client]\nlog_level = warning\n")
1048
1049 def test_write_manually_set_precedence(self):
1050@@ -329,7 +329,7 @@
1051 self.config.load(["--log-level", "warning"])
1052 self.config.log_level = "error"
1053 self.config.write()
1054- data = read_file(self.config_filename)
1055+ data = read_text_file(self.config_filename)
1056 self.assertConfigEqual(data, "[client]\nlog_level = error\n")
1057
1058 def test_write_to_given_config_file(self):
1059@@ -338,7 +338,7 @@
1060 ["--log-level", "warning", "--config", filename])
1061 self.config.log_level = "error"
1062 self.config.write()
1063- data = read_file(filename)
1064+ data = read_text_file(filename)
1065 self.assertConfigEqual(data, "[client]\nlog_level = error\n")
1066
1067 def test_comments_are_maintained(self):
1068@@ -351,7 +351,7 @@
1069 self.config.load_configuration_file(filename)
1070 self.config.log_level = "error"
1071 self.config.write()
1072- new_config = read_file(filename)
1073+ new_config = read_text_file(filename)
1074 self.assertConfigEqual(
1075 new_config,
1076 "[client]\n# Comment 1\nlog_level = error\n#Comment 2\n")
1077@@ -412,7 +412,7 @@
1078 """
1079 filename = self.makeFile("[client]\nhello = world1\n")
1080 self.config.load(["--config", filename])
1081- create_file(filename, "[client]\nhello = world2\n")
1082+ create_text_file(filename, "[client]\nhello = world2\n")
1083 self.config.reload()
1084 self.assertEqual(self.config.hello, "world2")
1085

Subscribers

People subscribed via source and target branches

to all changes: