Git Product home page Git Product logo

entrypoints's Introduction

This package is in maintenance-only mode. New code should use the importlib.metadata module in the Python standard library to find and load entry points.

Entry points are a way for Python packages to advertise objects with some common interface. The most common examples are console_scripts entry points, which define shell commands by identifying a Python function to run.

Groups of entry points, such as console_scripts, point to objects with similar interfaces. An application might use a group to find its plugins, or multiple groups if it has different kinds of plugins.

The entrypoints module contains functions to find and load entry points. You can install it from PyPI with pip install entrypoints.

To advertise entry points when distributing a package, see entry_points in the Python Packaging User Guide.

The pkg_resources module distributed with setuptools provides a way to discover entrypoints as well, but it contains other functionality unrelated to entrypoint discovery, and it does a lot of work at import time. Merely importing pkg_resources causes it to scan the files of all installed packages. Thus, in environments where a large number of packages are installed, importing pkg_resources can be very slow (several seconds).

By contrast, entrypoints is focused solely on entrypoint discovery and it is faster. Importing entrypoints does not scan anything, and getting a given entrypoint group performs a more focused scan.

When there are multiple versions of the same distribution in different directories on sys.path, entrypoints follows the rule that the first one wins. In most cases, this follows the logic of imports. Similarly, Entrypoints relies on pip to ensure that only one .dist-info or .egg-info directory exists for each installed package. There is no reliable way to pick which of several .dist-info folders accurately relates to the importable modules.

entrypoints's People

Contributors

adamchainz avatar danielballan avatar dergenaue avatar hugovk avatar janfreyberg avatar jdufresne avatar jwilk avatar lowell80 avatar mgorny avatar takluyver avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

entrypoints's Issues

No suitable distribution

Hi,

jupyter-1.0.0 metapackage has a dependency on entrypoints

Trying to install jupyter issue an error on entrypoints:

Searching for entrypoints
Reading https://pypi.python.org/simple/entrypoints/
No local packages or download links found for entrypoints
error: Could not find suitable distribution for Requirement.parse('entrypoints')

Forcing to the whl file does no better:

Processing entrypoints-0.2.2-py2.py3-none-any.whl
error: Couldn't find a setup script in /tmp/easy_install-psn0idx6/entrypoints-0.2.2-py2.py3-none-any.whl

Bests

Getting a `configparser.DuplicateOptionError` when calling nbconvert

I am seeing a similar problem as jupyter/nbconvert#298 but I am using the latest entrypoints 0.2.2. One can reproduce the error below by installing jupyter and compliance-checker together and then issuing: entrypoints.get_single('nbconvert.exporters', 'python').load()

