Ticket #2366: twisted.python.filepath-2366-1.patch

File twisted.python.filepath-2366-1.patch, 52.6 KB (added by Harry Bock, 4 years ago)

first stab at a fix for both Python 2.6+/3.3+

  • twisted/test/test_paths.py

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
     
    88from __future__ import division, absolute_import
    99
    1010import os, time, pickle, errno, stat
     11import shutil
    1112import contextlib
    1213from pprint import pformat
    1314
     
    2021
    2122from zope.interface.verify import verifyObject
    2223
     24if _PY3 and platform.isWindows():
     25    import warnings
     26    warnings.filterwarnings("once", category=DeprecationWarning,
     27                            message="Windows bytes API")
    2328
    24 class BytesTestCase(TestCase):
    25     """
    26     Override default method implementations to support byte paths.
    27     """
    28     def mktemp(self):
    29         """
    30         Return a temporary path, encoded as bytes.
    31         """
    32         return TestCase.mktemp(self).encode("utf-8")
    33 
    34 
    35 
    36 class AbstractFilePathTestCase(BytesTestCase):
    37 
     29class AbstractFilePathTestCase(TestCase):
     30    # The contents of the files are actually binary, as they are opened "rb"
    3831    f1content = b"file 1"
    3932    f2content = b"file 2"
    4033
     
    5649    def setUp(self):
    5750        self.now = time.time()
    5851        cmn = self.cmn = os.path.abspath(self.mktemp())
     52
     53        if _PY3:
     54            _cmnUnicode = cmn
     55            _cmnBytes = _cmnUnicode.encode("utf-8")
     56        else:
     57            _cmnBytes = cmn
     58            _cmnUnicode = _cmnBytes.decode("utf-8")
     59
     60        self.assertIsUnicode(_cmnUnicode)
     61        self.assertIsBytes(_cmnBytes)
     62
     63        self.basePathUnicode = filepath.FilePath(_cmnUnicode)
     64        self.basePathBytes = filepath.FilePath(_cmnBytes)
     65
    5966        self.all = [cmn]
    6067        os.mkdir(cmn)
    61         self.subdir(b"sub1")
    62         f = self.subfile(b"file1")
     68        self.subdir("sub1")
     69        f = self.subfile("file1")
    6370        f.write(self.f1content)
    6471        f.close()
    65         f = self.subfile(b"sub1", b"file2")
     72        f = self.subfile("sub1", "file2")
    6673        f.write(self.f2content)
    6774        f.close()
    68         self.subdir(b'sub3')
    69         f = self.subfile(b"sub3", b"file3.ext1")
     75        self.subdir('sub3')
     76        f = self.subfile("sub3", "file3.ext1")
    7077        f.close()
    71         f = self.subfile(b"sub3", b"file3.ext2")
     78        f = self.subfile("sub3", "file3.ext2")
    7279        f.close()
    73         f = self.subfile(b"sub3", b"file3.ext3")
     80        f = self.subfile("sub3", "file3.ext3")
    7481        f.close()
    7582        self.path = filepath.FilePath(cmn)
    76         self.root = filepath.FilePath(b"/")
     83        self.root = filepath.FilePath("/")
    7784
     85        # Detect symlink support on Python 3.x + Windows -
     86        # os.symlink is available, but only if you have
     87        # administrative privileges.
     88        # If you do not have privleges, OSError with errno
     89        # set to None is raised.  Unfortunately there's not
     90        # a better way to do this detection AFAICT.
     91        if os.name == "nt" and hasattr(os, "symlink"):
     92            testSymlinkPathname = os.path.join(self.cmn, "___sym1")
     93            # Assume we can symlink until proven otherwise by making the syscall
     94            self.osCanSymlink = True
     95            try:
     96                os.symlink(os.path.join(self.cmn, "file1"), testSymlinkPathname)
     97            except OSError as err:
     98                if err.errno is None:
     99                    self.osCanSymlink = False
     100                # if we get a non-None errno, it's possible we could
     101                # symlink in general, but can't do it on the file we specified.
     102                # TODO what's the best way to detect this?
    78103
     104        else:
     105            self.osCanSymlink = hasattr(os, "symlink")
     106
     107    def tearDown(self):
     108        shutil.rmtree(self.cmn, ignore_errors=True)
     109
     110    def assertIsUnicode(self, string):
     111        """
     112        Assert that the input string is a unicode string.
     113        """
     114        unicodeType = str
     115        if not _PY3:
     116            unicodeType = unicode
     117        self.assertTrue(isinstance(string, unicodeType))
     118
     119    def assertIsBytes(self, string):
     120        """
     121        Assert that the input string is a byte string.
     122        """
     123        self.assertTrue(isinstance(string, bytes))
     124
     125    def test_unicodeParentIsUnicode(self):
     126        self.assertIsUnicode(self.basePathUnicode.parent().path)
     127
     128    def test_bytesParentIsBytes(self):
     129        self.assertIsBytes(self.basePathBytes.parent().path)
     130
     131    def test_inputStringTypeMatches(self):
     132        """
     133        Verify that the type of the path attribute on FilePath objects reflects the
     134        input type.
     135        """
     136        path = filepath.FilePath(u"test.txt")
     137        self.assertIsUnicode(path.path)
     138        self.assertEqual(path.path, os.path.abspath(u"test.txt"))
     139
     140        path = filepath.FilePath(b"test.txt")
     141        self.assertIsBytes(path.path)
     142        self.assertEqual(path.path, os.path.abspath(b"test.txt"))
     143
     144        # Once more, with feeling this time!
     145        path = filepath.FilePath(u"test_\u0ca0_\u0ca0.txt")
     146        self.assertIsUnicode(path.path)
     147        self.assertEqual(path.path, os.path.abspath(u"test_\u0ca0_\u0ca0.txt"))
     148
     149        # Non-ASCII encoding for good measure
     150        path = filepath.FilePath(b"test_\x0c\xa0_\x0c\xa0.txt")
     151        self.assertIsBytes(path.path)
     152        self.assertEqual(path.path, os.path.abspath(b"test_\x0c\xa0_\x0c\xa0.txt"))
     153
     154    def test_unicodePathnameListings(self):
     155        """
     156        Verify that FilePath.listdir returns paths as str/unicode when the FilePath instance
     157        is a unicode path, including when some files include non-ASCII code points.
     158        """
     159        path = self.basePathUnicode.child(u"unicode-test")
     160        path.makedirs()
     161        unicodePath1 = path.child(u"\u0ca0_\u0ca0.txt")
     162        unicodePath2 = path.child(u"98\u00b0.txt")
     163        unicodePath1.touch()
     164        unicodePath2.touch()
     165
     166        unicodeListing = path.listdir()
     167        self.assertEqual(len(unicodeListing), 2)
     168        self.assertIn(u"98\u00b0.txt", unicodeListing)
     169        self.assertIn(u"\u0ca0_\u0ca0.txt", unicodeListing)
     170
     171    def test_bytesPathnameListdir(self):
     172        """
     173        Verify that FilePath.listdir returns paths as bytes when the FilePath instance
     174        is a byte path, including when some files include non-ASCII characters.
     175        """
     176        path = self.basePathBytes.child(b"bytes-test")
     177        path.makedirs()
     178        bytesPath1 = path.child(b"\xfe\xff.txt")
     179        bytesPath2 = path.child(b"hello\xc0\x80.txt")
     180        bytesPath3 = path.child(b"helloworld.txt")
     181        bytesPath1.touch()
     182        bytesPath2.touch()
     183        bytesPath3.touch()
     184
     185        bytesListing = path.listdir()
     186        self.assertEqual(len(bytesListing), 3)
     187        self.assertIn(b"\xfe\xff.txt", bytesListing)
     188        self.assertIn(b"hello\xc0\x80.txt", bytesListing)
     189        self.assertIn(b"helloworld.txt", bytesListing)
     190
     191    def test_unicodeGlobChildren(self):
     192        """
     193        Verify that FilePath.globChildren functions correctly when the input
     194        is a unicode string.
     195        """
     196        sub3 = self.basePathUnicode.child(u"sub3")
     197        globbedChildren = sub3.globChildren(u"file3*")
     198        self.assertEqual(len(globbedChildren), 3)
     199        self.assertIn(sub3.child(u"file3.ext1"), globbedChildren)
     200        self.assertIn(sub3.child(u"file3.ext2"), globbedChildren)
     201        self.assertIn(sub3.child(u"file3.ext3"), globbedChildren)
     202
     203    def test_bytesGlobChildren(self):
     204        """
     205        Verify that FilePath.globChildren functions correctly when the input
     206        is a byte string.
     207        """
     208        sub3 = self.basePathBytes.child(b"sub3")
     209        globbedChildren = sub3.globChildren(b"file3*")
     210        self.assertEqual(len(globbedChildren), 3)
     211        self.assertIn(sub3.child(b"file3.ext1"), globbedChildren)
     212        self.assertIn(sub3.child(b"file3.ext2"), globbedChildren)
     213        self.assertIn(sub3.child(b"file3.ext3"), globbedChildren)
     214
     215    def test_setContentUnicodeFailure(self):
     216        """
     217        Verify that setContent fails with TypeError when unicode strings are
     218        passed as the content parameter, and that no file was created.
     219        """
     220        unicodeData = u"asdfjkl;"
     221        newPath = self.path.child("unicodeFailure.bin")
     222        self.assertRaises(TypeError, newPath.setContent, unicodeData)
     223        self.assertFalse(newPath.exists())
     224
    79225    def test_segmentsFromPositive(self):
    80226        """
    81227        Verify that the segments between two paths are correctly identified.
    82228        """
    83229        self.assertEqual(
    84             self.path.child(b"a").child(b"b").child(b"c").segmentsFrom(self.path),
    85             [b"a", b"b", b"c"])
     230            self.path.child("a").child("b").child("c").segmentsFrom(self.path),
     231            ["a", "b", "c"])
    86232
    87233    def test_segmentsFromNegative(self):
    88234        """
     
    90236        """
    91237        self.assertRaises(
    92238            ValueError,
    93             self.path.child(b"a").child(b"b").child(b"c").segmentsFrom,
    94                 self.path.child(b"d").child(b"c").child(b"e"))
     239            self.path.child("a").child("b").child("c").segmentsFrom,
     240                self.path.child("d").child("c").child("e"))
    95241
    96242
    97243    def test_walk(self):
     
    109255        the L{FilePath} in question.
    110256        """
    111257        L = []
    112         pathobj = self.path.child(b"a").child(b"b").child(b"c")
     258        pathobj = self.path.child("a").child("b").child("c")
    113259        fullpath = pathobj.path
    114260        lastpath = fullpath
    115261        thispath = os.path.dirname(fullpath)
     
    125271        Verify that a valid subdirectory will show up as a directory, but not as a
    126272        file, not as a symlink, and be listable.
    127273        """
    128         sub1 = self.path.child(b'sub1')
     274        sub1 = self.path.child('sub1')
    129275        self.failUnless(sub1.exists(),
    130276                        "This directory does exist.")
    131277        self.failUnless(sub1.isdir(),
     
    134280                        "It's a directory.")
    135281        self.failUnless(not sub1.islink(),
    136282                        "It's a directory.")
    137         self.assertEqual(sub1.listdir(),
    138                              [b'file2'])
     283        sub1_listing = sub1.listdir()
     284        self.assertEqual(sub1_listing,
     285                             ['file2'])
    139286
    140287
    141288    def test_invalidSubdir(self):
    142289        """
    143290        Verify that a subdirectory that doesn't exist is reported as such.
    144291        """
    145         sub2 = self.path.child(b'sub2')
     292        sub2 = self.path.child('sub2')
    146293        self.failIf(sub2.exists(),
    147294                    "This directory does not exist.")
    148295
     
    150297        """
    151298        Make sure that we can read existent non-empty files.
    152299        """
    153         f1 = self.path.child(b'file1')
     300        f1 = self.path.child('file1')
    154301        with contextlib.closing(f1.open()) as f:
    155302            self.assertEqual(f.read(), self.f1content)
    156         f2 = self.path.child(b'sub1').child(b'file2')
     303        f2 = self.path.child('sub1').child('file2')
    157304        with contextlib.closing(f2.open()) as f:
    158305            self.assertEqual(f.read(), self.f2content)
    159306
     
    163310        C{fp.descendant([a, b, c])} returns the same L{FilePath} as is returned
    164311        by C{fp.child(a).child(b).child(c)}.
    165312        """
    166         multiple = self.path.descendant([b'a', b'b', b'c'])
    167         single = self.path.child(b'a').child(b'b').child(b'c')
     313        multiple = self.path.descendant(['a', 'b', 'c'])
     314        single = self.path.child('a').child('b').child('c')
    168315        self.assertEqual(multiple, single)
    169316
    170317
     
    172319        """
    173320        Verify that path instances are usable as dictionary keys.
    174321        """
    175         f1 = self.path.child(b'file1')
    176         f1prime = self.path.child(b'file1')
    177         f2 = self.path.child(b'file2')
     322        f1 = self.path.child('file1')
     323        f1prime = self.path.child('file1')
     324        f2 = self.path.child('file2')
    178325        dictoid = {}
    179326        dictoid[f1] = 3
    180327        dictoid[f1prime] = 4
     
    192339        Verify that path instances are usable as dictionary keys which do not clash
    193340        with their string counterparts.
    194341        """
    195         f1 = self.path.child(b'file1')
     342        f1 = self.path.child('file1')
    196343        dictoid = {f1: 'hello'}
    197344        dictoid[f1.path] = 'goodbye'
    198345        self.assertEqual(len(dictoid), 2)
     
    204351        directories.
    205352        """
    206353        self.assertRaises(filepath.UnlistableError,
    207                           self.path.child(b'not real').children)
     354                          self.path.child('not real').children)
    208355
    209356    def test_childrenNotDirectoryError(self):
    210357        """
     
    212359        a file rather than a directory.
    213360        """
    214361        self.assertRaises(filepath.UnlistableError,
    215                           self.path.child(b'file1').children)
     362                          self.path.child('file1').children)
    216363
    217364
    218365    def test_newTimesAreFloats(self):
     
    220367        Verify that all times returned from the various new time functions are ints
    221368        (and hopefully therefore 'high precision').
    222369        """
    223         for p in self.path, self.path.child(b'file1'):
     370        for p in self.path, self.path.child('file1'):
    224371            self.assertEqual(type(p.getAccessTime()), float)
    225372            self.assertEqual(type(p.getModificationTime()), float)
    226373            self.assertEqual(type(p.getStatusChangeTime()), float)
     
    231378        Verify that all times returned from the various time functions are
    232379        integers, for compatibility.
    233380        """
    234         for p in self.path, self.path.child(b'file1'):
     381        for p in self.path, self.path.child('file1'):
    235382            self.assertEqual(type(p.getatime()), int)
    236383            self.assertEqual(type(p.getmtime()), int)
    237384            self.assertEqual(type(p.getctime()), int)
     
    253400
    254401
    255402
    256 class ListingCompatibilityTests(BytesTestCase):
     403class ListingCompatibilityTests(TestCase):
    257404    """
    258405    These tests verify compatibility with legacy behavior of directory listing.
    259406    """
    260407
    261     def test_windowsErrorExcept(self):
    262         """
    263         Verify that when a WindowsError is raised from listdir, catching
    264         WindowsError works.
    265         """
    266         fwp = FakeWindowsPath(self.mktemp())
    267         self.assertRaises(filepath.UnlistableError, fwp.children)
    268         self.assertRaises(WindowsError, fwp.children)
    269 
    270 
    271408    def test_alwaysCatchOSError(self):
    272409        """
    273410        Verify that in the normal case where a directory does not exist, we will
     
    422559
    423560
    424561
    425 class PermissionsTestCase(BytesTestCase):
     562class PermissionsTestCase(TestCase):
    426563    """
    427564    Test Permissions and RWX classes
    428565    """
     
    590727        basic modes that should work everywhere (even on Windows).
    591728        """
    592729        for mode in (0o555, 0o777):
    593             self.path.child(b"sub1").chmod(mode)
     730            self.path.child("sub1").chmod(mode)
    594731            self.assertEqual(
    595                 stat.S_IMODE(os.stat(self.path.child(b"sub1").path).st_mode),
     732                stat.S_IMODE(os.stat(self.path.child("sub1").path).st_mode),
    596733                mode)
    597734
    598735
     
    605742        @raise SkipTest: raised if symbolic links are not supported on the
    606743            host platform.
    607744        """
    608         if getattr(os, 'symlink', None) is None:
     745        if not hasattr(os, "symlink"):
    609746            raise SkipTest(
    610747                "Platform does not support symbolic links.")
    611         os.symlink(target, name)
     748        try:
     749            os.symlink(target, name)
     750        except OSError as exc:
     751            if os.name == "nt" and exc.errno is None: # win32 + python 3: see Python issue #9333
     752                raise SkipTest("User does not have permission to create symlinks")
    612753
    613754
    614755    def createLinks(self):
    615756        """
    616757        Create several symbolic links to files and directories.
    617758        """
    618         subdir = self.path.child(b"sub1")
    619         self.symlink(subdir.path, self._mkpath(b"sub1.link"))
    620         self.symlink(subdir.child(b"file2").path, self._mkpath(b"file2.link"))
    621         self.symlink(subdir.child(b"file2").path,
    622                      self._mkpath(b"sub1", b"sub1.file2.link"))
     759        subdir = self.path.child("sub1")
     760        self.symlink(subdir.path, self._mkpath("sub1.link"))
     761        self.symlink(subdir.child("file2").path, self._mkpath("file2.link"))
     762        self.symlink(subdir.child("file2").path,
     763                     self._mkpath("sub1", "sub1.file2.link"))
    623764
    624765
    625766    def test_realpathSymlink(self):
     
    628769        symlink.
    629770        """
    630771        self.createLinks()
    631         self.symlink(self.path.child(b"file2.link").path,
    632                      self.path.child(b"link.link").path)
    633         self.assertEqual(self.path.child(b"link.link").realpath(),
    634                           self.path.child(b"sub1").child(b"file2"))
     772        self.symlink(self.path.child("file2.link").path,
     773                     self.path.child("link.link").path)
     774        self.assertEqual(self.path.child("link.link").realpath(),
     775                          self.path.child("sub1").child("file2"))
    635776
    636777
    637778    def test_realpathCyclicalSymlink(self):
     
    639780        L{FilePath.realpath} raises L{filepath.LinkError} if the path is a
    640781        symbolic link which is part of a cycle.
    641782        """
    642         self.symlink(self.path.child(b"link1").path, self.path.child(b"link2").path)
    643         self.symlink(self.path.child(b"link2").path, self.path.child(b"link1").path)
     783        self.symlink(self.path.child("link1").path, self.path.child("link2").path)
     784        self.symlink(self.path.child("link2").path, self.path.child("link1").path)
    644785        self.assertRaises(filepath.LinkError,
    645                           self.path.child(b"link2").realpath)
     786                          self.path.child("link2").realpath)
    646787
    647788
    648789    def test_realpathNoSymlink(self):
     
    650791        L{FilePath.realpath} returns the path itself if the path is not a
    651792        symbolic link.
    652793        """
    653         self.assertEqual(self.path.child(b"sub1").realpath(),
    654                           self.path.child(b"sub1"))
     794        self.assertEqual(self.path.child("sub1").realpath(),
     795                          self.path.child("sub1"))
    655796
    656797
    657798    def test_walkCyclicalSymlink(self):
     
    659800        Verify that walking a path with a cyclical symlink raises an error
    660801        """
    661802        self.createLinks()
    662         self.symlink(self.path.child(b"sub1").path,
    663                      self.path.child(b"sub1").child(b"sub1.loopylink").path)
     803        self.symlink(self.path.child("sub1").path,
     804                     self.path.child("sub1").child("sub1.loopylink").path)
    664805        def iterateOverPath():
    665806            return [foo.path for foo in self.path.walk()]
    666807        self.assertRaises(filepath.LinkError, iterateOverPath)
     
    674815        """
    675816        self.createLinks()
    676817        # we create cyclical symlinks
    677         self.symlink(self.path.child(b"sub1").path,
    678                      self.path.child(b"sub1").child(b"sub1.loopylink").path)
     818        self.symlink(self.path.child("sub1").path,
     819                     self.path.child("sub1").child("sub1.loopylink").path)
    679820        def noSymLinks(path):
    680821            return not path.islink()
    681822        def iterateOverPath():
     
    697838
    698839    def test_getAndSet(self):
    699840        content = b'newcontent'
    700         self.path.child(b'new').setContent(content)
    701         newcontent = self.path.child(b'new').getContent()
     841        self.path.child('new').setContent(content)
     842        newcontent = self.path.child('new').getContent()
    702843        self.assertEqual(content, newcontent)
    703844        content = b'content'
    704         self.path.child(b'new').setContent(content, b'.tmp')
    705         newcontent = self.path.child(b'new').getContent()
     845        self.path.child('new').setContent(content, '.tmp')
     846        newcontent = self.path.child('new').getContent()
    706847        self.assertEqual(content, newcontent)
    707848
    708849
     
    711852        If reading from the underlying file raises an exception,
    712853        L{FilePath.getContent} raises that exception after closing the file.
    713854        """
    714         fp = ExplodingFilePath(b"")
     855        fp = ExplodingFilePath("")
    715856        self.assertRaises(IOError, fp.getContent)
    716857        self.assertTrue(fp.fp.closed)
    717858
     
    721862        If writing to the underlying file raises an exception,
    722863        L{FilePath.setContent} raises that exception after closing the file.
    723864        """
    724         fp = ExplodingFilePath(b"")
     865        fp = ExplodingFilePath("")
    725866        self.assertRaises(IOError, fp.setContent, b"blah")
    726867        self.assertTrue(fp.fp.closed)
    727868
     
    753894        fp.setContent(b"hello")
    754895        opened = fp.openedPaths()
    755896        self.assertEqual(len(opened), 1)
    756         self.assertTrue(opened[0].basename().endswith(b".new"),
     897        self.assertTrue(opened[0].basename().endswith(".new"),
    757898                        "%s does not end with default '.new' extension" % (
    758899                            opened[0].basename()))
    759         fp.setContent(b"goodbye", b"-something-else")
     900        fp.setContent(b"goodbye", "-something-else")
    760901        opened = fp.openedPaths()
    761902        self.assertEqual(len(opened), 2)
    762         self.assertTrue(opened[1].basename().endswith(b"-something-else"),
     903        self.assertTrue(opened[1].basename().endswith("-something-else"),
    763904                        "%s does not end with -something-else extension" % (
    764905                            opened[1].basename()))
    765906
     
    770911        non-links. Also check that the symbolic link shares the directory
    771912        property with its target.
    772913        """
    773         s4 = self.path.child(b"sub4")
    774         s3 = self.path.child(b"sub3")
     914        s4 = self.path.child("sub4")
     915        s3 = self.path.child("sub3")
    775916        self.symlink(s3.path, s4.path)
    776917        self.assertTrue(s4.islink())
    777918        self.assertFalse(s3.islink())
     
    786927        directory.
    787928        """
    788929        targetLinks = [
    789             (self.path.child(b"sub2"), self.path.child(b"sub2.link")),
    790             (self.path.child(b"sub2").child(b"file3.ext1"),
    791              self.path.child(b"file3.ext1.link"))
     930            (self.path.child("sub2"), self.path.child("sub2.link")),
     931            (self.path.child("sub2").child("file3.ext1"),
     932             self.path.child("file3.ext1.link"))
    792933            ]
    793934        for target, link in targetLinks:
    794             target.linkTo(link)
     935            try:
     936                target.linkTo(link)
     937            except OSError as exc:
     938                if os.name == "nt" and exc.errno is None: # win32 + python 3: see Python issue #9333
     939                    raise SkipTest("User does not have permission to create symlinks")
     940
    795941            self.assertTrue(link.islink(), "This is a link")
    796942            self.assertEqual(target.isdir(), link.isdir())
    797943            self.assertEqual(target.isfile(), link.isfile())
     
    803949            - the target is in a directory that doesn't exist
    804950            - the target already exists
    805951        """
    806         self.assertRaises(OSError, self.path.child(b"file1").linkTo,
    807                           self.path.child(b'nosub').child(b'file1'))
    808         self.assertRaises(OSError, self.path.child(b"file1").linkTo,
    809                           self.path.child(b'sub1').child(b'file2'))
     952        self.assertRaises(OSError, self.path.child("file1").linkTo,
     953                          self.path.child('nosu').child('file1'))
     954        self.assertRaises(OSError, self.path.child("file1").linkTo,
     955                          self.path.child('sub1').child('file2'))
    810956
    811957
    812958    if not getattr(os, "symlink", None):
     
    817963
    818964
    819965    def testMultiExt(self):
    820         f3 = self.path.child(b'sub3').child(b'file3')
    821         exts = b'.foo', b'.bar', b'ext1', b'ext2', b'ext3'
     966        f3 = self.path.child('sub3').child('file3')
     967        exts = '.foo', '.bar', 'ext1', 'ext2', 'ext3'
    822968        self.failIf(f3.siblingExtensionSearch(*exts))
    823         f3e = f3.siblingExtension(b".foo")
     969        f3e = f3.siblingExtension(".foo")
    824970        f3e.touch()
    825971        self.failIf(not f3.siblingExtensionSearch(*exts).exists())
    826         self.failIf(not f3.siblingExtensionSearch(b'*').exists())
     972        self.failIf(not f3.siblingExtensionSearch('*').exists())
    827973        f3e.remove()
    828974        self.failIf(f3.siblingExtensionSearch(*exts))
    829975
    830976    def testPreauthChild(self):
    831         fp = filepath.FilePath(b'.')
    832         fp.preauthChild(b'foo/bar')
    833         self.assertRaises(filepath.InsecurePath, fp.child, b'/foo')
     977        fp = filepath.FilePath('.')
     978        fp.preauthChild('foo/bar')
     979        self.assertRaises(filepath.InsecurePath, fp.child, '/foo')
    834980
    835981    def testStatCache(self):
    836         p = self.path.child(b'stattest')
     982        p = self.path.child('stattest')
    837983        p.touch()
    838984        self.assertEqual(p.getsize(), 0)
    839985        self.assertEqual(abs(p.getmtime() - time.time()) // 20, 0)
     
    8571003        self.assertEqual(self.path.path, newpath.path)
    8581004
    8591005    def testInsecureUNIX(self):
    860         self.assertRaises(filepath.InsecurePath, self.path.child, b"..")
    861         self.assertRaises(filepath.InsecurePath, self.path.child, b"/etc")
    862         self.assertRaises(filepath.InsecurePath, self.path.child, b"../..")
     1006        self.assertRaises(filepath.InsecurePath, self.path.child, "..")
     1007        self.assertRaises(filepath.InsecurePath, self.path.child, "/etc")
     1008        self.assertRaises(filepath.InsecurePath, self.path.child, "../..")
    8631009
    8641010    def testInsecureWin32(self):
    865         self.assertRaises(filepath.InsecurePath, self.path.child, b"..\\..")
    866         self.assertRaises(filepath.InsecurePath, self.path.child, b"C:randomfile")
     1011        self.assertRaises(filepath.InsecurePath, self.path.child, "..\\..")
     1012        self.assertRaises(filepath.InsecurePath, self.path.child, "C:randomfile")
    8671013
    8681014    if platform.getType() != 'win32':
    8691015        testInsecureWin32.skip = "Test will run only on Windows."
     
    8761022        the filesystem.  For obvious reasons, we do not wish to normally permit
    8771023        access to these.
    8781024        """
    879         self.assertRaises(filepath.InsecurePath, self.path.child, b"CON")
    880         self.assertRaises(filepath.InsecurePath, self.path.child, b"C:CON")
     1025        self.assertRaises(filepath.InsecurePath, self.path.child, "CON")
     1026        self.assertRaises(filepath.InsecurePath, self.path.child, "C:CON")
    8811027        self.assertRaises(filepath.InsecurePath, self.path.child, r"C:\CON")
    8821028
    8831029    if platform.getType() != 'win32':
     
    8851031
    8861032
    8871033    def testComparison(self):
    888         self.assertEqual(filepath.FilePath(b'a'),
    889                           filepath.FilePath(b'a'))
    890         self.failUnless(filepath.FilePath(b'z') >
    891                         filepath.FilePath(b'a'))
    892         self.failUnless(filepath.FilePath(b'z') >=
    893                         filepath.FilePath(b'a'))
    894         self.failUnless(filepath.FilePath(b'a') >=
    895                         filepath.FilePath(b'a'))
    896         self.failUnless(filepath.FilePath(b'a') <=
    897                         filepath.FilePath(b'a'))
    898         self.failUnless(filepath.FilePath(b'a') <
    899                         filepath.FilePath(b'z'))
    900         self.failUnless(filepath.FilePath(b'a') <=
    901                         filepath.FilePath(b'z'))
    902         self.failUnless(filepath.FilePath(b'a') !=
    903                         filepath.FilePath(b'z'))
    904         self.failUnless(filepath.FilePath(b'z') !=
    905                         filepath.FilePath(b'a'))
     1034        self.assertEqual(filepath.FilePath('a'),
     1035                          filepath.FilePath('a'))
     1036        self.failUnless(filepath.FilePath('z') >
     1037                        filepath.FilePath('a'))
     1038        self.failUnless(filepath.FilePath('z') >=
     1039                        filepath.FilePath('a'))
     1040        self.failUnless(filepath.FilePath('a') >=
     1041                        filepath.FilePath('a'))
     1042        self.failUnless(filepath.FilePath('a') <=
     1043                        filepath.FilePath('a'))
     1044        self.failUnless(filepath.FilePath('a') <
     1045                        filepath.FilePath('z'))
     1046        self.failUnless(filepath.FilePath('a') <=
     1047                        filepath.FilePath('z'))
     1048        self.failUnless(filepath.FilePath('a') !=
     1049                        filepath.FilePath('z'))
     1050        self.failUnless(filepath.FilePath('z') !=
     1051                        filepath.FilePath('a'))
    9061052
    907         self.failIf(filepath.FilePath(b'z') !=
    908                     filepath.FilePath(b'z'))
     1053        self.failIf(filepath.FilePath('z') !=
     1054                    filepath.FilePath('z'))
    9091055
    9101056
    9111057    def test_descendantOnly(self):
     
    9141060        L{InsecurePath} is raised.
    9151061        """
    9161062        self.assertRaises(
    917             filepath.InsecurePath, self.path.descendant, [b'a', b'..'])
     1063            filepath.InsecurePath, self.path.descendant, ['a', '..'])
    9181064
    9191065
    9201066    def testSibling(self):
    921         p = self.path.child(b'sibling_start')
    922         ts = p.sibling(b'sibling_test')
     1067        p = self.path.child('sibling_start')
     1068        ts = p.sibling('sibling_test')
    9231069        self.assertEqual(ts.dirname(), p.dirname())
    924         self.assertEqual(ts.basename(), b'sibling_test')
     1070        self.assertEqual(ts.basename(), 'sibling_test')
    9251071        ts.createDirectory()
    9261072        self.assertIn(ts, self.path.children())
    9271073
     
    9381084        If L{FilePath.temporarySibling} is given an extension argument, it will
    9391085        produce path objects with that extension appended to their names.
    9401086        """
    941         testExtension = b".test-extension"
     1087        testExtension = ".test-extension"
    9421088        ts = self.path.temporarySibling(testExtension)
    9431089        self.assertTrue(ts.basename().endswith(testExtension),
    9441090                        "%s does not end with %s" % (
     
    9591105        For a path which is a symbolic link, L{FilePath.remove} just deletes
    9601106        the link, not the target.
    9611107        """
    962         link = self.path.child(b"sub1.link")
     1108        link = self.path.child("sub1.link")
    9631109        # setUp creates the sub1 child
    964         self.symlink(self.path.child(b"sub1").path, link.path)
     1110        self.symlink(self.path.child("sub1").path, link.path)
    9651111        link.remove()
    9661112        self.assertFalse(link.exists())
    967         self.assertTrue(self.path.child(b"sub1").exists())
     1113        self.assertTrue(self.path.child("sub1").exists())
    9681114
    9691115
    9701116    def test_copyToDirectory(self):
     
    9891135        source file to read from, the destination file is closed and the
    9901136        exception is raised to the caller of L{FilePath.copyTo}.
    9911137        """
    992         nosuch = self.path.child(b"nothere")
     1138        nosuch = self.path.child("nothere")
    9931139        # Make it look like something to copy, even though it doesn't exist.
    9941140        # This could happen if the file is deleted between the isfile check and
    9951141        # the file actually being opened.
     
    10231169        attempting to copy a directory to a child of itself.
    10241170        """
    10251171        self.assertRaises((OSError, IOError),
    1026                           self.path.copyTo, self.path.child(b'file1'))
     1172                          self.path.copyTo, self.path.child('file1'))
    10271173
    10281174
    10291175    def test_copyToWithSymlink(self):
     
    10311177        Verify that copying with followLinks=True copies symlink targets
    10321178        instead of symlinks
    10331179        """
    1034         self.symlink(self.path.child(b"sub1").path,
    1035                      self.path.child(b"link1").path)
     1180        self.symlink(self.path.child("sub1").path,
     1181                     self.path.child("link1").path)
    10361182        fp = filepath.FilePath(self.mktemp())
    10371183        self.path.copyTo(fp)
    1038         self.assertFalse(fp.child(b"link1").islink())
    1039         self.assertEqual([x.basename() for x in fp.child(b"sub1").children()],
    1040                           [x.basename() for x in fp.child(b"link1").children()])
     1184        self.assertFalse(fp.child("link1").islink())
     1185        self.assertEqual([x.basename() for x in fp.child("sub1").children()],
     1186                          [x.basename() for x in fp.child("link1").children()])
    10411187
    10421188
    10431189    def test_copyToWithoutSymlink(self):
    10441190        """
    10451191        Verify that copying with followLinks=False copies symlinks as symlinks
    10461192        """
    1047         self.symlink(b"sub1", self.path.child(b"link1").path)
     1193        self.symlink("sub1", self.path.child("link1").path)
    10481194        fp = filepath.FilePath(self.mktemp())
    10491195        self.path.copyTo(fp, followLinks=False)
    1050         self.assertTrue(fp.child(b"link1").islink())
    1051         self.assertEqual(os.readlink(self.path.child(b"link1").path),
    1052                           os.readlink(fp.child(b"link1").path))
     1196        self.assertTrue(fp.child("link1").islink())
     1197        self.assertEqual(os.readlink(self.path.child("link1").path),
     1198                          os.readlink(fp.child("link1").path))
    10531199
    10541200
    10551201    def test_copyToMissingSource(self):
     
    11521298        IOError if you want to move a path into one of its child. It's simply
    11531299        the error raised by the underlying rename system call.
    11541300        """
    1155         self.assertRaises((OSError, IOError), self.path.moveTo, self.path.child(b'file1'))
     1301        self.assertRaises((OSError, IOError), self.path.moveTo, self.path.child('file1'))
    11561302
    11571303
    11581304    def setUpFaultyRename(self):
     
    11981344        actually copy the content of the linked node.
    11991345        """
    12001346        invokedWith = self.setUpFaultyRename()
    1201         f2 = self.path.child(b'file2')
    1202         f3 = self.path.child(b'file3')
    1203         self.symlink(self.path.child(b'file1').path, f2.path)
     1347        f2 = self.path.child('file2')
     1348        f3 = self.path.child('file3')
     1349        self.symlink(self.path.child('file1').path, f2.path)
    12041350        f2.moveTo(f3)
    12051351        self.assertFalse(f3.islink())
    1206         self.assertEqual(f3.getContent(), b'file 1')
     1352        self.assertEqual(f3.getContent(), 'file 1')
    12071353        self.assertTrue(invokedWith)
    12081354
    12091355
     
    12131359        another symlink.
    12141360        """
    12151361        invokedWith = self.setUpFaultyRename()
    1216         f2 = self.path.child(b'file2')
    1217         f3 = self.path.child(b'file3')
    1218         self.symlink(self.path.child(b'file1').path, f2.path)
     1362        f2 = self.path.child('file2')
     1363        f3 = self.path.child('file3')
     1364        self.symlink(self.path.child('file1').path, f2.path)
    12191365        f2.moveTo(f3, followLinks=False)
    12201366        self.assertTrue(f3.islink())
    12211367        self.assertEqual(f3.getContent(), b'file 1')
     
    12331379        """
    12341380        path = filepath.FilePath(self.mktemp())
    12351381        f = path.create()
    1236         self.failUnless("b" in f.mode)
     1382        self.failUnless("" in f.mode)
    12371383        f.write(b"\n")
    12381384        f.close()
    1239         read = open(path.path, "rb").read()
    1240         self.assertEqual(read, b"\n")
     1385        with open(path.path, "rb") as f:
     1386            read = f.read()
     1387            self.assertEqual(read, b"\n")
    12411388
    12421389
    12431390    def testOpen(self):
    12441391        # Opening a file for reading when it does not already exist is an error
    1245         nonexistent = self.path.child(b'nonexistent')
     1392        nonexistent = self.path.child('nonexistent')
    12461393        e = self.assertRaises(IOError, nonexistent.open)
    12471394        self.assertEqual(e.errno, errno.ENOENT)
    12481395
    12491396        # Opening a file for writing when it does not exist is okay
    1250         writer = self.path.child(b'writer')
     1397        writer = self.path.child('writer')
    12511398        f = writer.open('w')
    12521399        f.write(b'abc\ndef')
    12531400        f.close()
     
    12671414
    12681415        # Put some bytes in a file so we can test that appending does not
    12691416        # destroy them.
    1270         appender = self.path.child(b'appender')
     1417        appender = self.path.child('appender')
    12711418        f = appender.open('w')
    12721419        f.write(b'abc')
    12731420        f.close()
     
    13381485
    13391486        See http://bugs.python.org/issue7686 for details about the bug.
    13401487        """
    1341         writer = self.path.child(b'explicit-binary')
     1488        writer = self.path.child('explicit-binary')
    13421489        file = writer.open('wb')
    13431490        file.write(b'abc\ndef')
    13441491        file.close()
     
    13551502
    13561503        See http://bugs.python.org/issue7686 for details about the bug.
    13571504        """
    1358         writer = self.path.child(b'multiple-binary')
     1505        writer = self.path.child('multiple-binary')
    13591506        file = writer.open('wbb')
    13601507        file.write(b'abc\ndef')
    13611508        file.close()
     
    14071554        """
    14081555        for mode in (0o777, 0o700):
    14091556            self.path.child(b"sub1").chmod(mode)
    1410             self.assertEqual(self.path.child(b"sub1").getPermissions(),
     1557            self.assertEqual(self.path.child("sub1").getPermissions(),
    14111558                              filepath.Permissions(mode))
    1412         self.path.child(b"sub1").chmod(0o764) #sanity check
    1413         self.assertEqual(self.path.child(b"sub1").getPermissions().shorthand(),
     1559        self.path.child("sub1").chmod(0o764) #sanity check
     1560        self.assertEqual(self.path.child("sub1").getPermissions().shorthand(),
    14141561                          "rwxrw-r--")
    14151562
    14161563
     
    14231570        bit.
    14241571        """
    14251572        # Change permission after test so file can be deleted
    1426         self.addCleanup(self.path.child(b"sub1").chmod, 0o777)
     1573        self.addCleanup(self.path.child("sub1").chmod, 0o777)
    14271574
    14281575        for mode in (0o777, 0o555):
    1429             self.path.child(b"sub1").chmod(mode)
    1430             self.assertEqual(self.path.child(b"sub1").getPermissions(),
     1576            self.path.child("sub1").chmod(mode)
     1577            self.assertEqual(self.path.child("sub1").getPermissions(),
    14311578                              filepath.Permissions(mode))
    1432         self.path.child(b"sub1").chmod(0o511) #sanity check to make sure that
     1579        self.path.child("sub1").chmod(0o511) #sanity check to make sure that
    14331580        # user=group=other permissions
    1434         self.assertEqual(self.path.child(b"sub1").getPermissions().shorthand(),
     1581        self.assertEqual(self.path.child("sub1").getPermissions().shorthand(),
    14351582                          "r-xr-xr-x")
    14361583
    14371584
     
    14631610            numbers = int
    14641611        else:
    14651612            numbers = (int, long)
    1466         c = self.path.child(b'file1')
     1613        c = self.path.child('file1')
    14671614        for p in self.path, c:
    14681615            self.assertIsInstance(p.getInodeNumber(), numbers)
    14691616            self.assertIsInstance(p.getDevice(), numbers)
  • twisted/python/filepath.py

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
     
    3030# things import this module, and it would be good if it could easily be
    3131# modified for inclusion in the standard library.  --glyph
    3232
    33 from twisted.python.compat import comparable, cmp
     33from twisted.python.compat import comparable, cmp, _PY3
    3434from twisted.python.runtime import platform
    35 
    36 from twisted.python.win32 import ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND
    37 from twisted.python.win32 import ERROR_INVALID_NAME, ERROR_DIRECTORY, O_BINARY
    3835from twisted.python.win32 import WindowsError
    39 
    4036from twisted.python.util import FancyEqMixin
    4137
    4238
    4339_CREATE_FLAGS = (os.O_EXCL |
    4440                 os.O_CREAT |
    4541                 os.O_RDWR |
    46                  O_BINARY)
     42                 os.O_BINARY)
    4743
    4844
    4945def _stub_islink(path):
     
    203199        """
    204200        A file path for the directory containing the file at this file path.
    205201
    206         @param name: the name of a sibling of this path. C{name} must be a direct
    207             sibling of this path and may not contain a path separator.
     202        @param name: the name of a sibling of this path. C{name} must be a
     203            direct sibling of this path and may not contain a path separator.
    208204
    209205        @return: a sibling file path of this one.
    210206        """
     
    259255
    260256
    261257
    262 def _secureEnoughString():
     258def _secureEnoughBytes():
    263259    """
    264260    Compute a string usable as a new, temporary filename.
    265261
     
    324320        """
    325321        try:
    326322            subnames = self.listdir()
    327         except WindowsError as winErrObj:
    328             # WindowsError is an OSError subclass, so if not for this clause
    329             # the OSError clause below would be handling these.  Windows error
    330             # codes aren't the same as POSIX error codes, so we need to handle
    331             # them differently.
    332323
    333             # Under Python 2.5 on Windows, WindowsError has a winerror
    334             # attribute and an errno attribute.  The winerror attribute is
    335             # bound to the Windows error code while the errno attribute is
    336             # bound to a translation of that code to a perhaps equivalent POSIX
    337             # error number.
    338 
    339             # Under Python 2.4 on Windows, WindowsError only has an errno
    340             # attribute.  It is bound to the Windows error code.
    341 
    342             # For simplicity of code and to keep the number of paths through
    343             # this suite minimal, we grab the Windows error code under either
    344             # version.
    345 
    346             # Furthermore, attempting to use os.listdir on a non-existent path
    347             # in Python 2.4 will result in a Windows error code of
    348             # ERROR_PATH_NOT_FOUND.  However, in Python 2.5,
    349             # ERROR_FILE_NOT_FOUND results instead. -exarkun
    350             winerror = getattr(winErrObj, 'winerror', winErrObj.errno)
    351             if winerror not in (ERROR_PATH_NOT_FOUND,
    352                                 ERROR_FILE_NOT_FOUND,
    353                                 ERROR_INVALID_NAME,
    354                                 ERROR_DIRECTORY):
    355                 raise
    356             raise _WindowsUnlistableError(winErrObj)
    357324        except OSError as ose:
    358             if ose.errno not in (errno.ENOENT, errno.ENOTDIR):
     325            # Fun fact: Python 2.6-3.2 maps Windows ERROR_DIRECTORY (267) to
     326            # EINVAL, but 3.3 more "correctly" maps it to ENOTDIR.
     327            # Handle EINVAL to catch older Python versions.
     328            if ose.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
    359329                # Other possible errors here, according to linux manpages:
    360330                # EACCES, EMIFLE, ENFILE, ENOMEM.  None of these seem like the
    361331                # sort of thing which should be handled normally. -glyph
    362332                raise
    363333            raise UnlistableError(ose)
    364         return map(self.child, subnames)
    365334
     335        return [self.child(subname) for subname in subnames]
     336
    366337    def walk(self, descend=None):
    367338        """
    368339        Yield myself, then each of my children, and each of those children's
     
    456427            return segments
    457428        raise ValueError("%r not parent of %r" % (ancestor, self))
    458429
     430    def __eq__(self, other):
     431        """
     432        Test whether we refer to the same path as twisanother L{FilePath} instance.
    459433
     434        @param other: The L{FilePath} instance we are comparing against.
     435        @type other: L{FilePath}
     436        """
     437        return self.path == other.path
     438
    460439    # new in 8.0
    461440    def __hash__(self):
    462441        """
     
    609588    Greater-than-second precision is only available in Windows on Python2.5 and
    610589    later.
    611590
    612     On both Python 2 and Python 3, paths can only be bytes.
     591    On both Python 2 and Python 3, paths can be either bytes or unicode
     592    (str on Python 3).  Depending on the string type for which the path
     593    was created, all subsequent operations involving strings must use
     594    and will return that type.
    613595
    614596    @type alwaysCreate: L{bool}
    615597    @ivar alwaysCreate: When opening this file, only succeed if the file does
    616598        not already exist.
    617599
    618     @type path: L{bytes}
     600    @type path: L{str or bytes}
    619601    @ivar path: The path from which 'downward' traversal is permitted.
    620602
    621603    @ivar statinfo: The currently cached status information about the file on
     
    636618    statinfo = None
    637619    path = None
    638620
    639     sep = slash.encode("ascii")
    640 
    641621    def __init__(self, path, alwaysCreate=False):
    642622        """
    643623        Convert a path string to an absolute path if necessary and initialize
    644624        the L{FilePath} with the result.
    645625        """
     626        # Keep track of whether we are str or bytes internally.
     627        # We use several internal constants that must be of the same
     628        # type as self.path, or Python will be quite angry.
     629        if _PY3:
     630            self._unicode = isinstance(path, str)
     631            self.sep = slash if self._unicode else slash.encode("ascii")
     632        else:
     633            self._unicode = isinstance(path, unicode)
     634            self.sep = slash.decode("ascii") if self._unicode else slash
     635
     636        self._colon    = self._getMatchedStringType(u":")
     637        self._globChar = self._getMatchedStringType(u"*")
     638        self._extSep   = self._getMatchedStringType(u".")
     639
    646640        self.path = abspath(path)
    647641        self.alwaysCreate = alwaysCreate
    648642
     643    def _getMatchedStringType(self, string):
     644        """
     645        @param string:
     646        @type string: L{str or unicode}
     647        """
     648        if self._unicode:
     649            return string
     650        else:
     651            return string.encode("ascii")
     652
    649653    def __getstate__(self):
    650654        """
    651655        Support serialization by discarding cached L{os.stat} results and
     
    664668
    665669        @param path: The base name of the new L{FilePath}.  If this contains
    666670            directory separators or parent references it will be rejected.
    667         @type path: L{bytes}
     671        @type path: L{str or bytes}
    668672
    669673        @raise InsecurePath: If the result of combining this path with C{path}
    670674            would result in a path which is not a direct child of this path.
     
    672676        @return: The child path.
    673677        @rtype: L{FilePath}
    674678        """
    675         if platform.isWindows() and path.count(b":"):
     679        if platform.isWindows() and path.count(self._colon):
    676680            # Catch paths like C:blah that don't have a slash
    677681            raise InsecurePath("%r contains a colon." % (path,))
    678682        norm = normpath(path)
    679683        if self.sep in norm:
    680             raise InsecurePath("%r contains one or more directory separators" % (path,))
     684            raise InsecurePath("%r contains one or more directory "
     685                               "separators" % (path,))
    681686        newpath = abspath(joinpath(self.path, norm))
    682687        if not newpath.startswith(self.path):
    683688            raise InsecurePath("%r is not a child of %s" % (newpath, self.path))
     
    690695
    691696        @param path: A relative path (ie, a path not starting with C{"/"}) which
    692697            will be interpreted as a child or descendant of this path.
    693         @type path: L{bytes}
     698        @type path: L{str or bytes}
    694699
    695700        @return: The child path.
    696701        @rtype: L{FilePath}
     
    738743        for ext in exts:
    739744            if not ext and self.exists():
    740745                return self
    741             if ext == b'*':
    742                 basedot = basename(p) + b'.'
    743                 for fn in listdir(dirname(p)):
     746            if ext == self._globChar:
     747                basedot = basename(p) + self._extSep
     748                for fn in self.parent().listdir():
    744749                    if fn.startswith(basedot):
    745750                        return self.clonePath(joinpath(dirname(p), fn))
    746751            p2 = p + ext
     
    831836
    832837    def restat(self, reraise=True):
    833838        """
    834         Re-calculate cached effects of 'stat'.  To refresh information on this path
    835         after you know the filesystem may have changed, call this method.
     839        Re-calculate cached effects of 'stat'.  To refresh information on this
     840        path after you know the filesystem may have changed, call this method.
    836841
    837842        @param reraise: a boolean.  If true, re-raise exceptions from
    838843            L{os.stat}; otherwise, mark this path as not existing, and remove
     
    11691174        """
    11701175        List the base names of the direct children of this L{FilePath}.
    11711176
    1172         @return: A L{list} of L{bytes} giving the names of the contents of the
    1173             directory this L{FilePath} refers to.  These names are relative to
    1174             this L{FilePath}.
     1177        @return: A L{list} of L{str or bytes} giving the names of the contents
     1178            of the directory this L{FilePath} refers to.  These names are
     1179            relative to this L{FilePath}.
    11751180        @rtype: L{list}
    11761181
    11771182        @raise: Anything the platform L{os.listdir} implementation might raise
     
    12431248        representing my children that match the given pattern.
    12441249
    12451250        @param pattern: A glob pattern to use to match child paths.
    1246         @type pattern: L{bytes}
     1251        @type pattern: L{str or bytes}
    12471252
    12481253        @return: A L{list} of matching children.
    12491254        @rtype: L{list}
    12501255        """
    12511256        import glob
    1252         path = self.path[-1] == b'/' and self.path + pattern or self.sep.join(
    1253             [self.path, pattern])
    1254         return map(self.clonePath, glob.glob(path))
     1257        path = self.path[-1] == self.sep and self.path + pattern or \
     1258               self.sep.join([self.path, pattern])
     1259        return [self.clonePath(globbed_path)
     1260                for globbed_path in glob.glob(path)]
    12551261
    12561262
    12571263    def basename(self):
     
    12611267
    12621268        @return: The final component of the L{FilePath}'s path (Everything
    12631269            after the final path separator).
    1264         @rtype: L{bytes}
     1270        @rtype: L{str or bytes}
    12651271        """
    12661272        return basename(self.path)
    12671273
     
    12731279
    12741280        @return: All of the components of the L{FilePath}'s path except the
    12751281            last one (everything up to the final path separator).
    1276         @rtype: L{bytes}
     1282        @rtype: L{str or bytes}
    12771283        """
    12781284        return dirname(self.path)
    12791285
     
    12891295        return self.clonePath(self.dirname())
    12901296
    12911297
    1292     def setContent(self, content, ext=b'.new'):
     1298    def setContent(self, content, ext=None):
    12931299        """
    12941300        Replace the file at this path with a new file that contains the given
    12951301        bytes, trying to avoid data-loss in the meanwhile.
     
    13311337        @param ext: An extension to append to the temporary filename used to
    13321338            store the bytes while they are being written.  This can be used to
    13331339            make sure that temporary files can be identified by their suffix,
    1334             for cleanup in case of crashes.
     1340            for cleanup in case of crashes. If it is C{None}, the default
     1341            extension is ".new".
    13351342
    1336         @type ext: L{bytes}
     1343        @type ext: L{str or bytes}
    13371344        """
     1345        if not isinstance(content, bytes):
     1346            raise TypeError("New file contents must be bytes.")
     1347
     1348        # Get the default extension in the correct string type
     1349        if ext is None:
     1350            ext = self._getMatchedStringType(".new")
     1351
    13381352        sib = self.temporarySibling(ext)
    13391353        f = sib.open('w')
    13401354        try:
     
    13911405        return os.fdopen(fdint, 'w+b')
    13921406
    13931407
    1394     def temporarySibling(self, extension=b""):
     1408    def temporarySibling(self, extension=None):
    13951409        """
    13961410        Construct a path referring to a sibling of this path.
    13971411
     
    14041418            that if you want an extension with a '.' you must include the '.'
    14051419            yourself.)
    14061420
    1407         @type extension: L{bytes}
     1421        @type extension: L{str or bytes}
    14081422
    14091423        @return: a path object with the given extension suffix, C{alwaysCreate}
    14101424            set to True.
    14111425
    14121426        @rtype: L{FilePath}
    14131427        """
    1414         sib = self.sibling(_secureEnoughString() + self.basename() + extension)
     1428        tempBytes = _secureEnoughBytes()
     1429        # Ensure the type of temporary string generated matches the input path.
     1430        if self._unicode:
     1431            tempBytes = tempBytes.decode("ascii")
     1432        if extension is None:
     1433            extension = self._getMatchedStringType("")
     1434
     1435        sib = self.sibling(tempBytes + self.basename() + extension)
    14151436        sib.requireCreate()
    14161437        return sib
    14171438
  • twisted/topfiles/2366.bugfix

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
     
     1twisted.python.filepath now fully supports Unicode pathnames and Python 3 on Windows.
     2 No newline at end of file