Skip to main content

bunches

Version PyPI Latest Release GitHub Latest Release
Status Build Status Development Status Project Stability
Documentation Hosted By
Tools Documentation Linter Dependency Manager Pre-commit CI Editor Settings Repository Template Dependency Maintainer
Compatibility Compatible Python Versions Linux MacOS Windows
Stats PyPI Download Rate (per month) GitHub Stars GitHub Contributors GitHub Issues GitHub Forks

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 contents attribute, so you can always drop back to the built-in type;
  • has an add method, the default way to put data in the collection;
  • has a delete method, the default way to remove data (it is also what del collection[item] calls);
  • has a subset method 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 use add.

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 python dict with an add method for a default mechanism of adding data, a delete method for a default mechanism of deleting data, and a subset method for returning a subset of the key/value pairs in a new Dictionary. Its keys, values and items methods return tuples and it has defaultdict-like behavior when using get.
  • Catalog: wildcard-accepting dict which is intended for storing different options and strategies. It recognizes the special keys all, default and none and returns lists of matches if a list of keys is provided.
  • ChainDict: a Dictionary that stores several dictionaries and searches them in order, like collections.ChainMap.
  • Repository: a dictionary that automatically supplies key names for stored items. The overwrite argument 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 an add method for a default mechanism of adding data, a delete method for a default mechanism of deleting data, a prepend method, and a subset method for returning a subset of the items in a new Listing.
  • DictList: iterable with both dict and list interfaces. Stored items must be hashable or have a name attribute.

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

  • collections in the Python standard library provides UserDict, UserList, ChainMap and defaultdict, which inspired several of the classes in bunches.
  • sortedcontainers provides sorted drop-in replacements for list, dict and set.

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.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bunches 0.2.0
File Size Uploaded
bunches-0.2.0.tar.gz 125.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bunches 0.2.0
File Interpreter ABI Platform
bunches-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 147.8 kB

Release files / bunches-0.2.0.tar.gz

Download URL bunches-0.2.0.tar.gz
Size 125.4 kB
Tags Source
SHA-256 checksum
How to use checksums
054af5c0bbd30dd6260887ce0b965bad697d2566d715c28e7cab0723bc7f90a6
BLAKE2b-256 checksum
How to use checksums
735dcf6c6cdde499e3841650e7753acd76ca9247fc264970a5442b3929f297b7
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.0-py3-none-any.whl

Download URL bunches-0.2.0-py3-none-any.whl
Size 22.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a6d888fc32154542b522e7cee634f81da3320bbd584d92344d39dedd74ec42ba
BLAKE2b-256 checksum
How to use checksums
dca2c3bd3f5949e889609e427d353fabc44e8d1bb9d78cd9063dc7958897694c
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 history Release notifications | RSS feed

0.2.1

2 release files

This release

0.2.0 This release

2 release files

0.1.3

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page