You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When writing a reproduction for #1381 I stumbled upon this.
rustworkx version: currently on main (commit f2f45425c70b49d89aa5527271a34f64fb114f1d)
Python version: 3.12
Rust version: ...
Operating system: ubuntu
What is the current behavior?
The method PyDiGraph.extend_from_edge_list restricts the input graph's to PyDiGraph[_S | None, _T | None]. In turn this causes static type checker to rightfully complain when the typevars are declared to but not None.
This is because PyDiGraph is defined to be invariant WRT the _T and _S typevars. This implies that PyDiGraph[int, int] is not assignable to PyDiGraph[int | None, int | None].
I tried searching for more function with | None and found that the methods (of both graph classes) extend_from_edge_list, extend_from_weighted_edge_list, add_edges_from_no_data, and the functions digraph_complement, graph_complement, complement, local_complement.
Probably suffer from a similar issue.
What is the expected behavior?
I expected to be able to run the reproduction below without mypy / pyright complaining about bad argument.
As annotation fixes:
for the methods extend_from_edge_list, extend_from_weighted_edge_list, add_edges_from_no_data, this is simply removing the | None.
For the universal complement and it two non-universal variant functions, if I understand the documentation correctly, the return type should have just None on the edge payload typvar, and not _T | None.
For local_complement, I think the type annotation is correct as is.
The annotations make me think that the graph classes are not intended to behave invariantly, but rather covariantly, if this is desirable the way to do it is:
Personally, I think its better to keep them invariant, and if users of rustworkx want covariance / contravariance in their external functions they can define their signature as they like.
t.py:5: error: Invalid self argument "PyDiGraph[int, int]" to attribute function "extend_from_edge_list" with type "Callable[[PyDiGraph[_S | None, _T | None], Iterable[tuple[int, int]]], None]" [misc]
Found 1 error in 1 file (checked 1 source file)
and pyright t.py (in "basic" setting):
/home/barak-katzir/dev/rustworkx-check/t.py
/home/barak-katzir/dev/rustworkx-check/t.py:6:7 - error: Cannot access attribute "extend_from_edge_list" for class "PyDiGraph[int, int]"
Could not bind method "extend_from_edge_list" because "PyDiGraph[int, int]" is not assignable to parameter "self"
"PyDiGraph[int, int]" is not assignable to "PyDiGraph[int | None, int | None]"
Type parameter "_S@PyDiGraph" is invariant, but "int" is not the same as "int | None"
Type parameter "_T@PyDiGraph" is invariant, but "int" is not the same as "int | None" (reportAttributeAccessIssue)
1 error, 0 warnings, 0 informations
The text was updated successfully, but these errors were encountered:
We had this discussion in #401 and I think that adding Optional was the possibly wrong solution we came at the time.
The best solution would to have a specialization forbidding adding edges without data if _T cannot be None.
The second best solution in the meantime is to cast, we are not covariant on purpose. It is kind like Python lists. But casting to a covariant type is always right
Interesting, now that you write it like that it seems that mypy and pyright did exactly that, and forbade adding None to int in the reproduction I gave.
If so, the only thing left of this issue is maybe to change the return type of complement, graph_complement and digraph_complement to have edge type of None
Information
When writing a reproduction for #1381 I stumbled upon this.
f2f45425c70b49d89aa5527271a34f64fb114f1d
)What is the current behavior?
The method
PyDiGraph.extend_from_edge_list
restricts the input graph's toPyDiGraph[_S | None, _T | None]
. In turn this causes static type checker to rightfully complain when the typevars are declared to but notNone
.This is because
PyDiGraph
is defined to be invariant WRT the_T
and_S
typevars. This implies thatPyDiGraph[int, int]
is not assignable toPyDiGraph[int | None, int | None]
.I tried searching for more function with
| None
and found that the methods (of both graph classes)extend_from_edge_list
,extend_from_weighted_edge_list
,add_edges_from_no_data
, and the functionsdigraph_complement
,graph_complement
,complement
,local_complement
.Probably suffer from a similar issue.
What is the expected behavior?
I expected to be able to run the reproduction below without
mypy
/pyright
complaining about bad argument.As annotation fixes:
extend_from_edge_list
,extend_from_weighted_edge_list
,add_edges_from_no_data
, this is simply removing the| None
.complement
and it two non-universal variant functions, if I understand the documentation correctly, the return type should have justNone
on the edge payload typvar, and not_T | None
.local_complement
, I think the type annotation is correct as is.The annotations make me think that the graph classes are not intended to behave invariantly, but rather covariantly, if this is desirable the way to do it is:
Personally, I think its better to keep them invariant, and if users of rustworkx want covariance / contravariance in their external functions they can define their signature as they like.
Steps to reproduce the problem
When run
mypy t.py
I getand
pyright t.py
(in"basic"
setting):The text was updated successfully, but these errors were encountered: