6

I am writing a program which stores some JSON-encoded data in a file, but sometimes the resulting file is blank (because there wasn't found any new data). When the program finds data and stores it, I do this:

with open('data.tmp') as f:
    data = json.load(f)
os.remove('data.tmp')

Of course, if the file is blank this will raise an exception, which I can catch but does not let me to remove the file. I have tried:

try:
    with open('data.tmp') as f:
        data = json.load(f)
except:
    os.remove('data.tmp')

And I get this error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "MyScript.py", line 50, in run
    os.remove('data.tmp')
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process

How could I delete the file when the exception occurs?

Code-Apprentice
  • 76,639
  • 19
  • 130
  • 241
bitomic
  • 150
  • 9
  • It looks like you need to close the file before removing it - try not using `with` and add `f.close()` before `os.remove` in the `except` statement – Adam Jan 05 '19 at 20:50
  • 2
    @Adam: That may not work unless there's a `finally` block that also closes the file, or somesuch. But yeah, the file must be closed before it can be removed. – Robert Harvey Jan 05 '19 at 20:50
  • I already tried doing that. Wrote a `f.close()` before the `os.remove`, but it keeps raising the same exception on the same line (on the `os.remove` sentence) – bitomic Jan 05 '19 at 20:51
  • 1
    Is it being used by another program? – iz_ Jan 05 '19 at 20:51
  • So should I write the `f.close()` inside the `except` block and remove it in the `finally`? – bitomic Jan 05 '19 at 20:52
  • @Tomothy32 Nope, it is only being used by this script. – bitomic Jan 05 '19 at 20:52
  • did you try writing the try-except inside the with open block? you may as well do f.close first in the except block. – Shariq Jan 05 '19 at 20:56
  • @Shariq I did, the result is the same. Even if I just pass the exception and try to remove the file after the `with` statement, it raises the same exception. I think it isn't closing the file, but I can't even close it explicitly... – bitomic Jan 05 '19 at 20:59
  • I tried your code, create data.tmp, put a json inside it, ran the program, works. Then removed the json so the file is blank, still works. json.load(f) doesn't give any error when the file is blank. – Shariq Jan 05 '19 at 21:02
  • @Shariq doesn't it raise a `json.decoder.JSONDecodeError` when a blank file is passed to `json.load`? Because it does when I try it. – bitomic Jan 05 '19 at 21:08
  • Oh well my bad, I couldnt come across the error because it was inside try-except, and the file could be deleted successfuly without the error you're facing. Running Win10, the tmp file & python code placed on desktop – Shariq Jan 05 '19 at 21:15

2 Answers2

1

How about separating out file reading and json loading? json.loads behaves exactly same as json.load but uses a string.

with open('data.tmp') as f:
    dataread = f.read()
os.remove('data.tmp')

#handle exceptions as needed here...
data = json.loads(dataread)
JL Peyret
  • 9,051
  • 2
  • 41
  • 63
  • This works perfectly! This always removes the file, and I can treat the `json.decoder.JSONDecodeError` away from the `with` statement. Thanks! – bitomic Jan 05 '19 at 21:51
0

you need to edit the remove part, so it handles the non-existing case gracefully.

import os
try:
    fn = 'data.tmp'
    with open(fn) as f:
        data = json.load(f)
except:
    try:
        if os.stat(fn).st_size > 0:
            os.remove(fn) if os.path.exists(fn) else None
    except OSError as e: # this would be "except OSError, e:" before Python 2.6
        if e.errno != errno.ENOENT:
            raise

see also Most pythonic way to delete a file which may not exist

you could extract the silent removal in a separate function.

also, from the same other SO question:

# python3.4 and above
import contextlib, os

try:
    fn = 'data.tmp'
    with open(fn) as f:
        data = json.load(f)
except:
    with contextlib.suppress(FileNotFoundError):
        if os.stat(fn).st_size > 0:
            os.remove(fn)

I personally like the latter approach better - it's explicit.

Jörg Beyer
  • 3,573
  • 20
  • 35
  • The same exception occurs :\ – bitomic Jan 05 '19 at 20:56
  • As a note, the file is always granted to exist, so the problem won't be about trying to remove an inexistent file... I think I'll just have to read the file and delete it if hasn't content (aka, is blank), but I would like to have a method handling the exception in case I try to parse JSON data saved incorrectly. – bitomic Jan 05 '19 at 21:04
  • 1
    ok, you can check it like this: os.stat(fn).st_size > 0 Does that help, @Bitom ? – Jörg Beyer Jan 05 '19 at 21:07
  • I think I will use this, since I can't find any other way. I'll wait for other answers, if none could help I'll mark this as the answer. Thanks! ^^ – bitomic Jan 05 '19 at 21:10