创建和发布自己的 Python 包到 PyPI 上

像 Java 可发布包到 Maven 仓库,NodeJS 发布包到 NPM 一样,我们也可以创建自己的 Python 包并发布到 PyPI 仓库中去。或者内部使用的包,只须发布到私有的 Nexus 服务器上。

本文中的例子将创建一个 Python 包 bounded-executor, 并发布到 PyPI 上。为什么创建这个包呢?原因是直接用 Python 的 ThreadPoolExecutor 或  ProcessPoolExecutor 来提交任务的话,任务的等待队列是没有边界的,这就会造成因提交任务过快而使得内存爆满。本包最为合适的名称应该是 bounded-pool-executor, 可是名字已被他人使用,但此外的实现有所不同,ThreadPoolExecutor 用 Queue(maxsize) 来控制,而 ProcessPoolExceutor 用 BoundedSemaphore 来控制。

我们以经典的 Python 工程目录结构为例,构建的核心是执行 setup.py 中的 setup 函数,由此来理解 setup 的最主要配置与关键命令做了些什么。这样有助于我们理解其他的 Python 包管理工具的底层行为,从中我们可以对比 poetry 的 build, install, 和 publish 命令。 阅读全文 >>

理解 Docker Client/Server 架构, 找寻 Docker Desktop 替代品

本文继上篇 摆脱 Docker Desktop 即将到来的收费 进一步寻找符合自己需求的 Docker Desktop 替代品,前面试用过 hyperkit + minikube, Podman, 最终还是确定了用 docker-machine。之所以选择了它是基于下面几个需求:

  1. 连接 VPN 后 Docker 还要能继续工作 (通过 socket 文件和 localhost 与 Docker Host 通信不惧怕 VPN 连接. 因为 VPN 会接管路由表,所以用 IP 来连接 Docker Host 的话,VPN 连上后将可能无法访问 Docker Host)
  2. 能与 IDE 进行集成开发与调试  (IntelliJ IDEA 能与 Docker Desktop, Docker Machine, TCP socket 和 SSH 上的 Docker Host 集成调试,但无法与 Daemonless 的 Podman 集成)
  3. DOCKER_HOST 能是远程机器 (由于 Podman 设计为 Daemonless,也就没有 Docker Host, 无法进行远程构建)

本文力图更深入的理解 Docker 的架构来解释最后选择的来由,清楚了原理后可以自主创建一个 Docker Host,连 docker-machine 也可以不用。比如创建一个 AWS EC2 实例作为 Docker Host, 然后在本地执行 docker 命令进行镜像的构建与容器的运行,这时候镜像构建过程与容器执行的环境是在 EC2 上,再也不用先把本地的文件上传(scp 或 rsync) 到 EC2 上,然后 ssh  到 EC2 去执行 docker 命令了。

一个小插曲:本人曾经随手在  ~/Downloads 目录下建立一个只有 FROM busybox 一行的 Dockerfile 文件,然后运行 docker build ...  命令,结果每次都提示磁盘空间不足,本机磁盘还非常宽裕,Docker Machine 也分配了 20 G 内存,怎么会不够了呢?登入到 Docker Machine  后 df 确实没空间了。四处找原因,原来是 docker build ... 一执行,不管 3721 首先把当前目录下的所有文件全部拷贝到 Docker Machine 中去,~/Downloads 目录中下了几十个 G 的内容,所以把 Docker Machine 给挤暴掉。解决办法就是要把  Dockerfile 放到一个没有无用文件的独立目录中去,这也是为什么 Dockerfile 中的 COPY 命令只能从当前目录中拷贝文件的原因。 阅读全文 >>

Python 中创建 PostgreSQL 数据库连接池

征战 Java 多年,习惯于使用数据库之前都必须创建一个连接池,即使是单线程的应用,只要有多个方法中需用到数据库连接,建立一两个连接的也会考虑先池化他们。连接池的好处多多,1) 如果反复创建连接相当耗时,2) 对于单个连接一路用到底的应用,有连接池时避免了数据库连接对象传来传去,3) 忘记关连接了,连接池幸许还能帮忙在一定时长后关掉,当然密集取连接的应用势将耗尽连接,3) 一个应用打开连接的数量是可控的

