# littletable - a Python module to give ORM-like access to a collection of objects
[![Build Status](https://travis-ci.org/ptmcg/littletable.svg?branch=master)](https://travis-ci.org/ptmcg/littletable) [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/ptmcg/littletable/master)
- [Introduction](#introduction)
- [Importing data from CSV files](#importing-data-from-csv-files)
- [Tabular output](#tabular-output)
- [For More Info](#for-more-info)
- [Sample Demo](#sample-demo)
Introduction
------------
The `littletable` module provides a low-overhead, schema-less, in-memory database access to a collection
of user objects. `littletable` Tables will accept Python `dict`s or any user-defined object type, including:
- `namedtuples` and `typing.NamedTuples`
- `dataclasses`
- `types.SimpleNamespaces`
- `attrs` classes
- `PyDantic` data models
- `traitlets`
`littletable` infers the Table's "columns" from those objects' `__dict__`, `__slots__`, or `_fields` mappings to access
object attributes.
If populated with Python `dict`s, they get stored as `SimpleNamespace`s or `littletable.DictObject`s.
In addition to basic ORM-style insert/remove/query/delete access to the contents of a `Table`, `littletable` offers:
* simple indexing for improved retrieval performance, and optional enforcing key uniqueness
* access to objects using indexed attributes
* direct import/export to CSV and Excel .xlsx files
* clean tabular output for data presentation
* simplified joins using `"+"` operator syntax between annotated `Table`s
* the result of any query or join is a new first-class `littletable` `Table`
* simple full-text search against multi-word text attributes
* access like a standard Python list to the records in a Table, including indexing/slicing, `iter`, `zip`, `len`, `groupby`, etc.
* access like a standard Python `dict` to attributes with a unique index, or like a standard Python `defaultdict(list)` to attributes with a non-unique index
`littletable` `Table`s do not require an upfront schema definition, but simply work off of the attributes in
the stored values, and those referenced in any query parameters.
Importing data from CSV files
-----------------------------
You can easily import a CSV file into a Table using Table.csv_import():
```python
t = Table().csv_import("my_data.csv")
```
In place of a local file name, you can also specify an HTTP url:
```python
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv"
names = ["sepal-length", "sepal-width", "petal-length", "petal-width", "class"]
iris_table = Table('iris').csv_import(url, fieldnames=names)
```
You can also directly import CSV data as a string:
```python
catalog = Table("catalog")
catalog_data = """\
sku,description,unitofmeas,unitprice
BRDSD-001,Bird seed,LB,3
BBS-001,Steel BB's,LB,5
MGNT-001,Magnet,EA,8"""
catalog.csv_import(catalog_data, transforms={'unitprice': int})
```
Data can also be directly imported from compressed .zip, .gz, and .xz files.
Files containing JSON-formatted records can be similarly imported using `Table.json_import()`.
Tabular output
--------------
To produce a nice tabular output for a table, you can use the embedded support for
the [rich](https://github.com/willmcgugan/rich) module, `as_html()` in [Jupyter Notebook](https://jupyter.org/),
or the [tabulate](https://github.com/astanin/python-tabulate) module:
Using `table.present()` (implemented using `rich`; `present()` accepts `rich` `Table` keyword args):
```python
table(title_str).present(fields=["col1", "col2", "col3"])
or
table.select("col1 col2 col3")(title_str).present(caption="caption text",
caption_justify="right")
```
Using `Jupyter Notebook`:
```python
from IPython.display import HTML, display
display(HTML(table.as_html()))
```
Using `tabulate`:
```python
from tabulate import tabulate
print(tabulate((vars(rec) for rec in table), headers="keys"))
```
For More Info
-------------
Extended "getting started" notes at [how_to_use_littletable.md](https://github.com/ptmcg/littletable/blob/master/how_to_use_littletable.md).
Sample Demo
-----------
Here is a simple littletable data storage/retrieval example:
```python
from littletable import Table
customers = Table('customers')
customers.create_index("id", unique=True)
customers.csv_import("""\
id,name
0010,George Jetson
0020,Wile E. Coyote
0030,Jonny Quest
""")
catalog = Table('catalog')
catalog.create_index("sku", unique=True)
catalog.insert({"sku": "ANVIL-001", "descr": "1000lb anvil", "unitofmeas": "EA","unitprice": 100})
catalog.insert({"sku": "BRDSD-001", "descr": "Bird seed", "unitofmeas": "LB","unitprice": 3})
catalog.insert({"sku": "MAGNT-001", "descr": "Magnet", "unitofmeas": "EA","unitprice": 8})
catalog.insert({"sku": "MAGLS-001", "descr": "Magnifying glass", "unitofmeas": "EA","unitprice": 12})
wishitems = Table('wishitems')
wishitems.create_index("custid")
wishitems.create_index("sku")
# easy to import CSV data from a string or file
wishitems.csv_import("""\
custid,sku
0020,ANVIL-001
0020,BRDSD-001
0020,MAGNT-001
0030,MAGNT-001
0030,MAGLS-001
""")
# print a particular customer name
# (unique indexes will return a single item; non-unique
# indexes will return a list of all matching items)
print(customers.by.id["0030"].name)
# see all customer names
for name in customers.all.name:
print(name)
# print all items sold by the pound
for item in catalog.where(unitofmeas="LB"):
print(item.sku, item.descr)
# print all items that cost more than 10
for item in catalog.where(lambda o: o.unitprice > 10):
print(item.sku, item.descr, item.unitprice)
# join tables to create queryable wishlists collection
wishlists = customers.join_on("id") + wishitems.join_on("custid") + catalog.join_on("sku")
# print all wishlist items with price > 10 (can use Table.gt comparator instead of lambda)
bigticketitems = wishlists().where(unitprice=Table.gt(10))
for item in bigticketitems:
print(item)
# list all wishlist items in descending order by price
for item in wishlists().sort("unitprice desc"):
print(item)
# print output as a nicely-formatted table
wishlists().sort("unitprice desc")("Wishlists").present()
# print output as an HTML table
print(wishlists().sort("unitprice desc")("Wishlists").as_html())
# print output as a Markdown table
print(wishlists().sort("unitprice desc")("Wishlists").as_markdown())
```
Raw data
{
"_id": null,
"home_page": "https://github.com/ptmcg/littletable/",
"name": "littletable",
"maintainer": null,
"docs_url": "https://pythonhosted.org/littletable/",
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": null,
"author": "Paul McGuire",
"author_email": "ptmcg@austin.rr.com",
"download_url": "https://files.pythonhosted.org/packages/f3/d3/d3284f8413ebf7aaf15273ba341229b76e70410495d3d7b77e2a7b0dffd2/littletable-2.2.5.tar.gz",
"platform": null,
"description": "# littletable - a Python module to give ORM-like access to a collection of objects\n[![Build Status](https://travis-ci.org/ptmcg/littletable.svg?branch=master)](https://travis-ci.org/ptmcg/littletable) [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/ptmcg/littletable/master)\n\n- [Introduction](#introduction)\n- [Importing data from CSV files](#importing-data-from-csv-files)\n- [Tabular output](#tabular-output)\n- [For More Info](#for-more-info)\n- [Sample Demo](#sample-demo)\n\nIntroduction\n------------\nThe `littletable` module provides a low-overhead, schema-less, in-memory database access to a collection \nof user objects. `littletable` Tables will accept Python `dict`s or any user-defined object type, including:\n\n- `namedtuples` and `typing.NamedTuples`\n- `dataclasses`\n- `types.SimpleNamespaces`\n- `attrs` classes\n- `PyDantic` data models\n- `traitlets`\n\n`littletable` infers the Table's \"columns\" from those objects' `__dict__`, `__slots__`, or `_fields` mappings to access\nobject attributes. \n\nIf populated with Python `dict`s, they get stored as `SimpleNamespace`s or `littletable.DictObject`s.\n\nIn addition to basic ORM-style insert/remove/query/delete access to the contents of a `Table`, `littletable` offers:\n* simple indexing for improved retrieval performance, and optional enforcing key uniqueness \n* access to objects using indexed attributes\n* direct import/export to CSV and Excel .xlsx files\n* clean tabular output for data presentation\n* simplified joins using `\"+\"` operator syntax between annotated `Table`s \n* the result of any query or join is a new first-class `littletable` `Table` \n* simple full-text search against multi-word text attributes\n* access like a standard Python list to the records in a Table, including indexing/slicing, `iter`, `zip`, `len`, `groupby`, etc.\n* access like a standard Python `dict` to attributes with a unique index, or like a standard Python `defaultdict(list)` to attributes with a non-unique index\n\n`littletable` `Table`s do not require an upfront schema definition, but simply work off of the attributes in \nthe stored values, and those referenced in any query parameters.\n\n\nImporting data from CSV files\n-----------------------------\nYou can easily import a CSV file into a Table using Table.csv_import():\n\n```python\nt = Table().csv_import(\"my_data.csv\")\n```\n\nIn place of a local file name, you can also specify an HTTP url:\n\n```python\nurl = \"https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv\"\nnames = [\"sepal-length\", \"sepal-width\", \"petal-length\", \"petal-width\", \"class\"]\niris_table = Table('iris').csv_import(url, fieldnames=names)\n```\n\nYou can also directly import CSV data as a string:\n\n```python\ncatalog = Table(\"catalog\")\n\ncatalog_data = \"\"\"\\\nsku,description,unitofmeas,unitprice\nBRDSD-001,Bird seed,LB,3\nBBS-001,Steel BB's,LB,5\nMGNT-001,Magnet,EA,8\"\"\"\n\ncatalog.csv_import(catalog_data, transforms={'unitprice': int})\n```\n\nData can also be directly imported from compressed .zip, .gz, and .xz files.\n\nFiles containing JSON-formatted records can be similarly imported using `Table.json_import()`.\n\n\nTabular output\n--------------\nTo produce a nice tabular output for a table, you can use the embedded support for\nthe [rich](https://github.com/willmcgugan/rich) module, `as_html()` in [Jupyter Notebook](https://jupyter.org/),\nor the [tabulate](https://github.com/astanin/python-tabulate) module:\n\nUsing `table.present()` (implemented using `rich`; `present()` accepts `rich` `Table` keyword args):\n\n```python\ntable(title_str).present(fields=[\"col1\", \"col2\", \"col3\"])\n or\ntable.select(\"col1 col2 col3\")(title_str).present(caption=\"caption text\", \n caption_justify=\"right\")\n```\n\nUsing `Jupyter Notebook`:\n\n```python\nfrom IPython.display import HTML, display\ndisplay(HTML(table.as_html()))\n```\n\nUsing `tabulate`:\n\n```python\nfrom tabulate import tabulate\nprint(tabulate((vars(rec) for rec in table), headers=\"keys\"))\n```\n\nFor More Info\n-------------\nExtended \"getting started\" notes at [how_to_use_littletable.md](https://github.com/ptmcg/littletable/blob/master/how_to_use_littletable.md).\n\nSample Demo\n-----------\nHere is a simple littletable data storage/retrieval example:\n\n```python\nfrom littletable import Table\n\ncustomers = Table('customers')\ncustomers.create_index(\"id\", unique=True)\ncustomers.csv_import(\"\"\"\\\nid,name\n0010,George Jetson\n0020,Wile E. Coyote\n0030,Jonny Quest\n\"\"\")\n\ncatalog = Table('catalog')\ncatalog.create_index(\"sku\", unique=True)\ncatalog.insert({\"sku\": \"ANVIL-001\", \"descr\": \"1000lb anvil\", \"unitofmeas\": \"EA\",\"unitprice\": 100})\ncatalog.insert({\"sku\": \"BRDSD-001\", \"descr\": \"Bird seed\", \"unitofmeas\": \"LB\",\"unitprice\": 3})\ncatalog.insert({\"sku\": \"MAGNT-001\", \"descr\": \"Magnet\", \"unitofmeas\": \"EA\",\"unitprice\": 8})\ncatalog.insert({\"sku\": \"MAGLS-001\", \"descr\": \"Magnifying glass\", \"unitofmeas\": \"EA\",\"unitprice\": 12})\n\nwishitems = Table('wishitems')\nwishitems.create_index(\"custid\")\nwishitems.create_index(\"sku\")\n\n# easy to import CSV data from a string or file\nwishitems.csv_import(\"\"\"\\\ncustid,sku\n0020,ANVIL-001\n0020,BRDSD-001\n0020,MAGNT-001\n0030,MAGNT-001\n0030,MAGLS-001\n\"\"\")\n\n# print a particular customer name\n# (unique indexes will return a single item; non-unique\n# indexes will return a list of all matching items)\nprint(customers.by.id[\"0030\"].name)\n\n# see all customer names\nfor name in customers.all.name:\n print(name)\n\n# print all items sold by the pound\nfor item in catalog.where(unitofmeas=\"LB\"):\n print(item.sku, item.descr)\n\n# print all items that cost more than 10\nfor item in catalog.where(lambda o: o.unitprice > 10):\n print(item.sku, item.descr, item.unitprice)\n\n# join tables to create queryable wishlists collection\nwishlists = customers.join_on(\"id\") + wishitems.join_on(\"custid\") + catalog.join_on(\"sku\")\n\n# print all wishlist items with price > 10 (can use Table.gt comparator instead of lambda)\nbigticketitems = wishlists().where(unitprice=Table.gt(10))\nfor item in bigticketitems:\n print(item)\n\n# list all wishlist items in descending order by price\nfor item in wishlists().sort(\"unitprice desc\"):\n print(item)\n\n# print output as a nicely-formatted table\nwishlists().sort(\"unitprice desc\")(\"Wishlists\").present()\n\n# print output as an HTML table\nprint(wishlists().sort(\"unitprice desc\")(\"Wishlists\").as_html())\n\n# print output as a Markdown table\nprint(wishlists().sort(\"unitprice desc\")(\"Wishlists\").as_markdown())\n\n```\n",
"bugtrack_url": null,
"license": "MIT License",
"summary": "Python in-memory ORM database",
"version": "2.2.5",
"project_urls": {
"Download": "https://pypi.org/project/littletable/",
"Homepage": "https://github.com/ptmcg/littletable/"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d234cf56ac1470cc206c98a17bb542d8060096b8a8bfb7cfb3c15f9203aa0d0d",
"md5": "1cd55ae4b92085ea8d173002b6aaaf27",
"sha256": "3b389210ef8022e88f65539b055340e36e3b85656bf638ff3bf389c4d2c81029"
},
"downloads": -1,
"filename": "littletable-2.2.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "1cd55ae4b92085ea8d173002b6aaaf27",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 43971,
"upload_time": "2024-04-09T01:52:12",
"upload_time_iso_8601": "2024-04-09T01:52:12.711360Z",
"url": "https://files.pythonhosted.org/packages/d2/34/cf56ac1470cc206c98a17bb542d8060096b8a8bfb7cfb3c15f9203aa0d0d/littletable-2.2.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "f3d3d3284f8413ebf7aaf15273ba341229b76e70410495d3d7b77e2a7b0dffd2",
"md5": "865644dada53984dec8b24aca99411d6",
"sha256": "2ea05392ba7d8cf2af80b4861856a174d6b332b6816616fcf7e16421b2cc701d"
},
"downloads": -1,
"filename": "littletable-2.2.5.tar.gz",
"has_sig": false,
"md5_digest": "865644dada53984dec8b24aca99411d6",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 77013,
"upload_time": "2024-04-09T01:52:14",
"upload_time_iso_8601": "2024-04-09T01:52:14.667179Z",
"url": "https://files.pythonhosted.org/packages/f3/d3/d3284f8413ebf7aaf15273ba341229b76e70410495d3d7b77e2a7b0dffd2/littletable-2.2.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-04-09 01:52:14",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ptmcg",
"github_project": "littletable",
"travis_ci": true,
"coveralls": false,
"github_actions": false,
"lcname": "littletable"
}