Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QFileInfo vs QFile to test if a file is writable

I'm using PyQt and I noticed strange behavior when testing my application with Windows (everything is working as expected with Linux).

I have a file that I can read and write and I want to test it from the app:

>>> from PyQt4.QtCore import QFile, QFileInfo

>>> f1 = QFileInfo("C:\Users\Maxime\Desktop\script.py")
>>> f2 = QFile("C:\Users\Maxime\Desktop\script.py")

>>> f1.isWritable()
True
>>> f2.isWritable()
False

So it looks like QFile is wrong on that test case. But, on another file that is read-only:

>>> f1 = QFileInfo("C:\Program Files (x86)\MySoftware\stuff\script.py")
>>> f2 = QFile("C:\Program Files (x86)\MySoftware\stuff\script.py")

>>> f1.isWritable()
True
>>> f2.isWritable()
False

Now, this is QFileInfo which is wrong!

So I decided maybe I should use os.access instead:

>>> import os

>>> os.access("C:\Users\Maxime\Desktop\script.py")
True
>>> os.access("C:\Program Files (x86)\MySoftware\stuff\script.py")
True

So os.access is also wrong in one case and returns the same results as QFileInfo.

I have multiple questions:

  • I am not familiar with Windows, is there something I'm missing?
  • Using Qt, I can use QFileInfo and QFile to test if a file can be written. Should I use one instead of the other?
  • In case that's just a bug in Qt (and Python??), I'd like a workaround that can also work on Linux and Mac OS.

Edit:

A very interesting comment from Frank explained that QFile::isWritable() will always return False since I haven't opened the file.

>>> f = QFile("C:\Users\Maxime\Desktop\script.py")
>>> f.open(QFile.WriteOnly)
True
>>> f.isWritable()
True

>>> f = QFile("C:\Program Files (x86)\MySoftware\stuff\script.py")
>>> f.open(QFile.WriteOnly)
False
>>> f.isWritable()
False
like image 270
Maxime Chéramy Avatar asked Oct 21 '22 18:10

Maxime Chéramy


1 Answers

For checking writeability, it shouldn't really matter which one you use.

The main difference with QFileInfo is that, for performance reasons, it caches some of the information about the target file. However, you can use the refresh method to re-read the information, or just use setCaching to switch caching off altogether.

Also, as noted in the question comments, QFile.isWritable will return False if the file has not been opened. This is not a bug. The documentation makes it clear that isWritable checks the OpenMode of the file. This will be zero (QIODevice.NotOpen) before the file is opened, and otherwise defaults to QIODevice.ReadWrite if unspecified.

The only other issue to be aware of is that methods like QFileInfo.isWritable are specific to the current user. Use QFileInfo.permission for ownership information about other classes of user (but note the warning regarding platform differences). This is analogous to the difference between using os.access and os.stat.

Finally, here's a simple script that tests writeability:

import os, stat, sip

sip.setapi('QString', 2)
from PyQt4.QtCore import QTemporaryFile, QFile, QFileInfo

tmp = QTemporaryFile()
tmp.setAutoRemove(False)
tmp.open()
tmp.close()

path = tmp.fileName()

info = QFileInfo(path)
print('File: %s' % info.filePath())
print('')
print('Qt Writable: %s' % info.isWritable())
print('Qt Permission: %s' % bool(info.permissions() & QFile.WriteUser))
print('Py Writable: %s' % os.access(path, os.W_OK))
print('Py Permission: %s' % bool(os.stat(path).st_mode & stat.S_IWUSR))

tmp = QFile(path)
tmp.setPermissions(QFile.ReadUser)
print('')
print('Set Permissions: ReadUser')
print('')

info.refresh()
print('Qt Writable: %s' % info.isWritable())
print('Qt Permission: %s' % bool(info.permissions() & QFile.WriteUser))
print('Py Writable: %s' % os.access(path, os.W_OK))
print('Py Permission: %s' % bool(os.stat(path).st_mode & stat.S_IWUSR))

tmp.setPermissions(QFile.WriteUser)
print('')
print('Removed: %s' % tmp.remove())

For me, on both Linux and WinXp, I get results like this:

File: /tmp/qt_temp.TJ1535

Qt Writable: True
Qt Permission: True
Py Writable: True
Py Permission: True

Set Permissions: ReadUser

Qt Writable: False
Qt Permission: False
Py Writable: False
Py Permission: False

Removed: True
like image 79
ekhumoro Avatar answered Oct 23 '22 11:10

ekhumoro