#29 Werkzeug WSGI 框架

2017-01-30

示例

from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule

class Application:
    def __init__(self):
        self.url_map = Map([
            Rule('/', endpoint='hello')
        ])

    def hello(self, request):
        text = 'Hello, World!'
        response = Response(text, content_type='text/plain')
        return response

    @Request.application
    def __call__(self, request):
        adapter = self.url_map.bind_to_environ(request.environ)
        endpoint, values = adapter.match()

        handler = getattr(self, endpoint)
        return handler(request, **values)

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    app = Application()
    run_simple('localhost', 5000, app)

Werkzeug 与协程(async/await

Werkzeug 1.x 开始已经提供了对协程的支持。
PS:WSGI 规范是基于同步的设计,没有较好的适配异步编程,所以后面一些更年轻的框架选择了 ASGI(Async Server Gateway Interface)。
PS:2014/03/01, WSGI
PS:2021/11/06, 体验 ASGI

import asyncio
from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule

class Application:
    def __init__(self):
        self.url_map = Map([
            Rule('/', endpoint='hello')
        ])

    async def hello(self, request):
        text = 'Hello, World!'
        response = Response(text, content_type='text/plain')
        return response

    @Request.application
    async def __call__(self, request):
        adapter = self.url_map.bind_to_environ(request.environ)
        endpoint, values = adapter.match()

        handler = getattr(self, endpoint)
        response = await handler(request, **values)
        return response

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    app = Application()
    run_simple('localhost', 5000, app)

附:版本历史

版本 时间
2.3.4 May 9, 2023
2.3.3 May 1, 2023
2.3.2 Apr 29, 2023
2.3.1 Apr 27, 2023
2.3.0 Apr 26, 2023
2.2.3 Feb 15, 2023
2.2.2 Aug 9, 2022
2.2.1 Jul 28, 2022
2.2.0 Jul 24, 2022
2.1.2 Apr 29, 2022
2.1.1 Apr 2, 2022
2.1.0 Mar 29, 2022
2.0.3 Feb 8, 2022
2.0.2 Oct 6, 2021
2.0.1 May 18, 2021
2.0.0 May 12, 2021
1.0.1 Apr 1, 2020
1.0.0 Feb 7, 2020
0.16.1 Jan 27, 2020
0.16.0 Sep 19, 2019
0.15.6 Sep 5, 2019
0.15.5 Jul 17, 2019
0.15.4 May 15, 2019
0.15.3 May 15, 2019
0.15.2 Apr 3, 2019
0.15.1 Mar 22, 2019
0.15.0 Mar 20, 2019
0.14.1 Jan 1, 2018
0.14 Dec 31, 2017
0.13 Dec 8, 2017
0.12.2 May 16, 2017
0.12.1 Mar 16, 2017
0.12 Mar 10, 2017
0.11.15 Dec 31, 2016
0.11.14 Dec 31, 2016
0.11.13 Dec 27, 2016
0.11.12 Dec 26, 2016
0.11.11 Aug 31, 2016
0.11.10 May 24, 2016
0.11.9 Apr 25, 2016
0.11.8 Apr 15, 2016
0.11.7 Apr 15, 2016
0.11.6 Apr 14, 2016
0.11.5 Mar 23, 2016
0.11.4 Feb 15, 2016
0.11.3 Dec 20, 2015
0.11.2 Nov 12, 2015
0.11.1 Nov 10, 2015
0.11 Nov 8, 2015
0.10.4 Mar 26, 2015
0.10.3 Mar 26, 2015
0.10.2 Mar 26, 2015
0.10.1 Feb 4, 2015
0.10 Jan 30, 2015
0.9.6 Jun 7, 2014
0.9.5 Jun 7, 2014
0.9.4 Aug 26, 2013
0.9.3 Jul 25, 2013
0.9.2 Jul 18, 2013
0.9.1 Jun 14, 2013
0.9 Jun 13, 2013
0.8.3 Feb 5, 2012
0.8.2 Dec 16, 2011
0.8.1 Sep 30, 2011
0.8 Sep 30, 2011
0.7.2 Sep 30, 2011
0.7.1 Jul 26, 2011
0.7 Jul 24, 2011
0.6.2 Apr 24, 2010
0.6.1 Apr 13, 2010
0.6 Feb 19, 2010
0.5.1 Jul 10, 2009
0.5 Apr 25, 2009
0.4.1 Jan 11, 2009
0.4 Nov 23, 2008
0.3.1 Jun 24, 2008
0.3 Jun 15, 2008
0.2 Feb 14, 2008
0.1 Dec 10, 2007

#28 The Pallets Projects

2017-01-30

这个组织下的每个项目单拿出来都是响当当的存在:

  • Click — Beautiful, composable command line interface creation kit.
  • Flask — a flexible and popular web development framework
  • ItsDangerous — Safely pass trusted data to untrusted environments and back.
  • Jinja — a full featured template engine for Python
  • MarkupSafe — Safely add untrusted strings to HTML/XML markup.
  • Quart — an async reimplementation of flask
  • Werkzeug — The comprehensive WSGI web application library.
  • Click 命令行工具
  • Flask 轻量级 Web 框架
  • ItsDangerous
  • Jinja 知名模板库
  • MackupSafe
  • Quart
  • Werkzeug Web 工具箱(WSGI),Flask 的底层

#26 Python bytes 类型

2016-05-16
  1. bytes 按索引取值得到的是整数。

    b'abc'[0]
    97
    
  2. strbytes 只需要编码一下就行了。反过来就是解码一下。

    s = '你好'
    b = bytes(s, 'utf-8')
    # b'\xe4\xbd\xa0\xe5\xa5\xbd'
    assert b.decode('utf-8') == s
    
    bytes('hello')
    TypeError: string argument without an encoding
    
    bytes('hello', 'ascii')
    b'hello'
    
    'hello'.encode()
    b'hello'
    
    bytes('hello', 'utf-16')
    b'\xff\xfeh\x00e\x00l\x00l\x00o\x00'
    
    bytes('hello', 'utf-32')
    b'\xff\xfe\x00\x00h\x00\x00\x00e\x00\x00\x00l\x00\x00\x00l\x00\x00\x00o\x00\x00\x00'
    
  3. bytesint 列表的转换。

    list(b'abc')
    [97, 98, 99]
    
    bytes([97, 98, 99])
    b'abc'
    
    bytes([256])
    ValueError: bytes must be in range(0, 256)
    
    # 大端序
    (2008).to_bytes(length=4, byteorder='big', signed=False)
    b'\x00\x00\x07\xd8'
    # 小端序
    (2008).to_bytes(length=4, byteorder='little', signed=False)
    b'\xd8\x07\x00\x00'
    struct.pack('<I', 2008)
    b'\xd8\x07\x00\x00'
    
    int.from_bytes(b'\x00\x00\x07\xd8', 'big')
    2008
    int.from_bytes(b'\xd8\x07\x00\x00', 'little')
    2008
    
    int.from_bytes(b'abc', 'little')
    6513249
    int.from_bytes(b'cba', 'big')
    6513249
    

    PS:2020/11/02, 字节顺序(大端序、小端序)

  4. Python2 字符串

    # python2
    print(repr('你好'))
    '\xc4\xe3\xba\xc3'
    print('\xc4\xe3\xba\xc3')
    你好
    
    # python3
    print('\xc4\xe3\xba\xc3')
    'ÄãºÃ'
    print('\xc4\xe3\xba\xc3'.encode('latin-1'))
    b'\xc4\xe3\xba\xc3'
    print('\xc4\xe3\xba\xc3'.encode('latin-1').decode('gbk'))
    '你好'
    

#25 Python tempfile

2016-02-03
import tempfile
import time

timestr = time.strftime("%Y%m%d%H%M%S")

临时文件

# tempfile.mktemp(suffix='', prefix='tmp', dir=None)
# tempfile.mkstemp(suffix=None, prefix=None, dir=None, text=False)

filepath_temp = tempfile.mktemp(suffix='.html', prefix='.cache_%s_' % timestr)
print(filepath_temp)
# /tmp/.cache_20210929205452_zlmi3pkf.html

filepath_temp = tempfile.mktemp(suffix='.html', prefix='.cache_%s_' % timestr,
                                dir='/opt/apps/markjour/tmp/')
print(filepath_temp)
# /opt/apps/markjour/tmp/.cache_20210929205452_mcr7nj3e.html

filepath_temp = tempfile.mkstemp(suffix='.html', prefix='.cache_%s_' % timestr, text=True)

mkstempmktemp 的区别:mkstemp 返回一个文件描述符,mktemp 返回一个文件路径。
mktemp 返回的路径理论上会被另一个进程使用,所以这是 UNSAFE 的,应该用 mkstemp 代替。
mktemp 从 Python 2.3 开始标记为 Deprecated,但是至今还是可以调用。

临时目录

# tempfile.mkdtemp(suffix=None, prefix=None, dir=None)
dirpath_temp = tempfile.mkdtemp()
print(dirpath_temp)
# /tmp/tmp1dj2cl0d

dirpath_temp = tempfile.mkdtemp(prefix='build_',
                                dir='/opt/apps/markjour/tmp/')
print(dirpath_temp)
# /opt/apps/markjour/tmp/build_9k5synh5

#24 Python zipfile

2016-02-02
import zipfile
import os

zip_path = "/path/to/zip/file.zip"
extract_path = "/path/to/extract/directory"

if not os.path.exists(extract_path):
    os.makedirs(extract_path)

with zipfile.ZipFile(zip_path, 'r') as fp:
    # 直接解压
    zip_ref.extractall(target_dir)

    # 逐个解压
    for filename in fp.namelist():

        # 如果文件存在就先移除,避免 FileExistsError
        extract_file_path = os.path.join(extract_path, filename)
        if os.path.exists(extract_file_path):
            # print("跳过解压缩文件:", filename)
            # continue
            os.remove(extract_file_path)

        # 解压,会自动创建目录结构
        fp.extract(filename, extract_path)

#22 Python 常见后缀

2016-01-21

.gitignore 常见的 *.py[cod]

参考 gitignore.io

  • .py
  • .pyc 编译过后生成的字节码文件
  • .pyo 经过优化的字节码文件。Python2 时代常见,Python3 不再使用。现在是 .opt-1.pyc, opt-2.pyc
    PS:关于这个优化到底是做什么以后再好好研究。
  • .pyd
  • .pyi Python Stub 文件,IDE 中为了提供更好的提示会带一些这样的文件,只是所有方法都是空的。
    ps: 现在的 PyCharm 好像带的 stub 文件都是 py 后缀了。
  • .pyw Windows 专供,py 文件由 python.exe 解析,pyw 文件由 pythonw.exe 执行
    他们不同之处就是,python.exe 会导致一个命令行窗口的出现,而,pythonw.exe 不会,所以常用在 GUI 程序上。
  • .pth 自定义路径导入规则的文件,参考:.pth 文件和 site 模块

#21 Python 文件压缩方式汇总

2015-12-31
  • zlib — Compression compatible with gzip
  • gzip — Support for gzip files
  • bz2 — Support for bzip2 compression
  • lzma — Compression using the LZMA algorithm
  • zipfile — Work with ZIP archives
  • tarfile — Read and write tar archive files