Traceback (most recent call last):
  File "/home/travis/miniconda/envs/IOOS/bin/jupyter-nbconvert", line 4, in <module>
    from nbconvert.nbconvertapp import main
  File "/home/travis/miniconda/envs/IOOS/lib/python3.5/site-packages/nbconvert/nbconvertapp.py", line 99, in <module>
    class NbConvertApp(JupyterApp):
  File "/home/travis/miniconda/envs/IOOS/lib/python3.5/site-packages/nbconvert/nbconvertapp.py", line 179, in NbConvertApp
    """.format(get_export_names()))
  File "/home/travis/miniconda/envs/IOOS/lib/python3.5/site-packages/nbconvert/exporters/export.py", line 210, in get_export_names
    sorted(entrypoints.get_group_named('nbconvert.exporters'))
  File "/home/travis/miniconda/envs/IOOS/lib/python3.5/site-packages/entrypoints.py", line 191, in get_group_named
    for ep in get_group_all(group, path=path):
  File "/home/travis/miniconda/envs/IOOS/lib/python3.5/site-packages/entrypoints.py", line 202, in get_group_all
    for config, distro in iter_files_distros(path=path):
  File "/home/travis/miniconda/envs/IOOS/lib/python3.5/site-packages/entrypoints.py", line 168, in iter_files_distros
    cp.read(path)
  File "/home/travis/miniconda/envs/IOOS/lib/python3.5/configparser.py", line 696, in read
    self._read(fp, filename)
  File "/home/travis/miniconda/envs/IOOS/lib/python3.5/configparser.py", line 1089, in _read
    fpname, lineno)
configparser.DuplicateOptionError: While reading from '/home/travis/miniconda/envs/IOOS/lib/python3.5/site-packages/compliance_checker-2.2.0-py3.5.egg-info/entry_points.txt' [line  3]: option 'acdd' in section 'compliance_checker.suites' already exists

Not sure how to fix that...

xref: ioos/compliance-checker#300

Anchor link in README is dead

The documentation and README seems to largely outsource the discussion of how to actually use this library to the Python Packaging documentation using this link: https://packaging.python.org/en/latest/distributing.html#entry-points

The problem is that it seems that that page has changed, the anchor link is dead and Ctrl+F for "entry" gives nothing. Is there a new link where this information is kept? Might it be a good idea to mirror that in the documentation in some minor way?

I am not really sure how this project relates to the entry_points argument in setuptools.setup, I was hoping the link might clarify that.

Test failure with python2 and pytest 3.9.2

The test_bad test fails because apparently the pytest upgrade added some warning (didn't happen with older pytest versions, doesn't happen with python3):

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        bad_path = [osp.join(samples_dir, 'packages3')]

        with warnings.catch_warnings(record=True) as w:
            group = entrypoints.get_group_named('entrypoints.test1', bad_path)

        assert 'bad' not in group
>       assert len(w) == 1
E       assert 2 == 1
E        +  where 2 = len([<warnings.WarningMessage object at 0x7ffff17852d0>, <warnings.WarningMessage object at 0x7ffff1766f10>])

tests/test_entrypoints.py:70: AssertionError

entrypoints unavailable for python 3.6?

I fail to install ipywidgets with pip under python 3.6 on Xubuntu 16.04 with the following message:

Collecting entrypoints>=0.2.2 (from nbconvert->notebook>=4.4.1->widgetsnbextension~=2.0.0->ipywidgets)
  Could not find a version that satisfies the requirement entrypoints>=0.2.2 (from nbconvert->notebook>=4.4.1->widgetsnbextension~=2.0.0->ipywidgets) (from versions: )
No matching distribution found for entrypoints>=0.2.2 (from nbconvert->notebook>=4.4.1->widgetsnbextension~=2.0.0->ipywidgets)

If I try to install entrypoints alone:

$ pip3.6 install entrypoints
Collecting entrypoints
  Could not find a version that satisfies the requirement entrypoints (from versions: )
No matching distribution found for entrypoints

license clarification

Greetings!

Although the project includes license text (MIT) , the source files have no license headers. Can you please clarify the license for all the files?

This is in connection with including entrypoints in Fedora (this clarification request originally came up in Fedora package review) [1].

Thank you!

[1] https://bugzilla.redhat.com/show_bug.cgi?id=1379095

Publishing tar.gz to pypi

If it's not too much trouble, would you be able to publish a tar.gz to pypi? We have some old tooling which is having trouble with whls at the moment.

Cannot install from sources

This repository is missing a setup.py file. Unless I am missing something, this means that it cannot be installed from source.

Support loading of entrypoints from importable wheels

One use-case that the import ecosystem intends to support is importable wheels - wheels that much like zip eggs of the past can be added to sys.path and imported. Consider this environment:

draft $ python -m venv env
draft $ env/bin/pip install -q -U pip importlib_metadata
draft $ env/bin/pip download --no-deps keyring
Collecting keyring
  Using cached https://files.pythonhosted.org/packages/85/25/55798660a50bd2fd7a8ef58a4394fd4fbb474e6b87d55a8d3e49e300d2a4/keyring-16.0.0-py2.py3-none-any.whl
  Saved ./keyring-16.0.0-py2.py3-none-any.whl
draft $ env/bin/pip install entrypoints
Collecting entrypoints
  Using cached https://files.pythonhosted.org/packages/cc/8b/4eefa9b47f1910b3d2081da67726b066e379b04ca897acfe9f92bac56147/entrypoints-0.2.3-py2.py3-none-any.whl
Installing collected packages: entrypoints
Successfully installed entrypoints-0.2.3

keyring (which has entry points) is present as an importable wheel but isn't on sys.path (by default).

One can readily see that the entry points are visible using importlib_metadata.

draft $ env PYTHONPATH=./keyring-16.0.0-py2.py3-none-any.whl env/bin/python
Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import importlib_metadata
>>> list(importlib_metadata.entry_points('keyring')['keyring.backends'])
['kwallet', 'secretservice', 'windows', 'macos']

But with entrypoints, the metadata is missing even though keyring is importable:

draft $ env PYTHONPATH=./keyring-16.0.0-py2.py3-none-any.whl env/bin/python
Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import keyring
>>> import entrypoints
>>> entrypoints.get_group_all('keyring.backends')
[]

I suggest entrypoints should support loading of entrypoints from importable wheels in addition to eggs.

configparser dependency

Is there any good reason to actually pull a configparser backport dependency from PyPI on python == 2.7 rather than using the standard library? Could this dependency be eliminated in favor of ConfigParser?

Multiple versions of entry points

Should the entrypoint module handle multiple versions of a single package?

After upgrading a package, it seems that old .dist-info folders are hanging around. Now I'm experience this 2 places, (1) where I'm doing local development on a package (and the package version is updated after every commit: e.g,0.6.2.dev2+f0b8738.dirty meaning 2 revisions past the 0.6.2 tag, and that my local copy has changes). So this means more packages which exaggerates my issue a bit. And (2), I'm also seeing this when I'm doing some unusual package installation stuff pip install PKG -t INSTALL_DIR. So I fully understand why duplicate dist-info folders exist in that case.

What's unclear to me is what should be the normal behavior. I apologize for "packaging" question here, but the reason why I bring it up is that I do see different results between say:

list( pkg_resources.iter_entry_points("ksconf_cmd") )

and

entrypoints.get_group_all("ksconf_cmd")

Based on a quick test, pkg_resources seems to be pulling in the most recent version, where as entrypoints seems to be pulling in the older version. (I suppose there could also be a lexicographical sort or internal directory listing order factor in here too. Haven't dug that deep.)

So 2 questions:

1.) Is the assumption that pip (or whatever installer tool) is already taking are of duplicate .dist-info folders and only keeping the most recently installed one.
2.) If not, is there a way to get visibility into the multiple distributions using entrypoints?

source archive upload on pypi

Hello,

Could you please consider uploading sorce archive (i.e. *.tar.gz or *.zip) on pypi, so that "entrypoints" can be installed as an egg ? I am using buildout to install "ipython" that requires "nbconvert" and recent "nbconvert" requires "entrypoints".

Thanks in advance !

support egg links

We should detect egg links and discover egg-info at targets they point too ๐Ÿ‘

please keep providing source tarball on PyPI

Hello,
could you please consider keep providing (and also add to the current releases) source tarball on PyPI and not only wheels? there are some situation where it's preferable to download the tarball

thanks!

Caching entry point data

This issue is to discuss how best to cache entry points, and how to ensure that it's performant and accurate.

TypeError: argument of type 'instance' is not iterable

Not exactly sure where this is coming from, but with version 0.2 (installed with conda), I cannot run juypter nbconvert:

$ jupyter nbconvert
Traceback (most recent call last):
  File ".../bin/jupyter-nbconvert", line 3, in <module>
    from nbconvert.nbconvertapp import main
  File ".../lib/python2.7/site-packages/nbconvert/nbconvertapp.py", line 99, in <module>
    class NbConvertApp(JupyterApp):
  File ".../lib/python2.7/site-packages/nbconvert/nbconvertapp.py", line 179, in NbConvertApp
    """.format(get_export_names()))
  File ".../lib/python2.7/site-packages/nbconvert/exporters/export.py", line 210, in get_export_names
    sorted(entrypoints.get_group_named('nbconvert.exporters'))
  File "/data/apps/anaconda/envs/work/lib/python2.7/site-packages/entrypoints.py", line 183, in get_group_named
    for ep in get_group_all(group, path=path):
  File ".../lib/python2.7/site-packages/entrypoints.py", line 195, in get_group_all
    if group in config:
