Replies: 6 comments 3 replies
-
|
@Yicong-Huang Could you share any advice on this? Thank you so much! |
Beta Was this translation helpful? Give feedback.
-
|
@kz930 Before other people provide comments, please use a real example with a diagram to explain the details. @carloea2 : as you are the mentor of this project, please chime in to provide your thoughts. |
Beta Was this translation helpful? Give feedback.
-
|
In my opinion, for each operator, we should define a function that returns a small sample dataset. This dataset can then be used as input to test the outputs in both Python Translation and the Texera engine. I also think it would be a good idea to include a method for instantiating an operator instance that can consume this input by filling in the required properties. These properties may belong to different domains, so automating this process reliably would be difficult, or even impossible. |
Beta Was this translation helpful? Give feedback.
-
|
@kz930 Can you draw a diagram to visualize a workflow and explain how it's translated? That could be easier to understand than your current diagrams. |
Beta Was this translation helpful? Give feedback.
-
|
@kz930 Per our offline meeting, please describe what changes we want to make for each operator. We need to first finish existing operators, then make a plan for future operators. |
Beta Was this translation helpful? Give feedback.
-
|
@chenlica Following our meeting, here is the concrete per-operator change, using the two simple cases we discussed. For each operator, making it verifiable should be a small and uniform change:
Two simple examples:
Plan: first finish and verify the existing operators one by one with this plan. Then, for future operators: shared fixture by default; when it can't represent the operator's input well, the author provides a small dataset for a more accurate test. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
We've been working on translating Texera workflows into standalone Python scripts and verifying that the translation is correct. We've built a working prototype for making verification scale: a shared fixture plus automatic per-operator configuration. It already runs — operators are auto-discovered and each is verified against the shared fixture, and concrete cases like CSVScan and ChoroplethMap pass end-to-end. Before we invest more in widening coverage, we'd like input on whether this shared-fixture direction is the right foundation.
Background: the two workflows
Translation. A Texera workflow is converted into a standalone Python script. The UI sends the workflow to the translator, the translator asks each operator for its code fragment, and the fragments are stitched together into one
.pyfile that is returned to the user.Verification. To check the translation is correct, we run each operator two ways: first through the native Texera execution path (the ground truth), then through the generated Python script. We compare the outputs from both paths. If they match, the translation is considered faithful.
Problem: verification does not scale
The current verification approach requires one hand-written test case per operator, and each test case needs its own input data and operator configuration.
This does not scale. Texera has around 150 operators, and more are added over time. Manually writing and maintaining a fixture for every operator is too much work.
Options considered
1. Keep hand-writing a fixture per operator (status quo). Accurate, but the maintenance cost grows with every new operator — the thing we're trying to get away from.
2. One shared CSV fixture + automatic configuration. Instead of a separate fixture per operator, build a single large shared CSV and auto-configure each operator against it, so a new
operator needs little or no additional hand-written test code. (This is the direction we currently lean toward — details below.)
3. Per-operator generated/synthetic input. Generate input tailored to each operator's declared schema on the fly. More precise per operator, but closer in spirit to the status quo and
harder to keep meaningful across domains.
Our current position / proposed plan
For most table-based operators, use one large shared CSV fixture. Each operator is tested against this shared input table, and its configuration is filled automatically.
Designing the shared CSV. We scan operator fields and identify what each field needs — numeric columns, text columns, date columns, country codes, p-values in (0,1), price-related columns,
and other domain-specific values — and add meaningful columns to cover those needs.
Testing an operator. Feed the shared CSV into the operator, auto-fill its configuration, run both the native path and the generated Python path, and compare outputs. Since both paths use
the same input and the same configuration, any output difference should indicate a translation bug.
Choosing a column for a field (two steps):
If a field can't be filled meaningfully, we flag it rather than silently passing the test.
Filling non-column settings (by type):
Example:
ChoroplethMapChoroplethMapdraws a world map. It has two column-reference fields:locations— needs a country codecolor— needs a numeric columnAgainst the shared CSV:
auto-config fills the two fields using the two steps above:
color→id— match by type (first numeric column)locations→iso_country— match by domain (a plain text column likenamewould render nothing, so it needs the country-code column)This gives the config
{ locations: "iso_country", color: "id" }. Both paths then run on the same input + same config. If the outputs match, the translation is faithful.locations = iso_countryisexactly the "match by domain" case: with any text column the map draws nothing and the test would be vacuous — the country-code column makes it a real test.
An example workflow ending in
ChoroplethMapEach box in the diagram becomes one code block below; each arrow —
df1,df2,df3— is the DataFrame variable handed to the next operator. The translator walks the workflow in topological order and stitches these fragments into one script.Each operator emits its fragment using placeholders — it doesn't know its neighbors. For example, Filter always generates:
The translator sees that Filter's input comes from CSV Scan (
df1) and assigns Filter's own outputdf2, then substitutes the placeholders:Doing this for every operator in topological order — and concatenating the results — produces the full script below:
Special cases
generated). Only a few should be needed, since the stitching mainly has to cover a handful of shapes — simple chains, fan-out, joins, and multiple-output operators.
Next steps (tentative)
What we'd like input on
Beta Was this translation helpful? Give feedback.
All reactions