nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: libp2p/go-libp2p
Pull request #3286 (2025-05-07 08:02:03)

eventbus: change slow consumer event from error to warn
Change event bus slow consumer event logging from `ERROR` to `WARN`.

`WARN` seems more appropriate since this isn't an error.

Closes https://github.com/ipfs/kubo/issues/10778


Patch:
diff --git a/p2p/host/eventbus/basic.go b/p2p/host/eventbus/basic.go
index af6a74bd..32051f54 100644
--- a/p2p/host/eventbus/basic.go
+++ b/p2p/host/eventbus/basic.go
@@ -14,6 +14,7 @@ import (
 
 type logInterface interface {
 	Errorf(string, ...interface{})
+	Warnf(string, ...interface{})
 }
 
 var log logInterface = logging.Logger("eventbus")
@@ -464,7 +465,7 @@ func emitAndLogError(timer *time.Timer, typ reflect.Type, evt interface{}, sink
 			<-timer.C
 		}
 	case <-timer.C:
-		log.Errorf("subscriber named \"%s\" is a slow consumer of %s. This can lead to libp2p stalling and hard to debug issues.", sink.name, typ)
+		log.Warnf("subscriber named \"%s\" is a slow consumer of %s. This can lead to libp2p stalling and hard to debug issues.", sink.name, typ)
 		// Continue to stall since there's nothing else we can do.
 		sink.ch <- evt
 	}


Test patch:
diff --git a/p2p/host/eventbus/basic_test.go b/p2p/host/eventbus/basic_test.go
index 530a46ff..b3fdb12e 100644
--- a/p2p/host/eventbus/basic_test.go
+++ b/p2p/host/eventbus/basic_test.go
@@ -18,8 +18,10 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
-type EventA struct{}
-type EventB int
+type (
+	EventA struct{}
+	EventB int
+)
 
 func getN() int {
 	n := 50000
@@ -144,6 +146,10 @@ func (m *mockLogger) Errorf(format string, args ...interface{}) {
 	m.logs = append(m.logs, fmt.Sprintf(format, args...))
 }
 
+func (m *mockLogger) Warnf(format string, args ...interface{}) {
+	m.Errorf(format, args...)
+}
+
 func (m *mockLogger) Logs() []string {
 	m.mu.Lock()
 	defer m.mu.Unlock()
Repository: libp2p/go-libp2p
Pull request #2520 (2023-08-24 08:37:25)

quic: don't claim to be able to dial draft-29 in CanDial


Patch:
diff --git a/p2p/transport/quic/transport.go b/p2p/transport/quic/transport.go
index aef3f4c9..18d198bb 100644
--- a/p2p/transport/quic/transport.go
+++ b/p2p/transport/quic/transport.go
@@ -268,8 +268,8 @@ loop:
 	}
 }
 
