Skip to content

Conversation

@lukeocodes
Copy link

Fixes #598

python-dotenv already had basic FIFO support (added in #586), it didn't work with asynchronously mounted FIFO files, like by 1Password's new (beta) Environment feat

Existing implementation opened FIFOs directly:

with open(self.dotenv_path, encoding=self.encoding) as stream:
    yield stream

The flaw with this approach: when a FIFO exists but isn't immediately ready to read (common with async-mounted filesystems), open() can block indefinitely waiting for a writer, or read it as empty.

The existing test (test_load_dotenv_from_fifo) worked because it started a writer thread before attempting to read, ensuring the FIFO was ready and had content

Solution

I've added a new _wait_for_file_content() function that handles FIFOs that may not be immediately readable:

  1. Detects FIFOs using stat.S_ISFIFO() to distinguish them from regular files
  2. Uses select.select() to wait for the FIFO to become readable (with a 5-second timeout)
  3. Opens in binary mode with unbuffered I/O (rb, buffering=0) for accurate readiness detection
  4. Reads content once when ready and returns it as a StringIO object
  5. Handles regular files normally without any waiting overhead

The result is that even when using regular FIFO or using 1Password, it reads (or prompts 1Password for an unlock password) correctly

Changes

  • Added _wait_for_file_content() function in src/dotenv/main.py
  • Updated _get_stream() to use the new function for FIFO-aware file reading

Testing

  • All existing tests pass (210/210)
  • New tests verify FIFOs are properly handled with waiting logic

Impact

This change is backward compatible and imprpves support for:

  • 1Password mounted files
  • Other mounted filesystems
  • Any FIFO that may not be immediately readable when first accessed (5 sec timeout)

Add support for reading .env files from FIFOs (named pipes) which may
not have content immediately available when first accessed. This is useful
for environments that expose .env data via FIFOs or mounted filesystems
that may initially be empty.

- Add _wait_for_file_content() function to handle both regular files
  and FIFOs with proper blocking/waiting logic
- Update _get_stream() to use the new function for FIFO-aware file reading
- Add select and time imports for FIFO handling
Add tests for _wait_for_file_content() to verify it correctly handles
both regular files and FIFOs. The existing FIFO test worked because it
started a writer thread before reading, ensuring the FIFO was ready.

However, with 1Password's asynchronously mounted FIFO files, the FIFO
may exist but not be immediately readable when first accessed. The old
code would open FIFOs directly in text mode, which could block
indefinitely waiting for a writer.

The new _wait_for_file_content() function addresses this by:
- Detecting FIFOs using stat.S_ISFIFO()
- Using select.select() to wait for the FIFO to become readable
- Reading content only when the FIFO is ready

These tests verify:
- Regular files continue to work correctly (no regression)
- FIFOs are properly handled with waiting logic for async-mounted files
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: python-dotenv doesn't load 1Password “mounted” .env files (looks like a FIFO / fd-backed file)

1 participant