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:

    "doc"
    class PylistTest(object):
        "doc"
        def __new__(cls, arg):
            self = object.__new__(cls)
            self.arg = arg
            return self
        def show(self):
            "doc"
            print 'self.arg =', self.arg
        def another(self):
            "doc"
            pass

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__
    None
    >>>

  - 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
analyzed statements.

Here's the (rather lightly tested -- I ran it over more than
just the above example, but not over a lot of code) patch.

Chris

>From c313da803ed2b2e676b6cad472874e41af998ac8 Mon Sep 17 00:00:00 2001
From: Chris Torek <[email protected]>
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
--- a/logilab/astng/bases.py
+++ b/logilab/astng/bases.py
@@ -264,6 +264,15 @@ class UnboundMethod(Proxy):
             return iter((self._proxied,))
         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[0].infer()
+        raise InferenceError()
+

 class BoundMethod(UnboundMethod):
     """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
--- a/logilab/astng/builder.py
+++ b/logilab/astng/builder.py
@@ -199,6 +199,8 @@ 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)


-- 
1.7.0.3
_______________________________________________
Python-Projects mailing list
[email protected]
http://lists.logilab.org/mailman/listinfo/python-projects

Reply via email to