Skip to content

Commit

Permalink
Merge pull request #623 from twisted/revert-621-8937-deprecated-filepath
Browse files Browse the repository at this point in the history
Revert "Remove deprecated parts of FilePath"

Reopens ticket:8937
  • Loading branch information
glyph committed Dec 9, 2016
2 parents 0384682 + 3f5e79b commit 6ec4521
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 7 deletions.
78 changes: 78 additions & 0 deletions src/twisted/python/filepath.py
Expand Up @@ -31,7 +31,9 @@
# modified for inclusion in the standard library. --glyph

from twisted.python.compat import comparable, cmp, unicode
from twisted.python.deprecate import deprecated
from twisted.python.runtime import platform
from incremental import Version

from twisted.python.win32 import ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND
from twisted.python.win32 import ERROR_INVALID_NAME, ERROR_DIRECTORY, O_BINARY
Expand Down Expand Up @@ -480,6 +482,28 @@ def __hash__(self):
return hash((self.__class__, self.path))


# pending deprecation in 8.0
def getmtime(self):
"""
Deprecated. Use getModificationTime instead.
"""
return int(self.getModificationTime())


def getatime(self):
"""
Deprecated. Use getAccessTime instead.
"""
return int(self.getAccessTime())


def getctime(self):
"""
Deprecated. Use getStatusChangeTime instead.
"""
return int(self.getStatusChangeTime())



