codeant-ai-for-open-source[bot] commented on code in PR #41611: URL: https://github.com/apache/superset/pull/41611#discussion_r3531327128
########## superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py: ########## @@ -0,0 +1,227 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""MCP tool: get_compatible_dimensions + +Returns dimensions compatible with the current metric/dimension selection. +""" + +import logging + +from fastmcp import Context +from superset_core.mcp.decorators import tool, ToolAnnotations + +from superset.extensions import event_logger +from superset.mcp_service.privacy import ( + DATA_MODEL_METADATA_ERROR_TYPE, + requires_data_model_metadata_access, + user_can_view_data_model_metadata, +) +from superset.mcp_service.semantic_layer.schemas import ( + CompatibleDimensionsResponse, + DimensionInfo, + GetCompatibleDimensionsRequest, + SemanticLayerError, +) + +logger = logging.getLogger(__name__) + + +@tool( + tags=["data", "semantic"], + class_permission_name="Dataset", + annotations=ToolAnnotations( + title="Get compatible dimensions", + readOnlyHint=True, + destructiveHint=False, + ), +) +@requires_data_model_metadata_access +async def get_compatible_dimensions( + request: GetCompatibleDimensionsRequest, + ctx: Context, +) -> CompatibleDimensionsResponse | SemanticLayerError: + """Return dimensions compatible with the current metric/dimension selection. + + Used to drive progressive disclosure in query builders: after the user + selects one or more metrics (and optionally some dimensions), this tool + returns the dimensions that can validly be added without breaking the + underlying query. + + Provide exactly one of ``dataset_id`` (built-in) or ``view_id`` (external). + + For built-in datasets, returns all groupby-enabled columns from the dataset. + SQL datasets have no semantic compatibility constraints between metrics and + dimensions, so all groupby columns are always returned regardless of the + selected metrics. + + For external semantic views, delegates to the view's + ``get_compatible_dimensions`` implementation. + + Example: + ```json + { + "selected_metrics": ["revenue"], + "selected_dimensions": [], + "view_id": 5 + } + ``` + """ + await ctx.info( + "Getting compatible dimensions: dataset_id=%s, view_id=%s, " + "metrics=%s, dims=%s" + % ( + request.dataset_id, + request.view_id, + request.selected_metrics, + request.selected_dimensions, + ) + ) + + if not user_can_view_data_model_metadata(): + return SemanticLayerError.create( + error="You don't have permission to access dataset details for your role.", + error_type=DATA_MODEL_METADATA_ERROR_TYPE, + ) + + if request.dataset_id is None and request.view_id is None: + return SemanticLayerError.create( + error="Provide either dataset_id (built-in) or view_id (external).", + error_type="ValidationError", + ) + if request.dataset_id is not None and request.view_id is not None: + return SemanticLayerError.create( + error="Provide only one of dataset_id or view_id, not both.", + error_type="ValidationError", + ) + + try: + # ------------------------------------------------------------------ + # Built-in dataset path + # ------------------------------------------------------------------ + if request.dataset_id is not None: + from sqlalchemy.orm import subqueryload + + from superset.connectors.sqla.models import SqlaTable + from superset.daos.dataset import DatasetDAO + + dataset_id: int = request.dataset_id + with event_logger.log_context( + action="mcp.get_compatible_dimensions.builtin" + ): + dataset = DatasetDAO.find_by_id( + dataset_id, + query_options=[ + subqueryload(SqlaTable.columns), + subqueryload(SqlaTable.metrics), + ], + ) + + if dataset is None: + return SemanticLayerError.create( + error=f"No dataset found with id: {request.dataset_id}.", + error_type="NotFound", + ) + + # For built-in datasets all groupby columns are always compatible; + # there's no per-metric compatibility constraint at the SQL level. + dims = [ + DimensionInfo( + name=col.column_name, + verbose_name=col.verbose_name or None, + description=col.description or None, + type=col.type or None, + is_dttm=bool(col.is_dttm), + groupby=bool(col.groupby), + filterable=bool(col.filterable), + source="builtin", + ) + for col in dataset.columns + if col.groupby + ] Review Comment: **Suggestion:** Add an explicit type annotation to this local variable so the compatible dimension collection has a declared type. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This new local variable is introduced without a type hint even though it can be annotated as a list of DimensionInfo, which matches the repository rule requiring type hints for relevant variables in modified Python code. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=8abb7e6e57c34a1dbd762b6226f48d73&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=8abb7e6e57c34a1dbd762b6226f48d73&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py **Line:** 142:155 **Comment:** *Custom Rule: Add an explicit type annotation to this local variable so the compatible dimension collection has a declared type. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=b862742c5d996926b79a482e3dd4001f7fb9ca3927f092df82fd71e4173cecaa&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=b862742c5d996926b79a482e3dd4001f7fb9ca3927f092df82fd71e4173cecaa&reaction=dislike'>👎</a> ########## superset/mcp_service/dataset/tool/query_dataset.py: ########## @@ -379,44 +360,7 @@ async def query_dataset( # noqa: C901 warnings=warnings, ) - # Build column metadata in a single pass per column. - # Cap stats computation at STATS_SAMPLE rows to avoid O(rows*cols) - # overhead on large result sets (row_limit allows up to 50k). - stats_sample_size = 5000 - stats_rows = data[:stats_sample_size] - - columns_meta: list[DataColumn] = [] - for col_name in raw_columns: - sample_values = [ - row.get(col_name) for row in data[:3] if row.get(col_name) is not None - ] - data_type = "string" - if sample_values: - if all(isinstance(v, bool) for v in sample_values): - data_type = "boolean" - elif all(isinstance(v, (int, float)) for v in sample_values): - data_type = "numeric" - - # Compute null_count and unique non-null values in one pass - null_count = 0 - unique_vals: set[str] = set() - for row in stats_rows: - val = row.get(col_name) - if val is None: - null_count += 1 - else: - unique_vals.add(str(val)) - - columns_meta.append( - DataColumn( - name=col_name, - display_name=col_name.replace("_", " ").title(), - data_type=data_type, - sample_values=sample_values[:3], - null_count=null_count, - unique_count=len(unique_vals), - ) - ) + columns_meta = format_data_columns(data, raw_columns) Review Comment: **Suggestion:** Add an explicit type annotation to `columns_meta` (for example as a list of response column schema objects) to satisfy the required type-hint rule for relevant new variables. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> The new local variable `columns_meta` is introduced without a type annotation, and it is a relevant Python variable in modified code that can be annotated. This matches the type-hint rule violation. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=c6b4820178ba41b6886dcd136e771672&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=c6b4820178ba41b6886dcd136e771672&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** superset/mcp_service/dataset/tool/query_dataset.py **Line:** 363:363 **Comment:** *Custom Rule: Add an explicit type annotation to `columns_meta` (for example as a list of response column schema objects) to satisfy the required type-hint rule for relevant new variables. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=e55d5ab32128a618610983a33115c224c865baff0757743ee57dd792f2615aae&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=e55d5ab32128a618610983a33115c224c865baff0757743ee57dd792f2615aae&reaction=dislike'>👎</a> ########## superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py: ########## @@ -0,0 +1,227 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""MCP tool: get_compatible_dimensions + +Returns dimensions compatible with the current metric/dimension selection. +""" + +import logging + +from fastmcp import Context +from superset_core.mcp.decorators import tool, ToolAnnotations + +from superset.extensions import event_logger +from superset.mcp_service.privacy import ( + DATA_MODEL_METADATA_ERROR_TYPE, + requires_data_model_metadata_access, + user_can_view_data_model_metadata, +) +from superset.mcp_service.semantic_layer.schemas import ( + CompatibleDimensionsResponse, + DimensionInfo, + GetCompatibleDimensionsRequest, + SemanticLayerError, +) + +logger = logging.getLogger(__name__) + + +@tool( + tags=["data", "semantic"], + class_permission_name="Dataset", + annotations=ToolAnnotations( + title="Get compatible dimensions", + readOnlyHint=True, + destructiveHint=False, + ), +) +@requires_data_model_metadata_access +async def get_compatible_dimensions( + request: GetCompatibleDimensionsRequest, + ctx: Context, +) -> CompatibleDimensionsResponse | SemanticLayerError: + """Return dimensions compatible with the current metric/dimension selection. + + Used to drive progressive disclosure in query builders: after the user + selects one or more metrics (and optionally some dimensions), this tool + returns the dimensions that can validly be added without breaking the + underlying query. + + Provide exactly one of ``dataset_id`` (built-in) or ``view_id`` (external). + + For built-in datasets, returns all groupby-enabled columns from the dataset. + SQL datasets have no semantic compatibility constraints between metrics and + dimensions, so all groupby columns are always returned regardless of the + selected metrics. + + For external semantic views, delegates to the view's + ``get_compatible_dimensions`` implementation. + + Example: + ```json + { + "selected_metrics": ["revenue"], + "selected_dimensions": [], + "view_id": 5 + } + ``` + """ + await ctx.info( + "Getting compatible dimensions: dataset_id=%s, view_id=%s, " + "metrics=%s, dims=%s" + % ( + request.dataset_id, + request.view_id, + request.selected_metrics, + request.selected_dimensions, + ) + ) + + if not user_can_view_data_model_metadata(): + return SemanticLayerError.create( + error="You don't have permission to access dataset details for your role.", + error_type=DATA_MODEL_METADATA_ERROR_TYPE, + ) + + if request.dataset_id is None and request.view_id is None: + return SemanticLayerError.create( + error="Provide either dataset_id (built-in) or view_id (external).", + error_type="ValidationError", + ) + if request.dataset_id is not None and request.view_id is not None: + return SemanticLayerError.create( + error="Provide only one of dataset_id or view_id, not both.", + error_type="ValidationError", + ) + + try: + # ------------------------------------------------------------------ + # Built-in dataset path + # ------------------------------------------------------------------ + if request.dataset_id is not None: + from sqlalchemy.orm import subqueryload + + from superset.connectors.sqla.models import SqlaTable + from superset.daos.dataset import DatasetDAO + + dataset_id: int = request.dataset_id + with event_logger.log_context( + action="mcp.get_compatible_dimensions.builtin" + ): + dataset = DatasetDAO.find_by_id( + dataset_id, + query_options=[ + subqueryload(SqlaTable.columns), + subqueryload(SqlaTable.metrics), + ], + ) + + if dataset is None: + return SemanticLayerError.create( + error=f"No dataset found with id: {request.dataset_id}.", + error_type="NotFound", + ) + + # For built-in datasets all groupby columns are always compatible; + # there's no per-metric compatibility constraint at the SQL level. + dims = [ + DimensionInfo( + name=col.column_name, + verbose_name=col.verbose_name or None, + description=col.description or None, + type=col.type or None, + is_dttm=bool(col.is_dttm), + groupby=bool(col.groupby), + filterable=bool(col.filterable), + source="builtin", + ) + for col in dataset.columns + if col.groupby + ] + + await ctx.info("Compatible dimensions (builtin): count=%d" % len(dims)) + return CompatibleDimensionsResponse( + compatible_dimensions=dims, + source="builtin", + ) + + # ------------------------------------------------------------------ + # External semantic view path + # ------------------------------------------------------------------ + from superset.daos.semantic_layer import SemanticViewDAO + from superset.exceptions import SupersetSecurityException + + view_id: int = request.view_id # type: ignore[assignment] + with event_logger.log_context(action="mcp.get_compatible_dimensions.external"): + view = SemanticViewDAO.find_by_id(view_id) + + if view is None: + return SemanticLayerError.create( + error=f"No semantic view found with id: {view_id}.", + error_type="NotFound", + ) + + try: + view.raise_for_access() + except SupersetSecurityException as ex: + return SemanticLayerError.create( + error=str(ex.error.message), + error_type="AccessDenied", + ) + + compatible_names = view.get_compatible_dimensions( + request.selected_metrics, + request.selected_dimensions, + ) Review Comment: **Suggestion:** Add a concrete type hint to this variable assignment to document and enforce the expected return shape. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> The assignment introduces a new local variable with no type annotation, despite it being a clearly annotatable collection returned from a method call. That fits the type-hint requirement for modified Python code. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=96d22b897e944cb79bf2c3ea50284be8&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=96d22b897e944cb79bf2c3ea50284be8&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py **Line:** 187:190 **Comment:** *Custom Rule: Add a concrete type hint to this variable assignment to document and enforce the expected return shape. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=c2ead22871ecceeb91af433f98b2660b0d64747eb47a6317ef32957141bdf8fb&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=c2ead22871ecceeb91af433f98b2660b0d64747eb47a6317ef32957141bdf8fb&reaction=dislike'>👎</a> ########## superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py: ########## @@ -0,0 +1,227 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""MCP tool: get_compatible_dimensions + +Returns dimensions compatible with the current metric/dimension selection. +""" + +import logging + +from fastmcp import Context +from superset_core.mcp.decorators import tool, ToolAnnotations + +from superset.extensions import event_logger +from superset.mcp_service.privacy import ( + DATA_MODEL_METADATA_ERROR_TYPE, + requires_data_model_metadata_access, + user_can_view_data_model_metadata, +) +from superset.mcp_service.semantic_layer.schemas import ( + CompatibleDimensionsResponse, + DimensionInfo, + GetCompatibleDimensionsRequest, + SemanticLayerError, +) + +logger = logging.getLogger(__name__) + + +@tool( + tags=["data", "semantic"], + class_permission_name="Dataset", + annotations=ToolAnnotations( + title="Get compatible dimensions", + readOnlyHint=True, + destructiveHint=False, + ), +) +@requires_data_model_metadata_access +async def get_compatible_dimensions( + request: GetCompatibleDimensionsRequest, + ctx: Context, +) -> CompatibleDimensionsResponse | SemanticLayerError: + """Return dimensions compatible with the current metric/dimension selection. + + Used to drive progressive disclosure in query builders: after the user + selects one or more metrics (and optionally some dimensions), this tool + returns the dimensions that can validly be added without breaking the + underlying query. + + Provide exactly one of ``dataset_id`` (built-in) or ``view_id`` (external). + + For built-in datasets, returns all groupby-enabled columns from the dataset. + SQL datasets have no semantic compatibility constraints between metrics and + dimensions, so all groupby columns are always returned regardless of the + selected metrics. + + For external semantic views, delegates to the view's + ``get_compatible_dimensions`` implementation. + + Example: + ```json + { + "selected_metrics": ["revenue"], + "selected_dimensions": [], + "view_id": 5 + } + ``` + """ + await ctx.info( + "Getting compatible dimensions: dataset_id=%s, view_id=%s, " + "metrics=%s, dims=%s" + % ( + request.dataset_id, + request.view_id, + request.selected_metrics, + request.selected_dimensions, + ) + ) + + if not user_can_view_data_model_metadata(): + return SemanticLayerError.create( + error="You don't have permission to access dataset details for your role.", + error_type=DATA_MODEL_METADATA_ERROR_TYPE, + ) + + if request.dataset_id is None and request.view_id is None: + return SemanticLayerError.create( + error="Provide either dataset_id (built-in) or view_id (external).", + error_type="ValidationError", + ) + if request.dataset_id is not None and request.view_id is not None: + return SemanticLayerError.create( + error="Provide only one of dataset_id or view_id, not both.", + error_type="ValidationError", + ) + + try: + # ------------------------------------------------------------------ + # Built-in dataset path + # ------------------------------------------------------------------ + if request.dataset_id is not None: + from sqlalchemy.orm import subqueryload + + from superset.connectors.sqla.models import SqlaTable + from superset.daos.dataset import DatasetDAO + + dataset_id: int = request.dataset_id + with event_logger.log_context( + action="mcp.get_compatible_dimensions.builtin" + ): + dataset = DatasetDAO.find_by_id( + dataset_id, + query_options=[ + subqueryload(SqlaTable.columns), + subqueryload(SqlaTable.metrics), + ], + ) + + if dataset is None: + return SemanticLayerError.create( + error=f"No dataset found with id: {request.dataset_id}.", + error_type="NotFound", + ) + + # For built-in datasets all groupby columns are always compatible; + # there's no per-metric compatibility constraint at the SQL level. + dims = [ + DimensionInfo( + name=col.column_name, + verbose_name=col.verbose_name or None, + description=col.description or None, + type=col.type or None, + is_dttm=bool(col.is_dttm), + groupby=bool(col.groupby), + filterable=bool(col.filterable), + source="builtin", + ) + for col in dataset.columns + if col.groupby + ] + + await ctx.info("Compatible dimensions (builtin): count=%d" % len(dims)) + return CompatibleDimensionsResponse( + compatible_dimensions=dims, + source="builtin", + ) + + # ------------------------------------------------------------------ + # External semantic view path + # ------------------------------------------------------------------ + from superset.daos.semantic_layer import SemanticViewDAO + from superset.exceptions import SupersetSecurityException + + view_id: int = request.view_id # type: ignore[assignment] + with event_logger.log_context(action="mcp.get_compatible_dimensions.external"): + view = SemanticViewDAO.find_by_id(view_id) + + if view is None: + return SemanticLayerError.create( + error=f"No semantic view found with id: {view_id}.", + error_type="NotFound", + ) + + try: + view.raise_for_access() + except SupersetSecurityException as ex: + return SemanticLayerError.create( + error=str(ex.error.message), + error_type="AccessDenied", + ) + + compatible_names = view.get_compatible_dimensions( + request.selected_metrics, + request.selected_dimensions, + ) + + # Enrich with full column metadata + all_cols = {col.column_name: col for col in view.columns} Review Comment: **Suggestion:** Annotate this metadata lookup dictionary with explicit key/value types to satisfy variable type-hint requirements. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This new dictionary is introduced without any type hint, even though its key/value types are inferable and can be annotated. That is a real instance of omitted type hints in modified Python code. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=8ac0a1a09df4423e82b58999683d00b3&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=8ac0a1a09df4423e82b58999683d00b3&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py **Line:** 193:193 **Comment:** *Custom Rule: Annotate this metadata lookup dictionary with explicit key/value types to satisfy variable type-hint requirements. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=7c3a9d6bce6f6a2a1bf6b286bcf993e542881c1eb106864a8c8c782edc68582d&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=7c3a9d6bce6f6a2a1bf6b286bcf993e542881c1eb106864a8c8c782edc68582d&reaction=dislike'>👎</a> ########## tests/unit_tests/mcp_service/semantic_layer/tool/test_get_table.py: ########## @@ -0,0 +1,263 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Unit tests for the get_table MCP tool.""" + +from __future__ import annotations + +import importlib +from collections.abc import Generator +from unittest.mock import MagicMock, Mock, patch + +import pytest +from fastmcp import Client, FastMCP + +from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.exceptions import SupersetSecurityException +from superset.mcp_service.app import mcp +from superset.utils import json + +get_table_module = importlib.import_module( + "superset.mcp_service.semantic_layer.tool.get_table" +) Review Comment: **Suggestion:** Add an explicit type annotation to the module-level imported tool reference so the new variable complies with the required type-hinting rule. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This is a new module-level variable in Python code that can be annotated, but no type hint is provided. That matches the required type-hinting rule violation. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=de7a1b3f9d114fb494a4dfe1b4446773&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=de7a1b3f9d114fb494a4dfe1b4446773&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** tests/unit_tests/mcp_service/semantic_layer/tool/test_get_table.py **Line:** 34:36 **Comment:** *Custom Rule: Add an explicit type annotation to the module-level imported tool reference so the new variable complies with the required type-hinting rule. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=38f300c7e5d18dfe5a9b345e49bcfb9b9ecbff86d4385f5071cb0b9c4674ccb9&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=38f300c7e5d18dfe5a9b345e49bcfb9b9ecbff86d4385f5071cb0b9c4674ccb9&reaction=dislike'>👎</a> ########## tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_metrics.py: ########## @@ -0,0 +1,222 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Unit tests for the get_compatible_metrics MCP tool.""" + +from __future__ import annotations + +import importlib +from collections.abc import Generator +from unittest.mock import MagicMock, Mock, patch + +import pytest +from fastmcp import Client, FastMCP + +from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.exceptions import SupersetSecurityException +from superset.mcp_service.app import mcp +from superset.utils import json + +get_compatible_metrics_module = importlib.import_module( + "superset.mcp_service.semantic_layer.tool.get_compatible_metrics" +) Review Comment: **Suggestion:** Add an explicit type annotation for this module-level variable so annotatable variables comply with the required type-hint rule. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This new module-level variable is annotatable but has no type hint. The custom rule requires type hints for relevant variables in new or modified Python code, so this is a real violation. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=78993223f8bd477399db112807ee35c0&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=78993223f8bd477399db112807ee35c0&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_metrics.py **Line:** 34:36 **Comment:** *Custom Rule: Add an explicit type annotation for this module-level variable so annotatable variables comply with the required type-hint rule. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=78f63425556415db707a1452213cffb64a83cc5ffcb6e5723d59664f3fde3b55&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=78f63425556415db707a1452213cffb64a83cc5ffcb6e5723d59664f3fde3b55&reaction=dislike'>👎</a> ########## tests/unit_tests/mcp_service/semantic_layer/tool/test_list_metrics.py: ########## @@ -0,0 +1,183 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""Unit tests for the list_metrics MCP tool.""" + +from __future__ import annotations + +import importlib +from collections.abc import Generator +from unittest.mock import MagicMock, Mock, patch + +import pytest +from fastmcp import Client, FastMCP + +from superset.mcp_service.app import mcp +from superset.utils import json + +list_metrics_module = importlib.import_module( + "superset.mcp_service.semantic_layer.tool.list_metrics" +) Review Comment: **Suggestion:** Add an explicit type annotation to this module-level variable to satisfy the requirement for annotating relevant variables. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This new Python file introduces a module-level variable without a type hint. The rule requires annotating relevant variables that can be typed, and `importlib.import_module(...)` can be annotated as a module/object type, so the suggestion matches a real violation. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=b28da425f4964b7eb75a735daa13ba13&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=b28da425f4964b7eb75a735daa13ba13&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** tests/unit_tests/mcp_service/semantic_layer/tool/test_list_metrics.py **Line:** 32:34 **Comment:** *Custom Rule: Add an explicit type annotation to this module-level variable to satisfy the requirement for annotating relevant variables. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=b1c569337411cecd4d1ca2f776ce1607aebfe66a6425644ad9b25a310f32ce86&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=b1c569337411cecd4d1ca2f776ce1607aebfe66a6425644ad9b25a310f32ce86&reaction=dislike'>👎</a> ########## tests/unit_tests/mcp_service/utils/test_query_utils.py: ########## @@ -0,0 +1,62 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" +Unit tests for MCP service query utilities. +""" + +from superset.mcp_service.utils.query_utils import validate_names + + +class TestValidateNames: + """Test validate_names function.""" + + def test_all_names_valid_returns_no_errors(self): + """Should return an empty list when every name is valid.""" + errors = validate_names( + ["region", "product"], {"region", "product"}, "dimension" + ) + assert errors == [] + + def test_empty_requested_returns_no_errors(self): + """Should return an empty list when nothing was requested.""" + errors = validate_names([], {"region"}, "dimension") + assert errors == [] + + def test_unknown_name_without_close_match(self): + """Should report an unknown name with no suggestion when nothing is close.""" + errors = validate_names(["zzz_unknown"], {"region", "product"}, "dimension") + assert len(errors) == 1 + assert errors[0] == "Unknown dimension: 'zzz_unknown'" + + def test_unknown_name_with_close_match_suggests_alternatives(self): + """Should suggest close matches when available.""" + errors = validate_names(["regoin"], {"region", "product"}, "dimension") + assert len(errors) == 1 + assert errors[0].startswith("Unknown dimension: 'regoin'") + assert "Did you mean: region" in errors[0] + + def test_multiple_unknown_names_produce_multiple_errors(self): + """Should produce one error per unknown name.""" + errors = validate_names(["revenue", "bogus_metric"], {"revenue"}, "metric") + assert len(errors) == 1 + assert "bogus_metric" in errors[0] + + def test_error_message_uses_provided_kind(self): Review Comment: **Suggestion:** Add explicit return type annotations to the new test methods (for example, annotate each test method to return None) to comply with the Python type-hint requirement. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> The new test methods in this file omit explicit type hints. Under the provided Python type-hint rule, functions and methods that can be annotated should include them, and these test methods can reasonably be annotated with a return type of None. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=1ca57d4df29c4eedb5f9ae148abb3924&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=1ca57d4df29c4eedb5f9ae148abb3924&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** tests/unit_tests/mcp_service/utils/test_query_utils.py **Line:** 28:59 **Comment:** *Custom Rule: Add explicit return type annotations to the new test methods (for example, annotate each test method to return None) to comply with the Python type-hint requirement. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=b0551de819ff33562e2dbbd35aec671b2362c4aebaa264a4442ea7d3ef9771a1&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=b0551de819ff33562e2dbbd35aec671b2362c4aebaa264a4442ea7d3ef9771a1&reaction=dislike'>👎</a> -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
