Ticket #1072: rename-stringutils-drop-open_unicode.dpatch

File rename-stringutils-drop-open_unicode.dpatch, 30.7 KB (added by davidsarah, at 2010-07-13T04:44:46Z)

Rename stringutils to encodingutil, and drop open_unicode (since the Python 'open' function works fine with Unicode paths).

Line 
1Sun Jul 11 20:55:25 GMT Daylight Time 2010  david-sarah@jacaranda.org
2  * Allow URIs passed in the initial JSON for t=mkdir-with-children, t=mkdir-immutable to be Unicode. Also pass the name of each child into nodemaker.create_from_cap for error reporting.
3
4Tue Jul 13 05:27:15 GMT Daylight Time 2010  david-sarah@jacaranda.org
5  * Rename stringutils to encodingutil, and drop open_unicode (since the Python 'open' function works fine with Unicode paths).
6
7New patches:
8
9[Allow URIs passed in the initial JSON for t=mkdir-with-children, t=mkdir-immutable to be Unicode. Also pass the name of each child into nodemaker.create_from_cap for error reporting.
10david-sarah@jacaranda.org**20100711195525
11 Ignore-this: deac32d8b91ba26ede18905d3f7d2b93
12] {
13hunk ./src/allmydata/web/common.py 14
14      EmptyPathnameComponentError, MustBeDeepImmutableError, \
15      MustBeReadonlyError, MustNotBeUnknownRWError
16 from allmydata.mutable.common import UnrecoverableFileError
17-from allmydata.util import abbreviate # TODO: consolidate
18+from allmydata.util import abbreviate
19+from allmydata.util.stringutils import to_str
20 
21 class IOpHandleTable(Interface):
22     pass
23hunk ./src/allmydata/web/common.py 68
24     children = {}
25     if children_json:
26         data = simplejson.loads(children_json)
27-        for (name, (ctype, propdict)) in data.iteritems():
28-            name = unicode(name)
29-            writecap = propdict.get("rw_uri")
30-            if writecap is not None:
31-                writecap = str(writecap)
32-            readcap = propdict.get("ro_uri")
33-            if readcap is not None:
34-                readcap = str(readcap)
35+        for (namex, (ctype, propdict)) in data.iteritems():
36+            namex = unicode(namex)
37+            writecap = to_str(propdict.get("rw_uri"))
38+            readcap = to_str(propdict.get("ro_uri"))
39             metadata = propdict.get("metadata", {})
40hunk ./src/allmydata/web/common.py 73
41-            childnode = nodemaker.create_from_cap(writecap, readcap)
42-            children[name] = (childnode, metadata)
43+            # name= argument is just for error reporting
44+            childnode = nodemaker.create_from_cap(writecap, readcap, name=namex)
45+            children[namex] = (childnode, metadata)
46     return children
47 
48 def abbreviate_time(data):
49}
50[Rename stringutils to encodingutil, and drop open_unicode (since the Python 'open' function works fine with Unicode paths).
51david-sarah@jacaranda.org**20100713042715
52 Ignore-this: fa2bb6b5d48ce9ba7ea2b1afc9f3b7b4
53] {
54move ./src/allmydata/test/test_stringutils.py ./src/allmydata/test/test_encodingutil.py
55move ./src/allmydata/util/stringutils.py ./src/allmydata/util/encodingutil.py
56hunk ./src/allmydata/dirnode.py 19
57      DeepCheckAndRepairResults
58 from allmydata.monitor import Monitor
59 from allmydata.util import hashutil, mathutil, base32, log
60-from allmydata.util.stringutils import quote_output
61+from allmydata.util.encodingutil import quote_output
62 from allmydata.util.assertutil import precondition
63 from allmydata.util.netstring import netstring, split_netstring
64 from allmydata.util.consumer import download_to_data
65hunk ./src/allmydata/scripts/cli.py 4
66 import os.path, re, sys, fnmatch
67 from twisted.python import usage
68 from allmydata.scripts.common import BaseOptions, get_aliases
69-from allmydata.util.stringutils import argv_to_unicode
70+from allmydata.util.encodingutil import argv_to_unicode
71 
72 NODEURL_RE=re.compile("http(s?)://([^:]*)(:([1-9][0-9]*))?")
73 
74hunk ./src/allmydata/scripts/common.py 5
75 import os, sys, urllib
76 import codecs
77 from twisted.python import usage
78-from allmydata.util.stringutils import unicode_to_url, quote_output
79+from allmydata.util.encodingutil import unicode_to_url, quote_output
80 from allmydata.util.assertutil import precondition
81 
82 class BaseOptions:
83hunk ./src/allmydata/scripts/common_http.py 6
84 import urlparse, httplib
85 import allmydata # for __full_version__
86 
87-from allmydata.util.stringutils import quote_output
88+from allmydata.util.encodingutil import quote_output
89 from allmydata.scripts.common import TahoeError
90 
91 
92hunk ./src/allmydata/scripts/slow_operation.py 7
93                                      UnknownAliasError
94 from allmydata.scripts.common_http import do_http, format_http_error
95 from allmydata.util import base32
96-from allmydata.util.stringutils import quote_output, is_printable_ascii
97+from allmydata.util.encodingutil import quote_output, is_printable_ascii
98 import urllib
99 import simplejson
100 
101hunk ./src/allmydata/scripts/tahoe_add_alias.py 8
102 from allmydata.scripts.common_http import do_http, check_http_error
103 from allmydata.scripts.common import get_aliases
104 from allmydata.util.fileutil import move_into_place
105-from allmydata.util.stringutils import unicode_to_output, quote_output
106+from allmydata.util.encodingutil import unicode_to_output, quote_output
107 
108 
109 def add_line_to_aliasfile(aliasfile, alias, cap):
110hunk ./src/allmydata/scripts/tahoe_backup.py 12
111 from allmydata.scripts.common_http import do_http, HTTPError, format_http_error
112 from allmydata.util import time_format
113 from allmydata.scripts import backupdb
114-from allmydata.util.stringutils import listdir_unicode, open_unicode, quote_output, to_str
115+from allmydata.util.encodingutil import listdir_unicode, quote_output, to_str, FilenameEncodingError
116 from allmydata.util.assertutil import precondition
117 
118 
119hunk ./src/allmydata/scripts/tahoe_backup.py 174
120             self.directories_skipped += 1
121             self.warn("WARNING: permission denied on directory %s" % quote_output(localpath))
122             children = []
123+        except FilenameEncodingError:
124+            self.directories_skipped += 1
125+            self.warn("WARNING: could not list directory %s due to a filename encoding error" % quote_output(localpath))
126+            children = []
127 
128         for child in self.options.filter_listdir(children):
129             assert isinstance(child, unicode), child
130hunk ./src/allmydata/scripts/tahoe_backup.py 299
131 
132         if must_upload:
133             self.verboseprint("uploading %s.." % quote_output(childpath))
134-            infileobj = open_unicode(childpath, "rb")
135+            infileobj = open(childpath, "rb")
136             url = self.options['node-url'] + "uri"
137             resp = do_http("PUT", url, infileobj)
138             if resp.status not in (200, 201):
139hunk ./src/allmydata/scripts/tahoe_check.py 8
140 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \
141                                      UnknownAliasError
142 from allmydata.scripts.common_http import do_http, format_http_error
143-from allmydata.util.stringutils import quote_output, quote_path
144+from allmydata.util.encodingutil import quote_output, quote_path
145 
146 class Checker:
147     pass
148hunk ./src/allmydata/scripts/tahoe_cp.py 11
149                                      DefaultAliasMarker, TahoeError
150 from allmydata.scripts.common_http import do_http, HTTPError
151 from allmydata import uri
152-from allmydata.util.stringutils import unicode_to_url, listdir_unicode, open_unicode, \
153-    abspath_expanduser_unicode, quote_output, to_str
154+from allmydata.util import fileutil
155+from allmydata.util.encodingutil import unicode_to_url, listdir_unicode, quote_output, to_str
156 from allmydata.util.assertutil import precondition
157 
158 
159hunk ./src/allmydata/scripts/tahoe_cp.py 16
160-def _put_local_file(pathname, inf):
161-    # TODO: create temporary file and move into place?
162-    # TODO: move this to fileutil.
163-    outf = open_unicode(pathname, "wb")
164-    try:
165-        while True:
166-            data = inf.read(32768)
167-            if not data:
168-                break
169-            outf.write(data)
170-    finally:
171-        outf.close()
172-
173-
174 class MissingSourceError(TahoeError):
175     def __init__(self, name):
176         TahoeError.__init__(self, "No such file or directory %s" % quote_output(name))
177hunk ./src/allmydata/scripts/tahoe_cp.py 70
178         return True
179 
180     def open(self, caps_only):
181-        return open_unicode(self.pathname, "rb")
182+        return open(os.path.expanduser(self.pathname), "rb")
183 
184 
185 class LocalFileTarget:
186hunk ./src/allmydata/scripts/tahoe_cp.py 79
187         self.pathname = pathname
188 
189     def put_file(self, inf):
190-        _put_local_file(self.pathname, inf)
191+        fileutil.put_file(self.pathname, inf)
192 
193 
194 class LocalMissingTarget:
195hunk ./src/allmydata/scripts/tahoe_cp.py 88
196         self.pathname = pathname
197 
198     def put_file(self, inf):
199-        _put_local_file(self.pathname, inf)
200+        fileutil.put_file(self.pathname, inf)
201 
202 
203 class LocalDirectorySource:
204hunk ./src/allmydata/scripts/tahoe_cp.py 157
205     def put_file(self, name, inf):
206         precondition(isinstance(name, unicode), name)
207         pathname = os.path.join(self.pathname, name)
208-        _put_local_file(pathname, inf)
209+        fileutil.put_file(pathname, inf)
210 
211     def set_children(self):
212         pass
213hunk ./src/allmydata/scripts/tahoe_cp.py 514
214         rootcap, path = get_alias(self.aliases, destination_spec, None)
215         if rootcap == DefaultAliasMarker:
216             # no alias, so this is a local file
217-            pathname = abspath_expanduser_unicode(path.decode('utf-8'))
218+            pathname = os.path.abspath(os.path.expanduser(path.decode('utf-8')))
219             if not os.path.exists(pathname):
220                 t = LocalMissingTarget(pathname)
221             elif os.path.isdir(pathname):
222hunk ./src/allmydata/scripts/tahoe_cp.py 554
223         rootcap, path = get_alias(self.aliases, source_spec, None)
224         if rootcap == DefaultAliasMarker:
225             # no alias, so this is a local file
226-            pathname = abspath_expanduser_unicode(path.decode('utf-8'))
227+            pathname = os.path.abspath(os.path.expanduser(path.decode('utf-8')))
228             name = os.path.basename(pathname)
229             if not os.path.exists(pathname):
230                 raise MissingSourceError(source_spec)
231hunk ./src/allmydata/scripts/tahoe_get.py 2
232 
233-import urllib
234+import os, urllib
235 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \
236                                      UnknownAliasError
237 from allmydata.scripts.common_http import do_http, format_http_error
238hunk ./src/allmydata/scripts/tahoe_get.py 6
239-from allmydata.util.stringutils import open_unicode
240 
241 def get(options):
242     nodeurl = options['node-url']
243hunk ./src/allmydata/scripts/tahoe_get.py 29
244     resp = do_http("GET", url)
245     if resp.status in (200, 201,):
246         if to_file:
247-            outf = open_unicode(to_file, "wb")
248+            outf = open(os.path.expanduser(to_file), "wb")
249         else:
250             outf = stdout
251         while True:
252hunk ./src/allmydata/scripts/tahoe_ls.py 7
253 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \
254                                      UnknownAliasError
255 from allmydata.scripts.common_http import do_http, format_http_error
256-from allmydata.util.stringutils import unicode_to_output, quote_output, is_printable_ascii, to_str
257+from allmydata.util.encodingutil import unicode_to_output, quote_output, is_printable_ascii, to_str
258 
259 def list(options):
260     nodeurl = options['node-url']
261hunk ./src/allmydata/scripts/tahoe_manifest.py 9
262 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \
263                                      UnknownAliasError
264 from allmydata.scripts.common_http import do_http, format_http_error
265-from allmydata.util.stringutils import quote_output, quote_path
266+from allmydata.util.encodingutil import quote_output, quote_path
267 
268 class FakeTransport:
269     disconnecting = False
270hunk ./src/allmydata/scripts/tahoe_mkdir.py 5
271 import urllib
272 from allmydata.scripts.common_http import do_http, check_http_error
273 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, UnknownAliasError
274-from allmydata.util.stringutils import quote_output
275+from allmydata.util.encodingutil import quote_output
276 
277 def mkdir(options):
278     nodeurl = options['node-url']
279hunk ./src/allmydata/scripts/tahoe_mv.py 8
280 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \
281                                      UnknownAliasError
282 from allmydata.scripts.common_http import do_http, format_http_error
283-from allmydata.util.stringutils import to_str
284+from allmydata.util.encodingutil import to_str
285 
286 # this script is used for both 'mv' and 'ln'
287 
288hunk ./src/allmydata/scripts/tahoe_put.py 2
289 
290+import os
291 from cStringIO import StringIO
292 import urllib
293 from allmydata.scripts.common_http import do_http, format_http_success, format_http_error
294hunk ./src/allmydata/scripts/tahoe_put.py 8
295 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \
296                                      UnknownAliasError
297-from allmydata.util.stringutils import quote_output, open_unicode
298+from allmydata.util.encodingutil import quote_output
299 
300 def put(options):
301     """
302hunk ./src/allmydata/scripts/tahoe_put.py 68
303     if mutable:
304         url += "?mutable=true"
305     if from_file:
306-        infileobj = open_unicode(from_file, "rb")
307+        infileobj = open(os.path.expanduser(from_file), "rb")
308     else:
309         # do_http() can't use stdin directly: for one thing, we need a
310         # Content-Length field. So we currently must copy it.
311hunk ./src/allmydata/test/test_backupdb.py 7
312 from twisted.trial import unittest
313 
314 from allmydata.util import fileutil
315-from allmydata.util.stringutils import listdir_unicode, get_filesystem_encoding, unicode_platform
316+from allmydata.util.encodingutil import listdir_unicode, get_filesystem_encoding, unicode_platform
317 from allmydata.util.assertutil import precondition
318 from allmydata.scripts import backupdb
319 
320hunk ./src/allmydata/test/test_cli.py 34
321 from twisted.python import usage
322 
323 from allmydata.util.assertutil import precondition
324-from allmydata.util.stringutils import listdir_unicode, open_unicode, unicode_platform, \
325+from allmydata.util.encodingutil import listdir_unicode, unicode_platform, \
326     quote_output, get_output_encoding, get_argv_encoding, get_filesystem_encoding, \
327     unicode_to_output, to_str
328 
329hunk ./src/allmydata/test/test_cli.py 442
330         fileutil.make_dirs(basedir)
331 
332         for name in filenames:
333-            open_unicode(os.path.join(unicode(basedir), name), "wb").close()
334+            open(os.path.join(unicode(basedir), name), "wb").close()
335 
336         for file in listdir_unicode(unicode(basedir)):
337             self.failUnlessIn(normalize(file), filenames)
338hunk ./src/allmydata/test/test_cli.py 977
339         rel_fn = os.path.join(unicode(self.basedir), u"à trier.txt")
340         # we make the file small enough to fit in a LIT file, for speed
341         DATA = "short file"
342-        f = open_unicode(rel_fn, "wb")
343-        try:
344-            f.write(DATA)
345-        finally:
346-            f.close()
347+        fileutil.write(rel_fn, DATA)
348 
349         d = self.do_cli("create-alias", "tahoe")
350 
351hunk ./src/allmydata/test/test_cli.py 1348
352         self.set_up_grid()
353 
354         DATA1 = "unicode file content"
355-        f = open_unicode(fn1, "wb")
356-        try:
357-            f.write(DATA1)
358-        finally:
359-            f.close()
360+        fileutil.write(fn1, DATA1)
361 
362         fn2 = os.path.join(self.basedir, "Metallica")
363         DATA2 = "non-unicode file content"
364hunk ./src/allmydata/test/test_encodingutil.py 26
365         sys.exit(1)
366     
367     print
368-    print "class MyWeirdOS(StringUtils, unittest.TestCase):"
369+    print "class MyWeirdOS(EncodingUtil, unittest.TestCase):"
370     print "    uname = '%s'" % ' '.join(platform.uname())
371     if sys.platform != "win32":
372         print "    argv = %s" % repr(sys.argv[1])
373hunk ./src/allmydata/test/test_encodingutil.py 56
374 
375 from twisted.trial import unittest
376 from mock import patch
377-import sys
378+import os, sys, locale
379 
380 from allmydata.test.common_util import ReallyEqualMixin
381hunk ./src/allmydata/test/test_encodingutil.py 59
382-from allmydata.util.stringutils import argv_to_unicode, unicode_to_url, \
383-    unicode_to_output, unicode_platform, listdir_unicode, open_unicode, \
384-    FilenameEncodingError, get_output_encoding, _reload
385+from allmydata.util.encodingutil import argv_to_unicode, unicode_to_url, \
386+    unicode_to_output, unicode_platform, listdir_unicode, FilenameEncodingError, \
387+    get_output_encoding, get_filesystem_encoding, _reload
388 from allmydata.dirnode import normalize
389 
390 from twisted.python import usage
391hunk ./src/allmydata/test/test_encodingutil.py 66
392 
393-class StringUtilsErrors(ReallyEqualMixin, unittest.TestCase):
394+class EncodingUtilErrors(ReallyEqualMixin, unittest.TestCase):
395     def tearDown(self):
396         _reload()
397 
398hunk ./src/allmydata/test/test_encodingutil.py 87
399         mock_stdout.encoding = 'nonexistent_encoding'
400         self.failUnlessRaises(AssertionError, _reload)
401 
402-        # TODO: mock_stdout.encoding = None
403+    @patch('locale.getpreferredencoding')
404+    def test_get_output_encoding_not_from_stdout(self, mock_locale_getpreferredencoding):
405+        locale  # hush pyflakes
406+        mock_locale_getpreferredencoding.return_value = 'koi8-r'
407+
408+        class DummyStdout:
409+            pass
410+        old_stdout = sys.stdout
411+        sys.stdout = DummyStdout()
412+        try:
413+            _reload()
414+            self.failUnlessReallyEqual(get_output_encoding(), 'koi8-r')
415+
416+            sys.stdout.encoding = None
417+            _reload()
418+            self.failUnlessReallyEqual(get_output_encoding(), 'koi8-r')
419+
420+            mock_locale_getpreferredencoding.return_value = None
421+            _reload()
422+            self.failUnlessReallyEqual(get_output_encoding(), 'utf-8')
423+        finally:
424+            sys.stdout = old_stdout
425 
426     @patch('sys.stdout')
427     def test_argv_to_unicode(self, mock):
428hunk ./src/allmydata/test/test_encodingutil.py 139
429         finally:
430             sys.platform = orig_platform
431 
432-# The following tests applies only to platforms which don't store filenames as
433+# The following tests apply only to platforms that don't store filenames as
434 # Unicode entities on the filesystem.
435hunk ./src/allmydata/test/test_encodingutil.py 141
436-class StringUtilsNonUnicodePlatform(unittest.TestCase):
437+class EncodingUtilNonUnicodePlatform(unittest.TestCase):
438     def setUp(self):
439         # Mock sys.platform because unicode_platform() uses it
440         self.original_platform = sys.platform
441hunk ./src/allmydata/test/test_encodingutil.py 174
442                               listdir_unicode,
443                               u'/' + lumiere_nfc)
444 
445-    @patch('sys.getfilesystemencoding')
446-    def test_open_unicode(self, mock):
447-        mock.return_value = 'ascii'
448-        _reload()
449-        self.failUnlessRaises(FilenameEncodingError,
450-                              open_unicode,
451-                              lumiere_nfc, 'rb')
452-
453-class StringUtils(ReallyEqualMixin):
454+class EncodingUtil(ReallyEqualMixin):
455     def setUp(self):
456         # Mock sys.platform because unicode_platform() uses it
457         self.original_platform = sys.platform
458hunk ./src/allmydata/test/test_encodingutil.py 233
459 
460         mock_listdir.return_value = self.dirlist
461         mock_getfilesystemencoding.return_value = self.filesystem_encoding
462-       
463+
464         _reload()
465         filenames = listdir_unicode(u'/dummy')
466 
467hunk ./src/allmydata/test/test_encodingutil.py 240
468         self.failUnlessEqual(set([normalize(fname) for fname in filenames]),
469                              set(TEST_FILENAMES))
470 
471-    @patch('sys.getfilesystemencoding')
472-    @patch('__builtin__.open')
473-    def test_open_unicode(self, mock_open, mock_getfilesystemencoding):
474-        mock_getfilesystemencoding.return_value = self.filesystem_encoding
475-        fn = u'/dummy_directory/" + lumiere_nfc + ".txt'
476 
477hunk ./src/allmydata/test/test_encodingutil.py 241
478-        try:
479-            u"test".encode(self.filesystem_encoding)
480-        except (LookupError, AttributeError):
481-            raise unittest.SkipTest("This platform does not support the '%s' filesystem encoding "
482-                                    "that we are testing for the benefit of a different platform."
483-                                    % (self.filesystem_encoding,))
484+class StdlibUnicode(unittest.TestCase):
485+    """This mainly tests that some of the stdlib functions support Unicode paths, but also that
486+    listdir_unicode works for valid filenames."""
487+
488+    def skip_if_cannot_represent_filename(self, u):
489+        enc = get_filesystem_encoding()
490+        if not unicode_platform():
491+            try:
492+                u.encode(enc)
493+            except UnicodeEncodeError:
494+                raise unittest.SkipTest("A non-ASCII filename could not be encoded on this platform.")
495+
496+    def test_mkdir_open_exists_abspath_listdir_expanduser(self):
497+        self.skip_if_cannot_represent_filename(lumiere_nfc)
498 
499hunk ./src/allmydata/test/test_encodingutil.py 256
500-        _reload()
501         try:
502hunk ./src/allmydata/test/test_encodingutil.py 257
503-            open_unicode(fn, 'rb')
504-        except FilenameEncodingError:
505-            return
506+            os.mkdir(lumiere_nfc)
507+        except EnvironmentError, e:
508+            raise unittest.SkipTest("%r\nIt is possible that the filesystem on which this test is being run "
509+                                    "does not support Unicode, even though the platform does." % (e,))
510+
511+        fn = lumiere_nfc + '/' + lumiere_nfc + '.txt'
512+        open(fn, 'wb').close()
513+        self.failUnless(os.path.exists(fn))
514+        self.failUnless(os.path.exists(os.path.abspath(fn)))
515+        filenames = listdir_unicode(lumiere_nfc)
516+
517+        # We only require that the listing includes a filename that is canonically equivalent
518+        # to lumiere_nfc (on Mac OS X, it will be the NFD equivalent).
519+        self.failUnlessIn(lumiere_nfc + ".txt", set([normalize(fname) for fname in filenames]))
520 
521hunk ./src/allmydata/test/test_encodingutil.py 272
522-        # Pass Unicode string to open() on Unicode platforms
523+        expanded = os.path.expanduser("~/" + lumiere_nfc)
524+        self.failIfIn("~", expanded)
525+        self.failUnless(expanded.endswith(lumiere_nfc), expanded)
526+
527+    @patch('sys.getfilesystemencoding')
528+    def test_open_unrepresentable(self, mock):
529         if unicode_platform():
530hunk ./src/allmydata/test/test_encodingutil.py 279
531-            mock_open.assert_called_with(fn, 'rb')
532+            raise unittest.SkipTest("This test is not applicable to platforms that represent filenames as Unicode.")
533 
534hunk ./src/allmydata/test/test_encodingutil.py 281
535-        # Pass correctly encoded bytestrings to open() on non-Unicode platforms
536-        else:
537-            fn_bytestring = fn.encode(self.filesystem_encoding)
538-            mock_open.assert_called_with(fn_bytestring, 'rb')
539+        mock.return_value = 'ascii'
540+        self.failUnlessRaises(UnicodeEncodeError, open, lumiere_nfc, 'rb')
541 
542 
543hunk ./src/allmydata/test/test_encodingutil.py 285
544-class UbuntuKarmicUTF8(StringUtils, unittest.TestCase):
545+class UbuntuKarmicUTF8(EncodingUtil, unittest.TestCase):
546     uname = 'Linux korn 2.6.31-14-generic #48-Ubuntu SMP Fri Oct 16 14:05:01 UTC 2009 x86_64'
547     output = 'lumi\xc3\xa8re'
548     argv = 'lumi\xc3\xa8re'
549hunk ./src/allmydata/test/test_encodingutil.py 295
550     argv_encoding = 'UTF-8'
551     dirlist = ['test_file', '\xc3\x84rtonwall.mp3', 'Blah blah.txt']
552 
553-class UbuntuKarmicLatin1(StringUtils, unittest.TestCase):
554+class UbuntuKarmicLatin1(EncodingUtil, unittest.TestCase):
555     uname = 'Linux korn 2.6.31-14-generic #48-Ubuntu SMP Fri Oct 16 14:05:01 UTC 2009 x86_64'
556     output = 'lumi\xe8re'
557     argv = 'lumi\xe8re'
558hunk ./src/allmydata/test/test_encodingutil.py 305
559     argv_encoding = 'ISO-8859-1'
560     dirlist = ['test_file', 'Blah blah.txt', '\xc4rtonwall.mp3']
561 
562-class WindowsXP(StringUtils, unittest.TestCase):
563+class WindowsXP(EncodingUtil, unittest.TestCase):
564     uname = 'Windows XP 5.1.2600 x86 x86 Family 15 Model 75 Step ping 2, AuthenticAMD'
565     output = 'lumi\x8are'
566     platform = 'win32'
567hunk ./src/allmydata/test/test_encodingutil.py 314
568     argv_encoding = 'ascii'
569     dirlist = [u'Blah blah.txt', u'test_file', u'\xc4rtonwall.mp3']
570 
571-class WindowsXP_UTF8(StringUtils, unittest.TestCase):
572+class WindowsXP_UTF8(EncodingUtil, unittest.TestCase):
573     uname = 'Windows XP 5.1.2600 x86 x86 Family 15 Model 75 Step ping 2, AuthenticAMD'
574     output = 'lumi\xc3\xa8re'
575     platform = 'win32'
576hunk ./src/allmydata/test/test_encodingutil.py 323
577     argv_encoding = 'ascii'
578     dirlist = [u'Blah blah.txt', u'test_file', u'\xc4rtonwall.mp3']
579 
580-class WindowsVista(StringUtils, unittest.TestCase):
581+class WindowsVista(EncodingUtil, unittest.TestCase):
582     uname = 'Windows Vista 6.0.6000 x86 x86 Family 6 Model 15 Stepping 11, GenuineIntel'
583     output = 'lumi\x8are'
584     platform = 'win32'
585hunk ./src/allmydata/test/test_encodingutil.py 332
586     argv_encoding = 'ascii'
587     dirlist = [u'Blah blah.txt', u'test_file', u'\xc4rtonwall.mp3']
588 
589-class MacOSXLeopard(StringUtils, unittest.TestCase):
590+class MacOSXLeopard(EncodingUtil, unittest.TestCase):
591     uname = 'Darwin g5.local 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:57:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_PPC Power Macintosh powerpc'
592     output = 'lumi\xc3\xa8re'
593     argv = 'lumi\xc3\xa8re'
594hunk ./src/allmydata/test/test_encodingutil.py 342
595     argv_encoding = 'UTF-8'
596     dirlist = [u'A\u0308rtonwall.mp3', u'Blah blah.txt', u'test_file']
597 
598-class MacOSXLeopard7bit(StringUtils, unittest.TestCase):
599+class MacOSXLeopard7bit(EncodingUtil, unittest.TestCase):
600     uname = 'Darwin g5.local 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:57:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_PPC Power Macintosh powerpc'
601     platform = 'darwin'
602     filesystem_encoding = 'utf-8'
603hunk ./src/allmydata/test/test_encodingutil.py 350
604     argv_encoding = 'US-ASCII'
605     dirlist = [u'A\u0308rtonwall.mp3', u'Blah blah.txt', u'test_file']
606 
607-class OpenBSD(StringUtils, unittest.TestCase):
608+class OpenBSD(EncodingUtil, unittest.TestCase):
609     uname = 'OpenBSD 4.1 GENERIC#187 i386 Intel(R) Celeron(R) CPU 2.80GHz ("GenuineIntel" 686-class)'
610     platform = 'openbsd4'
611     filesystem_encoding = '646'
612hunk ./src/allmydata/util/encodingutil.py 218
613         return os.listdir(path)
614     else:
615         return listdir_unicode_fallback(path)
616-
617-def open_unicode(path, mode):
618-    """
619-    Wrapper around open() which provides safe access to the convenient Unicode
620-    API even under Unix.
621-    """
622-    precondition(isinstance(path, unicode), path)
623-
624-    if is_unicode_platform:
625-        return open(os.path.expanduser(path), mode)
626-    else:
627-        try:
628-            return open(os.path.expanduser(path.encode(filesystem_encoding)), mode)
629-        except UnicodeEncodeError:
630-            raise FilenameEncodingError(path)
631-
632-def abspath_expanduser_unicode(path):
633-    precondition(isinstance(path, unicode), path)
634-
635-    if is_unicode_platform:
636-        return os.path.abspath(os.path.expanduser(path))
637-    else:
638-        try:
639-            pathstr = path.encode(filesystem_encoding)
640-            return os.path.abspath(os.path.expanduser(pathstr)).decode(filesystem_encoding)
641-        except (UnicodeEncodeError, UnicodeDecodeError):
642-            raise FilenameEncodingError(path)
643hunk ./src/allmydata/util/fileutil.py 212
644     finally:
645         rf.close()
646 
647+def put_file(pathname, inf):
648+    # TODO: create temporary file and move into place?
649+    outf = open(os.path.expanduser(pathname), "wb")
650+    try:
651+        while True:
652+            data = inf.read(32768)
653+            if not data:
654+                break
655+            outf.write(data)
656+    finally:
657+        outf.close()
658+
659hunk ./src/allmydata/web/common.py 15
660      MustBeReadonlyError, MustNotBeUnknownRWError
661 from allmydata.mutable.common import UnrecoverableFileError
662 from allmydata.util import abbreviate
663-from allmydata.util.stringutils import to_str
664+from allmydata.util.encodingutil import to_str
665 
666 class IOpHandleTable(Interface):
667     pass
668}
669
670Context:
671
672[SFTP: address some of the comments in zooko's review (#1106).
673david-sarah@jacaranda.org**20100712025537
674 Ignore-this: c3921638a2d4f1de2a776ae78e4dc37e
675] 
676[docs/logging.txt: note that setting flogging vars might affect tests with race conditions.
677david-sarah@jacaranda.org**20100712050721
678 Ignore-this: fc1609d215fcd5561a57fd1226206f27
679] 
680[test_storage.py: potential fix for failures when logging is enabled.
681david-sarah@jacaranda.org**19700713040546
682 Ignore-this: 5815693a0df3e64c52c3c6b7be2846c7
683] 
684[upcase_since_on_welcome
685terrellrussell@gmail.com**20100708193903] 
686[server_version_on_welcome_page.dpatch.txt
687freestorm77@gmail.com**20100605191721
688 Ignore-this: b450c76dc875f5ac8cca229a666cbd0a
689 
690 
691 - The storage server version is 0 for all storage nodes in the Welcome Page
692 
693 
694] 
695[NEWS: add NEWS snippets about two recent patches
696zooko@zooko.com**20100708162058
697 Ignore-this: 6c9da6a0ad7351a960bdd60f81532899
698] 
699[directory_html_top_banner.dpatch
700freestorm77@gmail.com**20100622205301
701 Ignore-this: 1d770d975e0c414c996564774f049bca
702 
703 The div tag with the link "Return to Welcome page" on the directory.xhtml page is not correct
704 
705] 
706[tahoe_css_toolbar.dpatch
707freestorm77@gmail.com**20100622210046
708 Ignore-this: 5b3ebb2e0f52bbba718a932f80c246c0
709 
710 CSS modification to be correctly diplayed with Internet Explorer 8
711 
712 The links on the top of page directory.xhtml are not diplayed in the same line as display with Firefox.
713 
714] 
715[runnin_test_tahoe_css.dpatch
716freestorm77@gmail.com**20100622214714
717 Ignore-this: e0db73d68740aad09a7b9ae60a08c05c
718 
719 Runnin test for changes in tahoe.css file
720 
721] 
722[runnin_test_directory_xhtml.dpatch
723freestorm77@gmail.com**20100622201403
724 Ignore-this: f8962463fce50b9466405cb59fe11d43
725 
726 Runnin test for diretory.xhtml top banner
727 
728] 
729[stringutils.py: tolerate sys.stdout having no 'encoding' attribute.
730david-sarah@jacaranda.org**20100626040817
731 Ignore-this: f42cad81cef645ee38ac1df4660cc850
732] 
733[quickstart.html: python 2.5 -> 2.6 as recommended version
734david-sarah@jacaranda.org**20100705175858
735 Ignore-this: bc3a14645ea1d5435002966ae903199f
736] 
737[SFTP: don't call .stopProducing on the producer registered with OverwriteableFileConsumer (which breaks with warner's new downloader).
738david-sarah@jacaranda.org**20100628231926
739 Ignore-this: 131b7a5787bc85a9a356b5740d9d996f
740] 
741[docs/how_to_make_a_tahoe-lafs_release.txt: trivial correction, install.html should now be quickstart.html.
742david-sarah@jacaranda.org**20100625223929
743 Ignore-this: 99a5459cac51bd867cc11ad06927ff30
744] 
745[setup: in the Makefile, refuse to upload tarballs unless someone has passed the environment variable "BB_BRANCH" with value "trunk"
746zooko@zooko.com**20100619034928
747 Ignore-this: 276ddf9b6ad7ec79e27474862e0f7d6
748] 
749[trivial: tiny update to in-line comment
750zooko@zooko.com**20100614045715
751 Ignore-this: 10851b0ed2abfed542c97749e5d280bc
752 (I'm actually committing this patch as a test of the new eager-annotation-computation of trac-darcs.)
753] 
754[docs: about.html link to home page early on, and be decentralized storage instead of cloud storage this time around
755zooko@zooko.com**20100619065318
756 Ignore-this: dc6db03f696e5b6d2848699e754d8053
757] 
758[docs: update about.html, especially to have a non-broken link to quickstart.html, and also to comment out the broken links to "for Paranoids" and "for Corporates"
759zooko@zooko.com**20100619065124
760 Ignore-this: e292c7f51c337a84ebfeb366fbd24d6c
761] 
762[TAG allmydata-tahoe-1.7.0
763zooko@zooko.com**20100619052631
764 Ignore-this: d21e27afe6d85e2e3ba6a3292ba2be1
765] 
766Patch bundle hash:
76729fe9a0c6399795c94c07f81cb2771f0425bd895