robotframework icon indicating copy to clipboard operation
robotframework copied to clipboard

Allow resource files and libraries to be imported privately in other resource files

Open BCGST opened this issue 3 years ago • 15 comments

It could be beneficial if users could import resource files and libraries in a "private" way. Currently, resource files are imported in a sort of recursive way where you have access to all keywords that resource file imports as well, as described in the user guide here. This can be unhelpful when you are abstracting a library or resource such that other contributors should not make direct calls to the underlying libraries.

This was especially important to me on a recent project where I was refactoring a test suite to be able choose whether to run with Browser library or SeleniumLibrary to compare their pros and cons. You could pick which browser control to use but writing a test that made direct keyword calls to the opposite library would cause that control to crash out. Using an abstracted resource file allows you to pick which library to use on the fly, however with recursive importation, a contributor could still mistakenly call a non-abstracted keyword from one or the other library and cause the opposing library crash the test when they reach the unexpected keyword.

In more biased terms, private importation of libraries and resources feels like a much more familiar mode for project structure for me given that is how python seems to handle resource/library importation.

BCGST avatar Sep 20 '22 20:09 BCGST

Already addressed by #430

tw39124-1 avatar Sep 21 '22 09:09 tw39124-1

Ah. My bad. I did a little bit of digging around before posting this and didn't see that issue initially. Should I close this?

EDIT: Wait, I posted in that issue. I have tried getting traction on the RF slack here and nobody responded. I figured my best next option was starting a new issue.

BCGST avatar Sep 21 '22 15:09 BCGST

Yeah, private keywords brought by #430 in RF 5.1 aren't exactly the same as private imports. They are highly related, though, and #430 is a great step forward. This issue is more closely related to #2581.

pekkaklarck avatar Sep 21 '22 17:09 pekkaklarck

The functionality that whatever resource files import is visible to whomever imports that resource file is by design and often useful. It's also so widely used that due to backwards compatibility reasons we couldn't really change it even if we wanted to. I do agree this behavior isn't always desired, though, and would be open for ideas how to explicitly disable it when needed. Possibilities include:

  • New settings like Private Resource and Private Library that can be used instead of the existing Resource and Library when needed.
  • Some way to configure Resource and Library so that imports are private. This would avoid the need for a new setting, but with libraries something like private=True could clash with existing library config parameters.
  • Some way to list keywords (and possibly also variables) that a resource file exposes. This would be similar to __all__ in Python.
  • New tag to explicitly mark keywords public. #430 added robot:private so this should probably be robot:public. We'd then also need some way to indicate that anything that's not explicitly public shouldn't be exposed.

pekkaklarck avatar Sep 21 '22 17:09 pekkaklarck

I think the first two methods are compelling because they apply to Library and Resource where the last too seem like they would work strictly with Resource (or user generated libraries).

BCGST avatar Sep 28 '22 18:09 BCGST

I'll add this tentatively to RF 6.1 scope. I cannot make promises it will be included nor when we actually start 6.1 development.

I doubt this will be too complicated to implement. The hardest part is likely coming up with good syntax.

pekkaklarck avatar Nov 14 '22 14:11 pekkaklarck

My current thinking is that it would be best to handle this with a new setting that specifies what a resource file exposes. It would be similar to __all__ in Python that affects what the importer gets with from x import *. Some reasons why I feel that way:

  • Our imports are very much like from x import * in Python and using a similar solution as they use for liming what's exposed feels pretty logical.
  • This would avoid the need to change existing Library and Resource, which makes it easier to enhance them otherwise in the future. I'd like our imports to support Python style from x import y, z and import x imports, and imports both having configuration for what to import and what to expose can make them pretty complicated.
  • Another problem with enhancing Library and Resource is that configuring what's exposed is relevant only in resource files. Making a separate setting only available in resource files is easier than having a setting that can be used differently depending on the context.
  • An alternative to enhancing Library and Resource, that would avoid the two problems listed above, would be adding new settings Private Library and Private Resource. I find having two settings for importing libraries and another two for importing resources a bit confusing. Just a single setting that controls the "external interface" of the resource files feels simpler.
  • In general I think it's better to separate what is imported from what is exposed.
  • A separate setting for controlling what keywords are exposed could also be used to specify what keywords from the resource file itself are exposed. We nowadays have robot:private tag for that purpose, but if you have only few public keywords and many private ones it would be easier to list the former than tag the latter.
  • A setting for controlling what keywords are exposed could also be used for controlling what variables are exposed. That would be better than adding Private Variables, which also wouldn't solve how to limit what variables in the Variables section are exposed.

