{"id":470,"library":"cattrs","title":"cattrs: Composable Attrs/Dataclass Structuring","description":"cattrs is a Python library (version 26.1.0) that provides composable tools for converting between unstructured Python data (like dictionaries) and structured data (like `attrs` classes and `dataclasses`). It excels at recursively structuring and unstructuring data while supporting type hints and offering extensive customization via hooks. Releases are frequent, often including breaking changes across minor versions.","status":"active","version":"26.1.0","language":"python","source_language":"en","source_url":"https://github.com/python-attrs/cattrs","tags":["data serialization","attrs","dataclasses","type hinting","validation"],"install":[{"cmd":"pip install cattrs","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"symbol":"structure","correct":"from cattrs import structure"},{"symbol":"unstructure","correct":"from cattrs import unstructure"},{"symbol":"Converter","correct":"from cattrs import Converter"}],"quickstart":{"code":"from attrs import define\nfrom cattrs import structure, unstructure\n\n@define\nclass User:\n    id: int\n    name: str\n    email: str\n\n# Unstructured data (e.g., from JSON)\nunstructured_data = {\"id\": 1, \"name\": \"Alice\", \"email\": \"alice@example.com\"}\n\n# Structure into a User instance\nuser_instance = structure(unstructured_data, User)\nprint(f\"Structured: {user_instance}\")\n\n# Unstructure back to a dictionary\nunstructured_output = unstructure(user_instance)\nprint(f\"Unstructured: {unstructured_output}\")","lang":"python","description":"Demonstrates basic structuring of a dictionary into an `attrs` class instance and unstructuring it back, using the global converter."},"warnings":[{"fix":"If the previous behavior (structuring into `set`) is required, register a custom structure hook for `collections.abc.Set` on your converter instance (e.g., `converter.register_structure_hook(Set, lambda d, t: set(d))`).","message":"As of v25.3.0, abstract sets (`collections.abc.Set`) are now structured into `frozenset` by default, instead of `set`. This might affect code expecting mutable sets.","severity":"breaking","affected_versions":">=25.3.0"},{"fix":"If the previous behavior (structuring into `list`) is required, register a custom structure hook for `collections.abc.Sequence` on your converter instance (e.g., `converter.register_structure_hook(Sequence, lambda d, t: list(d))`).","message":"As of v25.2.0, sequences (`collections.abc.Sequence`) are now structured into `tuple` by default, instead of `list`. This change provides better immutability and consistency.","severity":"breaking","affected_versions":">=25.2.0"},{"fix":"Ensure all types intended for structuring have appropriate hooks registered *before* attempting to use the converter. Consult the `cattrs` migration guide for details on customizing `unstructure_hook_fallback_factory` if necessary.","message":"As of v25.1.0, `StructureHandlerNotFoundError` is raised more eagerly (on hook creation rather than on first use). This helps surface missing hooks sooner.","severity":"breaking","affected_versions":">=25.1.0"},{"fix":"If your application relied on the previous inconsistent behavior for `typing.Any`, you may need to explicitly register custom `unstructure_hook`s for specific types or `typing.Any` to achieve the desired effect.","message":"As of v24.1.0, unstructuring hooks for `typing.Any` now consistently use the runtime type of the value. Previously, this behavior was underspecified and inconsistent.","severity":"breaking","affected_versions":">=24.1.0"},{"fix":"For complex applications or when developing libraries, it is strongly recommended to create and manage your own `cattrs.Converter()` instance(s) and register hooks on those private instances to avoid polluting the global state.","message":"The top-level `cattrs.structure()` and `cattrs.unstructure()` functions operate on a global converter instance. Registering hooks or changing settings on this global converter can lead to unexpected side effects across different parts of an application or in library code.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"search_vec":"'26.1.0':11 'across':57 'attr':28,62 'attrs/dataclass':3 'break':55 'cattr':1,5 'chang':56 'class':29 'compos':2,14 'convert':17 'custom':47 'data':21,26,39,60 'dataclass':31,63 'dictionari':23 'excel':33 'extens':46 'frequent':52 'hint':43,65 'hook':49 'includ':54 'librari':9 'like':22,27 'minor':58 'offer':45 'often':53 'provid':13 'python':8,20 'recurs':35 'releas':50 'serial':61 'structur':4,25,36 'support':41 'tool':15 'type':42,64 'unstructur':19,38 'valid':66 'version':10,59 'via':48","created_at":"2026-03-28T15:14:59.021193+00:00","updated_at":"2026-04-16T01:33:38.213840+00:00","problems":[{"fix":"Install `typing_extensions` using pip: `pip install typing_extensions`.","cause":"`cattrs` sometimes conditionally imports `typing_extensions` for compatibility with older Python versions, but dependency resolution or specific `cattrs` versions can lead to this module being missing on systems where it's still needed.","error":"ModuleNotFoundError: No module named 'typing_extensions'"},{"fix":"Register a custom structuring hook for the specific type with the `cattrs` converter. For example, for a `datetime` object: `converter.register_structure_hook(datetime, lambda d, t: datetime.fromisoformat(d))`.","cause":"`cattrs` does not automatically know how to convert unstructured data (like a dictionary) into instances of arbitrary custom classes or complex types (e.g., `datetime` or a non-`attrs`/`dataclass` class) without a registered structuring hook.","error":"cattrs.errors.StructureHandlerNotFoundError: Cannot find a structuring handler for <class 'your.CustomClass'>"},{"fix":"Ensure that all classes are fully defined before attempting to register hooks for them using `ForwardRef`s. If you must use `ForwardRef`s, resolve them to the actual class type using `typing.get_type_hints` or by passing the actual class directly after it's defined.","cause":"The `register_structure_hook` or `register_unstructure_hook` methods, which use `functools.singledispatch` internally, require an actual class type as their first argument, not a `ForwardRef` object.","error":"TypeError: Invalid first argument to `register()`. ForwardRef('MyClass') is not a class."},{"fix":"Provide an input value that exactly matches one of the `Enum` members' values or names. If custom mapping or case-insensitivity is needed, register a custom structuring hook for the `Enum` type.","cause":"When structuring data into an `Enum` type, the input value does not match any of the defined members (by value or name) of the target `Enum` class.","error":"ValueError: 'some_string' is not a valid MyEnum"},{"fix":"Either remove the extra keys from your input data before structuring, or disable the `forbid_extra_keys` setting if these extra keys should be ignored. If the keys are legitimate, add them as attributes to your target class.","cause":"The `forbid_extra_keys=True` option is enabled on the `cattrs` converter or for the specific class being structured, and the input data contains keys that do not correspond to any attributes defined in the target class.","error":"cattrs.errors.ForbiddenExtraKeysError: While structuring <class 'your.MyClass'>, extra keys were found: {'unexpected_key'}"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"quickstart_score":80,"quickstart_tag":"verified","pypi_latest":"26.1.0","cli_name":"","cli_version":null,"type":"library","homepage":"https://catt.rs","github":"https://github.com/python-attrs/cattrs","docs":"https://catt.rs/en/stable/","changelog":"https://catt.rs/en/latest/history.html","pypi":"https://pypi.org/project/cattrs/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["serialization","data"],"base_url":null,"auth_type":null,"provenance":{"verified_status":"passing","verified_at":"2026-06-28","last_verified":"2026-08-27","next_check":"2026-07-28","install_tag":"verified"}}