Giter VIP home page Giter VIP logo

pyfladesk's Introduction

PyFladesk

Create desktop application by using Flask and QtWebEngine.

Idea

Rather than open Flask app in user browser, create a QWebview and then run Flask app on it.

By default, every internal link is open inside the app and every external link is open in the default browser.

Dependencies

  • Python3
  • Flask
  • PyQt

Note: Some releases require Conda to properly create a virtual environment.

Versions

There are 3 available versions:

Note: Both PyQt4 and PyQt5.6 are only made available for compatibility reasons, there is no intention to keep them updated unless requested.

Installation with pip

If you want to install PyFladesk with pip you just run.

pip install pyfladesk

Only the latest version (PyQt5.10) is uploaded to PyPI. If you want to use a legacy version check the instructions in the corresponding branch readme. Each version is maintained in a different form due to versions issues so you should check the readme of the branch of the version you want to use.

No pip installation

In case you don't want to use pip or you want to use a freezed version of PyFladesk, just download the __init__.py file from the pyfladesk folder and place it in your project (change the name to pyfladesk.py), then you can follow the instructions below.

Usage

You just need to change two lines:

Add an import at the top:

from pyfladesk import init_gui

And wherever you run the app (app.run) replace it with:

init_gui(app)

Then run your app as usual

Example

from flask import Flask
from pyfladesk import init_gui

app = Flask(__name__)

from routes import *

if __name__ == '__main__':
    init_gui(app)

Parameters

The init_gui function has some optional parameters that you may find useful:

init_gui(application, port=5000, width=300, height=400,
             window_title="PyFladesk", icon="appicon.png", argv=None)
  • port: choose in which port the application will run.
  • width: The initial width of the main window.
  • height: The initial height of the main window.
  • window_title: The main window title.
  • icon: the path to the icon file of the main window.
  • argv: additional parameters to the QApplication instance.

Packaging

For a full guide on how to package the app in one executable with PyInstaller file check this blog post

This avoids the need for the Python interpreter and the packages you use inside your project.

If you haven't already, install it with pip (if you use virtual environments you should install it inside it).

pip install pyinstaller

Some parameters to consider:

  • F - Bundles everything in a single file
  • w - Avoid displaying a console
  • --add-data - Add Folders to the directory/executable

Since Flask relies on a directory structure you should pass it to the folder, in the example case we only have two folders: templates and static, in case you use a database or some other directory structure you should adapt this.

Note: For more complex scenarios check the PyInstaller Docs

If we want everything in one executable file we can

Windows:

pyinstaller -w -F --add-data "templates;templates" --add-data "static;static" app.py

Linux:

pyinstaller -w -F --add-data "templates:templates" --add-data "static:static" app.py

Depending on the Linux version, you might need to install sudo apt install libpython3.x-dev

This will create a folder dist with our executable ready to be shipped. The executable will open the main window of our app.

