Hi - I’m using sqlite on disk as temporary storage, and would like to use tempfile to create a file for the lifetime of the object, as my calculations are out of memory.
Hereby I presume that the file will be safely deleted once the object is garbage collected. Unfortunately this code raises the error below:
The code:
from tempfile import NamedTemporaryFile
import sqlite3
class A(object):
def __init__(self):
self.tempfile = NamedTemporaryFile(suffix='.db')
self.conn = sqlite3.connect(self.tempfile.name)
obj = A()
The error message:
Traceback (most recent call last):
self.conn = sqlite3.connect(self.tempfile.name)
sqlite3.OperationalError: unable to open database file
Process finished with exit code 1
It is not a bug. I copied your code into tempdb.py and did the following in the REPL:
Python 3.6.10 (default, Jan 16 2020, 09:12:04) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tempdb
>>> tempdb.obj
<tempdb.A object at 0x7f74b9dd7b70>
>>> tempdb.obj.conn
<sqlite3.Connection object at 0x7f74b946f030>
>>> tempdb.obj.tempfile
<tempfile._TemporaryFileWrapper object at 0x7f74b9dec438>
The temporary file was in directory /tmp. The issue is not in your code.
Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows NT or later).
from string import ascii_lowercase
from random import choice
from tempfile import NamedTemporaryFile
import sqlite3
from pathlib import Path
class A(object):
def __init__(self):
t = NamedTemporaryFile().name
safe_folder = Path(t).parent
suffix = '.db'
while 1:
n = "".join([choice(ascii_lowercase) for i in range(5)])
name = f"tmp{n}{suffix}"
p = safe_folder / name
if not p.exists():
break
self._file = p
self.conn = sqlite3.connect(p)
def __del__(self):
self.conn.close()
self._file.unlink()
obj = A()
print(obj._file)
del obj
I’ve patched my project with this tempfile function for windows:
def windows_tempfile(prefix='tmp', suffix='.db'):
""" generates a safe tempfile which windows can't handle. """
t = NamedTemporaryFile().name
safe_folder = Path(t).parent
while 1:
n = "".join(choice(ascii_lowercase) for i in range(5))
name = f"{prefix}{n}{suffix}"
p = safe_folder / name
if not p.exists():
break
return p
I would rather use a temporary directory, in which you can create whatever file you want: https://docs.python.org/3/library/tempfile.html#tempfile.TemporaryDirectory. That way you still get cleanup for free, aren’t creating an unused temporary file, and aren’t subject to headache when somebody has already created the file you’re trying to use for a database.