mirror of
https://github.com/facebook/sapling.git
synced 2024-10-09 16:31:02 +03:00
f1c575a099
Summary: This check is useful and detects real errors (ex. fbconduit). Unfortunately `arc lint` will run it with both py2 and py3 so a lot of py2 builtins will still be warned. I didn't find a clean way to disable py3 check. So this diff tries to fix them. For `xrange`, the change was done by a script: ``` import sys import redbaron headertypes = {'comment', 'endl', 'from_import', 'import', 'string', 'assignment', 'atomtrailers'} xrangefix = '''try: xrange(0) except NameError: xrange = range ''' def isxrange(x): try: return x[0].value == 'xrange' except Exception: return False def main(argv): for i, path in enumerate(argv): print('(%d/%d) scanning %s' % (i + 1, len(argv), path)) content = open(path).read() try: red = redbaron.RedBaron(content) except Exception: print(' warning: failed to parse') continue hasxrange = red.find('atomtrailersnode', value=isxrange) hasxrangefix = 'xrange = range' in content if hasxrangefix or not hasxrange: print(' no need to change') continue # find a place to insert the compatibility statement changed = False for node in red: if node.type in headertypes: continue # node.insert_before is an easier API, but it has bugs changing # other "finally" and "except" positions. So do the insert # manually. # # node.insert_before(xrangefix) line = node.absolute_bounding_box.top_left.line - 1 lines = content.splitlines(1) content = ''.join(lines[:line]) + xrangefix + ''.join(lines[line:]) changed = True break if changed: # "content" is faster than "red.dumps()" open(path, 'w').write(content) print(' updated') if __name__ == "__main__": sys.exit(main(sys.argv[1:])) ``` For other py2 builtins that do not have a py3 equivalent, some `# noqa` were added as a workaround for now. Reviewed By: DurhamG Differential Revision: D6934535 fbshipit-source-id: 546b62830af144bc8b46788d2e0fd00496838939
126 lines
4.2 KiB
Python
126 lines
4.2 KiB
Python
from __future__ import absolute_import
|
|
|
|
import glob
|
|
import os
|
|
import shutil
|
|
import tempfile
|
|
import unittest
|
|
|
|
from mercurial import (
|
|
util,
|
|
)
|
|
atomictempfile = util.atomictempfile
|
|
|
|
try:
|
|
xrange(0)
|
|
except NameError:
|
|
xrange = range
|
|
|
|
class testatomictempfile(unittest.TestCase):
|
|
def setUp(self):
|
|
self._testdir = tempfile.mkdtemp('atomictempfiletest')
|
|
self._filename = os.path.join(self._testdir, 'testfilename')
|
|
|
|
def tearDown(self):
|
|
shutil.rmtree(self._testdir, True)
|
|
|
|
def testsimple(self):
|
|
file = atomictempfile(self._filename)
|
|
self.assertFalse(os.path.isfile(self._filename))
|
|
tempfilename = file._tempname
|
|
self.assertTrue(tempfilename in glob.glob(
|
|
os.path.join(self._testdir, '.testfilename-*')))
|
|
|
|
file.write(b'argh\n')
|
|
file.close()
|
|
|
|
self.assertTrue(os.path.isfile(self._filename))
|
|
self.assertTrue(tempfilename not in glob.glob(
|
|
os.path.join(self._testdir, '.testfilename-*')))
|
|
|
|
# discard() removes the temp file without making the write permanent
|
|
def testdiscard(self):
|
|
file = atomictempfile(self._filename)
|
|
(dir, basename) = os.path.split(file._tempname)
|
|
|
|
file.write(b'yo\n')
|
|
file.discard()
|
|
|
|
self.assertFalse(os.path.isfile(self._filename))
|
|
self.assertTrue(basename not in os.listdir('.'))
|
|
|
|
# if a programmer screws up and passes bad args to atomictempfile, they
|
|
# get a plain ordinary TypeError, not infinite recursion
|
|
def testoops(self):
|
|
with self.assertRaises(TypeError):
|
|
atomictempfile()
|
|
|
|
# checkambig=True avoids ambiguity of timestamp
|
|
def testcheckambig(self):
|
|
def atomicwrite(checkambig):
|
|
f = atomictempfile(self._filename, checkambig=checkambig)
|
|
f.write('FOO')
|
|
f.close()
|
|
|
|
# try some times, because reproduction of ambiguity depends on
|
|
# "filesystem time"
|
|
for i in xrange(5):
|
|
atomicwrite(False)
|
|
oldstat = os.stat(self._filename)
|
|
if oldstat.st_ctime != oldstat.st_mtime:
|
|
# subsequent changing never causes ambiguity
|
|
continue
|
|
|
|
repetition = 3
|
|
|
|
# repeat atomic write with checkambig=True, to examine
|
|
# whether st_mtime is advanced multiple times as expected
|
|
for j in xrange(repetition):
|
|
atomicwrite(True)
|
|
newstat = os.stat(self._filename)
|
|
if oldstat.st_ctime != newstat.st_ctime:
|
|
# timestamp ambiguity was naturally avoided while repetition
|
|
continue
|
|
|
|
# st_mtime should be advanced "repetition" times, because
|
|
# all atomicwrite() occurred at same time (in sec)
|
|
self.assertTrue(newstat.st_mtime ==
|
|
((oldstat.st_mtime + repetition) & 0x7fffffff))
|
|
# no more examination is needed, if assumption above is true
|
|
break
|
|
else:
|
|
# This platform seems too slow to examine anti-ambiguity
|
|
# of file timestamp (or test happened to be executed at
|
|
# bad timing). Exit silently in this case, because running
|
|
# on other faster platforms can detect problems
|
|
pass
|
|
|
|
def testread(self):
|
|
with open(self._filename, 'wb') as f:
|
|
f.write(b'foobar\n')
|
|
file = atomictempfile(self._filename, mode='rb')
|
|
self.assertTrue(file.read(), b'foobar\n')
|
|
file.discard()
|
|
|
|
def testcontextmanagersuccess(self):
|
|
"""When the context closes, the file is closed"""
|
|
with atomictempfile('foo') as f:
|
|
self.assertFalse(os.path.isfile('foo'))
|
|
f.write(b'argh\n')
|
|
self.assertTrue(os.path.isfile('foo'))
|
|
|
|
def testcontextmanagerfailure(self):
|
|
"""On exception, the file is discarded"""
|
|
try:
|
|
with atomictempfile('foo') as f:
|
|
self.assertFalse(os.path.isfile('foo'))
|
|
f.write(b'argh\n')
|
|
raise ValueError
|
|
except ValueError:
|
|
pass
|
|
self.assertFalse(os.path.isfile('foo'))
|
|
|
|
if __name__ == '__main__':
|
|
import silenttestrunner
|
|
silenttestrunner.main(__name__)
|