lodum.field
1# SPDX-FileCopyrightText: 2025-present Michael R. Bernstein <zopemaven@gmail.com> 2# 3# SPDX-License-Identifier: Apache-2.0 4import threading 5from typing import Any, Callable, Dict, List, Optional, Type, Union 6 7 8# Global registry for lodum-enabled classes to support ForwardRef resolution 9_NAME_TO_TYPE_CACHE: Dict[str, Type[Any]] = {} 10_REGISTRY_LOCK = threading.RLock() 11 12 13def register_type(cls: Type[Any]) -> None: 14 """Registers a class in the global name-to-type cache.""" 15 with _REGISTRY_LOCK: 16 _NAME_TO_TYPE_CACHE[cls.__name__] = cls 17 18 19# A sentinel object to detect if a parameter is supplied or not. 20class _MISSING_TYPE: 21 pass 22 23 24_MISSING = _MISSING_TYPE() 25 26 27class Field: 28 """ 29 A class that stores metadata for a field in a lodum-enabled class. 30 31 This is not intended to be instantiated directly. Instead, use the `field()` 32 function, which provides a more convenient API. 33 """ 34 35 def __init__( 36 self, 37 rename: Optional[str] = None, 38 skip_serializing: bool = False, 39 default: Any = _MISSING, 40 default_factory: Optional[Callable[[], Any]] = None, 41 serializer: Optional[Callable[[Any], Any]] = None, 42 deserializer: Optional[Callable[[Any], Any]] = None, 43 validate: Optional[ 44 Union[Callable[[Any], None], List[Callable[[Any], None]]] 45 ] = None, 46 ) -> None: 47 if default is not _MISSING and default_factory is not None: 48 raise ValueError("cannot specify both default and default_factory") 49 50 self.rename = rename 51 self.skip_serializing = skip_serializing 52 self.default = default 53 self.default_factory = default_factory 54 self.serializer = serializer 55 self.deserializer = deserializer 56 self.validate = validate 57 self.name: str = "" # Will be populated by the decorator 58 self.type: Any = None # Will be populated by the decorator 59 60 @property 61 def has_default(self) -> bool: 62 return self.default is not _MISSING or self.default_factory is not None 63 64 def get_default(self) -> Any: 65 if self.default_factory is not None: 66 return self.default_factory() 67 return self.default 68 69 def __repr__(self) -> str: 70 parts = [] 71 if self.name: 72 parts.append(f"name={self.name!r}") 73 if self.type: 74 parts.append(f"type={self.type!r}") 75 if self.rename: 76 parts.append(f"rename={self.rename!r}") 77 if self.skip_serializing: 78 parts.append(f"skip_serializing={self.skip_serializing!r}") 79 if self.default is not _MISSING: 80 parts.append(f"default={self.default!r}") 81 if self.default_factory: 82 parts.append(f"default_factory={self.default_factory!r}") 83 if self.serializer: 84 parts.append(f"serializer={self.serializer!r}") 85 if self.deserializer: 86 parts.append(f"deserializer={self.deserializer!r}") 87 if self.validate: 88 parts.append(f"validate={self.validate!r}") 89 return f"Field({', '.join(parts)})" 90 91 def __eq__(self, other: Any) -> bool: 92 if not isinstance(other, Field): 93 return NotImplemented 94 return ( 95 self.name == other.name 96 and self.type == other.type 97 and self.rename == other.rename 98 and self.skip_serializing == other.skip_serializing 99 and self.default == other.default 100 and self.default_factory == other.default_factory 101 and self.serializer == other.serializer 102 and self.deserializer == other.deserializer 103 and self.validate == other.validate 104 ) 105 106 107def field( 108 *, 109 rename: Optional[str] = None, 110 skip_serializing: bool = False, 111 default: Any = _MISSING, 112 default_factory: Optional[Callable[[], Any]] = None, 113 serializer: Optional[Callable[[Any], Any]] = None, 114 deserializer: Optional[Callable[[Any], Any]] = None, 115 validate: Optional[ 116 Union[Callable[[Any], None], List[Callable[[Any], None]]] 117 ] = None, 118) -> Any: 119 """ 120 Provides metadata to the `@lodum` decorator for a single field. 121 122 Args: 123 rename: The name to use for the field in the output. 124 skip_serializing: If `True`, the field will not be included in the 125 output. 126 default: A default value to use for the field during decoding 127 if it is missing from the input data. 128 default_factory: A zero-argument function that will be called to 129 create a default value for a missing field. 130 serializer: A function to call to encode the field's value. 131 deserializer: A function to call to decode the field's value. 132 validate: A callable or list of callables to validate the field's value during decoding. 133 """ 134 return Field( 135 rename=rename, 136 skip_serializing=skip_serializing, 137 default=default, 138 default_factory=default_factory, 139 serializer=serializer, 140 deserializer=deserializer, 141 validate=validate, 142 )
14def register_type(cls: Type[Any]) -> None: 15 """Registers a class in the global name-to-type cache.""" 16 with _REGISTRY_LOCK: 17 _NAME_TO_TYPE_CACHE[cls.__name__] = cls
Registers a class in the global name-to-type cache.
28class Field: 29 """ 30 A class that stores metadata for a field in a lodum-enabled class. 31 32 This is not intended to be instantiated directly. Instead, use the `field()` 33 function, which provides a more convenient API. 34 """ 35 36 def __init__( 37 self, 38 rename: Optional[str] = None, 39 skip_serializing: bool = False, 40 default: Any = _MISSING, 41 default_factory: Optional[Callable[[], Any]] = None, 42 serializer: Optional[Callable[[Any], Any]] = None, 43 deserializer: Optional[Callable[[Any], Any]] = None, 44 validate: Optional[ 45 Union[Callable[[Any], None], List[Callable[[Any], None]]] 46 ] = None, 47 ) -> None: 48 if default is not _MISSING and default_factory is not None: 49 raise ValueError("cannot specify both default and default_factory") 50 51 self.rename = rename 52 self.skip_serializing = skip_serializing 53 self.default = default 54 self.default_factory = default_factory 55 self.serializer = serializer 56 self.deserializer = deserializer 57 self.validate = validate 58 self.name: str = "" # Will be populated by the decorator 59 self.type: Any = None # Will be populated by the decorator 60 61 @property 62 def has_default(self) -> bool: 63 return self.default is not _MISSING or self.default_factory is not None 64 65 def get_default(self) -> Any: 66 if self.default_factory is not None: 67 return self.default_factory() 68 return self.default 69 70 def __repr__(self) -> str: 71 parts = [] 72 if self.name: 73 parts.append(f"name={self.name!r}") 74 if self.type: 75 parts.append(f"type={self.type!r}") 76 if self.rename: 77 parts.append(f"rename={self.rename!r}") 78 if self.skip_serializing: 79 parts.append(f"skip_serializing={self.skip_serializing!r}") 80 if self.default is not _MISSING: 81 parts.append(f"default={self.default!r}") 82 if self.default_factory: 83 parts.append(f"default_factory={self.default_factory!r}") 84 if self.serializer: 85 parts.append(f"serializer={self.serializer!r}") 86 if self.deserializer: 87 parts.append(f"deserializer={self.deserializer!r}") 88 if self.validate: 89 parts.append(f"validate={self.validate!r}") 90 return f"Field({', '.join(parts)})" 91 92 def __eq__(self, other: Any) -> bool: 93 if not isinstance(other, Field): 94 return NotImplemented 95 return ( 96 self.name == other.name 97 and self.type == other.type 98 and self.rename == other.rename 99 and self.skip_serializing == other.skip_serializing 100 and self.default == other.default 101 and self.default_factory == other.default_factory 102 and self.serializer == other.serializer 103 and self.deserializer == other.deserializer 104 and self.validate == other.validate 105 )
A class that stores metadata for a field in a lodum-enabled class.
This is not intended to be instantiated directly. Instead, use the field()
function, which provides a more convenient API.
36 def __init__( 37 self, 38 rename: Optional[str] = None, 39 skip_serializing: bool = False, 40 default: Any = _MISSING, 41 default_factory: Optional[Callable[[], Any]] = None, 42 serializer: Optional[Callable[[Any], Any]] = None, 43 deserializer: Optional[Callable[[Any], Any]] = None, 44 validate: Optional[ 45 Union[Callable[[Any], None], List[Callable[[Any], None]]] 46 ] = None, 47 ) -> None: 48 if default is not _MISSING and default_factory is not None: 49 raise ValueError("cannot specify both default and default_factory") 50 51 self.rename = rename 52 self.skip_serializing = skip_serializing 53 self.default = default 54 self.default_factory = default_factory 55 self.serializer = serializer 56 self.deserializer = deserializer 57 self.validate = validate 58 self.name: str = "" # Will be populated by the decorator 59 self.type: Any = None # Will be populated by the decorator
108def field( 109 *, 110 rename: Optional[str] = None, 111 skip_serializing: bool = False, 112 default: Any = _MISSING, 113 default_factory: Optional[Callable[[], Any]] = None, 114 serializer: Optional[Callable[[Any], Any]] = None, 115 deserializer: Optional[Callable[[Any], Any]] = None, 116 validate: Optional[ 117 Union[Callable[[Any], None], List[Callable[[Any], None]]] 118 ] = None, 119) -> Any: 120 """ 121 Provides metadata to the `@lodum` decorator for a single field. 122 123 Args: 124 rename: The name to use for the field in the output. 125 skip_serializing: If `True`, the field will not be included in the 126 output. 127 default: A default value to use for the field during decoding 128 if it is missing from the input data. 129 default_factory: A zero-argument function that will be called to 130 create a default value for a missing field. 131 serializer: A function to call to encode the field's value. 132 deserializer: A function to call to decode the field's value. 133 validate: A callable or list of callables to validate the field's value during decoding. 134 """ 135 return Field( 136 rename=rename, 137 skip_serializing=skip_serializing, 138 default=default, 139 default_factory=default_factory, 140 serializer=serializer, 141 deserializer=deserializer, 142 validate=validate, 143 )
Provides metadata to the @lodum decorator for a single field.
Args:
rename: The name to use for the field in the output.
skip_serializing: If True, the field will not be included in the
output.
default: A default value to use for the field during decoding
if it is missing from the input data.
default_factory: A zero-argument function that will be called to
create a default value for a missing field.
serializer: A function to call to encode the field's value.
deserializer: A function to call to decode the field's value.
validate: A callable or list of callables to validate the field's value during decoding.