From 78d660fc8147c060f09160d3087bac96f42f1976 Mon Sep 17 00:00:00 2001 From: Aymen-Soussi-01 Date: Thu, 14 Aug 2025 10:11:13 +0200 Subject: [PATCH 1/2] Fix most of line length errors plus some other errors --- .../score_draw_uml_funcs/__init__.py | 10 +-- .../score_draw_uml_funcs/helpers.py | 3 +- .../score_header_service/__init__.py | 1 + .../test/test_header_service.py | 3 +- .../test/test_header_service_integration.py | 5 +- src/extensions/score_layout/__init__.py | 3 +- src/extensions/score_layout/html_options.py | 3 +- src/extensions/score_metamodel/__init__.py | 14 ++- .../checks/attributes_format.py | 21 +++-- .../score_metamodel/checks/graph_checks.py | 8 +- .../checks/id_contains_feature.py | 10 ++- .../score_metamodel/checks/standards.py | 8 +- .../score_metamodel/external_needs.py | 12 +-- .../score_metamodel/tests/__init__.py | 8 +- .../tests/test_check_options.py | 3 +- .../score_metamodel/tests/test_standards.py | 6 +- src/extensions/score_plantuml.py | 3 +- .../score_source_code_linker/__init__.py | 18 ++-- .../generate_source_code_links_json.py | 25 +----- .../score_source_code_linker/needlinks.py | 8 +- .../tests/test_requirement_links.py | 22 ++--- .../tests/test_source_link.py | 24 +++-- src/tests/test_consumer.py | 88 ++++++++++++------- 23 files changed, 170 insertions(+), 136 deletions(-) diff --git a/src/extensions/score_draw_uml_funcs/__init__.py b/src/extensions/score_draw_uml_funcs/__init__.py index 00712bcbf..e3f254ecf 100644 --- a/src/extensions/score_draw_uml_funcs/__init__.py +++ b/src/extensions/score_draw_uml_funcs/__init__.py @@ -42,9 +42,7 @@ get_impl_comp_from_logic_iface, get_interface_from_component, get_interface_from_int, - get_logical_interface_real, get_module, - get_real_interface_logical, ) from sphinx.application import Sphinx from sphinx_needs.logging import get_logger @@ -97,10 +95,10 @@ def draw_comp_incl_impl_int( :param dict[str,str] need: Component which should be drawn :param dict all_needs: Dictionary containing all needs - :param dict[str,dict] proc_impl_interfaces: Dictionary containing all implemented interfaces - which were already processed during this cycle - :param dict[str,dict] proc_used_interfaces: Dictionary containing all used interfaces - which were already processed during this cycle + :param dict[str,dict] proc_impl_interfaces: Dictionary containing + all implemented interfaces which were already processed during this cycle + :param dict[str,dict] proc_used_interfaces: Dictionary containing + all used interfaces which were already processed during this cycle """ # Draw outer component structure_text = f"{gen_struct_element('component', need)} {{\n" diff --git a/src/extensions/score_draw_uml_funcs/helpers.py b/src/extensions/score_draw_uml_funcs/helpers.py index ef59ebbe5..09594a1d9 100644 --- a/src/extensions/score_draw_uml_funcs/helpers.py +++ b/src/extensions/score_draw_uml_funcs/helpers.py @@ -269,7 +269,8 @@ def get_logical_interface_real( logical_ifop_need = all_needs.get(logical_ifop[0]) if not logical_ifop_need: logger.info( - f"{real_ifop}: Logical Interface Operation Need not defined, probably misspelled!" + f"{real_ifop}: Logical Interface Operation Need not defined, " + "probably misspelled!" ) continue diff --git a/src/extensions/score_header_service/__init__.py b/src/extensions/score_header_service/__init__.py index 829d51543..b82187f51 100644 --- a/src/extensions/score_header_service/__init__.py +++ b/src/extensions/score_header_service/__init__.py @@ -11,6 +11,7 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* from sphinx.application import Sphinx + from src.extensions.score_header_service.header_service import register diff --git a/src/extensions/score_header_service/test/test_header_service.py b/src/extensions/score_header_service/test/test_header_service.py index 3c232642a..b02ed58de 100644 --- a/src/extensions/score_header_service/test/test_header_service.py +++ b/src/extensions/score_header_service/test/test_header_service.py @@ -15,9 +15,10 @@ from unittest.mock import ANY, MagicMock, patch import pytest -import src.extensions.score_header_service.header_service as hs from sphinx.util.docutils import SphinxDirective +import src.extensions.score_header_service.header_service as hs + @pytest.fixture(scope="session", autouse=True) def add_metadata(record_testsuite_property: Callable[[str, str | list[str]], None]): diff --git a/src/extensions/score_header_service/test/test_header_service_integration.py b/src/extensions/score_header_service/test/test_header_service_integration.py index ef7d9f839..3caf69e0a 100644 --- a/src/extensions/score_header_service/test/test_header_service_integration.py +++ b/src/extensions/score_header_service/test/test_header_service_integration.py @@ -16,7 +16,6 @@ from unittest.mock import MagicMock, patch import pytest -import src.extensions.score_header_service.header_service as hs from pytest import TempPathFactory from sphinx.testing.util import SphinxTestApp @@ -85,8 +84,8 @@ def wrapper(use_github_data: bool = True): "src.extensions.score_header_service", ] needs_types = [ - dict(title = "Review Header", directive = "review_header", color="#BFD8D2", style="node", - prefix = "review_header__"), + dict(title = "Review Header", directive = "review_header", + color="#BFD8D2", style="node", prefix = "review_header__"), ] needs_id_regex = ".*" needs_extra_options = [ diff --git a/src/extensions/score_layout/__init__.py b/src/extensions/score_layout/__init__.py index 3e534819c..aa1b07619 100644 --- a/src/extensions/score_layout/__init__.py +++ b/src/extensions/score_layout/__init__.py @@ -37,7 +37,8 @@ def update_config(app: Sphinx, _config: Any): # Setting HTML static path # For now this seems the only place this is used / needed. - # In the future it might be a good idea to make this available in other places, maybe via the 'find_runfiles' lib + # In the future it might be a good idea to make this available in other places, + # maybe via the 'find_runfiles' lib if r := os.getenv("RUNFILES_DIR"): dirs = [str(x) for x in Path(r).glob("*score_docs_as_code+")] if dirs: diff --git a/src/extensions/score_layout/html_options.py b/src/extensions/score_layout/html_options.py index 24ada62ab..5794a9bd0 100644 --- a/src/extensions/score_layout/html_options.py +++ b/src/extensions/score_layout/html_options.py @@ -73,7 +73,8 @@ def return_html_context(app: Sphinx) -> dict[str, str]: and not app.config.html_context.get("github_repo") ): return { - # still required for use_edit_page_button and other elements except version switcher + # still required for use_edit_page_button and other elements + # except version switcher "github_user": "dummy", "github_repo": "dummy", "github_version": "main", diff --git a/src/extensions/score_metamodel/__init__.py b/src/extensions/score_metamodel/__init__.py index 4e2b32ec4..1127a3b4b 100644 --- a/src/extensions/score_metamodel/__init__.py +++ b/src/extensions/score_metamodel/__init__.py @@ -105,7 +105,8 @@ def _run_checks(app: Sphinx, exception: Exception | None) -> None: if exception: return - # Filter out external needs, as checks are only intended to be run on internal needs. + # Filter out external needs, as checks are only intended to be run + # on internal needs. needs_all_needs = SphinxNeedsData(app.env).get_needs_view() logger.debug(f"Running checks for {len(needs_all_needs)} needs") @@ -145,13 +146,14 @@ def is_check_enabled(check: local_check_function | graph_check_function): if log.has_infos: log.info( - "Some needs have issues related to the new checks. See the log for more information." + "Some needs have issues related to the new checks. " + "See the log for more information." ) # TODO: exit code def convert_checks_to_dataclass(checks_dict) -> list[ProhibitedWordCheck]: - prohibited_words_checks = [ + return [ ProhibitedWordCheck( name=check_name, option_check={k: v for k, v in check_config.items() if k != "types"}, @@ -159,7 +161,6 @@ def convert_checks_to_dataclass(checks_dict) -> list[ProhibitedWordCheck]: ) for check_name, check_config in checks_dict.items() ] - return prohibited_words_checks def load_metamodel_data(): @@ -190,11 +191,6 @@ def load_metamodel_data(): proh_checks_dict = data.get("prohibited_words_checks", {}) prohibited_words_checks = convert_checks_to_dataclass(proh_checks_dict) - # prohibited_words_checks= [ProhibitedWordCheck(**check) for check in pro_checks.values()] - - # stop_words_list = global_base_options.get("prohibited_words", {}).get("title", []) - # weak_words_list = global_base_options.get("prohibited_words", {}).get("content", []) - # Default options by sphinx, sphinx-needs or anything else we need to account for default_options_list = default_options() diff --git a/src/extensions/score_metamodel/checks/attributes_format.py b/src/extensions/score_metamodel/checks/attributes_format.py index 608bd82fd..2d3a6cb39 100644 --- a/src/extensions/score_metamodel/checks/attributes_format.py +++ b/src/extensions/score_metamodel/checks/attributes_format.py @@ -40,11 +40,15 @@ def check_id_format(app: Sphinx, need: NeedsInfoType, log: CheckLogger): if id_parts_len != expected_parts: msg = "" if expected_parts == 2: - msg = "expected to consist of this format: `__`. Only one '__' is allowed in this need's id." + msg = ( + "expected to consist of this format: `__`. " + "Only one '__' is allowed in this need's id." + ) elif expected_parts == 3: msg = ( "expected to consist of this format: " - "`____`. Only two '__' are allowed in this need's id." + "`____`. " + "Only two '__' are allowed in this need's id." ) log.warning_for_option(need, "id", msg) @@ -56,8 +60,9 @@ def check_id_length(app: Sphinx, need: NeedsInfoType, log: CheckLogger): While the recommended limit is 30 characters, this check enforces a strict maximum of 45 characters. If the ID exceeds 45 characters, a warning is logged specifying the actual length. - Any examples that are required to have 3 parts (2x'__') have an exception, and get 17 extra characters - to compensate for the lenght of `_example_feature_` that would be replaced by actually feature names. + Any examples that are required to have 3 parts (2x'__') have an exception, + and get 17 extra characters to compensate for the lenght of `_example_feature_` + that would be replaced by actually feature names. --- """ max_lenght = 45 @@ -67,7 +72,8 @@ def check_id_length(app: Sphinx, need: NeedsInfoType, log: CheckLogger): if len(need["id"]) > max_lenght: msg = ( f"exceeds the maximum allowed length of 45 characters " - f"(current length: {len(need['id']) if 'example_feature' not in need['id'] else len(need['id']) - 17})." + "(current length: " + f"{len(need['id']) if 'example_feature' not in need['id'] else len(need['id']) - 17})." ) log.warning_for_option(need, "id", msg) @@ -82,7 +88,10 @@ def _check_options_for_prohibited_words( forbidden_words = prohibited_word_checks.option_check[option] for word in need[option].split(): if word in forbidden_words: - msg = f"contains a weak word: `{word}` in option: `{option}`. Please revise the wording." + msg = ( + f"contains a weak word: `{word}` in option: `{option}`. " + "Please revise the wording." + ) log.warning_for_need(need, msg) diff --git a/src/extensions/score_metamodel/checks/graph_checks.py b/src/extensions/score_metamodel/checks/graph_checks.py index 06b7a200d..fae247eef 100644 --- a/src/extensions/score_metamodel/checks/graph_checks.py +++ b/src/extensions/score_metamodel/checks/graph_checks.py @@ -158,7 +158,8 @@ def check_metamodel_graph( check_to_perform: dict[str, str | dict] = check_config.get("check") explanation = check_config.get("explanation", "") assert explanation != "", ( - f"Explanation for graph check {check_name} is missing. Explanations are mandatory for graph checks." + f"Explanation for graph check {check_name} is missing. " + "Explanations are mandatory for graph checks." ) # Get all needs matching the selection criteria selected_needs = filter_needs_by_criteria( @@ -168,7 +169,10 @@ def check_metamodel_graph( for need in selected_needs: for parent_relation in list(check_to_perform.keys()): if parent_relation not in need: - msg = f"Attribute not defined: `{parent_relation}` in need `{need['id']}`." + msg = ( + f"Attribute not defined: `{parent_relation}` " + f"in need `{need['id']}`." + ) log.warning_for_need(need, msg) continue diff --git a/src/extensions/score_metamodel/checks/id_contains_feature.py b/src/extensions/score_metamodel/checks/id_contains_feature.py index d71150986..f347f7cba 100644 --- a/src/extensions/score_metamodel/checks/id_contains_feature.py +++ b/src/extensions/score_metamodel/checks/id_contains_feature.py @@ -13,13 +13,12 @@ import os import re -from sphinx.application import Sphinx -from sphinx_needs.data import NeedsInfoType - from score_metamodel import ( CheckLogger, local_check, ) +from sphinx.application import Sphinx +from sphinx_needs.data import NeedsInfoType @local_check @@ -66,5 +65,8 @@ def id_contains_feature(app: Sphinx, need: NeedsInfoType, log: CheckLogger): log.warning_for_option( need, "id", - f"Featurepart '{featureparts}' not in path '{docname}' or abbreviation not ok, expected: '{initials}'.", + ( + f"Featurepart '{featureparts}' not in path '{docname}' " + f"or abbreviation not ok, expected: '{initials}'." + ), ) diff --git a/src/extensions/score_metamodel/checks/standards.py b/src/extensions/score_metamodel/checks/standards.py index c0f6c66f4..76cf53921 100644 --- a/src/extensions/score_metamodel/checks/standards.py +++ b/src/extensions/score_metamodel/checks/standards.py @@ -224,18 +224,18 @@ def my_pie_linked_standard_requirements_by_tag( :labels: Linked, Not Linked :legend: :colors: LightSeaGreen, lightgray - :filter-func: score_metamodel.checks.standards.my_pie_linked_standard_requirements_by_tag(aspice40_man5) + :filter-func: path.to.function(tag_name) The call: - => score_metamodel.checks.standards.my_pie_linked_standard_requirements_by_tag(aspice40_man5) + => path.to.function(tag_name) would then pass 'aspice40_man5' as the arg1 and you have access to it then that way. NOTE:: There can not be any `.`(dots) in the tag passed into this function Return: - The direct return of this function is None. Sphinx-needs will get the mutated `results` - list, and use this to display/generate the piechart. + The direct return of this function is None. Sphinx-needs will get + the mutated `results`list, and use this to display/generate the piechart. """ count_linked = 0 diff --git a/src/extensions/score_metamodel/external_needs.py b/src/extensions/score_metamodel/external_needs.py index d7a9de909..913392aee 100644 --- a/src/extensions/score_metamodel/external_needs.py +++ b/src/extensions/score_metamodel/external_needs.py @@ -52,9 +52,9 @@ def _parse_bazel_external_need(s: str) -> ExternalNeedsSource | None: return ExternalNeedsSource( bazel_module=repo, path_to_target=path_to_target, target=target ) - else: - # Unknown data target. Probably not a needs.json file. - return None + + # Unknown data target. Probably not a needs.json file. + return None def parse_external_needs_sources_from_DATA(v: str) -> list[ExternalNeedsSource]: @@ -148,7 +148,8 @@ def connect_external_needs(app: Sphinx, config: Config): fixed_json_file = Path(r) / json_file else: logger.debug( - "Running outside bazel. Determining git root for external needs JSON file." + "Running outside bazel. " + "Determining git root for external needs JSON file." ) git_root = Path.cwd().resolve() while not (git_root / ".git").exists(): @@ -182,7 +183,8 @@ def connect_external_needs(app: Sphinx, config: Config): "json_path": json_file, } ) - # Making the prefixes uppercase here to match sphinx_needs, as it does this internally too. + # Making the prefixes uppercase here to match sphinx_needs, + # as it does this internally too. assert isinstance(app.config.allowed_external_prefixes, list) # pyright: ignore[reportAny] app.config.allowed_external_prefixes.append( # pyright: ignore[reportUnknownMemberType] needs_json_data["project_prefix"].upper() # pyright: ignore[reportAny] diff --git a/src/extensions/score_metamodel/tests/__init__.py b/src/extensions/score_metamodel/tests/__init__.py index a915b2d12..c675ba4af 100644 --- a/src/extensions/score_metamodel/tests/__init__.py +++ b/src/extensions/score_metamodel/tests/__init__.py @@ -46,8 +46,8 @@ def assert_no_infos(self): def assert_warning(self, expected_substring: str, expect_location: bool = True): """ - Assert that the logger warning was called exactly once with a message containing - a specific substring. + Assert that the logger warning was called exactly once with a message + containing a specific substring. This also verifies that the defaults from need() are used correctly. So you must use need() to create the need object that is passed @@ -71,8 +71,8 @@ def assert_warning(self, expected_substring: str, expect_location: bool = True): def assert_info(self, expected_substring: str, expect_location: bool = True): """ - Assert that the logger info was called exactly once with a message containing - a specific substring. + Assert that the logger info was called exactly once with a message + containing a specific substring. This also verifies that the defaults from need() are used correctly. So you must use need() to create the need object that is passed diff --git a/src/extensions/score_metamodel/tests/test_check_options.py b/src/extensions/score_metamodel/tests/test_check_options.py index f2eb5f335..094850481 100644 --- a/src/extensions/score_metamodel/tests/test_check_options.py +++ b/src/extensions/score_metamodel/tests/test_check_options.py @@ -15,13 +15,12 @@ from unittest.mock import Mock import pytest -from sphinx.application import Sphinx - from score_metamodel.checks.check_options import ( check_extra_options, check_options, ) from score_metamodel.tests import fake_check_logger, need +from sphinx.application import Sphinx @pytest.mark.metadata( diff --git a/src/extensions/score_metamodel/tests/test_standards.py b/src/extensions/score_metamodel/tests/test_standards.py index 670f3cb75..70f9a3b00 100644 --- a/src/extensions/score_metamodel/tests/test_standards.py +++ b/src/extensions/score_metamodel/tests/test_standards.py @@ -15,6 +15,7 @@ # from sphinx.application import Sphinx import pytest + from src.extensions.score_metamodel.checks import standards from src.extensions.score_metamodel.tests import need # ,fake_check_logger @@ -946,7 +947,10 @@ def test_assert_multiple_kwargs(self): # Test if our assert works with pytest.raises( AssertionError, - match="Can only provide one tag to `my_pie_linked_standard_requirements_by_tag`", + match=( + "Can only provide one tag to " + "`my_pie_linked_standard_requirements_by_tag`" + ), ): standards.my_pie_linked_standard_requirements_by_tag( needs, results, arg1="test_tag", arg2="test_test_tag" diff --git a/src/extensions/score_plantuml.py b/src/extensions/score_plantuml.py index b360dfb25..2669e0cdf 100644 --- a/src/extensions/score_plantuml.py +++ b/src/extensions/score_plantuml.py @@ -70,7 +70,8 @@ def get_runfiles_dir() -> Path: def find_correct_path(runfiles: str) -> str: """ - This ensures that the 'plantuml' binary path is found in local 'score_docs_as_code' and module use. + This ensures that the 'plantuml' binary path is found in local 'score_docs_as_code' + and module use. """ dirs = [str(x) for x in Path(runfiles).glob("*score_docs_as_code+")] if dirs: diff --git a/src/extensions/score_source_code_linker/__init__.py b/src/extensions/score_source_code_linker/__init__.py index 8046f1685..7d047501e 100644 --- a/src/extensions/score_source_code_linker/__init__.py +++ b/src/extensions/score_source_code_linker/__init__.py @@ -146,7 +146,9 @@ def group_by_need(source_code_links: list[NeedLink]) -> dict[str, list[NeedLink] def parse_git_output(str_line: str) -> str: if len(str_line.split()) < 2: LOGGER.warning( - f"Got wrong input line from 'get_github_repo_info'. Input: {str_line}. Expected example: 'origin git@github.com:user/repo.git'" + "Got wrong input line from 'get_github_repo_info'. " + f"Input: {str_line}." + "Expected example: 'origin git@github.com:user/repo.git'" ) return "" url = str_line.split()[1] # Get the URL part @@ -170,11 +172,13 @@ def get_github_repo_info(git_root_cwd: Path) -> str: else: # If we do not find 'origin' we just take the first line LOGGER.info( - "Did not find origin remote name. Will now take first result from: 'git remote -v'" + "Did not find origin remote name. " + "Will now take first result from: 'git remote -v'" ) repo = parse_git_output(process.stdout.split("\n")[0]) assert repo != "", ( - "Remote repository is not defined. Make sure you have a remote set. Check this via 'git remote -v'" + "Remote repository is not defined. Make sure you have a remote set. " + "Check this via 'git remote -v'" ) return repo @@ -246,10 +250,11 @@ def inject_links_into_needs(app: Sphinx, env: BuildEnvironment) -> None: needs ) # TODO: why do we create a copy? Can we also needs_copy = needs[:]? copy(needs)? - for id, need in needs.items(): + for _, need in needs.items(): if need.get("source_code_link"): LOGGER.debug( - f"?? Need {need['id']} already has source_code_link: {need.get('source_code_link')}" + f"?? Need {need['id']} already has source_code_link: " + f"{need.get('source_code_link')}" ) source_code_links = load_source_code_links_json(get_cache_filename(app.outdir)) @@ -283,7 +288,8 @@ def inject_links_into_needs(app: Sphinx, env: BuildEnvironment) -> None: Needs_Data.remove_need(need["id"]) Needs_Data.add_need(need) - # source_code_link of affected needs was overwritten. Make sure it's empty in all others! + # source_code_link of affected needs was overwritten. + # Make sure it's empty in all others! for need in needs.values(): if need["id"] not in source_code_links_by_need: need["source_code_link"] = "" diff --git a/src/extensions/score_source_code_linker/generate_source_code_links_json.py b/src/extensions/score_source_code_linker/generate_source_code_links_json.py index 347d5f364..12b714086 100644 --- a/src/extensions/score_source_code_linker/generate_source_code_links_json.py +++ b/src/extensions/score_source_code_linker/generate_source_code_links_json.py @@ -1,5 +1,5 @@ # ******************************************************************************* -# Copyright (c) 2024 Contributors to the Eclipse Foundation +# Copyright (c) 2025 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -18,9 +18,7 @@ """ import os -import sys from pathlib import Path -from pprint import pprint from src.extensions.score_source_code_linker.needlinks import ( NeedLink, @@ -74,7 +72,9 @@ def _extract_references_from_file(root: Path, file_path: Path) -> list[NeedLink] """Scan a single file for template strings and return findings.""" assert root.is_absolute(), "Root path must be absolute" assert not file_path.is_absolute(), "File path must be relative to the root" - # assert file_path.is_relative_to(root), f"File path ({file_path}) must be relative to the root ({root})" + # assert file_path.is_relative_to(root), ( + # f"File path ({file_path}) must be relative to the root ({root})" + # ) assert (root / file_path).exists(), ( f"File {file_path} does not exist in root {root}." ) @@ -159,20 +159,3 @@ def generate_source_code_links_json(search_path: Path, file: Path): """ needlinks = find_all_need_references(search_path) store_source_code_links_json(file, needlinks) - - -# incremental_latest: -# DEBUG: Workspace root is /home/lla2hi/score/docs-as-code -# DEBUG: Current working directory is /home/lla2hi/.cache/bazel/_bazel_lla2hi/e35bb7c4cc72b99eb76653ab839f4f8e/execroot/_main/bazel-out/k8-fastbuild/bin/docs/incremental_latest.runfiles/_main -# DEBUG: Git root is /home/lla2hi/score/docs-as-code - -# incremental_release: (-> bazel build sandbox of process repository) -# DEBUG: Workspace root is None -# DEBUG: Current working directory is /home/lla2hi/.cache/bazel/_bazel_lla2hi/e35bb7c4cc72b99eb76653ab839f4f8e/sandbox/linux-sandbox/25/execroot/_main (-> process repo!!) -# rst files are in .../bazel-out/k8-fastbuild/bin/external/score_process~/process/_docs_needs_latest/score_process~/* -# DEBUG: Git root is /home/lla2hi/score/docs-as-code - -# docs_latest: -# DEBUG: Workspace root is None -# DEBUG: Current working directory is /home/lla2hi/.cache/bazel/_bazel_lla2hi/e35bb7c4cc72b99eb76653ab839f4f8e/sandbox/linux-sandbox/26/execroot/_main -# DEBUG: Git root is /home/lla2hi/score/docs-as-code diff --git a/src/extensions/score_source_code_linker/needlinks.py b/src/extensions/score_source_code_linker/needlinks.py index dbb52b386..406ad9419 100644 --- a/src/extensions/score_source_code_linker/needlinks.py +++ b/src/extensions/score_source_code_linker/needlinks.py @@ -59,13 +59,13 @@ def needlink_decoder(d: dict[str, Any]) -> NeedLink | dict[str, Any]: need=d["need"], full_line=d["full_line"], ) - else: - # It's something else, pass it on to other decoders - return d + # It's something else, pass it on to other decoders + return d def store_source_code_links_json(file: Path, needlist: list[NeedLink]): - # After `rm -rf _build` or on clean builds the directory does not exist, so we need to create it + # After `rm -rf _build` or on clean builds the directory does not exist, + # so we need to create it file.parent.mkdir(exist_ok=True) with open(file, "w") as f: json.dump( diff --git a/src/extensions/score_source_code_linker/tests/test_requirement_links.py b/src/extensions/score_source_code_linker/tests/test_requirement_links.py index d706884e0..4b57f8b38 100644 --- a/src/extensions/score_source_code_linker/tests/test_requirement_links.py +++ b/src/extensions/score_source_code_linker/tests/test_requirement_links.py @@ -14,14 +14,14 @@ import os import subprocess import tempfile -from pathlib import Path -from sphinx_needs.data import NeedsMutable -from src.extensions.score_metamodel.tests import need as test_need from dataclasses import asdict +from pathlib import Path from typing import Any - import pytest +from sphinx_needs.data import NeedsMutable + +from src.extensions.score_metamodel.tests import need as test_need # Import the module under test # Note: You'll need to adjust these imports based on your actual module structure @@ -29,7 +29,6 @@ find_need, get_cache_filename, get_current_git_hash, - get_github_base_url, get_github_link, get_github_repo_info, group_by_need, @@ -37,8 +36,8 @@ ) from src.extensions.score_source_code_linker.needlinks import ( NeedLink, - store_source_code_links_json, load_source_code_links_json, + store_source_code_links_json, ) """ @@ -84,9 +83,9 @@ def needlink_test_decoder(d: dict[str, Any]) -> NeedLink | dict[str, Any]: need=d["need"], full_line=decode_comment(d["full_line"]), ) - else: - # It's something else, pass it on to other decoders - return d + + # It's something else, pass it on to other decoders + return d @pytest.fixture @@ -401,7 +400,7 @@ def test_get_github_repo_info_https_remote(git_repo_with_https_remote): def test_get_github_repo_info_multiple_remotes(git_repo_multiple_remotes): - """Test getting GitHub repository information with multiple remotes (should prefer origin).""" + """Test GitHub repo info retrieval with multiple remotes (origin preferred).""" result = get_github_repo_info(git_repo_multiple_remotes) assert result == "test-user/test-repo" @@ -591,7 +590,8 @@ def another_function(): ["git", "commit", "-m", "Add implementation files"], cwd=git_repo, check=True ) - # Create needlinks manually (simulating what generate_source_code_links_json would do) + # Create needlinks manually + # (simulating what generate_source_code_links_json would do) needlinks = [ NeedLink( file=Path("src/implementation1.py"), diff --git a/src/extensions/score_source_code_linker/tests/test_source_link.py b/src/extensions/score_source_code_linker/tests/test_source_link.py index 8771f48dc..6c40f5e31 100644 --- a/src/extensions/score_source_code_linker/tests/test_source_link.py +++ b/src/extensions/score_source_code_linker/tests/test_source_link.py @@ -11,32 +11,30 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* import json +import os +import shutil +import subprocess from collections import Counter from collections.abc import Callable from pathlib import Path +from typing import cast import pytest -import os -import subprocess -import shutil - -from typing import cast from pytest import TempPathFactory from sphinx.testing.util import SphinxTestApp from sphinx_needs.data import SphinxNeedsData - from test_requirement_links import needlink_test_decoder + from src.extensions.score_source_code_linker import get_github_base_url, get_github_link -from src.extensions.score_source_code_linker.needlinks import NeedLink from src.extensions.score_source_code_linker.generate_source_code_links_json import ( find_ws_root, ) +from src.extensions.score_source_code_linker.needlinks import NeedLink @pytest.fixture() def sphinx_base_dir(tmp_path_factory: TempPathFactory) -> Path: - repo_path = tmp_path_factory.mktemp("test_git_repo") - return repo_path + return tmp_path_factory.mktemp("test_git_repo") @pytest.fixture() @@ -222,7 +220,6 @@ def basic_needs(): @pytest.fixture() def example_source_link_text_all_ok(sphinx_base_dir): - repo_path = sphinx_base_dir return { "TREQ_ID_1": [ NeedLink( @@ -254,7 +251,6 @@ def example_source_link_text_all_ok(sphinx_base_dir): @pytest.fixture() def example_source_link_text_non_existent(sphinx_base_dir): - repo_path = sphinx_base_dir return [ { "TREQ_ID_200": [ @@ -282,12 +278,14 @@ def compare_json_files(file1: Path, golden_file: Path): with open(golden_file, "r") as f2: json2 = json.load(f2, object_hook=needlink_test_decoder) assert len(json1) == len(json2), ( - f"{file1}'s lenth are not the same as in the golden file lenght. Len of{file1}: {len(json1)}. Len of Golden File: {len(json2)}" + f"{file1}'s lenth are not the same as in the golden file lenght. " + f"Len of{file1}: {len(json1)}. Len of Golden File: {len(json2)}" ) c1 = Counter(n for n in json1) c2 = Counter(n for n in json2) assert c1 == c2, ( - f"Testfile does not have same needs as golden file. Testfile: {c1}\nGoldenFile: {c2}" + "Testfile does not have same needs as golden file. " + f"Testfile: {c1}\nGoldenFile: {c2}" ) diff --git a/src/tests/test_consumer.py b/src/tests/test_consumer.py index c0fb091b3..b5e93ae31 100644 --- a/src/tests/test_consumer.py +++ b/src/tests/test_consumer.py @@ -29,16 +29,20 @@ ) """ -This script's main usecase is to test consumers of Docs-As-Code with the new changes made in PR's. -This enables us to find new issues and problems we introduce with changes that we otherwise would only know much later. +This script's main usecase is to test consumers of Docs-As-Code with +the new changes made in PR's. +This enables us to find new issues and problems we introduce with changes +that we otherwise would only know much later. There are several things to note. -- The `print` function has been overwritten by the 'rich' package to allow for richer text output. +- The `print` function has been overwritten by the 'rich' package to allow for richer +text output. - The script itself takes quiet a bit of time, roughly 5+ min for a full run. - If you need more output, enable it via `-v` or `-vv` - Start the script via the following command: - bazel run //:ide_support - - .venv_docs/bin/python -m pytest -s src/tests (If you need more verbosity add `-v` or `-vv`) + - .venv_docs/bin/python -m pytest -s src/tests + (If you need more verbosity add `-v` or `-vv`) """ # Max width of the printout @@ -159,7 +163,8 @@ def filter_repos(repo_filter: str | None) -> list[ConsumerRepo]: # This prevents accidentally running zero tests due to typos if not filtered_repos and repo_filter: print( - f"[red]No valid repositories found in filter, running all repositories instead[/red]" + "[red]No valid repositories found in filter, " + "running all repositories instead[/red]" ) return REPOS_TO_TEST @@ -173,15 +178,13 @@ def replace_bazel_dep_with_local_override(module_content: str) -> str: pattern = rf'bazel_dep\(name = "score_docs_as_code", version = "[^"]+"\)' # Replacement with local_path_override - replacement = f"""bazel_dep(name = "score_docs_as_code", version = "0.0.0") + replacement = """bazel_dep(name = "score_docs_as_code", version = "0.0.0") local_path_override( module_name = "score_docs_as_code", path = "../docs_as_code" )""" - modified_content = re.sub(pattern, replacement, module_content) - - return modified_content + return re.sub(pattern, replacement, module_content) def replace_bazel_dep_with_git_override( @@ -196,9 +199,7 @@ def replace_bazel_dep_with_git_override( commit = "{git_hash}" )''' - modified_content = re.sub(pattern, replacement, module_content) - - return modified_content + return re.sub(pattern, replacement, module_content) def strip_ansi_codes(text: str) -> str: @@ -219,7 +220,8 @@ def parse_bazel_output(BR: BuildOutput, pytestconfig) -> BuildOutput: print(f"[DEBUG] Warning {i}: {repr(warning)}") for raw_warning in split_warnings: - # In the CLI we seem to have some ansi codes in the warnings. Need to strip those + # In the CLI we seem to have some ansi codes in the warnings. + # Need to strip those clean_warning = strip_ansi_codes(raw_warning).strip() logger = "[NO SPECIFIC LOGGER]" @@ -239,19 +241,25 @@ def print_overview_logs(BR: BuildOutput): warning_loggers = list(BR.warnings.keys()) len_left_test_result = len_max - len("TEST RESULTS") print( - f"[blue]{'=' * int(len_left_test_result / 2)}TEST RESULTS{'=' * int(len_left_test_result / 2)}[/blue]" + f"[blue]{'=' * int(len_left_test_result / 2)}" + f"TEST RESULTS" + f"{'=' * int(len_left_test_result / 2)}[/blue]" ) print(f"[navy_blue]{'=' * len_max}[/navy_blue]") warning_total_loggers_msg = f"Warning Loggers Total: {len(warning_loggers)}" len_left_loggers = len_max - len(warning_total_loggers_msg) print( - f"[blue]{'=' * int(len_left_loggers / 2)}{warning_total_loggers_msg}{'=' * int(len_left_loggers / 2)}[/blue]" + f"[blue]{'=' * int(len_left_loggers / 2)}" + f"{warning_total_loggers_msg}" + f"{'=' * int(len_left_loggers / 2)}[/blue]" ) warning_loggers = list(BR.warnings.keys()) - warning_total_msg = f"Logger Warnings Accumulated" + warning_total_msg = "Logger Warnings Accumulated" len_left_loggers_total = len_max - len(warning_total_msg) print( - f"[blue]{'=' * int(len_left_loggers_total / 2)}{warning_total_msg}{'=' * int(len_left_loggers_total / 2)}[/blue]" + f"[blue]{'=' * int(len_left_loggers_total / 2)}" + f"{warning_total_msg}" + f"{'=' * int(len_left_loggers_total / 2)}[/blue]" ) for logger in warning_loggers: if len(BR.warnings[logger]) == 0: @@ -260,7 +268,9 @@ def print_overview_logs(BR: BuildOutput): warning_logger_msg = f"{logger} has {len(BR.warnings[logger])} warnings" len_left_logger = len_max - len(warning_logger_msg) print( - f"[{color}]{'=' * int(len_left_logger / 2)}{warning_logger_msg}{'=' * int(len_left_logger / 2)}[/{color}]" + f"[{color}]{'=' * int(len_left_logger / 2)}" + f"{warning_logger_msg}" + f"{'=' * int(len_left_logger / 2)}[/{color}]" ) print(f"[blue]{'=' * len_max}[/blue]") @@ -271,7 +281,9 @@ def verbose_printout(BR: BuildOutput): for logger in warning_loggers: len_left_logger = len_max - len(logger) print( - f"[cornflower_blue]{'=' * int(len_left_logger / 2)}{logger}{'=' * int(len_left_logger / 2)}[/cornflower_blue]" + f"[cornflower_blue]{'=' * int(len_left_logger / 2)}" + f"{logger}" + f"{'=' * int(len_left_logger / 2)}[/cornflower_blue]" ) warnings = BR.warnings[logger] len_left_warnings = len_max - len(f"Warnings Found: {len(warnings)}\n") @@ -279,7 +291,9 @@ def verbose_printout(BR: BuildOutput): if logger == "[NO SPECIFIC LOGGER]": color = "orange1" print( - f"[{color}]{'=' * int(len_left_warnings / 2)}{f'Warnings Found: {len(warnings)}'}{'=' * int(len_left_warnings / 2)}[/{color}]" + f"[{color}]{'=' * int(len_left_warnings / 2)}" + f"{f'Warnings Found: {len(warnings)}'}" + f"{'=' * int(len_left_warnings / 2)}[/{color}]" ) print("\n".join(f"[{color}]{x}[/{color}]" for x in warnings)) @@ -291,13 +305,19 @@ def print_running_cmd(repo: str, cmd: str, local_or_git: str): len_left_local = len_max - len(local_or_git) print(f"\n[cyan]{'=' * len_max}[/cyan]") print( - f"[cornflower_blue]{'=' * int(len_left_repo / 2)}{repo}{'=' * int(len_left_repo / 2)}[/cornflower_blue]" + f"[cornflower_blue]{'=' * int(len_left_repo / 2)}" + f"{repo}" + f"{'=' * int(len_left_repo / 2)}[/cornflower_blue]" ) print( - f"[cornflower_blue]{'=' * int(len_left_local / 2)}{local_or_git}{'=' * int(len_left_local / 2)}[/cornflower_blue]" + f"[cornflower_blue]{'=' * int(len_left_local / 2)}" + f"{local_or_git}" + f"{'=' * int(len_left_local / 2)}[/cornflower_blue]" ) print( - f"[cornflower_blue]{'=' * int(len_left_cmd / 2)}{cmd}{'=' * int(len_left_cmd / 2)}[/cornflower_blue]" + f"[cornflower_blue]{'=' * int(len_left_cmd / 2)}" + f"{cmd}" + f"{'=' * int(len_left_cmd / 2)}[/cornflower_blue]" ) print(f"[cyan]{'=' * len_max}[/cyan]") @@ -310,7 +330,8 @@ def analyze_build_success(BR: BuildOutput) -> tuple[bool, str]: - '[NO SPECIFIC LOGGER]' warnings are always ignored """ - # Unsure if this is good, as sometimes the returncode is 1 but it should still go through? + # Unsure if this is good, as sometimes the returncode is 1 + # but it should still go through? # Logging for feedback here if BR.returncode != 0: return False, f"Build failed with return code {BR.returncode}" @@ -354,7 +375,9 @@ def print_final_result(BR: BuildOutput, repo_name: str, cmd: str, pytestconfig): result_msg = f"{repo_name} - {cmd}: {status}" len_left = len_max - len(result_msg) print( - f"[{color}]{'=' * int(len_left / 2)}{result_msg}{'=' * int(len_left / 2)}[/{color}]" + f"[{color}]{'=' * int(len_left / 2)}" + f"{result_msg}" + f"{'=' * int(len_left / 2)}[/{color}]" ) print(f"[{color}]Reason: {reason}[/{color}]") print(f"[{color}]{'=' * len_max}[/{color}]") @@ -479,7 +502,8 @@ def setup_test_environment(sphinx_base_dir, pytestconfig): print(f"[DEBUG] gh_url: {gh_url}") print(f"[DEBUG] current_hash: {current_hash}") print( - f"[DEBUG] Working directory has uncommitted changes: {has_uncommitted_changes(curr_path)}" + "[DEBUG] Working directory has uncommitted changes: " + f"{has_uncommitted_changes(curr_path)}" ) # Create symlink for local docs-as-code @@ -564,9 +588,11 @@ def test_and_clone_repos_updated(sphinx_base_dir, pytestconfig): return print( - f"[green]Testing {len(repos_to_test)} repositories: {[r.name for r in repos_to_test]}[/green]" + f"[green]Testing {len(repos_to_test)} repositories: " + f"{[r.name for r in repos_to_test]}[/green]" ) - # This might be hacky, but currently the best way I could solve the issue of going to the right place. + # This might be hacky, but currently the best way I could solve the issue + # of going to the right place. gh_url, current_hash = setup_test_environment(sphinx_base_dir, pytestconfig) overall_success = True @@ -615,11 +641,13 @@ def test_and_clone_repos_updated(sphinx_base_dir, pytestconfig): if not is_success: overall_success = False - # NOTE: We have to change directories back to the parent, otherwise the cloning & override will not be correct + # NOTE: We have to change directories back to the parent + # otherwise the cloning & override will not be correct os.chdir(Path.cwd().parent) # Printing a 'overview' table as a result print_result_table(results) assert overall_success, ( - "Consumer Tests failed, see table for which commands specifically. Enable verbosity for warning/error printouts" + "Consumer Tests failed, see table for which commands specifically. " + "Enable verbosity for warning/error printouts" ) From e4eb978fee41b0e2e03f7d4661f580641793ef33 Mon Sep 17 00:00:00 2001 From: Aymen-Soussi-01 Date: Thu, 14 Aug 2025 10:48:46 +0200 Subject: [PATCH 2/2] Fix review comments --- src/extensions/score_metamodel/tests/test_standards.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/extensions/score_metamodel/tests/test_standards.py b/src/extensions/score_metamodel/tests/test_standards.py index 70f9a3b00..bda4e197a 100644 --- a/src/extensions/score_metamodel/tests/test_standards.py +++ b/src/extensions/score_metamodel/tests/test_standards.py @@ -947,10 +947,8 @@ def test_assert_multiple_kwargs(self): # Test if our assert works with pytest.raises( AssertionError, - match=( - "Can only provide one tag to " - "`my_pie_linked_standard_requirements_by_tag`" - ), + match="Can only provide one tag to " + + "`my_pie_linked_standard_requirements_by_tag`", ): standards.my_pie_linked_standard_requirements_by_tag( needs, results, arg1="test_tag", arg2="test_test_tag"