在基于 InterSystems IRIS 开发 Python 应用时,你很快就会发现存在多种执行上下文:
- 由 IRIS 直接启动的 Embedded Python;
- 加载本地 IRIS 安装中 Embedded Python 库的常规
python3进程; - 通过官方原生驱动连接 IRIS 的外部 Python 应用。
这三种场景都非常有用,但在导入机制、系统配置、对象 API 以及 SQL 访问方面,它们的行为并不完全一致。iris-embedded-python-wrapper项目提供了一个稳定的 Python 门面(Facade),旨在减少这些差异,并提供一个统一的入口点:import iris。
存在的问题
在一个围绕 IRIS 构建的 Python 项目中,同一份代码可能需要在多种环境中运行:
- 在 IRIS 终端中,通过
iris python iris或iris session iris后输入:py; - 通过
python3启动的本地 Python 脚本; - 连接到 IRIS 实例的远程 Python 服务。
如果没有抽象层,许多细节往往就需要分别处理:
- Embedded Python 的
iris模块只有在 IRIS 运行时被正确加载时才可用; - 原生 SDK 同样暴露了一个
iris包,这可能导致冲突或产生歧义的导入; iris.cls(...)和 DB-API 连接在嵌入式模式和远程模式下的执行路径并不完全一致;- 在 Linux 和 macOS 上,必须在 Python 进程启动前预先配置好动态库路径;
- 边界值(如 SQL NULL 和空字符串)在不同的后端中可能有不同的表示方式。
该包装器(Wrapper)的目标在于,让应用程序能够清晰地声明其执行上下文,同时在嵌入式模式和原生模式下保持业务逻辑代码的相似性。
包装器提供的能力
该包提供了一个 import iris门面(Facade),保留了最常用的入口点:
iris.cls(...):用于访问 IRIS 类;iris.connect(...):根据上下文配置或打开连接;iris.dbapi:用于符合 PEP 249 规范的 SQL 访问;iris.runtime:用于检查并显式控制当前的活动模式。
支持的模式如下:
| 模式 (Mode) | 描述 (Description) | 示例 (Example) |
|---|---|---|
| embedded-kernel | Python 由 IRIS 启动 | iris python iris或 :py |
| embedded-local | python3从本地 IRIS 安装加载 Embedded Python 库 |
IRISINSTALLDIR, iris.connect(path=...) |
| native-remote | Python 连接到远程 IRIS 实例 | 官方原生驱动 intersystems-irispython |
| unavailable | 尚无可用的 IRIS 后端 | 使用前需要配置 |
安装
该包可以使用 pip进行安装:
pip install iris-embedded-python-wrapper
该项目依赖于官方驱动:
intersystems-irispython>=5.0.0
对于嵌入式模式,你还需要本地安装 InterSystems IRIS。若要从外部 Python 进程访问嵌入式模式,必须启用 %Service_CallIn服务。
示例:使用 Embedded Python
在由 IRIS 启动的 Embedded Python Shell 中:
iris python iris
或者在 IRIS 会话中:
USER>:py
你可以像往常一样导入 iris:
import iris
print(iris.system.Version.GetVersion())
print(iris.runtime.state)
在此上下文中,iris.runtime.state应报告:
'embedded-kernel'
如果你想强制使用本地项目目录中的包装器:
PYTHONPATH=/path/to/iris-embedded-python-wrapper iris python iris
示例:从本地 python3加载 IRIS
embedded-local模式允许你在运行常规 Python 脚本的同时,使用来自 IRIS 安装的 Embedded Python 库。
在 Linux 上:
export IRISINSTALLDIR=/opt/iris
export LD_LIBRARY_PATH=$IRISINSTALLDIR/bin:$LD_LIBRARY_PATH
python3 my_script.py
在 macOS 上:
export IRISINSTALLDIR=/opt/iris
export DYLD_LIBRARY_PATH=$IRISINSTALLDIR/bin:$DYLD_LIBRARY_PATH
python3 my_script.py
该包装器还允许你显式声明 IRIS 安装路径:
import iris
iris.connect(path="/opt/iris")
obj = iris.cls("Ens.StringRequest")._New()
obj.StringValue = "hello from embedded-local"
重要提示:在 Unix 系统上,iris.connect(path=...)可以在运行时配置 Python 路径,但如果 Python 进程在没有正确设置 LD_LIBRARY_PATH或 DYLD_LIBRARY_PATH的情况下已经启动,它无法追溯性地修复动态库解析问题。
以下是该部分文档的严格翻译,已按原文结构整理为 Markdown 格式:
示例:在远程原生模式下保留 iris.cls(...)
使用原生 SDK 时,远程代码通常直接使用显式的 IRIS 句柄:
import iris
conn = iris.connect("localhost", 1972, "USER", "SuperUser", "<password>")
db = iris.createIRIS(conn)
req = db.classMethodValue("Ens.StringRequest", "%New")
db.set(req, "StringValue", "hello")
value = db.get(req, "StringValue")
使用该包装器,你可以绑定一次原生连接,并保留与 Embedded Python 相近的语法:
import iris
conn = iris.connect("localhost", 1972, "USER", "SuperUser", "<password>")
iris.runtime.configure(native_connection=conn)
req = iris.cls("Ens.StringRequest")._New()
req.StringValue = "hello"
value = req.StringValue
原生代理(Native Proxy)会将首位的下划线 _转换为 %,这使得你可以在 Python 中编写 _New()来调用 %New。
显式控制运行时
iris.runtime是该包装器关于当前活动上下文的“单一事实来源(Source of Truth)”。
import iris
ctx = iris.runtime.get()
print(ctx.mode)
print(ctx.state)
print(ctx.embedded_available)
有用的属性包括:
iris.runtime.mode:选定的策略,例如auto、embedded或native;iris.runtime.state:检测到的状态,例如embedded-kernel、embedded-local、native-remote或unavailable;iris.runtime.embedded_available:嵌入式后端是否可用;iris.runtime.iris:绑定到运行时的原生 IRIS 句柄(如果可用);iris.runtime.dbapi:显式绑定的 DB-API 连接(如果可用)。
你也可以强制指定模式:
import iris
iris.runtime.configure(mode="embedded")
或者重置为自动检测:
import iris
iris.runtime.reset()
使用 iris.dbapi进行 SQL 访问
该包装器暴露了一个兼容常见用法的 DB-API 门面:
connect();cursor();execute();fetchone()、fetchmany()、fetchall();commit()、rollback()、close();- PEP 249 异常,如
InterfaceError、OperationalError等。
在嵌入式模式下:
import iris
conn = iris.dbapi.connect(mode="embedded")
cur = conn.cursor()
cur.execute("SELECT Name FROM Sample.Person")
rows = cur.fetchall()
cur.close()
conn.close()
在带有显式路径的嵌入式本地(embedded-local)模式下:
import iris
conn = iris.dbapi.connect(path="/opt/iris", namespace="USER")
cur = conn.cursor()
cur.execute("SELECT 1")
print(cur.fetchone())
在远程原生模式下:
import iris
conn = iris.dbapi.connect(
mode="native",
hostname="localhost",
port=1972,
namespace="USER",
username="SuperUser",
password="<password>",
)
cur = conn.cursor()
cur.execute("SELECT 1")
print(cur.fetchone())
在 auto(自动)模式下,包装器会根据提供的参数和 iris.runtime的状态来选择后端。例如,如果你提供了主机名(hostname)、端口(port)、命名空间(namespace)、用户名(username)和密码(password),连接将被路由到原生驱动。
该包装器还对某些嵌入式场景进行了规范化处理,使其行为更接近原生 DB-API:
- SQL NULL 变为 Python
None; - 空的 SQL 字符串变为
""; - 作为参数传入的
None保持为 SQL NULL; - 作为参数传入的
""保持为空 SQL 字符串。
将虚拟环境绑定到 Embedded Python
该项目提供了两个实用的命令:
bind_iris
unbind_iris
bind_iris会查找当前虚拟环境的 Python 库,更新 IRIS Embedded Python 配置,并创建 iris.cpf文件的备份。
示例:
python3 -m venv .venv
. .venv/bin/activate
pip install iris-embedded-python-wrapper
bind_iris
根据平台和 IRIS 配置的不同,可能需要 IRIS 管理员权限。在 Windows 上,更改配置后可能需要重启 IRIS 实例。
何时应该使用此包装器?
如果你希望实现以下目标,该包装器将非常有用:
- 编写既能在嵌入式模式又能在远程模式下运行的 Python IRIS 代码;
- 减少 Embedded Python 与原生 API 之间的差异;
- 通过
iris.runtime使执行模式变得可观测; - 在应用代码中使用单一的 DB-API 门面;
- 简化 Embedded Python 的虚拟环境配置;
- 更轻松地测试嵌入式和远程路径。
它不是 InterSystems IRIS 或官方原生 SDK 的替代品。它是一个构建在这些组件之上的便利层,旨在提高应用程序代码的可移植性。
资源
- GitHub 项目:https://github.com/grongierisc/iris-embedded-python-wrapper
- 项目文档:https://github.com/grongierisc/iris-embedded-python-wrapper/blob/master/README.md
- 安装方式:
pip install iris-embedded-python-wrapper - 许可证:MIT
结语
iris-embedded-python-wrapper围绕 InterSystems IRIS 的主要 Python 执行模式提供了一个简单的门面。其主要优势在于能够编写如下代码:
import iris
然后明确地决定代码是在 Embedded Python、嵌入式本地模式(embedded-local)还是通过远程原生连接中运行。对于需要在不同模式间切换的应用程序,或者希望在本地方便脚本、嵌入式作业和外部 Python 服务之间共享更多代码的团队而言,这种方法消除了大量的技术干扰。
