From 6a993c5df41290f2bad64c69446e8fa86a819f6b Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sat, 24 Oct 2020 14:05:03 -0700 Subject: [PATCH 1/7] Make --namespace-packages the default Unfortunately, a number of tests fail. Please help fixing them :-) Especially the ones to do with cache inconsistencies... There's at least one known bug here: #7276 --- mypy/main.py | 2 +- mypy/options.py | 2 +- test-data/unit/check-modules.test | 5 +++-- test-data/unit/fine-grained-modules.test | 2 +- test-data/unit/semanal-errors.test | 7 ++++--- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/mypy/main.py b/mypy/main.py index 763bd9e95638..e99d1ec483ec 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -446,7 +446,7 @@ def add_invertible_flag(flag: str, title='Import discovery', description="Configure how imports are discovered and followed.") add_invertible_flag( - '--namespace-packages', default=False, + '--no-namespace-packages', dest="namespace_packages", default=True, help="Support namespace packages (PEP 420, __init__.py-less)", group=imports_group) imports_group.add_argument( diff --git a/mypy/options.py b/mypy/options.py index 901b90f28f53..0b148853295e 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -87,7 +87,7 @@ def __init__(self) -> None: # Intended to be used for disabling specific stubs. self.follow_imports_for_stubs = False # PEP 420 namespace packages - self.namespace_packages = False + self.namespace_packages = True # disallow_any options self.disallow_any_generics = False diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 140a0c017bfd..4a16b31934e2 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -2617,12 +2617,13 @@ from foo.bar import x x = 0 [case testClassicNotPackage] +# flags: --no-namespace-packages from foo.bar import x [file foo/bar.py] x = 0 [out] -main:1: error: Cannot find implementation or library stub for module named 'foo.bar' -main:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports +main:2: error: Cannot find implementation or library stub for module named 'foo.bar' +main:2: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports [case testNamespacePackage] # flags: --namespace-packages diff --git a/test-data/unit/fine-grained-modules.test b/test-data/unit/fine-grained-modules.test index 6fb947eb511a..5c829f77c566 100644 --- a/test-data/unit/fine-grained-modules.test +++ b/test-data/unit/fine-grained-modules.test @@ -845,7 +845,7 @@ main:2: error: Argument 1 to "f" has incompatible type "int"; expected "str" == main:1: error: Cannot find implementation or library stub for module named 'p.a' main:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports -main:1: error: Cannot find implementation or library stub for module named 'p' +main:2: error: "object" has no attribute "a" [case testDeletePackage2] import p diff --git a/test-data/unit/semanal-errors.test b/test-data/unit/semanal-errors.test index 7933341b9079..9fa125466750 100644 --- a/test-data/unit/semanal-errors.test +++ b/test-data/unit/semanal-errors.test @@ -316,15 +316,16 @@ x = y tmp/k.py:2: error: Name 'y' is not defined [case testPackageWithoutInitFile] +# flags: --no-namespace-packages import typing import m.n m.n.x [file m/n.py] x = 1 [out] -main:2: error: Cannot find implementation or library stub for module named 'm.n' -main:2: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports -main:2: error: Cannot find implementation or library stub for module named 'm' +main:3: error: Cannot find implementation or library stub for module named 'm.n' +main:3: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports +main:3: error: Cannot find implementation or library stub for module named 'm' [case testBreakOutsideLoop] break From 088990d7cfdf25088a12adb9250aa5ce32cffd7d Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Wed, 11 Nov 2020 23:53:00 -0800 Subject: [PATCH 2/7] allow cache metadata to point to directory --- mypy/build.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mypy/build.py b/mypy/build.py index d70b421c380b..8d88d5b29ea9 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -1303,8 +1303,10 @@ def validate_meta(meta: Optional[CacheMeta], id: str, path: Optional[str], st = manager.get_stat(path) except OSError: return None - if not stat.S_ISREG(st.st_mode): - manager.log('Metadata abandoned for {}: file {} does not exist'.format(id, path)) + if not stat.S_ISDIR(st.st_mode) and not stat.S_ISREG(st.st_mode): + manager.log( + 'Metadata abandoned for {}: file or directory {} does not exist'.format(id, path) + ) return None manager.add_stats(validate_stat_time=time.time() - t0) From 1f2891bf974aaf696defb0a8a79fe4d2b244e5ae Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Fri, 6 Aug 2021 17:03:44 -0700 Subject: [PATCH 3/7] add exclude rule --- mypy_self_check.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy_self_check.ini b/mypy_self_check.ini index 0139deff863b..8fbdf9b96500 100644 --- a/mypy_self_check.ini +++ b/mypy_self_check.ini @@ -19,4 +19,4 @@ pretty = True always_false = MYPYC plugins = misc/proper_plugin.py python_version = 3.6 -exclude = mypy/typeshed/ +exclude = mypy/typeshed/|mypyc/test-data/|mypyc/lib-rt/ From 9d06c8b63643ea499d0a9a02989c3e22c79a9dc3 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 3 Oct 2021 23:04:44 -0700 Subject: [PATCH 4/7] doc link --- test-data/unit/fine-grained-modules.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/fine-grained-modules.test b/test-data/unit/fine-grained-modules.test index 08884be1109f..2383f7ce83cf 100644 --- a/test-data/unit/fine-grained-modules.test +++ b/test-data/unit/fine-grained-modules.test @@ -844,7 +844,7 @@ def f(x: str) -> None: pass main:2: error: Argument 1 to "f" has incompatible type "int"; expected "str" == main:1: error: Cannot find implementation or library stub for module named "p.a" -main:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports +main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports main:2: error: "object" has no attribute "a" [case testDeletePackage2] From cb8f2aa02c83d3c13905cc32320fb95c7e205170 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Tue, 8 Feb 2022 21:33:57 -0800 Subject: [PATCH 5/7] update docs --- docs/source/command_line.rst | 32 +++++++++++++------------------- docs/source/config_file.rst | 7 ++++--- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index a729ac2baca0..b55eebc162b6 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -129,30 +129,12 @@ Import discovery The following flags customize how exactly mypy discovers and follows imports. -.. option:: --namespace-packages - - This flag enables import discovery to use namespace packages (see - :pep:`420`). In particular, this allows discovery of imported - packages that don't have an ``__init__.py`` (or ``__init__.pyi``) - file. - - Namespace packages are found (using the PEP 420 rules, which - prefers "classic" packages over namespace packages) along the - module search path -- this is primarily set from the source files - passed on the command line, the ``MYPYPATH`` environment variable, - and the :confval:`mypy_path` config option. - - This flag affects how mypy finds modules and packages explicitly passed on - the command line. It also affects how mypy determines fully qualified module - names for files passed on the command line. See :ref:`Mapping file paths to - modules ` for details. - .. option:: --explicit-package-bases This flag tells mypy that top-level packages will be based in either the current directory, or a member of the ``MYPYPATH`` environment variable or :confval:`mypy_path` config option. This option is only useful in - conjunction with :option:`--namespace-packages`. See :ref:`Mapping file + in the absence of `__init__.py`. See :ref:`Mapping file paths to modules ` for details. .. option:: --ignore-missing-imports @@ -213,6 +195,18 @@ imports. compliant packages. Adding this flag will disable this behavior. +.. option:: --no-namespace-packages + + This flag disables import discovery of namespace packages (see :pep:`420`). + In particular, this prevents discovery of packages that don't have an + ``__init__.py`` (or ``__init__.pyi``) file. + + This flag affects how mypy finds modules and packages explicitly passed on + the command line. It also affects how mypy determines fully qualified module + names for files passed on the command line. See :ref:`Mapping file paths to + modules ` for details. + + .. _platform-configuration: Platform configuration diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index c34f23d9e169..f8774812f0d8 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -217,10 +217,11 @@ section of the command line docs. .. confval:: namespace_packages :type: boolean - :default: False + :default: True Enables :pep:`420` style namespace packages. See the - corresponding flag :option:`--namespace-packages ` for more information. + corresponding flag :option:`--no-namespace-packages ` + for more information. This option may only be set in the global section (``[mypy]``). @@ -232,7 +233,7 @@ section of the command line docs. This flag tells mypy that top-level packages will be based in either the current directory, or a member of the ``MYPYPATH`` environment variable or :confval:`mypy_path` config option. This option is only useful in - conjunction with :confval:`namespace_packages`. See :ref:`Mapping file + the absence of `__init__.py`. See :ref:`Mapping file paths to modules ` for details. This option may only be set in the global section (``[mypy]``). From aabae70ac42da845aa415adf09d4329da09e7722 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Tue, 8 Feb 2022 21:53:57 -0800 Subject: [PATCH 6/7] more docs --- docs/source/running_mypy.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/source/running_mypy.rst b/docs/source/running_mypy.rst index d1c701e27e5a..364b89d69055 100644 --- a/docs/source/running_mypy.rst +++ b/docs/source/running_mypy.rst @@ -26,10 +26,6 @@ Specifying code to be checked Mypy lets you specify what files it should type check in several different ways. -Note that if you use namespace packages (in particular, packages without -``__init__.py``), you'll need to specify :option:`--namespace-packages `. - 1. First, you can pass in paths to Python files and directories you want to type check. For example:: From e781ae719ca6b8d4e4c884967a430ca11602adb6 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Tue, 8 Feb 2022 22:17:12 -0800 Subject: [PATCH 7/7] more docs --- docs/source/running_mypy.rst | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/docs/source/running_mypy.rst b/docs/source/running_mypy.rst index 364b89d69055..852ec2a63cf0 100644 --- a/docs/source/running_mypy.rst +++ b/docs/source/running_mypy.rst @@ -310,11 +310,6 @@ this error, try: you must run ``mypy ~/foo-project/src`` (or set the ``MYPYPATH`` to ``~/foo-project/src``. -4. If you are using namespace packages -- packages which do not contain - ``__init__.py`` files within each subfolder -- using the - :option:`--namespace-packages ` command - line flag. - In some rare cases, you may get the "Cannot find implementation or library stub for module" error even when the module is installed in your system. This can happen when the module is both missing type hints and is installed @@ -411,10 +406,10 @@ to modules to type check. added to mypy's module search paths. How mypy determines fully qualified module names depends on if the options -:option:`--namespace-packages ` and +:option:`--no-namespace-packages ` and :option:`--explicit-package-bases ` are set. -1. If :option:`--namespace-packages ` is off, +1. If :option:`--no-namespace-packages ` is set, mypy will rely solely upon the presence of ``__init__.py[i]`` files to determine the fully qualified module name. That is, mypy will crawl up the directory tree for as long as it continues to find ``__init__.py`` (or @@ -424,12 +419,13 @@ How mypy determines fully qualified module names depends on if the options would require ``pkg/__init__.py`` and ``pkg/subpkg/__init__.py`` to exist in order correctly associate ``mod.py`` with ``pkg.subpkg.mod`` -2. If :option:`--namespace-packages ` is on, but - :option:`--explicit-package-bases ` is off, - mypy will allow for the possibility that directories without - ``__init__.py[i]`` are packages. Specifically, mypy will look at all parent - directories of the file and use the location of the highest - ``__init__.py[i]`` in the directory tree to determine the top-level package. +2. The default case. If :option:`--namespace-packages ` is on, but :option:`--explicit-package-bases ` is off, mypy will allow for the possibility that + directories without ``__init__.py[i]`` are packages. Specifically, mypy will + look at all parent directories of the file and use the location of the + highest ``__init__.py[i]`` in the directory tree to determine the top-level + package. For example, say your directory tree consists solely of ``pkg/__init__.py`` and ``pkg/a/b/c/d/mod.py``. When determining ``mod.py``'s fully qualified