We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
mypy fails with *-stubs is not a valid Python package name
According to PEP 561 [stub-only package](https://www.python.org/dev/peps/pep-0561/#stub-only-packages):

> The name of the stub package MUST follow the scheme foopkg-stubs for type stubs for the package named foopkg. 

However if we invoke mypy on such package providing only path it fails with 

>  *-stubs is not a valid Python package name

This can be reproduced on the [example package](https://github.com/ethanhs/stub-package):

```
git clone https://github.com/ethanhs/stub-package
cd stub-package
mypy ./typedpkg-stubs
typedpkg-stubs is not a valid Python package name
```

Invoking `mypy` with `-p` option works

```
mypy -p typedpkg-stubs
Success: no issues found in 2 source files
```

but the former behavior is rather confusing.

Expected behavior:

- mypy should recognize `*-stubs` paths as roots of stub-only packages.


Tested with:

- mypy 0.761
- mypy-0.770+dev.9101707bd0c96624d09cb31fe573d7e25c89a35c



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mypy/find_sources.py`
Content:
```
1 """Routines for finding the sources that mypy will check"""
2 
3 import os.path
4 
5 from typing import List, Sequence, Set, Tuple, Optional, Dict
6 from typing_extensions import Final
7 
8 from mypy.modulefinder import BuildSource, PYTHON_EXTENSIONS
9 from mypy.fscache import FileSystemCache
10 from mypy.options import Options
11 
12 PY_EXTENSIONS = tuple(PYTHON_EXTENSIONS)  # type: Final
13 
14 
15 class InvalidSourceList(Exception):
16     """Exception indicating a problem in the list of sources given to mypy."""
17 
18 
19 def create_source_list(files: Sequence[str], options: Options,
20                        fscache: Optional[FileSystemCache] = None,
21                        allow_empty_dir: bool = False) -> List[BuildSource]:
22     """From a list of source files/directories, makes a list of BuildSources.
23 
24     Raises InvalidSourceList on errors.
25     """
26     fscache = fscache or FileSystemCache()
27     finder = SourceFinder(fscache)
28 
29     targets = []
30     for f in files:
31         if f.endswith(PY_EXTENSIONS):
32             # Can raise InvalidSourceList if a directory doesn't have a valid module name.
33             name, base_dir = finder.crawl_up(os.path.normpath(f))
34             targets.append(BuildSource(f, name, None, base_dir))
35         elif fscache.isdir(f):
36             sub_targets = finder.expand_dir(os.path.normpath(f))
37             if not sub_targets and not allow_empty_dir:
38                 raise InvalidSourceList("There are no .py[i] files in directory '{}'"
39                                         .format(f))
40             targets.extend(sub_targets)
41         else:
42             mod = os.path.basename(f) if options.scripts_are_modules else None
43             targets.append(BuildSource(f, mod, None))
44     return targets
45 
46 
47 def keyfunc(name: str) -> Tuple[int, str]:
48     """Determines sort order for directory listing.
49 
50     The desirable property is foo < foo.pyi < foo.py.
51     """
52     base, suffix = os.path.splitext(name)
53     for i, ext in enumerate(PY_EXTENSIONS):
54         if suffix == ext:
55             return (i, base)
56     return (-1, name)
57 
58 
59 class SourceFinder:
60     def __init__(self, fscache: FileSystemCache) -> None:
61         self.fscache = fscache
62         # A cache for package names, mapping from directory path to module id and base dir
63         self.package_cache = {}  # type: Dict[str, Tuple[str, str]]
64 
65     def expand_dir(self, arg: str, mod_prefix: str = '') -> List[BuildSource]:
66         """Convert a directory name to a list of sources to build."""
67         f = self.get_init_file(arg)
68         if mod_prefix and not f:
69             return []
70         seen = set()  # type: Set[str]
71         sources = []
72         top_mod, base_dir = self.crawl_up_dir(arg)
73         if f and not mod_prefix:
74             mod_prefix = top_mod + '.'
75         if mod_prefix:
76             sources.append(BuildSource(f, mod_prefix.rstrip('.'), None, base_dir))
77         names = self.fscache.listdir(arg)
78         names.sort(key=keyfunc)
79         for name in names:
80             # Skip certain names altogether
81             if (name == '__pycache__' or name == 'py.typed'
82                     or name.startswith('.')
83                     or name.endswith(('~', '.pyc', '.pyo'))):
84                 continue
85             path = os.path.join(arg, name)
86             if self.fscache.isdir(path):
87                 sub_sources = self.expand_dir(path, mod_prefix + name + '.')
88                 if sub_sources:
89                     seen.add(name)
90                     sources.extend(sub_sources)
91             else:
92                 base, suffix = os.path.splitext(name)
93                 if base == '__init__':
94                     continue
95                 if base not in seen and '.' not in base and suffix in PY_EXTENSIONS:
96                     seen.add(base)
97                     src = BuildSource(path, mod_prefix + base, None, base_dir)
98                     sources.append(src)
99         return sources
100 
101     def crawl_up(self, arg: str) -> Tuple[str, str]:
102         """Given a .py[i] filename, return module and base directory
103 
104         We crawl up the path until we find a directory without
105         __init__.py[i], or until we run out of path components.
106         """
107         dir, mod = os.path.split(arg)
108         mod = strip_py(mod) or mod
109         base, base_dir = self.crawl_up_dir(dir)
110         if mod == '__init__' or not mod:
111             mod = base
112         else:
113             mod = module_join(base, mod)
114 
115         return mod, base_dir
116 
117     def crawl_up_dir(self, dir: str) -> Tuple[str, str]:
118         """Given a directory name, return the corresponding module name and base directory
119 
120         Use package_cache to cache results.
121         """
122         if dir in self.package_cache:
123             return self.package_cache[dir]
124 
125         parent_dir, base = os.path.split(dir)
126         if not dir or not self.get_init_file(dir) or not base:
127             res = ''
128             base_dir = dir or '.'
129         else:
130             # Ensure that base is a valid python module name
131             if not base.isidentifier():
132                 raise InvalidSourceList('{} is not a valid Python package name'.format(base))
133             parent, base_dir = self.crawl_up_dir(parent_dir)
134             res = module_join(parent, base)
135 
136         self.package_cache[dir] = res, base_dir
137         return res, base_dir
138 
139     def get_init_file(self, dir: str) -> Optional[str]:
140         """Check whether a directory contains a file named __init__.py[i].
141 
142         If so, return the file's name (with dir prefixed).  If not, return
143         None.
144 
145         This prefers .pyi over .py (because of the ordering of PY_EXTENSIONS).
146         """
147         for ext in PY_EXTENSIONS:
148             f = os.path.join(dir, '__init__' + ext)
149             if self.fscache.isfile(f):
150                 return f
151             if ext == '.py' and self.fscache.init_under_package_root(f):
152                 return f
153         return None
154 
155 
156 def module_join(parent: str, child: str) -> str:
157     """Join module ids, accounting for a possibly empty parent."""
158     if parent:
159         return parent + '.' + child
160     else:
161         return child
162 
163 
164 def strip_py(arg: str) -> Optional[str]:
165     """Strip a trailing .py or .pyi suffix.
166 
167     Return None if no such suffix is found.
168     """
169     for ext in PY_EXTENSIONS:
170         if arg.endswith(ext):
171             return arg[:-len(ext)]
172     return None
173
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mypy/find_sources.py b/mypy/find_sources.py
--- a/mypy/find_sources.py
+++ b/mypy/find_sources.py
@@ -128,6 +128,8 @@
             base_dir = dir or '.'
         else:
             # Ensure that base is a valid python module name
+            if base.endswith('-stubs'):
+                base = base[:-6]  # PEP-561 stub-only directory
             if not base.isidentifier():
                 raise InvalidSourceList('{} is not a valid Python package name'.format(base))
             parent, base_dir = self.crawl_up_dir(parent_dir)

{"golden_diff": "diff --git a/mypy/find_sources.py b/mypy/find_sources.py\n--- a/mypy/find_sources.py\n+++ b/mypy/find_sources.py\n@@ -128,6 +128,8 @@\n             base_dir = dir or '.'\n         else:\n             # Ensure that base is a valid python module name\n+            if base.endswith('-stubs'):\n+                base = base[:-6]  # PEP-561 stub-only directory\n             if not base.isidentifier():\n                 raise InvalidSourceList('{} is not a valid Python package name'.format(base))\n             parent, base_dir = self.crawl_up_dir(parent_dir)\n", "issue": "mypy fails with *-stubs is not a valid Python package name\nAccording to PEP 561 [stub-only package](https://www.python.org/dev/peps/pep-0561/#stub-only-packages):\r\n\r\n> The name of the stub package MUST follow the scheme foopkg-stubs for type stubs for the package named foopkg. \r\n\r\nHowever if we invoke mypy on such package providing only path it fails with \r\n\r\n>  *-stubs is not a valid Python package name\r\n\r\nThis can be reproduced on the [example package](https://github.com/ethanhs/stub-package):\r\n\r\n```\r\ngit clone https://github.com/ethanhs/stub-package\r\ncd stub-package\r\nmypy ./typedpkg-stubs\r\ntypedpkg-stubs is not a valid Python package name\r\n```\r\n\r\nInvoking `mypy` with `-p` option works\r\n\r\n```\r\nmypy -p typedpkg-stubs\r\nSuccess: no issues found in 2 source files\r\n```\r\n\r\nbut the former behavior is rather confusing.\r\n\r\nExpected behavior:\r\n\r\n- mypy should recognize `*-stubs` paths as roots of stub-only packages.\r\n\r\n\r\nTested with:\r\n\r\n- mypy 0.761\r\n- mypy-0.770+dev.9101707bd0c96624d09cb31fe573d7e25c89a35c\r\n\r\n\n", "before_files": [{"content": "\"\"\"Routines for finding the sources that mypy will check\"\"\"\n\nimport os.path\n\nfrom typing import List, Sequence, Set, Tuple, Optional, Dict\nfrom typing_extensions import Final\n\nfrom mypy.modulefinder import BuildSource, PYTHON_EXTENSIONS\nfrom mypy.fscache import FileSystemCache\nfrom mypy.options import Options\n\nPY_EXTENSIONS = tuple(PYTHON_EXTENSIONS)  # type: Final\n\n\nclass InvalidSourceList(Exception):\n    \"\"\"Exception indicating a problem in the list of sources given to mypy.\"\"\"\n\n\ndef create_source_list(files: Sequence[str], options: Options,\n                       fscache: Optional[FileSystemCache] = None,\n                       allow_empty_dir: bool = False) -> List[BuildSource]:\n    \"\"\"From a list of source files/directories, makes a list of BuildSources.\n\n    Raises InvalidSourceList on errors.\n    \"\"\"\n    fscache = fscache or FileSystemCache()\n    finder = SourceFinder(fscache)\n\n    targets = []\n    for f in files:\n        if f.endswith(PY_EXTENSIONS):\n            # Can raise InvalidSourceList if a directory doesn't have a valid module name.\n            name, base_dir = finder.crawl_up(os.path.normpath(f))\n            targets.append(BuildSource(f, name, None, base_dir))\n        elif fscache.isdir(f):\n            sub_targets = finder.expand_dir(os.path.normpath(f))\n            if not sub_targets and not allow_empty_dir:\n                raise InvalidSourceList(\"There are no .py[i] files in directory '{}'\"\n                                        .format(f))\n            targets.extend(sub_targets)\n        else:\n            mod = os.path.basename(f) if options.scripts_are_modules else None\n            targets.append(BuildSource(f, mod, None))\n    return targets\n\n\ndef keyfunc(name: str) -> Tuple[int, str]:\n    \"\"\"Determines sort order for directory listing.\n\n    The desirable property is foo < foo.pyi < foo.py.\n    \"\"\"\n    base, suffix = os.path.splitext(name)\n    for i, ext in enumerate(PY_EXTENSIONS):\n        if suffix == ext:\n            return (i, base)\n    return (-1, name)\n\n\nclass SourceFinder:\n    def __init__(self, fscache: FileSystemCache) -> None:\n        self.fscache = fscache\n        # A cache for package names, mapping from directory path to module id and base dir\n        self.package_cache = {}  # type: Dict[str, Tuple[str, str]]\n\n    def expand_dir(self, arg: str, mod_prefix: str = '') -> List[BuildSource]:\n        \"\"\"Convert a directory name to a list of sources to build.\"\"\"\n        f = self.get_init_file(arg)\n        if mod_prefix and not f:\n            return []\n        seen = set()  # type: Set[str]\n        sources = []\n        top_mod, base_dir = self.crawl_up_dir(arg)\n        if f and not mod_prefix:\n            mod_prefix = top_mod + '.'\n        if mod_prefix:\n            sources.append(BuildSource(f, mod_prefix.rstrip('.'), None, base_dir))\n        names = self.fscache.listdir(arg)\n        names.sort(key=keyfunc)\n        for name in names:\n            # Skip certain names altogether\n            if (name == '__pycache__' or name == 'py.typed'\n                    or name.startswith('.')\n                    or name.endswith(('~', '.pyc', '.pyo'))):\n                continue\n            path = os.path.join(arg, name)\n            if self.fscache.isdir(path):\n                sub_sources = self.expand_dir(path, mod_prefix + name + '.')\n                if sub_sources:\n                    seen.add(name)\n                    sources.extend(sub_sources)\n            else:\n                base, suffix = os.path.splitext(name)\n                if base == '__init__':\n                    continue\n                if base not in seen and '.' not in base and suffix in PY_EXTENSIONS:\n                    seen.add(base)\n                    src = BuildSource(path, mod_prefix + base, None, base_dir)\n                    sources.append(src)\n        return sources\n\n    def crawl_up(self, arg: str) -> Tuple[str, str]:\n        \"\"\"Given a .py[i] filename, return module and base directory\n\n        We crawl up the path until we find a directory without\n        __init__.py[i], or until we run out of path components.\n        \"\"\"\n        dir, mod = os.path.split(arg)\n        mod = strip_py(mod) or mod\n        base, base_dir = self.crawl_up_dir(dir)\n        if mod == '__init__' or not mod:\n            mod = base\n        else:\n            mod = module_join(base, mod)\n\n        return mod, base_dir\n\n    def crawl_up_dir(self, dir: str) -> Tuple[str, str]:\n        \"\"\"Given a directory name, return the corresponding module name and base directory\n\n        Use package_cache to cache results.\n        \"\"\"\n        if dir in self.package_cache:\n            return self.package_cache[dir]\n\n        parent_dir, base = os.path.split(dir)\n        if not dir or not self.get_init_file(dir) or not base:\n            res = ''\n            base_dir = dir or '.'\n        else:\n            # Ensure that base is a valid python module name\n            if not base.isidentifier():\n                raise InvalidSourceList('{} is not a valid Python package name'.format(base))\n            parent, base_dir = self.crawl_up_dir(parent_dir)\n            res = module_join(parent, base)\n\n        self.package_cache[dir] = res, base_dir\n        return res, base_dir\n\n    def get_init_file(self, dir: str) -> Optional[str]:\n        \"\"\"Check whether a directory contains a file named __init__.py[i].\n\n        If so, return the file's name (with dir prefixed).  If not, return\n        None.\n\n        This prefers .pyi over .py (because of the ordering of PY_EXTENSIONS).\n        \"\"\"\n        for ext in PY_EXTENSIONS:\n            f = os.path.join(dir, '__init__' + ext)\n            if self.fscache.isfile(f):\n                return f\n            if ext == '.py' and self.fscache.init_under_package_root(f):\n                return f\n        return None\n\n\ndef module_join(parent: str, child: str) -> str:\n    \"\"\"Join module ids, accounting for a possibly empty parent.\"\"\"\n    if parent:\n        return parent + '.' + child\n    else:\n        return child\n\n\ndef strip_py(arg: str) -> Optional[str]:\n    \"\"\"Strip a trailing .py or .pyi suffix.\n\n    Return None if no such suffix is found.\n    \"\"\"\n    for ext in PY_EXTENSIONS:\n        if arg.endswith(ext):\n            return arg[:-len(ext)]\n    return None\n", "path": "mypy/find_sources.py"}], "after_files": [{"content": "\"\"\"Routines for finding the sources that mypy will check\"\"\"\n\nimport os.path\n\nfrom typing import List, Sequence, Set, Tuple, Optional, Dict\nfrom typing_extensions import Final\n\nfrom mypy.modulefinder import BuildSource, PYTHON_EXTENSIONS\nfrom mypy.fscache import FileSystemCache\nfrom mypy.options import Options\n\nPY_EXTENSIONS = tuple(PYTHON_EXTENSIONS)  # type: Final\n\n\nclass InvalidSourceList(Exception):\n    \"\"\"Exception indicating a problem in the list of sources given to mypy.\"\"\"\n\n\ndef create_source_list(files: Sequence[str], options: Options,\n                       fscache: Optional[FileSystemCache] = None,\n                       allow_empty_dir: bool = False) -> List[BuildSource]:\n    \"\"\"From a list of source files/directories, makes a list of BuildSources.\n\n    Raises InvalidSourceList on errors.\n    \"\"\"\n    fscache = fscache or FileSystemCache()\n    finder = SourceFinder(fscache)\n\n    targets = []\n    for f in files:\n        if f.endswith(PY_EXTENSIONS):\n            # Can raise InvalidSourceList if a directory doesn't have a valid module name.\n            name, base_dir = finder.crawl_up(os.path.normpath(f))\n            targets.append(BuildSource(f, name, None, base_dir))\n        elif fscache.isdir(f):\n            sub_targets = finder.expand_dir(os.path.normpath(f))\n            if not sub_targets and not allow_empty_dir:\n                raise InvalidSourceList(\"There are no .py[i] files in directory '{}'\"\n                                        .format(f))\n            targets.extend(sub_targets)\n        else:\n            mod = os.path.basename(f) if options.scripts_are_modules else None\n            targets.append(BuildSource(f, mod, None))\n    return targets\n\n\ndef keyfunc(name: str) -> Tuple[int, str]:\n    \"\"\"Determines sort order for directory listing.\n\n    The desirable property is foo < foo.pyi < foo.py.\n    \"\"\"\n    base, suffix = os.path.splitext(name)\n    for i, ext in enumerate(PY_EXTENSIONS):\n        if suffix == ext:\n            return (i, base)\n    return (-1, name)\n\n\nclass SourceFinder:\n    def __init__(self, fscache: FileSystemCache) -> None:\n        self.fscache = fscache\n        # A cache for package names, mapping from directory path to module id and base dir\n        self.package_cache = {}  # type: Dict[str, Tuple[str, str]]\n\n    def expand_dir(self, arg: str, mod_prefix: str = '') -> List[BuildSource]:\n        \"\"\"Convert a directory name to a list of sources to build.\"\"\"\n        f = self.get_init_file(arg)\n        if mod_prefix and not f:\n            return []\n        seen = set()  # type: Set[str]\n        sources = []\n        top_mod, base_dir = self.crawl_up_dir(arg)\n        if f and not mod_prefix:\n            mod_prefix = top_mod + '.'\n        if mod_prefix:\n            sources.append(BuildSource(f, mod_prefix.rstrip('.'), None, base_dir))\n        names = self.fscache.listdir(arg)\n        names.sort(key=keyfunc)\n        for name in names:\n            # Skip certain names altogether\n            if (name == '__pycache__' or name == 'py.typed'\n                    or name.startswith('.')\n                    or name.endswith(('~', '.pyc', '.pyo'))):\n                continue\n            path = os.path.join(arg, name)\n            if self.fscache.isdir(path):\n                sub_sources = self.expand_dir(path, mod_prefix + name + '.')\n                if sub_sources:\n                    seen.add(name)\n                    sources.extend(sub_sources)\n            else:\n                base, suffix = os.path.splitext(name)\n                if base == '__init__':\n                    continue\n                if base not in seen and '.' not in base and suffix in PY_EXTENSIONS:\n                    seen.add(base)\n                    src = BuildSource(path, mod_prefix + base, None, base_dir)\n                    sources.append(src)\n        return sources\n\n    def crawl_up(self, arg: str) -> Tuple[str, str]:\n        \"\"\"Given a .py[i] filename, return module and base directory\n\n        We crawl up the path until we find a directory without\n        __init__.py[i], or until we run out of path components.\n        \"\"\"\n        dir, mod = os.path.split(arg)\n        mod = strip_py(mod) or mod\n        base, base_dir = self.crawl_up_dir(dir)\n        if mod == '__init__' or not mod:\n            mod = base\n        else:\n            mod = module_join(base, mod)\n\n        return mod, base_dir\n\n    def crawl_up_dir(self, dir: str) -> Tuple[str, str]:\n        \"\"\"Given a directory name, return the corresponding module name and base directory\n\n        Use package_cache to cache results.\n        \"\"\"\n        if dir in self.package_cache:\n            return self.package_cache[dir]\n\n        parent_dir, base = os.path.split(dir)\n        if not dir or not self.get_init_file(dir) or not base:\n            res = ''\n            base_dir = dir or '.'\n        else:\n            # Ensure that base is a valid python module name\n            if base.endswith('-stubs'):\n                base = base[:-6]  # PEP-561 stub-only directory\n            if not base.isidentifier():\n                raise InvalidSourceList('{} is not a valid Python package name'.format(base))\n            parent, base_dir = self.crawl_up_dir(parent_dir)\n            res = module_join(parent, base)\n\n        self.package_cache[dir] = res, base_dir\n        return res, base_dir\n\n    def get_init_file(self, dir: str) -> Optional[str]:\n        \"\"\"Check whether a directory contains a file named __init__.py[i].\n\n        If so, return the file's name (with dir prefixed).  If not, return\n        None.\n\n        This prefers .pyi over .py (because of the ordering of PY_EXTENSIONS).\n        \"\"\"\n        for ext in PY_EXTENSIONS:\n            f = os.path.join(dir, '__init__' + ext)\n            if self.fscache.isfile(f):\n                return f\n            if ext == '.py' and self.fscache.init_under_package_root(f):\n                return f\n        return None\n\n\ndef module_join(parent: str, child: str) -> str:\n    \"\"\"Join module ids, accounting for a possibly empty parent.\"\"\"\n    if parent:\n        return parent + '.' + child\n    else:\n        return child\n\n\ndef strip_py(arg: str) -> Optional[str]:\n    \"\"\"Strip a trailing .py or .pyi suffix.\n\n    Return None if no such suffix is found.\n    \"\"\"\n    for ext in PY_EXTENSIONS:\n        if arg.endswith(ext):\n            return arg[:-len(ext)]\n    return None\n", "path": "mypy/find_sources.py"}]}