PyQt5 / PyQt

PyQt Examples(PyQt各种测试和例子) PyQt4 PyQt5

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Running PyQT QWebEngineView application using docker without using host display

godomainz opened this issue · comments

I have a Dockerfile like this

FROM ubuntu:20.04

ENV DEBIAN_FRONTEND=noninteractive
RUN adduser --quiet --disabled-password qtuser && usermod -a -G video qtuser
RUN apt-get update -y \
    && apt-get install alsa -y \
    && apt-get install libnss3 -y \
    && apt-get install -y python3-pyqt5 \
    && apt-get install python3-pip -y \
    && pip3 install pyqtwebengine
# RUN apt-get install xauth -y
# RUN apt-get install xvfb -y
# RUN apt-get install x11vnc -y
# RUN mkdir ~/.vnc
# RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Set display port and dbus env to avoid hanging
ENV DISPLAY=:99
ENV DBUS_SESSION_BUS_ADDRESS=/dev/null
USER qtuser
ENV HOME /home/qtuser
WORKDIR /htmltopdf

whenever I run this image I'm getting below error

qt.qpa.xcb: could not connect to display :99
    qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
    This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

I want to run this without using host support only way to run above image is using below command

docker run --rm -it -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY -v $(pwd):/htmltopdf --device=/dev/dri:/dev/dri htmltopdf:latest python3 htmlToPdfnew.py --url https://www.w3schools.com/howto/howto_css_register_form.asp

Is it possible to run PyQT without using these ???
-v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY --device=/dev/dri:/dev/dri

I tried everything in internet

installed xvfb, xorg,vnc

still no luck

this is my python code

import sys
from PyQt5 import QtWidgets, QtWebEngineWidgets
from PyQt5.QtCore import QUrl, QTimer
from PyQt5.QtGui import QPageLayout, QPageSize
from PyQt5.QtWidgets import QApplication
import argparse



def _fullScreenRequested(request):
    request.accept()
    loader.showFullScreen()

