Dataclass default_factory field treated as required in union disambiguation
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 72/100
Direzione di ricerca
Inizia eseguendo lo script di riproduzione nell'issue per confermare che l'unione di dataclass restituisce D2 per un payload privo di tags. Il controllo dei valori predefiniti si trova in create_default_dis_func in src/cattrs/disambiguators.py, intorno alle righe 154-157, e fields_dict e adapted_fields in src/cattrs/_compat.py mostrano perché default_factory è invisibile lì. È completato quando il caso delle dataclass corrisponde al comportamento di attrs, con un test per default_factory aggiunto in tests/test_disambiguators.py.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
A dataclass field with default_factory is treated as a required field when cattrs builds the disambiguator for a union of dataclasses, so a payload that omits it is silently structured as the other class.
Minimal example
from dataclasses import dataclass, field
from typing import Union
from attrs import Factory, define
from cattrs import Converter
@dataclass
class D1:
x: int
tags: list = field(default_factory=list)
@dataclass
class D2:
x: int
c = Converter(omit_if_default=True)
payload = c.unstructure(D1(1))
print("payload:", payload)
for union in (Union[D1, D2], Union[D2, D1]):
print(f"structure(payload, {union}) observed:", repr(c.structure(payload, union)))
print("expected: D1(x=1, tags=[]) or a 'Could not disambiguate' TypeError, as for attrs below")
@define
class A1:
x: int
tags: list = Factory(list)
@define
class A2:
x: int
c2 = Converter(omit_if_default=True)
try:
print("attrs twin:", repr(c2.structure(c2.unstructure(A1(1)), Union[A1, A2])))
except TypeError as e:
print("attrs twin raises:", type(e).__name__, e)
Observed output
payload: {'x': 1}
structure(payload, typing.Union[__main__.D1, __main__.D2]) observed: D2(x=1)
structure(payload, typing.Union[__main__.D2, __main__.D1]) observed: D2(x=1)
expected: D1(x=1, tags=[]) or a 'Could not disambiguate' TypeError, as for attrs below
attrs twin raises: TypeError Could not disambiguate between <class '__main__.A1'>, <class '__main__.A2'>: no unique non-default attributes
D1(1) round-trips to D2(x=1) in both union orders, with no error. The same classes written with attrs and Factory(list) raise when the union hook is built.
Expected behaviour
A field with default_factory should count as having a default, the same as an attrs Factory and a dataclass plain default. The dataclass union should then raise the same "Could not disambiguate" TypeError as the attrs version, instead of picking tags as the key and falling back to D2.
Versions
- Python 3.12.3
- cattrs 26.2.1 (26.1.0 gives the same output)
- attrs 26.1.0
- OS: Linux
Cause
In create_default_dis_func (src/cattrs/disambiguators.py, main at 73fa273), line 154 takes cl_fields = fields_dict(get_origin(cl) or cl) and line 157 treats a field as required when cl_fields[orig_name].default in (NOTHING, MISSING). For a dataclass, fields_dict (src/cattrs/_compat.py lines 131-135) returns the raw dataclasses.Field, whose .default is MISSING when only default_factory is set. adapted_fields (_compat.py lines 155-159) already turns default_factory into Factory, but the default check doesn't use it, so tags becomes the unique required field of D1, and a payload without it goes to D2.
Proposed fix
Check defaults on the adapted_fields view, which already maps default_factory to Factory, or also treat default_factory is not MISSING as a default at line 157. A dataclass default_factory case in tests/test_disambiguators.py would cover it; the existing dataclass tests there only use required fields.
I'm happy to open a PR with this fix and a test.
- Lingua principale
- Python
- Stelle
- 1.1k
- Fork
- 171
- Merge medio
- 14h 46m
- PR unite (30g)
- 5
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di python-attrs/cattrs
-
decimal.Decimal not handled in preconf converters (json, pyyaml)Forse già presa @Binilkks l’ha presa 112 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
python-attrs/cattrs#761 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
python-attrs/cattrs#513 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Structure hook on a PEP 695 alias is ignored inside a passthrough unionForse già presa Una pull request collegata a questa issue è aperta o già unita. Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 62/100
python-attrs/cattrs#797 ·
I maintainer di solito rispondono entro 1 giorno
-
msgspec converter skips hooks and drops private fields in nested recursionForse già presa Una pull request collegata a questa issue è aperta o già unita. Aperta
Difficoltà 3/5 Mezza giornata Idoneità per principianti 64/100
python-attrs/cattrs#795 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 25/100
python-attrs/cattrs#794 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di python-attrs/cattrs
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
cellrishi-code/claude-skills-atlas#165 ·
I maintainer di solito rispondono entro 1 giorno
-
bug confirmed issue
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
open-webui/open-webui#32635 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Filters: ?field:ne=null matches NULL rows instead of non-NULL onesForse già presa @rshdhere l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
Netflix/metaflow-service#504 ·
-
needs-triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
gke-labs/kube-agents#3394 ·
I maintainer di solito rispondono entro 1 giorno
-
A2A audit timestamps end in +00:00Z (invalid ISO 8601)Forse già presa @O1sumitkumar l’ha presa oggi. Apertabug good first issue help wanted python
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno