Skip to content

inconsistency in typing, depending whether imported function from subfolder or explicitly type hinted return #12580

@YSaxon

Description

@YSaxon

Bug Report

(A clear and concise description of what the bug is.)

To Reproduce

rootfolder/testfile.py

from typing import Optional
import other_file
import subfolder.file_in_subfolder
                
same_folder_labeled:Optional[str]
same_folder_labeled=other_file.labeled_return()
same_folder_labeled.capitalize()

same_folder_unlabeled:Optional[str]
same_folder_unlabeled=other_file.unlabeled_return()
same_folder_unlabeled.capitalize()

sub_folder_labeled:Optional[str]
sub_folder_labeled=subfolder.file_in_subfolder.labeled_return()
sub_folder_labeled.capitalize()

sub_folder_unlabeled:Optional[str]
sub_folder_unlabeled=subfolder.file_in_subfolder.unlabeled_return()
sub_folder_unlabeled.capitalize()

rootfolder/otherfile.py

def labeled_return()->str:
    return "a"
def unlabeled_return():
    return "a"

rootfolder/subfolder/file_in_subfolder.py (exact same)

def labeled_return()->str:
    return "a"
def unlabeled_return():
    return "a"

Expected Behavior

My expectation is that this should work fine in all cases. Mypy should be able to recognize that although the variable was initially declared as an Optional[str], in point of fact it has been filled with a str (or if you prefer, a Literal["a"]), and so it will have a capitalize method. (Note: this is a contrived and highly simplified example, in my real code, depending on other factors, the variable might get filled with a real value, or might get filled with None, which is why I would want to initially declare it as an optional, but in the case that it gets filled for real, I want to then call a method on it immediately afterwards)

In any case, the behavior certainly should not depend on whether the function filling the variable is in the same folder as the main file, or a subfolder. And it also shouldn't matter whether the return type of the function is explicitly type-hinted, since mypy can easily tell what type is getting returned.

Actual Behavior

The very first of the four examples, from an explicitly labeled return function imported from the same folder, works fine. But if the function is unlabeled (though it is implicitly obvious that it is returning a string), or even stranger, if the function is imported from a subfolder, then mypy complains that the variable is of Optional type, and doesn't have a capitalize method.

I would also note that although I set the type as str in the labeled_return examples above, nothing changes either way if you instead set the type to Literal["a"].

Your Environment

macOS 12.1 on an Apple Silicon (arm) chip.
Python 3.9.10
Mypy 0.942 installed by pip
I'm primarily using vscode, but I've tested it with the command line version of mypy as well with the same results.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions