Skip to content

Implicit relative#50

Draft
MWR27 wants to merge 5 commits into
softdevteam:migrationfrom
MWR27:implicit-relative
Draft

Implicit relative#50
MWR27 wants to merge 5 commits into
softdevteam:migrationfrom
MWR27:implicit-relative

Conversation

@MWR27

@MWR27 MWR27 commented Jun 3, 2026

Copy link
Copy Markdown

Python 2 supports implicit relative imports inside packages. A bare import inside a package can resolve to a sibling module.

Example package:

pkg/
  __init__.py
  foo.py
  bar.py
# pkg/bar.py
import foo

In Python 2, this can resolve to:

pkg.foo

In Python 3, imports are absolute by default, so the same code resolves to:

foo

This means that the code can import a different top-level module or fail with ImportError.

For same environment of

# pkg/bar.py
import foo

Python 2 resolves to pkg.foo.
Python 3 resolves to top-level foo.

I modified import.c to fire warning only if

  1. The import uses Python 2 implicit-relative semantics, not explicit-relative.
  2. The importing module has package context (i.e. a parent package).
  3. Runtime resolution actually selected a sibling submodule.

To ensure above, it checks that the importing module has a parent package, that there are no dots in the import name, and that the resolved name is equivalent to:
parent_package + "." + imported_name

For example, with import foo, there are no dots in foo and

pkg + "." + foo == pkg.foo

Therefore, the import depended on Python 2 implicit relative import behavior, so pygrate2 emits a warning.

@nanjekyejoannah nanjekyejoannah marked this pull request as draft June 9, 2026 15:48
@nanjekyejoannah nanjekyejoannah requested a review from ltratt June 9, 2026 15:49
Comment thread Lib/test/test_py3kwarn.py Outdated

def assertWarningWithFix(self, _, warning, expected_msg, expected_fix):
self.assertTrue(hasattr(warning, 'fix'))
self.assertEqual(str(warning.message) + ': ' + str(warning.fix), expected_msg + ': ' + expected_fix)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Rather than "..." + ".." f strings would probably be clearer?

Comment thread Python/import.c
if (strcmp(potential_resolved, buf) == 0) {
char msg[524];
char fix[260];
if (is_from_form) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we can get to this line with is_from_form uninitialised?

@ltratt

ltratt commented Jun 10, 2026

Copy link
Copy Markdown
Member

This looks mostly good, but I have a couple of small comments.

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.

2 participants