Skip to content

02: Functions: Constructor Issues #144

@dschwartznyc

Description

@dschwartznyc

Bug Report

There are two issues:

1. Title: Partial Object Construction (Stepwise Initialization)

Problem Description:

Rosetta functions often populate an output object through multiple set operations. Pydantic's default constructor (used by the legacy _get_rune_object) enforces validation of all required fields immediately. If the object is missing other required fields during the first set operation, Pydantic throws a ValidationError. Additionally, _get_rune_object fails with a KeyError because it cannot resolve classes from the generated _bundle module's namespace.

Note: Invalid Rune is not supported

As with all aspects of the generator, this functionality only applies to valid Rune models. If a model is invalid, it will be discarded before generation. For example, the following is invalid Rune and would be skipped:

type IncompleteObject:
    value1 int (1..1)
    value2 int (1..1)

func TestIncompleteObjectReturn:
    inputs:
        value1 int (1..1)
    output:
        result IncompleteObject (1..1)
    set result:
        IncompleteObject {
            value1: value1
        }

Steps to Reproduce:

  1. Define a Rosetta type with multiple required fields.
  2. Define a Rosetta function that sets these fields one by one.
  3. Call the function in Python.

Example Rune code: IncompleteObjects.rosetta

type A:
    a1 int (1..1)
    a2 int (1..1)

func CreateA:
    inputs:
        a1 int (1..1)
    output:
        a A (1..1)
    set a->a1: a1
    set a->a2: a1 * 2

Test Case:

  • Python: test/python_unit_tests/features/language/test_incomplete_objects.py
  • Rosetta: test/python_unit_tests/features/language/IncompleteObjects.rosetta

Other Tests (currently disabled/skipped):

Rune: FunctionTest.rosetta
Python Unit Tests: test_functions_object_creation.py

  • def test_create_incomplete_object_succeeds_in_python():
  • def test_complex_type_inputs():

Expected Result:

The object should be constructed successfully in steps, with validation deferred until the object is fully populated or explicitly validated.

Actual Result:

The below generated Python produces two errors:

  • KeyError: _get_rune_object cannot find the model class in the rune.runtime.utils namespace.
  • ValidationError: If the class is found, Pydantic fails immediately on the first set because required fields are still None.
@replaceable
@validate_call
def rosetta_dsl_test_language_IncompleteObjects_functions_CreateA(a1: int) -> rosetta_dsl_test_language_IncompleteObjects_A:
    """

    Parameters
    ----------
    a1 : int

    Returns
    -------
    a : rosetta_dsl.test.language.IncompleteObjects.A

    """
    self = inspect.currentframe()


    a = _get_rune_object('rosetta_dsl_test_language_IncompleteObjects_A', 'a1', rune_resolve_attr(self, "a1"))
    a = set_rune_attr(rune_resolve_attr(self, 'a'), 'a2', (rune_resolve_attr(self, "a1") * 2))


    return a

Additional Context:

Partial fix implemented in PythonFunctionGenerator.java by switching to model_construct(), but full removal of _get_rune_object is still pending.

2. Title: Fragile Object Building (Direct Constructors)

The generator relies on a magic _get_rune_object helper which bypasses IDE checks and is hard to debug. This helper attempts to resolve model classes from the global namespace, which is fragile and leads to isolation issues when multiple bundles are present.

Steps to Reproduce:

  1. Define a Rosetta function that creator a new object (e.g., using set).
  2. Observe the generated code calling _get_rune_object.

Example Rune code: (See JUnit Test testComplexSetConstructors)

type ObservationIdentifier:
    observable Observable (1..1)
    observationDate date (1..1)

func ResolveObservation:
    inputs: date date (1..1)
    output: identifiers ObservationIdentifier (1..1)
    set identifiers -> observationDate:
        date

Test Case:

  • JUnit: PythonFunctionTypeTest.testComplexSetConstructors (Disabled)

Expected Result:

The generator should emit direct Python constructor calls (e.g., MyClass(attr=val)) or standard Pydantic methods, providing full IDE support and transparency.

Actual Result:

Generated code uses _get_rune_object(base_model, attribute, value), which is opaque to static analysis.
In some cases, when the generator uses _get_rune_object when it encounters the need to create a new object. This function does not perform as expected, it bypasses IDE checks and is hard to debug.

Proposed Solution:

Refactor PythonFunctionGenerator to use direct Python constructor calls (e.g., MyClass(attr=val)).

Sub-issues

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions