More than a collection, less than a database
Project description
nanotable
Nanotable is meant to bridge the gap between simple collections, such as list and dict,
and full-on database tables. It lets you store a set of objects, index it by
several keys, and more! It's fast, memory-efficient, and well-tested.
The project draws inspiration from littletable,
but is a completely original implementation. Its goal is to avoid feature bloat
and maintain performance on par with built-in collections.
There are several situations where you might want to use Nanotable:
-
When you'd otherwise use a
dictfrom an object's field to the object itself. Nanotable does that for you, and also provides additional features, such as checking for the existence of an element with a simpleincheck; hanging the value of the key field withTable.rekey, or catching accidental changes to the key field automatically. -
When you'd otherwise use a
bidict. That's a great library in its own right, but Nanotable provides some additional functionality such as storing extra non-hashable metadata along your objects (also see the previous point). -
When you'd otherwise use a database. Nanotable spares you the computational and mental overhead. You probably have already written your own domain-specific version of Nanotable at some point in your life -- now you can use a well-tested library instead.
Installation
pip install nanotable
Usage
A basic usage example is given below:
from nanotable import Table
table = Table(of_dicts=True)\
.primary_index_on("name")\
.index_on("phone")
table.add({"name": "John Doe", "phone": "123-456-7890", "age": 25})
table.add({"name": "Jane Doe", "phone": "987-654-3210", "age": 26})
table.add({"name": "Barrack Obama", "age": "idk"})
table.at["Jane Doe"] # {"name": "Jane Doe", "phone": "987-654-3210", "age": 26}
table.by.name["John Doe"] # Same as above
table.by.phone["987-654-3210"] # {"name": "Jane Doe", "phone": "987-654-3210", "age": 26}
table.remove(table.by.name["Barrack Obama"])
You can store any kind of object in the table. Specify of_dicts=True or getfield=getfield_item
to use mappings (dict or anything with obj[key] item access); of_objects=True or
getfield=getfield_attr to use objects with attributes (obj.key access); or
any function with the signature (obj, key: str) -> Any | MISSING as getfield.
You can also specify of=MyType to have the table infer either of_objects or of_dicts
based on the anticipated element type.
Typing
The library is fully type-annotated. To make use of this, at the bare minimum you can specify the type of the objects you want to store in the table:
table = Table[Person](of_objects=True)
# or
table = Table[dict[str, Any]](of_dicts=True)
To add static typing to your indexes, you need to define a type with all of them:
class MyIndexes(Protocol):
name: UniqueIndex[Person, str]
phone: UniqueIndex[Person, str]
# The first template parameter is the object type;
# The second template parameter is protocol for `by`;
# The third template parameter is the primary index type.
table = Table[Person, MyIndexes, UniqueIndex[Person, str]](of_objects=True)
table.primary_index_on("name", required=True)
table.index_on("phone")
Indexes
TODO: UniqueIndex, MultiIndex
TODO: [sorted] extra and SortedUniqueIndex, SortedMultiIndex
Storage
TODO
Caveats
Indexed fields must be hashable, like with the built-in dict. This already
imposes the restriction that they must be immutable (which is why you can't
use, for example, a list as a dict key -- see here to learn why).
With Nanotable, however, comes the additional restriction that the value of the
indexed field itself mustn't be changed. For a dict this obviously isn't
a concern since it stores keys and values separately, inaccessible to the user.
Nanotable will try to detect this happening and warn you, but this unfortunately cannot be done reliably.
If you wish to change an indexed field, the correct way to do that is to
remove it from the table, change the field and re-add it. Nanotable provides
a helper that does this for you:
with table.rekey(obj):
obj.field = new_value
If a field is not indexed, this is unnecessary.
If you are certain that your code never modifies an indexed field of an object
in a Table, you can disable the checks that issue the warning by setting
nanotable.safety.disable_safety_checks to False. This provides a small
performance improvement, with the downside that any potential bugs will be
almost impossible to catch and will show up as subtly wrong results. It is
recommended that you keep the safety checks on unless you know what you're
doing.
Nanotable is also not thread-safe. When using a Table from multiple threads
at once, use a synchronization primitive such as a threading.Lock to ensure
that only one thread can interact with the table at a time. Multithreaded
read-only access should theoretically be fine.
License
Nanotable is distributed under the terms of the MIT license. See the LICENSE.txt for details.
© 2026 abel1502
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nanotable-0.1.0.tar.gz.
File metadata
- Download URL: nanotable-0.1.0.tar.gz
- Upload date:
- Size: 46.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c973212a9ec77367c871d149a5c8beac9aa393ff20cba12ee903e5af30033e22
|
|
| MD5 |
6818a3b4b34c78a44b336696acc21285
|
|
| BLAKE2b-256 |
f9db4d3fc18e6e5ee947f403feb537a1a129e19be08f52ddd756f5068e749aad
|
File details
Details for the file nanotable-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nanotable-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
791c0bc480c4c0941d900771a81137dfe0807fec0767e4b964c6bd20135bfe96
|
|
| MD5 |
95a1bbac79f07d6d61a9b41d935f8570
|
|
| BLAKE2b-256 |
eabcaeb4b085bb6cc8ef335e51720652f5df1e6fa8e68bb69d16a38c09a39f82
|