Hello community,

here is the log from the commit of package python3-pyflakes for 
openSUSE:Factory checked in at 2016-05-16 12:04:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-pyflakes (Old)
 and      /work/SRC/openSUSE:Factory/.python3-pyflakes.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-pyflakes"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-pyflakes/python3-pyflakes.changes        
2016-03-07 13:29:46.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.python3-pyflakes.new/python3-pyflakes.changes   
2016-05-16 12:04:14.000000000 +0200
@@ -1,0 +2,23 @@
+Sun May 15 04:30:52 UTC 2016 - [email protected]
+
+- update to version 1.2.3:
+  * Fix TypeError when processing relative imports
+
+- changes from version 1.2.2:
+  * Avoid traceback when exception is del-ed in except
+
+- changes from version 1.2.1:
+  * Fix false RedefinedWhileUnesed for submodule imports
+
+- changes from version 1.2.0:
+  * Warn against reusing exception names after the except: block on
+    Python 3
+  * Improve the error messages for imports
+
+-------------------------------------------------------------------
+Sun May  8 07:04:51 UTC 2016 - [email protected]
+
+- specfile:
+  * updated source url to files.pythonhosted.org
+
+-------------------------------------------------------------------

Old:
----
  pyflakes-1.1.0.tar.gz

New:
----
  pyflakes-1.2.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python3-pyflakes.spec ++++++
--- /var/tmp/diff_new_pack.mXXAYB/_old  2016-05-16 12:04:15.000000000 +0200
+++ /var/tmp/diff_new_pack.mXXAYB/_new  2016-05-16 12:04:15.000000000 +0200
@@ -17,13 +17,13 @@
 
 
 Name:           python3-pyflakes
-Version:        1.1.0
+Version:        1.2.3
 Release:        0
 Url:            https://github.com/pyflakes/pyflakes
 Summary:        Passive checker of Python 3 programs
 License:        MIT
 Group:          Development/Languages/Python
-Source:         
https://pypi.python.org/packages/source/p/pyflakes/pyflakes-%{version}.tar.gz
+Source:         
https://files.pythonhosted.org/packages/source/p/pyflakes/pyflakes-%{version}.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 # please do not remove, needed for openSUSE <= 12.2
 BuildRequires:  python3

++++++ pyflakes-1.1.0.tar.gz -> pyflakes-1.2.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-1.1.0/NEWS.txt new/pyflakes-1.2.3/NEWS.txt
--- old/pyflakes-1.1.0/NEWS.txt 2015-11-03 14:18:49.000000000 +0100
+++ new/pyflakes-1.2.3/NEWS.txt 2016-05-12 20:30:42.000000000 +0200
@@ -1,3 +1,33 @@
+1.2.3 (2016-05-12):
+  - Fix TypeError when processing relative imports
+
+1.2.2 (2016-05-06):
+  - Avoid traceback when exception is del-ed in except
+
+1.2.1 (2015-05-05):
+  - Fix false RedefinedWhileUnesed for submodule imports
+
+1.2.0 (2016-05-03):
+  - Warn against reusing exception names after the except: block on Python 3
+  - Improve the error messages for imports
+
+1.1.0 (2016-03-01):
+  - Allow main() to accept arguments.
+  - Support @ matrix-multiplication operator
+  - Validate __future__ imports
+  - Fix doctest scope testing
+  - Warn for tuple assertions which are always true
+  - Warn for "import *" not at module level on Python 3
+  - Catch many more kinds of SyntaxErrors
+  - Check PEP 498 f-strings
+  - (and a few more sundry bugfixes)
+
+1.0.0 (2015-09-20):
+  - Python 3.5 support. async/await statements in particular.
+  - Fix test_api.py on Windows.
+  - Eliminate a false UnusedImport warning when the name has been
+    declared "global"
+
 0.9.2 (2015-06-17):
   - Fix a traceback when a global is defined in one scope, and used in another.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-1.1.0/PKG-INFO new/pyflakes-1.2.3/PKG-INFO
--- old/pyflakes-1.1.0/PKG-INFO 2016-03-01 16:32:21.000000000 +0100
+++ new/pyflakes-1.2.3/PKG-INFO 2016-05-12 20:38:30.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: pyflakes
-Version: 1.1.0
+Version: 1.2.3
 Summary: passive checker of Python programs
 Home-page: https://github.com/pyflakes/pyflakes
 Author: A lot of people
