From 3b46e202d0a762f96c1433fc5969fa0902c1dde8 Mon Sep 17 00:00:00 2001 From: Eric Mehl Date: Thu, 5 Dec 2024 15:36:44 -0500 Subject: [PATCH] IECoreBinding : `repr` infinity for `eval` --- Changes | 4 ++++ src/IECorePython/IECoreBinding.cpp | 34 ++++++++++++++++++++++++++++-- test/IECore/ReprTest.py | 22 +++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index c5be5cd683..042373ae62 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,10 @@ 10.5.x.x (relative to 10.5.11.0) ======== +Fixes +----- + +- IECore : Fixed bug that was causing imath vectors and colors with values of `inf` / `std::numeric_limits::infinity()` to be serialised in a way that could not be evaluated with `eval()`. 10.5.11.0 (relative to 10.5.10.0) diff --git a/src/IECorePython/IECoreBinding.cpp b/src/IECorePython/IECoreBinding.cpp index d0ee134754..ce5a4f9ed1 100644 --- a/src/IECorePython/IECoreBinding.cpp +++ b/src/IECorePython/IECoreBinding.cpp @@ -58,6 +58,14 @@ IECORE_POP_DEFAULT_VISIBILITY using namespace std; using namespace Imath; +namespace +{ + +static std::string g_positiveInfString = "float( 'inf' )"; +static std::string g_negativeInfString = "-float( 'inf' )"; + +} + namespace IECorePython { @@ -70,7 +78,18 @@ std::string repr( VEC &x )\ s << "imath." << #VEC << "( ";\ for( unsigned i=0; i( x[i] );\ + if constexpr( std::numeric_limits::has_infinity )\ + {\ + s << (\ + x[i] == std::numeric_limits::infinity() ? g_positiveInfString :\ + ( x[i] == -std::numeric_limits::infinity() ? g_negativeInfString :\ + boost::lexical_cast( x[i] ) ) \ + );\ + }\ + else\ + {\ + s << boost::lexical_cast( x[i] );\ + }\ if( i!=VEC::dimensions()-1 )\ {\ s << ", ";\ @@ -142,7 +161,18 @@ std::string repr( COL &x )\ s << "imath." << #COL << "( ";\ for( unsigned i=0; i( x[i] );\ + if constexpr( std::numeric_limits::has_infinity )\ + {\ + s << (\ + x[i] == std::numeric_limits::infinity() ? g_positiveInfString :\ + ( x[i] == -std::numeric_limits::infinity() ? g_negativeInfString :\ + boost::lexical_cast( x[i] ) ) \ + );\ + }\ + else\ + {\ + s << boost::lexical_cast( x[i] );\ + }\ if( i!=COL::dimensions()-1 )\ {\ s << ", ";\ diff --git a/test/IECore/ReprTest.py b/test/IECore/ReprTest.py index 6423a93ac4..65b7ed19d3 100644 --- a/test/IECore/ReprTest.py +++ b/test/IECore/ReprTest.py @@ -60,6 +60,28 @@ def test( self ) : ] : self.assertTrue( type( v ) is type( eval( IECore.repr( v ) ) ) ) self.assertEqual( v, eval( IECore.repr( v ) ) ) + + def testInfinity( self ) : + + for v in [ + # Python raises "OverflowError : bad numeric conversion : positive overflow" + # when passing `float( "inf" )` to `V2f`` + imath.V2d( float( "inf" ), float( "inf" ) ), + imath.V3f( float( "inf" ), float( "inf" ), float( "inf" ) ), + imath.V3d( float( "inf" ), float( "inf" ), float( "inf" ) ), + imath.Color3f( float( "inf" ), float( "inf" ), float( "inf" ) ), + imath.Color4f( float( "inf" ), float( "inf" ), float( "inf" ), float( "inf" ) ), + ] : + with self.subTest( v = v ) : + self.assertTrue( type( v ) is type( eval( IECore.repr( v ) ) ) ) + self.assertEqual( v, eval( IECore.repr( v ) ) ) + + self.assertTrue( type( -v ) is type( eval( IECore.repr( -v ) ) ) ) + self.assertEqual( -v, eval( IECore.repr( -v ) ) ) + + self.assertEqual( str( v ), "{}({})".format( type( v ).__name__, ", ".join( ["inf"] * v.dimensions() ) ) ) + self.assertEqual( str( -v ), "{}({})".format( type( v ).__name__, ", ".join( ["-inf"] * v.dimensions() ) ) ) + if __name__ == "__main__": unittest.main()