Skip to content

Commit

Permalink
Switch from pkg_resources to importlib.metadata (#2155)
Browse files Browse the repository at this point in the history
* Switch from pkg_resources to importlib.metadata

importlib.metadata is a standard library replacement for
pkg_resources, available starting with Python 3.8. It is faster than
pkg_resources. This lets the plugin interface use it when available,
i.e. on Python 3.8 and later. On earlier Python, it uses the
importlib_metadata PyPI backport if available, and finally falls back
on pkg_resources. setup.cfg gains an extra called plugins, which can
allow a project to install "pygments[plugins]" in order to ensure that
plugins support is present even if installed with older Python
versions.

Timings for lexing an empty file with a lexer from a random plugin:

Before:

real	0m0,238s
user	0m0,210s
sys	0m0,029s

After:

real	0m0,141s
user	0m0,125s
sys	0m0,017s

Fixes #2116, #2126
  • Loading branch information
jeanas committed Jun 4, 2022
1 parent f46b708 commit 362c967
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 13 deletions.
39 changes: 34 additions & 5 deletions doc/docs/plugins.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
================
Register Plugins
================
=======
Plugins
=======

If you want to extend Pygments without hacking the sources, but want to
use the lexer/formatter/style/filter lookup functions (`lexers.get_lexer_by_name`
Expand All @@ -13,8 +13,37 @@ That means you can use your highlighter modules with the `pygmentize` script,
which relies on the mentioned functions.


Entrypoints
===========
Plugin discovery
================

At runtime, discovering plugins is preferentially done using Python's
standard library module `importlib.metadata`_, available in Python 3.8
and higher. In earlier Python versions, Pygments attempts to use the
`importlib_metadata`_ backport, if available. If not available, a
fallback is attempted on the older `pkg_resources`_ module. Finally, if
``pkg_resources`` is not available, no plugins will be loaded at
all. Note that ``pkg_resources`` is distributed with `setuptools`_, and
thus available on most Python environments. However, ``pkg_resources``
is considerably slower than ``importlib.metadata`` or its
``importlib_metadata`` backport. For this reason, if you run Pygments
under Python older than 3.8, it is recommended to install
``importlib-metadata``. Pygments defines a ``plugins`` packaging extra,
so you can ensure it is installed with best plugin support (i.e., that
``importlib-metadata`` is also installed in case you are running Python
earlier than 3.8) by specifying ``pygments[plugins]`` as the
requirement, for example, with ``pip``:

.. sourcecode:: shell

$ python -m pip install --user pygments[plugins]

.. _importlib.metadata: https://docs.python.org/3.10/library/importlib.metadata.html
.. _importlib_metadata: https://pypi.org/project/importlib-metadata
.. _pkg_resources: https://setuptools.pypa.io/en/latest/pkg_resources.html


Defining plugins through entrypoints
====================================

Here is a list of setuptools entrypoints that Pygments understands:

Expand Down
35 changes: 27 additions & 8 deletions pygments/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
pygments.plugin
~~~~~~~~~~~~~~~
Pygments setuptools plugin interface. The methods defined
here also work if setuptools isn't installed but they just
return nothing.
Pygments plugin interface. By default, this tries to use
``importlib.metadata``, which is in the Python standard
library since Python 3.8, or its ``importlib_metadata``
backport for earlier versions of Python. It falls back on
``pkg_resources`` if not found. Finally, if ``pkg_resources``
is not found either, no plugins are loaded at all.
lexer plugins::
Expand Down Expand Up @@ -34,6 +37,7 @@
:copyright: Copyright 2006-2022 by the Pygments team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

LEXER_ENTRY_POINT = 'pygments.lexers'
FORMATTER_ENTRY_POINT = 'pygments.formatters'
STYLE_ENTRY_POINT = 'pygments.styles'
Expand All @@ -42,11 +46,26 @@

def iter_entry_points(group_name):
try:
import pkg_resources
except (ImportError, OSError):
return []

return pkg_resources.iter_entry_points(group_name)
from importlib.metadata import entry_points
except ImportError:
try:
from importlib_metadata import entry_points
except ImportError:
try:
from pkg_resources import iter_entry_points
except (ImportError, OSError):
return []
else:
return iter_entry_points(group_name)
groups = entry_points()
if hasattr(groups, 'select'):
# New interface in Python 3.10 and newer versions of the
# importlib_metadata backport.
return groups.select(group=group_name)
else:
# Older interface, deprecated in Python 3.10 and recent
# importlib_metadata, but we need it in Python 3.8 and 3.9.
return groups.get(group_name, [])


def find_plugin_lexers():
Expand Down
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ include =
console_scripts =
pygmentize = pygments.cmdline:main

[options.extras_require]
plugins =
importlib-metadata;python_version<'3.8'

[aliases]
release = egg_info -Db ''
upload = upload --sign --identity=36580288

0 comments on commit 362c967

Please sign in to comment.