9

Here's the breakdown of my Windows WSL environment:

  • Windows 11
  • WSL version 2
  • Ubuntu version 20.04.3 LTS
  • Python 3.8.10

I have a super simple Python program I'm using to open a web page in my default browser.

Here is my code:

import webbrowser

webbrowser.open('https://github.com')

When I run this from my terminal the webpage opens up as expected, but I also get this error in the terminal:

tcgetpgrp failed: Not a tty

When my terminal displays this message, the cursor goes down to the next line and it looks like a process is hung or something. To be able to use the terminal I have to Ctrl+C to get it to give me the command prompt.

I looked for answers and everything I could find has to do with using Jupyter or PHP but I'm not using either of them, I'm just using plain old Python to try and open the browser.

Can anyone tell me what the issue is here and how to fix this/prevent it from happening?

2 Answers 2

12

Short answer (confirmed)

export BROWSER=/mnt/c/path/to/windows/browser before starting Python, but ...

See other answer (also confirmed)

While this solves the original question that was asked, it does not work for file:/// URIs where the file in inside the WSL filesystem.

This answer from NeoMatrixJR solves both the original problem and also works with file:/// URIs.

More detail

Yes, I can also reproduce it from the Python (and IPython) REPL on Ubuntu under WSL. I don't get the "lockup" that requires Ctrl+C when running interactively, at least.

I'll theorize on the "why". Most of this I can confirm myself, but the last bullet below is still a bit of a mystery to me:

  • webbrowser-open uses whatever browser is defined by the BROWSER environment variable first, but falls back to (I believe) xdg-open.

  • xdg-open uses whatever browser is defined in the alternatives system for x-www-browser or www-browser.

  • On Ubuntu 20.04 on WSL, the wslu package is installed by default (it is no longer a default package under 22.04, though).

  • That package includes the wslview helper. From its manpage:

    [wslview] is a file viewer on WSL that allows you to open files and folders from WSL in Windows and a fake web browser that allows opening urls in your default browser on Windows 10.

  • wslview is registered during the wslu installation as the alternative for both x-www-browser and www-browser.

  • webbrowser.open doesn't just call xdg-open, but it attempts to get the process information of the resulting browser so that it can (at the least) raise the window if requested. Part of this is obtaining the process group via, apparently, the tcgetpgrp system call. According to the tcgetpgrp manpage:

    The function tcgetpgrp() returns the process group ID of the foreground process group on the terminal associated to fd, which must be the controlling terminal of the calling process.

  • Here's where I have to "hand-wave" a bit -- Something in the hand-off from webbrowser.open to wslview to binfmt_misc (the kernel system that allows it to launch Windows executables) is "losing" or redirecting a file descriptor of the terminal, resulting in this message.

    It appears to me to be a bug (unintended side-effect?) of wslview, since making sure it isn't used will prevent the error from occurring.

As a workaround, either:

  • export BROWSER=/mnt/c/path/to/windows/browser before starting Python. For example, for Edge:

    export BROWSER='/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe'
    

    Credit to @rahul13579 for supplying the Edge location in a subsequent answer which was, unfortunately, not-an-answer and has been deleted.

  • Or, since you are on Windows 11, install a Linux browser. I used Vivaldi to test and confirm that it opened properly from Python under WSL. Note that you can't sudo apt install either Chromium or Firefox under WSL since they are both Snaps.

Sign up to request clarification or add additional context in comments.

9 Comments

such a great answer! thank you so much for taking the time to explain this in such a clear way. I was able to use the first workaround of exporting the path to my browser executable. After doing that I can run the script with no errors. Marked as accepted and upvoted, thanks again!
the export BROWSER=path_to_chrome.exe worked great for me!! many thanks!
I had a similar issue, but I had a DISPLAY environment variable set from when I was playing with X410 - I also needed to unset this in order to get the browser to listen to the BROWSER setting.
I investigated this issue recently. The "something" in the handoff is BackgroundBrowser in webbrowser.py. You can test this manually - if BROWSER ends in '&', it is executed via BackgroundBrowser, and produces this error. Otherwise, it doesn't. This makes this a minimal reproduction of the error: BROWSER='firefox&' python -m webbrowser -t "https://www.python.org" produces the symptom. BROWSER='firefox' ... does not. This even happens with BROWSER='lynx&', which seems to actually also fall back to a successful browser choice.
@Atnas I assume you are referring to file:/// URIs? I agree - While my answer solves the original question, the answer from NeoMatrixJR solves both the original question and works for more use-cases. I'll update my answer to point there. The bad news is that wslu just got abandoned recently, so hopefully someone picks it up before we see issues in it. If it weren't GPL-3, I'd be asking the Microsoft WSL team to include it like they do wslpath, but this wouldn't be possible given the licensing.
|
4

Looks like if you install wslu manually on 22.04+ you can also export BROWSER=/usr/bin/wslview to resolve this.

3 Comments

where do we put this export?
Run in command line before python command
This solution works on me with WSL-20.04.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.