Karl Knechtel
Karl Knechtel

Reputation: 61635

Why do I get "TypeError: open() missing required argument 'flags' (pos 2)" or "TypeError: an integer is required (got type str)" when opening a file?

If your question was closed as a duplicate of this, it is because you have code along the lines of:

from os import *

with open('example.txt', mode='r') as f:
    print('successfully opened example.txt')

This causes an error message that says TypeError: open() missing required argument 'flags' (pos 2).

Alternately, you may have tried specifying the mode as a positional argument instead of a keyword argument, like:

from os import *

with open('example.txt', 'r') as f:
    print('successfully opened example.txt')

But that does not work either - it gives a different error, which says TypeError: an integer is required (got type str).

You may have noticed that there is no such keyword argument flags for the built-in open function:

>>> help(open)
Help on built-in function open in module io:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
    Open file and return a stream.  Raise OSError upon failure.

Indeed, if you try removing from os import * from the code example, you should find that the problem is resolved.

This question is an artificial canonical duplicate, to explain what happened, i.e.: Why is it different when the code says from os import *? Also, how can the problem be resolved?

Upvotes: 1

Views: 2150

Answers (1)

Karl Knechtel
Karl Knechtel

Reputation: 61635

Using a star import like from os import * - or explicitly using from os import open, or perhaps taking some more indirect route - means that the name open will no longer refer to the built-in open function (which is also available from the io standard library module), but instead to os.open.1

This function is also used for opening files, but it provides a lower-level interface. It offers more options for controlling how the file is opened.

In particular: the flags argument here is analogous to the mode used by the built-in open, but it offers many more options (most of which are platform-specific). Rather than a string, it should be an integer produced by bitwise-OR of some flag values (i.e., it directly reflects a C interface). The mode argument, on the other hand, indicates the (UNIX-like file system) permissions that will be used when creating a new file, if open should create one.

Again: normal code should not use this, but instead use the built-in open. (To fix the file permissions after creating a new file, use os.chmod.)

To avoid this name collision, simply don't use star-imports and don't import open explicitly. Instead, if os standard library module functionality is needed, just import os and then use qualified names.

At the interpreter prompt, del open will get rid of the global binding of the name open, making the builtin one visible again. Alternately, since the built-in open is the same function as the built-in open (not simply another function doing the same thing, but literally the same object), we can re-import that name: from io import open. These techniques would also work within a script that did from os import * after that import, but it will be much cleaner and less error-prone in the long run to just avoid star-imports.

1 Keep in mind that a name can only refer to one thing at a time. See also: Short description of the scoping rules? and Why does code like `str = str(...)` cause a TypeError, but only the second time?.

Upvotes: 1

Related Questions