Skip to content

Commit 8d65248

Browse files
committed
[JupyROOT] Add tests for TColor metadata preservation fix
Add notebook test and unit test to verify that TColor.__init__ metadata is preserved after pythonization. This ensures that introspection-heavy environments like Jupyter can properly inspect the method. - Add tcolor_definedcolors.ipynb: reproduces original issue #20018 - Add test_tcolor_metadata.py: unit tests for metadata preservation - Update CMakeLists.txt: register notebook test in test suite Fixes #20018
1 parent f184be5 commit 8d65248

File tree

3 files changed

+208
-1
lines changed

3 files changed

+208
-1
lines changed

roottest/python/JupyROOT/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ set(NOTEBOOKS importROOT.ipynb
1515
simpleCppMagic.ipynb
1616
thread_local.ipynb
1717
ROOT_kernel.ipynb
18-
tpython.ipynb)
18+
tpython.ipynb
19+
tcolor_definedcolors.ipynb)
1920

2021
# Test all modules with doctest. All new tests will be automatically picked up
2122
file(GLOB pyfiles ${MODULES_LOCATION}/*.py)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "b8ef0e09",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"import ROOT"
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": null,
16+
"id": "ac871508",
17+
"metadata": {},
18+
"outputs": [],
19+
"source": [
20+
"ROOT.TColor.DefinedColors(1)"
21+
]
22+
},
23+
{
24+
"cell_type": "code",
25+
"execution_count": null,
26+
"id": "4800d2c7",
27+
"metadata": {},
28+
"outputs": [],
29+
"source": [
30+
"c = ROOT.TCanvas(\"c\", \"Basic ROOT Plot\", 800, 600)"
31+
]
32+
},
33+
{
34+
"cell_type": "code",
35+
"execution_count": null,
36+
"id": "f3900d8a",
37+
"metadata": {},
38+
"outputs": [],
39+
"source": [
40+
"h = ROOT.TH1F(\"h\", \"Example Histogram;X axis;Entries\", 100, 0, 10)"
41+
]
42+
},
43+
{
44+
"cell_type": "code",
45+
"execution_count": null,
46+
"id": "d83cc9da",
47+
"metadata": {},
48+
"outputs": [],
49+
"source": [
50+
"for _ in range(10000):\n",
51+
" h.Fill(ROOT.gRandom.Gaus(5, 1))"
52+
]
53+
},
54+
{
55+
"cell_type": "code",
56+
"execution_count": null,
57+
"id": "1df7d032",
58+
"metadata": {},
59+
"outputs": [],
60+
"source": [
61+
"h.Draw()"
62+
]
63+
},
64+
{
65+
"cell_type": "code",
66+
"execution_count": null,
67+
"id": "3743fddc",
68+
"metadata": {},
69+
"outputs": [],
70+
"source": [
71+
"c.Draw()"
72+
]
73+
}
74+
],
75+
"metadata": {
76+
"kernelspec": {
77+
"display_name": "Python 3",
78+
"language": "python",
79+
"name": "python3"
80+
},
81+
"language_info": {
82+
"codemirror_mode": {
83+
"name": "ipython",
84+
"version": 3
85+
},
86+
"file_extension": ".py",
87+
"mimetype": "text/x-python",
88+
"name": "python",
89+
"nbconvert_exporter": "python",
90+
"pygments_lexer": "ipython3"
91+
}
92+
},
93+
"nbformat": 4,
94+
"nbformat_minor": 5
95+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Test script to verify that TColor.DefinedColors works correctly in Jupyter-like environments.
4+
This test verifies the fix for issue #20018.
5+
"""
6+
import sys
7+
8+
9+
def test_tcolor_metadata_preservation():
10+
"""
11+
Test that TColor.__init__ preserves metadata after pythonization.
12+
This ensures that introspection-heavy environments like Jupyter can
13+
properly inspect the method.
14+
"""
15+
import ROOT
16+
17+
# Check that __init__ has the expected attributes from functools.wraps
18+
assert hasattr(ROOT.TColor.__init__, '__wrapped__'), \
19+
"TColor.__init__ should have __wrapped__ attribute from functools.wraps"
20+
21+
# Check that __name__ is preserved
22+
assert hasattr(ROOT.TColor.__init__, '__name__'), \
23+
"TColor.__init__ should have __name__ attribute"
24+
25+
# Check that __doc__ is preserved
26+
assert hasattr(ROOT.TColor.__init__, '__doc__'), \
27+
"TColor.__init__ should have __doc__ attribute"
28+
29+
print("Metadata preservation test: PASSED")
30+
return True
31+
32+
def test_tcolor_definedcolors():
33+
"""
34+
Test the original issue: TColor.DefinedColors(1) should work without errors.
35+
"""
36+
import ROOT
37+
38+
try:
39+
# This was the problematic call in Jupyter notebooks
40+
result = ROOT.TColor.DefinedColors(1)
41+
print(f"TColor.DefinedColors(1) returned: {result}")
42+
print("DefinedColors test: PASSED")
43+
return True
44+
except Exception as e:
45+
print(f"TColor.DefinedColors(1) failed with error: {e}")
46+
print("DefinedColors test: FAILED")
47+
return False
48+
49+
def test_tcolor_full_workflow():
50+
"""
51+
Test the full workflow from the original issue report.
52+
"""
53+
import ROOT
54+
55+
try:
56+
# Create a canvas
57+
ROOT.TColor.DefinedColors(1)
58+
c = ROOT.TCanvas("c", "Basic ROOT Plot", 800, 600)
59+
60+
# Create a histogram with 100 bins from 0 to 10
61+
h = ROOT.TH1F("h", "Example Histogram;X axis;Entries", 100, 0, 10)
62+
63+
# Fill histogram with random Gaussian numbers
64+
for _ in range(10000):
65+
h.Fill(ROOT.gRandom.Gaus(5, 1))
66+
67+
# Draw the histogram
68+
h.Draw()
69+
70+
# Draw canvas
71+
c.Draw()
72+
73+
print("Full workflow test: PASSED")
74+
return True
75+
except Exception as e:
76+
print(f"Full workflow test failed with error: {e}")
77+
print("Full workflow test: FAILED")
78+
return False
79+
80+
def main():
81+
"""
82+
Run all tests and return exit code.
83+
"""
84+
print("=" * 60)
85+
print("Testing TColor metadata preservation fix for issue #20018")
86+
print("=" * 60)
87+
88+
tests = [
89+
test_tcolor_metadata_preservation,
90+
test_tcolor_definedcolors,
91+
test_tcolor_full_workflow
92+
]
93+
94+
results = []
95+
for test in tests:
96+
print(f"\nRunning {test.__name__}...")
97+
try:
98+
result = test()
99+
results.append(result)
100+
except Exception as e:
101+
print(f"Test {test.__name__} raised exception: {e}")
102+
results.append(False)
103+
104+
print("\n" + "=" * 60)
105+
print(f"Test Results: {sum(results)}/{len(results)} passed")
106+
print("=" * 60)
107+
108+
return 0 if all(results) else 1
109+
110+
if __name__ == "__main__":
111+
sys.exit(main())

0 commit comments

Comments
 (0)