DanielGibbs
DanielGibbs

Reputation: 10191

Opening a file in a Python module and closing it when the script ends

I have a Python module that performs some logging during some of the methods it contains:

module.py

LOG_FILE = "/var/log/module.log"

def log(message):
    with os.fdopen(os.open(LOG_FILE, os.O_RDWR | os.O_CREAT, 0664), "a+") as f:
        f.write("[%s] %s\n" % (time.strftime("%c"), message))

def do_something():
    log("Doing something")
    # ...

In this implementation the log file will be opened and closed every time the log method is called.

I'm considering refactoring it so the file is opened once when the module is loaded, but I'm not sure how to ensure it is closed when a script importing the module ends. Is there a clean way to do this?

Edit: I'm not asking about closing the file when an exception is encountered, but when the script that imports my module exits.

Upvotes: 0

Views: 1165

Answers (3)

jfs
jfs

Reputation: 414265

OS takes care of open file descriptors then a process dies. It may lead to a data loss if file buffers inside the application are not flushed. You could add f.flush() in the log() function after each write (note: it does not guarantee that the data is physically written to disk and therefore it is still may be lost on a power failure, see Threadsafe and fault-tolerant file writes).

Python may also close (and flush) the file on exit during a garbage collection. But you shouldn't rely on it.

atexit works only during a normal exit (and exit on some signals). It won't help if the script is killed abruptly.

As @René Fleschenberg suggested, use logging module that calls .flush() and perhaps registers atexit handlers for you.

Upvotes: 2

René Fleschenberg
René Fleschenberg

Reputation: 2548

Python will automatically close the opened files for you when the script that has imported your module exits.

But really, just use Python's logging module.

Upvotes: 0

RoadieRich
RoadieRich

Reputation: 6566

Python is usually pretty good at cleaning up after itself. If you must do something when the script ends, you need to look at the atexit module - but even then, it offers no guarantees.

You may also want to consider logging to either stdout or stderr, depending on purpose, which avoids keeping a file around all together:

import sys

def log(message):
    sys.stderr.write("[%s] %s\n" % (time.strftime("%c"), message))

Upvotes: 1

Related Questions