René's URL Explorer Experiment


Title: Diffable.diff is misleadingly annotated regarding special `other` values · Issue #1874 · gitpython-developers/GitPython · GitHub

Open Graph Title: Diffable.diff is misleadingly annotated regarding special `other` values · Issue #1874 · gitpython-developers/GitPython

X Title: Diffable.diff is misleadingly annotated regarding special `other` values · Issue #1874 · gitpython-developers/GitPython

Description: The other parameter of Diffable.diff is annotated this way: GitPython/git/diff.py Line 110 in e880c33 other: Union[Type["Index"], "Tree", "Commit", None, str, object] = Index, Diffable.diff accepts a few special values: None for a workin...

Open Graph Description: The other parameter of Diffable.diff is annotated this way: GitPython/git/diff.py Line 110 in e880c33 other: Union[Type["Index"], "Tree", "Commit", None, str, object] = Index, Diffable.diff accepts...

X Description: The other parameter of Diffable.diff is annotated this way: GitPython/git/diff.py Line 110 in e880c33 other: Union[Type["Index"], "Tree", "Commit", None, str, object] ...

Opengraph URL: https://github.com/gitpython-developers/GitPython/issues/1874

X: @github

direct link

Domain: redirect.github.com


Hey, it has json ld scripts:
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Diffable.diff is misleadingly annotated regarding special `other` values","articleBody":"The `other` parameter of `Diffable.diff` is annotated this way:\r\n\r\nhttps://github.com/gitpython-developers/GitPython/blob/e880c33284f2abff55d3cddfef2302663b178005/git/diff.py#L110\r\n\r\n`Diffable.diff` accepts a few special values:\r\n\r\n- `None` for a working tree diff.\r\n- `Diffable.Index`, a `type` object that is meant to be used opaquely rather than instantiated, to compare to the index.\r\n- `NULL_TREE`, a direct instance of `object` (not to be confused with `Object`), for a diff against an empty tree.\r\n\r\n#### The type of `NULL_TREE` should be expressed better than `object`\r\n\r\nThe main problem here, which exists in the documentary effect of the annotations even if a type checker is never used, is the presence of `object` in the union. Since `object` is the root of the type hierarchy in Python, a union of anything with `object` is equivalent to just `object`. But the intent of the annotation is not to express that it is correct to pass arbitrary objects as `other`. Instead, the idea is that it is okay to pass `NULL_TREE`.\r\n\r\nThis is also the cause of the incompatible override type error on the `IndexFile.diff` override in `git.index.base`, which does not include the `object` alternative:\r\n\r\nhttps://github.com/gitpython-developers/GitPython/blob/e880c33284f2abff55d3cddfef2302663b178005/git/index/base.py#L1482\r\n\r\nThere are several places in GitPython's source code where an overridden method has an incompatible signature, violating substitutability. The reason this place is of interest is that it is hard to tell efficiently by examining the code or type errors *what* conceptually this means. It turns out it means the override does not support `NULL_TREE`:\r\n\r\n```text\r\n\u003e\u003e\u003e import git\r\n\u003e\u003e\u003e repo = git.Repo()\r\n\u003e\u003e\u003e repo.index.diff(git.NULL_TREE)\r\nTraceback (most recent call last):\r\n  File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\r\n  File \"C:\\Users\\ek\\source\\repos\\GitPython\\git\\index\\base.py\", line 1521, in diff\r\n    raise ValueError(\"other must be None, Diffable.Index, a Tree or Commit, was %r\" % other)\r\nValueError: other must be None, Diffable.Index, a Tree or Commit, was \u003cobject object at 0x00000265862B8A30\u003e\r\n```\r\n\r\nBut `object` does not express (to humans or tools) that what is really meant is the literal value `NULL_TREE`.\r\n\r\nWe cannot currently write `Literal[NULL_TREE]`, but if `NULL_TREE` is made into an enumeration constant, then this can be done, though cumbersomely it seems it can only be written--in annotations--as `ET.NULL_TREE` where `ET` is the declared enumeration type. Or, if `ET` has `NULL_TREE` as its only value, then writing `ET` should be sufficient, though this may be less intuitive due to not involving `Literal` in any way while expressing a literal.\r\n\r\nTo be clear, this will not cause the mypy error about an incompatible override to go away. But it will make the error make sense, as well as making the *suppression* comment on it make sense in terms of what it is expressing. *And it will allow type checkers to catch errors about incorrect values of `other`.*\r\n\r\n#### `Diffable.Index` should ideally also be improved\r\n\r\n`Diffable.Index` is used as an opaque constant, as is `NULL_TREE`. But `Diffable.Index` is a class. This is confusing because it should not be instantiated. Its static type can be expressed pretty specifically, as `Type[Diffable.Index]` (as is done; I'm omitting the quotes here for simplicity). However, this does not allow `if`-`else` logic to be type-checked exhaustively, because there is no guarantee that the `Diffable.Index` class is the only value of the static type `Type[Diffable.Index]`:\r\n\r\n```python\r\nclass Derived(Diffable.Index):\r\n    pass\r\n```\r\n\r\nHopefully no one is doing that--just as hopefully no one is instantiating it--but `mypy` and other tools, including editors, cannot tell that `Diffable.Index` is the only value of `Type[Diffable.Index]`. Humans who notice that it is intended to be used as an opaque constant *will* recognize this, however. Also, it *should* be possible to get type checkers to recognize it as the only value, and type-check `if`-`else` logic exhaustively, by decorating the definition of `Index` with `@final`. This works for some type checkers, at least `pyright` and `pylance`. But it does not work for `mypy`.\r\n\r\nThe bigger issue is that it is easy to confuse and, for example, instantiate it.\r\n\r\n`Diffable.Index` can also be made an enumeration constant, and all reasonable usage will continue to work. *At runtime.* However, if someone wants to statically annotate their own method to accept or return it, then they would need to change the annotations, since expressing it with `Type[Diffable.Index]` would no longer be able to work. (Two separate special objects cannot both be used, because existing subclasses of `Diffable` outside of GitPython would only be covering one. But if it is redefined, existing code can continue to cover it at runtime, since it should only ever have been, or be, used as an opaque constant.)\r\n\r\nIt is also possible for unreasonable usage to break at runtime, such as attempting to check if `x` is `Diffable.Index` by writing `issubclass(x, Diffable.Index)`. I am less worried about this.\r\n\r\nIt seems to me that this change is worth making for `Diffable.Index` as well, but this is a judgment call, and the new interface should perhaps be given special attention in review. When I searched for existing code outside GitPython, its forks, vendored copies of it, etc., that used these annotations in a way where they would cause a new static type error, I didn't find anything, but I only used GitHub code search, and I may not have found everything even on GitHub. My argument for making this change is to achieve greater correctness without breaking anything at runtime, and *not* that I am at all confident nobody will have to change their code to keep it passing static checks.\r\n\r\n#### Connection to #1859\r\n\r\nI've included fixes for both of these things in #1859. See [65863a2](https://github.com/gitpython-developers/GitPython/pull/1859/commits/65863a28c2bfebe084e1c86d409fbf68b0b33a76) especially, whose docstring has some more information about the specific design choices there.\r\n\r\nIf you decide you don't want the change to `Diffable.Index` there, that can be undone without sacrificing the rest. Although I am in favor of this aspect of the change, it should not be accepted on the basis of the sunk-cost fallacy. Furthermore, the sunk cost would be quite low, because it was already helpful in enabling me to figure out what needed to be done in other related parts of the code.\r\n\r\nThe purpose of this issue is twofold:\r\n\r\n- To allow the bug to be tracked if [#1859](https://github.com/gitpython-developers/GitPython/pull/1859) is changed in such a way as not to fully solve it.\r\n- To described it separately from that PR so it's easier to understand. I considered describing it in comments there, but thought opening an issue would be better.","author":{"url":"https://github.com/EliahKagan","@type":"Person","name":"EliahKagan"},"datePublished":"2024-03-14T08:06:12.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":3},"url":"https://github.com/1874/GitPython/issues/1874"}

route-pattern/_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format)
route-controllervoltron_issues_fragments
route-actionissue_layout
fetch-noncev2:88b5386d-e051-e965-0e72-3746320a0733
current-catalog-service-hash81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114
request-id9012:822D:15C2E91:1E9EBA5:6968F722
html-safe-nonce28c0f1d98442ac74a07d16257163074eeb311e5c65f6283d0e5637694666ceae
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5MDEyOjgyMkQ6MTVDMkU5MToxRTlFQkE1OjY5NjhGNzIyIiwidmlzaXRvcl9pZCI6IjQ2NjIwMzk5NTkwNzYxNDA4MzUiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ==
visitor-hmacb26f8e054d5bf5a8dea0af1776b236d1ef6e5b7c0e00be677296ffe1db083e58
hovercard-subject-tagissue:2185695487
github-keyboard-shortcutsrepository,issues,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///voltron/issues_fragments/issue_layout
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/gitpython-developers/GitPython/1874/issue_layout
twitter:imagehttps://opengraph.githubassets.com/235180ede82552ee0d2924ac33574674a3a0e0b96a7fba73cb55d946e713ea4b/gitpython-developers/GitPython/issues/1874
twitter:cardsummary_large_image
og:imagehttps://opengraph.githubassets.com/235180ede82552ee0d2924ac33574674a3a0e0b96a7fba73cb55d946e713ea4b/gitpython-developers/GitPython/issues/1874
og:image:altThe other parameter of Diffable.diff is annotated this way: GitPython/git/diff.py Line 110 in e880c33 other: Union[Type["Index"], "Tree", "Commit", None, str, object] = Index, Diffable.diff accepts...
og:image:width1200
og:image:height600
og:site_nameGitHub
og:typeobject
og:author:usernameEliahKagan
hostnamegithub.com
expected-hostnamegithub.com
Noneb229519d8adb10c7bce106d807003c585a919bd07491d720d8aada92dc43746b
turbo-cache-controlno-preview
go-importgithub.com/gitpython-developers/GitPython git https://github.com/gitpython-developers/GitPython.git
octolytics-dimension-user_id503709
octolytics-dimension-user_logingitpython-developers
octolytics-dimension-repository_id1126087
octolytics-dimension-repository_nwogitpython-developers/GitPython
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id1126087
octolytics-dimension-repository_network_root_nwogitpython-developers/GitPython
turbo-body-classeslogged-out env-production page-responsive
disable-turbofalse
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release176ddd19d172d50da7e20b971f928ffe57138b35
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://redirect.github.com/gitpython-developers/GitPython/issues/1874#start-of-content
https://redirect.github.com/
Sign in https://redirect.github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fgitpython-developers%2FGitPython%2Fissues%2F1874
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub SparkBuild and deploy intelligent appshttps://github.com/features/spark
GitHub ModelsManage and compare promptshttps://github.com/features/models
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
GitHub SponsorsFund open source developershttps://github.com/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/accelerator
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://redirect.github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fgitpython-developers%2FGitPython%2Fissues%2F1874
Sign up https://redirect.github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fvoltron%2Fissues_fragments%2Fissue_layout&source=header-repo&source_repo=gitpython-developers%2FGitPython
Reloadhttps://redirect.github.com/gitpython-developers/GitPython/issues/1874
Reloadhttps://redirect.github.com/gitpython-developers/GitPython/issues/1874
Reloadhttps://redirect.github.com/gitpython-developers/GitPython/issues/1874
gitpython-developers https://redirect.github.com/gitpython-developers
GitPythonhttps://redirect.github.com/gitpython-developers/GitPython
Please reload this pagehttps://redirect.github.com/gitpython-developers/GitPython/issues/1874
Notifications https://redirect.github.com/login?return_to=%2Fgitpython-developers%2FGitPython
Fork 964 https://redirect.github.com/login?return_to=%2Fgitpython-developers%2FGitPython
Star 5k https://redirect.github.com/login?return_to=%2Fgitpython-developers%2FGitPython
Code https://redirect.github.com/gitpython-developers/GitPython
Issues 169 https://redirect.github.com/gitpython-developers/GitPython/issues
Pull requests 8 https://redirect.github.com/gitpython-developers/GitPython/pulls
Discussions https://redirect.github.com/gitpython-developers/GitPython/discussions
Actions https://redirect.github.com/gitpython-developers/GitPython/actions
Security Uh oh! There was an error while loading. Please reload this page. https://redirect.github.com/gitpython-developers/GitPython/security
Please reload this pagehttps://redirect.github.com/gitpython-developers/GitPython/issues/1874
Insights https://redirect.github.com/gitpython-developers/GitPython/pulse
Code https://redirect.github.com/gitpython-developers/GitPython
Issues https://redirect.github.com/gitpython-developers/GitPython/issues
Pull requests https://redirect.github.com/gitpython-developers/GitPython/pulls
Discussions https://redirect.github.com/gitpython-developers/GitPython/discussions
Actions https://redirect.github.com/gitpython-developers/GitPython/actions
Security https://redirect.github.com/gitpython-developers/GitPython/security
Insights https://redirect.github.com/gitpython-developers/GitPython/pulse
New issuehttps://redirect.github.com/login?return_to=https://github.com/gitpython-developers/GitPython/issues/1874
New issuehttps://redirect.github.com/login?return_to=https://github.com/gitpython-developers/GitPython/issues/1874
#1859https://github.com/gitpython-developers/GitPython/pull/1859
Diffable.diff is misleadingly annotated regarding special other valueshttps://redirect.github.com/gitpython-developers/GitPython/issues/1874#top
#1859https://github.com/gitpython-developers/GitPython/pull/1859
acknowledgedhttps://github.com/gitpython-developers/GitPython/issues?q=state%3Aopen%20label%3A%22acknowledged%22
https://github.com/EliahKagan
https://github.com/EliahKagan
EliahKaganhttps://github.com/EliahKagan
on Mar 14, 2024https://github.com/gitpython-developers/GitPython/issues/1874#issue-2185695487
GitPython/git/diff.pyhttps://github.com/gitpython-developers/GitPython/blob/e880c33284f2abff55d3cddfef2302663b178005/git/diff.py#L110
e880c33https://redirect.github.com/gitpython-developers/GitPython/commit/e880c33284f2abff55d3cddfef2302663b178005
GitPython/git/index/base.pyhttps://github.com/gitpython-developers/GitPython/blob/e880c33284f2abff55d3cddfef2302663b178005/git/index/base.py#L1482
e880c33https://redirect.github.com/gitpython-developers/GitPython/commit/e880c33284f2abff55d3cddfef2302663b178005
#1859https://github.com/gitpython-developers/GitPython/pull/1859
#1859https://github.com/gitpython-developers/GitPython/pull/1859
65863a2https://github.com/gitpython-developers/GitPython/pull/1859/commits/65863a28c2bfebe084e1c86d409fbf68b0b33a76
#1859https://github.com/gitpython-developers/GitPython/pull/1859
acknowledgedhttps://github.com/gitpython-developers/GitPython/issues?q=state%3Aopen%20label%3A%22acknowledged%22
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.