You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+105-7Lines changed: 105 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,6 +19,8 @@ Dataclass CSV makes working with CSV files easier and much better than working w
19
19
- Familiar syntax. The `DataclassReader` is used almost the same way as the `DictReader` in the standard library.
20
20
- It uses `dataclass` features that let you define metadata properties so the data can be parsed exactly the way you want.
21
21
- Make the code cleaner. No more extra loops to convert data to the correct type, perform validation, set default values, the `DataclassReader` will do all this for you.
22
+
- In additon of the `DataclassReader` the library also provides a `DataclassWriter` which enables creating a CSV file
One of the advantages of using the `DataclassReader` is that it makes it easy to detect when the type of data in the CSV file is not what your application's model is expecting. And, the `DataclassReader` shows errors that will help to identify the rows with problem in your CSV file.
96
100
@@ -109,7 +113,7 @@ received a value of type <class 'str'>. [CSV Line number: 3]
109
113
110
114
Note that apart from telling what the error was, the `DataclassReader` will also show which line of the CSV file contain the data with errors.
111
115
112
-
## Default values
116
+
###Default values
113
117
114
118
The `DataclassReader` also handles properties with default values. Let's modify the dataclass `User` and add a default value for the field `email`:
115
119
@@ -154,7 +158,7 @@ class User:
154
158
age: int
155
159
```
156
160
157
-
## Mapping dataclass fields to columns
161
+
###Mapping dataclass fields to columns
158
162
159
163
The mapping between a dataclass property and a column in the CSV file will be done automatically if the names match, however, there are situations that the name of the header for a column is different. We can easily tell the `DataclassReader` how the mapping should be done using the method `map`. Assuming that we have a CSV file with the contents below:
Now the DataclassReader will know how to extract the data from the column **First Name** and add it to the to dataclass property **firstname**
176
180
177
-
## Supported type annotation
181
+
###Supported type annotation
178
182
179
183
At the moment the `DataclassReader` support `int`, `str`, `float`, `complex`, `datetime`, and `bool`. When defining a `datetime` property, it is necessary to use the `dateformat` decorator, for example:
180
184
@@ -214,7 +218,7 @@ The output would look like this:
It is important to note that the `dateformat` decorator will define the date format that will be used to parse date to all properties
220
224
in the class. Now there are situations where the data in a CSV file contains two or more columns with date values in different formats. It is possible
@@ -248,7 +252,7 @@ class User:
248
252
Note that the format for the `birthday` field was not speficied using the `field` metadata. In this case the format specified in the `dateformat`
249
253
decorator will be used.
250
254
251
-
## Handling values with empty spaces
255
+
###Handling values with empty spaces
252
256
253
257
When defining a property of type `str` in the `dataclass`, the `DataclassReader` will treat values with only white spaces as invalid. To change this
254
258
behavior, there is a decorator called `@accept_whitespaces`. When decorating the class with the `@accept_whitespaces` all the properties in the class
@@ -279,7 +283,7 @@ class User:
279
283
created_at: datetime
280
284
```
281
285
282
-
## User-defined types
286
+
###User-defined types
283
287
284
288
You can use any type for a field as long as its constructor accepts a string:
285
289
@@ -300,6 +304,100 @@ class User:
300
304
ssn: SSN
301
305
```
302
306
307
+
308
+
## Using the DataclassWriter
309
+
310
+
Reading a CSV file using the `DataclassReader` is great and gives us the type-safety of Python's dataclasses and type annotation, however, there are situations where we would like to use dataclasses for creating CSV files, that's where the `DataclassWriter` comes in handy.
311
+
312
+
Using the `DataclassWriter` is quite simple. Given that we have a dataclass `User`:
In order to create a CSV using the `DataclassWriter` import it from `dataclass_csv`:
337
+
338
+
```python
339
+
from dataclass_csv import DataclassWriter
340
+
```
341
+
342
+
Initialize it with the required arguments and call the method `write`:
343
+
344
+
```python
345
+
withopen("users.csv", "w") as f:
346
+
w = DataclassWriter(f, users, User)
347
+
w.writer()
348
+
```
349
+
350
+
That's it! Let's break down the snippet above.
351
+
352
+
First, we open a file called `user.csv` for writing. After that, an instance of the `DataclassWriter` is created. To create a `DataclassWriter` we need to pass the `file`, the list of `User` instances, and lastly, the type, which in this case is `User`.
353
+
354
+
The type is required since the writer uses it when trying to figure out the CSV header. By default, it will use the names of the
355
+
properties defined in the dataclass, in the case of the dataclass `User` the title of each column
356
+
will be `firstname`, `lastname` and `age`.
357
+
358
+
See below the CSV created out of a list of `User`:
359
+
360
+
```text
361
+
firstname,lastname,age
362
+
John,Smith,40
363
+
Daniel,Nilsson,10
364
+
Ella,Fralla,4
365
+
```
366
+
367
+
The `DataclassWriter` also takes a `**fmtparams` which accepts the same parameters as the `csv.writer`, for more
368
+
information see: https://docs.python.org/3/library/csv.html#csv-fmt-params
369
+
370
+
Now, there are situations where we don't want to write the CSV header. In this case, the method `write` of
371
+
the `DataclassWriter` accepts an extra argument, called `skip_header`. The default value is `False` and when set to
372
+
`True` it will skip the header.
373
+
374
+
#### Modifying the CSV header
375
+
376
+
As previously mentioned the `DataclassWriter` uses the names of the properties defined in the dataclass as the CSV header titles, however,
377
+
depending on your use case it makes sense to change it. The `DataclassWriter` has a `map` method just for this purpose.
378
+
379
+
Using the `User` dataclass with the properties `firstname`, `lastname` and `age`. The snippet below shows how to change `firstname` to `First name` and `lastname` to `Last name`:
380
+
381
+
```python
382
+
withopen("users.csv", "w") as f:
383
+
w = DataclassWriter(f, users, User)
384
+
385
+
# Add mappings for firstname and lastname
386
+
w.map("firstname").to("First name")
387
+
w.map("lastname").to("Last name")
388
+
389
+
w.writer()
390
+
```
391
+
392
+
The CSV output of the snippet above will be:
393
+
394
+
```text
395
+
First name,Last name,age
396
+
John,Smith,40
397
+
Daniel,Nilsson,10
398
+
Ella,Fralla,4
399
+
```
400
+
303
401
## Copyright and License
304
402
305
403
Copyright (c) 2018 Daniel Furtado. Code released under BSD 3-clause license
0 commit comments