通过bench start启动
启动后可以通过http://localhost:8000访问;
Bench是一个命令行实用程序,可以帮助您在[*nix系统](https://en.wikipedia.org/wiki/Unix-like)上安装,更新和管理用于开发和生产的Frappe/ERPNext应用程序的多个站点。
bench通过setuptools打包
如何使用setuptools打包Python项目参考 【新】使用setuptools打包Python项目_python打包setuptools_王路ylu的博客-优快云博客
在pyproject.toml中指定了可执行命令
[project.scripts] bench = "bench.cli:cli"
如:bench start
会执行到bench\bench\cli.py文件里的cli方法。
进入到这个分支:if cmd_from_sys in bench_command.commands:
执行bench_command()
再通过click模块的作用,执行了bench\bench\commands\utils.py中的start创建命令行
@click.command("start", help="Start Frappe development processes") @click.option("--no-dev", is_flag=True, default=False) @click.option( "--no-prefix", is_flag=True, default=False, help="Hide process name from bench start log", ) @click.option("--concurrency", "-c", type=str) @click.option("--procfile", "-p", type=str) @click.option("--man", "-m", help="Process Manager of your choice ;)") def start(no_dev, concurrency, procfile, no_prefix, man):
os.exec*族主要用来代替当前进程,执行新的程序,不返回值。在UNIX上,新的执行程序加载到当前进程,与调用它的进程有相同的id
def start(no_dev=False, concurrency=None, procfile=None, no_prefix=False, procman=None): program = which(procman) if procman else get_process_manager() if not program: raise Exception("No process manager found") os.environ["PYTHONUNBUFFERED"] = "true" if not no_dev: os.environ["DEV_SERVER"] = "true" command = [program, "start"] if concurrency: command.extend(["-c", concurrency]) if procfile: command.extend(["-f", procfile]) if no_prefix: command.extend(["--no-prefix"]) os.execv(program, command)
调用os.execv(program, command),执行命令
这里program默认为honcho
def get_process_manager() -> str: for proc_man in ["honcho", "foreman", "forego"]: proc_man_path = which(proc_man) if proc_man_path: return proc_man_path
honcho是Foreman的python端口,这是一个用于管理基于procfile的应用程序的工具
在frappe-bench目录下有个Profile文件,这里面的内容就是真正执行的命令了
redis_cache: redis-server config/redis_cache.conf redis_socketio: redis-server config/redis_socketio.conf redis_queue: redis-server config/redis_queue.conf web: bench serve --port 8000 socketio: /home/shixb/.nvm/versions/node/v14.21.3/bin/node apps/frappe/socketio.js watch: bench watch schedule: bench schedule
启动WEB服务
Profile文件中的bench serve --port 8000用于在本机的8000端口启动web服务监听
这个命令,会调用到frappe框架下的frappe\frappe\commands\utils.py中的serve方法
@click.command("serve") @click.option("--port", default=8000) @click.option("--profile", is_flag=True, default=False) @click.option("--noreload", "no_reload", is_flag=True, default=False) @click.option("--nothreading", "no_threading", is_flag=True, default=False) @click.option("--with-coverage", is_flag=True, default=False) @pass_context def serve( context, port=None, profile=False, no_reload=False, no_threading=False, sites_path=".", site=None, with_coverage=False, ):
with CodeCoverage(with_coverage, "frappe"): if with_coverage: # unable to track coverage with threading enabled no_threading = True no_reload = True frappe.app.serve( port=port, profile=profile, no_reload=no_reload, no_threading=no_threading, site=site, sites_path=".", )
调用了frappe\frappe\app.py里的serve方法,启动了werkzeug服务
def serve( port=8000, profile=False, no_reload=False, no_threading=False, site=None, sites_path="." ): global application, _site, _sites_path _site = site _sites_path = sites_path from werkzeug.serving import run_simple
werkzeug通过frappe\frappe\app.py中的application处理web请求
@local_manager.middleware @Request.application def application(request: Request):
如,通过http://localhost:8000访问的时候,由frappe\frappe\app.py中的application处理web请求,并跳转到login页面
elif request.method in ("GET", "HEAD", "POST"): response = get_response()
调用了frappe\frappe\website\serve.py中的 get_response方法
def get_response(path=None, http_status_code=200): """Resolves path and renders page""" response = None path = path or frappe.local.request.path endpoint = path try: endpoint, renderer_instance = path_resolver.resolve()//处理请求路径
调用了frappe\frappe\website\path_resolver.py的resolve_path方法
def resolve_path(path): if not path: path = "index" if path.endswith(".html"): path = path[:-5] if path == "index": path = get_home_page()
调用了frappe\frappe\website\utils.py的 get_home_page方法,跳转到login页面
def get_home_page(): if frappe.local.flags.home_page and not frappe.flags.in_test: return frappe.local.flags.home_page def _get_home_page(): home_page = None if not home_page: home_page = "login" if frappe.session.user == "Guest" else "me" home_page = home_page.strip("/") return home_page