Title: The public interface of git.exc is ambiguous · Issue #1718 · gitpython-developers/GitPython · GitHub
Open Graph Title: The public interface of git.exc is ambiguous · Issue #1718 · gitpython-developers/GitPython
X Title: The public interface of git.exc is ambiguous · Issue #1718 · gitpython-developers/GitPython
Description: I believe the intent of git.exc is twofold: To publish the exceptions it defines, which it unambiguously does. To republish exceptions defined in gitdb.exc, which it... doesn't? The problem is that the conceptually public names in a modu...
Open Graph Description: I believe the intent of git.exc is twofold: To publish the exceptions it defines, which it unambiguously does. To republish exceptions defined in gitdb.exc, which it... doesn't? The problem is that...
X Description: I believe the intent of git.exc is twofold: To publish the exceptions it defines, which it unambiguously does. To republish exceptions defined in gitdb.exc, which it... doesn't? The problem is ...
Opengraph URL: https://github.com/gitpython-developers/GitPython/issues/1718
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"The public interface of git.exc is ambiguous","articleBody":"I believe the intent of `git.exc` is twofold:\r\n\r\n- To publish the exceptions it defines, which it unambiguously does.\r\n- To republish exceptions defined in `gitdb.exc`, which it... *doesn't?*\r\n\r\nThe problem is that the conceptually public names in a module are (basically) those listed in `__all__` when `__all__` is present, and since an original and continuing use of `__all__` is to control what names a `*` import binds, it might seem like whatever a `*` import binds is considered conceptually public even without `__all__`... but that is not the case.\r\n\r\nInstead, in the absence of `__all__`, names that both do not start with an `_` and also *were not introduced merely by themselves being imported* are the conceptually public names. As [the \"Public and internal interfaces\" section of PEP-8](https://pep8.org/#public-and-internal-interfaces) says:\r\n\r\n\u003e Imported names should always be considered an implementation detail. Other modules must not rely on indirect access to such imported names unless they are an explicitly documented part of the containing module’s API\u003cem\u003e[...]\u003c/em\u003e\r\n\r\nTo make such a name public, it can be included in `__all__`, but `git.exc` currently does not define `__all__`. Does it otherwise document those names as public? Well...\r\n\r\nhttps://github.com/gitpython-developers/GitPython/blob/44102f30eaadcd122899f5f801f28b83bd9a5111/git/exc.py#L6\r\n\r\nThis is why I say the situation is ambiguous--this might be interpreted to mean that the names are public, in that they are the names of exceptions that are thrown throughout GitPython and would not otherwise be public in GitPython. But really this is a stretch, and rather than saying the situation is ambiguous, it might be more reasonable to say that they are definitely not public.\r\n\r\nBut I am pretty sure they are intended to be public. So they should be documented as such. The best way to do this is by defining `git.exc.__all__` and listing them there.\r\n\r\nThere then becomes the question of whether anything else that is currently imported by `from git.exc import *` belongs in `__all__`. I believe the answer is no. It's not reasonable for code outside `git.exc` to rely on those being part of `git.exc` (because they are present only due to imports, so they are nonpublic per the above-quoted rule, and the documentation of `git.exc` does not reference them even obliquely). It is especially unreasonable for code outside the `git.exc` module to rely on receiving them from a `*` import.\r\n\r\nHowever, the top-level `__init__.py` does just that. *When* it began to do it depends on one's perspective. For some time, it has been including those names (such as `safe_decode` from `git.util`) in `git.__all__` because of the way `git.__all__` was dynamically generated with a comprehension. In #1659, the comprehension was removed and replaced with a listing of everything that was found to be in `__all__`.\r\n\r\nBecause `git.__all__` did, and does, exist, and it included those names, it should continue to include them for backward compatibility, even in the case of some of them from `typing` that hopefully no one is importing from the `git` module. However, I think no similar reasoning applies to `git.exc` itself, since `git.exc.__all__` has not existed. This is to say that I think it is always a bug to rely on picking up nonpublic names from `*` imports, including in `git/__init__.py`, which is currently doing that.\r\n\r\nTo keep `from git import *` working, as well as to keep `git.__all__` a correct statement of names guaranteed accessible as attributes of `git`, when fixing this in `git.exc` it will also be necessary to modify the code of `git/__init__.py` to get these names from the modules that really provide them publicly. That should be no problem, though, and I'd say it would be an improvement even by itself.\r\n\r\nI believe `git.exc` is the clearest place in GitPython where this kind of problem exists, but every attempt to suppress an unused import lint rule is a strong hint of a similar bug, so I'm pretty sure this is far from the only case. However, I'm opening an issue about this specifically because recent changes (in #1659) combine with it to create a situation where the bug could become entrenched if not addressed fairly soon. I say this because although `git/__init__.py` has, for quite some time, being wrongly relying on those names being present, in that it has been effectively guaranteeing their presence for future patch versions by including them in `__all__` as it would be inspected by users, it is only now that this dependence can be easily discerned, and thus perhaps further relied on, by reading the code.","author":{"url":"https://github.com/EliahKagan","@type":"Person","name":"EliahKagan"},"datePublished":"2023-10-20T07:34:36.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/1718/GitPython/issues/1718"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:5e38d84a-2ad7-dee6-348a-6f5b0d90be63 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | B7B8:211260:535DE2:7424CB:6968CB3E |
| html-safe-nonce | 5c017f9a86ed1a74676b2e25cec85081dc252c2d96c44c1999a2a74cee87c334 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCN0I4OjIxMTI2MDo1MzVERTI6NzQyNENCOjY5NjhDQjNFIiwidmlzaXRvcl9pZCI6IjM2NTk5Mzk0MTM2MzkwODg5NTgiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 0ddab5f13679aa5c89663d131af8b02c8935eaff33439c518c4ff2acc2fd98c9 |
| hovercard-subject-tag | issue:1953712981 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/gitpython-developers/GitPython/1718/issue_layout |
| twitter:image | https://opengraph.githubassets.com/21766b18e6c2196e435dd01727497d80a836ef840d5432c9495c46a6599807f3/gitpython-developers/GitPython/issues/1718 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/21766b18e6c2196e435dd01727497d80a836ef840d5432c9495c46a6599807f3/gitpython-developers/GitPython/issues/1718 |
| og:image:alt | I believe the intent of git.exc is twofold: To publish the exceptions it defines, which it unambiguously does. To republish exceptions defined in gitdb.exc, which it... doesn't? The problem is that... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | EliahKagan |
| hostname | github.com |
| expected-hostname | github.com |
| None | af2d7af0cc84117fa10bf36808605ef68a335c9d8a804b9cdac55f8d77230b00 |
| turbo-cache-control | no-preview |
| go-import | github.com/gitpython-developers/GitPython git https://github.com/gitpython-developers/GitPython.git |
| octolytics-dimension-user_id | 503709 |
| octolytics-dimension-user_login | gitpython-developers |
| octolytics-dimension-repository_id | 1126087 |
| octolytics-dimension-repository_nwo | gitpython-developers/GitPython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1126087 |
| octolytics-dimension-repository_network_root_nwo | gitpython-developers/GitPython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | cc844ab6ee0198cc2e2c142dcb8a5c2a61d48743 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width