Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions agent-notes/improve-documentation-opening.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Goal

Open an existing localized documentation file through a valid file URI.

# State

Isolated branch based on improve/integration-contract (PR #1). Existing action
name and bundled/source layouts are preserved. Tests cover exact, base-language
and root fallback, missing documentation and URI escaping.

# Decisions and why

Check readme.html itself rather than the locale directory. Use pathlib as_uri
for Windows separators, Unicode and reserved URL characters. An incomplete
locale folder no longer blocks a valid language/root document. Show a translated
warning when no document exists. No manifest field or remote fallback added.

# Surprises

The existing function opened nonexistent files whenever a localized directory
existed without readme.html. No actual packaged app was launched during this work.

# Next step

Publish and read PR CI; controlled browser calls and real temporary filesystem
fixtures do not establish packaged-product or live screen-reader behavior.
26 changes: 13 additions & 13 deletions app_elements/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

logger = getLogger("app_elements.interface")
import datetime
import os
import sys
import webbrowser
from pathlib import Path

import app_framework
import app_framework.shutdown
Expand All @@ -25,19 +25,19 @@

def view_documentation():
if paths.is_frozen():
docpath = paths.embedded_data_path()
docpath = Path(paths.embedded_data_path())
else:
docpath = os.path.join(paths.app_path(), "..", "documentation")
locale = application.locale
if os.path.exists(os.path.join(docpath, locale)):
docpath = os.path.join(docpath, locale)
else:
locale = locale.split("_")[0]
if os.path.exists(os.path.join(docpath, locale)):
docpath = os.path.join(docpath, locale)
docpath = os.path.join(docpath, "readme.html")
docpath = "file://%s" % os.path.abspath(docpath)
webbrowser.open(docpath)
docpath = Path(paths.app_path()).parent / "documentation"
locale = application.locale.split(".")[0].split("@")[0].replace("-", "_")
for language in (locale, locale.split("_")[0], ""):
document = docpath / language / "readme.html"
if document.is_file():
webbrowser.open(document.resolve().as_uri())
return
popups.warning_message(
title=_("Documentation unavailable"),
message=_("Documentation could not be found. Check that the documentation files are installed with this application."),
)


def show_about_dialog():
Expand Down
56 changes: 56 additions & 0 deletions tests/test_documentation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch

from support import load_component


class DocumentationTests(unittest.TestCase):
def test_exact_then_language_then_root_fallback_uses_existing_file(self):
for available, expected in [
(["fr_CA", "fr", ""], "fr_CA"),
(["fr", ""], "fr"),
([""], ""),
]:
with self.subTest(available=available), tempfile.TemporaryDirectory() as directory:
root = Path(directory) / "My App #1 café"
root.mkdir()
for language in available:
folder = root / language
folder.mkdir(exist_ok=True)
(folder / "readme.html").touch()
(root / "fr_CA").mkdir(exist_ok=True)
with load_component("app_elements.interface", locale="fr-CA.UTF-8") as (component, _, modules):
paths = modules["platform_utils.paths"]
paths.is_frozen.return_value = True
paths.embedded_data_path.return_value = str(root)
with patch.object(component.webbrowser, "open") as browser:
component.view_documentation()
browser.assert_called_once_with((root / expected / "readme.html").resolve().as_uri())
modules["wx_utils.popups"].warning_message.assert_not_called()

def test_source_run_uses_sibling_documentation_directory(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
application_path = root / "Example"
application_path.mkdir()
docs = root / "documentation"
docs.mkdir()
(docs / "readme.html").touch()
with load_component("app_elements.interface") as (component, _, modules):
modules["platform_utils.paths"].app_path.return_value = str(application_path)
with patch.object(component.webbrowser, "open") as browser:
component.view_documentation()
browser.assert_called_once_with((docs / "readme.html").as_uri())

def test_missing_document_warns_instead_of_opening_a_broken_url(self):
with tempfile.TemporaryDirectory() as directory:
with load_component("app_elements.interface") as (component, _, modules):
paths = modules["platform_utils.paths"]
paths.is_frozen.return_value = True
paths.embedded_data_path.return_value = directory
with patch.object(component.webbrowser, "open") as browser:
component.view_documentation()
browser.assert_not_called()
modules["wx_utils.popups"].warning_message.assert_called_once()
Loading