diff options
| author | Barry Warsaw | 2017-07-22 03:02:05 +0000 |
|---|---|---|
| committer | Barry Warsaw | 2017-07-22 03:02:05 +0000 |
| commit | f00b94f18e1d82d1488cbcee6053f03423bc2f49 (patch) | |
| tree | 1a8e56dff0eab71e58e5fc9ecc5f3c614d7edca7 /src/mailman/commands/docs | |
| parent | f54c045519300f6f70947d1114f46c2b8ae0d368 (diff) | |
| download | mailman-f00b94f18e1d82d1488cbcee6053f03423bc2f49.tar.gz mailman-f00b94f18e1d82d1488cbcee6053f03423bc2f49.tar.zst mailman-f00b94f18e1d82d1488cbcee6053f03423bc2f49.zip | |
Diffstat (limited to 'src/mailman/commands/docs')
| -rw-r--r-- | src/mailman/commands/docs/aliases.rst | 38 | ||||
| -rw-r--r-- | src/mailman/commands/docs/conf.rst | 20 | ||||
| -rw-r--r-- | src/mailman/commands/docs/control.rst | 53 | ||||
| -rw-r--r-- | src/mailman/commands/docs/create.rst | 131 | ||||
| -rw-r--r-- | src/mailman/commands/docs/import.rst | 59 | ||||
| -rw-r--r-- | src/mailman/commands/docs/info.rst | 17 | ||||
| -rw-r--r-- | src/mailman/commands/docs/inject.rst | 126 | ||||
| -rw-r--r-- | src/mailman/commands/docs/lists.rst | 50 | ||||
| -rw-r--r-- | src/mailman/commands/docs/members.rst | 166 | ||||
| -rw-r--r-- | src/mailman/commands/docs/qfile.rst | 20 | ||||
| -rw-r--r-- | src/mailman/commands/docs/remove.rst | 33 | ||||
| -rw-r--r-- | src/mailman/commands/docs/shell.rst (renamed from src/mailman/commands/docs/withlist.rst) | 106 | ||||
| -rw-r--r-- | src/mailman/commands/docs/status.rst | 17 | ||||
| -rw-r--r-- | src/mailman/commands/docs/unshunt.rst | 15 | ||||
| -rw-r--r-- | src/mailman/commands/docs/version.rst | 9 |
15 files changed, 298 insertions, 562 deletions
diff --git a/src/mailman/commands/docs/aliases.rst b/src/mailman/commands/docs/aliases.rst index 31fda21e4..bea1e311a 100644 --- a/src/mailman/commands/docs/aliases.rst +++ b/src/mailman/commands/docs/aliases.rst @@ -8,10 +8,7 @@ server. Generally these files are automatically kept up-to-date when mailing lists are created or removed, but you might occasionally need to manually regenerate the file. The ``mailman aliases`` command does this. - >>> class FakeArgs: - ... directory = None - >>> from mailman.commands.cli_aliases import Aliases - >>> command = Aliases() + >>> command = cli('mailman.commands.cli_aliases.aliases') For example, connecting Mailman to Postfix is generally done through the LMTP protocol. Mailman starts an LMTP server and Postfix delivers messages to @@ -28,17 +25,20 @@ generation. ... lmtp_port: 24 ... """) +.. + Clean up. + >>> ignore = cleanups.callback(config.pop, 'postfix') + Let's create a mailing list and then display the transport map for it. We'll write the appropriate files to a temporary directory. :: + >>> mlist = create_list('ant@example.com') + >>> import os, shutil, tempfile >>> output_directory = tempfile.mkdtemp() >>> ignore = cleanups.callback(shutil.rmtree, output_directory) - - >>> FakeArgs.directory = output_directory - >>> mlist = create_list('test@example.com') - >>> command.process(FakeArgs) + >>> command('mailman aliases --directory ' + output_directory) For Postfix, there are two files in the output directory. @@ -54,15 +54,15 @@ The transport map file contains all the aliases for the mailing list. ... print(fp.read()) # AUTOMATICALLY GENERATED BY MAILMAN ON ... ... - test@example.com lmtp:[lmtp.example.com]:24 - test-bounces@example.com lmtp:[lmtp.example.com]:24 - test-confirm@example.com lmtp:[lmtp.example.com]:24 - test-join@example.com lmtp:[lmtp.example.com]:24 - test-leave@example.com lmtp:[lmtp.example.com]:24 - test-owner@example.com lmtp:[lmtp.example.com]:24 - test-request@example.com lmtp:[lmtp.example.com]:24 - test-subscribe@example.com lmtp:[lmtp.example.com]:24 - test-unsubscribe@example.com lmtp:[lmtp.example.com]:24 + ant@example.com lmtp:[lmtp.example.com]:24 + ant-bounces@example.com lmtp:[lmtp.example.com]:24 + ant-confirm@example.com lmtp:[lmtp.example.com]:24 + ant-join@example.com lmtp:[lmtp.example.com]:24 + ant-leave@example.com lmtp:[lmtp.example.com]:24 + ant-owner@example.com lmtp:[lmtp.example.com]:24 + ant-request@example.com lmtp:[lmtp.example.com]:24 + ant-subscribe@example.com lmtp:[lmtp.example.com]:24 + ant-unsubscribe@example.com lmtp:[lmtp.example.com]:24 <BLANKLINE> The relay domains file contains a list of all the domains. @@ -72,7 +72,3 @@ The relay domains file contains a list of all the domains. # AUTOMATICALLY GENERATED BY MAILMAN ON ... ... example.com example.com - -.. - Clean up. - >>> config.pop('postfix') diff --git a/src/mailman/commands/docs/conf.rst b/src/mailman/commands/docs/conf.rst index f465aab53..1a6a4679d 100644 --- a/src/mailman/commands/docs/conf.rst +++ b/src/mailman/commands/docs/conf.rst @@ -10,17 +10,12 @@ Mailman's configuration is divided in multiple sections which contain multiple key-value pairs. The ``mailman conf`` command allows you to display a specific key-value pair, or several key-value pairs. - >>> class FakeArgs: - ... key = None - ... section = None - ... output = None - >>> from mailman.commands.cli_conf import Conf - >>> command = Conf() + >>> command = cli('mailman.commands.cli_conf.conf') To get a list of all key-value pairs of any section, you need to call the command without any options. - >>> command.process(FakeArgs) + >>> command('mailman conf') [antispam] header_checks: ... [logging.bounce] level: info @@ -30,8 +25,7 @@ command without any options. You can list all the key-value pairs of a specific section. - >>> FakeArgs.section = 'shell' - >>> command.process(FakeArgs) + >>> command('mailman conf --section shell') [shell] banner: Welcome to the GNU Mailman shell [shell] history_file: [shell] prompt: >>> @@ -40,9 +34,7 @@ You can list all the key-value pairs of a specific section. You can also pass a key and display all key-value pairs matching the given key, along with the names of the corresponding sections. - >>> FakeArgs.section = None - >>> FakeArgs.key = 'path' - >>> command.process(FakeArgs) + >>> command('mailman conf --key path') [logging.archiver] path: mailman.log [logging.bounce] path: bounce.log [logging.config] path: mailman.log @@ -61,9 +53,7 @@ key, along with the names of the corresponding sections. If you specify both a section and a key, you will get the corresponding value. - >>> FakeArgs.section = 'mailman' - >>> FakeArgs.key = 'site_owner' - >>> command.process(FakeArgs) + >>> command('mailman conf --section mailman --key site_owner') noreply@example.com diff --git a/src/mailman/commands/docs/control.rst b/src/mailman/commands/docs/control.rst index b268b50a4..446c3652f 100644 --- a/src/mailman/commands/docs/control.rst +++ b/src/mailman/commands/docs/control.rst @@ -13,29 +13,22 @@ All we care about is the master process; normally it starts a bunch of runners, but we don't care about any of them, so write a test configuration file for the master that disables all the runners. - >>> from mailman.commands.tests.test_control import make_config + >>> from mailman.commands.tests.test_cli_control import make_config + >>> make_config(cleanups) Starting ======== - >>> from mailman.commands.cli_control import Start - >>> start = Start() - - >>> class FakeArgs: - ... force = False - ... run_as_user = True - ... quiet = False - ... config = make_config() - >>> args = FakeArgs() + >>> command = cli('mailman.commands.cli_control.start') Starting the daemons prints a useful message and starts the master watcher process in the background. - >>> start.process(args) + >>> command('mailman start') Starting Mailman's master runner - >>> from mailman.commands.tests.test_control import find_master + >>> from mailman.commands.tests.test_cli_control import find_master The process exists, and its pid is available in a run time file. @@ -51,34 +44,12 @@ You can also stop the master watcher process from the command line, which stops all the child processes too. :: - >>> from mailman.commands.cli_control import Stop - >>> stop = Stop() - >>> stop.process(args) + >>> command = cli('mailman.commands.cli_control.stop') + >>> command('mailman stop') Shutting down Mailman's master runner - >>> from datetime import datetime, timedelta - >>> import os - >>> import time - >>> import errno - >>> def bury_master(): - ... until = timedelta(seconds=2) + datetime.now() - ... while datetime.now() < until: - ... time.sleep(0.1) - ... try: - ... os.kill(pid, 0) - ... os.waitpid(pid, os.WNOHANG) - ... except OSError as error: - ... if error.errno == errno.ESRCH: - ... # The process has exited. - ... print('Master process went bye bye') - ... return - ... else: - ... raise - ... else: - ... raise AssertionError('Master process lingered') - - >>> bury_master() - Master process went bye bye - - -XXX We need tests for restart (SIGUSR1) and reopen (SIGHUP). +.. + # Clean up. + >>> from mailman.commands.tests.test_cli_control import ( + ... kill_with_extreme_prejudice) + >>> kill_with_extreme_prejudice(pid) diff --git a/src/mailman/commands/docs/create.rst b/src/mailman/commands/docs/create.rst index 12e3a1c95..c80ff7a3d 100644 --- a/src/mailman/commands/docs/create.rst +++ b/src/mailman/commands/docs/create.rst @@ -4,34 +4,19 @@ Command line list creation A system administrator can create mailing lists by the command line. - >>> class FakeArgs: - ... language = None - ... owners = [] - ... quiet = False - ... domain = True - ... listname = None - ... notify = False + >>> command = cli('mailman.commands.cli_lists.create') -You cannot create a mailing list in an unknown domain. +You can prevent creation of a mailing list in an unknown domain. - >>> from mailman.commands.cli_lists import Create - >>> command = Create() - - >>> class FakeParser: - ... def error(self, message): - ... print(message) - >>> command.parser = FakeParser() - - >>> FakeArgs.domain = False - >>> FakeArgs.listname = ['test@example.xx'] - >>> command.process(FakeArgs) - Undefined domain: example.xx + >>> command('mailman create --no-domain ant@example.xx') + Usage: create [OPTIONS] LISTNAME + <BLANKLINE> + Error: Undefined domain: example.xx By default, Mailman will create the domain if it doesn't exist. - >>> FakeArgs.domain = True - >>> command.process(FakeArgs) - Created mailing list: test@example.xx + >>> command('mailman create ant@example.xx') + Created mailing list: ant@example.xx Now both the domain and the mailing list exist in the database. :: @@ -39,36 +24,20 @@ Now both the domain and the mailing list exist in the database. >>> from mailman.interfaces.listmanager import IListManager >>> from zope.component import getUtility >>> list_manager = getUtility(IListManager) - >>> list_manager.get('test@example.xx') - <mailing list "test@example.xx" at ...> + >>> list_manager.get('ant@example.xx') + <mailing list "ant@example.xx" at ...> >>> from mailman.interfaces.domain import IDomainManager >>> getUtility(IDomainManager).get('example.xx') <Domain example.xx> -You can prevent the creation of the domain in existing domains by using the -``-D`` or ``--no-domain`` flag. Although the ``--no-domain`` flag is not -required when domain already exists it can be used to force an error when -domain doesn't exist. - - >>> FakeArgs.domain = False - >>> FakeArgs.listname = ['test1@example.com'] - >>> command.process(FakeArgs) - Created mailing list: test1@example.com - - >>> list_manager.get('test1@example.com') - <mailing list "test1@example.com" at ...> - The command can also operate quietly. :: - >>> FakeArgs.quiet = True - >>> FakeArgs.listname = ['test2@example.com'] - >>> command.process(FakeArgs) - - >>> mlist = list_manager.get('test2@example.com') + >>> command('mailman create --quiet bee@example.com') + >>> mlist = list_manager.get('bee@example.com') >>> mlist - <mailing list "test2@example.com" at ...> + <mailing list "bee@example.com" at ...> Setting the owner @@ -83,32 +52,29 @@ But you can specify an owner address on the command line when you create the mailing list. :: - >>> FakeArgs.quiet = False - >>> FakeArgs.listname = ['test4@example.com'] - >>> FakeArgs.owners = ['foo@example.org'] - >>> command.process(FakeArgs) - Created mailing list: test4@example.com + >>> command('mailman create --owner anne@example.com cat@example.com') + Created mailing list: cat@example.com - >>> mlist = list_manager.get('test4@example.com') + >>> mlist = list_manager.get('cat@example.com') >>> dump_list(repr(address) for address in mlist.owners.addresses) - <Address: foo@example.org [not verified] at ...> + <Address: anne@example.com [not verified] at ...> You can even specify more than one address for the owners. :: - >>> FakeArgs.owners = ['foo@example.net', - ... 'bar@example.net', - ... 'baz@example.net'] - >>> FakeArgs.listname = ['test5@example.com'] - >>> command.process(FakeArgs) - Created mailing list: test5@example.com + >>> command('mailman create ' + ... '--owner anne@example.com ' + ... '--owner bart@example.com ' + ... '--owner cate@example.com ' + ... 'dog@example.com') + Created mailing list: dog@example.com - >>> mlist = list_manager.get('test5@example.com') + >>> mlist = list_manager.get('dog@example.com') >>> from operator import attrgetter >>> dump_list(repr(address) for address in mlist.owners.addresses) - <Address: bar@example.net [not verified] at ...> - <Address: baz@example.net [not verified] at ...> - <Address: foo@example.net [not verified] at ...> + <Address: anne@example.com [not verified] at ...> + <Address: bart@example.com [not verified] at ...> + <Address: cate@example.com [not verified] at ...> Setting the language @@ -118,25 +84,21 @@ You can set the default language for the new mailing list when you create it. The language must be known to Mailman. :: - >>> FakeArgs.listname = ['test3@example.com'] - >>> FakeArgs.language = 'ee' - >>> command.process(FakeArgs) - Invalid language code: ee + >>> command('mailman create --language xx ewe@example.com') + Usage: create [OPTIONS] LISTNAME + <BLANKLINE> + Error: Invalid language code: xx >>> from mailman.interfaces.languages import ILanguageManager - >>> getUtility(ILanguageManager).add('ee', 'iso-8859-1', 'Freedonian') - <Language [ee] Freedonian> + >>> getUtility(ILanguageManager).add('xx', 'iso-8859-1', 'Freedonian') + <Language [xx] Freedonian> - >>> FakeArgs.quiet = False - >>> FakeArgs.listname = ['test3@example.com'] - >>> FakeArgs.language = 'fr' - >>> command.process(FakeArgs) - Created mailing list: test3@example.com + >>> command('mailman create --language xx ewe@example.com') + Created mailing list: ewe@example.com - >>> mlist = list_manager.get('test3@example.com') + >>> mlist = list_manager.get('ewe@example.com') >>> print(mlist.preferred_language) - <Language [fr] French> - >>> FakeArgs.language = None + <Language [xx] Freedonian> Notifications @@ -144,10 +106,13 @@ Notifications When told to, Mailman will notify the list owners of their new mailing list. - >>> FakeArgs.listname = ['test6@example.com'] - >>> FakeArgs.notify = True - >>> command.process(FakeArgs) - Created mailing list: test6@example.com + >>> command('mailman create ' + ... '--notify ' + ... '--owner anne@example.com ' + ... '--owner bart@example.com ' + ... '--owner cate@example.com ' + ... 'fly@example.com') + Created mailing list: fly@example.com The notification message is in the virgin queue. :: @@ -161,19 +126,19 @@ The notification message is in the virgin queue. ... print(message.msg.as_string()) MIME-Version: 1.0 ... - Subject: Your new mailing list: test6@example.com + Subject: Your new mailing list: fly@example.com From: noreply@example.com - To: foo@example.net, bar@example.net, baz@example.net + To: anne@example.com, bart@example.com, cate@example.com ... <BLANKLINE> - The mailing list 'test6@example.com' has just been created for you. + The mailing list 'fly@example.com' has just been created for you. The following is some basic information about your mailing list. <BLANKLINE> There is an email-based interface for users (not administrators) of your list; you can get info about using it by sending a message with just the word 'help' as subject or in the body, to: <BLANKLINE> - test6-request@example.com + fly-request@example.com <BLANKLINE> Please address all questions to noreply@example.com. <BLANKLINE> diff --git a/src/mailman/commands/docs/import.rst b/src/mailman/commands/docs/import.rst index 86a31d6ff..5c5883921 100644 --- a/src/mailman/commands/docs/import.rst +++ b/src/mailman/commands/docs/import.rst @@ -2,55 +2,52 @@ Importing list data =================== -If you have the config.pck file for a version 2.1 mailing list, you can import -that into an existing mailing list in Mailman 3.0. -:: +If you have the ``config.pck`` file for a version 2.1 mailing list, you can +import that into an existing mailing list in Mailman 3.0. - >>> from mailman.commands.cli_import import Import21 - >>> command = Import21() + >>> command = cli('mailman.commands.cli_import.import21') - >>> class FakeArgs: - ... listname = None - ... pickle_file = None +You must specify the mailing list you are importing into, and it must exist. - >>> class FakeParser: - ... def error(self, message): - ... print(message) - >>> command.parser = FakeParser() + >>> command('mailman import21') + Usage: ... [OPTIONS] LISTSPEC PICKLE_FILE + <BLANKLINE> + Error: Missing argument "listspec". -You must specify the mailing list you are importing into, and it must exist. -:: +You must also specify a pickle file to import. - >>> command.process(FakeArgs) - List name is required + >>> command('mailman import21 import@example.com') + Usage: ... [OPTIONS] LISTSPEC PICKLE_FILE + <BLANKLINE> + Error: Missing argument "pickle_file". - >>> FakeArgs.listname = ['import@example.com'] - >>> command.process(FakeArgs) - No such list: import@example.com +Too bad the list doesn't exist. + + >>> from pkg_resources import resource_filename + >>> pickle_file = resource_filename('mailman.testing', 'config.pck') + >>> command('mailman import21 import@example.com ' + pickle_file) + Usage: ... [OPTIONS] LISTSPEC PICKLE_FILE + <BLANKLINE> + Error: No such list: import@example.com When the mailing list exists, you must specify a real pickle file to import from. :: >>> mlist = create_list('import@example.com') - >>> command.process(FakeArgs) - config.pck file is required - - >>> FakeArgs.pickle_file = [__file__] - >>> command.process(FakeArgs) - Not a Mailman 2.1 configuration file: .../import.rst + >>> transaction.commit() + >>> command('mailman import21 import@example.com ' + __file__) + Usage: ... [OPTIONS] LISTSPEC PICKLE_FILE + <BLANKLINE> + Error: Not a Mailman 2.1 configuration file: .../import.rst'... Now we can import the test pickle file. As a simple illustration of the -import, the mailing list's 'real name' has changed. +import, the mailing list's "real name" will change. :: - >>> from pkg_resources import resource_filename - >>> FakeArgs.pickle_file = [ - ... resource_filename('mailman.testing', 'config.pck')] - >>> print(mlist.display_name) Import - >>> command.process(FakeArgs) + >>> command('mailman import21 import@example.com ' + pickle_file) >>> print(mlist.display_name) Test diff --git a/src/mailman/commands/docs/info.rst b/src/mailman/commands/docs/info.rst index 6fce70783..219143cab 100644 --- a/src/mailman/commands/docs/info.rst +++ b/src/mailman/commands/docs/info.rst @@ -6,15 +6,9 @@ You can get information about Mailman's environment by using the command line script ``mailman info``. By default, the info is printed to standard output. :: - >>> from mailman.commands.cli_info import Info - >>> command = Info() + >>> command = cli('mailman.commands.cli_info.info') - >>> class FakeArgs: - ... output = None - ... verbose = None - >>> args = FakeArgs() - - >>> command.process(args) + >>> command('mailman info') GNU Mailman 3... Python ... ... @@ -28,8 +22,7 @@ By passing in the ``-o/--output`` option, you can print the info to a file. >>> from mailman.config import config >>> import os >>> output_path = os.path.join(config.VAR_DIR, 'output.txt') - >>> args.output = output_path - >>> command.process(args) + >>> command('mailman info -o ' + output_path) >>> with open(output_path) as fp: ... print(fp.read()) GNU Mailman 3... @@ -44,8 +37,6 @@ By passing in the ``-o/--output`` option, you can print the info to a file. You can also get more verbose information, which contains a list of the file system paths that Mailman is using. - >>> args.output = None - >>> args.verbose = True >>> config.create_paths = False >>> config.push('fhs', """ ... [mailman] @@ -57,7 +48,7 @@ system paths that Mailman is using. The `Filesystem Hierarchy Standard`_ layout is the same everywhere by definition. - >>> command.process(args) + >>> command('mailman info --verbose') GNU Mailman 3... Python ... ... diff --git a/src/mailman/commands/docs/inject.rst b/src/mailman/commands/docs/inject.rst index 163f62886..3db22013a 100644 --- a/src/mailman/commands/docs/inject.rst +++ b/src/mailman/commands/docs/inject.rst @@ -4,29 +4,12 @@ Command line message injection You can inject a message directly into a queue directory via the command line. -:: - - >>> from mailman.commands.cli_inject import Inject - >>> command = Inject() - - >>> class FakeArgs: - ... queue = None - ... show = False - ... filename = None - ... listname = None - ... keywords = [] - >>> args = FakeArgs() - >>> class FakeParser: - ... def error(self, message): - ... print(message) - >>> command.parser = FakeParser() + >>> command = cli('mailman.commands.cli_inject.inject') It's easy to find out which queues are available. -:: - >>> args.show = True - >>> command.process(args) + >>> command('mailman inject --show') Available queues: archive bad @@ -41,49 +24,40 @@ It's easy to find out which queues are available. shunt virgin - >>> args.show = False - Usually, the text of the message to inject is in a file. - >>> import os, tempfile - >>> fd, filename = tempfile.mkstemp() - >>> with os.fdopen(fd, 'w') as fp: + >>> from tempfile import NamedTemporaryFile + >>> filename = cleanups.enter_context(NamedTemporaryFile()).name + >>> with open(filename, 'w', encoding='utf-8') as fp: ... print("""\ ... From: aperson@example.com - ... To: test@example.com + ... To: ant@example.com ... Subject: testing ... Message-ID: <aardvark> ... ... This is a test message. ... """, file=fp) -However, the mailing list name is always required. +Create a mailing list to inject this message into. - >>> args.filename = filename - >>> command.process(args) - List name is required + >>> mlist = create_list('ant@example.com') + >>> transaction.commit() -Let's provide a list name and try again. -:: +The mailing list's incoming queue is empty. - >>> mlist = create_list('test@example.com') - >>> transaction.commit() >>> from mailman.testing.helpers import get_queue_messages - >>> get_queue_messages('in') [] - >>> args.listname = ['test@example.com'] - >>> command.process(args) -By default, the incoming queue is used. -:: +By default, messages are injected into the incoming queue. + >>> command('mailman inject --filename ' + filename + ' ant@example.com') >>> items = get_queue_messages('in') >>> len(items) 1 >>> print(items[0].msg.as_string()) From: aperson@example.com - To: test@example.com + To: ant@example.com Subject: testing Message-ID: ... Date: ... @@ -92,17 +66,19 @@ By default, the incoming queue is used. <BLANKLINE> <BLANKLINE> +And the message is destined for ant@example.com. + >>> dump_msgdata(items[0].msgdata) _parsemsg : False - listid : test.example.com - original_size: 253 + listid : ant.example.com + original_size: 252 version : 3 But a different queue can be specified on the command line. :: - >>> args.queue = 'virgin' - >>> command.process(args) + >>> command('mailman inject --queue virgin --filename ' + + ... filename + ' ant@example.com') >>> get_queue_messages('in') [] @@ -111,7 +87,7 @@ But a different queue can be specified on the command line. 1 >>> print(items[0].msg.as_string()) From: aperson@example.com - To: test@example.com + To: ant@example.com Subject: testing Message-ID: ... Date: ... @@ -122,8 +98,8 @@ But a different queue can be specified on the command line. >>> dump_msgdata(items[0].msgdata) _parsemsg : False - listid : test.example.com - original_size: 253 + listid : ant.example.com + original_size: 252 version : 3 @@ -133,29 +109,22 @@ Standard input The message text can also be provided on standard input. :: - >>> from io import StringIO - - >>> standard_in = StringIO(str("""\ + >>> stdin = """\ ... From: bperson@example.com - ... To: test@example.com + ... To: ant@example.com ... Subject: another test ... Message-ID: <badger> ... ... This is another test message. - ... """)) - - >>> import sys - >>> sys.stdin = standard_in - >>> args.filename = '-' - >>> args.queue = None + ... """ - >>> command.process(args) + >>> command('mailman inject --filename - ant@example.com', input=stdin) >>> items = get_queue_messages('in') >>> len(items) 1 >>> print(items[0].msg.as_string()) From: bperson@example.com - To: test@example.com + To: ant@example.com Subject: another test Message-ID: ... Date: ... @@ -166,14 +135,10 @@ The message text can also be provided on standard input. >>> dump_msgdata(items[0].msgdata) _parsemsg : False - listid : test.example.com - original_size: 261 + listid : ant.example.com + original_size: 260 version : 3 -.. Clean up. - >>> sys.stdin = sys.__stdin__ - >>> args.filename = filename - Metadata ======== @@ -183,39 +148,14 @@ pairs get added to the message metadata dictionary when the message is injected. :: - >>> args = FakeArgs() - >>> args.filename = filename - >>> args.listname = ['test@example.com'] - >>> args.keywords = ['foo=one', 'bar=two'] - >>> command.process(args) + >>> command('mailman inject --filename ' + filename + + ... ' -m foo=one -m bar=two ant@example.com') >>> items = get_queue_messages('in') >>> dump_msgdata(items[0].msgdata) _parsemsg : False bar : two foo : one - listid : test.example.com - original_size: 253 + listid : ant.example.com + original_size: 252 version : 3 - - -Errors -====== - -It is an error to specify a queue that doesn't exist. - - >>> args.queue = 'xxbogusxx' - >>> command.process(args) - No such queue: xxbogusxx - -It is also an error to specify a mailing list that doesn't exist. - - >>> args.queue = None - >>> args.listname = ['bogus'] - >>> command.process(args) - No such list: bogus - - -.. - # Clean up the tempfile. - >>> os.remove(filename) diff --git a/src/mailman/commands/docs/lists.rst b/src/mailman/commands/docs/lists.rst index 04e0d744d..317d06930 100644 --- a/src/mailman/commands/docs/lists.rst +++ b/src/mailman/commands/docs/lists.rst @@ -6,16 +6,8 @@ A system administrator can display all the mailing lists via the command line. When there are no mailing lists, a helpful message is displayed. :: - >>> class FakeArgs: - ... advertised = False - ... names = False - ... descriptions = False - ... quiet = False - ... domains = None - - >>> from mailman.commands.cli_lists import Lists - >>> command = Lists() - >>> command.process(FakeArgs) + >>> command = cli('mailman.commands.cli_lists.lists') + >>> command('mailman lists') No matching mailing lists found When there are a few mailing lists, they are shown in alphabetical order by @@ -36,7 +28,7 @@ their fully qualified list names, with a description. >>> mlist_3 = create_list('list-one@example.net') >>> mlist_3.description = 'List One in Example.Net' - >>> command.process(FakeArgs) + >>> command('mailman lists') 3 matching mailing lists found: list-one@example.com list-one@example.net @@ -49,8 +41,7 @@ Names You can display the mailing list names with their posting addresses, using the ``--names/-n`` switch. - >>> FakeArgs.names = True - >>> command.process(FakeArgs) + >>> command('mailman lists --names') 3 matching mailing lists found: list-one@example.com [List-one] list-one@example.net [List-one] @@ -63,8 +54,7 @@ Descriptions You can also display the mailing list descriptions, using the ``--descriptions/-d`` option. - >>> FakeArgs.descriptions = True - >>> command.process(FakeArgs) + >>> command('mailman lists --descriptions --names') 3 matching mailing lists found: list-one@example.com [List-one] - List One list-one@example.net [List-one] - List One in Example.Net @@ -72,8 +62,7 @@ You can also display the mailing list descriptions, using the Maybe you want the descriptions but not the names. - >>> FakeArgs.names = False - >>> command.process(FakeArgs) + >>> command('mailman lists --descriptions --no-names') 3 matching mailing lists found: list-one@example.com - List One list-one@example.net - List One in Example.Net @@ -85,9 +74,7 @@ Less verbosity There's also a ``--quiet/-q`` switch which reduces the verbosity a bit. - >>> FakeArgs.quiet = True - >>> FakeArgs.descriptions = False - >>> command.process(FakeArgs) + >>> command('mailman lists --quiet') list-one@example.com list-one@example.net list-two@example.com @@ -99,24 +86,20 @@ Specific domain You can narrow the search down to a specific domain with the --domain option. A helpful message is displayed if no matching domains are given. - >>> FakeArgs.quiet = False - >>> FakeArgs.domain = ['example.org'] - >>> command.process(FakeArgs) + >>> command('mailman lists --domain example.org') No matching mailing lists found But if a matching domain is given, only mailing lists in that domain are shown. - >>> FakeArgs.domain = ['example.net'] - >>> command.process(FakeArgs) + >>> command('mailman lists --domain example.net') 1 matching mailing lists found: list-one@example.net -More than one --domain argument can be given; then all mailing lists in +More than one ``--domain`` argument can be given; then all mailing lists in matching domains are shown. - >>> FakeArgs.domain = ['example.com', 'example.net'] - >>> command.process(FakeArgs) + >>> command('mailman lists --domain example.com --domain example.net') 3 matching mailing lists found: list-one@example.com list-one@example.net @@ -126,16 +109,13 @@ matching domains are shown. Advertised lists ================ -Mailing lists can be 'advertised' meaning their existence is public -knowledge. Non-advertised lists are considered private. Display through the -command line can select on this attribute. +Mailing lists can be "advertised" meaning their existence is public knowledge. +Non-advertised lists are considered private. Display through the command line +can select on this attribute. :: - >>> FakeArgs.domain = [] - >>> FakeArgs.advertised = True >>> mlist_1.advertised = False - - >>> command.process(FakeArgs) + >>> command('mailman lists --advertised') 2 matching mailing lists found: list-one@example.net list-two@example.com diff --git a/src/mailman/commands/docs/members.rst b/src/mailman/commands/docs/members.rst index c40afb122..4c266d63f 100644 --- a/src/mailman/commands/docs/members.rst +++ b/src/mailman/commands/docs/members.rst @@ -4,22 +4,8 @@ Managing members The ``mailman members`` command allows a site administrator to display, add, and remove members from a mailing list. -:: - - >>> ant = create_list('ant@example.com') - >>> class FakeArgs: - ... input_filename = None - ... output_filename = None - ... list = [] - ... regular = False - ... digest = None - ... nomail = None - ... role = None - >>> args = FakeArgs() - - >>> from mailman.commands.cli_members import Members - >>> command = Members() + >>> command = cli('mailman.commands.cli_members.members') Listing members @@ -28,11 +14,12 @@ Listing members You can list all the members of a mailing list by calling the command with no options. To start with, there are no members of the mailing list. - >>> args.list = ['ant.example.com'] - >>> command.process(args) + >>> ant = create_list('ant@example.com') + >>> command('mailman members ant.example.com') ant.example.com has no members Once the mailing list add some members, they will be displayed. +:: >>> from mailman.testing.helpers import subscribe >>> subscribe(ant, 'Anne', email='anne@example.com') @@ -41,7 +28,8 @@ Once the mailing list add some members, they will be displayed. >>> subscribe(ant, 'Bart', email='bart@example.com') <Member: Bart Person <bart@example.com> on ant@example.com as MemberRole.member> - >>> command.process(args) + + >>> command('mailman members ant.example.com') Anne Person <anne@example.com> Bart Person <bart@example.com> @@ -51,74 +39,69 @@ Members are displayed in alphabetical order based on their address. >>> subscribe(ant, 'Anne', email='anne@aaaxample.com') <Member: Anne Person <anne@aaaxample.com> on ant@example.com as MemberRole.member> - >>> command.process(args) + + >>> command('mailman members ant.example.com') Anne Person <anne@aaaxample.com> Anne Person <anne@example.com> Bart Person <bart@example.com> You can also output this list to a file. +:: >>> from tempfile import NamedTemporaryFile - >>> with NamedTemporaryFile() as outfp: - ... args.output_filename = outfp.name - ... command.process(args) - ... with open(args.output_filename) as infp: - ... print(infp.read()) + >>> filename = cleanups.enter_context(NamedTemporaryFile()).name + + >>> command('mailman members -o ' + filename + ' ant.example.com') + >>> with open(filename, 'r', encoding='utf-8') as fp: + ... print(fp.read()) Anne Person <anne@aaaxample.com> Anne Person <anne@example.com> Bart Person <bart@example.com> - >>> args.output_filename = None The output file can also be standard out. - >>> args.output_filename = '-' - >>> command.process(args) + >>> command('mailman members -o - ant.example.com') Anne Person <anne@aaaxample.com> Anne Person <anne@example.com> Bart Person <bart@example.com> - >>> args.output_filename = None Filtering on delivery mode -------------------------- You can limit output to just the regular non-digest members... +:: - >>> from mailman.interfaces.member import DeliveryMode - >>> args.regular = True >>> member = ant.members.get_member('anne@example.com') + >>> from mailman.interfaces.member import DeliveryMode >>> member.preferences.delivery_mode = DeliveryMode.plaintext_digests - >>> command.process(args) + + >>> command('mailman members --regular ant.example.com') Anne Person <anne@aaaxample.com> Bart Person <bart@example.com> ...or just the digest members. Furthermore, you can either display all digest members... +:: >>> member = ant.members.get_member('anne@aaaxample.com') >>> member.preferences.delivery_mode = DeliveryMode.mime_digests - >>> args.regular = False - >>> args.digest = 'any' - >>> command.process(args) + + >>> command('mailman members --digest any ant.example.com') Anne Person <anne@aaaxample.com> Anne Person <anne@example.com> ...just plain text digest members... - >>> args.digest = 'plaintext' - >>> command.process(args) + >>> command('mailman members --digest plaintext ant.example.com') Anne Person <anne@example.com> -...just MIME digest members. +...or just MIME digest members. :: - >>> args.digest = 'mime' - >>> command.process(args) + >>> command('mailman members --digest mime ant.example.com') Anne Person <anne@aaaxample.com> - # Reset for following tests. - >>> args.digest = None - Filtering on delivery status ---------------------------- @@ -142,48 +125,39 @@ status is enabled... >>> member = subscribe(ant, 'Elle', email='elle@example.com') >>> member.preferences.delivery_status = DeliveryStatus.by_bounces - >>> args.nomail = 'enabled' - >>> command.process(args) + >>> command('mailman members --nomail enabled ant.example.com') Anne Person <anne@example.com> Dave Person <dave@example.com> ...or disabled by the user... - >>> args.nomail = 'byuser' - >>> command.process(args) + >>> command('mailman members --nomail byuser ant.example.com') Bart Person <bart@example.com> ...or disabled by the list administrator (or moderator)... - >>> args.nomail = 'byadmin' - >>> command.process(args) + >>> command('mailman members --nomail byadmin ant.example.com') Anne Person <anne@aaaxample.com> ...or by the bounce processor... - >>> args.nomail = 'bybounces' - >>> command.process(args) + >>> command('mailman members --nomail bybounces ant.example.com') Elle Person <elle@example.com> ...or for unknown (legacy) reasons. - >>> args.nomail = 'unknown' - >>> command.process(args) + >>> command('mailman members --nomail unknown ant.example.com') Cris Person <cris@example.com> You can also display all members who have delivery disabled for any reason. :: - >>> args.nomail = 'any' - >>> command.process(args) + >>> command('mailman members --nomail any ant.example.com') Anne Person <anne@aaaxample.com> Bart Person <bart@example.com> Cris Person <cris@example.com> Elle Person <elle@example.com> - # Reset for following tests. - >>> args.nomail = None - Adding members ============== @@ -194,16 +168,14 @@ need a file containing email addresses and full names that can be parsed by :: >>> bee = create_list('bee@example.com') - >>> with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as fp: - ... for address in ('aperson@example.com', - ... 'Bart Person <bperson@example.com>', - ... 'cperson@example.com (Cate Person)', - ... ): - ... print(address, file=fp) - ... fp.flush() - ... args.input_filename = fp.name - ... args.list = ['bee.example.com'] - ... command.process(args) + >>> with open(filename, 'w', encoding='utf-8') as fp: + ... print("""\ + ... aperson@example.com + ... Bart Person <bperson@example.com> + ... cperson@example.com (Cate Person) + ... """, file=fp) + + >>> command('mailman members --add ' + filename + ' bee.example.com') >>> from operator import attrgetter >>> dump_list(bee.members.addresses, key=attrgetter('email')) @@ -215,22 +187,12 @@ You can also specify ``-`` as the filename, in which case the addresses are taken from standard input. :: - >>> from io import StringIO - >>> fp = StringIO() - >>> for address in ('dperson@example.com', - ... 'Elly Person <eperson@example.com>', - ... 'fperson@example.com (Fred Person)', - ... ): - ... print(address, file=fp) - >>> args.input_filename = '-' - >>> filepos = fp.seek(0) - >>> import sys - >>> try: - ... stdin = sys.stdin - ... sys.stdin = fp - ... command.process(args) - ... finally: - ... sys.stdin = stdin + >>> stdin = """\ + ... dperson@example.com + ... Elly Person <eperson@example.com> + ... fperson@example.com (Fred Person) + ... """ + >>> command('mailman members --add - bee.example.com', input=stdin) >>> dump_list(bee.members.addresses, key=attrgetter('email')) aperson@example.com @@ -243,16 +205,15 @@ taken from standard input. Blank lines and lines that begin with '#' are ignored. :: - >>> with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as fp: - ... for address in ('gperson@example.com', - ... '# hperson@example.com', - ... ' ', - ... '', - ... 'iperson@example.com', - ... ): - ... print(address, file=fp) - ... args.input_filename = fp.name - ... command.process(args) + >>> with open(filename, 'w', encoding='utf-8') as fp: + ... print("""\ + ... gperson@example.com + ... # hperson@example.com + ... + ... iperson@example.com + ... """, file=fp) + + >>> command('mailman members --add ' + filename + ' bee.example.com') >>> dump_list(bee.members.addresses, key=attrgetter('email')) aperson@example.com @@ -268,14 +229,14 @@ Addresses which are already subscribed are ignored, although a warning is printed. :: - >>> with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as fp: - ... for address in ('gperson@example.com', - ... 'aperson@example.com', - ... 'jperson@example.com', - ... ): - ... print(address, file=fp) - ... args.input_filename = fp.name - ... command.process(args) + >>> with open(filename, 'w', encoding='utf-8') as fp: + ... print("""\ + ... gperson@example.com + ... aperson@example.com + ... jperson@example.com + ... """, file=fp) + + >>> command('mailman members --add ' + filename + ' bee.example.com') Already subscribed (skipping): gperson@example.com Already subscribed (skipping): aperson@example.com @@ -296,8 +257,7 @@ Displaying members With no arguments, the command displays all members of the list. - >>> args.input_filename = None - >>> command.process(args) + >>> command('mailman members bee.example.com') aperson@example.com Bart Person <bperson@example.com> Cate Person <cperson@example.com> diff --git a/src/mailman/commands/docs/qfile.rst b/src/mailman/commands/docs/qfile.rst index e097ebf97..4b0d887b7 100644 --- a/src/mailman/commands/docs/qfile.rst +++ b/src/mailman/commands/docs/qfile.rst @@ -5,8 +5,6 @@ Dumping queue files The ``qfile`` command dumps the contents of a queue pickle file. This is especially useful when you have shunt files you want to inspect. -XXX Test the interactive operation of qfile - Pretty printing =============== @@ -15,20 +13,14 @@ By default, the ``qfile`` command pretty prints the contents of a queue pickle file to standard output. :: - >>> from mailman.commands.cli_qfile import QFile - >>> command = QFile() - - >>> class FakeArgs: - ... interactive = False - ... doprint = True - ... qfile = [] + >>> command = cli('mailman.commands.cli_qfile.qfile') Let's say Mailman shunted a message file. :: >>> msg = message_from_string("""\ ... From: aperson@example.com - ... To: test@example.com + ... To: ant@example.com ... Subject: Uh oh ... ... I borkeded Mailman. @@ -43,12 +35,11 @@ Once we've figured out the file name of the shunted message, we can print it. >>> from os.path import join >>> qfile = join(shuntq.queue_directory, basename + '.pck') - >>> FakeArgs.qfile = [qfile] - >>> command.process(FakeArgs) + >>> command('mailman qfile ' + qfile) [----- start pickle -----] <----- start object 1 -----> From: aperson@example.com - To: test@example.com + To: ant@example.com Subject: Uh oh <BLANKLINE> I borkeded Mailman. @@ -60,5 +51,4 @@ Once we've figured out the file name of the shunted message, we can print it. Maybe we don't want to print the contents of the file though, in case we want to enter the interactive prompt. - >>> FakeArgs.doprint = False - >>> command.process(FakeArgs) + >>> command('mailman qfile --no-print ' + qfile) diff --git a/src/mailman/commands/docs/remove.rst b/src/mailman/commands/docs/remove.rst index c534741f3..f13d8cacd 100644 --- a/src/mailman/commands/docs/remove.rst +++ b/src/mailman/commands/docs/remove.rst @@ -5,37 +5,26 @@ Command line list removal A system administrator can remove mailing lists by the command line. :: - >>> create_list('test@example.com') - <mailing list "test@example.com" at ...> + >>> create_list('ant@example.com') + <mailing list "ant@example.com" at ...> + + >>> command = cli('mailman.commands.cli_lists.remove') + >>> command('mailman remove ant@example.com') + Removed list: ant@example.com >>> from mailman.interfaces.listmanager import IListManager >>> from zope.component import getUtility >>> list_manager = getUtility(IListManager) - >>> list_manager.get('test@example.com') - <mailing list "test@example.com" at ...> - - >>> class FakeArgs: - ... quiet = False - ... archives = False - ... listname = ['test@example.com'] - >>> args = FakeArgs() - - >>> from mailman.commands.cli_lists import Remove - >>> command = Remove() - >>> command.process(args) - Removed list: test@example.com - - >>> print(list_manager.get('test@example.com')) + >>> print(list_manager.get('ant@example.com')) None You can also remove lists quietly. :: - >>> create_list('test@example.com') - <mailing list "test@example.com" at ...> + >>> create_list('ant@example.com') + <mailing list "ant@example.com" at ...> - >>> args.quiet = True - >>> command.process(args) + >>> command('mailman remove ant@example.com --quiet') - >>> print(list_manager.get('test@example.com')) + >>> print(list_manager.get('ant@example.com')) None diff --git a/src/mailman/commands/docs/withlist.rst b/src/mailman/commands/docs/shell.rst index d551cb9d6..545376e51 100644 --- a/src/mailman/commands/docs/withlist.rst +++ b/src/mailman/commands/docs/shell.rst @@ -11,110 +11,93 @@ through custom made Python functions. Getting detailed help ===================== -Because ``withlist`` is so complex, you need to request detailed help. +Because ``shell`` is so complex, you might want to read the detailed help. :: - >>> from mailman.commands.cli_withlist import Withlist - >>> command = Withlist() + >>> command = cli('mailman.commands.cli_withlist.shell') - >>> class FakeArgs: - ... interactive = False - ... run = None - ... details = True - ... listname = [] - - >>> class FakeParser: - ... def error(self, message): - ... print(message) - >>> command.parser = FakeParser() - - >>> args = FakeArgs() - >>> command.process(args) + >>> command('mailman shell --details') This script provides you with a general framework for interacting with a mailing list. ... -Running a command -================= +Running a function +================== By putting a Python function somewhere on your ``sys.path``, you can have -``withlist`` call that function on a given mailing list. The function takes a -single argument, the mailing list. -:: +``shell`` call that function on a given mailing list. >>> import os, sys >>> old_path = sys.path[:] >>> sys.path.insert(0, config.VAR_DIR) +.. cleanup + >>> ignore = cleanups.callback(setattr, sys, 'path', old_path) + +The function takes at least a single argument, the mailing list. +:: + >>> with open(os.path.join(config.VAR_DIR, 'showme.py'), 'w') as fp: ... print("""\ - ... def showme(mailing_list): - ... print("The list's name is", mailing_list.fqdn_listname) + ... def showme(mlist): + ... print("The list's name is", mlist.fqdn_listname) + ... + ... def displayname(mlist): + ... print("The list's display name is", mlist.display_name) ... - ... def displayname(mailing_list): - ... print("The list's display name is", mailing_list.display_name) + ... def changeme(mlist, display_name): + ... mlist.display_name = display_name ... """, file=fp) If the name of the function is the same as the module, then you only need to name the function once. - >>> mlist = create_list('aardvark@example.com') - >>> args.details = False - >>> args.run = 'showme' - >>> args.listname = 'aardvark@example.com' - >>> command.process(args) - The list's name is aardvark@example.com + >>> mlist = create_list('ant@example.com') + >>> command('mailman shell -l ant@example.com --run showme') + The list's name is ant@example.com The function's name can also be different than the modules name. In that case, just give the full module path name to the function you want to call. - >>> args.run = 'showme.displayname' - >>> command.process(args) - The list's display name is Aardvark + >>> command('mailman shell -l ant@example.com --run showme.displayname') + The list's display name is Ant + + +Passing arguments +================= + +Your function can also accept an arbitrary number of arguments. Every command +line argument after the callable name is passed as a positional argument to +the function. For example, to change the mailing list's display name, you can +do this:: + + >>> command('mailman shell -l ant@example.com --run showme.changeme ANT!') + >>> print(mlist.display_name) + ANT! Multiple lists ============== You can run a command over more than one list by using a regular expression in -the `listname` argument. To indicate a regular expression is used, the string -must start with a caret. +the ``listname`` argument. To indicate a regular expression is used, the +string must start with a caret. :: >>> mlist_2 = create_list('badger@example.com') >>> mlist_3 = create_list('badboys@example.com') - >>> args.listname = '^.*example.com' - >>> command.process(args) - The list's display name is Aardvark + >>> command('mailman shell --run showme.displayname -l ^.*example.com') + The list's display name is ANT! The list's display name is Badboys The list's display name is Badger - >>> args.listname = '^bad.*' - >>> command.process(args) + >>> command('mailman shell --run showme.displayname -l ^bad.*') The list's display name is Badboys The list's display name is Badger - >>> args.listname = '^foo' - >>> command.process(args) - - -Error handling -============== - -You get an error if you try to run a function over a non-existent mailing -list. - - >>> args.listname = 'mystery@example.com' - >>> command.process(args) - No such list: mystery@example.com - -You also get an error if no mailing list is named. - - >>> args.listname = None - >>> command.process(args) - --run requires a mailing list name + >>> command('mailman shell --run showme.displayname -l ^foo') Interactive use @@ -153,9 +136,6 @@ IPython must be installed and available on your system When using IPython, the ``[shell]history_file`` is not used. -.. Clean up - >>> sys.path = old_path - .. _IPython: http://ipython.org/ .. _REPL: https://en.wikipedia.org/wiki/REPL .. _`GNU readline`: https://docs.python.org/3/library/readline.html diff --git a/src/mailman/commands/docs/status.rst b/src/mailman/commands/docs/status.rst index 7587157bc..1824e1717 100644 --- a/src/mailman/commands/docs/status.rst +++ b/src/mailman/commands/docs/status.rst @@ -6,32 +6,27 @@ The status of the Mailman master process can be queried from the command line. It's clear at this point that nothing is running. :: - >>> from mailman.commands.cli_status import Status - >>> status = Status() - - >>> class FakeArgs: - ... pass + >>> command = cli('mailman.commands.cli_status.status') The status is printed to stdout and a status code is returned. - >>> status.process(FakeArgs) + >>> command('mailman status') GNU Mailman is not running - 0 We can simulate the master starting up by acquiring its lock. >>> from flufl.lock import Lock >>> lock = Lock(config.LOCK_FILE) >>> lock.lock() + >>> ignore = cleanups.callback(lock.unlock, unconditionally=True) Getting the status confirms that the master is running. - >>> status.process(FakeArgs) + >>> command('mailman status') GNU Mailman is running (master pid: ... We shut down the master and confirm the status. - >>> lock.unlock() - >>> status.process(FakeArgs) + >>> lock.unlock(unconditionally=True) + >>> command('mailman status') GNU Mailman is not running - 0 diff --git a/src/mailman/commands/docs/unshunt.rst b/src/mailman/commands/docs/unshunt.rst index 9532ae029..fb2a4b602 100644 --- a/src/mailman/commands/docs/unshunt.rst +++ b/src/mailman/commands/docs/unshunt.rst @@ -7,11 +7,7 @@ the ``shunt`` queue. The ``unshunt`` command allows system administrators to manage the shunt queue. :: - >>> from mailman.commands.cli_unshunt import Unshunt - >>> command = Unshunt() - - >>> class FakeArgs: - ... discard = False + >>> command = cli('mailman.commands.cli_unshunt.unshunt') Let's say there is a message in the shunt queue. :: @@ -39,7 +35,7 @@ queue. >>> len(list(inq.files)) 0 - >>> command.process(FakeArgs) + >>> command('mailman unshunt') >>> from mailman.testing.helpers import get_queue_messages >>> items = get_queue_messages('in') @@ -77,7 +73,7 @@ queue. >>> len(list(shuntq.files)) 2 - >>> command.process(FakeArgs) + >>> command('mailman unshunt') >>> items = get_queue_messages('in') >>> len(items) 2 @@ -114,7 +110,7 @@ The queue that the message comes from is in message metadata. The message is automatically re-queued to the bounces queue. :: - >>> command.process(FakeArgs) + >>> command('mailman unshunt') >>> len(list(shuntq.files)) 0 >>> items = get_queue_messages('bounces') @@ -145,8 +141,7 @@ If you don't care about the shunted messages, just discard them. ... """) >>> base_name = shuntq.enqueue(msg, {}) - >>> FakeArgs.discard = True - >>> command.process(FakeArgs) + >>> command('mailman unshunt --discard') The messages are now gone. diff --git a/src/mailman/commands/docs/version.rst b/src/mailman/commands/docs/version.rst index 8032df20a..47667ac4a 100644 --- a/src/mailman/commands/docs/version.rst +++ b/src/mailman/commands/docs/version.rst @@ -2,11 +2,8 @@ Printing the version ==================== -You can print the Mailman version number. -:: +You can print the Mailman version number by invoking the ``version`` command. - >>> from mailman.commands.cli_version import Version - >>> command = Version() - - >>> command.process(None) + >>> command = cli('mailman.commands.cli_version.version') + >>> command('mailman version') GNU Mailman 3... |
