0

我有一个与外部工具接口的库,并公开了一些基本关键字以从机器人框架中使用;这个库是作为一个 python 包实现的,我想在这个包的模块中实现实现复杂逻辑并公开更多关键字的扩展功能。该软件包具有测试用例范围,但我不完全确定它是如何工作的。如果我提出一些我想到的方法,那么有更多知识的人可以让我知道我在正确的轨道上,以及我在哪里吠叫错误的树......

  1. 使用实例变量 - 如果范围是这样的,python 解释器将看到当前测试用例导入的包(即,这在不同的测试用例中被视为单独的包,而不是同一包的单独实例),然后在初始化时,我可以设置一个全局变量INSTANCEself然后从包中的另一个模块导入INSTANCE并使用它。

  2. 使用实例字典 - 如果范围是所有导入都将包视为相同,我可以使用 robots.running.context 设置字典键,以便在实例字典中为包所在的每个上下文都有一个项目已导入 - 这意味着我可以在基于此的模块中使用相同的上下文变量作为查找键。(这个的缺点是它会阻止垃圾收集,直到包本身超出范围,并且依赖于它持久地在范围内。)

  3. 我尚未意识到的上下文变量将为我提供范围内的实例。这些文档很难搜索,因此完全有可能我遗漏了一些东西,这会使这变得微不足道。同样好的是允许我调用范围内的关键字。

  4. 一些我没有考虑过的极好的可能性......

那么有人可以帮忙吗?

4

2 回答 2

1

这要归功于robotframework用户组的Kevin O.,但本质上robot.libraries.BuiltIn.BuiltIn().get_library_instance(library_name)可以像这样使用魔法:

from robot.libraries.BuiltIn import BuiltIn
class SeleniumTestLibrary(object):
  def element_should_be_really_visible(self):
    s2l = BuiltIn().get_library_instance('Selenium2Library')
    element = s2l._element_find(locator, True, False)
于 2012-09-17T09:26:57.570 回答
0

听起来您正在谈论对导入的代码进行猴子修补,以便导入该包的其他模块也将看到您的运行时修改。(如果我错了,请纠正我;您的问题中有几处我不太关注)

对于简单的包导入,这应该有效:

import my_package

def method_override():
    return "Foo"

my_package.some_method = method_override

my_package,在这种情况下,指的是导入的模块,而不仅仅是本地名称,因此其他模块将看到覆盖的方法。

这在其他代码已经完成的情况下不起作用

from my_package import some_method

因为在这种情况下,它some_method 导入位置的本地名称。如果您在其他地方替换该方法,则不会看到该更改。

如果发生这种情况,那么您需要更改源以导入整个模块,或者通过替换方法内部来更深入地修补:

import my_package

def method_override():
    return "Foo"

my_package.some_method.func_code = method_override.func_code

那时,如何在任何其他模块中导入该方法都无关紧要;与该方法关联的代码对象已被替换,您的新代码将运行而不是原始代码。

在这种情况下,唯一需要担心的是,在每种情况下,模块都是从同一路径导入的。Python 解释器将尝试重用现有模块,而不是重新导入和重新初始化它们,只要它们是从同一路径导入的。

但是,如果您的 python 路径设置为包含两个目录,例如:'/foo' 和 '/foo/bar',那么这两个导入

from foo.bar import baz

from bar import baz

最终会加载模块两次,并在模块中定义任何对象(方法、类等)的两个版本。如果发生这种情况,那么修补一个不会影响另一个。

如果您需要防范这种情况,那么您可能必须遍历 sys.modules,查找导入的包,并修补您找到的每个版本。当然,这只有在所有其他导入都已经发生的情况下才有效,您不能先发制人地这样做(不编写导入钩子,但这又是另一个更深的层次:))

你确定你不能只分叉原始包并直接扩展它吗?那会容易得多:)

于 2012-09-13T07:16:02.333 回答