Hy宏导入模块失效:with-cwd宏报NameError: os未定义
解决Hy语言with-cwd宏的NameError问题
问题背景
使用Hy 0.25.0编写pytest测试时,调用自定义的with-cwd宏触发NameError: name 'os' is not defined错误,但手动在测试文件中导入os后测试可正常运行。
测试文件代码
(import pytest [mark]) (import pathlib [Path]) (require oreo [with-cwd]) (defn [mark.with-cwd] test-with-cwd [cookies] (let [ cwd (.cwd Path) ] (with-cwd cookies (assert (= (.cwd Path) cookies))) (assert (= (.cwd Path) cwd))))
错误信息
Traceback (most recent call last): File "/home/shadowrylander/shadowrylander/sylveon/syvlorg/oreo/tests/test-with-cwd.hy", line 7, in test_with_cwd (with-cwd cookies (assert (= (.cwd Path) cookies))) NameError: name 'os' is not defined During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/shadowrylander/shadowrylander/sylveon/syvlorg/oreo/tests/test-with-cwd.hy", line 7, in test_with_cwd (with-cwd cookies (assert (= (.cwd Path) cookies))) NameError: name 'os' is not defined
cookies fixture定义
@pytest.fixture() def cookies(request): from pathlib import Path return Path(request.config.rootdir).expanduser().resolve(strict = True) / "cookies"
原with-cwd宏实现
(eval-and-compile (import os hy)) (defmacro with-cwd [dir #* body] (setv cwd (hy.gensym)) `(let [ ~cwd (.cwd Path) ] (try (.chdir os ~dir) ~@body (finally (.chdir os ~cwd)))))
尝试过的修改(仍报错)
(defmacro with-cwd [dir #* body] (setv cwd (hy.gensym) os (hy.gensym)) `(let [ ~cwd (.cwd Path) ] (import os :as ~os) (try ((. ~os chdir) ~dir) ~@body (finally ((. ~os chdir) ~cwd)))))
解决方案
问题根源是:宏展开后的代码在调用者的命名空间中寻找os,但原宏仅在宏定义时导入os,并未将os的导入逻辑包含到展开后的代码中;修改后的宏虽尝试导入,但语法有误,且Path同样依赖调用者的导入。
正确的宏实现应确保展开后的代码自行导入所需依赖,避免依赖调用者的命名空间:
(eval-and-compile (import hy)) (defmacro with-cwd [dir #* body] (setv cwd (hy.gensym)) `(do ;; 在展开后的代码中导入所需模块 (import os) (import pathlib [Path]) (let [~cwd (.cwd Path)] (try (.chdir os ~dir) ~@body (finally (.chdir os ~cwd))))))
如果希望复用调用者已导入的Path,至少要确保os在展开后的代码中被导入:
(eval-and-compile (import hy)) (defmacro with-cwd [dir #* body] (setv cwd (hy.gensym)) `(do (import os) (let [~cwd (.cwd Path)] (try (.chdir os ~dir) ~@body (finally (.chdir os ~cwd))))))
修改后,宏展开时会自动在调用代码中插入os的导入语句,无需测试文件手动导入os即可正常运行。
内容的提问来源于stack exchange,提问作者syvlorg
相关产品推荐
相关产品推荐

