Source code for rootpy.tree.treetypes

"""
Wrappers for basic types that are compatible with ROOT TTrees
"""
from __future__ import absolute_import

import itertools
from array import array
import sys
if sys.version_info[0] >= 3:
    long = int

from ..extern.six.moves import range
from .. import register

# only list Column subclasses here
__all__ = [
    'ObjectCol',
    'BoolCol',
    'BoolArrayCol',
    'CharCol',
    'CharArrayCol',
    'UCharCol',
    'UCharArrayCol',
    'ShortCol',
    'ShortArrayCol',
    'UShortCol',
    'UShortArrayCol',
    'IntCol',
    'IntArrayCol',
    'UIntCol',
    'UIntArrayCol',
    'LongCol',
    'LongArrayCol',
    'ULongCol',
    'ULongArrayCol',
    'FloatCol',
    'FloatArrayCol',
    'DoubleCol',
    'DoubleArrayCol',
]


class Column(object):
    _counter = itertools.count()

    def __init__(self, *args, **kwargs):
        self.idx = next(Column._counter)
        self.args = args
        self.kwargs = kwargs

    def __call__(self):
        return self.type(*self.args, **self.kwargs)

    def __repr__(self):
        arg_params = ', '.join([str(a) for a in self.args])
        kwd_params = ', '.join(['{0}={1}'.format(name, value)
                                for name, value in self.kwargs.items()])
        params = []
        if arg_params:
            params.append(arg_params)
        if kwd_params:
            params.append(kwd_params)
        return "{0}({1})".format(
            self.__class__.__name__, ', '.join(params))

    def __str__(self):
        return repr(self)


