0

I have the Property and Properties dataclasses and want to output into a csv format. I took the references from https://pypi.org/project/dataclass-csv/ for csv writer.

@dataclass
class Property:
    property_id: str = field(default=None)
    property_features: dict[str, str] = field(default_factory=lambda: {
        'Property_1': None,
        'Property_2': None,
    })
@dataclass
class Properties:
    Property_list: list[Property] = field(default_factory=list)

output:

p_collection = Properties(Property_list=[Property(property_id='48a7bfa2', property_features={'Property_1': 'tin', 'Property_2': 'Electric blue'})])

To save the p_collection as csv, I tried:

from dataclass_csv import DataclassWriter
with open(output_file_name, 'w') as f:
   w = DataclassWriter(f, p_collection, Properties)
   w.write()

This errors with ValueError("Invalid 'data' argument. It must be a list") Here Properties is a list of Property. Could you see if I am missing anything?

Adrian Klaver
  • 15,886
  • 2
  • 17
  • 28
Aavik
  • 967
  • 19
  • 48
  • "Here Properties is a list of Property." False. `p_collection` is of type `Properties`. The error message is telling you that you need to pass an argument of type `list`. It looks like replacing `p_collection` with `p_collection.Property_list` would work. And probably the third argument would need to be `Property` not `Properties`. Another option may be replacing `p_collection` with `[p_collection]`, but I'm not sure if `dataclass_csv` can handle nested dataclasses. – Steven Rumbalski Oct 30 '22 at 14:04
  • yeah. Thanks p_collection.Property_list fixes the error and still require property_features to convert as csv. Thank you. – Aavik Oct 30 '22 at 14:10

1 Answers1

0

An alternate solution using just Python global modules.

from dataclasses import dataclass, field, asdict, fields
import csv

@dataclass
class Property:
    property_id: str = field(default=None)
    property_features: dict[str, str] = field(default_factory=lambda: {
        'Property_1': None,
        'Property_2': None,
    })
@dataclass
class Properties:
    Property_list: list[Property] = field(default_factory=list)

p_collection = Properties(Property_list=[Property(property_id='48a7bfa2', property_features={'Property_1': 'tin', 'Property_2': 'Electric blue'})])

with open('dataclass_test.csv', 'w') as f:
   flds = [fld.name for fld in fields(Property)]
   w = csv.DictWriter(f, flds)
   w.writeheader()
   w.writerows([asdict(prop) for prop in p_collection.Property_list])

cat dataclass_test.csv
property_id,property_features
48a7bfa2,"{'Property_1': 'tin', 'Property_2': 'Electric blue'}"


Adrian Klaver
  • 15,886
  • 2
  • 17
  • 28
  • Thanks @Adrian. How do you further convert the inner dict property_features to csv format – Aavik Oct 31 '22 at 08:08
  • It produces the same output as the `DataclassWriter(f, p_collection.Property_list, Property)`. You will need to be more specific about "... convert the inner dict property_features to csv format"? CSV does not have nesting, so I am not sure what you are after? Add example of desired output **as update** to your question. – Adrian Klaver Oct 31 '22 at 15:21
  • I unnested the property_features using reference from https://stackoverflow.com/questions/70794624/unnest-dictionary-with-nested-dictionary-or-list-of-dictionaries. This helped. Is there a way to get the column names of the property_features as well? – Aavik Nov 01 '22 at 07:26
  • example after unnest it looks like: [{'property_id': '48a7bfa2', 'property_features.Property_1': 'tin', 'property_features.Property_2': 'Electric blue'},{}] – Aavik Nov 01 '22 at 07:27
  • Per request in my comment **add the information** in your comments above as update to your question. Including the unnesting code you came up with and where you put it. Then folks don't have search comments for relevant information. – Adrian Klaver Nov 01 '22 at 14:57
  • Without the code I can't be more specific, but it would seem you just need to end up with : `flds = ['property_id', 'property_features.Property_1', 'property_features.Property_2']` – Adrian Klaver Nov 01 '22 at 15:01