##// END OF EJS Templates
pytype: stop excluding mercurial/ui.py...
pytype: stop excluding mercurial/ui.py ui.extractchoices() is perhaps making assumptions that it shouldn't about the pattern always matching, but presumably we have test coverage for that. PyCharm flags the updated classes with a warning "Class xxx must implement all abstract methods", and suggests adding `abc.ABC` to the superclasses. I'm not sure why, unless it doesn't recognize the `__getattr__()` delegation pattern. Additionally, we can't unconditionally subclass `typing.BinaryIO` because that defeats the `__getattr__` delegation to the wrapped object at runtime. Instead, it has to only subclass during the type checking phase[1]. In any event, this fixes: File "/mnt/c/Users/Matt/hg/mercurial/ui.py", line 1518, in _runpager: Function subprocess.Popen.__new__ was called with the wrong arguments [wrong-arg-types] Expected: (cls, args, bufsize, executable, stdin, stdout: Optional[Union[IO, int]] = ..., ...) Actually passed: (cls, args, bufsize, stdin, stdout: Union[mercurial.utils.procutil.WriteAllWrapper, mercurial.windows.winstdout], ...) File "/mnt/c/Users/Matt/hg/mercurial/ui.py", line 1798, in extractchoices: No attribute 'group' on None [attribute-error] In Optional[Match[bytes]] File "/mnt/c/Users/Matt/hg/mercurial/ui.py", line 1799, in extractchoices: No attribute 'group' on None [attribute-error] In Optional[Match[bytes]] [1] https://stackoverflow.com/q/71365594

File last commit:

r50669:48e38b17 stable
r50688:8147abc0 default
Show More
demandimportpy3.py
176 lines | 5.2 KiB | text/x-python | PythonLexer
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 # demandimportpy3 - global demand-loading of modules for Mercurial
#
# Copyright 2017 Facebook Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""Lazy loading for Python 3.6 and above.
This uses the new importlib finder/loader functionality available in Python 3.5
and up. The code reuses most of the mechanics implemented inside importlib.util,
but with a few additions:
* Allow excluding certain modules from lazy imports.
* Expose an interface that's substantially the same as demandimport for
Python 2.
This also has some limitations compared to the Python 2 implementation:
* Much of the logic is per-package, not per-module, so any packages loaded
before demandimport is enabled will not be lazily imported in the future. In
practice, we only expect builtins to be loaded before demandimport is
enabled.
"""
import contextlib
import importlib.util
Augie Fackler
demandimportpy3: update to pass import checker
r33899 import sys
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
Augie Fackler
demandimport: add tracing coverage for Python 3...
r42674 from . import tracing
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 _deactivated = False
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 class _lazyloaderex(importlib.util.LazyLoader):
"""This is a LazyLoader except it also follows the _deactivated global and
the ignore list.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 def exec_module(self, module):
"""Make the module load lazily."""
Augie Fackler
demandimport: add tracing coverage for Python 3...
r42674 with tracing.log('demandimport %s', module):
if _deactivated or module.__name__ in ignores:
Jason R. Coombs
demandimport: ensure lazyloaderex sets loader attributes (issue6725)...
r50483 # Reset the loader on the module as super() does (issue6725)
module.__spec__.loader = self.loader
module.__loader__ = self.loader
Augie Fackler
demandimport: add tracing coverage for Python 3...
r42674 self.loader.exec_module(module)
else:
super().exec_module(module)
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class LazyFinder:
Gregory Szorc
hgdemandimport: apply lazy module loading to sys.meta_path finders...
r44577 """A wrapper around a ``MetaPathFinder`` that makes loaders lazy.
``sys.meta_path`` finders have their ``find_spec()`` called to locate a
module. This returns a ``ModuleSpec`` if found or ``None``. The
``ModuleSpec`` has a ``loader`` attribute, which is called to actually
load a module.
Our class wraps an existing finder and overloads its ``find_spec()`` to
replace the ``loader`` with our lazy loader proxy.
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
Gregory Szorc
hgdemandimport: apply lazy module loading to sys.meta_path finders...
r44577 We have to use __getattribute__ to proxy the instance because some meta
path finders don't support monkeypatching.
"""
__slots__ = ("_finder",)
def __init__(self, finder):
object.__setattr__(self, "_finder", finder)
def __repr__(self):
return "<LazyFinder for %r>" % object.__getattribute__(self, "_finder")
# __bool__ is canonical Python 3. But check-code insists on __nonzero__ being
# defined via `def`.
def __nonzero__(self):
return bool(object.__getattribute__(self, "_finder"))
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
hgdemandimport: apply lazy module loading to sys.meta_path finders...
r44577 __bool__ = __nonzero__
def __getattribute__(self, name):
if name in ("_finder", "find_spec"):
return object.__getattribute__(self, name)
return getattr(object.__getattribute__(self, "_finder"), name)
def __delattr__(self, name):
return delattr(object.__getattribute__(self, "_finder"))
def __setattr__(self, name, value):
return setattr(object.__getattribute__(self, "_finder"), name, value)
Manuel Jacob
demandimport: fix compatibility with meta path finders w/o find_spec() method...
r45337 def find_spec(self, fullname, path, target=None):
Gregory Szorc
hgdemandimport: apply lazy module loading to sys.meta_path finders...
r44577 finder = object.__getattribute__(self, "_finder")
Manuel Jacob
demandimport: fix compatibility with meta path finders w/o find_spec() method...
r45337 try:
find_spec = finder.find_spec
except AttributeError:
loader = finder.find_module(fullname, path)
if loader is None:
spec = None
else:
spec = importlib.util.spec_from_loader(fullname, loader)
else:
spec = find_spec(fullname, path, target)
Gregory Szorc
hgdemandimport: apply lazy module loading to sys.meta_path finders...
r44577
# Lazy loader requires exec_module().
if (
spec is not None
and spec.loader is not None
Matt Harbison
demandimport: don't raise AttributeError if `exec_module` is missing...
r46347 and getattr(spec.loader, "exec_module", None)
Gregory Szorc
hgdemandimport: apply lazy module loading to sys.meta_path finders...
r44577 ):
spec.loader = _lazyloaderex(spec.loader)
return spec
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
demandimport: make module ignores a set (API)...
r37862 ignores = set()
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
demandimport: make module ignores a set (API)...
r37862 def init(ignoreset):
global ignores
ignores = ignoreset
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 def isenabled():
Gregory Szorc
hgdemandimport: apply lazy module loading to sys.meta_path finders...
r44577 return not _deactivated and any(
isinstance(finder, LazyFinder) for finder in sys.meta_path
)
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 def disable():
Gregory Szorc
hgdemandimport: apply lazy module loading to sys.meta_path finders...
r44577 new_finders = []
for finder in sys.meta_path:
new_finders.append(
finder._finder if isinstance(finder, LazyFinder) else finder
)
sys.meta_path[:] = new_finders
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 def enable():
Gregory Szorc
hgdemandimport: apply lazy module loading to sys.meta_path finders...
r44577 new_finders = []
for finder in sys.meta_path:
new_finders.append(
LazyFinder(finder) if not isinstance(finder, LazyFinder) else finder
)
sys.meta_path[:] = new_finders
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 @contextlib.contextmanager
def deactivated():
# This implementation is a bit different from Python 2's. Python 3
# maintains a per-package finder cache in sys.path_importer_cache (see
# PEP 302). This means that we can't just call disable + enable.
# If we do that, in situations like:
#
# demandimport.enable()
# ...
# from foo.bar import mod1
# with demandimport.deactivated():
# from foo.bar import mod2
#
# mod2 will be imported lazily. (The converse also holds -- whatever finder
# first gets cached will be used.)
#
# Instead, have a global flag the LazyLoader can use.
global _deactivated
demandenabled = isenabled()
if demandenabled:
_deactivated = True
try:
yield
finally:
if demandenabled:
_deactivated = False