-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
WIP: type annotations #2877
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
WIP: type annotations #2877
Changes from 2 commits
b9b0543
a646404
ae14ff5
d640c8b
fd31571
1028c71
bdbb4fe
b1a0e9e
266d8f4
c9d0c1a
81701ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,6 +1,8 @@ | ||||||
| from collections import OrderedDict | ||||||
| from contextlib import suppress | ||||||
| from textwrap import dedent | ||||||
| from typing import (Callable, Iterable, Mapping, Optional, Tuple, TypeVar, | ||||||
| Sequence, Union, overload) | ||||||
|
|
||||||
| import numpy as np | ||||||
| import pandas as pd | ||||||
|
|
@@ -15,6 +17,9 @@ | |||||
| ALL_DIMS = ReprObject('<all-dims>') | ||||||
|
|
||||||
|
|
||||||
| T = TypeVar('T') | ||||||
|
|
||||||
|
|
||||||
| class ImplementsArrayReduce(object): | ||||||
| @classmethod | ||||||
| def _reduce_method(cls, func, include_skipna, numeric_only): | ||||||
|
|
@@ -115,7 +120,15 @@ def __iter__(self): | |||||
| def T(self): | ||||||
| return self.transpose() | ||||||
|
|
||||||
| def get_axis_num(self, dim): | ||||||
| @overload | ||||||
| def get_axis_num(self, dim: str) -> int: | ||||||
| pass | ||||||
|
|
||||||
| @overload # noqa:F811 | ||||||
| def get_axis_num(self, dim: Iterable[str]) -> Tuple[int]: | ||||||
|
||||||
| def get_axis_num(self, dim: Iterable[str]) -> Tuple[int]: | |
| def get_axis_num(self, dim: Iterable[Hashable]) -> Tuple[int, ...]: |
(Also Tuple[int] should be Tuple[int, ...])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If they were intended to be allowed to be non-strings, sure they aren't tested for it!
>>> xarray.DataArray([1,2], dims=[123])
TypeError: dimension 123 is not a string
Also I've never seen it mentioned in the documentation...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed Tuple[int, ...]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. It seems that you can only construct these sorts of names/dimensions with the Dataset API:
In [8]: xarray.Dataset({123: ((456,), [1, 2, 3])})
Out[8]:
<xarray.Dataset>
Dimensions: (456: 3)
Dimensions without coordinates: 456
Data variables:
123 (456) int64 1 2 3
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| def _get_axis_num(self, dim: str) -> int: | |
| def _get_axis_num(self, dim: Hashable) -> int: |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think Frozen is a valid type annotation. Maybe better to stick with Mapping[str, int]?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is valid as I changed the Frozen class to be a subclass of typing.Mapping
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed to Mapping[str, int] for the sake of user friendliness, as Frozen isn't really part of the public API
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably should be something more relaxed, perhaps dim: Union[Hashable, Iterable[Hashable]]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trouble with Iterable is that it doesn't necessarily allow you to iterate upon it twice (e.g. a file handler). I've tweaked the code to allow for it.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
key can actually be any hashable item here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like coord_func is more flexible than this. It looks like this should probably: Union[str, Mapping[Any, str]].
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
didn't you say that all dims should be Hashable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Mapping[Any, str] and Mapping[Hashable, str] are equivalent -- every mapping key must be hashable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, there's absolutely nothing in Mapping saying that the keys must be hashable.
This is perfectly legit, and pretty useful too:
class AnyKeyDict(MutableMapping[K, V]):
def __init__(self, *args: Tuple[K, V], **kwargs: V)::
self.mapping = {}
for k, v in args:
self[k] = v
for k, v in kwargs.items():
self[k] = v
def __setitem__(self, k: K, v: V) -> None:
try:
self.mapping[k] = v
except TypeError:
self.mapping[pickle.dumps(k)] = v
...
This can be useful in a few borderline scenarios; for example when de-serialising msgpack data from a non-Python producer, as in msgpack map keys can be anything. Also I'd love to see something like this:
class DataArray:
def __setitem__(self, k, v):
if isinstance(k, Mapping):
view = self.sel(**k)
else:
view = self.isel(**k)
view[:] = v
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, good point.
It turns out we actually do already support this for DataArray :)
>>> data = xarray.DataArray([0, 0, 0], dims='x')
>>> data[{'x': 1}] = 1
>>> data
<xarray.DataArray (x: 3)>
array([0, 1, 0])
Dimensions without coordinates: x
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's more idiomatic to use
...rather thanpasswhen writing overloads?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed