Skip to content

fix(gazelle): Do not resolve absolute imports to sibling modules #3106

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

Merged
merged 9 commits into from
Jul 29, 2025

Conversation

amartani
Copy link
Contributor

@amartani amartani commented Jul 19, 2025

Currently, gazelle allows absolute imports to be resolved to sibling modules: an import foo statement will resolve to a foo.py file in the same folder if such file exists. This seems to be a Python 2 behavior (ie. pre-from __future__ import absolute_import), and doesn't work on the current rules_python setup.

This behavior is explicitly tested in the siblings_import test case. However, recreating the exact same repository layout from this test case and running bazel test //pkg:unit_test, the test fails with the import failing.

This PR adds a new directive, gazelle:python_resolve_sibling_imports, to allow disabling such behavior.

The actual changes are in 3 places:

  • In gazelle/python/target.go, the directive is added to if t.siblingSrcs.Contains(fileName) && fileName != filepath.Base(dep.Filepath), which is where the import is converted to a full absolute import if it matches a sibling file;
  • In gazelle/python/generate.go, the handling of conftest.py was dependent on this behavior (ie. it added a dependency on the module conftest, assuming that it would be resolved to the relative module). That was modified to compute the full absolute module path instead.
  • In gazelle/python/resolve.go, resolve relative imports even when using file generation mode.

I also explicitly added gazelle:python_resolve_sibling_imports true to any test that breaks if the default value of this directive is changed to false.

@amartani amartani marked this pull request as ready for review July 19, 2025 01:58
@aignas
Copy link
Collaborator

aignas commented Jul 24, 2025

Thanks for the PR. Since the current gazelle code would result in un-runnable code, is there a good reason to not default to the correct behaviour and have the flag in case some user wants to do this step-wise?

@amartani
Copy link
Contributor Author

Thanks for the PR. Since the current gazelle code would result in un-runnable code, is there a good reason to not default to the correct behaviour and have the flag in case some user wants to do this step-wise?

Honestly, my main reason is a feeling of "I must be missing something" about it. The sibling import behavior is not accidental: there's code added that only exists for resolving sibling imports, a test that explicitly tests for this behavior, and multiple other tests that implicitly depend on it. And, as far as I know, it was all written much after python2 was unsupported, which is the only reason that I can think of for why this would be desired. That said, I'd be happy to switch the default if you believe that would be ok.

@aignas
Copy link
Collaborator

aignas commented Jul 25, 2025

I'll wait for other to chime in on here. @arrdem, your insight from the Aspect.dev point of view would be valuable here as well.

Copy link
Collaborator

@dougthor42 dougthor42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran this branch against our QuantumIA code base with the directive set to true and false.

When false, there were some changes made. I checked them all and they were indeed because the original behavior was incorrect - foo.py importing math but Gazelle thinks its the sibling math.py.

This is super nice and caught some issues for us, thank you!

is there a good reason to not default to the correct behaviour and have the flag in case some user wants to do this step-wise?

I think one argument against is just subverting expectations. People are probably used to the current behavior and adjusting the current behavior would be disruptive.

The current behavior is not necessarily broken in that it always causes bazel build to fail, but it does mean that targets have more dependencies than strictly required. Those additional deps can cause circular dependencies, especially in file generation mode.

Thus my vote is to adjust the default to the correct behavior: python_resolve_sibling_imports false.

@aignas
Copy link
Collaborator

aignas commented Jul 26, 2025

I'm +1 for keeping the default and creating a ticket to switch the behaviour when we release 2.0.

@amartani amartani changed the title feat(gazelle): Allow disabling sibling module resolution fix(gazelle): Do not resolve absolute imports to sibling modules Jul 26, 2025
@amartani
Copy link
Contributor Author

Changes since the initial PR request:

  • Switched default to python_resolve_sibling_imports false;
  • Re-worded PR title and CHANGELOG entry as a fix instead of feat / added since we are changing the default behavior;
  • Adjusted behavior of relative imports when using gazelle:experimental_allow_relative_imports true and gazelle:python_generation_mode file to also resolve relative imports properly.

@amartani amartani requested a review from dougthor42 July 26, 2025 18:40
@dougthor42
Copy link
Collaborator

I'm +1 for keeping the default and creating a ticket to switch the behaviour when we release 2.0.

Oooo sounds like we're about to fight!

Nah I'm kidding of course. I definitely do not feel strongly about adjusting the default to the correct behavior. I'm at like a 3 out of 10. So it'll be pretty easy to convince me otherwise.

@amartani
Copy link
Contributor Author

I'm +1 for keeping the default and creating a ticket to switch the behaviour when we release 2.0.

Oooo sounds like we're about to fight!

Nah I'm kidding of course. I definitely do not feel strongly about adjusting the default to the correct behavior. I'm at like a 3 out of 10. So it'll be pretty easy to convince me otherwise.

My understanding of the documented policy is that, if this is considered a breaking change but "is not too disruptive" (which I think this would fit), then we want to:

  • Merge this with gazelle: python_resolve_sibling_imports true (preserve existing behavior);
  • After the next minor version (ie. after 1.6 is "cut"), switch default to false;
  • On 2.0, remove the directive (if we believe there is no reasonable use case for the previous behavior).

@aignas
Copy link
Collaborator

aignas commented Jul 27, 2025

Ah sorry... :D I misunderstood/misread/did-not-read properly:

Thus my vote is to adjust the default to the correct behavior: python_resolve_sibling_imports false.

+1 to go with your suggestion. Gazelle does not have the same stability guarantees as rules_python core. This breaking change should not be too disruptive the way I see it.

Copy link
Collaborator

@dougthor42 dougthor42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, new tests LGTM.

I verified the most recent commit a00ec81 on our repo. All 👍 🎉

@dougthor42 dougthor42 added this pull request to the merge queue Jul 29, 2025
Merged via the queue into bazel-contrib:main with commit ab3e3f7 Jul 29, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy