Skip to content

Commit 0cf7515

Browse files
committed
Add --pep561-override option to force packages as typed even they don't have a py.typed file
1 parent b2edab2 commit 0cf7515

File tree

4 files changed

+26
-7
lines changed

4 files changed

+26
-7
lines changed

mypy/config_parser.py

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ def split_and_match_files(paths: str) -> List[str]:
8585
'package_root': lambda s: [p.strip() for p in s.split(',')],
8686
'cache_dir': expand_path,
8787
'python_executable': expand_path,
88+
'pep561_override': lambda s: [p.strip() for p in s.split(',')],
8889
} # type: Final
8990

9091

mypy/main.py

+4
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,10 @@ def add_invertible_flag(flag: str,
467467
imports_group.add_argument(
468468
'--no-silence-site-packages', action='store_true',
469469
help="Do not silence errors in PEP 561 compliant installed packages")
470+
imports_group.add_argument(
471+
'--pep561-override', action='append', default=[],
472+
help="Consider the given package typed even if it does not claim to be "
473+
"PEP 561 compatible (may be repeated)")
470474

471475
platform_group = parser.add_argument_group(
472476
title='Platform configuration',

mypy/modulefinder.py

+19-7
Original file line numberDiff line numberDiff line change
@@ -168,19 +168,31 @@ def find_module(self, id: str) -> ModuleSearchResult:
168168

169169
def _find_module_non_stub_helper(self, components: List[str],
170170
pkg_dir: str) -> Union[OnePackageDir, ModuleNotFoundReason]:
171-
plausible_match = False
171+
plausible_match = None # type: Optional[Tuple[str, OnePackageDir]]
172+
plausible_match_is_ns = False
172173
dir_path = pkg_dir
173174
for index, component in enumerate(components):
174175
dir_path = os.path.join(dir_path, component)
175176
if self.fscache.isfile(os.path.join(dir_path, 'py.typed')):
176177
return os.path.join(pkg_dir, *components[:-1]), index == 0
177-
elif not plausible_match and (self.fscache.isdir(dir_path)
178-
or self.fscache.isfile(dir_path + ".py")):
179-
plausible_match = True
180-
if plausible_match:
181-
return ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS
182-
else:
178+
if not plausible_match or plausible_match_is_ns:
179+
have_package_or_mod = self.fscache.isfile(os.path.join(dir_path, '__init__.py')) \
180+
or self.fscache.isfile(dir_path + ".py")
181+
if not have_package_or_mod:
182+
have_ns_package = self.fscache.isdir(dir_path)
183+
184+
if have_package_or_mod or (not plausible_match_is_ns and have_ns_package):
185+
plausible_match = (
186+
'.'.join(components[:(index + 1)]),
187+
(os.path.join(pkg_dir, *components[:-1]), index == 0)
188+
)
189+
plausible_match_is_ns = not have_package_or_mod
190+
if not plausible_match:
183191
return ModuleNotFoundReason.NOT_FOUND
192+
elif self.options and plausible_match[0] in self.options.pep561_override:
193+
return plausible_match[1]
194+
else:
195+
return ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS
184196

185197
def _update_ns_ancestors(self, components: List[str], match: Tuple[str, bool]) -> None:
186198
path, verify = match

mypy/options.py

+2
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ def __init__(self) -> None:
267267
self.transform_source = None # type: Optional[Callable[[Any], Any]]
268268
# Print full path to each file in the report.
269269
self.show_absolute_path = False # type: bool
270+
# Consider packages typed even if they do not declare PEP-561 compatiblity
271+
self.pep561_override = [] # type: List[str]
270272

271273
# To avoid breaking plugin compatibility, keep providing new_semantic_analyzer
272274
@property

0 commit comments

Comments
 (0)