[docs]class ObjectCol(Column): def __init__(self, cls, *args, **kwargs): self.type = cls Column.__init__(self, *args, **kwargs)
class Scalar(object): def clear(self): """Supplied to match the interface of ROOT.vector""" self.reset() class BaseScalar(Scalar, array): """This is the base class for all variables""" def __init__(self, resetable=True): array.__init__(self) self.resetable = resetable def reset(self): """Reset the value to the default""" if self.resetable: self[0] = self.default @property def value(self): """The current value""" return self[0] def set(self, value): """Set the value""" if isinstance(value, BaseScalar): self[0] = self.convert(value.value) else: self[0] = self.convert(value) def __str__(self): return self.__repr__() def __repr__(self): return "{0}({1}) at {2}".format( self.__class__.__name__, repr(self.value), hex(id(self))) def __getitem__(self, i): return array.__getitem__(self, 0) def __setitem__(self, i, value): if isinstance(value, BaseScalar): array.__setitem__(self, 0, value.value) else: array.__setitem__(self, 0, value) def __lt__(self, value): if isinstance(value, BaseScalar): return self.value < value.value return self.value < value def __le__(self, value): if isinstance(value, BaseScalar): return self.value <= value.value return self.value <= value def __eq__(self, value): if isinstance(value, BaseScalar): return self.value == value.value return self.value == value def __ne__(self, value): if isinstance(value, BaseScalar): return self.value != value.value return self.value != value def __gt__(self, value): if isinstance(value, BaseScalar): return self.value > value.value return self.value > value def __ge__(self, value): if isinstance(value, BaseScalar): return self.value >= value.value return self.value >= value def __nonzero__(self): return self.value != 0 __bool__ = __nonzero__ def __add__(self, other): if isinstance(other, BaseScalar): return self.value + other.value return self.value + other def __radd__(self, other): return self + other def __sub__(self, other): if isinstance(other, BaseScalar): return self.value - other.value return self.value - other def __rsub__(self, other): return other - self.value def __mul__(self, other): if isinstance(other, BaseScalar): return self.value * other.value return self.value * other def __rmul__(self, other): return self * other def __div__(self, other): if isinstance(other, BaseScalar): return self.value / other.value return self.value / other def __rdiv__(self, other): return other / self.value class Array(object): def __init__(self, resetable=True, length_name=None): self.resetable = resetable self.length_name = length_name def clear(self): """Supplied to match the interface of ROOT.vector""" self.reset() class BaseArray(Array, array): """This is the base class for all array variables""" def __init__(self, **kwargs): array.__init__(self) Array.__init__(self, **kwargs) def reset(self): """Reset the value to the default""" if self.resetable: for i in range(len(self)): self[i] = self.default def set(self, other): for i, thing in enumerate(other): self[i] = self.convert(thing) for i in range(i + 1, len(self)): self[i] = self.default def __str__(self): return self.__repr__() def __repr__(self): return "{0}[{1}] at {2}".format( self.__class__.__name__, ', '.join(map(str, self)), hex(id(self))) class BaseChar(object): @property def value(self): return str(self.rstrip(b'\0').decode('ascii')) def __str__(self): return self.value def __repr__(self): return "{0}[{1}] at {2}".format( self.__class__.__name__, repr(str(self)), hex(id(self))) class BaseCharScalar(BaseChar, Scalar, bytearray): """This is the base class for all char variables""" def __init__(self, resetable=True): bytearray.__init__(self, 2) self.resetable = resetable def reset(self): """Reset the value to the default""" if self.resetable: # reset to null bytes self[0] = 0 def set(self, other): self[0] = other class BaseCharArray(BaseChar, Array, bytearray): """This is the base class for all char array variables""" def __init__(self, length, **kwargs): if not isinstance(length, int): raise TypeError("char array length must be an int") if length < 2: raise ValueError( "char array length must be at least 2 " "to include null-termination") bytearray.__init__(self, length) Array.__init__(self, **kwargs) def reset(self): """Reset the value to the default""" if self.resetable: # reset to null bytes self[:] = bytearray(len(self)) def set(self, other): # leave the null-termination untouched if len(other) >= len(self): raise ValueError( "string of length {0:d} is too long to " "fit in array of length {1:d} with null-termination".format( len(other), len(self))) self[:len(other)] = other @register(names=('B', 'Bool_t'), builtin=True) class Bool(BaseScalar): """ This is a variable containing a Boolean type """ # The ROOT character representation of the Boolean type type = 'O' typename = 'Bool_t' def __new__(cls, default=False, **kwargs): return BaseScalar.__new__(cls, 'B', [Bool.convert(default)]) def __init__(self, default=False, **kwargs): BaseScalar.__init__(self, **kwargs) self.default = Bool.convert(default) @classmethod def convert(cls, value): return int(bool(value))
[docs]class BoolCol(Column): type = Bool
@register(names=('B[]', 'Bool_t[]'), builtin=True) class BoolArray(BaseArray): """ This is an array of Booleans """ # The ROOT character representation of the Boolean type type = 'O' typename = 'Bool_t' convert = Bool.convert def __new__(cls, length, default=False, **kwargs): return BaseArray.__new__( cls, 'B', [Bool.convert(default)] * length) def __init__(self, length, default=False, **kwargs): BaseArray.__init__(self, **kwargs) self.default = Bool.convert(default)
[docs]class BoolArrayCol(Column): type = BoolArray
@register(names=('C', 'Char_t'), builtin=True) class Char(BaseCharScalar): """ This is a variable containing a character type """ # The ROOT character representation of the char type type = 'C' typename = 'Char_t'
[docs]class CharCol(Column): type = Char
@register(names=('C[]', 'Char_t[]'), builtin=True) class CharArray(BaseCharArray): """ This is an array of characters """ # The ROOT character representation of the char type type = 'C' typename = 'Char_t' scalar = Char
[docs]class CharArrayCol(Column): type = CharArray
@register(names=('UC', 'UChar_t'), builtin=True) class UChar(BaseCharScalar): """ This is a variable containing an unsigned character type """ # The ROOT character representation of the unsigned char type type = 'c' typename = 'UChar_t'
[docs]class UCharCol(Column): type = UChar
@register(names=('UC[]', 'UChar_t[]'), builtin=True) class UCharArray(BaseCharArray): """ This is an array of unsigned characters """ # The ROOT character representation of the unsigned char type type = 'c' typename = 'UChar_t' scalar = UChar
[docs]class UCharArrayCol(Column): type = UCharArray
@register(names=('S', 'Short_t'), builtin=True) class Short(BaseScalar): """ This is a variable containing an integer """ # The ROOT character representation of the short type type = 'S' typename = 'Short_t' def __new__(cls, default=0, **kwargs): return BaseScalar.__new__(cls, 'h', [Short.convert(default)]) def __init__(self, default=0, **kwargs): BaseScalar.__init__(self, **kwargs) self.default = Short.convert(default) @classmethod def convert(cls, value): return int(value)
[docs]class ShortCol(Column): type = Short
@register(names=('S[]', 'Short_t[]'), builtin=True) class ShortArray(BaseArray): """ This is an array of integers """ # The ROOT character representation of the short type type = 'S' typename = 'Short_t' convert = Short.convert def __new__(cls, length, default=0, **kwargs): return BaseArray.__new__( cls, 'h', [Short.convert(default)] * length) def __init__(self, length, default=0, **kwargs): BaseArray.__init__(self, **kwargs) self.default = Short.convert(default)
[docs]class ShortArrayCol(Column): type = ShortArray
@register(names=('US', 'UShort_t'), builtin=True) class UShort(BaseScalar): """ This is a variable containing a short """ # The ROOT character representation of the unsigned short type type = 's' typename = 'UShort_t' def __new__(cls, default=0, **kwargs): return BaseScalar.__new__(cls, 'H', [UShort.convert(default)]) def __init__(self, default=0, **kwargs): BaseScalar.__init__(self, **kwargs) self.default = UShort.convert(default) @classmethod def convert(cls, value): if value < 0: raise ValueError( "Assigning negative value ({0:d}) " "to unsigned type".format(value)) return int(value)
[docs]class UShortCol(Column): type = UShort
@register(names=('US[]', 'UShort_t[]'), builtin=True) class UShortArray(BaseArray): """ This is an array of unsigned shorts """ # The ROOT character representation of the unsigned short type type = 's' typename = 'UShort_t' convert = UShort.convert def __new__(cls, length, default=0, **kwargs): return BaseArray.__new__( cls, 'H', [UShort.convert(default)] * length) def __init__(self, length, default=0, **kwargs): BaseArray.__init__(self, **kwargs) self.default = UShort.convert(default)
[docs]class UShortArrayCol(Column): type = UShortArray
@register(names=('I', 'Int_t'), builtin=True) class Int(BaseScalar): """ This is a variable containing an integer """ # The ROOT character representation of the integer type type = 'I' typename = 'Int_t' def __new__(cls, default=0, **kwargs): return BaseScalar.__new__(cls, 'i', [Int.convert(default)]) def __init__(self, default=0, **kwargs): BaseScalar.__init__(self, **kwargs) self.default = Int.convert(default) @classmethod def convert(cls, value): return int(value)
[docs]class IntCol(Column): type = Int
@register(names=('I[]', 'Int_t[]'), builtin=True) class IntArray(BaseArray): """ This is an array of integers """ # The ROOT character representation of the integer type type = 'I' typename = 'Int_t' convert = Int.convert def __new__(cls, length, default=0, **kwargs): return BaseArray.__new__( cls, 'i', [Int.convert(default)] * length) def __init__(self, length, default=0, **kwargs): BaseArray.__init__(self, **kwargs) self.default = Int.convert(default)
[docs]class IntArrayCol(Column): type = IntArray
@register(names=('UI', 'UInt_t'), builtin=True) class UInt(BaseScalar): """ This is a variable containing an unsigned integer """ # The ROOT character representation of the unsigned integer type type = 'i' typename = 'UInt_t' def __new__(cls, default=0, **kwargs): return BaseScalar.__new__(cls, 'I', [UInt.convert(default)]) def __init__(self, default=0, **kwargs): BaseScalar.__init__(self, **kwargs) self.default = UInt.convert(default) @classmethod def convert(cls, value): if value < 0: raise ValueError( "Assigning negative value ({0:d}) " "to unsigned type".format(value)) return long(value)
[docs]class UIntCol(Column): type = UInt
@register(names=('UI[]', 'UInt_t[]'), builtin=True) class UIntArray(BaseArray): """ This is an array of unsigned integers """ # The ROOT character representation of the unsigned integer type type = 'i' typename = 'UInt_t' convert = UInt.convert def __new__(cls, length, default=0, **kwargs): return BaseArray.__new__( cls, 'I', [UInt.convert(default)] * length) def __init__(self, length, default=0, **kwargs): BaseArray.__init__(self, **kwargs) self.default = UInt.convert(default)
[docs]class UIntArrayCol(Column): type = UIntArray
@register(names=('L', 'Long64_t'), builtin=True) class Long(BaseScalar): """ This is a variable containing a long """ # The ROOT character representation of the long type type = 'L' typename = 'Long64_t' def __new__(cls, default=0, **kwargs): return BaseScalar.__new__(cls, 'l', [Long.convert(default)]) def __init__(self, default=0, **kwargs): BaseScalar.__init__(self, **kwargs) self.default = Long.convert(default) @classmethod def convert(cls, value): return long(value)
[docs]class LongCol(Column): type = Long
@register(names=('L[]', 'Long64_t[]'), builtin=True) class LongArray(BaseArray): """ This is an array of longs """ # The ROOT character representation of the long type type = 'L' typename = 'Long64_t' convert = Long.convert def __new__(cls, length, default=0, **kwargs): return BaseArray.__new__( cls, 'l', [Long.convert(default)] * length) def __init__(self, length, default=0, **kwargs): BaseArray.__init__(self, **kwargs) self.default = Long.convert(default)
[docs]class LongArrayCol(Column): type = LongArray
@register(names=('UL', 'ULong64_t'), builtin=True) class ULong(BaseScalar): """ This is a variable containing an unsigned long """ # The ROOT character representation of the long type type = 'l' typename = 'ULong64_t' def __new__(cls, default=0, **kwargs): return BaseScalar.__new__(cls, 'L', [ULong.convert(default)]) def __init__(self, default=0, **kwargs): BaseScalar.__init__(self, **kwargs) self.default = ULong.convert(default) @classmethod def convert(cls, value): if value < 0: raise ValueError( "Assigning negative value ({0:d}) " "to unsigned type".format(value)) return long(value)
[docs]class ULongCol(Column): type = ULong
@register(names=('UL[]', 'ULong64_t[]'), builtin=True) class ULongArray(BaseArray): """ This is of unsigned longs """ # The ROOT character representation of the long type type = 'l' typename = 'ULong64_t' convert = ULong.convert def __new__(cls, length, default=0, **kwargs): return BaseArray.__new__( cls, 'L', [ULong.convert(default)] * length) def __init__(self, length, default=0, **kwargs): BaseArray.__init__(self, **kwargs) self.default = ULong.convert(default)
[docs]class ULongArrayCol(Column): type = ULongArray
@register(names=('F', 'Float_t'), builtin=True) class Float(BaseScalar): """ This is a variable containing a float """ # The ROOT character representation of the float type type = 'F' typename = 'Float_t' def __new__(cls, default=0., **kwargs): return BaseScalar.__new__(cls, 'f', [Float.convert(default)]) def __init__(self, default=0., **kwargs): BaseScalar.__init__(self, **kwargs) self.default = Float.convert(default) @classmethod def convert(cls, value): return float(value)
[docs]class FloatCol(Column): type = Float
@register(names=('F[]', 'Float_t[]'), builtin=True) class FloatArray(BaseArray): """ This is an array of floats """ # The ROOT character representation of the float type type = 'F' typename = 'Float_t' convert = Float.convert def __new__(cls, length, default=0., **kwargs): return BaseArray.__new__( cls, 'f', [Float.convert(default)] * length) def __init__(self, length, default=0., **kwargs): BaseArray.__init__(self, **kwargs) self.default = Float.convert(default)
[docs]class FloatArrayCol(Column): type = FloatArray
@register(names=('D', 'Double_t'), builtin=True) class Double(BaseScalar): """ This is a variable containing a double """ # The ROOT character representation of the double type type = 'D' typename = 'Double_t' def __new__(cls, default=0., **kwargs): return BaseScalar.__new__(cls, 'd', [Double.convert(default)]) def __init__(self, default=0., **kwargs): BaseScalar.__init__(self, **kwargs) self.default = Double.convert(default) @classmethod def convert(cls, value): return float(value)
[docs]class DoubleCol(Column): type = Double
@register(names=('D[]', 'Double_t[]'), builtin=True) class DoubleArray(BaseArray): """ This is an array of doubles """ # The ROOT character representation of the double type type = 'D' typename = 'Double_t' convert = Double.convert def __new__(cls, length, default=0., **kwargs): return BaseArray.__new__( cls, 'd', [Double.convert(default)] * length) def __init__(self, length, default=0., **kwargs): BaseArray.__init__(self, **kwargs) self.default = Double.convert(default)
[docs]class DoubleArrayCol(Column): type = DoubleArray
# ROOT type codes: root_type_codes = '''\ O a boolean (Bool_t) (see note 1) B an 8 bit signed integer (Char_t) b an 8 bit unsigned integer (UChar_t) S a 16 bit signed integer (Short_t) s a 16 bit unsigned integer (UShort_t) I a 32 bit signed integer (Int_t) i a 32 bit unsigned integer (UInt_t) L a 64 bit signed integer (Long64_t) l a 64 bit unsigned integer (ULong64_t) F a 32 bit floating point (Float_t) D a 64 bit floating point (Double_t)\ ''' root_type_codes = [line.split()[0] for line in root_type_codes.split('\n')] # ROOT type names: root_type_names = '''\ Bool_t Char_t UChar_t Short_t UShort_t Int_t UInt_t Long64_t ULong64_t Float_t Double_t\ ''' root_type_names = [line.split()[0] for line in root_type_names.split('\n')] # Python array: python_codes = '''\ B unsigned char int 1 (used as boolean) b signed char int 1 B unsigned char int 1 h signed short int 2 H unsigned short int 2 i signed int int 2 I unsigned int long 2 l signed long int 4 L unsigned long long 4 f float float 4 d double float 8\ ''' python_codes = [line.split()[0] for line in python_codes.split('\n')] # Python NumPy array: numpy_codes = '''\ b Boolean i1 Char u1 Unsigned Char i2 Short Integer u2 Unsigned Short integer i4 Integer u4 Unsigned integer i8 Long Integer u8 Unsigned Long integer f4 Floating point f8 Double Floating point\ ''' numpy_codes = [line.split()[0] for line in numpy_codes.split('\n')] def convert(origin, target, type): """ convert type from origin to target origin/target must be ROOTCODE, ROOTNAME, ARRAY, or NUMPY """ _origin = origin.upper() if _origin == 'ROOTCODE': _origin = root_type_codes elif _origin == 'ROOTNAME': _origin = root_type_names elif _origin == 'ARRAY': _origin = python_codes elif _origin == 'NUMPY': _origin = numpy_codes else: raise ValueError("{0} is not a valid type".format(origin)) _target = target.upper() if _target == 'ROOTCODE': _target = root_type_codes elif _target == 'ROOTNAME': _target = root_type_names elif _target == 'ARRAY': _target = python_codes elif _target == 'NUMPY': _target = numpy_codes else: raise ValueError("{0} is not a valid type".format(target)) if type not in _origin: raise ValueError("{0} is not a valid {1} type".format(type, origin)) return _target[_origin.index(type)]