astng patches to make object.__new__ work with pylint on python2.5
Chris Torek <chris.torek <at> gmail.com>
2011-01-04 15:08:12 GMT
I don't know if any of this is needed for later versions of python,
but I have an old Python 2.5 installation, and running pylint on
code using __new__ instead of __init__ in class definitions
resulted in complaints like this:
************* Module pylinttest
E: 10:PylistTest.show: Instance of 'PylistTest' has no 'arg' member
when the contents of pylinttest.py are:
def __new__(cls, arg):
self = object.__new__(cls)
self.arg = arg
print 'self.arg =', self.arg
This turned out to be due to two things:
- the builtin module scanner tossed out functions like __new__
because their module names come up as "None":
Python 2.5.1 (r251:54863, Sep 1 2010, 22:03:14)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> print object.__new__.__module__
- Having worked around that, a call to object.__new__ resulted
in an "unbound method" instance that had no way to look at
the supplied argument (cls) and extract it back from the
original arguments (cls,arg). This was easy enough to add
although the method I used is not particularly pretty.
Having fixed that, no changes to pylint were required: running
pylint on the test file now gets a 10/10 score for the 10
Here's the (rather lightly tested -- I ran it over more than
just the above example, but not over a lot of code) patch.
From c313da803ed2b2e676b6cad472874e41af998ac8 Mon Sep 17 00:00:00 2001
From: Chris Torek <chris.torek <at> gmail.com>
Date: Tue, 4 Jan 2011 07:43:07 -0700
Subject: [PATCH] handle builtin object.__new__
The builtin object.__new__ function takes a class and returns
an object of that type, i.e., we should infer the result has
whatever type we can find from the first argument.
To make this work (with Python2.5 at least), we need to note
that built in functions whose __module__ is None are really
in the __builtin__ module.
logilab/astng/bases.py | 9 +++++++++
logilab/astng/builder.py | 2 ++
2 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/logilab/astng/bases.py b/logilab/astng/bases.py
index f03a13e..5b6fec5 100755
<at> <at> -264,6 +264,15 <at> <at> class UnboundMethod(Proxy):
return super(UnboundMethod, self).igetattr(name, context)
+ def infer_call_result(self, caller, context):
+ # If we're unbound method new of builtin __object__,
+ # the result is the class (the single argument).
+ frame = self._proxied.parent.frame()
+ if (self._proxied.name == '__new__' and
+ frame.qname() == '__builtin__.object'):
+ return caller.args.infer()
+ raise InferenceError()
"""a special node representing a method bound to an instance"""
diff --git a/logilab/astng/builder.py b/logilab/astng/builder.py
index 7aa0f24..a58f016 100755
<at> <at> -199,6 +199,8 <at> <at> class ASTNGBuilder:
def _member_module(self, member):
modname = getattr(member, '__module__', None)
+ if modname is None:
+ modname = '__builtin__'
return self._dyn_modname_map.get(modname, modname)