You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
6.3 KiB
184 lines
6.3 KiB
from __future__ import unicode_literals
|
|
# Copyright (c) 2006-2019 Andrey Golovigin
|
|
# Copyright (c) 2014 Matthias C. M. Troffaes
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
# a copy of this software and associated documentation files (the
|
|
# "Software"), to deal in the Software without restriction, including
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
# the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be
|
|
# included in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
import os.path # splitext
|
|
import pkg_resources
|
|
|
|
from pybtex.exceptions import PybtexError
|
|
|
|
|
|
class Plugin(object):
|
|
pass
|
|
|
|
|
|
#: default pybtex plugins
|
|
_DEFAULT_PLUGINS = {
|
|
"pybtex.database.input": "bibtex",
|
|
"pybtex.database.output": "bibtex",
|
|
"pybtex.backends": "latex",
|
|
"pybtex.style.labels": "number",
|
|
"pybtex.style.names": "plain",
|
|
"pybtex.style.sorting": "none",
|
|
"pybtex.style.formatting": "unsrt",
|
|
}
|
|
|
|
|
|
class PluginGroupNotFound(PybtexError):
|
|
|
|
def __init__(self, group_name):
|
|
message = u'plugin group {group_name} not found'.format(
|
|
group_name=group_name,
|
|
)
|
|
super(PluginGroupNotFound, self).__init__(message)
|
|
|
|
|
|
class PluginNotFound(PybtexError):
|
|
|
|
def __init__(self, plugin_group, name):
|
|
if not name.startswith('.'):
|
|
message = u'plugin {plugin_group}.{name} not found'.format(
|
|
plugin_group=plugin_group,
|
|
name=name,
|
|
)
|
|
else:
|
|
assert plugin_group.endswith('.suffixes')
|
|
message = (
|
|
u'plugin {plugin_group} for suffix {suffix} not found'.format(
|
|
plugin_group=plugin_group,
|
|
suffix=name,
|
|
)
|
|
)
|
|
|
|
super(PluginNotFound, self).__init__(message)
|
|
|
|
|
|
def _load_entry_point(group, name, use_aliases=False):
|
|
groups = [group, group + '.aliases'] if use_aliases else [group]
|
|
for search_group in groups:
|
|
for entry_point in pkg_resources.iter_entry_points(search_group, name):
|
|
return entry_point.load()
|
|
raise PluginNotFound(group, name)
|
|
|
|
|
|
def find_plugin(plugin_group, name=None, filename=None):
|
|
"""Find a :class:`Plugin` class within *plugin_group* which
|
|
matches *name*, or *filename* if *name* is not specified, or
|
|
the default plugin if neither *name* nor *filename* is
|
|
specified.
|
|
|
|
If *name* is specified, return the :class:`Plugin` class
|
|
registered under *name*. If *filename* is specified, look at
|
|
its suffix (i.e. extension) and return the :class:`Plugin`
|
|
class registered for this suffix.
|
|
|
|
If *name* is not a string, but a plugin class, just return it back.
|
|
(Used to make functions like :function:`make_bibliography` accept already
|
|
loaded plugins as well as plugin names.
|
|
|
|
"""
|
|
if isinstance(name, type) and issubclass(name, Plugin):
|
|
return name
|
|
|
|
if plugin_group not in _DEFAULT_PLUGINS:
|
|
raise PluginGroupNotFound(plugin_group)
|
|
if name:
|
|
return _load_entry_point(plugin_group, name, use_aliases=True)
|
|
elif filename:
|
|
suffix = os.path.splitext(filename)[1]
|
|
return _load_entry_point(plugin_group + '.suffixes', suffix)
|
|
else:
|
|
return _load_entry_point(plugin_group, _DEFAULT_PLUGINS[plugin_group])
|
|
|
|
|
|
def enumerate_plugin_names(plugin_group):
|
|
"""Enumerate all plugin names for the given *plugin_group*."""
|
|
return (entry_point.name
|
|
for entry_point in pkg_resources.iter_entry_points(plugin_group))
|
|
|
|
|
|
class _FakeEntryPoint(pkg_resources.EntryPoint):
|
|
|
|
def __init__(self, name, klass):
|
|
self.name = name
|
|
self.klass = klass
|
|
|
|
def __str__(self):
|
|
return "%s = :%s" % (self.name, self.klass.__name__)
|
|
|
|
def __repr__(self):
|
|
return (
|
|
"_FakeEntryPoint(name=%r, klass=%s)"
|
|
% (self.name, self.klass.__name__))
|
|
|
|
def load(self, require=True, env=None, installer=None):
|
|
return self.klass
|
|
|
|
def require(self, env=None, installer=None):
|
|
pass
|
|
|
|
|
|
def register_plugin(plugin_group, name, klass, force=False):
|
|
"""Register a plugin on the fly.
|
|
|
|
This works by adding *klass* as a pybtex entry point, under entry
|
|
point group *plugin_group* and entry point name *name*.
|
|
|
|
To register a suffix, append ".suffixes" to the plugin group, and
|
|
*name* is then simply the suffix, which should start with a
|
|
period.
|
|
|
|
To register an alias plugin name, append ".aliases" to the plugin group.
|
|
Aliases work just as real names, but are not returned by
|
|
:function:`enumerate_plugin_names` and not advertised in the command line
|
|
help.
|
|
|
|
If *force* is ``False``, then existing entry points are not
|
|
overwritten. If an entry point with the given group and name
|
|
already exists, then returns ``False``, otherwise returns
|
|
``True``.
|
|
|
|
If *force* is ``True``, then existing entry points are
|
|
overwritten, and the function always returns ``True``.
|
|
|
|
"""
|
|
if plugin_group.endswith(".suffixes"):
|
|
base_group, _ = plugin_group.rsplit(".", 1)
|
|
if not name.startswith('.'):
|
|
raise ValueError("a suffix must start with a period")
|
|
elif plugin_group.endswith(".aliases"):
|
|
base_group, _ = plugin_group.rsplit(".", 1)
|
|
else:
|
|
base_group = plugin_group
|
|
if base_group not in _DEFAULT_PLUGINS:
|
|
raise PluginGroupNotFound(base_group)
|
|
|
|
dist = pkg_resources.get_distribution('pybtex')
|
|
ep_map = pkg_resources.get_entry_map(dist)
|
|
if plugin_group not in ep_map:
|
|
ep_map[plugin_group] = {}
|
|
if name in ep_map[plugin_group] and not force:
|
|
return False
|
|
else:
|
|
ep_map[plugin_group][name] = _FakeEntryPoint(name, klass)
|
|
return True
|
|
|