-
Notifications
You must be signed in to change notification settings - Fork 24
Msp disallow needextends on options #544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
MaximilianSoerenPollak
wants to merge
5
commits into
eclipse-score:main
Choose a base branch
from
MaximilianSoerenPollak:MSP_disallow_needextends_on_options
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
f768eba
WIP: Adding needextends forbidden options check
MaximilianSoerenPollak caf57fd
Feat: Enable unmutable options in needextends check
MaximilianSoerenPollak 39dc8b4
Chore: Formatting
MaximilianSoerenPollak dfb0ae7
WIP: Testing.
MaximilianSoerenPollak 87769bd
WIP: testing
MaximilianSoerenPollak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
229 changes: 229 additions & 0 deletions
229
src/extensions/score_metamodel/checks/check_needs_extends.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,229 @@ | ||
| # ******************************************************************************* | ||
| # Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| # | ||
| # See the NOTICE file(s) distributed with this work for additional | ||
| # information regarding copyright ownership. | ||
| # | ||
| # This program and the accompanying materials are made available under the | ||
| # terms of the Apache License Version 2.0 which is available at | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # ******************************************************************************* | ||
| from __future__ import annotations | ||
|
|
||
| import sphinx_needs.directives.need | ||
| from docutils import nodes | ||
| from sphinx_needs.config import NeedsSphinxConfig | ||
| from sphinx_needs.data import ExtendType, NeedsExtendType, NeedsMutable | ||
| from sphinx_needs.exceptions import NeedsInvalidFilter | ||
| from sphinx_needs.filter_common import filter_needs_mutable | ||
| from sphinx_needs.logging import get_logger, log_warning | ||
| from sphinx_needs.need_item import NeedModification | ||
| from sphinx_needs.needs_schema import ( | ||
| FieldFunctionArray, | ||
| FieldLiteralValue, | ||
| LinksFunctionArray, | ||
| LinksLiteralValue, | ||
| ) | ||
|
|
||
|
|
||
| class Needextend(nodes.General, nodes.Element): | ||
| pass | ||
|
|
||
|
|
||
| logger = get_logger(__name__) | ||
|
|
||
|
|
||
| def score_extend_needs_data_func( | ||
| all_needs: NeedsMutable, | ||
| extends: dict[str, NeedsExtendType], | ||
| needs_config: NeedsSphinxConfig, | ||
| ) -> None: | ||
| """Use data gathered from needextend directives to modify fields of existing needs.""" | ||
|
|
||
| # Sort by (docname, lineno) to ensure deterministic ordering, | ||
| # regardless of parallel build worker completion order. | ||
| sorted_extends = sorted(extends.values(), key=lambda x: (x["docname"], x["lineno"])) | ||
|
|
||
| current_needextend: NeedsExtendType | ||
| raise RuntimeError("TESING replacement func") | ||
| for current_needextend in sorted_extends: | ||
| need_filter = current_needextend["filter"] | ||
| location = (current_needextend["docname"], current_needextend["lineno"]) | ||
| if current_needextend["filter_is_id"]: | ||
| try: | ||
| found_needs = [all_needs[need_filter]] | ||
| except KeyError: | ||
| error = f"Provided id {need_filter!r} for needextend does not exist." | ||
| if current_needextend["strict"]: | ||
| raise NeedsInvalidFilter(error) | ||
| log_warning(logger, error, "needextend", location=location) | ||
| continue | ||
| else: | ||
| try: | ||
| found_needs = filter_needs_mutable( | ||
| all_needs, | ||
| needs_config, | ||
| need_filter, | ||
| location=location, | ||
| origin_docname=current_needextend["docname"], | ||
| ) | ||
| except Exception as e: | ||
| log_warning( | ||
| logger, | ||
| f"Invalid filter {need_filter!r}: {e}", | ||
| "needextend", | ||
| location=location, | ||
| ) | ||
| continue | ||
| for found_need in found_needs: | ||
| # Work in the stored needs, not on the search result | ||
| need = all_needs[found_need["id"]] | ||
| need.add_modification( | ||
| NeedModification( | ||
| docname=current_needextend["docname"], | ||
| lineno=current_needextend["lineno"], | ||
| ) | ||
| ) | ||
|
|
||
| location = ( | ||
| current_needextend["docname"], | ||
| current_needextend["lineno"], | ||
| ) | ||
|
|
||
| for option_name, etype, link_value in current_needextend[ | ||
| "list_modifications" | ||
| ]: | ||
| # append link = ok?! | ||
| # replace / remove link = nope | ||
| # set option = ok | ||
| # replace / remove option = nope | ||
| match (etype, link_value): | ||
| case (ExtendType.APPEND, LinksLiteralValue()): | ||
| if (df := need._dynamic_fields.get(option_name)) is not None: | ||
| need._dynamic_fields[option_name] = LinksFunctionArray( | ||
| (*df.value, *link_value.value) | ||
| ) | ||
| need[option_name] = [] | ||
| else: | ||
| existing = need.get_links(option_name, as_str=False) | ||
| need[option_name] = [ | ||
| *existing, | ||
| *( # keep unique | ||
| v for v in link_value.value if v not in existing | ||
| ), | ||
| ] | ||
| case (ExtendType.APPEND, LinksFunctionArray()): | ||
| if (df := need._dynamic_fields.get(option_name)) is not None: | ||
| need._dynamic_fields[option_name] = LinksFunctionArray( | ||
| ( # keep unique | ||
| *df.value, | ||
| *(v for v in link_value.value if v not in df.value), | ||
| ) | ||
| ) | ||
| need[option_name] = [] | ||
| else: | ||
| existing = need.get_links(option_name, as_str=False) | ||
| need._dynamic_fields[option_name] = LinksFunctionArray( | ||
| ( | ||
| *existing, | ||
| *( # keep unique | ||
| v for v in link_value.value if v not in existing | ||
| ), | ||
| ) | ||
| ) | ||
| need[option_name] = [] | ||
| case (ExtendType.REPLACE | ExtendType.DELETE, LinksLiteralValue()): | ||
| error_msg = ( | ||
| "Replace or Delete action is not allowed via needextends." | ||
| ) | ||
| log_warning(logger, error_msg, "needextend", location=location) | ||
| raise RuntimeError(f"{location}: {error_msg}") | ||
| case (ExtendType.REPLACE | ExtendType.DELETE, LinksFunctionArray()): | ||
| error_msg = ( | ||
| "Replace or Delete action is not allowed via needextends." | ||
| ) | ||
| log_warning(logger, error_msg, "needextend", location=location) | ||
| raise RuntimeError(f"{location}: {error_msg}") | ||
| case other_link: | ||
| raise RuntimeError( | ||
| f"Unhandled case {other_link} for {option_name!r}" | ||
| ) | ||
|
|
||
| for option_name, etype, field_value in current_needextend["modifications"]: | ||
| match (etype, field_value): | ||
| case (ExtendType.APPEND, FieldLiteralValue()): | ||
| if (df := need._dynamic_fields.get(option_name)) is not None: | ||
| need._dynamic_fields[option_name] = ( | ||
| FieldFunctionArray((*df.value, *field_value.value)) | ||
| if isinstance(field_value.value, list) | ||
| else FieldFunctionArray((*df.value, field_value.value)) | ||
| ) | ||
| else: | ||
| if isinstance(field_value.value, list): | ||
| need[option_name] = [ | ||
| *need[option_name], | ||
| *field_value.value, | ||
| ] | ||
| elif isinstance(field_value.value, str): | ||
| need[option_name] = ( | ||
| need[option_name] + " " + field_value.value | ||
| if need[option_name] | ||
| else field_value.value | ||
| ) | ||
| else: | ||
| raise RuntimeError( | ||
| f"Cannot append non-string/array value {field_value.value!r} to field '{option_name}'" | ||
| ) | ||
| case (ExtendType.APPEND, FieldFunctionArray()): | ||
| if (df := need._dynamic_fields.get(option_name)) is not None: | ||
| need._dynamic_fields[option_name] = FieldFunctionArray( | ||
| (*df.value, *field_value.value) | ||
| ) | ||
| else: | ||
| if isinstance(need[option_name], list): | ||
| need._dynamic_fields[option_name] = FieldFunctionArray( | ||
| (*need[option_name], *field_value.value) | ||
| ) | ||
| elif isinstance(need[option_name], str): | ||
| need._dynamic_fields[option_name] = FieldFunctionArray( | ||
| ( | ||
| need[option_name], | ||
| *field_value.value, | ||
| ) | ||
| ) | ||
| else: | ||
| raise RuntimeError( | ||
| f"Cannot append non-string/array value {field_value.value!r} to field '{option_name}'" | ||
| ) | ||
| case (ExtendType.REPLACE | ExtendType.DELETE, None): | ||
| error_msg = ( | ||
| "Replace or Delete action is not allowed via needextends." | ||
| ) | ||
| log_warning(logger, error_msg, "needextend", location=location) | ||
| raise RuntimeError(f"{location}: {error_msg}") | ||
| case (ExtendType.REPLACE | ExtendType.DELETE, FieldLiteralValue()): | ||
| error_msg = ( | ||
| "Replace or Delete action is not allowed via needextends." | ||
| ) | ||
| log_warning(logger, error_msg, "needextend", location=location) | ||
| raise RuntimeError(f"{location}: {error_msg}") | ||
| case (ExtendType.REPLACE | ExtendType.DELETE, FieldFunctionArray()): | ||
| error_msg = ( | ||
| "Replace or Delete action is not allowed via needextends." | ||
| ) | ||
| log_warning(logger, error_msg, "needextend", location=location) | ||
| raise RuntimeError(f"{location}: {error_msg}") | ||
| # TODO reset need[option_name] to something sensible? | ||
| case other_field: | ||
| raise RuntimeError( | ||
| f"Unhandled case {other_field} for {option_name!r}" | ||
| ) | ||
|
|
||
|
|
||
| sphinx_needs.directives.need.extends_needs_data = score_extend_needs_data_func | ||
|
|
||
| print("=====================================") | ||
| print("WE HAVE REPLACED THE EXTENDS FUNC") | ||
| print("=====================================") | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The word is "immutable".