Repository: litestar-org/litestar

Issue:
Properly indented docstrings result in incorrectly rendered Markdown in openapi docs
**Describe the bug**

A properly formatted docstring is indented to match the indentation of the function or method. The markdown rendering that is passed into the API docs seems to be interpreting these indentations in such a way that the markdown is not properly formatted unless the docstring is out-dented to an unconventional flush left.

**To Reproduce**

I have the following function definition with docstring:

```
async def content_classifier_model_details(model_name:str) -> ModelClassDetailsResponse:
    """Retrieve the variants and versions of a group of content classifier models for a
    given named classification.

    Models can be specified at the `classify` endpoint as follows:

    - **Class name only** (`model_name`). E.g. `climate_action`. Will utilize the
    default model as indicated by the default flag in the model details. _This format
    is provided primarily for development and exploratory purposes._ In production
    code, it is recommended that the variant be specified.
    - **Class with variant** (`name-variant`). E.g. `climate_action-nx`. Will utilize
      the current version of the specified variant as indicated by the `current` field
      in the model details.
    - **Full versioned identifier** (`name-variant-version`). E.g. `climate_action-nx-1` is
      useful for pinning your application to a specific historical version.
    """
```
The result is shown in the screenshot titled incorrect-markdown-render.png. The expected rendering is shown in correct-markdown-render.png which can be achieved by the following unconventional docstring format:

```
async def content_classifier_model_details(model_name:str) -> ModelClassDetailsResponse:
    """Retrieve the variants and versions of a group of content classifier models for a
given named classification.

Models can be specified at the `classify` endpoint as follows:

- **Class name only** (`model_name`). E.g. `climate_action`. Will utilize the
default model as indicated by the default flag in the model details. _This format
is provided primarily for development and exploratory purposes._ In production
code, it is recommended that the variant be specified.
- **Class with variant** (`name-variant`). E.g. `climate_action-nx`. Will utilize
  the current version of the specified variant as indicated by the `current` field
  in the model details.
- **Full versioned identifier** (`name-variant-version`). E.g. `climate_action-nx-1` is
  useful for pinning your application to a specific historical version.
"""
```

## incorrect-markdown-render

<img width="579" alt="incorrect-markdown-render" src="https://user-images.githubusercontent.com/307713/200467063-af74141c-f289-49f0-afe6-1aa28e9bea73.png">

## correct-markdown-render

(achieved via unconventional docstring out-denting)

<img width="571" alt="correct-markdown-render" src="https://user-images.githubusercontent.com/307713/200467064-349dfbda-0a21-4d99-8929-ab3a9f51323f.png">




Discussion:

Resolving patch:
diff --git a/starlite/openapi/path_item.py b/starlite/openapi/path_item.py
--- a/starlite/openapi/path_item.py
+++ b/starlite/openapi/path_item.py
@@ -1,3 +1,4 @@
+from inspect import cleandoc
 from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, cast
 
 from pydantic_openapi_schema.v3_1_0.operation import Operation
@@ -31,7 +32,7 @@ def get_description_for_handler(route_handler: "HTTPRouteHandler", use_handler_d
     """
     handler_description = route_handler.description
     if handler_description is None and use_handler_docstrings:
-        return route_handler.fn.__doc__
+        return cleandoc(route_handler.fn.__doc__) if route_handler.fn.__doc__ else None
     return handler_description
 
 


Test patch:
diff --git a/tests/openapi/test_path_item.py b/tests/openapi/test_path_item.py
--- a/tests/openapi/test_path_item.py
+++ b/tests/openapi/test_path_item.py
@@ -41,3 +41,10 @@ def test_create_path_item_use_handler_docstring_true(route: HTTPRoute) -> None:
     assert schema.get.description == "Description in docstring."
     assert schema.patch
     assert schema.patch.description == "Description in decorator"
+    assert schema.put
+    assert schema.put.description
+    # make sure multiline docstring is fully included
+    assert "Line 3." in schema.put.description
+    # make sure internal docstring indentation used to line up with the code
+    # is removed from description
+    assert "    " not in schema.put.description
diff --git a/tests/openapi/utils.py b/tests/openapi/utils.py
--- a/tests/openapi/utils.py
+++ b/tests/openapi/utils.py
@@ -109,6 +109,10 @@ def partial_update_person(self, person_id: str, data: Partial[Person]) -> Person
 
     @put(path="/{person_id:str}")
     def update_person(self, person_id: str, data: Person) -> Person:
+        """Multiline docstring example.
+
+        Line 3.
+        """
         return data
 
     @delete(path="/{person_id:str}")