Install
pip install grainy
Usage example
from grainy.core import PermissionSet
from grainy.const import *
pset = PermissionSet(
{
"a" : PERM_READ,
"a.b" : PERM_RW,
"a.b.c" : PERM_DENY,
"b" : PERM_READ,
"b.*.a" : PERM_RW
}
)
pset.check("a", PERM_READ) # True
pset.check("a.b", PERM_READ) # True
pset.check("a.b", PERM_WRITE) # True
pset.check("a.b.c", PERM_READ) # False
pset.check("a.b.c", PERM_WRITE) # False
pset.check("a.x", PERM_READ) # True
pset.check("b.a.a", PERM_RW) # True
pset.check("b.b.a", PERM_RW) # True
pset.check("b.b.b", PERM_RW) # False
pset.check("a", PERM_READ, explicit=True) # True
pset.check("a.b", PERM_READ, explicit=True) # True
pset.check("a.c", PERM_READ, explicit=True) # False
pset.check("a.?.c", PERM_READ) # False
pset.check("b.?.a", PERM_RW) # True
pset.check("a.?", PERM_RW) # True
Setting and Deleting
pset["a.b"] = const.PERM_READ
del pset["a.b"]
pset.update(
{
"a.b" : const.PERM_READ
}
)
assert "a.b" in pset
Applying to data
You can apply the permissions stored in the permission set to any data dict and data that the permission set does not have READ access to will be removed.
grainy was created out of a need to apply granular permissions on potentially large dict objects and perform well.
# init
pset = core.PermissionSet(
{
"a" : const.PERM_READ,
"a.b.c" : const.PERM_RW,
"a.b.e" : const.PERM_DENY,
"a.b.*.d" : const.PERM_DENY,
"f.g" : const.PERM_READ
}
)
# original data
data = {
"a" : {
"b" : {
"c" : {
"A" : True
},
"d" : {
"A" : True
},
"e" : {
"A" : False
}
}
},
"f": {
"a" : False,
"g" : True
}
}
# expected data after permissions are appied
expected = {
"a" : {
"b" : {
"c" : {
"A" : True
},
"d" : {
"A" : True
}
}
},
"f": {
"g" : True
}
}
rv = pset.apply(data)
assert rv == expected
As of version 1.2 it is also possible to apply permissions to lists using namespace handlers
pset = core.PermissionSet({
"a.b" : const.PERM_READ,
"x" : const.PERM_READ,
"x.z" : const.PERM_DENY,
"nested.*.data.public" : const.PERM_READ
})
data= {
"a" : [
{ "id" : "b" },
{ "id" : "c" }
],
"x" : [
{ "custom" : "y" },
{ "custom" : "z" }
],
"nested" : [
{
"data" : [
{
"level" : "public",
"some" : "data"
},
{
"level" : "private",
"sekret" : "data"
}
]
}
]
}
expected = {
"a" : [
{ "id" : "b" }
],
"nested" : [
{
"data" : [
{ "level" : "public", "some" : "data" }
]
}
],
"x" : [
{ "custom" : "y" }
]
}
applicator = core.Applicator()
applicator.handle("x", key=lambda row,idx: row["custom"])
applicator.handle("nested.*.data", key=lambda row,idx: row["level"])
rv = pset.apply(data, applicator=applicator)
assert rv == expected