If you still see TemplateNotFound, you may try the following (From issue #9):

Define this in a helper script:

def resource_path(relative_path):
 """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)

Include this at the top, under imports

if getattr(sys, 'frozen', False):
    template_folder = resource_path('templates')
    static_folder = resource_path('static')
    app = Flask(__name__, template_folder=template_folder, static_folder=static_folder)
else:
    app = Flask(__name__)

Also from issue #9, in Windows 10 you may need to run this script:

pyinstaller -w -F --add-data "templates;templates" --add-data "static;static" app.py --path 'C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x64'

Since Qt is quite big, your executables will be big too. The example app of this repository is 70 MB (69 MB of which are the Qt Component for displaying HTML). This is reasonable taking into account that we are shipping a self contain web browser. In case size is crucial, you can follow this suggestions

Sample apps

List of apps made by PyFladesk

Contributing Oportunities

Feel free to open issues and pull requests for new features and improvements. This is a guide for things that may be useful for the project:

  • Add different backends (wxPython, TKinter, etc)
  • Test performance of HTML5 and CSS3
  • Add Directory structure for large projects (Flask Patterns)
  • Test other micro web frameworks (Bottle, etc)
  • Make sample apps

Thanks

Thanks to Mathias Ettinger for his reviews, one for the old code and one for the new one

pyfladesk's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyfladesk's Issues

Change host?

Hi, i was wondering how could i change host.. Normally we put it in app.run() but now it's replace by init_gui how we do it? I'm trying to get access over my network so 0.0.0.0

Btw i'm not advanced in Python/Flask thanks in advance.

Use PySide2 instead of PyQt5

PyQt5 is licensed GPL3 or commercial. That can be problematic. Would it be possible to use PySide2 which is LGPLv3 licensed (besides GPLv2 and commercial) and API compatible? This is no legal advice but opinion based suggestion: Using a LGPL license for PyFladesk would allow other projects to use PyFladesk without being forced to be open sourced themself by externalizing PyFladesk as LGPL dependency like described here.

Context menu in QtWebEngine

Can you tweak it, so that, at least in development -- 1. Developer menu 2. Open in external browser.

Currently, I use simply print(url), to help opening in external browser, if I need it.

App window opens and then closes when bundled in an .exe

Hi I'm using windows 10, python 3.6.4, I'm trying to bunddle the example app into an .exe.

When I run it with this command it works just fine, it stays open but it shows the console (I dont want the console to be seen):

pyinstaller -F --add-data "templates;templates" --add-data "static;static" app.py

But if I run it with this command it shows a window and then closes.

pyinstaller -w -F --add-data "templates;templates" --add-data "static;static" app.py

It seems that when the console is closed the Flask server process is closed too.
Any idea of how could this be solved?

Thanks in advance

Add Backward Compatibility to PyQt4 and <=PyQt5.6

I've already create two separated branches for the PyQt4 version and the PyQt5.6 version. The 5.6 is the one with greatest performance since QWebView is still faster than QWebEngineView.

Create two branches in the main repository so I can open a PR. One branch from 8baec2 and another from c44a01

Port 0

It isn't natively supported in PyFladesk, but I got it working with (according to SO)

import socket

if port == 0:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost', 0))
    port = sock.getsockname()[1]
    sock.close()

My full edit of __init__.py.

Question: Is it possible to create a new window in pyfladesk?

I would like to open up a new window if for example a certain link or button is clicked. The new window should render a template for example. Is this possible?

I tried to implement it manually but unfortunately did not succeed.

thanks in advance

rerouting problem

when I add an tag in index.html and its have typical flask {{url_for('foo')}} as their href. it opens the content with my browser but I want to render other template within the main window of the app and close temporarily the index.html.

any solution for this?

How to provide a File as download/output ?

I am trying to build a flask app, which takes in a file, saves and processes the file based on its contents and give the file as an output.

In a browser the file can be downloaded but when I use pyfladesk I am unable to download the file.

I am using the 'send_file' function to output the file.

Qt error message after closing the window

Your code works like a charm out-of-the-box, thank you! Anyway, I think I have discovered a cosmetic defect that does not affect the functionality of the program, but is probably easy to fix. I'm not deep enough into PyQt5 to know exactly what needs to be done, but maybe you can help out?

It must be the part that opens external links in the browser (I checked that):

class WebPage(QtWebEngineWidgets.QWebEnginePage):
def __init__(self, root_url):
super(WebPage, self).__init__()
self.root_url = root_url
def home(self):
self.load(QtCore.QUrl(self.root_url))
def acceptNavigationRequest(self, url, kind, is_main_frame):
"""Open external links in browser and internal links in the webview"""
ready_url = url.toEncoded().data().decode()
is_clicked = kind == self.NavigationTypeLinkClicked
if is_clicked and self.root_url not in ready_url:
QtGui.QDesktopServices.openUrl(url)
return False
return super(WebPage, self).acceptNavigationRequest(url, kind, is_main_frame)

With window stuff you often have to explicitly dispose the widgets before exiting the program. Otherwise it can happen that somewhere else an event listener gets an event and wants to do something, although parts of the program are already gone โ†’ segfault. Does this make sense?

When I run your app.py in the examples folder and close the Qt window again, I get the following error message in the console:

Received signal 11 SEGV_MAPERR 000000000000
#0 0x7f2642d0b9a5 <unknown>
#1 0x7f2641a4b501 <unknown>
#2 0x7f2642d0bd3d <unknown>
#3 0x7f26543db890 <unknown>
#4 0x7f264a2649a3 QGuiApplication::font()
#5 0x7f264aa79e29 QApplication::font()
#6 0x7f264aa7b1f3 QApplication::font()
#7 0x7f264aaa2fe1 QWidgetPrivate::naturalWidgetFont()
#8 0x7f264aaa968d QWidgetPrivate::resolveFont()
#9 0x7f264aab8427 QWidget::setParent()
#10 0x7f264aab8eac QWidget::setParent()
#11 0x7f26481def7a <unknown>
#12 0x7f26481dd26b <unknown>
#13 0x7f26481cdcc4 QWebEnginePage::~QWebEnginePage()
#14 0x7f26484089f9 sipQWebEnginePage::~sipQWebEnginePage()
#15 0x7f264b8f1686 forgetObject
#16 0x7f264b8f16a9 sipWrapper_dealloc
#17 0x0000004d8395 <unknown>
#18 0x00000048a6c4 <unknown>
#19 0x00000054f519 <unknown>
#20 0x00000054fe6d <unknown>
#21 0x0000005546cf _PyEval_EvalFrameDefault
#22 0x00000054fbe1 <unknown>
#23 0x000000550b93 PyEval_EvalCode
#24 0x00000042b519 PyRun_FileExFlags
#25 0x00000042b705 PyRun_SimpleFileExFlags
#26 0x000000441fcb Py_Main
#27 0x000000421ff4 main
#28 0x7f2653405b97 __libc_start_main
#29 0x0000004220aa _start
  r8: 000000000800f000  r9: 00007f26547f10a0 r10: 0000000002406d80 r11: 0000000000000000
 r12: 00007ffd4aeb7d50 r13: 00007f264a91b010 r14: 0000000000000000 r15: 0000000000000000
  di: 0000000000000000  si: 0000000000000000  bp: 00000000023b44d0  bx: 00007f264a91b118
  dx: 0000000000000001  ax: 00007f264a91b0a8  cx: 0000000000000016  sp: 00007ffd4aeb7c70
  ip: 00007f264a2649a3 efl: 0000000000010246 cgf: 002b000000000033 erf: 0000000000000004
 trp: 000000000000000e msk: 0000000000000000 cr2: 0000000000000000
[end of stack trace]
Calling _exit(1). Core file will not be generated.

Can you reproduce that?

cant "download" file dont know if its easily possible

I am using flask response for downloading a file within the normal browser

like this:

response = make_response('test')
response.headers["Cache-Control"] = "must-revalidate"
response.headers["Pragma"] = "must-revalidate"
response.headers["Content-type"] = "application/txt"
response.headers["Content-Disposition"] = "attachment; filename="test"
return response

and nothing happend and i dont know how to fix it.

Have found this but i don't know how to deal with it.

https://doc.qt.io/qt-5/qwebengineprofile.html#downloadRequested
https://code.qt.io/cgit/qt/qtwebengine.git/tree/src/webenginewidgets/api/qwebengineprofile.h#n106

Internal server error after packaging with pyinstaller

Hi,
The app works when I run it locally. However once I convert it to an exe using pyinstaller, I get an internal server error. Any ideas on how or where I can start troubleshooting this? First time using pyinstaller. THanks!

Add dependency for PyQtWebEngine

Installed PyFladesk today and wen I tried to run it. I received an import error that QtWebEngineWidgets could not be imported. After installing PyQtWebEngine it ran without errors.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.