How to call methods of the instance of a library already in scope of the current running test case

StackOverflow https://stackoverflow.com/questions/12393108

  •  01-07-2021
  •  | 
  •  

문제

I have a library that interfaces with an external tool and exposes some basic keywords to use from robotframework; This library is implemented as a python package, and I would like to implement extended functionality that implements complex logic, and exposes more keywords, within modules of this package. The package is given test case scope, but I'm not entirely sure how this works. If I suggest a few ways I have thought of, could someone with a bit more knowledge let me know where I'm on the right track, and where I'm barking up the wrong tree...

  1. Use an instance variable - if the scope is such that the python interpreter will see the package as imported by the current test case (i.e this is treated as a separate package in different test cases rather than a separate instance of the same package), then on initialisation I could set a global variable INSTANCE to self and then from another module within the package, import INSTANCE and use it.

  2. Use an instance dictionary - if the scope is such that all imports see the package as the same, I could use robot.running.context to set a dictionary key such that there is an item in the instance dictionary for each context where the package has been imported - this would then mean that I could use the same context variable as a lookup key in the modules that are based on this. (The disadvantage of this one is that it will prevent garbage collection until the package itself is out of scope, and relies on it being in scope persistently.)

  3. A context variable that I am as of yet unaware of that will give me the instance that is in scope. The docs are fairly difficult to search, so it's fully possible that there is something that I'm missing that will make this trivial. Also just as good would be something that allowed me to call the keywords that are in scope.

  4. Some excellent possibility I haven't considered....

So can anyone help?

도움이 되었습니까?

해결책

Credit for this goes to Kevin O. from the robotframework user group, but essentially the magic lives in robot.libraries.BuiltIn.BuiltIn().get_library_instance(library_name) which can be used like this:

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)

다른 팁

It sounds like you are talking about monkeypatching the imported code, so that other modules which import that package will also see your runtime modifications. (Correct me if I'm wrong; there are a couple of bits in your question that I'm not quite following)

For simple package imports, this should work:

import my_package

def method_override():
    return "Foo"

my_package.some_method = method_override

my_package, in this case, refers to the imported module, and is not just a local name, so other modules will see the overridden method.

This won't work in cases where other code has already done

from my_package import some_method

Since in that case, some_method is a local name in the place it is imported. If you replace the method elsewhere, that change won't be seen.

If this is happening, then you either need to change the source to import the entire module, or patch a little bit deeper, by replacing method internals:

import my_package

def method_override():
    return "Foo"

my_package.some_method.func_code = method_override.func_code

At that point, it doesn't matter how the method was imported in any other module; the code object associated with the method has been replaced, and your new code will run rather than the original.

The only thing to worry about in that case is that the module is imported from the same path in every case. The Python interpreter will try to reuse existing modules, rather than re-import and re-initialize them, whenever they are imported from the same path.

However, if your python path is set up to contain two directories, say: '/foo' and '/foo/bar', then these two imports

from foo.bar import baz

and

from bar import baz

would end up loading the module twice, and defining two versions of any objects (methods, classes, etc) in the module. If that happens, then patching one will not affect the other.

If you need to guard against that case, then you may have to traverse sys.modules, looking for the imported package, and patching each version that you find. This, of course, will only work if all of the other imports have already happened, you can't do that pre-emptively (without writing an import hook, but that's another level deeper again :) )

Are you sure you can't just fork the original package and extend it directly? That would be much easier :)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top