5

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
Maxime Chéramy
  • 17,761
  • 8
  • 54
  • 75
  • possible duplicate of [Checking File Permissions in Linux with Python](http://stackoverflow.com/questions/1861836/checking-file-permissions-in-linux-with-python) – ismail Dec 21 '13 at 16:09
  • See https://bugreports.qt-project.org/browse/QTBUG-30148 – Frank Osterfeld Dec 21 '13 at 16:14
  • @ismail can you tell me why do you think it's a duplicate? – Maxime Chéramy Dec 21 '13 at 16:16
  • 2
    I think QFile::isWritable, which is actually QIODevice::isWritable will always return false in your setup. QIODevice::isWritable) returns whether the file is /opened/ for writing, but as you didn't open() anything, it will always return false http://qt-project.org/doc/qt-5.0/qtcore/qiodevice.html#isWritable – Frank Osterfeld Dec 21 '13 at 16:17
  • @FrankOsterfeld Thank you, that's a very interesting comment. I have updated my question. Do you think it's a good way of testing if I can write a file? – Maxime Chéramy Dec 21 '13 at 16:29
  • @Maxime because the duplicate question has the answer of os.access problem. – ismail Dec 21 '13 at 16:49
  • @ismail No, the other question is about checking the group and other access on Linux. My question is about checking the permission to write for the user (not the group or other), on Windows. I don't see the answer. If you do, feel free to answer to my question, because right now I don't see. – Maxime Chéramy Dec 21 '13 at 16:56
  • Hmm, yeah, you misunderstood the purpose of two methods called the same way. :) That said, I gave a +1 because I think it may be intereting for people trying to understand it. – László Papp Dec 22 '13 at 08:02

1 Answers1

4

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
ekhumoro
  • 115,249
  • 20
  • 229
  • 336