Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 35 additions & 65 deletions bindings/pyroot/pythonizations/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ endif()
ROOT_ADD_PYUNITTEST(pyroot_root_module root_module.py)
ROOT_ADD_PYUNITTEST(pyroot_root_no_implicit_cppyy root_no_implicit_cppyy.py)

# @pythonization decorator
ROOT_ADD_PYUNITTEST(pyroot_pyz_decorator pythonization_decorator.py)

# General pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_pretty_printing pretty_printing.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_array_interface array_interface.py PYTHON_DEPS numpy)
Expand All @@ -29,88 +26,64 @@ if(Python3_VERSION VERSION_GREATER_EQUAL 3.9)
ROOT_ADD_PYUNITTEST(uhi_test_suite uhi_test_suite.py GENERIC PYTHON_DEPS uhi numpy)
endif()

# STL containers pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_stl_vector stl_vector.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_stl_set stl_set.py)

# TObject and subclasses pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tobject_contains tobject_contains.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tobject_comparisonops tobject_comparisonops.py)

# TClass pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tclass_dynamiccast tclass_dynamiccast.py)
# STL containers pythonizations (std::vector and std::set)
ROOT_ADD_PYUNITTEST(pyroot_pyz_stl stl.py)

# TContext pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tcontext_contextmanager tcontext_contextmanager.py)
# TObject and subclasses pythonizations (__contains__ and comparison operators)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tobject tobject.py)

# TDirectory and subclasses pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tdirectory_attrsyntax tdirectory_attrsyntax.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tdirectoryfile_attrsyntax_get tdirectoryfile_attrsyntax_get.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tfile_attrsyntax_get_writeobject_open tfile_attrsyntax_get_writeobject_open.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tfile_constructor tfile_constructor.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tfile_context_manager tfile_context_manager.py)
# TDirectory and TFile pythonizations (attr/item syntax, Get, WriteObject, Open,
# constructor and context manager)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tdirectory_tfile tdirectory_tfile.py)

