Skip to content

Improve error messages for unsupported Python objects in user-facing APIs#9607

Open
jhonabreul wants to merge 9 commits into
QuantConnect:masterfrom
jhonabreul:bug-consolidator-period-error-message
Open

Improve error messages for unsupported Python objects in user-facing APIs#9607
jhonabreul wants to merge 9 commits into
QuantConnect:masterfrom
jhonabreul:bug-consolidator-period-error-message

Conversation

@jhonabreul

@jhonabreul jhonabreul commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Description

Passing an unsupported Python object to several user-facing APIs surfaces pythonnet's raw conversion error, which gives the user no hint about what went wrong or how to fix it. For example:

consolidator = QuoteBarConsolidator(Resolution.DAILY)

fails with:

cannot convert object to target type

Since none of the constructor overloads accept a Resolution, the call binds to the PyObject overload, whose handling in PeriodCountConsolidatorBase.GetPeriodSpecificationFromPyObject only supports a timedelta or a callable returning a CalendarInfo. The fallback pyObject.As<TimeSpan>() conversion throws a raw InvalidCastException.

This change catches these conversion failures and throws descriptive exceptions instead, stating the given value and its Python type and listing the available overloads, keeping the original exception as inner exception:

Unable to create a consolidator period from 'DAILY' of type 'Resolution': it is not a supported period type. The following overloads are available:
  QuoteBarConsolidator(period: timedelta, start_time: Optional[timedelta] = None)
  QuoteBarConsolidator(max_count: int)
  QuoteBarConsolidator(max_count: int, period: timedelta)
  QuoteBarConsolidator(func: Callable[[datetime], CalendarInfo])

The overloads are rendered as Python signatures (snake_case names, name: type annotations, Python types). The PyObject overloads — the ones that just rejected the value — are excluded from the hint.

The overload list is rendered by MethodSignatureFormatter, the helper exposed by QuantConnect/pythonnet#136 (the same formatting pythonnet uses for its "No method matches given arguments" hint). This PR therefore depends on that pythonnet PR being merged and released as 2.0.61 (the reference is already bumped here) — CI will fail until the package is published.

A new PyObject.ToDisplayString() extension centralizes the value-and-type rendering, and the same pattern is applied to the other user-facing conversion sites that surfaced the same raw error:

  • PeriodCountConsolidatorBase(PyObject) — all period-based consolidator constructors (TradeBarConsolidator, QuoteBarConsolidator, TickConsolidator, etc.)
  • QCAlgorithm.SetBenchmark(PyObject) — non-callable, non-Symbol benchmark arguments
  • DynamicData.SetProperty — assigning incompatible Python values to the reserved time/end_time/value/symbol properties of custom data, now naming the offending property
  • Security.Get<T>/TryGet<T>/Remove<T> custom properties — reading a Python-stored property with an incompatible type now names the property key and target type (still InvalidCastException, as documented)
  • ScheduledUniverse / ScheduledUniverseSelectionModel Python constructors — a non-callable selector now throws a descriptive ArgumentException instead of failing later with a NullReferenceException

Additionally, QuoteBarConsolidator.FromResolution(Resolution) is added, matching the existing helper in TradeBarConsolidator, BaseDataConsolidator and OpenInterestConsolidator, so a quote bar consolidator can be created directly from a Resolution.

Related Issue

N/A

Related PR: QuantConnect/pythonnet#136 — exposes the MethodSignatureFormatter helper this PR uses to render the overload lists. The QuantConnect.pythonnet reference is already bumped to 2.0.61 here (the version being released by QuantConnect/pythonnet#135); CI will pass once that package is published with #136 included.

Motivation and Context

The raw pythonnet error cannot convert object to target type surfaces directly to Python algorithm users during algorithm initialization and gives them no information about which argument is wrong, why, or what to use instead. This is a common stumbling block since other APIs (e.g. self.consolidate) do accept a Resolution, making it natural for users to try passing one to the consolidator constructors.

Requires Documentation Change

No.

How Has This Been Tested?

  • New unit tests covering each improved error site:
    • PeriodCountConsolidatorTests.PyObjectConstructorThrowsDescriptiveErrorForUnsupportedPeriodType
    • PeriodCountConsolidatorTests.QuoteBarConsolidatorFromResolutionCreatesConsolidatorWithExpectedPeriod
    • AlgorithmBenchmarkTests.PythonSetBenchmarkThrowsDescriptiveErrorForUnsupportedBenchmarkType
    • DynamicDataTests.SettingReservedPropertyWithUnsupportedPythonValueThrowsDescriptiveError
    • SecurityTests.GettingPythonCustomPropertyWithIncompatibleTypeThrowsDescriptiveError
    • ScheduledUniverseTests.PythonConstructorThrowsDescriptiveErrorWhenSelectorIsNotAFunction
  • Ran the full PeriodCountConsolidatorTests, CalendarConsolidatorsTests, DynamicDataTests and ScheduledUniverseTests suites, which cover the supported conversion paths (Python callables, timedelta, valid property values), to verify no behavior change.
  • Reproduced the original consolidator error end-to-end with a Python algorithm running through the Lean launcher and verified the new message is shown after the change.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • Refactor (non-breaking change which improves implementation)
  • Performance (non-breaking change which improves performance. Please add associated performance test and results)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Non-functional change (xml comments/documentation/etc)

Checklist:

  • My code follows the code style of this project.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • My branch follows the naming convention bug-<issue#>-<description> or feature-<issue#>-<description>

@jhonabreul jhonabreul changed the title Improve error message when consolidator period Python object is unsupported Improve error messages for unsupported Python objects in user-facing APIs Jul 10, 2026
@jhonabreul jhonabreul marked this pull request as ready for review July 10, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants