Repository: facebookresearch/hydra

Issue:
Document hydra.utils.{get_class,get_method}
Users would benefit from documentation for the following:
[`hydra.utils.get_class`](https://github.com/facebookresearch/hydra/blob/1cbe86ebecbeb134a3f2041120d57447a7394314/hydra/utils.py#L21)
[`hydra.utils.get_method`](https://github.com/facebookresearch/hydra/blob/1cbe86ebecbeb134a3f2041120d57447a7394314/hydra/utils.py#L32)


Discussion:
Would be greatly appreciated if this could be doumented!

Resolving patch:
diff --git a/hydra/utils.py b/hydra/utils.py
--- a/hydra/utils.py
+++ b/hydra/utils.py
@@ -19,6 +19,14 @@
 
 
 def get_class(path: str) -> type:
+    """
+    Look up a class based on a dotpath.
+    Fails if the path does not point to a class.
+
+    >>> import my_module
+    >>> from hydra.utils import get_class
+    >>> assert get_class("my_module.MyClass") is my_module.MyClass
+    """
     try:
         cls = _locate(path)
         if not isinstance(cls, type):
@@ -28,11 +36,19 @@ def get_class(path: str) -> type:
             )
         return cls
     except Exception as e:
-        log.error(f"Error initializing class at {path}: {e}")
+        log.error(f"Error getting class at {path}: {e}")
         raise e
 
 
 def get_method(path: str) -> Callable[..., Any]:
+    """
+    Look up a callable based on a dotpath.
+    Fails if the path does not point to a callable object.
+
+    >>> import my_module
+    >>> from hydra.utils import get_method
+    >>> assert get_method("my_module.my_function") is my_module.my_function
+    """
     try:
         obj = _locate(path)
         if not callable(obj):
@@ -51,6 +67,22 @@ def get_method(path: str) -> Callable[..., Any]:
 get_static_method = get_method
 
 
+def get_object(path: str) -> Any:
+    """
+    Look up a callable based on a dotpath.
+
+    >>> import my_module
+    >>> from hydra.utils import get_object
+    >>> assert get_object("my_module.my_object") is my_module.my_object
+    """
+    try:
+        obj = _locate(path)
+        return obj
+    except Exception as e:
+        log.error(f"Error getting object at {path} : {e}")
+        raise e
+
+
 def get_original_cwd() -> str:
     """
     :return: the original working directory the Hydra application was launched from


Test patch:
diff --git a/tests/instantiate/__init__.py b/tests/instantiate/__init__.py
--- a/tests/instantiate/__init__.py
+++ b/tests/instantiate/__init__.py
@@ -436,3 +436,6 @@ def recisinstance(got: Any, expected: Any) -> bool:
             for key in expected._fields
         )
     return True
+
+
+an_object = object()
diff --git a/tests/instantiate/test_helpers.py b/tests/instantiate/test_helpers.py
--- a/tests/instantiate/test_helpers.py
+++ b/tests/instantiate/test_helpers.py
@@ -8,7 +8,7 @@
 from pytest import mark, param
 
 from hydra._internal.utils import _locate
-from hydra.utils import get_class, get_method
+from hydra.utils import get_class, get_method, get_object
 from tests.instantiate import (
     AClass,
     Adam,
@@ -16,6 +16,7 @@
     ASubclass,
     NestingClass,
     Parameters,
+    an_object,
 )
 
 from .module_shadowed_by_function import a_function
@@ -131,6 +132,7 @@
             ),
             id="import_assertion_error",
         ),
+        param("tests.instantiate.an_object", an_object, id="object"),
     ],
 )
 def test_locate(name: str, expected: Any) -> None:
@@ -174,6 +176,14 @@ def test_locate_relative_import_fails(name: str) -> None:
             ),
             id="module-error",
         ),
+        param(
+            "tests.instantiate.an_object",
+            raises(
+                ValueError,
+                match="Located non-callable of type 'object' while loading 'tests.instantiate.an_object'",
+            ),
+            id="object-error",
+        ),
     ],
 )
 def test_get_method(path: str, expected: Any) -> None:
@@ -205,6 +215,14 @@ def test_get_method(path: str, expected: Any) -> None:
             ),
             id="module-error",
         ),
+        param(
+            "tests.instantiate.an_object",
+            raises(
+                ValueError,
+                match="Located non-class of type 'object' while loading 'tests.instantiate.an_object'",
+            ),
+            id="object-error",
+        ),
     ],
 )
 def test_get_class(path: str, expected: Any) -> None:
@@ -213,3 +231,38 @@ def test_get_class(path: str, expected: Any) -> None:
             get_class(path)
     else:
         assert get_class(path) == expected
+
+
+@mark.parametrize(
+    "path,expected",
+    [
+        param("tests.instantiate.AClass", AClass, id="class"),
+        param("builtins.print", print, id="callable"),
+        param(
+            "datetime",
+            datetime,
+            id="module-error",
+        ),
+        param("tests.instantiate.an_object", an_object, id="object"),
+        param(
+            "builtins.int.not_found",
+            raises(
+                ImportError,
+                match=dedent(
+                    r"""
+                    Error loading 'builtins\.int\.not_found':
+                    AttributeError\("type object 'int' has no attribute 'not_found'",?\)
+                    Are you sure that 'not_found' is an attribute of 'builtins\.int'\?
+                    """
+                ).strip(),
+            ),
+            id="builtin_attribute_error",
+        ),
+    ],
+)
+def test_get_object(path: str, expected: Any) -> None:
+    if isinstance(expected, RaisesContext):
+        with expected:
+            get_object(path)
+    else:
+        assert get_object(path) == expected