lidatong / dataclasses-json

Easily serialize Data Classes to and from JSON
MIT License
1.38k stars 154 forks source link

Attribute error: 'list' object has no attribute 'items' #127

Closed karambaq closed 5 years ago

karambaq commented 5 years ago

Example

main.py

import json
from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, config

from typing import List, Dict, Any

@dataclass_json
@dataclass
class Coef:
    val: float = field(default=float, metadata=config(field_name="C"))
    cf_type: float = field(default=int, metadata=config(field_name="G"))
    total: float = field(default=float, metadata=config(field_name="T"))

@dataclass_json
@dataclass
class QuarterCoefs:
    coefs: List[Coef] = field(default_factory=list,
                              metadata=config(field_name="E"))
    num: str = field(default="", metadata=config(field_name="PN"))

@dataclass_json
@dataclass
class Game:
    quarter_coefs: QuarterCoefs = field(default_factory=list,
                                        metadata=config(field_name="SG"))

with open('test.json', 'r') as f:
    match = json.load(f)

game_json = json.dumps(match)
m = Game.from_json(game_json)
print(m)

test.json

{
    "SG": [{
        "E": [{
                "C": 1.71,
                "G": 1,
                "T": 1
            },
            {
                "C": 9,
                "G": 1,
                "T": 2
            },
            {
                "C": 2.4,
                "G": 1,
                "T": 3
            }
        ],
        "PN": "2 Quarter"
    }]
}

Error

raceback (most recent call last):
  File "/Users/peq/code/vk/bball_bot/test.py", line 35, in <module>
    m = Game.from_json(game_json)
  File "/usr/local/lib/python3.7/site-packages/dataclasses_json/api.py", line 110, in from_json
    return cls.from_dict(kvs, infer_missing=infer_missing)
  File "/usr/local/lib/python3.7/site-packages/dataclasses_json/api.py", line 117, in from_dict
    return _decode_dataclass(cls, kvs, infer_missing)
  File "/usr/local/lib/python3.7/site-packages/dataclasses_json/core.py", line 166, in _decode_dataclass
    infer_missing)
  File "/usr/local/lib/python3.7/site-packages/dataclasses_json/core.py", line 109, in _decode_dataclass
    kvs = {decode_names.get(k, k): v for k, v in kvs.items()}
AttributeError: 'list' object has no attribute 'items'

What I'm doing wrong?

nathan5280 commented 5 years ago

When I get stuck on something like this I create the object and then serialize it to make sure I have all the [{}] in the right places. In this case it looks like you are missing one set of {}.

game = Game(QuarterCoefs([Coef(1.71, 1, 1), Coef(9, 1, 2), Coef(2.4, 1, 3)], "2 Quarters")) print(Game.to_json(game, indent=2))

{ "SG": { "E": [ { "C": 1.71, "G": 1, "T": 1 }, { "C": 9, "G": 1, "T": 2 }, { "C": 2.4, "G": 1, "T": 3 } ], "PN": "2 Quarters" } }

On Fri, Aug 23, 2019 at 9:27 AM Maxim Lyubiev notifications@github.com wrote:

Example main.py

import json from dataclasses import dataclass, field from dataclasses_json import dataclass_json, config

from typing import List, Dict, Any

@dataclass_json @dataclass class Coef: val: float = field(default=float, metadata=config(field_name="C")) cf_type: float = field(default=int, metadata=config(field_name="G")) total: float = field(default=float, metadata=config(field_name="T"))

@dataclass_json @dataclass class QuarterCoefs: coefs: List[Coef] = field(default_factory=list, metadata=config(field_name="E")) num: str = field(default="", metadata=config(field_name="PN"))

@dataclass_json @dataclass class Game: quarter_coefs: QuarterCoefs = field(default_factory=list, metadata=config(field_name="SG"))

with open('test.json', 'r') as f: match = json.load(f)

game_json = json.dumps(match) m = Game.from_json(game_json) print(m)

test.json

{ "SG": [{ "E": [{ "C": 1.71, "G": 1, "T": 1 }, { "C": 9, "G": 1, "T": 2 }, { "C": 2.4, "G": 1, "T": 3 } ], "PN": "2 Quarter" }] }

Error

