Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code intellisense broken in few libraries #621

Closed
mikahanninen opened this issue Sep 7, 2022 · 7 comments
Closed

Code intellisense broken in few libraries #621

mikahanninen opened this issue Sep 7, 2022 · 7 comments
Assignees
Labels
bug Bad or unexpected behaviour wontfix This won't or can't be worked on

Comments

@mikahanninen
Copy link
Member

mikahanninen commented Sep 7, 2022

Libraries that are based on robotlibcore.DynamicCore do not provide class methods when accessed in the Python mode, in VSCode for example.

Verified with rpaframework==16.1.0

affected libraries (at least):

  • RPA.Desktop
  • RPA.PDF
  • RPA.Windows

Original report by Andres Douglass in the Dev Slack - link

Information in the Robot Framework user guide

@mikahanninen mikahanninen added the bug Bad or unexpected behaviour label Sep 7, 2022
@cmin764 cmin764 self-assigned this Sep 8, 2022
@cmin764
Copy link
Contributor

cmin764 commented Sep 8, 2022

I have no idea how to fix it, I guess we need to debug how VSCode's IntelliSense (or Kite as an alternative) is inspecting the objects (a PDF instance in our case or anything inheriting from DynamicCore) so we know what we're missing.

Here's what I tried:

  • In the PDF library class I added at the end of __init__:
...
        cls = self.__class__
        for attr, meth in self.__dict__["attributes"].items():
            setattr(cls, attr, meth)  # should be converted to unbound method (function)

and at module level:

setattr(PDF, "open_pdf", DocumentKeywords.open_pdf)

and I feel even with a meta-class that dynamically picks the methods and adds them to the library class won't change something.

Screenshot 2022-09-08 at 19 21 13 1

and as you can see, only run_dialog is clickable. (since that library isn't using the DynamicCore approach)

Problem is that these dynamically added methods happen at instantiation time and black magic is done to the holder instance, which confuses the static introspection. While in normal scenarios, methods (and all attributes) are collected from the actual and base classes at importing (code reading) time and inferred from there.

A class definition like:

class PDF(DynamicCore, DocumentKeywords, FinderKeywords, ModelKeywords):

will solve IntelliSense, but we'll be running into other kind of issues as the dynamic registration wasn't designed to work like this.


❌ I'm going to mark this as "won't fix" and @mikahanninen can even close the issue if there isn't any sane solution to this. (like augmenting our own vendorized DynamicCore with a mixin in such a way it will provide to VSCode the missing methods (keywords) from every final library class adopting this pattern)

@cmin764
Copy link
Contributor

cmin764 commented Sep 15, 2022

Closing this in favor to the upstream reported Issue: robotframework/PythonLibCore#95

We can partially overcome this limitation by creating *.pyi module stubs with mypy.

@cmin764 cmin764 closed this as completed Sep 15, 2022
@aaltat
Copy link

aaltat commented Sep 15, 2022

Actually it is not black magic all, PythonLibCore fully follows Robot Framework Dynamic library API. It seems that rpaframework only implements the static library API, which is the most popular API, but is not the only API available in the Robot Framework (Please note that there is actually three different library API in RF).

The difference between library API is easy. From user guide: Every dynamic library must have both the get_keyword_names and run_keyword methods but rest of the methods in the dynamic API are optional.. Also in user guide In the hybrid API, there is no run_keyword method for executing keywords.. So if the library has get_keyword_names and run_keyword methods, it is dynamic library and keyword discovery should be done within the rules of the dynamic library API. If library has get_keyword_names, but does not have run_keyword method, then it is hybrid library and keyword discovery should be done within the rules of the hybrid library API. If library does not have get_keyword_names and run_keyword methods, then it is static library and rpaframework can do same thing as now.

From PythonLibCore (PLC) point of view closing this issue is not correct, because PLC will only support dynamic library API. Instead this issue should be reopened and underlying problem should be fixed in the rpaframework.

@cmin764
Copy link
Contributor

cmin764 commented Sep 16, 2022

Thank you for the thorough explanations and they all make sense! But just to be sure we are highlighting correctly the pain point here, Robot Framework syntax discovery and rpaframework usage works perfectly fine. It is a problem only when editing Python code and trying to have VSCode displaying all the existing methods in the dynamic library instance.

And the same happens with every library inheriting from DynamicCore, no matter where that comes from. And I agree, most probably it is a problem on how the Python extension discovers the methods in VSCode, not with us and/or RF. In the Selenium case, you have *.pyi files which helps on discovering those methods and we haven't generated such interfaces yet. But even if we do, the problem is solved partially, because exactly as in your case, we won't be able to display documentation when writing robots with Python.

@aaltat Just to be sure, is there a way where you can see in VSCode the keyword documentation (docstring) when writing a robot in Python code? (while using a library inheriting from the DynamicCore)

@aaltat
Copy link

aaltat commented Sep 24, 2022

I do not use VSCOde, so I am not able to answer your question. Generally speaking capabilities depends on the plugin used by in the VSCode. When looking matter from the PLC and dynamic library API point of view, there is not limitations when or how often keywords and other data from library is discovered. Plugin can do discovery every second, if that is the implementation of the plugin. But discovery should be done in the VSCode plugin side, library/PLC/dynamic library API can not push changes to VSCode direction.

The best solution from user point of view, would be automatic refresh for changes. Example plugin could discover files used by the library and detect changes on them. Example, I think, it is possible to use libdoc --specdocformatoption and that format should contain the file paths, where the keyword is implemented. Then plugin could use that information and discover the files it need to monitor. Or if not feasible to implement automatic discovery, then plugin could offer users a command to force refresh of the keywords.

In short, all depends on the VSCode plugin implementation, PLC and dynamic library API support your needs.

@aaltat
Copy link

aaltat commented Sep 24, 2022

My memory served me well source is available at least according the json schema file: https://github.com/robotframework/robotframework/blob/master/doc/schema/libdoc.json#L35

@douglassjohnandrew
Copy link

@cmin764 I know it's been a while since this issue was closed but I wanted to apologize and thank you for the time you spent looking into this. I'm fairly new at Python development and for some reason I thought that if Intellisense didn't work, that meant the code had syntax errors and wouldn't work. If I had known that the code would work even without Intellisense highlighting it, I wouldn't have submitted this as an issue at all. Thank you again for explaining what's going on behind the scenes, it's much appreciated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bad or unexpected behaviour wontfix This won't or can't be worked on
Projects
None yet
Development

No branches or pull requests

4 participants