Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/unreleased/Under the Hood-20251013-140929.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Under the Hood
body: Rename `Metricflow*` -> `MetricFlow*`
time: 2025-10-13T14:09:29.326515-07:00
custom:
Author: plypaul
Issue: "1904"
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
ModelObjectLookup,
)
from metricflow_semantics.experimental.dsi.simple_metric_model_object_lookup import SimpleMetricModelObjectLookup
from metricflow_semantics.experimental.metricflow_exception import MetricflowInternalError
from metricflow_semantics.experimental.metricflow_exception import MetricFlowInternalError
from metricflow_semantics.experimental.ordered_set import FrozenOrderedSet, MutableOrderedSet, OrderedSet
from metricflow_semantics.experimental.semantic_graph.model_id import SemanticModelId
from metricflow_semantics.mf_logging.attribute_pretty_format import AttributeMapping, AttributePrettyFormattable
Expand Down Expand Up @@ -67,7 +67,7 @@ def _semantic_model_and_simple_metrics_pairs(self) -> Sequence[Pair[SemanticMode
if metric_type is MetricType.SIMPLE:
metric_aggregation_params = metric.type_params.metric_aggregation_params
if metric_aggregation_params is None:
raise MetricflowInternalError(
raise MetricFlowInternalError(
LazyFormat("A simple metric is missing `metric_aggregation_params`", metric=metric)
)
model_name_to_simple_metrics[metric_aggregation_params.semantic_model].append(metric)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from metricflow_semantics.experimental.dataclass_helpers import fast_frozen_dataclass
from metricflow_semantics.experimental.dsi.model_object_lookup import ModelObjectLookup
from metricflow_semantics.experimental.metricflow_exception import InvalidManifestException, MetricflowInternalError
from metricflow_semantics.experimental.metricflow_exception import InvalidManifestException, MetricFlowInternalError
from metricflow_semantics.mf_logging.attribute_pretty_format import AttributeMapping
from metricflow_semantics.mf_logging.lazy_formattable import LazyFormat
from metricflow_semantics.model.semantics.simple_metric_input import (
Expand Down Expand Up @@ -45,20 +45,20 @@ def __init__( # noqa: D107
model_name = semantic_model.name
# Sanity checks.
if not simple_metrics:
raise MetricflowInternalError(
raise MetricFlowInternalError(
LazyFormat(
"Can't initialize with empty `simple_metrics`",
simple_metrics=simple_metrics,
)
)
for metric in simple_metrics:
if metric.type is not MetricType.SIMPLE:
raise MetricflowInternalError(
raise MetricFlowInternalError(
LazyFormat("Can't initialize with a metric that is not a simple metric", metric=metric)
)
metric_aggregation_params = metric.type_params.metric_aggregation_params
if metric_aggregation_params is None or metric_aggregation_params.semantic_model != model_name:
raise MetricflowInternalError(
raise MetricFlowInternalError(
LazyFormat(
"Can't initialize with a metric that is not associated with this semantic model",
metric=metric,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
from __future__ import annotations


class MetricflowException(Exception):
class MetricFlowException(Exception):
"""Base class for custom exceptions in MF."""

pass


class MetricflowInternalError(MetricflowException):
class MetricFlowInternalError(MetricFlowException):
"""A non-recoverable error due to an issue within MF and not caused by the user.."""

pass


class InvalidManifestException(MetricflowException):
class InvalidManifestException(MetricFlowException):
"""Raised when an invalid manifest is detected.

Generally, a semantic manifest is validated before it is passed into the engine. This is useful to raise in
Expand All @@ -23,5 +23,5 @@ class InvalidManifestException(MetricflowException):
pass


class GraphvizException(MetricflowException):
class GraphvizException(MetricFlowException):
"""Raised when there is an error when calling `graphviz` methods."""
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
from abc import ABC, abstractmethod

if typing.TYPE_CHECKING:
from metricflow_semantics.experimental.mf_graph.mf_graph import MetricflowGraph
from metricflow_semantics.experimental.mf_graph.mf_graph import MetricFlowGraph

logger = logging.getLogger(__name__)


class MetricflowGraphFormatter(ABC):
class MetricFlowGraphFormatter(ABC):
"""Interface for a graph-to-text formatter."""

@abstractmethod
def format_graph(self, graph: MetricflowGraph) -> str:
def format_graph(self, graph: MetricFlowGraph) -> str:
"""Format the given graph to text."""
raise NotImplementedError
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@

from typing_extensions import override

from metricflow_semantics.experimental.mf_graph.formatting.graph_formatter import MetricflowGraphFormatter
from metricflow_semantics.experimental.mf_graph.formatting.graph_formatter import MetricFlowGraphFormatter
from metricflow_semantics.mf_logging.pretty_print import mf_pformat

if typing.TYPE_CHECKING:
from metricflow_semantics.experimental.mf_graph.mf_graph import MetricflowGraph
from metricflow_semantics.experimental.mf_graph.mf_graph import MetricFlowGraph

logger = logging.getLogger(__name__)


class PrettyFormatGraphFormatter(MetricflowGraphFormatter):
class PrettyFormatGraphFormatter(MetricFlowGraphFormatter):
"""Formats a graph using `mf_pformat()`."""

@override
def format_graph(self, graph: MetricflowGraph) -> str:
def format_graph(self, graph: MetricFlowGraph) -> str:
return mf_pformat(graph)
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
from abc import ABC, abstractmethod
from typing import Generic, TypeVar

from metricflow_semantics.experimental.mf_graph.mf_graph import MetricflowGraph
from metricflow_semantics.experimental.mf_graph.mf_graph import MetricFlowGraph

logger = logging.getLogger(__name__)


OutputGraphT = TypeVar("OutputGraphT")


class MetricflowGraphConverter(Generic[OutputGraphT], ABC):
class MetricFlowGraphConverter(Generic[OutputGraphT], ABC):
"""Base class for a class that converts graphs."""

@abstractmethod
def convert_graph(self, graph: MetricflowGraph) -> OutputGraphT:
def convert_graph(self, graph: MetricFlowGraph) -> OutputGraphT:
"""Convert the graph to the given output type."""
raise NotImplementedError()
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def displayed_properties(self) -> AnyLengthTuple[DisplayedProperty]:
return ()


class MetricflowGraphElement(HasDisplayedProperty, ABC):
class MetricFlowGraphElement(HasDisplayedProperty, ABC):
"""An element in a graph (e.g. node)."""

pass
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
logger = logging.getLogger(__name__)


class MetricflowGraphId(ABC):
class MetricFlowGraphId(ABC):
"""Interface for an object to identify different graphs."""

@property
Expand All @@ -25,7 +25,7 @@ def str_value(self) -> str:
raise NotImplementedError


class SequentialGraphId(MetricflowGraphId, MetricFlowPrettyFormattable):
class SequentialGraphId(MetricFlowGraphId, MetricFlowPrettyFormattable):
"""Graph IDs that are generated sequentially."""

# `itertools.count()` returns an iterable that is thread-safe, so this is a way of generating sequential
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from metricflow_semantics.experimental.mf_graph.comparable import Comparable, ComparisonKey


class MetricflowGraphLabel(Comparable, ABC):
class MetricFlowGraphLabel(Comparable, ABC):
"""Base class for objects that can be used to lookup nodes / edges in a graph."""

@cached_property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
DotGraphAttributeSet,
DotNodeAttributeSet,
)
from metricflow_semantics.experimental.mf_graph.formatting.graph_formatter import MetricflowGraphFormatter
from metricflow_semantics.experimental.mf_graph.formatting.graph_formatter import MetricFlowGraphFormatter
from metricflow_semantics.experimental.mf_graph.formatting.pretty_graph_formatter import PrettyFormatGraphFormatter
from metricflow_semantics.experimental.mf_graph.graph_element import (
MetricflowGraphElement,
MetricFlowGraphElement,
)
from metricflow_semantics.experimental.mf_graph.graph_id import MetricflowGraphId
from metricflow_semantics.experimental.mf_graph.graph_labeling import MetricflowGraphLabel
from metricflow_semantics.experimental.mf_graph.node_descriptor import MetricflowGraphNodeDescriptor
from metricflow_semantics.experimental.mf_graph.graph_id import MetricFlowGraphId
from metricflow_semantics.experimental.mf_graph.graph_labeling import MetricFlowGraphLabel
from metricflow_semantics.experimental.mf_graph.node_descriptor import MetricFlowGraphNodeDescriptor
from metricflow_semantics.experimental.ordered_set import FrozenOrderedSet, MutableOrderedSet, OrderedSet
from metricflow_semantics.mf_logging.format_option import PrettyFormatOption
from metricflow_semantics.mf_logging.lazy_formattable import LazyFormat
Expand All @@ -39,17 +39,17 @@

logger = logging.getLogger(__name__)

NodeT = TypeVar("NodeT", bound="MetricflowGraphNode")
EdgeT = TypeVar("EdgeT", bound="MetricflowGraphEdge")
NodeT = TypeVar("NodeT", bound="MetricFlowGraphNode")
EdgeT = TypeVar("EdgeT", bound="MetricFlowGraphEdge")

NodeT_co = TypeVar("NodeT_co", bound="MetricflowGraphNode", covariant=True)
EdgeT_co = TypeVar("EdgeT_co", bound="MetricflowGraphEdge", covariant=True)
NodeT_co = TypeVar("NodeT_co", bound="MetricFlowGraphNode", covariant=True)
EdgeT_co = TypeVar("EdgeT_co", bound="MetricFlowGraphEdge", covariant=True)


class MetricflowGraphNode(MetricflowGraphElement, MetricFlowPrettyFormattable, Comparable, ABC):
class MetricFlowGraphNode(MetricFlowGraphElement, MetricFlowPrettyFormattable, Comparable, ABC):
"""Base class for nodes in a directed graph."""

_DEFAULT_NODE_LABELS: ClassVar[OrderedSet[MetricflowGraphLabel]] = FrozenOrderedSet()
_DEFAULT_NODE_LABELS: ClassVar[OrderedSet[MetricFlowGraphLabel]] = FrozenOrderedSet()

def as_dot_node(self, include_graphical_attributes: bool) -> DotNodeAttributeSet:
"""Return this as attributes for a DOT node.
Expand All @@ -65,13 +65,13 @@ def as_dot_node(self, include_graphical_attributes: bool) -> DotNodeAttributeSet

@property
@abstractmethod
def node_descriptor(self) -> MetricflowGraphNodeDescriptor: # noqa: D102
def node_descriptor(self) -> MetricFlowGraphNodeDescriptor: # noqa: D102
raise NotImplementedError

@property
def labels(self) -> OrderedSet[MetricflowGraphLabel]:
def labels(self) -> OrderedSet[MetricFlowGraphLabel]:
"""Return the labels that can be used for lookups to get this node."""
return MetricflowGraphNode._DEFAULT_NODE_LABELS
return MetricFlowGraphNode._DEFAULT_NODE_LABELS

@override
def pretty_format(self, format_context: PrettyFormatContext) -> Optional[str]:
Expand All @@ -89,13 +89,13 @@ def pretty_format(self, format_context: PrettyFormatContext) -> Optional[str]:


@fast_frozen_dataclass(order=False)
class MetricflowGraphEdge(MetricflowGraphElement, MetricFlowPrettyFormattable, Comparable, Generic[NodeT_co], ABC):
class MetricFlowGraphEdge(MetricFlowGraphElement, MetricFlowPrettyFormattable, Comparable, Generic[NodeT_co], ABC):
"""Base class for edges in a directed graph.

An edge can be visualized as an arrow that points from the tail node to the head node.
"""

_DEFAULT_EDGE_LABELS: ClassVar[OrderedSet[MetricflowGraphLabel]] = FrozenOrderedSet()
_DEFAULT_EDGE_LABELS: ClassVar[OrderedSet[MetricFlowGraphLabel]] = FrozenOrderedSet()

tail_node: NodeT_co
head_node: NodeT_co
Expand Down Expand Up @@ -125,9 +125,9 @@ def as_dot_edge(self, include_graphical_attributes: bool) -> DotEdgeAttributeSet
)

@property
def labels(self) -> OrderedSet[MetricflowGraphLabel]:
def labels(self) -> OrderedSet[MetricFlowGraphLabel]:
"""Return the labels that can be used for lookups to get this edge."""
return MetricflowGraphEdge._DEFAULT_EDGE_LABELS
return MetricFlowGraphEdge._DEFAULT_EDGE_LABELS

@override
def pretty_format(self, format_context: PrettyFormatContext) -> Optional[str]:
Expand All @@ -144,15 +144,15 @@ def pretty_format(self, format_context: PrettyFormatContext) -> Optional[str]:
)

@cached_property
def labels_for_path_addition(self) -> OrderedSet[MetricflowGraphLabel]:
def labels_for_path_addition(self) -> OrderedSet[MetricFlowGraphLabel]:
"""Return the labels for this edge and the head node.

This is useful for collecting labels while building a path by adding an edge.
"""
return self.labels.union(self.head_node.labels)


class MetricflowGraph(MetricFlowPrettyFormattable, Generic[NodeT_co, EdgeT_co], ABC):
class MetricFlowGraph(MetricFlowPrettyFormattable, Generic[NodeT_co, EdgeT_co], ABC):
"""Base class for a directed graph."""

@property
Expand All @@ -162,11 +162,11 @@ def nodes(self) -> OrderedSet[NodeT_co]:
raise NotImplementedError()

@abstractmethod
def nodes_with_labels(self, *graph_labels: MetricflowGraphLabel) -> OrderedSet[NodeT_co]:
def nodes_with_labels(self, *graph_labels: MetricFlowGraphLabel) -> OrderedSet[NodeT_co]:
"""Return nodes in the graph with any one of the given labels."""
raise NotImplementedError()

def node_with_label(self, label: MetricflowGraphLabel) -> NodeT_co:
def node_with_label(self, label: MetricFlowGraphLabel) -> NodeT_co:
"""Finds the node with the given label. If not exactly one if found, an error is raised."""
nodes = self.nodes_with_labels(label)
matching_node_count = len(nodes)
Expand All @@ -187,34 +187,34 @@ def edges(self) -> OrderedSet[EdgeT_co]:
raise NotImplementedError()

@abstractmethod
def edges_with_tail_node(self, tail_node: MetricflowGraphNode) -> OrderedSet[EdgeT_co]:
def edges_with_tail_node(self, tail_node: MetricFlowGraphNode) -> OrderedSet[EdgeT_co]:
"""Returns edges with the given tail node."""
raise NotImplementedError()

@abstractmethod
def edges_with_head_node(self, tail_node: MetricflowGraphNode) -> OrderedSet[EdgeT_co]:
def edges_with_head_node(self, tail_node: MetricFlowGraphNode) -> OrderedSet[EdgeT_co]:
"""Returns edges with the given head node."""
raise NotImplementedError()

@abstractmethod
def edges_with_label(self, label: MetricflowGraphLabel) -> OrderedSet[EdgeT_co]:
def edges_with_label(self, label: MetricFlowGraphLabel) -> OrderedSet[EdgeT_co]:
"""Return the set of edges in a graph that have the given label."""
raise NotImplementedError()

def format(self, formatter: MetricflowGraphFormatter = PrettyFormatGraphFormatter()) -> str:
def format(self, formatter: MetricFlowGraphFormatter = PrettyFormatGraphFormatter()) -> str:
"""Return a representation of this graph using the given formatter."""
return formatter.format_graph(self)

@abstractmethod
def successors(self, node: MetricflowGraphNode) -> OrderedSet[NodeT_co]:
def successors(self, node: MetricFlowGraphNode) -> OrderedSet[NodeT_co]:
"""Returns successors of the given node.

Raises `UnknownNodeException` if the node does not exist in the graph.
"""
return FrozenOrderedSet(edge.head_node for edge in self.edges_with_tail_node(node))

@abstractmethod
def predecessors(self, node: MetricflowGraphNode) -> OrderedSet[NodeT_co]:
def predecessors(self, node: MetricFlowGraphNode) -> OrderedSet[NodeT_co]:
"""Returns predecessors of the given node.

Raises `UnknownNodeException` if the node does not exist in the graph.
Expand All @@ -233,7 +233,7 @@ def as_sorted(self) -> Self:
"""Return a copy of this graph with the nodes and edges sorted."""
raise NotImplementedError

def _intersect_edges(self, other: MetricflowGraph[NodeT_co, EdgeT_co]) -> OrderedSet[EdgeT_co]:
def _intersect_edges(self, other: MetricFlowGraph[NodeT_co, EdgeT_co]) -> OrderedSet[EdgeT_co]:
return self.edges.intersection(other.edges)

@abstractmethod
Expand Down Expand Up @@ -267,7 +267,7 @@ def as_dot_graph(self, include_graphical_attributes: bool) -> DotGraphAttributeS

@property
@abstractmethod
def graph_id(self) -> MetricflowGraphId:
def graph_id(self) -> MetricFlowGraphId:
"""Return a graph ID.

This ID will be used for caching cases.
Expand Down
Loading