# TTree and subclasses pythonizations
# TTree and subclasses pythonizations (branch attr access, iteration and
# SetBranchAddress). ttree_branch stays separate: it declares its own MyStruct,
# which would clash with the TreeHelper.h definition used by the others.
file(COPY TreeHelper.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
ROOT_ADD_PYUNITTEST(pyroot_pyz_ttree_branch_attr ttree_branch_attr.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_ttree_iterable ttree_iterable.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_ttree_setbranchaddress ttree_setbranchaddress.py PYTHON_DEPS numpy)
ROOT_ADD_PYUNITTEST(pyroot_pyz_ttree ttree.py PYTHON_DEPS numpy)
ROOT_ADD_PYUNITTEST(pyroot_pyz_ttree_branch ttree_branch.py PYTHON_DEPS numpy)

# TColor-related pythonizations
# TColor-related pythonizations (regression_20018 lives in tcolor.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tcolor tcolor.py)
ROOT_ADD_PYUNITTEST(regression_20018 regression_20018.py)

# TH1 and subclasses pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_th1 th1.py)
# The above tests a deadlock. It should complete in about 1s. If we don't reduce the timeout, we need to wait 1500 s.
set_tests_properties(pyunittests-bindings-pyroot-pythonizations-pyroot-pyz-th1 PROPERTIES TIMEOUT 30)
ROOT_ADD_PYUNITTEST(pyroot_pyz_th1_fillN th1_fillN.py PYTHON_DEPS numpy)
ROOT_ADD_PYUNITTEST(pyroot_pyz_th1_addfunction th1_addfunction.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_th2_fillN th2_fillN.py PYTHON_DEPS numpy)
ROOT_ADD_PYUNITTEST(pyroot_pyz_th2 th2.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_th3 th3.py)
# th1_addfunction, th2 and th3 merged into thist.py
ROOT_ADD_PYUNITTEST(pyroot_pyz_thist thist.py)

# TGraph, TGraph2D and error subclasses pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tgraph_getters tgraph_getters.py)
# TCollection and subclasses pythonizations (len, list methods, operators, iteration)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tcollection tcollection.py)

# TCollection and subclasses pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tcollection_len tcollection_len.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tcollection_listmethods tcollection_listmethods.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tcollection_operators tcollection_operators.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tcollection_iterable tcollection_iterable.py)
# TSeqCollection and subclasses pythonizations (item access and list methods)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tseqcollection tseqcollection.py)

# TSeqCollection and subclasses pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tseqcollection_itemaccess tseqcollection_itemaccess.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tseqcollection_listmethods tseqcollection_listmethods.py)
# TArray and subclasses pythonizations (len and item access)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tarray tarray.py)

# TIter pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_titer_iterator titer_iterator.py)
# TVectorT pythonizations (len and item access)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tvectort tvectort.py)

# TArray and subclasses pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tarray_len tarray_len.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tarray_getitem tarray_getitem.py)
# TVector3 pythonizations (len and item access)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tvector3 tvector3.py)

# TVectorT pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tvectort_len tvectort_len.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tvectort_getitem tvectort_getitem.py)
# TString pythonizations (len, str/repr, comparison operators and converter)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tstring tstring.py)

# TVector3 pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tvector3_len tvector3_len.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tvector3_getitem tvector3_getitem.py)
# TObjString pythonizations (len, str/repr and comparison operators)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tobjstring tobjstring.py)

# TString pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tstring_len tstring_len.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tstring_str_repr tstring_str_repr.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tstring_comparisonops tstring_comparisonops.py)

# TString converter
ROOT_ADD_PYUNITTEST(pyroot_conv_tstring tstring_converter.py)
# @pythonization decorator (kept standalone: it inspects the global set of
# pythonized classes, so it must not share a process with other tests)
ROOT_ADD_PYUNITTEST(pyroot_pyz_decorator pythonization_decorator.py)

# TObjString pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_tobjstring_len tobjstring_len.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tobjstring_str_repr tobjstring_str_repr.py)
ROOT_ADD_PYUNITTEST(pyroot_pyz_tobjstring_comparisonops tobjstring_comparisonops.py)
# Miscellaneous small pythonizations grouped in a single file to avoid paying the
# Python-startup + import-ROOT overhead once per tiny test: TClass::DynamicCast,
# TContext context manager, TComplex operators, TIter iteration and TGraph getters.
ROOT_ADD_PYUNITTEST(pyroot_pyz_misc misc_pyz.py)

# RVec and subclasses pythonizations
ROOT_ADD_PYUNITTEST(pyroot_pyz_rvec rvec.py)
Expand Down Expand Up @@ -187,9 +160,6 @@ if (dataframe)
endif()
endif()

# TComplex pythonizations
ROOT_ADD_PYUNITTEST(pyroot_tcomplex tcomplex_operators.py)

# Tests with memory usage
ROOT_ADD_PYUNITTEST(pyroot_memory memory.py)

Expand Down
4 changes: 4 additions & 0 deletions bindings/pyroot/pythonizations/test/TreeHelper.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#ifndef PYROOT_TEST_TREEHELPER_H
#define PYROOT_TEST_TREEHELPER_H

// Helper struct for this test
struct MyStruct {
Expand Down Expand Up @@ -120,3 +122,5 @@ class MyTree : public TTree {
}
};
}

#endif // PYROOT_TEST_TREEHELPER_H
Original file line number Diff line number Diff line change
@@ -1,7 +1,185 @@
import unittest
import array
import os
import unittest

import ROOT
from ROOT import TClass, TComplex, TDirectory, TObject, TObjString


class TClassDynamicCast(unittest.TestCase):
"""
Test for the pythonization of TClass::DynamicCast, which adds an
an extra cast before returning the Python proxy to the user so that
it has the right type.
"""

# Tests
def test_dynamiccast(self):
tobj_class = TClass.GetClass("TObject")
tobjstr_class = TClass.GetClass("TObjString")

o = TObjString("a")

# Upcast: TObject <- TObjString
o_upcast = tobjstr_class.DynamicCast(tobj_class, o)
self.assertEqual(type(o_upcast), TObject)

# Downcast: TObject -> TObjString
o_downcast = tobjstr_class.DynamicCast(tobj_class, o_upcast, False)
self.assertEqual(type(o_downcast), TObjString)


class TContextContextManager(unittest.TestCase):
"""
Test of TContext used as context manager
"""

def default_constructor(self):
"""
Check status of gDirectory with default constructor.
"""
filename = "TContextContextManager_test_default_constructor.root"
self.assertEqual(ROOT.gDirectory, ROOT.gROOT)

