Pyinstaller

用户将python程序打包成各个平台可直接运行的程序,也可以算作是对代码加密的一种方式。pyinstaller的安装及使用方式请参考官网。

注:该文章的系统环境是ubuntu

将flask应用打包

项目结构

这是我开发的一个项目,并且已经成功打包并上线运行

项目结构

api 所有的代码都在里面

app.py只有一行代码,from api import create_app

开始打包

下面我们来将该项目打包pyinstaller -F app.py -name app, 通过这个命令,我们就能将整个项目打包成一个名为app的bin文件。直接运行./app,你会发现程序没有运行,因为app.py里面只是单纯的引入了app模块,如果你想通过flask run来执行的话,抱歉,app是个bin文件,不是python模块,会提示找不到app的,简单的解决办法就是在app.py文件中添加以下代码.

from api import create_app

if __name__ == "__main__":

app = create_app()

app.run()

然后在执行打包命令pyinstaller -F app.py -name app,这个时候我们的app就可以直接运行了./app,想要在启动的时候指定端口,主机名等等的参数,使用click.

使用gunicorn

总所周知,flask使用的是Werkzeug来作为它的WSGI server,但是性能很一般,生产环境一般会使用其他的WSGI server, 网上查到有以下WSGI server:

Gunicorn 独角兽,从Ruby的Unicorn移植过来的。

uWSGI 比较全能的一个WSGI server。

mod_wsgi 这个包提供了一个Apache模块,并实现了与wsgi兼容的接口,可以让python程序运行在Apache web server之上。

CherryPy CherryPy是Python的一个HTTP Framework,然后它也有WSGI server。

可能还有其他的一些WSGI server,对于这几种,哪个好,我也不知道,我只对于gunicorn熟悉,那么要使用gunicorn,app.py需添加以下代码:

import gunicorn.app.base

class StandaloneApplication(gunicorn.app.base.BaseApplication):

"""

Custom application

"""

def init(self, parser, opts, args):

pass

def __init__(self, app, options=None):

self.options = options or {}

self.application = app

super(StandaloneApplication, self).__init__()

def load_config(self):

config = dict([(key, value) for key, value in iteritems(self.options)

if key in self.cfg.settings and value is not None])

for key, value in iteritems(config):

self.cfg.set(key.lower(), value)

def load(self):

return self.application

if __name__ == "__main__":

options = {

"bind": "127.0.0.1:8000"

}

StandaloneApplication(app, options=options).run()

接下来再执行pyinstaller -F app.py -name app,./app就会使用gunicorn来运行服务了,对于gunicorn的参数,依然使用click来搞定。然而,当你开开心心运行程序的时候,突然报错了:

gunicorn.glogging是啥?它为什么找不到?我要去哪里找它?这是gunicorn的日志包,但是pyinstaller在打包的时候没有将它一起打入进去,所以运行是找不到,这里我们需要在打包的时候加个参数:

pyinstaller -F app.py --name app --hidden-import=gunicorn.glogging

这是啥意思呢,因为gunicorn自身的代码,并没有直接引入这个包,所以需要手动添加,--hidden-import参数含义请翻阅官方文档。接下来运行./app,还是报错,为什么路途就这么不顺呢?

这个包是gunicorn默认的工作类,pyinstaller在打包的时候也没有将它一起打入进去

pyinstaller -F app.py --name app \

--hidden-import=gunicorn.glogging \

--hidden-import=gunicorn.workers.sync

再次执行./app,程序就完美使用gunicorn来运行了。如果你想使用其他的worker_class,请在打包的时候传入对应的包名,如:

pyinstaller -F app.py --name app \

--hidden-import=gunicorn.glogging \

--hidden-import=gunicorn.workers.sync \

--hidden-import=gunicorn.workers.ggevent

添加命令行工具

像flask一样

从flask 0.11版本开始,就内建了一个命令行工具flask,而我们在开发项目的时候,也会添加一些自定义命令,然后通过flask来执行。为了让我们的打包后的可执行文件能够实现这一功能,修改app.py代码:

...

if __name__ == "__main__":

...

app.cli()

但是酱紫之后,服务如何来启动呢,我的解决办法是添加一个run命令到app.cli里面,大家如果有更好的方法,还望不吝赐教。

...

def run():

"""运行服务"""

options = {

...

}

StandaloneApplication(app, options=options).run()

if __name__ == "__main__":

app.cli.add_command(run)

app.cli()

打包之后,运行./app和./app run,运行十分顺利。

支持db命令

flask_migrate数据库迁移库是个相当棒的工具,flask命令会自动去添加db命令,我们也可以把它添加到我们的命令中去:

...

from flask_migrate.cli import db

if __name__ == "__main__":

...

app.cli.add_command(db)

...

之后当你兴高采烈的运行db命令的时候,又一个拦路虎出现了

找不到flask应用,我不是app = create_app()已经创建了么,为啥还要去找FLASK_APP这个环境变量呢,其实不单单是db命令会报这个错,就连我们自己写的命令也可能会报这个错,我们先来查看源代码flask_migrate/cli.py,大概在85行的位置:

...

@with_appcontext

def migrate(directory, message, sql, head, splice, branch_label, version_path,

rev_id, x_arg):

"""Autogenerate a new revision file (Alias for 'revision --autogenerate')"""

_migrate(directory, message, sql, head, splice, branch_label, version_path,

rev_id, x_arg)

这里使用了with_appcontext这个装饰器,它来自于flask/cli.py文件:

def with_appcontext(f):

@click.pass_context

def decorator(__ctx, *args, **kwargs):

with __ctx.ensure_object(ScriptInfo).load_app().app_context():

return __ctx.invoke(f, *args, **kwargs)

return update_wrapper(decorator, f)

这个装饰器的作用就是让被装饰的函数在app的上下文去执行,__ctx.ensure_object(ScriptInfo).load_app()这个函数就是flask根据FLASK_APP环境变量,或者默认的文件名app.py, wsgi.py,去找到app,所以db使用的app都是它自己去找到位置然后定义。如果使用的是flask.cli.AppGroup来定义自己的命令,那么也是一样的逻辑。所以现在要解决的问题是如何把我们手动创建的app传入进去。很直接的我想到的是current_app,只要把我们的app压入栈就可以了。

# overide.py

import click

from functools import update_wrapper

from flask import current_app

from flask.cli import with_appcontext as origin_with_appcontext

def override_with_appcontext(f):

@click.pass_context

def decorator(__ctx, *args, **kwargs):

with current_app.app_context():

return __ctx.invoke(f, *args, **kwargs)

return update_wrapper(decorator, f)

# If the app starts up in Pyinstaller binary mode, the bootloader will set sys.frozen attribute.

if hasattr(sys, "frozen"):

with_appcontext = override_with_appcontext

print("Use override with_appcontext")

else:

with_appcontext = origin_with_appcontext

print("Use original with_appcontext")

# app.py

...

ctx = app.app_context()

ctx.push()

app.cli()

ctx.pop() # 这里的pop运行不到这里来

这里我兼容pyinstaller打包的运行的和常规运行两种,然后在需要上下文的命令函数加上重写后的with_appcontext就可以了,而对于flask_migrate.cli.db,我采用暴力的方式,直接拷贝了它的源代码,然后使用重写的with_appcontext,然后再打包就可以了。

其他注意点

非python文件的使用

如果你代码里面读取了其他文件的内容,那么在打包的时候,需要把这些文件加上,通过--add-data来添加, 代码中通过下面代码来判断

base_path = getattr(sys, "_MEIPASS",os.path.realpath(os.path.dirname(__file__)))。

gunicorn使用gevent

gunicorn使用gevent的时候,需要在代码最前面加上

from gevent import monkey

monkey.patch_all(subprocess=True)

本文作者: Lim

版权声明: 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

