codeant-ai-for-open-source[bot] commented on code in PR #37516:
URL: https://github.com/apache/superset/pull/37516#discussion_r3601035997
##########
superset/common/query_actions.py:
##########
@@ -97,67 +144,83 @@ def _get_query(
return result
-def _detect_currency(
+def _acquire_currency_dependency(
query_context: QueryContext,
query_obj: QueryObject,
- datasource: Explorable,
- df: Any = None,
-) -> str | None:
- """
- Detect currency from filtered data for AUTO mode currency formatting.
-
- First attempts to detect from the provided dataframe if the currency
- column is present. Falls back to a separate query only when needed.
-
- Checks both top-level currency_format (used by Pie, Timeseries, etc.)
- and column_config (used by Table charts) for AUTO currency settings.
-
- :param query_context: The query context with form_data containing
currency_format
- :param query_obj: The original query object with filters
- :param datasource: The datasource being queried
- :param df: Optional dataframe to detect currency from (avoids extra query)
- :return: ISO 4217 currency code (e.g., "USD") or None
- """
+ acquisition: QueryAcquisitionResult,
+ force_cached: bool,
+ detect_value: bool = True,
+) -> tuple[QueryAcquisitionResult, str | None, int]:
+ """Acquire AUTO currency metadata through the normal cache-aware path."""
+ datasource = _get_datasource(query_context, query_obj)
form_data = query_context.form_data or {}
-
- # Check top-level currency_format (for Pie, Timeseries, etc.)
currency_format = form_data.get("currency_format", {})
- top_level_auto = (
+ auto_enabled = (
isinstance(currency_format, dict) and currency_format.get("symbol") ==
"AUTO"
- )
-
- # Check column_config (for Table charts)
- column_config_auto = has_auto_currency_in_column_config(form_data)
-
- # Only detect if AUTO is configured somewhere
- if not top_level_auto and not column_config_auto:
- return None
-
+ ) or has_auto_currency_in_column_config(form_data)
currency_column = getattr(datasource, "currency_code_column", None)
- if not currency_column:
- return None
-
- if df is not None and currency_column in df.columns:
- return detect_currency_from_df(df, currency_column)
+ if not auto_enabled or not currency_column:
+ return acquisition, None, 0
+ if acquisition.payload["status"] == QueryStatus.FAILED:
+ return acquisition, None, 0
+ if currency_column in acquisition.payload["df"].columns:
+ if not detect_value:
+ return acquisition, None, 0
+ processing_start_ns = time.perf_counter_ns()
+ detected_currency = detect_currency_from_df(
+ acquisition.payload["df"], currency_column
+ )
+ return (
+ acquisition,
+ detected_currency,
+ max(0, time.perf_counter_ns() - processing_start_ns),
+ )
- return detect_currency(
- datasource=datasource,
- filters=query_obj.filter,
- granularity=query_obj.granularity,
- from_dttm=query_obj.from_dttm,
- to_dttm=query_obj.to_dttm,
- extras=query_obj.extras,
+ currency_query = copy.copy(query_obj)
Review Comment:
**Suggestion:** Add a concrete type hint for this copied query object
variable to keep the new query-preparation flow fully typed. [custom_rule]
**Severity Level:** Minor ๐งน
<details>
<summary><b>Why it matters? โญ </b></summary>
The copied query object is a newly introduced local variable and is used as
a `QueryObject`, but it is not explicitly annotated. This is a valid instance
of the type-hint rule violation described in the custom rule.
</details>
<details>
<summary><b>Rule source ๐ </b></summary>
.cursor/rules/dev-standard.mdc (line 28)
</details>
[](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=07bbe1704e6a4c149029cfbc88f76d87&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=07bbe1704e6a4c149029cfbc88f76d87&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/common/query_actions.py
**Line:** 179:179
**Comment:**
*Custom Rule: Add a concrete type hint for this copied query object
variable to keep the new query-preparation flow fully typed.
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%2F37516&comment_hash=71d5b20ab69daa9fe8fe695658d8ecd8aa5fbd3c4252568887e6a639443a719b&reaction=like'>๐</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37516&comment_hash=71d5b20ab69daa9fe8fe695658d8ecd8aa5fbd3c4252568887e6a639443a719b&reaction=dislike'>๐</a>
##########
superset/common/query_actions.py:
##########
@@ -97,67 +144,83 @@ def _get_query(
return result
-def _detect_currency(
+def _acquire_currency_dependency(
query_context: QueryContext,
query_obj: QueryObject,
- datasource: Explorable,
- df: Any = None,
-) -> str | None:
- """
- Detect currency from filtered data for AUTO mode currency formatting.
-
- First attempts to detect from the provided dataframe if the currency
- column is present. Falls back to a separate query only when needed.
-
- Checks both top-level currency_format (used by Pie, Timeseries, etc.)
- and column_config (used by Table charts) for AUTO currency settings.
-
- :param query_context: The query context with form_data containing
currency_format
- :param query_obj: The original query object with filters
- :param datasource: The datasource being queried
- :param df: Optional dataframe to detect currency from (avoids extra query)
- :return: ISO 4217 currency code (e.g., "USD") or None
- """
+ acquisition: QueryAcquisitionResult,
+ force_cached: bool,
+ detect_value: bool = True,
+) -> tuple[QueryAcquisitionResult, str | None, int]:
+ """Acquire AUTO currency metadata through the normal cache-aware path."""
+ datasource = _get_datasource(query_context, query_obj)
form_data = query_context.form_data or {}
Review Comment:
**Suggestion:** Add an explicit type annotation for this new local variable
so static type checking can validate accesses to form data fields. [custom_rule]
**Severity Level:** Minor ๐งน
<details>
<summary><b>Why it matters? โญ </b></summary>
The new local variable `form_data` is assigned a dictionary-like value but
has no explicit type annotation. This matches the custom rule requiring type
hints on relevant variables that can be annotated, so the violation is real.
</details>
<details>
<summary><b>Rule source ๐ </b></summary>
.cursor/rules/dev-standard.mdc (line 28)
</details>
[](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=727271474d5b4da58bd8c27a3f201851&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=727271474d5b4da58bd8c27a3f201851&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/common/query_actions.py
**Line:** 156:156
**Comment:**
*Custom Rule: Add an explicit type annotation for this new local
variable so static type checking can validate accesses to form data fields.
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%2F37516&comment_hash=c999778126603f859bc190e05d2e3c950403957e19d6f1a18ec2505e90827bab&reaction=like'>๐</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37516&comment_hash=c999778126603f859bc190e05d2e3c950403957e19d6f1a18ec2505e90827bab&reaction=dislike'>๐</a>
##########
superset/common/chart_data_timing.py:
##########
@@ -0,0 +1,803 @@
+# 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.
+from __future__ import annotations
+
+import logging
+import time
+from collections.abc import Callable, Iterator, Mapping
+from contextlib import contextmanager
+from contextvars import ContextVar
+from dataclasses import dataclass, field, replace
+from enum import Enum
+from typing import Any, Literal, TYPE_CHECKING
+
+from flask import current_app
+
+if TYPE_CHECKING:
+ from superset.common.query_context import QueryContext
+
+NANOSECONDS_PER_MILLISECOND: int = 1_000_000
+SOURCE_TRACE_VERSION: int = 2
+MAX_SOURCE_TRACE_DEPTH: int = 8
+MAX_SOURCE_TRACE_NODES: int = 64
+
+SourcePhase = Literal["planning", "execution", "processing"]
+
+logger: logging.Logger = logging.getLogger(__name__)
+
+
+class SourceKind(str, Enum):
+ """The reason a data source was contacted."""
+
+ PRIMARY = "primary"
+ SERIES_LIMIT = "series_limit"
+ TIME_OFFSET = "time_offset"
+ ANNOTATION = "annotation"
+ CURRENCY_DETECTION = "currency_detection"
+
+
+class SourceProvider(str, Enum):
+ """The implementation family that supplied data."""
+
+ SQL = "sql"
+ SEMANTIC = "semantic"
+ OTHER = "other"
+
+
+class SourceOrigin(str, Enum):
+ """Whether a source trace was captured during this execution or
replayed."""
+
+ CURRENT = "current"
+ CACHE = "cache"
+
+
+class CacheWriteOutcome(str, Enum):
+ """Outcome of a requested cache write."""
+
+ SUCCEEDED = "succeeded"
+ FAILED = "failed"
+ SKIPPED = "skipped"
+ NOT_ATTEMPTED = "not_attempted"
+
+
+_CACHE_WRITE_OUTCOME_PRIORITY: dict[CacheWriteOutcome, int] = {
+ CacheWriteOutcome.NOT_ATTEMPTED: 0,
+ CacheWriteOutcome.SUCCEEDED: 1,
+ CacheWriteOutcome.SKIPPED: 2,
+ CacheWriteOutcome.FAILED: 3,
+}
+
+
+def combine_cache_write_outcomes(
+ *outcomes: CacheWriteOutcome,
+) -> CacheWriteOutcome:
+ """Return the most restrictive outcome for a compound acquisition."""
+
+ return max(outcomes, key=_CACHE_WRITE_OUTCOME_PRIORITY.__getitem__)
+
+
+def _elapsed_ns(start_ns: int, clock: Callable[[], int]) -> int:
+ return max(0, clock() - start_ns)
+
+
+def _to_ms(value_ns: int | None) -> float | None:
+ if value_ns is None:
+ return None
+ return round(value_ns / NANOSECONDS_PER_MILLISECOND, 2)
+
+
+@dataclass(frozen=True)
+class SourceTiming:
+ """Bounded, content-free timing trace for one source operation."""
+
+ kind: SourceKind
+ provider: SourceProvider
+ origin: SourceOrigin
+ planning_ns: int = 0
+ execution_ns: int = 0
+ processing_ns: int = 0
+ total_ns: int = 0
+ children: tuple[SourceTiming, ...] = ()
+ truncated: bool = False
+
+ def as_public_dict(self) -> dict[str, Any]:
+ """Return the stable public representation in milliseconds."""
+ return {
+ "kind": self.kind.value,
+ "provider": self.provider.value,
+ "origin": self.origin.value,
+ "planning_ms": _to_ms(self.planning_ns),
+ "execution_ms": _to_ms(self.execution_ns),
+ "processing_ms": _to_ms(self.processing_ns),
+ "total_ms": _to_ms(self.total_ns),
+ "children": [child.as_public_dict() for child in self.children],
+ "truncated": self.truncated,
+ }
+
+ def as_cache_value(self) -> dict[str, Any]:
+ """Return a versioned cache representation with integer durations."""
+ return {
+ "kind": self.kind.value,
+ "provider": self.provider.value,
+ "planning_ns": self.planning_ns,
+ "execution_ns": self.execution_ns,
+ "processing_ns": self.processing_ns,
+ "total_ns": self.total_ns,
+ "children": [child.as_cache_value() for child in self.children],
+ "truncated": self.truncated,
+ }
+
+
+@dataclass(frozen=True)
+class QueryAcquisitionTiming:
+ """Timing captured before response materialization."""
+
+ cache_key_ns: int
+ cache_read_ns: int
+ source_ns: int
+ cache_write_ns: int | None
+ cache_write_outcome: CacheWriteOutcome
+ cache_hit: bool | None
+ sources: tuple[SourceTiming, ...] | None
+ elapsed_ns: int | None = None
+
+ @property
+ def total_ns(self) -> int:
+ if self.elapsed_ns is not None:
+ return self.elapsed_ns
+ return (
+ self.cache_key_ns
+ + self.cache_read_ns
+ + self.source_ns
+ + (self.cache_write_ns or 0)
+ )
+
+ def materialized(self, materialization_ns: int) -> QueryTiming:
+ """Create the completed immutable query timing snapshot."""
+ return QueryTiming(
+ cache_key_ns=self.cache_key_ns,
+ cache_read_ns=self.cache_read_ns,
+ source_ns=self.source_ns,
+ cache_write_ns=self.cache_write_ns,
+ cache_write_outcome=self.cache_write_outcome,
+ materialization_ns=materialization_ns,
+ total_ns=self.total_ns + materialization_ns,
+ cache_hit=self.cache_hit,
+ sources=self.sources,
+ )
+
+
+@dataclass(frozen=True)
+class QueryAcquisitionResult:
+ """A dataframe payload paired with acquisition timing."""
+
+ payload: dict[str, Any]
+ timing: QueryAcquisitionTiming
+
+
+def combine_acquisition_timings(
+ primary: QueryAcquisitionTiming,
+ dependency: QueryAcquisitionTiming,
+) -> QueryAcquisitionTiming:
+ """Combine sequential acquisition phases without overlapping query
totals."""
+
+ def combine_optional_int(left: int | None, right: int | None) -> int |
None:
+ if left is None and right is None:
+ return None
+ return (left or 0) + (right or 0)
+
+ cache_hits = {primary.cache_hit, dependency.cache_hit}
+ if False in cache_hits:
+ cache_hit: bool | None = False
+ elif cache_hits == {True}:
+ cache_hit = True
+ else:
+ cache_hit = None
+
+ known_sources = bound_source_trace(
+ tuple(
+ source
+ for sources in (primary.sources, dependency.sources)
+ if sources is not None
+ for source in sources
+ )
+ )
+ sources = (
+ None
+ if primary.sources is None and dependency.sources is None and not
known_sources
+ else known_sources
+ )
+ return QueryAcquisitionTiming(
+ cache_key_ns=primary.cache_key_ns + dependency.cache_key_ns,
+ cache_read_ns=primary.cache_read_ns + dependency.cache_read_ns,
+ source_ns=primary.source_ns + dependency.source_ns,
+ cache_write_ns=combine_optional_int(
+ primary.cache_write_ns, dependency.cache_write_ns
+ ),
+ cache_write_outcome=combine_cache_write_outcomes(
+ primary.cache_write_outcome,
+ dependency.cache_write_outcome,
+ ),
+ cache_hit=cache_hit,
+ sources=sources,
+ elapsed_ns=primary.total_ns + dependency.total_ns,
+ )
+
+
+@dataclass(frozen=True)
+class QueryTiming:
+ """Completed timing snapshot for one independently materialized query."""
+
+ cache_key_ns: int
+ cache_read_ns: int
+ source_ns: int
+ cache_write_ns: int | None
+ cache_write_outcome: CacheWriteOutcome
+ materialization_ns: int
+ total_ns: int
+ cache_hit: bool | None
+ sources: tuple[SourceTiming, ...] | None
+
+ def as_public_dict(self) -> dict[str, Any]:
+ """Return the versioned chart-data API representation."""
+ return {
+ "version": 1,
+ "query": {
+ "cache_key_ms": _to_ms(self.cache_key_ns),
+ "cache_read_ms": _to_ms(self.cache_read_ns),
+ "source_ms": _to_ms(self.source_ns),
+ "cache_write_ms": _to_ms(self.cache_write_ns),
+ "cache_write_status": self.cache_write_outcome.value,
+ "materialization_ms": _to_ms(self.materialization_ns),
+ "total_ms": _to_ms(self.total_ns),
+ "cache_hit": self.cache_hit,
+ },
+ "sources": (
+ None
+ if self.sources is None
+ else [
+ source.as_public_dict()
+ for source in bound_source_trace(self.sources)
+ ]
+ ),
+ }
+
+
+@dataclass(frozen=True)
+class QueryDataResult:
+ """A query payload paired with its completed timing sidecar."""
+
+ payload: dict[str, Any]
+ timing: QueryTiming
+
+
+@dataclass(frozen=True)
+class QueryContextExecutionResult:
+ """Execution result before the command attaches its query context."""
+
+ queries: tuple[QueryDataResult, ...]
+ cache_key: str | None = None
+ context_cache_write_outcome: CacheWriteOutcome =
CacheWriteOutcome.NOT_ATTEMPTED
+
+
+@dataclass(frozen=True)
+class ChartDataExecutionResult:
+ """Typed result of executing a chart data command."""
+
+ query_context: QueryContext
+ queries: tuple[QueryDataResult, ...]
+ cache_key: str | None = None
+
+ def materialize(self) -> dict[str, Any]:
+ """Return the historical command payload without timing metadata."""
+ result: dict[str, Any] = {
+ "query_context": self.query_context,
+ # Response projection adds timing and client-processing fields at
the
+ # query-dict level. Keep those mutations outside the reusable
execution
+ # result without copying potentially large data values.
+ "queries": [dict(query.payload) for query in self.queries],
+ }
+ if self.cache_key is not None:
+ result["cache_key"] = self.cache_key
+ return result
+
+
+@dataclass
+class _MutableSourceTiming:
+ kind: SourceKind
+ provider: SourceProvider
+ start_ns: int
+ planning_ns: int = 0
+ execution_ns: int = 0
+ processing_ns: int = 0
+ children: list[SourceTiming] = field(default_factory=list)
+ truncated: bool = False
+
+
+@dataclass
+class _MutableSourcePhase:
+ node: _MutableSourceTiming
+ phase: SourcePhase
+ active_since_ns: int | None
+
+
+class _SourceParseState(str, Enum):
+ VALID = "valid"
+ TRUNCATED = "truncated"
+ INVALID = "invalid"
+
+
+@dataclass(frozen=True)
+class _SourceParseResult:
+ state: _SourceParseState
+ source: SourceTiming | None = None
+
+
+@dataclass(frozen=True)
+class _ParsedSourceFields:
+ kind: SourceKind
+ provider: SourceProvider
+ planning_ns: int
+ execution_ns: int
+ processing_ns: int
+ total_ns: int
+ children: list[Any]
+ truncated: bool
+
+
+_active_source_collector: ContextVar[SourceTimingCollector | None] =
ContextVar(
+ "chart_data_source_timing_collector",
+ default=None,
+)
+_chart_data_execution_depth: ContextVar[int] = ContextVar(
+ "chart_data_execution_depth", default=0
+)
+
+
+@contextmanager
+def chart_data_execution_scope() -> Iterator[bool]:
+ """Identify the outer command execution that owns telemetry emission."""
+
+ depth = _chart_data_execution_depth.get()
+ token = _chart_data_execution_depth.set(depth + 1)
+ try:
+ yield depth == 0
+ finally:
+ _chart_data_execution_depth.reset(token)
+
+
+class SourceTimingCollector:
+ """Collect a bounded source tree without retaining query content."""
+
+ def __init__(self, clock: Callable[[], int] = time.perf_counter_ns) ->
None:
Review Comment:
**Suggestion:** Add an explicit instance attribute type annotation for this
assigned callable so static type checking can validate collector clock usage.
[custom_rule]
**Severity Level:** Minor ๐งน
<details>
<summary><b>Why it matters? โญ </b></summary>
The attribute is assigned in __init__ without an explicit instance
annotation even though its type is known from the constructor signature. This
matches the custom rule requiring type hints for relevant annotatable variables
in new Python code.
</details>
<details>
<summary><b>Rule source ๐ </b></summary>
.cursor/rules/dev-standard.mdc (line 28)
</details>
[](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=a3535d11ae1347bcbab11ba18fccd97b&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=a3535d11ae1347bcbab11ba18fccd97b&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/common/chart_data_timing.py
**Line:** 386:386
**Comment:**
*Custom Rule: Add an explicit instance attribute type annotation for
this assigned callable so static type checking can validate collector clock
usage.
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%2F37516&comment_hash=aa4c464b8dd7baf45c5f569f1870e9bb3353c048e12241e01ac315159fed8ba6&reaction=like'>๐</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37516&comment_hash=aa4c464b8dd7baf45c5f569f1870e9bb3353c048e12241e01ac315159fed8ba6&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]