1==========================
2Operating on mailing lists
3==========================
4
5The ``shell`` (alias: ``withlist``) command is a pretty powerful way to
6operate on mailing lists from the command line.  This command allows you to
7interact with a list at a Python prompt, or process one or more mailing lists
8through custom made Python functions.
9
10
11Getting detailed help
12=====================
13
14Because ``shell`` is so complex, you might want to read the detailed help.
15::
16
17    >>> command = cli('mailman.commands.cli_withlist.shell')
18
19    >>> command('mailman shell --details')
20    This script provides you with a general framework for interacting with a
21    mailing list.
22    ...
23
24
25Running a function
26==================
27
28By putting a Python function somewhere on your ``sys.path``, you can have
29``shell`` call that function on a given mailing list.
30
31    >>> import os, sys
32    >>> old_path = sys.path[:]
33    >>> sys.path.insert(0, config.VAR_DIR)
34
35.. cleanup
36    >>> ignore = cleanups.callback(setattr, sys, 'path', old_path)
37
38The function takes at least a single argument, the mailing list.
39::
40
41    >>> with open(os.path.join(config.VAR_DIR, 'showme.py'), 'w') as fp:
42    ...     print("""\
43    ... def showme(mlist):
44    ...     print("The list's name is", mlist.fqdn_listname)
45    ...
46    ... def displayname(mlist):
47    ...     print("The list's display name is", mlist.display_name)
48    ...
49    ... def changeme(mlist, display_name):
50    ...     mlist.display_name = display_name
51    ... """, file=fp)
52
53If the name of the function is the same as the module, then you only need to
54name the function once.
55
56    >>> mlist = create_list('ant@example.com')
57    >>> command('mailman shell -l ant@example.com --run showme')
58    The list's name is ant@example.com
59
60The function's name can also be different than the modules name.  In that
61case, just give the full module path name to the function you want to call.
62
63    >>> command('mailman shell -l ant@example.com --run showme.displayname')
64    The list's display name is Ant
65
66
67Passing arguments
68=================
69
70Your function can also accept an arbitrary number of arguments.  Every command
71line argument after the callable name is passed as a positional argument to
72the function.  For example, to change the mailing list's display name, you can
73do this::
74
75    >>> command('mailman shell -l ant@example.com --run showme.changeme ANT!')
76    >>> print(mlist.display_name)
77    ANT!
78
79
80Multiple lists
81==============
82
83You can run a command over more than one list by using a regular expression in
84the ``listname`` argument.  To indicate a regular expression is used, the
85string must start with a caret.
86::
87
88    >>> mlist_2 = create_list('badger@example.com')
89    >>> mlist_3 = create_list('badboys@example.com')
90
91    >>> command('mailman shell --run showme.displayname -l ^.*example.com')
92    The list's display name is ANT!
93    The list's display name is Badboys
94    The list's display name is Badger
95
96    >>> command('mailman shell --run showme.displayname -l ^bad.*')
97    The list's display name is Badboys
98    The list's display name is Badger
99
100    >>> command('mailman shell --run showme.displayname -l ^foo')
101
102
103Interactive use
104===============
105
106You can also get an interactive prompt which allows you to inspect a live
107Mailman system directly.  Through the ``mailman.cfg`` file, you can set the
108prompt and banner, and you can choose between the standard Python REPL_ or
109IPython.
110
111If the `GNU readline`_ library is available, it will be enabled automatically,
112giving you command line editing and other features.  You can also set the
113``[shell]history_file`` variable in the ``mailman.cfg`` file and when the
114normal Python REPL is used, your interactive commands will be written to and
115read from this file.
116
117Note that the ``$PYTHONSTARTUP`` environment variable will also be honored if
118set, and any file named by this variable will be read at start up time.  It's
119common practice to *also* enable GNU readline history in a ``$PYTHONSTARTUP``
120file and if you do this, be aware that it will interact badly with
121``[shell]history_file``, causing your history to be written twice.  To disable
122this when using the interactive ``shell`` command, do something like::
123
124    $ PYTHONSTARTUP= mailman shell
125
126to temporarily unset the environment variable.
127
128
129IPython
130-------
131
132You can use IPython_ as the interactive shell by setting the
133``[shell]use_ipython`` variables in your `mailman.cfg` file to ``yes``.
134IPython must be installed and available on your system
135
136When using IPython, the ``[shell]history_file`` is not used.
137
138
139.. _IPython: http://ipython.org/
140.. _REPL: https://en.wikipedia.org/wiki/REPL
141.. _`GNU readline`: https://docs.python.org/3/library/readline.html
142