TypeError: argument of type 'instance' is not iterable

config is a <ConfigParser.ConfigParser instance at 0x10592a320>.

conda info gives:

nbconvert 4.2.0 py27_0
entrypoints 0.2 py27_0

Can't install with buildout

Trying to install another package (Jupyter) through buildout, but it fails at this package when installing dependencies.

Getting distribution for 'entrypoints'.
While:
  Installing all.
  Getting distribution for 'entrypoints'.
Error: Couldn't find a distribution for 'entrypoints'.

Same happens if you try to install entrypoints directly with buildout.

Not sure why it can't find the package, as it is registered on PyPi. Could it be due to his package not having a setup.py file?

Upload source archive to PyPI

Could you upload a source archive to PyPI? Right now there's only a .whl and this is a bit of a problem when trying to build nbconvert from source.

Add `setup.py`?

@takluyver

Since this package is now a dependency of nbconvert, would you mind adding conventional setupools installer (setup.py)? Even though it's a trivial package, some tools expect setup.py to exist (e.g. conda-build, tox and many others).

This is just a suggestion and would be up to you of course :)

Edit: I understand you're using your own pypi uploader/wrapper, this is a different question though.

iter_files_distros will fail if sys.path contains a PosixPath (AttributeError: 'PosixPath' object has no attribute 'rstrip')

