|
12 | 12 | import sys
|
13 | 13 | import types
|
14 | 14 |
|
| 15 | +import atomicwrites |
15 | 16 | import py
|
| 17 | + |
16 | 18 | from _pytest.assertion import util
|
17 | 19 |
|
18 | 20 |
|
@@ -140,7 +142,7 @@ def find_module(self, name, path=None):
|
140 | 142 | # Probably a SyntaxError in the test.
|
141 | 143 | return None
|
142 | 144 | if write:
|
143 |
| - _make_rewritten_pyc(state, source_stat, pyc, co) |
| 145 | + _write_pyc(state, co, source_stat, pyc) |
144 | 146 | else:
|
145 | 147 | state.trace("found cached rewritten pyc for %r" % (fn,))
|
146 | 148 | self.modules[name] = co, pyc
|
@@ -258,22 +260,21 @@ def _write_pyc(state, co, source_stat, pyc):
|
258 | 260 | # sometime to be able to use imp.load_compiled to load them. (See
|
259 | 261 | # the comment in load_module above.)
|
260 | 262 | try:
|
261 |
| - fp = open(pyc, "wb") |
262 |
| - except IOError: |
263 |
| - err = sys.exc_info()[1].errno |
264 |
| - state.trace("error writing pyc file at %s: errno=%s" % (pyc, err)) |
| 263 | + with atomicwrites.atomic_write(pyc, mode="wb", overwrite=True) as fp: |
| 264 | + fp.write(imp.get_magic()) |
| 265 | + mtime = int(source_stat.mtime) |
| 266 | + size = source_stat.size & 0xFFFFFFFF |
| 267 | + fp.write(struct.pack("<ll", mtime, size)) |
| 268 | + if six.PY2: |
| 269 | + marshal.dump(co, fp.file) |
| 270 | + else: |
| 271 | + marshal.dump(co, fp) |
| 272 | + except EnvironmentError as e: |
| 273 | + state.trace("error writing pyc file at %s: errno=%s" % (pyc, e.errno)) |
265 | 274 | # we ignore any failure to write the cache file
|
266 | 275 | # there are many reasons, permission-denied, __pycache__ being a
|
267 | 276 | # file etc.
|
268 | 277 | return False
|
269 |
| - try: |
270 |
| - fp.write(imp.get_magic()) |
271 |
| - mtime = int(source_stat.mtime) |
272 |
| - size = source_stat.size & 0xFFFFFFFF |
273 |
| - fp.write(struct.pack("<ll", mtime, size)) |
274 |
| - marshal.dump(co, fp) |
275 |
| - finally: |
276 |
| - fp.close() |
277 | 278 | return True
|
278 | 279 |
|
279 | 280 |
|
@@ -338,20 +339,6 @@ def _rewrite_test(config, fn):
|
338 | 339 | return stat, co
|
339 | 340 |
|
340 | 341 |
|
341 |
| -def _make_rewritten_pyc(state, source_stat, pyc, co): |
342 |
| - """Try to dump rewritten code to *pyc*.""" |
343 |
| - if sys.platform.startswith("win"): |
344 |
| - # Windows grants exclusive access to open files and doesn't have atomic |
345 |
| - # rename, so just write into the final file. |
346 |
| - _write_pyc(state, co, source_stat, pyc) |
347 |
| - else: |
348 |
| - # When not on windows, assume rename is atomic. Dump the code object |
349 |
| - # into a file specific to this process and atomically replace it. |
350 |
| - proc_pyc = pyc + "." + str(os.getpid()) |
351 |
| - if _write_pyc(state, co, source_stat, proc_pyc): |
352 |
| - os.rename(proc_pyc, pyc) |
353 |
| - |
354 |
| - |
355 | 342 | def _read_pyc(source, pyc, trace=lambda x: None):
|
356 | 343 | """Possibly read a pytest pyc containing rewritten code.
|
357 | 344 |
|
|
0 commit comments