@@ -69,6 +69,8 @@
         Contributing
         ------------
         
+        Issues are tracked on `Launchpad 
<https://bugs.launchpad.net/pyflakes>`_.
+        
         Patches may be submitted via a `GitHub pull request`_ or via the 
mailing list
         if you prefer. If you are comfortable doing so, please `rebase your 
changes`_
         so they may be applied to master with a fast-forward merge, and each 
commit is
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-1.1.0/README.rst 
new/pyflakes-1.2.3/README.rst
--- old/pyflakes-1.1.0/README.rst       2015-11-13 18:40:37.000000000 +0100
+++ new/pyflakes-1.2.3/README.rst       2016-05-06 00:37:30.000000000 +0200
@@ -61,6 +61,8 @@
 Contributing
 ------------
 
+Issues are tracked on `Launchpad <https://bugs.launchpad.net/pyflakes>`_.
+
 Patches may be submitted via a `GitHub pull request`_ or via the mailing list
 if you prefer. If you are comfortable doing so, please `rebase your changes`_
 so they may be applied to master with a fast-forward merge, and each commit is
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-1.1.0/pyflakes/__init__.py 
new/pyflakes-1.2.3/pyflakes/__init__.py
--- old/pyflakes-1.1.0/pyflakes/__init__.py     2016-03-01 15:41:11.000000000 
+0100
+++ new/pyflakes-1.2.3/pyflakes/__init__.py     2016-05-12 20:29:17.000000000 
+0200
@@ -1 +1 @@
-__version__ = '1.1.0'
+__version__ = '1.2.3'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-1.1.0/pyflakes/checker.py 
new/pyflakes-1.2.3/pyflakes/checker.py
--- old/pyflakes-1.1.0/pyflakes/checker.py      2016-03-01 15:04:37.000000000 
+0100
+++ new/pyflakes-1.2.3/pyflakes/checker.py      2016-05-12 20:29:04.000000000 
+0200
@@ -136,17 +136,103 @@
     @type fullName: C{str}
     """
 
-    def __init__(self, name, source):
-        self.fullName = name
+    def __init__(self, name, source, full_name=None):
+        self.fullName = full_name or name
         self.redefined = []
-        name = name.split('.')[0]
         super(Importation, self).__init__(name, source)
 
     def redefines(self, other):
-        if isinstance(other, Importation):
+        if isinstance(other, SubmoduleImportation):
+            # See note in SubmoduleImportation about RedefinedWhileUnused
             return self.fullName == other.fullName
         return isinstance(other, Definition) and self.name == other.name
 
+    def _has_alias(self):
+        """Return whether importation needs an as clause."""
+        return not self.fullName.split('.')[-1] == self.name
+
+    @property
+    def source_statement(self):
+        """Generate a source statement equivalent to the import."""
+        if self._has_alias():
+            return 'import %s as %s' % (self.fullName, self.name)
+        else:
+            return 'import %s' % self.fullName
+
+    def __str__(self):
+        """Return import full name with alias."""
+        if self._has_alias():
+            return self.fullName + ' as ' + self.name
+        else:
+            return self.fullName
+
+
+class SubmoduleImportation(Importation):
+    """
+    A binding created by a submodule import statement.
+
+    A submodule import is a special case where the root module is implicitly
+    imported, without an 'as' clause, and the submodule is also imported.
+    Python does not restrict which attributes of the root module may be used.
+
+    This class is only used when the submodule import is without an 'as' 
clause.
+
+    pyflakes handles this case by registering the root module name in the 
scope,
+    allowing any attribute of the root module to be accessed.
+
+    RedefinedWhileUnused is suppressed in `redefines` unless the submodule
+    name is also the same, to avoid false positives.
+    """
+
+    def __init__(self, name, source):
+        # A dot should only appear in the name when it is a submodule import
+        assert '.' in name and (not source or isinstance(source, ast.Import))
+        package_name = name.split('.')[0]
+        super(SubmoduleImportation, self).__init__(package_name, source)
+        self.fullName = name
+
+    def redefines(self, other):
+        if isinstance(other, Importation):
+            return self.fullName == other.fullName
+        return super(SubmoduleImportation, self).redefines(other)
+
+    def __str__(self):
+        return self.fullName
+
+    @property
+    def source_statement(self):
+        return 'import ' + self.fullName
+
+
+class ImportationFrom(Importation):
+
+    def __init__(self, name, source, module, real_name=None):
+        self.module = module
+        self.real_name = real_name or name
+
+        if module.endswith('.'):
+            full_name = module + self.real_name
+        else:
+            full_name = module + '.' + self.real_name
+
+        super(ImportationFrom, self).__init__(name, source, full_name)
+
+    def __str__(self):
+        """Return import full name with alias."""
+        if self.real_name != self.name:
+            return self.fullName + ' as ' + self.name
+        else:
+            return self.fullName
+
+    @property
+    def source_statement(self):
+        if self.real_name != self.name:
+            return 'from %s import %s as %s' % (self.module,
+                                                self.real_name,
+                                                self.name)
+        else:
+            return 'from %s import %s' % (self.module, self.name)
+
 
 class StarImportation(Importation):
     """A binding created by an 'from x import *' statement."""
@@ -158,8 +244,19 @@
         self.name = name + '.*'
         self.fullName = name
 
+    @property
+    def source_statement(self):
+        return 'from ' + self.fullName + ' import *'
+
+    def __str__(self):
+        # When the module ends with a ., avoid the ambiguous '..*'
+        if self.fullName.endswith('.'):
+            return self.source_statement
+        else:
+            return self.name
 
-class FutureImportation(Importation):
+
+class FutureImportation(ImportationFrom):
     """
     A binding created by a from `__future__` import statement.
 
