MNghia commited on
Commit
593db5a
·
verified ·
1 Parent(s): d0b03bd

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.10/site-packages/absl/__init__.py +15 -0
  2. lib/python3.10/site-packages/absl/__pycache__/__init__.cpython-310.pyc +0 -0
  3. lib/python3.10/site-packages/absl/__pycache__/app.cpython-310.pyc +0 -0
  4. lib/python3.10/site-packages/absl/__pycache__/command_name.cpython-310.pyc +0 -0
  5. lib/python3.10/site-packages/absl/app.py +488 -0
  6. lib/python3.10/site-packages/absl/app.pyi +88 -0
  7. lib/python3.10/site-packages/absl/command_name.py +63 -0
  8. lib/python3.10/site-packages/absl/flags/__init__.py +220 -0
  9. lib/python3.10/site-packages/absl/flags/__pycache__/__init__.cpython-310.pyc +0 -0
  10. lib/python3.10/site-packages/absl/flags/__pycache__/_argument_parser.cpython-310.pyc +0 -0
  11. lib/python3.10/site-packages/absl/flags/__pycache__/_defines.cpython-310.pyc +0 -0
  12. lib/python3.10/site-packages/absl/flags/__pycache__/_exceptions.cpython-310.pyc +0 -0
  13. lib/python3.10/site-packages/absl/flags/__pycache__/_flag.cpython-310.pyc +0 -0
  14. lib/python3.10/site-packages/absl/flags/__pycache__/_flagvalues.cpython-310.pyc +0 -0
  15. lib/python3.10/site-packages/absl/flags/__pycache__/_helpers.cpython-310.pyc +0 -0
  16. lib/python3.10/site-packages/absl/flags/__pycache__/_validators.cpython-310.pyc +0 -0
  17. lib/python3.10/site-packages/absl/flags/__pycache__/_validators_classes.cpython-310.pyc +0 -0
  18. lib/python3.10/site-packages/absl/flags/__pycache__/argparse_flags.cpython-310.pyc +0 -0
  19. lib/python3.10/site-packages/absl/flags/_argument_parser.py +633 -0
  20. lib/python3.10/site-packages/absl/flags/_defines.py +1702 -0
  21. lib/python3.10/site-packages/absl/flags/_exceptions.py +107 -0
  22. lib/python3.10/site-packages/absl/flags/_flag.py +566 -0
  23. lib/python3.10/site-packages/absl/flags/_flagvalues.py +1486 -0
  24. lib/python3.10/site-packages/absl/flags/_helpers.py +427 -0
  25. lib/python3.10/site-packages/absl/flags/_validators.py +353 -0
  26. lib/python3.10/site-packages/absl/flags/_validators_classes.py +172 -0
  27. lib/python3.10/site-packages/absl/flags/argparse_flags.py +390 -0
  28. lib/python3.10/site-packages/absl/logging/__init__.py +1331 -0
  29. lib/python3.10/site-packages/absl/logging/__init__.pyi +261 -0
  30. lib/python3.10/site-packages/absl/logging/__pycache__/__init__.cpython-310.pyc +0 -0
  31. lib/python3.10/site-packages/absl/logging/__pycache__/converter.cpython-310.pyc +0 -0
  32. lib/python3.10/site-packages/absl/logging/converter.py +214 -0
  33. lib/python3.10/site-packages/absl/py.typed +0 -0
  34. lib/python3.10/site-packages/absl/testing/__init__.py +13 -0
  35. lib/python3.10/site-packages/absl/testing/__pycache__/__init__.cpython-310.pyc +0 -0
  36. lib/python3.10/site-packages/absl/testing/__pycache__/_bazelize_command.cpython-310.pyc +0 -0
  37. lib/python3.10/site-packages/absl/testing/__pycache__/_pretty_print_reporter.cpython-310.pyc +0 -0
  38. lib/python3.10/site-packages/absl/testing/__pycache__/absltest.cpython-310.pyc +0 -0
  39. lib/python3.10/site-packages/absl/testing/__pycache__/flagsaver.cpython-310.pyc +0 -0
  40. lib/python3.10/site-packages/absl/testing/__pycache__/parameterized.cpython-310.pyc +0 -0
  41. lib/python3.10/site-packages/absl/testing/__pycache__/xml_reporter.cpython-310.pyc +0 -0
  42. lib/python3.10/site-packages/absl/testing/_bazelize_command.py +68 -0
  43. lib/python3.10/site-packages/absl/testing/_pretty_print_reporter.py +92 -0
  44. lib/python3.10/site-packages/absl/testing/absltest.py +0 -0
  45. lib/python3.10/site-packages/absl/testing/flagsaver.py +393 -0
  46. lib/python3.10/site-packages/absl/testing/parameterized.py +726 -0
  47. lib/python3.10/site-packages/absl/testing/xml_reporter.py +570 -0
  48. lib/python3.10/site-packages/absl_py-2.3.1.dist-info/INSTALLER +1 -0
  49. lib/python3.10/site-packages/absl_py-2.3.1.dist-info/METADATA +101 -0
  50. lib/python3.10/site-packages/absl_py-2.3.1.dist-info/RECORD +53 -0
lib/python3.10/site-packages/absl/__init__.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ __version__ = '2.3.1'
lib/python3.10/site-packages/absl/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (216 Bytes). View file
 
lib/python3.10/site-packages/absl/__pycache__/app.cpython-310.pyc ADDED
Binary file (13.9 kB). View file
 
lib/python3.10/site-packages/absl/__pycache__/command_name.cpython-310.pyc ADDED
Binary file (1.69 kB). View file
 
lib/python3.10/site-packages/absl/app.py ADDED
@@ -0,0 +1,488 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Generic entry point for Abseil Python applications.
16
+
17
+ To use this module, define a ``main`` function with a single ``argv`` argument
18
+ and call ``app.run(main)``. For example::
19
+
20
+ def main(argv):
21
+ if len(argv) > 1:
22
+ raise app.UsageError('Too many command-line arguments.')
23
+
24
+ if __name__ == '__main__':
25
+ app.run(main)
26
+ """
27
+
28
+ import collections
29
+ import errno
30
+ import os
31
+ import pdb
32
+ import sys
33
+ import textwrap
34
+ import traceback
35
+
36
+ from absl import command_name
37
+ from absl import flags
38
+ from absl import logging
39
+
40
+ try:
41
+ import faulthandler
42
+ except ImportError:
43
+ faulthandler = None
44
+
45
+ FLAGS = flags.FLAGS
46
+
47
+ flags.DEFINE_boolean('run_with_pdb', False, 'Set to true for PDB debug mode')
48
+ flags.DEFINE_boolean('pdb_post_mortem', False,
49
+ 'Set to true to handle uncaught exceptions with PDB '
50
+ 'post mortem.')
51
+ flags.DEFINE_alias('pdb', 'pdb_post_mortem')
52
+ flags.DEFINE_boolean('run_with_profiling', False,
53
+ 'Set to true for profiling the script. '
54
+ 'Execution will be slower, and the output format might '
55
+ 'change over time.')
56
+ flags.DEFINE_string('profile_file', None,
57
+ 'Dump profile information to a file (for python -m '
58
+ 'pstats). Implies --run_with_profiling.')
59
+ flags.DEFINE_boolean('use_cprofile_for_profiling', True,
60
+ 'Use cProfile instead of the profile module for '
61
+ 'profiling. This has no effect unless '
62
+ '--run_with_profiling is set.')
63
+ flags.DEFINE_boolean('only_check_args', False,
64
+ 'Set to true to validate args and exit.',
65
+ allow_hide_cpp=True)
66
+
67
+
68
+ # If main() exits via an abnormal exception, call into these
69
+ # handlers before exiting.
70
+ EXCEPTION_HANDLERS = []
71
+
72
+
73
+ class Error(Exception):
74
+ pass
75
+
76
+
77
+ class UsageError(Error):
78
+ """Exception raised when the arguments supplied by the user are invalid.
79
+
80
+ Raise this when the arguments supplied are invalid from the point of
81
+ view of the application. For example when two mutually exclusive
82
+ flags have been supplied or when there are not enough non-flag
83
+ arguments. It is distinct from flags.Error which covers the lower
84
+ level of parsing and validating individual flags.
85
+ """
86
+
87
+ def __init__(self, message, exitcode=1):
88
+ super().__init__(message)
89
+ self.exitcode = exitcode
90
+
91
+
92
+ class HelpFlag(flags.BooleanFlag):
93
+ """Special boolean flag that displays usage and raises SystemExit."""
94
+ NAME = 'help'
95
+ SHORT_NAME = '?'
96
+
97
+ def __init__(self):
98
+ super().__init__(
99
+ self.NAME,
100
+ False,
101
+ 'show this help',
102
+ short_name=self.SHORT_NAME,
103
+ allow_hide_cpp=True,
104
+ )
105
+
106
+ def parse(self, arg):
107
+ if self._parse(arg):
108
+ usage(shorthelp=True, writeto_stdout=True)
109
+ # Advertise --helpfull on stdout, since usage() was on stdout.
110
+ print()
111
+ print('Try --helpfull to get a list of all flags.')
112
+ sys.exit(1)
113
+
114
+
115
+ class HelpshortFlag(HelpFlag):
116
+ """--helpshort is an alias for --help."""
117
+ NAME = 'helpshort'
118
+ SHORT_NAME = None
119
+
120
+
121
+ class HelpfullFlag(flags.BooleanFlag):
122
+ """Display help for flags in the main module and all dependent modules."""
123
+
124
+ def __init__(self):
125
+ super().__init__('helpfull', False, 'show full help', allow_hide_cpp=True)
126
+
127
+ def parse(self, arg):
128
+ if self._parse(arg):
129
+ usage(writeto_stdout=True)
130
+ sys.exit(1)
131
+
132
+
133
+ class HelpXMLFlag(flags.BooleanFlag):
134
+ """Similar to HelpfullFlag, but generates output in XML format."""
135
+
136
+ def __init__(self):
137
+ super().__init__(
138
+ 'helpxml',
139
+ False,
140
+ 'like --helpfull, but generates XML output',
141
+ allow_hide_cpp=True,
142
+ )
143
+
144
+ def parse(self, arg):
145
+ if self._parse(arg):
146
+ flags.FLAGS.write_help_in_xml_format(sys.stdout)
147
+ sys.exit(1)
148
+
149
+
150
+ def parse_flags_with_usage(args):
151
+ """Tries to parse the flags, print usage, and exit if unparsable.
152
+
153
+ Args:
154
+ args: [str], a non-empty list of the command line arguments including
155
+ program name.
156
+
157
+ Returns:
158
+ [str], a non-empty list of remaining command line arguments after parsing
159
+ flags, including program name.
160
+ """
161
+ try:
162
+ return FLAGS(args)
163
+ except flags.Error as error:
164
+ message = str(error)
165
+ if '\n' in message:
166
+ final_message = 'FATAL Flags parsing error:\n%s\n' % textwrap.indent(
167
+ message, ' ')
168
+ else:
169
+ final_message = 'FATAL Flags parsing error: %s\n' % message
170
+ sys.stderr.write(final_message)
171
+ sys.stderr.write('Pass --helpshort or --helpfull to see help on flags.\n')
172
+ sys.exit(1)
173
+
174
+
175
+ _define_help_flags_called = False
176
+
177
+
178
+ def define_help_flags():
179
+ """Registers help flags. Idempotent."""
180
+ # Use a global to ensure idempotence.
181
+ global _define_help_flags_called
182
+
183
+ if not _define_help_flags_called:
184
+ flags.DEFINE_flag(HelpFlag())
185
+ flags.DEFINE_flag(HelpshortFlag()) # alias for --help
186
+ flags.DEFINE_flag(HelpfullFlag())
187
+ flags.DEFINE_flag(HelpXMLFlag())
188
+ _define_help_flags_called = True
189
+
190
+
191
+ def _register_and_parse_flags_with_usage(
192
+ argv=None,
193
+ flags_parser=parse_flags_with_usage,
194
+ ):
195
+ """Registers help flags, parses arguments and shows usage if appropriate.
196
+
197
+ This also calls sys.exit(0) if flag --only_check_args is True.
198
+
199
+ Args:
200
+ argv: [str], a non-empty list of the command line arguments including
201
+ program name, sys.argv is used if None.
202
+ flags_parser: Callable[[List[str]], Any], the function used to parse flags.
203
+ The return value of this function is passed to `main` untouched. It must
204
+ guarantee FLAGS is parsed after this function is called.
205
+
206
+ Returns:
207
+ The return value of `flags_parser`. When using the default `flags_parser`,
208
+ it returns the following:
209
+ [str], a non-empty list of remaining command line arguments after parsing
210
+ flags, including program name.
211
+
212
+ Raises:
213
+ Error: Raised when flags_parser is called, but FLAGS is not parsed.
214
+ SystemError: Raised when it's called more than once.
215
+ """
216
+ # fmt: on
217
+ if _register_and_parse_flags_with_usage.done:
218
+ raise SystemError('Flag registration can be done only once.')
219
+
220
+ define_help_flags()
221
+
222
+ original_argv = sys.argv if argv is None else argv
223
+ args_to_main = flags_parser(original_argv)
224
+ if not FLAGS.is_parsed():
225
+ raise Error('FLAGS must be parsed after flags_parser is called.')
226
+
227
+ # Exit when told so.
228
+ if FLAGS.only_check_args:
229
+ sys.exit(0)
230
+ # Immediately after flags are parsed, bump verbosity to INFO if the flag has
231
+ # not been set.
232
+ if FLAGS['verbosity'].using_default_value:
233
+ FLAGS.verbosity = 0
234
+ _register_and_parse_flags_with_usage.done = True
235
+
236
+ return args_to_main
237
+
238
+ _register_and_parse_flags_with_usage.done = False
239
+
240
+
241
+ def _run_main(main, argv):
242
+ """Calls main, optionally with pdb or profiler."""
243
+ if FLAGS.run_with_pdb:
244
+ sys.exit(pdb.runcall(main, argv))
245
+ elif FLAGS.run_with_profiling or FLAGS.profile_file:
246
+ # Avoid import overhead since most apps (including performance-sensitive
247
+ # ones) won't be run with profiling.
248
+ # pylint: disable=g-import-not-at-top
249
+ import atexit
250
+ if FLAGS.use_cprofile_for_profiling:
251
+ import cProfile as profile
252
+ else:
253
+ import profile
254
+ profiler = profile.Profile()
255
+ if FLAGS.profile_file:
256
+ atexit.register(profiler.dump_stats, FLAGS.profile_file)
257
+ else:
258
+ atexit.register(profiler.print_stats)
259
+ sys.exit(profiler.runcall(main, argv))
260
+ else:
261
+ sys.exit(main(argv))
262
+
263
+
264
+ def _call_exception_handlers(exception):
265
+ """Calls any installed exception handlers."""
266
+ for handler in EXCEPTION_HANDLERS:
267
+ try:
268
+ if handler.wants(exception):
269
+ handler.handle(exception)
270
+ except: # pylint: disable=bare-except
271
+ try:
272
+ # We don't want to stop for exceptions in the exception handlers but
273
+ # we shouldn't hide them either.
274
+ logging.error(traceback.format_exc())
275
+ except: # pylint: disable=bare-except
276
+ # In case even the logging statement fails, ignore.
277
+ pass
278
+
279
+
280
+ def run(
281
+ main,
282
+ argv=None,
283
+ flags_parser=parse_flags_with_usage,
284
+ ):
285
+ """Begins executing the program.
286
+
287
+ Args:
288
+ main: The main function to execute. It takes an single argument "argv",
289
+ which is a list of command line arguments with parsed flags removed.
290
+ The return value is passed to `sys.exit`, and so for example
291
+ a return value of 0 or None results in a successful termination, whereas
292
+ a return value of 1 results in abnormal termination.
293
+ For more details, see https://docs.python.org/3/library/sys#sys.exit
294
+ argv: A non-empty list of the command line arguments including program name,
295
+ sys.argv is used if None.
296
+ flags_parser: Callable[[List[str]], Any], the function used to parse flags.
297
+ The return value of this function is passed to `main` untouched.
298
+ It must guarantee FLAGS is parsed after this function is called.
299
+ Should be passed as a keyword-only arg which will become mandatory in a
300
+ future release.
301
+ - Parses command line flags with the flag module.
302
+ - If there are any errors, prints usage().
303
+ - Calls main() with the remaining arguments.
304
+ - If main() raises a UsageError, prints usage and the error message.
305
+ """
306
+ # fmt: on
307
+ try:
308
+ args = _run_init(
309
+ sys.argv if argv is None else argv,
310
+ flags_parser,
311
+ )
312
+ while _init_callbacks:
313
+ callback = _init_callbacks.popleft()
314
+ callback()
315
+ try:
316
+ _run_main(main, args)
317
+ except UsageError as error:
318
+ usage(shorthelp=True, detailed_error=error, exitcode=error.exitcode)
319
+ except:
320
+ exc = sys.exc_info()[1]
321
+ # Don't try to post-mortem debug successful SystemExits, since those
322
+ # mean there wasn't actually an error. In particular, the test framework
323
+ # raises SystemExit(False) even if all tests passed.
324
+ if isinstance(exc, SystemExit) and not exc.code:
325
+ raise
326
+
327
+ # Check the tty so that we don't hang waiting for input in an
328
+ # non-interactive scenario.
329
+ if FLAGS.pdb_post_mortem and sys.stdout.isatty():
330
+ traceback.print_exc()
331
+ print()
332
+ print(' *** Entering post-mortem debugging ***')
333
+ print()
334
+ pdb.post_mortem()
335
+ raise
336
+ except Exception as e:
337
+ _call_exception_handlers(e)
338
+ raise
339
+
340
+ # Callbacks which have been deferred until after _run_init has been called.
341
+ _init_callbacks = collections.deque()
342
+
343
+
344
+ def call_after_init(callback):
345
+ """Calls the given callback only once ABSL has finished initialization.
346
+
347
+ If ABSL has already finished initialization when ``call_after_init`` is
348
+ called then the callback is executed immediately, otherwise `callback` is
349
+ stored to be executed after ``app.run`` has finished initializing (aka. just
350
+ before the main function is called).
351
+
352
+ If called after ``app.run``, this is equivalent to calling ``callback()`` in
353
+ the caller thread. If called before ``app.run``, callbacks are run
354
+ sequentially (in an undefined order) in the same thread as ``app.run``.
355
+
356
+ Args:
357
+ callback: a callable to be called once ABSL has finished initialization.
358
+ This may be immediate if initialization has already finished. It
359
+ takes no arguments and returns nothing.
360
+ """
361
+ if _run_init.done:
362
+ callback()
363
+ else:
364
+ _init_callbacks.append(callback)
365
+
366
+
367
+ def _run_init(
368
+ argv,
369
+ flags_parser,
370
+ ):
371
+ """Does one-time initialization and re-parses flags on rerun."""
372
+ if _run_init.done:
373
+ return flags_parser(argv)
374
+ command_name.make_process_name_useful()
375
+ # Set up absl logging handler.
376
+ logging.use_absl_handler()
377
+ args = _register_and_parse_flags_with_usage(
378
+ argv=argv,
379
+ flags_parser=flags_parser,
380
+ )
381
+ if faulthandler:
382
+ try:
383
+ faulthandler.enable()
384
+ except Exception: # pylint: disable=broad-except
385
+ # Some tests verify stderr output very closely, so don't print anything.
386
+ # Disabled faulthandler is a low-impact error.
387
+ pass
388
+ _run_init.done = True
389
+ return args
390
+
391
+
392
+ _run_init.done = False
393
+
394
+
395
+ def usage(shorthelp=False, writeto_stdout=False, detailed_error=None,
396
+ exitcode=None):
397
+ """Writes __main__'s docstring to stderr with some help text.
398
+
399
+ Args:
400
+ shorthelp: bool, if True, prints only flags from the main module,
401
+ rather than all flags.
402
+ writeto_stdout: bool, if True, writes help message to stdout,
403
+ rather than to stderr.
404
+ detailed_error: str, additional detail about why usage info was presented.
405
+ exitcode: optional integer, if set, exits with this status code after
406
+ writing help.
407
+ """
408
+ if writeto_stdout:
409
+ stdfile = sys.stdout
410
+ else:
411
+ stdfile = sys.stderr
412
+
413
+ doc = sys.modules['__main__'].__doc__
414
+ if not doc:
415
+ doc = '\nUSAGE: %s [flags]\n' % sys.argv[0]
416
+ doc = flags.text_wrap(doc, indent=' ', firstline_indent='')
417
+ else:
418
+ # Replace all '%s' with sys.argv[0], and all '%%' with '%'.
419
+ num_specifiers = doc.count('%') - 2 * doc.count('%%')
420
+ try:
421
+ doc %= (sys.argv[0],) * num_specifiers
422
+ except (OverflowError, TypeError, ValueError):
423
+ # Just display the docstring as-is.
424
+ pass
425
+ if shorthelp:
426
+ flag_str = FLAGS.main_module_help()
427
+ else:
428
+ flag_str = FLAGS.get_help()
429
+ try:
430
+ stdfile.write(doc)
431
+ if flag_str:
432
+ stdfile.write('\nflags:\n')
433
+ stdfile.write(flag_str)
434
+ stdfile.write('\n')
435
+ if detailed_error is not None:
436
+ stdfile.write('\n%s\n' % detailed_error)
437
+ except OSError as e:
438
+ # We avoid printing a huge backtrace if we get EPIPE, because
439
+ # "foo.par --help | less" is a frequent use case.
440
+ if e.errno != errno.EPIPE:
441
+ raise
442
+ if exitcode is not None:
443
+ sys.exit(exitcode)
444
+
445
+
446
+ class ExceptionHandler:
447
+ """Base exception handler from which other may inherit."""
448
+
449
+ def wants(self, exc):
450
+ """Returns whether this handler wants to handle the exception or not.
451
+
452
+ This base class returns True for all exceptions by default. Override in
453
+ subclass if it wants to be more selective.
454
+
455
+ Args:
456
+ exc: Exception, the current exception.
457
+ """
458
+ del exc # Unused.
459
+ return True
460
+
461
+ def handle(self, exc):
462
+ """Do something with the current exception.
463
+
464
+ Args:
465
+ exc: Exception, the current exception
466
+
467
+ This method must be overridden.
468
+ """
469
+ raise NotImplementedError()
470
+
471
+
472
+ def install_exception_handler(handler):
473
+ """Installs an exception handler.
474
+
475
+ Args:
476
+ handler: ExceptionHandler, the exception handler to install.
477
+
478
+ Raises:
479
+ TypeError: Raised when the handler was not of the correct type.
480
+
481
+ All installed exception handlers will be called if main() exits via
482
+ an abnormal exception, i.e. not one of SystemExit, KeyboardInterrupt,
483
+ FlagsError or UsageError.
484
+ """
485
+ if not isinstance(handler, ExceptionHandler):
486
+ raise TypeError('handler of type %s does not inherit from ExceptionHandler'
487
+ % type(handler))
488
+ EXCEPTION_HANDLERS.append(handler)
lib/python3.10/site-packages/absl/app.pyi ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, Callable, Collection, Iterable, List, NoReturn, Optional, TypeVar, Union, overload
2
+
3
+ from absl.flags import _flag
4
+
5
+ _MainArgs = TypeVar('_MainArgs')
6
+ _Exc = TypeVar('_Exc', bound=Exception)
7
+
8
+ class ExceptionHandler():
9
+
10
+ def wants(self, exc: _Exc) -> bool:
11
+ ...
12
+
13
+ def handle(self, exc: _Exc):
14
+ ...
15
+
16
+ EXCEPTION_HANDLERS: List[ExceptionHandler] = ...
17
+
18
+ class HelpFlag(_flag.BooleanFlag):
19
+ def __init__(self):
20
+ ...
21
+
22
+ class HelpshortFlag(HelpFlag):
23
+ ...
24
+
25
+ class HelpfullFlag(_flag.BooleanFlag):
26
+ def __init__(self):
27
+ ...
28
+
29
+ class HelpXMLFlag(_flag.BooleanFlag):
30
+ def __init__(self):
31
+ ...
32
+
33
+ def define_help_flags() -> None:
34
+ ...
35
+
36
+ @overload
37
+ def usage(shorthelp: Union[bool, int] = ...,
38
+ writeto_stdout: Union[bool, int] = ...,
39
+ detailed_error: Optional[Any] = ...,
40
+ exitcode: None = ...) -> None:
41
+ ...
42
+
43
+ @overload
44
+ def usage(shorthelp: Union[bool, int],
45
+ writeto_stdout: Union[bool, int],
46
+ detailed_error: Optional[Any],
47
+ exitcode: int) -> NoReturn:
48
+ ...
49
+
50
+ @overload
51
+ def usage(shorthelp: Union[bool, int] = ...,
52
+ writeto_stdout: Union[bool, int] = ...,
53
+ detailed_error: Optional[Any] = ...,
54
+ *,
55
+ exitcode: int) -> NoReturn:
56
+ ...
57
+
58
+ def install_exception_handler(handler: ExceptionHandler) -> None:
59
+ ...
60
+
61
+ class Error(Exception):
62
+ ...
63
+
64
+ class UsageError(Error):
65
+ exitcode: int
66
+
67
+ def parse_flags_with_usage(args: List[str]) -> List[str]:
68
+ ...
69
+
70
+ def call_after_init(callback: Callable[[], Any]) -> None:
71
+ ...
72
+
73
+ # Without the flag_parser argument, `main` should require a List[str].
74
+ @overload
75
+ def run(
76
+ main: Callable[[List[str]], Any],
77
+ argv: Optional[List[str]] = ...,
78
+ ) -> NoReturn:
79
+ ...
80
+
81
+ @overload
82
+ def run(
83
+ main: Callable[[_MainArgs], Any],
84
+ argv: Optional[List[str]] = ...,
85
+ *,
86
+ flags_parser: Callable[[List[str]], _MainArgs],
87
+ ) -> NoReturn:
88
+ ...
lib/python3.10/site-packages/absl/command_name.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """A tiny stand alone library to change the kernel process name on Linux."""
16
+
17
+ import os
18
+ import sys
19
+
20
+ # This library must be kept small and stand alone. It is used by small things
21
+ # that require no extension modules.
22
+
23
+
24
+ def make_process_name_useful():
25
+ """Sets the process name to something better than 'python' if possible."""
26
+ set_kernel_process_name(os.path.basename(sys.argv[0]))
27
+
28
+
29
+ def set_kernel_process_name(name):
30
+ """Changes the Kernel's /proc/self/status process name on Linux.
31
+
32
+ The kernel name is NOT what will be shown by the ps or top command.
33
+ It is a 15 character string stored in the kernel's process table that
34
+ is included in the kernel log when a process is OOM killed.
35
+ The first 15 bytes of name are used. Non-ASCII unicode is replaced with '?'.
36
+
37
+ Does nothing if /proc/self/comm cannot be written or prctl() fails.
38
+
39
+ Args:
40
+ name: bytes|unicode, the Linux kernel's command name to set.
41
+ """
42
+ if not isinstance(name, bytes):
43
+ name = name.encode('ascii', 'replace')
44
+ try:
45
+ # This is preferred to using ctypes to try and call prctl() when possible.
46
+ with open('/proc/self/comm', 'wb') as proc_comm:
47
+ proc_comm.write(name[:15])
48
+ except OSError:
49
+ try:
50
+ import ctypes # pylint: disable=g-import-not-at-top
51
+ except ImportError:
52
+ return # No ctypes.
53
+ try:
54
+ libc = ctypes.CDLL('libc.so.6')
55
+ except OSError:
56
+ return # No libc.so.6.
57
+ pr_set_name = ctypes.c_ulong(15) # linux/prctl.h PR_SET_NAME value.
58
+ zero = ctypes.c_ulong(0)
59
+ try:
60
+ libc.prctl(pr_set_name, name, zero, zero, zero)
61
+ # Ignore the prctl return value. Nothing we can do if it errored.
62
+ except AttributeError:
63
+ return # No prctl.
lib/python3.10/site-packages/absl/flags/__init__.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """This package is used to define and parse command line flags.
15
+
16
+ This package defines a *distributed* flag-definition policy: rather than
17
+ an application having to define all flags in or near main(), each Python
18
+ module defines flags that are useful to it. When one Python module
19
+ imports another, it gains access to the other's flags. (This is
20
+ implemented by having all modules share a common, global registry object
21
+ containing all the flag information.)
22
+
23
+ Flags are defined through the use of one of the DEFINE_xxx functions.
24
+ The specific function used determines how the flag is parsed, checked,
25
+ and optionally type-converted, when it's seen on the command line.
26
+ """
27
+
28
+ import sys
29
+
30
+ from absl.flags import _argument_parser
31
+ from absl.flags import _defines
32
+ from absl.flags import _exceptions
33
+ from absl.flags import _flag
34
+ from absl.flags import _flagvalues
35
+ from absl.flags import _helpers
36
+ from absl.flags import _validators
37
+
38
+ __all__ = (
39
+ 'DEFINE',
40
+ 'DEFINE_flag',
41
+ 'DEFINE_string',
42
+ 'DEFINE_boolean',
43
+ 'DEFINE_bool',
44
+ 'DEFINE_float',
45
+ 'DEFINE_integer',
46
+ 'DEFINE_enum',
47
+ 'DEFINE_enum_class',
48
+ 'DEFINE_list',
49
+ 'DEFINE_spaceseplist',
50
+ 'DEFINE_multi',
51
+ 'DEFINE_multi_string',
52
+ 'DEFINE_multi_integer',
53
+ 'DEFINE_multi_float',
54
+ 'DEFINE_multi_enum',
55
+ 'DEFINE_multi_enum_class',
56
+ 'DEFINE_alias',
57
+ # Flag validators.
58
+ 'register_validator',
59
+ 'validator',
60
+ 'register_multi_flags_validator',
61
+ 'multi_flags_validator',
62
+ 'mark_flag_as_required',
63
+ 'mark_flags_as_required',
64
+ 'mark_flags_as_mutual_exclusive',
65
+ 'mark_bool_flags_as_mutual_exclusive',
66
+ # Flag modifiers.
67
+ 'set_default',
68
+ 'override_value',
69
+ # Key flag related functions.
70
+ 'declare_key_flag',
71
+ 'adopt_module_key_flags',
72
+ 'disclaim_key_flags',
73
+ # Module exceptions.
74
+ 'Error',
75
+ 'CantOpenFlagFileError',
76
+ 'DuplicateFlagError',
77
+ 'IllegalFlagValueError',
78
+ 'UnrecognizedFlagError',
79
+ 'UnparsedFlagAccessError',
80
+ 'ValidationError',
81
+ 'FlagNameConflictsWithMethodError',
82
+ # Public classes.
83
+ 'Flag',
84
+ 'BooleanFlag',
85
+ 'EnumFlag',
86
+ 'EnumClassFlag',
87
+ 'MultiFlag',
88
+ 'MultiEnumClassFlag',
89
+ 'FlagHolder',
90
+ 'FlagValues',
91
+ 'ArgumentParser',
92
+ 'BooleanParser',
93
+ 'EnumParser',
94
+ 'EnumClassParser',
95
+ 'ArgumentSerializer',
96
+ 'FloatParser',
97
+ 'IntegerParser',
98
+ 'BaseListParser',
99
+ 'ListParser',
100
+ 'ListSerializer',
101
+ 'EnumClassListSerializer',
102
+ 'CsvListSerializer',
103
+ 'WhitespaceSeparatedListParser',
104
+ 'EnumClassSerializer',
105
+ # Helper functions.
106
+ 'get_help_width',
107
+ 'text_wrap',
108
+ 'flag_dict_to_args',
109
+ 'doc_to_help',
110
+ # The global FlagValues instance.
111
+ 'FLAGS',
112
+ )
113
+
114
+ # Initialize the FLAGS_MODULE as early as possible.
115
+ # It's only used by adopt_module_key_flags to take SPECIAL_FLAGS into account.
116
+ _helpers.FLAGS_MODULE = sys.modules[__name__]
117
+
118
+ # Add current module to disclaimed module ids.
119
+ _helpers.disclaim_module_ids.add(id(sys.modules[__name__]))
120
+
121
+ # DEFINE functions. They are explained in more details in the module doc string.
122
+ # pylint: disable=invalid-name
123
+ DEFINE = _defines.DEFINE
124
+ DEFINE_flag = _defines.DEFINE_flag
125
+ DEFINE_string = _defines.DEFINE_string
126
+ DEFINE_boolean = _defines.DEFINE_boolean
127
+ DEFINE_bool = DEFINE_boolean # Match C++ API.
128
+ DEFINE_float = _defines.DEFINE_float
129
+ DEFINE_integer = _defines.DEFINE_integer
130
+ DEFINE_enum = _defines.DEFINE_enum
131
+ DEFINE_enum_class = _defines.DEFINE_enum_class
132
+ DEFINE_list = _defines.DEFINE_list
133
+ DEFINE_spaceseplist = _defines.DEFINE_spaceseplist
134
+ DEFINE_multi = _defines.DEFINE_multi
135
+ DEFINE_multi_string = _defines.DEFINE_multi_string
136
+ DEFINE_multi_integer = _defines.DEFINE_multi_integer
137
+ DEFINE_multi_float = _defines.DEFINE_multi_float
138
+ DEFINE_multi_enum = _defines.DEFINE_multi_enum
139
+ DEFINE_multi_enum_class = _defines.DEFINE_multi_enum_class
140
+ DEFINE_alias = _defines.DEFINE_alias
141
+ # pylint: enable=invalid-name
142
+
143
+ # Flag validators.
144
+ register_validator = _validators.register_validator
145
+ validator = _validators.validator
146
+ register_multi_flags_validator = _validators.register_multi_flags_validator
147
+ multi_flags_validator = _validators.multi_flags_validator
148
+ mark_flag_as_required = _validators.mark_flag_as_required
149
+ mark_flags_as_required = _validators.mark_flags_as_required
150
+ mark_flags_as_mutual_exclusive = _validators.mark_flags_as_mutual_exclusive
151
+ mark_bool_flags_as_mutual_exclusive = _validators.mark_bool_flags_as_mutual_exclusive
152
+
153
+ # Flag modifiers.
154
+ set_default = _defines.set_default
155
+ override_value = _defines.override_value
156
+
157
+ # Key flag related functions.
158
+ declare_key_flag = _defines.declare_key_flag
159
+ adopt_module_key_flags = _defines.adopt_module_key_flags
160
+ disclaim_key_flags = _defines.disclaim_key_flags
161
+
162
+ # Module exceptions.
163
+ # pylint: disable=invalid-name
164
+ Error = _exceptions.Error
165
+ CantOpenFlagFileError = _exceptions.CantOpenFlagFileError
166
+ DuplicateFlagError = _exceptions.DuplicateFlagError
167
+ IllegalFlagValueError = _exceptions.IllegalFlagValueError
168
+ UnrecognizedFlagError = _exceptions.UnrecognizedFlagError
169
+ UnparsedFlagAccessError = _exceptions.UnparsedFlagAccessError
170
+ ValidationError = _exceptions.ValidationError
171
+ FlagNameConflictsWithMethodError = _exceptions.FlagNameConflictsWithMethodError
172
+
173
+ # Public classes.
174
+ Flag = _flag.Flag
175
+ BooleanFlag = _flag.BooleanFlag
176
+ EnumFlag = _flag.EnumFlag
177
+ EnumClassFlag = _flag.EnumClassFlag
178
+ MultiFlag = _flag.MultiFlag
179
+ MultiEnumClassFlag = _flag.MultiEnumClassFlag
180
+ FlagHolder = _flagvalues.FlagHolder
181
+ FlagValues = _flagvalues.FlagValues
182
+ ArgumentParser = _argument_parser.ArgumentParser
183
+ BooleanParser = _argument_parser.BooleanParser
184
+ EnumParser = _argument_parser.EnumParser
185
+ EnumClassParser = _argument_parser.EnumClassParser
186
+ ArgumentSerializer = _argument_parser.ArgumentSerializer
187
+ FloatParser = _argument_parser.FloatParser
188
+ IntegerParser = _argument_parser.IntegerParser
189
+ BaseListParser = _argument_parser.BaseListParser
190
+ ListParser = _argument_parser.ListParser
191
+ ListSerializer = _argument_parser.ListSerializer
192
+ EnumClassListSerializer = _argument_parser.EnumClassListSerializer
193
+ CsvListSerializer = _argument_parser.CsvListSerializer
194
+ WhitespaceSeparatedListParser = _argument_parser.WhitespaceSeparatedListParser
195
+ EnumClassSerializer = _argument_parser.EnumClassSerializer
196
+ # pylint: enable=invalid-name
197
+
198
+ # Helper functions.
199
+ get_help_width = _helpers.get_help_width
200
+ text_wrap = _helpers.text_wrap
201
+ flag_dict_to_args = _helpers.flag_dict_to_args
202
+ doc_to_help = _helpers.doc_to_help
203
+
204
+ # Special flags.
205
+ _helpers.SPECIAL_FLAGS = FlagValues()
206
+
207
+ DEFINE_string(
208
+ 'flagfile', '',
209
+ 'Insert flag definitions from the given file into the command line.',
210
+ _helpers.SPECIAL_FLAGS) # pytype: disable=wrong-arg-types
211
+
212
+ DEFINE_string('undefok', '',
213
+ 'comma-separated list of flag names that it is okay to specify '
214
+ 'on the command line even if the program does not define a flag '
215
+ 'with that name. IMPORTANT: flags in this list that have '
216
+ 'arguments MUST use the --flag=value format.',
217
+ _helpers.SPECIAL_FLAGS) # pytype: disable=wrong-arg-types
218
+
219
+ #: The global FlagValues instance.
220
+ FLAGS = _flagvalues.FLAGS
lib/python3.10/site-packages/absl/flags/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (3.68 kB). View file
 
lib/python3.10/site-packages/absl/flags/__pycache__/_argument_parser.cpython-310.pyc ADDED
Binary file (22.4 kB). View file
 
lib/python3.10/site-packages/absl/flags/__pycache__/_defines.cpython-310.pyc ADDED
Binary file (39 kB). View file
 
lib/python3.10/site-packages/absl/flags/__pycache__/_exceptions.cpython-310.pyc ADDED
Binary file (3.81 kB). View file
 
lib/python3.10/site-packages/absl/flags/__pycache__/_flag.cpython-310.pyc ADDED
Binary file (18.6 kB). View file
 
lib/python3.10/site-packages/absl/flags/__pycache__/_flagvalues.cpython-310.pyc ADDED
Binary file (43.9 kB). View file
 
lib/python3.10/site-packages/absl/flags/__pycache__/_helpers.cpython-310.pyc ADDED
Binary file (10.1 kB). View file
 
lib/python3.10/site-packages/absl/flags/__pycache__/_validators.cpython-310.pyc ADDED
Binary file (13.3 kB). View file
 
lib/python3.10/site-packages/absl/flags/__pycache__/_validators_classes.cpython-310.pyc ADDED
Binary file (6.74 kB). View file
 
lib/python3.10/site-packages/absl/flags/__pycache__/argparse_flags.cpython-310.pyc ADDED
Binary file (11.2 kB). View file
 
lib/python3.10/site-packages/absl/flags/_argument_parser.py ADDED
@@ -0,0 +1,633 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Contains base classes used to parse and convert arguments.
16
+
17
+ Do NOT import this module directly. Import the flags package and use the
18
+ aliases defined at the package level instead.
19
+ """
20
+
21
+ import collections
22
+ import csv
23
+ import enum
24
+ import io
25
+ import string
26
+ from typing import Any, Dict, Generic, Iterable, List, Optional, Sequence, Type, TypeVar, Union
27
+ from xml.dom import minidom
28
+
29
+ from absl.flags import _helpers
30
+
31
+ _T = TypeVar('_T')
32
+ _ET = TypeVar('_ET', bound=enum.Enum)
33
+ _N = TypeVar('_N', int, float)
34
+
35
+
36
+ class _ArgumentParserCache(type):
37
+ """Metaclass used to cache and share argument parsers among flags."""
38
+
39
+ _instances: Dict[Any, Any] = {}
40
+
41
+ def __call__(cls, *args, **kwargs):
42
+ """Returns an instance of the argument parser cls.
43
+
44
+ This method overrides behavior of the __new__ methods in
45
+ all subclasses of ArgumentParser (inclusive). If an instance
46
+ for cls with the same set of arguments exists, this instance is
47
+ returned, otherwise a new instance is created.
48
+
49
+ If any keyword arguments are defined, or the values in args
50
+ are not hashable, this method always returns a new instance of
51
+ cls.
52
+
53
+ Args:
54
+ *args: Positional initializer arguments.
55
+ **kwargs: Initializer keyword arguments.
56
+
57
+ Returns:
58
+ An instance of cls, shared or new.
59
+ """
60
+ if kwargs:
61
+ return type.__call__(cls, *args, **kwargs)
62
+ else:
63
+ instances = cls._instances
64
+ key = (cls,) + tuple(args)
65
+ try:
66
+ return instances[key]
67
+ except KeyError:
68
+ # No cache entry for key exists, create a new one.
69
+ return instances.setdefault(key, type.__call__(cls, *args))
70
+ except TypeError:
71
+ # An object in args cannot be hashed, always return
72
+ # a new instance.
73
+ return type.__call__(cls, *args)
74
+
75
+
76
+ class ArgumentParser(Generic[_T], metaclass=_ArgumentParserCache):
77
+ """Base class used to parse and convert arguments.
78
+
79
+ The :meth:`parse` method checks to make sure that the string argument is a
80
+ legal value and convert it to a native type. If the value cannot be
81
+ converted, it should throw a ``ValueError`` exception with a human
82
+ readable explanation of why the value is illegal.
83
+
84
+ Subclasses should also define a syntactic_help string which may be
85
+ presented to the user to describe the form of the legal values.
86
+
87
+ Argument parser classes must be stateless, since instances are cached
88
+ and shared between flags. Initializer arguments are allowed, but all
89
+ member variables must be derived from initializer arguments only.
90
+ """
91
+
92
+ syntactic_help: str = ''
93
+
94
+ def parse(self, argument: str) -> Optional[_T]:
95
+ """Parses the string argument and returns the native value.
96
+
97
+ By default it returns its argument unmodified.
98
+
99
+ Args:
100
+ argument: string argument passed in the commandline.
101
+
102
+ Raises:
103
+ ValueError: Raised when it fails to parse the argument.
104
+ TypeError: Raised when the argument has the wrong type.
105
+
106
+ Returns:
107
+ The parsed value in native type.
108
+ """
109
+ if not isinstance(argument, str):
110
+ raise TypeError('flag value must be a string, found "{}"'.format(
111
+ type(argument)))
112
+ return argument # type: ignore[return-value]
113
+
114
+ def flag_type(self) -> str:
115
+ """Returns a string representing the type of the flag."""
116
+ return 'string'
117
+
118
+ def _custom_xml_dom_elements(
119
+ self, doc: minidom.Document
120
+ ) -> List[minidom.Element]:
121
+ """Returns a list of minidom.Element to add additional flag information.
122
+
123
+ Args:
124
+ doc: minidom.Document, the DOM document it should create nodes from.
125
+ """
126
+ del doc # Unused.
127
+ return []
128
+
129
+
130
+ class ArgumentSerializer(Generic[_T]):
131
+ """Base class for generating string representations of a flag value."""
132
+
133
+ def serialize(self, value: _T) -> str:
134
+ """Returns a serialized string of the value."""
135
+ return str(value)
136
+
137
+
138
+ class NumericParser(ArgumentParser[_N]):
139
+ """Parser of numeric values.
140
+
141
+ Parsed value may be bounded to a given upper and lower bound.
142
+ """
143
+
144
+ lower_bound: Optional[_N]
145
+ upper_bound: Optional[_N]
146
+
147
+ def is_outside_bounds(self, val: _N) -> bool:
148
+ """Returns whether the value is outside the bounds or not."""
149
+ return ((self.lower_bound is not None and val < self.lower_bound) or
150
+ (self.upper_bound is not None and val > self.upper_bound))
151
+
152
+ def parse(self, argument: Union[str, _N]) -> _N:
153
+ """See base class."""
154
+ val = self.convert(argument)
155
+ if self.is_outside_bounds(val):
156
+ raise ValueError('%s is not %s' % (val, self.syntactic_help))
157
+ return val
158
+
159
+ def _custom_xml_dom_elements(
160
+ self, doc: minidom.Document
161
+ ) -> List[minidom.Element]:
162
+ elements = []
163
+ if self.lower_bound is not None:
164
+ elements.append(_helpers.create_xml_dom_element(
165
+ doc, 'lower_bound', self.lower_bound))
166
+ if self.upper_bound is not None:
167
+ elements.append(_helpers.create_xml_dom_element(
168
+ doc, 'upper_bound', self.upper_bound))
169
+ return elements
170
+
171
+ def convert(self, argument: Union[str, _N]) -> _N:
172
+ """Returns the correct numeric value of argument.
173
+
174
+ Subclass must implement this method, and raise TypeError if argument is not
175
+ string or has the right numeric type.
176
+
177
+ Args:
178
+ argument: string argument passed in the commandline, or the numeric type.
179
+
180
+ Raises:
181
+ TypeError: Raised when argument is not a string or the right numeric type.
182
+ ValueError: Raised when failed to convert argument to the numeric value.
183
+ """
184
+ raise NotImplementedError
185
+
186
+
187
+ class FloatParser(NumericParser[float]):
188
+ """Parser of floating point values.
189
+
190
+ Parsed value may be bounded to a given upper and lower bound.
191
+ """
192
+ number_article = 'a'
193
+ number_name = 'number'
194
+ syntactic_help = ' '.join((number_article, number_name))
195
+
196
+ def __init__(
197
+ self,
198
+ lower_bound: Optional[float] = None,
199
+ upper_bound: Optional[float] = None,
200
+ ) -> None:
201
+ super().__init__()
202
+ self.lower_bound = lower_bound
203
+ self.upper_bound = upper_bound
204
+ sh = self.syntactic_help
205
+ if lower_bound is not None and upper_bound is not None:
206
+ sh = ('%s in the range [%s, %s]' % (sh, lower_bound, upper_bound))
207
+ elif lower_bound == 0:
208
+ sh = 'a non-negative %s' % self.number_name
209
+ elif upper_bound == 0:
210
+ sh = 'a non-positive %s' % self.number_name
211
+ elif upper_bound is not None:
212
+ sh = '%s <= %s' % (self.number_name, upper_bound)
213
+ elif lower_bound is not None:
214
+ sh = '%s >= %s' % (self.number_name, lower_bound)
215
+ self.syntactic_help = sh
216
+
217
+ def convert(self, argument: Union[int, float, str]) -> float:
218
+ """Returns the float value of argument."""
219
+ if (
220
+ (isinstance(argument, int) and not isinstance(argument, bool))
221
+ or isinstance(argument, float)
222
+ or isinstance(argument, str)
223
+ ):
224
+ return float(argument)
225
+ else:
226
+ raise TypeError(
227
+ 'Expect argument to be a string, int, or float, found {}'.format(
228
+ type(argument)))
229
+
230
+ def flag_type(self) -> str:
231
+ """See base class."""
232
+ return 'float'
233
+
234
+
235
+ class IntegerParser(NumericParser[int]):
236
+ """Parser of an integer value.
237
+
238
+ Parsed value may be bounded to a given upper and lower bound.
239
+ """
240
+ number_article = 'an'
241
+ number_name = 'integer'
242
+ syntactic_help = ' '.join((number_article, number_name))
243
+
244
+ def __init__(
245
+ self, lower_bound: Optional[int] = None, upper_bound: Optional[int] = None
246
+ ) -> None:
247
+ super().__init__()
248
+ self.lower_bound = lower_bound
249
+ self.upper_bound = upper_bound
250
+ sh = self.syntactic_help
251
+ if lower_bound is not None and upper_bound is not None:
252
+ sh = ('%s in the range [%s, %s]' % (sh, lower_bound, upper_bound))
253
+ elif lower_bound == 1:
254
+ sh = 'a positive %s' % self.number_name
255
+ elif upper_bound == -1:
256
+ sh = 'a negative %s' % self.number_name
257
+ elif lower_bound == 0:
258
+ sh = 'a non-negative %s' % self.number_name
259
+ elif upper_bound == 0:
260
+ sh = 'a non-positive %s' % self.number_name
261
+ elif upper_bound is not None:
262
+ sh = '%s <= %s' % (self.number_name, upper_bound)
263
+ elif lower_bound is not None:
264
+ sh = '%s >= %s' % (self.number_name, lower_bound)
265
+ self.syntactic_help = sh
266
+
267
+ def convert(self, argument: Union[int, str]) -> int:
268
+ """Returns the int value of argument."""
269
+ if isinstance(argument, int) and not isinstance(argument, bool):
270
+ return argument
271
+ elif isinstance(argument, str):
272
+ base = 10
273
+ if len(argument) > 2 and argument[0] == '0':
274
+ if argument[1] == 'o':
275
+ base = 8
276
+ elif argument[1] == 'x':
277
+ base = 16
278
+ return int(argument, base)
279
+ else:
280
+ raise TypeError('Expect argument to be a string or int, found {}'.format(
281
+ type(argument)))
282
+
283
+ def flag_type(self) -> str:
284
+ """See base class."""
285
+ return 'int'
286
+
287
+
288
+ class BooleanParser(ArgumentParser[bool]):
289
+ """Parser of boolean values."""
290
+
291
+ def parse(self, argument: Union[str, int]) -> bool:
292
+ """See base class."""
293
+ if isinstance(argument, str):
294
+ if argument.lower() in ('true', 't', '1'):
295
+ return True
296
+ elif argument.lower() in ('false', 'f', '0'):
297
+ return False
298
+ else:
299
+ raise ValueError('Non-boolean argument to boolean flag', argument)
300
+ elif isinstance(argument, int):
301
+ # Only allow bool or integer 0, 1.
302
+ # Note that float 1.0 == True, 0.0 == False.
303
+ bool_value = bool(argument)
304
+ if argument == bool_value:
305
+ return bool_value
306
+ else:
307
+ raise ValueError('Non-boolean argument to boolean flag', argument)
308
+
309
+ raise TypeError('Non-boolean argument to boolean flag', argument)
310
+
311
+ def flag_type(self) -> str:
312
+ """See base class."""
313
+ return 'bool'
314
+
315
+
316
+ class EnumParser(ArgumentParser[str]):
317
+ """Parser of a string enum value (a string value from a given set)."""
318
+
319
+ def __init__(
320
+ self, enum_values: Iterable[str], case_sensitive: bool = True
321
+ ) -> None:
322
+ """Initializes EnumParser.
323
+
324
+ Args:
325
+ enum_values: [str], a non-empty list of string values in the enum.
326
+ case_sensitive: bool, whether or not the enum is to be case-sensitive.
327
+
328
+ Raises:
329
+ ValueError: When enum_values is empty.
330
+ """
331
+ if not enum_values:
332
+ raise ValueError(f'enum_values cannot be empty, found "{enum_values}"')
333
+ if isinstance(enum_values, str):
334
+ raise ValueError(f'enum_values cannot be a str, found "{enum_values}"')
335
+ super().__init__()
336
+ self.enum_values = list(enum_values)
337
+ self.case_sensitive = case_sensitive
338
+
339
+ def parse(self, argument: str) -> str:
340
+ """Determines validity of argument and returns the correct element of enum.
341
+
342
+ Args:
343
+ argument: str, the supplied flag value.
344
+
345
+ Returns:
346
+ The first matching element from enum_values.
347
+
348
+ Raises:
349
+ ValueError: Raised when argument didn't match anything in enum.
350
+ """
351
+ if self.case_sensitive:
352
+ if argument not in self.enum_values:
353
+ raise ValueError('value should be one of <%s>' %
354
+ '|'.join(self.enum_values))
355
+ else:
356
+ return argument
357
+ else:
358
+ if argument.upper() not in [value.upper() for value in self.enum_values]:
359
+ raise ValueError('value should be one of <%s>' %
360
+ '|'.join(self.enum_values))
361
+ else:
362
+ return [value for value in self.enum_values
363
+ if value.upper() == argument.upper()][0]
364
+
365
+ def flag_type(self) -> str:
366
+ """See base class."""
367
+ return 'string enum'
368
+
369
+
370
+ class EnumClassParser(ArgumentParser[_ET]):
371
+ """Parser of an Enum class member."""
372
+
373
+ def __init__(
374
+ self, enum_class: Type[_ET], case_sensitive: bool = True
375
+ ) -> None:
376
+ """Initializes EnumParser.
377
+
378
+ Args:
379
+ enum_class: class, the Enum class with all possible flag values.
380
+ case_sensitive: bool, whether or not the enum is to be case-sensitive. If
381
+ False, all member names must be unique when case is ignored.
382
+
383
+ Raises:
384
+ TypeError: When enum_class is not a subclass of Enum.
385
+ ValueError: When enum_class is empty.
386
+ """
387
+ if not issubclass(enum_class, enum.Enum):
388
+ raise TypeError(f'{enum_class} is not a subclass of Enum.')
389
+ if not enum_class.__members__:
390
+ raise ValueError('enum_class cannot be empty, but "{}" is empty.'
391
+ .format(enum_class))
392
+ if not case_sensitive:
393
+ members = collections.Counter(
394
+ name.lower() for name in enum_class.__members__)
395
+ duplicate_keys = {
396
+ member for member, count in members.items() if count > 1
397
+ }
398
+ if duplicate_keys:
399
+ raise ValueError(
400
+ 'Duplicate enum values for {} using case_sensitive=False'.format(
401
+ duplicate_keys))
402
+
403
+ super().__init__()
404
+ self.enum_class = enum_class
405
+ self._case_sensitive = case_sensitive
406
+ if case_sensitive:
407
+ self._member_names = tuple(enum_class.__members__)
408
+ else:
409
+ self._member_names = tuple(
410
+ name.lower() for name in enum_class.__members__)
411
+
412
+ @property
413
+ def member_names(self) -> Sequence[str]:
414
+ """The accepted enum names, in lowercase if not case sensitive."""
415
+ return self._member_names
416
+
417
+ def parse(self, argument: Union[_ET, str]) -> _ET:
418
+ """Determines validity of argument and returns the correct element of enum.
419
+
420
+ Args:
421
+ argument: str or Enum class member, the supplied flag value.
422
+
423
+ Returns:
424
+ The first matching Enum class member in Enum class.
425
+
426
+ Raises:
427
+ ValueError: Raised when argument didn't match anything in enum.
428
+ """
429
+ if isinstance(argument, self.enum_class):
430
+ return argument # pytype: disable=bad-return-type
431
+ elif not isinstance(argument, str):
432
+ raise ValueError(
433
+ '{} is not an enum member or a name of a member in {}'.format(
434
+ argument, self.enum_class))
435
+ key = EnumParser(
436
+ self._member_names, case_sensitive=self._case_sensitive).parse(argument)
437
+ if self._case_sensitive:
438
+ return self.enum_class[key]
439
+ else:
440
+ # If EnumParser.parse() return a value, we're guaranteed to find it
441
+ # as a member of the class
442
+ return next(value for name, value in self.enum_class.__members__.items()
443
+ if name.lower() == key.lower())
444
+
445
+ def flag_type(self) -> str:
446
+ """See base class."""
447
+ return 'enum class'
448
+
449
+
450
+ class ListSerializer(Generic[_T], ArgumentSerializer[List[_T]]):
451
+
452
+ def __init__(self, list_sep: str) -> None:
453
+ self.list_sep = list_sep
454
+
455
+ def serialize(self, value: List[_T]) -> str:
456
+ """See base class."""
457
+ return self.list_sep.join([str(x) for x in value])
458
+
459
+
460
+ class EnumClassListSerializer(ListSerializer[_ET]):
461
+ """A serializer for :class:`MultiEnumClass` flags.
462
+
463
+ This serializer simply joins the output of `EnumClassSerializer` using a
464
+ provided separator.
465
+ """
466
+
467
+ _element_serializer: 'EnumClassSerializer'
468
+
469
+ def __init__(self, list_sep: str, **kwargs) -> None:
470
+ """Initializes EnumClassListSerializer.
471
+
472
+ Args:
473
+ list_sep: String to be used as a separator when serializing
474
+ **kwargs: Keyword arguments to the `EnumClassSerializer` used to serialize
475
+ individual values.
476
+ """
477
+ super().__init__(list_sep)
478
+ self._element_serializer = EnumClassSerializer(**kwargs)
479
+
480
+ def serialize(self, value: Union[_ET, List[_ET]]) -> str:
481
+ """See base class."""
482
+ if isinstance(value, list):
483
+ return self.list_sep.join(
484
+ self._element_serializer.serialize(x) for x in value)
485
+ else:
486
+ return self._element_serializer.serialize(value)
487
+
488
+
489
+ class CsvListSerializer(ListSerializer[str]):
490
+
491
+ def serialize(self, value: List[str]) -> str:
492
+ """Serializes a list as a CSV string or unicode."""
493
+ output = io.StringIO()
494
+ writer = csv.writer(output, delimiter=self.list_sep)
495
+ writer.writerow([str(x) for x in value])
496
+ serialized_value = output.getvalue().strip()
497
+
498
+ # We need the returned value to be pure ascii or Unicodes so that
499
+ # when the xml help is generated they are usefully encodable.
500
+ return str(serialized_value)
501
+
502
+
503
+ class EnumClassSerializer(ArgumentSerializer[_ET]):
504
+ """Class for generating string representations of an enum class flag value."""
505
+
506
+ def __init__(self, lowercase: bool) -> None:
507
+ """Initializes EnumClassSerializer.
508
+
509
+ Args:
510
+ lowercase: If True, enum member names are lowercased during serialization.
511
+ """
512
+ self._lowercase = lowercase
513
+
514
+ def serialize(self, value: _ET) -> str:
515
+ """Returns a serialized string of the Enum class value."""
516
+ as_string = str(value.name)
517
+ return as_string.lower() if self._lowercase else as_string
518
+
519
+
520
+ class BaseListParser(ArgumentParser):
521
+ """Base class for a parser of lists of strings.
522
+
523
+ To extend, inherit from this class; from the subclass ``__init__``, call::
524
+
525
+ super().__init__(token, name)
526
+
527
+ where token is a character used to tokenize, and name is a description
528
+ of the separator.
529
+ """
530
+
531
+ def __init__(
532
+ self, token: Optional[str] = None, name: Optional[str] = None
533
+ ) -> None:
534
+ assert name
535
+ super().__init__()
536
+ self._token = token
537
+ self._name = name
538
+ self.syntactic_help = 'a %s separated list' % self._name
539
+
540
+ def parse(self, argument: str) -> List[str]:
541
+ """See base class."""
542
+ if isinstance(argument, list):
543
+ return argument
544
+ elif not argument:
545
+ return []
546
+ else:
547
+ return [s.strip() for s in argument.split(self._token)]
548
+
549
+ def flag_type(self) -> str:
550
+ """See base class."""
551
+ return '%s separated list of strings' % self._name
552
+
553
+
554
+ class ListParser(BaseListParser):
555
+ """Parser for a comma-separated list of strings."""
556
+
557
+ def __init__(self) -> None:
558
+ super().__init__(',', 'comma')
559
+
560
+ def parse(self, argument: Union[str, List[str]]) -> List[str]:
561
+ """Parses argument as comma-separated list of strings."""
562
+ if isinstance(argument, list):
563
+ return argument
564
+ elif not argument:
565
+ return []
566
+ else:
567
+ try:
568
+ return [s.strip() for s in list(csv.reader([argument], strict=True))[0]]
569
+ except csv.Error as e:
570
+ # Provide a helpful report for case like
571
+ # --listflag="$(printf 'hello,\nworld')"
572
+ # IOW, list flag values containing naked newlines. This error
573
+ # was previously "reported" by allowing csv.Error to
574
+ # propagate.
575
+ raise ValueError('Unable to parse the value %r as a %s: %s'
576
+ % (argument, self.flag_type(), e))
577
+
578
+ def _custom_xml_dom_elements(
579
+ self, doc: minidom.Document
580
+ ) -> List[minidom.Element]:
581
+ elements = super()._custom_xml_dom_elements(doc)
582
+ elements.append(_helpers.create_xml_dom_element(
583
+ doc, 'list_separator', repr(',')))
584
+ return elements
585
+
586
+
587
+ class WhitespaceSeparatedListParser(BaseListParser):
588
+ """Parser for a whitespace-separated list of strings."""
589
+
590
+ def __init__(self, comma_compat: bool = False) -> None:
591
+ """Initializer.
592
+
593
+ Args:
594
+ comma_compat: bool, whether to support comma as an additional separator.
595
+ If False then only whitespace is supported. This is intended only for
596
+ backwards compatibility with flags that used to be comma-separated.
597
+ """
598
+ self._comma_compat = comma_compat
599
+ name = 'whitespace or comma' if self._comma_compat else 'whitespace'
600
+ super().__init__(None, name)
601
+
602
+ def parse(self, argument: Union[str, List[str]]) -> List[str]:
603
+ """Parses argument as whitespace-separated list of strings.
604
+
605
+ It also parses argument as comma-separated list of strings if requested.
606
+
607
+ Args:
608
+ argument: string argument passed in the commandline.
609
+
610
+ Returns:
611
+ [str], the parsed flag value.
612
+ """
613
+ if isinstance(argument, list):
614
+ return argument
615
+ elif not argument:
616
+ return []
617
+ else:
618
+ if self._comma_compat:
619
+ argument = argument.replace(',', ' ')
620
+ return argument.split()
621
+
622
+ def _custom_xml_dom_elements(
623
+ self, doc: minidom.Document
624
+ ) -> List[minidom.Element]:
625
+ elements = super()._custom_xml_dom_elements(doc)
626
+ separators = list(string.whitespace)
627
+ if self._comma_compat:
628
+ separators.append(',')
629
+ separators.sort()
630
+ for sep_char in separators:
631
+ elements.append(_helpers.create_xml_dom_element(
632
+ doc, 'list_separator', repr(sep_char)))
633
+ return elements
lib/python3.10/site-packages/absl/flags/_defines.py ADDED
@@ -0,0 +1,1702 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """This modules contains flags DEFINE functions.
15
+
16
+ Do NOT import this module directly. Import the flags package and use the
17
+ aliases defined at the package level instead.
18
+ """
19
+
20
+ import enum
21
+ import sys
22
+ import types
23
+ from typing import Any, Iterable, List, Literal, Optional, Type, TypeVar, Union, overload
24
+
25
+ from absl.flags import _argument_parser
26
+ from absl.flags import _exceptions
27
+ from absl.flags import _flag
28
+ from absl.flags import _flagvalues
29
+ from absl.flags import _helpers
30
+ from absl.flags import _validators
31
+
32
+ _helpers.disclaim_module_ids.add(id(sys.modules[__name__]))
33
+
34
+ _T = TypeVar('_T')
35
+ _ET = TypeVar('_ET', bound=enum.Enum)
36
+
37
+
38
+ def _register_bounds_validator_if_needed(parser, name, flag_values):
39
+ """Enforces lower and upper bounds for numeric flags.
40
+
41
+ Args:
42
+ parser: NumericParser (either FloatParser or IntegerParser), provides lower
43
+ and upper bounds, and help text to display.
44
+ name: str, name of the flag
45
+ flag_values: FlagValues.
46
+ """
47
+ if parser.lower_bound is not None or parser.upper_bound is not None:
48
+
49
+ def checker(value):
50
+ if value is not None and parser.is_outside_bounds(value):
51
+ message = '%s is not %s' % (value, parser.syntactic_help)
52
+ raise _exceptions.ValidationError(message)
53
+ return True
54
+
55
+ _validators.register_validator(name, checker, flag_values=flag_values)
56
+
57
+
58
+ @overload
59
+ def DEFINE( # pylint: disable=invalid-name
60
+ parser: _argument_parser.ArgumentParser[_T],
61
+ name: str,
62
+ default: Any,
63
+ help: Optional[str], # pylint: disable=redefined-builtin
64
+ flag_values: _flagvalues.FlagValues = ...,
65
+ serializer: Optional[_argument_parser.ArgumentSerializer[_T]] = ...,
66
+ module_name: Optional[str] = ...,
67
+ required: Literal[True] = ...,
68
+ **args: Any
69
+ ) -> _flagvalues.FlagHolder[_T]:
70
+ ...
71
+
72
+
73
+ @overload
74
+ def DEFINE( # pylint: disable=invalid-name
75
+ parser: _argument_parser.ArgumentParser[_T],
76
+ name: str,
77
+ default: Optional[Any],
78
+ help: Optional[str], # pylint: disable=redefined-builtin
79
+ flag_values: _flagvalues.FlagValues = ...,
80
+ serializer: Optional[_argument_parser.ArgumentSerializer[_T]] = ...,
81
+ module_name: Optional[str] = ...,
82
+ required: bool = ...,
83
+ **args: Any
84
+ ) -> _flagvalues.FlagHolder[Optional[_T]]:
85
+ ...
86
+
87
+
88
+ def DEFINE( # pylint: disable=invalid-name
89
+ parser,
90
+ name,
91
+ default,
92
+ help, # pylint: disable=redefined-builtin
93
+ flag_values=_flagvalues.FLAGS,
94
+ serializer=None,
95
+ module_name=None,
96
+ required=False,
97
+ **args):
98
+ """Registers a generic Flag object.
99
+
100
+ NOTE: in the docstrings of all DEFINE* functions, "registers" is short
101
+ for "creates a new flag and registers it".
102
+
103
+ Auxiliary function: clients should use the specialized ``DEFINE_<type>``
104
+ function instead.
105
+
106
+ Args:
107
+ parser: :class:`ArgumentParser`, used to parse the flag arguments.
108
+ name: str, the flag name.
109
+ default: The default value of the flag.
110
+ help: str, the help message.
111
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
112
+ flag will be registered. This should almost never need to be overridden.
113
+ serializer: :class:`ArgumentSerializer`, the flag serializer instance.
114
+ module_name: str, the name of the Python module declaring this flag. If not
115
+ provided, it will be computed using the stack trace of this call.
116
+ required: bool, is this a required flag. This must be used as a keyword
117
+ argument.
118
+ **args: dict, the extra keyword args that are passed to ``Flag.__init__``.
119
+
120
+ Returns:
121
+ a handle to defined flag.
122
+ """
123
+ return DEFINE_flag(
124
+ _flag.Flag(parser, serializer, name, default, help, **args),
125
+ flag_values,
126
+ module_name,
127
+ required=True if required else False,
128
+ )
129
+
130
+
131
+ @overload
132
+ def DEFINE_flag( # pylint: disable=invalid-name
133
+ flag: _flag.Flag[_T],
134
+ flag_values: _flagvalues.FlagValues = ...,
135
+ module_name: Optional[str] = ...,
136
+ required: Literal[True] = ...,
137
+ ) -> _flagvalues.FlagHolder[_T]:
138
+ ...
139
+
140
+
141
+ @overload
142
+ def DEFINE_flag( # pylint: disable=invalid-name
143
+ flag: _flag.Flag[_T],
144
+ flag_values: _flagvalues.FlagValues = ...,
145
+ module_name: Optional[str] = ...,
146
+ required: bool = ...,
147
+ ) -> _flagvalues.FlagHolder[Optional[_T]]:
148
+ ...
149
+
150
+
151
+ def DEFINE_flag( # pylint: disable=invalid-name
152
+ flag,
153
+ flag_values=_flagvalues.FLAGS,
154
+ module_name=None,
155
+ required=False):
156
+ """Registers a :class:`Flag` object with a :class:`FlagValues` object.
157
+
158
+ By default, the global :const:`FLAGS` ``FlagValue`` object is used.
159
+
160
+ Typical users will use one of the more specialized DEFINE_xxx
161
+ functions, such as :func:`DEFINE_string` or :func:`DEFINE_integer`. But
162
+ developers who need to create :class:`Flag` objects themselves should use
163
+ this function to register their flags.
164
+
165
+ Args:
166
+ flag: :class:`Flag`, a flag that is key to the module.
167
+ flag_values: :class:`FlagValues`, the ``FlagValues`` instance with which the
168
+ flag will be registered. This should almost never need to be overridden.
169
+ module_name: str, the name of the Python module declaring this flag. If not
170
+ provided, it will be computed using the stack trace of this call.
171
+ required: bool, is this a required flag. This must be used as a keyword
172
+ argument.
173
+
174
+ Returns:
175
+ a handle to defined flag.
176
+ """
177
+ if required and flag.default is not None:
178
+ raise ValueError(
179
+ 'Required flag --%s needs to have None as default' % flag.name
180
+ )
181
+ # Copying the reference to flag_values prevents pychecker warnings.
182
+ fv = flag_values
183
+ fv[flag.name] = flag
184
+ # Tell flag_values who's defining the flag.
185
+ if module_name:
186
+ module = sys.modules.get(module_name)
187
+ else:
188
+ module, module_name = _helpers.get_calling_module_object_and_name()
189
+ flag_values.register_flag_by_module(module_name, flag)
190
+ flag_values.register_flag_by_module_id(id(module), flag)
191
+ if required:
192
+ _validators.mark_flag_as_required(flag.name, fv)
193
+ ensure_non_none_value = (flag.default is not None) or required
194
+ return _flagvalues.FlagHolder(
195
+ fv, flag, ensure_non_none_value=ensure_non_none_value)
196
+
197
+
198
+ def set_default(flag_holder: _flagvalues.FlagHolder[_T], value: _T) -> None:
199
+ """Changes the default value of the provided flag object.
200
+
201
+ The flag's current value is also updated if the flag is currently using
202
+ the default value, i.e. not specified in the command line, and not set
203
+ by FLAGS.name = value.
204
+
205
+ Args:
206
+ flag_holder: FlagHolder, the flag to modify.
207
+ value: The new default value.
208
+
209
+ Raises:
210
+ IllegalFlagValueError: Raised when value is not valid.
211
+ """
212
+ flag_holder._flagvalues.set_default(flag_holder.name, value) # pylint: disable=protected-access
213
+
214
+
215
+ def override_value(flag_holder: _flagvalues.FlagHolder[_T], value: _T) -> None:
216
+ """Overrides the value of the provided flag.
217
+
218
+ This value takes precedent over the default value and, when called after flag
219
+ parsing, any value provided at the command line.
220
+
221
+ Args:
222
+ flag_holder: FlagHolder, the flag to modify.
223
+ value: The new value.
224
+
225
+ Raises:
226
+ IllegalFlagValueError: The value did not pass the flag parser or validators.
227
+ """
228
+ fv = flag_holder._flagvalues # pylint: disable=protected-access
229
+ # Ensure the new value satisfies the flag's parser while avoiding side
230
+ # effects of calling parse().
231
+ parsed = fv[flag_holder.name]._parse(value) # pylint: disable=protected-access
232
+ if parsed != value:
233
+ raise _exceptions.IllegalFlagValueError(
234
+ 'flag %s: parsed value %r not equal to original %r'
235
+ % (flag_holder.name, parsed, value)
236
+ )
237
+ setattr(fv, flag_holder.name, value)
238
+
239
+
240
+ def _internal_declare_key_flags(
241
+ flag_names: List[str],
242
+ flag_values: _flagvalues.FlagValues = _flagvalues.FLAGS,
243
+ key_flag_values: Optional[_flagvalues.FlagValues] = None,
244
+ ) -> None:
245
+ """Declares a flag as key for the calling module.
246
+
247
+ Internal function. User code should call declare_key_flag or
248
+ adopt_module_key_flags instead.
249
+
250
+ Args:
251
+ flag_names: [str], a list of names of already-registered Flag objects.
252
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
253
+ flags listed in flag_names have registered (the value of the flag_values
254
+ argument from the ``DEFINE_*`` calls that defined those flags). This
255
+ should almost never need to be overridden.
256
+ key_flag_values: :class:`FlagValues`, the FlagValues instance that (among
257
+ possibly many other things) keeps track of the key flags for each module.
258
+ Default ``None`` means "same as flag_values". This should almost never
259
+ need to be overridden.
260
+
261
+ Raises:
262
+ UnrecognizedFlagError: Raised when the flag is not defined.
263
+ """
264
+ key_flag_values = key_flag_values or flag_values
265
+
266
+ module = _helpers.get_calling_module()
267
+
268
+ for flag_name in flag_names:
269
+ key_flag_values.register_key_flag_for_module(module, flag_values[flag_name])
270
+
271
+
272
+ def declare_key_flag(
273
+ flag_name: Union[str, _flagvalues.FlagHolder],
274
+ flag_values: _flagvalues.FlagValues = _flagvalues.FLAGS,
275
+ ) -> None:
276
+ """Declares one flag as key to the current module.
277
+
278
+ Key flags are flags that are deemed really important for a module.
279
+ They are important when listing help messages; e.g., if the
280
+ --helpshort command-line flag is used, then only the key flags of the
281
+ main module are listed (instead of all flags, as in the case of
282
+ --helpfull).
283
+
284
+ Sample usage::
285
+
286
+ flags.declare_key_flag('flag_1')
287
+
288
+ Args:
289
+ flag_name: str | :class:`FlagHolder`, the name or holder of an already
290
+ declared flag. (Redeclaring flags as key, including flags implicitly key
291
+ because they were declared in this module, is a no-op.)
292
+ Positional-only parameter.
293
+ flag_values: :class:`FlagValues`, the FlagValues instance in which the
294
+ flag will be declared as a key flag. This should almost never need to be
295
+ overridden.
296
+
297
+ Raises:
298
+ ValueError: Raised if flag_name not defined as a Python flag.
299
+ """
300
+ flag_name, flag_values = _flagvalues.resolve_flag_ref(flag_name, flag_values)
301
+ if flag_name in _helpers.SPECIAL_FLAGS:
302
+ # Take care of the special flags, e.g., --flagfile, --undefok.
303
+ # These flags are defined in SPECIAL_FLAGS, and are treated
304
+ # specially during flag parsing, taking precedence over the
305
+ # user-defined flags.
306
+ _internal_declare_key_flags([flag_name],
307
+ flag_values=_helpers.SPECIAL_FLAGS,
308
+ key_flag_values=flag_values)
309
+ return
310
+ try:
311
+ _internal_declare_key_flags([flag_name], flag_values=flag_values)
312
+ except KeyError:
313
+ raise ValueError('Flag --%s is undefined. To set a flag as a key flag '
314
+ 'first define it in Python.' % flag_name)
315
+
316
+
317
+ def adopt_module_key_flags(
318
+ module: Any, flag_values: _flagvalues.FlagValues = _flagvalues.FLAGS
319
+ ) -> None:
320
+ """Declares that all flags key to a module are key to the current module.
321
+
322
+ Args:
323
+ module: module, the module object from which all key flags will be declared
324
+ as key flags to the current module.
325
+ flag_values: :class:`FlagValues`, the FlagValues instance in which the
326
+ flags will be declared as key flags. This should almost never need to be
327
+ overridden.
328
+
329
+ Raises:
330
+ Error: Raised when given an argument that is a module name (a string),
331
+ instead of a module object.
332
+ """
333
+ if not isinstance(module, types.ModuleType):
334
+ raise _exceptions.Error('Expected a module object, not %r.' % (module,))
335
+ _internal_declare_key_flags(
336
+ [f.name for f in flag_values.get_key_flags_for_module(module.__name__)],
337
+ flag_values=flag_values)
338
+ # If module is this flag module, take _helpers.SPECIAL_FLAGS into account.
339
+ if module == _helpers.FLAGS_MODULE:
340
+ _internal_declare_key_flags(
341
+ # As we associate flags with get_calling_module_object_and_name(), the
342
+ # special flags defined in this module are incorrectly registered with
343
+ # a different module. So, we can't use get_key_flags_for_module.
344
+ # Instead, we take all flags from _helpers.SPECIAL_FLAGS (a private
345
+ # FlagValues, where no other module should register flags).
346
+ [_helpers.SPECIAL_FLAGS[name].name for name in _helpers.SPECIAL_FLAGS],
347
+ flag_values=_helpers.SPECIAL_FLAGS,
348
+ key_flag_values=flag_values)
349
+
350
+
351
+ def disclaim_key_flags() -> None:
352
+ """Declares that the current module will not define any more key flags.
353
+
354
+ Normally, the module that calls the DEFINE_xxx functions claims the
355
+ flag to be its key flag. This is undesirable for modules that
356
+ define additional DEFINE_yyy functions with its own flag parsers and
357
+ serializers, since that module will accidentally claim flags defined
358
+ by DEFINE_yyy as its key flags. After calling this function, the
359
+ module disclaims flag definitions thereafter, so the key flags will
360
+ be correctly attributed to the caller of DEFINE_yyy.
361
+
362
+ After calling this function, the module will not be able to define
363
+ any more flags. This function will affect all FlagValues objects.
364
+ """
365
+ globals_for_caller = sys._getframe(1).f_globals # pylint: disable=protected-access
366
+ module = _helpers.get_module_object_and_name(globals_for_caller)
367
+ if module is not None:
368
+ _helpers.disclaim_module_ids.add(id(module.module))
369
+
370
+
371
+ @overload
372
+ def DEFINE_string( # pylint: disable=invalid-name
373
+ name: str,
374
+ default: Optional[str],
375
+ help: Optional[str], # pylint: disable=redefined-builtin
376
+ flag_values: _flagvalues.FlagValues = ...,
377
+ *,
378
+ required: Literal[True],
379
+ **args: Any
380
+ ) -> _flagvalues.FlagHolder[str]:
381
+ ...
382
+
383
+
384
+ @overload
385
+ def DEFINE_string( # pylint: disable=invalid-name
386
+ name: str,
387
+ default: None,
388
+ help: Optional[str], # pylint: disable=redefined-builtin
389
+ flag_values: _flagvalues.FlagValues = ...,
390
+ required: bool = ...,
391
+ **args: Any
392
+ ) -> _flagvalues.FlagHolder[Optional[str]]:
393
+ ...
394
+
395
+
396
+ @overload
397
+ def DEFINE_string( # pylint: disable=invalid-name
398
+ name: str,
399
+ default: str,
400
+ help: Optional[str], # pylint: disable=redefined-builtin
401
+ flag_values: _flagvalues.FlagValues = ...,
402
+ required: bool = ...,
403
+ **args: Any
404
+ ) -> _flagvalues.FlagHolder[str]:
405
+ ...
406
+
407
+
408
+ def DEFINE_string( # pylint: disable=invalid-name
409
+ name,
410
+ default,
411
+ help, # pylint: disable=redefined-builtin
412
+ flag_values=_flagvalues.FLAGS,
413
+ required=False,
414
+ **args
415
+ ):
416
+ """Registers a flag whose value can be any string."""
417
+ parser = _argument_parser.ArgumentParser[str]()
418
+ serializer = _argument_parser.ArgumentSerializer[str]()
419
+ return DEFINE(
420
+ parser,
421
+ name,
422
+ default,
423
+ help,
424
+ flag_values,
425
+ serializer,
426
+ required=True if required else False,
427
+ **args,
428
+ )
429
+
430
+
431
+ @overload
432
+ def DEFINE_boolean( # pylint: disable=invalid-name
433
+ name: str,
434
+ default: Union[None, str, bool, int],
435
+ help: Optional[str], # pylint: disable=redefined-builtin
436
+ flag_values: _flagvalues.FlagValues = ...,
437
+ module_name: Optional[str] = ...,
438
+ *,
439
+ required: Literal[True],
440
+ **args: Any
441
+ ) -> _flagvalues.FlagHolder[bool]:
442
+ ...
443
+
444
+
445
+ @overload
446
+ def DEFINE_boolean( # pylint: disable=invalid-name
447
+ name: str,
448
+ default: None,
449
+ help: Optional[str], # pylint: disable=redefined-builtin
450
+ flag_values: _flagvalues.FlagValues = ...,
451
+ module_name: Optional[str] = ...,
452
+ required: bool = ...,
453
+ **args: Any
454
+ ) -> _flagvalues.FlagHolder[Optional[bool]]:
455
+ ...
456
+
457
+
458
+ @overload
459
+ def DEFINE_boolean( # pylint: disable=invalid-name
460
+ name: str,
461
+ default: Union[str, bool, int],
462
+ help: Optional[str], # pylint: disable=redefined-builtin
463
+ flag_values: _flagvalues.FlagValues = ...,
464
+ module_name: Optional[str] = ...,
465
+ required: bool = ...,
466
+ **args: Any
467
+ ) -> _flagvalues.FlagHolder[bool]:
468
+ ...
469
+
470
+
471
+ # pytype: disable=bad-return-type
472
+ def DEFINE_boolean( # pylint: disable=invalid-name
473
+ name,
474
+ default,
475
+ help, # pylint: disable=redefined-builtin
476
+ flag_values=_flagvalues.FLAGS,
477
+ module_name=None,
478
+ required=False,
479
+ **args
480
+ ):
481
+ """Registers a boolean flag.
482
+
483
+ Such a boolean flag does not take an argument. If a user wants to
484
+ specify a false value explicitly, the long option beginning with 'no'
485
+ must be used: i.e. --noflag
486
+
487
+ This flag will have a value of None, True or False. None is possible
488
+ if default=None and the user does not specify the flag on the command
489
+ line.
490
+
491
+ Args:
492
+ name: str, the flag name.
493
+ default: bool|str|None, the default value of the flag.
494
+ help: str, the help message.
495
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
496
+ flag will be registered. This should almost never need to be overridden.
497
+ module_name: str, the name of the Python module declaring this flag. If not
498
+ provided, it will be computed using the stack trace of this call.
499
+ required: bool, is this a required flag. This must be used as a keyword
500
+ argument.
501
+ **args: dict, the extra keyword args that are passed to ``Flag.__init__``.
502
+
503
+ Returns:
504
+ a handle to defined flag.
505
+ """
506
+ return DEFINE_flag(
507
+ _flag.BooleanFlag(name, default, help, **args),
508
+ flag_values,
509
+ module_name,
510
+ required=True if required else False,
511
+ )
512
+
513
+
514
+ @overload
515
+ def DEFINE_float( # pylint: disable=invalid-name
516
+ name: str,
517
+ default: Union[None, float, str],
518
+ help: Optional[str], # pylint: disable=redefined-builtin
519
+ lower_bound: Optional[float] = ...,
520
+ upper_bound: Optional[float] = ...,
521
+ flag_values: _flagvalues.FlagValues = ...,
522
+ *,
523
+ required: Literal[True],
524
+ **args: Any
525
+ ) -> _flagvalues.FlagHolder[float]:
526
+ ...
527
+
528
+
529
+ @overload
530
+ def DEFINE_float( # pylint: disable=invalid-name
531
+ name: str,
532
+ default: None,
533
+ help: Optional[str], # pylint: disable=redefined-builtin
534
+ lower_bound: Optional[float] = ...,
535
+ upper_bound: Optional[float] = ...,
536
+ flag_values: _flagvalues.FlagValues = ...,
537
+ required: bool = ...,
538
+ **args: Any
539
+ ) -> _flagvalues.FlagHolder[Optional[float]]:
540
+ ...
541
+
542
+
543
+ @overload
544
+ def DEFINE_float( # pylint: disable=invalid-name
545
+ name: str,
546
+ default: Union[float, str],
547
+ help: Optional[str], # pylint: disable=redefined-builtin
548
+ lower_bound: Optional[float] = ...,
549
+ upper_bound: Optional[float] = ...,
550
+ flag_values: _flagvalues.FlagValues = ...,
551
+ required: bool = ...,
552
+ **args: Any
553
+ ) -> _flagvalues.FlagHolder[float]:
554
+ ...
555
+
556
+
557
+ def DEFINE_float( # pylint: disable=invalid-name
558
+ name,
559
+ default,
560
+ help, # pylint: disable=redefined-builtin
561
+ lower_bound=None,
562
+ upper_bound=None,
563
+ flag_values=_flagvalues.FLAGS,
564
+ required=False,
565
+ **args
566
+ ):
567
+ """Registers a flag whose value must be a float.
568
+
569
+ If ``lower_bound`` or ``upper_bound`` are set, then this flag must be
570
+ within the given range.
571
+
572
+ Args:
573
+ name: str, the flag name.
574
+ default: float|str|None, the default value of the flag.
575
+ help: str, the help message.
576
+ lower_bound: float, min value of the flag.
577
+ upper_bound: float, max value of the flag.
578
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
579
+ flag will be registered. This should almost never need to be overridden.
580
+ required: bool, is this a required flag. This must be used as a keyword
581
+ argument.
582
+ **args: dict, the extra keyword args that are passed to :func:`DEFINE`.
583
+
584
+ Returns:
585
+ a handle to defined flag.
586
+ """
587
+ parser = _argument_parser.FloatParser(lower_bound, upper_bound)
588
+ serializer = _argument_parser.ArgumentSerializer()
589
+ result = DEFINE(
590
+ parser,
591
+ name,
592
+ default,
593
+ help, # pylint: disable=redefined-builtin
594
+ flag_values,
595
+ serializer,
596
+ required=True if required else False,
597
+ **args,
598
+ )
599
+ _register_bounds_validator_if_needed(parser, name, flag_values=flag_values)
600
+ return result
601
+
602
+
603
+ @overload
604
+ def DEFINE_integer( # pylint: disable=invalid-name
605
+ name: str,
606
+ default: Union[None, int, str],
607
+ help: Optional[str], # pylint: disable=redefined-builtin
608
+ lower_bound: Optional[int] = ...,
609
+ upper_bound: Optional[int] = ...,
610
+ flag_values: _flagvalues.FlagValues = ...,
611
+ *,
612
+ required: Literal[True],
613
+ **args: Any
614
+ ) -> _flagvalues.FlagHolder[int]:
615
+ ...
616
+
617
+
618
+ @overload
619
+ def DEFINE_integer( # pylint: disable=invalid-name
620
+ name: str,
621
+ default: None,
622
+ help: Optional[str], # pylint: disable=redefined-builtin
623
+ lower_bound: Optional[int] = ...,
624
+ upper_bound: Optional[int] = ...,
625
+ flag_values: _flagvalues.FlagValues = ...,
626
+ required: bool = ...,
627
+ **args: Any
628
+ ) -> _flagvalues.FlagHolder[Optional[int]]:
629
+ ...
630
+
631
+
632
+ @overload
633
+ def DEFINE_integer( # pylint: disable=invalid-name
634
+ name: str,
635
+ default: Union[int, str],
636
+ help: Optional[str], # pylint: disable=redefined-builtin
637
+ lower_bound: Optional[int] = ...,
638
+ upper_bound: Optional[int] = ...,
639
+ flag_values: _flagvalues.FlagValues = ...,
640
+ required: bool = ...,
641
+ **args: Any
642
+ ) -> _flagvalues.FlagHolder[int]:
643
+ ...
644
+
645
+
646
+ def DEFINE_integer( # pylint: disable=invalid-name
647
+ name,
648
+ default,
649
+ help, # pylint: disable=redefined-builtin
650
+ lower_bound=None,
651
+ upper_bound=None,
652
+ flag_values=_flagvalues.FLAGS,
653
+ required=False,
654
+ **args
655
+ ):
656
+ """Registers a flag whose value must be an integer.
657
+
658
+ If ``lower_bound``, or ``upper_bound`` are set, then this flag must be
659
+ within the given range.
660
+
661
+ Args:
662
+ name: str, the flag name.
663
+ default: int|str|None, the default value of the flag.
664
+ help: str, the help message.
665
+ lower_bound: int, min value of the flag.
666
+ upper_bound: int, max value of the flag.
667
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
668
+ flag will be registered. This should almost never need to be overridden.
669
+ required: bool, is this a required flag. This must be used as a keyword
670
+ argument.
671
+ **args: dict, the extra keyword args that are passed to :func:`DEFINE`.
672
+
673
+ Returns:
674
+ a handle to defined flag.
675
+ """
676
+ parser = _argument_parser.IntegerParser(lower_bound, upper_bound)
677
+ serializer = _argument_parser.ArgumentSerializer()
678
+ result = DEFINE(
679
+ parser,
680
+ name,
681
+ default,
682
+ help, # pylint: disable=redefined-builtin
683
+ flag_values,
684
+ serializer,
685
+ required=True if required else False,
686
+ **args,
687
+ )
688
+ _register_bounds_validator_if_needed(parser, name, flag_values=flag_values)
689
+ return result
690
+
691
+
692
+ @overload
693
+ def DEFINE_enum( # pylint: disable=invalid-name
694
+ name: str,
695
+ default: Optional[str],
696
+ enum_values: Iterable[str],
697
+ help: Optional[str], # pylint: disable=redefined-builtin
698
+ flag_values: _flagvalues.FlagValues = ...,
699
+ module_name: Optional[str] = ...,
700
+ *,
701
+ required: Literal[True],
702
+ **args: Any
703
+ ) -> _flagvalues.FlagHolder[str]:
704
+ ...
705
+
706
+
707
+ @overload
708
+ def DEFINE_enum( # pylint: disable=invalid-name
709
+ name: str,
710
+ default: None,
711
+ enum_values: Iterable[str],
712
+ help: Optional[str], # pylint: disable=redefined-builtin
713
+ flag_values: _flagvalues.FlagValues = ...,
714
+ module_name: Optional[str] = ...,
715
+ required: bool = ...,
716
+ **args: Any
717
+ ) -> _flagvalues.FlagHolder[Optional[str]]:
718
+ ...
719
+
720
+
721
+ @overload
722
+ def DEFINE_enum( # pylint: disable=invalid-name
723
+ name: str,
724
+ default: str,
725
+ enum_values: Iterable[str],
726
+ help: Optional[str], # pylint: disable=redefined-builtin
727
+ flag_values: _flagvalues.FlagValues = ...,
728
+ module_name: Optional[str] = ...,
729
+ required: bool = ...,
730
+ **args: Any
731
+ ) -> _flagvalues.FlagHolder[str]:
732
+ ...
733
+
734
+
735
+ def DEFINE_enum( # pylint: disable=invalid-name
736
+ name,
737
+ default,
738
+ enum_values,
739
+ help, # pylint: disable=redefined-builtin
740
+ flag_values=_flagvalues.FLAGS,
741
+ module_name=None,
742
+ required=False,
743
+ **args
744
+ ):
745
+ """Registers a flag whose value can be any string from enum_values.
746
+
747
+ Instead of a string enum, prefer `DEFINE_enum_class`, which allows
748
+ defining enums from an `enum.Enum` class.
749
+
750
+ Args:
751
+ name: str, the flag name.
752
+ default: str|None, the default value of the flag.
753
+ enum_values: [str], a non-empty list of strings with the possible values for
754
+ the flag.
755
+ help: str, the help message.
756
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
757
+ flag will be registered. This should almost never need to be overridden.
758
+ module_name: str, the name of the Python module declaring this flag. If not
759
+ provided, it will be computed using the stack trace of this call.
760
+ required: bool, is this a required flag. This must be used as a keyword
761
+ argument.
762
+ **args: dict, the extra keyword args that are passed to ``Flag.__init__``.
763
+
764
+ Returns:
765
+ a handle to defined flag.
766
+ """
767
+ result = DEFINE_flag(
768
+ _flag.EnumFlag(name, default, help, enum_values, **args),
769
+ flag_values,
770
+ module_name,
771
+ required=True if required else False,
772
+ )
773
+ return result
774
+
775
+
776
+ @overload
777
+ def DEFINE_enum_class( # pylint: disable=invalid-name
778
+ name: str,
779
+ default: Union[None, _ET, str],
780
+ enum_class: Type[_ET],
781
+ help: Optional[str], # pylint: disable=redefined-builtin
782
+ flag_values: _flagvalues.FlagValues = ...,
783
+ module_name: Optional[str] = ...,
784
+ case_sensitive: bool = ...,
785
+ *,
786
+ required: Literal[True],
787
+ **args: Any
788
+ ) -> _flagvalues.FlagHolder[_ET]:
789
+ ...
790
+
791
+
792
+ @overload
793
+ def DEFINE_enum_class( # pylint: disable=invalid-name
794
+ name: str,
795
+ default: None,
796
+ enum_class: Type[_ET],
797
+ help: Optional[str], # pylint: disable=redefined-builtin
798
+ flag_values: _flagvalues.FlagValues = ...,
799
+ module_name: Optional[str] = ...,
800
+ case_sensitive: bool = ...,
801
+ required: bool = ...,
802
+ **args: Any
803
+ ) -> _flagvalues.FlagHolder[Optional[_ET]]:
804
+ ...
805
+
806
+
807
+ @overload
808
+ def DEFINE_enum_class( # pylint: disable=invalid-name
809
+ name: str,
810
+ default: Union[_ET, str],
811
+ enum_class: Type[_ET],
812
+ help: Optional[str], # pylint: disable=redefined-builtin
813
+ flag_values: _flagvalues.FlagValues = ...,
814
+ module_name: Optional[str] = ...,
815
+ case_sensitive: bool = ...,
816
+ required: bool = ...,
817
+ **args: Any
818
+ ) -> _flagvalues.FlagHolder[_ET]:
819
+ ...
820
+
821
+
822
+ def DEFINE_enum_class( # pylint: disable=invalid-name
823
+ name,
824
+ default,
825
+ enum_class,
826
+ help, # pylint: disable=redefined-builtin
827
+ flag_values=_flagvalues.FLAGS,
828
+ module_name=None,
829
+ case_sensitive=False,
830
+ required=False,
831
+ **args
832
+ ):
833
+ """Registers a flag whose value can be the name of enum members.
834
+
835
+ Args:
836
+ name: str, the flag name.
837
+ default: Enum|str|None, the default value of the flag.
838
+ enum_class: class, the Enum class with all the possible values for the flag.
839
+ help: str, the help message.
840
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
841
+ flag will be registered. This should almost never need to be overridden.
842
+ module_name: str, the name of the Python module declaring this flag. If not
843
+ provided, it will be computed using the stack trace of this call.
844
+ case_sensitive: bool, whether to map strings to members of the enum_class
845
+ without considering case.
846
+ required: bool, is this a required flag. This must be used as a keyword
847
+ argument.
848
+ **args: dict, the extra keyword args that are passed to ``Flag.__init__``.
849
+
850
+ Returns:
851
+ a handle to defined flag.
852
+ """
853
+ # NOTE: pytype fails if this is a direct return.
854
+ result = DEFINE_flag(
855
+ _flag.EnumClassFlag(
856
+ name, default, help, enum_class, case_sensitive=case_sensitive, **args
857
+ ),
858
+ flag_values,
859
+ module_name,
860
+ required=True if required else False,
861
+ )
862
+ return result
863
+
864
+
865
+ @overload
866
+ def DEFINE_list( # pylint: disable=invalid-name
867
+ name: str,
868
+ default: Union[None, Iterable[str], str],
869
+ help: str, # pylint: disable=redefined-builtin
870
+ flag_values: _flagvalues.FlagValues = ...,
871
+ *,
872
+ required: Literal[True],
873
+ **args: Any
874
+ ) -> _flagvalues.FlagHolder[List[str]]:
875
+ ...
876
+
877
+
878
+ @overload
879
+ def DEFINE_list( # pylint: disable=invalid-name
880
+ name: str,
881
+ default: None,
882
+ help: str, # pylint: disable=redefined-builtin
883
+ flag_values: _flagvalues.FlagValues = ...,
884
+ required: bool = ...,
885
+ **args: Any
886
+ ) -> _flagvalues.FlagHolder[Optional[List[str]]]:
887
+ ...
888
+
889
+
890
+ @overload
891
+ def DEFINE_list( # pylint: disable=invalid-name
892
+ name: str,
893
+ default: Union[Iterable[str], str],
894
+ help: str, # pylint: disable=redefined-builtin
895
+ flag_values: _flagvalues.FlagValues = ...,
896
+ required: bool = ...,
897
+ **args: Any
898
+ ) -> _flagvalues.FlagHolder[List[str]]:
899
+ ...
900
+
901
+
902
+ def DEFINE_list( # pylint: disable=invalid-name
903
+ name,
904
+ default,
905
+ help, # pylint: disable=redefined-builtin
906
+ flag_values=_flagvalues.FLAGS,
907
+ required=False,
908
+ **args
909
+ ):
910
+ """Registers a flag whose value is a comma-separated list of strings.
911
+
912
+ The flag value is parsed with a CSV parser.
913
+
914
+ Args:
915
+ name: str, the flag name.
916
+ default: list|str|None, the default value of the flag.
917
+ help: str, the help message.
918
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
919
+ flag will be registered. This should almost never need to be overridden.
920
+ required: bool, is this a required flag. This must be used as a keyword
921
+ argument.
922
+ **args: Dictionary with extra keyword args that are passed to the
923
+ ``Flag.__init__``.
924
+
925
+ Returns:
926
+ a handle to defined flag.
927
+ """
928
+ parser = _argument_parser.ListParser()
929
+ serializer = _argument_parser.CsvListSerializer(',')
930
+ return DEFINE(
931
+ parser,
932
+ name,
933
+ default,
934
+ help,
935
+ flag_values,
936
+ serializer,
937
+ required=True if required else False,
938
+ **args,
939
+ )
940
+
941
+
942
+ @overload
943
+ def DEFINE_spaceseplist( # pylint: disable=invalid-name
944
+ name: str,
945
+ default: Union[None, Iterable[str], str],
946
+ help: str, # pylint: disable=redefined-builtin
947
+ comma_compat: bool = ...,
948
+ flag_values: _flagvalues.FlagValues = ...,
949
+ *,
950
+ required: Literal[True],
951
+ **args: Any
952
+ ) -> _flagvalues.FlagHolder[List[str]]:
953
+ ...
954
+
955
+
956
+ @overload
957
+ def DEFINE_spaceseplist( # pylint: disable=invalid-name
958
+ name: str,
959
+ default: None,
960
+ help: str, # pylint: disable=redefined-builtin
961
+ comma_compat: bool = ...,
962
+ flag_values: _flagvalues.FlagValues = ...,
963
+ required: bool = ...,
964
+ **args: Any
965
+ ) -> _flagvalues.FlagHolder[Optional[List[str]]]:
966
+ ...
967
+
968
+
969
+ @overload
970
+ def DEFINE_spaceseplist( # pylint: disable=invalid-name
971
+ name: str,
972
+ default: Union[Iterable[str], str],
973
+ help: str, # pylint: disable=redefined-builtin
974
+ comma_compat: bool = ...,
975
+ flag_values: _flagvalues.FlagValues = ...,
976
+ required: bool = ...,
977
+ **args: Any
978
+ ) -> _flagvalues.FlagHolder[List[str]]:
979
+ ...
980
+
981
+
982
+ def DEFINE_spaceseplist( # pylint: disable=invalid-name
983
+ name,
984
+ default,
985
+ help, # pylint: disable=redefined-builtin
986
+ comma_compat=False,
987
+ flag_values=_flagvalues.FLAGS,
988
+ required=False,
989
+ **args
990
+ ):
991
+ """Registers a flag whose value is a whitespace-separated list of strings.
992
+
993
+ Any whitespace can be used as a separator.
994
+
995
+ Args:
996
+ name: str, the flag name.
997
+ default: list|str|None, the default value of the flag.
998
+ help: str, the help message.
999
+ comma_compat: bool - Whether to support comma as an additional separator. If
1000
+ false then only whitespace is supported. This is intended only for
1001
+ backwards compatibility with flags that used to be comma-separated.
1002
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
1003
+ flag will be registered. This should almost never need to be overridden.
1004
+ required: bool, is this a required flag. This must be used as a keyword
1005
+ argument.
1006
+ **args: Dictionary with extra keyword args that are passed to the
1007
+ ``Flag.__init__``.
1008
+
1009
+ Returns:
1010
+ a handle to defined flag.
1011
+ """
1012
+ parser = _argument_parser.WhitespaceSeparatedListParser(
1013
+ comma_compat=comma_compat)
1014
+ serializer = _argument_parser.ListSerializer(' ')
1015
+ return DEFINE(
1016
+ parser,
1017
+ name,
1018
+ default,
1019
+ help,
1020
+ flag_values,
1021
+ serializer,
1022
+ required=True if required else False,
1023
+ **args,
1024
+ )
1025
+
1026
+
1027
+ @overload
1028
+ def DEFINE_multi( # pylint: disable=invalid-name
1029
+ parser: _argument_parser.ArgumentParser[_T],
1030
+ serializer: _argument_parser.ArgumentSerializer[_T],
1031
+ name: str,
1032
+ default: Iterable[_T],
1033
+ help: str, # pylint: disable=redefined-builtin
1034
+ flag_values: _flagvalues.FlagValues = ...,
1035
+ module_name: Optional[str] = ...,
1036
+ *,
1037
+ required: Literal[True],
1038
+ **args: Any
1039
+ ) -> _flagvalues.FlagHolder[List[_T]]:
1040
+ ...
1041
+
1042
+
1043
+ @overload
1044
+ def DEFINE_multi( # pylint: disable=invalid-name
1045
+ parser: _argument_parser.ArgumentParser[_T],
1046
+ serializer: _argument_parser.ArgumentSerializer[_T],
1047
+ name: str,
1048
+ default: Union[None, _T],
1049
+ help: str, # pylint: disable=redefined-builtin
1050
+ flag_values: _flagvalues.FlagValues = ...,
1051
+ module_name: Optional[str] = ...,
1052
+ *,
1053
+ required: Literal[True],
1054
+ **args: Any
1055
+ ) -> _flagvalues.FlagHolder[List[_T]]:
1056
+ ...
1057
+
1058
+
1059
+ @overload
1060
+ def DEFINE_multi( # pylint: disable=invalid-name
1061
+ parser: _argument_parser.ArgumentParser[_T],
1062
+ serializer: _argument_parser.ArgumentSerializer[_T],
1063
+ name: str,
1064
+ default: None,
1065
+ help: str, # pylint: disable=redefined-builtin
1066
+ flag_values: _flagvalues.FlagValues = ...,
1067
+ module_name: Optional[str] = ...,
1068
+ required: bool = ...,
1069
+ **args: Any
1070
+ ) -> _flagvalues.FlagHolder[Optional[List[_T]]]:
1071
+ ...
1072
+
1073
+
1074
+ @overload
1075
+ def DEFINE_multi( # pylint: disable=invalid-name
1076
+ parser: _argument_parser.ArgumentParser[_T],
1077
+ serializer: _argument_parser.ArgumentSerializer[_T],
1078
+ name: str,
1079
+ default: Iterable[_T],
1080
+ help: str, # pylint: disable=redefined-builtin
1081
+ flag_values: _flagvalues.FlagValues = ...,
1082
+ module_name: Optional[str] = ...,
1083
+ required: bool = ...,
1084
+ **args: Any
1085
+ ) -> _flagvalues.FlagHolder[List[_T]]:
1086
+ ...
1087
+
1088
+
1089
+ @overload
1090
+ def DEFINE_multi( # pylint: disable=invalid-name
1091
+ parser: _argument_parser.ArgumentParser[_T],
1092
+ serializer: _argument_parser.ArgumentSerializer[_T],
1093
+ name: str,
1094
+ default: _T,
1095
+ help: str, # pylint: disable=redefined-builtin
1096
+ flag_values: _flagvalues.FlagValues = ...,
1097
+ module_name: Optional[str] = ...,
1098
+ required: bool = ...,
1099
+ **args: Any
1100
+ ) -> _flagvalues.FlagHolder[List[_T]]:
1101
+ ...
1102
+
1103
+
1104
+ def DEFINE_multi( # pylint: disable=invalid-name
1105
+ parser,
1106
+ serializer,
1107
+ name,
1108
+ default,
1109
+ help, # pylint: disable=redefined-builtin
1110
+ flag_values=_flagvalues.FLAGS,
1111
+ module_name=None,
1112
+ required=False,
1113
+ **args
1114
+ ):
1115
+ """Registers a generic MultiFlag that parses its args with a given parser.
1116
+
1117
+ Auxiliary function. Normal users should NOT use it directly.
1118
+
1119
+ Developers who need to create their own 'Parser' classes for options
1120
+ which can appear multiple times can call this module function to
1121
+ register their flags.
1122
+
1123
+ Args:
1124
+ parser: ArgumentParser, used to parse the flag arguments.
1125
+ serializer: ArgumentSerializer, the flag serializer instance.
1126
+ name: str, the flag name.
1127
+ default: Union[Iterable[T], str, None], the default value of the flag. If
1128
+ the value is text, it will be parsed as if it was provided from the
1129
+ command line. If the value is a non-string iterable, it will be iterated
1130
+ over to create a shallow copy of the values. If it is None, it is left
1131
+ as-is.
1132
+ help: str, the help message.
1133
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
1134
+ flag will be registered. This should almost never need to be overridden.
1135
+ module_name: A string, the name of the Python module declaring this flag. If
1136
+ not provided, it will be computed using the stack trace of this call.
1137
+ required: bool, is this a required flag. This must be used as a keyword
1138
+ argument.
1139
+ **args: Dictionary with extra keyword args that are passed to the
1140
+ ``Flag.__init__``.
1141
+
1142
+ Returns:
1143
+ a handle to defined flag.
1144
+ """
1145
+ result = DEFINE_flag(
1146
+ _flag.MultiFlag(parser, serializer, name, default, help, **args),
1147
+ flag_values,
1148
+ module_name,
1149
+ required=True if required else False,
1150
+ )
1151
+ return result
1152
+
1153
+
1154
+ @overload
1155
+ def DEFINE_multi_string( # pylint: disable=invalid-name
1156
+ name: str,
1157
+ default: Union[None, Iterable[str], str],
1158
+ help: str, # pylint: disable=redefined-builtin
1159
+ flag_values: _flagvalues.FlagValues = ...,
1160
+ *,
1161
+ required: Literal[True],
1162
+ **args: Any
1163
+ ) -> _flagvalues.FlagHolder[List[str]]:
1164
+ ...
1165
+
1166
+
1167
+ @overload
1168
+ def DEFINE_multi_string( # pylint: disable=invalid-name
1169
+ name: str,
1170
+ default: None,
1171
+ help: str, # pylint: disable=redefined-builtin
1172
+ flag_values: _flagvalues.FlagValues = ...,
1173
+ required: bool = ...,
1174
+ **args: Any
1175
+ ) -> _flagvalues.FlagHolder[Optional[List[str]]]:
1176
+ ...
1177
+
1178
+
1179
+ @overload
1180
+ def DEFINE_multi_string( # pylint: disable=invalid-name
1181
+ name: str,
1182
+ default: Union[Iterable[str], str],
1183
+ help: str, # pylint: disable=redefined-builtin
1184
+ flag_values: _flagvalues.FlagValues = ...,
1185
+ required: bool = ...,
1186
+ **args: Any
1187
+ ) -> _flagvalues.FlagHolder[List[str]]:
1188
+ ...
1189
+
1190
+
1191
+ def DEFINE_multi_string( # pylint: disable=invalid-name
1192
+ name,
1193
+ default,
1194
+ help, # pylint: disable=redefined-builtin
1195
+ flag_values=_flagvalues.FLAGS,
1196
+ required=False,
1197
+ **args
1198
+ ):
1199
+ """Registers a flag whose value can be a list of any strings.
1200
+
1201
+ Use the flag on the command line multiple times to place multiple
1202
+ string values into the list. The 'default' may be a single string
1203
+ (which will be converted into a single-element list) or a list of
1204
+ strings.
1205
+
1206
+
1207
+ Args:
1208
+ name: str, the flag name.
1209
+ default: Union[Iterable[str], str, None], the default value of the flag; see
1210
+ :func:`DEFINE_multi`.
1211
+ help: str, the help message.
1212
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
1213
+ flag will be registered. This should almost never need to be overridden.
1214
+ required: bool, is this a required flag. This must be used as a keyword
1215
+ argument.
1216
+ **args: Dictionary with extra keyword args that are passed to the
1217
+ ``Flag.__init__``.
1218
+
1219
+ Returns:
1220
+ a handle to defined flag.
1221
+ """
1222
+ parser = _argument_parser.ArgumentParser()
1223
+ serializer = _argument_parser.ArgumentSerializer()
1224
+ return DEFINE_multi(
1225
+ parser,
1226
+ serializer,
1227
+ name,
1228
+ default,
1229
+ help, # pylint: disable=redefined-builtin
1230
+ flag_values,
1231
+ required=True if required else False,
1232
+ **args,
1233
+ )
1234
+
1235
+
1236
+ @overload
1237
+ def DEFINE_multi_integer( # pylint: disable=invalid-name
1238
+ name: str,
1239
+ default: Union[None, Iterable[int], int, str],
1240
+ help: str, # pylint: disable=redefined-builtin
1241
+ lower_bound: Optional[int] = ...,
1242
+ upper_bound: Optional[int] = ...,
1243
+ flag_values: _flagvalues.FlagValues = ...,
1244
+ *,
1245
+ required: Literal[True],
1246
+ **args: Any
1247
+ ) -> _flagvalues.FlagHolder[List[int]]:
1248
+ ...
1249
+
1250
+
1251
+ @overload
1252
+ def DEFINE_multi_integer( # pylint: disable=invalid-name
1253
+ name: str,
1254
+ default: None,
1255
+ help: str, # pylint: disable=redefined-builtin
1256
+ lower_bound: Optional[int] = ...,
1257
+ upper_bound: Optional[int] = ...,
1258
+ flag_values: _flagvalues.FlagValues = ...,
1259
+ required: bool = ...,
1260
+ **args: Any
1261
+ ) -> _flagvalues.FlagHolder[Optional[List[int]]]:
1262
+ ...
1263
+
1264
+
1265
+ @overload
1266
+ def DEFINE_multi_integer( # pylint: disable=invalid-name
1267
+ name: str,
1268
+ default: Union[Iterable[int], int, str],
1269
+ help: str, # pylint: disable=redefined-builtin
1270
+ lower_bound: Optional[int] = ...,
1271
+ upper_bound: Optional[int] = ...,
1272
+ flag_values: _flagvalues.FlagValues = ...,
1273
+ required: bool = ...,
1274
+ **args: Any
1275
+ ) -> _flagvalues.FlagHolder[List[int]]:
1276
+ ...
1277
+
1278
+
1279
+ def DEFINE_multi_integer( # pylint: disable=invalid-name
1280
+ name,
1281
+ default,
1282
+ help, # pylint: disable=redefined-builtin
1283
+ lower_bound=None,
1284
+ upper_bound=None,
1285
+ flag_values=_flagvalues.FLAGS,
1286
+ required=False,
1287
+ **args
1288
+ ):
1289
+ """Registers a flag whose value can be a list of arbitrary integers.
1290
+
1291
+ Use the flag on the command line multiple times to place multiple
1292
+ integer values into the list. The 'default' may be a single integer
1293
+ (which will be converted into a single-element list) or a list of
1294
+ integers.
1295
+
1296
+ Args:
1297
+ name: str, the flag name.
1298
+ default: Union[Iterable[int], str, None], the default value of the flag; see
1299
+ `DEFINE_multi`.
1300
+ help: str, the help message.
1301
+ lower_bound: int, min values of the flag.
1302
+ upper_bound: int, max values of the flag.
1303
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
1304
+ flag will be registered. This should almost never need to be overridden.
1305
+ required: bool, is this a required flag. This must be used as a keyword
1306
+ argument.
1307
+ **args: Dictionary with extra keyword args that are passed to the
1308
+ ``Flag.__init__``.
1309
+
1310
+ Returns:
1311
+ a handle to defined flag.
1312
+ """
1313
+ parser = _argument_parser.IntegerParser(lower_bound, upper_bound)
1314
+ serializer = _argument_parser.ArgumentSerializer()
1315
+ return DEFINE_multi(
1316
+ parser,
1317
+ serializer,
1318
+ name,
1319
+ default,
1320
+ help, # pylint: disable=redefined-builtin
1321
+ flag_values,
1322
+ required=True if required else False,
1323
+ **args,
1324
+ )
1325
+
1326
+
1327
+ @overload
1328
+ def DEFINE_multi_float( # pylint: disable=invalid-name
1329
+ name: str,
1330
+ default: Union[None, Iterable[float], float, str],
1331
+ help: str, # pylint: disable=redefined-builtin
1332
+ lower_bound: Optional[float] = ...,
1333
+ upper_bound: Optional[float] = ...,
1334
+ flag_values: _flagvalues.FlagValues = ...,
1335
+ *,
1336
+ required: Literal[True],
1337
+ **args: Any
1338
+ ) -> _flagvalues.FlagHolder[List[float]]:
1339
+ ...
1340
+
1341
+
1342
+ @overload
1343
+ def DEFINE_multi_float( # pylint: disable=invalid-name
1344
+ name: str,
1345
+ default: None,
1346
+ help: str, # pylint: disable=redefined-builtin
1347
+ lower_bound: Optional[float] = ...,
1348
+ upper_bound: Optional[float] = ...,
1349
+ flag_values: _flagvalues.FlagValues = ...,
1350
+ required: bool = ...,
1351
+ **args: Any
1352
+ ) -> _flagvalues.FlagHolder[Optional[List[float]]]:
1353
+ ...
1354
+
1355
+
1356
+ @overload
1357
+ def DEFINE_multi_float( # pylint: disable=invalid-name
1358
+ name: str,
1359
+ default: Union[Iterable[float], float, str],
1360
+ help: str, # pylint: disable=redefined-builtin
1361
+ lower_bound: Optional[float] = ...,
1362
+ upper_bound: Optional[float] = ...,
1363
+ flag_values: _flagvalues.FlagValues = ...,
1364
+ required: bool = ...,
1365
+ **args: Any
1366
+ ) -> _flagvalues.FlagHolder[List[float]]:
1367
+ ...
1368
+
1369
+
1370
+ def DEFINE_multi_float( # pylint: disable=invalid-name
1371
+ name,
1372
+ default,
1373
+ help, # pylint: disable=redefined-builtin
1374
+ lower_bound=None,
1375
+ upper_bound=None,
1376
+ flag_values=_flagvalues.FLAGS,
1377
+ required=False,
1378
+ **args
1379
+ ):
1380
+ """Registers a flag whose value can be a list of arbitrary floats.
1381
+
1382
+ Use the flag on the command line multiple times to place multiple
1383
+ float values into the list. The 'default' may be a single float
1384
+ (which will be converted into a single-element list) or a list of
1385
+ floats.
1386
+
1387
+ Args:
1388
+ name: str, the flag name.
1389
+ default: Union[Iterable[float], str, None], the default value of the flag;
1390
+ see `DEFINE_multi`.
1391
+ help: str, the help message.
1392
+ lower_bound: float, min values of the flag.
1393
+ upper_bound: float, max values of the flag.
1394
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
1395
+ flag will be registered. This should almost never need to be overridden.
1396
+ required: bool, is this a required flag. This must be used as a keyword
1397
+ argument.
1398
+ **args: Dictionary with extra keyword args that are passed to the
1399
+ ``Flag.__init__``.
1400
+
1401
+ Returns:
1402
+ a handle to defined flag.
1403
+ """
1404
+ parser = _argument_parser.FloatParser(lower_bound, upper_bound)
1405
+ serializer = _argument_parser.ArgumentSerializer()
1406
+ return DEFINE_multi(
1407
+ parser,
1408
+ serializer,
1409
+ name,
1410
+ default,
1411
+ help,
1412
+ flag_values,
1413
+ required=True if required else False,
1414
+ **args,
1415
+ )
1416
+
1417
+
1418
+ @overload
1419
+ def DEFINE_multi_enum( # pylint: disable=invalid-name
1420
+ name: str,
1421
+ default: Union[None, Iterable[str], str],
1422
+ enum_values: Iterable[str],
1423
+ help: str, # pylint: disable=redefined-builtin
1424
+ flag_values: _flagvalues.FlagValues = ...,
1425
+ *,
1426
+ required: Literal[True],
1427
+ **args: Any
1428
+ ) -> _flagvalues.FlagHolder[List[str]]:
1429
+ ...
1430
+
1431
+
1432
+ @overload
1433
+ def DEFINE_multi_enum( # pylint: disable=invalid-name
1434
+ name: str,
1435
+ default: None,
1436
+ enum_values: Iterable[str],
1437
+ help: str, # pylint: disable=redefined-builtin
1438
+ flag_values: _flagvalues.FlagValues = ...,
1439
+ required: bool = ...,
1440
+ **args: Any
1441
+ ) -> _flagvalues.FlagHolder[Optional[List[str]]]:
1442
+ ...
1443
+
1444
+
1445
+ @overload
1446
+ def DEFINE_multi_enum( # pylint: disable=invalid-name
1447
+ name: str,
1448
+ default: Union[Iterable[str], str],
1449
+ enum_values: Iterable[str],
1450
+ help: str, # pylint: disable=redefined-builtin
1451
+ flag_values: _flagvalues.FlagValues = ...,
1452
+ required: bool = ...,
1453
+ **args: Any
1454
+ ) -> _flagvalues.FlagHolder[List[str]]:
1455
+ ...
1456
+
1457
+
1458
+ def DEFINE_multi_enum( # pylint: disable=invalid-name
1459
+ name,
1460
+ default,
1461
+ enum_values,
1462
+ help, # pylint: disable=redefined-builtin
1463
+ flag_values=_flagvalues.FLAGS,
1464
+ case_sensitive=True,
1465
+ required=False,
1466
+ **args
1467
+ ):
1468
+ """Registers a flag whose value can be a list strings from enum_values.
1469
+
1470
+ Use the flag on the command line multiple times to place multiple
1471
+ enum values into the list. The 'default' may be a single string
1472
+ (which will be converted into a single-element list) or a list of
1473
+ strings.
1474
+
1475
+ Args:
1476
+ name: str, the flag name.
1477
+ default: Union[Iterable[str], str, None], the default value of the flag; see
1478
+ `DEFINE_multi`.
1479
+ enum_values: [str], a non-empty list of strings with the possible values for
1480
+ the flag.
1481
+ help: str, the help message.
1482
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
1483
+ flag will be registered. This should almost never need to be overridden.
1484
+ case_sensitive: Whether or not the enum is to be case-sensitive.
1485
+ required: bool, is this a required flag. This must be used as a keyword
1486
+ argument.
1487
+ **args: Dictionary with extra keyword args that are passed to the
1488
+ ``Flag.__init__``.
1489
+
1490
+ Returns:
1491
+ a handle to defined flag.
1492
+ """
1493
+ parser = _argument_parser.EnumParser(enum_values, case_sensitive)
1494
+ serializer = _argument_parser.ArgumentSerializer()
1495
+ return DEFINE_multi(
1496
+ parser,
1497
+ serializer,
1498
+ name,
1499
+ default,
1500
+ '<%s>: %s' % ('|'.join(enum_values), help),
1501
+ flag_values,
1502
+ required=True if required else False,
1503
+ **args,
1504
+ )
1505
+
1506
+
1507
+ @overload
1508
+ def DEFINE_multi_enum_class( # pylint: disable=invalid-name
1509
+ name: str,
1510
+ # This is separate from `Union[None, _ET, Iterable[str], str]` to avoid a
1511
+ # Pytype issue inferring the return value to
1512
+ # FlagHolder[List[Union[_ET, enum.Enum]]] when an iterable of concrete enum
1513
+ # subclasses are used.
1514
+ default: Iterable[_ET],
1515
+ enum_class: Type[_ET],
1516
+ help: str, # pylint: disable=redefined-builtin
1517
+ flag_values: _flagvalues.FlagValues = ...,
1518
+ module_name: Optional[str] = ...,
1519
+ *,
1520
+ required: Literal[True],
1521
+ **args: Any
1522
+ ) -> _flagvalues.FlagHolder[List[_ET]]:
1523
+ ...
1524
+
1525
+
1526
+ @overload
1527
+ def DEFINE_multi_enum_class( # pylint: disable=invalid-name
1528
+ name: str,
1529
+ default: Union[None, _ET, Iterable[str], str],
1530
+ enum_class: Type[_ET],
1531
+ help: str, # pylint: disable=redefined-builtin
1532
+ flag_values: _flagvalues.FlagValues = ...,
1533
+ module_name: Optional[str] = ...,
1534
+ *,
1535
+ required: Literal[True],
1536
+ **args: Any
1537
+ ) -> _flagvalues.FlagHolder[List[_ET]]:
1538
+ ...
1539
+
1540
+
1541
+ @overload
1542
+ def DEFINE_multi_enum_class( # pylint: disable=invalid-name
1543
+ name: str,
1544
+ default: None,
1545
+ enum_class: Type[_ET],
1546
+ help: str, # pylint: disable=redefined-builtin
1547
+ flag_values: _flagvalues.FlagValues = ...,
1548
+ module_name: Optional[str] = ...,
1549
+ required: bool = ...,
1550
+ **args: Any
1551
+ ) -> _flagvalues.FlagHolder[Optional[List[_ET]]]:
1552
+ ...
1553
+
1554
+
1555
+ @overload
1556
+ def DEFINE_multi_enum_class( # pylint: disable=invalid-name
1557
+ name: str,
1558
+ # This is separate from `Union[None, _ET, Iterable[str], str]` to avoid a
1559
+ # Pytype issue inferring the return value to
1560
+ # FlagHolder[List[Union[_ET, enum.Enum]]] when an iterable of concrete enum
1561
+ # subclasses are used.
1562
+ default: Iterable[_ET],
1563
+ enum_class: Type[_ET],
1564
+ help: str, # pylint: disable=redefined-builtin
1565
+ flag_values: _flagvalues.FlagValues = ...,
1566
+ module_name: Optional[str] = ...,
1567
+ required: bool = ...,
1568
+ **args: Any
1569
+ ) -> _flagvalues.FlagHolder[List[_ET]]:
1570
+ ...
1571
+
1572
+
1573
+ @overload
1574
+ def DEFINE_multi_enum_class( # pylint: disable=invalid-name
1575
+ name: str,
1576
+ default: Union[_ET, Iterable[str], str],
1577
+ enum_class: Type[_ET],
1578
+ help: str, # pylint: disable=redefined-builtin
1579
+ flag_values: _flagvalues.FlagValues = ...,
1580
+ module_name: Optional[str] = ...,
1581
+ required: bool = ...,
1582
+ **args: Any
1583
+ ) -> _flagvalues.FlagHolder[List[_ET]]:
1584
+ ...
1585
+
1586
+
1587
+ def DEFINE_multi_enum_class( # pylint: disable=invalid-name
1588
+ name,
1589
+ default,
1590
+ enum_class,
1591
+ help, # pylint: disable=redefined-builtin
1592
+ flag_values=_flagvalues.FLAGS,
1593
+ module_name=None,
1594
+ case_sensitive=False,
1595
+ required=False,
1596
+ **args
1597
+ ):
1598
+ """Registers a flag whose value can be a list of enum members.
1599
+
1600
+ Use the flag on the command line multiple times to place multiple
1601
+ enum values into the list.
1602
+
1603
+ Args:
1604
+ name: str, the flag name.
1605
+ default: Union[Iterable[Enum], Iterable[str], Enum, str, None], the default
1606
+ value of the flag; see `DEFINE_multi`; only differences are documented
1607
+ here. If the value is a single Enum, it is treated as a single-item list
1608
+ of that Enum value. If it is an iterable, text values within the iterable
1609
+ will be converted to the equivalent Enum objects.
1610
+ enum_class: class, the Enum class with all the possible values for the flag.
1611
+ help: str, the help message.
1612
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
1613
+ flag will be registered. This should almost never need to be overridden.
1614
+ module_name: A string, the name of the Python module declaring this flag. If
1615
+ not provided, it will be computed using the stack trace of this call.
1616
+ case_sensitive: bool, whether to map strings to members of the enum_class
1617
+ without considering case.
1618
+ required: bool, is this a required flag. This must be used as a keyword
1619
+ argument.
1620
+ **args: Dictionary with extra keyword args that are passed to the
1621
+ ``Flag.__init__``.
1622
+
1623
+ Returns:
1624
+ a handle to defined flag.
1625
+ """
1626
+ # NOTE: pytype fails if this is a direct return.
1627
+ result = DEFINE_flag(
1628
+ _flag.MultiEnumClassFlag(
1629
+ name,
1630
+ default,
1631
+ help,
1632
+ enum_class,
1633
+ case_sensitive=case_sensitive,
1634
+ **args,
1635
+ ),
1636
+ flag_values,
1637
+ module_name,
1638
+ required=True if required else False,
1639
+ )
1640
+ return result
1641
+
1642
+
1643
+ def DEFINE_alias( # pylint: disable=invalid-name
1644
+ name: str,
1645
+ original_name: str,
1646
+ flag_values: _flagvalues.FlagValues = _flagvalues.FLAGS,
1647
+ module_name: Optional[str] = None,
1648
+ ) -> _flagvalues.FlagHolder[Any]:
1649
+ """Defines an alias flag for an existing one.
1650
+
1651
+ Args:
1652
+ name: str, the flag name.
1653
+ original_name: str, the original flag name.
1654
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
1655
+ flag will be registered. This should almost never need to be overridden.
1656
+ module_name: A string, the name of the module that defines this flag.
1657
+
1658
+ Returns:
1659
+ a handle to defined flag.
1660
+
1661
+ Raises:
1662
+ flags.FlagError:
1663
+ UnrecognizedFlagError: if the referenced flag doesn't exist.
1664
+ DuplicateFlagError: if the alias name has been used by some existing flag.
1665
+ """
1666
+ if original_name not in flag_values:
1667
+ raise _exceptions.UnrecognizedFlagError(original_name)
1668
+ flag = flag_values[original_name]
1669
+
1670
+ class _FlagAlias(_flag.Flag):
1671
+ """Overrides Flag class so alias value is copy of original flag value."""
1672
+
1673
+ def parse(self, argument):
1674
+ flag.parse(argument)
1675
+ self.present += 1
1676
+
1677
+ def _parse_from_default(self, value):
1678
+ # The value was already parsed by the aliased flag, so there is no
1679
+ # need to call the parser on it a second time.
1680
+ # Additionally, because of how MultiFlag parses and merges values,
1681
+ # it isn't possible to delegate to the aliased flag and still get
1682
+ # the correct values.
1683
+ return value
1684
+
1685
+ @property
1686
+ def value(self):
1687
+ return flag.value
1688
+
1689
+ @value.setter
1690
+ def value(self, value):
1691
+ flag.value = value
1692
+
1693
+ help_msg = 'Alias for --%s.' % flag.name
1694
+ # If alias_name has been used, flags.DuplicatedFlag will be raised.
1695
+ return DEFINE_flag(
1696
+ _FlagAlias(
1697
+ flag.parser,
1698
+ flag.serializer,
1699
+ name,
1700
+ flag.default,
1701
+ help_msg,
1702
+ boolean=flag.boolean), flag_values, module_name)
lib/python3.10/site-packages/absl/flags/_exceptions.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Exception classes in ABSL flags library.
16
+
17
+ Do NOT import this module directly. Import the flags package and use the
18
+ aliases defined at the package level instead.
19
+ """
20
+
21
+ import sys
22
+
23
+ from absl.flags import _helpers
24
+
25
+
26
+ _helpers.disclaim_module_ids.add(id(sys.modules[__name__]))
27
+
28
+
29
+ class Error(Exception):
30
+ """The base class for all flags errors."""
31
+
32
+
33
+ class CantOpenFlagFileError(Error):
34
+ """Raised when flagfile fails to open.
35
+
36
+ E.g. the file doesn't exist, or has wrong permissions.
37
+ """
38
+
39
+
40
+ class DuplicateFlagError(Error):
41
+ """Raised if there is a flag naming conflict."""
42
+
43
+ @classmethod
44
+ def from_flag(cls, flagname, flag_values, other_flag_values=None):
45
+ """Creates a DuplicateFlagError by providing flag name and values.
46
+
47
+ Args:
48
+ flagname: str, the name of the flag being redefined.
49
+ flag_values: :class:`FlagValues`, the FlagValues instance containing the
50
+ first definition of flagname.
51
+ other_flag_values: :class:`FlagValues`, if it is not None, it should be
52
+ the FlagValues object where the second definition of flagname occurs.
53
+ If it is None, we assume that we're being called when attempting to
54
+ create the flag a second time, and we use the module calling this one
55
+ as the source of the second definition.
56
+
57
+ Returns:
58
+ An instance of DuplicateFlagError.
59
+ """
60
+ first_module = flag_values.find_module_defining_flag(
61
+ flagname, default='<unknown>')
62
+ if other_flag_values is None:
63
+ second_module = _helpers.get_calling_module()
64
+ else:
65
+ second_module = other_flag_values.find_module_defining_flag(
66
+ flagname, default='<unknown>')
67
+ flag_summary = flag_values[flagname].help
68
+ msg = ("The flag '%s' is defined twice. First from %s, Second from %s. "
69
+ "Description from first occurrence: %s") % (
70
+ flagname, first_module, second_module, flag_summary)
71
+ return cls(msg)
72
+
73
+
74
+ class IllegalFlagValueError(Error):
75
+ """Raised when the flag command line argument is illegal."""
76
+
77
+
78
+ class UnrecognizedFlagError(Error):
79
+ """Raised when a flag is unrecognized.
80
+
81
+ Attributes:
82
+ flagname: str, the name of the unrecognized flag.
83
+ flagvalue: The value of the flag, empty if the flag is not defined.
84
+ """
85
+
86
+ def __init__(self, flagname, flagvalue='', suggestions=None):
87
+ self.flagname = flagname
88
+ self.flagvalue = flagvalue
89
+ if suggestions:
90
+ # Space before the question mark is intentional to not include it in the
91
+ # selection when copy-pasting the suggestion from (some) terminals.
92
+ tip = '. Did you mean: %s ?' % ', '.join(suggestions)
93
+ else:
94
+ tip = ''
95
+ super().__init__("Unknown command line flag '%s'%s" % (flagname, tip))
96
+
97
+
98
+ class UnparsedFlagAccessError(Error):
99
+ """Raised when accessing the flag value from unparsed :class:`FlagValues`."""
100
+
101
+
102
+ class ValidationError(Error):
103
+ """Raised when flag validator constraint is not satisfied."""
104
+
105
+
106
+ class FlagNameConflictsWithMethodError(Error):
107
+ """Raised when a flag name conflicts with :class:`FlagValues` methods."""
lib/python3.10/site-packages/absl/flags/_flag.py ADDED
@@ -0,0 +1,566 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Contains Flag class - information about single command-line flag.
16
+
17
+ Do NOT import this module directly. Import the flags package and use the
18
+ aliases defined at the package level instead.
19
+ """
20
+
21
+ from collections import abc
22
+ import copy
23
+ import enum
24
+ import functools
25
+ from typing import Any, Dict, Generic, Iterable, List, Optional, Type, TypeVar, Union
26
+ from xml.dom import minidom
27
+
28
+ from absl.flags import _argument_parser
29
+ from absl.flags import _exceptions
30
+ from absl.flags import _helpers
31
+
32
+ _T = TypeVar('_T')
33
+ _ET = TypeVar('_ET', bound=enum.Enum)
34
+
35
+
36
+ @functools.total_ordering
37
+ class Flag(Generic[_T]):
38
+ """Information about a command-line flag.
39
+
40
+ Attributes:
41
+ name: the name for this flag
42
+ default: the default value for this flag
43
+ default_unparsed: the unparsed default value for this flag.
44
+ default_as_str: default value as repr'd string, e.g., "'true'"
45
+ (or None)
46
+ value: the most recent parsed value of this flag set by :meth:`parse`
47
+ help: a help string or None if no help is available
48
+ short_name: the single letter alias for this flag (or None)
49
+ boolean: if 'true', this flag does not accept arguments
50
+ present: true if this flag was parsed from command line flags
51
+ parser: an :class:`~absl.flags.ArgumentParser` object
52
+ serializer: an ArgumentSerializer object
53
+ allow_override: the flag may be redefined without raising an error,
54
+ and newly defined flag overrides the old one.
55
+ allow_override_cpp: use the flag from C++ if available the flag
56
+ definition is replaced by the C++ flag after init
57
+ allow_hide_cpp: use the Python flag despite having a C++ flag with
58
+ the same name (ignore the C++ flag)
59
+ using_default_value: the flag value has not been set by user
60
+ allow_overwrite: the flag may be parsed more than once without
61
+ raising an error, the last set value will be used
62
+ allow_using_method_names: whether this flag can be defined even if
63
+ it has a name that conflicts with a FlagValues method.
64
+ validators: list of the flag validators.
65
+
66
+ The only public method of a ``Flag`` object is :meth:`parse`, but it is
67
+ typically only called by a :class:`~absl.flags.FlagValues` object. The
68
+ :meth:`parse` method is a thin wrapper around the
69
+ :meth:`ArgumentParser.parse()<absl.flags.ArgumentParser.parse>` method. The
70
+ parsed value is saved in ``.value``, and the ``.present`` attribute is
71
+ updated. If this flag was already present, an Error is raised.
72
+
73
+ :meth:`parse` is also called during ``__init__`` to parse the default value
74
+ and initialize the ``.value`` attribute. This enables other python modules to
75
+ safely use flags even if the ``__main__`` module neglects to parse the
76
+ command line arguments. The ``.present`` attribute is cleared after
77
+ ``__init__`` parsing. If the default value is set to ``None``, then the
78
+ ``__init__`` parsing step is skipped and the ``.value`` attribute is
79
+ initialized to None.
80
+
81
+ Note: The default value is also presented to the user in the help
82
+ string, so it is important that it be a legal value for this flag.
83
+ """
84
+
85
+ # NOTE: pytype doesn't find defaults without this.
86
+ default: Optional[_T]
87
+ default_as_str: Optional[str]
88
+ default_unparsed: Union[Optional[_T], str]
89
+
90
+ parser: _argument_parser.ArgumentParser[_T]
91
+
92
+ def __init__(
93
+ self,
94
+ parser: _argument_parser.ArgumentParser[_T],
95
+ serializer: Optional[_argument_parser.ArgumentSerializer[_T]],
96
+ name: str,
97
+ default: Union[Optional[_T], str],
98
+ help_string: Optional[str],
99
+ short_name: Optional[str] = None,
100
+ boolean: bool = False,
101
+ allow_override: bool = False,
102
+ allow_override_cpp: bool = False,
103
+ allow_hide_cpp: bool = False,
104
+ allow_overwrite: bool = True,
105
+ allow_using_method_names: bool = False,
106
+ ) -> None:
107
+ self.name = name
108
+
109
+ if not help_string:
110
+ help_string = '(no help available)'
111
+
112
+ self.help = help_string
113
+ self.short_name = short_name
114
+ self.boolean = boolean
115
+ self.present = 0
116
+ self.parser = parser # type: ignore[annotation-type-mismatch]
117
+ self.serializer = serializer
118
+ self.allow_override = allow_override
119
+ self.allow_override_cpp = allow_override_cpp
120
+ self.allow_hide_cpp = allow_hide_cpp
121
+ self.allow_overwrite = allow_overwrite
122
+ self.allow_using_method_names = allow_using_method_names
123
+
124
+ self.using_default_value = True
125
+ self._value: Optional[_T] = None
126
+ self.validators: List[Any] = []
127
+ if self.allow_hide_cpp and self.allow_override_cpp:
128
+ raise _exceptions.Error(
129
+ "Can't have both allow_hide_cpp (means use Python flag) and "
130
+ 'allow_override_cpp (means use C++ flag after InitGoogle)')
131
+
132
+ self._set_default(default)
133
+
134
+ @property
135
+ def value(self) -> Optional[_T]:
136
+ return self._value
137
+
138
+ @value.setter
139
+ def value(self, value: Optional[_T]):
140
+ self._value = value
141
+
142
+ def __hash__(self):
143
+ return hash(id(self))
144
+
145
+ def __eq__(self, other):
146
+ return self is other
147
+
148
+ def __lt__(self, other):
149
+ if isinstance(other, Flag):
150
+ return id(self) < id(other)
151
+ return NotImplemented
152
+
153
+ def __bool__(self):
154
+ raise TypeError('A Flag instance would always be True. '
155
+ 'Did you mean to test the `.value` attribute?')
156
+
157
+ def __getstate__(self):
158
+ raise TypeError("can't pickle Flag objects")
159
+
160
+ def __copy__(self):
161
+ raise TypeError('%s does not support shallow copies. '
162
+ 'Use copy.deepcopy instead.' % type(self).__name__)
163
+
164
+ def __deepcopy__(self, memo: Dict[int, Any]) -> 'Flag[_T]':
165
+ result = object.__new__(type(self))
166
+ result.__dict__ = copy.deepcopy(self.__dict__, memo)
167
+ return result
168
+
169
+ def _get_parsed_value_as_string(self, value: Optional[_T]) -> Optional[str]:
170
+ """Returns parsed flag value as string."""
171
+ if value is None:
172
+ return None
173
+ if self.serializer:
174
+ return repr(self.serializer.serialize(value))
175
+ if self.boolean:
176
+ if value:
177
+ return repr('true')
178
+ else:
179
+ return repr('false')
180
+ return repr(str(value))
181
+
182
+ def parse(self, argument: Union[str, _T]) -> None:
183
+ """Parses string and sets flag value.
184
+
185
+ Args:
186
+ argument: str or the correct flag value type, argument to be parsed.
187
+ """
188
+ if self.present and not self.allow_overwrite:
189
+ raise _exceptions.IllegalFlagValueError(
190
+ 'flag --%s=%s: already defined as %s' % (
191
+ self.name, argument, self.value))
192
+ self.value = self._parse(argument)
193
+ self.present += 1
194
+
195
+ def _parse(self, argument: Union[str, _T]) -> Optional[_T]:
196
+ """Internal parse function.
197
+
198
+ It returns the parsed value, and does not modify class states.
199
+
200
+ Args:
201
+ argument: str or the correct flag value type, argument to be parsed.
202
+
203
+ Returns:
204
+ The parsed value.
205
+ """
206
+ try:
207
+ return self.parser.parse(argument) # type: ignore[arg-type]
208
+ except (TypeError, ValueError, OverflowError) as e:
209
+ # Recast as IllegalFlagValueError.
210
+ raise _exceptions.IllegalFlagValueError(
211
+ 'flag --%s=%s: %s' % (self.name, argument, e))
212
+
213
+ def unparse(self) -> None:
214
+ self.value = self.default
215
+ self.using_default_value = True
216
+ self.present = 0
217
+
218
+ def serialize(self) -> str:
219
+ """Serializes the flag."""
220
+ return self._serialize(self.value)
221
+
222
+ def _serialize(self, value: Optional[_T]) -> str:
223
+ """Internal serialize function."""
224
+ if value is None:
225
+ return ''
226
+ if self.boolean:
227
+ if value:
228
+ return '--%s' % self.name
229
+ else:
230
+ return '--no%s' % self.name
231
+ else:
232
+ if not self.serializer:
233
+ raise _exceptions.Error(
234
+ 'Serializer not present for flag %s' % self.name)
235
+ return '--%s=%s' % (self.name, self.serializer.serialize(value))
236
+
237
+ def _set_default(self, value: Union[Optional[_T], str]) -> None:
238
+ """Changes the default value (and current value too) for this Flag."""
239
+ self.default_unparsed = value
240
+ if value is None:
241
+ self.default = None
242
+ else:
243
+ self.default = self._parse_from_default(value)
244
+ self.default_as_str = self._get_parsed_value_as_string(self.default)
245
+ if self.using_default_value:
246
+ self.value = self.default
247
+
248
+ # This is split out so that aliases can skip regular parsing of the default
249
+ # value.
250
+ def _parse_from_default(self, value: Union[str, _T]) -> Optional[_T]:
251
+ return self._parse(value)
252
+
253
+ def flag_type(self) -> str:
254
+ """Returns a str that describes the type of the flag.
255
+
256
+ NOTE: we use strings, and not the types.*Type constants because
257
+ our flags can have more exotic types, e.g., 'comma separated list
258
+ of strings', 'whitespace separated list of strings', etc.
259
+ """
260
+ return self.parser.flag_type()
261
+
262
+ def _create_xml_dom_element(
263
+ self, doc: minidom.Document, module_name: str, is_key: bool = False
264
+ ) -> minidom.Element:
265
+ """Returns an XML element that contains this flag's information.
266
+
267
+ This is information that is relevant to all flags (e.g., name,
268
+ meaning, etc.). If you defined a flag that has some other pieces of
269
+ info, then please override _ExtraXMLInfo.
270
+
271
+ Please do NOT override this method.
272
+
273
+ Args:
274
+ doc: minidom.Document, the DOM document it should create nodes from.
275
+ module_name: str,, the name of the module that defines this flag.
276
+ is_key: boolean, True iff this flag is key for main module.
277
+
278
+ Returns:
279
+ A minidom.Element instance.
280
+ """
281
+ element = doc.createElement('flag')
282
+ if is_key:
283
+ element.appendChild(_helpers.create_xml_dom_element(doc, 'key', 'yes'))
284
+ element.appendChild(_helpers.create_xml_dom_element(
285
+ doc, 'file', module_name))
286
+ # Adds flag features that are relevant for all flags.
287
+ element.appendChild(_helpers.create_xml_dom_element(doc, 'name', self.name))
288
+ if self.short_name:
289
+ element.appendChild(_helpers.create_xml_dom_element(
290
+ doc, 'short_name', self.short_name))
291
+ if self.help:
292
+ element.appendChild(_helpers.create_xml_dom_element(
293
+ doc, 'meaning', self.help))
294
+ # The default flag value can either be represented as a string like on the
295
+ # command line, or as a Python object. We serialize this value in the
296
+ # latter case in order to remain consistent.
297
+ if self.serializer and not isinstance(self.default, str):
298
+ if self.default is not None:
299
+ default_serialized = self.serializer.serialize(self.default)
300
+ else:
301
+ default_serialized = ''
302
+ else:
303
+ default_serialized = self.default # type: ignore[assignment]
304
+ element.appendChild(_helpers.create_xml_dom_element(
305
+ doc, 'default', default_serialized))
306
+ value_serialized = self._serialize_value_for_xml(self.value)
307
+ element.appendChild(_helpers.create_xml_dom_element(
308
+ doc, 'current', value_serialized))
309
+ element.appendChild(_helpers.create_xml_dom_element(
310
+ doc, 'type', self.flag_type()))
311
+ # Adds extra flag features this flag may have.
312
+ for e in self._extra_xml_dom_elements(doc):
313
+ element.appendChild(e)
314
+ return element
315
+
316
+ def _serialize_value_for_xml(self, value: Optional[_T]) -> Any:
317
+ """Returns the serialized value, for use in an XML help text."""
318
+ return value
319
+
320
+ def _extra_xml_dom_elements(
321
+ self, doc: minidom.Document
322
+ ) -> List[minidom.Element]:
323
+ """Returns extra info about this flag in XML.
324
+
325
+ "Extra" means "not already included by _create_xml_dom_element above."
326
+
327
+ Args:
328
+ doc: minidom.Document, the DOM document it should create nodes from.
329
+
330
+ Returns:
331
+ A list of minidom.Element.
332
+ """
333
+ # Usually, the parser knows the extra details about the flag, so
334
+ # we just forward the call to it.
335
+ return self.parser._custom_xml_dom_elements(doc) # pylint: disable=protected-access
336
+
337
+
338
+ class BooleanFlag(Flag[bool]):
339
+ """Basic boolean flag.
340
+
341
+ Boolean flags do not take any arguments, and their value is either
342
+ ``True`` (1) or ``False`` (0). The false value is specified on the command
343
+ line by prepending the word ``'no'`` to either the long or the short flag
344
+ name.
345
+
346
+ For example, if a Boolean flag was created whose long name was
347
+ ``'update'`` and whose short name was ``'x'``, then this flag could be
348
+ explicitly unset through either ``--noupdate`` or ``--nox``.
349
+ """
350
+
351
+ def __init__(
352
+ self,
353
+ name: str,
354
+ default: Union[Optional[bool], str],
355
+ help: Optional[str], # pylint: disable=redefined-builtin
356
+ short_name: Optional[str] = None,
357
+ **args
358
+ ) -> None:
359
+ p = _argument_parser.BooleanParser()
360
+ super().__init__(p, None, name, default, help, short_name, True, **args)
361
+
362
+
363
+ class EnumFlag(Flag[str]):
364
+ """Basic enum flag; its value can be any string from list of enum_values."""
365
+
366
+ parser: _argument_parser.EnumParser
367
+
368
+ def __init__(
369
+ self,
370
+ name: str,
371
+ default: Optional[str],
372
+ help: Optional[str], # pylint: disable=redefined-builtin
373
+ enum_values: Iterable[str],
374
+ short_name: Optional[str] = None,
375
+ case_sensitive: bool = True,
376
+ **args
377
+ ):
378
+ p = _argument_parser.EnumParser(enum_values, case_sensitive)
379
+ g: _argument_parser.ArgumentSerializer[str]
380
+ g = _argument_parser.ArgumentSerializer()
381
+ super().__init__(p, g, name, default, help, short_name, **args)
382
+ self.parser = p
383
+ self.help = '<%s>: %s' % ('|'.join(p.enum_values), self.help)
384
+
385
+ def _extra_xml_dom_elements(
386
+ self, doc: minidom.Document
387
+ ) -> List[minidom.Element]:
388
+ elements = []
389
+ for enum_value in self.parser.enum_values:
390
+ elements.append(_helpers.create_xml_dom_element(
391
+ doc, 'enum_value', enum_value))
392
+ return elements
393
+
394
+
395
+ class EnumClassFlag(Flag[_ET]):
396
+ """Basic enum flag; its value is an enum class's member."""
397
+
398
+ parser: _argument_parser.EnumClassParser
399
+
400
+ def __init__(
401
+ self,
402
+ name: str,
403
+ default: Union[Optional[_ET], str],
404
+ help: Optional[str], # pylint: disable=redefined-builtin
405
+ enum_class: Type[_ET],
406
+ short_name: Optional[str] = None,
407
+ case_sensitive: bool = False,
408
+ **args
409
+ ):
410
+ p = _argument_parser.EnumClassParser(
411
+ enum_class, case_sensitive=case_sensitive
412
+ )
413
+ g: _argument_parser.EnumClassSerializer[_ET]
414
+ g = _argument_parser.EnumClassSerializer(lowercase=not case_sensitive)
415
+ super().__init__(p, g, name, default, help, short_name, **args)
416
+ self.parser = p
417
+ self.help = '<%s>: %s' % ('|'.join(p.member_names), self.help)
418
+
419
+ def _extra_xml_dom_elements(
420
+ self, doc: minidom.Document
421
+ ) -> List[minidom.Element]:
422
+ elements = []
423
+ for enum_value in self.parser.enum_class.__members__.keys():
424
+ elements.append(_helpers.create_xml_dom_element(
425
+ doc, 'enum_value', enum_value))
426
+ return elements
427
+
428
+
429
+ class MultiFlag(Generic[_T], Flag[List[_T]]):
430
+ """A flag that can appear multiple time on the command-line.
431
+
432
+ The value of such a flag is a list that contains the individual values
433
+ from all the appearances of that flag on the command-line.
434
+
435
+ See the __doc__ for Flag for most behavior of this class. Only
436
+ differences in behavior are described here:
437
+
438
+ * The default value may be either a single value or an iterable of values.
439
+ A single value is transformed into a single-item list of that value.
440
+
441
+ * The value of the flag is always a list, even if the option was
442
+ only supplied once, and even if the default value is a single
443
+ value
444
+ """
445
+
446
+ def __init__(self, *args, **kwargs):
447
+ super().__init__(*args, **kwargs)
448
+ self.help += ';\n repeat this option to specify a list of values'
449
+
450
+ def parse(self, arguments: Union[str, _T, Iterable[_T]]): # pylint: disable=arguments-renamed
451
+ """Parses one or more arguments with the installed parser.
452
+
453
+ Args:
454
+ arguments: a single argument or a list of arguments (typically a
455
+ list of default values); a single argument is converted
456
+ internally into a list containing one item.
457
+ """
458
+ new_values = self._parse(arguments)
459
+ if self.present:
460
+ assert self.value is not None
461
+ self.value.extend(new_values)
462
+ else:
463
+ self.value = new_values
464
+ self.present += len(new_values)
465
+
466
+ def _parse(self, arguments: Union[str, _T, Iterable[_T]]) -> List[_T]: # pylint: disable=arguments-renamed
467
+ arguments_list: List[Union[str, _T]]
468
+
469
+ if isinstance(arguments, str):
470
+ arguments_list = [arguments]
471
+
472
+ elif isinstance(arguments, abc.Iterable):
473
+ arguments_list = list(arguments)
474
+
475
+ else:
476
+ # Default value may be a list of values. Most other arguments
477
+ # will not be, so convert them into a single-item list to make
478
+ # processing simpler below.
479
+ arguments_list = [arguments]
480
+
481
+ return [super(MultiFlag, self)._parse(item) for item in arguments_list] # type: ignore
482
+
483
+ def _serialize(self, value: Optional[List[_T]]) -> str:
484
+ """See base class."""
485
+ if not self.serializer:
486
+ raise _exceptions.Error(
487
+ 'Serializer not present for flag %s' % self.name)
488
+ if value is None:
489
+ return ''
490
+
491
+ serialized_items = [
492
+ super(MultiFlag, self)._serialize(value_item) # type: ignore[arg-type]
493
+ for value_item in value
494
+ ]
495
+
496
+ return '\n'.join(serialized_items)
497
+
498
+ def flag_type(self):
499
+ """See base class."""
500
+ return 'multi ' + self.parser.flag_type()
501
+
502
+ def _extra_xml_dom_elements(
503
+ self, doc: minidom.Document
504
+ ) -> List[minidom.Element]:
505
+ elements = []
506
+ if hasattr(self.parser, 'enum_values'):
507
+ for enum_value in self.parser.enum_values: # pytype: disable=attribute-error
508
+ elements.append(_helpers.create_xml_dom_element(
509
+ doc, 'enum_value', enum_value))
510
+ return elements
511
+
512
+
513
+ class MultiEnumClassFlag(MultiFlag[_ET]): # pytype: disable=not-indexable
514
+ """A multi_enum_class flag.
515
+
516
+ See the __doc__ for MultiFlag for most behaviors of this class. In addition,
517
+ this class knows how to handle enum.Enum instances as values for this flag
518
+ type.
519
+ """
520
+
521
+ parser: _argument_parser.EnumClassParser[_ET] # type: ignore[assignment]
522
+
523
+ def __init__(
524
+ self,
525
+ name: str,
526
+ default: Union[None, Iterable[_ET], _ET, Iterable[str], str],
527
+ help_string: str,
528
+ enum_class: Type[_ET],
529
+ case_sensitive: bool = False,
530
+ **args
531
+ ):
532
+ p = _argument_parser.EnumClassParser(
533
+ enum_class, case_sensitive=case_sensitive)
534
+ g: _argument_parser.EnumClassListSerializer
535
+ g = _argument_parser.EnumClassListSerializer(
536
+ list_sep=',', lowercase=not case_sensitive)
537
+ super().__init__(p, g, name, default, help_string, **args)
538
+ # NOTE: parser should be typed EnumClassParser[_ET] but the constructor
539
+ # restricts the available interface to ArgumentParser[str].
540
+ self.parser = p
541
+ # NOTE: serializer should be non-Optional but this isn't inferred.
542
+ self.serializer = g
543
+ self.help = (
544
+ '<%s>: %s;\n repeat this option to specify a list of values' %
545
+ ('|'.join(p.member_names), help_string or '(no help available)'))
546
+
547
+ def _extra_xml_dom_elements(
548
+ self, doc: minidom.Document
549
+ ) -> List[minidom.Element]:
550
+ elements = []
551
+ for enum_value in self.parser.enum_class.__members__.keys(): # pytype: disable=attribute-error
552
+ elements.append(_helpers.create_xml_dom_element(
553
+ doc, 'enum_value', enum_value))
554
+ return elements
555
+
556
+ def _serialize_value_for_xml(self, value):
557
+ """See base class."""
558
+ if value is not None:
559
+ if not self.serializer:
560
+ raise _exceptions.Error(
561
+ 'Serializer not present for flag %s' % self.name
562
+ )
563
+ value_serialized = self.serializer.serialize(value)
564
+ else:
565
+ value_serialized = ''
566
+ return value_serialized
lib/python3.10/site-packages/absl/flags/_flagvalues.py ADDED
@@ -0,0 +1,1486 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Defines the FlagValues class - registry of 'Flag' objects.
15
+
16
+ Do NOT import this module directly. Import the flags package and use the
17
+ aliases defined at the package level instead.
18
+ """
19
+
20
+ import copy
21
+ import logging
22
+ import os
23
+ import sys
24
+ from typing import Any, Callable, Dict, Generic, Iterable, Iterator, List, Optional, Sequence, Set, TextIO, Tuple, TypeVar, Union
25
+ from xml.dom import minidom
26
+
27
+ from absl.flags import _exceptions
28
+ from absl.flags import _flag
29
+ from absl.flags import _helpers
30
+ from absl.flags import _validators_classes
31
+ from absl.flags._flag import Flag
32
+
33
+ # Add flagvalues module to disclaimed module ids.
34
+ _helpers.disclaim_module_ids.add(id(sys.modules[__name__]))
35
+
36
+ _T = TypeVar('_T')
37
+ _T_co = TypeVar('_T_co', covariant=True) # pytype: disable=not-supported-yet
38
+
39
+
40
+ class FlagValues:
41
+ """Registry of :class:`~absl.flags.Flag` objects.
42
+
43
+ A :class:`FlagValues` can then scan command line arguments, passing flag
44
+ arguments through to the 'Flag' objects that it owns. It also
45
+ provides easy access to the flag values. Typically only one
46
+ :class:`FlagValues` object is needed by an application:
47
+ :const:`FLAGS`.
48
+
49
+ This class is heavily overloaded:
50
+
51
+ :class:`Flag` objects are registered via ``__setitem__``::
52
+
53
+ FLAGS['longname'] = x # register a new flag
54
+
55
+ The ``.value`` attribute of the registered :class:`~absl.flags.Flag` objects
56
+ can be accessed as attributes of this :class:`FlagValues` object, through
57
+ ``__getattr__``. Both the long and short name of the original
58
+ :class:`~absl.flags.Flag` objects can be used to access its value::
59
+
60
+ FLAGS.longname # parsed flag value
61
+ FLAGS.x # parsed flag value (short name)
62
+
63
+ Command line arguments are scanned and passed to the registered
64
+ :class:`~absl.flags.Flag` objects through the ``__call__`` method. Unparsed
65
+ arguments, including ``argv[0]`` (e.g. the program name) are returned::
66
+
67
+ argv = FLAGS(sys.argv) # scan command line arguments
68
+
69
+ The original registered :class:`~absl.flags.Flag` objects can be retrieved
70
+ through the use of the dictionary-like operator, ``__getitem__``::
71
+
72
+ x = FLAGS['longname'] # access the registered Flag object
73
+
74
+ The ``str()`` operator of a :class:`absl.flags.FlagValues` object provides
75
+ help for all of the registered :class:`~absl.flags.Flag` objects.
76
+ """
77
+
78
+ _HAS_DYNAMIC_ATTRIBUTES = True
79
+
80
+ # A note on collections.abc.Mapping:
81
+ # FlagValues defines __getitem__, __iter__, and __len__. It makes perfect
82
+ # sense to let it be a collections.abc.Mapping class. However, we are not
83
+ # able to do so. The mixin methods, e.g. keys, values, are not uncommon flag
84
+ # names. Those flag values would not be accessible via the FLAGS.xxx form.
85
+
86
+ __dict__: Dict[str, Any]
87
+
88
+ def __init__(self):
89
+ # Since everything in this class is so heavily overloaded, the only
90
+ # way of defining and using fields is to access __dict__ directly.
91
+
92
+ # Dictionary: flag name (string) -> Flag object.
93
+ self.__dict__['__flags'] = {}
94
+
95
+ # Set: name of hidden flag (string).
96
+ # Holds flags that should not be directly accessible from Python.
97
+ self.__dict__['__hiddenflags'] = set()
98
+
99
+ # Dictionary: module name (string) -> list of Flag objects that are defined
100
+ # by that module.
101
+ self.__dict__['__flags_by_module'] = {}
102
+ # Dictionary: module id (int) -> list of Flag objects that are defined by
103
+ # that module.
104
+ self.__dict__['__flags_by_module_id'] = {}
105
+ # Dictionary: module name (string) -> list of Flag objects that are
106
+ # key for that module.
107
+ self.__dict__['__key_flags_by_module'] = {}
108
+
109
+ # Bool: True if flags were parsed.
110
+ self.__dict__['__flags_parsed'] = False
111
+
112
+ # Bool: True if unparse_flags() was called.
113
+ self.__dict__['__unparse_flags_called'] = False
114
+
115
+ # None or Method(name, value) to call from __setattr__ for an unknown flag.
116
+ self.__dict__['__set_unknown'] = None
117
+
118
+ # A set of banned flag names. This is to prevent users from accidentally
119
+ # defining a flag that has the same name as a method on this class.
120
+ # Users can still allow defining the flag by passing
121
+ # allow_using_method_names=True in DEFINE_xxx functions.
122
+ self.__dict__['__banned_flag_names'] = frozenset(dir(FlagValues))
123
+
124
+ # Bool: Whether to use GNU style scanning.
125
+ self.__dict__['__use_gnu_getopt'] = True
126
+
127
+ # Bool: Whether use_gnu_getopt has been explicitly set by the user.
128
+ self.__dict__['__use_gnu_getopt_explicitly_set'] = False
129
+
130
+ # Function: Takes a flag name as parameter, returns a tuple
131
+ # (is_retired, type_is_bool).
132
+ self.__dict__['__is_retired_flag_func'] = None
133
+
134
+ def set_gnu_getopt(self, gnu_getopt: bool = True) -> None:
135
+ """Sets whether or not to use GNU style scanning.
136
+
137
+ GNU style allows mixing of flag and non-flag arguments. See
138
+ http://docs.python.org/library/getopt.html#getopt.gnu_getopt
139
+
140
+ Args:
141
+ gnu_getopt: bool, whether or not to use GNU style scanning.
142
+ """
143
+ self.__dict__['__use_gnu_getopt'] = gnu_getopt
144
+ self.__dict__['__use_gnu_getopt_explicitly_set'] = True
145
+
146
+ def is_gnu_getopt(self) -> bool:
147
+ return self.__dict__['__use_gnu_getopt']
148
+
149
+ def _flags(self) -> Dict[str, Flag]:
150
+ return self.__dict__['__flags']
151
+
152
+ def flags_by_module_dict(self) -> Dict[str, List[Flag]]:
153
+ """Returns the dictionary of module_name -> list of defined flags.
154
+
155
+ Returns:
156
+ A dictionary. Its keys are module names (strings). Its values
157
+ are lists of Flag objects.
158
+ """
159
+ return self.__dict__['__flags_by_module']
160
+
161
+ def flags_by_module_id_dict(self) -> Dict[int, List[Flag]]:
162
+ """Returns the dictionary of module_id -> list of defined flags.
163
+
164
+ Returns:
165
+ A dictionary. Its keys are module IDs (ints). Its values
166
+ are lists of Flag objects.
167
+ """
168
+ return self.__dict__['__flags_by_module_id']
169
+
170
+ def key_flags_by_module_dict(self) -> Dict[str, List[Flag]]:
171
+ """Returns the dictionary of module_name -> list of key flags.
172
+
173
+ Returns:
174
+ A dictionary. Its keys are module names (strings). Its values
175
+ are lists of Flag objects.
176
+ """
177
+ return self.__dict__['__key_flags_by_module']
178
+
179
+ def register_flag_by_module(self, module_name: str, flag: Flag) -> None:
180
+ """Records the module that defines a specific flag.
181
+
182
+ We keep track of which flag is defined by which module so that we
183
+ can later sort the flags by module.
184
+
185
+ Args:
186
+ module_name: str, the name of a Python module.
187
+ flag: Flag, the Flag instance that is key to the module.
188
+ """
189
+ flags_by_module = self.flags_by_module_dict()
190
+ flags_by_module.setdefault(module_name, []).append(flag)
191
+
192
+ def register_flag_by_module_id(self, module_id: int, flag: Flag) -> None:
193
+ """Records the module that defines a specific flag.
194
+
195
+ Args:
196
+ module_id: int, the ID of the Python module.
197
+ flag: Flag, the Flag instance that is key to the module.
198
+ """
199
+ flags_by_module_id = self.flags_by_module_id_dict()
200
+ flags_by_module_id.setdefault(module_id, []).append(flag)
201
+
202
+ def register_key_flag_for_module(self, module_name: str, flag: Flag) -> None:
203
+ """Specifies that a flag is a key flag for a module.
204
+
205
+ Args:
206
+ module_name: str, the name of a Python module.
207
+ flag: Flag, the Flag instance that is key to the module.
208
+ """
209
+ key_flags_by_module = self.key_flags_by_module_dict()
210
+ # The list of key flags for the module named module_name.
211
+ key_flags = key_flags_by_module.setdefault(module_name, [])
212
+ # Add flag, but avoid duplicates.
213
+ if flag not in key_flags:
214
+ key_flags.append(flag)
215
+
216
+ def _flag_is_registered(self, flag_obj: Flag) -> bool:
217
+ """Checks whether a Flag object is registered under long name or short name.
218
+
219
+ Args:
220
+ flag_obj: Flag, the Flag instance to check for.
221
+
222
+ Returns:
223
+ bool, True iff flag_obj is registered under long name or short name.
224
+ """
225
+ flag_dict = self._flags()
226
+ # Check whether flag_obj is registered under its long name.
227
+ name = flag_obj.name
228
+ if name in flag_dict and flag_dict[name] == flag_obj:
229
+ return True
230
+ # Check whether flag_obj is registered under its short name.
231
+ short_name = flag_obj.short_name
232
+ if (
233
+ short_name is not None
234
+ and short_name in flag_dict
235
+ and flag_dict[short_name] == flag_obj
236
+ ):
237
+ return True
238
+ return False
239
+
240
+ def _cleanup_unregistered_flag_from_module_dicts(
241
+ self, flag_obj: Flag
242
+ ) -> None:
243
+ """Cleans up unregistered flags from all module -> [flags] dictionaries.
244
+
245
+ If flag_obj is registered under either its long name or short name, it
246
+ won't be removed from the dictionaries.
247
+
248
+ Args:
249
+ flag_obj: Flag, the Flag instance to clean up for.
250
+ """
251
+ if self._flag_is_registered(flag_obj):
252
+ return
253
+ # Materialize dict values to list to avoid concurrent modification.
254
+ for flags_in_module in [
255
+ *self.flags_by_module_dict().values(),
256
+ *self.flags_by_module_id_dict().values(),
257
+ *self.key_flags_by_module_dict().values(),
258
+ ]:
259
+ # While (as opposed to if) takes care of multiple occurrences of a
260
+ # flag in the list for the same module.
261
+ while flag_obj in flags_in_module:
262
+ flags_in_module.remove(flag_obj)
263
+
264
+ def get_flags_for_module(self, module: Union[str, Any]) -> List[Flag]:
265
+ """Returns the list of flags defined by a module.
266
+
267
+ Args:
268
+ module: module|str, the module to get flags from.
269
+
270
+ Returns:
271
+ [Flag], a new list of Flag instances. Caller may update this list as
272
+ desired: none of those changes will affect the internals of this
273
+ FlagValue instance.
274
+ """
275
+ if not isinstance(module, str):
276
+ module = module.__name__
277
+ if module == '__main__':
278
+ module = sys.argv[0]
279
+
280
+ return list(self.flags_by_module_dict().get(module, []))
281
+
282
+ def get_key_flags_for_module(self, module: Union[str, Any]) -> List[Flag]:
283
+ """Returns the list of key flags for a module.
284
+
285
+ Args:
286
+ module: module|str, the module to get key flags from.
287
+
288
+ Returns:
289
+ [Flag], a new list of Flag instances. Caller may update this list as
290
+ desired: none of those changes will affect the internals of this
291
+ FlagValue instance.
292
+ """
293
+ if not isinstance(module, str):
294
+ module = module.__name__
295
+ if module == '__main__':
296
+ module = sys.argv[0]
297
+
298
+ # Any flag is a key flag for the module that defined it. NOTE:
299
+ # key_flags is a fresh list: we can update it without affecting the
300
+ # internals of this FlagValues object.
301
+ key_flags = self.get_flags_for_module(module)
302
+
303
+ # Take into account flags explicitly declared as key for a module.
304
+ for flag in self.key_flags_by_module_dict().get(module, []):
305
+ if flag not in key_flags:
306
+ key_flags.append(flag)
307
+ return key_flags
308
+
309
+ # TODO(yileiyang): Restrict default to Optional[str].
310
+ def find_module_defining_flag(
311
+ self, flagname: str, default: Optional[_T] = None
312
+ ) -> Union[str, Optional[_T]]:
313
+ """Return the name of the module defining this flag, or default.
314
+
315
+ Args:
316
+ flagname: str, name of the flag to lookup.
317
+ default: Value to return if flagname is not defined. Defaults to None.
318
+
319
+ Returns:
320
+ The name of the module which registered the flag with this name.
321
+ If no such module exists (i.e. no flag with this name exists),
322
+ we return default.
323
+ """
324
+ registered_flag = self._flags().get(flagname)
325
+ if registered_flag is None:
326
+ return default
327
+ for module, flags in self.flags_by_module_dict().items():
328
+ for flag in flags:
329
+ # It must compare the flag with the one in _flags. This is because a
330
+ # flag might be overridden only for its long name (or short name),
331
+ # and only its short name (or long name) is considered registered.
332
+ if (flag.name == registered_flag.name and
333
+ flag.short_name == registered_flag.short_name):
334
+ return module
335
+ return default
336
+
337
+ # TODO(yileiyang): Restrict default to Optional[str].
338
+ def find_module_id_defining_flag(
339
+ self, flagname: str, default: Optional[_T] = None
340
+ ) -> Union[int, Optional[_T]]:
341
+ """Return the ID of the module defining this flag, or default.
342
+
343
+ Args:
344
+ flagname: str, name of the flag to lookup.
345
+ default: Value to return if flagname is not defined. Defaults to None.
346
+
347
+ Returns:
348
+ The ID of the module which registered the flag with this name.
349
+ If no such module exists (i.e. no flag with this name exists),
350
+ we return default.
351
+ """
352
+ registered_flag = self._flags().get(flagname)
353
+ if registered_flag is None:
354
+ return default
355
+ for module_id, flags in self.flags_by_module_id_dict().items():
356
+ for flag in flags:
357
+ # It must compare the flag with the one in _flags. This is because a
358
+ # flag might be overridden only for its long name (or short name),
359
+ # and only its short name (or long name) is considered registered.
360
+ if (flag.name == registered_flag.name and
361
+ flag.short_name == registered_flag.short_name):
362
+ return module_id
363
+ return default
364
+
365
+ def _register_unknown_flag_setter(
366
+ self, setter: Callable[[str, Any], None]
367
+ ) -> None:
368
+ """Allow set default values for undefined flags.
369
+
370
+ Args:
371
+ setter: Method(name, value) to call to __setattr__ an unknown flag. Must
372
+ raise NameError or ValueError for invalid name/value.
373
+ """
374
+ self.__dict__['__set_unknown'] = setter
375
+
376
+ def _set_unknown_flag(self, name: str, value: _T) -> _T:
377
+ """Returns value if setting flag |name| to |value| returned True.
378
+
379
+ Args:
380
+ name: str, name of the flag to set.
381
+ value: Value to set.
382
+
383
+ Returns:
384
+ Flag value on successful call.
385
+
386
+ Raises:
387
+ UnrecognizedFlagError
388
+ IllegalFlagValueError
389
+ """
390
+ setter = self.__dict__['__set_unknown']
391
+ if setter:
392
+ try:
393
+ setter(name, value)
394
+ return value
395
+ except (TypeError, ValueError): # Flag value is not valid.
396
+ raise _exceptions.IllegalFlagValueError(
397
+ f'"{value}" is not valid for --{name}'
398
+ )
399
+ except NameError: # Flag name is not valid.
400
+ pass
401
+ raise _exceptions.UnrecognizedFlagError(name, value)
402
+
403
+ def append_flag_values(self, flag_values: 'FlagValues') -> None:
404
+ """Appends flags registered in another FlagValues instance.
405
+
406
+ Args:
407
+ flag_values: FlagValues, the FlagValues instance from which to copy flags.
408
+ """
409
+ for flag_name, flag in flag_values._flags().items(): # pylint: disable=protected-access
410
+ # Each flags with short_name appears here twice (once under its
411
+ # normal name, and again with its short name). To prevent
412
+ # problems (DuplicateFlagError) with double flag registration, we
413
+ # perform a check to make sure that the entry we're looking at is
414
+ # for its normal name.
415
+ if flag_name == flag.name:
416
+ try:
417
+ self[flag_name] = flag
418
+ except _exceptions.DuplicateFlagError:
419
+ raise _exceptions.DuplicateFlagError.from_flag(
420
+ flag_name, self, other_flag_values=flag_values)
421
+
422
+ def remove_flag_values(
423
+ self, flag_values: 'Union[FlagValues, Iterable[str]]'
424
+ ) -> None:
425
+ """Remove flags that were previously appended from another FlagValues.
426
+
427
+ Args:
428
+ flag_values: FlagValues, the FlagValues instance containing flags to
429
+ remove.
430
+ """
431
+ for flag_name in flag_values:
432
+ self.__delattr__(flag_name)
433
+
434
+ def __setitem__(self, name: str, flag: Flag) -> None:
435
+ """Registers a new flag variable."""
436
+ fl = self._flags()
437
+ if not isinstance(flag, _flag.Flag):
438
+ raise _exceptions.IllegalFlagValueError(
439
+ f'Expect Flag instances, found type {type(flag)}. '
440
+ "Maybe you didn't mean to use FlagValue.__setitem__?")
441
+ if not isinstance(name, str):
442
+ raise _exceptions.Error('Flag name must be a string')
443
+ if not name:
444
+ raise _exceptions.Error('Flag name cannot be empty')
445
+ if ' ' in name:
446
+ raise _exceptions.Error('Flag name cannot contain a space')
447
+ self._check_method_name_conflicts(name, flag)
448
+ if name in fl and not flag.allow_override and not fl[name].allow_override:
449
+ module, module_name = _helpers.get_calling_module_object_and_name()
450
+ if (self.find_module_defining_flag(name) == module_name and
451
+ id(module) != self.find_module_id_defining_flag(name)):
452
+ # If the flag has already been defined by a module with the same name,
453
+ # but a different ID, we can stop here because it indicates that the
454
+ # module is simply being imported a subsequent time.
455
+ return
456
+ raise _exceptions.DuplicateFlagError.from_flag(name, self)
457
+ # If a new flag overrides an old one, we need to cleanup the old flag's
458
+ # modules if it's not registered.
459
+ flags_to_cleanup = set()
460
+ short_name: Optional[str] = flag.short_name
461
+ if short_name is not None:
462
+ if (short_name in fl and not flag.allow_override and
463
+ not fl[short_name].allow_override):
464
+ raise _exceptions.DuplicateFlagError.from_flag(short_name, self)
465
+ if short_name in fl and fl[short_name] != flag:
466
+ flags_to_cleanup.add(fl[short_name])
467
+ fl[short_name] = flag
468
+ if (name not in fl # new flag
469
+ or fl[name].using_default_value or not flag.using_default_value):
470
+ if name in fl and fl[name] != flag:
471
+ flags_to_cleanup.add(fl[name])
472
+ fl[name] = flag
473
+ for f in flags_to_cleanup:
474
+ self._cleanup_unregistered_flag_from_module_dicts(f)
475
+
476
+ def __dir__(self) -> List[str]:
477
+ """Returns list of names of all defined flags.
478
+
479
+ Useful for TAB-completion in ipython.
480
+
481
+ Returns:
482
+ [str], a list of names of all defined flags.
483
+ """
484
+ return sorted(self._flags())
485
+
486
+ def __getitem__(self, name: str) -> Flag:
487
+ """Returns the Flag object for the flag --name."""
488
+ return self._flags()[name]
489
+
490
+ def _hide_flag(self, name):
491
+ """Marks the flag --name as hidden."""
492
+ self.__dict__['__hiddenflags'].add(name)
493
+
494
+ def __getattr__(self, name: str) -> Any:
495
+ """Retrieves the 'value' attribute of the flag --name."""
496
+ flag_entry = self._flags().get(name)
497
+ if flag_entry is None:
498
+ raise AttributeError(name)
499
+ if name in self.__dict__['__hiddenflags']:
500
+ raise AttributeError(name)
501
+
502
+ if self.__dict__['__flags_parsed'] or flag_entry.present:
503
+ return flag_entry.value
504
+ else:
505
+ raise _exceptions.UnparsedFlagAccessError(
506
+ 'Trying to access flag --%s before flags were parsed.' % name)
507
+
508
+ def __setattr__(self, name: str, value: _T) -> _T:
509
+ """Sets the 'value' attribute of the flag --name."""
510
+ self._set_attributes(**{name: value})
511
+ return value
512
+
513
+ def _set_attributes(self, **attributes: Any) -> None:
514
+ """Sets multiple flag values together, triggers validators afterwards."""
515
+ fl = self._flags()
516
+ known_flag_vals = {}
517
+ known_flag_used_defaults = {}
518
+ try:
519
+ for name, value in attributes.items():
520
+ if name in self.__dict__['__hiddenflags']:
521
+ raise AttributeError(name)
522
+ flag_entry = fl.get(name)
523
+ if flag_entry is not None:
524
+ orig = flag_entry.value
525
+ flag_entry.value = value
526
+ known_flag_vals[name] = orig
527
+ else:
528
+ self._set_unknown_flag(name, value)
529
+ for name in known_flag_vals:
530
+ self._assert_validators(fl[name].validators)
531
+ known_flag_used_defaults[name] = fl[name].using_default_value
532
+ fl[name].using_default_value = False
533
+ except:
534
+ for name, orig in known_flag_vals.items():
535
+ fl[name].value = orig
536
+ for name, orig in known_flag_used_defaults.items():
537
+ fl[name].using_default_value = orig
538
+ # NOTE: We do not attempt to undo unknown flag side effects because we
539
+ # cannot reliably undo the user-configured behavior.
540
+ raise
541
+
542
+ def validate_all_flags(self) -> None:
543
+ """Verifies whether all flags pass validation.
544
+
545
+ Raises:
546
+ AttributeError: Raised if validators work with a non-existing flag.
547
+ IllegalFlagValueError: Raised if validation fails for at least one
548
+ validator.
549
+ """
550
+ all_validators = set()
551
+ for flag in self._flags().values():
552
+ all_validators.update(flag.validators)
553
+ self._assert_validators(all_validators)
554
+
555
+ def _assert_validators(
556
+ self, validators: Iterable[_validators_classes.Validator]
557
+ ) -> None:
558
+ """Asserts if all validators in the list are satisfied.
559
+
560
+ It asserts validators in the order they were created.
561
+
562
+ Args:
563
+ validators: Iterable(validators.Validator), validators to be verified.
564
+
565
+ Raises:
566
+ AttributeError: Raised if validators work with a non-existing flag.
567
+ IllegalFlagValueError: Raised if validation fails for at least one
568
+ validator.
569
+ """
570
+ messages = []
571
+ bad_flags: Set[str] = set()
572
+ for validator in sorted(
573
+ validators, key=lambda validator: validator.insertion_index):
574
+ try:
575
+ if isinstance(validator, _validators_classes.SingleFlagValidator):
576
+ if validator.flag_name in bad_flags:
577
+ continue
578
+ elif isinstance(validator, _validators_classes.MultiFlagsValidator):
579
+ if bad_flags & set(validator.flag_names):
580
+ continue
581
+ validator.verify(self)
582
+ except _exceptions.ValidationError as e:
583
+ if isinstance(validator, _validators_classes.SingleFlagValidator):
584
+ bad_flags.add(validator.flag_name)
585
+ elif isinstance(validator, _validators_classes.MultiFlagsValidator):
586
+ bad_flags.update(set(validator.flag_names))
587
+ message = validator.print_flags_with_values(self)
588
+ messages.append('%s: %s' % (message, str(e)))
589
+ if messages:
590
+ raise _exceptions.IllegalFlagValueError('\n'.join(messages))
591
+
592
+ def __delattr__(self, flag_name: str) -> None:
593
+ """Deletes a previously-defined flag from a flag object.
594
+
595
+ This method makes sure we can delete a flag by using
596
+
597
+ del FLAGS.<flag_name>
598
+
599
+ E.g.,
600
+
601
+ flags.DEFINE_integer('foo', 1, 'Integer flag.')
602
+ del flags.FLAGS.foo
603
+
604
+ If a flag is also registered by its the other name (long name or short
605
+ name), the other name won't be deleted.
606
+
607
+ Args:
608
+ flag_name: str, the name of the flag to be deleted.
609
+
610
+ Raises:
611
+ AttributeError: Raised when there is no registered flag named flag_name.
612
+ """
613
+ fl = self._flags()
614
+ flag_entry = fl.get(flag_name)
615
+ if flag_entry is None:
616
+ raise AttributeError(flag_name)
617
+ del fl[flag_name]
618
+
619
+ self._cleanup_unregistered_flag_from_module_dicts(flag_entry)
620
+
621
+ def set_default(self, name: str, value: Any) -> None:
622
+ """Changes the default value of the named flag object.
623
+
624
+ The flag's current value is also updated if the flag is currently using
625
+ the default value, i.e. not specified in the command line, and not set
626
+ by FLAGS.name = value.
627
+
628
+ Args:
629
+ name: str, the name of the flag to modify.
630
+ value: The new default value.
631
+
632
+ Raises:
633
+ UnrecognizedFlagError: Raised when there is no registered flag named name.
634
+ IllegalFlagValueError: Raised when value is not valid.
635
+ """
636
+ fl = self._flags()
637
+ flag_entry = fl.get(name)
638
+ if flag_entry is None:
639
+ self._set_unknown_flag(name, value)
640
+ return
641
+ flag_entry._set_default(value) # pylint: disable=protected-access
642
+ self._assert_validators(flag_entry.validators)
643
+
644
+ def __contains__(self, name: str) -> bool:
645
+ """Returns True if name is a value (flag) in the dict."""
646
+ return name in self._flags()
647
+
648
+ def __len__(self) -> int:
649
+ return len(self.__dict__['__flags'])
650
+
651
+ def __iter__(self) -> Iterator[str]:
652
+ return iter(self._flags())
653
+
654
+ def __call__(
655
+ self, argv: Sequence[str], known_only: bool = False
656
+ ) -> List[str]:
657
+ """Parses flags from argv; stores parsed flags into this FlagValues object.
658
+
659
+ All unparsed arguments are returned.
660
+
661
+ Args:
662
+ argv: a tuple/list of strings.
663
+ known_only: bool, if True, parse and remove known flags; return the rest
664
+ untouched. Unknown flags specified by --undefok are not returned.
665
+
666
+ Returns:
667
+ The list of arguments not parsed as options, including argv[0].
668
+
669
+ Raises:
670
+ Error: Raised on any parsing error.
671
+ TypeError: Raised on passing wrong type of arguments.
672
+ ValueError: Raised on flag value parsing error.
673
+ """
674
+ if isinstance(argv, (str, bytes)):
675
+ raise TypeError(
676
+ 'argv should be a tuple/list of strings, not bytes or string.')
677
+ if not argv:
678
+ raise ValueError(
679
+ 'argv cannot be an empty list, and must contain the program name as '
680
+ 'the first element.')
681
+
682
+ # This pre parses the argv list for --flagfile=<> options.
683
+ program_name = argv[0]
684
+ args = self.read_flags_from_files(argv[1:], force_gnu=False)
685
+
686
+ # Parse the arguments.
687
+ unknown_flags, unparsed_args = self._parse_args(args, known_only)
688
+
689
+ # Handle unknown flags by raising UnrecognizedFlagError.
690
+ # Note some users depend on us raising this particular error.
691
+ for name, value in unknown_flags:
692
+ suggestions = _helpers.get_flag_suggestions(name, list(self))
693
+ raise _exceptions.UnrecognizedFlagError(
694
+ name, value, suggestions=suggestions)
695
+
696
+ self.mark_as_parsed()
697
+ self.validate_all_flags()
698
+ return [program_name] + unparsed_args
699
+
700
+ def __getstate__(self) -> Any:
701
+ raise TypeError("can't pickle FlagValues")
702
+
703
+ def __copy__(self) -> Any:
704
+ raise TypeError('FlagValues does not support shallow copies. '
705
+ 'Use absl.testing.flagsaver or copy.deepcopy instead.')
706
+
707
+ def __deepcopy__(self, memo) -> Any:
708
+ result = object.__new__(type(self))
709
+ result.__dict__.update(copy.deepcopy(self.__dict__, memo))
710
+ return result
711
+
712
+ def _set_is_retired_flag_func(self, is_retired_flag_func):
713
+ """Sets a function for checking retired flags.
714
+
715
+ Do not use it. This is a private absl API used to check retired flags
716
+ registered by the absl C++ flags library.
717
+
718
+ Args:
719
+ is_retired_flag_func: Callable(str) -> (bool, bool), a function takes flag
720
+ name as parameter, returns a tuple (is_retired, type_is_bool).
721
+ """
722
+ self.__dict__['__is_retired_flag_func'] = is_retired_flag_func
723
+
724
+ def _parse_args(
725
+ self, args: List[str], known_only: bool
726
+ ) -> Tuple[List[Tuple[str, Any]], List[str]]:
727
+ """Helper function to do the main argument parsing.
728
+
729
+ This function goes through args and does the bulk of the flag parsing.
730
+ It will find the corresponding flag in our flag dictionary, and call its
731
+ .parse() method on the flag value.
732
+
733
+ Args:
734
+ args: [str], a list of strings with the arguments to parse.
735
+ known_only: bool, if True, parse and remove known flags; return the rest
736
+ untouched. Unknown flags specified by --undefok are not returned.
737
+
738
+ Returns:
739
+ A tuple with the following:
740
+ unknown_flags: List of (flag name, arg) for flags we don't know about.
741
+ unparsed_args: List of arguments we did not parse.
742
+
743
+ Raises:
744
+ Error: Raised on any parsing error.
745
+ ValueError: Raised on flag value parsing error.
746
+ """
747
+ unparsed_names_and_args: List[Tuple[Optional[str], str]] = []
748
+ undefok: Set[str] = set()
749
+ retired_flag_func = self.__dict__['__is_retired_flag_func']
750
+
751
+ flag_dict = self._flags()
752
+ args_it = iter(args)
753
+ del args
754
+ for arg in args_it:
755
+ value = None
756
+
757
+ def get_value() -> str:
758
+ try:
759
+ return next(args_it) if value is None else value # pylint: disable=cell-var-from-loop
760
+ except StopIteration:
761
+ raise _exceptions.Error('Missing value for flag ' + arg) from None # pylint: disable=cell-var-from-loop
762
+
763
+ if not arg.startswith('-'):
764
+ # A non-argument: default is break, GNU is skip.
765
+ unparsed_names_and_args.append((None, arg))
766
+ if self.is_gnu_getopt():
767
+ continue
768
+ else:
769
+ break
770
+
771
+ if arg == '--':
772
+ if known_only:
773
+ unparsed_names_and_args.append((None, arg))
774
+ break
775
+
776
+ # At this point, arg must start with '-'.
777
+ if arg.startswith('--'):
778
+ arg_without_dashes = arg[2:]
779
+ else:
780
+ arg_without_dashes = arg[1:]
781
+
782
+ if '=' in arg_without_dashes:
783
+ name, value = arg_without_dashes.split('=', 1)
784
+ else:
785
+ name, value = arg_without_dashes, None
786
+
787
+ if not name:
788
+ # The argument is all dashes (including one dash).
789
+ unparsed_names_and_args.append((None, arg))
790
+ if self.is_gnu_getopt():
791
+ continue
792
+ else:
793
+ break
794
+
795
+ # --undefok is a special case.
796
+ if name == 'undefok':
797
+ value = get_value()
798
+ undefok.update(v.strip() for v in value.split(','))
799
+ undefok.update('no' + v.strip() for v in value.split(','))
800
+ continue
801
+
802
+ flag = flag_dict.get(name)
803
+ if flag is not None:
804
+ if flag.boolean and value is None:
805
+ value = 'true'
806
+ else:
807
+ value = get_value()
808
+ elif name.startswith('no') and len(name) > 2:
809
+ # Boolean flags can take the form of --noflag, with no value.
810
+ noflag = flag_dict.get(name[2:])
811
+ if noflag is not None and noflag.boolean:
812
+ if value is not None:
813
+ raise ValueError(arg + ' does not take an argument')
814
+ flag = noflag
815
+ value = 'false'
816
+
817
+ if retired_flag_func and flag is None:
818
+ is_retired, is_bool = retired_flag_func(name)
819
+
820
+ # If we didn't recognize that flag, but it starts with
821
+ # "no" then maybe it was a boolean flag specified in the
822
+ # --nofoo form.
823
+ if not is_retired and name.startswith('no'):
824
+ is_retired, is_bool = retired_flag_func(name[2:])
825
+ is_retired = is_retired and is_bool
826
+
827
+ if is_retired:
828
+ if not is_bool and value is None:
829
+ # This happens when a non-bool retired flag is specified
830
+ # in format of "--flag value".
831
+ get_value()
832
+ logging.error(
833
+ 'Flag "%s" is retired and should no longer be specified. See '
834
+ 'https://abseil.io/tips/90.',
835
+ name,
836
+ )
837
+ continue
838
+
839
+ if flag is not None:
840
+ # LINT.IfChange
841
+ flag.parse(value)
842
+ flag.using_default_value = False
843
+ # LINT.ThenChange(../testing/flagsaver.py:flag_override_parsing)
844
+ else:
845
+ unparsed_names_and_args.append((name, arg))
846
+
847
+ unknown_flags = []
848
+ unparsed_args = []
849
+ for arg_name, arg in unparsed_names_and_args:
850
+ if arg_name is None:
851
+ # Positional arguments.
852
+ unparsed_args.append(arg)
853
+ elif arg_name in undefok:
854
+ # Remove undefok flags.
855
+ continue
856
+ else:
857
+ # This is an unknown flag.
858
+ if known_only:
859
+ unparsed_args.append(arg)
860
+ else:
861
+ unknown_flags.append((arg_name, arg))
862
+
863
+ unparsed_args.extend(list(args_it))
864
+ return unknown_flags, unparsed_args
865
+
866
+ def is_parsed(self) -> bool:
867
+ """Returns whether flags were parsed."""
868
+ return self.__dict__['__flags_parsed']
869
+
870
+ def mark_as_parsed(self) -> None:
871
+ """Explicitly marks flags as parsed.
872
+
873
+ Use this when the caller knows that this FlagValues has been parsed as if
874
+ a ``__call__()`` invocation has happened. This is only a public method for
875
+ use by things like appcommands which do additional command like parsing.
876
+ """
877
+ self.__dict__['__flags_parsed'] = True
878
+
879
+ def unparse_flags(self) -> None:
880
+ """Unparses all flags to the point before any FLAGS(argv) was called."""
881
+ for f in self._flags().values():
882
+ f.unparse()
883
+ # We log this message before marking flags as unparsed to avoid a
884
+ # problem when the logging library causes flags access.
885
+ logging.info('unparse_flags() called; flags access will now raise errors.')
886
+ self.__dict__['__flags_parsed'] = False
887
+ self.__dict__['__unparse_flags_called'] = True
888
+
889
+ def flag_values_dict(self) -> Dict[str, Any]:
890
+ """Returns a dictionary that maps flag names to flag values."""
891
+ return {name: flag.value for name, flag in list(self._flags().items())}
892
+
893
+ def __str__(self):
894
+ """Returns a help string for all known flags."""
895
+ return self.get_help()
896
+
897
+ def get_help(
898
+ self, prefix: str = '', include_special_flags: bool = True
899
+ ) -> str:
900
+ """Returns a help string for all known flags.
901
+
902
+ Args:
903
+ prefix: str, per-line output prefix.
904
+ include_special_flags: bool, whether to include description of
905
+ SPECIAL_FLAGS, i.e. --flagfile and --undefok.
906
+
907
+ Returns:
908
+ str, formatted help message.
909
+ """
910
+ flags_by_module = self.flags_by_module_dict()
911
+ if flags_by_module:
912
+ modules = sorted(flags_by_module)
913
+ # Print the help for the main module first, if possible.
914
+ main_module = sys.argv[0]
915
+ if main_module in modules:
916
+ modules.remove(main_module)
917
+ modules = [main_module] + modules
918
+ return self._get_help_for_modules(modules, prefix, include_special_flags)
919
+ else:
920
+ output_lines: List[str] = []
921
+ # Just print one long list of flags.
922
+ values = list(self._flags().values())
923
+ if include_special_flags:
924
+ values.extend(_helpers.SPECIAL_FLAGS._flags().values()) # pylint: disable=protected-access
925
+ self._render_flag_list(values, output_lines, prefix)
926
+ return '\n'.join(output_lines)
927
+
928
+ def _get_help_for_modules(self, modules, prefix, include_special_flags):
929
+ """Returns the help string for a list of modules.
930
+
931
+ Private to absl.flags package.
932
+
933
+ Args:
934
+ modules: List[str], a list of modules to get the help string for.
935
+ prefix: str, a string that is prepended to each generated help line.
936
+ include_special_flags: bool, whether to include description of
937
+ SPECIAL_FLAGS, i.e. --flagfile and --undefok.
938
+ """
939
+ output_lines = []
940
+ for module in modules:
941
+ self._render_our_module_flags(module, output_lines, prefix)
942
+ if include_special_flags:
943
+ self._render_module_flags(
944
+ 'absl.flags',
945
+ _helpers.SPECIAL_FLAGS._flags().values(), # pylint: disable=protected-access # pytype: disable=attribute-error
946
+ output_lines,
947
+ prefix,
948
+ )
949
+ return '\n'.join(output_lines)
950
+
951
+ def _render_module_flags(self, module, flags, output_lines, prefix=''):
952
+ """Returns a help string for a given module."""
953
+ if not isinstance(module, str):
954
+ module = module.__name__
955
+ output_lines.append('\n%s%s:' % (prefix, module))
956
+ self._render_flag_list(flags, output_lines, prefix + ' ')
957
+
958
+ def _render_our_module_flags(self, module, output_lines, prefix=''):
959
+ """Returns a help string for a given module."""
960
+ flags = self.get_flags_for_module(module)
961
+ if flags:
962
+ self._render_module_flags(module, flags, output_lines, prefix)
963
+
964
+ def _render_our_module_key_flags(self, module, output_lines, prefix=''):
965
+ """Returns a help string for the key flags of a given module.
966
+
967
+ Args:
968
+ module: module|str, the module to render key flags for.
969
+ output_lines: [str], a list of strings. The generated help message lines
970
+ will be appended to this list.
971
+ prefix: str, a string that is prepended to each generated help line.
972
+ """
973
+ key_flags = self.get_key_flags_for_module(module)
974
+ if key_flags:
975
+ self._render_module_flags(module, key_flags, output_lines, prefix)
976
+
977
+ def module_help(self, module: Any) -> str:
978
+ """Describes the key flags of a module.
979
+
980
+ Args:
981
+ module: module|str, the module to describe the key flags for.
982
+
983
+ Returns:
984
+ str, describing the key flags of a module.
985
+ """
986
+ helplist: List[str] = []
987
+ self._render_our_module_key_flags(module, helplist)
988
+ return '\n'.join(helplist)
989
+
990
+ def main_module_help(self) -> str:
991
+ """Describes the key flags of the main module.
992
+
993
+ Returns:
994
+ str, describing the key flags of the main module.
995
+ """
996
+ return self.module_help(sys.argv[0])
997
+
998
+ def _render_flag_list(self, flaglist, output_lines, prefix=' '):
999
+ fl = self._flags()
1000
+ special_fl = _helpers.SPECIAL_FLAGS._flags() # pylint: disable=protected-access # pytype: disable=attribute-error
1001
+ flaglist = [(flag.name, flag) for flag in flaglist]
1002
+ flaglist.sort()
1003
+ flagset = {}
1004
+ for (name, flag) in flaglist:
1005
+ # It's possible this flag got deleted or overridden since being
1006
+ # registered in the per-module flaglist. Check now against the
1007
+ # canonical source of current flag information, the _flags.
1008
+ if fl.get(name, None) != flag and special_fl.get(name, None) != flag:
1009
+ # a different flag is using this name now
1010
+ continue
1011
+ # only print help once
1012
+ if flag in flagset:
1013
+ continue
1014
+ flagset[flag] = 1
1015
+ flaghelp = ''
1016
+ if flag.short_name:
1017
+ flaghelp += '-%s,' % flag.short_name
1018
+ if flag.boolean:
1019
+ flaghelp += '--[no]%s:' % flag.name
1020
+ else:
1021
+ flaghelp += '--%s:' % flag.name
1022
+ flaghelp += ' '
1023
+ if flag.help:
1024
+ flaghelp += flag.help
1025
+ flaghelp = _helpers.text_wrap(
1026
+ flaghelp, indent=prefix + ' ', firstline_indent=prefix)
1027
+ if flag.default_as_str:
1028
+ flaghelp += '\n'
1029
+ flaghelp += _helpers.text_wrap(
1030
+ '(default: %s)' % flag.default_as_str, indent=prefix + ' ')
1031
+ if flag.parser.syntactic_help:
1032
+ flaghelp += '\n'
1033
+ flaghelp += _helpers.text_wrap(
1034
+ '(%s)' % flag.parser.syntactic_help, indent=prefix + ' ')
1035
+ output_lines.append(flaghelp)
1036
+
1037
+ def get_flag_value(self, name: str, default: Any) -> Any: # pylint: disable=invalid-name
1038
+ """Returns the value of a flag (if not None) or a default value.
1039
+
1040
+ Args:
1041
+ name: str, the name of a flag.
1042
+ default: Default value to use if the flag value is None.
1043
+
1044
+ Returns:
1045
+ Requested flag value or default.
1046
+ """
1047
+
1048
+ value = self.__getattr__(name)
1049
+ if value is not None: # Can't do if not value, b/c value might be '0' or ""
1050
+ return value
1051
+ else:
1052
+ return default
1053
+
1054
+ def _is_flag_file_directive(self, flag_string):
1055
+ """Checks whether flag_string contain a --flagfile=<foo> directive."""
1056
+ if isinstance(flag_string, str):
1057
+ if flag_string.startswith('--flagfile='):
1058
+ return 1
1059
+ elif flag_string == '--flagfile':
1060
+ return 1
1061
+ elif flag_string.startswith('-flagfile='):
1062
+ return 1
1063
+ elif flag_string == '-flagfile':
1064
+ return 1
1065
+ else:
1066
+ return 0
1067
+ return 0
1068
+
1069
+ def _extract_filename(self, flagfile_str):
1070
+ """Returns filename from a flagfile_str of form -[-]flagfile=filename.
1071
+
1072
+ The cases of --flagfile foo and -flagfile foo shouldn't be hitting
1073
+ this function, as they are dealt with in the level above this
1074
+ function.
1075
+
1076
+ Args:
1077
+ flagfile_str: str, the flagfile string.
1078
+
1079
+ Returns:
1080
+ str, the filename from a flagfile_str of form -[-]flagfile=filename.
1081
+
1082
+ Raises:
1083
+ Error: Raised when illegal --flagfile is provided.
1084
+ """
1085
+ if flagfile_str.startswith('--flagfile='):
1086
+ return os.path.expanduser((flagfile_str[(len('--flagfile=')):]).strip())
1087
+ elif flagfile_str.startswith('-flagfile='):
1088
+ return os.path.expanduser((flagfile_str[(len('-flagfile=')):]).strip())
1089
+ else:
1090
+ raise _exceptions.Error('Hit illegal --flagfile type: %s' % flagfile_str)
1091
+
1092
+ def _get_flag_file_lines(self, filename, parsed_file_stack=None):
1093
+ """Returns the useful (!=comments, etc) lines from a file with flags.
1094
+
1095
+ Args:
1096
+ filename: str, the name of the flag file.
1097
+ parsed_file_stack: [str], a list of the names of the files that we have
1098
+ recursively encountered at the current depth. MUTATED BY THIS FUNCTION
1099
+ (but the original value is preserved upon successfully returning from
1100
+ function call).
1101
+
1102
+ Returns:
1103
+ List of strings. See the note below.
1104
+
1105
+ NOTE(springer): This function checks for a nested --flagfile=<foo>
1106
+ tag and handles the lower file recursively. It returns a list of
1107
+ all the lines that _could_ contain command flags. This is
1108
+ EVERYTHING except whitespace lines and comments (lines starting
1109
+ with '#' or '//').
1110
+ """
1111
+ # For consistency with the cpp version, ignore empty values.
1112
+ if not filename:
1113
+ return []
1114
+ if parsed_file_stack is None:
1115
+ parsed_file_stack = []
1116
+ # We do a little safety check for reparsing a file we've already encountered
1117
+ # at a previous depth.
1118
+ if filename in parsed_file_stack:
1119
+ sys.stderr.write('Warning: Hit circular flagfile dependency. Ignoring'
1120
+ ' flagfile: %s\n' % (filename,))
1121
+ return []
1122
+ else:
1123
+ parsed_file_stack.append(filename)
1124
+
1125
+ line_list = [] # All line from flagfile.
1126
+ flag_line_list = [] # Subset of lines w/o comments, blanks, flagfile= tags.
1127
+ try:
1128
+ file_obj = open(filename)
1129
+ except OSError as e_msg:
1130
+ raise _exceptions.CantOpenFlagFileError(
1131
+ 'ERROR:: Unable to open flagfile: %s' % e_msg)
1132
+
1133
+ with file_obj:
1134
+ line_list = file_obj.readlines()
1135
+
1136
+ # This is where we check each line in the file we just read.
1137
+ for line in line_list:
1138
+ if line.isspace():
1139
+ pass
1140
+ # Checks for comment (a line that starts with '#').
1141
+ elif line.startswith('#') or line.startswith('//'):
1142
+ pass
1143
+ # Checks for a nested "--flagfile=<bar>" flag in the current file.
1144
+ # If we find one, recursively parse down into that file.
1145
+ elif self._is_flag_file_directive(line):
1146
+ sub_filename = self._extract_filename(line)
1147
+ included_flags = self._get_flag_file_lines(
1148
+ sub_filename, parsed_file_stack=parsed_file_stack)
1149
+ flag_line_list.extend(included_flags)
1150
+ else:
1151
+ # Any line that's not a comment or a nested flagfile should get
1152
+ # copied into 2nd position. This leaves earlier arguments
1153
+ # further back in the list, thus giving them higher priority.
1154
+ flag_line_list.append(line.strip())
1155
+
1156
+ parsed_file_stack.pop()
1157
+ return flag_line_list
1158
+
1159
+ def read_flags_from_files(
1160
+ self, argv: Sequence[str], force_gnu: bool = True
1161
+ ) -> List[str]:
1162
+ """Processes command line args, but also allow args to be read from file.
1163
+
1164
+ Args:
1165
+ argv: [str], a list of strings, usually sys.argv[1:], which may contain
1166
+ one or more flagfile directives of the form --flagfile="./filename".
1167
+ Note that the name of the program (sys.argv[0]) should be omitted.
1168
+ force_gnu: bool, if False, --flagfile parsing obeys the
1169
+ FLAGS.is_gnu_getopt() value. If True, ignore the value and always follow
1170
+ gnu_getopt semantics.
1171
+
1172
+ Returns:
1173
+ A new list which has the original list combined with what we read
1174
+ from any flagfile(s).
1175
+
1176
+ Raises:
1177
+ IllegalFlagValueError: Raised when --flagfile is provided with no
1178
+ argument.
1179
+
1180
+ This function is called by FLAGS(argv).
1181
+ It scans the input list for a flag that looks like:
1182
+ --flagfile=<somefile>. Then it opens <somefile>, reads all valid key
1183
+ and value pairs and inserts them into the input list in exactly the
1184
+ place where the --flagfile arg is found.
1185
+
1186
+ Note that your application's flags are still defined the usual way
1187
+ using absl.flags DEFINE_flag() type functions.
1188
+
1189
+ Notes (assuming we're getting a commandline of some sort as our input):
1190
+
1191
+ * For duplicate flags, the last one we hit should "win".
1192
+ * Since flags that appear later win, a flagfile's settings can be "weak"
1193
+ if the --flagfile comes at the beginning of the argument sequence,
1194
+ and it can be "strong" if the --flagfile comes at the end.
1195
+ * A further "--flagfile=<otherfile.cfg>" CAN be nested in a flagfile.
1196
+ It will be expanded in exactly the spot where it is found.
1197
+ * In a flagfile, a line beginning with # or // is a comment.
1198
+ * Entirely blank lines _should_ be ignored.
1199
+ """
1200
+ rest_of_args = argv
1201
+ new_argv = []
1202
+ while rest_of_args:
1203
+ current_arg = rest_of_args[0]
1204
+ rest_of_args = rest_of_args[1:]
1205
+ if self._is_flag_file_directive(current_arg):
1206
+ # This handles the case of -(-)flagfile foo. In this case the
1207
+ # next arg really is part of this one.
1208
+ if current_arg == '--flagfile' or current_arg == '-flagfile':
1209
+ if not rest_of_args:
1210
+ raise _exceptions.IllegalFlagValueError(
1211
+ '--flagfile with no argument')
1212
+ flag_filename = os.path.expanduser(rest_of_args[0])
1213
+ rest_of_args = rest_of_args[1:]
1214
+ else:
1215
+ # This handles the case of (-)-flagfile=foo.
1216
+ flag_filename = self._extract_filename(current_arg)
1217
+ new_argv.extend(self._get_flag_file_lines(flag_filename))
1218
+ else:
1219
+ new_argv.append(current_arg)
1220
+ # Stop parsing after '--', like getopt and gnu_getopt.
1221
+ if current_arg == '--':
1222
+ break
1223
+ # Stop parsing after a non-flag, like getopt.
1224
+ if not current_arg.startswith('-'):
1225
+ if not force_gnu and not self.__dict__['__use_gnu_getopt']:
1226
+ break
1227
+ else:
1228
+ if ('=' not in current_arg and rest_of_args and
1229
+ not rest_of_args[0].startswith('-')):
1230
+ # If this is an occurrence of a legitimate --x y, skip the value
1231
+ # so that it won't be mistaken for a standalone arg.
1232
+ fl = self._flags()
1233
+ name = current_arg.lstrip('-')
1234
+ if name in fl and not fl[name].boolean:
1235
+ current_arg = rest_of_args[0]
1236
+ rest_of_args = rest_of_args[1:]
1237
+ new_argv.append(current_arg)
1238
+
1239
+ if rest_of_args:
1240
+ new_argv.extend(rest_of_args)
1241
+
1242
+ return new_argv
1243
+
1244
+ def flags_into_string(self) -> str:
1245
+ """Returns a string with the flags assignments from this FlagValues object.
1246
+
1247
+ This function ignores flags whose value is None. Each flag
1248
+ assignment is separated by a newline.
1249
+
1250
+ NOTE: MUST mirror the behavior of the C++ CommandlineFlagsIntoString
1251
+ from https://github.com/gflags/gflags.
1252
+
1253
+ Returns:
1254
+ str, the string with the flags assignments from this FlagValues object.
1255
+ The flags are ordered by (module_name, flag_name).
1256
+ """
1257
+ module_flags = sorted(self.flags_by_module_dict().items())
1258
+ s = ''
1259
+ for unused_module_name, flags in module_flags:
1260
+ flags = sorted(flags, key=lambda f: f.name)
1261
+ for flag in flags:
1262
+ if flag.value is not None:
1263
+ s += flag.serialize() + '\n'
1264
+ return s
1265
+
1266
+ def append_flags_into_file(self, filename: str) -> None:
1267
+ """Appends all flags assignments from this FlagInfo object to a file.
1268
+
1269
+ Output will be in the format of a flagfile.
1270
+
1271
+ NOTE: MUST mirror the behavior of the C++ AppendFlagsIntoFile
1272
+ from https://github.com/gflags/gflags.
1273
+
1274
+ Args:
1275
+ filename: str, name of the file.
1276
+ """
1277
+ with open(filename, 'a') as out_file:
1278
+ out_file.write(self.flags_into_string())
1279
+
1280
+ def write_help_in_xml_format(self, outfile: Optional[TextIO] = None) -> None:
1281
+ """Outputs flag documentation in XML format.
1282
+
1283
+ NOTE: We use element names that are consistent with those used by
1284
+ the C++ command-line flag library, from
1285
+ https://github.com/gflags/gflags.
1286
+ We also use a few new elements (e.g., <key>), but we do not
1287
+ interfere / overlap with existing XML elements used by the C++
1288
+ library. Please maintain this consistency.
1289
+
1290
+ Args:
1291
+ outfile: File object we write to. Default None means sys.stdout.
1292
+ """
1293
+ doc = minidom.Document()
1294
+ all_flag = doc.createElement('AllFlags')
1295
+ doc.appendChild(all_flag)
1296
+
1297
+ all_flag.appendChild(
1298
+ _helpers.create_xml_dom_element(doc, 'program',
1299
+ os.path.basename(sys.argv[0])))
1300
+
1301
+ usage_doc = sys.modules['__main__'].__doc__
1302
+ if not usage_doc:
1303
+ usage_doc = '\nUSAGE: %s [flags]\n' % sys.argv[0]
1304
+ else:
1305
+ usage_doc = usage_doc.replace('%s', sys.argv[0])
1306
+ all_flag.appendChild(
1307
+ _helpers.create_xml_dom_element(doc, 'usage', usage_doc))
1308
+
1309
+ # Get list of key flags for the main module.
1310
+ key_flags = self.get_key_flags_for_module(sys.argv[0])
1311
+
1312
+ flags_by_module = self.flags_by_module_dict()
1313
+ # Sort flags by declaring module name and next by flag name.
1314
+ for module_name in sorted(flags_by_module.keys()):
1315
+ flag_list = [(f.name, f) for f in flags_by_module[module_name]]
1316
+ flag_list.sort()
1317
+ for unused_flag_name, flag in flag_list:
1318
+ is_key = flag in key_flags
1319
+ all_flag.appendChild(
1320
+ flag._create_xml_dom_element( # pylint: disable=protected-access
1321
+ doc,
1322
+ module_name,
1323
+ is_key=is_key))
1324
+
1325
+ outfile = outfile or sys.stdout
1326
+ outfile.write(
1327
+ doc.toprettyxml(indent=' ', encoding='utf-8').decode('utf-8'))
1328
+ outfile.flush()
1329
+
1330
+ def _check_method_name_conflicts(self, name: str, flag: Flag):
1331
+ if flag.allow_using_method_names:
1332
+ return
1333
+ short_name = flag.short_name
1334
+ flag_names = {name} if short_name is None else {name, short_name}
1335
+ for flag_name in flag_names:
1336
+ if flag_name in self.__dict__['__banned_flag_names']:
1337
+ raise _exceptions.FlagNameConflictsWithMethodError(
1338
+ 'Cannot define a flag named "{name}". It conflicts with a method '
1339
+ 'on class "{class_name}". To allow defining it, use '
1340
+ 'allow_using_method_names and access the flag value with '
1341
+ "FLAGS['{name}'].value. FLAGS.{name} returns the method, "
1342
+ 'not the flag value.'.format(
1343
+ name=flag_name, class_name=type(self).__name__))
1344
+
1345
+
1346
+ FLAGS = FlagValues()
1347
+
1348
+
1349
+ class FlagHolder(Generic[_T_co]):
1350
+ """Holds a defined flag.
1351
+
1352
+ This facilitates a cleaner api around global state. Instead of::
1353
+
1354
+ flags.DEFINE_integer('foo', ...)
1355
+ flags.DEFINE_integer('bar', ...)
1356
+
1357
+ def method():
1358
+ # prints parsed value of 'bar' flag
1359
+ print(flags.FLAGS.foo)
1360
+ # runtime error due to typo or possibly bad coding style.
1361
+ print(flags.FLAGS.baz)
1362
+
1363
+ it encourages code like::
1364
+
1365
+ _FOO_FLAG = flags.DEFINE_integer('foo', ...)
1366
+ _BAR_FLAG = flags.DEFINE_integer('bar', ...)
1367
+
1368
+ def method():
1369
+ print(_FOO_FLAG.value)
1370
+ print(_BAR_FLAG.value)
1371
+
1372
+ since the name of the flag appears only once in the source code.
1373
+ """
1374
+
1375
+ value: _T_co
1376
+
1377
+ def __init__(
1378
+ self,
1379
+ flag_values: FlagValues,
1380
+ flag: Flag[_T_co],
1381
+ ensure_non_none_value: bool = False,
1382
+ ):
1383
+ """Constructs a FlagHolder instance providing typesafe access to flag.
1384
+
1385
+ Args:
1386
+ flag_values: The container the flag is registered to.
1387
+ flag: The flag object for this flag.
1388
+ ensure_non_none_value: Is the value of the flag allowed to be None.
1389
+ """
1390
+ self._flagvalues = flag_values
1391
+ # We take the entire flag object, but only keep the name. Why?
1392
+ # - We want FlagHolder[T] to be generic container
1393
+ # - flag_values contains all flags, so has no reference to T.
1394
+ # - typecheckers don't like to see a generic class where none of the ctor
1395
+ # arguments refer to the generic type.
1396
+ self._name = flag.name
1397
+ # We intentionally do NOT check if the default value is None.
1398
+ # This allows future use of this for "required flags with None default"
1399
+ self._ensure_non_none_value = ensure_non_none_value
1400
+
1401
+ def __eq__(self, other):
1402
+ raise TypeError(
1403
+ "unsupported operand type(s) for ==: '{0}' and '{1}' "
1404
+ "(did you mean to use '{0}.value' instead?)".format(
1405
+ type(self).__name__, type(other).__name__))
1406
+
1407
+ def __bool__(self):
1408
+ raise TypeError(
1409
+ "bool() not supported for instances of type '{0}' "
1410
+ "(did you mean to use '{0}.value' instead?)".format(
1411
+ type(self).__name__))
1412
+
1413
+ __nonzero__ = __bool__
1414
+
1415
+ @property
1416
+ def name(self) -> str:
1417
+ return self._name
1418
+
1419
+ @property # type: ignore[no-redef]
1420
+ def value(self) -> _T_co:
1421
+ """Returns the value of the flag.
1422
+
1423
+ If ``_ensure_non_none_value`` is ``True``, then return value is not
1424
+ ``None``.
1425
+
1426
+ Raises:
1427
+ UnparsedFlagAccessError: if flag parsing has not finished.
1428
+ IllegalFlagValueError: if value is None unexpectedly.
1429
+ """
1430
+ val = getattr(self._flagvalues, self._name)
1431
+ if self._ensure_non_none_value and val is None:
1432
+ raise _exceptions.IllegalFlagValueError(
1433
+ 'Unexpected None value for flag %s' % self._name)
1434
+ return val
1435
+
1436
+ @property
1437
+ def default(self) -> _T_co:
1438
+ """Returns the default value of the flag."""
1439
+ return self._flagvalues[self._name].default # type: ignore[return-value]
1440
+
1441
+ @property
1442
+ def present(self) -> bool:
1443
+ """Returns True if the flag was parsed from command-line flags."""
1444
+ return bool(self._flagvalues[self._name].present)
1445
+
1446
+ def serialize(self) -> str:
1447
+ """Returns a serialized representation of the flag."""
1448
+ return self._flagvalues[self._name].serialize()
1449
+
1450
+
1451
+ def resolve_flag_ref(
1452
+ flag_ref: Union[str, FlagHolder], flag_values: FlagValues
1453
+ ) -> Tuple[str, FlagValues]:
1454
+ """Helper to validate and resolve a flag reference argument."""
1455
+ if isinstance(flag_ref, FlagHolder):
1456
+ new_flag_values = flag_ref._flagvalues # pylint: disable=protected-access
1457
+ if flag_values != FLAGS and flag_values != new_flag_values:
1458
+ raise ValueError(
1459
+ 'flag_values must not be customized when operating on a FlagHolder')
1460
+ return flag_ref.name, new_flag_values
1461
+ return flag_ref, flag_values
1462
+
1463
+
1464
+ def resolve_flag_refs(
1465
+ flag_refs: Sequence[Union[str, FlagHolder]], flag_values: FlagValues
1466
+ ) -> Tuple[List[str], FlagValues]:
1467
+ """Helper to validate and resolve flag reference list arguments."""
1468
+ fv = None
1469
+ names = []
1470
+ for ref in flag_refs:
1471
+ if isinstance(ref, FlagHolder):
1472
+ newfv = ref._flagvalues # pylint: disable=protected-access
1473
+ name = ref.name
1474
+ else:
1475
+ newfv = flag_values
1476
+ name = ref
1477
+ if fv and fv != newfv:
1478
+ raise ValueError(
1479
+ 'multiple FlagValues instances used in invocation. '
1480
+ 'FlagHolders must be registered to the same FlagValues instance as '
1481
+ 'do flag names, if provided.')
1482
+ fv = newfv
1483
+ names.append(name)
1484
+ if fv is None:
1485
+ raise ValueError('flag_refs argument must not be empty')
1486
+ return names, fv
lib/python3.10/site-packages/absl/flags/_helpers.py ADDED
@@ -0,0 +1,427 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Internal helper functions for Abseil Python flags library."""
16
+
17
+ import os
18
+ import re
19
+ import struct
20
+ import sys
21
+ import textwrap
22
+ import types
23
+ from typing import Any, Dict, Iterable, List, NamedTuple, Optional, Sequence, Set
24
+ from xml.dom import minidom
25
+ # pylint: disable=g-import-not-at-top
26
+ fcntl: Optional[types.ModuleType]
27
+ try:
28
+ import fcntl
29
+ except ImportError:
30
+ fcntl = None
31
+ termios: Optional[types.ModuleType]
32
+ try:
33
+ # Importing termios will fail on non-unix platforms.
34
+ import termios
35
+ except ImportError:
36
+ termios = None
37
+ # pylint: enable=g-import-not-at-top
38
+
39
+
40
+ _DEFAULT_HELP_WIDTH = 80 # Default width of help output.
41
+ # Minimal "sane" width of help output. We assume that any value below 40 is
42
+ # unreasonable.
43
+ _MIN_HELP_WIDTH = 40
44
+
45
+ # Define the allowed error rate in an input string to get suggestions.
46
+ #
47
+ # We lean towards a high threshold because we tend to be matching a phrase,
48
+ # and the simple algorithm used here is geared towards correcting word
49
+ # spellings.
50
+ #
51
+ # For manual testing, consider "<command> --list" which produced a large number
52
+ # of spurious suggestions when we used "least_errors > 0.5" instead of
53
+ # "least_erros >= 0.5".
54
+ _SUGGESTION_ERROR_RATE_THRESHOLD = 0.50
55
+
56
+ # Characters that cannot appear or are highly discouraged in an XML 1.0
57
+ # document. (See http://www.w3.org/TR/REC-xml/#charsets or
58
+ # https://en.wikipedia.org/wiki/Valid_characters_in_XML#XML_1.0)
59
+ _ILLEGAL_XML_CHARS_REGEX = re.compile(
60
+ '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]'
61
+ )
62
+
63
+ # This is a set of module ids for the modules that disclaim key flags.
64
+ # This module is explicitly added to this set so that we never consider it to
65
+ # define key flag.
66
+ disclaim_module_ids: Set[int] = {id(sys.modules[__name__])}
67
+
68
+
69
+ # Define special flags here so that help may be generated for them.
70
+ # NOTE: Please do NOT use SPECIAL_FLAGS from outside flags module.
71
+ # Initialized inside flagvalues.py.
72
+ # NOTE: This cannot be annotated as its actual FlagValues type since this would
73
+ # create a circular dependency.
74
+ SPECIAL_FLAGS: Any = None
75
+
76
+
77
+ # This points to the flags module, initialized in flags/__init__.py.
78
+ # This should only be used in adopt_module_key_flags to take SPECIAL_FLAGS into
79
+ # account.
80
+ FLAGS_MODULE: Optional[types.ModuleType] = None
81
+
82
+
83
+ class _ModuleObjectAndName(NamedTuple):
84
+ """Module object and name.
85
+
86
+ Fields:
87
+ - module: object, module object.
88
+ - module_name: str, module name.
89
+ """
90
+ module: types.ModuleType
91
+ module_name: str
92
+
93
+
94
+ def get_module_object_and_name(
95
+ globals_dict: Dict[str, Any],
96
+ ) -> Optional[_ModuleObjectAndName]:
97
+ """Returns the module that defines a global environment, and its name.
98
+
99
+ Args:
100
+ globals_dict: A dictionary that should correspond to an environment
101
+ providing the values of the globals.
102
+
103
+ Returns:
104
+ _ModuleObjectAndName - pair of module object & module name.
105
+ Returns None if the module could not be identified.
106
+ """
107
+ try:
108
+ name = globals_dict['__name__']
109
+ module = sys.modules[name]
110
+ except KeyError:
111
+ return None
112
+ # Pick a more informative name for the main module.
113
+ return _ModuleObjectAndName(module,
114
+ (sys.argv[0] if name == '__main__' else name))
115
+
116
+
117
+ def get_calling_module_object_and_name() -> _ModuleObjectAndName:
118
+ """Returns the module that's calling into this module.
119
+
120
+ We generally use this function to get the name of the module calling a
121
+ DEFINE_foo... function.
122
+
123
+ Returns:
124
+ The module object that called into this one.
125
+
126
+ Raises:
127
+ AssertionError: Raised when no calling module could be identified.
128
+ """
129
+ for depth in range(1, sys.getrecursionlimit()):
130
+ # sys._getframe is the right thing to use here, as it's the best
131
+ # way to walk up the call stack.
132
+ globals_for_frame = sys._getframe(depth).f_globals # pylint: disable=protected-access
133
+ module = get_module_object_and_name(globals_for_frame)
134
+ if module is not None and id(module.module) not in disclaim_module_ids:
135
+ return module
136
+ raise AssertionError('No module was found')
137
+
138
+
139
+ def get_calling_module() -> str:
140
+ """Returns the name of the module that's calling into this module."""
141
+ return get_calling_module_object_and_name().module_name
142
+
143
+
144
+ def create_xml_dom_element(
145
+ doc: minidom.Document, name: str, value: Any
146
+ ) -> minidom.Element:
147
+ """Returns an XML DOM element with name and text value.
148
+
149
+ Args:
150
+ doc: minidom.Document, the DOM document it should create nodes from.
151
+ name: str, the tag of XML element.
152
+ value: object, whose string representation will be used
153
+ as the value of the XML element. Illegal or highly discouraged xml 1.0
154
+ characters are stripped.
155
+
156
+ Returns:
157
+ An instance of minidom.Element.
158
+ """
159
+ s = str(value)
160
+ if isinstance(value, bool):
161
+ # Display boolean values as the C++ flag library does: no caps.
162
+ s = s.lower()
163
+ # Remove illegal xml characters.
164
+ s = _ILLEGAL_XML_CHARS_REGEX.sub('', s)
165
+
166
+ e = doc.createElement(name)
167
+ e.appendChild(doc.createTextNode(s))
168
+ return e
169
+
170
+
171
+ def get_help_width() -> int:
172
+ """Returns the integer width of help lines that is used in TextWrap."""
173
+ if not sys.stdout.isatty() or termios is None or fcntl is None:
174
+ return _DEFAULT_HELP_WIDTH
175
+ try:
176
+ data = fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, b'1234')
177
+ columns = struct.unpack('hh', data)[1]
178
+ # Emacs mode returns 0.
179
+ # Here we assume that any value below 40 is unreasonable.
180
+ if columns >= _MIN_HELP_WIDTH:
181
+ return columns
182
+ # Returning an int as default is fine, int(int) just return the int.
183
+ return int(os.getenv('COLUMNS', _DEFAULT_HELP_WIDTH))
184
+
185
+ except (TypeError, OSError, struct.error):
186
+ return _DEFAULT_HELP_WIDTH
187
+
188
+
189
+ def get_flag_suggestions(
190
+ attempt: str, longopt_list: Sequence[str]
191
+ ) -> List[str]:
192
+ """Returns helpful similar matches for an invalid flag."""
193
+ # Don't suggest on very short strings, or if no longopts are specified.
194
+ if len(attempt) <= 2 or not longopt_list:
195
+ return []
196
+
197
+ option_names = [v.split('=')[0] for v in longopt_list]
198
+
199
+ # Find close approximations in flag prefixes.
200
+ # This also handles the case where the flag is spelled right but ambiguous.
201
+ distances = [(_damerau_levenshtein(attempt, option[0:len(attempt)]), option)
202
+ for option in option_names]
203
+ # t[0] is distance, and sorting by t[1] allows us to have stable output.
204
+ distances.sort()
205
+
206
+ least_errors, _ = distances[0]
207
+ # Don't suggest excessively bad matches.
208
+ if least_errors >= _SUGGESTION_ERROR_RATE_THRESHOLD * len(attempt):
209
+ return []
210
+
211
+ suggestions = []
212
+ for errors, name in distances:
213
+ if errors == least_errors:
214
+ suggestions.append(name)
215
+ else:
216
+ break
217
+ return suggestions
218
+
219
+
220
+ def _damerau_levenshtein(a, b):
221
+ """Returns Damerau-Levenshtein edit distance from a to b."""
222
+ memo = {}
223
+
224
+ def distance(x, y):
225
+ """Recursively defined string distance with memoization."""
226
+ if (x, y) in memo:
227
+ return memo[x, y]
228
+ if not x:
229
+ d = len(y)
230
+ elif not y:
231
+ d = len(x)
232
+ else:
233
+ d = min(
234
+ distance(x[1:], y) + 1, # correct an insertion error
235
+ distance(x, y[1:]) + 1, # correct a deletion error
236
+ distance(x[1:], y[1:]) + (x[0] != y[0])) # correct a wrong character
237
+ if len(x) >= 2 and len(y) >= 2 and x[0] == y[1] and x[1] == y[0]:
238
+ # Correct a transposition.
239
+ t = distance(x[2:], y[2:]) + 1
240
+ if d > t:
241
+ d = t
242
+
243
+ memo[x, y] = d
244
+ return d
245
+ return distance(a, b)
246
+
247
+
248
+ def text_wrap(
249
+ text: str,
250
+ length: Optional[int] = None,
251
+ indent: str = '',
252
+ firstline_indent: Optional[str] = None,
253
+ ) -> str:
254
+ """Wraps a given text to a maximum line length and returns it.
255
+
256
+ It turns lines that only contain whitespace into empty lines, keeps new lines,
257
+ and expands tabs using 4 spaces.
258
+
259
+ Args:
260
+ text: str, text to wrap.
261
+ length: int, maximum length of a line, includes indentation.
262
+ If this is None then use get_help_width()
263
+ indent: str, indent for all but first line.
264
+ firstline_indent: str, indent for first line; if None, fall back to indent.
265
+
266
+ Returns:
267
+ str, the wrapped text.
268
+
269
+ Raises:
270
+ ValueError: Raised if indent or firstline_indent not shorter than length.
271
+ """
272
+ # Get defaults where callee used None
273
+ if length is None:
274
+ length = get_help_width()
275
+ if indent is None:
276
+ indent = ''
277
+ if firstline_indent is None:
278
+ firstline_indent = indent
279
+
280
+ if len(indent) >= length:
281
+ raise ValueError('Length of indent exceeds length')
282
+ if len(firstline_indent) >= length:
283
+ raise ValueError('Length of first line indent exceeds length')
284
+
285
+ text = text.expandtabs(4)
286
+
287
+ result = []
288
+ # Create one wrapper for the first paragraph and one for subsequent
289
+ # paragraphs that does not have the initial wrapping.
290
+ wrapper = textwrap.TextWrapper(
291
+ width=length, initial_indent=firstline_indent, subsequent_indent=indent)
292
+ subsequent_wrapper = textwrap.TextWrapper(
293
+ width=length, initial_indent=indent, subsequent_indent=indent)
294
+
295
+ # textwrap does not have any special treatment for newlines. From the docs:
296
+ # "...newlines may appear in the middle of a line and cause strange output.
297
+ # For this reason, text should be split into paragraphs (using
298
+ # str.splitlines() or similar) which are wrapped separately."
299
+ for paragraph in (p.strip() for p in text.splitlines()):
300
+ if paragraph:
301
+ result.extend(wrapper.wrap(paragraph))
302
+ else:
303
+ result.append('') # Keep empty lines.
304
+ # Replace initial wrapper with wrapper for subsequent paragraphs.
305
+ wrapper = subsequent_wrapper
306
+
307
+ return '\n'.join(result)
308
+
309
+
310
+ def flag_dict_to_args(
311
+ flag_map: Dict[str, Any], multi_flags: Optional[Set[str]] = None
312
+ ) -> Iterable[str]:
313
+ """Convert a dict of values into process call parameters.
314
+
315
+ This method is used to convert a dictionary into a sequence of parameters
316
+ for a binary that parses arguments using this module.
317
+
318
+ Args:
319
+ flag_map: dict, a mapping where the keys are flag names (strings).
320
+ values are treated according to their type:
321
+
322
+ * If value is ``None``, then only the name is emitted.
323
+ * If value is ``True``, then only the name is emitted.
324
+ * If value is ``False``, then only the name prepended with 'no' is
325
+ emitted.
326
+ * If value is a string then ``--name=value`` is emitted.
327
+ * If value is a collection, this will emit
328
+ ``--name=value1,value2,value3``, unless the flag name is in
329
+ ``multi_flags``, in which case this will emit
330
+ ``--name=value1 --name=value2 --name=value3``.
331
+ * Everything else is converted to string an passed as such.
332
+
333
+ multi_flags: set, names (strings) of flags that should be treated as
334
+ multi-flags.
335
+ Yields:
336
+ sequence of string suitable for a subprocess execution.
337
+ """
338
+ for key, value in flag_map.items():
339
+ if value is None:
340
+ yield '--%s' % key
341
+ elif isinstance(value, bool):
342
+ if value:
343
+ yield '--%s' % key
344
+ else:
345
+ yield '--no%s' % key
346
+ elif isinstance(value, (bytes, str)):
347
+ # We don't want strings to be handled like python collections.
348
+ yield '--%s=%s' % (key, value) # type: ignore[str-bytes-safe]
349
+ else:
350
+ # Now we attempt to deal with collections.
351
+ try:
352
+ if multi_flags and key in multi_flags:
353
+ for item in value:
354
+ yield '--%s=%s' % (key, str(item))
355
+ else:
356
+ yield '--%s=%s' % (key, ','.join(str(item) for item in value))
357
+ except TypeError:
358
+ # Default case.
359
+ yield '--%s=%s' % (key, value)
360
+
361
+
362
+ def trim_docstring(docstring: str) -> str:
363
+ """Removes indentation from triple-quoted strings.
364
+
365
+ This is the function specified in PEP 257 to handle docstrings:
366
+ https://www.python.org/dev/peps/pep-0257/.
367
+
368
+ Args:
369
+ docstring: str, a python docstring.
370
+
371
+ Returns:
372
+ str, docstring with indentation removed.
373
+ """
374
+ if not docstring:
375
+ return ''
376
+
377
+ # If you've got a line longer than this you have other problems...
378
+ max_indent = 1 << 29
379
+
380
+ # Convert tabs to spaces (following the normal Python rules)
381
+ # and split into a list of lines:
382
+ lines = docstring.expandtabs().splitlines()
383
+
384
+ # Determine minimum indentation (first line doesn't count):
385
+ indent = max_indent
386
+ for line in lines[1:]:
387
+ stripped = line.lstrip()
388
+ if stripped:
389
+ indent = min(indent, len(line) - len(stripped))
390
+ # Remove indentation (first line is special):
391
+ trimmed = [lines[0].strip()]
392
+ if indent < max_indent:
393
+ for line in lines[1:]:
394
+ trimmed.append(line[indent:].rstrip())
395
+ # Strip off trailing and leading blank lines:
396
+ while trimmed and not trimmed[-1]:
397
+ trimmed.pop()
398
+ while trimmed and not trimmed[0]:
399
+ trimmed.pop(0)
400
+ # Return a single string:
401
+ return '\n'.join(trimmed)
402
+
403
+
404
+ def doc_to_help(doc: str) -> str:
405
+ """Takes a __doc__ string and reformats it as help."""
406
+
407
+ # Get rid of starting and ending white space. Using lstrip() or even
408
+ # strip() could drop more than maximum of first line and right space
409
+ # of last line.
410
+ doc = doc.strip()
411
+
412
+ # Get rid of all empty lines.
413
+ whitespace_only_line = re.compile('^[ \t]+$', re.M)
414
+ doc = whitespace_only_line.sub('', doc)
415
+
416
+ # Cut out common space at line beginnings.
417
+ doc = trim_docstring(doc)
418
+
419
+ # Just like this module's comment, comments tend to be aligned somehow.
420
+ # In other words they all start with the same amount of white space.
421
+ # 1) keep double new lines;
422
+ # 2) keep ws after new lines if not empty line;
423
+ # 3) all other new lines shall be changed to a space;
424
+ # Solution: Match new lines between non white space and replace with space.
425
+ doc = re.sub(r'(?<=\S)\n(?=\S)', ' ', doc, flags=re.M)
426
+
427
+ return doc
lib/python3.10/site-packages/absl/flags/_validators.py ADDED
@@ -0,0 +1,353 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Module to enforce different constraints on flags.
16
+
17
+ Flags validators can be registered using following functions / decorators::
18
+
19
+ flags.register_validator
20
+ @flags.validator
21
+ flags.register_multi_flags_validator
22
+ @flags.multi_flags_validator
23
+
24
+ Three convenience functions are also provided for common flag constraints::
25
+
26
+ flags.mark_flag_as_required
27
+ flags.mark_flags_as_required
28
+ flags.mark_flags_as_mutual_exclusive
29
+ flags.mark_bool_flags_as_mutual_exclusive
30
+
31
+ See their docstring in this module for a usage manual.
32
+
33
+ Do NOT import this module directly. Import the flags package and use the
34
+ aliases defined at the package level instead.
35
+ """
36
+
37
+ import warnings
38
+
39
+ from absl.flags import _exceptions
40
+ from absl.flags import _flagvalues
41
+ from absl.flags import _validators_classes
42
+
43
+
44
+ def register_validator(flag_name,
45
+ checker,
46
+ message='Flag validation failed',
47
+ flag_values=_flagvalues.FLAGS):
48
+ """Adds a constraint, which will be enforced during program execution.
49
+
50
+ The constraint is validated when flags are initially parsed, and after each
51
+ change of the corresponding flag's value.
52
+
53
+ Args:
54
+ flag_name: str | FlagHolder, name or holder of the flag to be checked.
55
+ Positional-only parameter.
56
+ checker: callable, a function to validate the flag.
57
+
58
+ * input - A single positional argument: The value of the corresponding
59
+ flag (string, boolean, etc. This value will be passed to checker
60
+ by the library).
61
+ * output - bool, True if validator constraint is satisfied.
62
+ If constraint is not satisfied, it should either ``return False`` or
63
+ ``raise flags.ValidationError(desired_error_message)``.
64
+
65
+ message: str, error text to be shown to the user if checker returns False.
66
+ If checker raises flags.ValidationError, message from the raised
67
+ error will be shown.
68
+ flag_values: flags.FlagValues, optional FlagValues instance to validate
69
+ against.
70
+
71
+ Raises:
72
+ AttributeError: Raised when flag_name is not registered as a valid flag
73
+ name.
74
+ ValueError: Raised when flag_values is non-default and does not match the
75
+ FlagValues of the provided FlagHolder instance.
76
+ """
77
+ flag_name, flag_values = _flagvalues.resolve_flag_ref(flag_name, flag_values)
78
+ v = _validators_classes.SingleFlagValidator(flag_name, checker, message)
79
+ _add_validator(flag_values, v)
80
+
81
+
82
+ def validator(flag_name, message='Flag validation failed',
83
+ flag_values=_flagvalues.FLAGS):
84
+ """A function decorator for defining a flag validator.
85
+
86
+ Registers the decorated function as a validator for flag_name, e.g.::
87
+
88
+ @flags.validator('foo')
89
+ def _CheckFoo(foo):
90
+ ...
91
+
92
+ See :func:`register_validator` for the specification of checker function.
93
+
94
+ Args:
95
+ flag_name: str | FlagHolder, name or holder of the flag to be checked.
96
+ Positional-only parameter.
97
+ message: str, error text to be shown to the user if checker returns False.
98
+ If checker raises flags.ValidationError, message from the raised
99
+ error will be shown.
100
+ flag_values: flags.FlagValues, optional FlagValues instance to validate
101
+ against.
102
+ Returns:
103
+ A function decorator that registers its function argument as a validator.
104
+ Raises:
105
+ AttributeError: Raised when flag_name is not registered as a valid flag
106
+ name.
107
+ """
108
+
109
+ def decorate(function):
110
+ register_validator(flag_name, function,
111
+ message=message,
112
+ flag_values=flag_values)
113
+ return function
114
+ return decorate
115
+
116
+
117
+ def register_multi_flags_validator(flag_names,
118
+ multi_flags_checker,
119
+ message='Flags validation failed',
120
+ flag_values=_flagvalues.FLAGS):
121
+ """Adds a constraint to multiple flags.
122
+
123
+ The constraint is validated when flags are initially parsed, and after each
124
+ change of the corresponding flag's value.
125
+
126
+ Args:
127
+ flag_names: [str | FlagHolder], a list of the flag names or holders to be
128
+ checked. Positional-only parameter.
129
+ multi_flags_checker: callable, a function to validate the flag.
130
+
131
+ * input - dict, with keys() being flag_names, and value for each key
132
+ being the value of the corresponding flag (string, boolean, etc).
133
+ * output - bool, True if validator constraint is satisfied.
134
+ If constraint is not satisfied, it should either return False or
135
+ raise flags.ValidationError.
136
+
137
+ message: str, error text to be shown to the user if checker returns False.
138
+ If checker raises flags.ValidationError, message from the raised
139
+ error will be shown.
140
+ flag_values: flags.FlagValues, optional FlagValues instance to validate
141
+ against.
142
+
143
+ Raises:
144
+ AttributeError: Raised when a flag is not registered as a valid flag name.
145
+ ValueError: Raised when multiple FlagValues are used in the same
146
+ invocation. This can occur when FlagHolders have different `_flagvalues`
147
+ or when str-type flag_names entries are present and the `flag_values`
148
+ argument does not match that of provided FlagHolder(s).
149
+ """
150
+ flag_names, flag_values = _flagvalues.resolve_flag_refs(
151
+ flag_names, flag_values)
152
+ v = _validators_classes.MultiFlagsValidator(
153
+ flag_names, multi_flags_checker, message)
154
+ _add_validator(flag_values, v)
155
+
156
+
157
+ def multi_flags_validator(flag_names,
158
+ message='Flag validation failed',
159
+ flag_values=_flagvalues.FLAGS):
160
+ """A function decorator for defining a multi-flag validator.
161
+
162
+ Registers the decorated function as a validator for flag_names, e.g.::
163
+
164
+ @flags.multi_flags_validator(['foo', 'bar'])
165
+ def _CheckFooBar(flags_dict):
166
+ ...
167
+
168
+ See :func:`register_multi_flags_validator` for the specification of checker
169
+ function.
170
+
171
+ Args:
172
+ flag_names: [str | FlagHolder], a list of the flag names or holders to be
173
+ checked. Positional-only parameter.
174
+ message: str, error text to be shown to the user if checker returns False.
175
+ If checker raises flags.ValidationError, message from the raised
176
+ error will be shown.
177
+ flag_values: flags.FlagValues, optional FlagValues instance to validate
178
+ against.
179
+
180
+ Returns:
181
+ A function decorator that registers its function argument as a validator.
182
+
183
+ Raises:
184
+ AttributeError: Raised when a flag is not registered as a valid flag name.
185
+ """
186
+
187
+ def decorate(function):
188
+ register_multi_flags_validator(flag_names,
189
+ function,
190
+ message=message,
191
+ flag_values=flag_values)
192
+ return function
193
+
194
+ return decorate
195
+
196
+
197
+ def mark_flag_as_required(flag_name, flag_values=_flagvalues.FLAGS):
198
+ """Ensures that flag is not None during program execution.
199
+
200
+ Registers a flag validator, which will follow usual validator rules.
201
+ Important note: validator will pass for any non-``None`` value, such as
202
+ ``False``, ``0`` (zero), ``''`` (empty string) and so on.
203
+
204
+ If your module might be imported by others, and you only wish to make the flag
205
+ required when the module is directly executed, call this method like this::
206
+
207
+ if __name__ == '__main__':
208
+ flags.mark_flag_as_required('your_flag_name')
209
+ app.run()
210
+
211
+ Args:
212
+ flag_name: str | FlagHolder, name or holder of the flag.
213
+ Positional-only parameter.
214
+ flag_values: flags.FlagValues, optional :class:`~absl.flags.FlagValues`
215
+ instance where the flag is defined.
216
+ Raises:
217
+ AttributeError: Raised when flag_name is not registered as a valid flag
218
+ name.
219
+ ValueError: Raised when flag_values is non-default and does not match the
220
+ FlagValues of the provided FlagHolder instance.
221
+ """
222
+ flag_name, flag_values = _flagvalues.resolve_flag_ref(flag_name, flag_values)
223
+ if flag_values[flag_name].default is not None:
224
+ warnings.warn(
225
+ 'Flag --%s has a non-None default value; therefore, '
226
+ 'mark_flag_as_required will pass even if flag is not specified in the '
227
+ 'command line!' % flag_name,
228
+ stacklevel=2)
229
+ register_validator(
230
+ flag_name,
231
+ lambda value: value is not None,
232
+ message=f'Flag --{flag_name} must have a value other than None.',
233
+ flag_values=flag_values,
234
+ )
235
+
236
+
237
+ def mark_flags_as_required(flag_names, flag_values=_flagvalues.FLAGS):
238
+ """Ensures that flags are not None during program execution.
239
+
240
+ If your module might be imported by others, and you only wish to make the flag
241
+ required when the module is directly executed, call this method like this::
242
+
243
+ if __name__ == '__main__':
244
+ flags.mark_flags_as_required(['flag1', 'flag2', 'flag3'])
245
+ app.run()
246
+
247
+ Args:
248
+ flag_names: Sequence[str | FlagHolder], names or holders of the flags.
249
+ flag_values: flags.FlagValues, optional FlagValues instance where the flags
250
+ are defined.
251
+ Raises:
252
+ AttributeError: If any of flag name has not already been defined as a flag.
253
+ """
254
+ for flag_name in flag_names:
255
+ mark_flag_as_required(flag_name, flag_values)
256
+
257
+
258
+ def mark_flags_as_mutual_exclusive(flag_names, required=False,
259
+ flag_values=_flagvalues.FLAGS):
260
+ """Ensures that only one flag among flag_names is not None.
261
+
262
+ Important note: This validator checks if flag values are ``None``, and it does
263
+ not distinguish between default and explicit values. Therefore, this validator
264
+ does not make sense when applied to flags with default values other than None,
265
+ including other false values (e.g. ``False``, ``0``, ``''``, ``[]``). That
266
+ includes multi flags with a default value of ``[]`` instead of None.
267
+
268
+ Args:
269
+ flag_names: [str | FlagHolder], names or holders of flags.
270
+ Positional-only parameter.
271
+ required: bool. If true, exactly one of the flags must have a value other
272
+ than None. Otherwise, at most one of the flags can have a value other
273
+ than None, and it is valid for all of the flags to be None.
274
+ flag_values: flags.FlagValues, optional FlagValues instance where the flags
275
+ are defined.
276
+
277
+ Raises:
278
+ ValueError: Raised when multiple FlagValues are used in the same
279
+ invocation. This can occur when FlagHolders have different `_flagvalues`
280
+ or when str-type flag_names entries are present and the `flag_values`
281
+ argument does not match that of provided FlagHolder(s).
282
+ """
283
+ flag_names, flag_values = _flagvalues.resolve_flag_refs(
284
+ flag_names, flag_values)
285
+ for flag_name in flag_names:
286
+ if flag_values[flag_name].default is not None:
287
+ warnings.warn(
288
+ 'Flag --{} has a non-None default value. That does not make sense '
289
+ 'with mark_flags_as_mutual_exclusive, which checks whether the '
290
+ 'listed flags have a value other than None.'.format(flag_name),
291
+ stacklevel=2)
292
+
293
+ def validate_mutual_exclusion(flags_dict):
294
+ flag_count = sum(1 for val in flags_dict.values() if val is not None)
295
+ if flag_count == 1 or (not required and flag_count == 0):
296
+ return True
297
+ raise _exceptions.ValidationError(
298
+ '{} one of ({}) must have a value other than None.'.format(
299
+ 'Exactly' if required else 'At most', ', '.join(flag_names)))
300
+
301
+ register_multi_flags_validator(
302
+ flag_names, validate_mutual_exclusion, flag_values=flag_values)
303
+
304
+
305
+ def mark_bool_flags_as_mutual_exclusive(flag_names, required=False,
306
+ flag_values=_flagvalues.FLAGS):
307
+ """Ensures that only one flag among flag_names is True.
308
+
309
+ Args:
310
+ flag_names: [str | FlagHolder], names or holders of flags.
311
+ Positional-only parameter.
312
+ required: bool. If true, exactly one flag must be True. Otherwise, at most
313
+ one flag can be True, and it is valid for all flags to be False.
314
+ flag_values: flags.FlagValues, optional FlagValues instance where the flags
315
+ are defined.
316
+
317
+ Raises:
318
+ ValueError: Raised when multiple FlagValues are used in the same
319
+ invocation. This can occur when FlagHolders have different `_flagvalues`
320
+ or when str-type flag_names entries are present and the `flag_values`
321
+ argument does not match that of provided FlagHolder(s).
322
+ """
323
+ flag_names, flag_values = _flagvalues.resolve_flag_refs(
324
+ flag_names, flag_values)
325
+ for flag_name in flag_names:
326
+ if not flag_values[flag_name].boolean:
327
+ raise _exceptions.ValidationError(
328
+ 'Flag --{} is not Boolean, which is required for flags used in '
329
+ 'mark_bool_flags_as_mutual_exclusive.'.format(flag_name))
330
+
331
+ def validate_boolean_mutual_exclusion(flags_dict):
332
+ flag_count = sum(bool(val) for val in flags_dict.values())
333
+ if flag_count == 1 or (not required and flag_count == 0):
334
+ return True
335
+ raise _exceptions.ValidationError(
336
+ '{} one of ({}) must be True.'.format(
337
+ 'Exactly' if required else 'At most', ', '.join(flag_names)))
338
+
339
+ register_multi_flags_validator(
340
+ flag_names, validate_boolean_mutual_exclusion, flag_values=flag_values)
341
+
342
+
343
+ def _add_validator(fv, validator_instance):
344
+ """Register new flags validator to be checked.
345
+
346
+ Args:
347
+ fv: flags.FlagValues, the FlagValues instance to add the validator.
348
+ validator_instance: validators.Validator, the validator to add.
349
+ Raises:
350
+ KeyError: Raised when validators work with a non-existing flag.
351
+ """
352
+ for flag_name in validator_instance.get_flags_names():
353
+ fv[flag_name].validators.append(validator_instance)
lib/python3.10/site-packages/absl/flags/_validators_classes.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2021 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Defines *private* classes used for flag validators.
16
+
17
+ Do NOT import this module. DO NOT use anything from this module. They are
18
+ private APIs.
19
+ """
20
+
21
+ from absl.flags import _exceptions
22
+
23
+
24
+ class Validator:
25
+ """Base class for flags validators.
26
+
27
+ Users should NOT overload these classes, and use flags.Register...
28
+ methods instead.
29
+ """
30
+
31
+ # Used to assign each validator an unique insertion_index
32
+ validators_count = 0
33
+
34
+ def __init__(self, checker, message):
35
+ """Constructor to create all validators.
36
+
37
+ Args:
38
+ checker: function to verify the constraint.
39
+ Input of this method varies, see SingleFlagValidator and
40
+ multi_flags_validator for a detailed description.
41
+ message: str, error message to be shown to the user.
42
+ """
43
+ self.checker = checker
44
+ self.message = message
45
+ Validator.validators_count += 1
46
+ # Used to assert validators in the order they were registered.
47
+ self.insertion_index = Validator.validators_count
48
+
49
+ def verify(self, flag_values):
50
+ """Verifies that constraint is satisfied.
51
+
52
+ flags library calls this method to verify Validator's constraint.
53
+
54
+ Args:
55
+ flag_values: flags.FlagValues, the FlagValues instance to get flags from.
56
+ Raises:
57
+ Error: Raised if constraint is not satisfied.
58
+ """
59
+ param = self._get_input_to_checker_function(flag_values)
60
+ if not self.checker(param):
61
+ raise _exceptions.ValidationError(self.message)
62
+
63
+ def get_flags_names(self):
64
+ """Returns the names of the flags checked by this validator.
65
+
66
+ Returns:
67
+ [string], names of the flags.
68
+ """
69
+ raise NotImplementedError('This method should be overloaded')
70
+
71
+ def print_flags_with_values(self, flag_values):
72
+ raise NotImplementedError('This method should be overloaded')
73
+
74
+ def _get_input_to_checker_function(self, flag_values):
75
+ """Given flag values, returns the input to be given to checker.
76
+
77
+ Args:
78
+ flag_values: flags.FlagValues, containing all flags.
79
+ Returns:
80
+ The input to be given to checker. The return type depends on the specific
81
+ validator.
82
+ """
83
+ raise NotImplementedError('This method should be overloaded')
84
+
85
+
86
+ class SingleFlagValidator(Validator):
87
+ """Validator behind register_validator() method.
88
+
89
+ Validates that a single flag passes its checker function. The checker function
90
+ takes the flag value and returns True (if value looks fine) or, if flag value
91
+ is not valid, either returns False or raises an Exception.
92
+ """
93
+
94
+ def __init__(self, flag_name, checker, message):
95
+ """Constructor.
96
+
97
+ Args:
98
+ flag_name: string, name of the flag.
99
+ checker: function to verify the validator.
100
+ input - value of the corresponding flag (string, boolean, etc).
101
+ output - bool, True if validator constraint is satisfied.
102
+ If constraint is not satisfied, it should either return False or
103
+ raise flags.ValidationError(desired_error_message).
104
+ message: str, error message to be shown to the user if validator's
105
+ condition is not satisfied.
106
+ """
107
+ super().__init__(checker, message)
108
+ self.flag_name = flag_name
109
+
110
+ def get_flags_names(self):
111
+ return [self.flag_name]
112
+
113
+ def print_flags_with_values(self, flag_values):
114
+ return 'flag --%s=%s' % (self.flag_name, flag_values[self.flag_name].value)
115
+
116
+ def _get_input_to_checker_function(self, flag_values):
117
+ """Given flag values, returns the input to be given to checker.
118
+
119
+ Args:
120
+ flag_values: flags.FlagValues, the FlagValues instance to get flags from.
121
+ Returns:
122
+ object, the input to be given to checker.
123
+ """
124
+ return flag_values[self.flag_name].value
125
+
126
+
127
+ class MultiFlagsValidator(Validator):
128
+ """Validator behind register_multi_flags_validator method.
129
+
130
+ Validates that flag values pass their common checker function. The checker
131
+ function takes flag values and returns True (if values look fine) or,
132
+ if values are not valid, either returns False or raises an Exception.
133
+ """
134
+
135
+ def __init__(self, flag_names, checker, message):
136
+ """Constructor.
137
+
138
+ Args:
139
+ flag_names: [str], containing names of the flags used by checker.
140
+ checker: function to verify the validator.
141
+ input - dict, with keys() being flag_names, and value for each
142
+ key being the value of the corresponding flag (string, boolean,
143
+ etc).
144
+ output - bool, True if validator constraint is satisfied.
145
+ If constraint is not satisfied, it should either return False or
146
+ raise flags.ValidationError(desired_error_message).
147
+ message: str, error message to be shown to the user if validator's
148
+ condition is not satisfied
149
+ """
150
+ super().__init__(checker, message)
151
+ self.flag_names = flag_names
152
+
153
+ def _get_input_to_checker_function(self, flag_values):
154
+ """Given flag values, returns the input to be given to checker.
155
+
156
+ Args:
157
+ flag_values: flags.FlagValues, the FlagValues instance to get flags from.
158
+ Returns:
159
+ dict, with keys() being self.flag_names, and value for each key
160
+ being the value of the corresponding flag (string, boolean, etc).
161
+ """
162
+ return {key: flag_values[key].value for key in self.flag_names}
163
+
164
+ def print_flags_with_values(self, flag_values):
165
+ prefix = 'flags '
166
+ flags_with_values = []
167
+ for key in self.flag_names:
168
+ flags_with_values.append('%s=%s' % (key, flag_values[key].value))
169
+ return prefix + ', '.join(flags_with_values)
170
+
171
+ def get_flags_names(self):
172
+ return self.flag_names
lib/python3.10/site-packages/absl/flags/argparse_flags.py ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2018 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """This module provides argparse integration with absl.flags.
16
+
17
+ ``argparse_flags.ArgumentParser`` is a drop-in replacement for
18
+ :class:`argparse.ArgumentParser`. It takes care of collecting and defining absl
19
+ flags in :mod:`argparse`.
20
+
21
+ Here is a simple example::
22
+
23
+ # Assume the following absl.flags is defined in another module:
24
+ #
25
+ # from absl import flags
26
+ # flags.DEFINE_string('echo', None, 'The echo message.')
27
+ #
28
+ parser = argparse_flags.ArgumentParser(
29
+ description='A demo of absl.flags and argparse integration.')
30
+ parser.add_argument('--header', help='Header message to print.')
31
+
32
+ # The parser will also accept the absl flag `--echo`.
33
+ # The `header` value is available as `args.header` just like a regular
34
+ # argparse flag. The absl flag `--echo` continues to be available via
35
+ # `absl.flags.FLAGS` if you want to access it.
36
+ args = parser.parse_args()
37
+
38
+ # Example usages:
39
+ # ./program --echo='A message.' --header='A header'
40
+ # ./program --header 'A header' --echo 'A message.'
41
+
42
+
43
+ Here is another example demonstrates subparsers::
44
+
45
+ parser = argparse_flags.ArgumentParser(description='A subcommands demo.')
46
+ parser.add_argument('--header', help='The header message to print.')
47
+
48
+ subparsers = parser.add_subparsers(help='The command to execute.')
49
+
50
+ roll_dice_parser = subparsers.add_parser(
51
+ 'roll_dice', help='Roll a dice.',
52
+ # By default, absl flags can also be specified after the sub-command.
53
+ # To only allow them before sub-command, pass
54
+ # `inherited_absl_flags=None`.
55
+ inherited_absl_flags=None)
56
+ roll_dice_parser.add_argument('--num_faces', type=int, default=6)
57
+ roll_dice_parser.set_defaults(command=roll_dice)
58
+
59
+ shuffle_parser = subparsers.add_parser('shuffle', help='Shuffle inputs.')
60
+ shuffle_parser.add_argument(
61
+ 'inputs', metavar='I', nargs='+', help='Inputs to shuffle.')
62
+ shuffle_parser.set_defaults(command=shuffle)
63
+
64
+ args = parser.parse_args(argv[1:])
65
+ args.command(args)
66
+
67
+ # Example usages:
68
+ # ./program --echo='A message.' roll_dice --num_faces=6
69
+ # ./program shuffle --echo='A message.' 1 2 3 4
70
+
71
+
72
+ There are several differences between :mod:`absl.flags` and
73
+ :mod:`~absl.flags.argparse_flags`:
74
+
75
+ 1. Flags defined with absl.flags are parsed differently when using the
76
+ argparse parser. Notably:
77
+
78
+ 1) absl.flags allows both single-dash and double-dash for any flag, and
79
+ doesn't distinguish them; argparse_flags only allows double-dash for
80
+ flag's regular name, and single-dash for flag's ``short_name``.
81
+ 2) Boolean flags in absl.flags can be specified with ``--bool``,
82
+ ``--nobool``, as well as ``--bool=true/false`` (though not recommended);
83
+ in argparse_flags, it only allows ``--bool``, ``--nobool``.
84
+
85
+ 2. Help related flag differences:
86
+
87
+ 1) absl.flags does not define help flags, absl.app does that; argparse_flags
88
+ defines help flags unless passed with ``add_help=False``.
89
+ 2) absl.app supports ``--helpxml``; argparse_flags does not.
90
+ 3) argparse_flags supports ``-h``; absl.app does not.
91
+ """
92
+
93
+ import argparse
94
+ import sys
95
+
96
+ from absl import flags
97
+
98
+
99
+ _BUILT_IN_FLAGS = frozenset({
100
+ 'help',
101
+ 'helpshort',
102
+ 'helpfull',
103
+ 'helpxml',
104
+ 'flagfile',
105
+ 'undefok',
106
+ })
107
+
108
+
109
+ class ArgumentParser(argparse.ArgumentParser):
110
+ """Custom ArgumentParser class to support special absl flags."""
111
+
112
+ def __init__(self, **kwargs):
113
+ """Initializes ArgumentParser.
114
+
115
+ Args:
116
+ **kwargs: same as argparse.ArgumentParser, except:
117
+ 1. It also accepts `inherited_absl_flags`: the absl flags to inherit.
118
+ The default is the global absl.flags.FLAGS instance. Pass None to
119
+ ignore absl flags.
120
+ 2. The `prefix_chars` argument must be the default value '-'.
121
+
122
+ Raises:
123
+ ValueError: Raised when prefix_chars is not '-'.
124
+ """
125
+ prefix_chars = kwargs.get('prefix_chars', '-')
126
+ if prefix_chars != '-':
127
+ raise ValueError(
128
+ 'argparse_flags.ArgumentParser only supports "-" as the prefix '
129
+ 'character, found "{}".'.format(prefix_chars))
130
+
131
+ # Remove inherited_absl_flags before calling super.
132
+ self._inherited_absl_flags = kwargs.pop('inherited_absl_flags', flags.FLAGS)
133
+ # Now call super to initialize argparse.ArgumentParser before calling
134
+ # add_argument in _define_absl_flags.
135
+ super().__init__(**kwargs)
136
+
137
+ if self.add_help:
138
+ # -h and --help are defined in super.
139
+ # Also add the --helpshort and --helpfull flags.
140
+ self.add_argument(
141
+ # Action 'help' defines a similar flag to -h/--help.
142
+ '--helpshort', action='help',
143
+ default=argparse.SUPPRESS, help=argparse.SUPPRESS)
144
+ self.add_argument(
145
+ '--helpfull', action=_HelpFullAction,
146
+ default=argparse.SUPPRESS, help='show full help message and exit')
147
+
148
+ if self._inherited_absl_flags is not None:
149
+ self.add_argument(
150
+ '--undefok', default=argparse.SUPPRESS, help=argparse.SUPPRESS)
151
+ self._define_absl_flags(self._inherited_absl_flags)
152
+
153
+ def parse_known_args(self, args=None, namespace=None):
154
+ if args is None:
155
+ args = sys.argv[1:]
156
+ if self._inherited_absl_flags is not None:
157
+ # Handle --flagfile.
158
+ # Explicitly specify force_gnu=True, since argparse behaves like
159
+ # gnu_getopt: flags can be specified after positional arguments.
160
+ args = self._inherited_absl_flags.read_flags_from_files(
161
+ args, force_gnu=True)
162
+
163
+ undefok_missing = object()
164
+ undefok = getattr(namespace, 'undefok', undefok_missing)
165
+
166
+ namespace, args = super().parse_known_args(args, namespace)
167
+
168
+ # For Python <= 2.7.8: https://bugs.python.org/issue9351, a bug where
169
+ # sub-parsers don't preserve existing namespace attributes.
170
+ # Restore the undefok attribute if a sub-parser dropped it.
171
+ if undefok is not undefok_missing:
172
+ namespace.undefok = undefok
173
+
174
+ if self._inherited_absl_flags is not None:
175
+ # Handle --undefok. At this point, `args` only contains unknown flags,
176
+ # so it won't strip defined flags that are also specified with --undefok.
177
+ # For Python <= 2.7.8: https://bugs.python.org/issue9351, a bug where
178
+ # sub-parsers don't preserve existing namespace attributes. The undefok
179
+ # attribute might not exist because a subparser dropped it.
180
+ if hasattr(namespace, 'undefok'):
181
+ args = _strip_undefok_args(namespace.undefok, args)
182
+ # absl flags are not exposed in the Namespace object. See Namespace:
183
+ # https://docs.python.org/3/library/argparse.html#argparse.Namespace.
184
+ del namespace.undefok
185
+ self._inherited_absl_flags.mark_as_parsed()
186
+ try:
187
+ self._inherited_absl_flags.validate_all_flags()
188
+ except flags.IllegalFlagValueError as e:
189
+ self.error(str(e))
190
+
191
+ return namespace, args
192
+
193
+ def _define_absl_flags(self, absl_flags):
194
+ """Defines flags from absl_flags."""
195
+ key_flags = set(absl_flags.get_key_flags_for_module(sys.argv[0]))
196
+ for name in absl_flags:
197
+ if name in _BUILT_IN_FLAGS:
198
+ # Do not inherit built-in flags.
199
+ continue
200
+ flag_instance = absl_flags[name]
201
+ # Each flags with short_name appears in FLAGS twice, so only define
202
+ # when the dictionary key is equal to the regular name.
203
+ if name == flag_instance.name:
204
+ # Suppress the flag in the help short message if it's not a main
205
+ # module's key flag.
206
+ suppress = flag_instance not in key_flags
207
+ self._define_absl_flag(flag_instance, suppress)
208
+
209
+ def _define_absl_flag(self, flag_instance, suppress):
210
+ """Defines a flag from the flag_instance."""
211
+ flag_name = flag_instance.name
212
+ short_name = flag_instance.short_name
213
+ argument_names = ['--' + flag_name]
214
+ if short_name:
215
+ argument_names.insert(0, '-' + short_name)
216
+ if suppress:
217
+ helptext = argparse.SUPPRESS
218
+ else:
219
+ # argparse help string uses %-formatting. Escape the literal %'s.
220
+ helptext = flag_instance.help.replace('%', '%%')
221
+ if flag_instance.boolean:
222
+ # Only add the `no` form to the long name.
223
+ argument_names.append('--no' + flag_name)
224
+ self.add_argument(
225
+ *argument_names, action=_BooleanFlagAction, help=helptext,
226
+ metavar=flag_instance.name.upper(),
227
+ flag_instance=flag_instance)
228
+ else:
229
+ self.add_argument(
230
+ *argument_names, action=_FlagAction, help=helptext,
231
+ metavar=flag_instance.name.upper(),
232
+ flag_instance=flag_instance)
233
+
234
+
235
+ class _FlagAction(argparse.Action):
236
+ """Action class for Abseil non-boolean flags."""
237
+
238
+ def __init__(
239
+ self,
240
+ option_strings,
241
+ dest,
242
+ help, # pylint: disable=redefined-builtin
243
+ metavar,
244
+ flag_instance,
245
+ default=argparse.SUPPRESS):
246
+ """Initializes _FlagAction.
247
+
248
+ Args:
249
+ option_strings: See argparse.Action.
250
+ dest: Ignored. The flag is always defined with dest=argparse.SUPPRESS.
251
+ help: See argparse.Action.
252
+ metavar: See argparse.Action.
253
+ flag_instance: absl.flags.Flag, the absl flag instance.
254
+ default: Ignored. The flag always uses dest=argparse.SUPPRESS so it
255
+ doesn't affect the parsing result.
256
+ """
257
+ del dest
258
+ self._flag_instance = flag_instance
259
+ super().__init__(
260
+ option_strings=option_strings,
261
+ dest=argparse.SUPPRESS,
262
+ help=help,
263
+ metavar=metavar,
264
+ )
265
+
266
+ def __call__(self, parser, namespace, values, option_string=None):
267
+ """See https://docs.python.org/3/library/argparse.html#action-classes."""
268
+ self._flag_instance.parse(values)
269
+ self._flag_instance.using_default_value = False
270
+
271
+
272
+ class _BooleanFlagAction(argparse.Action):
273
+ """Action class for Abseil boolean flags."""
274
+
275
+ def __init__(
276
+ self,
277
+ option_strings,
278
+ dest,
279
+ help, # pylint: disable=redefined-builtin
280
+ metavar,
281
+ flag_instance,
282
+ default=argparse.SUPPRESS):
283
+ """Initializes _BooleanFlagAction.
284
+
285
+ Args:
286
+ option_strings: See argparse.Action.
287
+ dest: Ignored. The flag is always defined with dest=argparse.SUPPRESS.
288
+ help: See argparse.Action.
289
+ metavar: See argparse.Action.
290
+ flag_instance: absl.flags.Flag, the absl flag instance.
291
+ default: Ignored. The flag always uses dest=argparse.SUPPRESS so it
292
+ doesn't affect the parsing result.
293
+ """
294
+ del dest, default
295
+ self._flag_instance = flag_instance
296
+ flag_names = [self._flag_instance.name]
297
+ if self._flag_instance.short_name:
298
+ flag_names.append(self._flag_instance.short_name)
299
+ self._flag_names = frozenset(flag_names)
300
+ super().__init__(
301
+ option_strings=option_strings,
302
+ dest=argparse.SUPPRESS,
303
+ nargs=0, # Does not accept values, only `--bool` or `--nobool`.
304
+ help=help,
305
+ metavar=metavar,
306
+ )
307
+
308
+ def __call__(self, parser, namespace, values, option_string=None):
309
+ """See https://docs.python.org/3/library/argparse.html#action-classes."""
310
+ if not isinstance(values, list) or values:
311
+ raise ValueError('values must be an empty list.')
312
+ if option_string.startswith('--'):
313
+ option = option_string[2:]
314
+ else:
315
+ option = option_string[1:]
316
+ if option in self._flag_names:
317
+ self._flag_instance.parse('true')
318
+ else:
319
+ if not option.startswith('no') or option[2:] not in self._flag_names:
320
+ raise ValueError('invalid option_string: ' + option_string)
321
+ self._flag_instance.parse('false')
322
+ self._flag_instance.using_default_value = False
323
+
324
+
325
+ class _HelpFullAction(argparse.Action):
326
+ """Action class for --helpfull flag."""
327
+
328
+ def __init__(self, option_strings, dest, default, help): # pylint: disable=redefined-builtin
329
+ """Initializes _HelpFullAction.
330
+
331
+ Args:
332
+ option_strings: See argparse.Action.
333
+ dest: Ignored. The flag is always defined with dest=argparse.SUPPRESS.
334
+ default: Ignored.
335
+ help: See argparse.Action.
336
+ """
337
+ del dest, default
338
+ super().__init__(
339
+ option_strings=option_strings,
340
+ dest=argparse.SUPPRESS,
341
+ default=argparse.SUPPRESS,
342
+ nargs=0,
343
+ help=help,
344
+ )
345
+
346
+ def __call__(self, parser, namespace, values, option_string=None):
347
+ """See https://docs.python.org/3/library/argparse.html#action-classes."""
348
+ # This only prints flags when help is not argparse.SUPPRESS.
349
+ # It includes user defined argparse flags, as well as main module's
350
+ # key absl flags. Other absl flags use argparse.SUPPRESS, so they aren't
351
+ # printed here.
352
+ parser.print_help()
353
+
354
+ absl_flags = parser._inherited_absl_flags # pylint: disable=protected-access
355
+ if absl_flags is not None:
356
+ modules = sorted(absl_flags.flags_by_module_dict())
357
+ main_module = sys.argv[0]
358
+ if main_module in modules:
359
+ # The main module flags are already printed in parser.print_help().
360
+ modules.remove(main_module)
361
+ print(absl_flags._get_help_for_modules( # pylint: disable=protected-access
362
+ modules, prefix='', include_special_flags=True))
363
+ parser.exit()
364
+
365
+
366
+ def _strip_undefok_args(undefok, args):
367
+ """Returns a new list of args after removing flags in --undefok."""
368
+ if undefok:
369
+ undefok_names = {name.strip() for name in undefok.split(',')}
370
+ undefok_names |= {'no' + name for name in undefok_names}
371
+ # Remove undefok flags.
372
+ args = [arg for arg in args if not _is_undefok(arg, undefok_names)]
373
+ return args
374
+
375
+
376
+ def _is_undefok(arg, undefok_names):
377
+ """Returns whether we can ignore arg based on a set of undefok flag names."""
378
+ if not arg.startswith('-'):
379
+ return False
380
+ if arg.startswith('--'):
381
+ arg_without_dash = arg[2:]
382
+ else:
383
+ arg_without_dash = arg[1:]
384
+ if '=' in arg_without_dash:
385
+ name, _ = arg_without_dash.split('=', 1)
386
+ else:
387
+ name = arg_without_dash
388
+ if name in undefok_names:
389
+ return True
390
+ return False
lib/python3.10/site-packages/absl/logging/__init__.py ADDED
@@ -0,0 +1,1331 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Abseil Python logging module implemented on top of standard logging.
16
+
17
+ Simple usage::
18
+
19
+ from absl import logging
20
+
21
+ logging.info('Interesting Stuff')
22
+ logging.info('Interesting Stuff with Arguments: %d', 42)
23
+
24
+ logging.set_verbosity(logging.INFO)
25
+ logging.log(logging.DEBUG, 'This will *not* be printed')
26
+ logging.set_verbosity(logging.DEBUG)
27
+ logging.log(logging.DEBUG, 'This will be printed')
28
+
29
+ logging.warning('Worrying Stuff')
30
+ logging.error('Alarming Stuff')
31
+ logging.fatal('AAAAHHHHH!!!!') # Process exits.
32
+
33
+ Usage note: Do not pre-format the strings in your program code.
34
+ Instead, let the logging module perform argument interpolation.
35
+ This saves cycles because strings that don't need to be printed
36
+ are never formatted. Note that this module does not attempt to
37
+ interpolate arguments when no arguments are given. In other words::
38
+
39
+ logging.info('Interesting Stuff: %s')
40
+
41
+ does not raise an exception because logging.info() has only one
42
+ argument, the message string.
43
+
44
+ "Lazy" evaluation for debugging
45
+ -------------------------------
46
+
47
+ If you do something like this::
48
+
49
+ logging.debug('Thing: %s', thing.ExpensiveOp())
50
+
51
+ then the ExpensiveOp will be evaluated even if nothing
52
+ is printed to the log. To avoid this, use the level_debug() function::
53
+
54
+ if logging.level_debug():
55
+ logging.debug('Thing: %s', thing.ExpensiveOp())
56
+
57
+ Per file level logging is supported by logging.vlog() and
58
+ logging.vlog_is_on(). For example::
59
+
60
+ if logging.vlog_is_on(2):
61
+ logging.vlog(2, very_expensive_debug_message())
62
+
63
+ Notes on Unicode
64
+ ----------------
65
+
66
+ The log output is encoded as UTF-8. Don't pass data in other encodings in
67
+ bytes() instances -- instead pass unicode string instances when you need to
68
+ (for both the format string and arguments).
69
+
70
+ Note on critical and fatal:
71
+ Standard logging module defines fatal as an alias to critical, but it's not
72
+ documented, and it does NOT actually terminate the program.
73
+ This module only defines fatal but not critical, and it DOES terminate the
74
+ program.
75
+
76
+ The differences in behavior are historical and unfortunate.
77
+ """
78
+
79
+ import collections
80
+ from collections import abc
81
+ import getpass
82
+ import io
83
+ import inspect
84
+ import itertools
85
+ import logging
86
+ import os
87
+ import socket
88
+ import struct
89
+ import sys
90
+ import tempfile
91
+ import threading
92
+ import time
93
+ import timeit
94
+ import traceback
95
+ import types
96
+ import warnings
97
+
98
+ from absl import flags
99
+ from absl.logging import converter
100
+
101
+ # pylint: disable=g-import-not-at-top
102
+ try:
103
+ from typing import NoReturn
104
+ except ImportError:
105
+ pass
106
+
107
+ # pylint: enable=g-import-not-at-top
108
+
109
+ FLAGS = flags.FLAGS
110
+
111
+
112
+ # Logging levels.
113
+ FATAL = converter.ABSL_FATAL
114
+ ERROR = converter.ABSL_ERROR
115
+ WARNING = converter.ABSL_WARNING
116
+ WARN = converter.ABSL_WARNING # Deprecated name.
117
+ INFO = converter.ABSL_INFO
118
+ DEBUG = converter.ABSL_DEBUG
119
+
120
+ # Regex to match/parse log line prefixes.
121
+ ABSL_LOGGING_PREFIX_REGEX = (
122
+ r'^(?P<severity>[IWEF])'
123
+ r'(?P<month>\d\d)(?P<day>\d\d) '
124
+ r'(?P<hour>\d\d):(?P<minute>\d\d):(?P<second>\d\d)'
125
+ r'\.(?P<microsecond>\d\d\d\d\d\d) +'
126
+ r'(?P<thread_id>-?\d+) '
127
+ r'(?P<filename>[a-zA-Z<][\w._<>-]+):(?P<line>\d+)')
128
+
129
+
130
+ # Mask to convert integer thread ids to unsigned quantities for logging purposes
131
+ _THREAD_ID_MASK = 2 ** (struct.calcsize('L') * 8) - 1
132
+
133
+ # Extra property set on the LogRecord created by ABSLLogger when its level is
134
+ # CRITICAL/FATAL.
135
+ _ABSL_LOG_FATAL = '_absl_log_fatal'
136
+ # Extra prefix added to the log message when a non-absl logger logs a
137
+ # CRITICAL/FATAL message.
138
+ _CRITICAL_PREFIX = 'CRITICAL - '
139
+
140
+ # Used by findCaller to skip callers from */logging/__init__.py.
141
+ _LOGGING_FILE_PREFIX = os.path.join('logging', '__init__.')
142
+
143
+ # The ABSL logger instance, initialized in _initialize().
144
+ _absl_logger = None
145
+ # The ABSL handler instance, initialized in _initialize().
146
+ _absl_handler = None
147
+
148
+
149
+ _CPP_NAME_TO_LEVELS = {
150
+ 'debug': '0', # Abseil C++ has no DEBUG level, mapping it to INFO here.
151
+ 'info': '0',
152
+ 'warning': '1',
153
+ 'warn': '1',
154
+ 'error': '2',
155
+ 'fatal': '3'
156
+ }
157
+
158
+ _CPP_LEVEL_TO_NAMES = {
159
+ '0': 'info',
160
+ '1': 'warning',
161
+ '2': 'error',
162
+ '3': 'fatal',
163
+ }
164
+
165
+
166
+ class _VerbosityFlag(flags.Flag):
167
+ """Flag class for -v/--verbosity."""
168
+
169
+ def __init__(self, *args, **kwargs):
170
+ super().__init__(
171
+ flags.IntegerParser(), flags.ArgumentSerializer(), *args, **kwargs
172
+ )
173
+
174
+ @property
175
+ def value(self):
176
+ return self._value
177
+
178
+ @value.setter
179
+ def value(self, v):
180
+ self._value = v
181
+ self._update_logging_levels()
182
+
183
+ def _update_logging_levels(self):
184
+ """Updates absl logging levels to the current verbosity.
185
+
186
+ Visibility: module-private
187
+ """
188
+ if not _absl_logger:
189
+ return
190
+
191
+ if self._value <= converter.ABSL_DEBUG:
192
+ standard_verbosity = converter.absl_to_standard(self._value)
193
+ else:
194
+ # --verbosity is set to higher than 1 for vlog.
195
+ standard_verbosity = logging.DEBUG - (self._value - 1)
196
+
197
+ # Also update root level when absl_handler is used.
198
+ if _absl_handler in logging.root.handlers:
199
+ # Make absl logger inherit from the root logger. absl logger might have
200
+ # a non-NOTSET value if logging.set_verbosity() is called at import time.
201
+ _absl_logger.setLevel(logging.NOTSET)
202
+ logging.root.setLevel(standard_verbosity)
203
+ else:
204
+ _absl_logger.setLevel(standard_verbosity)
205
+
206
+
207
+ class _LoggerLevelsFlag(flags.Flag):
208
+ """Flag class for --logger_levels."""
209
+
210
+ def __init__(self, *args, **kwargs):
211
+ super().__init__(
212
+ _LoggerLevelsParser(), _LoggerLevelsSerializer(), *args, **kwargs
213
+ )
214
+
215
+ @property
216
+ def value(self):
217
+ # For lack of an immutable type, be defensive and return a copy.
218
+ # Modifications to the dict aren't supported and won't have any affect.
219
+ # While Py3 could use MappingProxyType, that isn't deepcopy friendly, so
220
+ # just return a copy.
221
+ return self._value.copy()
222
+
223
+ @value.setter
224
+ def value(self, v):
225
+ self._value = {} if v is None else v
226
+ self._update_logger_levels()
227
+
228
+ def _update_logger_levels(self):
229
+ # Visibility: module-private.
230
+ # This is called by absl.app.run() during initialization.
231
+ for name, level in self._value.items():
232
+ logging.getLogger(name).setLevel(level)
233
+
234
+
235
+ class _LoggerLevelsParser(flags.ArgumentParser):
236
+ """Parser for --logger_levels flag."""
237
+
238
+ def parse(self, value):
239
+ if isinstance(value, abc.Mapping):
240
+ return value
241
+
242
+ pairs = [pair.strip() for pair in value.split(',') if pair.strip()]
243
+
244
+ # Preserve the order so that serialization is deterministic.
245
+ levels = collections.OrderedDict()
246
+ for name_level in pairs:
247
+ name, level = name_level.split(':', 1)
248
+ name = name.strip()
249
+ level = level.strip()
250
+ levels[name] = level
251
+ return levels
252
+
253
+
254
+ class _LoggerLevelsSerializer:
255
+ """Serializer for --logger_levels flag."""
256
+
257
+ def serialize(self, value):
258
+ if isinstance(value, str):
259
+ return value
260
+ return ','.join(f'{name}:{level}' for name, level in value.items())
261
+
262
+
263
+ class _StderrthresholdFlag(flags.Flag):
264
+ """Flag class for --stderrthreshold."""
265
+
266
+ def __init__(self, *args, **kwargs):
267
+ super().__init__(
268
+ flags.ArgumentParser(), flags.ArgumentSerializer(), *args, **kwargs
269
+ )
270
+
271
+ @property
272
+ def value(self):
273
+ return self._value
274
+
275
+ @value.setter
276
+ def value(self, v):
277
+ if v in _CPP_LEVEL_TO_NAMES:
278
+ # --stderrthreshold also accepts numeric strings whose values are
279
+ # Abseil C++ log levels.
280
+ cpp_value = int(v)
281
+ v = _CPP_LEVEL_TO_NAMES[v] # Normalize to strings.
282
+ elif v.lower() in _CPP_NAME_TO_LEVELS:
283
+ v = v.lower()
284
+ if v == 'warn':
285
+ v = 'warning' # Use 'warning' as the canonical name.
286
+ cpp_value = int(_CPP_NAME_TO_LEVELS[v])
287
+ else:
288
+ raise ValueError(
289
+ '--stderrthreshold must be one of (case-insensitive) '
290
+ "'debug', 'info', 'warning', 'error', 'fatal', "
291
+ "or '0', '1', '2', '3', not '%s'" % v)
292
+
293
+ self._value = v
294
+
295
+
296
+ LOGTOSTDERR = flags.DEFINE_boolean(
297
+ 'logtostderr',
298
+ False,
299
+ 'Should only log to stderr?',
300
+ allow_override_cpp=True,
301
+ )
302
+ ALSOLOGTOSTDERR = flags.DEFINE_boolean(
303
+ 'alsologtostderr',
304
+ False,
305
+ 'also log to stderr?',
306
+ allow_override_cpp=True,
307
+ )
308
+ LOG_DIR = flags.DEFINE_string(
309
+ 'log_dir',
310
+ os.getenv('TEST_TMPDIR', ''),
311
+ 'directory to write logfiles into',
312
+ allow_override_cpp=True,
313
+ )
314
+ VERBOSITY = flags.DEFINE_flag(
315
+ _VerbosityFlag(
316
+ 'verbosity',
317
+ -1,
318
+ (
319
+ 'Logging verbosity level. Messages logged at this level or lower'
320
+ ' will be included. Set to 1 for debug logging. If the flag was not'
321
+ ' set or supplied, the value will be changed from the default of -1'
322
+ ' (warning) to 0 (info) after flags are parsed.'
323
+ ),
324
+ short_name='v',
325
+ allow_hide_cpp=True,
326
+ )
327
+ )
328
+ LOGGER_LEVELS = flags.DEFINE_flag(
329
+ _LoggerLevelsFlag(
330
+ 'logger_levels',
331
+ {},
332
+ (
333
+ 'Specify log level of loggers. The format is a CSV list of '
334
+ '`name:level`. Where `name` is the logger name used with '
335
+ '`logging.getLogger()`, and `level` is a level name (INFO, DEBUG, '
336
+ 'etc). e.g. `myapp.foo:INFO,other.logger:DEBUG`'
337
+ ),
338
+ )
339
+ )
340
+ STDERRTHRESHOLD = flags.DEFINE_flag(
341
+ _StderrthresholdFlag(
342
+ 'stderrthreshold',
343
+ 'fatal',
344
+ (
345
+ 'log messages at this level, or more severe, to stderr in '
346
+ 'addition to the logfile. Possible values are '
347
+ "'debug', 'info', 'warning', 'error', and 'fatal'. "
348
+ 'Obsoletes --alsologtostderr. Using --alsologtostderr '
349
+ 'cancels the effect of this flag. Please also note that '
350
+ 'this flag is subject to --verbosity and requires logfile '
351
+ 'not be stderr.'
352
+ ),
353
+ allow_hide_cpp=True,
354
+ )
355
+ )
356
+ SHOWPREFIXFORINFO = flags.DEFINE_boolean(
357
+ 'showprefixforinfo',
358
+ True,
359
+ (
360
+ 'If False, do not prepend prefix to info messages '
361
+ "when it's logged to stderr, "
362
+ '--verbosity is set to INFO level, '
363
+ 'and python logging is used.'
364
+ ),
365
+ )
366
+
367
+
368
+ def get_verbosity():
369
+ """Returns the logging verbosity."""
370
+ return FLAGS['verbosity'].value
371
+
372
+
373
+ def set_verbosity(v):
374
+ """Sets the logging verbosity.
375
+
376
+ Causes all messages of level <= v to be logged,
377
+ and all messages of level > v to be silently discarded.
378
+
379
+ Args:
380
+ v: int|str, the verbosity level as an integer or string. Legal string values
381
+ are those that can be coerced to an integer as well as case-insensitive
382
+ 'debug', 'info', 'warning', 'error', and 'fatal'.
383
+ """
384
+ try:
385
+ new_level = int(v)
386
+ except ValueError:
387
+ new_level = converter.ABSL_NAMES[v.upper()]
388
+ FLAGS.verbosity = new_level
389
+
390
+
391
+ def set_stderrthreshold(s):
392
+ """Sets the stderr threshold to the value passed in.
393
+
394
+ Args:
395
+ s: str|int, valid strings values are case-insensitive 'debug',
396
+ 'info', 'warning', 'error', and 'fatal'; valid integer values are
397
+ logging.DEBUG|INFO|WARNING|ERROR|FATAL.
398
+
399
+ Raises:
400
+ ValueError: Raised when s is an invalid value.
401
+ """
402
+ if s in converter.ABSL_LEVELS:
403
+ FLAGS.stderrthreshold = converter.ABSL_LEVELS[s]
404
+ elif isinstance(s, str) and s.upper() in converter.ABSL_NAMES:
405
+ FLAGS.stderrthreshold = s
406
+ else:
407
+ raise ValueError(
408
+ 'set_stderrthreshold only accepts integer absl logging level '
409
+ 'from -3 to 1, or case-insensitive string values '
410
+ "'debug', 'info', 'warning', 'error', and 'fatal'. "
411
+ 'But found "{}" ({}).'.format(s, type(s)))
412
+
413
+
414
+ def fatal(msg, *args, **kwargs):
415
+ # type: (Any, Any, Any) -> NoReturn
416
+ """Logs a fatal message."""
417
+ log(FATAL, msg, *args, **kwargs)
418
+
419
+
420
+ def error(msg, *args, **kwargs):
421
+ """Logs an error message."""
422
+ log(ERROR, msg, *args, **kwargs)
423
+
424
+
425
+ def warning(msg, *args, **kwargs):
426
+ """Logs a warning message."""
427
+ log(WARNING, msg, *args, **kwargs)
428
+
429
+
430
+ def warn(msg, *args, **kwargs):
431
+ """Deprecated, use 'warning' instead."""
432
+ warnings.warn("The 'warn' function is deprecated, use 'warning' instead",
433
+ DeprecationWarning, 2)
434
+ log(WARNING, msg, *args, **kwargs)
435
+
436
+
437
+ def info(msg, *args, **kwargs):
438
+ """Logs an info message."""
439
+ log(INFO, msg, *args, **kwargs)
440
+
441
+
442
+ def debug(msg, *args, **kwargs):
443
+ """Logs a debug message."""
444
+ log(DEBUG, msg, *args, **kwargs)
445
+
446
+
447
+ def exception(msg, *args, exc_info=True, **kwargs):
448
+ """Logs an exception, with traceback and message."""
449
+ error(msg, *args, exc_info=exc_info, **kwargs)
450
+
451
+
452
+ def _fast_stack_trace():
453
+ """A fast stack trace that gets us the minimal information we need.
454
+
455
+ Compared to using `get_absl_logger().findCaller(stack_info=True)`, this
456
+ function is ~100x faster.
457
+
458
+ Returns:
459
+ A tuple of tuples of (filename, line_number, last_instruction_offset).
460
+ """
461
+ cur_stack = inspect.currentframe()
462
+ if cur_stack is None or cur_stack.f_back is None:
463
+ return tuple()
464
+ # We drop the first frame, which is this function itself.
465
+ cur_stack = cur_stack.f_back
466
+ call_stack = []
467
+ while cur_stack.f_back:
468
+ cur_stack = cur_stack.f_back
469
+ call_stack.append(
470
+ (cur_stack.f_code.co_filename, cur_stack.f_lineno, cur_stack.f_lasti)
471
+ )
472
+ return tuple(call_stack)
473
+
474
+
475
+ # Counter to keep track of number of log entries per token.
476
+ _log_counter_per_token = {}
477
+
478
+
479
+ def _get_next_log_count_per_token(token):
480
+ """Wrapper for _log_counter_per_token. Thread-safe.
481
+
482
+ Args:
483
+ token: The token for which to look up the count.
484
+
485
+ Returns:
486
+ The number of times this function has been called with
487
+ *token* as an argument (starting at 0).
488
+ """
489
+ # Can't use a defaultdict because defaultdict isn't atomic, whereas
490
+ # setdefault is.
491
+ return next(_log_counter_per_token.setdefault(token, itertools.count()))
492
+
493
+
494
+ def log_every_n(level, msg, n, *args, use_call_stack=False):
495
+ """Logs ``msg % args`` at level 'level' once per 'n' times.
496
+
497
+ Logs the 1st call, (N+1)st call, (2N+1)st call, etc.
498
+ Not threadsafe.
499
+
500
+ Args:
501
+ level: int, the absl logging level at which to log.
502
+ msg: str, the message to be logged.
503
+ n: int, the number of times this should be called before it is logged.
504
+ *args: The args to be substituted into the msg.
505
+ use_call_stack: bool, whether to include the call stack when counting the
506
+ number of times the message is logged.
507
+ """
508
+ caller_info = get_absl_logger().findCaller()
509
+ if use_call_stack:
510
+ # To reduce storage costs, we hash the call stack.
511
+ caller_info = (*caller_info[0:3], hash(_fast_stack_trace()))
512
+ count = _get_next_log_count_per_token(caller_info)
513
+ log_if(level, msg, not (count % n), *args)
514
+
515
+
516
+ # Keeps track of the last log time of the given token.
517
+ # Note: must be a dict since set/get is atomic in CPython.
518
+ # Note: entries are never released as their number is expected to be low.
519
+ _log_timer_per_token = {}
520
+
521
+
522
+ def _seconds_have_elapsed(token, num_seconds):
523
+ """Tests if 'num_seconds' have passed since 'token' was requested.
524
+
525
+ Not strictly thread-safe - may log with the wrong frequency if called
526
+ concurrently from multiple threads. Accuracy depends on resolution of
527
+ 'timeit.default_timer()'.
528
+
529
+ Always returns True on the first call for a given 'token'.
530
+
531
+ Args:
532
+ token: The token for which to look up the count.
533
+ num_seconds: The number of seconds to test for.
534
+
535
+ Returns:
536
+ Whether it has been >= 'num_seconds' since 'token' was last requested.
537
+ """
538
+ now = timeit.default_timer()
539
+ then = _log_timer_per_token.get(token, None)
540
+ if then is None or (now - then) >= num_seconds:
541
+ _log_timer_per_token[token] = now
542
+ return True
543
+ else:
544
+ return False
545
+
546
+
547
+ def log_every_n_seconds(level, msg, n_seconds, *args, use_call_stack=False):
548
+ """Logs ``msg % args`` at level ``level`` iff ``n_seconds`` elapsed since last call.
549
+
550
+ Logs the first call, logs subsequent calls if 'n' seconds have elapsed since
551
+ the last logging call from the same call site (file + line). Not thread-safe.
552
+
553
+ Args:
554
+ level: int, the absl logging level at which to log.
555
+ msg: str, the message to be logged.
556
+ n_seconds: float or int, seconds which should elapse before logging again.
557
+ *args: The args to be substituted into the msg.
558
+ use_call_stack: bool, whether to include the call stack when counting the
559
+ number of times the message is logged.
560
+ """
561
+ caller_info = get_absl_logger().findCaller()
562
+ if use_call_stack:
563
+ # To reduce storage costs, we hash the call stack.
564
+ caller_info = (*caller_info[0:3], hash(_fast_stack_trace()))
565
+ should_log = _seconds_have_elapsed(caller_info, n_seconds)
566
+ log_if(level, msg, should_log, *args)
567
+
568
+
569
+ def log_first_n(level, msg, n, *args, use_call_stack=False):
570
+ """Logs ``msg % args`` at level ``level`` only first ``n`` times.
571
+
572
+ Not threadsafe.
573
+
574
+ Args:
575
+ level: int, the absl logging level at which to log.
576
+ msg: str, the message to be logged.
577
+ n: int, the maximal number of times the message is logged.
578
+ *args: The args to be substituted into the msg.
579
+ use_call_stack: bool, whether to include the call stack when counting the
580
+ number of times the message is logged.
581
+ """
582
+ caller_info = get_absl_logger().findCaller()
583
+ if use_call_stack:
584
+ # To reduce storage costs, we hash the call stack.
585
+ caller_info = (*caller_info[0:3], hash(_fast_stack_trace()))
586
+ count = _get_next_log_count_per_token(caller_info)
587
+ log_if(level, msg, count < n, *args)
588
+
589
+
590
+ def log_if(level, msg, condition, *args):
591
+ """Logs ``msg % args`` at level ``level`` only if condition is fulfilled."""
592
+ if condition:
593
+ log(level, msg, *args)
594
+
595
+
596
+ def log(level, msg, *args, **kwargs):
597
+ """Logs ``msg % args`` at absl logging level ``level``.
598
+
599
+ If no args are given just print msg, ignoring any interpolation specifiers.
600
+
601
+ Args:
602
+ level: int, the absl logging level at which to log the message
603
+ (logging.DEBUG|INFO|WARNING|ERROR|FATAL). While some C++ verbose logging
604
+ level constants are also supported, callers should prefer explicit
605
+ logging.vlog() calls for such purpose.
606
+
607
+ msg: str, the message to be logged.
608
+ *args: The args to be substituted into the msg.
609
+ **kwargs: May contain exc_info to add exception traceback to message.
610
+ """
611
+ if level > converter.ABSL_DEBUG:
612
+ # Even though this function supports level that is greater than 1, users
613
+ # should use logging.vlog instead for such cases.
614
+ # Treat this as vlog, 1 is equivalent to DEBUG.
615
+ standard_level = converter.STANDARD_DEBUG - (level - 1)
616
+ else:
617
+ if level < converter.ABSL_FATAL:
618
+ level = converter.ABSL_FATAL
619
+ standard_level = converter.absl_to_standard(level)
620
+
621
+ # Match standard logging's behavior. Before use_absl_handler() and
622
+ # logging is configured, there is no handler attached on _absl_logger nor
623
+ # logging.root. So logs go no where.
624
+ if not logging.root.handlers:
625
+ logging.basicConfig()
626
+
627
+ _absl_logger.log(standard_level, msg, *args, **kwargs)
628
+
629
+
630
+ def vlog(level, msg, *args, **kwargs):
631
+ """Log ``msg % args`` at C++ vlog level ``level``.
632
+
633
+ Args:
634
+ level: int, the C++ verbose logging level at which to log the message,
635
+ e.g. 1, 2, 3, 4... While absl level constants are also supported,
636
+ callers should prefer logging.log|debug|info|... calls for such purpose.
637
+ msg: str, the message to be logged.
638
+ *args: The args to be substituted into the msg.
639
+ **kwargs: May contain exc_info to add exception traceback to message.
640
+ """
641
+ log(level, msg, *args, **kwargs)
642
+
643
+
644
+ def vlog_is_on(level):
645
+ """Checks if vlog is enabled for the given level in caller's source file.
646
+
647
+ Args:
648
+ level: int, the C++ verbose logging level at which to log the message,
649
+ e.g. 1, 2, 3, 4... While absl level constants are also supported,
650
+ callers should prefer level_debug|level_info|... calls for
651
+ checking those.
652
+
653
+ Returns:
654
+ True if logging is turned on for that level.
655
+ """
656
+
657
+ if level > converter.ABSL_DEBUG:
658
+ # Even though this function supports level that is greater than 1, users
659
+ # should use logging.vlog instead for such cases.
660
+ # Treat this as vlog, 1 is equivalent to DEBUG.
661
+ standard_level = converter.STANDARD_DEBUG - (level - 1)
662
+ else:
663
+ if level < converter.ABSL_FATAL:
664
+ level = converter.ABSL_FATAL
665
+ standard_level = converter.absl_to_standard(level)
666
+ return _absl_logger.isEnabledFor(standard_level)
667
+
668
+
669
+ def flush():
670
+ """Flushes all log files."""
671
+ get_absl_handler().flush()
672
+
673
+
674
+ def level_debug():
675
+ """Returns True if debug logging is turned on."""
676
+ return get_verbosity() >= DEBUG
677
+
678
+
679
+ def level_info():
680
+ """Returns True if info logging is turned on."""
681
+ return get_verbosity() >= INFO
682
+
683
+
684
+ def level_warning():
685
+ """Returns True if warning logging is turned on."""
686
+ return get_verbosity() >= WARNING
687
+
688
+
689
+ level_warn = level_warning # Deprecated function.
690
+
691
+
692
+ def level_error():
693
+ """Returns True if error logging is turned on."""
694
+ return get_verbosity() >= ERROR
695
+
696
+
697
+ def get_log_file_name(level=INFO):
698
+ """Returns the name of the log file.
699
+
700
+ For Python logging, only one file is used and level is ignored. And it returns
701
+ empty string if it logs to stderr/stdout or the log stream has no `name`
702
+ attribute.
703
+
704
+ Args:
705
+ level: int, the absl.logging level.
706
+
707
+ Raises:
708
+ ValueError: Raised when `level` has an invalid value.
709
+ """
710
+ if level not in converter.ABSL_LEVELS:
711
+ raise ValueError(f'Invalid absl.logging level {level}')
712
+ stream = get_absl_handler().python_handler.stream
713
+ if (stream == sys.stderr or stream == sys.stdout or
714
+ not hasattr(stream, 'name')):
715
+ return ''
716
+ else:
717
+ return stream.name
718
+
719
+
720
+ def find_log_dir_and_names(program_name=None, log_dir=None):
721
+ """Computes the directory and filename prefix for log file.
722
+
723
+ Args:
724
+ program_name: str|None, the filename part of the path to the program that is
725
+ running without its extension. e.g: if your program is called
726
+ ``usr/bin/foobar.py`` this method should probably be called with
727
+ ``program_name='foobar`` However, this is just a convention, you can pass
728
+ in any string you want, and it will be used as part of the log filename.
729
+ If you don't pass in anything, the default behavior is as described in the
730
+ example. In python standard logging mode, the program_name will be
731
+ prepended with ``py_`` if it is the ``program_name`` argument is omitted.
732
+ log_dir: str|None, the desired log directory.
733
+
734
+ Returns:
735
+ (log_dir, file_prefix, symlink_prefix)
736
+
737
+ Raises:
738
+ FileNotFoundError: raised when it cannot find a log directory.
739
+ """
740
+ if not program_name:
741
+ # Strip the extension (foobar.par becomes foobar, and
742
+ # fubar.py becomes fubar). We do this so that the log
743
+ # file names are similar to C++ log file names.
744
+ program_name = os.path.splitext(os.path.basename(sys.argv[0]))[0]
745
+
746
+ # Prepend py_ to files so that python code gets a unique file, and
747
+ # so that C++ libraries do not try to write to the same log files as us.
748
+ program_name = 'py_%s' % program_name
749
+
750
+ actual_log_dir = find_log_dir(log_dir=log_dir)
751
+
752
+ try:
753
+ username = getpass.getuser()
754
+ except KeyError:
755
+ # This can happen, e.g. when running under docker w/o passwd file.
756
+ if hasattr(os, 'getuid'):
757
+ # Windows doesn't have os.getuid
758
+ username = str(os.getuid())
759
+ else:
760
+ username = 'unknown'
761
+ hostname = socket.gethostname()
762
+ file_prefix = '%s.%s.%s.log' % (program_name, hostname, username)
763
+
764
+ return actual_log_dir, file_prefix, program_name
765
+
766
+
767
+ def find_log_dir(log_dir=None):
768
+ """Returns the most suitable directory to put log files into.
769
+
770
+ Args:
771
+ log_dir: str|None, if specified, the logfile(s) will be created in that
772
+ directory. Otherwise if the --log_dir command-line flag is provided, the
773
+ logfile will be created in that directory. Otherwise the logfile will be
774
+ created in a standard location.
775
+
776
+ Raises:
777
+ FileNotFoundError: raised when it cannot find a log directory.
778
+ """
779
+ # Get a list of possible log dirs (will try to use them in order).
780
+ # NOTE: Google's internal implementation has a special handling for Google
781
+ # machines, which uses a list of directories. Hence the following uses `dirs`
782
+ # instead of a single directory.
783
+ if log_dir:
784
+ # log_dir was explicitly specified as an arg, so use it and it alone.
785
+ dirs = [log_dir]
786
+ elif FLAGS['log_dir'].value:
787
+ # log_dir flag was provided, so use it and it alone (this mimics the
788
+ # behavior of the same flag in logging.cc).
789
+ dirs = [FLAGS['log_dir'].value]
790
+ else:
791
+ dirs = [tempfile.gettempdir()]
792
+
793
+ # Find the first usable log dir.
794
+ for d in dirs:
795
+ if os.path.isdir(d) and os.access(d, os.W_OK):
796
+ return d
797
+ raise FileNotFoundError(
798
+ "Can't find a writable directory for logs, tried %s" % dirs)
799
+
800
+
801
+ def get_absl_log_prefix(record):
802
+ """Returns the absl log prefix for the log record.
803
+
804
+ Args:
805
+ record: logging.LogRecord, the record to get prefix for.
806
+ """
807
+ created_tuple = time.localtime(record.created)
808
+ created_microsecond = int(record.created % 1.0 * 1e6)
809
+
810
+ critical_prefix = ''
811
+ level = record.levelno
812
+ if _is_non_absl_fatal_record(record):
813
+ # When the level is FATAL, but not logged from absl, lower the level so
814
+ # it's treated as ERROR.
815
+ level = logging.ERROR
816
+ critical_prefix = _CRITICAL_PREFIX
817
+ severity = converter.get_initial_for_level(level)
818
+
819
+ return '%c%02d%02d %02d:%02d:%02d.%06d %5d %s:%d] %s' % (
820
+ severity,
821
+ created_tuple.tm_mon,
822
+ created_tuple.tm_mday,
823
+ created_tuple.tm_hour,
824
+ created_tuple.tm_min,
825
+ created_tuple.tm_sec,
826
+ created_microsecond,
827
+ _get_thread_id(),
828
+ record.filename,
829
+ record.lineno,
830
+ critical_prefix)
831
+
832
+
833
+ def skip_log_prefix(func):
834
+ """Skips reporting the prefix of a given function or name by :class:`~absl.logging.ABSLLogger`.
835
+
836
+ This is a convenience wrapper function / decorator for
837
+ :meth:`~absl.logging.ABSLLogger.register_frame_to_skip`.
838
+
839
+ If a callable function is provided, only that function will be skipped.
840
+ If a function name is provided, all functions with the same name in the
841
+ file that this is called in will be skipped.
842
+
843
+ This can be used as a decorator of the intended function to be skipped.
844
+
845
+ Args:
846
+ func: Callable function or its name as a string.
847
+
848
+ Returns:
849
+ func (the input, unchanged).
850
+
851
+ Raises:
852
+ ValueError: The input is callable but does not have a function code object.
853
+ TypeError: The input is neither callable nor a string.
854
+ """
855
+ if callable(func):
856
+ func_code = getattr(func, '__code__', None)
857
+ if func_code is None:
858
+ raise ValueError('Input callable does not have a function code object.')
859
+ file_name = func_code.co_filename
860
+ func_name = func_code.co_name
861
+ func_lineno = func_code.co_firstlineno
862
+ elif isinstance(func, str):
863
+ file_name = get_absl_logger().findCaller()[0]
864
+ func_name = func
865
+ func_lineno = None
866
+ else:
867
+ raise TypeError('Input is neither callable nor a string.')
868
+ ABSLLogger.register_frame_to_skip(file_name, func_name, func_lineno)
869
+ return func
870
+
871
+
872
+ def _is_non_absl_fatal_record(log_record):
873
+ return (log_record.levelno >= logging.FATAL and
874
+ not log_record.__dict__.get(_ABSL_LOG_FATAL, False))
875
+
876
+
877
+ def _is_absl_fatal_record(log_record):
878
+ return (log_record.levelno >= logging.FATAL and
879
+ log_record.__dict__.get(_ABSL_LOG_FATAL, False))
880
+
881
+
882
+ # Indicates if we still need to warn about pre-init logs going to stderr.
883
+ _warn_preinit_stderr = True
884
+
885
+
886
+ class PythonHandler(logging.StreamHandler):
887
+ """The handler class used by Abseil Python logging implementation."""
888
+
889
+ def __init__(self, stream=None, formatter=None):
890
+ super().__init__(stream)
891
+ self.setFormatter(formatter or PythonFormatter())
892
+
893
+ def start_logging_to_file(self, program_name=None, log_dir=None):
894
+ """Starts logging messages to files instead of standard error."""
895
+ FLAGS.logtostderr = False
896
+
897
+ actual_log_dir, file_prefix, symlink_prefix = find_log_dir_and_names(
898
+ program_name=program_name, log_dir=log_dir)
899
+
900
+ basename = '%s.INFO.%s.%d' % (
901
+ file_prefix,
902
+ time.strftime('%Y%m%d-%H%M%S', time.localtime(time.time())),
903
+ os.getpid())
904
+ filename = os.path.join(actual_log_dir, basename)
905
+
906
+ self.stream = open(filename, 'a', encoding='utf-8')
907
+
908
+ # os.symlink is not available on Windows Python 2.
909
+ if getattr(os, 'symlink', None):
910
+ # Create a symlink to the log file with a canonical name.
911
+ symlink = os.path.join(actual_log_dir, symlink_prefix + '.INFO')
912
+ try:
913
+ if os.path.islink(symlink):
914
+ os.unlink(symlink)
915
+ os.symlink(os.path.basename(filename), symlink)
916
+ except OSError:
917
+ # If it fails, we're sad but it's no error. Commonly, this
918
+ # fails because the symlink was created by another user and so
919
+ # we can't modify it
920
+ pass
921
+
922
+ def use_absl_log_file(self, program_name=None, log_dir=None):
923
+ """Conditionally logs to files, based on --logtostderr."""
924
+ if FLAGS['logtostderr'].value:
925
+ self.stream = sys.stderr
926
+ else:
927
+ self.start_logging_to_file(program_name=program_name, log_dir=log_dir)
928
+
929
+ def flush(self):
930
+ """Flushes all log files."""
931
+ self.acquire()
932
+ try:
933
+ if self.stream and hasattr(self.stream, 'flush'):
934
+ self.stream.flush()
935
+ except (OSError, ValueError):
936
+ # A ValueError is thrown if we try to flush a closed file.
937
+ pass
938
+ finally:
939
+ self.release()
940
+
941
+ def _log_to_stderr(self, record):
942
+ """Emits the record to stderr.
943
+
944
+ This temporarily sets the handler stream to stderr, calls
945
+ StreamHandler.emit, then reverts the stream back.
946
+
947
+ Args:
948
+ record: logging.LogRecord, the record to log.
949
+ """
950
+ # emit() is protected by a lock in logging.Handler, so we don't need to
951
+ # protect here again.
952
+ old_stream = self.stream
953
+ self.stream = sys.stderr
954
+ try:
955
+ super().emit(record)
956
+ finally:
957
+ self.stream = old_stream
958
+
959
+ def emit(self, record):
960
+ """Prints a record out to some streams.
961
+
962
+ 1. If ``FLAGS.logtostderr`` is set, it will print to ``sys.stderr`` ONLY.
963
+ 2. If ``FLAGS.alsologtostderr`` is set, it will print to ``sys.stderr``.
964
+ 3. If ``FLAGS.logtostderr`` is not set, it will log to the stream
965
+ associated with the current thread.
966
+
967
+ Args:
968
+ record: :class:`logging.LogRecord`, the record to emit.
969
+ """
970
+ # People occasionally call logging functions at import time before
971
+ # our flags may have even been defined yet, let alone even parsed, as we
972
+ # rely on the C++ side to define some flags for us and app init to
973
+ # deal with parsing. Match the C++ library behavior of notify and emit
974
+ # such messages to stderr. It encourages people to clean-up and does
975
+ # not hide the message.
976
+ level = record.levelno
977
+ if not FLAGS.is_parsed(): # Also implies "before flag has been defined".
978
+ global _warn_preinit_stderr
979
+ if _warn_preinit_stderr:
980
+ sys.stderr.write(
981
+ 'WARNING: Logging before flag parsing goes to stderr.\n')
982
+ _warn_preinit_stderr = False
983
+ self._log_to_stderr(record)
984
+ elif FLAGS['logtostderr'].value:
985
+ self._log_to_stderr(record)
986
+ else:
987
+ super().emit(record)
988
+ stderr_threshold = converter.string_to_standard(
989
+ FLAGS['stderrthreshold'].value)
990
+ if ((FLAGS['alsologtostderr'].value or level >= stderr_threshold) and
991
+ self.stream != sys.stderr):
992
+ self._log_to_stderr(record)
993
+ # Die when the record is created from ABSLLogger and level is FATAL.
994
+ if _is_absl_fatal_record(record):
995
+ self.flush() # Flush the log before dying.
996
+
997
+ # In threaded python, sys.exit() from a non-main thread only
998
+ # exits the thread in question.
999
+ os.abort()
1000
+
1001
+ def close(self):
1002
+ """Closes the stream to which we are writing."""
1003
+ self.acquire()
1004
+ try:
1005
+ self.flush()
1006
+ try:
1007
+ # Do not close the stream if it's sys.stderr|stdout. They may be
1008
+ # redirected or overridden to files, which should be managed by users
1009
+ # explicitly.
1010
+ user_managed = sys.stderr, sys.stdout, sys.__stderr__, sys.__stdout__
1011
+ if self.stream not in user_managed and (
1012
+ not hasattr(self.stream, 'isatty') or not self.stream.isatty()):
1013
+ self.stream.close()
1014
+ except ValueError:
1015
+ # A ValueError is thrown if we try to run isatty() on a closed file.
1016
+ pass
1017
+ super().close()
1018
+ finally:
1019
+ self.release()
1020
+
1021
+
1022
+ class ABSLHandler(logging.Handler):
1023
+ """Abseil Python logging module's log handler."""
1024
+
1025
+ def __init__(self, python_logging_formatter):
1026
+ super().__init__()
1027
+
1028
+ self._python_handler = PythonHandler(formatter=python_logging_formatter)
1029
+ self.activate_python_handler()
1030
+
1031
+ def format(self, record):
1032
+ return self._current_handler.format(record)
1033
+
1034
+ def setFormatter(self, fmt):
1035
+ self._current_handler.setFormatter(fmt)
1036
+
1037
+ def emit(self, record):
1038
+ self._current_handler.emit(record)
1039
+
1040
+ def flush(self):
1041
+ self._current_handler.flush()
1042
+
1043
+ def close(self):
1044
+ super().close()
1045
+ self._current_handler.close()
1046
+
1047
+ def handle(self, record):
1048
+ rv = self.filter(record)
1049
+ if rv:
1050
+ return self._current_handler.handle(record)
1051
+ return rv
1052
+
1053
+ @property
1054
+ def python_handler(self):
1055
+ return self._python_handler
1056
+
1057
+ def activate_python_handler(self):
1058
+ """Uses the Python logging handler as the current logging handler."""
1059
+ self._current_handler = self._python_handler
1060
+
1061
+ def use_absl_log_file(self, program_name=None, log_dir=None):
1062
+ self._current_handler.use_absl_log_file(program_name, log_dir)
1063
+
1064
+ def start_logging_to_file(self, program_name=None, log_dir=None):
1065
+ self._current_handler.start_logging_to_file(program_name, log_dir)
1066
+
1067
+
1068
+ class PythonFormatter(logging.Formatter):
1069
+ """Formatter class used by :class:`~absl.logging.PythonHandler`."""
1070
+
1071
+ def format(self, record):
1072
+ """Appends the message from the record to the results of the prefix.
1073
+
1074
+ Args:
1075
+ record: logging.LogRecord, the record to be formatted.
1076
+
1077
+ Returns:
1078
+ The formatted string representing the record.
1079
+ """
1080
+ if (not FLAGS['showprefixforinfo'].value and
1081
+ FLAGS['verbosity'].value == converter.ABSL_INFO and
1082
+ record.levelno == logging.INFO and
1083
+ _absl_handler.python_handler.stream == sys.stderr):
1084
+ prefix = ''
1085
+ else:
1086
+ prefix = get_absl_log_prefix(record)
1087
+ return prefix + super().format(record)
1088
+
1089
+
1090
+ class ABSLLogger(logging.getLoggerClass()):
1091
+ """A logger that will create LogRecords while skipping some stack frames.
1092
+
1093
+ This class maintains an internal list of filenames and method names
1094
+ for use when determining who called the currently executing stack
1095
+ frame. Any method names from specific source files are skipped when
1096
+ walking backwards through the stack.
1097
+
1098
+ Client code should use the register_frame_to_skip method to let the
1099
+ ABSLLogger know which method from which file should be
1100
+ excluded from the walk backwards through the stack.
1101
+ """
1102
+ _frames_to_skip = set()
1103
+
1104
+ def findCaller(self, stack_info=False, stacklevel=1):
1105
+ """Finds the frame of the calling method on the stack.
1106
+
1107
+ This method skips any frames registered with the
1108
+ ABSLLogger and any methods from this file, and whatever
1109
+ method is currently being used to generate the prefix for the log
1110
+ line. Then it returns the file name, line number, and method name
1111
+ of the calling method. An optional fourth item may be returned,
1112
+ callers who only need things from the first three are advised to
1113
+ always slice or index the result rather than using direct unpacking
1114
+ assignment.
1115
+
1116
+ Args:
1117
+ stack_info: bool, when True, include the stack trace as a fourth item
1118
+ returned. On Python 3 there are always four items returned - the fourth
1119
+ will be None when this is False. On Python 2 the stdlib base class API
1120
+ only returns three items. We do the same when this new parameter is
1121
+ unspecified or False for compatibility.
1122
+ stacklevel: int, if greater than 1, that number of frames will be skipped.
1123
+
1124
+ Returns:
1125
+ (filename, lineno, methodname[, sinfo]) of the calling method.
1126
+ """
1127
+ f_to_skip = ABSLLogger._frames_to_skip
1128
+ # Use sys._getframe(2) instead of logging.currentframe(), it's slightly
1129
+ # faster because there is one less frame to traverse.
1130
+ frame = sys._getframe(2) # pylint: disable=protected-access
1131
+ frame_to_return = None
1132
+
1133
+ while frame:
1134
+ code = frame.f_code
1135
+ if (_LOGGING_FILE_PREFIX not in code.co_filename and
1136
+ (code.co_filename, code.co_name,
1137
+ code.co_firstlineno) not in f_to_skip and
1138
+ (code.co_filename, code.co_name) not in f_to_skip):
1139
+ frame_to_return = frame
1140
+ stacklevel -= 1
1141
+ if stacklevel <= 0:
1142
+ break
1143
+ frame = frame.f_back
1144
+
1145
+ if frame_to_return is not None:
1146
+ sinfo = None
1147
+ if stack_info:
1148
+ out = io.StringIO()
1149
+ out.write('Stack (most recent call last):\n')
1150
+ traceback.print_stack(frame, file=out)
1151
+ sinfo = out.getvalue().rstrip('\n')
1152
+ return (
1153
+ frame_to_return.f_code.co_filename,
1154
+ frame_to_return.f_lineno,
1155
+ frame_to_return.f_code.co_name,
1156
+ sinfo,
1157
+ )
1158
+
1159
+ return None
1160
+
1161
+ def critical(self, msg, *args, **kwargs):
1162
+ """Logs ``msg % args`` with severity ``CRITICAL``."""
1163
+ self.log(logging.CRITICAL, msg, *args, **kwargs)
1164
+
1165
+ def fatal(self, msg, *args, **kwargs):
1166
+ """Logs ``msg % args`` with severity ``FATAL``."""
1167
+ self.log(logging.FATAL, msg, *args, **kwargs)
1168
+
1169
+ def error(self, msg, *args, **kwargs):
1170
+ """Logs ``msg % args`` with severity ``ERROR``."""
1171
+ self.log(logging.ERROR, msg, *args, **kwargs)
1172
+
1173
+ def warn(self, msg, *args, **kwargs):
1174
+ """Logs ``msg % args`` with severity ``WARN``."""
1175
+ warnings.warn("The 'warn' method is deprecated, use 'warning' instead",
1176
+ DeprecationWarning, 2)
1177
+ self.log(logging.WARN, msg, *args, **kwargs)
1178
+
1179
+ def warning(self, msg, *args, **kwargs):
1180
+ """Logs ``msg % args`` with severity ``WARNING``."""
1181
+ self.log(logging.WARNING, msg, *args, **kwargs)
1182
+
1183
+ def info(self, msg, *args, **kwargs):
1184
+ """Logs ``msg % args`` with severity ``INFO``."""
1185
+ self.log(logging.INFO, msg, *args, **kwargs)
1186
+
1187
+ def debug(self, msg, *args, **kwargs):
1188
+ """Logs ``msg % args`` with severity ``DEBUG``."""
1189
+ self.log(logging.DEBUG, msg, *args, **kwargs)
1190
+
1191
+ def log(self, level, msg, *args, **kwargs):
1192
+ """Logs a message at a cetain level substituting in the supplied arguments.
1193
+
1194
+ This method behaves differently in python and c++ modes.
1195
+
1196
+ Args:
1197
+ level: int, the standard logging level at which to log the message.
1198
+ msg: str, the text of the message to log.
1199
+ *args: The arguments to substitute in the message.
1200
+ **kwargs: The keyword arguments to substitute in the message.
1201
+ """
1202
+ if level >= logging.FATAL:
1203
+ # Add property to the LogRecord created by this logger.
1204
+ # This will be used by the ABSLHandler to determine whether it should
1205
+ # treat CRITICAL/FATAL logs as really FATAL.
1206
+ extra = kwargs.setdefault('extra', {})
1207
+ extra[_ABSL_LOG_FATAL] = True
1208
+ super().log(level, msg, *args, **kwargs)
1209
+
1210
+ def handle(self, record):
1211
+ """Calls handlers without checking ``Logger.disabled``.
1212
+
1213
+ Non-root loggers are set to disabled after setup with :func:`logging.config`
1214
+ if it's not explicitly specified. Historically, absl logging will not be
1215
+ disabled by that. To maintaining this behavior, this function skips
1216
+ checking the ``Logger.disabled`` bit.
1217
+
1218
+ This logger can still be disabled by adding a filter that filters out
1219
+ everything.
1220
+
1221
+ Args:
1222
+ record: logging.LogRecord, the record to handle.
1223
+ """
1224
+ if self.filter(record):
1225
+ self.callHandlers(record)
1226
+
1227
+ @classmethod
1228
+ def register_frame_to_skip(cls, file_name, function_name, line_number=None):
1229
+ """Registers a function name to skip when walking the stack.
1230
+
1231
+ The :class:`~absl.logging.ABSLLogger` sometimes skips method calls on the
1232
+ stack to make the log messages meaningful in their appropriate context.
1233
+ This method registers a function from a particular file as one
1234
+ which should be skipped.
1235
+
1236
+ Args:
1237
+ file_name: str, the name of the file that contains the function.
1238
+ function_name: str, the name of the function to skip.
1239
+ line_number: int, if provided, only the function with this starting line
1240
+ number will be skipped. Otherwise, all functions with the same name
1241
+ in the file will be skipped.
1242
+ """
1243
+ if line_number is not None:
1244
+ cls._frames_to_skip.add((file_name, function_name, line_number))
1245
+ else:
1246
+ cls._frames_to_skip.add((file_name, function_name))
1247
+
1248
+
1249
+ def _get_thread_id():
1250
+ """Gets id of current thread, suitable for logging as an unsigned quantity.
1251
+
1252
+ If pywrapbase is linked, returns GetTID() for the thread ID to be
1253
+ consistent with C++ logging. Otherwise, returns the numeric thread id.
1254
+ The quantities are made unsigned by masking with 2*sys.maxint + 1.
1255
+
1256
+ Returns:
1257
+ Thread ID unique to this process (unsigned)
1258
+ """
1259
+ thread_id = threading.get_ident()
1260
+ return thread_id & _THREAD_ID_MASK
1261
+
1262
+
1263
+ def get_absl_logger():
1264
+ """Returns the absl logger instance."""
1265
+ assert _absl_logger is not None
1266
+ return _absl_logger
1267
+
1268
+
1269
+ def get_absl_handler():
1270
+ """Returns the absl handler instance."""
1271
+ assert _absl_handler is not None
1272
+ return _absl_handler
1273
+
1274
+
1275
+ def use_python_logging(quiet=False):
1276
+ """Uses the python implementation of the logging code.
1277
+
1278
+ Args:
1279
+ quiet: No logging message about switching logging type.
1280
+ """
1281
+ get_absl_handler().activate_python_handler()
1282
+ if not quiet:
1283
+ info('Restoring pure python logging')
1284
+
1285
+
1286
+ _attempted_to_remove_stderr_stream_handlers = False
1287
+
1288
+
1289
+ def use_absl_handler():
1290
+ """Uses the ABSL logging handler for logging.
1291
+
1292
+ This method is called in :func:`app.run()<absl.app.run>` so the absl handler
1293
+ is used in absl apps.
1294
+ """
1295
+ global _attempted_to_remove_stderr_stream_handlers
1296
+ if not _attempted_to_remove_stderr_stream_handlers:
1297
+ # The absl handler logs to stderr by default. To prevent double logging to
1298
+ # stderr, the following code tries its best to remove other handlers that
1299
+ # emit to stderr. Those handlers are most commonly added when
1300
+ # logging.info/debug is called before calling use_absl_handler().
1301
+ handlers = [
1302
+ h for h in logging.root.handlers
1303
+ if isinstance(h, logging.StreamHandler) and h.stream == sys.stderr]
1304
+ for h in handlers:
1305
+ logging.root.removeHandler(h)
1306
+ _attempted_to_remove_stderr_stream_handlers = True
1307
+
1308
+ absl_handler = get_absl_handler()
1309
+ if absl_handler not in logging.root.handlers:
1310
+ logging.root.addHandler(absl_handler)
1311
+ FLAGS['verbosity']._update_logging_levels() # pylint: disable=protected-access
1312
+ FLAGS['logger_levels']._update_logger_levels() # pylint: disable=protected-access
1313
+
1314
+
1315
+ def _initialize():
1316
+ """Initializes loggers and handlers."""
1317
+ global _absl_logger, _absl_handler
1318
+
1319
+ if _absl_logger:
1320
+ return
1321
+
1322
+ original_logger_class = logging.getLoggerClass()
1323
+ logging.setLoggerClass(ABSLLogger)
1324
+ _absl_logger = logging.getLogger('absl')
1325
+ logging.setLoggerClass(original_logger_class)
1326
+
1327
+ python_logging_formatter = PythonFormatter()
1328
+ _absl_handler = ABSLHandler(python_logging_formatter)
1329
+
1330
+
1331
+ _initialize()
lib/python3.10/site-packages/absl/logging/__init__.pyi ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import logging
16
+ from typing import Any, Callable, Dict, IO, NoReturn, Optional, Tuple, TypeVar, Union
17
+
18
+ from absl import flags
19
+
20
+ # Logging levels.
21
+ FATAL: int
22
+ ERROR: int
23
+ WARNING: int
24
+ WARN: int # Deprecated name.
25
+ INFO: int
26
+ DEBUG: int
27
+
28
+ ABSL_LOGGING_PREFIX_REGEX: str
29
+
30
+ LOGTOSTDERR: flags.FlagHolder[bool]
31
+ ALSOLOGTOSTDERR: flags.FlagHolder[bool]
32
+ LOG_DIR: flags.FlagHolder[str]
33
+ VERBOSITY: flags.FlagHolder[int]
34
+ LOGGER_LEVELS: flags.FlagHolder[Dict[str, str]]
35
+ STDERRTHRESHOLD: flags.FlagHolder[str]
36
+ SHOWPREFIXFORINFO: flags.FlagHolder[bool]
37
+
38
+ def get_verbosity() -> int:
39
+ ...
40
+
41
+ def set_verbosity(v: Union[int, str]) -> None:
42
+ ...
43
+
44
+ def set_stderrthreshold(s: Union[int, str]) -> None:
45
+ ...
46
+
47
+ # TODO(b/277607978): Provide actual args+kwargs shadowing stdlib's logging functions.
48
+ def fatal(msg: Any, *args: Any, **kwargs: Any) -> NoReturn:
49
+ ...
50
+
51
+ def error(msg: Any, *args: Any, **kwargs: Any) -> None:
52
+ ...
53
+
54
+ def warning(msg: Any, *args: Any, **kwargs: Any) -> None:
55
+ ...
56
+
57
+ def warn(msg: Any, *args: Any, **kwargs: Any) -> None:
58
+ ...
59
+
60
+ def info(msg: Any, *args: Any, **kwargs: Any) -> None:
61
+ ...
62
+
63
+ def debug(msg: Any, *args: Any, **kwargs: Any) -> None:
64
+ ...
65
+
66
+ def exception(msg: Any, *args: Any, **kwargs: Any) -> None:
67
+ ...
68
+
69
+ def log_every_n(
70
+ level: int, msg: Any, n: int, *args: Any, use_call_stack: bool = ...
71
+ ) -> None:
72
+ ...
73
+
74
+ def log_every_n_seconds(
75
+ level: int,
76
+ msg: Any,
77
+ n_seconds: float,
78
+ *args: Any,
79
+ use_call_stack: bool = ...
80
+ ) -> None:
81
+ ...
82
+
83
+ def log_first_n(
84
+ level: int, msg: Any, n: int, *args: Any, use_call_stack: bool = ...
85
+ ) -> None:
86
+ ...
87
+
88
+ def log_if(level: int, msg: Any, condition: Any, *args: Any) -> None:
89
+ ...
90
+
91
+ def log(level: int, msg: Any, *args: Any, **kwargs: Any) -> None:
92
+ ...
93
+
94
+ def vlog(level: int, msg: Any, *args: Any, **kwargs: Any) -> None:
95
+ ...
96
+
97
+ def vlog_is_on(level: int) -> bool:
98
+ ...
99
+
100
+ def flush() -> None:
101
+ ...
102
+
103
+ def level_debug() -> bool:
104
+ ...
105
+
106
+ def level_info() -> bool:
107
+ ...
108
+
109
+ def level_warning() -> bool:
110
+ ...
111
+
112
+ level_warn = level_warning # Deprecated function.
113
+
114
+ def level_error() -> bool:
115
+ ...
116
+
117
+ def get_log_file_name(level: int = ...) -> str:
118
+ ...
119
+
120
+ def find_log_dir_and_names(
121
+ program_name: Optional[str] = ..., log_dir: Optional[str] = ...
122
+ ) -> Tuple[str, str, str]:
123
+ ...
124
+
125
+ def find_log_dir(log_dir: Optional[str] = ...) -> str:
126
+ ...
127
+
128
+ def get_absl_log_prefix(record: logging.LogRecord) -> str:
129
+ ...
130
+
131
+ _SkipLogT = TypeVar('_SkipLogT', str, Callable[..., Any])
132
+
133
+ def skip_log_prefix(func: _SkipLogT) -> _SkipLogT:
134
+ ...
135
+
136
+ _StreamT = TypeVar('_StreamT')
137
+
138
+ class PythonHandler(logging.StreamHandler[_StreamT]): # type: ignore[type-var]
139
+
140
+ def __init__(
141
+ self,
142
+ stream: Optional[_StreamT] = ...,
143
+ formatter: Optional[logging.Formatter] = ...,
144
+ ) -> None:
145
+ ...
146
+
147
+ def start_logging_to_file(
148
+ self, program_name: Optional[str] = ..., log_dir: Optional[str] = ...
149
+ ) -> None:
150
+ ...
151
+
152
+ def use_absl_log_file(
153
+ self, program_name: Optional[str] = ..., log_dir: Optional[str] = ...
154
+ ) -> None:
155
+ ...
156
+
157
+ def flush(self) -> None:
158
+ ...
159
+
160
+ def emit(self, record: logging.LogRecord) -> None:
161
+ ...
162
+
163
+ def close(self) -> None:
164
+ ...
165
+
166
+ class ABSLHandler(logging.Handler):
167
+
168
+ def __init__(self, python_logging_formatter: PythonFormatter) -> None:
169
+ ...
170
+
171
+ def format(self, record: logging.LogRecord) -> str:
172
+ ...
173
+
174
+ def setFormatter(self, fmt) -> None:
175
+ ...
176
+
177
+ def emit(self, record: logging.LogRecord) -> None:
178
+ ...
179
+
180
+ def flush(self) -> None:
181
+ ...
182
+
183
+ def close(self) -> None:
184
+ ...
185
+
186
+ def handle(self, record: logging.LogRecord) -> bool:
187
+ ...
188
+
189
+ @property
190
+ def python_handler(self) -> PythonHandler:
191
+ ...
192
+
193
+ def activate_python_handler(self) -> None:
194
+ ...
195
+
196
+ def use_absl_log_file(
197
+ self, program_name: Optional[str] = ..., log_dir: Optional[str] = ...
198
+ ) -> None:
199
+ ...
200
+
201
+ def start_logging_to_file(self, program_name=None, log_dir=None) -> None:
202
+ ...
203
+
204
+ class PythonFormatter(logging.Formatter):
205
+
206
+ def format(self, record: logging.LogRecord) -> str:
207
+ ...
208
+
209
+ class ABSLLogger(logging.Logger):
210
+
211
+ def findCaller(
212
+ self, stack_info: bool = ..., stacklevel: int = ...
213
+ ) -> Tuple[str, int, str, Optional[str]]:
214
+ ...
215
+
216
+ def critical(self, msg: Any, *args: Any, **kwargs: Any) -> None:
217
+ ...
218
+
219
+ def fatal(self, msg: Any, *args: Any, **kwargs: Any) -> NoReturn: # type: ignore[override]
220
+ ...
221
+
222
+ def error(self, msg: Any, *args: Any, **kwargs: Any) -> None:
223
+ ...
224
+
225
+ def warn(self, msg: Any, *args: Any, **kwargs: Any) -> None:
226
+ ...
227
+
228
+ def warning(self, msg: Any, *args: Any, **kwargs: Any) -> None:
229
+ ...
230
+
231
+ def info(self, msg: Any, *args: Any, **kwargs: Any) -> None:
232
+ ...
233
+
234
+ def debug(self, msg: Any, *args: Any, **kwargs: Any) -> None:
235
+ ...
236
+
237
+ def log(self, level: int, msg: Any, *args: Any, **kwargs: Any) -> None:
238
+ ...
239
+
240
+ def handle(self, record: logging.LogRecord) -> None:
241
+ ...
242
+
243
+ @classmethod
244
+ def register_frame_to_skip(
245
+ cls, file_name: str, function_name: str, line_number: Optional[int] = ...
246
+ ) -> None:
247
+ ...
248
+
249
+ # NOTE: Returns None before _initialize called but shouldn't occur after import.
250
+ def get_absl_logger() -> ABSLLogger:
251
+ ...
252
+
253
+ # NOTE: Returns None before _initialize called but shouldn't occur after import.
254
+ def get_absl_handler() -> ABSLHandler:
255
+ ...
256
+
257
+ def use_python_logging(quiet: bool = ...) -> None:
258
+ ...
259
+
260
+ def use_absl_handler() -> None:
261
+ ...
lib/python3.10/site-packages/absl/logging/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (38.9 kB). View file
 
lib/python3.10/site-packages/absl/logging/__pycache__/converter.cpython-310.pyc ADDED
Binary file (5.26 kB). View file
 
lib/python3.10/site-packages/absl/logging/converter.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Module to convert log levels between Abseil Python, C++, and Python standard.
16
+
17
+ This converter has to convert (best effort) between three different
18
+ logging level schemes:
19
+
20
+ * **cpp**: The C++ logging level scheme used in Abseil C++.
21
+ * **absl**: The absl.logging level scheme used in Abseil Python.
22
+ * **standard**: The python standard library logging level scheme.
23
+
24
+ Here is a handy ascii chart for easy mental mapping::
25
+
26
+ LEVEL | cpp | absl | standard |
27
+ ---------+-----+--------+----------+
28
+ DEBUG | 0 | 1 | 10 |
29
+ INFO | 0 | 0 | 20 |
30
+ WARNING | 1 | -1 | 30 |
31
+ ERROR | 2 | -2 | 40 |
32
+ CRITICAL | 3 | -3 | 50 |
33
+ FATAL | 3 | -3 | 50 |
34
+
35
+ Note: standard logging ``CRITICAL`` is mapped to absl/cpp ``FATAL``.
36
+ However, only ``CRITICAL`` logs from the absl logger (or absl.logging.fatal)
37
+ will terminate the program. ``CRITICAL`` logs from non-absl loggers are treated
38
+ as error logs with a message prefix ``"CRITICAL - "``.
39
+
40
+ Converting from standard to absl or cpp is a lossy conversion.
41
+ Converting back to standard will lose granularity. For this reason,
42
+ users should always try to convert to standard, the richest
43
+ representation, before manipulating the levels, and then only to cpp
44
+ or absl if those level schemes are absolutely necessary.
45
+ """
46
+
47
+ import logging
48
+
49
+ STANDARD_CRITICAL = logging.CRITICAL
50
+ STANDARD_ERROR = logging.ERROR
51
+ STANDARD_WARNING = logging.WARNING
52
+ STANDARD_INFO = logging.INFO
53
+ STANDARD_DEBUG = logging.DEBUG
54
+
55
+ # These levels are also used to define the constants
56
+ # FATAL, ERROR, WARNING, INFO, and DEBUG in the
57
+ # absl.logging module.
58
+ ABSL_FATAL = -3
59
+ ABSL_ERROR = -2
60
+ ABSL_WARNING = -1
61
+ ABSL_WARN = -1 # Deprecated name.
62
+ ABSL_INFO = 0
63
+ ABSL_DEBUG = 1
64
+
65
+ ABSL_LEVELS = {ABSL_FATAL: 'FATAL',
66
+ ABSL_ERROR: 'ERROR',
67
+ ABSL_WARNING: 'WARNING',
68
+ ABSL_INFO: 'INFO',
69
+ ABSL_DEBUG: 'DEBUG'}
70
+
71
+ # Inverts the ABSL_LEVELS dictionary
72
+ ABSL_NAMES = {'FATAL': ABSL_FATAL,
73
+ 'ERROR': ABSL_ERROR,
74
+ 'WARNING': ABSL_WARNING,
75
+ 'WARN': ABSL_WARNING, # Deprecated name.
76
+ 'INFO': ABSL_INFO,
77
+ 'DEBUG': ABSL_DEBUG}
78
+
79
+ ABSL_TO_STANDARD = {ABSL_FATAL: STANDARD_CRITICAL,
80
+ ABSL_ERROR: STANDARD_ERROR,
81
+ ABSL_WARNING: STANDARD_WARNING,
82
+ ABSL_INFO: STANDARD_INFO,
83
+ ABSL_DEBUG: STANDARD_DEBUG}
84
+
85
+ # Inverts the ABSL_TO_STANDARD
86
+ STANDARD_TO_ABSL = {v: k for (k, v) in ABSL_TO_STANDARD.items()}
87
+
88
+
89
+ def get_initial_for_level(level):
90
+ """Gets the initial that should start the log line for the given level.
91
+
92
+ It returns:
93
+
94
+ * ``'I'`` when: ``level < STANDARD_WARNING``.
95
+ * ``'W'`` when: ``STANDARD_WARNING <= level < STANDARD_ERROR``.
96
+ * ``'E'`` when: ``STANDARD_ERROR <= level < STANDARD_CRITICAL``.
97
+ * ``'F'`` when: ``level >= STANDARD_CRITICAL``.
98
+
99
+ Args:
100
+ level: int, a Python standard logging level.
101
+
102
+ Returns:
103
+ The first initial as it would be logged by the C++ logging module.
104
+ """
105
+ if level < STANDARD_WARNING:
106
+ return 'I'
107
+ elif level < STANDARD_ERROR:
108
+ return 'W'
109
+ elif level < STANDARD_CRITICAL:
110
+ return 'E'
111
+ else:
112
+ return 'F'
113
+
114
+
115
+ def absl_to_cpp(level):
116
+ """Converts an absl log level to a cpp log level.
117
+
118
+ Args:
119
+ level: int, an absl.logging level.
120
+
121
+ Raises:
122
+ TypeError: Raised when level is not an integer.
123
+
124
+ Returns:
125
+ The corresponding integer level for use in Abseil C++.
126
+ """
127
+ if not isinstance(level, int):
128
+ raise TypeError(f'Expect an int level, found {type(level)}')
129
+ if level >= 0:
130
+ # C++ log levels must be >= 0
131
+ return 0
132
+ else:
133
+ return -level
134
+
135
+
136
+ def absl_to_standard(level):
137
+ """Converts an integer level from the absl value to the standard value.
138
+
139
+ Args:
140
+ level: int, an absl.logging level.
141
+
142
+ Raises:
143
+ TypeError: Raised when level is not an integer.
144
+
145
+ Returns:
146
+ The corresponding integer level for use in standard logging.
147
+ """
148
+ if not isinstance(level, int):
149
+ raise TypeError(f'Expect an int level, found {type(level)}')
150
+ if level < ABSL_FATAL:
151
+ level = ABSL_FATAL
152
+ if level <= ABSL_DEBUG:
153
+ return ABSL_TO_STANDARD[level]
154
+ # Maps to vlog levels.
155
+ return STANDARD_DEBUG - level + 1
156
+
157
+
158
+ def string_to_standard(level):
159
+ """Converts a string level to standard logging level value.
160
+
161
+ Args:
162
+ level: str, case-insensitive ``'debug'``, ``'info'``, ``'warning'``,
163
+ ``'error'``, ``'fatal'``.
164
+
165
+ Returns:
166
+ The corresponding integer level for use in standard logging.
167
+ """
168
+ return absl_to_standard(ABSL_NAMES.get(level.upper()))
169
+
170
+
171
+ def standard_to_absl(level):
172
+ """Converts an integer level from the standard value to the absl value.
173
+
174
+ Args:
175
+ level: int, a Python standard logging level.
176
+
177
+ Raises:
178
+ TypeError: Raised when level is not an integer.
179
+
180
+ Returns:
181
+ The corresponding integer level for use in absl logging.
182
+ """
183
+ if not isinstance(level, int):
184
+ raise TypeError(f'Expect an int level, found {type(level)}')
185
+ if level < 0:
186
+ level = 0
187
+ if level < STANDARD_DEBUG:
188
+ # Maps to vlog levels.
189
+ return STANDARD_DEBUG - level + 1
190
+ elif level < STANDARD_INFO:
191
+ return ABSL_DEBUG
192
+ elif level < STANDARD_WARNING:
193
+ return ABSL_INFO
194
+ elif level < STANDARD_ERROR:
195
+ return ABSL_WARNING
196
+ elif level < STANDARD_CRITICAL:
197
+ return ABSL_ERROR
198
+ else:
199
+ return ABSL_FATAL
200
+
201
+
202
+ def standard_to_cpp(level):
203
+ """Converts an integer level from the standard value to the cpp value.
204
+
205
+ Args:
206
+ level: int, a Python standard logging level.
207
+
208
+ Raises:
209
+ TypeError: Raised when level is not an integer.
210
+
211
+ Returns:
212
+ The corresponding integer level for use in cpp logging.
213
+ """
214
+ return absl_to_cpp(standard_to_absl(level))
lib/python3.10/site-packages/absl/py.typed ADDED
File without changes
lib/python3.10/site-packages/absl/testing/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
lib/python3.10/site-packages/absl/testing/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (203 Bytes). View file
 
lib/python3.10/site-packages/absl/testing/__pycache__/_bazelize_command.cpython-310.pyc ADDED
Binary file (1.66 kB). View file
 
lib/python3.10/site-packages/absl/testing/__pycache__/_pretty_print_reporter.cpython-310.pyc ADDED
Binary file (3.14 kB). View file
 
lib/python3.10/site-packages/absl/testing/__pycache__/absltest.cpython-310.pyc ADDED
Binary file (87.3 kB). View file
 
lib/python3.10/site-packages/absl/testing/__pycache__/flagsaver.cpython-310.pyc ADDED
Binary file (12.7 kB). View file
 
lib/python3.10/site-packages/absl/testing/__pycache__/parameterized.cpython-310.pyc ADDED
Binary file (23.6 kB). View file
 
lib/python3.10/site-packages/absl/testing/__pycache__/xml_reporter.cpython-310.pyc ADDED
Binary file (18.6 kB). View file
 
lib/python3.10/site-packages/absl/testing/_bazelize_command.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Internal helper for running tests on Windows Bazel."""
16
+
17
+ import os
18
+
19
+ from absl import flags
20
+
21
+ FLAGS = flags.FLAGS
22
+
23
+
24
+ def get_executable_path(py_binary_name):
25
+ """Returns the executable path of a py_binary.
26
+
27
+ This returns the executable path of a py_binary that is in another Bazel
28
+ target's data dependencies.
29
+
30
+ On Linux/macOS, the path and __file__ has the same root directory.
31
+ On Windows, bazel builds an .exe file and we need to use the MANIFEST file
32
+ the location the actual binary.
33
+
34
+ Args:
35
+ py_binary_name: string, the name of a py_binary that is in another Bazel
36
+ target's data dependencies.
37
+
38
+ Raises:
39
+ RuntimeError: Raised when it cannot locate the executable path.
40
+ """
41
+
42
+ if os.name == 'nt':
43
+ py_binary_name += '.exe'
44
+ manifest_file = os.path.join(FLAGS.test_srcdir, 'MANIFEST')
45
+ workspace_name = os.environ['TEST_WORKSPACE']
46
+ manifest_entry = f'{workspace_name}/{py_binary_name}'
47
+ with open(manifest_file) as manifest_fd:
48
+ for line in manifest_fd:
49
+ tokens = line.strip().split(' ')
50
+ if len(tokens) != 2:
51
+ continue
52
+ if manifest_entry == tokens[0]:
53
+ return tokens[1]
54
+ raise RuntimeError(
55
+ 'Cannot locate executable path for {}, MANIFEST file: {}.'.format(
56
+ py_binary_name, manifest_file))
57
+ else:
58
+ # NOTE: __file__ may be .py or .pyc, depending on how the module was
59
+ # loaded and executed.
60
+ path = __file__
61
+
62
+ # Use the package name to find the root directory: every dot is
63
+ # a directory, plus one for ourselves.
64
+ for _ in range(__name__.count('.') + 1):
65
+ path = os.path.dirname(path)
66
+
67
+ root_directory = path
68
+ return os.path.join(root_directory, py_binary_name)
lib/python3.10/site-packages/absl/testing/_pretty_print_reporter.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2018 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """TestResult implementing default output for test execution status."""
16
+
17
+ import unittest
18
+
19
+
20
+ class TextTestResult(unittest.TextTestResult):
21
+ """TestResult class that provides the default text result formatting."""
22
+
23
+ def __init__(self, stream, descriptions, verbosity):
24
+ # Disable the verbose per-test output from the superclass, since it would
25
+ # conflict with our customized output.
26
+ super().__init__(stream, descriptions, 0)
27
+ self._per_test_output = verbosity > 0
28
+
29
+ def _print_status(self, tag, test, reason=None):
30
+ if self._per_test_output:
31
+ test_id = test.id()
32
+ if test_id.startswith('__main__.'):
33
+ test_id = test_id[len('__main__.'):]
34
+ if reason:
35
+ print('[%s] %s - %s' % (tag, test_id, reason), file=self.stream)
36
+ else:
37
+ print('[%s] %s' % (tag, test_id), file=self.stream)
38
+ self.stream.flush()
39
+
40
+ def startTest(self, test):
41
+ super().startTest(test)
42
+ self._print_status(' RUN ', test)
43
+
44
+ def addSuccess(self, test):
45
+ super().addSuccess(test)
46
+ self._print_status(' OK ', test)
47
+
48
+ def addError(self, test, err):
49
+ super().addError(test, err)
50
+ self._print_status(' FAILED ', test)
51
+
52
+ def addFailure(self, test, err):
53
+ super().addFailure(test, err)
54
+ self._print_status(' FAILED ', test)
55
+
56
+ def addSkip(self, test, reason):
57
+ super().addSkip(test, reason)
58
+ self._print_status(' SKIPPED ', test, reason)
59
+
60
+ def addExpectedFailure(self, test, err):
61
+ super().addExpectedFailure(test, err)
62
+ self._print_status(' OK ', test)
63
+
64
+ def addUnexpectedSuccess(self, test):
65
+ super().addUnexpectedSuccess(test)
66
+ self._print_status(' FAILED ', test)
67
+
68
+
69
+ class TextTestRunner(unittest.TextTestRunner):
70
+ """A test runner that produces formatted text results."""
71
+
72
+ _TEST_RESULT_CLASS = TextTestResult
73
+
74
+ # Set this to true at the class or instance level to run tests using a
75
+ # debug-friendly method (e.g, one that doesn't catch exceptions and interacts
76
+ # better with debuggers).
77
+ # Usually this is set using --pdb_post_mortem.
78
+ run_for_debugging = False
79
+
80
+ def run(self, test) -> unittest.TextTestResult:
81
+ if self.run_for_debugging:
82
+ return self._run_debug(test)
83
+ else:
84
+ return super().run(test)
85
+
86
+ def _run_debug(self, test) -> unittest.TextTestResult:
87
+ test.debug()
88
+ # Return an empty result to indicate success.
89
+ return self._makeResult()
90
+
91
+ def _makeResult(self):
92
+ return TextTestResult(self.stream, self.descriptions, self.verbosity)
lib/python3.10/site-packages/absl/testing/absltest.py ADDED
The diff for this file is too large to render. See raw diff
 
lib/python3.10/site-packages/absl/testing/flagsaver.py ADDED
@@ -0,0 +1,393 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Decorator and context manager for saving and restoring flag values.
16
+
17
+ There are many ways to save and restore. Always use the most convenient method
18
+ for a given use case.
19
+
20
+ Here are examples of each method. They all call ``do_stuff()`` while
21
+ ``FLAGS.someflag`` is temporarily set to ``'foo'``::
22
+
23
+ from absl.testing import flagsaver
24
+
25
+ # Use a decorator which can optionally override flags via arguments.
26
+ @flagsaver.flagsaver(someflag='foo')
27
+ def some_func():
28
+ do_stuff()
29
+
30
+ # Use a decorator which can optionally override flags with flagholders.
31
+ @flagsaver.flagsaver((module.FOO_FLAG, 'foo'), (other_mod.BAR_FLAG, 23))
32
+ def some_func():
33
+ do_stuff()
34
+
35
+ # Use a decorator which does not override flags itself.
36
+ @flagsaver.flagsaver
37
+ def some_func():
38
+ FLAGS.someflag = 'foo'
39
+ do_stuff()
40
+
41
+ # Use a context manager which can optionally override flags via arguments.
42
+ with flagsaver.flagsaver(someflag='foo'):
43
+ do_stuff()
44
+
45
+ # Save and restore the flag values yourself.
46
+ saved_flag_values = flagsaver.save_flag_values()
47
+ try:
48
+ FLAGS.someflag = 'foo'
49
+ do_stuff()
50
+ finally:
51
+ flagsaver.restore_flag_values(saved_flag_values)
52
+
53
+ # Use the parsing version to emulate users providing the flags.
54
+ # Note that all flags must be provided as strings (unparsed).
55
+ @flagsaver.as_parsed(some_int_flag='123')
56
+ def some_func():
57
+ # Because the flag was parsed it is considered "present".
58
+ assert FLAGS.some_int_flag.present
59
+ do_stuff()
60
+
61
+ # flagsaver.as_parsed() can also be used as a context manager just like
62
+ # flagsaver.flagsaver()
63
+ with flagsaver.as_parsed(some_int_flag='123'):
64
+ do_stuff()
65
+
66
+ # The flagsaver.as_parsed() interface also supports FlagHolder objects.
67
+ @flagsaver.as_parsed((module.FOO_FLAG, 'foo'), (other_mod.BAR_FLAG, '23'))
68
+ def some_func():
69
+ do_stuff()
70
+
71
+ # Using as_parsed with a multi_X flag requires a sequence of strings.
72
+ @flagsaver.as_parsed(some_multi_int_flag=['123', '456'])
73
+ def some_func():
74
+ assert FLAGS.some_multi_int_flag.present
75
+ do_stuff()
76
+
77
+ # If a flag name includes non-identifier characters it can be specified like
78
+ # so:
79
+ @flagsaver.as_parsed(**{'i-like-dashes': 'true'})
80
+ def some_func():
81
+ do_stuff()
82
+
83
+ We save and restore a shallow copy of each Flag object's ``__dict__`` attribute.
84
+ This preserves all attributes of the flag, such as whether or not it was
85
+ overridden from its default value.
86
+
87
+ WARNING: Currently a flag that is saved and then deleted cannot be restored. An
88
+ exception will be raised. However if you *add* a flag after saving flag values,
89
+ and then restore flag values, the added flag will be deleted with no errors.
90
+ """
91
+
92
+ import collections
93
+ import functools
94
+ import inspect
95
+ from typing import Any, Callable, Dict, Mapping, Sequence, Tuple, Type, TypeVar, Union, overload
96
+
97
+ from absl import flags
98
+
99
+ FLAGS = flags.FLAGS
100
+
101
+
102
+ # The type of pre/post wrapped functions.
103
+ _CallableT = TypeVar('_CallableT', bound=Callable)
104
+
105
+
106
+ @overload
107
+ def flagsaver(func: _CallableT) -> _CallableT:
108
+ ...
109
+
110
+
111
+ @overload
112
+ def flagsaver(
113
+ *args: Tuple[flags.FlagHolder, Any], **kwargs: Any
114
+ ) -> '_FlagOverrider':
115
+ ...
116
+
117
+
118
+ def flagsaver(*args, **kwargs):
119
+ """The main flagsaver interface. See module doc for usage."""
120
+ return _construct_overrider(_FlagOverrider, *args, **kwargs) # type: ignore[bad-return-type]
121
+
122
+
123
+ @overload
124
+ def as_parsed(*args: Tuple[flags.FlagHolder, Union[str, Sequence[str]]],
125
+ **kwargs: Union[str, Sequence[str]]) -> '_ParsingFlagOverrider':
126
+ ...
127
+
128
+
129
+ @overload
130
+ def as_parsed(func: _CallableT) -> _CallableT:
131
+ ...
132
+
133
+
134
+ def as_parsed(*args, **kwargs):
135
+ """Overrides flags by parsing strings, saves flag state similar to flagsaver.
136
+
137
+ This function can be used as either a decorator or context manager similar to
138
+ flagsaver.flagsaver(). However, where flagsaver.flagsaver() directly sets the
139
+ flags to new values, this function will parse the provided arguments as if
140
+ they were provided on the command line. Among other things, this will cause
141
+ `FLAGS['flag_name'].present == True`.
142
+
143
+ A note on unparsed input: For many flag types, the unparsed version will be
144
+ a single string. However for multi_x (multi_string, multi_integer, multi_enum)
145
+ the unparsed version will be a Sequence of strings.
146
+
147
+ Args:
148
+ *args: Tuples of FlagHolders and their unparsed value.
149
+ **kwargs: The keyword args are flag names, and the values are unparsed
150
+ values.
151
+
152
+ Returns:
153
+ _ParsingFlagOverrider that serves as a context manager or decorator. Will
154
+ save previous flag state and parse new flags, then on cleanup it will
155
+ restore the previous flag state.
156
+ """
157
+ return _construct_overrider(_ParsingFlagOverrider, *args, **kwargs)
158
+
159
+
160
+ # NOTE: the order of these overload declarations matters. The type checker will
161
+ # pick the first match which could be incorrect.
162
+ @overload
163
+ def _construct_overrider(
164
+ flag_overrider_cls: Type['_ParsingFlagOverrider'],
165
+ *args: Tuple[flags.FlagHolder, Union[str, Sequence[str]]],
166
+ **kwargs: Union[str, Sequence[str]]) -> '_ParsingFlagOverrider':
167
+ ...
168
+
169
+
170
+ @overload
171
+ def _construct_overrider(
172
+ flag_overrider_cls: Type['_FlagOverrider'], func: _CallableT
173
+ ) -> _CallableT:
174
+ ...
175
+
176
+
177
+ @overload
178
+ def _construct_overrider(
179
+ flag_overrider_cls: Type['_FlagOverrider'],
180
+ *args: Tuple[flags.FlagHolder, Any],
181
+ **kwargs: Any,
182
+ ) -> '_FlagOverrider':
183
+ ...
184
+
185
+
186
+ def _construct_overrider(flag_overrider_cls, *args, **kwargs):
187
+ """Handles the args/kwargs returning an instance of flag_overrider_cls.
188
+
189
+ If flag_overrider_cls is _FlagOverrider then values should be native python
190
+ types matching the python types. Otherwise if flag_overrider_cls is
191
+ _ParsingFlagOverrider the values should be strings or sequences of strings.
192
+
193
+ Args:
194
+ flag_overrider_cls: The class that will do the overriding.
195
+ *args: Tuples of FlagHolder and the new flag value.
196
+ **kwargs: Keword args mapping flag name to new flag value.
197
+
198
+ Returns:
199
+ A _FlagOverrider to be used as a decorator or context manager.
200
+ """
201
+ if not args:
202
+ return flag_overrider_cls(**kwargs)
203
+ # args can be [func] if used as `@flagsaver` instead of `@flagsaver(...)`
204
+ if len(args) == 1 and callable(args[0]):
205
+ if kwargs:
206
+ raise ValueError(
207
+ "It's invalid to specify both positional and keyword parameters.")
208
+ func = args[0]
209
+ if inspect.isclass(func):
210
+ raise TypeError('@flagsaver.flagsaver cannot be applied to a class.')
211
+ return _wrap(flag_overrider_cls, func, {})
212
+ # args can be a list of (FlagHolder, value) pairs.
213
+ # In which case they augment any specified kwargs.
214
+ for arg in args:
215
+ if not isinstance(arg, tuple) or len(arg) != 2:
216
+ raise ValueError('Expected (FlagHolder, value) pair, found %r' % (arg,))
217
+ holder, value = arg
218
+ if not isinstance(holder, flags.FlagHolder):
219
+ raise ValueError('Expected (FlagHolder, value) pair, found %r' % (arg,))
220
+ if holder.name in kwargs:
221
+ raise ValueError('Cannot set --%s multiple times' % holder.name)
222
+ kwargs[holder.name] = value
223
+ return flag_overrider_cls(**kwargs)
224
+
225
+
226
+ def save_flag_values(
227
+ flag_values: flags.FlagValues = FLAGS,
228
+ ) -> Dict[str, Dict[str, Any]]:
229
+ """Returns copy of flag values as a dict.
230
+
231
+ Args:
232
+ flag_values: FlagValues, the FlagValues instance with which the flag will be
233
+ saved. This should almost never need to be overridden.
234
+
235
+ Returns:
236
+ Dictionary mapping keys to values. Keys are flag names, values are
237
+ corresponding ``__dict__`` members. E.g. ``{'key': value_dict, ...}``.
238
+ """
239
+ return {name: _copy_flag_dict(flag_values[name]) for name in flag_values}
240
+
241
+
242
+ def restore_flag_values(
243
+ saved_flag_values: Mapping[str, Dict[str, Any]],
244
+ flag_values: flags.FlagValues = FLAGS,
245
+ ) -> None:
246
+ """Restores flag values based on the dictionary of flag values.
247
+
248
+ Args:
249
+ saved_flag_values: {'flag_name': value_dict, ...}
250
+ flag_values: FlagValues, the FlagValues instance from which the flag will be
251
+ restored. This should almost never need to be overridden.
252
+ """
253
+ new_flag_names = list(flag_values)
254
+ for name in new_flag_names:
255
+ saved = saved_flag_values.get(name)
256
+ if saved is None:
257
+ # If __dict__ was not saved delete "new" flag.
258
+ delattr(flag_values, name)
259
+ else:
260
+ if flag_values[name].value != saved['_value']:
261
+ flag_values[name].value = saved['_value'] # Ensure C++ value is set.
262
+ flag_values[name].__dict__ = saved
263
+
264
+
265
+ @overload
266
+ def _wrap(flag_overrider_cls: Type['_FlagOverrider'], func: _CallableT,
267
+ overrides: Mapping[str, Any]) -> _CallableT:
268
+ ...
269
+
270
+
271
+ @overload
272
+ def _wrap(flag_overrider_cls: Type['_ParsingFlagOverrider'], func: _CallableT,
273
+ overrides: Mapping[str, Union[str, Sequence[str]]]) -> _CallableT:
274
+ ...
275
+
276
+
277
+ def _wrap(flag_overrider_cls, func, overrides):
278
+ """Creates a wrapper function that saves/restores flag values.
279
+
280
+ Args:
281
+ flag_overrider_cls: The class that will be used as a context manager.
282
+ func: This will be called between saving flags and restoring flags.
283
+ overrides: Flag names mapped to their values. These flags will be set after
284
+ saving the original flag state. The type of the values depends on if
285
+ _FlagOverrider or _ParsingFlagOverrider was specified.
286
+
287
+ Returns:
288
+ A wrapped version of func.
289
+ """
290
+
291
+ @functools.wraps(func)
292
+ def _flagsaver_wrapper(*args, **kwargs):
293
+ """Wrapper function that saves and restores flags."""
294
+ with flag_overrider_cls(**overrides):
295
+ return func(*args, **kwargs)
296
+
297
+ return _flagsaver_wrapper
298
+
299
+
300
+ class _FlagOverrider:
301
+ """Overrides flags for the duration of the decorated function call.
302
+
303
+ It also restores all original values of flags after decorated method
304
+ completes.
305
+ """
306
+
307
+ def __init__(self, **overrides: Any):
308
+ self._overrides = overrides
309
+ self._saved_flag_values = None
310
+
311
+ def __call__(self, func: _CallableT) -> _CallableT:
312
+ if inspect.isclass(func):
313
+ raise TypeError('flagsaver cannot be applied to a class.')
314
+ return _wrap(self.__class__, func, self._overrides)
315
+
316
+ def __enter__(self):
317
+ self._saved_flag_values = save_flag_values(FLAGS)
318
+ try:
319
+ FLAGS._set_attributes(**self._overrides)
320
+ except:
321
+ # It may fail because of flag validators.
322
+ restore_flag_values(self._saved_flag_values, FLAGS)
323
+ raise
324
+
325
+ def __exit__(self, exc_type, exc_value, traceback):
326
+ restore_flag_values(self._saved_flag_values, FLAGS)
327
+
328
+
329
+ class _ParsingFlagOverrider(_FlagOverrider):
330
+ """Context manager for overriding flags.
331
+
332
+ Simulates command line parsing.
333
+
334
+ This is simlar to _FlagOverrider except that all **overrides should be
335
+ strings or sequences of strings, and when context is entered this class calls
336
+ .parse(value)
337
+
338
+ This results in the flags having .present set properly.
339
+ """
340
+
341
+ def __init__(self, **overrides: Union[str, Sequence[str]]):
342
+ for flag_name, new_value in overrides.items():
343
+ if isinstance(new_value, str):
344
+ continue
345
+ if (isinstance(new_value, collections.abc.Sequence) and
346
+ all(isinstance(single_value, str) for single_value in new_value)):
347
+ continue
348
+ raise TypeError(
349
+ f'flagsaver.as_parsed() cannot parse {flag_name}. Expected a single '
350
+ f'string or sequence of strings but {type(new_value)} was provided.')
351
+ super().__init__(**overrides)
352
+
353
+ def __enter__(self):
354
+ self._saved_flag_values = save_flag_values(FLAGS)
355
+ try:
356
+ for flag_name, unparsed_value in self._overrides.items():
357
+ # LINT.IfChange(flag_override_parsing)
358
+ FLAGS[flag_name].parse(unparsed_value)
359
+ FLAGS[flag_name].using_default_value = False
360
+ # LINT.ThenChange()
361
+
362
+ # Perform the validation on all modified flags. This is something that
363
+ # FLAGS._set_attributes() does for you in _FlagOverrider.
364
+ for flag_name in self._overrides:
365
+ FLAGS._assert_validators(FLAGS[flag_name].validators)
366
+
367
+ except KeyError as e:
368
+ # If a flag doesn't exist, an UnrecognizedFlagError is more specific.
369
+ restore_flag_values(self._saved_flag_values, FLAGS)
370
+ raise flags.UnrecognizedFlagError('Unknown command line flag.') from e
371
+
372
+ except:
373
+ # It may fail because of flag validators or general parsing issues.
374
+ restore_flag_values(self._saved_flag_values, FLAGS)
375
+ raise
376
+
377
+
378
+ def _copy_flag_dict(flag: flags.Flag) -> Dict[str, Any]:
379
+ """Returns a copy of the flag object's ``__dict__``.
380
+
381
+ It's mostly a shallow copy of the ``__dict__``, except it also does a shallow
382
+ copy of the validator list.
383
+
384
+ Args:
385
+ flag: flags.Flag, the flag to copy.
386
+
387
+ Returns:
388
+ A copy of the flag object's ``__dict__``.
389
+ """
390
+ copy = flag.__dict__.copy()
391
+ copy['_value'] = flag.value # Ensure correct restore for C++ flags.
392
+ copy['validators'] = list(flag.validators)
393
+ return copy
lib/python3.10/site-packages/absl/testing/parameterized.py ADDED
@@ -0,0 +1,726 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Adds support for parameterized tests to Python's unittest TestCase class.
16
+
17
+ A parameterized test is a method in a test case that is invoked with different
18
+ argument tuples.
19
+
20
+ A simple example::
21
+
22
+ class AdditionExample(parameterized.TestCase):
23
+ @parameterized.parameters(
24
+ (1, 2, 3),
25
+ (4, 5, 9),
26
+ (1, 1, 3))
27
+ def testAddition(self, op1, op2, result):
28
+ self.assertEqual(result, op1 + op2)
29
+
30
+ Each invocation is a separate test case and properly isolated just
31
+ like a normal test method, with its own setUp/tearDown cycle. In the
32
+ example above, there are three separate testcases, one of which will
33
+ fail due to an assertion error (1 + 1 != 3).
34
+
35
+ Parameters for individual test cases can be tuples (with positional parameters)
36
+ or dictionaries (with named parameters)::
37
+
38
+ class AdditionExample(parameterized.TestCase):
39
+ @parameterized.parameters(
40
+ {'op1': 1, 'op2': 2, 'result': 3},
41
+ {'op1': 4, 'op2': 5, 'result': 9},
42
+ )
43
+ def testAddition(self, op1, op2, result):
44
+ self.assertEqual(result, op1 + op2)
45
+
46
+ If a parameterized test fails, the error message will show the
47
+ original test name and the parameters for that test.
48
+
49
+ The id method of the test, used internally by the unittest framework, is also
50
+ modified to show the arguments (but note that the name reported by `id()`
51
+ doesn't match the actual test name, see below). To make sure that test names
52
+ stay the same across several invocations, object representations like::
53
+
54
+ >>> class Foo(object):
55
+ ... pass
56
+ >>> repr(Foo())
57
+ '<__main__.Foo object at 0x23d8610>'
58
+
59
+ are turned into ``__main__.Foo``. When selecting a subset of test cases to run
60
+ on the command-line, the test cases contain an index suffix for each argument
61
+ in the order they were passed to :func:`parameters` (eg. testAddition0,
62
+ testAddition1, etc.) This naming scheme is subject to change; for more reliable
63
+ and stable names, especially in test logs, use :func:`named_parameters` instead.
64
+
65
+ Tests using :func:`named_parameters` are similar to :func:`parameters`, except
66
+ only tuples or dicts of args are supported. For tuples, the first parameter arg
67
+ has to be a string (or an object that returns an apt name when converted via
68
+ ``str()``). For dicts, a value for the key ``testcase_name`` must be present and
69
+ must be a string (or an object that returns an apt name when converted via
70
+ ``str()``)::
71
+
72
+ class NamedExample(parameterized.TestCase):
73
+ @parameterized.named_parameters(
74
+ ('Normal', 'aa', 'aaa', True),
75
+ ('EmptyPrefix', '', 'abc', True),
76
+ ('BothEmpty', '', '', True))
77
+ def testStartsWith(self, prefix, string, result):
78
+ self.assertEqual(result, string.startswith(prefix))
79
+
80
+ class NamedExample(parameterized.TestCase):
81
+ @parameterized.named_parameters(
82
+ {'testcase_name': 'Normal',
83
+ 'result': True, 'string': 'aaa', 'prefix': 'aa'},
84
+ {'testcase_name': 'EmptyPrefix',
85
+ 'result': True, 'string': 'abc', 'prefix': ''},
86
+ {'testcase_name': 'BothEmpty',
87
+ 'result': True, 'string': '', 'prefix': ''})
88
+ def testStartsWith(self, prefix, string, result):
89
+ self.assertEqual(result, string.startswith(prefix))
90
+
91
+ Named tests also have the benefit that they can be run individually
92
+ from the command line::
93
+
94
+ $ testmodule.py NamedExample.testStartsWithNormal
95
+ .
96
+ --------------------------------------------------------------------
97
+ Ran 1 test in 0.000s
98
+
99
+ OK
100
+
101
+ Parameterized Classes
102
+ =====================
103
+
104
+ If invocation arguments are shared across test methods in a single
105
+ TestCase class, instead of decorating all test methods
106
+ individually, the class itself can be decorated::
107
+
108
+ @parameterized.parameters(
109
+ (1, 2, 3),
110
+ (4, 5, 9))
111
+ class ArithmeticTest(parameterized.TestCase):
112
+ def testAdd(self, arg1, arg2, result):
113
+ self.assertEqual(arg1 + arg2, result)
114
+
115
+ def testSubtract(self, arg1, arg2, result):
116
+ self.assertEqual(result - arg1, arg2)
117
+
118
+ Inputs from Iterables
119
+ =====================
120
+
121
+ If parameters should be shared across several test cases, or are dynamically
122
+ created from other sources, a single non-tuple iterable can be passed into
123
+ the decorator. This iterable will be used to obtain the test cases::
124
+
125
+ class AdditionExample(parameterized.TestCase):
126
+ @parameterized.parameters(
127
+ c.op1, c.op2, c.result for c in testcases
128
+ )
129
+ def testAddition(self, op1, op2, result):
130
+ self.assertEqual(result, op1 + op2)
131
+
132
+
133
+ Single-Argument Test Methods
134
+ ============================
135
+
136
+ If a test method takes only one argument, the single arguments must not be
137
+ wrapped into a tuple::
138
+
139
+ class NegativeNumberExample(parameterized.TestCase):
140
+ @parameterized.parameters(
141
+ -1, -3, -4, -5
142
+ )
143
+ def testIsNegative(self, arg):
144
+ self.assertTrue(IsNegative(arg))
145
+
146
+
147
+ List/tuple as a Single Argument
148
+ ===============================
149
+
150
+ If a test method takes a single argument of a list/tuple, it must be wrapped
151
+ inside a tuple::
152
+
153
+ class ZeroSumExample(parameterized.TestCase):
154
+ @parameterized.parameters(
155
+ ([-1, 0, 1], ),
156
+ ([-2, 0, 2], ),
157
+ )
158
+ def testSumIsZero(self, arg):
159
+ self.assertEqual(0, sum(arg))
160
+
161
+
162
+ Cartesian product of Parameter Values as Parameterized Test Cases
163
+ =================================================================
164
+
165
+ If required to test method over a cartesian product of parameters,
166
+ `parameterized.product` may be used to facilitate generation of parameters
167
+ test combinations::
168
+
169
+ class TestModuloExample(parameterized.TestCase):
170
+ @parameterized.product(
171
+ num=[0, 20, 80],
172
+ modulo=[2, 4],
173
+ expected=[0]
174
+ )
175
+ def testModuloResult(self, num, modulo, expected):
176
+ self.assertEqual(expected, num % modulo)
177
+
178
+ This results in 6 test cases being created - one for each combination of the
179
+ parameters. It is also possible to supply sequences of keyword argument dicts
180
+ as elements of the cartesian product::
181
+
182
+ @parameterized.product(
183
+ (dict(num=5, modulo=3, expected=2),
184
+ dict(num=7, modulo=4, expected=3)),
185
+ dtype=(int, float)
186
+ )
187
+ def testModuloResult(self, num, modulo, expected, dtype):
188
+ self.assertEqual(expected, dtype(num) % modulo)
189
+
190
+ This results in 4 test cases being created - for each of the two sets of test
191
+ data (supplied as kwarg dicts) and for each of the two data types (supplied as
192
+ a named parameter). Multiple keyword argument dicts may be supplied if required.
193
+
194
+ Async Support
195
+ =============
196
+
197
+ If a test needs to call async functions, it can inherit from both
198
+ parameterized.TestCase and another TestCase that supports async calls, such
199
+ as [asynctest](https://github.com/Martiusweb/asynctest)::
200
+
201
+ import asynctest
202
+
203
+ class AsyncExample(parameterized.TestCase, asynctest.TestCase):
204
+ @parameterized.parameters(
205
+ ('a', 1),
206
+ ('b', 2),
207
+ )
208
+ async def testSomeAsyncFunction(self, arg, expected):
209
+ actual = await someAsyncFunction(arg)
210
+ self.assertEqual(actual, expected)
211
+ """
212
+
213
+ from collections import abc
214
+ import functools
215
+ import inspect
216
+ import itertools
217
+ import re
218
+ import types
219
+ import unittest
220
+ import warnings
221
+
222
+ from absl.testing import absltest
223
+
224
+
225
+ _ADDR_RE = re.compile(r'\<([a-zA-Z0-9_\-\.]+) object at 0x[a-fA-F0-9]+\>')
226
+ _NAMED = object()
227
+ _ARGUMENT_REPR = object()
228
+ _NAMED_DICT_KEY = 'testcase_name'
229
+
230
+
231
+ class NoTestsError(Exception):
232
+ """Raised when parameterized decorators do not generate any tests."""
233
+
234
+
235
+ class DuplicateTestNameError(Exception):
236
+ """Raised when a parameterized test has the same test name multiple times."""
237
+
238
+ def __init__(self, test_class_name, new_test_name, original_test_name):
239
+ super().__init__(
240
+ 'Duplicate parameterized test name in {}: generated test name {!r} '
241
+ '(generated from {!r}) already exists. Consider using '
242
+ 'named_parameters() to give your tests unique names and/or renaming '
243
+ 'the conflicting test method.'.format(
244
+ test_class_name, new_test_name, original_test_name
245
+ )
246
+ )
247
+
248
+
249
+ def _clean_repr(obj):
250
+ return _ADDR_RE.sub(r'<\1>', repr(obj))
251
+
252
+
253
+ def _non_string_or_bytes_iterable(obj):
254
+ return (isinstance(obj, abc.Iterable) and not isinstance(obj, str) and
255
+ not isinstance(obj, bytes))
256
+
257
+
258
+ def _format_parameter_list(testcase_params):
259
+ if isinstance(testcase_params, abc.Mapping):
260
+ return ', '.join('%s=%s' % (argname, _clean_repr(value))
261
+ for argname, value in testcase_params.items())
262
+ elif _non_string_or_bytes_iterable(testcase_params):
263
+ return ', '.join(map(_clean_repr, testcase_params))
264
+ else:
265
+ return _format_parameter_list((testcase_params,))
266
+
267
+
268
+ def _async_wrapped(func):
269
+ @functools.wraps(func)
270
+ async def wrapper(*args, **kwargs):
271
+ return await func(*args, **kwargs)
272
+ return wrapper
273
+
274
+
275
+ class _ParameterizedTestIter:
276
+ """Callable and iterable class for producing new test cases."""
277
+
278
+ def __init__(self, test_method, testcases, naming_type, original_name=None):
279
+ """Returns concrete test functions for a test and a list of parameters.
280
+
281
+ The naming_type is used to determine the name of the concrete
282
+ functions as reported by the unittest framework. If naming_type is
283
+ _FIRST_ARG, the testcases must be tuples, and the first element must
284
+ have a string representation that is a valid Python identifier.
285
+
286
+ Args:
287
+ test_method: The decorated test method.
288
+ testcases: (list of tuple/dict) A list of parameter tuples/dicts for
289
+ individual test invocations.
290
+ naming_type: The test naming type, either _NAMED or _ARGUMENT_REPR.
291
+ original_name: The original test method name. When decorated on a test
292
+ method, None is passed to __init__ and test_method.__name__ is used.
293
+ Note test_method.__name__ might be different than the original defined
294
+ test method because of the use of other decorators. A more accurate
295
+ value is set by TestGeneratorMetaclass.__new__ later.
296
+ """
297
+ self._test_method = test_method
298
+ self.testcases = testcases
299
+ self._naming_type = naming_type
300
+ if original_name is None:
301
+ original_name = test_method.__name__
302
+ self._original_name = original_name
303
+ self.__name__ = _ParameterizedTestIter.__name__
304
+
305
+ def __call__(self, *args, **kwargs):
306
+ raise RuntimeError('You appear to be running a parameterized test case '
307
+ 'without having inherited from parameterized.'
308
+ 'TestCase. This is bad because none of '
309
+ 'your test cases are actually being run. You may also '
310
+ 'be using another decorator before the parameterized '
311
+ 'one, in which case you should reverse the order.')
312
+
313
+ def __iter__(self):
314
+ test_method = self._test_method
315
+ naming_type = self._naming_type
316
+
317
+ def make_bound_param_test(testcase_params):
318
+ @functools.wraps(test_method)
319
+ def bound_param_test(self):
320
+ if isinstance(testcase_params, abc.Mapping):
321
+ return test_method(self, **testcase_params)
322
+ elif _non_string_or_bytes_iterable(testcase_params):
323
+ return test_method(self, *testcase_params)
324
+ else:
325
+ return test_method(self, testcase_params)
326
+
327
+ if naming_type is _NAMED:
328
+ # Signal the metaclass that the name of the test function is unique
329
+ # and descriptive.
330
+ bound_param_test.__x_use_name__ = True
331
+
332
+ testcase_name = None
333
+ if isinstance(testcase_params, abc.Mapping):
334
+ if _NAMED_DICT_KEY not in testcase_params:
335
+ raise RuntimeError(
336
+ 'Dict for named tests must contain key "%s"' % _NAMED_DICT_KEY)
337
+ # Create a new dict to avoid modifying the supplied testcase_params.
338
+ testcase_name = testcase_params[_NAMED_DICT_KEY]
339
+ testcase_params = {
340
+ k: v for k, v in testcase_params.items() if k != _NAMED_DICT_KEY
341
+ }
342
+ elif _non_string_or_bytes_iterable(testcase_params):
343
+ if not isinstance(testcase_params[0], str):
344
+ raise RuntimeError(
345
+ 'The first element of named test parameters is the test name '
346
+ 'suffix and must be a string')
347
+ testcase_name = testcase_params[0]
348
+ testcase_params = testcase_params[1:]
349
+ else:
350
+ raise RuntimeError(
351
+ 'Named tests must be passed a dict or non-string iterable.')
352
+
353
+ test_method_name = self._original_name
354
+ # Support PEP-8 underscore style for test naming if used.
355
+ if (test_method_name.startswith('test_')
356
+ and testcase_name
357
+ and not testcase_name.startswith('_')):
358
+ test_method_name += '_'
359
+
360
+ bound_param_test.__name__ = test_method_name + str(testcase_name)
361
+ elif naming_type is _ARGUMENT_REPR:
362
+ # If it's a generator, convert it to a tuple and treat them as
363
+ # parameters.
364
+ if isinstance(testcase_params, types.GeneratorType):
365
+ testcase_params = tuple(testcase_params)
366
+ # The metaclass creates a unique, but non-descriptive method name for
367
+ # _ARGUMENT_REPR tests using an indexed suffix.
368
+ # To keep test names descriptive, only the original method name is used.
369
+ # To make sure test names are unique, we add a unique descriptive suffix
370
+ # __x_params_repr__ for every test.
371
+ params_repr = '(%s)' % (_format_parameter_list(testcase_params),)
372
+ bound_param_test.__x_params_repr__ = params_repr
373
+ else:
374
+ raise RuntimeError('%s is not a valid naming type.' % (naming_type,))
375
+
376
+ bound_param_test.__doc__ = '%s(%s)' % (
377
+ bound_param_test.__name__, _format_parameter_list(testcase_params))
378
+ if test_method.__doc__:
379
+ bound_param_test.__doc__ += '\n%s' % (test_method.__doc__,)
380
+ if inspect.iscoroutinefunction(test_method):
381
+ return _async_wrapped(bound_param_test)
382
+ return bound_param_test
383
+
384
+ return (make_bound_param_test(c) for c in self.testcases)
385
+
386
+
387
+ def _modify_class(class_object, testcases, naming_type):
388
+ assert not getattr(class_object, '_test_params_reprs', None), (
389
+ 'Cannot add parameters to %s. Either it already has parameterized '
390
+ 'methods, or its super class is also a parameterized class.' % (
391
+ class_object,))
392
+ # NOTE: _test_params_repr is private to parameterized.TestCase and it's
393
+ # metaclass; do not use it outside of those classes.
394
+ class_object._test_params_reprs = test_params_reprs = {}
395
+ for name, obj in class_object.__dict__.copy().items():
396
+ if (name.startswith(unittest.TestLoader.testMethodPrefix)
397
+ and isinstance(obj, types.FunctionType)):
398
+ delattr(class_object, name)
399
+ methods = {}
400
+ _update_class_dict_for_param_test_case(
401
+ class_object.__name__, methods, test_params_reprs, name,
402
+ _ParameterizedTestIter(obj, testcases, naming_type, name))
403
+ for meth_name, meth in methods.items():
404
+ setattr(class_object, meth_name, meth)
405
+
406
+
407
+ def _parameter_decorator(naming_type, testcases):
408
+ """Implementation of the parameterization decorators.
409
+
410
+ Args:
411
+ naming_type: The naming type.
412
+ testcases: Testcase parameters.
413
+
414
+ Raises:
415
+ NoTestsError: Raised when the decorator generates no tests.
416
+
417
+ Returns:
418
+ A function for modifying the decorated object.
419
+ """
420
+ def _apply(obj):
421
+ if isinstance(obj, type):
422
+ _modify_class(obj, testcases, naming_type)
423
+ return obj
424
+ else:
425
+ return _ParameterizedTestIter(obj, testcases, naming_type)
426
+
427
+ if (len(testcases) == 1 and
428
+ not isinstance(testcases[0], tuple) and
429
+ not isinstance(testcases[0], abc.Mapping)):
430
+ # Support using a single non-tuple parameter as a list of test cases.
431
+ # Note that the single non-tuple parameter can't be Mapping either, which
432
+ # means a single dict parameter case.
433
+ assert _non_string_or_bytes_iterable(testcases[0]), (
434
+ 'Single parameter argument must be a non-string non-Mapping iterable')
435
+ testcases = testcases[0]
436
+
437
+ if not isinstance(testcases, abc.Sequence):
438
+ testcases = list(testcases)
439
+ if not testcases:
440
+ raise NoTestsError(
441
+ 'parameterized test decorators did not generate any tests. '
442
+ 'Make sure you specify non-empty parameters, '
443
+ 'and do not reuse generators more than once.')
444
+
445
+ return _apply
446
+
447
+
448
+ def parameters(*testcases):
449
+ """A decorator for creating parameterized tests.
450
+
451
+ See the module docstring for a usage example.
452
+
453
+ Args:
454
+ *testcases: Parameters for the decorated method, either a single
455
+ iterable, or a list of tuples/dicts/objects (for tests with only one
456
+ argument).
457
+
458
+ Raises:
459
+ NoTestsError: Raised when the decorator generates no tests.
460
+
461
+ Returns:
462
+ A test generator to be handled by TestGeneratorMetaclass.
463
+ """
464
+ return _parameter_decorator(_ARGUMENT_REPR, testcases)
465
+
466
+
467
+ def named_parameters(*testcases):
468
+ """A decorator for creating parameterized tests.
469
+
470
+ See the module docstring for a usage example. For every parameter tuple
471
+ passed, the first element of the tuple should be a string and will be appended
472
+ to the name of the test method. Each parameter dict passed must have a value
473
+ for the key "testcase_name", the string representation of that value will be
474
+ appended to the name of the test method.
475
+
476
+ Args:
477
+ *testcases: Parameters for the decorated method, either a single iterable,
478
+ or a list of tuples or dicts.
479
+
480
+ Raises:
481
+ NoTestsError: Raised when the decorator generates no tests.
482
+
483
+ Returns:
484
+ A test generator to be handled by TestGeneratorMetaclass.
485
+ """
486
+ return _parameter_decorator(_NAMED, testcases)
487
+
488
+
489
+ def product(*kwargs_seqs, **testgrid):
490
+ """A decorator for running tests over cartesian product of parameters values.
491
+
492
+ See the module docstring for a usage example. The test will be run for every
493
+ possible combination of the parameters.
494
+
495
+ Args:
496
+ *kwargs_seqs: Each positional parameter is a sequence of keyword arg dicts;
497
+ every test case generated will include exactly one kwargs dict from each
498
+ positional parameter; these will then be merged to form an overall list
499
+ of arguments for the test case.
500
+ **testgrid: A mapping of parameter names and their possible values. Possible
501
+ values should given as either a list or a tuple.
502
+
503
+ Raises:
504
+ NoTestsError: Raised when the decorator generates no tests.
505
+
506
+ Returns:
507
+ A test generator to be handled by TestGeneratorMetaclass.
508
+ """
509
+
510
+ for name, values in testgrid.items():
511
+ assert isinstance(values, (list, tuple)), (
512
+ 'Values of {} must be given as list or tuple, found {}'.format(
513
+ name, type(values)))
514
+
515
+ prior_arg_names = set()
516
+ for kwargs_seq in kwargs_seqs:
517
+ assert ((isinstance(kwargs_seq, (list, tuple))) and
518
+ all(isinstance(kwargs, dict) for kwargs in kwargs_seq)), (
519
+ 'Positional parameters must be a sequence of keyword arg'
520
+ 'dicts, found {}'
521
+ .format(kwargs_seq))
522
+ if kwargs_seq:
523
+ arg_names = set(kwargs_seq[0])
524
+ assert all(set(kwargs) == arg_names for kwargs in kwargs_seq), (
525
+ 'Keyword argument dicts within a single parameter must all have the '
526
+ 'same keys, found {}'.format(kwargs_seq))
527
+ assert not (arg_names & prior_arg_names), (
528
+ 'Keyword argument dict sequences must all have distinct argument '
529
+ 'names, found duplicate(s) {}'
530
+ .format(sorted(arg_names & prior_arg_names)))
531
+ prior_arg_names |= arg_names
532
+
533
+ assert not (prior_arg_names & set(testgrid)), (
534
+ 'Arguments supplied in kwargs dicts in positional parameters must not '
535
+ 'overlap with arguments supplied as named parameters; found duplicate '
536
+ 'argument(s) {}'.format(sorted(prior_arg_names & set(testgrid))))
537
+
538
+ # Convert testgrid into a sequence of sequences of kwargs dicts and combine
539
+ # with the positional parameters.
540
+ # So foo=[1,2], bar=[3,4] --> [[{foo: 1}, {foo: 2}], [{bar: 3, bar: 4}]]
541
+ testgrid = (tuple({k: v} for v in vs) for k, vs in testgrid.items())
542
+ testgrid = tuple(kwargs_seqs) + tuple(testgrid)
543
+
544
+ # Create all possible combinations of parameters as a cartesian product
545
+ # of parameter values.
546
+ testcases = [
547
+ dict(itertools.chain.from_iterable(case.items()
548
+ for case in cases))
549
+ for cases in itertools.product(*testgrid)
550
+ ]
551
+ return _parameter_decorator(_ARGUMENT_REPR, testcases)
552
+
553
+
554
+ class TestGeneratorMetaclass(type):
555
+ """Metaclass for adding tests generated by parameterized decorators."""
556
+
557
+ def __new__(cls, class_name, bases, dct):
558
+ # NOTE: _test_params_repr is private to parameterized.TestCase and it's
559
+ # metaclass; do not use it outside of those classes.
560
+ test_params_reprs = dct.setdefault('_test_params_reprs', {})
561
+ for name, obj in dct.copy().items():
562
+ if (name.startswith(unittest.TestLoader.testMethodPrefix) and
563
+ _non_string_or_bytes_iterable(obj)):
564
+ # NOTE: `obj` might not be a _ParameterizedTestIter in two cases:
565
+ # 1. a class-level iterable named test* that isn't a test, such as
566
+ # a list of something. Such attributes get deleted from the class.
567
+ #
568
+ # 2. If a decorator is applied to the parameterized test, e.g.
569
+ # @morestuff
570
+ # @parameterized.parameters(...)
571
+ # def test_foo(...): ...
572
+ #
573
+ # This is OK so long as the underlying parameterized function state
574
+ # is forwarded (e.g. using functool.wraps() and **without**
575
+ # accessing explicitly accessing the internal attributes.
576
+ if isinstance(obj, _ParameterizedTestIter):
577
+ # Update the original test method name so it's more accurate.
578
+ # The mismatch might happen when another decorator is used inside
579
+ # the parameterized decrators, and the inner decorator doesn't
580
+ # preserve its __name__.
581
+ obj._original_name = name
582
+ iterator = iter(obj)
583
+ dct.pop(name)
584
+ _update_class_dict_for_param_test_case(
585
+ class_name, dct, test_params_reprs, name, iterator)
586
+ # If the base class is a subclass of parameterized.TestCase, inherit its
587
+ # _test_params_reprs too.
588
+ for base in bases:
589
+ # Check if the base has _test_params_reprs first, then check if it's a
590
+ # subclass of parameterized.TestCase. Otherwise when this is called for
591
+ # the parameterized.TestCase definition itself, this raises because
592
+ # itself is not defined yet. This works as long as absltest.TestCase does
593
+ # not define _test_params_reprs.
594
+ base_test_params_reprs = getattr(base, '_test_params_reprs', None)
595
+ if base_test_params_reprs and issubclass(base, TestCase):
596
+ for test_method, test_method_id in base_test_params_reprs.items():
597
+ # test_method may both exists in base and this class.
598
+ # This class's method overrides base class's.
599
+ # That's why it should only inherit it if it does not exist.
600
+ test_params_reprs.setdefault(test_method, test_method_id)
601
+
602
+ return type.__new__(cls, class_name, bases, dct)
603
+
604
+
605
+ def _update_class_dict_for_param_test_case(
606
+ test_class_name, dct, test_params_reprs, name, iterator):
607
+ """Adds individual test cases to a dictionary.
608
+
609
+ Args:
610
+ test_class_name: The name of the class tests are added to.
611
+ dct: The target dictionary.
612
+ test_params_reprs: The dictionary for mapping names to test IDs.
613
+ name: The original name of the test case.
614
+ iterator: The iterator generating the individual test cases.
615
+
616
+ Raises:
617
+ DuplicateTestNameError: Raised when a test name occurs multiple times.
618
+ RuntimeError: If non-parameterized functions are generated.
619
+ """
620
+ for idx, func in enumerate(iterator):
621
+ assert callable(func), 'Test generators must yield callables, got %r' % (
622
+ func,)
623
+ if not (getattr(func, '__x_use_name__', None) or
624
+ getattr(func, '__x_params_repr__', None)):
625
+ raise RuntimeError(
626
+ '{}.{} generated a test function without using the parameterized '
627
+ 'decorators. Only tests generated using the decorators are '
628
+ 'supported.'.format(test_class_name, name))
629
+
630
+ if getattr(func, '__x_use_name__', False):
631
+ original_name = func.__name__
632
+ new_name = original_name
633
+ else:
634
+ original_name = name
635
+ new_name = '%s%d' % (original_name, idx)
636
+
637
+ if new_name in dct:
638
+ raise DuplicateTestNameError(test_class_name, new_name, original_name)
639
+
640
+ dct[new_name] = func
641
+ test_params_reprs[new_name] = getattr(func, '__x_params_repr__', '')
642
+
643
+
644
+ class TestCase(absltest.TestCase, metaclass=TestGeneratorMetaclass):
645
+ """Base class for test cases using the parameters decorator."""
646
+
647
+ # visibility: private; do not call outside this class.
648
+ def _get_params_repr(self):
649
+ return self._test_params_reprs.get(self._testMethodName, '')
650
+
651
+ def __str__(self):
652
+ params_repr = self._get_params_repr()
653
+ if params_repr:
654
+ params_repr = ' ' + params_repr
655
+ return '{}{} ({})'.format(
656
+ self._testMethodName, params_repr,
657
+ unittest.util.strclass(self.__class__))
658
+
659
+ def id(self):
660
+ """Returns the descriptive ID of the test.
661
+
662
+ This is used internally by the unittesting framework to get a name
663
+ for the test to be used in reports.
664
+
665
+ Returns:
666
+ The test id.
667
+ """
668
+ base = super().id()
669
+ params_repr = self._get_params_repr()
670
+ if params_repr:
671
+ # We include the params in the id so that, when reported in the
672
+ # test.xml file, the value is more informative than just "test_foo0".
673
+ # Use a space to separate them so that it's copy/paste friendly and
674
+ # easy to identify the actual test id.
675
+ return f'{base} {params_repr}'
676
+ else:
677
+ return base
678
+
679
+
680
+ # This function is kept CamelCase because it's used as a class's base class.
681
+ def CoopTestCase(other_base_class) -> type: # pylint: disable=invalid-name, g-bare-generic
682
+ """Returns a new base class with a cooperative metaclass base.
683
+
684
+ This enables the TestCase to be used in combination
685
+ with other base classes that have custom metaclasses, such as
686
+ ``mox.MoxTestBase``.
687
+
688
+ Only works with metaclasses that do not override ``type.__new__``.
689
+
690
+ Example::
691
+
692
+ from absl.testing import parameterized
693
+
694
+ class ExampleTest(parameterized.CoopTestCase(OtherTestCase)):
695
+ ...
696
+
697
+ Args:
698
+ other_base_class: (class) A test case base class.
699
+
700
+ Returns:
701
+ A new class object.
702
+ """
703
+ # If the other base class has a metaclass of 'type' then trying to combine
704
+ # the metaclasses will result in an MRO error. So simply combine them and
705
+ # return.
706
+ if type(other_base_class) == type: # pylint: disable=unidiomatic-typecheck
707
+ warnings.warn(
708
+ 'CoopTestCase is only necessary when combining with a class that uses'
709
+ ' a metaclass. Use multiple inheritance like this instead: class'
710
+ f' ExampleTest(paramaterized.TestCase, {other_base_class.__name__}):',
711
+ stacklevel=2,
712
+ )
713
+
714
+ class CoopTestCaseBase(other_base_class, TestCase):
715
+ pass
716
+
717
+ return CoopTestCaseBase
718
+ else:
719
+
720
+ class CoopMetaclass(type(other_base_class), TestGeneratorMetaclass): # type: ignore # pylint: disable=unused-variable
721
+ pass
722
+
723
+ class CoopTestCaseBase(other_base_class, TestCase, metaclass=CoopMetaclass): # type: ignore
724
+ pass
725
+
726
+ return CoopTestCaseBase
lib/python3.10/site-packages/absl/testing/xml_reporter.py ADDED
@@ -0,0 +1,570 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2017 The Abseil Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """A Python test reporter that generates test reports in JUnit XML format."""
16
+
17
+ import datetime
18
+ import re
19
+ import sys
20
+ import threading
21
+ import time
22
+ import traceback
23
+ from typing import Any, Dict
24
+ import unittest
25
+ from xml.sax import saxutils
26
+ from absl.testing import _pretty_print_reporter
27
+
28
+
29
+ # See http://www.w3.org/TR/REC-xml/#NT-Char
30
+ _bad_control_character_codes = set(range(0, 0x20)) - {0x9, 0xA, 0xD}
31
+
32
+
33
+ _control_character_conversions = {
34
+ chr(i): f'\\x{i:02x}' for i in _bad_control_character_codes
35
+ }
36
+
37
+
38
+ _escape_xml_attr_conversions = {
39
+ '"': '&quot;',
40
+ "'": '&apos;',
41
+ '\n': '&#xA;',
42
+ '\t': '&#x9;',
43
+ '\r': '&#xD;',
44
+ ' ': '&#x20;'}
45
+ _escape_xml_attr_conversions.update(_control_character_conversions)
46
+
47
+
48
+ # When class or module level function fails, unittest/suite.py adds a
49
+ # _ErrorHolder instance instead of a real TestCase, and it has a description
50
+ # like "setUpClass (__main__.MyTestCase)".
51
+ _CLASS_OR_MODULE_LEVEL_TEST_DESC_REGEX = re.compile(r'^(\w+) \((\S+)\)$')
52
+
53
+
54
+ # NOTE: while saxutils.quoteattr() theoretically does the same thing; it
55
+ # seems to often end up being too smart for it's own good not escaping properly.
56
+ # This function is much more reliable.
57
+ def _escape_xml_attr(content):
58
+ """Escapes xml attributes."""
59
+ # Note: saxutils doesn't escape the quotes.
60
+ return saxutils.escape(content, _escape_xml_attr_conversions)
61
+
62
+
63
+ def _escape_cdata(s):
64
+ """Escapes a string to be used as XML CDATA.
65
+
66
+ CDATA characters are treated strictly as character data, not as XML markup,
67
+ but there are still certain restrictions on them.
68
+
69
+ Args:
70
+ s: the string to be escaped.
71
+ Returns:
72
+ An escaped version of the input string.
73
+ """
74
+ for char, escaped in _control_character_conversions.items():
75
+ s = s.replace(char, escaped)
76
+ return s.replace(']]>', ']] >')
77
+
78
+
79
+ def _iso8601_timestamp(timestamp):
80
+ """Produces an ISO8601 datetime.
81
+
82
+ Args:
83
+ timestamp: an Epoch based timestamp in seconds.
84
+
85
+ Returns:
86
+ A iso8601 format timestamp if the input is a valid timestamp, None otherwise
87
+ """
88
+ if timestamp is None or timestamp < 0:
89
+ return None
90
+ return datetime.datetime.fromtimestamp(
91
+ timestamp, tz=datetime.timezone.utc).isoformat()
92
+
93
+
94
+ def _print_xml_element_header(element, attributes, stream, indentation=''):
95
+ """Prints an XML header of an arbitrary element.
96
+
97
+ Args:
98
+ element: element name (testsuites, testsuite, testcase)
99
+ attributes: 2-tuple list with (attributes, values) already escaped
100
+ stream: output stream to write test report XML to
101
+ indentation: indentation added to the element header
102
+ """
103
+ stream.write('%s<%s' % (indentation, element))
104
+ for attribute in attributes:
105
+ if (len(attribute) == 2 and attribute[0] is not None and
106
+ attribute[1] is not None):
107
+ stream.write(' %s="%s"' % (attribute[0], attribute[1]))
108
+ stream.write('>\n')
109
+
110
+ # Copy time.time which ensures the real time is used internally.
111
+ # This prevents bad interactions with tests that stub out time.
112
+ _time_copy = time.time
113
+
114
+
115
+ def _safe_str(obj: object) -> str:
116
+ """Returns a string representation of an object."""
117
+ try:
118
+ return str(obj)
119
+ except Exception: # pylint: disable=broad-except
120
+ return '<unprintable %s.%s object>' % (
121
+ type(obj).__module__,
122
+ type(obj).__name__,
123
+ )
124
+
125
+
126
+ class _TestCaseResult:
127
+ """Private helper for _TextAndXMLTestResult that represents a test result.
128
+
129
+ Attributes:
130
+ test: A TestCase instance of an individual test method.
131
+ name: The name of the individual test method.
132
+ full_class_name: The full name of the test class.
133
+ run_time: The duration (in seconds) it took to run the test.
134
+ start_time: Epoch relative timestamp of when test started (in seconds)
135
+ errors: A list of error 4-tuples. Error tuple entries are
136
+ 1) a string identifier of either "failure" or "error"
137
+ 2) an exception_type
138
+ 3) an exception_message
139
+ 4) a string version of a sys.exc_info()-style tuple of values
140
+ ('error', err[0], err[1], self._exc_info_to_string(err))
141
+ If the length of errors is 0, then the test is either passed or
142
+ skipped.
143
+ skip_reason: A string explaining why the test was skipped.
144
+ """
145
+
146
+ def __init__(self, test):
147
+ self.run_time = -1
148
+ self.start_time = -1
149
+ self.skip_reason = None
150
+ self.errors = []
151
+ self.test = test
152
+
153
+ # Parse the test id to get its test name and full class path.
154
+ # Unfortunately there is no better way of knowning the test and class.
155
+ # Worse, unittest uses _ErrorHandler instances to represent class / module
156
+ # level failures.
157
+ test_desc = test.id() or str(test)
158
+ # Check if it's something like "setUpClass (__main__.TestCase)".
159
+ match = _CLASS_OR_MODULE_LEVEL_TEST_DESC_REGEX.match(test_desc)
160
+ if match:
161
+ name = match.group(1)
162
+ full_class_name = match.group(2)
163
+ else:
164
+ class_name = unittest.util.strclass(test.__class__)
165
+ if isinstance(test, unittest.case._SubTest):
166
+ # If the test case is a _SubTest, the real TestCase instance is
167
+ # available as _SubTest.test_case.
168
+ class_name = unittest.util.strclass(test.test_case.__class__)
169
+ if test_desc.startswith(class_name + '.'):
170
+ # In a typical unittest.TestCase scenario, test.id() returns with
171
+ # a class name formatted using unittest.util.strclass.
172
+ name = test_desc[len(class_name)+1:]
173
+ full_class_name = class_name
174
+ else:
175
+ # Otherwise make a best effort to guess the test name and full class
176
+ # path.
177
+ parts = test_desc.rsplit('.', 1)
178
+ name = parts[-1]
179
+ full_class_name = parts[0] if len(parts) == 2 else ''
180
+ self.name = _escape_xml_attr(name)
181
+ self.full_class_name = _escape_xml_attr(full_class_name)
182
+
183
+ def set_run_time(self, time_in_secs):
184
+ self.run_time = time_in_secs
185
+
186
+ def set_start_time(self, time_in_secs):
187
+ self.start_time = time_in_secs
188
+
189
+ def print_xml_summary(self, stream):
190
+ """Prints an XML Summary of a TestCase.
191
+
192
+ Status and result are populated as per JUnit XML test result reporter.
193
+ A test that has been skipped will always have a skip reason,
194
+ as every skip method in Python's unittest requires the reason arg to be
195
+ passed.
196
+
197
+ Args:
198
+ stream: output stream to write test report XML to
199
+ """
200
+
201
+ if self.skip_reason is None:
202
+ status = 'run'
203
+ result = 'completed'
204
+ else:
205
+ status = 'notrun'
206
+ result = 'suppressed'
207
+
208
+ test_case_attributes = [
209
+ ('name', '%s' % self.name),
210
+ ('status', '%s' % status),
211
+ ('result', '%s' % result),
212
+ ('time', '%.3f' % self.run_time),
213
+ ('classname', self.full_class_name),
214
+ ('timestamp', _iso8601_timestamp(self.start_time)),
215
+ ]
216
+ _print_xml_element_header('testcase', test_case_attributes, stream, ' ')
217
+ self._print_testcase_details(stream)
218
+ stream.write(' </testcase>\n')
219
+
220
+ def _print_testcase_details(self, stream):
221
+ for error in self.errors:
222
+ outcome, exception_type, message, error_msg = error # pylint: disable=unpacking-non-sequence
223
+ message = _escape_xml_attr(_safe_str(message))
224
+ exception_type = _escape_xml_attr(str(exception_type))
225
+ error_msg = _escape_cdata(error_msg)
226
+ stream.write(' <%s message="%s" type="%s"><![CDATA[%s]]></%s>\n'
227
+ % (outcome, message, exception_type, error_msg, outcome))
228
+
229
+
230
+ class _TestSuiteResult:
231
+ """Private helper for _TextAndXMLTestResult."""
232
+
233
+ def __init__(self):
234
+ self.suites = {}
235
+ self.failure_counts = {}
236
+ self.error_counts = {}
237
+ self.overall_start_time = -1
238
+ self.overall_end_time = -1
239
+ self._testsuites_properties = {}
240
+
241
+ def add_test_case_result(self, test_case_result):
242
+ suite_name = type(test_case_result.test).__name__
243
+ if suite_name == '_ErrorHolder':
244
+ # _ErrorHolder is a special case created by unittest for class / module
245
+ # level functions.
246
+ suite_name = test_case_result.full_class_name.rsplit('.')[-1]
247
+ if isinstance(test_case_result.test, unittest.case._SubTest):
248
+ # If the test case is a _SubTest, the real TestCase instance is
249
+ # available as _SubTest.test_case.
250
+ suite_name = type(test_case_result.test.test_case).__name__
251
+
252
+ self._setup_test_suite(suite_name)
253
+ self.suites[suite_name].append(test_case_result)
254
+ for error in test_case_result.errors:
255
+ # Only count the first failure or error so that the sum is equal to the
256
+ # total number of *testcases* that have failures or errors.
257
+ if error[0] == 'failure':
258
+ self.failure_counts[suite_name] += 1
259
+ break
260
+ elif error[0] == 'error':
261
+ self.error_counts[suite_name] += 1
262
+ break
263
+
264
+ def print_xml_summary(self, stream):
265
+ overall_test_count = sum(len(x) for x in self.suites.values())
266
+ overall_failures = sum(self.failure_counts.values())
267
+ overall_errors = sum(self.error_counts.values())
268
+ overall_attributes = [
269
+ ('name', ''),
270
+ ('tests', '%d' % overall_test_count),
271
+ ('failures', '%d' % overall_failures),
272
+ ('errors', '%d' % overall_errors),
273
+ ('time', '%.3f' % (self.overall_end_time - self.overall_start_time)),
274
+ ('timestamp', _iso8601_timestamp(self.overall_start_time)),
275
+ ]
276
+ _print_xml_element_header('testsuites', overall_attributes, stream)
277
+ if self._testsuites_properties:
278
+ stream.write(' <properties>\n')
279
+ for name, value in sorted(self._testsuites_properties.items()):
280
+ stream.write(' <property name="%s" value="%s"></property>\n' %
281
+ (_escape_xml_attr(name), _escape_xml_attr(str(value))))
282
+ stream.write(' </properties>\n')
283
+
284
+ for suite_name in self.suites:
285
+ suite = self.suites[suite_name]
286
+ suite_end_time = max(x.start_time + x.run_time for x in suite)
287
+ suite_start_time = min(x.start_time for x in suite)
288
+ failures = self.failure_counts[suite_name]
289
+ errors = self.error_counts[suite_name]
290
+ suite_attributes = [
291
+ ('name', '%s' % suite_name),
292
+ ('tests', '%d' % len(suite)),
293
+ ('failures', '%d' % failures),
294
+ ('errors', '%d' % errors),
295
+ ('time', '%.3f' % (suite_end_time - suite_start_time)),
296
+ ('timestamp', _iso8601_timestamp(suite_start_time)),
297
+ ]
298
+ _print_xml_element_header('testsuite', suite_attributes, stream)
299
+
300
+ # test_case_result entries are not guaranteed to be in any user-friendly
301
+ # order, especially when using subtests. So sort them.
302
+ for test_case_result in sorted(suite, key=lambda t: t.name):
303
+ test_case_result.print_xml_summary(stream)
304
+ stream.write('</testsuite>\n')
305
+ stream.write('</testsuites>\n')
306
+
307
+ def _setup_test_suite(self, suite_name):
308
+ """Adds a test suite to the set of suites tracked by this test run.
309
+
310
+ Args:
311
+ suite_name: string, The name of the test suite being initialized.
312
+ """
313
+ if suite_name in self.suites:
314
+ return
315
+ self.suites[suite_name] = []
316
+ self.failure_counts[suite_name] = 0
317
+ self.error_counts[suite_name] = 0
318
+
319
+ def set_end_time(self, timestamp_in_secs):
320
+ """Sets the start timestamp of this test suite.
321
+
322
+ Args:
323
+ timestamp_in_secs: timestamp in seconds since epoch
324
+ """
325
+ self.overall_end_time = timestamp_in_secs
326
+
327
+ def set_start_time(self, timestamp_in_secs):
328
+ """Sets the end timestamp of this test suite.
329
+
330
+ Args:
331
+ timestamp_in_secs: timestamp in seconds since epoch
332
+ """
333
+ self.overall_start_time = timestamp_in_secs
334
+
335
+
336
+ class _TextAndXMLTestResult(_pretty_print_reporter.TextTestResult):
337
+ """Private TestResult class that produces both formatted text results and XML.
338
+
339
+ Used by TextAndXMLTestRunner.
340
+ """
341
+
342
+ _TEST_SUITE_RESULT_CLASS = _TestSuiteResult
343
+ _TEST_CASE_RESULT_CLASS = _TestCaseResult
344
+
345
+ def __init__(self, xml_stream, stream, descriptions, verbosity,
346
+ time_getter=_time_copy, testsuites_properties=None):
347
+ super().__init__(stream, descriptions, verbosity)
348
+ self.xml_stream = xml_stream
349
+ self.pending_test_case_results = {}
350
+ self.suite = self._TEST_SUITE_RESULT_CLASS()
351
+ if testsuites_properties:
352
+ self.suite._testsuites_properties = testsuites_properties
353
+ self.time_getter = time_getter
354
+
355
+ # This lock guards any mutations on pending_test_case_results.
356
+ self._pending_test_case_results_lock = threading.RLock()
357
+
358
+ def startTest(self, test):
359
+ self.start_time = self.time_getter()
360
+ super().startTest(test)
361
+
362
+ def stopTest(self, test):
363
+ # Grabbing the write lock to avoid conflicting with stopTestRun.
364
+ with self._pending_test_case_results_lock:
365
+ super().stopTest(test)
366
+ result = self.get_pending_test_case_result(test)
367
+ if not result:
368
+ test_name = test.id() or str(test)
369
+ sys.stderr.write('No pending test case: %s\n' % test_name)
370
+ return
371
+ if getattr(self, 'start_time', None) is None:
372
+ # startTest may not be called for skipped tests since Python 3.12.1.
373
+ self.start_time = self.time_getter()
374
+ test_id = id(test)
375
+ run_time = self.time_getter() - self.start_time
376
+ result.set_run_time(run_time)
377
+ result.set_start_time(self.start_time)
378
+ self.suite.add_test_case_result(result)
379
+ del self.pending_test_case_results[test_id]
380
+
381
+ def startTestRun(self):
382
+ self.suite.set_start_time(self.time_getter())
383
+ super().startTestRun()
384
+
385
+ def stopTestRun(self):
386
+ self.suite.set_end_time(self.time_getter())
387
+ # All pending_test_case_results will be added to the suite and removed from
388
+ # the pending_test_case_results dictionary. Grabbing the write lock to avoid
389
+ # results from being added during this process to avoid duplicating adds or
390
+ # accidentally erasing newly appended pending results.
391
+ with self._pending_test_case_results_lock:
392
+ # Errors in the test fixture (setUpModule, tearDownModule,
393
+ # setUpClass, tearDownClass) can leave a pending result which
394
+ # never gets added to the suite. The runner calls stopTestRun
395
+ # which gives us an opportunity to add these errors for
396
+ # reporting here.
397
+ for test_id in self.pending_test_case_results:
398
+ result = self.pending_test_case_results[test_id]
399
+ if getattr(self, 'start_time', None) is not None:
400
+ run_time = self.suite.overall_end_time - self.start_time
401
+ result.set_run_time(run_time)
402
+ result.set_start_time(self.start_time)
403
+ self.suite.add_test_case_result(result)
404
+ self.pending_test_case_results.clear()
405
+
406
+ def _exc_info_to_string(self, err, test=None):
407
+ """Converts a sys.exc_info()-style tuple of values into a string.
408
+
409
+ This method must be overridden because the method signature in
410
+ unittest.TestResult changed between Python 2.2 and 2.4.
411
+
412
+ Args:
413
+ err: A sys.exc_info() tuple of values for an error.
414
+ test: The test method.
415
+
416
+ Returns:
417
+ A formatted exception string.
418
+ """
419
+ if test:
420
+ return super()._exc_info_to_string(err, test)
421
+ return ''.join(traceback.format_exception(*err))
422
+
423
+ def add_pending_test_case_result(self, test, error_summary=None,
424
+ skip_reason=None):
425
+ """Adds result information to a test case result which may still be running.
426
+
427
+ If a result entry for the test already exists, add_pending_test_case_result
428
+ will add error summary tuples and/or overwrite skip_reason for the result.
429
+ If it does not yet exist, a result entry will be created.
430
+ Note that a test result is considered to have been run and passed
431
+ only if there are no errors or skip_reason.
432
+
433
+ Args:
434
+ test: A test method as defined by unittest
435
+ error_summary: A 4-tuple with the following entries:
436
+ 1) a string identifier of either "failure" or "error"
437
+ 2) an exception_type
438
+ 3) an exception_message
439
+ 4) a string version of a sys.exc_info()-style tuple of values
440
+ ('error', err[0], err[1], self._exc_info_to_string(err))
441
+ If the length of errors is 0, then the test is either passed or
442
+ skipped.
443
+ skip_reason: a string explaining why the test was skipped
444
+ """
445
+ with self._pending_test_case_results_lock:
446
+ test_id = id(test)
447
+ if test_id not in self.pending_test_case_results:
448
+ self.pending_test_case_results[test_id] = self._TEST_CASE_RESULT_CLASS(
449
+ test)
450
+ if error_summary:
451
+ self.pending_test_case_results[test_id].errors.append(error_summary)
452
+ if skip_reason:
453
+ self.pending_test_case_results[test_id].skip_reason = skip_reason
454
+
455
+ def delete_pending_test_case_result(self, test):
456
+ with self._pending_test_case_results_lock:
457
+ test_id = id(test)
458
+ del self.pending_test_case_results[test_id]
459
+
460
+ def get_pending_test_case_result(self, test):
461
+ test_id = id(test)
462
+ return self.pending_test_case_results.get(test_id, None)
463
+
464
+ def addSuccess(self, test):
465
+ super().addSuccess(test)
466
+ self.add_pending_test_case_result(test)
467
+
468
+ def addError(self, test, err):
469
+ super().addError(test, err)
470
+ error_summary = ('error', err[0], err[1],
471
+ self._exc_info_to_string(err, test=test))
472
+ self.add_pending_test_case_result(test, error_summary=error_summary)
473
+
474
+ def addFailure(self, test, err):
475
+ super().addFailure(test, err)
476
+ error_summary = ('failure', err[0], err[1],
477
+ self._exc_info_to_string(err, test=test))
478
+ self.add_pending_test_case_result(test, error_summary=error_summary)
479
+
480
+ def addSkip(self, test, reason):
481
+ super().addSkip(test, reason)
482
+ self.add_pending_test_case_result(test, skip_reason=reason)
483
+
484
+ def addExpectedFailure(self, test, err):
485
+ super().addExpectedFailure(test, err)
486
+ if callable(getattr(test, 'recordProperty', None)):
487
+ test.recordProperty('EXPECTED_FAILURE',
488
+ self._exc_info_to_string(err, test=test))
489
+ self.add_pending_test_case_result(test)
490
+
491
+ def addUnexpectedSuccess(self, test):
492
+ super().addUnexpectedSuccess(test)
493
+ test_name = test.id() or str(test)
494
+ error_summary = ('error', '', '',
495
+ 'Test case %s should have failed, but passed.'
496
+ % (test_name))
497
+ self.add_pending_test_case_result(test, error_summary=error_summary)
498
+
499
+ def addSubTest(self, test, subtest, err): # pylint: disable=invalid-name
500
+ super().addSubTest(test, subtest, err)
501
+ if err is not None:
502
+ if issubclass(err[0], test.failureException):
503
+ error_summary = ('failure', err[0], err[1],
504
+ self._exc_info_to_string(err, test=test))
505
+ else:
506
+ error_summary = ('error', err[0], err[1],
507
+ self._exc_info_to_string(err, test=test))
508
+ else:
509
+ error_summary = None
510
+ self.add_pending_test_case_result(subtest, error_summary=error_summary)
511
+
512
+ def printErrors(self):
513
+ super().printErrors()
514
+ self.xml_stream.write('<?xml version="1.0"?>\n')
515
+ self.suite.print_xml_summary(self.xml_stream)
516
+
517
+
518
+ class TextAndXMLTestRunner(unittest.TextTestRunner):
519
+ """A test runner that produces both formatted text results and XML.
520
+
521
+ It prints out the names of tests as they are run, errors as they
522
+ occur, and a summary of the results at the end of the test run.
523
+ """
524
+
525
+ _TEST_RESULT_CLASS = _TextAndXMLTestResult
526
+
527
+ _xml_stream = None
528
+ _testsuites_properties: Dict[Any, Any] = {}
529
+
530
+ def __init__(self, xml_stream=None, *args, **kwargs):
531
+ """Initialize a TextAndXMLTestRunner.
532
+
533
+ Args:
534
+ xml_stream: file-like or None; XML-formatted test results are output
535
+ via this object's write() method. If None (the default), the
536
+ new instance behaves as described in the set_default_xml_stream method
537
+ documentation below.
538
+ *args: passed unmodified to unittest.TextTestRunner.__init__.
539
+ **kwargs: passed unmodified to unittest.TextTestRunner.__init__.
540
+ """
541
+ super().__init__(*args, **kwargs)
542
+ if xml_stream is not None:
543
+ self._xml_stream = xml_stream
544
+ # else, do not set self._xml_stream to None -- this allows implicit fallback
545
+ # to the class attribute's value.
546
+
547
+ @classmethod
548
+ def set_default_xml_stream(cls, xml_stream):
549
+ """Sets the default XML stream for the class.
550
+
551
+ Args:
552
+ xml_stream: file-like or None; used for instances when xml_stream is None
553
+ or not passed to their constructors. If None is passed, instances
554
+ created with xml_stream=None will act as ordinary TextTestRunner
555
+ instances; this is the default state before any calls to this method
556
+ have been made.
557
+ """
558
+ cls._xml_stream = xml_stream
559
+
560
+ def _makeResult(self):
561
+ if self._xml_stream is None:
562
+ return super()._makeResult()
563
+ else:
564
+ return self._TEST_RESULT_CLASS(
565
+ self._xml_stream, self.stream, self.descriptions, self.verbosity,
566
+ testsuites_properties=self._testsuites_properties)
567
+
568
+ @classmethod
569
+ def set_testsuites_property(cls, key, value):
570
+ cls._testsuites_properties[key] = value
lib/python3.10/site-packages/absl_py-2.3.1.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
lib/python3.10/site-packages/absl_py-2.3.1.dist-info/METADATA ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: absl-py
3
+ Version: 2.3.1
4
+ Summary: Abseil Python Common Libraries, see https://github.com/abseil/abseil-py.
5
+ Project-URL: Changelog, https://github.com/abseil/abseil-py/blob/main/CHANGELOG.md
6
+ Project-URL: Documentation, https://abseil.io/docs/python/
7
+ Project-URL: Issues, https://github.com/abseil/abseil-py/issues
8
+ Project-URL: Source, https://github.com/abseil/abseil-py
9
+ Author: The Abseil Authors
10
+ License-Expression: Apache-2.0
11
+ License-File: AUTHORS
12
+ License-File: LICENSE
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Requires-Python: >=3.8
26
+ Description-Content-Type: text/markdown
27
+
28
+ [![Package version](https://img.shields.io/pypi/v/absl-py)](https://pypi.org/project/absl-py)
29
+ [![Supported Python versions](https://img.shields.io/pypi/pyversions/absl-py.svg?style=flat-square)](https://pypi.org/project/absl-py)
30
+ [![License](https://img.shields.io/github/license/abseil/abseil-py)](https://github.com/abseil/abseil-py/blob/main/LICENSE)
31
+ [![Build Status](https://github.com/abseil/abseil-py/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/abseil/abseil-py/actions)
32
+ [![Overall downloads](https://pepy.tech/badge/absl-py)](https://pepy.tech/project/absl-py)
33
+ [![Last month downloads](https://pepy.tech/badge/absl-py/month)](https://pepy.tech/project/absl-py)
34
+
35
+ # Abseil Python Common Libraries
36
+
37
+ This repository is a collection of Python library code for building Python
38
+ applications. The code is collected from Google's own Python code base, and has
39
+ been extensively tested and used in production.
40
+
41
+ ## Features
42
+
43
+ * Simple application startup
44
+ * Distributed commandline flags system
45
+ * Custom logging module with additional features
46
+ * Testing utilities
47
+
48
+ ## Getting Started
49
+
50
+ ### Installation
51
+
52
+ To install the package, simply run:
53
+
54
+ ```bash
55
+ pip install absl-py
56
+ ```
57
+
58
+ Or install from source:
59
+
60
+ ```bash
61
+ pip install .
62
+ ```
63
+
64
+ ### Running Tests
65
+
66
+ To run Abseil tests, you can clone the git repo and run
67
+ [bazel](https://bazel.build/):
68
+
69
+ ```bash
70
+ git clone https://github.com/abseil/abseil-py.git
71
+ cd abseil-py
72
+ bazel test absl/...
73
+ ```
74
+
75
+ Please also validate the type annotations against the latest mypy:
76
+
77
+ ```bash
78
+ pip install mypy
79
+ mypy absl
80
+ ```
81
+
82
+ ### Example Code
83
+
84
+ Please refer to
85
+ [smoke_tests/sample_app.py](https://github.com/abseil/abseil-py/blob/main/smoke_tests/sample_app.py)
86
+ as an example to get started.
87
+
88
+ ## Documentation
89
+
90
+ See the [Abseil Python Developer Guide](https://abseil.io/docs/python/).
91
+
92
+ ## Future Releases
93
+
94
+ The current repository includes an initial set of libraries for early adoption.
95
+ More components and interoperability with Abseil C++ Common Libraries
96
+ will come in future releases.
97
+
98
+ ## License
99
+
100
+ The Abseil Python library is licensed under the terms of the Apache
101
+ license. See [LICENSE](LICENSE) for more information.
lib/python3.10/site-packages/absl_py-2.3.1.dist-info/RECORD ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ absl/__init__.py,sha256=9iJ5PwnoYh12ztceccjD2JbnSvx6d2JVElEurn9cqJk,607
2
+ absl/__pycache__/__init__.cpython-310.pyc,,
3
+ absl/__pycache__/app.cpython-310.pyc,,
4
+ absl/__pycache__/command_name.cpython-310.pyc,,
5
+ absl/app.py,sha256=0WJpjLaYcgcXtl9NTn-i5jSEfAoweMg4SXAel2XLF0Y,15360
6
+ absl/app.pyi,sha256=NdRh0OBqWHKnc3hEjdLaspLdu6aDHn3XP360ZPZeQE8,1885
7
+ absl/command_name.py,sha256=FgWUMHmlX0yQxEuMPXxFxn5ayWWZSLB0cq8Vx361TpU,2283
8
+ absl/flags/__init__.py,sha256=n_uLeSK-15_1DKLb0wXivmt6A8xvADDC87D1yoJdqVU,7665
9
+ absl/flags/__pycache__/__init__.cpython-310.pyc,,
10
+ absl/flags/__pycache__/_argument_parser.cpython-310.pyc,,
11
+ absl/flags/__pycache__/_defines.cpython-310.pyc,,
12
+ absl/flags/__pycache__/_exceptions.cpython-310.pyc,,
13
+ absl/flags/__pycache__/_flag.cpython-310.pyc,,
14
+ absl/flags/__pycache__/_flagvalues.cpython-310.pyc,,
15
+ absl/flags/__pycache__/_helpers.cpython-310.pyc,,
16
+ absl/flags/__pycache__/_validators.cpython-310.pyc,,
17
+ absl/flags/__pycache__/_validators_classes.cpython-310.pyc,,
18
+ absl/flags/__pycache__/argparse_flags.cpython-310.pyc,,
19
+ absl/flags/_argument_parser.py,sha256=arzkHA3CbPJdJ7diqUyskdoaLtKt8Aij1EZCVH_qJHU,20629
20
+ absl/flags/_defines.py,sha256=NAK489NGv3YMvbYj2Jzl6q89HmAtmMI65di1L_RK7XE,52895
21
+ absl/flags/_exceptions.py,sha256=FZzlzhvkjqPImTxXqbS1pSPYKr_TvtOd5ellvoiVLDI,3619
22
+ absl/flags/_flag.py,sha256=mdMJFklKQdCi9WsWPvUlmBRoQ2IAPW0Z0lDIKj0Lsx8,20079
23
+ absl/flags/_flagvalues.py,sha256=cGzMsWxthqGYfpESReRSJCXjpRujosSmTT-efJW3CbQ,54364
24
+ absl/flags/_helpers.py,sha256=MHbgtRkbNpVnrr7_NCdkFi_x3voQa-1-bypqsunHCJE,14154
25
+ absl/flags/_validators.py,sha256=VcsJtZzohliNxsI974NECYpeozD8rswHNHXggrQ4BLo,14140
26
+ absl/flags/_validators_classes.py,sha256=PGUWzO7v3wPOHb9leIKKzry3q-pPeKCoMB_O7prLdnY,6093
27
+ absl/flags/argparse_flags.py,sha256=usJudgMpy3P6Vvq7-LmJNa2Rj3ygHM3hwDTGd1mbAzc,14386
28
+ absl/logging/__init__.py,sha256=XpcmJrFEzDK2iWTlmDwtNSScSiGiNedFibWuW0tWMbk,43583
29
+ absl/logging/__init__.pyi,sha256=39EEBOH_rAyDQJpwyito2vo4IAZP9hnw3-wXC_Gulvc,5925
30
+ absl/logging/__pycache__/__init__.cpython-310.pyc,,
31
+ absl/logging/__pycache__/converter.cpython-310.pyc,,
32
+ absl/logging/converter.py,sha256=6eBymfv9UNkog0BGat4HPWlxC_oSqvHcQ46jnSdtaMg,6323
33
+ absl/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ absl/testing/__init__.py,sha256=7cM57swk2T1Hc5wxmt-JpcaR6xfdPJyL_lyRqgODvuM,584
35
+ absl/testing/__pycache__/__init__.cpython-310.pyc,,
36
+ absl/testing/__pycache__/_bazelize_command.cpython-310.pyc,,
37
+ absl/testing/__pycache__/_pretty_print_reporter.cpython-310.pyc,,
38
+ absl/testing/__pycache__/absltest.cpython-310.pyc,,
39
+ absl/testing/__pycache__/flagsaver.cpython-310.pyc,,
40
+ absl/testing/__pycache__/parameterized.cpython-310.pyc,,
41
+ absl/testing/__pycache__/xml_reporter.cpython-310.pyc,,
42
+ absl/testing/_bazelize_command.py,sha256=qpioV02ln2sBBJ9kdlHgNpKk8_wxdz2hJGKbG6EWZMI,2287
43
+ absl/testing/_pretty_print_reporter.py,sha256=PZh9NXSXBbXDi0FOk-BOmpse8LXa92Er16tgyBRogMs,3065
44
+ absl/testing/absltest.py,sha256=PW4c4SVlOUPSvFIhayimJY2LEbJ7BAojob6u9SBUrck,105675
45
+ absl/testing/flagsaver.py,sha256=HIWzFyayy-Pa8TqTAXF7BtHQ7s9Uk68KE8AVVAM0o0w,13346
46
+ absl/testing/parameterized.py,sha256=TpTlWTUXjikGeUDE45AgubvnmHsPbFNj-wUtAwT-e6E,27817
47
+ absl/testing/xml_reporter.py,sha256=YFkM7SROW8aeoCCn8IsGZ4cqXu4x8MwL1oN42-OtPKI,21430
48
+ absl_py-2.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
49
+ absl_py-2.3.1.dist-info/METADATA,sha256=2HZS24vkmHw7GQqUWcDE_FdVXjW1dgVS7pWPdWJ5Yvg,3331
50
+ absl_py-2.3.1.dist-info/RECORD,,
51
+ absl_py-2.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
52
+ absl_py-2.3.1.dist-info/licenses/AUTHORS,sha256=YoLudsylaQg7W5mLn4FroQMuEnuNx8RpQrhkd_xvv6U,296
53
+ absl_py-2.3.1.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358