Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP faster baseline import #445

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 0 additions & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
repos:
- repo: https://github.com/PyCQA/autoflake
rev: v2.2.1
hooks:
- id: autoflake
name: autoflake
args: ["--in-place", "--remove-unused-variables", "--remove-all-unused-imports"]
language: python
files: \.py$
- repo: https://github.com/asottile/reorder-python-imports
rev: v3.11.0
hooks:
Expand Down
2 changes: 0 additions & 2 deletions src/pluggy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,5 @@
HookimplMarker,
HookCaller,
HookRelay,
HookspecOpts,
HookimplOpts,
HookImpl,
)
35 changes: 20 additions & 15 deletions src/pluggy/_callers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,30 @@
"""
from __future__ import annotations

from typing import cast
from typing import Generator
from typing import Mapping
from typing import Sequence
from typing import Tuple
from typing import Union

from ._hooks import HookImpl
from ._result import _raise_wrapfail
from ._result import HookCallError
from ._result import Result

TYPE_CHECKING = False
if TYPE_CHECKING:
from typing import cast
from typing import Generator
from typing import Mapping
from typing import Sequence

Check warning on line 16 in src/pluggy/_callers.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_callers.py#L13-L16

Added lines #L13 - L16 were not covered by tests
from typing import Tuple
from typing import Union

# Need to distinguish between old- and new-style hook wrappers.
# Wrapping one a singleton tuple is the fastest type-safe way I found to do it.

Check warning on line 21 in src/pluggy/_callers.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_callers.py#L21

Added line #L21 was not covered by tests
Teardown = Union[
Tuple[Generator[None, Result[object], None]],
Generator[None, object, object],
]
else:

# Need to distinguish between old- and new-style hook wrappers.
# Wrapping one a singleton tuple is the fastest type-safe way I found to do it.
Teardown = Union[
Tuple[Generator[None, Result[object], None]],
Generator[None, object, object],
]
def cast(t, v):
return v


def _multicall(
Expand Down Expand Up @@ -58,7 +63,7 @@
# If this cast is not valid, a type error is raised below,
# which is the desired response.
res = hook_impl.function(*args)
wrapper_gen = cast(Generator[None, Result[object], None], res)
wrapper_gen = cast("Generator[None, Result[object], None]", res)
next(wrapper_gen) # first yield
teardowns.append((wrapper_gen,))
except StopIteration:
Expand All @@ -68,7 +73,7 @@
# If this cast is not valid, a type error is raised below,
# which is the desired response.
res = hook_impl.function(*args)
function_gen = cast(Generator[None, object, object], res)
function_gen = cast("Generator[None, object, object]", res)
next(function_gen) # first yield
teardowns.append(function_gen)
except StopIteration:
Expand Down
137 changes: 72 additions & 65 deletions src/pluggy/_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,79 @@
"""
from __future__ import annotations

import inspect
import sys
import warnings
from types import ModuleType
from typing import AbstractSet
from typing import Any
from typing import Callable
from typing import Final
from typing import final
from typing import Generator
from typing import List
from typing import Mapping
from typing import Optional
from typing import overload
from typing import Sequence
from typing import Tuple
from typing import TYPE_CHECKING
from typing import TypedDict
from typing import TypeVar
from typing import Union

from ._result import Result


_T = TypeVar("_T")
_F = TypeVar("_F", bound=Callable[..., object])
_Namespace = Union[ModuleType, type]

Check warning on line 8 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L8

Added line #L8 was not covered by tests
_Plugin = object
_HookExec = Callable[
[str, Sequence["HookImpl"], Mapping[str, object], bool],
Union[object, List[object]],
]
_HookImplFunction = Callable[..., Union[_T, Generator[None, Result[_T], None]]]


class HookspecOpts(TypedDict):
"""Options for a hook specification."""

#: Whether the hook is :ref:`first result only <firstresult>`.
firstresult: bool
#: Whether the hook is :ref:`historic <historic>`.
historic: bool
#: Whether the hook :ref:`warns when implemented <warn_on_impl>`.
warn_on_impl: Warning | None


class HookimplOpts(TypedDict):
"""Options for a hook implementation."""

#: Whether the hook implementation is a :ref:`wrapper <hookwrapper>`.
wrapper: bool
#: Whether the hook implementation is an :ref:`old-style wrapper
#: <old_style_hookwrappers>`.
hookwrapper: bool
#: Whether validation against a hook specification is :ref:`optional
#: <optionalhook>`.
optionalhook: bool
#: Whether to try to order this hook implementation :ref:`first
#: <callorder>`.
tryfirst: bool
#: Whether to try to order this hook implementation :ref:`last
#: <callorder>`.
trylast: bool
#: The name of the hook specification to match, see :ref:`specname`.
specname: str | None

Check warning on line 10 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L10

Added line #L10 was not covered by tests
TYPE_CHECKING = False
if TYPE_CHECKING:
from types import ModuleType
from typing import AbstractSet
from typing import Any
from typing import Callable
from typing import Final
from typing import final
from typing import Generator
from typing import List
from typing import Mapping
from typing import Optional
from typing import overload
from typing import Sequence
from typing import Tuple

Check warning on line 25 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L13-L25