with TDirectory.TContext():
# Create a file to change gDirectory
testfile = ROOT.TFile(filename, "recreate")
self.assertEqual(ROOT.gDirectory, testfile)
testfile.Close()

self.assertEqual(ROOT.gDirectory, ROOT.gROOT)
os.remove(filename)

def constructor_onearg(self):
"""
Check status of gDirectory with constructor taking a new directory.
"""
filenames = ["TContextContextManager_test_constructor_onearg_{}.root".format(i) for i in range(2)]

file0 = ROOT.TFile(filenames[0], "recreate")
file1 = ROOT.TFile(filenames[1], "recreate")
self.assertEqual(ROOT.gDirectory, file1)

with TDirectory.TContext(file0):
self.assertEqual(ROOT.gDirectory, file0)

self.assertEqual(ROOT.gDirectory, file1)
file0.Close()
file1.Close()
for filename in filenames:
os.remove(filename)

def constructor_twoargs(self):
"""
Check status of gDirectory with constructor taking the previous directory and a new one.
"""
filenames = ["TContextContextManager_test_constructor_onearg_{}.root".format(i) for i in range(3)]

file0 = ROOT.TFile(filenames[0], "recreate")
file1 = ROOT.TFile(filenames[1], "recreate")
file2 = ROOT.TFile(filenames[2], "recreate")
self.assertEqual(ROOT.gDirectory, file2)

with TDirectory.TContext(file0, file1):
self.assertEqual(ROOT.gDirectory, file1)

self.assertEqual(ROOT.gDirectory, file0)
file0.Close()
file1.Close()
file2.Close()
for filename in filenames:
os.remove(filename)

def test_all(self):
"""
Run all tests of this class sequentially.
The tests of this class rely on the current directory, which can be changed
unpredictably if they are run concurrently.
"""
self.default_constructor()
self.constructor_onearg()
self.constructor_twoargs()


class TestTComplexOperators(unittest.TestCase):
"""
Test for the operators of TComplex:
__radd__, __rsub__, __rmul__, __rtruediv__/__rdiv__.
"""

c = TComplex(4.,0)

d = 2.

s = 'string'

# check the expected result for d + c and that Re(c + d) == Re(d + c)
def test_radd(self):
self.assertEqual((self.d + self.c).Re(), 6.0)
self.assertEqual((self.c + self.d).Re(), (self.d + self.c).Re())

# check the expected result for d - c and that Re(c - d) == -Re(d - c)
def test_rsub(self):
self.assertEqual((self.d - self.c).Re(), -2.0)
self.assertEqual((self.c - self.d).Re(), -((self.d - self.c).Re()))

# check the expected result for d * c and that Re(c * d) == Re(d * c)
def test_rmul(self):
self.assertEqual((self.d * self.c).Re(), 8.0)
self.assertEqual((self.c * self.d).Re(), (self.d * self.c).Re())

# check the expected result for d / c
def test_rdiv(self):
self.assertEqual((self.d / self.c).Re(), 0.5)
with self.assertRaises(TypeError):
self.s / self.c


class TIterIterator(unittest.TestCase):
"""
Test for the pythonization that allows instances of TIter to
behave as Python iterators.
"""

num_elems = 3

# Helpers
def create_tcollection(self):
c = ROOT.TList()
for _ in range(self.num_elems):
o = ROOT.TObject()
# Prevent immediate deletion of C++ TObjects
ROOT.SetOwnership(o, False)
c.Add(o)

return c

# Tests
def test_iterable(self):
# Check that TIter instances are iterable
c = self.create_tcollection()

itc = ROOT.TIter(c)
# An iterator of an iterator is itself
self.assertEqual(itc, iter(itc))

def test_iterator(self):
# Check that TIter instances are iterators
c = self.create_tcollection()

itc1 = ROOT.TIter(c)
itc2 = ROOT.TIter(c)
for _ in range(c.GetEntries()):
self.assertIs(next(itc1), itc2.Next())

def test_for_loop_syntax(self):
# Somehow redundant, but good to test with real syntax
c = self.create_tcollection()

itc1 = ROOT.TIter(c)
itc2 = ROOT.TIter(c)
for elem1, elem2 in zip(itc1, itc2):
self.assertIs(elem1, elem2)


class TGraphGetters(unittest.TestCase):
Expand Down
45 changes: 0 additions & 45 deletions bindings/pyroot/pythonizations/test/regression_20018.py

This file was deleted.

Loading
Loading