From 0d4cb6beed5b891a4dea5abc46d21b7d6f8a66c9 Mon Sep 17 00:00:00 2001 From: youmi <2508645198@qq.com> Date: Wed, 15 Jul 2026 13:18:11 +0800 Subject: [PATCH] Fix instruction decorator missing link handling --- office/lib/decorator_utils/instruction_url.py | 5 +- tests/test_code/test_instruction_url.py | 89 +++++++++++++++++++ 2 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 tests/test_code/test_instruction_url.py diff --git a/office/lib/decorator_utils/instruction_url.py b/office/lib/decorator_utils/instruction_url.py index 0978527..885aa69 100644 --- a/office/lib/decorator_utils/instruction_url.py +++ b/office/lib/decorator_utils/instruction_url.py @@ -119,10 +119,11 @@ def instruction(func): @wraps(func) def instruction_wrapper(*args, **kwargs): func_filename = os.path.basename(func.__code__.co_filename) # 取出方法所在的文件名 + instruction_url = instruction_file_dict.get(func_filename, {}).get(func.__name__) # 如果有这个文件,并且已经配置了方法名对应的说明链接,则打印出来 - if func_filename in instruction_file_dict.keys() and instruction_file_dict[func_filename][func.__name__]: + if instruction_url: random_color_print( - f'正在运行:office.{os.path.basename(func_filename)[:-3]}.{func.__name__} , 这个方法的使用说明:{instruction_file_dict[func_filename][func.__name__]}') + f'正在运行:office.{os.path.basename(func_filename)[:-3]}.{func.__name__} , 这个方法的使用说明:{instruction_url}') random_color_print(SPLIT_LINE) instruction_res = func(*args, **kwargs) return instruction_res diff --git a/tests/test_code/test_instruction_url.py b/tests/test_code/test_instruction_url.py new file mode 100644 index 0000000..592b538 --- /dev/null +++ b/tests/test_code/test_instruction_url.py @@ -0,0 +1,89 @@ +"""Tests for the instruction URL decorator.""" + +import importlib.util +from pathlib import Path +import sys +import types +import unittest + + +class TestInstructionUrl(unittest.TestCase): + def setUp(self): + self._original_modules = { + name: sys.modules.get(name) + for name in ( + "pocode", + "pocode.api", + "pocode.api.color", + "office", + "office.api", + "office.lib", + "office.lib.conf", + "office.lib.conf.CONST", + "office.lib.decorator_utils.instruction_url", + ) + } + + sys.modules["pocode"] = types.ModuleType("pocode") + sys.modules["pocode.api"] = types.ModuleType("pocode.api") + color_module = types.ModuleType("pocode.api.color") + color_module.random_color_print = lambda *args, **kwargs: None + sys.modules["pocode.api.color"] = color_module + const_module = types.ModuleType("office.lib.conf.CONST") + const_module.SPLIT_LINE = "-" * 20 + api_module = types.ModuleType("office.api") + office_module = types.ModuleType("office") + office_module.api = api_module + sys.modules["office"] = office_module + sys.modules["office.api"] = api_module + sys.modules["office.lib"] = types.ModuleType("office.lib") + sys.modules["office.lib.conf"] = types.ModuleType("office.lib.conf") + sys.modules["office.lib.conf.CONST"] = const_module + sys.modules.pop("office.lib.decorator_utils.instruction_url", None) + + def tearDown(self): + for name in ( + "pocode", + "pocode.api", + "pocode.api.color", + "office", + "office.api", + "office.lib", + "office.lib.conf", + "office.lib.conf.CONST", + "office.lib.decorator_utils.instruction_url", + ): + sys.modules.pop(name, None) + + for name, module in self._original_modules.items(): + if module is not None: + sys.modules[name] = module + + def test_missing_method_link_does_not_block_wrapped_function(self): + module_path = ( + Path(__file__).resolve().parents[2] + / "office" + / "lib" + / "decorator_utils" + / "instruction_url.py" + ) + spec = importlib.util.spec_from_file_location( + "office.lib.decorator_utils.instruction_url", + module_path, + ) + instruction_url = importlib.util.module_from_spec(spec) + sys.modules[spec.name] = instruction_url + spec.loader.exec_module(instruction_url) + namespace = {} + exec( + compile("def undocumented_feature():\n return 'ok'\n", "/tmp/excel.py", "exec"), + namespace, + ) + + wrapped = instruction_url.instruction(namespace["undocumented_feature"]) + + self.assertEqual("ok", wrapped()) + + +if __name__ == "__main__": + unittest.main()