Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type hints: Finish type hints and mark package as typed #3263

Closed
wants to merge 56 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
8279a1d
Include schema files in mypy type checking
binste Sep 29, 2023
00fff06
Merge branch 'main' into autoinfer_types
binste Sep 29, 2023
28b5727
Use actual names of Python types in docstrings
binste Sep 29, 2023
afaa49f
Simplify medium_description by removing unused code paths
binste Sep 29, 2023
3edb68d
Use Python type hint syntax instead of pseudo jsonschema syntax in do…
binste Sep 29, 2023
fb81f4e
First version of autoinferred type hints
binste Sep 29, 2023
8662430
Various improvements
binste Sep 29, 2023
6d60cf3
Add type hints to mixins.py
binste Sep 30, 2023
7d945d7
Bug fix: Add missing overload operators
binste Sep 30, 2023
b6d5c6a
Add type hints to arguments of overload signatures where the signatur…
binste Sep 30, 2023
161d47b
Add type hint for Parameter
binste Sep 30, 2023
f02518b
Deduplicate type hints
binste Sep 30, 2023
581ae27
Minor renaming and reordering of type hints
binste Sep 30, 2023
6f7a6ef
Recursively go through types to get all for type hints as well as doc…
binste Sep 30, 2023
a66e070
Instead of writing a List of Unions, do it the other way around and d…
binste Sep 30, 2023
30d9ea0
Use Sequence instead of List
binste Sep 30, 2023
c565fe4
Simplify code
binste Sep 30, 2023
10764db
Remove unused ignore statement. Seems like mypy can now correctly det…
binste Sep 30, 2023
54439c8
Switch to tooltip specification which conforms to type hints
binste Sep 30, 2023
8d212d6
Ignore mypy errors when it cannot detect the existence of the .copy m…
binste Sep 30, 2023
788bf8d
Explicitly pass kwarg arguments in these examples
binste Sep 30, 2023
fdadf95
Fix schema for 'shorthand' as it also accepts an array of strings
binste Sep 30, 2023
879365d
Revert "Switch to tooltip specification which conforms to type hints"
binste Sep 30, 2023
513709f
Fix some more mypy errors
binste Sep 30, 2023
e0c841e
Ignore mypy overload errors
binste Sep 30, 2023
0e803bc
Black and ruff
binste Sep 30, 2023
ebaaee2
Add type hints to channel mixins
binste Oct 1, 2023
7bdf2a0
Simplify docstrings by removing Union so they look better in docs. Re…
binste Oct 1, 2023
d964fa1
Merge branch 'main' into autoinfer_types
binste Oct 28, 2023
4a2d77a
Fix merge conflicts and rerun schema generation
binste Oct 28, 2023
2a3031a
Remove redundat capability with VL v2
binste Oct 29, 2023
f99e19c
Factor out adding shorthand into a separate function. Fix missing Fie…
binste Oct 29, 2023
c9ece69
Add missing shorthand to field definitions in core.py
binste Oct 29, 2023
9a0e96b
Add shorthand str and list[str] type hints to signature of encode method
binste Oct 29, 2023
a19f846
Fix various mypy errors
binste Oct 29, 2023
18d96e4
Fix mypy error for data argument. Add RepeatRef as a type hint for sh…
binste Oct 30, 2023
bbc9d50
Add _ParameterProtocol wherever ParameterExtent is accepted
binste Oct 30, 2023
76d4457
Merge branch 'main' into autoinfer_types
binste Oct 30, 2023
c4fcbe2
Switch to ruff as code formatter
binste Oct 30, 2023
d334a1e
Ruff fix
binste Oct 30, 2023
3b4703a
Move type ignore comment which was shifted by Ruff
binste Oct 30, 2023
3e28f3f
Try to fix mypy issue in pipeline which does not appear locally
binste Oct 30, 2023
58f486b
Change type signature of encode method to only include the types whic…
binste Oct 31, 2023
cadcf57
Only show type hints for datum and value if they are accepted
binste Oct 31, 2023
3526c36
Fix trailing whitespace
binste Oct 31, 2023
8209f75
Switch back to just 'dict'
binste Nov 2, 2023
0292f14
Add type hint for list to encoding channels which support it
binste Nov 4, 2023
dc4194d
Rename _ParameterProtocol to _Parameter
binste Nov 8, 2023
e76dd42
Fix ruff error
binste Nov 8, 2023
8116657
Add parameters incl. type hints to docstrings. Without descriptions f…
binste Nov 11, 2023
e4f3073
Add descriptions
binste Nov 11, 2023
c364b78
Change import statement for expr.core to help type checkers
binste Nov 11, 2023
f851268
Type Undefined as UndefinedType. Some minor mypy fixes
binste Nov 11, 2023
b513c14
Add entry to changelog
binste Nov 11, 2023
fb99ded
Make types public so users can use them in their own code if needed
binste Nov 11, 2023
780a18a
Add py.typed
binste Nov 11, 2023
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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ hatch run test
```


This also runs the [`black`](https://black.readthedocs.io/) code formatter, [`ruff`](https://ruff.rs/) linter and [`mypy`](https://mypy-lang.org/) as type checker.
This also runs the [`ruff`](https://ruff.rs/) linter and formatter as well as [`mypy`](https://mypy-lang.org/) as type checker.


Study the output of any failed tests and try to fix the issues
Expand Down
Empty file added altair/py.typed
Empty file.
6 changes: 3 additions & 3 deletions altair/utils/_vegafusion_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from altair.utils._importers import import_vegafusion
from altair.utils.core import _DataFrameLike
from altair.utils.data import _DataType, _ToValuesReturnType, MaxRowsError
from altair.utils.data import DataType, ToValuesReturnType, MaxRowsError
from altair.vegalite.data import default_data_transformer

# Temporary storage for dataframes that have been extracted
Expand All @@ -29,8 +29,8 @@ class _ToVegaFusionReturnUrlDict(TypedDict):

@curried.curry
def vegafusion_data_transformer(
data: _DataType, max_rows: int = 100000
) -> Union[_ToVegaFusionReturnUrlDict, _ToValuesReturnType]:
data: DataType, max_rows: int = 100000
) -> Union[_ToVegaFusionReturnUrlDict, ToValuesReturnType]:
"""VegaFusion Data Transformer"""
if hasattr(data, "__geo_interface__"):
# Use default transformer for geo interface objects
Expand Down
14 changes: 7 additions & 7 deletions altair/utils/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
if TYPE_CHECKING:
from pandas.core.interchange.dataframe_protocol import Column as PandasColumn

_V = TypeVar("_V")
_P = ParamSpec("_P")
V = TypeVar("V")
P = ParamSpec("P")


class _DataFrameLike(Protocol):
Expand Down Expand Up @@ -188,12 +188,12 @@ def __dataframe__(self, *args, **kwargs) -> DfiDataFrame:
]


_InferredVegaLiteType = Literal["ordinal", "nominal", "quantitative", "temporal"]
InferredVegaLiteType = Literal["ordinal", "nominal", "quantitative", "temporal"]


def infer_vegalite_type(
data: object,
) -> Union[_InferredVegaLiteType, Tuple[_InferredVegaLiteType, list]]:
) -> Union[InferredVegaLiteType, Tuple[InferredVegaLiteType, list]]:
"""
From an array-like input, infer the correct vega typecode
('ordinal', 'nominal', 'quantitative', or 'temporal')
Expand Down Expand Up @@ -637,7 +637,7 @@ def parse_shorthand(

def infer_vegalite_type_for_dfi_column(
column: Union[Column, "PandasColumn"],
) -> Union[_InferredVegaLiteType, Tuple[_InferredVegaLiteType, list]]:
) -> Union[InferredVegaLiteType, Tuple[InferredVegaLiteType, list]]:
from pyarrow.interchange.from_dataframe import column_to_array

try:
Expand Down Expand Up @@ -672,10 +672,10 @@ def infer_vegalite_type_for_dfi_column(
raise ValueError(f"Unexpected DtypeKind: {kind}")


def use_signature(Obj: Callable[_P, Any]):
def use_signature(Obj: Callable[P, Any]):
"""Apply call signature and documentation of Obj to the decorated method"""

def decorate(f: Callable[..., _V]) -> Callable[_P, _V]:
def decorate(f: Callable[..., V]) -> Callable[P, V]:
# call-signature of f is exposed via __wrapped__.
# we want it to mimic Obj.__init__
f.__wrapped__ = Obj.__init__ # type: ignore
Expand Down
22 changes: 11 additions & 11 deletions altair/utils/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ class _SupportsGeoInterface(Protocol):
__geo_interface__: MutableMapping


_DataType = Union[dict, pd.DataFrame, _SupportsGeoInterface, _DataFrameLike]
_TDataType = TypeVar("_TDataType", bound=_DataType)
DataType = Union[dict, pd.DataFrame, _SupportsGeoInterface, _DataFrameLike]
TDataType = TypeVar("TDataType", bound=DataType)

_VegaLiteDataDict = Dict[str, Union[str, dict, List[dict]]]
_ToValuesReturnType = Dict[str, Union[dict, List[dict]]]
VegaLiteDataDict = Dict[str, Union[str, dict, List[dict]]]
ToValuesReturnType = Dict[str, Union[dict, List[dict]]]


# ==============================================================================
Expand All @@ -46,7 +46,7 @@ class _SupportsGeoInterface(Protocol):
# form.
# ==============================================================================
class DataTransformerType(Protocol):
def __call__(self, data: _DataType, **kwargs) -> _VegaLiteDataDict:
def __call__(self, data: DataType, **kwargs) -> VegaLiteDataDict:
pass


Expand All @@ -70,7 +70,7 @@ class MaxRowsError(Exception):


@curried.curry
def limit_rows(data: _TDataType, max_rows: Optional[int] = 5000) -> _TDataType:
def limit_rows(data: TDataType, max_rows: Optional[int] = 5000) -> TDataType:
"""Raise MaxRowsError if the data model has more than max_rows.

If max_rows is None, then do not perform any check.
Expand Down Expand Up @@ -122,7 +122,7 @@ def raise_max_rows_error():

@curried.curry
def sample(
data: _DataType, n: Optional[int] = None, frac: Optional[float] = None
data: DataType, n: Optional[int] = None, frac: Optional[float] = None
) -> Optional[Union[pd.DataFrame, Dict[str, Sequence], "pyarrow.lib.Table"]]:
"""Reduce the size of the data model by sampling without replacement."""
check_data_type(data)
Expand Down Expand Up @@ -180,7 +180,7 @@ class _ToCsvReturnUrlDict(TypedDict):

@curried.curry
def to_json(
data: _DataType,
data: DataType,
prefix: str = "altair-data",
extension: str = "json",
filename: str = "{prefix}-{hash}.{extension}",
Expand Down Expand Up @@ -215,7 +215,7 @@ def to_csv(


@curried.curry
def to_values(data: _DataType) -> _ToValuesReturnType:
def to_values(data: DataType) -> ToValuesReturnType:
"""Replace a DataFrame by a data model with values."""
check_data_type(data)
if hasattr(data, "__geo_interface__"):
Expand All @@ -242,7 +242,7 @@ def to_values(data: _DataType) -> _ToValuesReturnType:
raise ValueError("Unrecognized data type: {}".format(type(data)))


def check_data_type(data: _DataType) -> None:
def check_data_type(data: DataType) -> None:
if not isinstance(data, (dict, pd.DataFrame)) and not any(
hasattr(data, attr) for attr in ["__geo_interface__", "__dataframe__"]
):
Expand All @@ -260,7 +260,7 @@ def _compute_data_hash(data_str: str) -> str:
return hashlib.md5(data_str.encode()).hexdigest()


def _data_to_json_string(data: _DataType) -> str:
def _data_to_json_string(data: DataType) -> str:
"""Return a JSON string representation of the input data"""
check_data_type(data)
if hasattr(data, "__geo_interface__"):
Expand Down
10 changes: 3 additions & 7 deletions altair/utils/schemapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
else:
from typing_extensions import Self

_TSchemaBase = TypeVar("_TSchemaBase", bound="SchemaBase")
TSchemaBase = TypeVar("TSchemaBase", bound=Type["SchemaBase"])

ValidationErrorList = List[jsonschema.exceptions.ValidationError]
GroupedValidationErrors = Dict[str, ValidationErrorList]
Expand Down Expand Up @@ -733,11 +733,7 @@ def __repr__(self):
return "Undefined"


# In the future Altair may implement a more complete set of type hints.
# But for now, we'll add an annotation to indicate that the type checker
# should permit any value passed to a function argument whose default
# value is Undefined.
Undefined: Any = UndefinedType()
Undefined = UndefinedType()


class SchemaBase:
Expand Down Expand Up @@ -1329,7 +1325,7 @@ def __call__(self, *args, **kwargs):
return obj


def with_property_setters(cls: _TSchemaBase) -> _TSchemaBase:
def with_property_setters(cls: TSchemaBase) -> TSchemaBase:
"""
Decorator to add property setters to a Schema class.
"""
Expand Down
6 changes: 3 additions & 3 deletions altair/vegalite/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
check_data_type,
)
from ..utils.data import DataTransformerRegistry as _DataTransformerRegistry
from ..utils.data import _DataType, _ToValuesReturnType
from ..utils.data import DataType, ToValuesReturnType
from ..utils.plugin_registry import PluginEnabler


@curried.curry
def default_data_transformer(
data: _DataType, max_rows: int = 5000
) -> _ToValuesReturnType:
data: DataType, max_rows: int = 5000
) -> ToValuesReturnType:
return curried.pipe(data, limit_rows(max_rows=max_rows), to_values)


Expand Down
Loading