Skip to content

Make the in-memory NPV cubes constructible from Python (#354) - #355

Open
dazivo wants to merge 1 commit into
OpenSourceRisk:masterfrom
dazivo:fix/inmemory-cube-swig-abstract
Open

Make the in-memory NPV cubes constructible from Python (#354)#355
dazivo wants to merge 1 commit into
OpenSourceRisk:masterfrom
dazivo:fix/inmemory-cube-swig-abstract

Conversation

@dazivo

@dazivo dazivo commented Aug 18, 2026

Copy link
Copy Markdown

Fixes #354.

SinglePrecisionInMemoryCubeN and DoublePrecisionInMemoryCubeN raised AttributeError: No constructor defined - class is abstract on construction, on the released 1.8.15.0 and 1.8.16.0 wheels alike. Since NPVCube and AggregationScenarioData are abstract by design and JointNPVCube only joins existing cubes, no NPV cube could be built from Python at all.

The InMemoryCubeOpt overrides in orea_cube.i did not textually match the base's pure virtuals as the SWIG parser sees them, for two independent reasons:

Either mismatch alone keeps the class abstract (verified by bisection in a minimal SWIG module, table in #354); SWIG then treats the pure virtuals as unimplemented and drops the constructors.

The fix spells the overrides exactly like the base — bare Size/Real, with the base's default repeated on getT0/get — and declares %feature("compactdefaultargs") for getT0/get on NPVCube and InMemoryCubeOpt. The feature is load-bearing: without it SWIG emits a reduced-arity call like cube->getT0(i) for the default-argument overload, which does not compile, because the C++ overrides do not repeat the base's default and default arguments are resolved against the static type. It has to be declared for base and overrides alike, and before both classes, or the abstract check stops matching them.

Verified by building the bindings and running them in a debian trixie container (clang 19, swig 4.3, apt boost): both classes construct, values round-trip through set/get at either arity, and overload dispatch on a base-typed NPVCube proxy (index vs trade id, with and without the depth argument) resolves correctly. Warning profile unchanged, independent of the #353 alias fix (verified with and without it applied).

The accompanying test constructs both precisions and round-trips values through set/get; it fails with the abstract-class AttributeError against both released wheels.

…k#354)

SinglePrecisionInMemoryCubeN and DoublePrecisionInMemoryCubeN raised
"No constructor defined - class is abstract" on construction, on the
released 1.8.15.0 and 1.8.16.0 wheels alike. Since NPVCube and
AggregationScenarioData are abstract by design and JointNPVCube only
joins existing cubes, no NPV cube could be built from Python at all.

The InMemoryCubeOpt overrides in orea_cube.i did not textually match the
base's pure virtuals as the SWIG parser sees them, for two independent
reasons:

- getT0/get dropped the base's `= 0` default argument. SWIG expands a
  pure virtual with a default into one required signature per arity, so
  an override without the default satisfies only the full-arity form.
- the parameters were spelled QuantLib::Size/QuantLib::Real, which the
  SWIG parser cannot resolve: the `using QuantLib::Size` that would
  bridge them to the declared `typedef size_t Size` sits inside a %{ %}
  block the parser never sees (the same visibility mechanism as OpenSourceRisk#351).

Either mismatch alone keeps the class abstract; SWIG then treats the
pure virtuals as unimplemented and drops the constructors.

Spell the overrides exactly like the base -- bare Size/Real, with the
base's default repeated on getT0/get -- and declare
%feature("compactdefaultargs") for getT0/get on NPVCube and
InMemoryCubeOpt. The feature is load-bearing: without it SWIG emits a
reduced-arity call like cube->getT0(i) for the default-argument
overload, which does not compile, because the C++ overrides do not
repeat the base's default and default arguments are resolved against
the static type. It has to be declared for base and overrides alike,
and before both classes, or the abstract check stops matching them.

Verified by building the bindings and running them in a debian trixie
container (clang 19, swig 4.3, apt boost): both classes construct,
values round-trip through set/get at either arity, and overload
dispatch on a base-typed NPVCube proxy (index vs trade id, with and
without the depth argument) resolves correctly.

The accompanying test constructs both precisions and round-trips values
through set/get; it fails with the abstract-class AttributeError against
both released wheels.
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.

Python bindings: in-memory NPV cubes are wrongly abstract, no NPVCube is constructible from Python

1 participant