Barry Warsaw pushed to branch master at mailman / Mailman

Commits:
d063ee4d by Barry Warsaw at 2016-01-25T14:59:36-05:00
Make creating Link objects a more convenient.

Link.__init__() can now take an IRule or the string naming a rule, which
will be looked up in config.rules.  Similarly, it can take an IChain or
the name of a chain.

- - - - -


10 changed files:

- src/mailman/chains/base.py
- src/mailman/chains/builtin.py
- src/mailman/chains/headers.py
- src/mailman/chains/moderation.py
- src/mailman/chains/tests/test_base.py
- src/mailman/core/chains.py
- src/mailman/core/rules.py
- src/mailman/rules/docs/header-matching.rst
- src/mailman/runners/docs/incoming.rst
- src/mailman/runners/tests/test_incoming.py


Changes:

=====================================
src/mailman/chains/base.py
=====================================
--- a/src/mailman/chains/base.py
+++ b/src/mailman/chains/base.py
@@ -27,18 +27,22 @@ __all__ = [
 from mailman.config import config
 from mailman.interfaces.chain import (
     IChain, IChainIterator, IChainLink, IMutableChain, LinkAction)
+from mailman.interfaces.rules import IRule
 from zope.interface import implementer
 
 
-
 @implementer(IChainLink)
 class Link:
     """A chain link."""
 
     def __init__(self, rule, action=None, chain=None, function=None):
-        self.rule = rule
+        self.rule = (rule
+                     if IRule.providedBy(rule)
+                     else config.rules[rule])
         self.action = (LinkAction.defer if action is None else action)
-        self.chain = chain
+        self.chain = (chain
+                      if chain is None or IChain.providedBy(chain)
+                      else config.chains[chain])
         self.function = function
 
     def __repr__(self):
@@ -55,7 +59,6 @@ class Link:
         return message.format(self)
 
 
-
 @implementer(IChain, IChainIterator)
 class TerminalChainBase:
     """A base chain that always matches and executes a method.
@@ -79,21 +82,19 @@ class TerminalChainBase:
 
     def __iter__(self):
         """See `IChainIterator`."""
-        truth = config.rules['truth']
         # First, yield a link that always runs the process method.
-        yield Link(truth, LinkAction.run, function=self._process)
+        yield Link('truth', LinkAction.run, function=self._process)
         # Now yield a rule that stops all processing.
-        yield Link(truth, LinkAction.stop)
+        yield Link('truth', LinkAction.stop)
 
 
-
 @implementer(IMutableChain)
 class Chain:
     """Generic chain base class."""
 
     def __init__(self, name, description):
         assert name not in config.chains, (
-            'Duplicate chain name: {0}'.format(name))
+            'Duplicate chain name: {}'.format(name))
         self.name = name
         self.description = description
         self._links = []
@@ -117,7 +118,6 @@ class Chain:
         yield from self._links
 
 
-
 @implementer(IChainIterator)
 class ChainIterator:
     """Generic chain iterator."""


=====================================
src/mailman/chains/builtin.py
=====================================
--- a/src/mailman/chains/builtin.py
+++ b/src/mailman/chains/builtin.py
@@ -25,7 +25,6 @@ __all__ = [
 import logging
 
 from mailman.chains.base import Link
-from mailman.config import config
 from mailman.core.i18n import _
 from mailman.interfaces.chain import IChain, LinkAction
 from zope.interface import implementer
@@ -73,11 +72,6 @@ class BuiltInChain:
         """See `IChain`."""
         if self._cached_links is None:
             self._cached_links = links = []
-            for rule_name, action, chain_name in self._link_descriptions:
-                # Get the named rule.
-                rule = config.rules[rule_name]
-                # Get the chain, if one is defined.
-                chain = (None if chain_name is None
-                         else config.chains[chain_name])
+            for rule, action, chain in self._link_descriptions:
                 links.append(Link(rule, action, chain))
         return iter(self._cached_links)


=====================================
src/mailman/chains/headers.py
=====================================
--- a/src/mailman/chains/headers.py
+++ b/src/mailman/chains/headers.py
@@ -49,7 +49,7 @@ def make_link(header, pattern, chain=None):
     :type header: string
     :param pattern: A regular expression for matching the header value.
     :type pattern: string
-    :param chain: When given, this is the chain to jump to if the
+    :param chain: When given, this is the name of the chain to jump to if the
         pattern matches the header.
     :type chain: string
     :return: The link representing this rule check.
@@ -58,7 +58,6 @@ def make_link(header, pattern, chain=None):
     rule = HeaderMatchRule(header, pattern)
     if chain is None:
         return Link(rule)
-    chain = config.chains[chain]
     return Link(rule, LinkAction.jump, chain)
 
 
@@ -85,7 +84,7 @@ class HeaderMatchRule:
         self.record = True
         # Register this rule so that other parts of the system can query it.
         assert self.name not in config.rules, (
-            'Duplicate HeaderMatchRule: {0} [{1}: {2}]'.format(
+            'Duplicate HeaderMatchRule: {} [{}: {}]'.format(
                 self.name, self.header, self.pattern))
         config.rules[self.name] = self
 
@@ -148,9 +147,7 @@ class HeaderMatchChain(Chain):
         # action until now, so jump to the chain defined in the configuration
         # file.  For security considerations, this takes precedence over
         # list-specific matches.
-        yield Link(config.rules['any'],
-                   LinkAction.jump,
-                   config.chains[config.antispam.jump_chain])
+        yield Link('any', LinkAction.jump, config.antispam.jump_chain)
         # Then return all the list-specific header matches.
         for entry in mlist.header_matches:
             yield make_link(entry.header, entry.pattern, entry.chain)


=====================================
src/mailman/chains/moderation.py
=====================================
--- a/src/mailman/chains/moderation.py
+++ b/src/mailman/chains/moderation.py
@@ -76,8 +76,6 @@ class ModerationChain:
             '{0}: Invalid moderation action: {1} for sender: {2}'.format(
                 mlist.fqdn_listname, action,
                 msgdata.get('moderation_sender', '(unknown)')))
-        truth = config.rules['truth']
-        chain = config.chains[jump_chain]
         return iter([
-            Link(truth, LinkAction.jump, chain),
+            Link('truth', LinkAction.jump, jump_chain),
             ])


=====================================
src/mailman/chains/tests/test_base.py
=====================================
--- a/src/mailman/chains/tests/test_base.py
+++ b/src/mailman/chains/tests/test_base.py
@@ -43,38 +43,38 @@ class TestMiscellaneous(unittest.TestCase):
 
     def test_link_repr(self):
         self.assertEqual(
-            repr(Link(Any)), '<Link "if any then LinkAction.defer">')
+            repr(Link(Any())), '<Link "if any then LinkAction.defer">')
 
     def test_link_repr_function(self):
         def function():
             pass
         self.assertEqual(
-            repr(Link(Any, function=function)),
+            repr(Link(Any(), function=function)),
             '<Link "if any then LinkAction.defer" function()>')
 
     def test_link_repr_chain(self):
         self.assertEqual(
-            repr(Link(Any, chain=AcceptChain)),
+            repr(Link(Any(), chain=AcceptChain())),
             '<Link "if any then LinkAction.defer" accept>')
 
     def test_link_repr_chain_and_function(self):
         def function():
             pass
         self.assertEqual(
-            repr(Link(Any, chain=AcceptChain, function=function)),
+            repr(Link(Any(), chain=AcceptChain(), function=function)),
             '<Link "if any then LinkAction.defer" accept function()>')
 
     def test_link_repr_chain_all(self):
         def function():
             pass
         self.assertEqual(
-            repr(Link(Any, LinkAction.stop, AcceptChain, function)),
+            repr(Link(Any(), LinkAction.stop, AcceptChain(), function)),
             '<Link "if any then LinkAction.stop" accept function()>')
 
     def test_flush(self):
         # Test that we can flush the links of a chain.
         chain = Chain('test', 'just a testing chain')
-        chain.append_link(Link(Any))
+        chain.append_link(Link(Any()))
         # Iterate over the links of the chain to prove there are some.
         count = sum(1 for link in chain.get_iterator())
         self.assertEqual(count, 1)


=====================================
src/mailman/core/chains.py
=====================================
--- a/src/mailman/core/chains.py
+++ b/src/mailman/core/chains.py
@@ -30,7 +30,6 @@ from mailman.utilities.modules import find_components
 from zope.interface.verify import verifyObject
 
 
-
 def process(mlist, msg, msgdata, start_chain='default-posting-chain'):
     """Process the message through a chain.
 
@@ -93,7 +92,6 @@ def process(mlist, msg, msgdata, 
start_chain='default-posting-chain'):
                 misses.append(link.rule.name)
 
 
-
 def initialize():
     """Set up chains, both built-in and from the database."""
     for chain_class in find_components('mailman.chains', IChain):
@@ -107,7 +105,7 @@ def initialize():
         chain = chain_class()
         verifyObject(IChain, chain)
         assert chain.name not in config.chains, (
-            'Duplicate chain "{0}" found in {1} (previously: {2}'.format(
+            'Duplicate chain "{}" found in {} (previously: {}'.format(
                 chain.name, chain_class, config.chains[chain.name]))
         config.chains[chain.name] = chain
     # XXX Read chains from the database and initialize them.


=====================================
src/mailman/core/rules.py
=====================================
--- a/src/mailman/core/rules.py
+++ b/src/mailman/core/rules.py
@@ -28,7 +28,6 @@ from mailman.utilities.modules import find_components
 from zope.interface.verify import verifyObject
 
 
-
 def initialize():
     """Find and register all rules in all plugins."""
     # Find rules in plugins.
@@ -36,6 +35,5 @@ def initialize():
         rule = rule_class()
         verifyObject(IRule, rule)
         assert rule.name not in config.rules, (
-            'Duplicate rule "{0}" found in {1}'.format(
-                rule.name, rule_class))
+            'Duplicate rule "{}" found in {}'.format(rule.name, rule_class))
         config.rules[rule.name] = rule


=====================================
src/mailman/rules/docs/header-matching.rst
=====================================
--- a/src/mailman/rules/docs/header-matching.rst
+++ b/src/mailman/rules/docs/header-matching.rst
@@ -39,7 +39,7 @@ through the chain with no matches.
     ...         print('Rule hits:')
     ...         for rule_name in hits:
     ...             rule = config.rules[rule_name]
-    ...             print('    {0}: {1}'.format(rule.header, rule.pattern))
+    ...             print('    {}: {}'.format(rule.header, rule.pattern))
     ...     misses = msgdata.get('rule_misses', [])
     ...     if len(misses) == 0:
     ...         print('No rules missed')
@@ -47,7 +47,7 @@ through the chain with no matches.
     ...         print('Rule misses:')
     ...         for rule_name in misses:
     ...             rule = config.rules[rule_name]
-    ...             print('    {0}: {1}'.format(rule.header, rule.pattern))
+    ...             print('    {}: {}'.format(rule.header, rule.pattern))
 
 By looking at the message metadata after chain processing, we can see that
 none of the rules matched.


=====================================
src/mailman/runners/docs/incoming.rst
=====================================
--- a/src/mailman/runners/docs/incoming.rst
+++ b/src/mailman/runners/docs/incoming.rst
@@ -183,11 +183,9 @@ new chain and set it as the mailing list's start chain.
     >>> from mailman.chains.base import Chain, Link
     >>> from mailman.interfaces.chain import LinkAction
     >>> def make_chain(name, target_chain):
-    ...     truth_rule = config.rules['truth']
-    ...     target_chain = config.chains[target_chain]
-    ...     test_chain = Chain(name, 'Testing {0}'.format(target_chain))
+    ...     test_chain = Chain(name, 'Testing {}'.format(target_chain))
     ...     config.chains[test_chain.name] = test_chain
-    ...     link = Link(truth_rule, LinkAction.jump, target_chain)
+    ...     link = Link('truth', LinkAction.jump, target_chain)
     ...     test_chain.append_link(link)
     ...     return test_chain
 


=====================================
src/mailman/runners/tests/test_incoming.py
=====================================
--- a/src/mailman/runners/tests/test_incoming.py
+++ b/src/mailman/runners/tests/test_incoming.py
@@ -58,7 +58,9 @@ class TestIncoming(unittest.TestCase):
         self._mlist.posting_chain = 'test posting'
         self._mlist.owner_chain = 'test owner'
         config.chains['test posting'] = Chain('posting')
+        self.addCleanup(config.chains.pop, 'test posting')
         config.chains['test owner'] = Chain('owner')
+        self.addCleanup(config.chains.pop, 'test owner')
         self._in = make_testable_runner(IncomingRunner, 'in')
         self._msg = mfs("""\
 From: a...@example.com
@@ -66,10 +68,6 @@ To: t...@example.com
 
 """)
 
-    def tearDown(self):
-        del config.chains['test posting']
-        del config.chains['test owner']
-
     def test_posting(self):
         # A message posted to the list goes through the posting chain.
         msgdata = dict(listid='test.example.com')



View it on GitLab: 
https://gitlab.com/mailman/mailman/commit/d063ee4dd4579ca931e36f0761084e4ab7cd0335
_______________________________________________
Mailman-checkins mailing list
Mailman-checkins@python.org
Unsubscribe: 
https://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org

Reply via email to