-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
mypy: allow explicit specification of package roots #9632
Conversation
Also maybe there should be some interaction with MYPYPATH? E.g. looking at |
The old behavior is used in a fairly hacky Bazel integration, but I'm not very familiar with how it works internally. I suspect we could enable namespace packages when using the Bazel integration and disable it otherwise, but it hard to say without trying it out. I wonder how hard would it be to retain the old behavior when using
Maybe we can always make every directory in MYPYPATH a package root when using namespace packages? I.e., it would be an alternative to using |
If using namespace packages causes Dropbox's Bazel to crash and burn, I'll try to reinstate all the old hacky code. I'll make the change to treat all MYPYPATH as package roots if the flag |
Sounds good! Providing backward compatibility is usually the right call if we make major breaking changes, since there are so many users and use cases that we can't possibly predict. But if this makes maintenance harder, it may be better to avoid this. Extra code that has tests and rarely needs to be updated isn't necessarily much of a burden, though.
Hmm I'd prefer to avoid another flag. What if MYPYPATH defines a package root only if namespace packages are enabled, and otherwise we fall back to the current behavior? I.e. when not using namespace packages, we'd keep the old behavior as closely as reasonable. With namespace packages enabled we can change some behavior, since the old behavior isn't a good match. Another thought: with namespace packages enabled MYPYPATH could be similar to how PYTHONPATH works. PYTHONPATH defines additional package roots, right? I don't remember all the details of namespace packages, so I may be mistaken above. If the idea doesn't work, it would be good to have an example use case which is affected. Another thing that could help is a matrix showing how the various configuration settings affect various behaviors. I've made a partial attempt below (again, not sure if this is actually correct). If namespace package are enabled:
If namespace packages are disabled:
|
I think that would work... One common use case for where the old
Here the breaking change is the command would go from While the concepts are related, I'm also still a little hesitant to solely rely on Here's my attempt and writing down some options (apologies for repetition and verbosity!). In all options, the following apply: Option A (your suggestion) By default, when given files we:
If
Effect on src layout example:
Pros:
Cons:
Option B By default, when given files we:
If
Effect on src layout example:
Pros:
Cons:
Option C By default, when given files we:
If
Effect on src layout example:
Pros & Cons:
|
(Sorry for the slow reply, I wanted to think about this carefully since this is a potentially major breaking change.) You've convinced me that my proposal needlessly breaks too many existing use cases. Let me reiterate how I understand your alternative proposal, to make sure I haven't missed anything:
Open questions:
|
Thanks, I agree we need to be careful, and sorry for any slowness on my part! Yes, that basically sums it up. To address the open questions brought up:
I think there is a case where things get pretty annoying and so I have an additional proposal. The case is if you have a top level
Before #9614, we had really bad behaviour, which is we just completely ignore Concretely, this would mean adding a term to Line 86 in 2695e95
--namespace-packages are on and if there's a current mod_prefix .
I'll try and implement this so we'll have a concrete thing to play around and discover UX issues with. We might also want to implement some kind of ignore feature, e.g. so mypy can check mypy with |
Merge for the logging improvements in 9672
This doesn't do much for us here, but makes things easier for my future change to crawl using absolute paths
Agreed. This is likely the common case, at least for projects that are using namespace packages.
Could we make this consistent, for example by always assuming that we are inside a namespace package if one of the parent directories contains a This would be a backward incompatible change, so we'd have to document this carefully in release notes.
Maybe we should just move Brainstorming: We could write a tool to help debug issues with wrongly configured namespace package roots. Here are some things we could report:
|
Also, sorry for the delay in review. This is complicated by needing to make sure the Bazel integration we use at Dropbox isn't broken by this, and I'm not very familiar how the integration works. Also, we can't easily try GitHub master with internal repos right now since there are some issues we need to investigate and fix/work around first. This will take at least until the end of month, because of vacations next week. I think that I might be able to merge this sooner if you can preserve the old hacky code used in our Bazel integration (i.e. without enabling namespace packages). How much trouble would this be? We could try removing the legacy code later, separately from this PR. Otherwise, we may need wait until master is clean with Dropbox internal repos. |
Sounds good, I'll break up this PR. Decoupling these changes from a) Bazel integration, b) making namespace packages the default, seems like an increasingly good idea. I'll make the change so that crawling up files will crawl all the way up in case of Agreed that good diagnostics and documentation will be important here. I think moving /mypy/typeshed to /typeshed will indeed potentially cause packaging issues. I'm going to hold off on looking into that, especially with modular typeshed looming on the horizon. |
This is succeeded by #9742 |
This is the successor to #9632. Things should basically be as discussed in that PR. Since #9616 is merged, this should now resolve #5759. We leave the Bazel integration with `--package-root` almost entirely untouched, save for a) one change that's a bugfix / doesn't affect the core of what `--package-root` is doing, b) another drive by bugfix that's not related to this PR. Change a) fixes the package root `__init__.py` hackery when passed absolute paths. Change b) fixes the validation logic for package roots above the current directory; it was broken if you passed `..` as a package root Since we're leaving `--package-root` alone for now, I named the new flag `--explicit-package-base` to try and avoid confusion. Doing so also matches the language used by BuildSource a little better. The new logic is summarised in the docstring of `SourceFinder.crawl_up`. Some commentary: - I change `find_sources_in_dir ` to call `crawl_up` directly to construct the BuildSource. This helps codify the fact that files discovered will use the same module names as if you passed them directly. - Doing so keeps things DRY with the more complicated logic and means, for instance, that we now do more sensible things in some cases when we recursively explore directories that have invalid package names. - Speaking of invalid package names, if we encounter a directory name with an invalid package name, we stop crawling. This is necessary because with namespace packages there's no guarantee that what we're crawling was meant to be a Python package. I add back in a check in the presence of `__init__.py` to preserve current unit tests where we raise InvalidSourceList. - The changes to modulefinder are purely cosmetic and can be ignored (there's some similar logic between the two files and this just makes sure they mirror each other closely) - One notable change is we now always use absolute paths to crawl. This makes the behaviour more predictable and addresses a common complaint: fixes #9677, fixes #8726 and others. - I figured this could use more extensive testing than a couple slow cmdline tests. Hopefully this test setup also helps clarify the behaviour :-) Co-authored-by: hauntsaninja <>
This should cover the current state on master, as implemented across python#9742, python#9683, python#9632, python#9616, python#9614, etc. This will need to be changed if we can make `--namespace-packages` the default (python#9636).
This should cover the current state on master, as previously discussed / implemented across python#9742, python#9683, python#9632, python#9616, python#9614, etc. This will need to be changed if we can make `--namespace-packages` the default (python#9636). I haven't documented some of the finer points of the changes, since it felt like an inappropriate level of detail (e.g. using absolute paths when crawling, how directories with invalid package names affect crawling, etc)
This should cover the current state on master, as previously discussed / implemented across python#9742, python#9683, python#9632, python#9616, python#9614, etc. This will need to be changed if we can make `--namespace-packages` the default (python#9636). I haven't documented some of the finer points of the changes, since it felt like an inappropriate level of detail (e.g. using absolute paths when crawling, how directories with invalid package names affect crawling, etc)
This should cover the current state on master, as previously discussed / implemented across #9742, #9683, #9632, #9616, #9614, etc. This will need to be changed if we can make `--namespace-packages` the default (#9636). I haven't documented some of the finer points of the changes, since it felt like an inappropriate level of detail (e.g. using absolute paths when crawling, how directories with invalid package names affect crawling, etc) Co-authored-by: hauntsaninja <>
This should cover the current state on master, as previously discussed / implemented across #9742, #9683, #9632, #9616, #9614, etc. This will need to be changed if we can make `--namespace-packages` the default (#9636). I haven't documented some of the finer points of the changes, since it felt like an inappropriate level of detail (e.g. using absolute paths when crawling, how directories with invalid package names affect crawling, etc) Co-authored-by: hauntsaninja <>
This is the next in a series of import handling improvements. (The overall vision is #8584 + there are some important bugs that should be fixed as part of this)
This, along with #9614 and #9616, fix #5759.
It turns out we already have an explicit package root flag (with tests :-) ) that we can co-opt for our purposes. It looks like the intention behind it was to satisfy some Dropbox build requirements, but as far as I can tell those requirements can be met by treating things as namespace packages. And we get to drop some pretty hacky code!
While this PR in itself is probably a breaking change for Dropbox, the good news is that the next item on #8584 is to make
--namespace-packages
the default. However, if there's a reason to have the old Dropbox behaviour and have namespace packages turned off that would be concerning, but I'm betting that's not the case.While much of the groundwork for this was laid in #9614, there were a couple issues that needed revisiting now that the explicit package root code paths get hit. The first is that the crawling up logic needs to take package roots into account. The second is that because of that, we make the package roots an instance attribute so that the caching logic is cleaner. While we no longer call crawl very much (due to #9614), the one case this can happen is if users pass in many files to mypy. I switch to
functools.lru_cache
because there are more return points now. The third is that we need to normalise paths before checking whether they're a package root (An aside here is I wanted to change things to absolute paths so that behaviour is consistent regardless of cwd — we've had one or two issues because of this — but unit tests really did not like that).I've also started to make a list of places we could put suggestions to use this (but let me know if you have something in mind) + I'll make a docs PR once I'm at a stopping point.