109 lines
3.6 KiB
Python
109 lines
3.6 KiB
Python
|
from __future__ import annotations
|
||
|
|
||
|
from typing import TYPE_CHECKING
|
||
|
|
||
|
if TYPE_CHECKING:
|
||
|
from collections.abc import Collection, Iterable
|
||
|
|
||
|
|
||
|
class NarwhalsError(ValueError):
|
||
|
"""Base class for all Narwhals exceptions."""
|
||
|
|
||
|
|
||
|
class FormattedKeyError(KeyError):
|
||
|
"""KeyError with formatted error message.
|
||
|
|
||
|
Python's `KeyError` has special casing around formatting
|
||
|
(see https://bugs.python.org/issue2651). Use this class when the error
|
||
|
message has newlines and other special format characters.
|
||
|
Needed by https://github.com/tensorflow/tensorflow/issues/36857.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, message: str) -> None:
|
||
|
self.message = message
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
return self.message
|
||
|
|
||
|
|
||
|
class ColumnNotFoundError(FormattedKeyError, NarwhalsError):
|
||
|
"""Exception raised when column name isn't present."""
|
||
|
|
||
|
def __init__(self, message: str) -> None:
|
||
|
self.message = message
|
||
|
super().__init__(self.message)
|
||
|
|
||
|
@classmethod
|
||
|
def from_missing_and_available_column_names(
|
||
|
cls, missing_columns: Iterable[str], available_columns: Collection[str], /
|
||
|
) -> ColumnNotFoundError:
|
||
|
message = (
|
||
|
f"The following columns were not found: {sorted(missing_columns)}"
|
||
|
f"\n\nHint: Did you mean one of these columns: {list(available_columns)}?"
|
||
|
)
|
||
|
return ColumnNotFoundError(message)
|
||
|
|
||
|
@classmethod
|
||
|
def from_available_column_names(
|
||
|
cls, available_columns: Collection[str]
|
||
|
) -> ColumnNotFoundError:
|
||
|
message = (
|
||
|
"The selected columns were not found."
|
||
|
f"\n\nHint: Did you mean one of these columns: {list(available_columns)}?"
|
||
|
)
|
||
|
return ColumnNotFoundError(message)
|
||
|
|
||
|
|
||
|
class ComputeError(NarwhalsError):
|
||
|
"""Exception raised when the underlying computation could not be evaluated."""
|
||
|
|
||
|
|
||
|
class ShapeError(NarwhalsError):
|
||
|
"""Exception raised when trying to perform operations on data structures with incompatible shapes."""
|
||
|
|
||
|
|
||
|
class MultiOutputExpressionError(NarwhalsError):
|
||
|
"""Exception raised when using multi-output expression in unsupported context."""
|
||
|
|
||
|
|
||
|
class DuplicateError(NarwhalsError):
|
||
|
"""Exception when duplicate column names are encountered."""
|
||
|
|
||
|
|
||
|
class InvalidOperationError(NarwhalsError):
|
||
|
"""Exception raised during invalid operations."""
|
||
|
|
||
|
|
||
|
class InvalidIntoExprError(TypeError, NarwhalsError):
|
||
|
"""Exception raised when object can't be converted to expression."""
|
||
|
|
||
|
def __init__(self, message: str) -> None:
|
||
|
self.message = message
|
||
|
super().__init__(self.message)
|
||
|
|
||
|
@classmethod
|
||
|
def from_invalid_type(cls: type, invalid_type: type) -> InvalidIntoExprError:
|
||
|
message = (
|
||
|
f"Expected an object which can be converted into an expression, got {invalid_type}\n\n"
|
||
|
"Hint:\n"
|
||
|
"- if you were trying to select a column which does not have a string\n"
|
||
|
" column name, then you should explicitly use `nw.col`.\n"
|
||
|
" For example, `df.select(nw.col(0))` if you have a column named `0`.\n"
|
||
|
"- if you were trying to create a new literal column, then you \n"
|
||
|
" should explicitly use `nw.lit`.\n"
|
||
|
" For example, `df.select(nw.lit(0))` if you want to create a new\n"
|
||
|
" column with literal value `0`."
|
||
|
)
|
||
|
return InvalidIntoExprError(message)
|
||
|
|
||
|
|
||
|
class UnsupportedDTypeError(NarwhalsError):
|
||
|
"""Exception raised when trying to convert to a DType which is not supported by the given backend."""
|
||
|
|
||
|
|
||
|
class NarwhalsUnstableWarning(UserWarning):
|
||
|
"""Warning issued when a method or function is considered unstable in the stable api."""
|
||
|
|
||
|
|
||
|
class PerformanceWarning(Warning): ...
|