-
Notifications
You must be signed in to change notification settings - Fork 5
feat: HasX attributes #34
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
base: main
Are you sure you want to change the base?
Conversation
@jorenham @NeilGirdhar @lucascolley this doesn't resolve the current discussion re a |
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 like the Has*
protocols. Optype will cover the CanArray*
ones I think. There might be some that can't be expressed because Self
can't be passed as generic type argument, but I suppose we can deal with it when needed.
One nit is that ...
are not needed when there's a docstring, which already counts as an expression or statement or something.
What do we do about docstrings?
Yes, my pylint is complaining. But IMO empty methods should have |
Hmm good question. Maybe a numpy-esque |
Yea I guess there's something to be said for that. It just looks a bit weird to me to see a |
8096aff
to
3793c1f
Compare
cb3dbb3
to
dec1842
Compare
dec1842
to
53ddb98
Compare
Signed-off-by: nstarman <[email protected]>
Signed-off-by: nstarman <[email protected]>
Signed-off-by: nstarman <[email protected]>
Signed-off-by: Nathaniel Starkman <[email protected]>
Signed-off-by: nstarman <[email protected]>
53ddb98
to
a5e3d5b
Compare
@jorenham I added tests and made the protocols public. |
@jorenham This should cover all the array attributes. |
"""Protocol for array classes that have a shape attribute.""" | ||
|
||
@property | ||
def shape(self) -> tuple[int | None, ...]: |
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 in a followup we should add a type parameter UnknownDimsT = TypeVar(None, Never, default=None)
so that it's possible to define an array where the dimensions are always known.
Array[..., UnknownDimsT=Never]
Then we can define the alias types
KnownDimsArray: TypeAlias = Array[..., Never]
UnknownDimsArray: TypeAlias = Array[..., None]
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.
what would UnknownDimsT
be the type of, then?
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.
?
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.
we should add a type parameter
UnknownDimsT = TypeVar(None, Never, default=None)
as in; what will it annotate
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.
The dim types, like
def shape(self) -> tuple[int | UnknownDimsT, ...]:
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.
Ah, ok, that makes sense. I was confused because it's a plural Dims
.
... | ||
|
||
|
||
class HasSize(Protocol): |
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.
What's the use-case of this one? Is there anything this can help with, that HasShape
can't?
Put differently; should we make this public API or not?
... | ||
|
||
|
||
class HasTranspose(Protocol): |
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.
Ah nice; this could be used to annotate functions that exclusively accept 2d arrays, without having to deal with shape-typing :)
HasNDim, | ||
HasShape, | ||
HasSize, | ||
HasTranspose, |
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.
This HasTranspose
restricts this to 2d arrays
_: np.dtype[F32] = x_f32.dtype | ||
_: np.dtype[I32] = x_i32.dtype | ||
_: np.dtype[B] = x_b.dtype | ||
|
||
# Check Attribute `.device` | ||
_: object = x_f32.device | ||
_: object = x_i32.device | ||
_: object = x_b.device |
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'd go with typing.assert_type
here
_: int = x_f32.ndim | ||
_: int = x_i32.ndim | ||
_: int = x_b.ndim | ||
|
||
# Check Attribute `.shape` | ||
_: tuple[int | None, ...] = x_f32.shape | ||
_: tuple[int | None, ...] = x_i32.shape | ||
_: tuple[int | None, ...] = x_b.shape | ||
|
||
# Check Attribute `.size` | ||
_: int | None = x_f32.size | ||
_: int | None = x_i32.size | ||
_: int | None = x_b.size |
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.
typing.assert_type
... | ||
|
||
|
||
class HasMatrixTranspose(Protocol): |
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'd move this one closer to HasTranspose
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.
And the use-case of this is to require at least 2 dimensions, right?
... | ||
|
||
|
||
class HasNDim(Protocol): |
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.
Is there a situation where you'd wanna use HasNDim
over e.g. HasShape
? Otherwise we probably should keep this private, given that
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
"""Protocol for array classes that have a device attribute.""" | ||
|
||
@property | ||
def device(self) -> object: # TODO: more specific type |
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 can see how this can be helpful for users if it would be generic. So I propose we either keep it private until that time, or to just make it generic right now.
Requires #32. I'll rebase when that's in.Now preceding #32.