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