-
Notifications
You must be signed in to change notification settings - Fork 185
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
Improve ListArtifact #1093
Improve ListArtifact #1093
Conversation
9c33e91
to
1d189b8
Compare
Codecov ReportAttention: Patch coverage is
📢 Thoughts on this report? Let us know! |
1d189b8
to
bd93052
Compare
bd93052
to
00b780e
Compare
410587d
to
7fe622c
Compare
I thought the type check was dependency related but there's something else going on. Looking into it. |
ba1a0d1
to
982f708
Compare
def validate_value(self, _: Attribute, value: list[T]) -> None: | ||
if self.validate_uniform_types and len(value) > 0: |
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 validate_uniform_types
still applicable here?
what would happen with:
ListArtifact[BlobArtifact]([TextArtifact("foo")], validate_uniform_types=False)
?
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 validate_uniform_types
is still useful as a runtime check (although we don't actually use it anywhere lol). In your example, it would fail type check but succeed at runtime.
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.
Awesome!
griptape/artifacts/list_artifact.py
Outdated
from collections.abc import Sequence | ||
from collections.abc import Iterator, Sequence | ||
|
||
T = TypeVar("T", bound=BaseArtifact) |
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 this should set covariant=True
.
This will allow for example, passing ListArtifact[TextArtifact]
where a ListArtifact[BaseTextArtifact]
is required.
Relating it to the definition of a covariant type, if ListArtifact[T]
is covariant in T
if ListArtifact[S]
is considered a subtype of ListArtifact[T]
whenever S
is a subtype of T
. Kind of like the bounds=
, but where the value of bounds is determined by a particular usage rather than all usages.
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.
Great suggestion! Will update.
class ListArtifact(BaseArtifact, Generic[T]): | ||
value: Sequence[T] = field(factory=list, metadata={"serializable": True}) |
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.
Could you remind me why value
is Sequence
instead of list
? If you wanted ListArtifact
to subclass a collection, would you pick Sequence
or list
? (I expect the choice to be based on whether or not ListArtifact should be mutable or not)
We currently implement the interface of at least Sequence
(required methods are __getitem__
, __len__
, __contains__
), but we just don't have the base class.
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.
list
is not covariant, Sequence
is. Here is an example pyright error:
Return type mismatch: base method returns type "BaseArtifact | list[BaseArtifact]", override returns type "list[CsvRowArtifact]"
Type "list[CsvRowArtifact]" is incompatible with type "BaseArtifact | list[BaseArtifact]"
"list[CsvRowArtifact]" is incompatible with "BaseArtifact"
"list[CsvRowArtifact]" is incompatible with "list[BaseArtifact]"
Type parameter "_T@list" is invariant, but "CsvRowArtifact" is not the same as "BaseArtifact"
Consider switching from "list" to "Sequence" which is covariant (reportIncompatibleMethodOverride)
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.
TIL!
After looking into why list
is not covariant and why Sequence
is, its because list
is mutable!
example:
class Animal:
pass
class Dog(Animal):
pass
dogs: list[Dog] = [Dog(), Dog()]
animals: list[Animal] = dogs # This would be allowed if lists were covariant
animals.append(Animal()) # Adding an Animal (not necessarily a Dog!) to a list of Dogs
So this leads me to the question, ListArtifact
is not intended to be mutable, is it?
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.
ListArtifact is not intended to be mutable, is it?
Good question, probably not. I can investigate changing back to list
, but it will have implications throughout the codebase so I think it should be done in a separate PR.
1c7f97d
to
a7f10d4
Compare
Many Artifact refactors incoming |
Describe your changes
Added
ListArtifact
.ListArtifact
.Issue ticket number and link
NA