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
To achieve the above goals, I need to correctly navigate git, GitHub, typeshed pull request processes (OR to know that I should not use a pull request and to know what other tool I should use), diagnostic errors from umpteen apps, and, you know, to accurately annotate a sophisticated package. Furthermore, I have only contributed to stdlib, and it feels strange to me to discuss an actively maintained third-party package. I feel like there must be etiquette for this, but I don't know what that might be.
Plus, I have no self-confidence about most topics, and I hate that I keep pissing people off.
Another (self-inflicted) complication
The typeshed stubs do not have docstrings. My stubs have edited docstrings based on the original docstrings. This is probably a trivial issue, but it is another issue.
Guidance?
The diff tool in a pull request seems useful, but I am not ready to claim that my versions of the three files should be part of typeshed, so a pull request seems like the wrong tool.
An important feature of a good process is the ability to accurately and quickly identify "misfits." If my suggested annotations are patently wrong, for example, a good process allows y'all to avoid wasting your time.
There is probably a smart way, or at least a smarter way, for me to start a conversation about this, but I don't know what it is.
Let me first answer a few of your simpler questions, then your "big" main question about diffing.
There is probably a smart way, or at least a smarter way, for me to start a conversation about this, but I don't know what it is.
This is pretty good actually! :) Asking on the issue tracker is the right thing to do if you're not sure whether you should make a pull request.
it feels strange to me to discuss an actively maintained third-party package. I feel like there must be etiquette for this, but I don't know what that might be.
Contributing to third-party packages is very similar to contributing to stdlib. As a contributor, you don't need to worry about this.
The typeshed stubs do not have docstrings. My stubs have edited docstrings based on the original docstrings. This is probably a trivial issue, but it is another issue.
The docstrings will show up in the diff. To get nice diffs, both compared files should be in a similar format (e.g. both contain docstrings or neither contains docstrings).
Now, let's tackle your big "main" question:
The diff tool in a pull request seems useful, but I am not ready to claim that my versions of the three files should be part of typeshed, so a pull request seems like the wrong tool.
You're right, a pull request is not needed for this. You want to get a diff without making a GitHub pull request. Let me walk you through that.
Let's create two files, foo.pyi and bar.pyi. Here is foo.pyi (typeshed's stub file):
We want to see a diff similar to what GitHub shows, but without a pull request, i.e. notice that return type of bar() is misspelled. Here's how to get that diff (assuming Windows, since you're on windows if I remember correctly).
Option 1: using diff
Open Git Bash or WSL. Doesn't really matter which. (Other terminal things may also work.)
Go to the folder that contains foo.pyi and bar.pyi with cd. For example cd Desktop/typeshed. Use / as path separator, not \. (Alternatively, right-click a folder and select "Git Bash here" to skip this step).
Run the following command to compare the files:
diff -u --color foo.pyi bar.pyi
If the files are in different folders, supply their paths as needed, e.g. diff -u --color folder1/foo.pyi folder2/subfolder/bar.pyi
You should get something like this:
Option 2: using Git
Add foo.pyi to a Git repository if it isn't already. (In your case, just git clone typeshed and you're done with this step.)
Check that git status doesn't show anything related to foo.pyi.
Replace content of foo.pyi with your bar.pyi. Just copy it on top.
Check that git status says "modified: foo.pyi" in red. (Red means it's not about to be committed.)
Run git diff. This tells git to report what changed.
(Optional) Run git restore foo.pyi. This brings back the original file contents.
(Optional) Check that git status doesn't show anything related to foo.pyi.
(.venv) C:\apps\stubFileNotFound>black --config c:\clones\typeshed\pyproject.toml "C:\clones\typeshed\stubs\networkx\networkx\classes\graph.pyi" but it didn't change the file, so the imports are sorted differently.
WinMerge. I despise git, and I can't decipher the + - stuff, so that would preclude a conversation.
WinMerge. I despise git, and I can't decipher the + - stuff, so that would preclude a conversation.
While Git could quite conveniently do the diffing, help you select which parts of the diff to include in a PR, and then help you create the PR, I understand that you don't like Git and you don't want to do any of this with git. I was the same way when I was getting started with git :)
The diff tool, my Option 1, has nothing to do with git. It does the thing you did with WinMerge, but on command line. I mentioned Git Bash, but you can just as well use WSL instead, or anything else that happens to have a working diff program. Git comes with diff, but it is not the only way to get the diff program.
But, these objects are the most important, right?
Yes, these diffs are what you care about. Next you need to study them and figure out what things to include in pull requests.
I looked at your digraph diff. It seems to be backwards compared to how we are used to reading diffs: typeshed's version is + (green) and yours is - (red).
Here are examples of changes that I would include in a PR: (I'm not sure whether all of these are correct, but we can figure it out when reviewing)
Your in_edges returns InEdgeView. Typeshed's in_edges returns OutEdgeView, which seems like a typo in typeshed.
Typeshed's in_degree and out_degree can be ints or views. Yours can only be views. I haven't checked, but my guess is that you are right and they are always views.
And here are examples of changes that don't make the cut:
Your version of the stub includes private things, such as _adj and _CachedPropertyResetterPred. In typeshed, we only add private things if someone needs them for some specific use case.
Your succ and pred use Incomplete where typeshed uses Any. While they are technically the same, there is a "cultural" difference that is often discussed here. IMO Any is better in this case, because the data comes from adding edges, and there's no good way to teach that to type checkers. However, we would appreciate adding a comment that explains why Any is used.
You have included various things that are inherited from the base class Graph. In typeshed, we like to repeat things inherited from a base class only if we want something different than the definition in base class (such as the to_undirected method).
I would split these changes to at least 3 pull requests, one per file. We have many open pull requests, but smaller pull requests are still easier to review.
You have included various things that are inherited from the base class Graph. In typeshed, we like to repeat things inherited from a base class only if we want something different than the definition in base class (such as the to_undirected method).
Therefore, I am starting with Graph.
I looked at your digraph diff. It seems to be backwards compared to how we are used to reading diffs: typeshed's version is + (green) and yours is - (red).
Is the above version backwards or normal?
Your succ and pred use Incomplete where typeshed uses Any.
This is confusing to me because my versions don't use Incomplete or have any missing annotations.
I'm now trying to decipher the stubtest errors.
Details
Command output:
error: networkx.MultiDiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx_init_.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]
Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multidigraph.py:417
def (self, u_for_edge, v_for_edge, key=None, **attr)
error: networkx.MultiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx_init_.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]
Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multigraph.py:431
def (self, u_for_edge, v_for_edge, key=None, **attr)
error: networkx.classes.MultiDiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx\classes_init_.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]
Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multidigraph.py:417
def (self, u_for_edge, v_for_edge, key=None, **attr)
error: networkx.classes.MultiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx\classes_init_.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]
Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multigraph.py:431
def (self, u_for_edge, v_for_edge, key=None, **attr)
error: networkx.classes.multidigraph.MultiDiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx\classes\multidigraph.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]
Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multidigraph.py:417
def (self, u_for_edge, v_for_edge, key=None, **attr)
error: networkx.classes.multigraph.MultiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx\classes\multigraph.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]
Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multigraph.py:431
def (self, u_for_edge, v_for_edge, key=None, **attr)
You have included various things that are inherited from the base class Graph. In typeshed, we like to repeat things inherited from a base class only if we want something different than the definition in base class (such as the to_undirected method).
Therefore, I am starting with Graph.
Because DiGraph depends on Graph, I assumed it would be wise to implement Graph first. Then I could work on DiGraph with a solid foundation.
There was a mypy bug resulting in nondeterministic output that was fixed promptly in python/mypy#19666. You can safely ignore it.
More detail: mypy_primer shows the difference in output between two runs of mypy (in this case, one with the version of typeshed from your PR, one with the version of typeshed from master). The idea being, if your PR affects mypy's output in some way, we will see the diff in mypy output. In the comment, you can see that the only thing in the diff is that the order of some arguments in an error message has changed (which is a harmless thing to have changed, and will not stop changing once the above mentioned fix gets picked up).
Typeshed's in_degree and out_degree can be ints or views. Yours can only be views. I haven't checked, but my guess is that you are right and they are always views.
Indeed, it can only be a view, but the merged PR has changed the type to include int, which now causes the following error from Mypy when using e.g. some_graph.in_degree(some_node):
error: "int" not callable [operator]
I haven't checked but I believe the same problem exists for out_degree.
@hunterhogan Can we please revert the changes to these two lines?
Activity
Akuli commentedon Jul 31, 2025
Let me first answer a few of your simpler questions, then your "big" main question about diffing.
This is pretty good actually! :) Asking on the issue tracker is the right thing to do if you're not sure whether you should make a pull request.
Contributing to third-party packages is very similar to contributing to stdlib. As a contributor, you don't need to worry about this.
The docstrings will show up in the diff. To get nice diffs, both compared files should be in a similar format (e.g. both contain docstrings or neither contains docstrings).
Now, let's tackle your big "main" question:
You're right, a pull request is not needed for this. You want to get a diff without making a GitHub pull request. Let me walk you through that.
Let's create two files,
foo.pyiandbar.pyi. Here isfoo.pyi(typeshed's stub file):And here is
bar.pyi(your stub file):We want to see a diff similar to what GitHub shows, but without a pull request, i.e. notice that return type of
bar()is misspelled. Here's how to get that diff (assuming Windows, since you're on windows if I remember correctly).Option 1: using
difffoo.pyiandbar.pyiwithcd. For examplecd Desktop/typeshed. Use/as path separator, not\. (Alternatively, right-click a folder and select "Git Bash here" to skip this step).diff -u --color folder1/foo.pyi folder2/subfolder/bar.pyiYou should get something like this:
Option 2: using Git
foo.pyito a Git repository if it isn't already. (In your case, justgit clonetypeshed and you're done with this step.)git statusdoesn't show anything related tofoo.pyi.foo.pyiwith yourbar.pyi. Just copy it on top.git statussays "modified: foo.pyi" in red. (Red means it's not about to be committed.)git diff. This tellsgitto report what changed.git restore foo.pyi. This brings back the original file contents.git statusdoesn't show anything related tofoo.pyi.hunterhogan commentedon Jul 31, 2025
Thank you for the detailed response.
Steps taken:
(.venv) C:\apps\stubFileNotFound>black --config c:\clones\typeshed\pyproject.toml C:\data\networkx(.venv) C:\apps\stubFileNotFound>black --config c:\clones\typeshed\pyproject.toml "C:\clones\typeshed\stubs\networkx\networkx\classes\graph.pyi"but it didn't change the file, so the imports are sorted differently.I think this is the same format as git.
digraph.sillyFormat.txt
graph.sillyFormat.txt
The same data, but rename to .htm to view.
digraph.htm.txt
graph.htm.txt
If this process works, I'll make the LCA algorithm, too.
But, these objects are the most important, right?
Akuli commentedon Jul 31, 2025
While Git could quite conveniently do the diffing, help you select which parts of the diff to include in a PR, and then help you create the PR, I understand that you don't like Git and you don't want to do any of this with git. I was the same way when I was getting started with git :)
The
difftool, my Option 1, has nothing to do with git. It does the thing you did with WinMerge, but on command line. I mentioned Git Bash, but you can just as well use WSL instead, or anything else that happens to have a workingdiffprogram. Git comes withdiff, but it is not the only way to get thediffprogram.Yes, these diffs are what you care about. Next you need to study them and figure out what things to include in pull requests.
I looked at your digraph diff. It seems to be backwards compared to how we are used to reading diffs: typeshed's version is
+(green) and yours is-(red).Here are examples of changes that I would include in a PR: (I'm not sure whether all of these are correct, but we can figure it out when reviewing)
in_edgesreturnsInEdgeView. Typeshed'sin_edgesreturnsOutEdgeView, which seems like a typo in typeshed.in_degreeandout_degreecan be ints or views. Yours can only be views. I haven't checked, but my guess is that you are right and they are always views.And here are examples of changes that don't make the cut:
_adjand_CachedPropertyResetterPred. In typeshed, we only add private things if someone needs them for some specific use case.succandpreduseIncompletewhere typeshed usesAny. While they are technically the same, there is a "cultural" difference that is often discussed here. IMOAnyis better in this case, because the data comes from adding edges, and there's no good way to teach that to type checkers. However, we would appreciate adding a comment that explains whyAnyis used.Graph. In typeshed, we like to repeat things inherited from a base class only if we want something different than the definition in base class (such as theto_undirectedmethod).I would split these changes to at least 3 pull requests, one per file. We have many open pull requests, but smaller pull requests are still easier to review.
hunterhogan commentedon Aug 1, 2025
diff
git diff
fwiw, I'm a trained editor, pioneered web usability in the 90s, and cut my teeth on line basic: Wordstar 2000 was better than diff or git.
My post is incomplete due to pain. I'll try again later.
hunterhogan commentedon Aug 2, 2025
Therefore, I am starting with Graph.
Is the above version backwards or normal?
This is confusing to me because my versions don't use Incomplete or have any missing annotations.
I'm now trying to decipher the stubtest errors.
Details
Command output:
error: networkx.MultiDiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx_init_.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node
1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multidigraph.py:417
def (self, u_for_edge, v_for_edge, key=None, **attr)
error: networkx.MultiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx_init_.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node
1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multigraph.py:431
def (self, u_for_edge, v_for_edge, key=None, **attr)
error: networkx.classes.MultiDiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx\classes_init_.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node
1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multidigraph.py:417
def (self, u_for_edge, v_for_edge, key=None, **attr)
error: networkx.classes.MultiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx\classes_init_.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node
1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multigraph.py:431
def (self, u_for_edge, v_for_edge, key=None, **attr)
error: networkx.classes.multidigraph.MultiDiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx\classes\multidigraph.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node
1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multidigraph.py:417
def (self, u_for_edge, v_for_edge, key=None, **attr)
error: networkx.classes.multigraph.MultiGraph.add_edge is inconsistent, runtime argument "key" has a default value but stub argument does not
Stub: in file C:\clones\typeshed\stubs\networkx\networkx\classes\multigraph.pyi:21
def (self: networkx.classes.multigraph.MultiGraph[_Node
1], u_for_edge: _Node1, v_for_edge: _Node`1, key: Union[typing.Hashable, builtins.int], **attr: Any) -> Union[typing.Hashable, builtins.int]Runtime: in file C:\Users\hunte\AppData\Local\Temp\stubtest-fs1zytcl\Lib\site-packages\networkx\classes\multigraph.py:431
def (self, u_for_edge, v_for_edge, key=None, **attr)
Complete networkx/graph.pyi. python#14499
Akuli commentedon Aug 2, 2025
The PR looks reasonable. Thanks!
The above diffs also look much better. Something weird happened previously.
hunterhogan commentedon Aug 4, 2025
Because
DiGraphdepends onGraph, I assumed it would be wise to implement Graph first. Then I could work on DiGraph with a solid foundation.Complete networkx/graph.pyi. #14499 (#14509)
complete networkx/digraph.pyi addresses python#14499 follows python#1…
complete networkx/digraph.pyi addresses #14499 follows #14509 (#14569)
complete networkx/...lowest_common_ancestors.pyi addresses python#14499…
hunterhogan commentedon Aug 17, 2025
Originally posted by @github-actions[bot] in #14582 (comment)
Line 883
Line 935
I don't understand what I need to do. #14582
hauntsaninja commentedon Aug 17, 2025
There was a mypy bug resulting in nondeterministic output that was fixed promptly in python/mypy#19666. You can safely ignore it.
More detail: mypy_primer shows the difference in output between two runs of mypy (in this case, one with the version of typeshed from your PR, one with the version of typeshed from master). The idea being, if your PR affects mypy's output in some way, we will see the diff in mypy output. In the comment, you can see that the only thing in the diff is that the order of some arguments in an error message has changed (which is a harmless thing to have changed, and will not stop changing once the above mentioned fix gets picked up).
TomerGodinger commentedon Aug 17, 2025
I think there was some mixup here, specifically regarding this bit in one of Akuli's posts above:
Indeed, it can only be a view, but the merged PR has changed the type to include
int, which now causes the following error from Mypy when using e.g.some_graph.in_degree(some_node):I haven't checked but I believe the same problem exists for
out_degree.@hunterhogan Can we please revert the changes to these two lines?
typeshed/stubs/networkx/networkx/classes/digraph.pyi
Lines 36 to 39 in 85a787b