Skip to content

Commit

Permalink
Intercept webbrowser open requests for local html files as well as …
Browse files Browse the repository at this point in the history
…localhost (#4178)

Addresses #4118 

Hooks into the new `'show-html-file'` comm path to display html files
opened with the `webbrowser` python module in the viewer pane.

Previously we overrode the `webbrowser` opening to forward localhost
servers, so this just adds a condition to check for html files and do a
similar thing.

Here's an example of it working on a bokeh plot that previously used to
open in an external browser:
<img width="1115" alt="image"
src="https://github.com/user-attachments/assets/d258ae4e-f8d2-449a-8490-b99bb282aaca">


Rough edges:
- Bokeh widget doesn't seem to care about the size of the viewer pane.


<!-- Thank you for submitting a pull request.
If this is your first pull request you can find information about
contributing here:
  * https://github.com/posit-dev/positron/blob/main/CONTRIBUTING.md

We recommend synchronizing your branch with the latest changes in the
main branch by either pulling or rebasing.
-->

<!--
  Describe briefly what problem this pull request resolves, or what
  new feature it introduces. Include screenshots of any new or altered
  UI. Link to any GitHub issues but avoid "magic" keywords that will 
  automatically close the issue. If there are any details about your 
approach that are unintuitive or you want to draw attention to, please
  describe them here.
-->

### QA Notes

<!--
  Add additional information for QA on how to validate the change,
  paying special attention to the level of risk, adjacent areas that
  could be affected by the change, and any important contextual
  information not present in the linked issues.
-->
  • Loading branch information
nstrayer authored Jul 30, 2024
1 parent c9ce224 commit 67eb32a
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 4 deletions.
4 changes: 2 additions & 2 deletions extensions/positron-python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ pyright
Install the test requirements that are used in CI:

```sh
pip install -r ../build/pinned-test-requirements.txt
pip install -r python_files/positron/pinned-test-requirements.txt
```

Run Positron's unit tests with [pytest](https://docs.pytest.org/en/8.0.x/):

```sh
pytest python_files/positron/
python -m pytest python_files/positron/
```
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ def show_url_event(url: str) -> Dict[str, Any]:
return json_rpc_notification("show_url", {"url": url})


def show_html_file_event(path: str, is_plot: bool) -> Dict[str, Any]:
return json_rpc_notification("show_html_file", {"path": path, "is_plot": is_plot})


def test_comm_open(ui_service: UiService) -> None:
# Double-check that comm is not yet open
assert ui_service._comm is None
Expand Down Expand Up @@ -149,7 +153,24 @@ def test_shutdown(ui_service: UiService, ui_comm: DummyComm) -> None:

@pytest.mark.parametrize(
("url", "expected"),
[("https://google.com", []), ("localhost:8000", [show_url_event("localhost:8000")])],
[
("https://google.com", []),
("localhost:8000", [show_url_event("localhost:8000")]),
# Unix path
(
"file://hello/my/friend.html",
[show_html_file_event("file://hello/my/friend.html", False)],
),
# Windows path
(
"file:///C:/Users/username/Documents/index.htm",
[show_html_file_event("file:///C:/Users/username/Documents/index.htm", False)],
),
# Not a local html file
("http://example.com/page.html", []),
# Not an html file
("file:///C:/Users/username/Documents/file.txt", []),
],
)
def test_viewer_webbrowser_does_not_open(
url, expected, shell: PositronShell, ui_comm: DummyComm, ui_service: UiService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
UiFrontendEvent,
WorkingDirectoryParams,
)
from .utils import JsonData, JsonRecord, alias_home
from .utils import JsonData, JsonRecord, alias_home, is_local_html_file

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -179,6 +179,18 @@ def open(self, url, new=0, autoraise=True):
if not self._comm:
return False

# If url is pointing to an HTML file, route to the ShowHtmlFile comm
if is_local_html_file(url):
self._comm.send_event(
name=UiFrontendEvent.ShowHtmlFile,
payload={
"path": url,
# TODO: Figure out if the file being displayed is a plot or not.
"is_plot": False,
},
)
return True

for addr in _localhosts:
if addr in url:
event = ShowUrlParams(url=url)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
Union,
cast,
)
from urllib.parse import urlparse, unquote

JsonData = Union[Dict[str, "JsonData"], List["JsonData"], str, int, float, bool, None]
JsonRecord = Dict[str, JsonData]
Expand Down Expand Up @@ -384,3 +385,23 @@ def positron_ipykernel_usage():
"numpy.cdouble",
"numpy.clongdouble",
]


def is_local_html_file(url: str) -> bool:
"""Check if a URL points to a local HTML file."""
try:
parsed_url = urlparse(unquote(url))

# Check if it's a file scheme
if parsed_url.scheme not in ("file"):
return False

# Check if the path contains the .html or .htm extensions
path = parsed_url.path.lower()
if any(ext in path for ext in (".html", ".htm")):
return True

return False

except Exception:
return False

0 comments on commit 67eb32a

Please sign in to comment.