class RWX(FancyEqMixin, object):
"""
Expand Down Expand Up @@ -575,6 +599,15 @@ def shorthand(self):
[x.shorthand() for x in (self.user, self.group, self.other)])


class _SpecialNoValue(object):
"""
An object that represents 'no value', to be used in deprecating statinfo.
Please remove once statinfo is removed.
"""
pass



def _asFilesystemBytes(path, encoding=None):
"""
Expand Down Expand Up @@ -676,6 +709,22 @@ class FilePath(AbstractFilePath):
@type path: L{bytes} or L{unicode}
@ivar path: The path from which 'downward' traversal is permitted.
@ivar statinfo: (WARNING: statinfo is deprecated as of Twisted 15.0.0 and
will become a private attribute)
The currently cached status information about the file on
the filesystem that this L{FilePath} points to. This attribute is
L{None} if the file is in an indeterminate state (either this
L{FilePath} has not yet had cause to call C{stat()} yet or
L{FilePath.changed} indicated that new information is required), 0 if
C{stat()} was called and returned an error (i.e. the path did not exist
when C{stat()} was called), or a C{stat_result} object that describes
the last known status of the underlying file (or directory, as the case
may be). Trust me when I tell you that you do not want to use this
attribute. Instead, use the methods on L{FilePath} which give you
information about it, like C{getsize()}, C{isdir()},
C{getModificationTime()}, and so on.
@type statinfo: L{int} or L{None} or L{os.stat_result}
"""
_statinfo = None
path = None
Expand Down Expand Up @@ -1687,4 +1736,33 @@ def moveTo(self, destination, followLinks=True):
destination.changed()


def statinfo(self, value=_SpecialNoValue):
"""
FilePath.statinfo is deprecated.
@param value: value to set statinfo to, if setting a value
@return: C{_statinfo} if getting, L{None} if setting
"""
# This is a pretty awful hack to use the deprecated decorator to
# deprecate a class attribute. Ideally, there would just be a
# statinfo property and a statinfo property setter, but the
# 'deprecated' decorator does not produce the correct FQDN on class
# methods. So the property stuff needs to be set outside the class
# definition - but the getter and setter both need the same function
# in order for the 'deprecated' decorator to produce the right
# deprecation string.
if value is _SpecialNoValue:
return self._statinfo
else:
self._statinfo = value


# This is all a terrible hack to get statinfo deprecated
_tmp = deprecated(
Version('Twisted', 15, 0, 0),
"other FilePath methods such as getsize(), "
"isdir(), getModificationTime(), etc.")(FilePath.statinfo)
FilePath.statinfo = property(_tmp, _tmp)


FilePath.clonePath = FilePath
71 changes: 67 additions & 4 deletions src/twisted/test/test_paths.py
Expand Up @@ -236,6 +236,17 @@ def test_newTimesAreFloats(self):
self.assertEqual(type(p.getStatusChangeTime()), float)


def test_oldTimesAreInts(self):
"""
Verify that all times returned from the various time functions are
integers, for compatibility.
"""
for p in self.path, self.path.child(b'file1'):
self.assertEqual(type(p.getatime()), int)
self.assertEqual(type(p.getmtime()), int)
self.assertEqual(type(p.getctime()), int)



class FakeWindowsPath(filepath.FilePath):
"""
Expand Down Expand Up @@ -805,9 +816,9 @@ def testStatCache(self):
p = self.path.child(b'stattest')
p.touch()
self.assertEqual(p.getsize(), 0)
self.assertEqual(abs(p.getModificationTime() - time.time()) // 20, 0)
self.assertEqual(abs(p.getStatusChangeTime() - time.time()) // 20, 0)
self.assertEqual(abs(p.getAccessTime() - time.time()) // 20, 0)
self.assertEqual(abs(p.getmtime() - time.time()) // 20, 0)
self.assertEqual(abs(p.getctime() - time.time()) // 20, 0)
self.assertEqual(abs(p.getatime() - time.time()) // 20, 0)
self.assertTrue(p.exists())
self.assertTrue(p.exists())
# OOB removal: FilePath.remove() will automatically restat
Expand Down Expand Up @@ -1442,7 +1453,7 @@ def test_changed(self):

# This path should look like we don't know what status it's in, not that
# we know that it didn't exist when last we checked.
self.assertIsNone(fp._statinfo)
self.assertIsNone(fp.statinfo)
self.assertEqual(fp.getsize(), 8)


Expand All @@ -1462,6 +1473,58 @@ def test_getPermissions_POSIX(self):
"rwxrw-r--")


def test_deprecateStatinfoGetter(self):
"""
Getting L{twisted.python.filepath.FilePath.statinfo} is deprecated.
"""
fp = filepath.FilePath(self.mktemp())
fp.statinfo
warningInfo = self.flushWarnings([self.test_deprecateStatinfoGetter])
self.assertEqual(len(warningInfo), 1)
self.assertEqual(warningInfo[0]['category'], DeprecationWarning)
self.assertEqual(
warningInfo[0]['message'],
"twisted.python.filepath.FilePath.statinfo was deprecated in "
"Twisted 15.0.0; please use other FilePath methods such as "
"getsize(), isdir(), getModificationTime(), etc. instead")


def test_deprecateStatinfoSetter(self):
"""
Setting L{twisted.python.filepath.FilePath.statinfo} is deprecated.
"""
fp = filepath.FilePath(self.mktemp())
fp.statinfo = None
warningInfo = self.flushWarnings([self.test_deprecateStatinfoSetter])
self.assertEqual(len(warningInfo), 1)
self.assertEqual(warningInfo[0]['category'], DeprecationWarning)
self.assertEqual(
warningInfo[0]['message'],
"twisted.python.filepath.FilePath.statinfo was deprecated in "
"Twisted 15.0.0; please use other FilePath methods such as "
"getsize(), isdir(), getModificationTime(), etc. instead")


def test_deprecateStatinfoSetterSets(self):
"""
Setting L{twisted.python.filepath.FilePath.statinfo} changes the value
of _statinfo such that getting statinfo again returns the new value.
"""
fp = filepath.FilePath(self.mktemp())
fp.statinfo = None
self.assertIsNone(fp.statinfo)


def test_filePathNotDeprecated(self):
"""
While accessing L{twisted.python.filepath.FilePath.statinfo} is
deprecated, the filepath itself is not.
"""
filepath.FilePath(self.mktemp())
warningInfo = self.flushWarnings([self.test_filePathNotDeprecated])
self.assertEqual(warningInfo, [])


def test_getPermissions_Windows(self):
"""
Getting permissions for a file returns a L{Permissions} object in
Expand Down
1 change: 0 additions & 1 deletion src/twisted/topfiles/8937.removal

This file was deleted.

3 changes: 1 addition & 2 deletions tox.ini
Expand Up @@ -77,7 +77,6 @@ setenv =
COVERAGE_FILE = {toxinidir}/.coverage
# Help tests know where the base directory is.
TOX_INI_DIR = {toxinidir}
PYTHON_OPTIONS = -Wdefault::DeprecationWarning

commands =
;
Expand All @@ -94,7 +93,7 @@ commands =
apidocs: pip install --no-deps epydoc pydoctor

; Run tests without wrapping them using coverage.
{nocov,nomodules,tests}: python {env:PYTHON_OPTIONS} -m twisted.trial --reactor={env:TWISTED_REACTOR:default} --reporter={env:TRIAL_REPORTER:verbose} {posargs:twisted}
{nocov,nomodules,tests}: python -m twisted.trial --reactor={env:TWISTED_REACTOR:default} --reporter={env:TRIAL_REPORTER:verbose} {posargs:twisted}

; Run the tests wrapped using coverage.
{withcov,coverage}: python {toxinidir}/admin/_copy.py {toxinidir}/admin/zz_coverage.pth {envsitepackagesdir}/zz_coverage.pth
Expand Down

0 comments on commit 6ec4521

Please sign in to comment.