Getting keywords from library using python

Hi… I’m working on internal library, as a part of this library, I want to use another library (KubeLibrary). It’s not only extension of this library, but I want to build uppon this.

I tried something like:

self.kubelib = KubeLibrary(kubeconfig)
dynamic_core = DynamicCore(["KubeLibrary"])
self._plugin_keywords.extend(dynamic_core.get_keyword_names())

The problem is, that kubelib will expose keywords, but I can’t get this keyword_names for robocorp extension, so in VSCode I just can’t see/use keywords that are direct connected to ‘KubeLibrary’

I also tried to do somehting like:
BuiltIn().import_library(“KubeLibrary”, kubeconfig)
self.kubelib = BuiltIn().get_library_instance(“KubeLibrary”)

But At the end it is the same… I still can’t get keywords for libdoc to be generated, thou They can’t be used through the keywords…

Is there any chance to get this working? To just somehow import ‘external’ library and expose its keywords to my custom lib?

Thanks

I tried also:

class xxxx(DynamicCore):
    """ TODO: write me!
    """
    def __init__(self, kubeconfig: str, registry: Optional[str] = None, username: Optional[str] = None,
                 password: Optional[str] = None):
        libraries = [HelmKeywords(self), KubernetesKeywords(self)]
        self.registries = {}
        if registry and username and password:
            self.registries[registry] = {"login": username, "password": password}
        else:
            BuiltIn().log(f"({self!r}) Registry not set at the init, skipping it")
        importer = Importer("IllumioCloudLibrary")
        kube = importer.import_class_or_module("KubeLibrary")
        kube = kube(kubeconfig)
        libraries.append(KubeLibrary(kubeconfig))
        DynamicCore.__init__(self, libraries)

when I ‘dir’ kube instance, I can see all the keywords, but robot framework cant recognize them…
No keyword with name 'List Namespaced Pod By Pattern' found.

My goal is to instantiate 1 library

*** Settings ***
Library    xxxx    path_to_kubeconfig    AS    cluster1
Library    xxxx    path_to_second_kubeconfig    AS     cluster2

Everything looks smooth, but the keywords from KubeLibrary are not exposed within the xxxx library, and within the tests themselfs

Ok after further research I come to

@library(scope="GLOBAL", version=version, auto_keywords=True)
class KubeLibrary:
  ...

KubeLibrary is Static one… So I can’t create instance within the dynamic/hybrid core

If I edit the library and just add (DynamicCore) as a parent and If I add @keyword decorator, than everything is working fine…

so looks like, that I’m looking for a way how to ‘parse’ StaticLibrary and ‘join’ it to set of dynamic/hybrid ones

You could go through all methods in KubeLibrary and add robot_name attribute to them (this is what @keyword does) before passing them to DynamicCore.

Enhancing PythonLibCore so that it supports also static libraries as library components could be considered as well. It probably wouldn’t require anything more than having a wrapper that can add those robot_name attributes as part of PLC. If you get this working with a custom solution, please submit an issue to PLC about it as well.

Hi @pekkaklarck … thanks, I was trying to achieve this.

Is there some robot framework native way, how to go through the library and get only keywords? Or I just need to do something like [kw for kw in dir(lib_instance) if not kw.startswith("__")] ? or is there better way?

Robot’s own logic for figuring out what keywords a static library containx isn’t exposed so that it could be easily used externally. Your example is already pretty good, but I’d enhance it a bit to something like this:

for name, kw in inspect.getmembers(lib):
    if name[0] != '_' and callable(kw) and not hasattr(kw, 'robot_name'):
        kw.__func__.robot_name = None

The above works with library instances where keywords are methods and kw.__func__.robot_name is needed. With library modules you probably should just use kw.robot_name. Probably not relevant for you, but needed to taken into account with a generic solution.

1 Like

Ok I tried it to get it work… the robot_name was the missing piece.

but In order to get it work I had to do this:

        importer = Importer()
        kubelib = importer.import_class_or_module("KubeLibrary")
        for name, keyword_ in inspect.getmembers(kubelib):
            if name[0] != '_' and callable(keyword_) and not hasattr(keyword_, 'robot_name'):
                BuiltIn().log(f"{name=} -> {keyword_=}", "WARN")
                keyword_.robot_name = None
                keyword_.robot_tags = None
        kubelib = kubelib(self.kubeconfig)
        libraries.append(kubelib)
        DynamicCore.__init__(self, libraries)

Thanks a lot.

It looks like the magic is finally done.

1 Like

Did you try using from KubeLibrary import KubeLibrary work? That Importer mainly handles imports by path like path/lib.py and provides better error reporting, but for importing normal modules just the standard import ought to work. You can obviously use it, but it’s not part of the stable public API so there’s a risk it changes in the future.

For logging I’d also recommend robot.api.logger instead of BuiltIn.log. Finally, setting robot_name is enough, no need to set robot_tags.

I just created some kind of ‘plugin’ api for this ones… I can change it, it should be sufficient, but my ‘plugin’ implementation is also working with importer, so if something will change in it, I need to change also my implementation.

As for the robot_tags it is required, I got errors

[ ERROR ] Error in library 'IllumioCloudLibrary': Adding keyword 'read_namespaced_persistent_volume_claim' failed: Calling dynamic method 'get_keyword_tags' failed: AttributeError: 'function' object has no attribute 'robot_tags'

So the solution was to add tags, into it

robotframework==6.0.2
robotframework-pythonlibcore==4.1.2

And logging :slight_smile: It was just the quick log, to see if everything is ok… It is no longer there. I’m using logger instead of it.