Skip to content

Commit

Permalink
Add support for entry points
Browse files Browse the repository at this point in the history
  • Loading branch information
ines committed Nov 3, 2019
1 parent a44c547 commit b7e3a91
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 7 deletions.
6 changes: 2 additions & 4 deletions azure-pipelines.yml
Expand Up @@ -53,7 +53,7 @@ jobs:
architecture: 'x64'

- script: |
pip install -U setuptools --user
pip install -U -r requirements.txt
python setup.py sdist
displayName: 'Build sdist'
Expand All @@ -67,7 +67,5 @@ jobs:
pip install dist/$SDIST
displayName: 'Install from sdist'
- script: |
pip install -U pytest
python -m pytest test_catalogue.py
- script: python -m pytest test_catalogue.py
displayName: 'Run tests'
40 changes: 37 additions & 3 deletions catalogue.py
Expand Up @@ -4,17 +4,24 @@
from collections import OrderedDict
import sys

try: # Python 3.8
import importlib.metadata as importlib_metadata
except ImportError:
import importlib_metadata

if sys.version_info[0] == 2:
basestring_ = basestring # noqa: F821
else:
basestring_ = str

# Ony ever call this once for performance reasons
AVAILABLE_ENTRY_POINTS = importlib_metadata.entry_points()

# This is where functions will be registered
REGISTRY = OrderedDict()


def create(*namespace):
def create(*namespace, entry_points=False):
"""Create a new registry.
*namespace (str): The namespace, e.g. "spacy" or "spacy", "architectures".
Expand All @@ -23,17 +30,22 @@ def create(*namespace):
"""
if check_exists(*namespace):
raise RegistryError("Namespace already exists: {}".format(namespace))
return Registry(namespace)
return Registry(namespace, entry_points=entry_points)


class Registry(object):
def __init__(self, namespace):
def __init__(self, namespace, entry_points=False):
"""Initialize a new registry.
namespace (Tuple[str]): The namespace.
entry_points (bool): Whether to also check for entry points.
RETURNS (Registry): The newly created object.
"""
self.namespace = namespace
self.entry_point_namespace = "_".join(namespace)
if entry_points:
for name, value in self.get_entry_points().items():
self.register(name, func=value)

def register(self, name, **kwargs):
"""Register a function for a given namespace.
Expand Down Expand Up @@ -79,6 +91,28 @@ def get_all(self):
result[keys[-1]] = value
return result

def get_entry_points(self):
"""Get registered entry points from other packages for this namespace.
RETURNS (dict): Entry points, keyed by name.
"""
result = {}
for entry_point in AVAILABLE_ENTRY_POINTS.get(self.entry_point_namespace, []):
result[entry_point.name] = entry_point.load()
return result

def get_entry_point(self, name, default=None):
"""Check if registered entry point is available for a given name in the
namespace and load it. Otherwise, return None.
name (unicode): Name of entry point to load.
RETURNS: The loaded entry point or None.
"""
for entry_point in AVAILABLE_ENTRY_POINTS.get(self.entry_point_namespace, []):
if entry_point.name == name:
return entry_point.load()
return default


def check_exists(*namespace):
"""Check if a namespace exists.
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
@@ -0,0 +1,3 @@
importlib_metadata>=0.20; python_version < "3.8"
setuptools
pytest>=4.6.5
2 changes: 2 additions & 0 deletions setup.cfg
Expand Up @@ -30,6 +30,8 @@ py_modules = catalogue
zip_safe = true
include_package_data = true
python_requires = >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
install_requires =
importlib_metadata>=0.20; python_version < "3.8"

[bdist_wheel]
universal = true
Expand Down
16 changes: 16 additions & 0 deletions test_catalogue.py
Expand Up @@ -87,3 +87,19 @@ def z():
assert items["z"] == z
assert catalogue.check_exists("x", "y", "z")
assert catalogue._get(("x", "y", "z")) == z


def test_entry_points():
# Create a new EntryPoint object by pretending we have a config.cfg and
# use one of catalogue's util functions as the advertised function
ep_string = "[options.entry_points]test_foo\n bar = catalogue:check_exists"
ep = catalogue.importlib_metadata.EntryPoint._from_text(ep_string)
catalogue.AVAILABLE_ENTRY_POINTS["test_foo"] = ep
assert catalogue.REGISTRY == {}
test_registry = catalogue.create("test", "foo", entry_points=True)
entry_points = test_registry.get_entry_points()
assert "bar" in entry_points
assert entry_points["bar"] == catalogue.check_exists
assert test_registry.get_entry_point("bar") == catalogue.check_exists
assert ("test", "foo", "bar") in catalogue.REGISTRY
assert catalogue._get(("test", "foo", "bar")) == catalogue.check_exists

0 comments on commit b7e3a91

Please sign in to comment.