Repository: omni-us/jsonargparse
Pull request #548 (2024-07-12 05:23:49)

Fix import path of inherited classmethod not resolving correctly
## What does this PR do?

Fixes https://github.com/Lightning-AI/pytorch-lightning/discussions/19863#discussioncomment-10010226

## Before submitting

- [x] Did you read the [contributing guideline](https://github.com/omni-us/jsonargparse/blob/main/CONTRIBUTING.rst)?
- [n/a] Did you update **the documentation**? (readme and public docstrings)
- [x] Did you write **unit tests** such that there is 100% coverage on related code? (required for bug fixes and new features)
- [x] Did you verify that new and existing **tests pass locally**?
- [x] Did you make sure that all changes preserve **backward compatibility**?
- [x] Did you update **the CHANGELOG**? (not for typos, docs, test updates, or minor internal changes/refactors)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=omni-us_jsonargparse&pullRequest=548) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=548&resolved=false&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=548&resolutions=WONTFIX)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=548&resolved=false&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=548&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=548&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=omni-us_jsonargparse&pullRequest=548)



Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 393b404..e38a17e 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -31,6 +31,9 @@ Fixed
 - ``dump`` failing when a link target requires serialization and
   ``skip_link_targets=False`` (`#542
   <https://github.com/omni-us/jsonargparse/pull/542>`__).
+- Import path of inherited classmethod not resolving correctly (`lightning#19863
+  comment
+  <https://github.com/Lightning-AI/pytorch-lightning/discussions/19863#discussioncomment-10010226>`__).
 
 
 v4.31.0 (2024-06-27)
diff --git a/jsonargparse/_util.py b/jsonargparse/_util.py
index f07d087..44e53d9 100644
--- a/jsonargparse/_util.py
+++ b/jsonargparse/_util.py
@@ -216,8 +216,12 @@ def get_import_path(value: Any) -> Optional[str]:
     """Returns the shortest dot import path for the given object."""
     path = None
     value = get_generic_origin(value)
-    module_path = getattr(value, "__module__", None)
-    qualname = getattr(value, "__qualname__", "")
+    if hasattr(value, "__self__") and inspect.isclass(value.__self__) and inspect.ismethod(value):
+        module_path = getattr(value.__self__, "__module__", None)
+        qualname = f"{value.__self__.__name__}.{value.__name__}"
+    else:
+        module_path = getattr(value, "__module__", None)
+        qualname = getattr(value, "__qualname__", "")
 
     if module_path is None:
         path = unresolvable_import_paths.get(value)
@@ -244,7 +248,7 @@ def get_import_path(value: Any) -> Optional[str]:
                 if getattr(module, attr, None) is value:
                     path = module_path + "." + attr
                     break
-                elif getattr(obj, attr, None) is value:
+                elif getattr(obj, attr, None) == value:
                     path = module_path + "." + qualname
                     break
             elif getattr(module, qualname, None) is value:


Test patch:
diff --git a/jsonargparse_tests/test_util.py b/jsonargparse_tests/test_util.py
index c7709ac..1abd85f 100644
--- a/jsonargparse_tests/test_util.py
+++ b/jsonargparse_tests/test_util.py
@@ -565,6 +565,23 @@ def test_get_import_path_static_method_shorthand():
     assert get_import_path(static_method) == f"{__name__}.static_method"
 
 
+class ParentClassmethod:
+    __module__ = "jsonargparse_tests"
+
+    @classmethod
+    def class_method(cls):
+        pass
+
+
+class ChildClassmethod(ParentClassmethod):
+    pass
+
+
+def test_get_import_path_classpath_inheritance():
+    assert get_import_path(ParentClassmethod.class_method) == "jsonargparse_tests.ParentClassmethod.class_method"
+    assert get_import_path(ChildClassmethod.class_method) == f"{__name__}.ChildClassmethod.class_method"
+
+
 def unresolvable_import():
     pass