beanbag.namespace¶
The beanbag.namespace module allows defining classes that provide arbitrary namespace behaviour. This is what allows the other beanbag modules to provide their clever syntactic sugar.
A entry in a namespace is identified by two components: a base and a path.
The base is constructed once for a namespace and is common to all entries
in the namespace, and each entry’s path is used to differentiate them. For
example, with AttrDict
, the base is the underlying dictionary
(d
), while the path is the sequence of references into that dictionary
(eg, ("foo", "bar")
corresponding to d["foo"]["bar"]
). The reason
for splitting these apart is mostly efficiency – the path element needs
to be cheap and easy to construct and copy since that may need to happen
for an attribute access.
To define a namespace you provide a class that inherits from
beanbag.namespace.Namespace
and defines the methods the base class
should have. The NamespaceMeta
metaclass then creates a new base
class containing these methods, and builds the namespace class on
top of that base class, mapping Python’s special method names to the
corresponding base class methods, minus the underscores. For example,
to define the behavour of the ~
operator (aka __invert__(self)
),
the Base class defines a method:
def invert(self, path):
...
The code can rely on the base value being self
, and the path being
path
, then do whatever calculation is necessary to create a result. If
that result should be a different entry in the same namespace, that can
be created by invoking self.namespace(newpath)
.
In order to make inplace operations work more smoothly, returning
None
from those options will be automatically treated as returning
the original namespace object (ie self.namespace(path)
, without the
overhead of reconstructing the object). This is primarily to make it easier
to avoid the “double setting” behaviour of python’s inplace operations, ie
where a[i] += j
is converted into:
tmp = a.__getitem__(i) # tmp = a[i]
res = tmp.__iadd__(j) # tmp += j
a.__setitem__(i, res) # a[i] = tmp
In particular, implementations of setitem
and setattr
can avoid
poor behaviour here by testing whether the value being set (res
)
is already the existing value, and performing a no-op if so. The
SettableHierarchialNS
class implements this behaviour.
NamespaceMeta¶
The NamespaceMeta
metaclass provides the magic for creating arbitrary
namespaces from Base classes as discussed above. When set as the metaclass
for a class, it will turn a base class into a namespace class directly,
while constructing an appropriate base class for the namespace to use.
-
class
beanbag.namespace.
NamespaceMeta
¶ -
__invert__
()¶ Obtain base class for namespace
-
__module__
= 'beanbag.namespace'¶
-
static
__new__
(mcls, name, bases, nmspc)¶
-
classmethod
deferfn
(cls, nsdict, basefnname, inum=False, attr=False)¶
-
classmethod
make_namespace
(cls)¶ create a unique Namespace class based on provided class
-
ops
= ['repr', 'str', 'call', 'bool', 'getitem', 'setitem', 'delitem', 'len', 'iter', 'reversed', 'contains', 'enter', 'exit', 'pos', 'neg', 'invert', 'eq', 'ne', 'lt', 'le', 'gt', 'ge', 'add', 'sub', 'mul', 'pow', 'div', 'floordiv', 'lshift', 'rshift', 'and', 'or', 'xor', 'radd', 'rsub', 'rmul', 'rpow', 'rdiv', 'rfloordiv', 'rlshift', 'rrshift', 'rand', 'ror', 'rxor']¶
-
ops_attr
= ['getattr', 'setattr', 'delattr']¶
-
ops_inum
= ['iadd', 'isub', 'imul', 'ipow', 'idiv', 'ifloordiv', 'ilshift', 'irshift', 'iand', 'ior', 'ixor']¶
-
static
wrap_path_fn
(basefn)¶
-
static
wrap_path_fn_attr
(basefn)¶
-
static
wrap_path_fn_inum
(basefn)¶
-
NamespaceBase¶
The generated base class will inherit from NamespaceBase
(or the base class corresponding to any namespaces the namespace class
inherits from), and will have a Namespace
attribute referencing the
namespace class. Further, the generated base class can be accessed by
using the inverse opertor on the namespace class, ie MyNamespaceBase
= ~MyNamespace
.
Namespace¶
Namespace
provides a trivial Base implementation. It’s primarily
useful as a parent class for inheritance, so that you don’t have
explicitly set NamespaceMeta
as your metaclass.
-
class
beanbag.namespace.
Namespace
(*args, **kwargs)¶
HierarchialNS¶
HierarchialNS
provides a simple basis for producing namespaces with
freeform attribute and item hierarchies, eg, where you might have something
like ns.foo.bar["baz"]
.
By default, this class specifies a path as a tuple of attributes, but this
can be changed by overriding the path
and _get
methods. If some
conversion is desired on either attribute or item access, the attr
and item
methods can be overridden respectively.
Otherwise, to get useful behaviour from this class, you probably want to
provide some additional methods, such as __call__
.
-
class
beanbag.namespace.
HierarchialNS
¶ Bases:
beanbag.namespace.Namespace
-
__eq__
(other)¶ self == other
-
__getattr__
(attr)¶ self.attr
-
__getitem__
(item)¶ self[attr]
-
__init__
()¶ x.__init__(…) initializes x; see help(type(x)) for signature
-
__module__
= 'beanbag.namespace'¶
-
__ne__
(other)¶ self != other
-
__repr__
()¶ Human readable representation of object
-
__str__
()¶ Returns path joined by dots
-
SettableHierarchialNS¶
SettableHierarchialNS
is intended to make life slightly easier if you
want to be able to assign to your hierarchial namespace. It provides set
and delete
methods that you can implement, without having to go to the
trouble of implementing both item and attribute variants of both functions.
This class implements the check for “setting to self” mentioned earlier in
order to prevent inplace operations having two effects. It uses the eq
method to test for equality.
-
class
beanbag.namespace.
SettableHierarchialNS
(*args, **kwargs)¶ Bases:
beanbag.namespace.HierarchialNS
-
__delattr__
(attr)¶ del self.attr
-
__delitem__
(item)¶ del self[item]
-
__eq__
(other)¶ self == other
-
__getattr__
(attr)¶ self.attr
-
__getitem__
(item)¶ self[attr]
-
__init__
(*args, **kwargs)¶
-
__module__
= 'beanbag.namespace'¶
-
__ne__
(other)¶ self != other
-
__repr__
()¶ Human readable representation of object
-
__setattr__
(attr, val)¶ self.attr = val
-
__setitem__
(item, val)¶ self[item] = val
-
__str__
()¶ Returns path joined by dots
-
sig_adapt¶
This is a helper function to make that generated methods in the namespace object provide more useful help.
-
beanbag.namespace.
sig_adapt
(sigfn, dropargs=None, name=None)¶ Function decorator that changes the name and (optionally) signature of a function to match another function. This is useful for making the help of generic wrapper functions match the functions they’re wrapping. For example:
def foo(a, b, c, d=None): pass @sig_adapt(foo) def myfn(*args, **kwargs): pass
The optional “name” parameter allows renaming the function to something different to the original function’s name.
The optional “dropargs” parameter allows dropping arguments by position or name. (Note positions are 0 based, so to convert foo(self, a, b) to foo(a, b) specify dropargs=(“self”,) or dropargs=(0,))