raceback (most recent call last): File "/Users/peq/code/vk/bball_bot/test.py", line 35, in m = Game.from_json(game_json) File "/usr/local/lib/python3.7/site-packages/dataclasses_json/api.py", line 110, in from_json return cls.from_dict(kvs, infer_missing=infer_missing) File "/usr/local/lib/python3.7/site-packages/dataclasses_json/api.py", line 117, in from_dict return _decode_dataclass(cls, kvs, infer_missing) File "/usr/local/lib/python3.7/site-packages/dataclasses_json/core.py", line 166, in _decode_dataclass infer_missing) File "/usr/local/lib/python3.7/site-packages/dataclasses_json/core.py", line 109, in _decode_dataclass kvs = {decode_names.get(k, k): v for k, v in kvs.items()} AttributeError: 'list' object has no attribute 'items'

What I'm doing wrong?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/lidatong/dataclasses-json/issues/127?email_source=notifications&email_token=AGWDBAJWOM5YFPBZWDSHDB3QF76UJA5CNFSM4IPAZ4Z2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HHCHMIQ, or mute the thread https://github.com/notifications/unsubscribe-auth/AGWDBAKZKI3CSYN5XPK7IYDQF76UJANCNFSM4IPAZ4ZQ .

-- Nathan Atkins 720.346.8292 atkinsnw@gmail.com linkedin.com/in/nathan-atkins

karambaq commented 5 years ago

@nathan5280 For me it looks exactly like it should:

game = Game([QuarterCoefs([Coef(1.71, 1, 1), Coef(9, 1, 2), Coef(2.4,
                                                                 1, 3)], "2 Quarters")])
print(Game.to_json(game, indent=2))

{
  "SG": [
    {
      "E": [
        {
          "C": 1.71,
          "G": 1,
          "T": 1
        },
        {
          "C": 9,
          "G": 1,
          "T": 2
        },
        {
          "C": 2.4,
          "G": 1,
          "T": 3
        }
      ],
      "PN": "2 Quarters"
    }
  ]
}
nathan5280 commented 5 years ago

Yours: {"SG": [{"E": [{"C": 1.71, "G": 1, "T": 1}, {"C": 9, "G": 1, "T": 2}, {"C": 2.4, "G": 1, "T": 3}], "PN": "2 Quarter"}]}

Mine: {"SG": {"E": [{"C": 171, "G": 1, "T": 1}, {"C": 9, "G": 1, "T": 2}, {"C": 2.4, "G": 1, "T": 3}], "PN": "2 Quarters"}}

I guess you have an extra list inside of the "SG" dictionary item.

Something I do 10 times a day to sort this out is a round trip of json and objects.

game = Game(QuarterCoefs([Coef(171, 1, 1), Coef(9, 1, 2), Coef(2.4, 1, 3)], "2 Quarters"))

j = Game.to_json(game)

print(j)

o = Game.from_json(j)

assert o == game
karambaq commented 5 years ago

@nathan5280 Yeah, but I have this extra [] in my data, this is external API, so I need to understand how to deal with it.

nathan5280 commented 5 years ago

Ah, I was working it backwards. I’m out of town tonight. I take a look at again tomorrow if you don’t find an answer.

On Fri, Aug 23, 2019 at 10:52 AM Maxim Lyubiev notifications@github.com wrote:

@nathan5280 https://github.com/nathan5280 Yeah, but I have this extra [] in my data, this is external API, so I need to understand how to deal with it.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/lidatong/dataclasses-json/issues/127?email_source=notifications&email_token=AGWDBAJXOUC4SDHCUQGPZB3QGAIVVA5CNFSM4IPAZ4Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD5AYCWQ#issuecomment-524386650, or mute the thread https://github.com/notifications/unsubscribe-auth/AGWDBAIZPUKOWTRCWUMKHYDQGAIVVANCNFSM4IPAZ4ZQ .

-- Nathan Atkins 720.346.8292 atkinsnw@gmail.com linkedin.com/in/nathan-atkins

nathan5280 commented 5 years ago

You can also use the type hint List[someclass] instead of the field factory method.

On Fri, Aug 23, 2019 at 12:12 PM Nathan Atkins atkinsnw@gmail.com wrote:

Ah, I was working it backwards. I’m out of town tonight. I take a look at again tomorrow if you don’t find an answer.

On Fri, Aug 23, 2019 at 10:52 AM Maxim Lyubiev notifications@github.com wrote:

@nathan5280 https://github.com/nathan5280 Yeah, but I have this extra [] in my data, this is external API, so I need to understand how to deal with it.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/lidatong/dataclasses-json/issues/127?email_source=notifications&email_token=AGWDBAJXOUC4SDHCUQGPZB3QGAIVVA5CNFSM4IPAZ4Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD5AYCWQ#issuecomment-524386650, or mute the thread https://github.com/notifications/unsubscribe-auth/AGWDBAIZPUKOWTRCWUMKHYDQGAIVVANCNFSM4IPAZ4ZQ .

