Skip to content

Commit be44564

Browse files
authored
Support for get_keyword_source (#28)
Returns path to file and line number where keyword is located.
1 parent 35f52e8 commit be44564

File tree

5 files changed

+132
-0
lines changed

5 files changed

+132
-0
lines changed

atest/DynamicTypesLibrary.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
from robotlibcore import DynamicCore, keyword
44

55

6+
def def_deco(func):
7+
return func
8+
9+
610
class DynamicTypesLibrary(DynamicCore):
711

812
def __init__(self, arg=False):
@@ -52,3 +56,8 @@ def keyword_none(self, arg=None):
5256
@keyword
5357
def is_python_3(self):
5458
return sys.version_info >= (3,)
59+
60+
@keyword
61+
@def_deco
62+
def keyword_with_def_deco(self):
63+
return 1

requirements-dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pytest
22
pytest-cov
3+
pytest-mockito
34
robotstatuschecker
45
flake8

src/robotlibcore.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"""
2121

2222
import inspect
23+
import os
2324
import sys
2425
try:
2526
import typing
@@ -174,6 +175,34 @@ def __join_defaults_with_types(self, method, types):
174175
types[name] = type(value)
175176
return types
176177

178+
def get_keyword_source(self, keyword_name):
179+
method = self.__get_keyword(keyword_name)
180+
path = self.__get_keyword_path(method)
181+
line_number = self.__get_keyword_line(method)
182+
if path and line_number:
183+
return '%s:%s' % (path, line_number)
184+
if path:
185+
return path
186+
if line_number:
187+
return ':%s' % line_number
188+
return None
189+
190+
def __get_keyword_line(self, method):
191+
try:
192+
source, line_number = inspect.getsourcelines(method)
193+
except (OSError, IOError, TypeError):
194+
return None
195+
for line in source:
196+
if line.strip().startswith('def'):
197+
return line_number
198+
line_number += 1
199+
200+
def __get_keyword_path(self, method):
201+
try:
202+
return os.path.normpath(inspect.getfile(method))
203+
except TypeError:
204+
return None
205+
177206

178207
class StaticCore(HybridCore):
179208

utest/test_get_keyword_source.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import inspect
2+
from os import path
3+
4+
import pytest
5+
from DynamicLibrary import DynamicLibrary
6+
from DynamicTypesLibrary import DynamicTypesLibrary
7+
from mockito.matchers import Any
8+
9+
10+
@pytest.fixture(scope='module')
11+
def lib():
12+
return DynamicLibrary()
13+
14+
15+
@pytest.fixture(scope='module')
16+
def lib_types():
17+
return DynamicTypesLibrary()
18+
19+
20+
@pytest.fixture(scope='module')
21+
def cur_dir():
22+
return path.dirname(__file__)
23+
24+
@pytest.fixture(scope='module')
25+
def lib_path(cur_dir):
26+
return path.normpath(path.join(cur_dir, '..', 'atest', 'DynamicLibrary.py'))
27+
28+
29+
@pytest.fixture(scope='module')
30+
def lib_path_components(cur_dir):
31+
return path.normpath(path.join(cur_dir, '..', 'atest', 'librarycomponents.py'))
32+
33+
34+
@pytest.fixture(scope='module')
35+
def lib_path_types(cur_dir):
36+
return path.normpath(path.join(cur_dir, '..', 'atest', 'DynamicTypesLibrary.py'))
37+
38+
39+
def test_location_in_main(lib, lib_path):
40+
source = lib.get_keyword_source('keyword_in_main')
41+
assert source == '%s:20' % lib_path
42+
43+
44+
def test_location_in_class(lib, lib_path_components):
45+
source = lib.get_keyword_source('method')
46+
assert source == '%s:15' % lib_path_components
47+
48+
49+
def test_location_in_class_custom_keyword_name(lib, lib_path_components):
50+
source = lib.get_keyword_source('Custom name')
51+
assert source == '%s:19' % lib_path_components
52+
53+
54+
def test_no_line_number(lib, lib_path, when):
55+
when(lib)._DynamicCore__get_keyword_line(Any()).thenReturn(None)
56+
source = lib.get_keyword_source('keyword_in_main')
57+
assert source == lib_path
58+
59+
60+
def test_no_path(lib, when):
61+
when(lib)._DynamicCore__get_keyword_path(Any()).thenReturn(None)
62+
source = lib.get_keyword_source('keyword_in_main')
63+
assert source == ':20'
64+
65+
66+
def test_no_path_and_no_line_number(lib, when):
67+
when(lib)._DynamicCore__get_keyword_path(Any()).thenReturn(None)
68+
when(lib)._DynamicCore__get_keyword_line(Any()).thenReturn(None)
69+
source = lib.get_keyword_source('keyword_in_main')
70+
assert source is None
71+
72+
73+
def test_def_in_decorator(lib_types, lib_path_types):
74+
source = lib_types.get_keyword_source('keyword_with_def_deco')
75+
assert source == '%s:62' % lib_path_types
76+
77+
78+
def test_error_in_getfile(lib, when):
79+
when(inspect).getfile(Any()).thenRaise(TypeError('Some message'))
80+
source = lib.get_keyword_source('keyword_in_main')
81+
assert source is None
82+
83+
84+
def test_error_in_line_number(lib, when, lib_path):
85+
when(inspect).getsourcelines(Any()).thenRaise(IOError('Some message'))
86+
source = lib.get_keyword_source('keyword_in_main')
87+
assert source == lib_path

utest/test_robotlibcore.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ def test_dir():
3131
'Embedded arguments "${here}"',
3232
'_DynamicCore__get_arg_spec',
3333
'_DynamicCore__get_keyword',
34+
'_DynamicCore__get_keyword_line',
35+
'_DynamicCore__get_keyword_path',
3436
'_DynamicCore__get_keyword_tags_supported',
3537
'_DynamicCore__get_typing_hints',
3638
'_DynamicCore__join_defaults_with_types',
@@ -48,6 +50,7 @@ def test_dir():
4850
'get_keyword_arguments',
4951
'get_keyword_documentation',
5052
'get_keyword_names',
53+
'get_keyword_source',
5154
'get_keyword_tags',
5255
'get_keyword_types',
5356
'instance_attribute',
@@ -65,10 +68,13 @@ def test_dir():
6568
expected = [e for e in expected if e not in ('_DynamicCore__get_typing_hints',
6669
'_DynamicCore__get_arg_spec',
6770
'_DynamicCore__get_keyword',
71+
'_DynamicCore__get_keyword_line',
72+
'_DynamicCore__get_keyword_path',
6873
'_DynamicCore__get_keyword_tags_supported',
6974
'_DynamicCore__join_defaults_with_types',
7075
'get_keyword_arguments',
7176
'get_keyword_documentation',
77+
'get_keyword_source',
7278
'get_keyword_tags',
7379
'run_keyword',
7480
'get_keyword_types')]

0 commit comments

Comments
 (0)