-// Don't use mafmt.QUIC as we don't want to dial DNS addresses. Just /ip{4,6}/udp/quic
-var dialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Or(mafmt.Base(ma.P_QUIC), mafmt.Base(ma.P_QUIC_V1)))
+// Don't use mafmt.QUIC as we don't want to dial DNS addresses. Just /ip{4,6}/udp/quic-v1
+var dialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Base(ma.P_QUIC_V1))
 
 // CanDial determines if we can dial to an address
 func (t *transport) CanDial(addr ma.Multiaddr) bool {


Test patch:
diff --git a/p2p/transport/quic/transport_test.go b/p2p/transport/quic/transport_test.go
index f774c615..41e7e4e4 100644
--- a/p2p/transport/quic/transport_test.go
+++ b/p2p/transport/quic/transport_test.go
@@ -46,6 +46,7 @@ func TestCanDial(t *testing.T) {
 		"/ip4/127.0.0.1/udp/1234",
 		"/ip4/5.5.5.5/tcp/1234",
 		"/dns/google.com/udp/443/quic-v1",
+		"/ip4/127.0.0.1/udp/1234/quic",
 	}
 	valid := []string{
 		"/ip4/127.0.0.1/udp/1234/quic-v1",
Repository: libp2p/go-libp2p
Pull request #2524 (2023-08-25 09:23:31)

swarm: return a more meaningful error when dialing QUIC draft-29


Patch:
diff --git a/p2p/net/swarm/swarm_dial.go b/p2p/net/swarm/swarm_dial.go
index e17c2735..1e5638f3 100644
--- a/p2p/net/swarm/swarm_dial.go
+++ b/p2p/net/swarm/swarm_dial.go
@@ -14,8 +14,10 @@ import (
 	"github.com/libp2p/go-libp2p/core/peer"
 	"github.com/libp2p/go-libp2p/core/peerstore"
 	"github.com/libp2p/go-libp2p/core/transport"
+
 	ma "github.com/multiformats/go-multiaddr"
 	madns "github.com/multiformats/go-multiaddr-dns"
+	mafmt "github.com/multiformats/go-multiaddr-fmt"
 	manet "github.com/multiformats/go-multiaddr/net"
 )
 
@@ -65,6 +67,19 @@ var (
 	ErrGaterDisallowedConnection = errors.New("gater disallows connection to peer")
 )
 
+// ErrQUICDraft29 wraps ErrNoTransport and provide a more meaningful error message
+var ErrQUICDraft29 errQUICDraft29
+
+type errQUICDraft29 struct{}
+
+func (errQUICDraft29) Error() string {
+	return "QUIC draft-29 has been removed, QUIC (RFC 9000) is accessible with /quic-v1"
+}
+
+func (errQUICDraft29) Unwrap() error {
+	return ErrNoTransport
+}
+
 // DialAttempts governs how many times a goroutine will try to dial a given peer.
 // Note: this is down to one, as we have _too many dials_ atm. To add back in,
 // add loop back in Dial(.)
@@ -407,6 +422,8 @@ func (s *Swarm) nonProxyAddr(addr ma.Multiaddr) bool {
 	return !t.Proxy()
 }
 
+var quicDraft29DialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Base(ma.P_QUIC))
+
 // filterKnownUndialables takes a list of multiaddrs, and removes those
 // that we definitely don't want to dial: addresses configured to be blocked,
 // IPv6 link-local addresses, addresses without a dial-capable transport,
@@ -435,7 +452,13 @@ func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) (goodAdd
 	// filter addresses with no transport
 	addrs = ma.FilterAddrs(addrs, func(a ma.Multiaddr) bool {
 		if s.TransportForDialing(a) == nil {
-			addrErrs = append(addrErrs, TransportError{Address: a, Cause: ErrNoTransport})
+			e := ErrNoTransport
+			// We used to support QUIC draft-29 for a long time.
+			// Provide a more useful error when attempting to dial a QUIC draft-29 address.
+			if quicDraft29DialMatcher.Matches(a) {
+				e = ErrQUICDraft29
+			}
+			addrErrs = append(addrErrs, TransportError{Address: a, Cause: e})
 			return false
 		}
 		return true


Test patch:
diff --git a/p2p/net/swarm/dial_test.go b/p2p/net/swarm/dial_test.go
index 324a9853..a614183b 100644
--- a/p2p/net/swarm/dial_test.go
+++ b/p2p/net/swarm/dial_test.go
@@ -642,3 +642,12 @@ func TestDialSelf(t *testing.T) {
 	_, err := s1.DialPeer(context.Background(), s1.LocalPeer())
 	require.ErrorIs(t, err, swarm.ErrDialToSelf, "expected error from self dial")
 }
+
+func TestDialQUICDraft29(t *testing.T) {
+	s := makeDialOnlySwarm(t)
+	id := testutil.RandPeerIDFatal(t)
+	s.Peerstore().AddAddr(id, ma.StringCast("/ip4/127.0.0.1/udp/1234/quic"), time.Hour)
+	_, err := s.DialPeer(context.Background(), id)
+	require.ErrorIs(t, err, swarm.ErrQUICDraft29)
+	require.ErrorIs(t, err, swarm.ErrNoTransport)
+}
Repository: libp2p/go-libp2p
Pull request #2571 (2023-09-14 05:58:42)

websocket: don't resolve /dnsaddr addresses
/dnsaddr allows forwarding to arbitrary multiaddresses. We can't assume that the host name stays the same.

Thanks to @sukunrt for pointing this out in https://github.com/libp2p/go-libp2p/pull/2564#pullrequestreview-1621750665.


Patch:
diff --git a/p2p/transport/websocket/websocket.go b/p2p/transport/websocket/websocket.go
index e1965123..0054df99 100644
--- a/p2p/transport/websocket/websocket.go
+++ b/p2p/transport/websocket/websocket.go
@@ -136,7 +136,7 @@ func (t *WebsocketTransport) Resolve(ctx context.Context, maddr ma.Multiaddr) ([
 		// We don't have an sni component, we'll use dns/dnsaddr
 		ma.ForEach(parsed.restMultiaddr, func(c ma.Component) bool {
 			switch c.Protocol().Code {
-			case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR:
+			case ma.P_DNS, ma.P_DNS4, ma.P_DNS6:
 				// err shouldn't happen since this means we couldn't parse a dns hostname for an sni value.
 				parsed.sni, err = ma.NewComponent("sni", c.Value())
 				return false


Test patch:
diff --git a/p2p/transport/websocket/websocket_test.go b/p2p/transport/websocket/websocket_test.go
index aa06c628..2023ee35 100644
--- a/p2p/transport/websocket/websocket_test.go
+++ b/p2p/transport/websocket/websocket_test.go
@@ -525,12 +525,13 @@ func TestWriteZero(t *testing.T) {
 func TestResolveMultiaddr(t *testing.T) {
 	// map[unresolved]resolved
 	testCases := map[string]string{
+		"/dns/example.com/tcp/1234/wss":        "/dns/example.com/tcp/1234/tls/sni/example.com/ws",
 		"/dns4/example.com/tcp/1234/wss":       "/dns4/example.com/tcp/1234/tls/sni/example.com/ws",
 		"/dns6/example.com/tcp/1234/wss":       "/dns6/example.com/tcp/1234/tls/sni/example.com/ws",
-		"/dnsaddr/example.com/tcp/1234/wss":    "/dnsaddr/example.com/tcp/1234/tls/sni/example.com/ws",
+		"/dnsaddr/example.com/tcp/1234/wss":    "/dnsaddr/example.com/tcp/1234/wss",
 		"/dns4/example.com/tcp/1234/tls/ws":    "/dns4/example.com/tcp/1234/tls/sni/example.com/ws",
 		"/dns6/example.com/tcp/1234/tls/ws":    "/dns6/example.com/tcp/1234/tls/sni/example.com/ws",
-		"/dnsaddr/example.com/tcp/1234/tls/ws": "/dnsaddr/example.com/tcp/1234/tls/sni/example.com/ws",
+		"/dnsaddr/example.com/tcp/1234/tls/ws": "/dnsaddr/example.com/tcp/1234/tls/ws",
 	}
 
 	for unresolved, expectedMA := range testCases {
Repository: libp2p/go-libp2p
Pull request #2578 (2023-09-21 09:27:35)

webrtc: fail Write early if deadline has exceeded before the call
fixing a bug where some small writes can succeed after the deadline has passed


Patch:
diff --git a/p2p/transport/webrtc/stream_write.go b/p2p/transport/webrtc/stream_write.go
index c7eb3bf7..698af9c4 100644
--- a/p2p/transport/webrtc/stream_write.go
+++ b/p2p/transport/webrtc/stream_write.go
@@ -35,6 +35,10 @@ func (s *stream) Write(b []byte) (int, error) {
 		s.readLoopOnce.Do(s.spawnControlMessageReader)
 	}
 
+	if !s.writeDeadline.IsZero() && time.Now().After(s.writeDeadline) {
+		return 0, os.ErrDeadlineExceeded
+	}
+
 	var writeDeadlineTimer *time.Timer
 	defer func() {
 		if writeDeadlineTimer != nil {


Test patch:
diff --git a/p2p/transport/webrtc/transport_test.go b/p2p/transport/webrtc/transport_test.go
index 19d39ba2..7f4df94f 100644
--- a/p2p/transport/webrtc/transport_test.go
+++ b/p2p/transport/webrtc/transport_test.go
@@ -402,10 +402,16 @@ func TestTransportWebRTC_Deadline(t *testing.T) {
 		stream, err := conn.OpenStream(context.Background())
 		require.NoError(t, err)
 
-		stream.SetWriteDeadline(time.Now().Add(200 * time.Millisecond))
+		stream.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
 		largeBuffer := make([]byte, 2*1024*1024)
 		_, err = stream.Write(largeBuffer)
 		require.ErrorIs(t, err, os.ErrDeadlineExceeded)
+
+		stream.SetWriteDeadline(time.Now().Add(-200 * time.Millisecond))
+		smallBuffer := make([]byte, 1024)
+		_, err = stream.Write(smallBuffer)
+		require.ErrorIs(t, err, os.ErrDeadlineExceeded)
+
 	})
 }
Repository: PyCQA/pyflakes
Pull request #80 (2016-09-08 01:16:56)

Fix format string checking
format strings (PEP 498) defines a new AST node, JOINEDSTR which
contains a list of string expressions.

jgarst: Hi - it looks like format strings in 3.6 now define two new AST nodes, FORMATTEDVALUE and JOINEDSTR, which causes pylint to crash in getNodeHandler with 
```AttributeError: 'Checker' object has no attribute 'JOINEDSTR'```

Having pylint pass and handle JOINEDSTR children is something of a guess - my hope is that if there are more conditions that can be checked, you will have a better idea of what those are than I do.

Let me know if you need anything else.


Patch:
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index f08ba3f..caa9db5 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -937,7 +937,7 @@ class Checker(object):
         MATMULT = ignore
 
     # additional node types
-    COMPREHENSION = KEYWORD = FORMATTEDVALUE = handleChildren
+    COMPREHENSION = KEYWORD = FORMATTEDVALUE = JOINEDSTR = handleChildren
 
     def DICT(self, node):
         # Complain if there are duplicate keys with different values


Test patch:
diff --git a/pyflakes/test/test_other.py b/pyflakes/test/test_other.py
index 90b980b..109bc66 100644
--- a/pyflakes/test/test_other.py
+++ b/pyflakes/test/test_other.py
@@ -1800,3 +1800,11 @@ class TestAsyncStatements(TestCase):
         def foo(a, b):
             return a @ b
         ''')
+
+    @skipIf(version_info < (3, 6), 'new in Python 3.6')
+    def test_formatstring(self):
+        self.flakes('''
+        hi = 'hi'
+        mom = 'mom'
+        f'{hi} {mom}'
+        ''')
Repository: PyCQA/pyflakes
Pull request #86 (2017-01-14 01:42:21)

Don't test against file perms when running as root
test_permissionDenied tests file modes by creating a temporary file, then sets the mode to 0000 and attempts to process it and see if and permission denied error is generated.  This never happens when the unit tests are run as root since it can open files regardless of file permissions.

sigmavirus24: Closing and reopening to generate a new merged commit for AppVeyor to test.
sigmavirus24: @cfs-pure I pushed updates to your branch. We're just waiting for AppVeyor to recover from their temporary outage.

Patch:
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index 3e8dc8d..382574e 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -1337,19 +1337,12 @@ class Checker(object):
                 pass
 
     def ANNASSIGN(self, node):
-        """
-        Annotated assignments don't have annotations evaluated on function
-        scope, hence the custom implementation.
-
-        See: PEP 526.
-        """
         if node.value:
             # Only bind the *targets* if the assignment has a value.
             # Otherwise it's not really ast.Store and shouldn't silence
             # UndefinedLocal warnings.
             self.handleNode(node.target, node)
-        if not isinstance(self.scope, FunctionScope):
-            self.handleNode(node.annotation, node)
+        self.handleNode(node.annotation, node)
         if node.value:
             # If the assignment has value, handle the *value* now.
             self.handleNode(node.value, node)


Test patch:
diff --git a/pyflakes/test/test_api.py b/pyflakes/test/test_api.py
index 77ee33c..51b0027 100644
--- a/pyflakes/test/test_api.py
+++ b/pyflakes/test/test_api.py
@@ -518,6 +518,9 @@ foo = '\\xyz'
         If the source file is not readable, this is reported on standard
         error.
         """
+        if os.getuid() == 0:
+            self.skipTest('root user can access all files regardless of '
+                          'permissions')
         sourcePath = self.makeTempFile('')
         os.chmod(sourcePath, 0)
         count, errors = self.getErrors(sourcePath)
diff --git a/pyflakes/test/test_other.py b/pyflakes/test/test_other.py
index 6f02001..9c8462e 100644
--- a/pyflakes/test/test_other.py
+++ b/pyflakes/test/test_other.py
@@ -1839,13 +1839,18 @@ class TestAsyncStatements(TestCase):
             name: str = 'Bob'
             age: int = 18
             foo: not_a_real_type = None
-        ''', m.UnusedVariable, m.UnusedVariable, m.UnusedVariable)
+        ''', m.UnusedVariable, m.UnusedVariable, m.UnusedVariable, m.UndefinedName)
         self.flakes('''
         def f():
             name: str
             print(name)
         ''', m.UndefinedName)
         self.flakes('''
+        from typing import Any
+        def f():
+            a: Any
+        ''')
+        self.flakes('''
         foo: not_a_real_type
         ''', m.UndefinedName)
         self.flakes('''
Repository: PyCQA/pyflakes
Pull request #88 (2017-01-15 18:27:15)

Process function scope variable annotations
Even though variable annotations in function scope aren't evaluated at
runtime it's still useful for static analysis tools to process them and
catch some issues (and not report some things that aren't issues).

Let's take the following code:

```python
     from typing import Any

     def fun():
          a: Any
```

Previously pyflakes would report Any to be unused:

```
     test.py:1: 'typing.Any' imported but unused
```

With this patch it's no longer the case.

jstasiak: I'm not sure about those CI tasks being stuck for hours now but as far as I know the CI suite passes with this change.
sigmavirus24: @jstasiak AppVeyor is suffering from an outage at the moment. That said, the tests still need to pass there for this to be accepted.
jstasiak: All the tests passed, let me know if there are any modifications I need to make here.

Patch:
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index 3e8dc8d..382574e 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -1337,19 +1337,12 @@ class Checker(object):
                 pass
 
     def ANNASSIGN(self, node):
-        """
-        Annotated assignments don't have annotations evaluated on function
-        scope, hence the custom implementation.
-
-        See: PEP 526.
-        """
         if node.value:
             # Only bind the *targets* if the assignment has a value.
             # Otherwise it's not really ast.Store and shouldn't silence
             # UndefinedLocal warnings.
             self.handleNode(node.target, node)
-        if not isinstance(self.scope, FunctionScope):
-            self.handleNode(node.annotation, node)
+        self.handleNode(node.annotation, node)
         if node.value:
             # If the assignment has value, handle the *value* now.
             self.handleNode(node.value, node)


Test patch:
diff --git a/pyflakes/test/test_other.py b/pyflakes/test/test_other.py
index 6f02001..9c8462e 100644
--- a/pyflakes/test/test_other.py
+++ b/pyflakes/test/test_other.py
@@ -1839,13 +1839,18 @@ class TestAsyncStatements(TestCase):
             name: str = 'Bob'
             age: int = 18
             foo: not_a_real_type = None
-        ''', m.UnusedVariable, m.UnusedVariable, m.UnusedVariable)
+        ''', m.UnusedVariable, m.UnusedVariable, m.UnusedVariable, m.UndefinedName)
         self.flakes('''
         def f():
             name: str
             print(name)
         ''', m.UndefinedName)
         self.flakes('''
+        from typing import Any
+        def f():
+            a: Any
+        ''')
+        self.flakes('''
         foo: not_a_real_type
         ''', m.UndefinedName)
         self.flakes('''
Repository: PyCQA/pyflakes
Pull request #277 (2017-06-03 01:53:03)

Detect `pythonw` in shebang
This addresses https://github.com/PyCQA/pyflakes/issues/149#issuecomment-305881232 by @asmeurer.

https://docs.python.org/3/using/mac.html?highlight=pythonw#running-scripts-with-a-gui

asmeurer: Awesome, thanks. 
asmeurer: I tested it and it works

Patch:
diff --git a/pyflakes/api.py b/pyflakes/api.py
index e30f920..49ee38d 100644
--- a/pyflakes/api.py
+++ b/pyflakes/api.py
@@ -14,7 +14,7 @@ from pyflakes import reporter as modReporter
 __all__ = ['check', 'checkPath', 'checkRecursive', 'iterSourceCode', 'main']
 
 
-PYTHON_SHEBANG_REGEX = re.compile(br'^#!.*\bpython[23]?\b\s*$')
+PYTHON_SHEBANG_REGEX = re.compile(br'^#!.*\bpython[23w]?\b\s*$')
 
 
 def check(codeString, filename, reporter=None):


Test patch:
diff --git a/pyflakes/test/test_api.py b/pyflakes/test/test_api.py
index a1e0be2..3f54ca4 100644
--- a/pyflakes/test/test_api.py
+++ b/pyflakes/test/test_api.py
@@ -192,16 +192,30 @@ class TestIterSourceCode(TestCase):
         Find Python files that don't end with `.py`, but contain a Python
         shebang.
         """
-        apath = os.path.join(self.tempdir, 'a')
-        fd = open(apath, 'w')
-        fd.write('#!/usr/bin/env python\n')
-        fd.close()
+        python = os.path.join(self.tempdir, 'a')
+        with open(python, 'w') as fd:
+            fd.write('#!/usr/bin/env python\n')
 
         self.makeEmptyFile('b')
 
+        with open(os.path.join(self.tempdir, 'c'), 'w') as fd:
+            fd.write('hello\nworld\n')
+
+        python2 = os.path.join(self.tempdir, 'd')
+        with open(python2, 'w') as fd:
+            fd.write('#!/usr/bin/env python2\n')
+
+        python3 = os.path.join(self.tempdir, 'e')
+        with open(python3, 'w') as fd:
+            fd.write('#!/usr/bin/env python3\n')
+
+        pythonw = os.path.join(self.tempdir, 'f')
+        with open(pythonw, 'w') as fd:
+            fd.write('#!/usr/bin/env pythonw\n')
+
         self.assertEqual(
-            list(iterSourceCode([self.tempdir])),
-            list([apath]))
+            sorted(iterSourceCode([self.tempdir])),
+            sorted([python, python2, python3, pythonw]))
 
     def test_multipleDirectories(self):
         """
Repository: PyCQA/pyflakes
Pull request #384 (2018-11-01 09:55:55)

Mark SubmoduleImportation imported with Importation with alias as used
If the name of SubmoduleImportation is same with the alias of other Importation
and it is used, the SubmoduleImportation should be marked as used, too.

Fixes https://github.com/PyCQA/pyflakes/issues/298


Patch:
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index ad25b5e..756b77e 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -818,6 +818,16 @@ class Checker(object):
 
             try:
                 scope[name].used = (self.scope, node)
+
+                # if the name of SubImportation is same as
+                # alias of other Importation and the alias
+                # is used, SubImportation also should be marked as used.
+                n = scope[name]
+                if isinstance(n, Importation) and n._has_alias():
+                    try:
+                        scope[n.fullName].used = (self.scope, node)
+                    except KeyError:
+                        pass
             except KeyError:
                 pass
             else:


Test patch:
diff --git a/pyflakes/test/test_imports.py b/pyflakes/test/test_imports.py
index f83e77e..4272186 100644
--- a/pyflakes/test/test_imports.py
+++ b/pyflakes/test/test_imports.py
@@ -887,6 +887,22 @@ class Test(TestCase):
         fu.x
         ''')
 
+    def test_used_package_with_submodule_import_of_alias(self):
+        """
+        Usage of package by alias marks submodule imports as used.
+        """
+        self.flakes('''
+        import foo as f
+        import foo.bar
+        f.bar.do_something()
+        ''')
+
+        self.flakes('''
+        import foo as f
+        import foo.bar.blah
+        f.bar.blah.do_something()
+        ''')
+
     def test_unused_package_with_submodule_import(self):
         """
         When a package and its submodule are imported, only report once.
Repository: PyCQA/pyflakes
Pull request #385 (2018-11-03 00:15:53)

checker.py: Report undefined names in __all__
This allows pyflakes to report undefined names
in `__all__` when `import *` is used, without having
to use pyflakes 2 times to detect the errors.

Fixes https://github.com/PyCQA/pyflakes/issues/280

asmeurer: This change seems odd. The names sin and cos *are* defined by the `import *`, so the error message is effectively wrong. 

Patch:
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index 756b77e..9937685 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -665,9 +665,16 @@ class Checker(object):
 
                 # mark all import '*' as used by the undefined in __all__
                 if scope.importStarred:
+                    from_list = []
                     for binding in scope.values():
                         if isinstance(binding, StarImportation):
                             binding.used = all_binding
+                            from_list.append(binding.fullName)
+                    # report * usage, with a list of possible sources
+                    from_list = ', '.join(sorted(from_list))
+                    for name in undefined:
+                        self.report(messages.ImportStarUsage,
+                                    scope['__all__'].source, name, from_list)
 
             # Look for imported names that aren't used.
             for value in scope.values():


Test patch:
diff --git a/pyflakes/test/test_imports.py b/pyflakes/test/test_imports.py
index 4272186..193f9d3 100644
--- a/pyflakes/test/test_imports.py
+++ b/pyflakes/test/test_imports.py
@@ -1110,12 +1110,13 @@ class TestSpecialAll(TestCase):
 
     def test_importStarExported(self):
         """
-        Do not report undefined if import * is used
+        Report undefined if import * is used
         """
         self.flakes('''
-        from foolib import *
-        __all__ = ["foo"]
-        ''', m.ImportStarUsed)
+        from math import *
+        __all__ = ['sin', 'cos']
+        csc(1)
+        ''', m.ImportStarUsed, m.ImportStarUsage, m.ImportStarUsage, m.ImportStarUsage)
 
     def test_importStarNotExported(self):
         """Report unused import when not needed to satisfy __all__."""