Repository: robotframework/PythonLibCore (language: python)

Issue:
Decorator resolves as wron file path 
Reported in https://github.com/MarketSquare/robotframework-browser/issues/2382

Original issue says 
Describe the bug

In the documentation generated with libdoc (in JSON or libspec format), the source file for the keyword New Context is Browser/utils/deprecated.py.

To Reproduce
Steps to reproduce the behavior:

Execute libdoc Browser browser.json
Search for "name": "New Context" and then for "source":
Expected behavior

The source of the keyword New Context is 


OS: Windows 10


The keyword New Context has the following definition
```python
@keyword(tags=("Setter", "BrowserControl"))
@attribute_warning(
    old_args=("videosPath", "videoSize"), new_args=("recordVideo", "recordVideo")
)
def new_context(
    self,
    ...
)
```
Apparently, libdoc expects that the line after the keyword decorator is a function definition.


Discussion / hints:
https://github.com/robotframework/PythonLibCore/blob/ef35336fbc895d3d329a6d61be52501c2a5a54d4/src/robotlibcore.py#L142 

should be:

```
return os.path.normpath(inspect.getsourcefile(inspect.unwrap(method)))
```
it is the same like robotframework gets the source for a keyword.
Most likely that is the problem, do you want to do PR, with test, to fix it?
sorry for my late answer ;-)

yes I can provide a PR, but only at the end of the week, if it's ok for you. Just have a few days vacation ;-)
No rush take your time. 

Fix patch:
diff --git a/src/robotlibcore.py b/src/robotlibcore.py
index deb7e1f..a63b053 100644
--- a/src/robotlibcore.py
+++ b/src/robotlibcore.py
@@ -157,7 +157,7 @@ def __get_keyword_line(self, method):
 
     def __get_keyword_path(self, method):
         try:
-            return os.path.normpath(inspect.getfile(method))
+            return os.path.normpath(inspect.getfile(inspect.unwrap(method)))
         except TypeError:
             return None
 


Test patch:
diff --git a/atest/custon_deco.py b/atest/custon_deco.py
new file mode 100644
index 0000000..6aca28d
--- /dev/null
+++ b/atest/custon_deco.py
@@ -0,0 +1,15 @@
+import functools
+
+
+def custom_deco(arg1, arg2):
+    print(arg1, arg2)
+
+    def actual_decorator(func):
+        @functools.wraps(func)
+        def wrapper(*args, **kwargs):
+            print("BEFORE")
+            value = func(*args, **kwargs)
+            print("AFTER")
+            return value
+        return wrapper
+    return actual_decorator
diff --git a/atest/librarycomponents.py b/atest/librarycomponents.py
index 6859098..eda048e 100644
--- a/atest/librarycomponents.py
+++ b/atest/librarycomponents.py
@@ -1,3 +1,4 @@
+from custon_deco import custom_deco
 from robotlibcore import keyword
 
 
@@ -13,8 +14,9 @@ class Names:
     def method(self):
         return 2
 
+    @custom_deco("foo", "bar")
     @keyword('Custom name')
-    def _custom_name(self):
+    def _other_name_here(self):
         return 3
 
     def not_keyword(self):
diff --git a/utest/test_get_keyword_source.py b/utest/test_get_keyword_source.py
index 343e4fd..43c8ad9 100644
--- a/utest/test_get_keyword_source.py
+++ b/utest/test_get_keyword_source.py
@@ -45,7 +45,7 @@ def test_location_in_main(lib, lib_path):
 
 def test_location_in_class(lib, lib_path_components):
     source = lib.get_keyword_source("method")
-    assert source == "%s:13" % lib_path_components
+    assert source == f"{lib_path_components}:14"
 
 
 def test_decorator_wrapper(lib_types, lib_path_types):
@@ -55,7 +55,7 @@ def test_decorator_wrapper(lib_types, lib_path_types):
 
 def test_location_in_class_custom_keyword_name(lib, lib_path_components):
     source = lib.get_keyword_source("Custom name")
-    assert source == "%s:17" % lib_path_components
+    assert source == f"{lib_path_components}:19"
 
 
 def test_no_line_number(lib, lib_path, when):
diff --git a/utest/test_robotlibcore.py b/utest/test_robotlibcore.py
index 96fb410..06c4971 100644
--- a/utest/test_robotlibcore.py
+++ b/utest/test_robotlibcore.py
@@ -41,7 +41,7 @@ def test_dir():
         "_DynamicCore__get_keyword_path",
         "_HybridCore__get_members",
         "_HybridCore__get_members_from_instance",
-        "_custom_name",
+        "_other_name_here",
         "add_library_components",
         "all_arguments",
         "attributes",
@@ -99,7 +99,7 @@ def test_getattr():
         assert lib.instance_attribute == "not keyword"
         assert lib.function() == 1
         assert lib.method() == 2
-        assert lib._custom_name() == 3
+        assert lib._other_name_here() == 3
         assert getattr(lib, "Custom name")() == 3
         with pytest.raises(AttributeError) as exc_info:
             lib.non_existing