summaryrefslogtreecommitdiff
path: root/kombu/matcher.py
diff options
context:
space:
mode:
authorJason Held <jasonsheld@gmail.com>2019-02-27 09:23:12 -0500
committerAsif Saif Uddin <auvipy@gmail.com>2019-02-27 20:23:12 +0600
commit41dbbe3063f4c1e5a11fc8a0ce6c366c14917df6 (patch)
treefc50ed257ae41c7d8204e4b19925c11e8317768c /kombu/matcher.py
parenteb6e4c8d512c6451d2430744322014439e8a0df8 (diff)
downloadkombu-41dbbe3063f4c1e5a11fc8a0ce6c366c14917df6.tar.gz
Control pattern matching (#997)
* Added pattern/matcher to Mailbox * pattern/match for kombu 4 * Ensure kombu.matcher is covered by our documentation. * Adds test_matcher & pidbox unit tests. * Added tests to ensure exception is raised when matcher is not registered. * Adds to test for destination passed in to process.
Diffstat (limited to 'kombu/matcher.py')
-rw-r--r--kombu/matcher.py140
1 files changed, 140 insertions, 0 deletions
diff --git a/kombu/matcher.py b/kombu/matcher.py
new file mode 100644
index 00000000..018a0955
--- /dev/null
+++ b/kombu/matcher.py
@@ -0,0 +1,140 @@
+"""Pattern matching registry."""
+from __future__ import absolute_import, unicode_literals
+
+from re import match as rematch
+from fnmatch import fnmatch
+
+from .utils.compat import entrypoints
+from .utils.encoding import bytes_to_str
+
+
+class MatcherNotInstalled(Exception):
+ """Matcher not installed/found."""
+
+ pass
+
+
+class MatcherRegistry(object):
+ """Pattern matching function registry."""
+
+ MatcherNotInstalled = MatcherNotInstalled
+ matcher_pattern_first = ["pcre", ]
+
+ def __init__(self):
+ self._matchers = {}
+ self._default_matcher = None
+
+ def register(self, name, matcher):
+ """Add matcher by name to the registry."""
+ self._matchers[name] = matcher
+
+ def unregister(self, name):
+ """Remove matcher by name from the registry."""
+ try:
+ self._matchers.pop(name)
+ except KeyError:
+ raise self.MatcherNotInstalled(
+ 'No matcher installed for {}'.format(name)
+ )
+
+ def _set_default_matcher(self, name):
+ """Set the default matching method.
+
+ :param name: The name of the registered matching method.
+ For example, `glob` (default), `pcre`, or any custom
+ methods registered using :meth:`register`.
+
+ :raises MatcherNotInstalled: If the matching method requested
+ is not available.
+ """
+ try:
+ self._default_matcher = self._matchers[name]
+ except KeyError:
+ raise self.MatcherNotInstalled(
+ 'No matcher installed for {}'.format(name)
+ )
+
+ def match(self, data, pattern, matcher=None, matcher_kwargs=None):
+ """Call the matcher."""
+ if matcher and not self._matchers.get(matcher):
+ raise self.MatcherNotInstalled(
+ 'No matcher installed for {}'.format(matcher)
+ )
+ match_func = self._matchers[matcher or 'glob']
+ if matcher in self.matcher_pattern_first:
+ first_arg = bytes_to_str(pattern)
+ second_arg = bytes_to_str(data)
+ else:
+ first_arg = bytes_to_str(data)
+ second_arg = bytes_to_str(pattern)
+ return match_func(first_arg, second_arg, **matcher_kwargs or {})
+
+
+#: Global registry of matchers.
+registry = MatcherRegistry()
+
+
+"""
+.. function:: match(data, pattern, matcher=default_matcher,
+ matcher_kwargs=None):
+
+ Match `data` by `pattern` using `matcher`.
+
+ :param data: The data that should be matched. Must be string.
+ :param pattern: The pattern that should be applied. Must be string.
+ :keyword matcher: An optional string representing the mathcing
+ method (for example, `glob` or `pcre`).
+
+ If :const:`None` (default), then `glob` will be used.
+
+ :keyword matcher_kwargs: Additional keyword arguments that will be passed
+ to the specified `matcher`.
+ :returns: :const:`True` if `data` matches pattern,
+ :const:`False` otherwise.
+
+ :raises MatcherNotInstalled: If the matching method requested is not
+ available.
+"""
+match = registry.match
+
+
+"""
+.. function:: register(name, matcher):
+ Register a new matching method.
+
+ :param name: A convience name for the mathing method.
+ :param matcher: A method that will be passed data and pattern.
+"""
+register = registry.register
+
+
+"""
+.. function:: unregister(name):
+ Unregister registered matching method.
+
+ :param name: Registered matching method name.
+"""
+unregister = registry.unregister
+
+
+def register_glob():
+ """Register glob into default registry."""
+ registry.register('glob', fnmatch)
+
+
+def register_pcre():
+ """Register pcre into default registry."""
+ registry.register('pcre', rematch)
+
+
+# Register the base matching methods.
+register_glob()
+register_pcre()
+
+# Default matching method is 'glob'
+registry._set_default_matcher('glob')
+
+
+# Load entrypoints from installed extensions
+for ep, args in entrypoints('kombu.matchers'):
+ register(ep.name, *args)