Some examples how this could work below:

# Expose some libraries and resources
Expose    library=Browser    library=SSHLibrary    resource=example.resource

# Expose no library
Expose    library=NONE

# Expose keywords and variables (no prefix needed)
Expose    My Keyword    Browser.Close Browser    ${VARIABLE}

pekkaklarck avatar Nov 16 '22 09:11 pekkaklarck

I have one question regarding this:

Why not follow the Python route here and instead of only providing a Library Import * / Resource Import *, provide a From Library.. Import ... / From Resource... Import ...? In general with an Import * and even with the proposed Expose, I think it's pretty hard to control what really gets into your namespace.

Also, maybe don't exactly follow 100% the Python route and make those lazy by default -- Python wants to do that now, but it's probably too late for Python, so, workarounds abound :wink:

fabioz avatar Jan 13 '23 09:01 fabioz

A related problem is that Robot doesn't have proper namespaces for resource files. When a resource file imports a library, another resource file, or a variable file, all imported keywords and variables are placed into the suite namespace. That causes issues like #2581. Fixing that problem basically requires re-implementing namespaces so that the suite namespace only contains keywords and variables in the suite file as well as references to libraries, resource files and variable files imported in that suite. Imported resource files would then have their own keywords and variables as well as references to libraries/resources/variables they import. Keyword and variable lookups would then go through these nested resource imports chains.

After the above change, it would be relatively easy to limit the visibility of the imported resource files. I guess it could somehow be done also without that change, but I wouldn't like to enhance the current namespace too much because there are pretty big reasons why it should be rewritten altogether. These two topics should be thought together and implemented in a same release.

pekkaklarck avatar Jan 16 '23 09:01 pekkaklarck

I get that the internals of RF may need to be improved due to the current implementation not taking that into account, but personally, I'd much rather have a proper implementation even if it takes longer than having those kind of fast but subpar workarounds...

fabioz avatar Jan 16 '23 10:01 fabioz

In my opinion, for better organization and ease of understanding, only the keywords implemented in a Resource should be available in the file that will use the Resource.

Today the behavior is like this:

file1.robot
*** Settings ***
Library    SeleniumLibrary
*** Keywords ***
keywork file 1
    Press Keys    Here I can use keywords from the SeleniumLibrary

file2.robot
Resource    file1.robot
*** Keywords ***
keywork file 2
     keywork file 1
     Press Keys    But I can also use the SeleniumLibrary keywords even if I don't add it as a Resource on file2.robot

My suggestion is to add a private MODIFIER, as exists in Java. I have not analyzed the Robot implementation to see if this modification is simple, but the idea would be to allow the Settings(Resource/Library/Variables) to allow the use of access/scope modifier.

If in the Resource/Library/Variables you don't inform the modifier, then it uses the default, as if it were a public one, remaining the current behavior.

Example:

file1.robot
*** Settings ***
private Library    SeleniumLibrary
*** Keywords ***
keywork file 1
    Press Keys    Here I can use keywords from the SeleniumLibrary

file2.robot
Resource    file1.robot
*** Keywords ***
keywork file 2
     keywork file 1
     #  I cannot use the SeleniumLibrary keywords because the private modifier in the Resource in file1.robot was used

adrianodemetrio avatar May 09 '23 14:05 adrianodemetrio

Too big for RF 7.

pekkaklarck avatar Aug 25 '23 11:08 pekkaklarck