Skip to content

Implement Annotation config types - #106

Open
dmartmillan wants to merge 20 commits into
milestone/v2.0.0from
64-implement-annotation-config-types
Open

Implement Annotation config types#106
dmartmillan wants to merge 20 commits into
milestone/v2.0.0from
64-implement-annotation-config-types

Conversation

@dmartmillan

@dmartmillan dmartmillan commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

This pull request corresponds to Implement Annotation config types, implement Annotation configuration and its validator along with its tests. Relates to #64 issue.

In a way of mimicking openvariant/annotation/config_annotation.py and openvariant/annotation/annotation.py from Python-based implementation.

  • Added src/annotation/config.rs, which defines the Annotation structure.
  • Added src/annotation/validator.rs, including the main functions for parsing and validating the format of Annotation YAML files.
  • Added the first Rust-based tests in src/tests/test_annotation/, which can be run with make test.
  • Added Rust test execution to the GitHub workflow.
  • Updated the Makefile to support Rust formatting and linting:
    • make fix: automatically fixes formatting and lint issues using clippy.
    • make check: verifies formatting and lint correctness.

For the moment, I didn't think about Warnings, only error. But they can be added.

If there are any tests missing, or if the validation is missing something, let me know. Also, I added tests inside src/ folder which I don't know if the best practice... because we have Python-based tests in the main folder as tests/

@dmartmillan dmartmillan linked an issue Jun 12, 2026 that may be closed by this pull request
3 tasks
@dmartmillan
dmartmillan changed the base branch from master to milestone/v2.0.0 June 12, 2026 14:47
@dmartmillan dmartmillan self-assigned this Jun 12, 2026
@dmartmillan dmartmillan added enhancement New feature or request test Tests relate labels Jun 12, 2026
@dmartmillan dmartmillan added this to the OpenVariant v2.0.0 milestone Jun 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a Rust-native annotation configuration model (serde/YAML compatible) plus validation logic and unit tests, wiring the new annotation module into the crate and CI.

Changes:

  • Added serde-compatible annotation config types (AnnotationType, AnnotationDelimiter, AnnotationFormat, and config structs) and re-exported them via src/annotation/mod.rs.
  • Implemented YAML parse + validation entrypoints (parse_and_validate, validate_config) and added unit tests for config round-trips and validation scenarios.
  • Updated build tooling and CI to run Rust tests, added stricter clippy settings, and introduced serde/yaml_serde dependencies.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/annotation/config.rs New serde/YAML config enums + structs for annotation configuration.
src/annotation/mod.rs New module entrypoint and public re-exports for config + validator APIs.
src/annotation/validator.rs New YAML parse + validation logic for annotation configs.
src/lib.rs Exposes annotation module publicly and enables in-crate unit tests.
src/tests/mod.rs Adds crate unit test module root.
src/tests/test_annotation/mod.rs Adds annotation test module wiring.
src/tests/test_annotation/test_config.rs Round-trip YAML serialization/deserialization tests for enums + config defaults.
src/tests/test_annotation/test_validator.rs Tests for validator success and error cases.
Cargo.toml Adds serde and yaml_serde dependencies needed for YAML config support.
Cargo.lock Lockfile updates for new dependencies.
Makefile Adds fmt/fix targets and makes clippy warnings fatal in lint/check.
.github/workflows/openvariant_tester.yml Runs Rust tests in CI in addition to existing Python tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tests/test_annotation/test_validator.rs
Comment thread src/annotation/validator.rs Outdated
Comment thread src/annotation/validator.rs
Comment thread src/annotation/validator.rs Outdated
Comment thread src/annotation/validator.rs Outdated
Comment thread src/annotation/config.rs
Comment thread src/annotation/config.rs Outdated
Comment thread src/annotation/config.rs Outdated
Comment thread src/annotation/config.rs
Comment thread src/annotation/config.rs
dmartmillan and others added 10 commits June 16, 2026 14:35
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…lab/openvariant into 64-implement-annotation-config-types

@FedericaBrando FedericaBrando left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks David for the work - very fun to review!

I have added some comments to be address, given the conversation we had on Slack.

Some other points:

  • We should check if the fileMapping exists and fail fast if the file does not exist, also we should allow absolute paths, not only relatives to the yaml
  • We should enforce the function field to start with lambda [var] : funct()
  • One of the main pain points in openvariant as of now is the lack of error message when a field fails. Here we could be more verbose about what is failing during validation

Below I attach a git diff patch to be applied with suggested changes. Feel free to remove, change, or discard them if you think this is not what you were thinking.

Thanks!

pr-105-review.patch

Comment thread src/annotation/config.rs
Comment on lines +95 to +122
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub enum AnnotationDelimiter {
/// Tab character (`\t`).
#[default]
T,
/// Comma character (`,`).
C,
}

impl AnnotationDelimiter {
/// Returns the delimiter as a `char`.
pub fn as_char(&self) -> char {
match self {
AnnotationDelimiter::T => '\t',
AnnotationDelimiter::C => ',',
}
}
}

impl fmt::Display for AnnotationDelimiter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
AnnotationDelimiter::T => "T",
AnnotationDelimiter::C => "C",
};
write!(f, "{s}")
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember we added a feature where the delimiter could be detected automatically if the user did not set it - how this implementation include also the above mentioned case? Given that we are given as delimiter T or C and we default to T, if none is provided? #52

Comment thread src/annotation/config.rs
/// AnnotationFormat

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub enum AnnotationFormat {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't we use:

#[serde(rename_all = "UPPERCASE")]

Comment thread src/annotation/config.rs
/// AnnotationEntry

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AnnotationEntry {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are using a struct, althugh serde does implement a tagged enum that maybe is useful in our case, and enforces the annotation field to have the correct entries.

#[serde(tag = "type", rename_all = "lowercase")]
enum AnnotationEntry {
    Static {
        field: String,
        value: yaml_serde::Value,
    },
    Internal {
        field: String,
        #[serde(default)]
        value: Option<String>,                
        field_source: <Vec<String>>,    
        #[serde(default)]
        function: Option<String>,             
    },
    Filename {
        field: String,
        #[serde(default)]
        function: Option<String>,
        #[serde(default)]
        regex: Option<String>,
    },
    Dirname {
        field: String,
        #[serde(default)]
        function: Option<String>,
        #[serde(default)]
        regex: Option<String>,
    },
    Plugin {
        field: String,
        plugin: String,                       
    },
    Mapping {
        field: String,
        field_source: Vec<String>,           
        field_mapping: String,
        file_mapping: String,
        field_value: String,
    },
}

// Plugin
AnnotationType::Plugin => {
check_required_str(&base, "plugin", entry.plugin.as_deref(), &mut diags);
check_required_str(&base, "function", entry.function.as_deref(), &mut diags);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function is not a field of Plugin, it is in fact a field of filename, dirname or internal right?

///
/// Returns *all* diagnostics (errors and warnings) found.
/// An empty `Vec<ValidationError>` means the configuration is fully valid, no errors found.
pub fn validate_config(config: &AnnotationConfig) -> Vec<ValidationError> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we use serde tagged enums, then we could reduce the fields that are validated. For example only validate non duplicated field within a list, if the values are non-empty and all the things that you can't validate with structure.

/// included for context).
pub fn parse_and_validate(yaml: &str) -> Result<AnnotationConfig, Vec<ValidationError>> {
// Pass 1 — syntax + structural (serde)
let config: AnnotationConfig = yaml_serde::from_str(yaml).map_err(|e| {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here couldn't we read it from a buffer directly?

https://docs.rs/yaml_serde/latest/yaml_serde/fn.from_reader.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request test Tests relate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Annotation config types

3 participants