def __new__(mcs, name: str, bases: tuple[type, ...], namespace: dict[str, Any]) -> type:
fields: dict[str, tuple[type, FieldInfo]] = {}
for base in bases:
if hasattr(base, "_fields"):
base_fields = cast("dict[str, tuple[type, FieldInfo]]", base._fields)
fields.update(base_fields)
# Eagerly validate a class-level strip_strings setting: a non-bool
# value is rejected at class-definition time so it can never silently
# produce char-set stripping (e.g. "true" -> strips t/r/u/e chars) or
# be treated as truthy (e.g. 1). Only a value present in THIS class's
# namespace is checked; inherited values were validated at their own
# definition time.
if "strip_strings" in namespace and not isinstance(namespace["strip_strings"], bool):
raise TypeError(
f"strip_strings must be a bool, got "
f"{type(namespace['strip_strings']).__name__}: "
f"{namespace['strip_strings']!r}"
)
hints = _get_annotations_from_namespace(namespace)
for field_name, field_type in hints.items():
if field_name.startswith("_"):
continue
# Class-level settings, not fields
if field_name in ("env_prefix", "strip_strings"):
continue
field_value = namespace.get(field_name, _MISSING)
if isinstance(field_value, FieldInfo):
field_info = field_value
if (
field_info.default is _MISSING
and field_info.default_factory is None
and _is_optional_type(field_type)
):
field_info.default = None
field_info.required = False
elif isinstance(field_value, _RequiredSentinel):
field_info = FieldInfo()
elif field_value is _MISSING:
if _is_optional_type(field_type):
field_info = FieldInfo(default=None)
else:
field_info = FieldInfo()
elif field_value is ...:
field_info = FieldInfo()
else:
field_info = FieldInfo(default=field_value)
fields[field_name] = (field_type, field_info)
# Set to None instead of removing so __annotate__ can still resolve
# the name on Python 3.14+ (PEP 649). FieldInfo objects must not
# remain as class attributes since they'd be shared across instances.
if field_name in namespace:
namespace[field_name] = None
namespace["_fields"] = fields
cls = super().__new__(mcs, name, bases, namespace)
# Resolve string annotations (PEP 563 future import or Python 3.14+ lazy annotations)
if any(isinstance(ft, str) for ft, _ in cls._fields.values()):
resolved = _resolve_type_hints(cls)
if resolved:
new_fields: dict[str, tuple[type, FieldInfo]] = {}
for fname, (ftype, finfo) in cls._fields.items():
rtype = resolved.get(fname, ftype)
if (
finfo.default is _MISSING
and finfo.default_factory is None
and _is_optional_type(rtype)
):
finfo.default = None
finfo.required = False
new_fields[fname] = (rtype, finfo)
cls._fields = new_fields
return cls