-
-
Notifications
You must be signed in to change notification settings - Fork 933
Let remote.push return a PushInfoList #1360
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
Let remote.push return a PushInfoList #1360
Conversation
Thanks for keeping the ball rolling on solving the matter. Changing the type of the return value could probably easily be a backward incompatible change unless (probably impossible) care is taken to make the type equivalent even in the presence of Hence I think having an entirely new method for it that can do what it wants is the only safe way. |
Well, the new @Yobmod, what do you think? |
Thanks for the clarification. Could you post an example invocation for me to understand how one would enable exceptions using the return type? My intuition here is that a separate method with different semantics will be similarly opt-in, but inherently more straightforward to use. |
The most straightforward usage is like this:
The return value of
This adds more flexibility for custom error handling, compared to a new method. A similar pattern is used in requests' raise_for_status, which raises an error when a HTTP request returns an error status code. |
Thanks for the clarification! I think my biggest stumbling block was the naming, specifically Maybe it will help most to rename it to Since the the respective field is called Once the naming is clear, I think there shouldn't be anything else holding this PR back. |
List-like, so that it's backward compatible. But it has a new method raise_on_error, that throws an exception if anything failed to push. Related to gitpython-developers#621
b705587
to
997a3b6
Compare
@Sjord Please feel free to mark this PR as ready when ready. If there are problems with types, [AT]Yobmod might be able to provide some clues. |
997a3b6
to
808179e
Compare
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 looks great, thanks a lot.
I think once we can prove that the type system won't break by this change either it's definitely ready to be merged.
Thanks a lot
git/remote.py
Outdated
@@ -116,6 +116,23 @@ def to_progress_instance(progress: Union[Callable[..., Any], RemoteProgress, Non | |||
return progress | |||
|
|||
|
|||
class PushInfoList(IterableList): |
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 strange thing is that I would expect IterableList[PushInfo]
to be the base class, or at least something in this type should indicate that PushInfo
s are iterated over.
That way, PushInfoList
would be fitting in place of IterableList[PushInfo]
, which might even be a test to add to assure the type system stays compatible, too.
Something like…
def f(l: IterableList[PushInfo]):
pass
f(PushInfoList())
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 agree, but I had trouble getting this to work with mypy.
The list with pushinfos was created like this:
output: IterableList[PushInfo] = IterableList('push_infos')
I am not sure what the push_infos
argument is for, but I tried moving it into PushInfoList:
class PushInfoList(IterableList[PushInfo]):
def __new__(cls) -> 'PushInfoList':
return super().__new__(cls, 'push_infos')
def __init__(self) -> None:
super().__init__('push_infos')
self.error: Optional[Exception] = None
However, mypy doesn't agree with this. The types don't match up in __new__
. super(IterableList[PushInfo], cls)
doesn't work, so now I have a call explicitly to IterableList.__new__
. Is that OK?
class PushInfoList(IterableList[PushInfo]):
def __new__(cls) -> 'PushInfoList':
return cast(PushInfoList, IterableList.__new__(cls, 'push_infos'))
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.
"push_infos"
is supposed to be an id_attribute
, which definitely isn't useful here as it is used like this.
Maybe @Yobmod can help us clarify if this .__new__
calling convention to pacify mypi is the expected way, or if there are more idiomatic ways to do this.
From my point of view, it's certainly OK even though I can't tell if a future patch release of mypi is going to stop accepting it.
eec1b97
to
a270deb
Compare
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.
Thanks for the improvement to the types, much appreciated.
Is it possible to add a test for this type, too, to validate that the new type now passes for the old if used in a typed function like this?
def f(l: IterableList[PushInfo]):
pass
f(PushInfoList())
This is not so easy. I tried the folllowing, but
Another possibility would be to let mypy do the testing; mypy would raise an error on your example code if |
Thanks for having given it a shot. I wasn't even aware that the tests aren't yet checked with mypi and can imagine that trying to do that would result in a slew of errors that aren't worth fixing. If you can tell me something like the code I suggested worked in your local tests, I think we are ready to merge, having tried our best to not break anything. Thank you |
Yes, I temporarily put the example you supplied in remote.py, and mypy agrees that 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.
Thanks a lot for all the work that went into this and for hanging in there :).
List-like, so that it's backward compatible. But it has a new method
raise_on_error, that throws an exception if anything failed to push.
Related to #621
This is more of a proposal for this design. Is this actually backward-compatible? Should we check the flags of all PushInfos in
raise_on_error
? Is this better than a new methodpush_really_or_else_raise()
orpush(raise=True)
? What if aPushInfo
is missing from the result because it totally failed?