mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-16 07:19:13 +08:00
Merge branch 'release_25.1' into release_26.0
This commit is contained in:
@@ -1959,7 +1959,7 @@ class Tool(UsesDictVisibleKeys, ToolParameterBundle):
|
||||
try:
|
||||
return rst_to_html(help_content.content)
|
||||
except Exception:
|
||||
log.info("Exception while parsing help for tool with id '%s'", self.id)
|
||||
log.warning("Exception while parsing help for tool with id '%s'", self.id, exc_info=True)
|
||||
return ""
|
||||
|
||||
def render_help(self, static_path: str, host_url: str) -> str:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import functools
|
||||
import os
|
||||
import threading
|
||||
|
||||
try:
|
||||
import docutils.core
|
||||
@@ -57,12 +58,17 @@ def get_publisher(error=False):
|
||||
return pub
|
||||
|
||||
|
||||
# Cached docutils publishers are stateful and not thread-safe.
|
||||
_publish_lock = threading.Lock()
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=None)
|
||||
def rst_to_html(s, error=False):
|
||||
if docutils is None:
|
||||
raise Exception("Attempted to use rst_to_html but docutils unavailable.")
|
||||
|
||||
publisher = get_publisher(error=error)
|
||||
publisher.set_source(s, None)
|
||||
publisher.set_destination(None, None)
|
||||
return publisher.publish(enable_exit_status=False)
|
||||
with _publish_lock:
|
||||
publisher = get_publisher(error=error)
|
||||
publisher.set_source(s, None)
|
||||
publisher.set_destination(None, None)
|
||||
return publisher.publish(enable_exit_status=False)
|
||||
|
||||
@@ -49,6 +49,11 @@ class TestTrsImport(SeleniumIntegrationTestCase):
|
||||
def trs_config_dir(cls):
|
||||
return cls.temp_config_dir("trs")
|
||||
|
||||
def _wait_for_import_redirect(self):
|
||||
# The client redirects to the workflow list only once the import request returns,
|
||||
# which includes the server fetching the workflow from the remote TRS server.
|
||||
self.components.workflows.workflows_list.wait_for_visible(wait_type=self.wait_types.SHED_SEARCH)
|
||||
|
||||
def assert_workflow_imported(self, name):
|
||||
# surround name with quotes to consider case where name contains colons
|
||||
self.workflow_index_search_for(f'"{name}"')
|
||||
@@ -76,7 +81,7 @@ class TestTrsImport(SeleniumIntegrationTestCase):
|
||||
workflow_name="galaxy-workflow-dockstore-example-1"
|
||||
).wait_for_and_click()
|
||||
self.components.trs_search.import_button.wait_for_and_click()
|
||||
self.sleep_for(self.wait_types.UX_RENDER)
|
||||
self._wait_for_import_redirect()
|
||||
self.workflow_index_open()
|
||||
self.assert_workflow_imported("Test Workflow")
|
||||
|
||||
@@ -85,7 +90,7 @@ class TestTrsImport(SeleniumIntegrationTestCase):
|
||||
self.components.trs_search.search.wait_for_and_send_keys("organization: iwc-workflows")
|
||||
self.components.trs_search.search_result(workflow_name=TRS_NAME).wait_for_and_click()
|
||||
self.components.trs_search.import_version(version="v0.4").wait_for_and_click()
|
||||
self.sleep_for(self.wait_types.UX_RENDER)
|
||||
self._wait_for_import_redirect()
|
||||
self.workflow_index_open()
|
||||
self.assert_workflow_imported(WORKFLOW_NAME)
|
||||
self.components.workflows.trs_icon.wait_for_visible()
|
||||
@@ -99,7 +104,7 @@ class TestTrsImport(SeleniumIntegrationTestCase):
|
||||
self.components.trs_search.search.wait_for_and_send_keys(WORKFLOW_NAME)
|
||||
self.components.trs_search.search_result(workflow_name=WORKFLOW_NAME).wait_for_and_click()
|
||||
self.components.trs_search.import_button.wait_for_and_click()
|
||||
self.sleep_for(self.wait_types.UX_RENDER)
|
||||
self._wait_for_import_redirect()
|
||||
self.workflow_index_open()
|
||||
self.assert_workflow_imported(WORKFLOW_NAME)
|
||||
|
||||
@@ -132,7 +137,7 @@ class TestTrsImport(SeleniumIntegrationTestCase):
|
||||
self.components.trs_import.select_server(server=server).wait_for_and_click()
|
||||
self.components.trs_import.input.wait_for_and_send_keys(trs_id)
|
||||
self.components.trs_import.import_version(version="v0.4").wait_for_and_click()
|
||||
self.sleep_for(self.wait_types.UX_RENDER)
|
||||
self._wait_for_import_redirect()
|
||||
self.workflow_index_open()
|
||||
self.assert_workflow_imported(WORKFLOW_NAME)
|
||||
|
||||
@@ -140,6 +145,6 @@ class TestTrsImport(SeleniumIntegrationTestCase):
|
||||
self.go_to_trs_by_id()
|
||||
self.components.trs_import.url_input.wait_for_and_send_keys(trs_url)
|
||||
self.components.trs_import.url_import_button.wait_for_and_click()
|
||||
self.sleep_for(self.wait_types.UX_RENDER)
|
||||
self._wait_for_import_redirect()
|
||||
self.workflow_index_open()
|
||||
self.assert_workflow_imported(WORKFLOW_NAME)
|
||||
|
||||
@@ -318,7 +318,8 @@ def test_timeout_kills_worker_under_waiting_wrapper(tmp_path, short_timeout_grac
|
||||
pid = int(pid_file.read_text())
|
||||
try:
|
||||
child = psutil.Process(pid)
|
||||
assert child.status() == psutil.STATUS_ZOMBIE
|
||||
# The orphaned worker is reaped asynchronously by init or a subreaper.
|
||||
assert child.status() in (psutil.STATUS_ZOMBIE, psutil.STATUS_DEAD)
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from galaxy.util.rst_to_html import rst_to_html
|
||||
|
||||
|
||||
def test_rst_to_html_basic():
|
||||
html = rst_to_html("**bold**")
|
||||
assert "<strong>bold</strong>" in html
|
||||
|
||||
|
||||
def test_rst_to_html_concurrent_conversions():
|
||||
documents = [f"Section {i}\n=========={'=' * len(str(i))}\n\nParagraph *{i}* with ``code``.\n" for i in range(50)]
|
||||
with ThreadPoolExecutor(max_workers=8) as executor:
|
||||
results = list(executor.map(rst_to_html, documents))
|
||||
for i, html in enumerate(results):
|
||||
assert f"Section {i}" in html
|
||||
assert f"<em>{i}</em>" in html
|
||||
Reference in New Issue
Block a user