blob: 88877a2f456a3bc0702954e9ce27b6c2da3359e7 [file] [log] [blame]
R David Murray3edd22a2011-04-18 13:59:37 -04001"""Policy framework for the email package.
2
3Allows fine grained feature control of how the package parses and emits data.
4"""
5
6__all__ = [
7 'Policy',
8 'default',
9 'strict',
10 'SMTP',
11 'HTTP',
12 ]
13
14
15class _PolicyBase:
16
17 """Policy Object basic framework.
18
19 This class is useless unless subclassed. A subclass should define
20 class attributes with defaults for any values that are to be
21 managed by the Policy object. The constructor will then allow
22 non-default values to be set for these attributes at instance
23 creation time. The instance will be callable, taking these same
24 attributes keyword arguments, and returning a new instance
25 identical to the called instance except for those values changed
26 by the keyword arguments. Instances may be added, yielding new
27 instances with any non-default values from the right hand
28 operand overriding those in the left hand operand. That is,
29
30 A + B == A(<non-default values of B>)
31
32 The repr of an instance can be used to reconstruct the object
33 if and only if the repr of the values can be used to reconstruct
34 those values.
35
36 """
37
38 def __init__(self, **kw):
39 """Create new Policy, possibly overriding some defaults.
40
41 See class docstring for a list of overridable attributes.
42
43 """
44 for name, value in kw.items():
45 if hasattr(self, name):
46 super(_PolicyBase,self).__setattr__(name, value)
47 else:
48 raise TypeError(
49 "{!r} is an invalid keyword argument for {}".format(
50 name, self.__class__.__name__))
51
52 def __repr__(self):
53 args = [ "{}={!r}".format(name, value)
54 for name, value in self.__dict__.items() ]
55 return "{}({})".format(self.__class__.__name__, args if args else '')
56
57 def clone(self, **kw):
58 """Return a new instance with specified attributes changed.
59
60 The new instance has the same attribute values as the current object,
61 except for the changes passed in as keyword arguments.
62
63 """
64 for attr, value in self.__dict__.items():
65 if attr not in kw:
66 kw[attr] = value
67 return self.__class__(**kw)
68
69 def __setattr__(self, name, value):
70 if hasattr(self, name):
71 msg = "{!r} object attribute {!r} is read-only"
72 else:
73 msg = "{!r} object has no attribute {!r}"
74 raise AttributeError(msg.format(self.__class__.__name__, name))
75
76 def __add__(self, other):
77 """Non-default values from right operand override those from left.
78
79 The object returned is a new instance of the subclass.
80
81 """
82 return self.clone(**other.__dict__)
83
84
85class Policy(_PolicyBase):
86
87 """Controls for how messages are interpreted and formatted.
88
89 Most of the classes and many of the methods in the email package
90 accept Policy objects as parameters. A Policy object contains a set
91 of values and functions that control how input is interpreted and how
92 output is rendered. For example, the parameter 'raise_on_defect'
93 controls whether or not an RFC violation throws an error or not,
94 while 'max_line_length' controls the maximum length of output lines
95 when a Message is serialized.
96
97 Any valid attribute may be overridden when a Policy is created by
98 passing it as a keyword argument to the constructor. Policy
99 objects are immutable, but a new Policy object can be created
100 with only certain values changed by calling the Policy instance
101 with keyword arguments. Policy objects can also be added,
102 producing a new Policy object in which the non-default attributes
103 set in the right hand operand overwrite those specified in the
104 left operand.
105
106 Settable attributes:
107
108 raise_on_defect -- If true, then defects should be raised
109 as errors. Default False.
110
111 linesep -- string containing the value to use as
112 separation between output lines. Default '\n'.
113
114 must_be_7bit -- output must contain only 7bit clean data.
115 Default False.
116
117 max_line_length -- maximum length of lines, excluding 'linesep',
118 during serialization. None means no line
119 wrapping is done. Default is 78.
120
121 Methods:
122
123 register_defect(obj, defect)
124 defect is a Defect instance. The default implementation appends defect
125 to the objs 'defects' attribute.
126
127 handle_defect(obj, defect)
128 intended to be called by parser code that finds a defect. If
129 raise_on_defect is True, defect is raised as an error, otherwise
130 register_defect is called.
131
132 """
133
134 raise_on_defect = False
135 linesep = '\n'
136 must_be_7bit = False
137 max_line_length = 78
138
139 def handle_defect(self, obj, defect):
140 """Based on policy, either raise defect or call register_defect.
141
142 handle_defect(obj, defect)
143
144 defect should be a Defect subclass, but in any case must be an
145 Exception subclass. obj is the object on which the defect should be
146 registered if it is not raised. If the raise_on_defect is True, the
147 defect is raised as an error, otherwise the object and the defect are
148 passed to register_defect.
149
150 This class is intended to be called by parsers that discover defects,
151 and will not be called from code using the library unless that code is
152 implementing an alternate parser.
153
154 """
155 if self.raise_on_defect:
156 raise defect
157 self.register_defect(obj, defect)
158
159 def register_defect(self, obj, defect):
160 """Record 'defect' on 'obj'.
161
162 Called by handle_defect if raise_on_defect is False. This method is
163 part of the Policy API so that Policy subclasses can implement custom
164 defect handling. The default implementation calls the append method
165 of the defects attribute of obj.
166
167 """
168 obj.defects.append(defect)
169
170
171default = Policy()
172strict = default.clone(raise_on_defect=True)
173SMTP = default.clone(linesep='\r\n')
174HTTP = default.clone(linesep='\r\n', max_line_length=None)