Extract FieldInfo list from a dataclass. This handles: - Extracting field metadata from pyfory.field() annotations - Filtering out ignored fields - Computing effective nullable based on Optional[T] - Computing runtime ref tracking based on global config - Inheritance: p
(
fory,
clz: type,
type_hints: dict,
)
| 185 | |
| 186 | |
| 187 | def _extract_field_infos( |
| 188 | fory, |
| 189 | clz: type, |
| 190 | type_hints: dict, |
| 191 | ) -> tuple[list[FieldInfo], dict[str, ForyFieldMeta]]: |
| 192 | """ |
| 193 | Extract FieldInfo list from a dataclass. |
| 194 | |
| 195 | This handles: |
| 196 | - Extracting field metadata from pyfory.field() annotations |
| 197 | - Filtering out ignored fields |
| 198 | - Computing effective nullable based on Optional[T] |
| 199 | - Computing runtime ref tracking based on global config |
| 200 | - Inheritance: parent fields first, subclass fields override parent fields |
| 201 | |
| 202 | Returns: |
| 203 | Tuple of (field_infos, field_metas) where field_metas maps field name to ForyFieldMeta |
| 204 | """ |
| 205 | if not dataclasses.is_dataclass(clz): |
| 206 | # Non-dataclass registration uses the runtime type inspection path. |
| 207 | return [], {} |
| 208 | |
| 209 | # Collect fields from class hierarchy (parent first, child last) |
| 210 | # Child fields override parent fields with same name |
| 211 | all_fields: Dict[str, dataclasses.Field] = {} |
| 212 | for klass in clz.__mro__[::-1]: # Reverse MRO: base classes first |
| 213 | if dataclasses.is_dataclass(klass) and klass is not clz: |
| 214 | for f in dataclasses.fields(klass): |
| 215 | all_fields[f.name] = f |
| 216 | # Add current class fields (override parent) |
| 217 | for f in dataclasses.fields(clz): |
| 218 | all_fields[f.name] = f |
| 219 | |
| 220 | # Extract field metas and filter ignored fields |
| 221 | field_metas: Dict[str, ForyFieldMeta] = {} |
| 222 | active_fields: List[tuple] = [] |
| 223 | |
| 224 | # Check if fory has field_nullable global setting |
| 225 | global_field_nullable = getattr(fory, "field_nullable", False) |
| 226 | |
| 227 | for field_name, dc_field in all_fields.items(): |
| 228 | meta = extract_field_meta(dc_field) |
| 229 | if meta is None: |
| 230 | # Field without pyfory.field() - use defaults |
| 231 | # Auto-detect Optional[T] for nullable, also respect global field_nullable |
| 232 | field_type = type_hints.get(field_name, typing.Any) |
| 233 | meta = _default_field_meta(field_type, global_field_nullable, getattr(fory, "xlang", False)) |
| 234 | |
| 235 | field_metas[field_name] = meta |
| 236 | |
| 237 | if not meta.ignore: |
| 238 | active_fields.append((field_name, dc_field)) |
| 239 | |
| 240 | # Validate field metas |
| 241 | validate_field_metas(clz, field_metas, type_hints) |
| 242 | |
| 243 | # Build FieldInfo list |
| 244 | field_infos: List[FieldInfo] = [] |
no test coverage detected