os.O_RDONLY

Pick exactly one access mode — O_RDONLY, O_WRONLY or O_RDWR (0, 1 and 2) — and OR in the extras. O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, O_CREAT, O_EXCL and O_TRUNC exist on Unix and Windows; the rest are Unix-only, Windows-only or Linux extensions. Always use the names: only the three access modes have the same value everywhere.

os constantsPython 3.0+ (O_CLOEXEC 3.3+, O_PATH and O_TMPFILE 3.4+)
Common call
os.O_WRONLY | os.O_CREAT | os.O_TRUNC
Returns
int bit mask for os.open
Replaces
the mode strings of open(): 'r', 'w', 'a', 'x', '+'
Watch out
Unix-only and Windows-only flags: guard with getattr(os, 'O_BINARY', 0)
os.O_RDONLY | os.O_WRONLY | os.O_RDWR (+ O_CREAT, O_TRUNC, O_APPEND, O_EXCL, …)
→ int

Common patterns

Portable binary flags
O_BINARY exists only on Windows; getattr gives 0 elsewhere, so the same line works everywhere.
import os
BINARY = getattr(os, 'O_BINARY', 0)
fd = os.open('blob.bin', os.O_RDWR | os.O_CREAT | BINARY)
The open() modes as flags
What 'w', 'a', 'x' and 'r+' mean in os.open terms.
import os
W  = os.O_WRONLY | os.O_CREAT | os.O_TRUNC   # 'w'
A  = os.O_WRONLY | os.O_CREAT | os.O_APPEND  # 'a'
X  = os.O_WRONLY | os.O_CREAT | os.O_EXCL    # 'x'
RP = os.O_RDWR                               # 'r+'
Refuse to follow a symlink (Unix)
O_NOFOLLOW makes os.open fail if the last path component is a symbolic link.
import os
fd = os.open('config.ini', os.O_RDONLY | os.O_NOFOLLOW | os.O_CLOEXEC)
Anonymous temporary file (Linux 3.11+)
O_TMPFILE creates an unnamed file in a directory: it never shows up in os.listdir.
import os
fd = os.open('/tmp', os.O_TMPFILE | os.O_RDWR, 0o600)
try:
    os.write(fd, b'scratch')
finally:
    os.close(fd)

Examples

1. The three access modes
import os (os.O_RDONLY, os.O_WRONLY, os.O_RDWR)
Returns
(0, 1, 2)
2. Combine with |, test with &
import os flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC (bool(flags & os.O_CREAT), bool(flags & os.O_APPEND))
Returns
(True, False)
3. Extract the access mode
import os ACC = getattr(os, 'O_ACCMODE', 3) flags = os.O_RDWR | os.O_CREAT | os.O_APPEND flags & ACC == os.O_RDWR
Returns
True
4. O_APPEND writes at the end, whatever the position
import os from pathlib import Path Path('log.txt').write_bytes(b'abc') fd = os.open('log.txt', os.O_WRONLY | os.O_APPEND) try: os.lseek(fd, 0, os.SEEK_SET) os.write(fd, b'Z') finally: os.close(fd) Path('log.txt').read_bytes()
Returns
b'abcZ'
5. O_BINARY keeps CR LF untouched (0 off Windows)
import os from pathlib import Path Path('w.txt').write_bytes(b'a\r\nb') fd = os.open('w.txt', os.O_RDONLY | getattr(os, 'O_BINARY', 0)) try: data = os.read(fd, 10) finally: os.close(fd) data
Returns
b'a\r\nb'
6. O_CREAT | O_EXCL: EEXIST if the file is there
import errno, os from pathlib import Path Path('taken').touch() try: os.open('taken', os.O_WRONLY | os.O_CREAT | os.O_EXCL) except OSError as e: result = (type(e).__name__, e.errno == errno.EEXIST) result
Returns
('FileExistsError', True)
7. Writing to an O_RDONLY descriptor
import errno, os from pathlib import Path Path('r.txt').touch() fd = os.open('r.txt', os.O_RDONLY) try: os.write(fd, b'x') except OSError as e: result = (type(e).__name__, e.errno == errno.EBADF) finally: os.close(fd) result
Returns
('OSError', True)

Pitfalls

1. O_RDONLY | O_WRONLY is not read-write
O_RDONLY is 0, so OR-ing it changes nothing: the result is plain O_WRONLY and reading fails. Use O_RDWR.
O_RDONLY | O_WRONLY
import os
from pathlib import Path
Path('f').write_bytes(b'data')
fd = os.open('f', os.O_RDONLY | os.O_WRONLY)
try:
    os.read(fd, 4)
except OSError as e:
    result = type(e).__name__
finally:
    os.close(fd)
result
'OSError'
O_RDWR
import os
from pathlib import Path
Path('f').write_bytes(b'data')
fd = os.open('f', os.O_RDWR | getattr(os, 'O_BINARY', 0))
try:
    result = os.read(fd, 4)
finally:
    os.close(fd)
result
b'data'
2. Testing O_RDONLY with &
flags & os.O_RDONLY is always 0 because O_RDONLY is 0. Mask the access mode out and compare it with ==.
flags & O_RDONLY
import os
flags = os.O_RDONLY
bool(flags & os.O_RDONLY)
False
compare the access mode
import os
flags = os.O_RDONLY
flags & getattr(os, 'O_ACCMODE', 3) == os.O_RDONLY
True
3. Using a flag your platform does not have
Platform-specific flags are simply missing from os elsewhere, so the code fails with AttributeError. Guard them with getattr(os, name, 0).
os.O_NOT_HERE
import os
os.O_NOT_A_FLAG
AttributeError: module 'os' has no attribute 'O_NOT_A_FLAG'
getattr(..., 0)
import os
getattr(os, 'O_NOT_A_FLAG', 0)
0

When to use

Use it
  • Building the flags argument of os.open
  • Behaviour open() cannot express: O_NOFOLLOW, O_DIRECTORY, O_NOATIME, O_SYNC, O_TMPFILE, O_TEMPORARY
Reach for something else
  • Ordinary files → open() with 'r', 'w', 'a', 'x' modes
  • Hard-coded numbers such as 64 or 256 → the value of O_CREAT differs by platform

Notes

CPython impl
The constants come from the C headers at build time (Modules/posixmodule.c): a flag is defined only when the platform C library defines it
Unix and Windows
O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, O_CREAT, O_EXCL, O_TRUNC
Unix only
O_DSYNC, O_RSYNC, O_SYNC, O_NDELAY, O_NONBLOCK, O_NOCTTY, O_CLOEXEC (3.3+). O_FSYNC is listed for macOS in the docs but Linux has it too (equal to O_SYNC there)
Windows only
O_BINARY, O_NOINHERIT, O_SHORT_LIVED, O_TEMPORARY (the file is deleted when the fd is closed), O_RANDOM, O_SEQUENTIAL, O_TEXT
C library extensions
O_ASYNC, O_DIRECT, O_DIRECTORY, O_NOFOLLOW, O_NOATIME, O_PATH (3.4+), O_TMPFILE (3.4+, Linux 3.11+) — present only where the C library defines them. O_ACCMODE (mask for the access mode, 3 on Linux) and O_LARGEFILE (0 on 64-bit Linux) are exported on Linux but not documented
Values
Only O_RDONLY = 0, O_WRONLY = 1, O_RDWR = 2 agree across Linux and Windows; for example O_CREAT is 64 on Linux and 256 on Windows, O_APPEND 1024 vs 8
Aliases on Linux
O_NDELAY == O_NONBLOCK, and O_SYNC == O_RSYNC == O_FSYNC

FAQ

O_BINARY, O_TEXT, O_NOINHERIT, O_TEMPORARY, O_SHORT_LIVED, O_RANDOM and O_SEQUENTIAL are Windows-only (docs.python.org lists them as such). Unix has no text mode, so there is nothing to switch off. Write getattr(os, 'O_BINARY', 0) and the same flags work on every system. This page has no live demo because the set of flags and their values depend on the platform; the examples only use names and values that agree on Linux and Windows.