Repository: litestar-org/litestar

Issue:
Bug: Path parameter consumed only by dependency treated as unconsumed (ref: #3295)
### Description

The unconsumed path parameter logic of #3295 doesn't consider path parameters consumed by dependencies.

If the type in path and the type in the dependency match exactly, this doesn't cause an issue. 
If the dependency uses an Annotated type or type coercion (like int to datetime), this will raise an error while generating the OpenAPI schema.

In the case of the MCVE, the exact error follows:
```
litestar.exceptions.http_exceptions.ImproperlyConfiguredException: 500: OpenAPI schema generation for handler `app.my_route` detected multiple parameters named 'path_param' with different types.
```



### URL to code causing the issue

_No response_

### MCVE

```python
from typing import Annotated

from litestar import Litestar, get
from litestar.params import Parameter
from litestar.di import Provide


def my_depfn(
    path_param: Annotated[str, Parameter(description="An annotated path parameter")],
) -> str:
    return path_param


@get(path="/{path_param:str}", dependencies={"my_dep": Provide(my_depfn)})
def my_route(my_dep: str) -> str:
    return my_dep


app = Litestar(
    route_handlers=[my_route],
)
```


### Steps to reproduce

```bash
1. Write MCVE to app.py
2. Run `litestar schema openapi`
3. See error
```


### Screenshots

_No response_

### Logs

```bash
Using Litestar app from app:app
Traceback (most recent call last):
  File "/dupe_path_param/.venv/bin/litestar", line 8, in <module>
    sys.exit(run_cli())
             ^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/__main__.py", line 6, in run_cli
    litestar_group()
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/click/core.py", line 1157, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/rich_click/rich_command.py", line 126, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/click/core.py", line 1434, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/click/core.py", line 783, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/click/decorators.py", line 33, in new_func
    return f(get_current_context(), *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/cli/_utils.py", line 248, in wrapped
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/click/decorators.py", line 33, in new_func
    return f(get_current_context(), *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/cli/_utils.py", line 248, in wrapped
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/cli/commands/schema.py", line 54, in generate_openapi_schema
    _generate_openapi_schema(app, output)
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/cli/commands/schema.py", line 34, in _generate_openapi_schema
    encode_json(app.openapi_schema.to_schema(), serializer=serializer),
                ^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/app.py", line 635, in openapi_schema
    return self.plugins.get(OpenAPIPlugin).provide_openapi()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/_openapi/plugin.py", line 94, in provide_openapi
    self._openapi = self._build_openapi()
                    ^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/_openapi/plugin.py", line 83, in _build_openapi
    path_item = create_path_item_for_route(context, route)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/_openapi/path_item.py", line 139, in create_path_item_for_route
    return path_item_factory.create_path_item()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/_openapi/path_item.py", line 44, in create_path_item
    operation = self.create_operation_for_handler_method(route_handler, HttpMethod(http_method))
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/_openapi/path_item.py", line 63, in create_operation_for_handler_method
    parameters = create_parameters_for_handler(self.context, route_handler, self.route.path_parameters)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/_openapi/parameters.py", line 244, in create_parameters_for_handler
    return factory.create_parameters_for_handler()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/_openapi/parameters.py", line 229, in create_parameters_for_handler
    self.create_parameters_for_field_definitions(handler_fields)
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/_openapi/parameters.py", line 207, in create_parameters_for_field_definitions
    self.parameters.add(self.create_parameter(field_definition=field_definition, parameter_name=field_name))
  File "/dupe_path_param/.venv/lib64/python3.11/site-packages/litestar/_openapi/parameters.py", line 67, in add
    raise ImproperlyConfiguredException(
litestar.exceptions.http_exceptions.ImproperlyConfiguredException: 500: OpenAPI schema generation for handler `app.my_route` detected multiple parameters named 'path_param' with different types.
```


### Litestar Version

2.8.0 and 2.8.1

### Platform

- [X] Linux
- [ ] Mac
- [ ] Windows
- [ ] Other (Please specify in the description above)

<!-- POLAR PLEDGE BADGE START -->
---
> [!NOTE]  
> While we are open for sponsoring on [GitHub Sponsors](https://github.com/sponsors/litestar-org/) and 
> [OpenCollective](https://opencollective.com/litestar), we also utilize [Polar.sh](https://polar.sh/) to engage in pledge-based sponsorship.
>
> Check out all issues funded or available for funding [on our Polar.sh dashboard](https://polar.sh/litestar-org)
> * If you would like to see an issue prioritized, make a pledge towards it!
> * We receive the pledge once the issue is completed & verified
> * This, along with engagement in the community, helps us know which features are a priority to our users.

<a href="https://polar.sh/litestar-org/litestar/issues/3369">
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://polar.sh/api/github/litestar-org/litestar/issues/3369/pledge.svg?darkmode=1">
  <img alt="Fund with Polar" src="https://polar.sh/api/github/litestar-org/litestar/issues/3369/pledge.svg">
</picture>
</a>
<!-- POLAR PLEDGE BADGE END -->



Discussion:

Resolving patch:
diff --git a/litestar/_openapi/parameters.py b/litestar/_openapi/parameters.py
--- a/litestar/_openapi/parameters.py
+++ b/litestar/_openapi/parameters.py
@@ -218,11 +218,15 @@ def create_parameters_for_handler(self) -> list[Parameter]:
         # not all path parameters have to be consumed by the handler. Because even not
         # consumed path parameters must still be specified, we create stub parameters
         # for the unconsumed ones so a correct OpenAPI schema can be generated
+        dependency_fields = {
+            name for dep in self.dependency_providers.values() for name in dep.parsed_fn_signature.parameters
+        }
         params_not_consumed_by_handler = set(self.path_parameters) - handler_fields.keys()
+        unconsumed_path_parameters = params_not_consumed_by_handler - dependency_fields
         handler_fields.update(
             {
                 param_name: FieldDefinition.from_kwarg(self.path_parameters[param_name].type, name=param_name)
-                for param_name in params_not_consumed_by_handler
+                for param_name in unconsumed_path_parameters
             }
         )
 


Test patch:
diff --git a/tests/unit/test_openapi/test_schema.py b/tests/unit/test_openapi/test_schema.py
--- a/tests/unit/test_openapi/test_schema.py
+++ b/tests/unit/test_openapi/test_schema.py
@@ -592,16 +592,24 @@ async def post_handler(param: str) -> None:
 
 def test_unconsumed_path_parameters_are_documented() -> None:
     # https://github.com/litestar-org/litestar/issues/3290
-    @get("/{param:str}")
-    async def handler() -> None:
+    # https://github.com/litestar-org/litestar/issues/3369
+
+    async def dd(param3: Annotated[str, Parameter(description="123")]) -> str:
+        return param3
+
+    async def d(dep_dep: str, param2: Annotated[str, Parameter(description="abc")]) -> str:
+        return f"{dep_dep}_{param2}"
+
+    @get("/{param1:str}/{param2:str}/{param3:str}", dependencies={"dep": d, "dep_dep": dd})
+    async def handler(dep: str) -> None:
         pass
 
     app = Litestar([handler])
-    params = app.openapi_schema.paths["/{param}"].get.parameters  # type: ignore[index, union-attr]
+    params = app.openapi_schema.paths["/{param1}/{param2}/{param3}"].get.parameters  # type: ignore[index, union-attr]
     assert params
-    assert len(params) == 1
-    param = params[0]
-    assert isinstance(param, OpenAPIParameter)
-    assert param.name == "param"
-    assert param.required is True
-    assert param.param_in is ParamType.PATH
+    assert len(params) == 3
+    for i, param in enumerate(sorted(params, key=lambda p: p.name), 1):  # pyright: ignore
+        assert isinstance(param, OpenAPIParameter)
+        assert param.name == f"param{i}"
+        assert param.required is True
+        assert param.param_in is ParamType.PATH