def main():
    url = ''
    parser = argparse.ArgumentParser(description="Just an example", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("--url", help="Type url")
    args = parser.parse_args()
    config = vars(args)
    url = config['url']


    app = QtWidgets.QApplication(sys.argv)
    loader = QtWebEngineWidgets.QWebEngineView()
    loader.setZoomFactor(1)
    layout = QPageLayout()
    layout.setPageSize(QPageSize(QPageSize.A4Extra))
    layout.setOrientation(QPageLayout.Portrait)
    loader.load(QUrl(url))
    loader.page().pdfPrintingFinished.connect(lambda *args: QApplication.exit())

    def emit_pdf(finished):
        QTimer.singleShot(2000, lambda: loader.page().printToPdf("test.pdf", pageLayout=layout))

    loader.loadFinished.connect(emit_pdf)
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

So how can I run above code without using these ??

-v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY --device=/dev/dri:/dev/dri

commented

When you use QtWidgets,QtWebEngineWidgets,QApplication, which means you use GUI mode, you must use display. the xcb error you can search Qt platform plugin "xcb" in "" even though it was found by google, and install some library.

or

you can run QCoreApplication, no gui mode, use QWebEnginePage to load url

@892768447 so I changed the code like below

import sys
from PyQt5 import QtWidgets, QtWebEngineWidgets
from PyQt5.QtCore import QUrl, QTimer, QCoreApplication
from PyQt5.QtGui import QPageLayout, QPageSize
from PyQt5.QtWidgets import QApplication
import argparse



def _fullScreenRequested(request):
    request.accept()
    loader.showFullScreen()

def main():
    url = ''
    parser = argparse.ArgumentParser(description="Just an example", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("--url", help="Type url" , required=True)
    args = parser.parse_args()
    config = vars(args)
    url = config['url']

    app = QCoreApplication(sys.argv)
    loader = QtWebEngineWidgets.QWebEnginePage()
    loader.setZoomFactor(1)
    layout = QPageLayout()
    layout.setPageSize(QPageSize(QPageSize.A4Extra))
    layout.setOrientation(QPageLayout.Portrait)
    loader.load(QUrl(url))
    loader.page().pdfPrintingFinished.connect(lambda *args: QCoreApplication.exit())

    def emit_pdf(finished):
        QTimer.singleShot(2000, lambda: loader.page().printToPdf("test.pdf", pageLayout=layout))

    loader.loadFinished.connect(emit_pdf)
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

it gives me this error Segmentation fault (core dumped)

commented

I see QWebEnginePage need QtWebEngineWidgets -> QtWidgets -> must need display.
unlike QWebView.

so you muse resolve the DISPLAY problem.

you can make self docker image, run vnc server.
and in your ~/.vnc/xstartup run your application.

I see QWebEnginePage need QtWebEngineWidgets -> QtWidgets -> must need display. unlike QWebView.

so you muse resolve the DISPLAY problem.

you can make self docker image, run vnc server. and in your ~/.vnc/xstartup run your application.

Thank you very much for your sujjestion @892768447
had to create a separate vnc server to run my code.
If anyone wonders below is my Dockerfile (refernce: https://github.com/accetto/ubuntu-vnc-xfce/blob/master/Dockerfile)

FROM ubuntu:20.04 as ubuntupyqt
ENV DEBIAN_FRONTEND=noninteractive
RUN adduser --quiet --disabled-password qtuser && usermod -a -G video qtuser
RUN apt-get update -y \
    && apt-get install alsa -y \
    && apt-get install libnss3 -y \
    && apt-get install -y python3-pyqt5 \
    && apt-get install python3-pip -y \
    && pip3 install pyqtwebengine

FROM ubuntupyqt as stage-ubuntu

ARG ARG_VCS_REF
ARG ARG_VERSION_STICKER

LABEL \
    maintainer="https://github.com/accetto" \
    vendor="accetto" \
    version-sticker="${ARG_VERSION_STICKER}" \
    org.label-schema.vcs-ref="${ARG_VCS_REF}" \
    org.label-schema.vcs-url="https://github.com/accetto/ubuntu-vnc-xfce"

### 'apt-get clean' runs automatically
RUN apt-get update \
    && DEBIAN_FRONTEND=noninteractive apt-get install -y \
        inetutils-ping \
        lsb-release \
        net-tools \
        unzip \
        vim \
        zip \
        curl \
        git \
        wget \
        nano
RUN rm -rf /var/lib/apt/lists/*

### install current 'jq' explicitly
RUN \
    { \
    JQ_VERSION="1.6" ; \
    JQ_DISTRO="jq-linux64" ; \
    cd /tmp ; \
    wget -q "https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/${JQ_DISTRO}" ; \
    wget -q "https://raw.githubusercontent.com/stedolan/jq/master/sig/v${JQ_VERSION}/sha256sum.txt" ; \
    test=$(grep "${JQ_DISTRO}" sha256sum.txt | sha256sum -c | grep -c "${JQ_DISTRO}: OK") ; \
    if [ $test -ne 1 ] ; then \
        echo "FAILURE: ${JQ_DISTRO} failed checksum test" ; \
        exit 1 ; \
    else \
        rm sha256sum.txt ; \
        chown root "${JQ_DISTRO}" ; \
        chmod +x "${JQ_DISTRO}" ; \
        # mv -f "${JQ_DISTRO}" $(which jq) ; \
        mv -f "${JQ_DISTRO}" /usr/bin/jq ; \
    fi ; \
    cd - ; \
    }

### next ENTRYPOINT command supports development and should be overriden or disabled
### it allows running detached containers created from intermediate images, for example:
### docker build --target stage-vnc -t dev/ubuntu-vnc-xfce:stage-vnc .
### docker run -d --name test-stage-vnc dev/ubuntu-vnc-xfce:stage-vnc
### docker exec -it test-stage-vnc bash
# ENTRYPOINT ["tail", "-f", "/dev/null"]

FROM stage-ubuntu as stage-xfce

ENV \
    LANG='en_US.UTF-8' \
    LANGUAGE='en_US:en' \
    LC_ALL='en_US.UTF-8'

### 'apt-get clean' runs automatically
RUN apt-get update \
    && DEBIAN_FRONTEND=noninteractive apt-get install -y \
        mousepad \
        locales \
        supervisor \
        xfce4 \
        xfce4-terminal \
    && locale-gen en_US.UTF-8 \
    && apt-get purge -y \
        pm-utils \
        xscreensaver* \
    && rm -rf /var/lib/apt/lists/*

FROM stage-xfce as stage-vnc

### 'apt-get clean' runs automatically
### installed into '/usr/share/usr/local/share/vnc'
### Bintray has been deprecated and disabled since 2021-05-01 
# RUN wget -qO- https://dl.bintray.com/tigervnc/stable/tigervnc-1.10.1.x86_64.tar.gz | tar xz --strip 1 -C /
# RUN wget -qO- https://github.com/accetto/tigervnc/releases/download/v1.10.1-mirror/tigervnc-1.10.1.x86_64.tar.gz | tar xz --strip 1 -C /
RUN wget -qO- https://sourceforge.net/projects/tigervnc/files/stable/1.10.1/tigervnc-1.10.1.x86_64.tar.gz | tar xz --strip 1 -C /

FROM stage-vnc as stage-novnc

### same parent path as VNC
ENV NO_VNC_HOME=/usr/share/usr/local/share/noVNCdim

### 'apt-get clean' runs automatically
### 'python-numpy' used for websockify/novnc
### ## Use the older version of websockify to prevent hanging connections on offline containers, 
### see https://github.com/ConSol/docker-headless-vnc-container/issues/50
### installed into '/usr/share/usr/local/share/noVNCdim'
RUN apt-get update \
    && DEBIAN_FRONTEND=noninteractive apt-get install -y \
        python-numpy \
    && mkdir -p ${NO_VNC_HOME}/utils/websockify \
    && wget -qO- https://github.com/novnc/noVNC/archive/v1.2.0.tar.gz | tar xz --strip 1 -C ${NO_VNC_HOME} \
    && wget -qO- https://github.com/novnc/websockify/archive/v0.9.0.tar.gz | tar xz --strip 1 -C ${NO_VNC_HOME}/utils/websockify \
    && chmod +x -v ${NO_VNC_HOME}/utils/*.sh \
    && rm -rf /var/lib/apt/lists/*

### add 'index.html' for choosing noVNC client
RUN echo \
"<!DOCTYPE html>\n" \
"<html>\n" \
"    <head>\n" \
"        <title>noVNC</title>\n" \
"        <meta charset=\"utf-8\"/>\n" \
"    </head>\n" \
"    <body>\n" \
"        <p><a href=\"vnc_lite.html\">noVNC Lite Client</a></p>\n" \
"        <p><a href=\"vnc.html\">noVNC Full Client</a></p>\n" \
"    </body>\n" \
"</html>" \
> ${NO_VNC_HOME}/index.html

FROM stage-novnc as stage-wrapper

### 'apt-get clean' runs automatically
### Install nss-wrapper to be able to execute image as non-root user
RUN apt-get update \
    && DEBIAN_FRONTEND=noninteractive apt-get install -y \
        gettext \
        libnss-wrapper \
    && rm -rf /var/lib/apt/lists/*

FROM stage-wrapper as stage-final

LABEL \
    any.accetto.description="Headless Ubuntu VNC/noVNC container with Xfce desktop" \
    any.accetto.display-name="Headless Ubuntu/Xfce VNC/noVNC container" \
    any.accetto.expose-services="6901:http,5901:xvnc" \
    any.accetto.tags="ubuntu, xfce, vnc, novnc"

### Arguments can be provided during build
ARG ARG_HOME
ARG ARG_REFRESHED_AT
ARG ARG_VERSION_STICKER
ARG ARG_VNC_BLACKLIST_THRESHOLD
ARG ARG_VNC_BLACKLIST_TIMEOUT
ARG ARG_VNC_PW
ARG ARG_VNC_RESOLUTION

ENV \
    DISPLAY=:1 \
    HOME=${ARG_HOME:-/home/headless} \
    NO_VNC_PORT="6901" \
    REFRESHED_AT=${ARG_REFRESHED_AT} \
    STARTUPDIR=/dockerstartup \
    VERSION_STICKER=${ARG_VERSION_STICKER} \
    VNC_BLACKLIST_THRESHOLD=${ARG_VNC_BLACKLIST_THRESHOLD:-20} \
    VNC_BLACKLIST_TIMEOUT=${ARG_VNC_BLACKLIST_TIMEOUT:-0} \
    VNC_COL_DEPTH=24 \
    VNC_PORT="5901" \
    VNC_PW=${ARG_VNC_PW:-headless} \
    VNC_RESOLUTION=${ARG_VNC_RESOLUTION:-1360x768} \
    VNC_VIEW_ONLY=false

### Creates home folder
WORKDIR ${HOME}

COPY [ "./src/startup", "${STARTUPDIR}/" ]

### Preconfigure Xfce
COPY [ "./src/home/Desktop", "./Desktop/" ]
COPY [ "./src/home/config/xfce4/panel", "./.config/xfce4/panel/" ]
COPY [ "./src/home/config/xfce4/xfconf/xfce-perchannel-xml", "./.config/xfce4/xfconf/xfce-perchannel-xml/" ]

### 'generate_container_user' has to be sourced to hold all env vars correctly
RUN echo 'source $STARTUPDIR/generate_container_user' >> ${HOME}/.bashrc

### Fix permissions
RUN chmod +x \
        "${STARTUPDIR}/set_user_permissions.sh" \
        "${STARTUPDIR}/vnc_startup.sh" \
        "${STARTUPDIR}/version_of.sh" \
        "${STARTUPDIR}/version_sticker.sh" \
    && gtk-update-icon-cache -f /usr/share/icons/hicolor \
    && "${STARTUPDIR}"/set_user_permissions.sh "${STARTUPDIR}" "${HOME}"    

EXPOSE ${VNC_PORT} ${NO_VNC_PORT}

USER qtuser
ENV XDG_RUNTIME_DIR /home/qtuser

### Issue #7: Mitigating problems with foreground mode
WORKDIR ${STARTUPDIR}
ENTRYPOINT ["./vnc_startup.sh"]
CMD [ "--wait" ]