python-attrs / python-attrs/cattrs

Structure when input is already partially structured

Open
#78 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
1.1k
Forks
159
Avg merge
12h 21m
Merged PRs (30d)
6

Description

  • cattrs version: 0.9.0
  • Python version: 3.7.5
  • Operating System: Mac OSX
Description

I am attempting to structure a blob of data into a recursive structure, where part of the blob has already been structured. When it reaches a key that already has a structured value, it errors out. After reading through the documentation it's unclear how to get around this issue.

What I would expect to happen is if a given key already has (valid) structured data, it includes it as is, rather than attempting to (and failing to) structure it.

I'm not sure if I am missing an obvious workaround (converter or hook?), or if this would require a PR to run a check of some sort before attempting to structure a sub-element.

What I Did

This is a minimal example:

from attr import dataclass
from cattr import structure, unstructure

@dataclass(auto_attribs=True)
class B:
    name: str


@dataclass(auto_attribs=True)
class A:
    name: str
    subber: B


dx = {
    "name": "alphas",
    "subber": {
        "name": "subclass"
    }
}

a = structure(dx, A)
print(a)
b = structure(dx.get("subber"), B)
print(b)
dy = {
    "name": "tau",
    "subber": unstructure(b)
}
a2 = structure(dy, A)
print(a2)
dz = {
    "name": "omega",
    "subber": b
}
a3 = structure(dz, A)

The above produces the following output:

A(name='alphas', subber=B(name='subclass'))
B(name='subclass')
A(name='tau', subber=B(name='subclass'))
Traceback (most recent call last):
  File "/Users/nford/Library/Preferences/IntelliJIdea2019.2/scratches/dc.py", line 46, in <module>
    a3 = structure(dz, A)
  File "/Users/nford/echelon/rolevp/echelon/.venv/lib/python3.7/site-packages/cattr/converters.py", line 178, in structure
    return self._structure_func.dispatch(cl)(obj, cl)
  File "/Users/nford/echelon/rolevp/echelon/.venv/lib/python3.7/site-packages/cattr/converters.py", line 298, in structure_attrs_fromdict
    conv_obj[name] = dispatch(type_)(val, type_)
  File "/Users/nford/echelon/rolevp/echelon/.venv/lib/python3.7/site-packages/cattr/converters.py", line 285, in structure_attrs_fromdict
    conv_obj = obj.copy()  # Dict of converted parameters.
AttributeError: 'B' object has no attribute 'copy'

But what I am hoping to achieve is:

A(name='alpha', subber=B(name='subclass'))
B(name='subclass')
A(name='tau', subber=B(name='subclass'))
A(name='omega', subber=B(name='subclass'))

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the structure entry point and structure_attrs_fromdict in cattr/converters.py, using the minimal example to reproduce the failure when subber is already a B instance. Trace how nested values are dispatched and verify that the completed behavior preserves valid structured values while retaining existing dictionary handling.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.