Attribute-based data structures.
Project description
attrbox
Attribute-based data structures.
Changelog - Issues - Documentation
Why?
I have common use cases where I want to improve python's dict
and list
:
AttrDict
: attribute-baseddict
with better merge and deep value accessAttrList
:list
that broadcasts operations to its members- Environment: reading environment files
- Configuration: loading command-line arguments and configuration files
JSend
: sending JSON responses
Install
python -m pip install attrbox
AttrDict
AttrDict
features:
-
Attribute Syntax for
dict
similar to accessing properties in JavaScript:thing.prop
meansthing["prop"]
for get / set / delete. -
No
KeyError
: if a key is missing, just returnNone
(likedict.get()
). -
Deep Indexing: use a list of keys and
int
to get and set deeply nested values. This is similar to lodash.get except that only the array-like syntax is supported and you must use actualint
to index acrosslist
objects. -
Deep Merge: combine two
dict
objects by extending deeply-nested keys where possible. This is different than the newdict
union operator (PEP 584).
from attrbox import AttrDict
items = AttrDict(a=1, b=[{"c": {"d": 5}}], e={"f": {"g": 7}})
items.a
# => 1
items.x is None
# => True
items.x = 10
items['x']
# => 10
items.get(["b", 0, "c", "d"])
# => 5
items <<= {"e": {"f": {"g": 20, "h": [30, 40]}}}
items.e.f.g
# => 20
items[['e', 'f', 'h', 1]]
# => 40
AttrList
AttrList
provides member broadcast: performing operations on the list performs the operation on all the items in the list. I typically use this to achieve the Composite design pattern.
from attrbox import AttrDict, AttrList
numbers = AttrList([complex(1, 2), complex(3, 4), complex(5, 6)])
numbers.real
# => [1.0, 3.0, 5.0]
words = AttrList(["Apple", "Bat", "Cat"])
words.lower()
# => ['apple', 'bat', 'cat']
items = AttrList([AttrDict(a=1, b=2), AttrDict(a=5)])
items.a
# => [1, 5]
items.b
# => [2, None]
Environment
attrbox.env
is similar to python-dotenv, but uses the AttrDict
ability to do deep indexing to allow for things like dotted variable names. Typically, you'll use it by calling attrbox.load_env()
which will find the nearest .env
file and load it into os.environ
.
Configuration
attrbox
supports loading configuration files from .json
, .toml
, and .env
files. By default, load_config()
looks for a key imports
and will recursively import those files (relative to the current file) before loading the rest of the current file (data is merged using AttrDict
). This allows you to create templates or smaller configurations that build up to a larger configuration.
For CLI applications, attrbox.parse_docopt()
let's you use the power of docopt
with the flexibility of AttrDict
. By default, --config
and <config>
arguments will load the file using the load_config()
"""Usage: prog.py [--help] [--version] [-c CONFIG] --file FILE
Options:
--help show this message and exit
--version show the version number and exit
-c, --config CONFIG load this configuration file (supported: .toml, .json, .env)
--file FILE the file to process
"""
def main():
args = parse_docopt(__doc__, version=__version__)
args.file # has the value of --file
if __name__ == "__main__":
main()
Building on top of docopt
we strip off leading dashes and convert them to underscores so that we can access the arguments as AttrDict
attributes.
Read more about attrbox.config
JSend
JSend
is an approximate implementation of the JSend
specification that makes it easy to create standard JSON responses. The main difference is that I added an ok
attribute to make it easy to tell if there was a problem (fail
or error
).
from attrbox import JSend
def some_function(arg1):
result = JSend() # default is "success"
if not is_good(arg1):
# fail = controlled problem
return result.fail(message="You gone messed up.")
try:
result.success(data=process(arg1))
except Exception:
# error = uncontrolled problem
return result.error(message="We have a problem.")
return result
Because the JSend
object is an AttrDict
, it acts like a dict
in every other respect (e.g., it is JSON-serializable).
License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.