设为首页 加入收藏

TOP

我自己的 Python Web 框架(一)
2023-07-23 13:45:52 】 浏览:71
Tags:Python Web 框架

原文地址: https://healeycodes.com/my-own-python-web-framework

在过去的几个月里,我一直在从头开始建立我自己的软件工具--像编程语言文本编辑器CLI工具。在周末,我建立了一个概念验证的网络框架,通过Build Output API部署到Vercel。

一个基于文件系统的规范,允许任何框架为Vercel构建,并利用Vercel的基础设施构建块,如边缘函数、边缘中间件、增量静态再生(ISR)、图像优化等。

Jar是一个玩具Python网络框架,用大约200行代码实现(见 cli.py )。我建立它是为了探索一些围绕框架API的想法,并从作者方面探索框架。请不要真的使用它。它之所以被称为Jar,是因为它几乎没有任何功能,你需要自己去填充它!

它使用文件系统路由并支持。

Jar项目的结构是这样的:

project/
├─ pages/
│  ├─ index.py
├─ public/
│  ├─ favicon.ico

API理念

我对Jar的个人使用情况是在没有前台框架的情况下建立小型动态网站。受到Next.js的API的一点启发,比如 getServerSidePropsgetStaticProps ,Jar的API是由三个函数签名定义的。

  • 数据函数在构建页面和重新生成的页面时被调用。当它在服务器上被调用时,它会收到一个带有方法、路径、头信息和正文的请求对象。

  • render函数接收data函数的返回值,并返回一个 body, info 的元组,其中的信息可以改变响应的状态代码和头文件。

  • 配置函数定义了页面的类型(构建、新鲜或再生)。

这是一个生成页面的例子kitchen sink example:

import time

def render(data):
    return f"<h1>Last regenerated at: {data['time']}</h1>", {}

def data(request=None):
    return {
        "time": time.time()
    }

def config():
    return {
        "regenerate": {
            "every": 5
        }
    }

因为我们是在Python领域,我希望API是灵活的。数据和配置函数是可选的(而且它们不需要接受任何参数)。因此,最小的Jar页面看起来像这样。

render = lambda: (“Hi! I'm a little page.”, {})

构建CLI

在对Jar的CLI进行原型设计时,Build Output API的文档例子足够全面,我没有遇到任何重大问题。通过试验和错误,没过多久我就通过构建和部署真正的项目来测试Jar(从头到尾大约需要6秒钟)。

Jar需要在构建时和在服务器上渲染页面,并使用大量的动态导入和元编程来减少代码行和复杂性。

为了把用户编写的页面当作 Python 模块,在运行时要像这样导入。

module_location = "project/pages/index.py"
spec = importlib.util.spec_from_file_location("", module_location)
page = importlib.util.module_from_spec(spec)
spec.loader.exec_module(page)
# `page` can now be called like `page.render()`

这意味着动态导入的构建页面可以在构建时被调用以生成静态文件。

# `page` is a dynamically imported module e.g. it exists at `pages/index.py`
with open(os.path.join(build_dir, f".vercel/output/static/{request_path}"), "w") as f:
    res = call_render(page)
    f.write(res['body'])
    build_config['overrides'][request_path] = {
        'contentType': res['headers']['Content-Type']
    }

为了创建新鲜和再生的页面,Jar创建了使用 python3.9 运行时的无服务器函数。用于创建构建页面的相同函数(例如 call_data , call_render )被写入一个处理文件,以便它们可以根据需要在服务器上运行。当我说相同的函数时,我的意思是它们是真的从内存中读取的。

def create_handler(path, module_location):
    # the following functions are used at build time to generated build pages
    # and are also used on the server to generated fresh/regenerated pages
    # so we bundle them into a handler file
    with open(path, "w") as f:
        # imports
        f.write("import json\nimport inspect\nimport importlib.util\n")
        f.write('\n')
        # request class
        request_source = inspect.getsource(Request)
        f.write(request_source)
        f.write('\n')
        # call_data function
        call_data_source = inspect.getsource(call_data)
        f.write(call_data_source)
        f.write('\n')
        # call_render function
        call_render_source = inspect.getsource(call_render)
        f.write(call_render_source)
        f.write('\n')
        # app function
        app_source = inspect.getsource(app)
        f.write(app_source.replace("__MODULE_LOCATION", module_location))
        f.write('\n')

构建输出API要求像包这样的外部文件被包含在函数的文件系统中。

一个无服务器功能在文件系统中被表示为一个名称上带有 .func 后缀的目录,包含在 .vercel/output/functions 目录中。
从概念上讲,你可以把这个 .func 目录看作是无服务器功能的文件系统挂载: .func 目录以下的文件被包括在内(递归), .func 目录以上的文件则不包括在内。私人文件可以安全地放在这个目录中,因为它们不会被终端用户直接访问。

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇git的介绍和使用 下一篇python基础-流程控制

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目