接触到 Python 后,在使用 PostgreSQL 也自然而然的考虑创建连接池,使用时从池中取,用完后还回去,而不是每次需要连接时创建一个物理的。Python 连接 PostgreSQL 是主要有两个包,py-postgresqlpsycopg2, 而本文的实例将使用后者。

Psycopg 在 psycopg2.pool 模块中提供了两个连接池的实现在,它们都继承自 psycopg2.pool.AbstractConnectionPool, 该抽象类的基本方法是

  1. getconn(key=None): 获取连接
  2. putconn(conn, key=None, close=False): 归还连接
  3. closeall(): 关闭连接池中的所有连接

阅读全文 >>

Python zipfile 只借助内存进行压缩与解压缩

Python zipfile 模块压缩与解压缩通常是对物理磁盘文件进行操作,比如参照官方的例子,生成压缩文件的代码是

with zipfile.ZipFile('spam.zip', 'w') as myzip:
    myzip.write('eggs.txt')
    myzip.write('beef.txt')

这样就生成了一个包含两个文件的压缩包 spam.zip, 相当于命令 zip spam.zip egges.txt beef.txt 的效果。用  unzip -l spam.zip 命令就能看到其中的两个文件。相应的解压缩的代码如下

with zipfile.ZipFile('spam.zip', 'r') as myzip:
    print(myzip.filelist())  # 可获得压缩包中的文件列表信息
    myzip.extractall()

同样是把压缩包 spam.zip 解压缩文件到当前目录中,相当于命令 unzip spam.zip 的效果。

前面顺便也是熟悉一下 zipfile 模块的常见用法,但有时候我们可能从数据库中,从网络上收到的是字节数据,希望直接处理字节的压缩解压缩,而不借助于中间的磁盘文件,因为通过磁盘文件来处理必须进行善后处理以及可能的资源的竞争,在内存宽裕的情况下效率也是个问题。 阅读全文 >>

Python Poetry 项目中相对路径模块引用的问题

最近一直在折腾 Python 项目,通过对几个 Python 项目依赖管理与构建工具的对比,最后选择了 Poetry。它管理依赖,构建与发布包还是简单的多,不需要处理 setup.py, setup.cfg 和 Makefile 文件, 甚至都不需要了解 wheel 是什么就能往 PyPI 发布包了。

可是,别看 Poetry 的官网一直守护着一副小清新的形像,其实照样处处是坑,其中一个就是与相对引用有关的问题。我们来看下什么样的现像,最后的结论就是:在 Python 中避免使用相对路径引用,因为相对路径的上下文经常在变,然后必要时先执行 poetry install, 甚至把入口代码拉到包外头去。

什么是相对引用与绝对路径引用,比如在一个包 my_package 中有两个模块(Python 文件) app.py 和 utils, app.py 中对 utils 资源的引用可以写成

from utils import md5               # 不确定 utils 是一个包还是一个模块,有点像是隐式相对路径模块引用
from .utils import md5              # 同一目录中的 utils 模块
import .utils
from ..utils import md5             # 上一级目录中的 utils 模块 (如果 utils.py 在与 app.py 上一级目录的话)
from my_package.utils import md5  # 绝对引用,总是从包名开始

注意 from 后面的 ...,相对路径引用不能直接 import, 如不能 import .utils.md5

阅读全文 >>

Lambda + API Gateway 创建需 API Key 验证的 API

希望在标题上尽量包含更多的信息,原本命题为: Lambda + API Gateway 创建需 API Key 验证的 API(Docker + Python + Terraform), 但是觉得太长了,于是只取了前半部份。仍然要在开头部分强调一下本文件打算要实现什么

  1. 在 AWS  用 Lambda  和  API Gateway 创建 API
  2. 创建的 API 是 public 的,需要用 x-api-key 来验证
  3. Lambda 的实现代码打包在了一个 Docker 镜像中
  4. 整个 AWS 的基础架构(包括 ECR, Lambda, API Gateway 及权限等)是由 Terraform 脚本创建管理的

目标明确,我们直冲到代码的目录结构来,项目目录为 api-gateway-demo, Github 上的链接为 api-gateway-demo. 后面详叙还会把其中每一个文件的内部给列出来 阅读全文 >>