chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:02:50 +08:00
commit 0fc60fdcb1
5008 changed files with 910633 additions and 0 deletions
@@ -0,0 +1,117 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using NUnit.Framework;
using NUnit.Framework.Constraints;
using Python.Runtime;
using QuantConnect.Exceptions;
using System;
using System.Collections.Generic;
namespace QuantConnect.Tests.Common.Exceptions
{
[TestFixture]
public class ClrBubbledExceptionInterpreterTests
{
private string _pythonModuleName = "Test_PythonExceptionInterpreter";
private ClrBubbledException _dotnetException;
private PythonException _pythonException;
[OneTimeSetUp]
public void Setup()
{
using (Py.GIL())
{
var module = Py.Import(_pythonModuleName);
dynamic algorithm = module.GetAttr("Test_PythonExceptionInterpreter").Invoke();
try
{
// self.MarketOrder(null, 1)
algorithm.dotnet_error();
}
catch (ClrBubbledException e)
{
_dotnetException = e;
}
try
{
// x = 1 / 0
algorithm.zero_division_error();
}
catch (PythonException e)
{
_pythonException = e;
}
Assert.IsNotNull(_dotnetException);
Assert.IsNotNull(_pythonException);
}
}
[Test]
[TestCase(typeof(Exception), ExpectedResult = false)]
[TestCase(typeof(KeyNotFoundException), ExpectedResult = false)]
[TestCase(typeof(DivideByZeroException), ExpectedResult = false)]
[TestCase(typeof(InvalidOperationException), ExpectedResult = false)]
[TestCase(typeof(PythonException), ExpectedResult = false)]
[TestCase(typeof(ClrBubbledException), ExpectedResult = true)]
public bool CanInterpretReturnsTrueOnlyForClrBubbledExceptionType(Type exceptionType)
{
var exception = CreateExceptionFromType(exceptionType);
return new ClrBubbledExceptionInterpreter().CanInterpret(exception);
}
[Test]
[TestCase(typeof(Exception), true)]
[TestCase(typeof(KeyNotFoundException), true)]
[TestCase(typeof(DivideByZeroException), true)]
[TestCase(typeof(InvalidOperationException), true)]
[TestCase(typeof(PythonException), true)]
[TestCase(typeof(ClrBubbledException), false)]
public void InterpretThrowsForNonClrBubbledExceptionTypes(Type exceptionType, bool expectThrow)
{
var exception = CreateExceptionFromType(exceptionType);
var interpreter = new ClrBubbledExceptionInterpreter();
var constraint = expectThrow ? (IResolveConstraint)Throws.Exception : Throws.Nothing;
Assert.That(() => interpreter.Interpret(exception, NullExceptionInterpreter.Instance), constraint);
}
[Test]
public void VerifyMessageContainsStackTraceInformation()
{
var exception = CreateExceptionFromType(typeof(ClrBubbledException));
var assembly = typeof(ClrBubbledExceptionInterpreter).Assembly;
var interpreter = StackExceptionInterpreter.CreateFromAssemblies();
exception = interpreter.Interpret(exception, NullExceptionInterpreter.Instance);
Assert.True(exception.Message.Contains("Object reference not set to an instance of an object.", StringComparison.InvariantCulture));
Assert.True(exception.Message.Contains("at dotnet_error", StringComparison.InvariantCulture));
Assert.True(exception.Message.Contains("self.market_order(None", StringComparison.InvariantCulture));
Assert.True(exception.Message.Contains($"in {_pythonModuleName}.py: line ", StringComparison.InvariantCulture));
}
private Exception CreateExceptionFromType(Type type)
{
if (type == typeof(ClrBubbledException))
{
return _dotnetException;
}
return type == typeof(PythonException) ? _pythonException : (Exception)Activator.CreateInstance(type);
}
}
}
@@ -0,0 +1,63 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using NUnit.Framework;
using NUnit.Framework.Constraints;
using QuantConnect.Exceptions;
using System;
using System.Collections.Generic;
namespace QuantConnect.Tests.Common.Exceptions
{
[TestFixture]
public class DllNotFoundPythonExceptionInterpreterTests
{
[Test]
[TestCase(typeof(Exception), ExpectedResult = false)]
[TestCase(typeof(KeyNotFoundException), ExpectedResult = false)]
[TestCase(typeof(DivideByZeroException), ExpectedResult = false)]
[TestCase(typeof(InvalidOperationException), ExpectedResult = false)]
[TestCase(typeof(DllNotFoundException), ExpectedResult = true)]
public bool CanInterpretReturnsTrueForOnlyDllNotFoundExceptionType(Type exceptionType)
{
var exception = CreateExceptionFromType(exceptionType);
return new DllNotFoundPythonExceptionInterpreter().CanInterpret(exception);
}
[Test]
[TestCase(typeof(Exception), true)]
[TestCase(typeof(KeyNotFoundException), true)]
[TestCase(typeof(DivideByZeroException), true)]
[TestCase(typeof(InvalidOperationException), true)]
[TestCase(typeof(DllNotFoundException), false)]
public void InterpretThrowsForNonDllNotFoundExceptionTypes(Type exceptionType, bool expectThrow)
{
var exception = CreateExceptionFromType(exceptionType);
var interpreter = new DllNotFoundPythonExceptionInterpreter();
var constraint = expectThrow ? (IResolveConstraint)Throws.Exception : Throws.Nothing;
Assert.That(() => interpreter.Interpret(exception, NullExceptionInterpreter.Instance), constraint);
}
private Exception CreateExceptionFromType(Type type)
{
if (type == typeof(DllNotFoundException))
{
return new DllNotFoundException("\'python3.6\'");
}
return (Exception)Activator.CreateInstance(type);
}
}
}
@@ -0,0 +1,67 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Exceptions;
namespace QuantConnect.Tests.Common.Exceptions
{
/// <summary>
/// Provids a fake implementation that can be utilized in tests
/// </summary>
/// <remarks>
/// Keep it internal so it doesn't get picked up when loading all exception interpreters from assemblies
/// </remarks>
internal class FakeExceptionInterpreter : IExceptionInterpreter
{
private readonly int _order = 0;
private readonly Func<Exception, bool> _canInterpret;
private readonly Func<Exception, Exception> _interpret;
public int Order => _order;
public FakeExceptionInterpreter()
{
_canInterpret = e => true;
var count = 0;
_interpret = e =>
{
if (e == null)
{
return null;
}
return new Exception($"Projected {++count}: " + e.Message, _interpret(e.InnerException));
};
}
public FakeExceptionInterpreter(Func<Exception, bool> canInterpret, Func<Exception, Exception> interpret, int order = 0)
{
_canInterpret = canInterpret;
_interpret = interpret;
_order = order;
}
public bool CanInterpret(Exception exception)
{
return _canInterpret(exception);
}
public Exception Interpret(Exception exception, IExceptionInterpreter innerInterpreter)
{
return _interpret(exception);
}
}
}
@@ -0,0 +1,83 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using NUnit.Framework;
using NUnit.Framework.Constraints;
using Python.Runtime;
using QuantConnect.Exceptions;
using System;
using System.Collections.Generic;
namespace QuantConnect.Tests.Common.Exceptions
{
[TestFixture]
public class InvalidTokenPythonExceptionInterpreterTests
{
private PythonException _pythonException;
[SetUp]
public void Setup()
{
using (Py.GIL())
{
try
{
// importing a module with syntax error 'x = 01' will throw
PyModule.FromString(Guid.NewGuid().ToString(), "x = 01");
}
catch (PythonException pythonException)
{
_pythonException = pythonException;
}
}
}
[TestCase(typeof(Exception), false)]
[TestCase(typeof(KeyNotFoundException), false)]
[TestCase(typeof(DivideByZeroException), false)]
[TestCase(typeof(InvalidOperationException), false)]
[TestCase(typeof(PythonException), true)]
public void CanInterpretReturnsTrueForOnlyInvalidTokenPythonExceptionType(Type exceptionType, bool expectedResult)
{
var exception = CreateExceptionFromType(exceptionType);
Assert.AreEqual(expectedResult, new InvalidTokenPythonExceptionInterpreter().CanInterpret(exception), $"Unexpected response for: {exception}");
}
[TestCase(typeof(Exception), true)]
[TestCase(typeof(KeyNotFoundException), true)]
[TestCase(typeof(DivideByZeroException), true)]
[TestCase(typeof(InvalidOperationException), true)]
[TestCase(typeof(PythonException), false)]
public void InterpretThrowsForNonInvalidTokenPythonExceptionTypes(Type exceptionType, bool expectThrow)
{
var exception = CreateExceptionFromType(exceptionType);
var interpreter = new InvalidTokenPythonExceptionInterpreter();
var constraint = expectThrow ? (IResolveConstraint)Throws.Exception : Throws.Nothing;
Assert.That(() => interpreter.Interpret(exception, NullExceptionInterpreter.Instance), constraint);
}
[Test]
public void VerifyMessageContainsStackTraceInformation()
{
var exception = CreateExceptionFromType(typeof(PythonException));
var assembly = typeof(PythonExceptionInterpreter).Assembly;
var interpreter = StackExceptionInterpreter.CreateFromAssemblies();
exception = interpreter.Interpret(exception, NullExceptionInterpreter.Instance);
Assert.True(exception.Message.Contains("x = 01"));
}
private Exception CreateExceptionFromType(Type type) => type == typeof(PythonException) ? _pythonException : (Exception)Activator.CreateInstance(type);
}
}
@@ -0,0 +1,88 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using NUnit.Framework;
using NUnit.Framework.Constraints;
using Python.Runtime;
using QuantConnect.Exceptions;
using System;
using System.Collections.Generic;
namespace QuantConnect.Tests.Common.Exceptions
{
[TestFixture]
public class KeyErrorPythonExceptionInterpreterTests
{
private PythonException _pythonException;
[SetUp]
public void Setup()
{
using (Py.GIL())
{
var module = Py.Import("Test_PythonExceptionInterpreter");
dynamic algorithm = module.GetAttr("Test_PythonExceptionInterpreter").Invoke();
try
{
// dict()['SPY']
algorithm.key_error();
}
catch (PythonException pythonException)
{
_pythonException = pythonException;
}
}
}
[Test]
[TestCase(typeof(Exception), ExpectedResult = false)]
[TestCase(typeof(KeyNotFoundException), ExpectedResult = false)]
[TestCase(typeof(DivideByZeroException), ExpectedResult = false)]
[TestCase(typeof(InvalidOperationException), ExpectedResult = false)]
[TestCase(typeof(PythonException), ExpectedResult = true)]
public bool CanInterpretReturnsTrueForOnlyKeyErrorPythonExceptionType(Type exceptionType)
{
var exception = CreateExceptionFromType(exceptionType);
return new KeyErrorPythonExceptionInterpreter().CanInterpret(exception);
}
[Test]
[TestCase(typeof(Exception), true)]
[TestCase(typeof(KeyNotFoundException), true)]
[TestCase(typeof(DivideByZeroException), true)]
[TestCase(typeof(InvalidOperationException), true)]
[TestCase(typeof(PythonException), false)]
public void InterpretThrowsForNonKeyErrorPythonExceptionTypes(Type exceptionType, bool expectThrow)
{
var exception = CreateExceptionFromType(exceptionType);
var interpreter = new KeyErrorPythonExceptionInterpreter();
var constraint = expectThrow ? (IResolveConstraint)Throws.Exception : Throws.Nothing;
Assert.That(() => interpreter.Interpret(exception, NullExceptionInterpreter.Instance), constraint);
}
[Test]
public void VerifyMessageContainsStackTraceInformation()
{
var exception = CreateExceptionFromType(typeof(PythonException));
var assembly = typeof(PythonExceptionInterpreter).Assembly;
var interpreter = StackExceptionInterpreter.CreateFromAssemblies();
exception = interpreter.Interpret(exception, NullExceptionInterpreter.Instance);
Assert.True(exception.Message.Contains("dict()['SPY']"));
}
private Exception CreateExceptionFromType(Type type) => type == typeof(PythonException) ? _pythonException : (Exception)Activator.CreateInstance(type);
}
}
@@ -0,0 +1,164 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using NUnit.Framework;
using NUnit.Framework.Constraints;
using Python.Runtime;
using QuantConnect.Exceptions;
using System;
using System.Collections.Generic;
namespace QuantConnect.Tests.Common.Exceptions
{
[TestFixture]
public class NoMethodMatchPythonExceptionInterpreterTests
{
private PythonException _pythonException;
[OneTimeSetUp]
public void Setup()
{
using (Py.GIL())
{
var module = Py.Import("Test_PythonExceptionInterpreter");
dynamic algorithm = module.GetAttr("Test_PythonExceptionInterpreter").Invoke();
try
{
// self.SetCash('SPY')
algorithm.no_method_match();
}
catch (PythonException pythonException)
{
_pythonException = pythonException;
}
}
}
[Test]
[TestCase(typeof(Exception), ExpectedResult = false)]
[TestCase(typeof(KeyNotFoundException), ExpectedResult = false)]
[TestCase(typeof(DivideByZeroException), ExpectedResult = false)]
[TestCase(typeof(InvalidOperationException), ExpectedResult = false)]
[TestCase(typeof(PythonException), ExpectedResult = true)]
public bool CanInterpretReturnsTrueForOnlyNoMethodMatchPythonExceptionType(Type exceptionType)
{
var exception = CreateExceptionFromType(exceptionType);
return new NoMethodMatchPythonExceptionInterpreter().CanInterpret(exception);
}
[Test]
[TestCase(typeof(Exception), true)]
[TestCase(typeof(KeyNotFoundException), true)]
[TestCase(typeof(DivideByZeroException), true)]
[TestCase(typeof(InvalidOperationException), true)]
[TestCase(typeof(PythonException), false)]
public void InterpretThrowsForNonNoMethodMatchPythonExceptionTypes(Type exceptionType, bool expectThrow)
{
var exception = CreateExceptionFromType(exceptionType);
var interpreter = new NoMethodMatchPythonExceptionInterpreter();
var constraint = expectThrow ? (IResolveConstraint)Throws.Exception : Throws.Nothing;
Assert.That(() => interpreter.Interpret(exception, NullExceptionInterpreter.Instance), constraint);
}
[Test]
public void VerifyMessageContainsStackTraceInformation()
{
var exception = CreateExceptionFromType(typeof(PythonException));
var assembly = typeof(PythonExceptionInterpreter).Assembly;
var interpreter = StackExceptionInterpreter.CreateFromAssemblies();
exception = interpreter.Interpret(exception, NullExceptionInterpreter.Instance);
Assert.True(exception.Message.Contains("self.set_cash('SPY')"));
}
[Test]
public void VerifyMessageContainsTheMethodName()
{
var exception = CreateExceptionFromType(typeof(PythonException));
var interpreter = new NoMethodMatchPythonExceptionInterpreter();
exception = interpreter.Interpret(exception, NullExceptionInterpreter.Instance);
// The interpreter should reference the actual method name that failed to resolve
// (set_cash, the snake_case name Python callers use), not a fragment of the argument
// type list (e.g. "'str'>)").
Assert.That(exception.Message, Does.Contain("set_cash"));
Assert.That(exception.Message, Does.Not.Contain(">)"));
}
[Test]
public void VerifyMessageContainsTheMethodNameForOverloadedMethod()
{
PythonException pythonException;
using (Py.GIL())
{
var module = Py.Import("Test_PythonExceptionInterpreter");
dynamic algorithm = module.GetAttr("Test_PythonExceptionInterpreter").Invoke();
// self.rsi(symbol, 15, Resolution.DAILY) -- the third argument should be a
// MovingAverageType, so no RSI overload matches the given arguments.
pythonException = Assert.Throws<PythonException>(() => algorithm.no_method_match_rsi());
}
var interpreter = new NoMethodMatchPythonExceptionInterpreter();
var exception = interpreter.Interpret(pythonException, NullExceptionInterpreter.Instance);
// The interpreter should reference the rsi method name (snake_case, as Python callers
// use it), not a fragment of the argument type list (e.g. "'QuantConnect.Resolution'>)").
Assert.That(exception.Message, Does.Contain("rsi"));
Assert.That(exception.Message, Does.Not.Contain(">)"));
}
[Test]
public void VerifyMessageKeepsTheOverloadsHint()
{
// pythonnet appends the candidate signatures to the binding-failure message.
// set_cash('SPY') has multiple candidate overloads.
var pythonException = (PythonException)CreateExceptionFromType(typeof(PythonException));
StringAssert.Contains("The following overloads are available:", pythonException.Message);
var interpreter = new NoMethodMatchPythonExceptionInterpreter();
var exception = interpreter.Interpret(pythonException, NullExceptionInterpreter.Instance);
// The interpreted message must keep the overloads hint so the user can see
// what the method expects, not just that no overload matched.
Assert.That(exception.Message, Does.Contain("The following overloads are available:"));
Assert.That(exception.Message, Does.Contain("set_cash("));
}
[Test]
public void VerifyMessageKeepsTheExpectedSignatureHint()
{
PythonException pythonException;
using (Py.GIL())
{
var module = Py.Import("Test_PythonExceptionInterpreter");
dynamic algorithm = module.GetAttr("Test_PythonExceptionInterpreter").Invoke();
pythonException = Assert.Throws<PythonException>(() => algorithm.no_method_match_rsi());
}
// rsi's candidate overloads collapse into a single snake-case signature,
// so pythonnet words the hint as "The expected signature is:"
StringAssert.Contains("The expected signature is:", pythonException.Message);
var interpreter = new NoMethodMatchPythonExceptionInterpreter();
var exception = interpreter.Interpret(pythonException, NullExceptionInterpreter.Instance);
Assert.That(exception.Message, Does.Contain("The expected signature is:"));
Assert.That(exception.Message, Does.Contain("rsi("));
}
private Exception CreateExceptionFromType(Type type) => type == typeof(PythonException) ? _pythonException : (Exception)Activator.CreateInstance(type);
}
}
@@ -0,0 +1,44 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Exceptions;
namespace QuantConnect.Tests.Common.Exceptions
{
/// <summary>
/// Provides a null implementation of <see cref="IExceptionInterpreter"/>
/// </summary>
public class NullExceptionInterpreter : IExceptionInterpreter
{
public static readonly IExceptionInterpreter Instance = new NullExceptionInterpreter();
public int Order => int.MaxValue;
private NullExceptionInterpreter()
{
}
public bool CanInterpret(Exception exception)
{
return false;
}
public Exception Interpret(Exception exception, IExceptionInterpreter innerInterpreter)
{
return exception;
}
}
}
@@ -0,0 +1,88 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using NUnit.Framework;
using NUnit.Framework.Constraints;
using Python.Runtime;
using QuantConnect.Exceptions;
using System;
using System.Collections.Generic;
namespace QuantConnect.Tests.Common.Exceptions
{
[TestFixture]
public class PythonExceptionInterpreterTests
{
private PythonException _pythonException;
[OneTimeSetUp]
public void Setup()
{
using (Py.GIL())
{
var module = Py.Import("Test_PythonExceptionInterpreter");
dynamic algorithm = module.GetAttr("Test_PythonExceptionInterpreter").Invoke();
try
{
// x = 1 / 0
algorithm.zero_division_error();
}
catch (PythonException pythonException)
{
_pythonException = pythonException;
}
}
}
[Test]
[TestCase(typeof(Exception), ExpectedResult = false)]
[TestCase(typeof(KeyNotFoundException), ExpectedResult = false)]
[TestCase(typeof(DivideByZeroException), ExpectedResult = false)]
[TestCase(typeof(InvalidOperationException), ExpectedResult = false)]
[TestCase(typeof(PythonException), ExpectedResult = true)]
public bool CanInterpretReturnsTrueForOnlyPythonExceptionType(Type exceptionType)
{
var exception = CreateExceptionFromType(exceptionType);
return new PythonExceptionInterpreter().CanInterpret(exception);
}
[Test]
[TestCase(typeof(Exception), true)]
[TestCase(typeof(KeyNotFoundException), true)]
[TestCase(typeof(DivideByZeroException), true)]
[TestCase(typeof(InvalidOperationException), true)]
[TestCase(typeof(PythonException), false)]
public void InterpretThrowsForNonPythonExceptionTypes(Type exceptionType, bool expectThrow)
{
var exception = CreateExceptionFromType(exceptionType);
var interpreter = new PythonExceptionInterpreter();
var constraint = expectThrow ? (IResolveConstraint)Throws.Exception : Throws.Nothing;
Assert.That(() => interpreter.Interpret(exception, NullExceptionInterpreter.Instance), constraint);
}
[Test]
public void VerifyMessageContainsStackTraceInformation()
{
var exception = CreateExceptionFromType(typeof(PythonException));
var assembly = typeof(PythonExceptionInterpreter).Assembly;
var interpreter = StackExceptionInterpreter.CreateFromAssemblies();
exception = interpreter.Interpret(exception, NullExceptionInterpreter.Instance);
Assert.True(exception.Message.Contains("x = 1 / 0"));
}
private Exception CreateExceptionFromType(Type type) => type == typeof(PythonException) ? _pythonException : (Exception)Activator.CreateInstance(type);
}
}
@@ -0,0 +1,105 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using NUnit.Framework.Constraints;
using QuantConnect.Exceptions;
using QuantConnect.Scheduling;
namespace QuantConnect.Tests.Common.Exceptions
{
[TestFixture]
public class ScheduledEventExceptionInterpreterTests
{
[Test]
[TestCase(typeof(Exception), ExpectedResult = false)]
[TestCase(typeof(KeyNotFoundException), ExpectedResult = false)]
[TestCase(typeof(DivideByZeroException), ExpectedResult = false)]
[TestCase(typeof(InvalidOperationException), ExpectedResult = false)]
[TestCase(typeof(ScheduledEventException), ExpectedResult = true)]
public bool CanProjectReturnsTrueForOnlyScheduledEventExceptionType(Type exceptionType)
{
var exception = CreateExceptionFromType(exceptionType);
return new ScheduledEventExceptionInterpreter().CanInterpret(exception);
}
[Test]
[TestCase(typeof(Exception), true)]
[TestCase(typeof(KeyNotFoundException), true)]
[TestCase(typeof(DivideByZeroException), true)]
[TestCase(typeof(InvalidOperationException), true)]
[TestCase(typeof(ScheduledEventException), false)]
public void ProjectThrowsForNonScheduledEventExceptionTypes(Type exceptionType, bool expectThrow)
{
var exception = CreateExceptionFromType(exceptionType);
var interpreter = new ScheduledEventExceptionInterpreter();
var constraint = expectThrow ? (IResolveConstraint)Throws.Exception : Throws.Nothing;
Assert.That(() => interpreter.Interpret(exception, NullExceptionInterpreter.Instance), constraint);
}
[Test]
public void ReformsMessageToIncludeScheduledEventName()
{
var id = Guid.NewGuid();
var name = id.ToStringInvariant("D");
var message = id.ToStringInvariant("N");
var exception = new ScheduledEventException(name, message, null);
var interpreted = new ScheduledEventExceptionInterpreter().Interpret(exception, NullExceptionInterpreter.Instance);
var expectedInterpretedMessage = $"In Scheduled Event '{name}',";
Assert.AreEqual(expectedInterpretedMessage, interpreted.Message);
}
[Test]
public void WrapsScheduledEventExceptionInnerException()
{
var inner = new Exception();
var exception = new ScheduledEventException("name", "message", inner);
var interpreted = new ScheduledEventExceptionInterpreter().Interpret(exception, NullExceptionInterpreter.Instance);
Assert.AreEqual(inner, interpreted.InnerException);
}
[Test]
public void InvokesInnerExceptionProjectionOnInnerException()
{
var inner = new Exception("inner");
var exception = new ScheduledEventException("name", "message", inner);
var mockInnerInterpreter = new Mock<IExceptionInterpreter>();
mockInnerInterpreter.Setup(iep => iep.Interpret(inner, mockInnerInterpreter.Object))
.Returns(new Exception("Projected " + inner.Message))
.Verifiable();
var interpreter = new ScheduledEventExceptionInterpreter();
interpreter.Interpret(exception, mockInnerInterpreter.Object);
mockInnerInterpreter.Verify(iep => iep.Interpret(inner, mockInnerInterpreter.Object), Times.Exactly(1));
}
private Exception CreateExceptionFromType(Type type)
{
if (type == typeof(ScheduledEventException))
{
var inner = new Exception("Sample inner message");
return new ScheduledEventException(Guid.NewGuid().ToStringInvariant(null), "Sample error message", inner);
}
return (Exception)Activator.CreateInstance(type);
}
}
}
@@ -0,0 +1,121 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using QuantConnect.Exceptions;
namespace QuantConnect.Tests.Common.Exceptions
{
[TestFixture]
public class StackExceptionInterpretersTests
{
[Test]
public void CreatesFromAssemblies()
{
var assembly = typeof(ClrBubbledExceptionInterpreter).Assembly;
var interpreter = StackExceptionInterpreter.CreateFromAssemblies();
Assert.AreEqual(1, interpreter.Interpreters.Count(p => p.GetType() == typeof(ClrBubbledExceptionInterpreter)));
}
[Test]
public void CallsInterpretOnFirstProjectionThatCanInterpret()
{
var canInterpretCalled = new List<int>();
var interpretCalled = new List<int>();
var interpreters = new[]
{
new FakeExceptionInterpreter(e =>
{
canInterpretCalled.Add(0);
return false;
}, e =>
{
interpretCalled.Add(0);
return e;
},
order : 2),
new FakeExceptionInterpreter(e =>
{
canInterpretCalled.Add(1);
return true;
}, e =>
{
interpretCalled.Add(1);
return e;
},
order : 1),
new FakeExceptionInterpreter(e =>
{
canInterpretCalled.Add(2);
return false;
}, e =>
{
interpretCalled.Add(2);
return e;
},
order : 0)
};
var interpreter = new StackExceptionInterpreter(interpreters);
interpreter.Interpret(new Exception(), null);
// can interpret called for 3nd and 2rd entry
Assert.Contains(2, canInterpretCalled);
Assert.Contains(1, canInterpretCalled);
Assert.That(canInterpretCalled, Is.Not.Contains(0));
// interpret only called on second entry
Assert.That(interpretCalled, Is.Not.Contains(0));
Assert.Contains(1, interpretCalled);
Assert.That(interpretCalled, Is.Not.Contains(2));
// interpreter called 3rd before 2nd
Assert.Greater(canInterpretCalled.First(), canInterpretCalled.Last());
}
[Test]
public void RecursivelyProjectsInnerExceptions()
{
var inner = new Exception("inner");
var middle = new Exception("middle", inner);
var outter = new Exception("outter", middle);
var interpreter = new StackExceptionInterpreter(new[]
{
new FakeExceptionInterpreter()
});
var interpreted = interpreter.Interpret(outter, null);
Assert.AreEqual("Projected 1: outter", interpreted.Message);
Assert.AreEqual("Projected 2: middle", interpreted.InnerException.Message);
Assert.AreEqual("Projected 3: inner", interpreted.InnerException.InnerException.Message);
}
[Test]
public void GetsExceptionMessageHeaderAsAllInnersJoinedBySpace()
{
var inner = new Exception("inner");
var middle = new Exception("middle", inner);
var outter = new Exception("outter", middle);
var message = new StackExceptionInterpreter(Enumerable.Empty<IExceptionInterpreter>()).GetExceptionMessageHeader(outter);
// header line w/ exception message and then the full detail on a new line
var expectedMessage = "outter middle inner";
Assert.AreEqual(expectedMessage, message);
}
}
}
@@ -0,0 +1,80 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using NUnit.Framework;
using QuantConnect.Exceptions;
using QuantConnect.Logging;
namespace QuantConnect.Tests.Common.Exceptions
{
[TestFixture]
public class SystemExceptionInterpreterTests
{
[Test]
public void InterpreterCorrectly()
{
var result = SystemExceptionInterpreter.TryGetLineAndFile(@" at QuantConnect.Algorithm.CSharp.BasicTemplateAlgorithm.Initialize() in D:\QuantConnect\MyLean\Lean\Algorithm.CSharp\BasicTemplateAlgorithm.cs:line 50
at QuantConnect.Lean.Engine.Setup.BacktestingSetupHandler.<>c__DisplayClass27_0.<Setup>b__0() in D:\QuantConnect\MyLean\Lean\Engine\Setup\BacktestingSetupHandler.cs:line 186
", out var fileAndLine);
Assert.IsTrue(result);
Assert.AreEqual(" in BasicTemplateAlgorithm.cs:line 50", fileAndLine);
}
[Test]
public void CleanupStacktrace()
{
var interpreter = new SystemExceptionInterpreter();
var message = "The ticker AAPL was not found in the SymbolCache. Use the Symbol object as key instead. Accessing the securities collection/slice object by string ticker is only available for" +
" securities added with the AddSecurity-family methods. For more details, please check out the documentation.";
var stackTrace = " at QuantConnect.ExtendedDictionary`1.get_Item(String ticker) in D:\\QuantConnect\\MyLean\\Lean\\Common\\ExtendedDictionary.cs:line 121\r\n at QuantConnect.Algorithm.CSh" +
"arp.BasicTemplateAlgorithm.OnData(Slice data) in D:\\QuantConnect\\MyLean\\Lean\\Algorithm.CSharp\\BasicTemplateAlgorithm.cs:line 58\r\n at QuantConnect.Lean.Engine.AlgorithmManager.R" +
"un(AlgorithmNodePacket job, IAlgorithm algorithm, ISynchronizer synchronizer, ITransactionHandler transactions, IResultHandler results, IRealTimeHandler realtime, ILeanManager leanMana" +
"ger, CancellationToken token) in D:\\QuantConnect\\MyLean\\Lean\\Engine\\AlgorithmManager.cs:line 525";
var result = interpreter.Interpret(new TestException(message, stackTrace), null);
Assert.AreEqual(" at QuantConnect.ExtendedDictionary`1.get_Item(String ticker) in Common\\ExtendedDictionary.cs:line 121\r\n at QuantConnect.Algorithm.CSharp.BasicTemplateAlgorithm.OnData(" +
"Slice data) in Algorithm.CSharp\\BasicTemplateAlgorithm.cs:line 58\r\n at QuantConnect.Lean.Engine.AlgorithmManager.Run(AlgorithmNodePacket job, IAlgorithm algorithm, ISynchronizer sync" +
"hronizer, ITransactionHandler transactions, IResultHandler results, IRealTimeHandler realtime, ILeanManager leanManager, CancellationToken token) in Engine\\AlgorithmManager.cs:line 525", result.InnerException.StackTrace);
}
[TestCase("")]
[TestCase(null)]
public void CleanupStackTraceHandles(string stackTrace)
{
var interpreter = new SystemExceptionInterpreter();
var result = interpreter.Interpret(new TestException("Message", stackTrace), null);
Assert.IsNull(result.InnerException);
}
private class TestException : Exception
{
private readonly string _message;
private readonly string _stackTrace;
public override string Message => _message;
public override string StackTrace => _stackTrace;
public TestException(string message, string stackTrace)
{
_message = message;
_stackTrace = Log.ClearLeanPaths(stackTrace);
}
}
}
}
@@ -0,0 +1,88 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using NUnit.Framework;
using NUnit.Framework.Constraints;
using Python.Runtime;
using QuantConnect.Exceptions;
using System;
using System.Collections.Generic;
namespace QuantConnect.Tests.Common.Exceptions
{
[TestFixture]
public class UnsupportedOperandPythonExceptionInterpreterTests
{
private PythonException _pythonException;
[OneTimeSetUp]
public void Setup()
{
using (Py.GIL())
{
var module = Py.Import("Test_PythonExceptionInterpreter");
dynamic algorithm = module.GetAttr("Test_PythonExceptionInterpreter").Invoke();
try
{
// x = None + "Pepe Grillo"
algorithm.unsupported_operand();
}
catch (PythonException pythonException)
{
_pythonException = pythonException;
}
}
}
[Test]
[TestCase(typeof(Exception), ExpectedResult = false)]
[TestCase(typeof(KeyNotFoundException), ExpectedResult = false)]
[TestCase(typeof(DivideByZeroException), ExpectedResult = false)]
[TestCase(typeof(InvalidOperationException), ExpectedResult = false)]
[TestCase(typeof(PythonException), ExpectedResult = true)]
public bool CanInterpretReturnsTrueForOnlyUnsupportedOperandPythonExceptionType(Type exceptionType)
{
var exception = CreateExceptionFromType(exceptionType);
return new UnsupportedOperandPythonExceptionInterpreter().CanInterpret(exception);
}
[Test]
[TestCase(typeof(Exception), true)]
[TestCase(typeof(KeyNotFoundException), true)]
[TestCase(typeof(DivideByZeroException), true)]
[TestCase(typeof(InvalidOperationException), true)]
[TestCase(typeof(PythonException), false)]
public void InterpretThrowsForNonUnsupportedOperandPythonExceptionTypes(Type exceptionType, bool expectThrow)
{
var exception = CreateExceptionFromType(exceptionType);
var interpreter = new UnsupportedOperandPythonExceptionInterpreter();
var constraint = expectThrow ? (IResolveConstraint)Throws.Exception : Throws.Nothing;
Assert.That(() => interpreter.Interpret(exception, NullExceptionInterpreter.Instance), constraint);
}
[Test]
public void VerifyMessageContainsStackTraceInformation()
{
var exception = CreateExceptionFromType(typeof(PythonException));
var assembly = typeof(PythonExceptionInterpreter).Assembly;
var interpreter = StackExceptionInterpreter.CreateFromAssemblies();
exception = interpreter.Interpret(exception, NullExceptionInterpreter.Instance);
Assert.True(exception.Message.Contains("x = None + \"Pepe Grillo\""));
}
private Exception CreateExceptionFromType(Type type) => type == typeof(PythonException) ? _pythonException : (Exception)Activator.CreateInstance(type);
}
}