Repository: pydantic/pydantic

Issue:
Maxlen property always set to None, when deque item type is provided.
### Initial Checks

- [X] I have searched GitHub for a duplicate issue and I'm sure this is something new
- [X] I have searched Google & StackOverflow for a solution and couldn't find anything
- [X] I have read and followed [the docs](https://docs.pydantic.dev) and still think this is a bug
- [X] I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like [FastAPI](https://fastapi.tiangolo.com) or [mypy](https://mypy.readthedocs.io/en/stable))


### Description

The `maxlen` property of the `deque` field seems to be set to `None` when the queue item type is provided.

In the example below I first create an untyped deque and upon instancing everything goes well - the `maxlen` is set to `15`.
However when the model definitions is more specific: `deque[int]` or `Deque[int]` then the `maxlen` value cannot be set.

### Example Code

```Python
>>> from pydantic import BaseModel
>>> from collections import deque
>>> class D(BaseModel):
...     q: deque = deque(maxlen=10)
... 
>>> d = D(q=deque(maxlen=15))
>>> d
D(q=deque([], maxlen=15))
>>> 
>>> 
>>> class DI(BaseModel):
...     q: deque[int] = deque(maxlen=10)
... 
>>> d = DI(q=deque(maxlen=15))
>>> d
DI(q=deque([]))
>>> 
>>> from typing import Deque
>>> 
>>> class DT(BaseModel):
...     q: Deque[int] = deque(maxlen=10)
... 
>>> d = DT(q=deque(maxlen=15))
>>> d
DT(q=deque([]))
```


### Python, Pydantic & OS Version

```Text
pydantic version: 1.10.5
pydantic compiled: True
install path: /opt/venv/lib/python3.11/site-packages/pydantic
python version: 3.11.4 (main, Jun 13 2023, 15:08:32) [GCC 10.2.1 20210110]
platform: Linux-5.15.90.1-microsoft-standard-WSL2-x86_64-with-glibc2.31
optional deps. installed: ['typing-extensions']
```


### Affected Components

- [ ] [Compatibility between releases](https://docs.pydantic.dev/changelog/)
- [ ] [Data validation/parsing](https://docs.pydantic.dev/usage/models/#basic-model-usage)
- [ ] [Data serialization](https://docs.pydantic.dev/usage/exporting_models/) - `.dict()` and `.json()`
- [ ] [JSON Schema](https://docs.pydantic.dev/usage/schema/)
- [ ] [Dataclasses](https://docs.pydantic.dev/usage/dataclasses/)
- [ ] [Model Config](https://docs.pydantic.dev/usage/model_config/)
- [X] [Field Types](https://docs.pydantic.dev/usage/types/) - adding or changing a particular data type
- [ ] [Function validation decorator](https://docs.pydantic.dev/usage/validation_decorator/)
- [ ] [Generic Models](https://docs.pydantic.dev/usage/models/#generic-models)
- [ ] [Other Model behaviour](https://docs.pydantic.dev/usage/models/) - `construct()`, pickling, private attributes, ORM mode
- [ ] [Plugins](https://docs.pydantic.dev/) and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.

Selected Assignee: @davidhewitt


Discussion:
Some more cases:

```
>>> from collections import deque
>>> from pydantic import BaseModel
>>> class D(BaseModel):
...     q: deque[int] = deque(maxlen=10)
... 
>>> d = D()
>>> d
D(q=deque([], maxlen=10))

>>> d.q = deque(maxlen=25)
>>> d
D(q=deque([], maxlen=25))
```

So it seems that it is validation issue on model creation only.

I do not know the codebase here but potentially:

https://github.com/pydantic/pydantic/blob/f35c780cc3cf073c400ee038b8b6dd6d7b5703d9/pydantic/v1/fields.py#L954C25-L954C25
Thanks @maciekglowka for this issue 🙏 

As you may know, `Pydantic V2` is out and we are not actively working on `V1`.

I've checked your first example code on V2, all of them returning `D(q=deque([], maxlen=15))`

Same for you second example. In `V2` you can have validation on assignment to a `deque` field like:

```py
from collections import deque
from typing import Deque

from typing_extensions import Annotated
from pydantic import BaseModel, ConfigDict, Field

class D(BaseModel):
    q: Annotated[Deque[int], Field(deque(maxlen=10), max_length=10)]

    model_config = ConfigDict(validate_assignment=True)

d = D()
d.q = deque([1] * 25)
```

Note: We still accept bug fixes on `V1` but it should be an easy fix.
Thanks for checking.
Yeah I've just forked the repo. If I'll be able to fix this I'm gonna make a PR.

Resolving patch:
diff --git a/pydantic/fields.py b/pydantic/fields.py
--- a/pydantic/fields.py
+++ b/pydantic/fields.py
@@ -943,7 +943,7 @@ def _validate_sequence_like(  # noqa: C901 (ignore complexity)
         elif self.shape == SHAPE_TUPLE_ELLIPSIS:
             converted = tuple(result)
         elif self.shape == SHAPE_DEQUE:
-            converted = deque(result)
+            converted = deque(result, maxlen=getattr(v, 'maxlen', None))
         elif self.shape == SHAPE_SEQUENCE:
             if isinstance(v, tuple):
                 converted = tuple(result)
@@ -952,7 +952,7 @@ def _validate_sequence_like(  # noqa: C901 (ignore complexity)
             elif isinstance(v, Generator):
                 converted = iter(result)
             elif isinstance(v, deque):
-                converted = deque(result)
+                converted = deque(result, maxlen=getattr(v, 'maxlen', None))
         return converted, None
 
     def _validate_iterable(


Test patch:
diff --git a/tests/test_types.py b/tests/test_types.py
--- a/tests/test_types.py
+++ b/tests/test_types.py
@@ -3123,6 +3123,25 @@ class Model(BaseModel):
     assert Model(v=value).v == result
 
 
+def test_deque_maxlen():
+    class DequeTypedModel(BaseModel):
+        field: Deque[int] = deque(maxlen=10)
+
+    assert DequeTypedModel(field=deque(maxlen=25)).field.maxlen == 25
+    assert DequeTypedModel().field.maxlen == 10
+
+    class DequeUnTypedModel(BaseModel):
+        field: deque = deque(maxlen=10)
+
+    assert DequeUnTypedModel(field=deque(maxlen=25)).field.maxlen == 25
+    assert DequeTypedModel().field.maxlen == 10
+
+    class DeuqueNoDefaultModel(BaseModel):
+        field: deque
+
+    assert DeuqueNoDefaultModel(field=deque(maxlen=25)).field.maxlen == 25
+
+
 @pytest.mark.parametrize(
     'cls,value,errors',
     (