PyCQA / PyCQA/isort

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

Open
#2,247 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
7k
Forks
687
Avg merge
4h 56m
Merged PRs (30d)
2

Description

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

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with _src_path() in isort/place.py and reproduce the behavior using the minimal app/fastapi example and the isort.Config/place_module_with_reason script from the issue. Trace why the configured app/fastapi path makes fastapi FIRSTPARTY. Done means fastapi is classified as THIRDPARTY while same_dir_module remains FIRSTPARTY, with regression coverage for this layout.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.