Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSError raised on opening a file with mismatched mode #1843

Open
BCSharp opened this issue Dec 17, 2024 · 1 comment
Open

OSError raised on opening a file with mismatched mode #1843

BCSharp opened this issue Dec 17, 2024 · 1 comment

Comments

@BCSharp
Copy link
Member

BCSharp commented Dec 17, 2024

One way of opening a file in Python is by using os.open to open a file descriptor, and then passing that descriptor to io.open (or the open builtin). Both calls require a file mode to be specified, but in a different way: os.open uses OS flags, and io.open a mode string. Both modes, though different in form, should be equivalent, though need not to.

For instance, flag os.O_WRONLY should be matched with 'w' or wb, os.O_RDONLY with 'r' or 'rb', and os.O_RDWR with 'w+' or 'wb+'.

In CPython, when the mode used with io.open does not match the opening flags used with os.open, the opening of the file succeeds, and io.UnsupportedOperation is raised only when the user code attempts to perform read/write operation that was not enabled when the file descriptor was opened.

In IronPython, OSError is raised immediately when the file object is being created, with a cryptic message "raw" argument must be readable. or "raw" argument must be writable.

This difference leads to some situations when the code works in CPython, but not in IronPython. Example:

import os, io

temp_file = "temp_file"

fd = os.open(temp_file, os.O_CREAT | os.O_WRONLY)
f = open(fd, 'w+') # OSError in IPY
f.write("hello\n")
f.close()

fd = os.open(temp_file, os.O_RDONLY)
f = io.open(fd, 'w+') # OSError in IPY
print(f.read())
f.close()

I consider it a minor incompatibility (because, basically, the user code is not quite consistent), but if changing IronPython is too complicated and not worth the effort for the payoff, at least the error message could be changed to something more informative, and the behavior documented in "Differences with CPython".

@slozier
Copy link
Contributor

slozier commented Dec 18, 2024

The difference appears to be that the CPython FileIO object is lying about it's readability/writability. It looks like the io wrappers are supposed to be throwing when you give them an object that's not seekable/readable/writable. Though the proper error messages would be of the form:

io.UnsupportedOperation: File or stream is not seekable.

It can be tested with something like:

import io

class test:
    def __init__(self, seekable, readable, writable):
        self._seekable = seekable
        self._readable = readable
        self._writable = writable
    def seekable(self): return self._seekable
    def readable(self): return self._readable
    def writable(self): return self._writable

io.BufferedRandom(test(False, False, False))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants