Skip to content

Implement get_library_information interface for Remote libraries (Rob… #3802

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

Merged
merged 14 commits into from
Mar 4, 2021
Merged

Conversation

JFoederer
Copy link
Contributor

In preparation of resolving issue #3362 about load-time performance of large libraries, this pull request offers a forward and backward compatible interface extension as suggested in the issue.

With this change the Remote library will utilize the new get_library_information call to retrieve all information in a single go. This significantly reduces load times of large libraries, from minutes to a couple of seconds. When the new call is unavailable or fails, the regular interface is used to provide both backward compatibility and maintain analyzability in case of failure.

This pull request includes the change to Robot framework code (1 file), a new acceptance test (3 files) and a fix for the remote server (1 file) in the testdata. The latter could return None while None marshalling is disabled by default. There is no impact on documentation.

There appears to be some technical debt on the remote server side. Pull request #73 has been opened to first fix the current baseline of tests before pushing any updates to that side of the interface. Input requested.

…ot side)

Prevents excessive load times for large remote libraries, by loading all keyword information in a single go.
@codecov-io
Copy link

codecov-io commented Dec 17, 2020

Codecov Report

Merging #3802 (c2e6988) into master (64808a1) will decrease coverage by 0.05%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3802      +/-   ##
==========================================
- Coverage   75.26%   75.21%   -0.04%     
==========================================
  Files         221      221              
  Lines       18704    18704              
  Branches     3037     3037              
==========================================
- Hits        14075    14066       -9     
- Misses       4094     4100       +6     
- Partials      535      538       +3     
Impacted Files Coverage Δ
src/robot/utils/robotinspect.py 47.62% <0.00%> (-19.04%) ⬇️
src/robot/version.py 55.56% <0.00%> (-11.11%) ⬇️
src/robot/libdocpkg/datatypes.py 94.57% <0.00%> (-1.08%) ⬇️
src/robot/utils/importer.py 83.81% <0.00%> (-0.95%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0ae8d16...c2e6988. Read the comment docs.

@JFoederer
Copy link
Contributor Author

My initial statement about there being no documentation impact was false. That was only true for the user part. Documention has now been extended in the remote protocol section.

def get_library_information(self):
info_dict = dict()
for kw in self.get_keyword_names():
kw_dict = dict()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about just:

info_dict[kw] = {
    'args': self.get_keyword_arguments(kw),
    'tags': self.get_keyword_tags(kw)
    'doc': self.get_keyword_documentation(kw)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @bhirsz and thanks for reviewing!

Good suggestion, I might even prefer:

info_dict[kw] = dict(args=self.get_keyword_arguments(kw),
                     tags=self.get_keyword_tags(kw),
                     doc=self.get_keyword_documentation(kw))

I have similar code in the Python remote server implementation. I will update there as well.

try:
with self._server as server:
self.__kw_cache = server.get_library_information()
except:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too broad exception, what are usual expected exceptions here? (in case of not supported version etc)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured there were 2 possible ways to go here.

  1. Check if get_library_information is implemented. If so, use it and let it fail whenever it does.
  2. Just try to call it and fall back to the old way if it doesn't work, for whatever reason.

I went for the latter , because I thought it stayed closest to the existing behaviour. Not a fan of broad exception handling myself, so we could still opt for the first option.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introspection isn't available, so checking if it is implemented can't be done. But as it turns out the exceptions were already narrowed down on another level, that also contained a retry. Now the try on get_library_info replaces the first attempt and only the specific error is caught.

def get_keyword_names(self):
if self._kw_cache:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what is possible with the Python version we need to support but I would try to implement decorator similiar to lru_cache instead, with optional argument. Ie:

@keyword_cache()

@keyword_cache(type='tags')
..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have now also processed this comment.

@pekkaklarck
Copy link
Member

As I just commented issue #3362, it would be great to get this into RF 4.0. I looked at this PR now and it seems ok so that ought to be doable.

The code is somewhat complex with all decorators and caching and I'm not sure is that needed. Wouldn't it be enough to call get_library_information in get_keyword_names? We know Robot calls get_keyword_names first and also that it is called exactly once. I'll checkout this PR locally and will test that approach.

@pekkaklarck
Copy link
Member

If you @JFoederer are around, we can discuss this further on the #devel channel on our Slack. Already started a thread about this enhancement there.

Code simplification based on the information that get_keyword_names() is always called first and exactly once.
@pekkaklarck
Copy link
Member

Thanks @JFoederer for updating the implementation to call get_library_information directly in get_keyword_names. Lot simpler that way.

I think we can simplify this a bit more by replacing the decorator with a helper method. In addition to that, probably need to enhance the documentation a bit. At least a note about this being new in RF 4.0 is needed. I'll do these changes myself after merging this PR.

@pekkaklarck pekkaklarck merged commit db0519c into robotframework:master Mar 4, 2021
pekkaklarck added a commit that referenced this pull request Mar 4, 2021
pekkaklarck added a commit that referenced this pull request Mar 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants