ยปCore Development>Code coverage>Lib/string.py

Python code coverage for Lib/string.py

#countcontent
1n/a"""A collection of string constants.
2n/a
3n/aPublic module variables:
4n/a
5n/awhitespace -- a string containing all ASCII whitespace
6n/aascii_lowercase -- a string containing all ASCII lowercase letters
7n/aascii_uppercase -- a string containing all ASCII uppercase letters
8n/aascii_letters -- a string containing all ASCII letters
9n/adigits -- a string containing all ASCII decimal digits
10n/ahexdigits -- a string containing all ASCII hexadecimal digits
11n/aoctdigits -- a string containing all ASCII octal digits
12n/apunctuation -- a string containing all ASCII punctuation characters
13n/aprintable -- a string containing all ASCII characters considered printable
14n/a
15n/a"""
16n/a
17n/a__all__ = ["ascii_letters", "ascii_lowercase", "ascii_uppercase", "capwords",
18n/a "digits", "hexdigits", "octdigits", "printable", "punctuation",
19n/a "whitespace", "Formatter", "Template"]
20n/a
21n/aimport _string
22n/a
23n/a# Some strings for ctype-style character classification
24n/awhitespace = ' \t\n\r\v\f'
25n/aascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
26n/aascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
27n/aascii_letters = ascii_lowercase + ascii_uppercase
28n/adigits = '0123456789'
29n/ahexdigits = digits + 'abcdef' + 'ABCDEF'
30n/aoctdigits = '01234567'
31n/apunctuation = r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
32n/aprintable = digits + ascii_letters + punctuation + whitespace
33n/a
34n/a# Functions which aren't available as string methods.
35n/a
36n/a# Capitalize the words in a string, e.g. " aBc dEf " -> "Abc Def".
37n/adef capwords(s, sep=None):
38n/a """capwords(s [,sep]) -> string
39n/a
40n/a Split the argument into words using split, capitalize each
41n/a word using capitalize, and join the capitalized words using
42n/a join. If the optional second argument sep is absent or None,
43n/a runs of whitespace characters are replaced by a single space
44n/a and leading and trailing whitespace are removed, otherwise
45n/a sep is used to split and join the words.
46n/a
47n/a """
48n/a return (sep or ' ').join(x.capitalize() for x in s.split(sep))
49n/a
50n/a
51n/a####################################################################
52n/aimport re as _re
53n/afrom collections import ChainMap as _ChainMap
54n/a
55n/aclass _TemplateMetaclass(type):
56n/a pattern = r"""
57n/a %(delim)s(?:
58n/a (?P<escaped>%(delim)s) | # Escape sequence of two delimiters
59n/a (?P<named>%(id)s) | # delimiter and a Python identifier
60n/a {(?P<braced>%(id)s)} | # delimiter and a braced identifier
61n/a (?P<invalid>) # Other ill-formed delimiter exprs
62n/a )
63n/a """
64n/a
65n/a def __init__(cls, name, bases, dct):
66n/a super(_TemplateMetaclass, cls).__init__(name, bases, dct)
67n/a if 'pattern' in dct:
68n/a pattern = cls.pattern
69n/a else:
70n/a pattern = _TemplateMetaclass.pattern % {
71n/a 'delim' : _re.escape(cls.delimiter),
72n/a 'id' : cls.idpattern,
73n/a }
74n/a cls.pattern = _re.compile(pattern, cls.flags | _re.VERBOSE)
75n/a
76n/a
77n/aclass Template(metaclass=_TemplateMetaclass):
78n/a """A string class for supporting $-substitutions."""
79n/a
80n/a delimiter = '$'
81n/a idpattern = r'[_a-z][_a-z0-9]*'
82n/a flags = _re.IGNORECASE
83n/a
84n/a def __init__(self, template):
85n/a self.template = template
86n/a
87n/a # Search for $$, $identifier, ${identifier}, and any bare $'s
88n/a
89n/a def _invalid(self, mo):
90n/a i = mo.start('invalid')
91n/a lines = self.template[:i].splitlines(keepends=True)
92n/a if not lines:
93n/a colno = 1
94n/a lineno = 1
95n/a else:
96n/a colno = i - len(''.join(lines[:-1]))
97n/a lineno = len(lines)
98n/a raise ValueError('Invalid placeholder in string: line %d, col %d' %
99n/a (lineno, colno))
100n/a
101n/a def substitute(*args, **kws):
102n/a if not args:
103n/a raise TypeError("descriptor 'substitute' of 'Template' object "
104n/a "needs an argument")
105n/a self, *args = args # allow the "self" keyword be passed
106n/a if len(args) > 1:
107n/a raise TypeError('Too many positional arguments')
108n/a if not args:
109n/a mapping = kws
110n/a elif kws:
111n/a mapping = _ChainMap(kws, args[0])
112n/a else:
113n/a mapping = args[0]
114n/a # Helper function for .sub()
115n/a def convert(mo):
116n/a # Check the most common path first.
117n/a named = mo.group('named') or mo.group('braced')
118n/a if named is not None:
119n/a return str(mapping[named])
120n/a if mo.group('escaped') is not None:
121n/a return self.delimiter
122n/a if mo.group('invalid') is not None:
123n/a self._invalid(mo)
124n/a raise ValueError('Unrecognized named group in pattern',
125n/a self.pattern)
126n/a return self.pattern.sub(convert, self.template)
127n/a
128n/a def safe_substitute(*args, **kws):
129n/a if not args:
130n/a raise TypeError("descriptor 'safe_substitute' of 'Template' object "
131n/a "needs an argument")
132n/a self, *args = args # allow the "self" keyword be passed
133n/a if len(args) > 1:
134n/a raise TypeError('Too many positional arguments')
135n/a if not args:
136n/a mapping = kws
137n/a elif kws:
138n/a mapping = _ChainMap(kws, args[0])
139n/a else:
140n/a mapping = args[0]
141n/a # Helper function for .sub()
142n/a def convert(mo):
143n/a named = mo.group('named') or mo.group('braced')
144n/a if named is not None:
145n/a try:
146n/a return str(mapping[named])
147n/a except KeyError:
148n/a return mo.group()
149n/a if mo.group('escaped') is not None:
150n/a return self.delimiter
151n/a if mo.group('invalid') is not None:
152n/a return mo.group()
153n/a raise ValueError('Unrecognized named group in pattern',
154n/a self.pattern)
155n/a return self.pattern.sub(convert, self.template)
156n/a
157n/a
158n/a
159n/a########################################################################
160n/a# the Formatter class
161n/a# see PEP 3101 for details and purpose of this class
162n/a
163n/a# The hard parts are reused from the C implementation. They're exposed as "_"
164n/a# prefixed methods of str.
165n/a
166n/a# The overall parser is implemented in _string.formatter_parser.
167n/a# The field name parser is implemented in _string.formatter_field_name_split
168n/a
169n/aclass Formatter:
170n/a def format(*args, **kwargs):
171n/a if not args:
172n/a raise TypeError("descriptor 'format' of 'Formatter' object "
173n/a "needs an argument")
174n/a self, *args = args # allow the "self" keyword be passed
175n/a try:
176n/a format_string, *args = args # allow the "format_string" keyword be passed
177n/a except ValueError:
178n/a raise TypeError("format() missing 1 required positional "
179n/a "argument: 'format_string'") from None
180n/a return self.vformat(format_string, args, kwargs)
181n/a
182n/a def vformat(self, format_string, args, kwargs):
183n/a used_args = set()
184n/a result, _ = self._vformat(format_string, args, kwargs, used_args, 2)
185n/a self.check_unused_args(used_args, args, kwargs)
186n/a return result
187n/a
188n/a def _vformat(self, format_string, args, kwargs, used_args, recursion_depth,
189n/a auto_arg_index=0):
190n/a if recursion_depth < 0:
191n/a raise ValueError('Max string recursion exceeded')
192n/a result = []
193n/a for literal_text, field_name, format_spec, conversion in \
194n/a self.parse(format_string):
195n/a
196n/a # output the literal text
197n/a if literal_text:
198n/a result.append(literal_text)
199n/a
200n/a # if there's a field, output it
201n/a if field_name is not None:
202n/a # this is some markup, find the object and do
203n/a # the formatting
204n/a
205n/a # handle arg indexing when empty field_names are given.
206n/a if field_name == '':
207n/a if auto_arg_index is False:
208n/a raise ValueError('cannot switch from manual field '
209n/a 'specification to automatic field '
210n/a 'numbering')
211n/a field_name = str(auto_arg_index)
212n/a auto_arg_index += 1
213n/a elif field_name.isdigit():
214n/a if auto_arg_index:
215n/a raise ValueError('cannot switch from manual field '
216n/a 'specification to automatic field '
217n/a 'numbering')
218n/a # disable auto arg incrementing, if it gets
219n/a # used later on, then an exception will be raised
220n/a auto_arg_index = False
221n/a
222n/a # given the field_name, find the object it references
223n/a # and the argument it came from
224n/a obj, arg_used = self.get_field(field_name, args, kwargs)
225n/a used_args.add(arg_used)
226n/a
227n/a # do any conversion on the resulting object
228n/a obj = self.convert_field(obj, conversion)
229n/a
230n/a # expand the format spec, if needed
231n/a format_spec, auto_arg_index = self._vformat(
232n/a format_spec, args, kwargs,
233n/a used_args, recursion_depth-1,
234n/a auto_arg_index=auto_arg_index)
235n/a
236n/a # format the object and append to the result
237n/a result.append(self.format_field(obj, format_spec))
238n/a
239n/a return ''.join(result), auto_arg_index
240n/a
241n/a
242n/a def get_value(self, key, args, kwargs):
243n/a if isinstance(key, int):
244n/a return args[key]
245n/a else:
246n/a return kwargs[key]
247n/a
248n/a
249n/a def check_unused_args(self, used_args, args, kwargs):
250n/a pass
251n/a
252n/a
253n/a def format_field(self, value, format_spec):
254n/a return format(value, format_spec)
255n/a
256n/a
257n/a def convert_field(self, value, conversion):
258n/a # do any conversion on the resulting object
259n/a if conversion is None:
260n/a return value
261n/a elif conversion == 's':
262n/a return str(value)
263n/a elif conversion == 'r':
264n/a return repr(value)
265n/a elif conversion == 'a':
266n/a return ascii(value)
267n/a raise ValueError("Unknown conversion specifier {0!s}".format(conversion))
268n/a
269n/a
270n/a # returns an iterable that contains tuples of the form:
271n/a # (literal_text, field_name, format_spec, conversion)
272n/a # literal_text can be zero length
273n/a # field_name can be None, in which case there's no
274n/a # object to format and output
275n/a # if field_name is not None, it is looked up, formatted
276n/a # with format_spec and conversion and then used
277n/a def parse(self, format_string):
278n/a return _string.formatter_parser(format_string)
279n/a
280n/a
281n/a # given a field_name, find the object it references.
282n/a # field_name: the field being looked up, e.g. "0.name"
283n/a # or "lookup[3]"
284n/a # used_args: a set of which args have been used
285n/a # args, kwargs: as passed in to vformat
286n/a def get_field(self, field_name, args, kwargs):
287n/a first, rest = _string.formatter_field_name_split(field_name)
288n/a
289n/a obj = self.get_value(first, args, kwargs)
290n/a
291n/a # loop through the rest of the field_name, doing
292n/a # getattr or getitem as needed
293n/a for is_attr, i in rest:
294n/a if is_attr:
295n/a obj = getattr(obj, i)
296n/a else:
297n/a obj = obj[i]
298n/a
299n/a return obj, first