bunches
| Version | |
| Status | |
| Documentation | |
| Tools | |
| Compatibility | |
| Stats | |
What is bunches?
bunches provides drop-in replacements for Python's built-in dict and list that add a consistent set of extra tools. Every class in the package:
- stores its data in a plain Python collection in the
contentsattribute, so you can always drop back to the built-in type; - has an
addmethod, the default way to put data in the collection; - has a
deletemethod, the default way to remove data (it is also whatdel collection[item]calls); - has a
subsetmethod that returns a new collection containing only some of the data; - supports
+(returns a new collection with an item added) and+=(adds the item in place), both of which useadd.
The package is fully typed, has no dependencies, and supports Python 3.11 and later.
Why use bunches?
The built-in collections are excellent, but they leave you to re-implement the same conveniences whenever you build a registry, a set of options, or an ordered group of named items. bunches supplies those conveniences once: wildcard lookups, keys inferred from the items you store, layered dictionaries, and lists that can be searched by name.
Classes
Mappings
Dictionary: drop-in replacement for a pythondictwith anaddmethod for a default mechanism of adding data, adeletemethod for a default mechanism of deleting data, and asubsetmethod for returning a subset of the key/value pairs in a newDictionary. Itskeys,valuesanditemsmethods returntuples and it hasdefaultdict-like behavior when usingget.Catalog: wildcard-accepting dict which is intended for storing different options and strategies. It recognizes the special keysall,defaultandnoneand returns lists of matches if a list of keys is provided.ChainDict: aDictionarythat stores several dictionaries and searches them in order, likecollections.ChainMap.Repository: a dictionary that automatically supplies key names for stored items. Theoverwriteargument determines if a unique key should always be created or whether entries may be overwritten.
Sequences
Listing: drop-in replacement for a python list with anaddmethod for a default mechanism of adding data, adeletemethod for a default mechanism of deleting data, aprependmethod, and asubsetmethod for returning a subset of the items in a newListing.DictList: iterable with both dict and list interfaces. Stored items must be hashable or have anameattribute.
Getting started
Requirements
bunches requires Python 3.11 or later and runs on Linux, macOS and Windows. It has no third-party dependencies.
Installation
To install bunches, use pip:
pip install bunches
Usage
Dictionary
A Dictionary works like a dict. Its add method updates the stored data, subset returns a new Dictionary, and get falls back on default_factory (a value or a callable) when a key is missing.
from bunches import Dictionary
colors = Dictionary(contents={"red": 1, "green": 2}, default_factory=0)
colors.add({"blue": 3})
colors["blue"] # 3
colors.get("purple") # 0
colors.subset(include=["red", "blue"]).contents # {'red': 1, 'blue': 3}
colors.subset(exclude="red").keys() # ('green', 'blue')
del colors["green"]
colors.contents # {'red': 1, 'blue': 3}
(colors + {"pink": 4}).contents # {'red': 1, 'blue': 3, 'pink': 4}
colors.contents # {'red': 1, 'blue': 3}
Catalog
A Catalog is meant for storing options. The all, default and none keys are special and a list of keys returns a list of values.
from bunches import Catalog
models = Catalog(contents={"tree": "DecisionTree", "forest": "RandomForest"})
models["tree"] # 'DecisionTree'
models[["tree", "forest"]] # ['DecisionTree', 'RandomForest']
models["all"] # ['DecisionTree', 'RandomForest']
models.default = "forest"
models["default"] # 'RandomForest'
models["none"] is None # True
ChainDict
A ChainDict searches its stored dictionaries in order and returns the first match. Set return_first to False to get every match.
from bunches import ChainDict, Dictionary
chain = ChainDict(contents=[Dictionary({"a": 1}), Dictionary({"a": 2, "b": 3})])
chain["a"], chain["b"] # (1, 3)
chain.return_first = False
chain["a"] # [1, 2]
chain.new_child(Dictionary({"c": 4}))
chain.keys() # ('c', 'a', 'a', 'b')
Repository
A Repository infers the key for each item added: the item itself if it is a str, its name attribute, or the snake-cased name of its class. Unless overwrite is True, a counter is appended to avoid overwriting existing items.
from dataclasses import dataclass
from bunches import Repository
@dataclass
class Worker:
name: str
class DataLoader:
pass
repository = Repository()
repository.add(Worker("ann"))
repository.add(DataLoader())
repository.add(DataLoader())
repository.add(Worker("bob"), key="boss")
repository.keys() # ('ann', 'data_loader', 'data_loader2', 'boss')
Listing
A Listing works like a list. add extends the list with a sequence and appends anything else, and prepend does the same at the beginning.
from bunches import Listing
letters = Listing(contents=["b", "c"])
letters.add("d")
letters.add(["e", "f"])
letters.prepend("a")
letters.contents # ['a', 'b', 'c', 'd', 'e', 'f']
letters.subset(include=["a", "b", "c"], exclude="b").contents # ['a', 'c']
letters.delete(0)
letters[0] # 'b'
DictList
A DictList is a list you can also search by name. Items are found by their name attribute or, if they have none, by their own value. Duplicate names are allowed; a DictList of the matches is returned.
from bunches import DictList
workers = DictList(contents=[Worker("ann"), Worker("bob"), Worker("ann")])
workers.keys() # ('ann', 'bob', 'ann')
workers["bob"] # Worker(name='bob')
len(workers["ann"]) # 2
workers[1] # Worker(name='bob')
workers.delete("ann")
workers.keys() # ('bob',)
Choosing what subset returns
Every subset method has a returns argument. 'class' (the default) returns a new instance of the same class, 'copy' returns a deep copy of the instance (keeping its other settings) and 'simple' returns the built-in type. To change the default for the whole package, use bunches.settings.set_subset_return.
colors = Dictionary({"red": 1, "green": 2})
colors.subset(include="red", returns="simple") # {'red': 1}
Naming items
Repository and DictList name items with a global function that you can replace using bunches.settings.set_key_namer.
from bunches import settings
settings.set_key_namer(lambda item: str(item).upper())
Repository({"a": 1}).add("b")
DictList(["x", "y"]).keys() # ('X', 'Y')
settings.set_key_namer(settings.utilities._namify)
Contributing
Contributors are always welcome. Feel free to grab an issue to work on or make a suggested improvement. If you wish to contribute, please read the Contribution Guide and Code of Conduct.
Similar Projects
collectionsin the Python standard library providesUserDict,UserList,ChainMapanddefaultdict, which inspired several of the classes inbunches.sortedcontainersprovides sorted drop-in replacements forlist,dictandset.
Acknowledgments
I'd also like to extend a special thanks to pawamoy whose excellent mkdocs extensions and utilities are incorporated into snickerdoodle. Some of the scripts, documentation, configuration files, and other CI code were adapted from pawamoy's repositories.
I would also like to thank the University of Kansas School of Law for tolerating and supporting this law professor's coding efforts, an endeavor which is well outside the typical scholarly activities in the discipline.
License
Use of this repository is authorized under the Apache Software License 2.0.
Metadata
Release files for bunches 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bunches-0.2.1.tar.gz | 125.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bunches-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 148.2 kB
Release files / bunches-0.2.1.tar.gz
| Download URL | bunches-0.2.1.tar.gz |
|---|---|
| Size | 125.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8eace5ec0c76e417a9e183db7787d5878826ad1b94647181e99b2b7bbce46784
|
|
BLAKE2b-256 checksum How to use checksums |
3007a8941929af1422e793b40638174945c9f287a29d007b7865130bc4601029
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","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}
|
Release files / bunches-0.2.1-py3-none-any.whl
| Download URL | bunches-0.2.1-py3-none-any.whl |
|---|---|
| Size | 22.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7d0d4aac80ebe8d838345887ffcfcfc5e9e5fa86308a4c3af2c78aecfe9cd06b
|
|
BLAKE2b-256 checksum How to use checksums |
16c74d6396d90c5d5e4e97bda37f86972d2131ee5b84391fb65c1f06d3d01087
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","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}
|