df03642
From 1d81b5521c1567fb11f680b1e6386b073b2f7a4d Mon Sep 17 00:00:00 2001
df03642
From: "Brian C. Lane" <bcl@redhat.com>
df03642
Date: Tue, 28 Apr 2015 09:58:03 -0700
df03642
Subject: [PATCH] Fix multiprocessing on py3.4
df03642
df03642
---
df03642
 astroid/brain/py2stdlib.py | 83 +++++++++++++++++++++++++++++++++++++++++++++-
df03642
 1 file changed, 82 insertions(+), 1 deletion(-)
df03642
df03642
diff --git a/astroid/brain/py2stdlib.py b/astroid/brain/py2stdlib.py
df03642
index 2bfcbcd..54cf2a7 100644
df03642
--- a/astroid/brain/py2stdlib.py
df03642
+++ b/astroid/brain/py2stdlib.py
df03642
@@ -12,7 +12,7 @@ from textwrap import dedent
df03642
 
df03642
 from astroid import (
df03642
     MANAGER, AsStringRegexpPredicate,
df03642
-    UseInferenceDefault, inference_tip,
df03642
+    UseInferenceDefault, inference_tip, BoundMethod,
df03642
     YES, InferenceError, register_module_extender)
df03642
 from astroid import exceptions
df03642
 from astroid import nodes
df03642
@@ -20,6 +20,7 @@ from astroid.builder import AstroidBuilder
df03642
 
df03642
 PY3K = sys.version_info > (3, 0)
df03642
 PY33 = sys.version_info >= (3, 3)
df03642
+PY34 = sys.version_info >= (3, 4)
df03642
 
df03642
 # general function
df03642
 
df03642
@@ -322,6 +323,83 @@ def infer_enum_class(node):
df03642
         break
df03642
     return node
df03642
 
df03642
+def multiprocessing_transform():
df03642
+    module = AstroidBuilder(MANAGER).string_build(dedent('''
df03642
+    from multiprocessing.managers import SyncManager
df03642
+    def Manager():
df03642
+        return SyncManager()
df03642
+    '''))
df03642
+    if not PY34:
df03642
+        return module
df03642
+
df03642
+    # On Python 3.4, multiprocessing uses a getattr lookup inside contexts,
df03642
+    # in order to get the attributes they need. Since it's extremely
df03642
+    # dynamic, we use this approach to fake it.
df03642
+    node = AstroidBuilder(MANAGER).string_build(dedent('''
df03642
+    from multiprocessing.context import DefaultContext, BaseContext
df03642
+    default = DefaultContext()
df03642
+    base = BaseContext()
df03642
+    '''))
df03642
+    try:
df03642
+        context = next(node['default'].infer())
df03642
+        base = next(node['base'].infer())
df03642
+    except InferenceError:
df03642
+        return module
df03642
+
df03642
+    for node in (context, base):
df03642
+        for key, value in node.locals.items():
df03642
+            if key.startswith("_"):
df03642
+                continue
df03642
+
df03642
+            value = value[0]
df03642
+            if isinstance(value, nodes.Function):
df03642
+                # We need to rebound this, since otherwise
df03642
+                # it will have an extra argument (self).
df03642
+                value = BoundMethod(value, node)
df03642
+            module[key] = value
df03642
+    return module
df03642
+
df03642
+def multiprocessing_managers_transform():
df03642
+    return AstroidBuilder(MANAGER).string_build(dedent('''
df03642
+    import array
df03642
+    import threading
df03642
+    import multiprocessing.pool as pool
df03642
+
df03642
+    import six
df03642
+
df03642
+    class Namespace(object):
df03642
+        pass
df03642
+
df03642
+    class Value(object):
df03642
+        def __init__(self, typecode, value, lock=True):
df03642
+            self._typecode = typecode
df03642
+            self._value = value
df03642
+        def get(self):
df03642
+            return self._value
df03642
+        def set(self, value):
df03642
+            self._value = value
df03642
+        def __repr__(self):
df03642
+            return '%s(%r, %r)'%(type(self).__name__, self._typecode, self._value)
df03642
+        value = property(get, set)
df03642
+
df03642
+    def Array(typecode, sequence, lock=True):
df03642
+        return array.array(typecode, sequence)
df03642
+
df03642
+    class SyncManager(object):
df03642
+        Queue = JoinableQueue = six.moves.queue.Queue
df03642
+        Event = threading.Event
df03642
+        RLock = threading.RLock
df03642
+        BoundedSemaphore = threading.BoundedSemaphore
df03642
+        Condition = threading.Condition
df03642
+        Barrier = threading.Barrier
df03642
+        Pool = pool.Pool
df03642
+        list = list
df03642
+        dict = dict
df03642
+        Value = Value
df03642
+        Array = Array
df03642
+        Namespace = Namespace
df03642
+    '''))
df03642
+
df03642
 
df03642
 MANAGER.register_transform(nodes.CallFunc, inference_tip(infer_named_tuple),
df03642
                            looks_like_namedtuple)
df03642
@@ -332,3 +410,6 @@ register_module_extender(MANAGER, 'hashlib', hashlib_transform)
df03642
 register_module_extender(MANAGER, 'collections', collections_transform)
df03642
 register_module_extender(MANAGER, 'pkg_resources', pkg_resources_transform)
df03642
 register_module_extender(MANAGER, 'subprocess', subprocess_transform)
df03642
+register_module_extender(MANAGER, 'multiprocessing.managers',
df03642
+                         multiprocessing_managers_transform)
df03642
+register_module_extender(MANAGER, 'multiprocessing', multiprocessing_transform)
df03642
-- 
df03642
2.1.0
df03642