@@ -167,7 +264,7 @@
     """
 
     def __init__(self, name, source, scope):
-        super(FutureImportation, self).__init__(name, source)
+        super(FutureImportation, self).__init__(name, source, '__future__')
         self.used = (scope, source)
 
 
@@ -284,7 +381,7 @@
     # Returns node.id, or node.name, or None
     if hasattr(node, 'id'):     # One of the many nodes with an id
         return node.id
-    if hasattr(node, 'name'):   # a ExceptHandler node
+    if hasattr(node, 'name'):   # an ExceptHandler node
         return node.name
 
 
@@ -430,7 +527,7 @@
                     used = value.used or value.name in all_names
                     if not used:
                         messg = messages.UnusedImport
-                        self.report(messg, value.source, value.name)
+                        self.report(messg, value.source, str(value))
                     for node in value.redefined:
                         if isinstance(self.getParent(node), ast.For):
                             messg = messages.ImportShadowedByLoopVar
@@ -1039,8 +1136,11 @@
 
     def IMPORT(self, node):
         for alias in node.names:
-            name = alias.asname or alias.name
-            importation = Importation(name, node)
+            if '.' in alias.name and not alias.asname:
+                importation = SubmoduleImportation(alias.name, node)
+            else:
+                name = alias.asname or alias.name
+                importation = Importation(name, node, alias.name)
             self.addBinding(node, importation)
 
     def IMPORTFROM(self, node):
@@ -1051,6 +1151,8 @@
         else:
             self.futuresAllowed = False
 
+        module = ('.' * node.level) + (node.module or '')
+
         for alias in node.names:
             name = alias.asname or alias.name
             if node.module == '__future__':
@@ -1062,14 +1164,15 @@
                 # Only Python 2, local import * is a SyntaxWarning
                 if not PY2 and not isinstance(self.scope, ModuleScope):
                     self.report(messages.ImportStarNotPermitted,
-                                node, node.module)
+                                node, module)
                     continue
 
                 self.scope.importStarred = True
-                self.report(messages.ImportStarUsed, node, node.module)
-                importation = StarImportation(node.module, node)
+                self.report(messages.ImportStarUsed, node, module)
+                importation = StarImportation(module, node)
             else:
-                importation = Importation(name, node)
+                importation = ImportationFrom(name, node,
+                                              module, alias.name)
             self.addBinding(node, importation)
 
     def TRY(self, node):
@@ -1095,8 +1198,35 @@
     TRYEXCEPT = TRY
 
     def EXCEPTHANDLER(self, node):
-        # 3.x: in addition to handling children, we must handle the name of
-        # the exception, which is not a Name node, but a simple string.
-        if isinstance(node.name, str):
-            self.handleNodeStore(node)
+        if PY2 or node.name is None:
+            self.handleChildren(node)
+            return
+
+        # 3.x: the name of the exception, which is not a Name node, but
+        # a simple string, creates a local that is only bound within the scope
+        # of the except: block.
+
+        for scope in self.scopeStack[::-1]:
+            if node.name in scope:
+                is_name_previously_defined = True
+                break
+        else:
+            is_name_previously_defined = False
+
+        self.handleNodeStore(node)
         self.handleChildren(node)
+        if not is_name_previously_defined:
+            # See discussion on https://github.com/pyflakes/pyflakes/pull/59.
+
+            # We're removing the local name since it's being unbound
+            # after leaving the except: block and it's always unbound
+            # if the except: block is never entered. This will cause an
+            # "undefined name" error raised if the checked code tries to
+            # use the name afterwards.
+            #
+            # Unless it's been removed already. Then do nothing.
+
+            try:
+                del self.scope[node.name]
+            except KeyError:
+                pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-1.1.0/pyflakes/test/test_imports.py 
new/pyflakes-1.2.3/pyflakes/test/test_imports.py
--- old/pyflakes-1.1.0/pyflakes/test/test_imports.py    2016-03-01 
15:04:37.000000000 +0100
+++ new/pyflakes-1.2.3/pyflakes/test/test_imports.py    2016-05-12 
20:29:04.000000000 +0200
@@ -2,26 +2,152 @@
 from sys import version_info
 
 from pyflakes import messages as m
+from pyflakes.checker import (
+    FutureImportation,
+    Importation,
+    ImportationFrom,
+    StarImportation,
+    SubmoduleImportation,
+)
 from pyflakes.test.harness import TestCase, skip, skipIf
 
 
+class TestImportationObject(TestCase):
+
+    def test_import_basic(self):
+        binding = Importation('a', None, 'a')
+        assert binding.source_statement == 'import a'
+        assert str(binding) == 'a'
+
+    def test_import_as(self):
+        binding = Importation('c', None, 'a')
+        assert binding.source_statement == 'import a as c'
+        assert str(binding) == 'a as c'
+
+    def test_import_submodule(self):
+        binding = SubmoduleImportation('a.b', None)
+        assert binding.source_statement == 'import a.b'
+        assert str(binding) == 'a.b'
+
+    def test_import_submodule_as(self):
+        # A submodule import with an as clause is not a SubmoduleImportation
+        binding = Importation('c', None, 'a.b')
+        assert binding.source_statement == 'import a.b as c'
+        assert str(binding) == 'a.b as c'
+
+    def test_import_submodule_as_source_name(self):
+        binding = Importation('a', None, 'a.b')
+        assert binding.source_statement == 'import a.b as a'
+        assert str(binding) == 'a.b as a'
+
+    def test_importfrom_relative(self):
+        binding = ImportationFrom('a', None, '.', 'a')
+        assert binding.source_statement == 'from . import a'
+        assert str(binding) == '.a'
+
+    def test_importfrom_relative_parent(self):
+        binding = ImportationFrom('a', None, '..', 'a')
+        assert binding.source_statement == 'from .. import a'
+        assert str(binding) == '..a'
+
+    def test_importfrom_relative_with_module(self):
+        binding = ImportationFrom('b', None, '..a', 'b')
+        assert binding.source_statement == 'from ..a import b'
+        assert str(binding) == '..a.b'
+
+    def test_importfrom_relative_with_module_as(self):
+        binding = ImportationFrom('c', None, '..a', 'b')
+        assert binding.source_statement == 'from ..a import b as c'
+        assert str(binding) == '..a.b as c'
+
+    def test_importfrom_member(self):
+        binding = ImportationFrom('b', None, 'a', 'b')
+        assert binding.source_statement == 'from a import b'
+        assert str(binding) == 'a.b'
+
+    def test_importfrom_submodule_member(self):
+        binding = ImportationFrom('c', None, 'a.b', 'c')
+        assert binding.source_statement == 'from a.b import c'
+        assert str(binding) == 'a.b.c'
+
+    def test_importfrom_member_as(self):
+        binding = ImportationFrom('c', None, 'a', 'b')
+        assert binding.source_statement == 'from a import b as c'
+        assert str(binding) == 'a.b as c'
+
+    def test_importfrom_submodule_member_as(self):
+        binding = ImportationFrom('d', None, 'a.b', 'c')
+        assert binding.source_statement == 'from a.b import c as d'
+        assert str(binding) == 'a.b.c as d'
+
+    def test_importfrom_star(self):
+        binding = StarImportation('a.b', None)
+        assert binding.source_statement == 'from a.b import *'
+        assert str(binding) == 'a.b.*'
+
+    def test_importfrom_star_relative(self):
+        binding = StarImportation('.b', None)
+        assert binding.source_statement == 'from .b import *'
+        assert str(binding) == '.b.*'
+
+    def test_importfrom_future(self):
+        binding = FutureImportation('print_function', None, None)
+        assert binding.source_statement == 'from __future__ import 
print_function'
+        assert str(binding) == '__future__.print_function'
+
+
 class Test(TestCase):
 
     def test_unusedImport(self):
         self.flakes('import fu, bar', m.UnusedImport, m.UnusedImport)
         self.flakes('from baz import fu, bar', m.UnusedImport, m.UnusedImport)
 
+    def test_unusedImport_relative(self):
+        self.flakes('from . import fu', m.UnusedImport)
+        self.flakes('from . import fu as baz', m.UnusedImport)
+        self.flakes('from .. import fu', m.UnusedImport)
+        self.flakes('from ... import fu', m.UnusedImport)
+        self.flakes('from .. import fu as baz', m.UnusedImport)
+        self.flakes('from .bar import fu', m.UnusedImport)
+        self.flakes('from ..bar import fu', m.UnusedImport)
+        self.flakes('from ...bar import fu', m.UnusedImport)
+        self.flakes('from ...bar import fu as baz', m.UnusedImport)
+
+        checker = self.flakes('from . import fu', m.UnusedImport)
+
+        error = checker.messages[0]
+        assert error.message == '%r imported but unused'
+        assert error.message_args == ('.fu', )
+
+        checker = self.flakes('from . import fu as baz', m.UnusedImport)
+
+        error = checker.messages[0]
+        assert error.message == '%r imported but unused'
+        assert error.message_args == ('.fu as baz', )
+
     def test_aliasedImport(self):
         self.flakes('import fu as FU, bar as FU',
                     m.RedefinedWhileUnused, m.UnusedImport)
         self.flakes('from moo import fu as FU, bar as FU',
                     m.RedefinedWhileUnused, m.UnusedImport)
 
+    def test_aliasedImportShadowModule(self):
+        """Imported aliases can shadow the source of the import."""
+        self.flakes('from moo import fu as moo; moo')
+        self.flakes('import fu as fu; fu')
+        self.flakes('import fu.bar as fu; fu')
+
     def test_usedImport(self):
         self.flakes('import fu; print(fu)')
         self.flakes('from baz import fu; print(fu)')
         self.flakes('import fu; del fu')
 
+    def test_usedImport_relative(self):
+        self.flakes('from . import fu; assert fu')
+        self.flakes('from .bar import fu; assert fu')
+        self.flakes('from .. import fu; assert fu')
+        self.flakes('from ..bar import fu as baz; assert baz')
+
     def test_redefinedWhileUnused(self):
         self.flakes('import fu; fu = 3', m.RedefinedWhileUnused)
         self.flakes('import fu; fu, bar = 3', m.RedefinedWhileUnused)
@@ -615,6 +741,49 @@
             pass
         ''', m.ImportStarUsed, m.UnusedImport)
 
+        checker = self.flakes('from fu import *',
+                              m.ImportStarUsed, m.UnusedImport)
+
+        error = checker.messages[0]
+        assert error.message.startswith("'from %s import *' used; unable ")
+        assert error.message_args == ('fu', )
+
+        error = checker.messages[1]
+        assert error.message == '%r imported but unused'
+        assert error.message_args == ('fu.*', )
+
+    def test_importStar_relative(self):
+        """Use of import * from a relative import is reported."""
+        self.flakes('from .fu import *', m.ImportStarUsed, m.UnusedImport)
+        self.flakes('''
+        try:
+            from .fu import *
+        except:
+            pass
+        ''', m.ImportStarUsed, m.UnusedImport)
+
+        checker = self.flakes('from .fu import *',
+                              m.ImportStarUsed, m.UnusedImport)
+
+        error = checker.messages[0]
+        assert error.message.startswith("'from %s import *' used; unable ")
+        assert error.message_args == ('.fu', )
+
+        error = checker.messages[1]
+        assert error.message == '%r imported but unused'
+        assert error.message_args == ('.fu.*', )
+
+        checker = self.flakes('from .. import *',
+                              m.ImportStarUsed, m.UnusedImport)
+
+        error = checker.messages[0]
+        assert error.message.startswith("'from %s import *' used; unable ")
+        assert error.message_args == ('..', )
+
+        error = checker.messages[1]
+        assert error.message == '%r imported but unused'
+        assert error.message_args == ('from .. import *', )
+
     @skipIf(version_info < (3,),
             'import * below module level is a warning on Python 2')
     def test_localImportStar(self):
@@ -628,6 +797,14 @@
             from fu import *
         ''', m.ImportStarNotPermitted)
 
+        checker = self.flakes('''
+        class a:
+            from .. import *
+        ''', m.ImportStarNotPermitted)
+        error = checker.messages[0]
+        assert error.message == "'from %s import *' only allowed at module 
level"
+        assert error.message_args == ('..', )
+
     @skipIf(version_info > (3,),
             'import * below module level is an error on Python 3')
     def test_importStarNested(self):
@@ -685,6 +862,35 @@
         fu.bar, fu.baz
         ''')
 
+    def test_used_package_with_submodule_import(self):
+        """
+        Usage of package marks submodule imports as used.
+        """
+        self.flakes('''
+        import fu
+        import fu.bar
+        fu.x
+        ''')
+
+        self.flakes('''
+        import fu.bar
+        import fu
+        fu.x
+        ''')
+
+    def test_unused_package_with_submodule_import(self):
+        """
+        When a package and its submodule are imported, only report once.
+        """
+        checker = self.flakes('''
+        import fu
+        import fu.bar
+        ''', m.UnusedImport)
+        error = checker.messages[0]
+        assert error.message == '%r imported but unused'
+        assert error.message_args == ('fu.bar', )
+        assert error.lineno == 5 if self.withDoctest else 3
+
     def test_assignRHSFirst(self):
         self.flakes('import fu; fu = fu')
         self.flakes('import fu; fu, bar = fu')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-1.1.0/pyflakes/test/test_undefined_names.py 
new/pyflakes-1.2.3/pyflakes/test/test_undefined_names.py
--- old/pyflakes-1.1.0/pyflakes/test/test_undefined_names.py    2016-03-01 
15:04:37.000000000 +0100
+++ new/pyflakes-1.2.3/pyflakes/test/test_undefined_names.py    2016-05-06 
18:40:47.000000000 +0200
@@ -22,6 +22,184 @@
         ''',
                     m.UndefinedName)
 
+    @skipIf(version_info < (3,),
+            'in Python 2 exception names stay bound after the except: block')
+    def test_undefinedExceptionName(self):
+        """Exception names can't be used after the except: block."""
+        self.flakes('''
+        try:
+            raise ValueError('ve')
+        except ValueError as exc:
+            pass
+        exc
+        ''',
+                    m.UndefinedName)
+
+    def test_namesDeclaredInExceptBlocks(self):
+        """Locals declared in except: blocks can be used after the block.
+
+        This shows the example in test_undefinedExceptionName is
+        different."""
+        self.flakes('''
+        try:
+            raise ValueError('ve')
+        except ValueError as exc:
+            e = exc
+        e
+        ''')
+
+    @skip('error reporting disabled due to false positives below')
+    def test_undefinedExceptionNameObscuringLocalVariable(self):
+        """Exception names obscure locals, can't be used after.
+
+        Last line will raise UnboundLocalError on Python 3 after exiting
+        the except: block. Note next two examples for false positives to
+        watch out for."""
+        self.flakes('''
+        exc = 'Original value'
+        try:
+            raise ValueError('ve')
+        except ValueError as exc:
+            pass
+        exc
+        ''',
+                    m.UndefinedName)
+
+    @skipIf(version_info < (3,),
+            'in Python 2 exception names stay bound after the except: block')
+    def test_undefinedExceptionNameObscuringLocalVariable2(self):
+        """Exception names are unbound after the `except:` block.
+
+        Last line will raise UnboundLocalError on Python 3 but would print out
+        've' on Python 2."""
+        self.flakes('''
+        try:
+            raise ValueError('ve')
+        except ValueError as exc:
+            pass
+        print(exc)
+        exc = 'Original value'
+        ''',
+                    m.UndefinedName)
+
+    def test_undefinedExceptionNameObscuringLocalVariableFalsePositive1(self):
+        """Exception names obscure locals, can't be used after. Unless.
+
+        Last line will never raise UnboundLocalError because it's only
+        entered if no exception was raised."""
+        self.flakes('''
+        exc = 'Original value'
+        try:
+            raise ValueError('ve')
+        except ValueError as exc:
+            print('exception logged')
+            raise
+        exc
+        ''')
+
+    def test_delExceptionInExcept(self):
+        """The exception name can be deleted in the except: block."""
+        self.flakes('''
+        try:
+            pass
+        except Exception as exc:
+            del exc
+        ''')
+
+    def test_undefinedExceptionNameObscuringLocalVariableFalsePositive2(self):
+        """Exception names obscure locals, can't be used after. Unless.
+
+        Last line will never raise UnboundLocalError because `error` is
+        only falsy if the `except:` block has not been entered."""
+        self.flakes('''
+        exc = 'Original value'
+        error = None
+        try:
+            raise ValueError('ve')
+        except ValueError as exc:
+            error = 'exception logged'
+        if error:
+            print(error)
+        else:
+            exc
+        ''')
+
+    @skip('error reporting disabled due to false positives below')
+    def test_undefinedExceptionNameObscuringGlobalVariable(self):
+        """Exception names obscure globals, can't be used after.
+
+        Last line will raise UnboundLocalError on both Python 2 and
+        Python 3 because the existence of that exception name creates
+        a local scope placeholder for it, obscuring any globals, etc."""
+        self.flakes('''
+        exc = 'Original value'
+        def func():
+            try:
+                pass  # nothing is raised
+            except ValueError as exc:
+                pass  # block never entered, exc stays unbound
+            exc
+        ''',
+                    m.UndefinedLocal)
+
+    @skip('error reporting disabled due to false positives below')
+    def test_undefinedExceptionNameObscuringGlobalVariable2(self):
+        """Exception names obscure globals, can't be used after.
+
+        Last line will raise NameError on Python 3 because the name is
+        locally unbound after the `except:` block, even if it's
+        nonlocal. We should issue an error in this case because code
+        only working correctly if an exception isn't raised, is invalid.
+        Unless it's explicitly silenced, see false positives below."""
+        self.flakes('''
+        exc = 'Original value'
+        def func():
+            global exc
+            try:
+                raise ValueError('ve')
+            except ValueError as exc:
+                pass  # block never entered, exc stays unbound
+            exc
+        ''',
+                    m.UndefinedLocal)
+
+    def test_undefinedExceptionNameObscuringGlobalVariableFalsePositive1(self):
+        """Exception names obscure globals, can't be used after. Unless.
+
+        Last line will never raise NameError because it's only entered
+        if no exception was raised."""
+        self.flakes('''
+        exc = 'Original value'
+        def func():
+            global exc
+            try:
+                raise ValueError('ve')
+            except ValueError as exc:
+                print('exception logged')
+                raise
+            exc
+        ''')
+
+    def test_undefinedExceptionNameObscuringGlobalVariableFalsePositive2(self):
+        """Exception names obscure globals, can't be used after. Unless.
+
+        Last line will never raise NameError because `error` is only
+        falsy if the `except:` block has not been entered."""
+        self.flakes('''
+        exc = 'Original value'
+        def func():
+            global exc
+            error = None
+            try:
+                raise ValueError('ve')
+            except ValueError as exc:
+                error = 'exception logged'
+            if error:
+                print(error)
+            else:
+                exc
+        ''')
+
     def test_functionsNeedGlobalScope(self):
         self.flakes('''
         class a:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-1.1.0/pyflakes.egg-info/PKG-INFO 
new/pyflakes-1.2.3/pyflakes.egg-info/PKG-INFO
--- old/pyflakes-1.1.0/pyflakes.egg-info/PKG-INFO       2016-03-01 
16:32:19.000000000 +0100
+++ new/pyflakes-1.2.3/pyflakes.egg-info/PKG-INFO       2016-05-12 
20:38:29.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: pyflakes
-Version: 1.1.0
+Version: 1.2.3
 Summary: passive checker of Python programs
 Home-page: https://github.com/pyflakes/pyflakes
 Author: A lot of people
@@ -69,6 +69,8 @@
         Contributing
         ------------
         
+        Issues are tracked on `Launchpad 
<https://bugs.launchpad.net/pyflakes>`_.
+        
         Patches may be submitted via a `GitHub pull request`_ or via the 
mailing list
         if you prefer. If you are comfortable doing so, please `rebase your 
changes`_
         so they may be applied to master with a fast-forward merge, and each 
commit is


Reply via email to