Revision: 4272
Author: pekka.klarck
Date: Wed Oct 27 05:52:27 2010
Log: if __all__ is used with module libs, create keywords only from
functions in it (issue 678)
http://code.google.com/p/robotframework/source/detail?r=4272
Modified:
/trunk/atest/robot/test_libraries/module_library.txt
/trunk/atest/testdata/test_libraries/module_library.txt
/trunk/atest/testresources/testlibs/module_library.py
/trunk/doc/userguide/src/ExtendingRobotFramework/CreatingTestLibraries.txt
/trunk/src/robot/running/testlibraries.py
=======================================
--- /trunk/atest/robot/test_libraries/module_library.txt Mon Apr 12
05:17:10 2010
+++ /trunk/atest/robot/test_libraries/module_library.txt Wed Oct 27
05:52:27 2010
@@ -5,53 +5,70 @@
*** Test Cases ***
Passing
- Check Test Case Passing
+ Check Test Case ${TESTNAME}
Failing
- Check Test Case Failing
+ Check Test Case ${TESTNAME}
Logging
- ${test} = Check Test Case Logging
+ ${test} = Check Test Case ${TESTNAME}
Check Log Message ${test.kws[0].msgs[0]} Hello from module library
Check Log Message ${test.kws[0].msgs[1]} WARNING! WARN
Returning
- Check Test Case Returning
+ Check Test Case ${TESTNAME}
One Argument
- Check Test Case One Argument
+ Check Test Case ${TESTNAME}
Many Arguments
- Check Test Case Many arguments
+ Check Test Case ${TESTNAME}
Default Arguments
- Check Test Case Default Arguments
+ Check Test Case ${TESTNAME}
Variable Arguments
- Check Test Case Variable Arguments
+ Check Test Case ${TESTNAME}
Only Methods And Functions Are Keywords
- Check Test Case Only methods and functions are Keywords
+ Check Test Case ${TESTNAME}
Class Methods In Module Library Are Not Keywords
- Check Test Case Class Methods in Module Library are Not Keywords
+ Check Test Case ${TESTNAME}
+
+Functions starting with underscore are not keywords
+ Check Test Case ${TESTNAME}
+
+If __all__ is present, only functions listed there are available
+ Check Test Case ${TESTNAME} 1
+ Check Test Case ${TESTNAME} 2
+ Check Test Case ${TESTNAME} 3
+ Check Test Case ${TESTNAME} 4
+ Keyword should not have been added join
+ Keyword should not have been added not_in_all
Class Method Assigned To Module Variable
- Check Test Case Class method assigned to Module variable
+ Check Test Case ${TESTNAME}
Lambda Keyword
- Check Test Case Lambda Keyword
+ Check Test Case ${TESTNAME}
Lambda Keyword With Arguments
- Check Test Case Lambda Keyword With Arguments
+ Check Test Case ${TESTNAME}
Attribute With Same Name As Module
- Check Test Case Attribute With Same Name as Module
+ Check Test Case ${TESTNAME}
Importing Submodule As Library
- Check Test Case Importing submodule As Library
+ Check Test Case ${TESTNAME}
Module Library Scope Should Be Global
${lib module path} = Join Path ${CURDIR}/../../
testresources/testlibs/module_library
Check Syslog Contains Imported library 'module_library' with
arguments [ ] (version test, module type, global scope, 12 keywords, source
${lib module path}
+
+***Keywords***
+
+Keyword should not have been added
+ [Arguments] ${kw} ${lib}=module_lib_with_all
+ Check Syslog Contains Adding keyword '${kw}' to library '${lib}'
failed: Not exposed as keyword
=======================================
--- /trunk/atest/testdata/test_libraries/module_library.txt Mon Mar 29
04:47:59 2010
+++ /trunk/atest/testdata/test_libraries/module_library.txt Wed Oct 27
05:52:27 2010
@@ -1,6 +1,7 @@
*** Settings ***
Library module_library
Library pythonmodule.library
+Library module_lib_with_all.py
*** Variables ***
@{INTS} 1 2 3 4 5 6 7
@@ -51,6 +52,30 @@
[Documentation] FAIL No keyword with name 'Not Keyword' found.
Not Keyword
+Functions starting with underscore are not keywords
+ [Documentation] FAIL No keyword with name '_not_keyword' found.
+ _not_keyword
+
+If __all__ is present, only functions listed there are available 1
+ [Documentation] FAIL No keyword with name 'Not in all' found.
+ ${path} = Join with execdir xxx
+ Should Be Equal ${path} ${EXECDIR}${/}xxx
+ ${path} = Abspath .
+ Should Be Equal ${path} ${EXECDIR}
+ Not in all
+
+If __all__ is present, only functions listed there are available 2
+ [Documentation] FAIL No keyword with name 'Join' found.
+ Join arg1 arg2
+
+If __all__ is present, only functions listed there are available 3
+ [Documentation] FAIL No keyword with name 'attr_is_not_kw' found.
+ attr_is_not_kw
+
+If __all__ is present, only functions listed there are available 4
+ [Documentation] FAIL No keyword with
name '_not_kw_even_if_listed_in_all' found.
+ _not_kw_even_if_listed_in_all
+
Class Method Assigned To Module Variable
[Documentation] FAIL Arguments should have been unequal, both
were 'Hi'
Two Arguments From Class Hello World
=======================================
--- /trunk/atest/testresources/testlibs/module_library.py Sun Mar 15
08:33:37 2009
+++ /trunk/atest/testresources/testlibs/module_library.py Wed Oct 27
05:52:27 2010
@@ -1,4 +1,4 @@
-ROBOT_LIBRARY_SCOPE = 'Test Suite' # this should be igonred.
+ROBOT_LIBRARY_SCOPE = 'Test Suite' # this should be ignored
__version__ = 'test' # this should be used as version of this library
@@ -46,6 +46,8 @@
lambda_keyword = lambda arg: int(arg) + 1
lambda_keyword_with_two_args = lambda x, y: int(x) / int(y)
+def _not_keyword():
+ pass
def module_library():
return "It should be OK to have an attribute with same name as the
module"
=======================================
---
/trunk/doc/userguide/src/ExtendingRobotFramework/CreatingTestLibraries.txt
Sat Aug 28 08:09:32 2010
+++
/trunk/doc/userguide/src/ExtendingRobotFramework/CreatingTestLibraries.txt
Wed Oct 27 05:52:27 2010
@@ -311,16 +311,72 @@
Creating static keywords
~~~~~~~~~~~~~~~~~~~~~~~~
-Keyword names
-'''''''''''''
+What methods are considered keywords
+''''''''''''''''''''''''''''''''''''
When the static library API is used, Robot Framework uses reflection
-to find out what methods the library implements. With `dynamic library
-API`_ and `hybrid library API`_, keyword names are got from the
-library directly. Naturally, Robot Framework can see only the public
-methods and it also excludes all methods starting with an
-underscore. With Java libraries, also methods that are implemented in
-:code:`java.lang.Object` and not overridden are ignored.
+to find out what public methods the library class or module
+implements. It will exclude all methods starting with an underscore,
+and with Java libraries also methods that are implemented only in
+:code:`java.lang.Object` are ignored. All the methods that are not
+ignored are considered keywords. For example, the Python and Java
+libraries below implement single keyword :name:`My Keyword`.
+
+.. sourcecode:: python
+
+ class MyLibrary:
+
+ def my_keyword(self, arg):
+ return self._helper_method(arg):
+
+ def _helper_method(self, arg):
+ return arg.upper()
+
+.. sourcecode:: java
+
+ public class MyLibrary {
+
+ public String myKeyword(String arg) {
+ return helperMethod(arg);
+ }
+
+ private String helperMethod(String arg) {
+ return arg.toUpperCase();
+ }
+ }
+
+When the library is implemented as a Python module, it is also
+possible to limit what methods are keywords by using Python's
+:code:`__all__` attribute. If :code:`__all__` is used, only methods
+listed in it can be keywords. For example, the library below
+implements keywords :name:`Example Keyword` and :name:`Second
+Example`. Without :code:`__all__`, it would implement also keywords
+:name:`Not Exposed As Keyword` and :name:`Current Thread`. The most
+important usage for :code:`__all__` is making sure imported helper
+methods, such as :code:`current_thread` in the example below, are not
+accidentally exposed as keywords.
+
+.. sourcecode:: python
+
+ from threading import current_thread
+
+ __all__ = ['example_keyword', 'second_example']
+
+ def example_keyword():
+ if current_thread().name == 'MainThread':
+ print 'Running in main thread'
+
+ def second_example():
+ pass
+
+ def not_exposed_as_keyword():
+ pass
+
+.. note:: Support for the :code:`__all__` attribute is available from
+ Robot Framework 2.5.5 onwards.
+
+Keyword names
+'''''''''''''
Keyword names used in the test data are compared with method names to
find the method implementing these keywords. Name comparison is
=======================================
--- /trunk/src/robot/running/testlibraries.py Tue Sep 21 03:12:02 2010
+++ /trunk/src/robot/running/testlibraries.py Wed Oct 27 05:52:27 2010
@@ -260,6 +260,12 @@
def _get_scope(self, libcode):
return 'GLOBAL'
+ def _get_handler_method(self, libcode, name):
+ method = _BaseTestLibrary._get_handler_method(self, libcode, name)
+ if hasattr(libcode, '__all__') and name not in libcode.__all__:
+ raise TypeError('Not exposed as keyword')
+ return method
+
def get_instance(self):
self.init.arguments.check_arg_limits(self.positional_args)
return self._libcode