Getting started¶
Install¶
pip install daffodil
Daffodil needs Python 3.10 or later. The table code is pure Python. Installing it also installs two small pure-Python packages: Markdown, and xlsx2csv for Excel files.
Some features need another package, which is not installed with daffodil:
| Feature | Package | Install |
|---|---|---|
to_pandas_df(), from_pandas_df() |
pandas | pip install daffodil[pandas] |
to_numpy(), from_numpy(), to_donpa(), sum_np() |
NumPy | pip install daffodil[numpy] |
| faster reading of list and dict cells | pyjson5 | pip install daffodil[pyjson5] |
from_csv() of an http or https address |
requests | pip install requests |
from_csv() and to_csv_file() with an s3:// name |
boto3 | pip install boto3 |
from_pdf(), which is experimental |
pdfplumber | pip install daffodil[pdf] |
A method that needs a missing package raises ImportError, or a RuntimeError that names it.
Make a table¶
A Daf is a list of rows, each a plain Python list, and a dict of the column names.
>>> from daffodil.daf import Daf
>>> daf = Daf(cols=['id', 'item', 'qty'], lol=[['a1', 'pen', 3], ['b2', 'ink', 10]], keyfield='id')
>>> print(daf.to_md())
| id | item | qty |
| -: | ---: | --: |
| a1 | pen | 3 |
| b2 | ink | 10 |
keyfield names the column whose values identify the rows. It is optional.
From a list of dicts, the columns are the keys:
>>> d2 = Daf.from_lod([{'id': 'a1', 'qty': 3}, {'id': 'b2', 'qty': 10}])
>>> d2.columns()
['id', 'qty']
From a CSV file, Daf.from_csv('file.csv') reads the header line as the column names. The
values are read as text. See Types and conversion to convert them.
Look at it¶
>>> len(daf), daf.shape(), daf.columns()
(2, (2, 3), ['id', 'item', 'qty'])
>>> daf.keys()
['a1', 'b2']
>>> bool(Daf())
False
print(daf) and daf.to_md() give a Markdown table. See Markdown reports.
Read values¶
A selection with [] returns a new Daf. Turn it into plain values with to_value(),
to_list() or to_dict(), or read them with the methods that never build a table.
>>> daf[1, 'qty'].to_value()
10
>>> daf[0].to_list()
['a1', 'pen', 3]
>>> daf.select_record('b2')
{'id': 'b2', 'item': 'ink', 'qty': 10}
>>> daf.col('qty')
[3, 10]
See Selecting and indexing for all the ways to select.
Add rows¶
>>> _ = daf.append({'id': 'c3', 'item': 'pad', 'qty': 7})
>>> _ = daf.append(['d4', 'cap', 1])
>>> daf.col('id')
['a1', 'b2', 'c3', 'd4']
A dict is placed by column name, and a list is in column order. append() returns the Daf,
so these examples assign it to _, to keep the output short. See
Building tables for the fast ways to build a table in a loop.
Change values¶
>>> daf[0, 'qty'] = 4
>>> daf.select_record('a1')['qty']
4
The usual pattern¶
Read a file, go through it row by row, and build a new table. This is where Daffodil is strongest: appending a row is cheap, and nothing is converted.
In the loop, each row is a new dict. Assigning a new value to it does not change the
source table. To change values in place, use update_record_krow(), apply_in_place(), or
iter_klist(), whose rows write through to the table.
>>> source = Daf.from_lod([{'name': 'pen', 'price': '1.50'}, {'name': 'ink', 'price': '4.00'}])
>>> out = Daf(cols=['name', 'price_cents'])
>>> for row in source:
... _ = out.append({'name': row['name'], 'price_cents': round(float(row['price']) * 100)})
>>> out.to_lod()
[{'name': 'pen', 'price_cents': 150}, {'name': 'ink', 'price_cents': 400}]
The same, with apply(), which calls a function for each row and builds the new table:
>>> def to_cents(row):
... return {'name': row['name'], 'price_cents': round(float(row['price']) * 100)}
>>> source.apply(to_cents).to_lod()
[{'name': 'pen', 'price_cents': 150}, {'name': 'ink', 'price_cents': 400}]
Get the data out¶
>>> out.to_lod()[0]
{'name': 'pen', 'price_cents': 150}
>>> out.lol
[['pen', 150], ['ink', 400]]
to_csv_file(path)writes a CSV file.to_pandas_df()andto_numpy()hand the data to pandas or NumPy, for heavy numeric work.