4 The switchboard is subsystem that moves messages between queues. Each
5 instance of a switchboard is responsible for one queue directory.
7 >>> msg = message_from_string("""\
8 ... From: aperson@example.com
9 ... To: _xtest@example.com
14 Create a switchboard by giving its queue directory.
17 >>> queue_directory = os.path.join(config.QUEUE_DIR, 'test')
18 >>> from mailman.queue import Switchboard
19 >>> switchboard = Switchboard(queue_directory)
20 >>> switchboard.queue_directory == queue_directory
23 Here's a helper function for ensuring things work correctly.
25 >>> def check_qfiles(directory=None):
26 ... if directory is None:
27 ... directory = queue_directory
29 ... for qfile in os.listdir(directory):
30 ... root, ext = os.path.splitext(qfile)
31 ... files[ext] = files.get(ext, 0) + 1
32 ... return sorted(files.items())
38 The message can be enqueued with metadata specified in the passed in
41 >>> filebase = switchboard.enqueue(msg)
45 To read the contents of a queue file, dequeue it.
47 >>> msg, msgdata = switchboard.dequeue(filebase)
48 >>> print msg.as_string()
49 From: aperson@example.com
50 To: _xtest@example.com
54 >>> sorted(msgdata.items())
55 [('_parsemsg', False), ('received_time', ...), ('version', 3)]
59 To complete the dequeing process, removing all traces of the message file,
60 finish it (without preservation).
62 >>> switchboard.finish(filebase)
66 When enqueing a file, you can provide additional metadata keys by using
69 >>> filebase = switchboard.enqueue(msg, {'foo': 1}, bar=2)
70 >>> msg, msgdata = switchboard.dequeue(filebase)
71 >>> switchboard.finish(filebase)
72 >>> sorted(msgdata.items())
73 [('_parsemsg', False),
74 ('bar', 2), ('foo', 1),
75 ('received_time', ...), ('version', 3)]
77 Keyword arguments override keys from the metadata dictionary.
79 >>> filebase = switchboard.enqueue(msg, {'foo': 1}, foo=2)
80 >>> msg, msgdata = switchboard.dequeue(filebase)
81 >>> switchboard.finish(filebase)
82 >>> sorted(msgdata.items())
83 [('_parsemsg', False),
85 ('received_time', ...), ('version', 3)]
91 There are two ways to iterate over all the files in a switchboard's queue.
92 Normally, queue files end in .pck (for 'pickle') and the easiest way to
93 iterate over just these files is to use the .files attribute.
95 >>> filebase_1 = switchboard.enqueue(msg, foo=1)
96 >>> filebase_2 = switchboard.enqueue(msg, foo=2)
97 >>> filebase_3 = switchboard.enqueue(msg, foo=3)
98 >>> filebases = sorted((filebase_1, filebase_2, filebase_3))
99 >>> sorted(switchboard.files) == filebases
104 You can also use the .get_files() method if you want to iterate over all the
105 file bases for some other extension.
107 >>> for filebase in switchboard.get_files():
108 ... msg, msgdata = switchboard.dequeue(filebase)
109 >>> bakfiles = sorted(switchboard.get_files('.bak'))
110 >>> bakfiles == filebases
114 >>> for filebase in switchboard.get_files('.bak'):
115 ... switchboard.finish(filebase)
123 Calling .dequeue() without calling .finish() leaves .bak backup files in
124 place. These can be recovered when the switchboard is instantiated.
126 >>> filebase_1 = switchboard.enqueue(msg, foo=1)
127 >>> filebase_2 = switchboard.enqueue(msg, foo=2)
128 >>> filebase_3 = switchboard.enqueue(msg, foo=3)
129 >>> for filebase in switchboard.files:
130 ... msg, msgdata = switchboard.dequeue(filebase)
131 ... # Don't call .finish()
134 >>> switchboard_2 = Switchboard(queue_directory, recover=True)
138 The files can be recovered explicitly.
140 >>> for filebase in switchboard.files:
141 ... msg, msgdata = switchboard.dequeue(filebase)
142 ... # Don't call .finish()
145 >>> switchboard.recover_backup_files()
149 But the files will only be recovered at most three times before they are
150 considered defective. In order to prevent mail bombs and loops, once this
151 maximum is reached, the files will be preserved in the 'bad' queue.
153 >>> for filebase in switchboard.files:
154 ... msg, msgdata = switchboard.dequeue(filebase)
155 ... # Don't call .finish()
158 >>> switchboard.recover_backup_files()
162 >>> bad = config.switchboards['bad']
163 >>> check_qfiles(bad.queue_directory)
168 >>> for file in os.listdir(bad.queue_directory):
169 ... os.remove(os.path.join(bad.queue_directory, file))
170 >>> check_qfiles(bad.queue_directory)
177 XXX Add tests for queue slices.