python打包flask 项目_使用pyinstaller将flask应用打包相关推荐

  1. python视频网站项目_[项目实战] Python Flask构建微电影视频网站

    注:本站源码仅做学术研究,自娱自乐使用,不得用于任何的非法商业用途 由于版权原因.本站将无限期停止微擎模块资源下载如果有任何侵犯您权益的内容请联系小站删除哦.小站一定会积极配合的. 课程目录: (下载 ...

  2. java和python结合做项目_由浅入深Java+Python结合项目实战

    [课程内容] [初级项目:图片社交+电商导购+漂流瓶] 项目实现功能: 用户注册,登录,登出图片的多种上传方式,删除首页图片分类,排序和分页个人页管理图片分享 课程内容: 开发工具和Python语言介 ...

  3. webpack 打包ts项目_使用webpack打包ts

    初始化package.json npm init -y cnpm i -D webpack webpack-cli(webpack命令行工具) typescript ts-loader(整合) 2.1 ...

  4. python怎么做项目_听说你没有python项目可做,我教你个方法

    原标题:听说你没有python项目可做,我教你个方法 学习了一段时间的Python,最近出现了"饥荒",感觉需要多看些代码,多学习学习别人做些什么,但却不知道做点什么来进行练习. ...

  5. python视频网站项目_价值2400元的python全栈开发系列Flask Python Web 网站编程视频

    2 e/ b4 F1 c' H$ D! X 价值2400元的python全栈开发系列Flask Python Web 网站编程视频-优品课堂' z3 _1 Y7 ]6 j4 z # p# r# g* ...

  6. windows 打包 python 然后linux执行_使用pyinstaller打包python源代码,成为linux/windows下可执行文件...

    pyinstaller,打包python源代码,成为linux/windows下可执行文件,多平台 下载:http://www.pyinstaller.org/static/ http://www.p ...

  7. python潜力开源项目_比较了1000多个Python开源项目,精选出这34个

    传智播客博学谷 微信号:boxuegu- get最新最全的IT技能 免费领取各种视频资料 在过去的一年里,Mybridge比较了近1000个的Python开源库,并从中评选出34个最有用的工具来帮助你 ...

  8. python打印汉字宝塔_利用宝塔+python+搭建falsk项目_详(一)

    首先安装python3 安装python3后安装宝塔面板 Centos安装脚本 : yum install -y wget && wget -O install.sh http://d ...

  9. python秒表小项目_适合新手练习的几个python小项目

    关于python练习的小项目,其实就是一些常用的模块的针对练习 一.找出电脑中遗忘的大文件 # !/usr/bin/env python # _*_ coding:utf-8 -*- import o ...

最新文章

  1. 网络推广——移动端网络推广备受关注
  2. UIAutomator 2
  3. elxel表格纸张尺寸_纸张知识|克重厚薄多少,正度大度纸开本尺寸规格是什么大小,和A4有啥区别?...
  4. BZOJ2442: [Usaco2011 Open]修剪草坪 单调队列优化dp
  5. php js date 格式化,javascript date格式化示例_javascript技巧
  6. 软件开发模式:瀑布与敏捷
  7. java 静态方法的使用_java的静态方法的使用
  8. android 重绘如何能不闪一下屏幕_前端性能优化之重绘和重排
  9. ThinkPad SL400 改装Win2003方法以及驱动下载列表
  10. matlab covar,Matlab功率谱估计
  11. word 批量转 pdf
  12. excel 将日期转换为8位数字
  13. scu(snoop control unit)
  14. python密码安全性检查代码
  15. pixel2真机调试aosp
  16. 最全面的 Fiddler 教程讲解
  17. matlab中基于传递函数或者状态方程的幅频特性分析
  18. Go语言学习笔记(三)---指针,运算符及流程控制
  19. python爬虫爬取安居客并进行简单数据分析
  20. 【AAAI2023】视觉辅助的常识知识获取Visually Grounded Commonsense Knowledge Acquisition 个人学习笔记

热门文章

  1. Flask入门教程—超详细
  2. RK3288 资源汇总
  3. 报错:RuntimeError: expected scalar type Double but found Float
  4. 单元测试|Unittest setup前置初始化和teardown后置操作
  5. 2023年网络安全HW攻防技术总结(珍藏版)
  6. Apple Music 推出空间音频和无损音频
  7. macOS手动启动 Simulator(ios模拟器)
  8. 第十七届全国大学生智能车竞赛 华南赛区竞赛(线上)事宜通知
  9. 2016.7.14 如何在浏览器中查看jsp文件
  10. 如何在计算机面试中牵着面试官鼻子走?