For static analysis, your type checker could understand what v_import does, how it works, and which symbols will be actually be there at runtime but yes, it’s starting to seem extremely complicated!
What you do with the return_value defines the behaviour you expect from it so to that extent you can rely on that instead of using isinstance:
x: Union[T1, T2] = f()
print(x.foo() ** 12.3)
Perhaps some function could build that Union type for you? It would be a pain to make it by hand if you had 50x different third-party dependencies each pulling in a slightly different requests (but which as far as you are concerned all return some small part of that package that are all compatible.)
If you’re importing a module to use it in some way you’re also declaring some kind of version dependency / compatability on it too, so that’s another thing your static analysis could check for you. That would actually be incredibly useful:
1/ Do your dependencies import an older version of requests than you do?
2/ Does it matter, and why? (eg x.foo() only exists in version 4.5 onwards, but m1 imports 4.4.)
The problem is they are different types, which has huge downstream impacts. Not least of all would be subclassing.
The static analysis you’ve described could work in simple and trivial cases, but the problem you’re now trying to solve is “what concrete type is this object”, and in a dynamic language like Python this can only be fully and 100% determined at runtime.
Mypy and the like do a good job, but often rely on protocols rather than concrete classes. There’s also no impact if the types are wrong or ignored, whereas for this a typing mismatch becomes a subtle runtime issue.
You depend on two packages, each with a function that returns a “requests.Request” object. These packages depend on different versions of “requests”.
How would you implement “isinstance(return_value, requests.Request)” on each of these calls?
Or, the indirect case of this: catching a “requests.HttpException” from each of these calls?
Importing the right thing isn’t hard, but doing things with it is the hard bit.