Added lines #L13 - L25 were not covered by tests
from typing import TYPE_CHECKING
from typing import TypedDict

Check warning on line 27 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L27

Added line #L27 was not covered by tests
from typing import TypeVar
from typing import Union

from ._result import Result

_T = TypeVar("_T")
_F = TypeVar("_F", bound=Callable[..., object])

Check warning on line 34 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L30-L34

Added lines #L30 - L34 were not covered by tests
_Namespace = Union[ModuleType, type]
_HookExec = Callable[
[str, Sequence["HookImpl"], Mapping[str, object], bool],
Union[object, List[object]],

Check warning on line 38 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L38

Added line #L38 was not covered by tests
]
_HookImplFunction = Callable[..., Union[_T, Generator[None, Result[_T], None]]]
_CallHistory = List[Tuple[Mapping[str, object], Optional[Callable[[Any], None]]]]

Check warning on line 41 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L41

Added line #L41 was not covered by tests

class HookspecOpts(TypedDict):
"""Options for a hook specification."""

Check warning on line 45 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L45

Added line #L45 was not covered by tests
#: Whether the hook is :ref:`first result only <firstresult>`.
firstresult: bool

Check warning on line 47 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L47

Added line #L47 was not covered by tests
#: Whether the hook is :ref:`historic <historic>`.
historic: bool

Check warning on line 49 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L49

Added line #L49 was not covered by tests
#: Whether the hook :ref:`warns when implemented <warn_on_impl>`.
warn_on_impl: Warning | None

Check warning on line 52 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L52

Added line #L52 was not covered by tests
class HookimplOpts(TypedDict):
"""Options for a hook implementation."""

#: Whether the hook implementation is a :ref:`wrapper <hookwrapper>`.

Check warning on line 56 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L56

Added line #L56 was not covered by tests
wrapper: bool
#: Whether the hook implementation is an :ref:`old-style wrapper
#: <old_style_hookwrappers>`.

Check warning on line 59 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L59

Added line #L59 was not covered by tests
hookwrapper: bool
#: Whether validation against a hook specification is :ref:`optional
#: <optionalhook>`.

Check warning on line 62 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L62

Added line #L62 was not covered by tests
optionalhook: bool
#: Whether to try to order this hook implementation :ref:`first
#: <callorder>`.

Check warning on line 65 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L65

Added line #L65 was not covered by tests
tryfirst: bool
#: Whether to try to order this hook implementation :ref:`last
#: <callorder>`.

Check warning on line 68 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L68

Added line #L68 was not covered by tests
trylast: bool
#: The name of the hook specification to match, see :ref:`specname`.

Check warning on line 70 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L70

Added line #L70 was not covered by tests
specname: str | None

else:

Check warning on line 74 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L74

Added line #L74 was not covered by tests
def final(func: _F) -> _F:
return func

overload = final


@final
Expand Down Expand Up @@ -286,6 +294,8 @@
In case of a class, its ``__init__`` method is considered.
For methods the ``self`` parameter is not included.
"""
import inspect

Check warning on line 298 in src/pluggy/_hooks.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_hooks.py#L298

Added line #L298 was not covered by tests
if inspect.isclass(func):
try:
func = func.__init__
Expand Down Expand Up @@ -364,9 +374,6 @@
_HookRelay = HookRelay


_CallHistory = List[Tuple[Mapping[str, object], Optional[Callable[[Any], None]]]]


class HookCaller:
"""A caller of all registered implementations of a hook specification."""

Expand Down
68 changes: 68 additions & 0 deletions src/pluggy/_importlib_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""this module contains importlib_metadata usage and importing

it's deferred to avoid import-time dependency on importlib_metadata

.. code-block:: console

python -X importtime -c 'import pluggy' 2> import0.log
tuna import0.log


"""
from __future__ import annotations

import importlib.metadata
from typing import Any

from . import _manager


class DistFacade:
"""Emulate a pkg_resources Distribution"""

def __init__(self, dist: importlib.metadata.Distribution) -> None:
self._dist = dist

@property
def project_name(self) -> str:
name: str = self.metadata["name"]
return name

def __getattr__(self, attr: str, default: object | None = None) -> Any:
return getattr(self._dist, attr, default)

def __dir__(self) -> list[str]:
return sorted(dir(self._dist) + ["_dist", "project_name"])

Check warning on line 35 in src/pluggy/_importlib_metadata.py

View check run for this annotation

Codecov / codecov/patch

src/pluggy/_importlib_metadata.py#L35

Added line #L35 was not covered by tests


def load_importlib_entrypoints(
manager: _manager.PluginManager,
group: str,
name: str | None = None,
) -> int:
"""Load modules from querying the specified setuptools ``group``.

:param group:
Entry point group to load plugins.
:param name:
If given, loads only plugins with the given ``name``.

:return:
The number of plugins loaded by this call.
"""
count = 0
for dist in list(importlib.metadata.distributions()):
for ep in dist.entry_points:
if (
ep.group != group
or (name is not None and ep.name != name)
# already registered
or manager.get_plugin(ep.name)
or manager.is_blocked(ep.name)
):
continue
plugin = ep.load()
manager.register(plugin, name=ep.name)
manager._plugin_dist_metadata.append((plugin, dist))
count += 1
return count