[pygobject/pygobject-3-18] Fix import warnings pointing to the wrong code with CPython 3.3/3.5



commit 7d6fd305912c71761240cbdc0b1dbbe213e3bfa8
Author: Christoph Reiter <creiter src gnome org>
Date:   Fri Oct 30 13:07:57 2015 +0100

    Fix import warnings pointing to the wrong code with CPython 3.3/3.5
    
    For making warnings point to the code doing the import, the stack frames
    of the import system need to be skipped. The frame count number varries
    between CPython versions and in 3.5 all frames of the import system are
    skipped for warnings (https://bugs.python.org/issue24305).
    
    This hardcodes the frame counts for all supported CPython versions
    which fixes the import warning output for CPython 3.3 and 3.5.
    
    This also fixes/works around a bug in CPython 3 where if a too
    large stacklevel value was passed to warn(), CPython would try to
    interpret a file called "sys" in the same directory of the
    executed script (https://bugs.python.org/issue25493
    and https://bugzilla.gnome.org/show_bug.cgi?id=757184).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=757184

 gi/importer.py                 |   28 +++++++++++++++++++++++-----
 tests/test_import_machinery.py |    4 ++++
 2 files changed, 27 insertions(+), 5 deletions(-)
---
diff --git a/gi/importer.py b/gi/importer.py
index 22c272b..9c743c4 100644
--- a/gi/importer.py
+++ b/gi/importer.py
@@ -78,6 +78,28 @@ def _check_require_version(namespace, stacklevel):
         PyGIWarning, stacklevel=stacklevel)
 
 
+def get_import_stacklevel(import_hook):
+    """Returns the stacklevel value for warnings.warn() for when the warning
+    gets emitted by an imported module, but the warning should point at the
+    code doing the import.
+
+    Pass import_hook=True if the warning gets generated by an import hook
+    (warn() gets called in load_module(), see PEP302)
+    """
+
+    py_version = sys.version_info[:2]
+    if py_version <= (3, 2):
+        # 2.7 included
+        return 4 if import_hook else 2
+    elif py_version == (3, 3):
+        return 8 if import_hook else 10
+    elif py_version == (3, 4):
+        return 10 if import_hook else 8
+    else:
+        # fixed again in 3.5+, see https://bugs.python.org/issue24305
+        return 4 if import_hook else 2
+
+
 class DynamicImporter(object):
 
     # Note: see PEP302 for the Importer Protocol implemented below.
@@ -105,11 +127,7 @@ class DynamicImporter(object):
 
         path, namespace = fullname.rsplit('.', 1)
 
-        # we want the warning to point to the line doing the import
-        if sys.version_info >= (3, 0):
-            stacklevel = 10
-        else:
-            stacklevel = 4
+        stacklevel = get_import_stacklevel(import_hook=True)
         with _check_require_version(namespace, stacklevel=stacklevel):
             introspection_module = get_introspection_module(namespace)
             dynamic_module = load_overrides(introspection_module)
diff --git a/tests/test_import_machinery.py b/tests/test_import_machinery.py
index de9f1e9..3c2572d 100644
--- a/tests/test_import_machinery.py
+++ b/tests/test_import_machinery.py
@@ -131,3 +131,7 @@ class TestImporter(unittest.TestCase):
             with check("InvalidGObjectRepositoryModuleName", 1):
                 from gi.repository import InvalidGObjectRepositoryModuleName
                 InvalidGObjectRepositoryModuleName
+
+    def test_get_import_stacklevel(self):
+        gi.importer.get_import_stacklevel(import_hook=True)
+        gi.importer.get_import_stacklevel(import_hook=False)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]