PyCQA / isort

A Python utility / library to sort imports.
https://pycqa.github.io/isort/
MIT License
6.45k stars 574 forks source link

THIRDPARTY module detected as FIRSTPARTY when import happens within subdir of same name #2247

Open jherland opened 6 months ago

jherland commented 6 months ago

This is certainly related to #1696, but I'm not sure that it's a duplicate, as I think the relevant directory layout is slightly different.

Consider the minimal example project at https://github.com/jherland/fawltydeps-issue419-test [^1]: Inside app/fastapi/main.py, we import fastapi. This is a third-party import: with a correctly configured venv, Python will resolve the fastapi import to the fastapi package installed in that venv. Later, we import same_dir_module, which is a straigh-forward first-party import. This is the output I get when running python app/fastapi/main.py:

fastapi found at /home/jherland/.cache/pypoetry/virtualenvs/app-WtNxBkJt-py3.11/lib/python3.11/site-packages/fastapi/__init__.py
same_dir_module found at /home/jherland/code/fd-test-419/app/fastapi/same_dir_module.py
sys.path is ['/home/jherland/code/fd-test-419/app/fastapi', ..., '/home/jherland/code/fd-test-419']

However, when I attempt to classify these imports, isort.place_module() claims that both imports are FIRSTPARTY imports:

#!/usr/bin/env python3

import isort

config = isort.Config(src_paths=("app/fastapi", "."))

print(isort.place_module_with_reason("fastapi", config=config))
print(isort.place_module_with_reason("same_dir_module", config=config))

produces this output:

('FIRSTPARTY', 'Found in one of the configured src_paths: /home/jherland/code/fd-test-419/app/fastapi.')
('FIRSTPARTY', 'Found in one of the configured src_paths: /home/jherland/code/fd-test-419/app/fastapi.')

Trying to examine what happens inside isort, I find these lines to be relevant (from _src_path() in isort/place.py):

  1. AFAICS, these lines cause the _is_module(module_path) test below to trigger whenever a 3rd-party import happens from within a file located in a directory with the same name as the import:
            if not prefix and not module_path.is_dir() and src_path.name == root_module_name:
                module_path = src_path.resolve()
  2. Also, the last or-clause of the if condition will trigger in the same circumstance.
                or _src_path_is_module(src_path, root_module_name)

I am not sure if I'm just "holding it wrong" here? At least, I'm unable to find a config for isort that will agree with Python's import resolver here, i.e. classify fastapi as THIRDPARTY and same_dir_module as FIRSTPARTY.

[^1]: This report is based on https://github.com/tweag/FawltyDeps/issues/419 and @jharrisonSV's original example at https://github.com/jharrisonSV/fawltydeps-test