Repository: PrefectHQ/prefect

Issue:
Async flow deployment regression in 2.19.3
### First check

- [X] I added a descriptive title to this issue.
- [X] I used the GitHub search to find a similar issue and didn't find it.
- [X] I searched the Prefect documentation for this issue.
- [X] I checked that this issue is related to Prefect and not one of its dependencies.

### Bug summary

Async flows cannot be deployed with Prefect 2.19.3. This worked fine with Prefect 2.19.2

### Reproduction

testflow.py:
```python3
from prefect import flow

@flow
async def main():
    pass
```


### Error

```bash
$ prefect deploy testflow.py:main
Could not find flow 'main' in 'testflow.py'
```

Given the above MRE, the `prefect deploy` command errors out with the message "Could not find flow 'main' in 'testflow.py'"


### Versions

```Text
Version:             2.19.3
API version:         0.8.4
Python version:      3.10.12
Git commit:          ce378efe
Built:               Thu, May 30, 2024 11:59 AM
OS/Arch:             linux/x86_64
Profile:             default
Server type:         ephemeral
Server:
  Database:          sqlite
  SQLite version:    3.37.2
```


### Additional context

_No response_


Discussion:

Resolving patch:
diff --git a/src/prefect/deployments/base.py b/src/prefect/deployments/base.py
--- a/src/prefect/deployments/base.py
+++ b/src/prefect/deployments/base.py
@@ -398,7 +398,13 @@ async def _find_flow_functions_in_file(filename: str) -> List[Dict]:
             return decorated_functions
 
     for node in ast.walk(tree):
-        if isinstance(node, ast.FunctionDef):
+        if isinstance(
+            node,
+            (
+                ast.FunctionDef,
+                ast.AsyncFunctionDef,
+            ),
+        ):
             for decorator in node.decorator_list:
                 # handles @flow
                 is_name_match = (
diff --git a/src/prefect/flows.py b/src/prefect/flows.py
--- a/src/prefect/flows.py
+++ b/src/prefect/flows.py
@@ -1913,7 +1913,14 @@ def load_flow_argument_from_entrypoint(
         (
             node
             for node in ast.walk(parsed_code)
-            if isinstance(node, ast.FunctionDef) and node.name == func_name
+            if isinstance(
+                node,
+                (
+                    ast.FunctionDef,
+                    ast.AsyncFunctionDef,
+                ),
+            )
+            and node.name == func_name
         ),
         None,
     )
diff --git a/src/prefect/utilities/callables.py b/src/prefect/utilities/callables.py
--- a/src/prefect/utilities/callables.py
+++ b/src/prefect/utilities/callables.py
@@ -456,7 +456,14 @@ def _generate_signature_from_source(
         (
             node
             for node in ast.walk(parsed_code)
-            if isinstance(node, ast.FunctionDef) and node.name == func_name
+            if isinstance(
+                node,
+                (
+                    ast.FunctionDef,
+                    ast.AsyncFunctionDef,
+                ),
+            )
+            and node.name == func_name
         ),
         None,
     )
@@ -544,7 +551,14 @@ def _get_docstring_from_source(source_code: str, func_name: str) -> Optional[str
         (
             node
             for node in ast.walk(parsed_code)
-            if isinstance(node, ast.FunctionDef) and node.name == func_name
+            if isinstance(
+                node,
+                (
+                    ast.FunctionDef,
+                    ast.AsyncFunctionDef,
+                ),
+            )
+            and node.name == func_name
         ),
         None,
     )


Test patch:
diff --git a/tests/test_flows.py b/tests/test_flows.py
--- a/tests/test_flows.py
+++ b/tests/test_flows.py
@@ -4164,6 +4164,25 @@ def flow_function(name: str) -> str:
 
         assert result == "flow-function"
 
+    def test_load_async_flow_from_entrypoint_no_name(self, tmp_path: Path):
+        flow_source = dedent(
+            """
+        from prefect import flow
+
+        @flow
+        async def flow_function(name: str) -> str:
+            return name
+        """
+        )
+
+        tmp_path.joinpath("flow.py").write_text(flow_source)
+
+        entrypoint = f"{tmp_path.joinpath('flow.py')}:flow_function"
+
+        result = load_flow_argument_from_entrypoint(entrypoint, "name")
+
+        assert result == "flow-function"
+
     def test_load_flow_description_from_entrypoint(self, tmp_path: Path):
         flow_source = dedent(
             """