task: metadata: install: pip install -e .[dev]
patch: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index ecd0090..015027e 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -6,7 +6,7 @@ on:
   pull_request:
     branches: [ "main" ]
   schedule:
-    - cron: "57 5 * * 3"
+    - cron: "57 5 * * 3"  # M H d m w (Every Wednesday at 5:57 AM)
 
 jobs:
   analyze:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index f23c37a..c77c510 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -17,6 +17,8 @@ v4.31.0 (2024-06-??)
 
 Added
 ^^^^^
+- Support async functions and methods in ``CLI`` (`#531
+  <https://github.com/omni-us/jsonargparse/pull/531>`__).
 - Support for ``Protocol`` types only accepting exact matching signature of
   public methods (`#526
   <https://github.com/omni-us/jsonargparse/pull/526>`__).
diff --git a/jsonargparse/_cli.py b/jsonargparse/_cli.py
index 43a08ba..1805347 100644
--- a/jsonargparse/_cli.py
+++ b/jsonargparse/_cli.py
@@ -92,8 +92,8 @@ def CLI(
             deprecation_warning_cli_return_parser()
             return parser
         cfg = parser.parse_args(args)
-        cfg_init = parser.instantiate_classes(cfg)
-        return _run_component(components, cfg_init)
+        init = parser.instantiate_classes(cfg)
+        return _run_component(components, init)
 
     elif isinstance(components, list):
         components = {c.__name__: c for c in components}
@@ -192,12 +192,13 @@ def _add_component_to_parser(
 
 def _run_component(component, cfg):
     cfg.pop("config", None)
-    if not inspect.isclass(component):
-        return component(**cfg)
     subcommand = cfg.pop("subcommand")
-    if not subcommand:
-        return component(**cfg)
-    subcommand_cfg = cfg.pop(subcommand, {})
-    subcommand_cfg.pop("config", None)
-    component_obj = component(**cfg)
-    return getattr(component_obj, subcommand)(**subcommand_cfg)
+    if inspect.isclass(component) and subcommand:
+        subcommand_cfg = cfg.pop(subcommand, {})
+        subcommand_cfg.pop("config", None)
+        component_obj = component(**cfg)
+        component = getattr(component_obj, subcommand)
+        cfg = subcommand_cfg
+    if inspect.iscoroutinefunction(component):
+        return __import__("asyncio").run(component(**cfg))
+    return component(**cfg)
diff --git a/pyproject.toml b/pyproject.toml
index 21a2259..1eb018a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -105,7 +105,6 @@ dev = [
     "jsonargparse[test]",
     "jsonargparse[coverage]",
     "jsonargparse[doc]",
-    "jsonargparse[mypy]",
     "pre-commit>=2.19.0",
     "tox>=3.25.0",
     "build>=0.10.0",

problem_statement: Add support for async objects in `CLI`
<!-- If you like this project, please ⭐ star it https://github.com/omni-us/jsonargparse/ -->

## 🚀 Feature request

Add support for objects that require asynchronous context for their creation.

### Motivation

Currently I cannot instantiate objects like `aiokafka.AIOKafkaProducer`. For example:

In `main.py`:

```Python
import aiokafka
from jsonargparse import CLI


async def main(producer: aiokafka.AIOKafkaProducer) -> None:
    print(producer)


if __name__ == "__main__":
    CLI(main)
```

In `config.yaml`:

```Yaml
producer:
  class_path: aiokafka.AIOKafkaProducer
  init_args:
    bootstrap_servers: ["localhost:9092"]
```

In terminal:

```Bash
python -m main --config config.yaml
```

Gives error:

```
RuntimeError: The object should be created within an async function or provide loop directly.
```

### Pitch

The above code should runs without errors.

### Alternatives

<!-- Any alternative solutions or features you've considered, if any. -->

repo: omni-us/jsonargparse
test_cmd: pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
test_patch: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 656a789..db6793f 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -28,7 +28,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        python: [3.8, "3.10"]
+        python: [3.8, "3.10", 3.12]
     steps:
       - uses: actions/checkout@v4
       - uses: actions/setup-python@v5
@@ -39,7 +39,7 @@ jobs:
       - run: tox -e py-all-extras
 
   unittest-omegaconf:
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
       - uses: actions/setup-python@v5
@@ -50,7 +50,7 @@ jobs:
       - run: tox -e omegaconf
 
   doctest:
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
       - uses: actions/setup-python@v5
diff --git a/jsonargparse_tests/test_cli.py b/jsonargparse_tests/test_cli.py
index 06d4879..ae51830 100644
--- a/jsonargparse_tests/test_cli.py
+++ b/jsonargparse_tests/test_cli.py
@@ -1,12 +1,13 @@
 from __future__ import annotations
 
+import asyncio
 import os
 import sys
 from contextlib import redirect_stderr, redirect_stdout, suppress
 from dataclasses import asdict, dataclass
 from io import StringIO
 from pathlib import Path
-from typing import Optional
+from typing import Callable, Optional
 from unittest.mock import patch
 
 import pytest
@@ -535,3 +536,44 @@ def test_final_and_subclass_type_config_file(tmp_cwd):
 
     out = CLI(run_bf, args=["--config=config.yaml"])
     assert "a yaml" == out
+
+
+# async tests
+
+
+async def run_async(time: float = 0.1):
+    await asyncio.sleep(time)
+    return "done"
+
+
+def test_async_function():
+    assert "done" == CLI(run_async, args=["--time=0.0"])
+
+
+class AsyncMethod:
+    def __init__(self, time: float = 0.1, require_async: bool = False):
+        self.time = time
+        if require_async:
+            self.loop = asyncio.get_event_loop()
+
+    async def run(self):
+        await asyncio.sleep(self.time)
+        return "done"
+
+
+def test_async_method():
+    assert "done" == CLI(AsyncMethod, args=["--time=0.0", "run"])
+
+
+async def run_async_instance(cls: Callable[[], AsyncMethod]):
+    return await cls().run()
+
+
+def test_async_instance():
+    config = {
+        "cls": {
+            "class_path": f"{__name__}.AsyncMethod",
+            "init_args": {"time": 0.0, "require_async": True},
+        }
+    }
+    assert "done" == CLI(run_async_instance, args=[f"--config={config}"])