-- Nathan Atkins 720.346.8292 atkinsnw@gmail.com linkedin.com/in/nathan-atkins

-- Nathan Atkins 720.346.8292 atkinsnw@gmail.com linkedin.com/in/nathan-atkins

karambaq commented 5 years ago

@nathan5280 Oh, thank you, changing it to List[QuarterCoefs] worked!

nathan5280 commented 5 years ago

Maxim,

Sorry for looking at the backwards yesterday. I think this does what you want. If not ping me back. Note that last pass at it uses the Marshmallow Schema and actually gets the coef's as floats. I'm not sure if you are trying to use the default=float to handle missing values in some way, but if I drop one of those fields it blows up. If you need to handle missing values let me know and I can see if I can figure that out.

import json

from dataclasses import dataclass, field

from dataclasses_json import dataclass_json, config

from typing import List, Dict, Any

@dataclass_json

@dataclass

class Coef:

val: float = field(default=float, metadata=config(field_name="C"))

cf_type: float = field(default=int, metadata=config(field_name="G"))

total: float = field(default=float, metadata=config(field_name="T"))

@dataclass_json

@dataclass

class QuarterCoefs:

E: List[Coef] = field(metadata=config(field_name="E"))

num: str = field(default="", metadata=config(field_name="PN"))

@dataclass_json

@dataclass

class Game:

quarget_coefs: List[QuarterCoefs] =

field(metadata=config(field_name="SG"))

target = {

"SG": [

    {"E": [{"C": 1.71, "G": 1, "T": 1}, {"C": 9, "G": 1, "T": 2}, {"C":

2.4, "G": 1, "T": 3}], "PN": "2 Quarter"} ]

}

if name == "main":

# From Dict

game1 = Game.from_dict(target)

j1 = Game.to_json(game1)

print(j1)

assert Game.from_json(j1) == game1

# From Object

game2 = Game([QuarterCoefs([Coef(1.71, 1, 1), Coef(9, 1, 2), Coef(2.4,

1, 3)], "2 Quarter")])

j2 = Game.to_json(game2)

print(j2)

assert Game.from_json(j2) == game2

# With Marshmallow Schema

game3 = Game.schema().load(target)

d3 = Game.schema().dump(game3)

j3 = json.dumps(d3)

# This looks a little different because the field type is enforced and

all the coef's are floats

print(j3)

assert Game.schema().loads(j3) == game3

{"SG": [{"E": [{"C": 1.71, "G": 1, "T": 1}, {"C": 9, "G": 1, "T": 2}, {"C": 2.4, "G": 1, "T": 3}], "PN": "2 Quarter"}]}

{"SG": [{"E": [{"C": 1.71, "G": 1, "T": 1}, {"C": 9, "G": 1, "T": 2}, {"C": 2.4, "G": 1, "T": 3}], "PN": "2 Quarter"}]}

{"SG": [{"E": [{"C": 1.71, "T": 1.0, "G": 1.0}, {"C": 9.0, "T": 2.0, "G": 1.0}, {"C": 2.4, "T": 3.0, "G": 1.0}], "PN": "2 Quarter"}]}

On Fri, Aug 23, 2019 at 12:23 PM Nathan Atkins atkinsnw@gmail.com wrote:

You can also use the type hint List[someclass] instead of the field factory method.

On Fri, Aug 23, 2019 at 12:12 PM Nathan Atkins atkinsnw@gmail.com wrote:

Ah, I was working it backwards. I’m out of town tonight. I take a look at again tomorrow if you don’t find an answer.

On Fri, Aug 23, 2019 at 10:52 AM Maxim Lyubiev notifications@github.com wrote:

@nathan5280 https://github.com/nathan5280 Yeah, but I have this extra [] in my data, this is external API, so I need to understand how to deal with it.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/lidatong/dataclasses-json/issues/127?email_source=notifications&email_token=AGWDBAJXOUC4SDHCUQGPZB3QGAIVVA5CNFSM4IPAZ4Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD5AYCWQ#issuecomment-524386650, or mute the thread https://github.com/notifications/unsubscribe-auth/AGWDBAIZPUKOWTRCWUMKHYDQGAIVVANCNFSM4IPAZ4ZQ .

-- Nathan Atkins 720.346.8292 atkinsnw@gmail.com linkedin.com/in/nathan-atkins

-- Nathan Atkins 720.346.8292 atkinsnw@gmail.com linkedin.com/in/nathan-atkins

-- Nathan Atkins 720.346.8292 atkinsnw@gmail.com linkedin.com/in/nathan-atkins