iter_files_distros(path=None, repeated_distro='first') will fail if one of the elements in sys.path is not a string. For example, my sys.path contained a PosixPath:

['/usr/local/bin', '/usr/local/lib/python38.zip', '/usr/local/lib/python3.8', '/usr/local/lib/python3.8/lib-dynload', '/usr/local/lib/python3.8/site-packages', PosixPath('/model_infrastructure')]

PosixPath objects do not implement an rstrip() method, and so the following happens [permalink]:

if path is None:
    path = sys.path

# `path` is now a list containing some strings and in my accidental case, a PosixPath

for folder in path:
    if folder.rstrip('/\\').endswith('.egg'):

# oops

I'll defer to someone with far more Python experience than I have to decide whether this is just a silly user error (i.e. entirely my fault), or something that should be handled within iter_files_distros(...).

Maybe it seems absurd that anything other than a string would find its way into sys.path, but for newcomers to Python (i.e. me, since ~3.5) who have grown up with pathlib, it doesn't feel too out of place. In fact, here's a PR.


For search engines and passers-by:

I had encountered this stacktrace in my Django + Dagster + MLflow + Gensim + Docker project:

AttributeError: 'PosixPath' object has no attribute 'rstrip'
  File "/usr/local/lib/python3.8/site-packages/dagster/core/execution/plan/utils.py", line 42, in solid_execution_error_boundary
    yield
  File "/usr/local/lib/python3.8/site-packages/dagster/utils/__init__.py", line 382, in iterate_with_context
    next_output = next(iterator)
  File "/usr/local/lib/python3.8/site-packages/dagster/core/execution/plan/compute_generator.py", line 65, in _coerce_solid_compute_fn_to_iterator
    result = fn(context, **kwargs) if context_arg_provided else fn(**kwargs)
  File "/model_infrastructure/solids/gensim.py", line 160, in cyclic_word2vec
    experiment = mlflow.get_experiment_by_name(experiment_name)
  File "/usr/local/lib/python3.8/site-packages/mlflow/tracking/fluent.py", line 815, in get_experiment_by_name
    return MlflowClient().get_experiment_by_name(name)
  File "/usr/local/lib/python3.8/site-packages/mlflow/tracking/client.py", line 434, in get_experiment_by_name
    return self._tracking_client.get_experiment_by_name(name)
  File "/usr/local/lib/python3.8/site-packages/mlflow/tracking/_tracking_service/client.py", line 128, in get_experiment_by_name
    return self.store.get_experiment_by_name(name)
  File "/usr/local/lib/python3.8/site-packages/mlflow/store/tracking/rest_store.py", line 263, in get_experiment_by_name
    response_proto = self._call_endpoint(GetExperimentByName, req_body)
  File "/usr/local/lib/python3.8/site-packages/mlflow/store/tracking/rest_store.py", line 55, in _call_endpoint
    return call_endpoint(self.get_host_creds(), endpoint, method, json_body, response_proto)
  File "/usr/local/lib/python3.8/site-packages/mlflow/utils/rest_utils.py", line 163, in call_endpoint
    response = http_request(
  File "/usr/local/lib/python3.8/site-packages/mlflow/utils/rest_utils.py", line 47, in http_request
    from mlflow.tracking.request_header.registry import resolve_request_headers
  File "/usr/local/lib/python3.8/site-packages/mlflow/tracking/request_header/registry.py", line 39, in <module>
    _request_header_provider_registry.register_entrypoints()
  File "/usr/local/lib/python3.8/site-packages/mlflow/tracking/request_header/registry.py", line 21, in register_entrypoints
    for entrypoint in entrypoints.get_group_all("mlflow.request_header_provider"):
  File "/usr/local/lib/python3.8/site-packages/entrypoints.py", line 236, in get_group_all
    for config, distro in iter_files_distros(path=path):
  File "/usr/local/lib/python3.8/site-packages/entrypoints.py", line 128, in iter_files_distros
    if folder.rstrip('/\\').endswith('.egg'):

It took me a while to find the cause.

My BASE_DIR in Django's settings.py was a pathlib Path object:

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

For whatever reason, I had to append BASE_DIR to sys.path from within a Dagster solid:

sys.path.append(BASE_DIR)

This resulted in a PosixPath object being added to sys.path. As explained above, sys.path is expected presently to hold only strings, and so iter_files_distros(path=None) will just call rstrip(...) on each element without type consideration.

A solution is ensure that a string is appended to sys.path:

sys.path.append(str(BASE_DIR.absolute()))

Optparse conflict when invoking as module vs. via entry point

Migrating this, as recommended, from a downstream flake8 issue. As the issue disappears with the latest flake8 version from the master branch (which has migrated away from entrypoints), it was suggested that this might be an issue with entrypoints. I've provided the reproduction steps from the downstream issue below, please let me know if there's something entrypoint-specific that would be more helpful for your triage.

I've installed a custom flake8 plugin into a fresh Python 3.8.1 virtualenv using the following setup.py and pip install -e .

from setuptools import setup


setup(
    name="flake8-test",
    version="1.0.0",
    description="Flake8 test",
    author="hello",
    entry_points={
        "flake8.extension": ["TST = flake8_test:TestChecker"]
    },
    install_requires=["flake8"],
)

Using the following skeleton (flake8_test.py):

from flake8.options.manager import OptionManager


class TestChecker:
    name = "flake8-test"
    version = "1.0.0"

    def __init__(self, tree, lines):
        self.lines = lines
        self.tree = tree

    def run(self):
        yield (1, 1, "This is a test", TestChecker)

    @classmethod
    def add_options(cls, parser) -> None:
        """Add custom configuration option(s) to flake8."""
        parser.add_option(
            "--test-config-option",
            default=False,
            action="store_true",
            parse_from_config=True,
            help="This is a test"
        )

    @classmethod
    def parse_options(cls, options) -> None:
        """Parse the custom configuration options given to flake8."""
        cls.test_config_option = options.test_config_option

I recieve the following when invoking as a module:

$ python -m flake8 setup.py
Traceback (most recent call last):
  File "C:\Users\User\AppData\Local\Programs\Python\Python38\Lib\runpy.py", line 193, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\User\AppData\Local\Programs\Python\Python38\Lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "C:\test\.venv\lib\site-packages\flake8\__main__.py", line 4, in <module>
    cli.main()
  File "C:\test\.venv\lib\site-packages\flake8\main\cli.py", line 18, in main
    app.run(argv)
  File "C:\test\.venv\lib\site-packages\flake8\main\application.py", line 393, in run
    self._run(argv)
  File "C:\test\.venv\lib\site-packages\flake8\main\application.py", line 380, in _run
    self.initialize(argv)
  File "C:\test\.venv\lib\site-packages\flake8\main\application.py", line 364, in initialize
    self.register_plugin_options()
  File "C:\test\.venv\lib\site-packages\flake8\main\application.py", line 205, in register_plugin_options
    self.check_plugins.register_options(self.option_manager)
  File "C:\test\.venv\lib\site-packages\flake8\plugins\manager.py", line 489, in register_options
    list(self.manager.map(register_and_enable))
  File "C:\test\.venv\lib\site-packages\flake8\plugins\manager.py", line 297, in map
    yield func(self.plugins[name], *args, **kwargs)
  File "C:\test\.venv\lib\site-packages\flake8\plugins\manager.py", line 485, in register_and_enable
    call_register_options(plugin)
  File "C:\test\.venv\lib\site-packages\flake8\plugins\manager.py", line 397, in generated_function
    return method(optmanager, *args, **kwargs)
  File "C:\test\.venv\lib\site-packages\flake8\plugins\manager.py", line 216, in register_options
    add_options(optmanager)
  File "C:\test\flake8_test.py", line 18, in add_options
    parser.add_option(
  File "C:\test\.venv\lib\site-packages\flake8\options\manager.py", line 231, in add_option
    self.parser.add_option(option.to_optparse())
  File "C:\Users\User\AppData\Local\Programs\Python\Python38\Lib\optparse.py", line 1008, in add_option
    self._check_conflict(option)
  File "C:\Users\User\AppData\Local\Programs\Python\Python38\Lib\optparse.py", line 980, in _check_conflict
    raise OptionConflictError(
optparse.OptionConflictError: option --test-config-option: conflicting option string(s): --test-config-option

While flake8 behaves as expected:

$ flake8 setup.py
setup.py:13:2: W292 no newline at end of file

For broader context, this is causing CI for my plugin (flake8-annotations) to fail (Azure) since we're invoking flake8 as a module rather than from the defined entry point.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.