Skip to content

Introduce composite tags#3347

Open
mraspaud wants to merge 3 commits intopytroll:mainfrom
mraspaud:composite_tags
Open

Introduce composite tags#3347
mraspaud wants to merge 3 commits intopytroll:mainfrom
mraspaud:composite_tags

Conversation

@mraspaud
Copy link
Member

@mraspaud mraspaud commented Mar 3, 2026

This PR introduce a system of tagging for composites, allowing switching preferred variants at load time or by configuration.

For example, having the following config:

  true_color_crefl:
    tags: ["crefl"]
    compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB
    prerequisites: ...
    standard_name: true_color

  true_color_raw:
    tags: ["raw"]
    compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB
    prerequisites: ...
    standard_name: true_color

  true_color:
    compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB
    prerequisites: ...
    standard_name: true_color

  true_color_nocorr:
    tags: ["nocorr"]
    compositor: !!python/name:satpy.composites.resolution.SelfSharpenedRGB
    prerequisites: ...
    standard_name: true_color

We can then load scn.load(["true_color:crefl"]) directly to load "true_color_crefl". Alternatively, we can set the config with SATPY_PREFERRED_COMPOSITE_TAGS=crefl so that scn.load(["true_color"]) loads "true_color_crefl" by default.

This is needed in order implement WMO RGB recommendations in a backwards- and forwards-compatible manner.

Also, possibility to warn for composites at load time has been added.

Disclaimer: AI was used in the design and implementation of this PR.

  • Tests added
  • Fully documented

@mraspaud mraspaud self-assigned this Mar 3, 2026
@mraspaud mraspaud added enhancement code enhancements, features, improvements component:compositors labels Mar 3, 2026
@mraspaud mraspaud requested review from djhoese and pnuu as code owners March 3, 2026 11:11
@codecov
Copy link

codecov bot commented Mar 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.33%. Comparing base (21b03f6) to head (7557662).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3347      +/-   ##
==========================================
- Coverage   96.34%   96.33%   -0.01%     
==========================================
  Files         463      463              
  Lines       58959    59048      +89     
==========================================
+ Hits        56802    56883      +81     
- Misses       2157     2165       +8     
Flag Coverage Δ
behaviourtests 3.60% <8.33%> (+<0.01%) ⬆️
unittests 96.42% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gerritholl
Copy link
Member

This looks great!

This PR adds a special meaning to "standard_name". Does this break backward compatibility? If I understand correctly, loading composites will no longer match by the key in the YAML file, but by the contents of the standard name?

We (at least in DWD) currently (ab)use "standard_name" to get a match between a composite and its enhancement. For example, we have many composites with standard name image_ready. I've always felt a bit uneasy by using the standard name attribute for making this match, and this PR might bite with our current use.

As an example of what we currently use:

  day_cloud_type:
    compositor: !!python/name:satpy.composites.fill.DayNightCompositor
    day_night: day_only
    prerequisites:
    - name: cloud_type
    standard_name: image_ready

Is this still loadable as sc.load(["day_cloud_type"])? Or would this be matched only by sc.load(["image_ready"])?

Copy link
Member

@pnuu pnuu left a comment

Choose a reason for hiding this comment

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

Some comments inline. I guess the variant loading without defining the variant in any way will need a test where different combinations are defined as options.


1. Try each tag in the list, in order, looking for a compositor with matching
``standard_name`` and that tag.
2. If no tagged variant is found, fall back to the normal name-based lookup.
Copy link
Member

Choose a reason for hiding this comment

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

Which variant is used if the tag is not defined in the load and the global env variable is not set and all/some of the following composites are defined?

  • foo_wmo
  • foo_crefl
  • foo

Each of them have the same standard_name: foo defined, no name is set. Only the first line in the YAML definition is different and for the first two there are tags set.

So what would I get with scn.load(["foo"]) call in the following cases:

  1. all variants are defined (I'd expect foo variant without any tags)
  2. only the two tagged versions are defined

Copy link
Member Author

Choose a reason for hiding this comment

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

If tags are not provided, neither at load time or in the configuration, the current behaviour is preserved, ie we will use the name (not standard name) to choose the composite to load.

  1. you get the composite name "foo"
  2. crash if you don't provide a tag (at load time or as config).

Copy link
Member

Choose a reason for hiding this comment

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

So something like this for the first case? I'm not sure how this works, but hopefully it's close enough:

        pytest.param(
            {"comp1": None, "comp1_wmo": ["wmo"]},
            None,
            "comp1",
            "comp1",
            id="use_plain_version_when_no_tag",
        ),

For case 2. the failure might need a completely separate test?


export SATPY_PREFERRED_COMPOSITE_TAGS=crefl,wmo

Or as a YAML configuration key:
Copy link
Member

Choose a reason for hiding this comment

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

In which config file should this be defined?

Copy link
Member Author

Choose a reason for hiding this comment

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

at the top of this file, you have your answer :)

YAML Configuration

YAML files that include these parameters can be in any of the following
locations:

  1. <python environment prefix>/etc/satpy/satpy.yaml
  2. <user_config_dir>/satpy.yaml (see below)
  3. ~/.satpy/satpy.yaml
  4. <SATPY_CONFIG_PATH>/satpy.yaml (see :ref:config_path_setting below)

Copy link
Member Author

Choose a reason for hiding this comment

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

sorry, it was actually in config.rst

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I didn't even know we had a satpy.yaml config file 😅

@pnuu
Copy link
Member

pnuu commented Mar 3, 2026

Good point Gerrit. I think that is actually the only use-case for standard_name for me, linking the composite and enhancement together. I think this is also related to my variant selection comment.

@mraspaud
Copy link
Member Author

mraspaud commented Mar 3, 2026

This looks great!

Thanks :)

This PR adds a special meaning to "standard_name". Does this break backward compatibility? If I understand correctly, loading composites will no longer match by the key in the YAML file, but by the contents of the standard name?

It is backwards compatible. Names of compositors that do not contain ":" are processed as usual.
The use of the standard name here is because it was the closest thing to a common name for different variants we had, so I used that instead of introducing an new item in the composite config.

We (at least in DWD) currently (ab)use "standard_name" to get a match between a composite and its enhancement. For example, we have many composites with standard name image_ready. I've always felt a bit uneasy by using the standard name attribute for making this match, and this PR might bite with our current use.

As an example of what we currently use:

  day_cloud_type:
    compositor: !!python/name:satpy.composites.fill.DayNightCompositor
    day_night: day_only
    prerequisites:
    - name: cloud_type
    standard_name: image_ready

Is this still loadable as sc.load(["day_cloud_type"])? Or would this be matched only by sc.load(["image_ready"])?

We use the same thing at SMHI, and the current behaviour should be unaffected. I agree it's not really clean to use standard_name for this purpose, would be nice if we had a good solution for that.

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

Labels

component:compositors enhancement code enhancements, features, improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants