This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: isinstance() fails depending on how modules imported
Type: Stage:
Components: Interpreter Core Versions: Python 2.4
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: doerwalter, georg.brandl, hgibson50, terry.reedy
Priority: normal Keywords:

Created on 2005-08-01 14:54 by hgibson50, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
isinstance_bug.zip hgibson50, 2005-08-01 14:54 Demonstrates isinstance bug.
isinstance_bug_2.zip hgibson50, 2005-08-02 13:00 Refinement of isinstance problem demonstration.
Messages (6)
msg25921 - (view) Author: Hugh Gibson (hgibson50) Date: 2005-08-01 14:54
I have found an inconsistency with instance type 
checking dependent on how modules are imported. 
Using Windows 2000, Python 2.4.1.

Source files are attached. Unzip preserving paths. To 
run, open a cmd window and set PythonPath to the 
location of the "system" folder. Run ServerRun.py.

The program creates two class instances in two different 
modules, then calls a class function on one instance 
which takes as parameter the second instance. A call to 
isinstance to check if the parameter is of the correct 
class fails. 

If a parameter is passed to ServerRun.py then the class 
module is imported in a different way (specifying the 
path to the class) and the isinstance check succeeds.

The output shows that before the call to the class 
function, an isinstance() call succeeds in both cases.

There is obviously an easy fix in code, but I think that 
isinstance checking should not depend on how modules 
are imported. And, if I am using an incorrect module 
import sequence, that sequence should be disallowed.

Sample output (also showing Windows 2000 version) is:

Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-2000 Microsoft Corp.

C:\system\server>set pythonpath=c:\system

C:\system\server>serverrun
ServerRun:
   oNew.__class__ == 
<class 'Stream.Stream.CElement'>
   Stream.CElement == 
<class 'Stream.Stream.CElement'>
   isinstance(oNew, Stream.CElement) == True
AddField():
   oNew.__class__ == 
<class 'Stream.Stream.CElement'>
   CElement == 
<class 'server.Stream.Stream.CElement'>
   isinstance(oNew, CElement) == False

C:\system\server>serverrun 1
ServerRun:
   oNew.__class__ == 
<class 'server.Stream.Stream.CElement'>
   Stream.CElement == 
<class 'server.Stream.Stream.CElement'>
   isinstance(oNew, Stream.CElement) == True
AddField():
   oNew.__class__ == 
<class 'server.Stream.Stream.CElement'>
   CElement == 
<class 'server.Stream.Stream.CElement'>
   isinstance(oNew, CElement) == True

C:\system\server>
msg25922 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2005-08-02 09:19
Logged In: YES 
user_id=1188172

This has bitten me too at one time.

When you import a module from a package starting from
different sys.path entries, you will end up with two
different modules in sys.modules.

This seems to be intended behaviour, but I don't know enough
about it to close this.
msg25923 - (view) Author: Hugh Gibson (hgibson50) Date: 2005-08-02 13:00
Logged In: YES 
user_id=732318

The case I found here is particularly worrying because I'm 
doing the isinstance() check in the module that contains the 
class. The success of the check depends on how that 
module was imported into other modules. The two cases are:

   from server.Stream import Stream

   from Stream import Stream

We found this problem in a large application under 
development. Unit testing of the class succeeded because of 
the way the class module was imported. But the application 
itself failed because of the way one module imported the 
class module. The failure was obvious in our application but 
clearly there may be subtle failure modes - for example, 
exception handling may use isinstance() internally to see if 
an exception is an instance of a given class.

I've modified the code and added some more testing which 
shows clearly that it's not the class object itself which is the 
problem, but when you have a class method which accepts 
an instance of the class as a parameter. Any test of the 
class of that parameter will fail if the first instance is created 
in one module and the second instance is created in another 
module, and they import the class module differently.

Note that it's not restricted to isinstance() - checking 
__class__ fails as well.

Also, in both of the modules that import the class module, 
isinstance() checking succeeds. There is a false sense of 
security that isinstance() checking will be OK.

Modifed code attached.

Hugh
msg25924 - (view) Author: Walter Dörwald (doerwalter) * (Python committer) Date: 2005-08-02 13:14
Logged In: YES 
user_id=89016

The problem is not isinstance() per se, but the fact that
you import one Python script as two different modules. A
simple demo might look like this:

class Foo: pass
import bug
print isinstance(Foo(), bug.Foo)

Put this in bug.py and run "python bug.py" and you'll get:
True
False

So I think this bug should be closed.
msg25925 - (view) Author: Hugh Gibson (hgibson50) Date: 2005-08-03 07:45
Logged In: YES 
user_id=732318

Thanks for the concise example.

I can see why our code fails. If I check each class instance 
using its own function then it will succeed, but if I check 
using another instance's function then it fails because as you 
say the module is imported differently.

Putting a statement at the start of the class module:

print __name__

shows two imports of the class module in the failure mode, 
with different names.

So an easy cross-check to make sure we are being 
consistent about importing is:

assert(__name__ == "server.Stream.Stream")

This fires if the incorrect sequence is used to import the 
module.

This is a simple check which can be added to every module 
and will guard against incorrect imports in future.

I suppose that I can't complain about flexibility in Python 
which allows all sorts of tricks. In this case I was handed just 
a bit too much rope. But the simple assert, added to our 
coding standards and code, will prevent any problems in 
future.

Thanks.

Hugh
msg25926 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2005-08-11 17:43
Logged In: YES 
user_id=593130

adding the resolution as 'invalid' based on the discussion here 
and elsewhere
History
Date User Action Args
2022-04-11 14:56:12adminsetgithub: 42236
2005-08-01 14:54:05hgibson50create