I’ve been experiencing some difficulties with Bokeh’s get_screenshot_as_png function.
It seems that in Bokeh 2.3.3, the dir parameter is not set in bokeh/io/expoty.py/ file under the class _TempFileinit function, and the default TMPDIR is automatically assigned to a location visible to the web driver. In this case, the function works as expected.
However, in newer versions of Bokeh, the dir parameter is set to os.getcwd(), which the web driver cannot access.
MRE
from bokeh.plotting import figure
from bokeh.io.export import get_screenshot_as_png
import chromedriver_autoinstaller
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
p = figure()
p.circle([0], [0])
chromedriver_autoinstaller.install()
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--disable-software-rasterizer")
chrome_driver = webdriver.Chrome(options=chrome_options)
image = get_screenshot_as_png(
p,
driver=chrome_driver,
)
image.save(p, 'png', optimize=True)
In the code above, one can stop the code at chrome_driver = webdriver.Chrome(options=chrome_options), type chrome_driver.title and see that the property is empty.
I am working on macOS with M1 chip and have cleared permissions to the app folder. In addition, I have searched online for discussions or solutions related to this topic, but I couldn’t find any.
Has anyone else encountered this issue? If so, do you have any suggestions on how to resolve it? I would greatly appreciate any guidance or insights on this matter.
def __init__(self, *, prefix: str = "tmp", suffix: str = "") -> None:
# XXX: selenium has issues with /tmp directory (or equivalent), so try using the
# current directory first, if writable, and otherwise fall back to the system
# default tmp directory.
try:
self.fd, self.path = mkstemp(prefix=prefix, suffix=suffix, dir=os.getcwd())
except OSError:
self.fd, self.path = mkstemp(prefix=prefix, suffix=suffix)
Since we can’t really reproduce whatever it is you are seeing, your best bet is to try to figure out a better approach to take here that works for you locally, then suggest that in a GitHub Issue or Pull Request.
Ostensibly if the getcwd path does not work, it should be falling back to the system default tmpdir. Are you saying that is not happening? Please post the complete and exact error back trace you are seeing.
The temporary file is created in the project’s root directory. However, the code fails on the wait_until_render_complete step:
def wait_until_render_complete(driver: WebDriver, timeout: int) -> None:
'''
'''
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.wait import WebDriverWait
def is_bokeh_loaded(driver: WebDriver) -> bool:
return cast(bool, driver.execute_script('''
return typeof Bokeh !== "undefined" && Bokeh.documents != null && Bokeh.documents.length != 0
'''))
try:
WebDriverWait(driver, timeout, poll_frequency=0.1).until(is_bokeh_loaded)
except TimeoutException as e:
_log_console(driver)
raise RuntimeError('Bokeh was not loaded in time. Something may have gone wrong.') from e
raising the RuntimeError of the above exception:
RuntimeError: Bokeh was not loaded in time. Something may have gone wrong.
Full Traceback:
File "/utility_modules/helper_functions.py", line 38, in get_plot_as_png
get_screenshot_as_png(
File "/venv/lib/python3.10/site-packages/bokeh/io/export.py", line 239, in get_screenshot_as_png
wait_until_render_complete(web_driver, timeout)
File "/venv/lib/python3.10/site-packages/bokeh/io/export.py", line 331, in wait_until_render_complete
raise RuntimeError('Bokeh was not loaded in time. Something may have gone wrong.') from e
RuntimeError: Bokeh was not loaded in time. Something may have gone wrong.
@Ofir You can pass your own timeout value to export_png. Does increasing the timeout help? Are you trying to run this code on an air-gapped network or in some situation that would cause problems to load BokehJS remotely from cdn.bokeh.org?