Spaces:
Paused
Paused
Upload 919 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +2 -0
- MLPY/Lib/site-packages/__pycache__/isympy.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/__pycache__/pythoncom.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/__pycache__/six.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/__pycache__/typing_extensions.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/_distutils_hack/__init__.py +128 -0
- MLPY/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/_distutils_hack/override.py +1 -0
- MLPY/Lib/site-packages/_yaml/__init__.py +33 -0
- MLPY/Lib/site-packages/_yaml/__pycache__/__init__.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/__init__.py +13 -0
- MLPY/Lib/site-packages/absl/__pycache__/__init__.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/__pycache__/app.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/__pycache__/command_name.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/app.py +480 -0
- MLPY/Lib/site-packages/absl/app.pyi +99 -0
- MLPY/Lib/site-packages/absl/command_name.py +63 -0
- MLPY/Lib/site-packages/absl/flags/__init__.py +225 -0
- MLPY/Lib/site-packages/absl/flags/__pycache__/__init__.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/flags/__pycache__/_argument_parser.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/flags/__pycache__/_defines.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/flags/__pycache__/_exceptions.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/flags/__pycache__/_flag.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/flags/__pycache__/_flagvalues.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/flags/__pycache__/_helpers.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/flags/__pycache__/_validators.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/flags/__pycache__/_validators_classes.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/flags/__pycache__/argparse_flags.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/flags/_argument_parser.py +638 -0
- MLPY/Lib/site-packages/absl/flags/_defines.py +1686 -0
- MLPY/Lib/site-packages/absl/flags/_exceptions.py +108 -0
- MLPY/Lib/site-packages/absl/flags/_flag.py +556 -0
- MLPY/Lib/site-packages/absl/flags/_flagvalues.py +1480 -0
- MLPY/Lib/site-packages/absl/flags/_helpers.py +421 -0
- MLPY/Lib/site-packages/absl/flags/_validators.py +352 -0
- MLPY/Lib/site-packages/absl/flags/_validators_classes.py +172 -0
- MLPY/Lib/site-packages/absl/flags/argparse_flags.py +388 -0
- MLPY/Lib/site-packages/absl/logging/__init__.py +1281 -0
- MLPY/Lib/site-packages/absl/logging/__init__.pyi +290 -0
- MLPY/Lib/site-packages/absl/logging/__pycache__/__init__.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/logging/__pycache__/converter.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/logging/converter.py +214 -0
- MLPY/Lib/site-packages/absl/testing/__init__.py +13 -0
- MLPY/Lib/site-packages/absl/testing/__pycache__/__init__.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/testing/__pycache__/_bazelize_command.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/testing/__pycache__/_pretty_print_reporter.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/testing/__pycache__/absltest.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/testing/__pycache__/flagsaver.cpython-39.pyc +0 -0
- MLPY/Lib/site-packages/absl/testing/__pycache__/parameterized.cpython-39.pyc +0 -0
.gitattributes
CHANGED
@@ -75,3 +75,5 @@ MLPY/Library/bin/mkl_vml_mc3.1.dll filter=lfs diff=lfs merge=lfs -text
|
|
75 |
MLPY/Library/bin/omptarget.rtl.level0.dll filter=lfs diff=lfs merge=lfs -text
|
76 |
MLPY/Library/bin/omptarget.rtl.opencl.dll filter=lfs diff=lfs merge=lfs -text
|
77 |
MLPY/Lib/site-packages/PyWin32.chm filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
75 |
MLPY/Library/bin/omptarget.rtl.level0.dll filter=lfs diff=lfs merge=lfs -text
|
76 |
MLPY/Library/bin/omptarget.rtl.opencl.dll filter=lfs diff=lfs merge=lfs -text
|
77 |
MLPY/Lib/site-packages/PyWin32.chm filter=lfs diff=lfs merge=lfs -text
|
78 |
+
MLPY/Lib/site-packages/google/protobuf/pyext/_message.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
79 |
+
MLPY/Lib/site-packages/grpc/_cython/cygrpc.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
|
MLPY/Lib/site-packages/__pycache__/isympy.cpython-39.pyc
ADDED
Binary file (9.4 kB). View file
|
|
MLPY/Lib/site-packages/__pycache__/pythoncom.cpython-39.pyc
ADDED
Binary file (229 Bytes). View file
|
|
MLPY/Lib/site-packages/__pycache__/six.cpython-39.pyc
ADDED
Binary file (27.5 kB). View file
|
|
MLPY/Lib/site-packages/__pycache__/typing_extensions.cpython-39.pyc
ADDED
Binary file (102 kB). View file
|
|
MLPY/Lib/site-packages/_distutils_hack/__init__.py
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
import os
|
3 |
+
import re
|
4 |
+
import importlib
|
5 |
+
import warnings
|
6 |
+
|
7 |
+
|
8 |
+
is_pypy = '__pypy__' in sys.builtin_module_names
|
9 |
+
|
10 |
+
|
11 |
+
warnings.filterwarnings('ignore',
|
12 |
+
r'.+ distutils\b.+ deprecated',
|
13 |
+
DeprecationWarning)
|
14 |
+
|
15 |
+
|
16 |
+
def warn_distutils_present():
|
17 |
+
if 'distutils' not in sys.modules:
|
18 |
+
return
|
19 |
+
if is_pypy and sys.version_info < (3, 7):
|
20 |
+
# PyPy for 3.6 unconditionally imports distutils, so bypass the warning
|
21 |
+
# https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
|
22 |
+
return
|
23 |
+
warnings.warn(
|
24 |
+
"Distutils was imported before Setuptools, but importing Setuptools "
|
25 |
+
"also replaces the `distutils` module in `sys.modules`. This may lead "
|
26 |
+
"to undesirable behaviors or errors. To avoid these issues, avoid "
|
27 |
+
"using distutils directly, ensure that setuptools is installed in the "
|
28 |
+
"traditional way (e.g. not an editable install), and/or make sure "
|
29 |
+
"that setuptools is always imported before distutils.")
|
30 |
+
|
31 |
+
|
32 |
+
def clear_distutils():
|
33 |
+
if 'distutils' not in sys.modules:
|
34 |
+
return
|
35 |
+
warnings.warn("Setuptools is replacing distutils.")
|
36 |
+
mods = [name for name in sys.modules if re.match(r'distutils\b', name)]
|
37 |
+
for name in mods:
|
38 |
+
del sys.modules[name]
|
39 |
+
|
40 |
+
|
41 |
+
def enabled():
|
42 |
+
"""
|
43 |
+
Allow selection of distutils by environment variable.
|
44 |
+
"""
|
45 |
+
which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib')
|
46 |
+
return which == 'local'
|
47 |
+
|
48 |
+
|
49 |
+
def ensure_local_distutils():
|
50 |
+
clear_distutils()
|
51 |
+
distutils = importlib.import_module('setuptools._distutils')
|
52 |
+
distutils.__name__ = 'distutils'
|
53 |
+
sys.modules['distutils'] = distutils
|
54 |
+
|
55 |
+
# sanity check that submodules load as expected
|
56 |
+
core = importlib.import_module('distutils.core')
|
57 |
+
assert '_distutils' in core.__file__, core.__file__
|
58 |
+
|
59 |
+
|
60 |
+
def do_override():
|
61 |
+
"""
|
62 |
+
Ensure that the local copy of distutils is preferred over stdlib.
|
63 |
+
|
64 |
+
See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
|
65 |
+
for more motivation.
|
66 |
+
"""
|
67 |
+
if enabled():
|
68 |
+
warn_distutils_present()
|
69 |
+
ensure_local_distutils()
|
70 |
+
|
71 |
+
|
72 |
+
class DistutilsMetaFinder:
|
73 |
+
def find_spec(self, fullname, path, target=None):
|
74 |
+
if path is not None:
|
75 |
+
return
|
76 |
+
|
77 |
+
method_name = 'spec_for_{fullname}'.format(**locals())
|
78 |
+
method = getattr(self, method_name, lambda: None)
|
79 |
+
return method()
|
80 |
+
|
81 |
+
def spec_for_distutils(self):
|
82 |
+
import importlib.abc
|
83 |
+
import importlib.util
|
84 |
+
|
85 |
+
class DistutilsLoader(importlib.abc.Loader):
|
86 |
+
|
87 |
+
def create_module(self, spec):
|
88 |
+
return importlib.import_module('setuptools._distutils')
|
89 |
+
|
90 |
+
def exec_module(self, module):
|
91 |
+
pass
|
92 |
+
|
93 |
+
return importlib.util.spec_from_loader('distutils', DistutilsLoader())
|
94 |
+
|
95 |
+
def spec_for_pip(self):
|
96 |
+
"""
|
97 |
+
Ensure stdlib distutils when running under pip.
|
98 |
+
See pypa/pip#8761 for rationale.
|
99 |
+
"""
|
100 |
+
if self.pip_imported_during_build():
|
101 |
+
return
|
102 |
+
clear_distutils()
|
103 |
+
self.spec_for_distutils = lambda: None
|
104 |
+
|
105 |
+
@staticmethod
|
106 |
+
def pip_imported_during_build():
|
107 |
+
"""
|
108 |
+
Detect if pip is being imported in a build script. Ref #2355.
|
109 |
+
"""
|
110 |
+
import traceback
|
111 |
+
return any(
|
112 |
+
frame.f_globals['__file__'].endswith('setup.py')
|
113 |
+
for frame, line in traceback.walk_stack(None)
|
114 |
+
)
|
115 |
+
|
116 |
+
|
117 |
+
DISTUTILS_FINDER = DistutilsMetaFinder()
|
118 |
+
|
119 |
+
|
120 |
+
def add_shim():
|
121 |
+
sys.meta_path.insert(0, DISTUTILS_FINDER)
|
122 |
+
|
123 |
+
|
124 |
+
def remove_shim():
|
125 |
+
try:
|
126 |
+
sys.meta_path.remove(DISTUTILS_FINDER)
|
127 |
+
except ValueError:
|
128 |
+
pass
|
MLPY/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (5.07 kB). View file
|
|
MLPY/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-39.pyc
ADDED
Binary file (203 Bytes). View file
|
|
MLPY/Lib/site-packages/_distutils_hack/override.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
__import__('_distutils_hack').do_override()
|
MLPY/Lib/site-packages/_yaml/__init__.py
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This is a stub package designed to roughly emulate the _yaml
|
2 |
+
# extension module, which previously existed as a standalone module
|
3 |
+
# and has been moved into the `yaml` package namespace.
|
4 |
+
# It does not perfectly mimic its old counterpart, but should get
|
5 |
+
# close enough for anyone who's relying on it even when they shouldn't.
|
6 |
+
import yaml
|
7 |
+
|
8 |
+
# in some circumstances, the yaml module we imoprted may be from a different version, so we need
|
9 |
+
# to tread carefully when poking at it here (it may not have the attributes we expect)
|
10 |
+
if not getattr(yaml, '__with_libyaml__', False):
|
11 |
+
from sys import version_info
|
12 |
+
|
13 |
+
exc = ModuleNotFoundError if version_info >= (3, 6) else ImportError
|
14 |
+
raise exc("No module named '_yaml'")
|
15 |
+
else:
|
16 |
+
from yaml._yaml import *
|
17 |
+
import warnings
|
18 |
+
warnings.warn(
|
19 |
+
'The _yaml extension module is now located at yaml._yaml'
|
20 |
+
' and its location is subject to change. To use the'
|
21 |
+
' LibYAML-based parser and emitter, import from `yaml`:'
|
22 |
+
' `from yaml import CLoader as Loader, CDumper as Dumper`.',
|
23 |
+
DeprecationWarning
|
24 |
+
)
|
25 |
+
del warnings
|
26 |
+
# Don't `del yaml` here because yaml is actually an existing
|
27 |
+
# namespace member of _yaml.
|
28 |
+
|
29 |
+
__name__ = '_yaml'
|
30 |
+
# If the module is top-level (i.e. not a part of any specific package)
|
31 |
+
# then the attribute should be set to ''.
|
32 |
+
# https://docs.python.org/3.8/library/types.html
|
33 |
+
__package__ = ''
|
MLPY/Lib/site-packages/_yaml/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (706 Bytes). View file
|
|
MLPY/Lib/site-packages/absl/__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.
|
MLPY/Lib/site-packages/absl/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (141 Bytes). View file
|
|
MLPY/Lib/site-packages/absl/__pycache__/app.cpython-39.pyc
ADDED
Binary file (13.9 kB). View file
|
|
MLPY/Lib/site-packages/absl/__pycache__/command_name.cpython-39.pyc
ADDED
Binary file (1.63 kB). View file
|
|
MLPY/Lib/site-packages/absl/app.py
ADDED
@@ -0,0 +1,480 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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(UsageError, self).__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(HelpFlag, self).__init__(
|
99 |
+
self.NAME, False, 'show this help',
|
100 |
+
short_name=self.SHORT_NAME, allow_hide_cpp=True)
|
101 |
+
|
102 |
+
def parse(self, arg):
|
103 |
+
if self._parse(arg):
|
104 |
+
usage(shorthelp=True, writeto_stdout=True)
|
105 |
+
# Advertise --helpfull on stdout, since usage() was on stdout.
|
106 |
+
print()
|
107 |
+
print('Try --helpfull to get a list of all flags.')
|
108 |
+
sys.exit(1)
|
109 |
+
|
110 |
+
|
111 |
+
class HelpshortFlag(HelpFlag):
|
112 |
+
"""--helpshort is an alias for --help."""
|
113 |
+
NAME = 'helpshort'
|
114 |
+
SHORT_NAME = None
|
115 |
+
|
116 |
+
|
117 |
+
class HelpfullFlag(flags.BooleanFlag):
|
118 |
+
"""Display help for flags in the main module and all dependent modules."""
|
119 |
+
|
120 |
+
def __init__(self):
|
121 |
+
super(HelpfullFlag, self).__init__(
|
122 |
+
'helpfull', False, 'show full help', allow_hide_cpp=True)
|
123 |
+
|
124 |
+
def parse(self, arg):
|
125 |
+
if self._parse(arg):
|
126 |
+
usage(writeto_stdout=True)
|
127 |
+
sys.exit(1)
|
128 |
+
|
129 |
+
|
130 |
+
class HelpXMLFlag(flags.BooleanFlag):
|
131 |
+
"""Similar to HelpfullFlag, but generates output in XML format."""
|
132 |
+
|
133 |
+
def __init__(self):
|
134 |
+
super(HelpXMLFlag, self).__init__(
|
135 |
+
'helpxml', False, 'like --helpfull, but generates XML output',
|
136 |
+
allow_hide_cpp=True)
|
137 |
+
|
138 |
+
def parse(self, arg):
|
139 |
+
if self._parse(arg):
|
140 |
+
flags.FLAGS.write_help_in_xml_format(sys.stdout)
|
141 |
+
sys.exit(1)
|
142 |
+
|
143 |
+
|
144 |
+
def parse_flags_with_usage(args):
|
145 |
+
"""Tries to parse the flags, print usage, and exit if unparsable.
|
146 |
+
|
147 |
+
Args:
|
148 |
+
args: [str], a non-empty list of the command line arguments including
|
149 |
+
program name.
|
150 |
+
|
151 |
+
Returns:
|
152 |
+
[str], a non-empty list of remaining command line arguments after parsing
|
153 |
+
flags, including program name.
|
154 |
+
"""
|
155 |
+
try:
|
156 |
+
return FLAGS(args)
|
157 |
+
except flags.Error as error:
|
158 |
+
message = str(error)
|
159 |
+
if '\n' in message:
|
160 |
+
final_message = 'FATAL Flags parsing error:\n%s\n' % textwrap.indent(
|
161 |
+
message, ' ')
|
162 |
+
else:
|
163 |
+
final_message = 'FATAL Flags parsing error: %s\n' % message
|
164 |
+
sys.stderr.write(final_message)
|
165 |
+
sys.stderr.write('Pass --helpshort or --helpfull to see help on flags.\n')
|
166 |
+
sys.exit(1)
|
167 |
+
|
168 |
+
|
169 |
+
_define_help_flags_called = False
|
170 |
+
|
171 |
+
|
172 |
+
def define_help_flags():
|
173 |
+
"""Registers help flags. Idempotent."""
|
174 |
+
# Use a global to ensure idempotence.
|
175 |
+
global _define_help_flags_called
|
176 |
+
|
177 |
+
if not _define_help_flags_called:
|
178 |
+
flags.DEFINE_flag(HelpFlag())
|
179 |
+
flags.DEFINE_flag(HelpshortFlag()) # alias for --help
|
180 |
+
flags.DEFINE_flag(HelpfullFlag())
|
181 |
+
flags.DEFINE_flag(HelpXMLFlag())
|
182 |
+
_define_help_flags_called = True
|
183 |
+
|
184 |
+
|
185 |
+
def _register_and_parse_flags_with_usage(
|
186 |
+
argv=None,
|
187 |
+
flags_parser=parse_flags_with_usage,
|
188 |
+
):
|
189 |
+
"""Registers help flags, parses arguments and shows usage if appropriate.
|
190 |
+
|
191 |
+
This also calls sys.exit(0) if flag --only_check_args is True.
|
192 |
+
|
193 |
+
Args:
|
194 |
+
argv: [str], a non-empty list of the command line arguments including
|
195 |
+
program name, sys.argv is used if None.
|
196 |
+
flags_parser: Callable[[List[Text]], Any], the function used to parse flags.
|
197 |
+
The return value of this function is passed to `main` untouched.
|
198 |
+
It must guarantee FLAGS is parsed after this function is called.
|
199 |
+
|
200 |
+
Returns:
|
201 |
+
The return value of `flags_parser`. When using the default `flags_parser`,
|
202 |
+
it returns the following:
|
203 |
+
[str], a non-empty list of remaining command line arguments after parsing
|
204 |
+
flags, including program name.
|
205 |
+
|
206 |
+
Raises:
|
207 |
+
Error: Raised when flags_parser is called, but FLAGS is not parsed.
|
208 |
+
SystemError: Raised when it's called more than once.
|
209 |
+
"""
|
210 |
+
if _register_and_parse_flags_with_usage.done:
|
211 |
+
raise SystemError('Flag registration can be done only once.')
|
212 |
+
|
213 |
+
define_help_flags()
|
214 |
+
|
215 |
+
original_argv = sys.argv if argv is None else argv
|
216 |
+
args_to_main = flags_parser(original_argv)
|
217 |
+
if not FLAGS.is_parsed():
|
218 |
+
raise Error('FLAGS must be parsed after flags_parser is called.')
|
219 |
+
|
220 |
+
# Exit when told so.
|
221 |
+
if FLAGS.only_check_args:
|
222 |
+
sys.exit(0)
|
223 |
+
# Immediately after flags are parsed, bump verbosity to INFO if the flag has
|
224 |
+
# not been set.
|
225 |
+
if FLAGS['verbosity'].using_default_value:
|
226 |
+
FLAGS.verbosity = 0
|
227 |
+
_register_and_parse_flags_with_usage.done = True
|
228 |
+
|
229 |
+
return args_to_main
|
230 |
+
|
231 |
+
_register_and_parse_flags_with_usage.done = False
|
232 |
+
|
233 |
+
|
234 |
+
def _run_main(main, argv):
|
235 |
+
"""Calls main, optionally with pdb or profiler."""
|
236 |
+
if FLAGS.run_with_pdb:
|
237 |
+
sys.exit(pdb.runcall(main, argv))
|
238 |
+
elif FLAGS.run_with_profiling or FLAGS.profile_file:
|
239 |
+
# Avoid import overhead since most apps (including performance-sensitive
|
240 |
+
# ones) won't be run with profiling.
|
241 |
+
# pylint: disable=g-import-not-at-top
|
242 |
+
import atexit
|
243 |
+
if FLAGS.use_cprofile_for_profiling:
|
244 |
+
import cProfile as profile
|
245 |
+
else:
|
246 |
+
import profile
|
247 |
+
profiler = profile.Profile()
|
248 |
+
if FLAGS.profile_file:
|
249 |
+
atexit.register(profiler.dump_stats, FLAGS.profile_file)
|
250 |
+
else:
|
251 |
+
atexit.register(profiler.print_stats)
|
252 |
+
sys.exit(profiler.runcall(main, argv))
|
253 |
+
else:
|
254 |
+
sys.exit(main(argv))
|
255 |
+
|
256 |
+
|
257 |
+
def _call_exception_handlers(exception):
|
258 |
+
"""Calls any installed exception handlers."""
|
259 |
+
for handler in EXCEPTION_HANDLERS:
|
260 |
+
try:
|
261 |
+
if handler.wants(exception):
|
262 |
+
handler.handle(exception)
|
263 |
+
except: # pylint: disable=bare-except
|
264 |
+
try:
|
265 |
+
# We don't want to stop for exceptions in the exception handlers but
|
266 |
+
# we shouldn't hide them either.
|
267 |
+
logging.error(traceback.format_exc())
|
268 |
+
except: # pylint: disable=bare-except
|
269 |
+
# In case even the logging statement fails, ignore.
|
270 |
+
pass
|
271 |
+
|
272 |
+
|
273 |
+
def run(
|
274 |
+
main,
|
275 |
+
argv=None,
|
276 |
+
flags_parser=parse_flags_with_usage,
|
277 |
+
):
|
278 |
+
"""Begins executing the program.
|
279 |
+
|
280 |
+
Args:
|
281 |
+
main: The main function to execute. It takes an single argument "argv",
|
282 |
+
which is a list of command line arguments with parsed flags removed.
|
283 |
+
The return value is passed to `sys.exit`, and so for example
|
284 |
+
a return value of 0 or None results in a successful termination, whereas
|
285 |
+
a return value of 1 results in abnormal termination.
|
286 |
+
For more details, see https://docs.python.org/3/library/sys#sys.exit
|
287 |
+
argv: A non-empty list of the command line arguments including program name,
|
288 |
+
sys.argv is used if None.
|
289 |
+
flags_parser: Callable[[List[Text]], Any], the function used to parse flags.
|
290 |
+
The return value of this function is passed to `main` untouched.
|
291 |
+
It must guarantee FLAGS is parsed after this function is called.
|
292 |
+
Should be passed as a keyword-only arg which will become mandatory in a
|
293 |
+
future release.
|
294 |
+
- Parses command line flags with the flag module.
|
295 |
+
- If there are any errors, prints usage().
|
296 |
+
- Calls main() with the remaining arguments.
|
297 |
+
- If main() raises a UsageError, prints usage and the error message.
|
298 |
+
"""
|
299 |
+
try:
|
300 |
+
args = _run_init(
|
301 |
+
sys.argv if argv is None else argv,
|
302 |
+
flags_parser,
|
303 |
+
)
|
304 |
+
while _init_callbacks:
|
305 |
+
callback = _init_callbacks.popleft()
|
306 |
+
callback()
|
307 |
+
try:
|
308 |
+
_run_main(main, args)
|
309 |
+
except UsageError as error:
|
310 |
+
usage(shorthelp=True, detailed_error=error, exitcode=error.exitcode)
|
311 |
+
except:
|
312 |
+
exc = sys.exc_info()[1]
|
313 |
+
# Don't try to post-mortem debug successful SystemExits, since those
|
314 |
+
# mean there wasn't actually an error. In particular, the test framework
|
315 |
+
# raises SystemExit(False) even if all tests passed.
|
316 |
+
if isinstance(exc, SystemExit) and not exc.code:
|
317 |
+
raise
|
318 |
+
|
319 |
+
# Check the tty so that we don't hang waiting for input in an
|
320 |
+
# non-interactive scenario.
|
321 |
+
if FLAGS.pdb_post_mortem and sys.stdout.isatty():
|
322 |
+
traceback.print_exc()
|
323 |
+
print()
|
324 |
+
print(' *** Entering post-mortem debugging ***')
|
325 |
+
print()
|
326 |
+
pdb.post_mortem()
|
327 |
+
raise
|
328 |
+
except Exception as e:
|
329 |
+
_call_exception_handlers(e)
|
330 |
+
raise
|
331 |
+
|
332 |
+
# Callbacks which have been deferred until after _run_init has been called.
|
333 |
+
_init_callbacks = collections.deque()
|
334 |
+
|
335 |
+
|
336 |
+
def call_after_init(callback):
|
337 |
+
"""Calls the given callback only once ABSL has finished initialization.
|
338 |
+
|
339 |
+
If ABSL has already finished initialization when ``call_after_init`` is
|
340 |
+
called then the callback is executed immediately, otherwise `callback` is
|
341 |
+
stored to be executed after ``app.run`` has finished initializing (aka. just
|
342 |
+
before the main function is called).
|
343 |
+
|
344 |
+
If called after ``app.run``, this is equivalent to calling ``callback()`` in
|
345 |
+
the caller thread. If called before ``app.run``, callbacks are run
|
346 |
+
sequentially (in an undefined order) in the same thread as ``app.run``.
|
347 |
+
|
348 |
+
Args:
|
349 |
+
callback: a callable to be called once ABSL has finished initialization.
|
350 |
+
This may be immediate if initialization has already finished. It
|
351 |
+
takes no arguments and returns nothing.
|
352 |
+
"""
|
353 |
+
if _run_init.done:
|
354 |
+
callback()
|
355 |
+
else:
|
356 |
+
_init_callbacks.append(callback)
|
357 |
+
|
358 |
+
|
359 |
+
def _run_init(
|
360 |
+
argv,
|
361 |
+
flags_parser,
|
362 |
+
):
|
363 |
+
"""Does one-time initialization and re-parses flags on rerun."""
|
364 |
+
if _run_init.done:
|
365 |
+
return flags_parser(argv)
|
366 |
+
command_name.make_process_name_useful()
|
367 |
+
# Set up absl logging handler.
|
368 |
+
logging.use_absl_handler()
|
369 |
+
args = _register_and_parse_flags_with_usage(
|
370 |
+
argv=argv,
|
371 |
+
flags_parser=flags_parser,
|
372 |
+
)
|
373 |
+
if faulthandler:
|
374 |
+
try:
|
375 |
+
faulthandler.enable()
|
376 |
+
except Exception: # pylint: disable=broad-except
|
377 |
+
# Some tests verify stderr output very closely, so don't print anything.
|
378 |
+
# Disabled faulthandler is a low-impact error.
|
379 |
+
pass
|
380 |
+
_run_init.done = True
|
381 |
+
return args
|
382 |
+
|
383 |
+
|
384 |
+
_run_init.done = False
|
385 |
+
|
386 |
+
|
387 |
+
def usage(shorthelp=False, writeto_stdout=False, detailed_error=None,
|
388 |
+
exitcode=None):
|
389 |
+
"""Writes __main__'s docstring to stderr with some help text.
|
390 |
+
|
391 |
+
Args:
|
392 |
+
shorthelp: bool, if True, prints only flags from the main module,
|
393 |
+
rather than all flags.
|
394 |
+
writeto_stdout: bool, if True, writes help message to stdout,
|
395 |
+
rather than to stderr.
|
396 |
+
detailed_error: str, additional detail about why usage info was presented.
|
397 |
+
exitcode: optional integer, if set, exits with this status code after
|
398 |
+
writing help.
|
399 |
+
"""
|
400 |
+
if writeto_stdout:
|
401 |
+
stdfile = sys.stdout
|
402 |
+
else:
|
403 |
+
stdfile = sys.stderr
|
404 |
+
|
405 |
+
doc = sys.modules['__main__'].__doc__
|
406 |
+
if not doc:
|
407 |
+
doc = '\nUSAGE: %s [flags]\n' % sys.argv[0]
|
408 |
+
doc = flags.text_wrap(doc, indent=' ', firstline_indent='')
|
409 |
+
else:
|
410 |
+
# Replace all '%s' with sys.argv[0], and all '%%' with '%'.
|
411 |
+
num_specifiers = doc.count('%') - 2 * doc.count('%%')
|
412 |
+
try:
|
413 |
+
doc %= (sys.argv[0],) * num_specifiers
|
414 |
+
except (OverflowError, TypeError, ValueError):
|
415 |
+
# Just display the docstring as-is.
|
416 |
+
pass
|
417 |
+
if shorthelp:
|
418 |
+
flag_str = FLAGS.main_module_help()
|
419 |
+
else:
|
420 |
+
flag_str = FLAGS.get_help()
|
421 |
+
try:
|
422 |
+
stdfile.write(doc)
|
423 |
+
if flag_str:
|
424 |
+
stdfile.write('\nflags:\n')
|
425 |
+
stdfile.write(flag_str)
|
426 |
+
stdfile.write('\n')
|
427 |
+
if detailed_error is not None:
|
428 |
+
stdfile.write('\n%s\n' % detailed_error)
|
429 |
+
except IOError as e:
|
430 |
+
# We avoid printing a huge backtrace if we get EPIPE, because
|
431 |
+
# "foo.par --help | less" is a frequent use case.
|
432 |
+
if e.errno != errno.EPIPE:
|
433 |
+
raise
|
434 |
+
if exitcode is not None:
|
435 |
+
sys.exit(exitcode)
|
436 |
+
|
437 |
+
|
438 |
+
class ExceptionHandler(object):
|
439 |
+
"""Base exception handler from which other may inherit."""
|
440 |
+
|
441 |
+
def wants(self, exc):
|
442 |
+
"""Returns whether this handler wants to handle the exception or not.
|
443 |
+
|
444 |
+
This base class returns True for all exceptions by default. Override in
|
445 |
+
subclass if it wants to be more selective.
|
446 |
+
|
447 |
+
Args:
|
448 |
+
exc: Exception, the current exception.
|
449 |
+
"""
|
450 |
+
del exc # Unused.
|
451 |
+
return True
|
452 |
+
|
453 |
+
def handle(self, exc):
|
454 |
+
"""Do something with the current exception.
|
455 |
+
|
456 |
+
Args:
|
457 |
+
exc: Exception, the current exception
|
458 |
+
|
459 |
+
This method must be overridden.
|
460 |
+
"""
|
461 |
+
raise NotImplementedError()
|
462 |
+
|
463 |
+
|
464 |
+
def install_exception_handler(handler):
|
465 |
+
"""Installs an exception handler.
|
466 |
+
|
467 |
+
Args:
|
468 |
+
handler: ExceptionHandler, the exception handler to install.
|
469 |
+
|
470 |
+
Raises:
|
471 |
+
TypeError: Raised when the handler was not of the correct type.
|
472 |
+
|
473 |
+
All installed exception handlers will be called if main() exits via
|
474 |
+
an abnormal exception, i.e. not one of SystemExit, KeyboardInterrupt,
|
475 |
+
FlagsError or UsageError.
|
476 |
+
"""
|
477 |
+
if not isinstance(handler, ExceptionHandler):
|
478 |
+
raise TypeError('handler of type %s does not inherit from ExceptionHandler'
|
479 |
+
% type(handler))
|
480 |
+
EXCEPTION_HANDLERS.append(handler)
|
MLPY/Lib/site-packages/absl/app.pyi
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
from typing import Any, Callable, Collection, Iterable, List, NoReturn, Optional, Text, TypeVar, Union, overload
|
3 |
+
|
4 |
+
from absl.flags import _flag
|
5 |
+
|
6 |
+
|
7 |
+
_MainArgs = TypeVar('_MainArgs')
|
8 |
+
_Exc = TypeVar('_Exc', bound=Exception)
|
9 |
+
|
10 |
+
|
11 |
+
class ExceptionHandler():
|
12 |
+
|
13 |
+
def wants(self, exc: _Exc) -> bool:
|
14 |
+
...
|
15 |
+
|
16 |
+
def handle(self, exc: _Exc):
|
17 |
+
...
|
18 |
+
|
19 |
+
|
20 |
+
EXCEPTION_HANDLERS: List[ExceptionHandler] = ...
|
21 |
+
|
22 |
+
|
23 |
+
class HelpFlag(_flag.BooleanFlag):
|
24 |
+
def __init__(self):
|
25 |
+
...
|
26 |
+
|
27 |
+
|
28 |
+
class HelpshortFlag(HelpFlag):
|
29 |
+
...
|
30 |
+
|
31 |
+
|
32 |
+
class HelpfullFlag(_flag.BooleanFlag):
|
33 |
+
def __init__(self):
|
34 |
+
...
|
35 |
+
|
36 |
+
|
37 |
+
class HelpXMLFlag(_flag.BooleanFlag):
|
38 |
+
def __init__(self):
|
39 |
+
...
|
40 |
+
|
41 |
+
|
42 |
+
def define_help_flags() -> None:
|
43 |
+
...
|
44 |
+
|
45 |
+
|
46 |
+
@overload
|
47 |
+
def usage(shorthelp: Union[bool, int] = ...,
|
48 |
+
writeto_stdout: Union[bool, int] = ...,
|
49 |
+
detailed_error: Optional[Any] = ...,
|
50 |
+
exitcode: None = ...) -> None:
|
51 |
+
...
|
52 |
+
|
53 |
+
|
54 |
+
@overload
|
55 |
+
def usage(shorthelp: Union[bool, int] = ...,
|
56 |
+
writeto_stdout: Union[bool, int] = ...,
|
57 |
+
detailed_error: Optional[Any] = ...,
|
58 |
+
exitcode: int = ...) -> NoReturn:
|
59 |
+
...
|
60 |
+
|
61 |
+
|
62 |
+
def install_exception_handler(handler: ExceptionHandler) -> None:
|
63 |
+
...
|
64 |
+
|
65 |
+
|
66 |
+
class Error(Exception):
|
67 |
+
...
|
68 |
+
|
69 |
+
|
70 |
+
class UsageError(Error):
|
71 |
+
exitcode: int
|
72 |
+
|
73 |
+
|
74 |
+
def parse_flags_with_usage(args: List[Text]) -> List[Text]:
|
75 |
+
...
|
76 |
+
|
77 |
+
|
78 |
+
def call_after_init(callback: Callable[[], Any]) -> None:
|
79 |
+
...
|
80 |
+
|
81 |
+
|
82 |
+
# Without the flag_parser argument, `main` should require a List[Text].
|
83 |
+
@overload
|
84 |
+
def run(
|
85 |
+
main: Callable[[List[Text]], Any],
|
86 |
+
argv: Optional[List[Text]] = ...,
|
87 |
+
*,
|
88 |
+
) -> NoReturn:
|
89 |
+
...
|
90 |
+
|
91 |
+
|
92 |
+
@overload
|
93 |
+
def run(
|
94 |
+
main: Callable[[_MainArgs], Any],
|
95 |
+
argv: Optional[List[Text]] = ...,
|
96 |
+
*,
|
97 |
+
flags_parser: Callable[[List[Text]], _MainArgs],
|
98 |
+
) -> NoReturn:
|
99 |
+
...
|
MLPY/Lib/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 EnvironmentError:
|
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 EnvironmentError:
|
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.
|
MLPY/Lib/site-packages/absl/flags/__init__.py
ADDED
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 getopt
|
29 |
+
import os
|
30 |
+
import re
|
31 |
+
import sys
|
32 |
+
import types
|
33 |
+
import warnings
|
34 |
+
|
35 |
+
from absl.flags import _argument_parser
|
36 |
+
from absl.flags import _defines
|
37 |
+
from absl.flags import _exceptions
|
38 |
+
from absl.flags import _flag
|
39 |
+
from absl.flags import _flagvalues
|
40 |
+
from absl.flags import _helpers
|
41 |
+
from absl.flags import _validators
|
42 |
+
|
43 |
+
__all__ = (
|
44 |
+
'DEFINE',
|
45 |
+
'DEFINE_flag',
|
46 |
+
'DEFINE_string',
|
47 |
+
'DEFINE_boolean',
|
48 |
+
'DEFINE_bool',
|
49 |
+
'DEFINE_float',
|
50 |
+
'DEFINE_integer',
|
51 |
+
'DEFINE_enum',
|
52 |
+
'DEFINE_enum_class',
|
53 |
+
'DEFINE_list',
|
54 |
+
'DEFINE_spaceseplist',
|
55 |
+
'DEFINE_multi',
|
56 |
+
'DEFINE_multi_string',
|
57 |
+
'DEFINE_multi_integer',
|
58 |
+
'DEFINE_multi_float',
|
59 |
+
'DEFINE_multi_enum',
|
60 |
+
'DEFINE_multi_enum_class',
|
61 |
+
'DEFINE_alias',
|
62 |
+
# Flag validators.
|
63 |
+
'register_validator',
|
64 |
+
'validator',
|
65 |
+
'register_multi_flags_validator',
|
66 |
+
'multi_flags_validator',
|
67 |
+
'mark_flag_as_required',
|
68 |
+
'mark_flags_as_required',
|
69 |
+
'mark_flags_as_mutual_exclusive',
|
70 |
+
'mark_bool_flags_as_mutual_exclusive',
|
71 |
+
# Flag modifiers.
|
72 |
+
'set_default',
|
73 |
+
'override_value',
|
74 |
+
# Key flag related functions.
|
75 |
+
'declare_key_flag',
|
76 |
+
'adopt_module_key_flags',
|
77 |
+
'disclaim_key_flags',
|
78 |
+
# Module exceptions.
|
79 |
+
'Error',
|
80 |
+
'CantOpenFlagFileError',
|
81 |
+
'DuplicateFlagError',
|
82 |
+
'IllegalFlagValueError',
|
83 |
+
'UnrecognizedFlagError',
|
84 |
+
'UnparsedFlagAccessError',
|
85 |
+
'ValidationError',
|
86 |
+
'FlagNameConflictsWithMethodError',
|
87 |
+
# Public classes.
|
88 |
+
'Flag',
|
89 |
+
'BooleanFlag',
|
90 |
+
'EnumFlag',
|
91 |
+
'EnumClassFlag',
|
92 |
+
'MultiFlag',
|
93 |
+
'MultiEnumClassFlag',
|
94 |
+
'FlagHolder',
|
95 |
+
'FlagValues',
|
96 |
+
'ArgumentParser',
|
97 |
+
'BooleanParser',
|
98 |
+
'EnumParser',
|
99 |
+
'EnumClassParser',
|
100 |
+
'ArgumentSerializer',
|
101 |
+
'FloatParser',
|
102 |
+
'IntegerParser',
|
103 |
+
'BaseListParser',
|
104 |
+
'ListParser',
|
105 |
+
'ListSerializer',
|
106 |
+
'EnumClassListSerializer',
|
107 |
+
'CsvListSerializer',
|
108 |
+
'WhitespaceSeparatedListParser',
|
109 |
+
'EnumClassSerializer',
|
110 |
+
# Helper functions.
|
111 |
+
'get_help_width',
|
112 |
+
'text_wrap',
|
113 |
+
'flag_dict_to_args',
|
114 |
+
'doc_to_help',
|
115 |
+
# The global FlagValues instance.
|
116 |
+
'FLAGS',
|
117 |
+
)
|
118 |
+
|
119 |
+
# Initialize the FLAGS_MODULE as early as possible.
|
120 |
+
# It's only used by adopt_module_key_flags to take SPECIAL_FLAGS into account.
|
121 |
+
_helpers.FLAGS_MODULE = sys.modules[__name__]
|
122 |
+
|
123 |
+
# Add current module to disclaimed module ids.
|
124 |
+
_helpers.disclaim_module_ids.add(id(sys.modules[__name__]))
|
125 |
+
|
126 |
+
# DEFINE functions. They are explained in more details in the module doc string.
|
127 |
+
# pylint: disable=invalid-name
|
128 |
+
DEFINE = _defines.DEFINE
|
129 |
+
DEFINE_flag = _defines.DEFINE_flag
|
130 |
+
DEFINE_string = _defines.DEFINE_string
|
131 |
+
DEFINE_boolean = _defines.DEFINE_boolean
|
132 |
+
DEFINE_bool = DEFINE_boolean # Match C++ API.
|
133 |
+
DEFINE_float = _defines.DEFINE_float
|
134 |
+
DEFINE_integer = _defines.DEFINE_integer
|
135 |
+
DEFINE_enum = _defines.DEFINE_enum
|
136 |
+
DEFINE_enum_class = _defines.DEFINE_enum_class
|
137 |
+
DEFINE_list = _defines.DEFINE_list
|
138 |
+
DEFINE_spaceseplist = _defines.DEFINE_spaceseplist
|
139 |
+
DEFINE_multi = _defines.DEFINE_multi
|
140 |
+
DEFINE_multi_string = _defines.DEFINE_multi_string
|
141 |
+
DEFINE_multi_integer = _defines.DEFINE_multi_integer
|
142 |
+
DEFINE_multi_float = _defines.DEFINE_multi_float
|
143 |
+
DEFINE_multi_enum = _defines.DEFINE_multi_enum
|
144 |
+
DEFINE_multi_enum_class = _defines.DEFINE_multi_enum_class
|
145 |
+
DEFINE_alias = _defines.DEFINE_alias
|
146 |
+
# pylint: enable=invalid-name
|
147 |
+
|
148 |
+
# Flag validators.
|
149 |
+
register_validator = _validators.register_validator
|
150 |
+
validator = _validators.validator
|
151 |
+
register_multi_flags_validator = _validators.register_multi_flags_validator
|
152 |
+
multi_flags_validator = _validators.multi_flags_validator
|
153 |
+
mark_flag_as_required = _validators.mark_flag_as_required
|
154 |
+
mark_flags_as_required = _validators.mark_flags_as_required
|
155 |
+
mark_flags_as_mutual_exclusive = _validators.mark_flags_as_mutual_exclusive
|
156 |
+
mark_bool_flags_as_mutual_exclusive = _validators.mark_bool_flags_as_mutual_exclusive
|
157 |
+
|
158 |
+
# Flag modifiers.
|
159 |
+
set_default = _defines.set_default
|
160 |
+
override_value = _defines.override_value
|
161 |
+
|
162 |
+
# Key flag related functions.
|
163 |
+
declare_key_flag = _defines.declare_key_flag
|
164 |
+
adopt_module_key_flags = _defines.adopt_module_key_flags
|
165 |
+
disclaim_key_flags = _defines.disclaim_key_flags
|
166 |
+
|
167 |
+
# Module exceptions.
|
168 |
+
# pylint: disable=invalid-name
|
169 |
+
Error = _exceptions.Error
|
170 |
+
CantOpenFlagFileError = _exceptions.CantOpenFlagFileError
|
171 |
+
DuplicateFlagError = _exceptions.DuplicateFlagError
|
172 |
+
IllegalFlagValueError = _exceptions.IllegalFlagValueError
|
173 |
+
UnrecognizedFlagError = _exceptions.UnrecognizedFlagError
|
174 |
+
UnparsedFlagAccessError = _exceptions.UnparsedFlagAccessError
|
175 |
+
ValidationError = _exceptions.ValidationError
|
176 |
+
FlagNameConflictsWithMethodError = _exceptions.FlagNameConflictsWithMethodError
|
177 |
+
|
178 |
+
# Public classes.
|
179 |
+
Flag = _flag.Flag
|
180 |
+
BooleanFlag = _flag.BooleanFlag
|
181 |
+
EnumFlag = _flag.EnumFlag
|
182 |
+
EnumClassFlag = _flag.EnumClassFlag
|
183 |
+
MultiFlag = _flag.MultiFlag
|
184 |
+
MultiEnumClassFlag = _flag.MultiEnumClassFlag
|
185 |
+
FlagHolder = _flagvalues.FlagHolder
|
186 |
+
FlagValues = _flagvalues.FlagValues
|
187 |
+
ArgumentParser = _argument_parser.ArgumentParser
|
188 |
+
BooleanParser = _argument_parser.BooleanParser
|
189 |
+
EnumParser = _argument_parser.EnumParser
|
190 |
+
EnumClassParser = _argument_parser.EnumClassParser
|
191 |
+
ArgumentSerializer = _argument_parser.ArgumentSerializer
|
192 |
+
FloatParser = _argument_parser.FloatParser
|
193 |
+
IntegerParser = _argument_parser.IntegerParser
|
194 |
+
BaseListParser = _argument_parser.BaseListParser
|
195 |
+
ListParser = _argument_parser.ListParser
|
196 |
+
ListSerializer = _argument_parser.ListSerializer
|
197 |
+
EnumClassListSerializer = _argument_parser.EnumClassListSerializer
|
198 |
+
CsvListSerializer = _argument_parser.CsvListSerializer
|
199 |
+
WhitespaceSeparatedListParser = _argument_parser.WhitespaceSeparatedListParser
|
200 |
+
EnumClassSerializer = _argument_parser.EnumClassSerializer
|
201 |
+
# pylint: enable=invalid-name
|
202 |
+
|
203 |
+
# Helper functions.
|
204 |
+
get_help_width = _helpers.get_help_width
|
205 |
+
text_wrap = _helpers.text_wrap
|
206 |
+
flag_dict_to_args = _helpers.flag_dict_to_args
|
207 |
+
doc_to_help = _helpers.doc_to_help
|
208 |
+
|
209 |
+
# Special flags.
|
210 |
+
_helpers.SPECIAL_FLAGS = FlagValues()
|
211 |
+
|
212 |
+
DEFINE_string(
|
213 |
+
'flagfile', '',
|
214 |
+
'Insert flag definitions from the given file into the command line.',
|
215 |
+
_helpers.SPECIAL_FLAGS) # pytype: disable=wrong-arg-types
|
216 |
+
|
217 |
+
DEFINE_string('undefok', '',
|
218 |
+
'comma-separated list of flag names that it is okay to specify '
|
219 |
+
'on the command line even if the program does not define a flag '
|
220 |
+
'with that name. IMPORTANT: flags in this list that have '
|
221 |
+
'arguments MUST use the --flag=value format.',
|
222 |
+
_helpers.SPECIAL_FLAGS) # pytype: disable=wrong-arg-types
|
223 |
+
|
224 |
+
#: The global FlagValues instance.
|
225 |
+
FLAGS = _flagvalues.FLAGS
|
MLPY/Lib/site-packages/absl/flags/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (3.71 kB). View file
|
|
MLPY/Lib/site-packages/absl/flags/__pycache__/_argument_parser.cpython-39.pyc
ADDED
Binary file (22.5 kB). View file
|
|
MLPY/Lib/site-packages/absl/flags/__pycache__/_defines.cpython-39.pyc
ADDED
Binary file (38.2 kB). View file
|
|
MLPY/Lib/site-packages/absl/flags/__pycache__/_exceptions.cpython-39.pyc
ADDED
Binary file (3.85 kB). View file
|
|
MLPY/Lib/site-packages/absl/flags/__pycache__/_flag.cpython-39.pyc
ADDED
Binary file (18.4 kB). View file
|
|
MLPY/Lib/site-packages/absl/flags/__pycache__/_flagvalues.cpython-39.pyc
ADDED
Binary file (44.1 kB). View file
|
|
MLPY/Lib/site-packages/absl/flags/__pycache__/_helpers.cpython-39.pyc
ADDED
Binary file (9.92 kB). View file
|
|
MLPY/Lib/site-packages/absl/flags/__pycache__/_validators.cpython-39.pyc
ADDED
Binary file (13.5 kB). View file
|
|
MLPY/Lib/site-packages/absl/flags/__pycache__/_validators_classes.cpython-39.pyc
ADDED
Binary file (6.83 kB). View file
|
|
MLPY/Lib/site-packages/absl/flags/__pycache__/argparse_flags.cpython-39.pyc
ADDED
Binary file (11.2 kB). View file
|
|
MLPY/Lib/site-packages/absl/flags/_argument_parser.py
ADDED
@@ -0,0 +1,638 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 Generic, List, Iterable, Optional, Sequence, Text, 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 |
+
def _is_integer_type(instance):
|
37 |
+
"""Returns True if instance is an integer, and not a bool."""
|
38 |
+
return (isinstance(instance, int) and
|
39 |
+
not isinstance(instance, bool))
|
40 |
+
|
41 |
+
|
42 |
+
class _ArgumentParserCache(type):
|
43 |
+
"""Metaclass used to cache and share argument parsers among flags."""
|
44 |
+
|
45 |
+
_instances = {}
|
46 |
+
|
47 |
+
def __call__(cls, *args, **kwargs):
|
48 |
+
"""Returns an instance of the argument parser cls.
|
49 |
+
|
50 |
+
This method overrides behavior of the __new__ methods in
|
51 |
+
all subclasses of ArgumentParser (inclusive). If an instance
|
52 |
+
for cls with the same set of arguments exists, this instance is
|
53 |
+
returned, otherwise a new instance is created.
|
54 |
+
|
55 |
+
If any keyword arguments are defined, or the values in args
|
56 |
+
are not hashable, this method always returns a new instance of
|
57 |
+
cls.
|
58 |
+
|
59 |
+
Args:
|
60 |
+
*args: Positional initializer arguments.
|
61 |
+
**kwargs: Initializer keyword arguments.
|
62 |
+
|
63 |
+
Returns:
|
64 |
+
An instance of cls, shared or new.
|
65 |
+
"""
|
66 |
+
if kwargs:
|
67 |
+
return type.__call__(cls, *args, **kwargs)
|
68 |
+
else:
|
69 |
+
instances = cls._instances
|
70 |
+
key = (cls,) + tuple(args)
|
71 |
+
try:
|
72 |
+
return instances[key]
|
73 |
+
except KeyError:
|
74 |
+
# No cache entry for key exists, create a new one.
|
75 |
+
return instances.setdefault(key, type.__call__(cls, *args))
|
76 |
+
except TypeError:
|
77 |
+
# An object in args cannot be hashed, always return
|
78 |
+
# a new instance.
|
79 |
+
return type.__call__(cls, *args)
|
80 |
+
|
81 |
+
|
82 |
+
class ArgumentParser(Generic[_T], metaclass=_ArgumentParserCache):
|
83 |
+
"""Base class used to parse and convert arguments.
|
84 |
+
|
85 |
+
The :meth:`parse` method checks to make sure that the string argument is a
|
86 |
+
legal value and convert it to a native type. If the value cannot be
|
87 |
+
converted, it should throw a ``ValueError`` exception with a human
|
88 |
+
readable explanation of why the value is illegal.
|
89 |
+
|
90 |
+
Subclasses should also define a syntactic_help string which may be
|
91 |
+
presented to the user to describe the form of the legal values.
|
92 |
+
|
93 |
+
Argument parser classes must be stateless, since instances are cached
|
94 |
+
and shared between flags. Initializer arguments are allowed, but all
|
95 |
+
member variables must be derived from initializer arguments only.
|
96 |
+
"""
|
97 |
+
|
98 |
+
syntactic_help: Text = ''
|
99 |
+
|
100 |
+
def parse(self, argument: Text) -> Optional[_T]:
|
101 |
+
"""Parses the string argument and returns the native value.
|
102 |
+
|
103 |
+
By default it returns its argument unmodified.
|
104 |
+
|
105 |
+
Args:
|
106 |
+
argument: string argument passed in the commandline.
|
107 |
+
|
108 |
+
Raises:
|
109 |
+
ValueError: Raised when it fails to parse the argument.
|
110 |
+
TypeError: Raised when the argument has the wrong type.
|
111 |
+
|
112 |
+
Returns:
|
113 |
+
The parsed value in native type.
|
114 |
+
"""
|
115 |
+
if not isinstance(argument, str):
|
116 |
+
raise TypeError('flag value must be a string, found "{}"'.format(
|
117 |
+
type(argument)))
|
118 |
+
return argument
|
119 |
+
|
120 |
+
def flag_type(self) -> Text:
|
121 |
+
"""Returns a string representing the type of the flag."""
|
122 |
+
return 'string'
|
123 |
+
|
124 |
+
def _custom_xml_dom_elements(
|
125 |
+
self, doc: minidom.Document
|
126 |
+
) -> List[minidom.Element]:
|
127 |
+
"""Returns a list of minidom.Element to add additional flag information.
|
128 |
+
|
129 |
+
Args:
|
130 |
+
doc: minidom.Document, the DOM document it should create nodes from.
|
131 |
+
"""
|
132 |
+
del doc # Unused.
|
133 |
+
return []
|
134 |
+
|
135 |
+
|
136 |
+
class ArgumentSerializer(Generic[_T]):
|
137 |
+
"""Base class for generating string representations of a flag value."""
|
138 |
+
|
139 |
+
def serialize(self, value: _T) -> Text:
|
140 |
+
"""Returns a serialized string of the value."""
|
141 |
+
return str(value)
|
142 |
+
|
143 |
+
|
144 |
+
class NumericParser(ArgumentParser[_N]):
|
145 |
+
"""Parser of numeric values.
|
146 |
+
|
147 |
+
Parsed value may be bounded to a given upper and lower bound.
|
148 |
+
"""
|
149 |
+
|
150 |
+
lower_bound: Optional[_N]
|
151 |
+
upper_bound: Optional[_N]
|
152 |
+
|
153 |
+
def is_outside_bounds(self, val: _N) -> bool:
|
154 |
+
"""Returns whether the value is outside the bounds or not."""
|
155 |
+
return ((self.lower_bound is not None and val < self.lower_bound) or
|
156 |
+
(self.upper_bound is not None and val > self.upper_bound))
|
157 |
+
|
158 |
+
def parse(self, argument: Text) -> _N:
|
159 |
+
"""See base class."""
|
160 |
+
val = self.convert(argument)
|
161 |
+
if self.is_outside_bounds(val):
|
162 |
+
raise ValueError('%s is not %s' % (val, self.syntactic_help))
|
163 |
+
return val
|
164 |
+
|
165 |
+
def _custom_xml_dom_elements(
|
166 |
+
self, doc: minidom.Document
|
167 |
+
) -> List[minidom.Element]:
|
168 |
+
elements = []
|
169 |
+
if self.lower_bound is not None:
|
170 |
+
elements.append(_helpers.create_xml_dom_element(
|
171 |
+
doc, 'lower_bound', self.lower_bound))
|
172 |
+
if self.upper_bound is not None:
|
173 |
+
elements.append(_helpers.create_xml_dom_element(
|
174 |
+
doc, 'upper_bound', self.upper_bound))
|
175 |
+
return elements
|
176 |
+
|
177 |
+
def convert(self, argument: Text) -> _N:
|
178 |
+
"""Returns the correct numeric value of argument.
|
179 |
+
|
180 |
+
Subclass must implement this method, and raise TypeError if argument is not
|
181 |
+
string or has the right numeric type.
|
182 |
+
|
183 |
+
Args:
|
184 |
+
argument: string argument passed in the commandline, or the numeric type.
|
185 |
+
|
186 |
+
Raises:
|
187 |
+
TypeError: Raised when argument is not a string or the right numeric type.
|
188 |
+
ValueError: Raised when failed to convert argument to the numeric value.
|
189 |
+
"""
|
190 |
+
raise NotImplementedError
|
191 |
+
|
192 |
+
|
193 |
+
class FloatParser(NumericParser[float]):
|
194 |
+
"""Parser of floating point values.
|
195 |
+
|
196 |
+
Parsed value may be bounded to a given upper and lower bound.
|
197 |
+
"""
|
198 |
+
number_article = 'a'
|
199 |
+
number_name = 'number'
|
200 |
+
syntactic_help = ' '.join((number_article, number_name))
|
201 |
+
|
202 |
+
def __init__(
|
203 |
+
self,
|
204 |
+
lower_bound: Optional[float] = None,
|
205 |
+
upper_bound: Optional[float] = None,
|
206 |
+
) -> None:
|
207 |
+
super(FloatParser, self).__init__()
|
208 |
+
self.lower_bound = lower_bound
|
209 |
+
self.upper_bound = upper_bound
|
210 |
+
sh = self.syntactic_help
|
211 |
+
if lower_bound is not None and upper_bound is not None:
|
212 |
+
sh = ('%s in the range [%s, %s]' % (sh, lower_bound, upper_bound))
|
213 |
+
elif lower_bound == 0:
|
214 |
+
sh = 'a non-negative %s' % self.number_name
|
215 |
+
elif upper_bound == 0:
|
216 |
+
sh = 'a non-positive %s' % self.number_name
|
217 |
+
elif upper_bound is not None:
|
218 |
+
sh = '%s <= %s' % (self.number_name, upper_bound)
|
219 |
+
elif lower_bound is not None:
|
220 |
+
sh = '%s >= %s' % (self.number_name, lower_bound)
|
221 |
+
self.syntactic_help = sh
|
222 |
+
|
223 |
+
def convert(self, argument: Union[int, float, str]) -> float:
|
224 |
+
"""Returns the float value of argument."""
|
225 |
+
if (_is_integer_type(argument) or isinstance(argument, float) or
|
226 |
+
isinstance(argument, str)):
|
227 |
+
return float(argument)
|
228 |
+
else:
|
229 |
+
raise TypeError(
|
230 |
+
'Expect argument to be a string, int, or float, found {}'.format(
|
231 |
+
type(argument)))
|
232 |
+
|
233 |
+
def flag_type(self) -> Text:
|
234 |
+
"""See base class."""
|
235 |
+
return 'float'
|
236 |
+
|
237 |
+
|
238 |
+
class IntegerParser(NumericParser[int]):
|
239 |
+
"""Parser of an integer value.
|
240 |
+
|
241 |
+
Parsed value may be bounded to a given upper and lower bound.
|
242 |
+
"""
|
243 |
+
number_article = 'an'
|
244 |
+
number_name = 'integer'
|
245 |
+
syntactic_help = ' '.join((number_article, number_name))
|
246 |
+
|
247 |
+
def __init__(
|
248 |
+
self, lower_bound: Optional[int] = None, upper_bound: Optional[int] = None
|
249 |
+
) -> None:
|
250 |
+
super(IntegerParser, self).__init__()
|
251 |
+
self.lower_bound = lower_bound
|
252 |
+
self.upper_bound = upper_bound
|
253 |
+
sh = self.syntactic_help
|
254 |
+
if lower_bound is not None and upper_bound is not None:
|
255 |
+
sh = ('%s in the range [%s, %s]' % (sh, lower_bound, upper_bound))
|
256 |
+
elif lower_bound == 1:
|
257 |
+
sh = 'a positive %s' % self.number_name
|
258 |
+
elif upper_bound == -1:
|
259 |
+
sh = 'a negative %s' % self.number_name
|
260 |
+
elif lower_bound == 0:
|
261 |
+
sh = 'a non-negative %s' % self.number_name
|
262 |
+
elif upper_bound == 0:
|
263 |
+
sh = 'a non-positive %s' % self.number_name
|
264 |
+
elif upper_bound is not None:
|
265 |
+
sh = '%s <= %s' % (self.number_name, upper_bound)
|
266 |
+
elif lower_bound is not None:
|
267 |
+
sh = '%s >= %s' % (self.number_name, lower_bound)
|
268 |
+
self.syntactic_help = sh
|
269 |
+
|
270 |
+
def convert(self, argument: Union[int, Text]) -> int:
|
271 |
+
"""Returns the int value of argument."""
|
272 |
+
if _is_integer_type(argument):
|
273 |
+
return argument
|
274 |
+
elif isinstance(argument, str):
|
275 |
+
base = 10
|
276 |
+
if len(argument) > 2 and argument[0] == '0':
|
277 |
+
if argument[1] == 'o':
|
278 |
+
base = 8
|
279 |
+
elif argument[1] == 'x':
|
280 |
+
base = 16
|
281 |
+
return int(argument, base)
|
282 |
+
else:
|
283 |
+
raise TypeError('Expect argument to be a string or int, found {}'.format(
|
284 |
+
type(argument)))
|
285 |
+
|
286 |
+
def flag_type(self) -> Text:
|
287 |
+
"""See base class."""
|
288 |
+
return 'int'
|
289 |
+
|
290 |
+
|
291 |
+
class BooleanParser(ArgumentParser[bool]):
|
292 |
+
"""Parser of boolean values."""
|
293 |
+
|
294 |
+
def parse(self, argument: Union[Text, int]) -> bool:
|
295 |
+
"""See base class."""
|
296 |
+
if isinstance(argument, str):
|
297 |
+
if argument.lower() in ('true', 't', '1'):
|
298 |
+
return True
|
299 |
+
elif argument.lower() in ('false', 'f', '0'):
|
300 |
+
return False
|
301 |
+
else:
|
302 |
+
raise ValueError('Non-boolean argument to boolean flag', argument)
|
303 |
+
elif isinstance(argument, int):
|
304 |
+
# Only allow bool or integer 0, 1.
|
305 |
+
# Note that float 1.0 == True, 0.0 == False.
|
306 |
+
bool_value = bool(argument)
|
307 |
+
if argument == bool_value:
|
308 |
+
return bool_value
|
309 |
+
else:
|
310 |
+
raise ValueError('Non-boolean argument to boolean flag', argument)
|
311 |
+
|
312 |
+
raise TypeError('Non-boolean argument to boolean flag', argument)
|
313 |
+
|
314 |
+
def flag_type(self) -> Text:
|
315 |
+
"""See base class."""
|
316 |
+
return 'bool'
|
317 |
+
|
318 |
+
|
319 |
+
class EnumParser(ArgumentParser[Text]):
|
320 |
+
"""Parser of a string enum value (a string value from a given set)."""
|
321 |
+
|
322 |
+
def __init__(
|
323 |
+
self, enum_values: Iterable[Text], case_sensitive: bool = True
|
324 |
+
) -> None:
|
325 |
+
"""Initializes EnumParser.
|
326 |
+
|
327 |
+
Args:
|
328 |
+
enum_values: [str], a non-empty list of string values in the enum.
|
329 |
+
case_sensitive: bool, whether or not the enum is to be case-sensitive.
|
330 |
+
|
331 |
+
Raises:
|
332 |
+
ValueError: When enum_values is empty.
|
333 |
+
"""
|
334 |
+
if not enum_values:
|
335 |
+
raise ValueError(
|
336 |
+
'enum_values cannot be empty, found "{}"'.format(enum_values))
|
337 |
+
if isinstance(enum_values, str):
|
338 |
+
raise ValueError(
|
339 |
+
'enum_values cannot be a str, found "{}"'.format(enum_values)
|
340 |
+
)
|
341 |
+
super(EnumParser, self).__init__()
|
342 |
+
self.enum_values = list(enum_values)
|
343 |
+
self.case_sensitive = case_sensitive
|
344 |
+
|
345 |
+
def parse(self, argument: Text) -> Text:
|
346 |
+
"""Determines validity of argument and returns the correct element of enum.
|
347 |
+
|
348 |
+
Args:
|
349 |
+
argument: str, the supplied flag value.
|
350 |
+
|
351 |
+
Returns:
|
352 |
+
The first matching element from enum_values.
|
353 |
+
|
354 |
+
Raises:
|
355 |
+
ValueError: Raised when argument didn't match anything in enum.
|
356 |
+
"""
|
357 |
+
if self.case_sensitive:
|
358 |
+
if argument not in self.enum_values:
|
359 |
+
raise ValueError('value should be one of <%s>' %
|
360 |
+
'|'.join(self.enum_values))
|
361 |
+
else:
|
362 |
+
return argument
|
363 |
+
else:
|
364 |
+
if argument.upper() not in [value.upper() for value in self.enum_values]:
|
365 |
+
raise ValueError('value should be one of <%s>' %
|
366 |
+
'|'.join(self.enum_values))
|
367 |
+
else:
|
368 |
+
return [value for value in self.enum_values
|
369 |
+
if value.upper() == argument.upper()][0]
|
370 |
+
|
371 |
+
def flag_type(self) -> Text:
|
372 |
+
"""See base class."""
|
373 |
+
return 'string enum'
|
374 |
+
|
375 |
+
|
376 |
+
class EnumClassParser(ArgumentParser[_ET]):
|
377 |
+
"""Parser of an Enum class member."""
|
378 |
+
|
379 |
+
def __init__(
|
380 |
+
self, enum_class: Type[_ET], case_sensitive: bool = True
|
381 |
+
) -> None:
|
382 |
+
"""Initializes EnumParser.
|
383 |
+
|
384 |
+
Args:
|
385 |
+
enum_class: class, the Enum class with all possible flag values.
|
386 |
+
case_sensitive: bool, whether or not the enum is to be case-sensitive. If
|
387 |
+
False, all member names must be unique when case is ignored.
|
388 |
+
|
389 |
+
Raises:
|
390 |
+
TypeError: When enum_class is not a subclass of Enum.
|
391 |
+
ValueError: When enum_class is empty.
|
392 |
+
"""
|
393 |
+
if not issubclass(enum_class, enum.Enum):
|
394 |
+
raise TypeError('{} is not a subclass of Enum.'.format(enum_class))
|
395 |
+
if not enum_class.__members__:
|
396 |
+
raise ValueError('enum_class cannot be empty, but "{}" is empty.'
|
397 |
+
.format(enum_class))
|
398 |
+
if not case_sensitive:
|
399 |
+
members = collections.Counter(
|
400 |
+
name.lower() for name in enum_class.__members__)
|
401 |
+
duplicate_keys = {
|
402 |
+
member for member, count in members.items() if count > 1
|
403 |
+
}
|
404 |
+
if duplicate_keys:
|
405 |
+
raise ValueError(
|
406 |
+
'Duplicate enum values for {} using case_sensitive=False'.format(
|
407 |
+
duplicate_keys))
|
408 |
+
|
409 |
+
super(EnumClassParser, self).__init__()
|
410 |
+
self.enum_class = enum_class
|
411 |
+
self._case_sensitive = case_sensitive
|
412 |
+
if case_sensitive:
|
413 |
+
self._member_names = tuple(enum_class.__members__)
|
414 |
+
else:
|
415 |
+
self._member_names = tuple(
|
416 |
+
name.lower() for name in enum_class.__members__)
|
417 |
+
|
418 |
+
@property
|
419 |
+
def member_names(self) -> Sequence[Text]:
|
420 |
+
"""The accepted enum names, in lowercase if not case sensitive."""
|
421 |
+
return self._member_names
|
422 |
+
|
423 |
+
def parse(self, argument: Union[_ET, Text]) -> _ET:
|
424 |
+
"""Determines validity of argument and returns the correct element of enum.
|
425 |
+
|
426 |
+
Args:
|
427 |
+
argument: str or Enum class member, the supplied flag value.
|
428 |
+
|
429 |
+
Returns:
|
430 |
+
The first matching Enum class member in Enum class.
|
431 |
+
|
432 |
+
Raises:
|
433 |
+
ValueError: Raised when argument didn't match anything in enum.
|
434 |
+
"""
|
435 |
+
if isinstance(argument, self.enum_class):
|
436 |
+
return argument # pytype: disable=bad-return-type
|
437 |
+
elif not isinstance(argument, str):
|
438 |
+
raise ValueError(
|
439 |
+
'{} is not an enum member or a name of a member in {}'.format(
|
440 |
+
argument, self.enum_class))
|
441 |
+
key = EnumParser(
|
442 |
+
self._member_names, case_sensitive=self._case_sensitive).parse(argument)
|
443 |
+
if self._case_sensitive:
|
444 |
+
return self.enum_class[key]
|
445 |
+
else:
|
446 |
+
# If EnumParser.parse() return a value, we're guaranteed to find it
|
447 |
+
# as a member of the class
|
448 |
+
return next(value for name, value in self.enum_class.__members__.items()
|
449 |
+
if name.lower() == key.lower())
|
450 |
+
|
451 |
+
def flag_type(self) -> Text:
|
452 |
+
"""See base class."""
|
453 |
+
return 'enum class'
|
454 |
+
|
455 |
+
|
456 |
+
class ListSerializer(Generic[_T], ArgumentSerializer[List[_T]]):
|
457 |
+
|
458 |
+
def __init__(self, list_sep: Text) -> None:
|
459 |
+
self.list_sep = list_sep
|
460 |
+
|
461 |
+
def serialize(self, value: List[_T]) -> Text:
|
462 |
+
"""See base class."""
|
463 |
+
return self.list_sep.join([str(x) for x in value])
|
464 |
+
|
465 |
+
|
466 |
+
class EnumClassListSerializer(ListSerializer[_ET]):
|
467 |
+
"""A serializer for :class:`MultiEnumClass` flags.
|
468 |
+
|
469 |
+
This serializer simply joins the output of `EnumClassSerializer` using a
|
470 |
+
provided separator.
|
471 |
+
"""
|
472 |
+
|
473 |
+
def __init__(self, list_sep: Text, **kwargs) -> None:
|
474 |
+
"""Initializes EnumClassListSerializer.
|
475 |
+
|
476 |
+
Args:
|
477 |
+
list_sep: String to be used as a separator when serializing
|
478 |
+
**kwargs: Keyword arguments to the `EnumClassSerializer` used to serialize
|
479 |
+
individual values.
|
480 |
+
"""
|
481 |
+
super(EnumClassListSerializer, self).__init__(list_sep)
|
482 |
+
self._element_serializer = EnumClassSerializer(**kwargs)
|
483 |
+
|
484 |
+
def serialize(self, value: Union[_ET, List[_ET]]) -> Text:
|
485 |
+
"""See base class."""
|
486 |
+
if isinstance(value, list):
|
487 |
+
return self.list_sep.join(
|
488 |
+
self._element_serializer.serialize(x) for x in value)
|
489 |
+
else:
|
490 |
+
return self._element_serializer.serialize(value)
|
491 |
+
|
492 |
+
|
493 |
+
class CsvListSerializer(ListSerializer[Text]):
|
494 |
+
|
495 |
+
def serialize(self, value: List[Text]) -> Text:
|
496 |
+
"""Serializes a list as a CSV string or unicode."""
|
497 |
+
output = io.StringIO()
|
498 |
+
writer = csv.writer(output, delimiter=self.list_sep)
|
499 |
+
writer.writerow([str(x) for x in value])
|
500 |
+
serialized_value = output.getvalue().strip()
|
501 |
+
|
502 |
+
# We need the returned value to be pure ascii or Unicodes so that
|
503 |
+
# when the xml help is generated they are usefully encodable.
|
504 |
+
return str(serialized_value)
|
505 |
+
|
506 |
+
|
507 |
+
class EnumClassSerializer(ArgumentSerializer[_ET]):
|
508 |
+
"""Class for generating string representations of an enum class flag value."""
|
509 |
+
|
510 |
+
def __init__(self, lowercase: bool) -> None:
|
511 |
+
"""Initializes EnumClassSerializer.
|
512 |
+
|
513 |
+
Args:
|
514 |
+
lowercase: If True, enum member names are lowercased during serialization.
|
515 |
+
"""
|
516 |
+
self._lowercase = lowercase
|
517 |
+
|
518 |
+
def serialize(self, value: _ET) -> Text:
|
519 |
+
"""Returns a serialized string of the Enum class value."""
|
520 |
+
as_string = str(value.name)
|
521 |
+
return as_string.lower() if self._lowercase else as_string
|
522 |
+
|
523 |
+
|
524 |
+
class BaseListParser(ArgumentParser):
|
525 |
+
"""Base class for a parser of lists of strings.
|
526 |
+
|
527 |
+
To extend, inherit from this class; from the subclass ``__init__``, call::
|
528 |
+
|
529 |
+
super().__init__(token, name)
|
530 |
+
|
531 |
+
where token is a character used to tokenize, and name is a description
|
532 |
+
of the separator.
|
533 |
+
"""
|
534 |
+
|
535 |
+
def __init__(
|
536 |
+
self, token: Optional[Text] = None, name: Optional[Text] = None
|
537 |
+
) -> None:
|
538 |
+
assert name
|
539 |
+
super(BaseListParser, self).__init__()
|
540 |
+
self._token = token
|
541 |
+
self._name = name
|
542 |
+
self.syntactic_help = 'a %s separated list' % self._name
|
543 |
+
|
544 |
+
def parse(self, argument: Text) -> List[Text]:
|
545 |
+
"""See base class."""
|
546 |
+
if isinstance(argument, list):
|
547 |
+
return argument
|
548 |
+
elif not argument:
|
549 |
+
return []
|
550 |
+
else:
|
551 |
+
return [s.strip() for s in argument.split(self._token)]
|
552 |
+
|
553 |
+
def flag_type(self) -> Text:
|
554 |
+
"""See base class."""
|
555 |
+
return '%s separated list of strings' % self._name
|
556 |
+
|
557 |
+
|
558 |
+
class ListParser(BaseListParser):
|
559 |
+
"""Parser for a comma-separated list of strings."""
|
560 |
+
|
561 |
+
def __init__(self) -> None:
|
562 |
+
super(ListParser, self).__init__(',', 'comma')
|
563 |
+
|
564 |
+
def parse(self, argument: Union[Text, List[Text]]) -> List[Text]:
|
565 |
+
"""Parses argument as comma-separated list of strings."""
|
566 |
+
if isinstance(argument, list):
|
567 |
+
return argument
|
568 |
+
elif not argument:
|
569 |
+
return []
|
570 |
+
else:
|
571 |
+
try:
|
572 |
+
return [s.strip() for s in list(csv.reader([argument], strict=True))[0]]
|
573 |
+
except csv.Error as e:
|
574 |
+
# Provide a helpful report for case like
|
575 |
+
# --listflag="$(printf 'hello,\nworld')"
|
576 |
+
# IOW, list flag values containing naked newlines. This error
|
577 |
+
# was previously "reported" by allowing csv.Error to
|
578 |
+
# propagate.
|
579 |
+
raise ValueError('Unable to parse the value %r as a %s: %s'
|
580 |
+
% (argument, self.flag_type(), e))
|
581 |
+
|
582 |
+
def _custom_xml_dom_elements(
|
583 |
+
self, doc: minidom.Document
|
584 |
+
) -> List[minidom.Element]:
|
585 |
+
elements = super(ListParser, self)._custom_xml_dom_elements(doc)
|
586 |
+
elements.append(_helpers.create_xml_dom_element(
|
587 |
+
doc, 'list_separator', repr(',')))
|
588 |
+
return elements
|
589 |
+
|
590 |
+
|
591 |
+
class WhitespaceSeparatedListParser(BaseListParser):
|
592 |
+
"""Parser for a whitespace-separated list of strings."""
|
593 |
+
|
594 |
+
def __init__(self, comma_compat: bool = False) -> None:
|
595 |
+
"""Initializer.
|
596 |
+
|
597 |
+
Args:
|
598 |
+
comma_compat: bool, whether to support comma as an additional separator.
|
599 |
+
If False then only whitespace is supported. This is intended only for
|
600 |
+
backwards compatibility with flags that used to be comma-separated.
|
601 |
+
"""
|
602 |
+
self._comma_compat = comma_compat
|
603 |
+
name = 'whitespace or comma' if self._comma_compat else 'whitespace'
|
604 |
+
super(WhitespaceSeparatedListParser, self).__init__(None, name)
|
605 |
+
|
606 |
+
def parse(self, argument: Union[Text, List[Text]]) -> List[Text]:
|
607 |
+
"""Parses argument as whitespace-separated list of strings.
|
608 |
+
|
609 |
+
It also parses argument as comma-separated list of strings if requested.
|
610 |
+
|
611 |
+
Args:
|
612 |
+
argument: string argument passed in the commandline.
|
613 |
+
|
614 |
+
Returns:
|
615 |
+
[str], the parsed flag value.
|
616 |
+
"""
|
617 |
+
if isinstance(argument, list):
|
618 |
+
return argument
|
619 |
+
elif not argument:
|
620 |
+
return []
|
621 |
+
else:
|
622 |
+
if self._comma_compat:
|
623 |
+
argument = argument.replace(',', ' ')
|
624 |
+
return argument.split()
|
625 |
+
|
626 |
+
def _custom_xml_dom_elements(
|
627 |
+
self, doc: minidom.Document
|
628 |
+
) -> List[minidom.Element]:
|
629 |
+
elements = super(WhitespaceSeparatedListParser, self
|
630 |
+
)._custom_xml_dom_elements(doc)
|
631 |
+
separators = list(string.whitespace)
|
632 |
+
if self._comma_compat:
|
633 |
+
separators.append(',')
|
634 |
+
separators.sort()
|
635 |
+
for sep_char in separators:
|
636 |
+
elements.append(_helpers.create_xml_dom_element(
|
637 |
+
doc, 'list_separator', repr(sep_char)))
|
638 |
+
return elements
|
MLPY/Lib/site-packages/absl/flags/_defines.py
ADDED
@@ -0,0 +1,1686 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
import typing
|
24 |
+
from typing import Text, List, Any, TypeVar, Optional, Union, Type, Iterable, overload
|
25 |
+
|
26 |
+
from absl.flags import _argument_parser
|
27 |
+
from absl.flags import _exceptions
|
28 |
+
from absl.flags import _flag
|
29 |
+
from absl.flags import _flagvalues
|
30 |
+
from absl.flags import _helpers
|
31 |
+
from absl.flags import _validators
|
32 |
+
|
33 |
+
_helpers.disclaim_module_ids.add(id(sys.modules[__name__]))
|
34 |
+
|
35 |
+
_T = TypeVar('_T')
|
36 |
+
_ET = TypeVar('_ET', bound=enum.Enum)
|
37 |
+
|
38 |
+
|
39 |
+
def _register_bounds_validator_if_needed(parser, name, flag_values):
|
40 |
+
"""Enforces lower and upper bounds for numeric flags.
|
41 |
+
|
42 |
+
Args:
|
43 |
+
parser: NumericParser (either FloatParser or IntegerParser), provides lower
|
44 |
+
and upper bounds, and help text to display.
|
45 |
+
name: str, name of the flag
|
46 |
+
flag_values: FlagValues.
|
47 |
+
"""
|
48 |
+
if parser.lower_bound is not None or parser.upper_bound is not None:
|
49 |
+
|
50 |
+
def checker(value):
|
51 |
+
if value is not None and parser.is_outside_bounds(value):
|
52 |
+
message = '%s is not %s' % (value, parser.syntactic_help)
|
53 |
+
raise _exceptions.ValidationError(message)
|
54 |
+
return True
|
55 |
+
|
56 |
+
_validators.register_validator(name, checker, flag_values=flag_values)
|
57 |
+
|
58 |
+
|
59 |
+
@overload
|
60 |
+
def DEFINE( # pylint: disable=invalid-name
|
61 |
+
parser: _argument_parser.ArgumentParser[_T],
|
62 |
+
name: Text,
|
63 |
+
default: Any,
|
64 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
65 |
+
flag_values: _flagvalues.FlagValues = ...,
|
66 |
+
serializer: Optional[_argument_parser.ArgumentSerializer[_T]] = ...,
|
67 |
+
module_name: Optional[Text] = ...,
|
68 |
+
required: 'typing.Literal[True]' = ...,
|
69 |
+
**args: Any
|
70 |
+
) -> _flagvalues.FlagHolder[_T]:
|
71 |
+
...
|
72 |
+
|
73 |
+
|
74 |
+
@overload
|
75 |
+
def DEFINE( # pylint: disable=invalid-name
|
76 |
+
parser: _argument_parser.ArgumentParser[_T],
|
77 |
+
name: Text,
|
78 |
+
default: Optional[Any],
|
79 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
80 |
+
flag_values: _flagvalues.FlagValues = ...,
|
81 |
+
serializer: Optional[_argument_parser.ArgumentSerializer[_T]] = ...,
|
82 |
+
module_name: Optional[Text] = ...,
|
83 |
+
required: bool = ...,
|
84 |
+
**args: Any
|
85 |
+
) -> _flagvalues.FlagHolder[Optional[_T]]:
|
86 |
+
...
|
87 |
+
|
88 |
+
|
89 |
+
def DEFINE( # pylint: disable=invalid-name
|
90 |
+
parser,
|
91 |
+
name,
|
92 |
+
default,
|
93 |
+
help, # pylint: disable=redefined-builtin
|
94 |
+
flag_values=_flagvalues.FLAGS,
|
95 |
+
serializer=None,
|
96 |
+
module_name=None,
|
97 |
+
required=False,
|
98 |
+
**args):
|
99 |
+
"""Registers a generic Flag object.
|
100 |
+
|
101 |
+
NOTE: in the docstrings of all DEFINE* functions, "registers" is short
|
102 |
+
for "creates a new flag and registers it".
|
103 |
+
|
104 |
+
Auxiliary function: clients should use the specialized ``DEFINE_<type>``
|
105 |
+
function instead.
|
106 |
+
|
107 |
+
Args:
|
108 |
+
parser: :class:`ArgumentParser`, used to parse the flag arguments.
|
109 |
+
name: str, the flag name.
|
110 |
+
default: The default value of the flag.
|
111 |
+
help: str, the help message.
|
112 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
113 |
+
flag will be registered. This should almost never need to be overridden.
|
114 |
+
serializer: :class:`ArgumentSerializer`, the flag serializer instance.
|
115 |
+
module_name: str, the name of the Python module declaring this flag. If not
|
116 |
+
provided, it will be computed using the stack trace of this call.
|
117 |
+
required: bool, is this a required flag. This must be used as a keyword
|
118 |
+
argument.
|
119 |
+
**args: dict, the extra keyword args that are passed to ``Flag.__init__``.
|
120 |
+
|
121 |
+
Returns:
|
122 |
+
a handle to defined flag.
|
123 |
+
"""
|
124 |
+
return DEFINE_flag(
|
125 |
+
_flag.Flag(parser, serializer, name, default, help, **args),
|
126 |
+
flag_values,
|
127 |
+
module_name,
|
128 |
+
required=True if required else False,
|
129 |
+
)
|
130 |
+
|
131 |
+
|
132 |
+
@overload
|
133 |
+
def DEFINE_flag( # pylint: disable=invalid-name
|
134 |
+
flag: _flag.Flag[_T],
|
135 |
+
flag_values: _flagvalues.FlagValues = ...,
|
136 |
+
module_name: Optional[Text] = ...,
|
137 |
+
required: 'typing.Literal[True]' = ...,
|
138 |
+
) -> _flagvalues.FlagHolder[_T]:
|
139 |
+
...
|
140 |
+
|
141 |
+
|
142 |
+
@overload
|
143 |
+
def DEFINE_flag( # pylint: disable=invalid-name
|
144 |
+
flag: _flag.Flag[_T],
|
145 |
+
flag_values: _flagvalues.FlagValues = ...,
|
146 |
+
module_name: Optional[Text] = ...,
|
147 |
+
required: bool = ...,
|
148 |
+
) -> _flagvalues.FlagHolder[Optional[_T]]:
|
149 |
+
...
|
150 |
+
|
151 |
+
|
152 |
+
def DEFINE_flag( # pylint: disable=invalid-name
|
153 |
+
flag,
|
154 |
+
flag_values=_flagvalues.FLAGS,
|
155 |
+
module_name=None,
|
156 |
+
required=False):
|
157 |
+
"""Registers a :class:`Flag` object with a :class:`FlagValues` object.
|
158 |
+
|
159 |
+
By default, the global :const:`FLAGS` ``FlagValue`` object is used.
|
160 |
+
|
161 |
+
Typical users will use one of the more specialized DEFINE_xxx
|
162 |
+
functions, such as :func:`DEFINE_string` or :func:`DEFINE_integer`. But
|
163 |
+
developers who need to create :class:`Flag` objects themselves should use
|
164 |
+
this function to register their flags.
|
165 |
+
|
166 |
+
Args:
|
167 |
+
flag: :class:`Flag`, a flag that is key to the module.
|
168 |
+
flag_values: :class:`FlagValues`, the ``FlagValues`` instance with which the
|
169 |
+
flag will be registered. This should almost never need to be overridden.
|
170 |
+
module_name: str, the name of the Python module declaring this flag. If not
|
171 |
+
provided, it will be computed using the stack trace of this call.
|
172 |
+
required: bool, is this a required flag. This must be used as a keyword
|
173 |
+
argument.
|
174 |
+
|
175 |
+
Returns:
|
176 |
+
a handle to defined flag.
|
177 |
+
"""
|
178 |
+
if required and flag.default is not None:
|
179 |
+
raise ValueError('Required flag --%s cannot have a non-None default' %
|
180 |
+
flag.name)
|
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[Text, _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 |
+
_helpers.disclaim_module_ids.add(id(module))
|
368 |
+
|
369 |
+
|
370 |
+
@overload
|
371 |
+
def DEFINE_string( # pylint: disable=invalid-name
|
372 |
+
name: Text,
|
373 |
+
default: Optional[Text],
|
374 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
375 |
+
flag_values: _flagvalues.FlagValues = ...,
|
376 |
+
*,
|
377 |
+
required: 'typing.Literal[True]',
|
378 |
+
**args: Any
|
379 |
+
) -> _flagvalues.FlagHolder[Text]:
|
380 |
+
...
|
381 |
+
|
382 |
+
|
383 |
+
@overload
|
384 |
+
def DEFINE_string( # pylint: disable=invalid-name
|
385 |
+
name: Text,
|
386 |
+
default: None,
|
387 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
388 |
+
flag_values: _flagvalues.FlagValues = ...,
|
389 |
+
required: bool = ...,
|
390 |
+
**args: Any
|
391 |
+
) -> _flagvalues.FlagHolder[Optional[Text]]:
|
392 |
+
...
|
393 |
+
|
394 |
+
|
395 |
+
@overload
|
396 |
+
def DEFINE_string( # pylint: disable=invalid-name
|
397 |
+
name: Text,
|
398 |
+
default: Text,
|
399 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
400 |
+
flag_values: _flagvalues.FlagValues = ...,
|
401 |
+
required: bool = ...,
|
402 |
+
**args: Any
|
403 |
+
) -> _flagvalues.FlagHolder[Text]:
|
404 |
+
...
|
405 |
+
|
406 |
+
|
407 |
+
def DEFINE_string( # pylint: disable=invalid-name,redefined-builtin
|
408 |
+
name,
|
409 |
+
default,
|
410 |
+
help,
|
411 |
+
flag_values=_flagvalues.FLAGS,
|
412 |
+
required=False,
|
413 |
+
**args):
|
414 |
+
"""Registers a flag whose value can be any string."""
|
415 |
+
parser = _argument_parser.ArgumentParser[str]()
|
416 |
+
serializer = _argument_parser.ArgumentSerializer[str]()
|
417 |
+
return DEFINE(
|
418 |
+
parser,
|
419 |
+
name,
|
420 |
+
default,
|
421 |
+
help,
|
422 |
+
flag_values,
|
423 |
+
serializer,
|
424 |
+
required=True if required else False,
|
425 |
+
**args,
|
426 |
+
)
|
427 |
+
|
428 |
+
|
429 |
+
@overload
|
430 |
+
def DEFINE_boolean( # pylint: disable=invalid-name
|
431 |
+
name: Text,
|
432 |
+
default: Union[None, Text, bool, int],
|
433 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
434 |
+
flag_values: _flagvalues.FlagValues = ...,
|
435 |
+
module_name: Optional[Text] = ...,
|
436 |
+
*,
|
437 |
+
required: 'typing.Literal[True]',
|
438 |
+
**args: Any
|
439 |
+
) -> _flagvalues.FlagHolder[bool]:
|
440 |
+
...
|
441 |
+
|
442 |
+
|
443 |
+
@overload
|
444 |
+
def DEFINE_boolean( # pylint: disable=invalid-name
|
445 |
+
name: Text,
|
446 |
+
default: None,
|
447 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
448 |
+
flag_values: _flagvalues.FlagValues = ...,
|
449 |
+
module_name: Optional[Text] = ...,
|
450 |
+
required: bool = ...,
|
451 |
+
**args: Any
|
452 |
+
) -> _flagvalues.FlagHolder[Optional[bool]]:
|
453 |
+
...
|
454 |
+
|
455 |
+
|
456 |
+
@overload
|
457 |
+
def DEFINE_boolean( # pylint: disable=invalid-name
|
458 |
+
name: Text,
|
459 |
+
default: Union[Text, bool, int],
|
460 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
461 |
+
flag_values: _flagvalues.FlagValues = ...,
|
462 |
+
module_name: Optional[Text] = ...,
|
463 |
+
required: bool = ...,
|
464 |
+
**args: Any
|
465 |
+
) -> _flagvalues.FlagHolder[bool]:
|
466 |
+
...
|
467 |
+
|
468 |
+
|
469 |
+
def DEFINE_boolean( # pylint: disable=invalid-name,redefined-builtin
|
470 |
+
name,
|
471 |
+
default,
|
472 |
+
help,
|
473 |
+
flag_values=_flagvalues.FLAGS,
|
474 |
+
module_name=None,
|
475 |
+
required=False,
|
476 |
+
**args):
|
477 |
+
"""Registers a boolean flag.
|
478 |
+
|
479 |
+
Such a boolean flag does not take an argument. If a user wants to
|
480 |
+
specify a false value explicitly, the long option beginning with 'no'
|
481 |
+
must be used: i.e. --noflag
|
482 |
+
|
483 |
+
This flag will have a value of None, True or False. None is possible
|
484 |
+
if default=None and the user does not specify the flag on the command
|
485 |
+
line.
|
486 |
+
|
487 |
+
Args:
|
488 |
+
name: str, the flag name.
|
489 |
+
default: bool|str|None, the default value of the flag.
|
490 |
+
help: str, the help message.
|
491 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
492 |
+
flag will be registered. This should almost never need to be overridden.
|
493 |
+
module_name: str, the name of the Python module declaring this flag. If not
|
494 |
+
provided, it will be computed using the stack trace of this call.
|
495 |
+
required: bool, is this a required flag. This must be used as a keyword
|
496 |
+
argument.
|
497 |
+
**args: dict, the extra keyword args that are passed to ``Flag.__init__``.
|
498 |
+
|
499 |
+
Returns:
|
500 |
+
a handle to defined flag.
|
501 |
+
"""
|
502 |
+
return DEFINE_flag(
|
503 |
+
_flag.BooleanFlag(name, default, help, **args),
|
504 |
+
flag_values,
|
505 |
+
module_name,
|
506 |
+
required=True if required else False,
|
507 |
+
)
|
508 |
+
|
509 |
+
|
510 |
+
@overload
|
511 |
+
def DEFINE_float( # pylint: disable=invalid-name
|
512 |
+
name: Text,
|
513 |
+
default: Union[None, float, Text],
|
514 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
515 |
+
lower_bound: Optional[float] = ...,
|
516 |
+
upper_bound: Optional[float] = ...,
|
517 |
+
flag_values: _flagvalues.FlagValues = ...,
|
518 |
+
*,
|
519 |
+
required: 'typing.Literal[True]',
|
520 |
+
**args: Any
|
521 |
+
) -> _flagvalues.FlagHolder[float]:
|
522 |
+
...
|
523 |
+
|
524 |
+
|
525 |
+
@overload
|
526 |
+
def DEFINE_float( # pylint: disable=invalid-name
|
527 |
+
name: Text,
|
528 |
+
default: None,
|
529 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
530 |
+
lower_bound: Optional[float] = ...,
|
531 |
+
upper_bound: Optional[float] = ...,
|
532 |
+
flag_values: _flagvalues.FlagValues = ...,
|
533 |
+
required: bool = ...,
|
534 |
+
**args: Any
|
535 |
+
) -> _flagvalues.FlagHolder[Optional[float]]:
|
536 |
+
...
|
537 |
+
|
538 |
+
|
539 |
+
@overload
|
540 |
+
def DEFINE_float( # pylint: disable=invalid-name
|
541 |
+
name: Text,
|
542 |
+
default: Union[float, Text],
|
543 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
544 |
+
lower_bound: Optional[float] = ...,
|
545 |
+
upper_bound: Optional[float] = ...,
|
546 |
+
flag_values: _flagvalues.FlagValues = ...,
|
547 |
+
required: bool = ...,
|
548 |
+
**args: Any
|
549 |
+
) -> _flagvalues.FlagHolder[float]:
|
550 |
+
...
|
551 |
+
|
552 |
+
|
553 |
+
def DEFINE_float( # pylint: disable=invalid-name,redefined-builtin
|
554 |
+
name,
|
555 |
+
default,
|
556 |
+
help,
|
557 |
+
lower_bound=None,
|
558 |
+
upper_bound=None,
|
559 |
+
flag_values=_flagvalues.FLAGS,
|
560 |
+
required=False,
|
561 |
+
**args):
|
562 |
+
"""Registers a flag whose value must be a float.
|
563 |
+
|
564 |
+
If ``lower_bound`` or ``upper_bound`` are set, then this flag must be
|
565 |
+
within the given range.
|
566 |
+
|
567 |
+
Args:
|
568 |
+
name: str, the flag name.
|
569 |
+
default: float|str|None, the default value of the flag.
|
570 |
+
help: str, the help message.
|
571 |
+
lower_bound: float, min value of the flag.
|
572 |
+
upper_bound: float, max value of the flag.
|
573 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
574 |
+
flag will be registered. This should almost never need to be overridden.
|
575 |
+
required: bool, is this a required flag. This must be used as a keyword
|
576 |
+
argument.
|
577 |
+
**args: dict, the extra keyword args that are passed to :func:`DEFINE`.
|
578 |
+
|
579 |
+
Returns:
|
580 |
+
a handle to defined flag.
|
581 |
+
"""
|
582 |
+
parser = _argument_parser.FloatParser(lower_bound, upper_bound)
|
583 |
+
serializer = _argument_parser.ArgumentSerializer()
|
584 |
+
result = DEFINE(
|
585 |
+
parser,
|
586 |
+
name,
|
587 |
+
default,
|
588 |
+
help,
|
589 |
+
flag_values,
|
590 |
+
serializer,
|
591 |
+
required=True if required else False,
|
592 |
+
**args,
|
593 |
+
)
|
594 |
+
_register_bounds_validator_if_needed(parser, name, flag_values=flag_values)
|
595 |
+
return result
|
596 |
+
|
597 |
+
|
598 |
+
@overload
|
599 |
+
def DEFINE_integer( # pylint: disable=invalid-name
|
600 |
+
name: Text,
|
601 |
+
default: Union[None, int, Text],
|
602 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
603 |
+
lower_bound: Optional[int] = ...,
|
604 |
+
upper_bound: Optional[int] = ...,
|
605 |
+
flag_values: _flagvalues.FlagValues = ...,
|
606 |
+
*,
|
607 |
+
required: 'typing.Literal[True]',
|
608 |
+
**args: Any
|
609 |
+
) -> _flagvalues.FlagHolder[int]:
|
610 |
+
...
|
611 |
+
|
612 |
+
|
613 |
+
@overload
|
614 |
+
def DEFINE_integer( # pylint: disable=invalid-name
|
615 |
+
name: Text,
|
616 |
+
default: None,
|
617 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
618 |
+
lower_bound: Optional[int] = ...,
|
619 |
+
upper_bound: Optional[int] = ...,
|
620 |
+
flag_values: _flagvalues.FlagValues = ...,
|
621 |
+
required: bool = ...,
|
622 |
+
**args: Any
|
623 |
+
) -> _flagvalues.FlagHolder[Optional[int]]:
|
624 |
+
...
|
625 |
+
|
626 |
+
|
627 |
+
@overload
|
628 |
+
def DEFINE_integer( # pylint: disable=invalid-name
|
629 |
+
name: Text,
|
630 |
+
default: Union[int, Text],
|
631 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
632 |
+
lower_bound: Optional[int] = ...,
|
633 |
+
upper_bound: Optional[int] = ...,
|
634 |
+
flag_values: _flagvalues.FlagValues = ...,
|
635 |
+
required: bool = ...,
|
636 |
+
**args: Any
|
637 |
+
) -> _flagvalues.FlagHolder[int]:
|
638 |
+
...
|
639 |
+
|
640 |
+
|
641 |
+
def DEFINE_integer( # pylint: disable=invalid-name,redefined-builtin
|
642 |
+
name,
|
643 |
+
default,
|
644 |
+
help,
|
645 |
+
lower_bound=None,
|
646 |
+
upper_bound=None,
|
647 |
+
flag_values=_flagvalues.FLAGS,
|
648 |
+
required=False,
|
649 |
+
**args):
|
650 |
+
"""Registers a flag whose value must be an integer.
|
651 |
+
|
652 |
+
If ``lower_bound``, or ``upper_bound`` are set, then this flag must be
|
653 |
+
within the given range.
|
654 |
+
|
655 |
+
Args:
|
656 |
+
name: str, the flag name.
|
657 |
+
default: int|str|None, the default value of the flag.
|
658 |
+
help: str, the help message.
|
659 |
+
lower_bound: int, min value of the flag.
|
660 |
+
upper_bound: int, max value of the flag.
|
661 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
662 |
+
flag will be registered. This should almost never need to be overridden.
|
663 |
+
required: bool, is this a required flag. This must be used as a keyword
|
664 |
+
argument.
|
665 |
+
**args: dict, the extra keyword args that are passed to :func:`DEFINE`.
|
666 |
+
|
667 |
+
Returns:
|
668 |
+
a handle to defined flag.
|
669 |
+
"""
|
670 |
+
parser = _argument_parser.IntegerParser(lower_bound, upper_bound)
|
671 |
+
serializer = _argument_parser.ArgumentSerializer()
|
672 |
+
result = DEFINE(
|
673 |
+
parser,
|
674 |
+
name,
|
675 |
+
default,
|
676 |
+
help,
|
677 |
+
flag_values,
|
678 |
+
serializer,
|
679 |
+
required=True if required else False,
|
680 |
+
**args,
|
681 |
+
)
|
682 |
+
_register_bounds_validator_if_needed(parser, name, flag_values=flag_values)
|
683 |
+
return result
|
684 |
+
|
685 |
+
|
686 |
+
@overload
|
687 |
+
def DEFINE_enum( # pylint: disable=invalid-name
|
688 |
+
name: Text,
|
689 |
+
default: Optional[Text],
|
690 |
+
enum_values: Iterable[Text],
|
691 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
692 |
+
flag_values: _flagvalues.FlagValues = ...,
|
693 |
+
module_name: Optional[Text] = ...,
|
694 |
+
*,
|
695 |
+
required: 'typing.Literal[True]',
|
696 |
+
**args: Any
|
697 |
+
) -> _flagvalues.FlagHolder[Text]:
|
698 |
+
...
|
699 |
+
|
700 |
+
|
701 |
+
@overload
|
702 |
+
def DEFINE_enum( # pylint: disable=invalid-name
|
703 |
+
name: Text,
|
704 |
+
default: None,
|
705 |
+
enum_values: Iterable[Text],
|
706 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
707 |
+
flag_values: _flagvalues.FlagValues = ...,
|
708 |
+
module_name: Optional[Text] = ...,
|
709 |
+
required: bool = ...,
|
710 |
+
**args: Any
|
711 |
+
) -> _flagvalues.FlagHolder[Optional[Text]]:
|
712 |
+
...
|
713 |
+
|
714 |
+
|
715 |
+
@overload
|
716 |
+
def DEFINE_enum( # pylint: disable=invalid-name
|
717 |
+
name: Text,
|
718 |
+
default: Text,
|
719 |
+
enum_values: Iterable[Text],
|
720 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
721 |
+
flag_values: _flagvalues.FlagValues = ...,
|
722 |
+
module_name: Optional[Text] = ...,
|
723 |
+
required: bool = ...,
|
724 |
+
**args: Any
|
725 |
+
) -> _flagvalues.FlagHolder[Text]:
|
726 |
+
...
|
727 |
+
|
728 |
+
|
729 |
+
def DEFINE_enum( # pylint: disable=invalid-name,redefined-builtin
|
730 |
+
name,
|
731 |
+
default,
|
732 |
+
enum_values,
|
733 |
+
help,
|
734 |
+
flag_values=_flagvalues.FLAGS,
|
735 |
+
module_name=None,
|
736 |
+
required=False,
|
737 |
+
**args):
|
738 |
+
"""Registers a flag whose value can be any string from enum_values.
|
739 |
+
|
740 |
+
Instead of a string enum, prefer `DEFINE_enum_class`, which allows
|
741 |
+
defining enums from an `enum.Enum` class.
|
742 |
+
|
743 |
+
Args:
|
744 |
+
name: str, the flag name.
|
745 |
+
default: str|None, the default value of the flag.
|
746 |
+
enum_values: [str], a non-empty list of strings with the possible values for
|
747 |
+
the flag.
|
748 |
+
help: str, the help message.
|
749 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
750 |
+
flag will be registered. This should almost never need to be overridden.
|
751 |
+
module_name: str, the name of the Python module declaring this flag. If not
|
752 |
+
provided, it will be computed using the stack trace of this call.
|
753 |
+
required: bool, is this a required flag. This must be used as a keyword
|
754 |
+
argument.
|
755 |
+
**args: dict, the extra keyword args that are passed to ``Flag.__init__``.
|
756 |
+
|
757 |
+
Returns:
|
758 |
+
a handle to defined flag.
|
759 |
+
"""
|
760 |
+
result = DEFINE_flag(
|
761 |
+
_flag.EnumFlag(name, default, help, enum_values, **args),
|
762 |
+
flag_values,
|
763 |
+
module_name,
|
764 |
+
required=True if required else False,
|
765 |
+
)
|
766 |
+
return result
|
767 |
+
|
768 |
+
|
769 |
+
@overload
|
770 |
+
def DEFINE_enum_class( # pylint: disable=invalid-name
|
771 |
+
name: Text,
|
772 |
+
default: Union[None, _ET, Text],
|
773 |
+
enum_class: Type[_ET],
|
774 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
775 |
+
flag_values: _flagvalues.FlagValues = ...,
|
776 |
+
module_name: Optional[Text] = ...,
|
777 |
+
case_sensitive: bool = ...,
|
778 |
+
*,
|
779 |
+
required: 'typing.Literal[True]',
|
780 |
+
**args: Any
|
781 |
+
) -> _flagvalues.FlagHolder[_ET]:
|
782 |
+
...
|
783 |
+
|
784 |
+
|
785 |
+
@overload
|
786 |
+
def DEFINE_enum_class( # pylint: disable=invalid-name
|
787 |
+
name: Text,
|
788 |
+
default: None,
|
789 |
+
enum_class: Type[_ET],
|
790 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
791 |
+
flag_values: _flagvalues.FlagValues = ...,
|
792 |
+
module_name: Optional[Text] = ...,
|
793 |
+
case_sensitive: bool = ...,
|
794 |
+
required: bool = ...,
|
795 |
+
**args: Any
|
796 |
+
) -> _flagvalues.FlagHolder[Optional[_ET]]:
|
797 |
+
...
|
798 |
+
|
799 |
+
|
800 |
+
@overload
|
801 |
+
def DEFINE_enum_class( # pylint: disable=invalid-name
|
802 |
+
name: Text,
|
803 |
+
default: Union[_ET, Text],
|
804 |
+
enum_class: Type[_ET],
|
805 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
806 |
+
flag_values: _flagvalues.FlagValues = ...,
|
807 |
+
module_name: Optional[Text] = ...,
|
808 |
+
case_sensitive: bool = ...,
|
809 |
+
required: bool = ...,
|
810 |
+
**args: Any
|
811 |
+
) -> _flagvalues.FlagHolder[_ET]:
|
812 |
+
...
|
813 |
+
|
814 |
+
|
815 |
+
def DEFINE_enum_class( # pylint: disable=invalid-name,redefined-builtin
|
816 |
+
name,
|
817 |
+
default,
|
818 |
+
enum_class,
|
819 |
+
help,
|
820 |
+
flag_values=_flagvalues.FLAGS,
|
821 |
+
module_name=None,
|
822 |
+
case_sensitive=False,
|
823 |
+
required=False,
|
824 |
+
**args):
|
825 |
+
"""Registers a flag whose value can be the name of enum members.
|
826 |
+
|
827 |
+
Args:
|
828 |
+
name: str, the flag name.
|
829 |
+
default: Enum|str|None, the default value of the flag.
|
830 |
+
enum_class: class, the Enum class with all the possible values for the flag.
|
831 |
+
help: str, the help message.
|
832 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
833 |
+
flag will be registered. This should almost never need to be overridden.
|
834 |
+
module_name: str, the name of the Python module declaring this flag. If not
|
835 |
+
provided, it will be computed using the stack trace of this call.
|
836 |
+
case_sensitive: bool, whether to map strings to members of the enum_class
|
837 |
+
without considering case.
|
838 |
+
required: bool, is this a required flag. This must be used as a keyword
|
839 |
+
argument.
|
840 |
+
**args: dict, the extra keyword args that are passed to ``Flag.__init__``.
|
841 |
+
|
842 |
+
Returns:
|
843 |
+
a handle to defined flag.
|
844 |
+
"""
|
845 |
+
# NOTE: pytype fails if this is a direct return.
|
846 |
+
result = DEFINE_flag(
|
847 |
+
_flag.EnumClassFlag(
|
848 |
+
name, default, help, enum_class, case_sensitive=case_sensitive, **args
|
849 |
+
),
|
850 |
+
flag_values,
|
851 |
+
module_name,
|
852 |
+
required=True if required else False,
|
853 |
+
)
|
854 |
+
return result
|
855 |
+
|
856 |
+
|
857 |
+
@overload
|
858 |
+
def DEFINE_list( # pylint: disable=invalid-name
|
859 |
+
name: Text,
|
860 |
+
default: Union[None, Iterable[Text], Text],
|
861 |
+
help: Text, # pylint: disable=redefined-builtin
|
862 |
+
flag_values: _flagvalues.FlagValues = ...,
|
863 |
+
*,
|
864 |
+
required: 'typing.Literal[True]',
|
865 |
+
**args: Any
|
866 |
+
) -> _flagvalues.FlagHolder[List[Text]]:
|
867 |
+
...
|
868 |
+
|
869 |
+
|
870 |
+
@overload
|
871 |
+
def DEFINE_list( # pylint: disable=invalid-name
|
872 |
+
name: Text,
|
873 |
+
default: None,
|
874 |
+
help: Text, # pylint: disable=redefined-builtin
|
875 |
+
flag_values: _flagvalues.FlagValues = ...,
|
876 |
+
required: bool = ...,
|
877 |
+
**args: Any
|
878 |
+
) -> _flagvalues.FlagHolder[Optional[List[Text]]]:
|
879 |
+
...
|
880 |
+
|
881 |
+
|
882 |
+
@overload
|
883 |
+
def DEFINE_list( # pylint: disable=invalid-name
|
884 |
+
name: Text,
|
885 |
+
default: Union[Iterable[Text], Text],
|
886 |
+
help: Text, # pylint: disable=redefined-builtin
|
887 |
+
flag_values: _flagvalues.FlagValues = ...,
|
888 |
+
required: bool = ...,
|
889 |
+
**args: Any
|
890 |
+
) -> _flagvalues.FlagHolder[List[Text]]:
|
891 |
+
...
|
892 |
+
|
893 |
+
|
894 |
+
def DEFINE_list( # pylint: disable=invalid-name,redefined-builtin
|
895 |
+
name,
|
896 |
+
default,
|
897 |
+
help,
|
898 |
+
flag_values=_flagvalues.FLAGS,
|
899 |
+
required=False,
|
900 |
+
**args):
|
901 |
+
"""Registers a flag whose value is a comma-separated list of strings.
|
902 |
+
|
903 |
+
The flag value is parsed with a CSV parser.
|
904 |
+
|
905 |
+
Args:
|
906 |
+
name: str, the flag name.
|
907 |
+
default: list|str|None, the default value of the flag.
|
908 |
+
help: str, the help message.
|
909 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
910 |
+
flag will be registered. This should almost never need to be overridden.
|
911 |
+
required: bool, is this a required flag. This must be used as a keyword
|
912 |
+
argument.
|
913 |
+
**args: Dictionary with extra keyword args that are passed to the
|
914 |
+
``Flag.__init__``.
|
915 |
+
|
916 |
+
Returns:
|
917 |
+
a handle to defined flag.
|
918 |
+
"""
|
919 |
+
parser = _argument_parser.ListParser()
|
920 |
+
serializer = _argument_parser.CsvListSerializer(',')
|
921 |
+
return DEFINE(
|
922 |
+
parser,
|
923 |
+
name,
|
924 |
+
default,
|
925 |
+
help,
|
926 |
+
flag_values,
|
927 |
+
serializer,
|
928 |
+
required=True if required else False,
|
929 |
+
**args,
|
930 |
+
)
|
931 |
+
|
932 |
+
|
933 |
+
@overload
|
934 |
+
def DEFINE_spaceseplist( # pylint: disable=invalid-name
|
935 |
+
name: Text,
|
936 |
+
default: Union[None, Iterable[Text], Text],
|
937 |
+
help: Text, # pylint: disable=redefined-builtin
|
938 |
+
comma_compat: bool = ...,
|
939 |
+
flag_values: _flagvalues.FlagValues = ...,
|
940 |
+
*,
|
941 |
+
required: 'typing.Literal[True]',
|
942 |
+
**args: Any
|
943 |
+
) -> _flagvalues.FlagHolder[List[Text]]:
|
944 |
+
...
|
945 |
+
|
946 |
+
|
947 |
+
@overload
|
948 |
+
def DEFINE_spaceseplist( # pylint: disable=invalid-name
|
949 |
+
name: Text,
|
950 |
+
default: None,
|
951 |
+
help: Text, # pylint: disable=redefined-builtin
|
952 |
+
comma_compat: bool = ...,
|
953 |
+
flag_values: _flagvalues.FlagValues = ...,
|
954 |
+
required: bool = ...,
|
955 |
+
**args: Any
|
956 |
+
) -> _flagvalues.FlagHolder[Optional[List[Text]]]:
|
957 |
+
...
|
958 |
+
|
959 |
+
|
960 |
+
@overload
|
961 |
+
def DEFINE_spaceseplist( # pylint: disable=invalid-name
|
962 |
+
name: Text,
|
963 |
+
default: Union[Iterable[Text], Text],
|
964 |
+
help: Text, # pylint: disable=redefined-builtin
|
965 |
+
comma_compat: bool = ...,
|
966 |
+
flag_values: _flagvalues.FlagValues = ...,
|
967 |
+
required: bool = ...,
|
968 |
+
**args: Any
|
969 |
+
) -> _flagvalues.FlagHolder[List[Text]]:
|
970 |
+
...
|
971 |
+
|
972 |
+
|
973 |
+
def DEFINE_spaceseplist( # pylint: disable=invalid-name,redefined-builtin
|
974 |
+
name,
|
975 |
+
default,
|
976 |
+
help,
|
977 |
+
comma_compat=False,
|
978 |
+
flag_values=_flagvalues.FLAGS,
|
979 |
+
required=False,
|
980 |
+
**args):
|
981 |
+
"""Registers a flag whose value is a whitespace-separated list of strings.
|
982 |
+
|
983 |
+
Any whitespace can be used as a separator.
|
984 |
+
|
985 |
+
Args:
|
986 |
+
name: str, the flag name.
|
987 |
+
default: list|str|None, the default value of the flag.
|
988 |
+
help: str, the help message.
|
989 |
+
comma_compat: bool - Whether to support comma as an additional separator. If
|
990 |
+
false then only whitespace is supported. This is intended only for
|
991 |
+
backwards compatibility with flags that used to be comma-separated.
|
992 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
993 |
+
flag will be registered. This should almost never need to be overridden.
|
994 |
+
required: bool, is this a required flag. This must be used as a keyword
|
995 |
+
argument.
|
996 |
+
**args: Dictionary with extra keyword args that are passed to the
|
997 |
+
``Flag.__init__``.
|
998 |
+
|
999 |
+
Returns:
|
1000 |
+
a handle to defined flag.
|
1001 |
+
"""
|
1002 |
+
parser = _argument_parser.WhitespaceSeparatedListParser(
|
1003 |
+
comma_compat=comma_compat)
|
1004 |
+
serializer = _argument_parser.ListSerializer(' ')
|
1005 |
+
return DEFINE(
|
1006 |
+
parser,
|
1007 |
+
name,
|
1008 |
+
default,
|
1009 |
+
help,
|
1010 |
+
flag_values,
|
1011 |
+
serializer,
|
1012 |
+
required=True if required else False,
|
1013 |
+
**args,
|
1014 |
+
)
|
1015 |
+
|
1016 |
+
|
1017 |
+
@overload
|
1018 |
+
def DEFINE_multi( # pylint: disable=invalid-name
|
1019 |
+
parser: _argument_parser.ArgumentParser[_T],
|
1020 |
+
serializer: _argument_parser.ArgumentSerializer[_T],
|
1021 |
+
name: Text,
|
1022 |
+
default: Iterable[_T],
|
1023 |
+
help: Text, # pylint: disable=redefined-builtin
|
1024 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1025 |
+
module_name: Optional[Text] = ...,
|
1026 |
+
*,
|
1027 |
+
required: 'typing.Literal[True]',
|
1028 |
+
**args: Any
|
1029 |
+
) -> _flagvalues.FlagHolder[List[_T]]:
|
1030 |
+
...
|
1031 |
+
|
1032 |
+
|
1033 |
+
@overload
|
1034 |
+
def DEFINE_multi( # pylint: disable=invalid-name
|
1035 |
+
parser: _argument_parser.ArgumentParser[_T],
|
1036 |
+
serializer: _argument_parser.ArgumentSerializer[_T],
|
1037 |
+
name: Text,
|
1038 |
+
default: Union[None, _T],
|
1039 |
+
help: Text, # pylint: disable=redefined-builtin
|
1040 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1041 |
+
module_name: Optional[Text] = ...,
|
1042 |
+
*,
|
1043 |
+
required: 'typing.Literal[True]',
|
1044 |
+
**args: Any
|
1045 |
+
) -> _flagvalues.FlagHolder[List[_T]]:
|
1046 |
+
...
|
1047 |
+
|
1048 |
+
|
1049 |
+
@overload
|
1050 |
+
def DEFINE_multi( # pylint: disable=invalid-name
|
1051 |
+
parser: _argument_parser.ArgumentParser[_T],
|
1052 |
+
serializer: _argument_parser.ArgumentSerializer[_T],
|
1053 |
+
name: Text,
|
1054 |
+
default: None,
|
1055 |
+
help: Text, # pylint: disable=redefined-builtin
|
1056 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1057 |
+
module_name: Optional[Text] = ...,
|
1058 |
+
required: bool = ...,
|
1059 |
+
**args: Any
|
1060 |
+
) -> _flagvalues.FlagHolder[Optional[List[_T]]]:
|
1061 |
+
...
|
1062 |
+
|
1063 |
+
|
1064 |
+
@overload
|
1065 |
+
def DEFINE_multi( # pylint: disable=invalid-name
|
1066 |
+
parser: _argument_parser.ArgumentParser[_T],
|
1067 |
+
serializer: _argument_parser.ArgumentSerializer[_T],
|
1068 |
+
name: Text,
|
1069 |
+
default: Iterable[_T],
|
1070 |
+
help: Text, # pylint: disable=redefined-builtin
|
1071 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1072 |
+
module_name: Optional[Text] = ...,
|
1073 |
+
required: bool = ...,
|
1074 |
+
**args: Any
|
1075 |
+
) -> _flagvalues.FlagHolder[List[_T]]:
|
1076 |
+
...
|
1077 |
+
|
1078 |
+
|
1079 |
+
@overload
|
1080 |
+
def DEFINE_multi( # pylint: disable=invalid-name
|
1081 |
+
parser: _argument_parser.ArgumentParser[_T],
|
1082 |
+
serializer: _argument_parser.ArgumentSerializer[_T],
|
1083 |
+
name: Text,
|
1084 |
+
default: _T,
|
1085 |
+
help: Text, # pylint: disable=redefined-builtin
|
1086 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1087 |
+
module_name: Optional[Text] = ...,
|
1088 |
+
required: bool = ...,
|
1089 |
+
**args: Any
|
1090 |
+
) -> _flagvalues.FlagHolder[List[_T]]:
|
1091 |
+
...
|
1092 |
+
|
1093 |
+
|
1094 |
+
def DEFINE_multi( # pylint: disable=invalid-name,redefined-builtin
|
1095 |
+
parser,
|
1096 |
+
serializer,
|
1097 |
+
name,
|
1098 |
+
default,
|
1099 |
+
help,
|
1100 |
+
flag_values=_flagvalues.FLAGS,
|
1101 |
+
module_name=None,
|
1102 |
+
required=False,
|
1103 |
+
**args):
|
1104 |
+
"""Registers a generic MultiFlag that parses its args with a given parser.
|
1105 |
+
|
1106 |
+
Auxiliary function. Normal users should NOT use it directly.
|
1107 |
+
|
1108 |
+
Developers who need to create their own 'Parser' classes for options
|
1109 |
+
which can appear multiple times can call this module function to
|
1110 |
+
register their flags.
|
1111 |
+
|
1112 |
+
Args:
|
1113 |
+
parser: ArgumentParser, used to parse the flag arguments.
|
1114 |
+
serializer: ArgumentSerializer, the flag serializer instance.
|
1115 |
+
name: str, the flag name.
|
1116 |
+
default: Union[Iterable[T], Text, None], the default value of the flag. If
|
1117 |
+
the value is text, it will be parsed as if it was provided from the
|
1118 |
+
command line. If the value is a non-string iterable, it will be iterated
|
1119 |
+
over to create a shallow copy of the values. If it is None, it is left
|
1120 |
+
as-is.
|
1121 |
+
help: str, the help message.
|
1122 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
1123 |
+
flag will be registered. This should almost never need to be overridden.
|
1124 |
+
module_name: A string, the name of the Python module declaring this flag. If
|
1125 |
+
not provided, it will be computed using the stack trace of this call.
|
1126 |
+
required: bool, is this a required flag. This must be used as a keyword
|
1127 |
+
argument.
|
1128 |
+
**args: Dictionary with extra keyword args that are passed to the
|
1129 |
+
``Flag.__init__``.
|
1130 |
+
|
1131 |
+
Returns:
|
1132 |
+
a handle to defined flag.
|
1133 |
+
"""
|
1134 |
+
result = DEFINE_flag(
|
1135 |
+
_flag.MultiFlag(parser, serializer, name, default, help, **args),
|
1136 |
+
flag_values,
|
1137 |
+
module_name,
|
1138 |
+
required=True if required else False,
|
1139 |
+
)
|
1140 |
+
return result
|
1141 |
+
|
1142 |
+
|
1143 |
+
@overload
|
1144 |
+
def DEFINE_multi_string( # pylint: disable=invalid-name
|
1145 |
+
name: Text,
|
1146 |
+
default: Union[None, Iterable[Text], Text],
|
1147 |
+
help: Text, # pylint: disable=redefined-builtin
|
1148 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1149 |
+
*,
|
1150 |
+
required: 'typing.Literal[True]',
|
1151 |
+
**args: Any
|
1152 |
+
) -> _flagvalues.FlagHolder[List[Text]]:
|
1153 |
+
...
|
1154 |
+
|
1155 |
+
|
1156 |
+
@overload
|
1157 |
+
def DEFINE_multi_string( # pylint: disable=invalid-name
|
1158 |
+
name: Text,
|
1159 |
+
default: None,
|
1160 |
+
help: Text, # pylint: disable=redefined-builtin
|
1161 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1162 |
+
required: bool = ...,
|
1163 |
+
**args: Any
|
1164 |
+
) -> _flagvalues.FlagHolder[Optional[List[Text]]]:
|
1165 |
+
...
|
1166 |
+
|
1167 |
+
|
1168 |
+
@overload
|
1169 |
+
def DEFINE_multi_string( # pylint: disable=invalid-name
|
1170 |
+
name: Text,
|
1171 |
+
default: Union[Iterable[Text], Text],
|
1172 |
+
help: Text, # pylint: disable=redefined-builtin
|
1173 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1174 |
+
required: bool = ...,
|
1175 |
+
**args: Any
|
1176 |
+
) -> _flagvalues.FlagHolder[List[Text]]:
|
1177 |
+
...
|
1178 |
+
|
1179 |
+
|
1180 |
+
def DEFINE_multi_string( # pylint: disable=invalid-name,redefined-builtin
|
1181 |
+
name,
|
1182 |
+
default,
|
1183 |
+
help,
|
1184 |
+
flag_values=_flagvalues.FLAGS,
|
1185 |
+
required=False,
|
1186 |
+
**args):
|
1187 |
+
"""Registers a flag whose value can be a list of any strings.
|
1188 |
+
|
1189 |
+
Use the flag on the command line multiple times to place multiple
|
1190 |
+
string values into the list. The 'default' may be a single string
|
1191 |
+
(which will be converted into a single-element list) or a list of
|
1192 |
+
strings.
|
1193 |
+
|
1194 |
+
|
1195 |
+
Args:
|
1196 |
+
name: str, the flag name.
|
1197 |
+
default: Union[Iterable[Text], Text, None], the default value of the flag;
|
1198 |
+
see :func:`DEFINE_multi`.
|
1199 |
+
help: str, the help message.
|
1200 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
1201 |
+
flag will be registered. This should almost never need to be overridden.
|
1202 |
+
required: bool, is this a required flag. This must be used as a keyword
|
1203 |
+
argument.
|
1204 |
+
**args: Dictionary with extra keyword args that are passed to the
|
1205 |
+
``Flag.__init__``.
|
1206 |
+
|
1207 |
+
Returns:
|
1208 |
+
a handle to defined flag.
|
1209 |
+
"""
|
1210 |
+
parser = _argument_parser.ArgumentParser()
|
1211 |
+
serializer = _argument_parser.ArgumentSerializer()
|
1212 |
+
return DEFINE_multi(
|
1213 |
+
parser,
|
1214 |
+
serializer,
|
1215 |
+
name,
|
1216 |
+
default,
|
1217 |
+
help,
|
1218 |
+
flag_values,
|
1219 |
+
required=True if required else False,
|
1220 |
+
**args,
|
1221 |
+
)
|
1222 |
+
|
1223 |
+
|
1224 |
+
@overload
|
1225 |
+
def DEFINE_multi_integer( # pylint: disable=invalid-name
|
1226 |
+
name: Text,
|
1227 |
+
default: Union[None, Iterable[int], int, Text],
|
1228 |
+
help: Text, # pylint: disable=redefined-builtin
|
1229 |
+
lower_bound: Optional[int] = ...,
|
1230 |
+
upper_bound: Optional[int] = ...,
|
1231 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1232 |
+
*,
|
1233 |
+
required: 'typing.Literal[True]',
|
1234 |
+
**args: Any
|
1235 |
+
) -> _flagvalues.FlagHolder[List[int]]:
|
1236 |
+
...
|
1237 |
+
|
1238 |
+
|
1239 |
+
@overload
|
1240 |
+
def DEFINE_multi_integer( # pylint: disable=invalid-name
|
1241 |
+
name: Text,
|
1242 |
+
default: None,
|
1243 |
+
help: Text, # pylint: disable=redefined-builtin
|
1244 |
+
lower_bound: Optional[int] = ...,
|
1245 |
+
upper_bound: Optional[int] = ...,
|
1246 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1247 |
+
required: bool = ...,
|
1248 |
+
**args: Any
|
1249 |
+
) -> _flagvalues.FlagHolder[Optional[List[int]]]:
|
1250 |
+
...
|
1251 |
+
|
1252 |
+
|
1253 |
+
@overload
|
1254 |
+
def DEFINE_multi_integer( # pylint: disable=invalid-name
|
1255 |
+
name: Text,
|
1256 |
+
default: Union[Iterable[int], int, Text],
|
1257 |
+
help: Text, # pylint: disable=redefined-builtin
|
1258 |
+
lower_bound: Optional[int] = ...,
|
1259 |
+
upper_bound: Optional[int] = ...,
|
1260 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1261 |
+
required: bool = ...,
|
1262 |
+
**args: Any
|
1263 |
+
) -> _flagvalues.FlagHolder[List[int]]:
|
1264 |
+
...
|
1265 |
+
|
1266 |
+
|
1267 |
+
def DEFINE_multi_integer( # pylint: disable=invalid-name,redefined-builtin
|
1268 |
+
name,
|
1269 |
+
default,
|
1270 |
+
help,
|
1271 |
+
lower_bound=None,
|
1272 |
+
upper_bound=None,
|
1273 |
+
flag_values=_flagvalues.FLAGS,
|
1274 |
+
required=False,
|
1275 |
+
**args):
|
1276 |
+
"""Registers a flag whose value can be a list of arbitrary integers.
|
1277 |
+
|
1278 |
+
Use the flag on the command line multiple times to place multiple
|
1279 |
+
integer values into the list. The 'default' may be a single integer
|
1280 |
+
(which will be converted into a single-element list) or a list of
|
1281 |
+
integers.
|
1282 |
+
|
1283 |
+
Args:
|
1284 |
+
name: str, the flag name.
|
1285 |
+
default: Union[Iterable[int], Text, None], the default value of the flag;
|
1286 |
+
see `DEFINE_multi`.
|
1287 |
+
help: str, the help message.
|
1288 |
+
lower_bound: int, min values of the flag.
|
1289 |
+
upper_bound: int, max values of the flag.
|
1290 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
1291 |
+
flag will be registered. This should almost never need to be overridden.
|
1292 |
+
required: bool, is this a required flag. This must be used as a keyword
|
1293 |
+
argument.
|
1294 |
+
**args: Dictionary with extra keyword args that are passed to the
|
1295 |
+
``Flag.__init__``.
|
1296 |
+
|
1297 |
+
Returns:
|
1298 |
+
a handle to defined flag.
|
1299 |
+
"""
|
1300 |
+
parser = _argument_parser.IntegerParser(lower_bound, upper_bound)
|
1301 |
+
serializer = _argument_parser.ArgumentSerializer()
|
1302 |
+
return DEFINE_multi(
|
1303 |
+
parser,
|
1304 |
+
serializer,
|
1305 |
+
name,
|
1306 |
+
default,
|
1307 |
+
help,
|
1308 |
+
flag_values,
|
1309 |
+
required=True if required else False,
|
1310 |
+
**args,
|
1311 |
+
)
|
1312 |
+
|
1313 |
+
|
1314 |
+
@overload
|
1315 |
+
def DEFINE_multi_float( # pylint: disable=invalid-name
|
1316 |
+
name: Text,
|
1317 |
+
default: Union[None, Iterable[float], float, Text],
|
1318 |
+
help: Text, # pylint: disable=redefined-builtin
|
1319 |
+
lower_bound: Optional[float] = ...,
|
1320 |
+
upper_bound: Optional[float] = ...,
|
1321 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1322 |
+
*,
|
1323 |
+
required: 'typing.Literal[True]',
|
1324 |
+
**args: Any
|
1325 |
+
) -> _flagvalues.FlagHolder[List[float]]:
|
1326 |
+
...
|
1327 |
+
|
1328 |
+
|
1329 |
+
@overload
|
1330 |
+
def DEFINE_multi_float( # pylint: disable=invalid-name
|
1331 |
+
name: Text,
|
1332 |
+
default: None,
|
1333 |
+
help: Text, # pylint: disable=redefined-builtin
|
1334 |
+
lower_bound: Optional[float] = ...,
|
1335 |
+
upper_bound: Optional[float] = ...,
|
1336 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1337 |
+
required: bool = ...,
|
1338 |
+
**args: Any
|
1339 |
+
) -> _flagvalues.FlagHolder[Optional[List[float]]]:
|
1340 |
+
...
|
1341 |
+
|
1342 |
+
|
1343 |
+
@overload
|
1344 |
+
def DEFINE_multi_float( # pylint: disable=invalid-name
|
1345 |
+
name: Text,
|
1346 |
+
default: Union[Iterable[float], float, Text],
|
1347 |
+
help: Text, # pylint: disable=redefined-builtin
|
1348 |
+
lower_bound: Optional[float] = ...,
|
1349 |
+
upper_bound: Optional[float] = ...,
|
1350 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1351 |
+
required: bool = ...,
|
1352 |
+
**args: Any
|
1353 |
+
) -> _flagvalues.FlagHolder[List[float]]:
|
1354 |
+
...
|
1355 |
+
|
1356 |
+
|
1357 |
+
def DEFINE_multi_float( # pylint: disable=invalid-name,redefined-builtin
|
1358 |
+
name,
|
1359 |
+
default,
|
1360 |
+
help,
|
1361 |
+
lower_bound=None,
|
1362 |
+
upper_bound=None,
|
1363 |
+
flag_values=_flagvalues.FLAGS,
|
1364 |
+
required=False,
|
1365 |
+
**args):
|
1366 |
+
"""Registers a flag whose value can be a list of arbitrary floats.
|
1367 |
+
|
1368 |
+
Use the flag on the command line multiple times to place multiple
|
1369 |
+
float values into the list. The 'default' may be a single float
|
1370 |
+
(which will be converted into a single-element list) or a list of
|
1371 |
+
floats.
|
1372 |
+
|
1373 |
+
Args:
|
1374 |
+
name: str, the flag name.
|
1375 |
+
default: Union[Iterable[float], Text, None], the default value of the flag;
|
1376 |
+
see `DEFINE_multi`.
|
1377 |
+
help: str, the help message.
|
1378 |
+
lower_bound: float, min values of the flag.
|
1379 |
+
upper_bound: float, max values of the flag.
|
1380 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
1381 |
+
flag will be registered. This should almost never need to be overridden.
|
1382 |
+
required: bool, is this a required flag. This must be used as a keyword
|
1383 |
+
argument.
|
1384 |
+
**args: Dictionary with extra keyword args that are passed to the
|
1385 |
+
``Flag.__init__``.
|
1386 |
+
|
1387 |
+
Returns:
|
1388 |
+
a handle to defined flag.
|
1389 |
+
"""
|
1390 |
+
parser = _argument_parser.FloatParser(lower_bound, upper_bound)
|
1391 |
+
serializer = _argument_parser.ArgumentSerializer()
|
1392 |
+
return DEFINE_multi(
|
1393 |
+
parser,
|
1394 |
+
serializer,
|
1395 |
+
name,
|
1396 |
+
default,
|
1397 |
+
help,
|
1398 |
+
flag_values,
|
1399 |
+
required=True if required else False,
|
1400 |
+
**args,
|
1401 |
+
)
|
1402 |
+
|
1403 |
+
|
1404 |
+
@overload
|
1405 |
+
def DEFINE_multi_enum( # pylint: disable=invalid-name
|
1406 |
+
name: Text,
|
1407 |
+
default: Union[None, Iterable[Text], Text],
|
1408 |
+
enum_values: Iterable[Text],
|
1409 |
+
help: Text, # pylint: disable=redefined-builtin
|
1410 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1411 |
+
*,
|
1412 |
+
required: 'typing.Literal[True]',
|
1413 |
+
**args: Any
|
1414 |
+
) -> _flagvalues.FlagHolder[List[Text]]:
|
1415 |
+
...
|
1416 |
+
|
1417 |
+
|
1418 |
+
@overload
|
1419 |
+
def DEFINE_multi_enum( # pylint: disable=invalid-name
|
1420 |
+
name: Text,
|
1421 |
+
default: None,
|
1422 |
+
enum_values: Iterable[Text],
|
1423 |
+
help: Text, # pylint: disable=redefined-builtin
|
1424 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1425 |
+
required: bool = ...,
|
1426 |
+
**args: Any
|
1427 |
+
) -> _flagvalues.FlagHolder[Optional[List[Text]]]:
|
1428 |
+
...
|
1429 |
+
|
1430 |
+
|
1431 |
+
@overload
|
1432 |
+
def DEFINE_multi_enum( # pylint: disable=invalid-name
|
1433 |
+
name: Text,
|
1434 |
+
default: Union[Iterable[Text], Text],
|
1435 |
+
enum_values: Iterable[Text],
|
1436 |
+
help: Text, # pylint: disable=redefined-builtin
|
1437 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1438 |
+
required: bool = ...,
|
1439 |
+
**args: Any
|
1440 |
+
) -> _flagvalues.FlagHolder[List[Text]]:
|
1441 |
+
...
|
1442 |
+
|
1443 |
+
|
1444 |
+
def DEFINE_multi_enum( # pylint: disable=invalid-name,redefined-builtin
|
1445 |
+
name,
|
1446 |
+
default,
|
1447 |
+
enum_values,
|
1448 |
+
help,
|
1449 |
+
flag_values=_flagvalues.FLAGS,
|
1450 |
+
case_sensitive=True,
|
1451 |
+
required=False,
|
1452 |
+
**args):
|
1453 |
+
"""Registers a flag whose value can be a list strings from enum_values.
|
1454 |
+
|
1455 |
+
Use the flag on the command line multiple times to place multiple
|
1456 |
+
enum values into the list. The 'default' may be a single string
|
1457 |
+
(which will be converted into a single-element list) or a list of
|
1458 |
+
strings.
|
1459 |
+
|
1460 |
+
Args:
|
1461 |
+
name: str, the flag name.
|
1462 |
+
default: Union[Iterable[Text], Text, None], the default value of the flag;
|
1463 |
+
see `DEFINE_multi`.
|
1464 |
+
enum_values: [str], a non-empty list of strings with the possible values for
|
1465 |
+
the flag.
|
1466 |
+
help: str, the help message.
|
1467 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
1468 |
+
flag will be registered. This should almost never need to be overridden.
|
1469 |
+
case_sensitive: Whether or not the enum is to be case-sensitive.
|
1470 |
+
required: bool, is this a required flag. This must be used as a keyword
|
1471 |
+
argument.
|
1472 |
+
**args: Dictionary with extra keyword args that are passed to the
|
1473 |
+
``Flag.__init__``.
|
1474 |
+
|
1475 |
+
Returns:
|
1476 |
+
a handle to defined flag.
|
1477 |
+
"""
|
1478 |
+
parser = _argument_parser.EnumParser(enum_values, case_sensitive)
|
1479 |
+
serializer = _argument_parser.ArgumentSerializer()
|
1480 |
+
return DEFINE_multi(
|
1481 |
+
parser,
|
1482 |
+
serializer,
|
1483 |
+
name,
|
1484 |
+
default,
|
1485 |
+
'<%s>: %s' % ('|'.join(enum_values), help),
|
1486 |
+
flag_values,
|
1487 |
+
required=True if required else False,
|
1488 |
+
**args,
|
1489 |
+
)
|
1490 |
+
|
1491 |
+
|
1492 |
+
@overload
|
1493 |
+
def DEFINE_multi_enum_class( # pylint: disable=invalid-name
|
1494 |
+
name: Text,
|
1495 |
+
# This is separate from `Union[None, _ET, Iterable[Text], Text]` to avoid a
|
1496 |
+
# Pytype issue inferring the return value to
|
1497 |
+
# FlagHolder[List[Union[_ET, enum.Enum]]] when an iterable of concrete enum
|
1498 |
+
# subclasses are used.
|
1499 |
+
default: Iterable[_ET],
|
1500 |
+
enum_class: Type[_ET],
|
1501 |
+
help: Text, # pylint: disable=redefined-builtin
|
1502 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1503 |
+
module_name: Optional[Text] = ...,
|
1504 |
+
*,
|
1505 |
+
required: 'typing.Literal[True]',
|
1506 |
+
**args: Any
|
1507 |
+
) -> _flagvalues.FlagHolder[List[_ET]]:
|
1508 |
+
...
|
1509 |
+
|
1510 |
+
|
1511 |
+
@overload
|
1512 |
+
def DEFINE_multi_enum_class( # pylint: disable=invalid-name
|
1513 |
+
name: Text,
|
1514 |
+
default: Union[None, _ET, Iterable[Text], Text],
|
1515 |
+
enum_class: Type[_ET],
|
1516 |
+
help: Text, # pylint: disable=redefined-builtin
|
1517 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1518 |
+
module_name: Optional[Text] = ...,
|
1519 |
+
*,
|
1520 |
+
required: 'typing.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: Text,
|
1529 |
+
default: None,
|
1530 |
+
enum_class: Type[_ET],
|
1531 |
+
help: Text, # pylint: disable=redefined-builtin
|
1532 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1533 |
+
module_name: Optional[Text] = ...,
|
1534 |
+
required: bool = ...,
|
1535 |
+
**args: Any
|
1536 |
+
) -> _flagvalues.FlagHolder[Optional[List[_ET]]]:
|
1537 |
+
...
|
1538 |
+
|
1539 |
+
|
1540 |
+
@overload
|
1541 |
+
def DEFINE_multi_enum_class( # pylint: disable=invalid-name
|
1542 |
+
name: Text,
|
1543 |
+
# This is separate from `Union[None, _ET, Iterable[Text], Text]` to avoid a
|
1544 |
+
# Pytype issue inferring the return value to
|
1545 |
+
# FlagHolder[List[Union[_ET, enum.Enum]]] when an iterable of concrete enum
|
1546 |
+
# subclasses are used.
|
1547 |
+
default: Iterable[_ET],
|
1548 |
+
enum_class: Type[_ET],
|
1549 |
+
help: Text, # pylint: disable=redefined-builtin
|
1550 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1551 |
+
module_name: Optional[Text] = ...,
|
1552 |
+
required: bool = ...,
|
1553 |
+
**args: Any
|
1554 |
+
) -> _flagvalues.FlagHolder[List[_ET]]:
|
1555 |
+
...
|
1556 |
+
|
1557 |
+
|
1558 |
+
@overload
|
1559 |
+
def DEFINE_multi_enum_class( # pylint: disable=invalid-name
|
1560 |
+
name: Text,
|
1561 |
+
default: Union[_ET, Iterable[Text], Text],
|
1562 |
+
enum_class: Type[_ET],
|
1563 |
+
help: Text, # pylint: disable=redefined-builtin
|
1564 |
+
flag_values: _flagvalues.FlagValues = ...,
|
1565 |
+
module_name: Optional[Text] = ...,
|
1566 |
+
required: bool = ...,
|
1567 |
+
**args: Any
|
1568 |
+
) -> _flagvalues.FlagHolder[List[_ET]]:
|
1569 |
+
...
|
1570 |
+
|
1571 |
+
|
1572 |
+
def DEFINE_multi_enum_class( # pylint: disable=invalid-name,redefined-builtin
|
1573 |
+
name,
|
1574 |
+
default,
|
1575 |
+
enum_class,
|
1576 |
+
help,
|
1577 |
+
flag_values=_flagvalues.FLAGS,
|
1578 |
+
module_name=None,
|
1579 |
+
case_sensitive=False,
|
1580 |
+
required=False,
|
1581 |
+
**args):
|
1582 |
+
"""Registers a flag whose value can be a list of enum members.
|
1583 |
+
|
1584 |
+
Use the flag on the command line multiple times to place multiple
|
1585 |
+
enum values into the list.
|
1586 |
+
|
1587 |
+
Args:
|
1588 |
+
name: str, the flag name.
|
1589 |
+
default: Union[Iterable[Enum], Iterable[Text], Enum, Text, None], the
|
1590 |
+
default value of the flag; see `DEFINE_multi`; only differences are
|
1591 |
+
documented here. If the value is a single Enum, it is treated as a
|
1592 |
+
single-item list of that Enum value. If it is an iterable, text values
|
1593 |
+
within the iterable will be converted to the equivalent Enum objects.
|
1594 |
+
enum_class: class, the Enum class with all the possible values for the flag.
|
1595 |
+
help: str, the help message.
|
1596 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
1597 |
+
flag will be registered. This should almost never need to be overridden.
|
1598 |
+
module_name: A string, the name of the Python module declaring this flag. If
|
1599 |
+
not provided, it will be computed using the stack trace of this call.
|
1600 |
+
case_sensitive: bool, whether to map strings to members of the enum_class
|
1601 |
+
without considering case.
|
1602 |
+
required: bool, is this a required flag. This must be used as a keyword
|
1603 |
+
argument.
|
1604 |
+
**args: Dictionary with extra keyword args that are passed to the
|
1605 |
+
``Flag.__init__``.
|
1606 |
+
|
1607 |
+
Returns:
|
1608 |
+
a handle to defined flag.
|
1609 |
+
"""
|
1610 |
+
# NOTE: pytype fails if this is a direct return.
|
1611 |
+
result = DEFINE_flag(
|
1612 |
+
_flag.MultiEnumClassFlag(
|
1613 |
+
name,
|
1614 |
+
default,
|
1615 |
+
help,
|
1616 |
+
enum_class,
|
1617 |
+
case_sensitive=case_sensitive,
|
1618 |
+
**args,
|
1619 |
+
),
|
1620 |
+
flag_values,
|
1621 |
+
module_name,
|
1622 |
+
required=True if required else False,
|
1623 |
+
)
|
1624 |
+
return result
|
1625 |
+
|
1626 |
+
|
1627 |
+
def DEFINE_alias( # pylint: disable=invalid-name
|
1628 |
+
name: Text,
|
1629 |
+
original_name: Text,
|
1630 |
+
flag_values: _flagvalues.FlagValues = _flagvalues.FLAGS,
|
1631 |
+
module_name: Optional[Text] = None,
|
1632 |
+
) -> _flagvalues.FlagHolder[Any]:
|
1633 |
+
"""Defines an alias flag for an existing one.
|
1634 |
+
|
1635 |
+
Args:
|
1636 |
+
name: str, the flag name.
|
1637 |
+
original_name: str, the original flag name.
|
1638 |
+
flag_values: :class:`FlagValues`, the FlagValues instance with which the
|
1639 |
+
flag will be registered. This should almost never need to be overridden.
|
1640 |
+
module_name: A string, the name of the module that defines this flag.
|
1641 |
+
|
1642 |
+
Returns:
|
1643 |
+
a handle to defined flag.
|
1644 |
+
|
1645 |
+
Raises:
|
1646 |
+
flags.FlagError:
|
1647 |
+
UnrecognizedFlagError: if the referenced flag doesn't exist.
|
1648 |
+
DuplicateFlagError: if the alias name has been used by some existing flag.
|
1649 |
+
"""
|
1650 |
+
if original_name not in flag_values:
|
1651 |
+
raise _exceptions.UnrecognizedFlagError(original_name)
|
1652 |
+
flag = flag_values[original_name]
|
1653 |
+
|
1654 |
+
class _FlagAlias(_flag.Flag):
|
1655 |
+
"""Overrides Flag class so alias value is copy of original flag value."""
|
1656 |
+
|
1657 |
+
def parse(self, argument):
|
1658 |
+
flag.parse(argument)
|
1659 |
+
self.present += 1
|
1660 |
+
|
1661 |
+
def _parse_from_default(self, value):
|
1662 |
+
# The value was already parsed by the aliased flag, so there is no
|
1663 |
+
# need to call the parser on it a second time.
|
1664 |
+
# Additionally, because of how MultiFlag parses and merges values,
|
1665 |
+
# it isn't possible to delegate to the aliased flag and still get
|
1666 |
+
# the correct values.
|
1667 |
+
return value
|
1668 |
+
|
1669 |
+
@property
|
1670 |
+
def value(self):
|
1671 |
+
return flag.value
|
1672 |
+
|
1673 |
+
@value.setter
|
1674 |
+
def value(self, value):
|
1675 |
+
flag.value = value
|
1676 |
+
|
1677 |
+
help_msg = 'Alias for --%s.' % flag.name
|
1678 |
+
# If alias_name has been used, flags.DuplicatedFlag will be raised.
|
1679 |
+
return DEFINE_flag(
|
1680 |
+
_FlagAlias(
|
1681 |
+
flag.parser,
|
1682 |
+
flag.serializer,
|
1683 |
+
name,
|
1684 |
+
flag.default,
|
1685 |
+
help_msg,
|
1686 |
+
boolean=flag.boolean), flag_values, module_name)
|
MLPY/Lib/site-packages/absl/flags/_exceptions.py
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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(UnrecognizedFlagError, self).__init__(
|
96 |
+
'Unknown command line flag \'%s\'%s' % (flagname, tip))
|
97 |
+
|
98 |
+
|
99 |
+
class UnparsedFlagAccessError(Error):
|
100 |
+
"""Raised when accessing the flag value from unparsed :class:`FlagValues`."""
|
101 |
+
|
102 |
+
|
103 |
+
class ValidationError(Error):
|
104 |
+
"""Raised when flag validator constraint is not satisfied."""
|
105 |
+
|
106 |
+
|
107 |
+
class FlagNameConflictsWithMethodError(Error):
|
108 |
+
"""Raised when a flag name conflicts with :class:`FlagValues` methods."""
|
MLPY/Lib/site-packages/absl/flags/_flag.py
ADDED
@@ -0,0 +1,556 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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, Text, 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[Text]
|
88 |
+
default_unparsed: Union[Optional[_T], Text]
|
89 |
+
|
90 |
+
def __init__(
|
91 |
+
self,
|
92 |
+
parser: _argument_parser.ArgumentParser[_T],
|
93 |
+
serializer: Optional[_argument_parser.ArgumentSerializer[_T]],
|
94 |
+
name: Text,
|
95 |
+
default: Union[Optional[_T], Text],
|
96 |
+
help_string: Optional[Text],
|
97 |
+
short_name: Optional[Text] = None,
|
98 |
+
boolean: bool = False,
|
99 |
+
allow_override: bool = False,
|
100 |
+
allow_override_cpp: bool = False,
|
101 |
+
allow_hide_cpp: bool = False,
|
102 |
+
allow_overwrite: bool = True,
|
103 |
+
allow_using_method_names: bool = False,
|
104 |
+
) -> None:
|
105 |
+
self.name = name
|
106 |
+
|
107 |
+
if not help_string:
|
108 |
+
help_string = '(no help available)'
|
109 |
+
|
110 |
+
self.help = help_string
|
111 |
+
self.short_name = short_name
|
112 |
+
self.boolean = boolean
|
113 |
+
self.present = 0
|
114 |
+
self.parser = parser
|
115 |
+
self.serializer = serializer
|
116 |
+
self.allow_override = allow_override
|
117 |
+
self.allow_override_cpp = allow_override_cpp
|
118 |
+
self.allow_hide_cpp = allow_hide_cpp
|
119 |
+
self.allow_overwrite = allow_overwrite
|
120 |
+
self.allow_using_method_names = allow_using_method_names
|
121 |
+
|
122 |
+
self.using_default_value = True
|
123 |
+
self._value = None
|
124 |
+
self.validators = []
|
125 |
+
if self.allow_hide_cpp and self.allow_override_cpp:
|
126 |
+
raise _exceptions.Error(
|
127 |
+
"Can't have both allow_hide_cpp (means use Python flag) and "
|
128 |
+
'allow_override_cpp (means use C++ flag after InitGoogle)')
|
129 |
+
|
130 |
+
self._set_default(default)
|
131 |
+
|
132 |
+
@property
|
133 |
+
def value(self) -> Optional[_T]:
|
134 |
+
return self._value
|
135 |
+
|
136 |
+
@value.setter
|
137 |
+
def value(self, value: Optional[_T]):
|
138 |
+
self._value = value
|
139 |
+
|
140 |
+
def __hash__(self):
|
141 |
+
return hash(id(self))
|
142 |
+
|
143 |
+
def __eq__(self, other):
|
144 |
+
return self is other
|
145 |
+
|
146 |
+
def __lt__(self, other):
|
147 |
+
if isinstance(other, Flag):
|
148 |
+
return id(self) < id(other)
|
149 |
+
return NotImplemented
|
150 |
+
|
151 |
+
def __bool__(self):
|
152 |
+
raise TypeError('A Flag instance would always be True. '
|
153 |
+
'Did you mean to test the `.value` attribute?')
|
154 |
+
|
155 |
+
def __getstate__(self):
|
156 |
+
raise TypeError("can't pickle Flag objects")
|
157 |
+
|
158 |
+
def __copy__(self):
|
159 |
+
raise TypeError('%s does not support shallow copies. '
|
160 |
+
'Use copy.deepcopy instead.' % type(self).__name__)
|
161 |
+
|
162 |
+
def __deepcopy__(self, memo: Dict[int, Any]) -> 'Flag[_T]':
|
163 |
+
result = object.__new__(type(self))
|
164 |
+
result.__dict__ = copy.deepcopy(self.__dict__, memo)
|
165 |
+
return result
|
166 |
+
|
167 |
+
def _get_parsed_value_as_string(self, value: Optional[_T]) -> Optional[Text]:
|
168 |
+
"""Returns parsed flag value as string."""
|
169 |
+
if value is None:
|
170 |
+
return None
|
171 |
+
if self.serializer:
|
172 |
+
return repr(self.serializer.serialize(value))
|
173 |
+
if self.boolean:
|
174 |
+
if value:
|
175 |
+
return repr('true')
|
176 |
+
else:
|
177 |
+
return repr('false')
|
178 |
+
return repr(str(value))
|
179 |
+
|
180 |
+
def parse(self, argument: Union[Text, Optional[_T]]) -> None:
|
181 |
+
"""Parses string and sets flag value.
|
182 |
+
|
183 |
+
Args:
|
184 |
+
argument: str or the correct flag value type, argument to be parsed.
|
185 |
+
"""
|
186 |
+
if self.present and not self.allow_overwrite:
|
187 |
+
raise _exceptions.IllegalFlagValueError(
|
188 |
+
'flag --%s=%s: already defined as %s' % (
|
189 |
+
self.name, argument, self.value))
|
190 |
+
self.value = self._parse(argument)
|
191 |
+
self.present += 1
|
192 |
+
|
193 |
+
def _parse(self, argument: Union[Text, _T]) -> Optional[_T]:
|
194 |
+
"""Internal parse function.
|
195 |
+
|
196 |
+
It returns the parsed value, and does not modify class states.
|
197 |
+
|
198 |
+
Args:
|
199 |
+
argument: str or the correct flag value type, argument to be parsed.
|
200 |
+
|
201 |
+
Returns:
|
202 |
+
The parsed value.
|
203 |
+
"""
|
204 |
+
try:
|
205 |
+
return self.parser.parse(argument)
|
206 |
+
except (TypeError, ValueError) as e: # Recast as IllegalFlagValueError.
|
207 |
+
raise _exceptions.IllegalFlagValueError(
|
208 |
+
'flag --%s=%s: %s' % (self.name, argument, e))
|
209 |
+
|
210 |
+
def unparse(self) -> None:
|
211 |
+
self.value = self.default
|
212 |
+
self.using_default_value = True
|
213 |
+
self.present = 0
|
214 |
+
|
215 |
+
def serialize(self) -> Text:
|
216 |
+
"""Serializes the flag."""
|
217 |
+
return self._serialize(self.value)
|
218 |
+
|
219 |
+
def _serialize(self, value: Optional[_T]) -> Text:
|
220 |
+
"""Internal serialize function."""
|
221 |
+
if value is None:
|
222 |
+
return ''
|
223 |
+
if self.boolean:
|
224 |
+
if value:
|
225 |
+
return '--%s' % self.name
|
226 |
+
else:
|
227 |
+
return '--no%s' % self.name
|
228 |
+
else:
|
229 |
+
if not self.serializer:
|
230 |
+
raise _exceptions.Error(
|
231 |
+
'Serializer not present for flag %s' % self.name)
|
232 |
+
return '--%s=%s' % (self.name, self.serializer.serialize(value))
|
233 |
+
|
234 |
+
def _set_default(self, value: Union[Optional[_T], Text]) -> None:
|
235 |
+
"""Changes the default value (and current value too) for this Flag."""
|
236 |
+
self.default_unparsed = value
|
237 |
+
if value is None:
|
238 |
+
self.default = None
|
239 |
+
else:
|
240 |
+
self.default = self._parse_from_default(value)
|
241 |
+
self.default_as_str = self._get_parsed_value_as_string(self.default)
|
242 |
+
if self.using_default_value:
|
243 |
+
self.value = self.default
|
244 |
+
|
245 |
+
# This is split out so that aliases can skip regular parsing of the default
|
246 |
+
# value.
|
247 |
+
def _parse_from_default(self, value: Union[Text, _T]) -> Optional[_T]:
|
248 |
+
return self._parse(value)
|
249 |
+
|
250 |
+
def flag_type(self) -> Text:
|
251 |
+
"""Returns a str that describes the type of the flag.
|
252 |
+
|
253 |
+
NOTE: we use strings, and not the types.*Type constants because
|
254 |
+
our flags can have more exotic types, e.g., 'comma separated list
|
255 |
+
of strings', 'whitespace separated list of strings', etc.
|
256 |
+
"""
|
257 |
+
return self.parser.flag_type()
|
258 |
+
|
259 |
+
def _create_xml_dom_element(
|
260 |
+
self, doc: minidom.Document, module_name: str, is_key: bool = False
|
261 |
+
) -> minidom.Element:
|
262 |
+
"""Returns an XML element that contains this flag's information.
|
263 |
+
|
264 |
+
This is information that is relevant to all flags (e.g., name,
|
265 |
+
meaning, etc.). If you defined a flag that has some other pieces of
|
266 |
+
info, then please override _ExtraXMLInfo.
|
267 |
+
|
268 |
+
Please do NOT override this method.
|
269 |
+
|
270 |
+
Args:
|
271 |
+
doc: minidom.Document, the DOM document it should create nodes from.
|
272 |
+
module_name: str,, the name of the module that defines this flag.
|
273 |
+
is_key: boolean, True iff this flag is key for main module.
|
274 |
+
|
275 |
+
Returns:
|
276 |
+
A minidom.Element instance.
|
277 |
+
"""
|
278 |
+
element = doc.createElement('flag')
|
279 |
+
if is_key:
|
280 |
+
element.appendChild(_helpers.create_xml_dom_element(doc, 'key', 'yes'))
|
281 |
+
element.appendChild(_helpers.create_xml_dom_element(
|
282 |
+
doc, 'file', module_name))
|
283 |
+
# Adds flag features that are relevant for all flags.
|
284 |
+
element.appendChild(_helpers.create_xml_dom_element(doc, 'name', self.name))
|
285 |
+
if self.short_name:
|
286 |
+
element.appendChild(_helpers.create_xml_dom_element(
|
287 |
+
doc, 'short_name', self.short_name))
|
288 |
+
if self.help:
|
289 |
+
element.appendChild(_helpers.create_xml_dom_element(
|
290 |
+
doc, 'meaning', self.help))
|
291 |
+
# The default flag value can either be represented as a string like on the
|
292 |
+
# command line, or as a Python object. We serialize this value in the
|
293 |
+
# latter case in order to remain consistent.
|
294 |
+
if self.serializer and not isinstance(self.default, str):
|
295 |
+
if self.default is not None:
|
296 |
+
default_serialized = self.serializer.serialize(self.default)
|
297 |
+
else:
|
298 |
+
default_serialized = ''
|
299 |
+
else:
|
300 |
+
default_serialized = self.default
|
301 |
+
element.appendChild(_helpers.create_xml_dom_element(
|
302 |
+
doc, 'default', default_serialized))
|
303 |
+
value_serialized = self._serialize_value_for_xml(self.value)
|
304 |
+
element.appendChild(_helpers.create_xml_dom_element(
|
305 |
+
doc, 'current', value_serialized))
|
306 |
+
element.appendChild(_helpers.create_xml_dom_element(
|
307 |
+
doc, 'type', self.flag_type()))
|
308 |
+
# Adds extra flag features this flag may have.
|
309 |
+
for e in self._extra_xml_dom_elements(doc):
|
310 |
+
element.appendChild(e)
|
311 |
+
return element
|
312 |
+
|
313 |
+
def _serialize_value_for_xml(self, value: Optional[_T]) -> Any:
|
314 |
+
"""Returns the serialized value, for use in an XML help text."""
|
315 |
+
return value
|
316 |
+
|
317 |
+
def _extra_xml_dom_elements(
|
318 |
+
self, doc: minidom.Document
|
319 |
+
) -> List[minidom.Element]:
|
320 |
+
"""Returns extra info about this flag in XML.
|
321 |
+
|
322 |
+
"Extra" means "not already included by _create_xml_dom_element above."
|
323 |
+
|
324 |
+
Args:
|
325 |
+
doc: minidom.Document, the DOM document it should create nodes from.
|
326 |
+
|
327 |
+
Returns:
|
328 |
+
A list of minidom.Element.
|
329 |
+
"""
|
330 |
+
# Usually, the parser knows the extra details about the flag, so
|
331 |
+
# we just forward the call to it.
|
332 |
+
return self.parser._custom_xml_dom_elements(doc) # pylint: disable=protected-access
|
333 |
+
|
334 |
+
|
335 |
+
class BooleanFlag(Flag[bool]):
|
336 |
+
"""Basic boolean flag.
|
337 |
+
|
338 |
+
Boolean flags do not take any arguments, and their value is either
|
339 |
+
``True`` (1) or ``False`` (0). The false value is specified on the command
|
340 |
+
line by prepending the word ``'no'`` to either the long or the short flag
|
341 |
+
name.
|
342 |
+
|
343 |
+
For example, if a Boolean flag was created whose long name was
|
344 |
+
``'update'`` and whose short name was ``'x'``, then this flag could be
|
345 |
+
explicitly unset through either ``--noupdate`` or ``--nox``.
|
346 |
+
"""
|
347 |
+
|
348 |
+
def __init__(
|
349 |
+
self,
|
350 |
+
name: Text,
|
351 |
+
default: Union[Optional[bool], Text],
|
352 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
353 |
+
short_name: Optional[Text] = None,
|
354 |
+
**args
|
355 |
+
) -> None:
|
356 |
+
p = _argument_parser.BooleanParser()
|
357 |
+
super(BooleanFlag, self).__init__(
|
358 |
+
p, None, name, default, help, short_name, True, **args
|
359 |
+
)
|
360 |
+
|
361 |
+
|
362 |
+
class EnumFlag(Flag[Text]):
|
363 |
+
"""Basic enum flag; its value can be any string from list of enum_values."""
|
364 |
+
|
365 |
+
def __init__(
|
366 |
+
self,
|
367 |
+
name: Text,
|
368 |
+
default: Optional[Text],
|
369 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
370 |
+
enum_values: Iterable[Text],
|
371 |
+
short_name: Optional[Text] = None,
|
372 |
+
case_sensitive: bool = True,
|
373 |
+
**args
|
374 |
+
):
|
375 |
+
p = _argument_parser.EnumParser(enum_values, case_sensitive)
|
376 |
+
g = _argument_parser.ArgumentSerializer()
|
377 |
+
super(EnumFlag, self).__init__(
|
378 |
+
p, g, name, default, help, short_name, **args)
|
379 |
+
# NOTE: parser should be typed EnumParser but the constructor
|
380 |
+
# restricts the available interface to ArgumentParser[str].
|
381 |
+
self.parser = p
|
382 |
+
self.help = '<%s>: %s' % ('|'.join(p.enum_values), self.help)
|
383 |
+
|
384 |
+
def _extra_xml_dom_elements(
|
385 |
+
self, doc: minidom.Document
|
386 |
+
) -> List[minidom.Element]:
|
387 |
+
elements = []
|
388 |
+
for enum_value in self.parser.enum_values:
|
389 |
+
elements.append(_helpers.create_xml_dom_element(
|
390 |
+
doc, 'enum_value', enum_value))
|
391 |
+
return elements
|
392 |
+
|
393 |
+
|
394 |
+
class EnumClassFlag(Flag[_ET]):
|
395 |
+
"""Basic enum flag; its value is an enum class's member."""
|
396 |
+
|
397 |
+
def __init__(
|
398 |
+
self,
|
399 |
+
name: Text,
|
400 |
+
default: Union[Optional[_ET], Text],
|
401 |
+
help: Optional[Text], # pylint: disable=redefined-builtin
|
402 |
+
enum_class: Type[_ET],
|
403 |
+
short_name: Optional[Text] = None,
|
404 |
+
case_sensitive: bool = False,
|
405 |
+
**args
|
406 |
+
):
|
407 |
+
p = _argument_parser.EnumClassParser(
|
408 |
+
enum_class, case_sensitive=case_sensitive)
|
409 |
+
g = _argument_parser.EnumClassSerializer(lowercase=not case_sensitive)
|
410 |
+
super(EnumClassFlag, self).__init__(
|
411 |
+
p, g, name, default, help, short_name, **args)
|
412 |
+
# NOTE: parser should be typed EnumClassParser[_ET] but the constructor
|
413 |
+
# restricts the available interface to ArgumentParser[_ET].
|
414 |
+
self.parser = p
|
415 |
+
self.help = '<%s>: %s' % ('|'.join(p.member_names), self.help)
|
416 |
+
|
417 |
+
def _extra_xml_dom_elements(
|
418 |
+
self, doc: minidom.Document
|
419 |
+
) -> List[minidom.Element]:
|
420 |
+
elements = []
|
421 |
+
for enum_value in self.parser.enum_class.__members__.keys():
|
422 |
+
elements.append(_helpers.create_xml_dom_element(
|
423 |
+
doc, 'enum_value', enum_value))
|
424 |
+
return elements
|
425 |
+
|
426 |
+
|
427 |
+
class MultiFlag(Generic[_T], Flag[List[_T]]):
|
428 |
+
"""A flag that can appear multiple time on the command-line.
|
429 |
+
|
430 |
+
The value of such a flag is a list that contains the individual values
|
431 |
+
from all the appearances of that flag on the command-line.
|
432 |
+
|
433 |
+
See the __doc__ for Flag for most behavior of this class. Only
|
434 |
+
differences in behavior are described here:
|
435 |
+
|
436 |
+
* The default value may be either a single value or an iterable of values.
|
437 |
+
A single value is transformed into a single-item list of that value.
|
438 |
+
|
439 |
+
* The value of the flag is always a list, even if the option was
|
440 |
+
only supplied once, and even if the default value is a single
|
441 |
+
value
|
442 |
+
"""
|
443 |
+
|
444 |
+
def __init__(self, *args, **kwargs):
|
445 |
+
super(MultiFlag, self).__init__(*args, **kwargs)
|
446 |
+
self.help += ';\n repeat this option to specify a list of values'
|
447 |
+
|
448 |
+
def parse(self, arguments: Union[Text, _T, Iterable[_T]]): # pylint: disable=arguments-renamed
|
449 |
+
"""Parses one or more arguments with the installed parser.
|
450 |
+
|
451 |
+
Args:
|
452 |
+
arguments: a single argument or a list of arguments (typically a
|
453 |
+
list of default values); a single argument is converted
|
454 |
+
internally into a list containing one item.
|
455 |
+
"""
|
456 |
+
new_values = self._parse(arguments)
|
457 |
+
if self.present:
|
458 |
+
self.value.extend(new_values)
|
459 |
+
else:
|
460 |
+
self.value = new_values
|
461 |
+
self.present += len(new_values)
|
462 |
+
|
463 |
+
def _parse(self, arguments: Union[Text, Optional[Iterable[_T]]]) -> List[_T]: # pylint: disable=arguments-renamed
|
464 |
+
if (isinstance(arguments, abc.Iterable) and
|
465 |
+
not isinstance(arguments, str)):
|
466 |
+
arguments = list(arguments)
|
467 |
+
|
468 |
+
if not isinstance(arguments, list):
|
469 |
+
# Default value may be a list of values. Most other arguments
|
470 |
+
# will not be, so convert them into a single-item list to make
|
471 |
+
# processing simpler below.
|
472 |
+
arguments = [arguments]
|
473 |
+
|
474 |
+
return [super(MultiFlag, self)._parse(item) for item in arguments]
|
475 |
+
|
476 |
+
def _serialize(self, value: Optional[List[_T]]) -> Text:
|
477 |
+
"""See base class."""
|
478 |
+
if not self.serializer:
|
479 |
+
raise _exceptions.Error(
|
480 |
+
'Serializer not present for flag %s' % self.name)
|
481 |
+
if value is None:
|
482 |
+
return ''
|
483 |
+
|
484 |
+
serialized_items = [
|
485 |
+
super(MultiFlag, self)._serialize(value_item) for value_item in value
|
486 |
+
]
|
487 |
+
|
488 |
+
return '\n'.join(serialized_items)
|
489 |
+
|
490 |
+
def flag_type(self):
|
491 |
+
"""See base class."""
|
492 |
+
return 'multi ' + self.parser.flag_type()
|
493 |
+
|
494 |
+
def _extra_xml_dom_elements(
|
495 |
+
self, doc: minidom.Document
|
496 |
+
) -> List[minidom.Element]:
|
497 |
+
elements = []
|
498 |
+
if hasattr(self.parser, 'enum_values'):
|
499 |
+
for enum_value in self.parser.enum_values: # pytype: disable=attribute-error
|
500 |
+
elements.append(_helpers.create_xml_dom_element(
|
501 |
+
doc, 'enum_value', enum_value))
|
502 |
+
return elements
|
503 |
+
|
504 |
+
|
505 |
+
class MultiEnumClassFlag(MultiFlag[_ET]): # pytype: disable=not-indexable
|
506 |
+
"""A multi_enum_class flag.
|
507 |
+
|
508 |
+
See the __doc__ for MultiFlag for most behaviors of this class. In addition,
|
509 |
+
this class knows how to handle enum.Enum instances as values for this flag
|
510 |
+
type.
|
511 |
+
"""
|
512 |
+
|
513 |
+
def __init__(
|
514 |
+
self,
|
515 |
+
name: str,
|
516 |
+
default: Union[None, Iterable[_ET], _ET, Iterable[Text], Text],
|
517 |
+
help_string: str,
|
518 |
+
enum_class: Type[_ET],
|
519 |
+
case_sensitive: bool = False,
|
520 |
+
**args
|
521 |
+
):
|
522 |
+
p = _argument_parser.EnumClassParser(
|
523 |
+
enum_class, case_sensitive=case_sensitive)
|
524 |
+
g = _argument_parser.EnumClassListSerializer(
|
525 |
+
list_sep=',', lowercase=not case_sensitive)
|
526 |
+
super(MultiEnumClassFlag, self).__init__(
|
527 |
+
p, g, name, default, help_string, **args)
|
528 |
+
# NOTE: parser should be typed EnumClassParser[_ET] but the constructor
|
529 |
+
# restricts the available interface to ArgumentParser[str].
|
530 |
+
self.parser = p
|
531 |
+
# NOTE: serializer should be non-Optional but this isn't inferred.
|
532 |
+
self.serializer = g
|
533 |
+
self.help = (
|
534 |
+
'<%s>: %s;\n repeat this option to specify a list of values' %
|
535 |
+
('|'.join(p.member_names), help_string or '(no help available)'))
|
536 |
+
|
537 |
+
def _extra_xml_dom_elements(
|
538 |
+
self, doc: minidom.Document
|
539 |
+
) -> List[minidom.Element]:
|
540 |
+
elements = []
|
541 |
+
for enum_value in self.parser.enum_class.__members__.keys(): # pytype: disable=attribute-error
|
542 |
+
elements.append(_helpers.create_xml_dom_element(
|
543 |
+
doc, 'enum_value', enum_value))
|
544 |
+
return elements
|
545 |
+
|
546 |
+
def _serialize_value_for_xml(self, value):
|
547 |
+
"""See base class."""
|
548 |
+
if value is not None:
|
549 |
+
if not self.serializer:
|
550 |
+
raise _exceptions.Error(
|
551 |
+
'Serializer not present for flag %s' % self.name
|
552 |
+
)
|
553 |
+
value_serialized = self.serializer.serialize(value)
|
554 |
+
else:
|
555 |
+
value_serialized = ''
|
556 |
+
return value_serialized
|
MLPY/Lib/site-packages/absl/flags/_flagvalues.py
ADDED
@@ -0,0 +1,1480 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 itertools
|
22 |
+
import logging
|
23 |
+
import os
|
24 |
+
import sys
|
25 |
+
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Text, TextIO, Generic, TypeVar, Union, Tuple
|
26 |
+
from xml.dom import minidom
|
27 |
+
|
28 |
+
from absl.flags import _exceptions
|
29 |
+
from absl.flags import _flag
|
30 |
+
from absl.flags import _helpers
|
31 |
+
from absl.flags import _validators_classes
|
32 |
+
from absl.flags._flag import Flag
|
33 |
+
|
34 |
+
# Add flagvalues module to disclaimed module ids.
|
35 |
+
_helpers.disclaim_module_ids.add(id(sys.modules[__name__]))
|
36 |
+
|
37 |
+
_T = TypeVar('_T')
|
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[Text, Flag]:
|
150 |
+
return self.__dict__['__flags']
|
151 |
+
|
152 |
+
def flags_by_module_dict(self) -> Dict[Text, 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[Text, 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: Text, 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: Text, 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 flag_dict.get(name, None) == 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 (short_name is not None and flag_dict.get(short_name, None) == flag_obj):
|
233 |
+
return True
|
234 |
+
return False
|
235 |
+
|
236 |
+
def _cleanup_unregistered_flag_from_module_dicts(
|
237 |
+
self, flag_obj: Flag
|
238 |
+
) -> None:
|
239 |
+
"""Cleans up unregistered flags from all module -> [flags] dictionaries.
|
240 |
+
|
241 |
+
If flag_obj is registered under either its long name or short name, it
|
242 |
+
won't be removed from the dictionaries.
|
243 |
+
|
244 |
+
Args:
|
245 |
+
flag_obj: Flag, the Flag instance to clean up for.
|
246 |
+
"""
|
247 |
+
if self._flag_is_registered(flag_obj):
|
248 |
+
return
|
249 |
+
for flags_by_module_dict in (self.flags_by_module_dict(),
|
250 |
+
self.flags_by_module_id_dict(),
|
251 |
+
self.key_flags_by_module_dict()):
|
252 |
+
for flags_in_module in flags_by_module_dict.values():
|
253 |
+
# While (as opposed to if) takes care of multiple occurrences of a
|
254 |
+
# flag in the list for the same module.
|
255 |
+
while flag_obj in flags_in_module:
|
256 |
+
flags_in_module.remove(flag_obj)
|
257 |
+
|
258 |
+
def get_flags_for_module(self, module: Union[Text, Any]) -> List[Flag]:
|
259 |
+
"""Returns the list of flags defined by a module.
|
260 |
+
|
261 |
+
Args:
|
262 |
+
module: module|str, the module to get flags from.
|
263 |
+
|
264 |
+
Returns:
|
265 |
+
[Flag], a new list of Flag instances. Caller may update this list as
|
266 |
+
desired: none of those changes will affect the internals of this
|
267 |
+
FlagValue instance.
|
268 |
+
"""
|
269 |
+
if not isinstance(module, str):
|
270 |
+
module = module.__name__
|
271 |
+
if module == '__main__':
|
272 |
+
module = sys.argv[0]
|
273 |
+
|
274 |
+
return list(self.flags_by_module_dict().get(module, []))
|
275 |
+
|
276 |
+
def get_key_flags_for_module(self, module: Union[Text, Any]) -> List[Flag]:
|
277 |
+
"""Returns the list of key flags for a module.
|
278 |
+
|
279 |
+
Args:
|
280 |
+
module: module|str, the module to get key flags from.
|
281 |
+
|
282 |
+
Returns:
|
283 |
+
[Flag], a new list of Flag instances. Caller may update this list as
|
284 |
+
desired: none of those changes will affect the internals of this
|
285 |
+
FlagValue instance.
|
286 |
+
"""
|
287 |
+
if not isinstance(module, str):
|
288 |
+
module = module.__name__
|
289 |
+
if module == '__main__':
|
290 |
+
module = sys.argv[0]
|
291 |
+
|
292 |
+
# Any flag is a key flag for the module that defined it. NOTE:
|
293 |
+
# key_flags is a fresh list: we can update it without affecting the
|
294 |
+
# internals of this FlagValues object.
|
295 |
+
key_flags = self.get_flags_for_module(module)
|
296 |
+
|
297 |
+
# Take into account flags explicitly declared as key for a module.
|
298 |
+
for flag in self.key_flags_by_module_dict().get(module, []):
|
299 |
+
if flag not in key_flags:
|
300 |
+
key_flags.append(flag)
|
301 |
+
return key_flags
|
302 |
+
|
303 |
+
# TODO(yileiyang): Restrict default to Optional[Text].
|
304 |
+
def find_module_defining_flag(
|
305 |
+
self, flagname: Text, default: Optional[_T] = None
|
306 |
+
) -> Union[str, Optional[_T]]:
|
307 |
+
"""Return the name of the module defining this flag, or default.
|
308 |
+
|
309 |
+
Args:
|
310 |
+
flagname: str, name of the flag to lookup.
|
311 |
+
default: Value to return if flagname is not defined. Defaults to None.
|
312 |
+
|
313 |
+
Returns:
|
314 |
+
The name of the module which registered the flag with this name.
|
315 |
+
If no such module exists (i.e. no flag with this name exists),
|
316 |
+
we return default.
|
317 |
+
"""
|
318 |
+
registered_flag = self._flags().get(flagname)
|
319 |
+
if registered_flag is None:
|
320 |
+
return default
|
321 |
+
for module, flags in self.flags_by_module_dict().items():
|
322 |
+
for flag in flags:
|
323 |
+
# It must compare the flag with the one in _flags. This is because a
|
324 |
+
# flag might be overridden only for its long name (or short name),
|
325 |
+
# and only its short name (or long name) is considered registered.
|
326 |
+
if (flag.name == registered_flag.name and
|
327 |
+
flag.short_name == registered_flag.short_name):
|
328 |
+
return module
|
329 |
+
return default
|
330 |
+
|
331 |
+
# TODO(yileiyang): Restrict default to Optional[Text].
|
332 |
+
def find_module_id_defining_flag(
|
333 |
+
self, flagname: Text, default: Optional[_T] = None
|
334 |
+
) -> Union[int, Optional[_T]]:
|
335 |
+
"""Return the ID of the module defining this flag, or default.
|
336 |
+
|
337 |
+
Args:
|
338 |
+
flagname: str, name of the flag to lookup.
|
339 |
+
default: Value to return if flagname is not defined. Defaults to None.
|
340 |
+
|
341 |
+
Returns:
|
342 |
+
The ID of the module which registered the flag with this name.
|
343 |
+
If no such module exists (i.e. no flag with this name exists),
|
344 |
+
we return default.
|
345 |
+
"""
|
346 |
+
registered_flag = self._flags().get(flagname)
|
347 |
+
if registered_flag is None:
|
348 |
+
return default
|
349 |
+
for module_id, flags in self.flags_by_module_id_dict().items():
|
350 |
+
for flag in flags:
|
351 |
+
# It must compare the flag with the one in _flags. This is because a
|
352 |
+
# flag might be overridden only for its long name (or short name),
|
353 |
+
# and only its short name (or long name) is considered registered.
|
354 |
+
if (flag.name == registered_flag.name and
|
355 |
+
flag.short_name == registered_flag.short_name):
|
356 |
+
return module_id
|
357 |
+
return default
|
358 |
+
|
359 |
+
def _register_unknown_flag_setter(
|
360 |
+
self, setter: Callable[[str, Any], None]
|
361 |
+
) -> None:
|
362 |
+
"""Allow set default values for undefined flags.
|
363 |
+
|
364 |
+
Args:
|
365 |
+
setter: Method(name, value) to call to __setattr__ an unknown flag. Must
|
366 |
+
raise NameError or ValueError for invalid name/value.
|
367 |
+
"""
|
368 |
+
self.__dict__['__set_unknown'] = setter
|
369 |
+
|
370 |
+
def _set_unknown_flag(self, name: str, value: _T) -> _T:
|
371 |
+
"""Returns value if setting flag |name| to |value| returned True.
|
372 |
+
|
373 |
+
Args:
|
374 |
+
name: str, name of the flag to set.
|
375 |
+
value: Value to set.
|
376 |
+
|
377 |
+
Returns:
|
378 |
+
Flag value on successful call.
|
379 |
+
|
380 |
+
Raises:
|
381 |
+
UnrecognizedFlagError
|
382 |
+
IllegalFlagValueError
|
383 |
+
"""
|
384 |
+
setter = self.__dict__['__set_unknown']
|
385 |
+
if setter:
|
386 |
+
try:
|
387 |
+
setter(name, value)
|
388 |
+
return value
|
389 |
+
except (TypeError, ValueError): # Flag value is not valid.
|
390 |
+
raise _exceptions.IllegalFlagValueError(
|
391 |
+
'"{1}" is not valid for --{0}'.format(name, value))
|
392 |
+
except NameError: # Flag name is not valid.
|
393 |
+
pass
|
394 |
+
raise _exceptions.UnrecognizedFlagError(name, value)
|
395 |
+
|
396 |
+
def append_flag_values(self, flag_values: 'FlagValues') -> None:
|
397 |
+
"""Appends flags registered in another FlagValues instance.
|
398 |
+
|
399 |
+
Args:
|
400 |
+
flag_values: FlagValues, the FlagValues instance from which to copy flags.
|
401 |
+
"""
|
402 |
+
for flag_name, flag in flag_values._flags().items(): # pylint: disable=protected-access
|
403 |
+
# Each flags with short_name appears here twice (once under its
|
404 |
+
# normal name, and again with its short name). To prevent
|
405 |
+
# problems (DuplicateFlagError) with double flag registration, we
|
406 |
+
# perform a check to make sure that the entry we're looking at is
|
407 |
+
# for its normal name.
|
408 |
+
if flag_name == flag.name:
|
409 |
+
try:
|
410 |
+
self[flag_name] = flag
|
411 |
+
except _exceptions.DuplicateFlagError:
|
412 |
+
raise _exceptions.DuplicateFlagError.from_flag(
|
413 |
+
flag_name, self, other_flag_values=flag_values)
|
414 |
+
|
415 |
+
def remove_flag_values(
|
416 |
+
self, flag_values: 'Union[FlagValues, Iterable[Text]]'
|
417 |
+
) -> None:
|
418 |
+
"""Remove flags that were previously appended from another FlagValues.
|
419 |
+
|
420 |
+
Args:
|
421 |
+
flag_values: FlagValues, the FlagValues instance containing flags to
|
422 |
+
remove.
|
423 |
+
"""
|
424 |
+
for flag_name in flag_values:
|
425 |
+
self.__delattr__(flag_name)
|
426 |
+
|
427 |
+
def __setitem__(self, name: Text, flag: Flag) -> None:
|
428 |
+
"""Registers a new flag variable."""
|
429 |
+
fl = self._flags()
|
430 |
+
if not isinstance(flag, _flag.Flag):
|
431 |
+
raise _exceptions.IllegalFlagValueError(
|
432 |
+
f'Expect Flag instances, found type {type(flag)}. '
|
433 |
+
"Maybe you didn't mean to use FlagValue.__setitem__?")
|
434 |
+
if not isinstance(name, str):
|
435 |
+
raise _exceptions.Error('Flag name must be a string')
|
436 |
+
if not name:
|
437 |
+
raise _exceptions.Error('Flag name cannot be empty')
|
438 |
+
if ' ' in name:
|
439 |
+
raise _exceptions.Error('Flag name cannot contain a space')
|
440 |
+
self._check_method_name_conflicts(name, flag)
|
441 |
+
if name in fl and not flag.allow_override and not fl[name].allow_override:
|
442 |
+
module, module_name = _helpers.get_calling_module_object_and_name()
|
443 |
+
if (self.find_module_defining_flag(name) == module_name and
|
444 |
+
id(module) != self.find_module_id_defining_flag(name)):
|
445 |
+
# If the flag has already been defined by a module with the same name,
|
446 |
+
# but a different ID, we can stop here because it indicates that the
|
447 |
+
# module is simply being imported a subsequent time.
|
448 |
+
return
|
449 |
+
raise _exceptions.DuplicateFlagError.from_flag(name, self)
|
450 |
+
# If a new flag overrides an old one, we need to cleanup the old flag's
|
451 |
+
# modules if it's not registered.
|
452 |
+
flags_to_cleanup = set()
|
453 |
+
short_name: str = flag.short_name # pytype: disable=annotation-type-mismatch
|
454 |
+
if short_name is not None:
|
455 |
+
if (short_name in fl and not flag.allow_override and
|
456 |
+
not fl[short_name].allow_override):
|
457 |
+
raise _exceptions.DuplicateFlagError.from_flag(short_name, self)
|
458 |
+
if short_name in fl and fl[short_name] != flag:
|
459 |
+
flags_to_cleanup.add(fl[short_name])
|
460 |
+
fl[short_name] = flag
|
461 |
+
if (name not in fl # new flag
|
462 |
+
or fl[name].using_default_value or not flag.using_default_value):
|
463 |
+
if name in fl and fl[name] != flag:
|
464 |
+
flags_to_cleanup.add(fl[name])
|
465 |
+
fl[name] = flag
|
466 |
+
for f in flags_to_cleanup:
|
467 |
+
self._cleanup_unregistered_flag_from_module_dicts(f)
|
468 |
+
|
469 |
+
def __dir__(self) -> List[Text]:
|
470 |
+
"""Returns list of names of all defined flags.
|
471 |
+
|
472 |
+
Useful for TAB-completion in ipython.
|
473 |
+
|
474 |
+
Returns:
|
475 |
+
[str], a list of names of all defined flags.
|
476 |
+
"""
|
477 |
+
return sorted(self.__dict__['__flags'])
|
478 |
+
|
479 |
+
def __getitem__(self, name: Text) -> Flag:
|
480 |
+
"""Returns the Flag object for the flag --name."""
|
481 |
+
return self._flags()[name]
|
482 |
+
|
483 |
+
def _hide_flag(self, name):
|
484 |
+
"""Marks the flag --name as hidden."""
|
485 |
+
self.__dict__['__hiddenflags'].add(name)
|
486 |
+
|
487 |
+
def __getattr__(self, name: Text) -> Any:
|
488 |
+
"""Retrieves the 'value' attribute of the flag --name."""
|
489 |
+
fl = self._flags()
|
490 |
+
if name not in fl:
|
491 |
+
raise AttributeError(name)
|
492 |
+
if name in self.__dict__['__hiddenflags']:
|
493 |
+
raise AttributeError(name)
|
494 |
+
|
495 |
+
if self.__dict__['__flags_parsed'] or fl[name].present:
|
496 |
+
return fl[name].value
|
497 |
+
else:
|
498 |
+
raise _exceptions.UnparsedFlagAccessError(
|
499 |
+
'Trying to access flag --%s before flags were parsed.' % name)
|
500 |
+
|
501 |
+
def __setattr__(self, name: Text, value: _T) -> _T:
|
502 |
+
"""Sets the 'value' attribute of the flag --name."""
|
503 |
+
self._set_attributes(**{name: value})
|
504 |
+
return value
|
505 |
+
|
506 |
+
def _set_attributes(self, **attributes: Any) -> None:
|
507 |
+
"""Sets multiple flag values together, triggers validators afterwards."""
|
508 |
+
fl = self._flags()
|
509 |
+
known_flag_vals = {}
|
510 |
+
known_flag_used_defaults = {}
|
511 |
+
try:
|
512 |
+
for name, value in attributes.items():
|
513 |
+
if name in self.__dict__['__hiddenflags']:
|
514 |
+
raise AttributeError(name)
|
515 |
+
if name in fl:
|
516 |
+
orig = fl[name].value
|
517 |
+
fl[name].value = value
|
518 |
+
known_flag_vals[name] = orig
|
519 |
+
else:
|
520 |
+
self._set_unknown_flag(name, value)
|
521 |
+
for name in known_flag_vals:
|
522 |
+
self._assert_validators(fl[name].validators)
|
523 |
+
known_flag_used_defaults[name] = fl[name].using_default_value
|
524 |
+
fl[name].using_default_value = False
|
525 |
+
except:
|
526 |
+
for name, orig in known_flag_vals.items():
|
527 |
+
fl[name].value = orig
|
528 |
+
for name, orig in known_flag_used_defaults.items():
|
529 |
+
fl[name].using_default_value = orig
|
530 |
+
# NOTE: We do not attempt to undo unknown flag side effects because we
|
531 |
+
# cannot reliably undo the user-configured behavior.
|
532 |
+
raise
|
533 |
+
|
534 |
+
def validate_all_flags(self) -> None:
|
535 |
+
"""Verifies whether all flags pass validation.
|
536 |
+
|
537 |
+
Raises:
|
538 |
+
AttributeError: Raised if validators work with a non-existing flag.
|
539 |
+
IllegalFlagValueError: Raised if validation fails for at least one
|
540 |
+
validator.
|
541 |
+
"""
|
542 |
+
all_validators = set()
|
543 |
+
for flag in self._flags().values():
|
544 |
+
all_validators.update(flag.validators)
|
545 |
+
self._assert_validators(all_validators)
|
546 |
+
|
547 |
+
def _assert_validators(
|
548 |
+
self, validators: Iterable[_validators_classes.Validator]
|
549 |
+
) -> None:
|
550 |
+
"""Asserts if all validators in the list are satisfied.
|
551 |
+
|
552 |
+
It asserts validators in the order they were created.
|
553 |
+
|
554 |
+
Args:
|
555 |
+
validators: Iterable(validators.Validator), validators to be verified.
|
556 |
+
|
557 |
+
Raises:
|
558 |
+
AttributeError: Raised if validators work with a non-existing flag.
|
559 |
+
IllegalFlagValueError: Raised if validation fails for at least one
|
560 |
+
validator.
|
561 |
+
"""
|
562 |
+
messages = []
|
563 |
+
bad_flags = set()
|
564 |
+
for validator in sorted(
|
565 |
+
validators, key=lambda validator: validator.insertion_index):
|
566 |
+
try:
|
567 |
+
if isinstance(validator, _validators_classes.SingleFlagValidator):
|
568 |
+
if validator.flag_name in bad_flags:
|
569 |
+
continue
|
570 |
+
elif isinstance(validator, _validators_classes.MultiFlagsValidator):
|
571 |
+
if bad_flags & set(validator.flag_names):
|
572 |
+
continue
|
573 |
+
validator.verify(self)
|
574 |
+
except _exceptions.ValidationError as e:
|
575 |
+
if isinstance(validator, _validators_classes.SingleFlagValidator):
|
576 |
+
bad_flags.add(validator.flag_name)
|
577 |
+
elif isinstance(validator, _validators_classes.MultiFlagsValidator):
|
578 |
+
bad_flags.update(set(validator.flag_names))
|
579 |
+
message = validator.print_flags_with_values(self)
|
580 |
+
messages.append('%s: %s' % (message, str(e)))
|
581 |
+
if messages:
|
582 |
+
raise _exceptions.IllegalFlagValueError('\n'.join(messages))
|
583 |
+
|
584 |
+
def __delattr__(self, flag_name: Text) -> None:
|
585 |
+
"""Deletes a previously-defined flag from a flag object.
|
586 |
+
|
587 |
+
This method makes sure we can delete a flag by using
|
588 |
+
|
589 |
+
del FLAGS.<flag_name>
|
590 |
+
|
591 |
+
E.g.,
|
592 |
+
|
593 |
+
flags.DEFINE_integer('foo', 1, 'Integer flag.')
|
594 |
+
del flags.FLAGS.foo
|
595 |
+
|
596 |
+
If a flag is also registered by its the other name (long name or short
|
597 |
+
name), the other name won't be deleted.
|
598 |
+
|
599 |
+
Args:
|
600 |
+
flag_name: str, the name of the flag to be deleted.
|
601 |
+
|
602 |
+
Raises:
|
603 |
+
AttributeError: Raised when there is no registered flag named flag_name.
|
604 |
+
"""
|
605 |
+
fl = self._flags()
|
606 |
+
if flag_name not in fl:
|
607 |
+
raise AttributeError(flag_name)
|
608 |
+
|
609 |
+
flag_obj = fl[flag_name]
|
610 |
+
del fl[flag_name]
|
611 |
+
|
612 |
+
self._cleanup_unregistered_flag_from_module_dicts(flag_obj)
|
613 |
+
|
614 |
+
def set_default(self, name: Text, value: Any) -> None:
|
615 |
+
"""Changes the default value of the named flag object.
|
616 |
+
|
617 |
+
The flag's current value is also updated if the flag is currently using
|
618 |
+
the default value, i.e. not specified in the command line, and not set
|
619 |
+
by FLAGS.name = value.
|
620 |
+
|
621 |
+
Args:
|
622 |
+
name: str, the name of the flag to modify.
|
623 |
+
value: The new default value.
|
624 |
+
|
625 |
+
Raises:
|
626 |
+
UnrecognizedFlagError: Raised when there is no registered flag named name.
|
627 |
+
IllegalFlagValueError: Raised when value is not valid.
|
628 |
+
"""
|
629 |
+
fl = self._flags()
|
630 |
+
if name not in fl:
|
631 |
+
self._set_unknown_flag(name, value)
|
632 |
+
return
|
633 |
+
fl[name]._set_default(value) # pylint: disable=protected-access
|
634 |
+
self._assert_validators(fl[name].validators)
|
635 |
+
|
636 |
+
def __contains__(self, name: Text) -> bool:
|
637 |
+
"""Returns True if name is a value (flag) in the dict."""
|
638 |
+
return name in self._flags()
|
639 |
+
|
640 |
+
def __len__(self) -> int:
|
641 |
+
return len(self.__dict__['__flags'])
|
642 |
+
|
643 |
+
def __iter__(self) -> Iterator[Text]:
|
644 |
+
return iter(self._flags())
|
645 |
+
|
646 |
+
def __call__(
|
647 |
+
self, argv: Sequence[Text], known_only: bool = False
|
648 |
+
) -> List[Text]:
|
649 |
+
"""Parses flags from argv; stores parsed flags into this FlagValues object.
|
650 |
+
|
651 |
+
All unparsed arguments are returned.
|
652 |
+
|
653 |
+
Args:
|
654 |
+
argv: a tuple/list of strings.
|
655 |
+
known_only: bool, if True, parse and remove known flags; return the rest
|
656 |
+
untouched. Unknown flags specified by --undefok are not returned.
|
657 |
+
|
658 |
+
Returns:
|
659 |
+
The list of arguments not parsed as options, including argv[0].
|
660 |
+
|
661 |
+
Raises:
|
662 |
+
Error: Raised on any parsing error.
|
663 |
+
TypeError: Raised on passing wrong type of arguments.
|
664 |
+
ValueError: Raised on flag value parsing error.
|
665 |
+
"""
|
666 |
+
if isinstance(argv, (str, bytes)):
|
667 |
+
raise TypeError(
|
668 |
+
'argv should be a tuple/list of strings, not bytes or string.')
|
669 |
+
if not argv:
|
670 |
+
raise ValueError(
|
671 |
+
'argv cannot be an empty list, and must contain the program name as '
|
672 |
+
'the first element.')
|
673 |
+
|
674 |
+
# This pre parses the argv list for --flagfile=<> options.
|
675 |
+
program_name = argv[0]
|
676 |
+
args = self.read_flags_from_files(argv[1:], force_gnu=False)
|
677 |
+
|
678 |
+
# Parse the arguments.
|
679 |
+
unknown_flags, unparsed_args = self._parse_args(args, known_only)
|
680 |
+
|
681 |
+
# Handle unknown flags by raising UnrecognizedFlagError.
|
682 |
+
# Note some users depend on us raising this particular error.
|
683 |
+
for name, value in unknown_flags:
|
684 |
+
suggestions = _helpers.get_flag_suggestions(name, list(self))
|
685 |
+
raise _exceptions.UnrecognizedFlagError(
|
686 |
+
name, value, suggestions=suggestions)
|
687 |
+
|
688 |
+
self.mark_as_parsed()
|
689 |
+
self.validate_all_flags()
|
690 |
+
return [program_name] + unparsed_args
|
691 |
+
|
692 |
+
def __getstate__(self) -> Any:
|
693 |
+
raise TypeError("can't pickle FlagValues")
|
694 |
+
|
695 |
+
def __copy__(self) -> Any:
|
696 |
+
raise TypeError('FlagValues does not support shallow copies. '
|
697 |
+
'Use absl.testing.flagsaver or copy.deepcopy instead.')
|
698 |
+
|
699 |
+
def __deepcopy__(self, memo) -> Any:
|
700 |
+
result = object.__new__(type(self))
|
701 |
+
result.__dict__.update(copy.deepcopy(self.__dict__, memo))
|
702 |
+
return result
|
703 |
+
|
704 |
+
def _set_is_retired_flag_func(self, is_retired_flag_func):
|
705 |
+
"""Sets a function for checking retired flags.
|
706 |
+
|
707 |
+
Do not use it. This is a private absl API used to check retired flags
|
708 |
+
registered by the absl C++ flags library.
|
709 |
+
|
710 |
+
Args:
|
711 |
+
is_retired_flag_func: Callable(str) -> (bool, bool), a function takes flag
|
712 |
+
name as parameter, returns a tuple (is_retired, type_is_bool).
|
713 |
+
"""
|
714 |
+
self.__dict__['__is_retired_flag_func'] = is_retired_flag_func
|
715 |
+
|
716 |
+
def _parse_args(
|
717 |
+
self, args: List[str], known_only: bool
|
718 |
+
) -> Tuple[List[Tuple[Optional[str], Any]], List[str]]:
|
719 |
+
"""Helper function to do the main argument parsing.
|
720 |
+
|
721 |
+
This function goes through args and does the bulk of the flag parsing.
|
722 |
+
It will find the corresponding flag in our flag dictionary, and call its
|
723 |
+
.parse() method on the flag value.
|
724 |
+
|
725 |
+
Args:
|
726 |
+
args: [str], a list of strings with the arguments to parse.
|
727 |
+
known_only: bool, if True, parse and remove known flags; return the rest
|
728 |
+
untouched. Unknown flags specified by --undefok are not returned.
|
729 |
+
|
730 |
+
Returns:
|
731 |
+
A tuple with the following:
|
732 |
+
unknown_flags: List of (flag name, arg) for flags we don't know about.
|
733 |
+
unparsed_args: List of arguments we did not parse.
|
734 |
+
|
735 |
+
Raises:
|
736 |
+
Error: Raised on any parsing error.
|
737 |
+
ValueError: Raised on flag value parsing error.
|
738 |
+
"""
|
739 |
+
unparsed_names_and_args = [] # A list of (flag name or None, arg).
|
740 |
+
undefok = set()
|
741 |
+
retired_flag_func = self.__dict__['__is_retired_flag_func']
|
742 |
+
|
743 |
+
flag_dict = self._flags()
|
744 |
+
args = iter(args)
|
745 |
+
for arg in args:
|
746 |
+
value = None
|
747 |
+
|
748 |
+
def get_value():
|
749 |
+
# pylint: disable=cell-var-from-loop
|
750 |
+
try:
|
751 |
+
return next(args) if value is None else value
|
752 |
+
except StopIteration:
|
753 |
+
raise _exceptions.Error('Missing value for flag ' + arg) # pylint: disable=undefined-loop-variable
|
754 |
+
|
755 |
+
if not arg.startswith('-'):
|
756 |
+
# A non-argument: default is break, GNU is skip.
|
757 |
+
unparsed_names_and_args.append((None, arg))
|
758 |
+
if self.is_gnu_getopt():
|
759 |
+
continue
|
760 |
+
else:
|
761 |
+
break
|
762 |
+
|
763 |
+
if arg == '--':
|
764 |
+
if known_only:
|
765 |
+
unparsed_names_and_args.append((None, arg))
|
766 |
+
break
|
767 |
+
|
768 |
+
# At this point, arg must start with '-'.
|
769 |
+
if arg.startswith('--'):
|
770 |
+
arg_without_dashes = arg[2:]
|
771 |
+
else:
|
772 |
+
arg_without_dashes = arg[1:]
|
773 |
+
|
774 |
+
if '=' in arg_without_dashes:
|
775 |
+
name, value = arg_without_dashes.split('=', 1)
|
776 |
+
else:
|
777 |
+
name, value = arg_without_dashes, None
|
778 |
+
|
779 |
+
if not name:
|
780 |
+
# The argument is all dashes (including one dash).
|
781 |
+
unparsed_names_and_args.append((None, arg))
|
782 |
+
if self.is_gnu_getopt():
|
783 |
+
continue
|
784 |
+
else:
|
785 |
+
break
|
786 |
+
|
787 |
+
# --undefok is a special case.
|
788 |
+
if name == 'undefok':
|
789 |
+
value = get_value()
|
790 |
+
undefok.update(v.strip() for v in value.split(','))
|
791 |
+
undefok.update('no' + v.strip() for v in value.split(','))
|
792 |
+
continue
|
793 |
+
|
794 |
+
flag = flag_dict.get(name)
|
795 |
+
if flag is not None:
|
796 |
+
if flag.boolean and value is None:
|
797 |
+
value = 'true'
|
798 |
+
else:
|
799 |
+
value = get_value()
|
800 |
+
elif name.startswith('no') and len(name) > 2:
|
801 |
+
# Boolean flags can take the form of --noflag, with no value.
|
802 |
+
noflag = flag_dict.get(name[2:])
|
803 |
+
if noflag is not None and noflag.boolean:
|
804 |
+
if value is not None:
|
805 |
+
raise ValueError(arg + ' does not take an argument')
|
806 |
+
flag = noflag
|
807 |
+
value = 'false'
|
808 |
+
|
809 |
+
if retired_flag_func and flag is None:
|
810 |
+
is_retired, is_bool = retired_flag_func(name)
|
811 |
+
|
812 |
+
# If we didn't recognize that flag, but it starts with
|
813 |
+
# "no" then maybe it was a boolean flag specified in the
|
814 |
+
# --nofoo form.
|
815 |
+
if not is_retired and name.startswith('no'):
|
816 |
+
is_retired, is_bool = retired_flag_func(name[2:])
|
817 |
+
is_retired = is_retired and is_bool
|
818 |
+
|
819 |
+
if is_retired:
|
820 |
+
if not is_bool and value is None:
|
821 |
+
# This happens when a non-bool retired flag is specified
|
822 |
+
# in format of "--flag value".
|
823 |
+
get_value()
|
824 |
+
logging.error(
|
825 |
+
'Flag "%s" is retired and should no longer be specified. See '
|
826 |
+
'https://abseil.io/tips/90.',
|
827 |
+
name,
|
828 |
+
)
|
829 |
+
continue
|
830 |
+
|
831 |
+
if flag is not None:
|
832 |
+
# LINT.IfChange
|
833 |
+
flag.parse(value)
|
834 |
+
flag.using_default_value = False
|
835 |
+
# LINT.ThenChange(../testing/flagsaver.py:flag_override_parsing)
|
836 |
+
else:
|
837 |
+
unparsed_names_and_args.append((name, arg))
|
838 |
+
|
839 |
+
unknown_flags = []
|
840 |
+
unparsed_args = []
|
841 |
+
for name, arg in unparsed_names_and_args:
|
842 |
+
if name is None:
|
843 |
+
# Positional arguments.
|
844 |
+
unparsed_args.append(arg)
|
845 |
+
elif name in undefok:
|
846 |
+
# Remove undefok flags.
|
847 |
+
continue
|
848 |
+
else:
|
849 |
+
# This is an unknown flag.
|
850 |
+
if known_only:
|
851 |
+
unparsed_args.append(arg)
|
852 |
+
else:
|
853 |
+
unknown_flags.append((name, arg))
|
854 |
+
|
855 |
+
unparsed_args.extend(list(args))
|
856 |
+
return unknown_flags, unparsed_args
|
857 |
+
|
858 |
+
def is_parsed(self) -> bool:
|
859 |
+
"""Returns whether flags were parsed."""
|
860 |
+
return self.__dict__['__flags_parsed']
|
861 |
+
|
862 |
+
def mark_as_parsed(self) -> None:
|
863 |
+
"""Explicitly marks flags as parsed.
|
864 |
+
|
865 |
+
Use this when the caller knows that this FlagValues has been parsed as if
|
866 |
+
a ``__call__()`` invocation has happened. This is only a public method for
|
867 |
+
use by things like appcommands which do additional command like parsing.
|
868 |
+
"""
|
869 |
+
self.__dict__['__flags_parsed'] = True
|
870 |
+
|
871 |
+
def unparse_flags(self) -> None:
|
872 |
+
"""Unparses all flags to the point before any FLAGS(argv) was called."""
|
873 |
+
for f in self._flags().values():
|
874 |
+
f.unparse()
|
875 |
+
# We log this message before marking flags as unparsed to avoid a
|
876 |
+
# problem when the logging library causes flags access.
|
877 |
+
logging.info('unparse_flags() called; flags access will now raise errors.')
|
878 |
+
self.__dict__['__flags_parsed'] = False
|
879 |
+
self.__dict__['__unparse_flags_called'] = True
|
880 |
+
|
881 |
+
def flag_values_dict(self) -> Dict[Text, Any]:
|
882 |
+
"""Returns a dictionary that maps flag names to flag values."""
|
883 |
+
return {name: flag.value for name, flag in self._flags().items()}
|
884 |
+
|
885 |
+
def __str__(self):
|
886 |
+
"""Returns a help string for all known flags."""
|
887 |
+
return self.get_help()
|
888 |
+
|
889 |
+
def get_help(
|
890 |
+
self, prefix: Text = '', include_special_flags: bool = True
|
891 |
+
) -> Text:
|
892 |
+
"""Returns a help string for all known flags.
|
893 |
+
|
894 |
+
Args:
|
895 |
+
prefix: str, per-line output prefix.
|
896 |
+
include_special_flags: bool, whether to include description of
|
897 |
+
SPECIAL_FLAGS, i.e. --flagfile and --undefok.
|
898 |
+
|
899 |
+
Returns:
|
900 |
+
str, formatted help message.
|
901 |
+
"""
|
902 |
+
flags_by_module = self.flags_by_module_dict()
|
903 |
+
if flags_by_module:
|
904 |
+
modules = sorted(flags_by_module)
|
905 |
+
# Print the help for the main module first, if possible.
|
906 |
+
main_module = sys.argv[0]
|
907 |
+
if main_module in modules:
|
908 |
+
modules.remove(main_module)
|
909 |
+
modules = [main_module] + modules
|
910 |
+
return self._get_help_for_modules(modules, prefix, include_special_flags)
|
911 |
+
else:
|
912 |
+
output_lines = []
|
913 |
+
# Just print one long list of flags.
|
914 |
+
values = self._flags().values()
|
915 |
+
if include_special_flags:
|
916 |
+
values = itertools.chain(
|
917 |
+
values, _helpers.SPECIAL_FLAGS._flags().values() # pylint: disable=protected-access # pytype: disable=attribute-error
|
918 |
+
)
|
919 |
+
self._render_flag_list(values, output_lines, prefix)
|
920 |
+
return '\n'.join(output_lines)
|
921 |
+
|
922 |
+
def _get_help_for_modules(self, modules, prefix, include_special_flags):
|
923 |
+
"""Returns the help string for a list of modules.
|
924 |
+
|
925 |
+
Private to absl.flags package.
|
926 |
+
|
927 |
+
Args:
|
928 |
+
modules: List[str], a list of modules to get the help string for.
|
929 |
+
prefix: str, a string that is prepended to each generated help line.
|
930 |
+
include_special_flags: bool, whether to include description of
|
931 |
+
SPECIAL_FLAGS, i.e. --flagfile and --undefok.
|
932 |
+
"""
|
933 |
+
output_lines = []
|
934 |
+
for module in modules:
|
935 |
+
self._render_our_module_flags(module, output_lines, prefix)
|
936 |
+
if include_special_flags:
|
937 |
+
self._render_module_flags(
|
938 |
+
'absl.flags',
|
939 |
+
_helpers.SPECIAL_FLAGS._flags().values(), # pylint: disable=protected-access # pytype: disable=attribute-error
|
940 |
+
output_lines,
|
941 |
+
prefix,
|
942 |
+
)
|
943 |
+
return '\n'.join(output_lines)
|
944 |
+
|
945 |
+
def _render_module_flags(self, module, flags, output_lines, prefix=''):
|
946 |
+
"""Returns a help string for a given module."""
|
947 |
+
if not isinstance(module, str):
|
948 |
+
module = module.__name__
|
949 |
+
output_lines.append('\n%s%s:' % (prefix, module))
|
950 |
+
self._render_flag_list(flags, output_lines, prefix + ' ')
|
951 |
+
|
952 |
+
def _render_our_module_flags(self, module, output_lines, prefix=''):
|
953 |
+
"""Returns a help string for a given module."""
|
954 |
+
flags = self.get_flags_for_module(module)
|
955 |
+
if flags:
|
956 |
+
self._render_module_flags(module, flags, output_lines, prefix)
|
957 |
+
|
958 |
+
def _render_our_module_key_flags(self, module, output_lines, prefix=''):
|
959 |
+
"""Returns a help string for the key flags of a given module.
|
960 |
+
|
961 |
+
Args:
|
962 |
+
module: module|str, the module to render key flags for.
|
963 |
+
output_lines: [str], a list of strings. The generated help message lines
|
964 |
+
will be appended to this list.
|
965 |
+
prefix: str, a string that is prepended to each generated help line.
|
966 |
+
"""
|
967 |
+
key_flags = self.get_key_flags_for_module(module)
|
968 |
+
if key_flags:
|
969 |
+
self._render_module_flags(module, key_flags, output_lines, prefix)
|
970 |
+
|
971 |
+
def module_help(self, module: Any) -> Text:
|
972 |
+
"""Describes the key flags of a module.
|
973 |
+
|
974 |
+
Args:
|
975 |
+
module: module|str, the module to describe the key flags for.
|
976 |
+
|
977 |
+
Returns:
|
978 |
+
str, describing the key flags of a module.
|
979 |
+
"""
|
980 |
+
helplist = []
|
981 |
+
self._render_our_module_key_flags(module, helplist)
|
982 |
+
return '\n'.join(helplist)
|
983 |
+
|
984 |
+
def main_module_help(self) -> Text:
|
985 |
+
"""Describes the key flags of the main module.
|
986 |
+
|
987 |
+
Returns:
|
988 |
+
str, describing the key flags of the main module.
|
989 |
+
"""
|
990 |
+
return self.module_help(sys.argv[0])
|
991 |
+
|
992 |
+
def _render_flag_list(self, flaglist, output_lines, prefix=' '):
|
993 |
+
fl = self._flags()
|
994 |
+
special_fl = _helpers.SPECIAL_FLAGS._flags() # pylint: disable=protected-access # pytype: disable=attribute-error
|
995 |
+
flaglist = [(flag.name, flag) for flag in flaglist]
|
996 |
+
flaglist.sort()
|
997 |
+
flagset = {}
|
998 |
+
for (name, flag) in flaglist:
|
999 |
+
# It's possible this flag got deleted or overridden since being
|
1000 |
+
# registered in the per-module flaglist. Check now against the
|
1001 |
+
# canonical source of current flag information, the _flags.
|
1002 |
+
if fl.get(name, None) != flag and special_fl.get(name, None) != flag:
|
1003 |
+
# a different flag is using this name now
|
1004 |
+
continue
|
1005 |
+
# only print help once
|
1006 |
+
if flag in flagset:
|
1007 |
+
continue
|
1008 |
+
flagset[flag] = 1
|
1009 |
+
flaghelp = ''
|
1010 |
+
if flag.short_name:
|
1011 |
+
flaghelp += '-%s,' % flag.short_name
|
1012 |
+
if flag.boolean:
|
1013 |
+
flaghelp += '--[no]%s:' % flag.name
|
1014 |
+
else:
|
1015 |
+
flaghelp += '--%s:' % flag.name
|
1016 |
+
flaghelp += ' '
|
1017 |
+
if flag.help:
|
1018 |
+
flaghelp += flag.help
|
1019 |
+
flaghelp = _helpers.text_wrap(
|
1020 |
+
flaghelp, indent=prefix + ' ', firstline_indent=prefix)
|
1021 |
+
if flag.default_as_str:
|
1022 |
+
flaghelp += '\n'
|
1023 |
+
flaghelp += _helpers.text_wrap(
|
1024 |
+
'(default: %s)' % flag.default_as_str, indent=prefix + ' ')
|
1025 |
+
if flag.parser.syntactic_help:
|
1026 |
+
flaghelp += '\n'
|
1027 |
+
flaghelp += _helpers.text_wrap(
|
1028 |
+
'(%s)' % flag.parser.syntactic_help, indent=prefix + ' ')
|
1029 |
+
output_lines.append(flaghelp)
|
1030 |
+
|
1031 |
+
def get_flag_value(self, name: Text, default: Any) -> Any: # pylint: disable=invalid-name
|
1032 |
+
"""Returns the value of a flag (if not None) or a default value.
|
1033 |
+
|
1034 |
+
Args:
|
1035 |
+
name: str, the name of a flag.
|
1036 |
+
default: Default value to use if the flag value is None.
|
1037 |
+
|
1038 |
+
Returns:
|
1039 |
+
Requested flag value or default.
|
1040 |
+
"""
|
1041 |
+
|
1042 |
+
value = self.__getattr__(name)
|
1043 |
+
if value is not None: # Can't do if not value, b/c value might be '0' or ""
|
1044 |
+
return value
|
1045 |
+
else:
|
1046 |
+
return default
|
1047 |
+
|
1048 |
+
def _is_flag_file_directive(self, flag_string):
|
1049 |
+
"""Checks whether flag_string contain a --flagfile=<foo> directive."""
|
1050 |
+
if isinstance(flag_string, str):
|
1051 |
+
if flag_string.startswith('--flagfile='):
|
1052 |
+
return 1
|
1053 |
+
elif flag_string == '--flagfile':
|
1054 |
+
return 1
|
1055 |
+
elif flag_string.startswith('-flagfile='):
|
1056 |
+
return 1
|
1057 |
+
elif flag_string == '-flagfile':
|
1058 |
+
return 1
|
1059 |
+
else:
|
1060 |
+
return 0
|
1061 |
+
return 0
|
1062 |
+
|
1063 |
+
def _extract_filename(self, flagfile_str):
|
1064 |
+
"""Returns filename from a flagfile_str of form -[-]flagfile=filename.
|
1065 |
+
|
1066 |
+
The cases of --flagfile foo and -flagfile foo shouldn't be hitting
|
1067 |
+
this function, as they are dealt with in the level above this
|
1068 |
+
function.
|
1069 |
+
|
1070 |
+
Args:
|
1071 |
+
flagfile_str: str, the flagfile string.
|
1072 |
+
|
1073 |
+
Returns:
|
1074 |
+
str, the filename from a flagfile_str of form -[-]flagfile=filename.
|
1075 |
+
|
1076 |
+
Raises:
|
1077 |
+
Error: Raised when illegal --flagfile is provided.
|
1078 |
+
"""
|
1079 |
+
if flagfile_str.startswith('--flagfile='):
|
1080 |
+
return os.path.expanduser((flagfile_str[(len('--flagfile=')):]).strip())
|
1081 |
+
elif flagfile_str.startswith('-flagfile='):
|
1082 |
+
return os.path.expanduser((flagfile_str[(len('-flagfile=')):]).strip())
|
1083 |
+
else:
|
1084 |
+
raise _exceptions.Error('Hit illegal --flagfile type: %s' % flagfile_str)
|
1085 |
+
|
1086 |
+
def _get_flag_file_lines(self, filename, parsed_file_stack=None):
|
1087 |
+
"""Returns the useful (!=comments, etc) lines from a file with flags.
|
1088 |
+
|
1089 |
+
Args:
|
1090 |
+
filename: str, the name of the flag file.
|
1091 |
+
parsed_file_stack: [str], a list of the names of the files that we have
|
1092 |
+
recursively encountered at the current depth. MUTATED BY THIS FUNCTION
|
1093 |
+
(but the original value is preserved upon successfully returning from
|
1094 |
+
function call).
|
1095 |
+
|
1096 |
+
Returns:
|
1097 |
+
List of strings. See the note below.
|
1098 |
+
|
1099 |
+
NOTE(springer): This function checks for a nested --flagfile=<foo>
|
1100 |
+
tag and handles the lower file recursively. It returns a list of
|
1101 |
+
all the lines that _could_ contain command flags. This is
|
1102 |
+
EVERYTHING except whitespace lines and comments (lines starting
|
1103 |
+
with '#' or '//').
|
1104 |
+
"""
|
1105 |
+
# For consistency with the cpp version, ignore empty values.
|
1106 |
+
if not filename:
|
1107 |
+
return []
|
1108 |
+
if parsed_file_stack is None:
|
1109 |
+
parsed_file_stack = []
|
1110 |
+
# We do a little safety check for reparsing a file we've already encountered
|
1111 |
+
# at a previous depth.
|
1112 |
+
if filename in parsed_file_stack:
|
1113 |
+
sys.stderr.write('Warning: Hit circular flagfile dependency. Ignoring'
|
1114 |
+
' flagfile: %s\n' % (filename,))
|
1115 |
+
return []
|
1116 |
+
else:
|
1117 |
+
parsed_file_stack.append(filename)
|
1118 |
+
|
1119 |
+
line_list = [] # All line from flagfile.
|
1120 |
+
flag_line_list = [] # Subset of lines w/o comments, blanks, flagfile= tags.
|
1121 |
+
try:
|
1122 |
+
file_obj = open(filename, 'r')
|
1123 |
+
except IOError as e_msg:
|
1124 |
+
raise _exceptions.CantOpenFlagFileError(
|
1125 |
+
'ERROR:: Unable to open flagfile: %s' % e_msg)
|
1126 |
+
|
1127 |
+
with file_obj:
|
1128 |
+
line_list = file_obj.readlines()
|
1129 |
+
|
1130 |
+
# This is where we check each line in the file we just read.
|
1131 |
+
for line in line_list:
|
1132 |
+
if line.isspace():
|
1133 |
+
pass
|
1134 |
+
# Checks for comment (a line that starts with '#').
|
1135 |
+
elif line.startswith('#') or line.startswith('//'):
|
1136 |
+
pass
|
1137 |
+
# Checks for a nested "--flagfile=<bar>" flag in the current file.
|
1138 |
+
# If we find one, recursively parse down into that file.
|
1139 |
+
elif self._is_flag_file_directive(line):
|
1140 |
+
sub_filename = self._extract_filename(line)
|
1141 |
+
included_flags = self._get_flag_file_lines(
|
1142 |
+
sub_filename, parsed_file_stack=parsed_file_stack)
|
1143 |
+
flag_line_list.extend(included_flags)
|
1144 |
+
else:
|
1145 |
+
# Any line that's not a comment or a nested flagfile should get
|
1146 |
+
# copied into 2nd position. This leaves earlier arguments
|
1147 |
+
# further back in the list, thus giving them higher priority.
|
1148 |
+
flag_line_list.append(line.strip())
|
1149 |
+
|
1150 |
+
parsed_file_stack.pop()
|
1151 |
+
return flag_line_list
|
1152 |
+
|
1153 |
+
def read_flags_from_files(
|
1154 |
+
self, argv: Sequence[Text], force_gnu: bool = True
|
1155 |
+
) -> List[Text]:
|
1156 |
+
"""Processes command line args, but also allow args to be read from file.
|
1157 |
+
|
1158 |
+
Args:
|
1159 |
+
argv: [str], a list of strings, usually sys.argv[1:], which may contain
|
1160 |
+
one or more flagfile directives of the form --flagfile="./filename".
|
1161 |
+
Note that the name of the program (sys.argv[0]) should be omitted.
|
1162 |
+
force_gnu: bool, if False, --flagfile parsing obeys the
|
1163 |
+
FLAGS.is_gnu_getopt() value. If True, ignore the value and always follow
|
1164 |
+
gnu_getopt semantics.
|
1165 |
+
|
1166 |
+
Returns:
|
1167 |
+
A new list which has the original list combined with what we read
|
1168 |
+
from any flagfile(s).
|
1169 |
+
|
1170 |
+
Raises:
|
1171 |
+
IllegalFlagValueError: Raised when --flagfile is provided with no
|
1172 |
+
argument.
|
1173 |
+
|
1174 |
+
This function is called by FLAGS(argv).
|
1175 |
+
It scans the input list for a flag that looks like:
|
1176 |
+
--flagfile=<somefile>. Then it opens <somefile>, reads all valid key
|
1177 |
+
and value pairs and inserts them into the input list in exactly the
|
1178 |
+
place where the --flagfile arg is found.
|
1179 |
+
|
1180 |
+
Note that your application's flags are still defined the usual way
|
1181 |
+
using absl.flags DEFINE_flag() type functions.
|
1182 |
+
|
1183 |
+
Notes (assuming we're getting a commandline of some sort as our input):
|
1184 |
+
|
1185 |
+
* For duplicate flags, the last one we hit should "win".
|
1186 |
+
* Since flags that appear later win, a flagfile's settings can be "weak"
|
1187 |
+
if the --flagfile comes at the beginning of the argument sequence,
|
1188 |
+
and it can be "strong" if the --flagfile comes at the end.
|
1189 |
+
* A further "--flagfile=<otherfile.cfg>" CAN be nested in a flagfile.
|
1190 |
+
It will be expanded in exactly the spot where it is found.
|
1191 |
+
* In a flagfile, a line beginning with # or // is a comment.
|
1192 |
+
* Entirely blank lines _should_ be ignored.
|
1193 |
+
"""
|
1194 |
+
rest_of_args = argv
|
1195 |
+
new_argv = []
|
1196 |
+
while rest_of_args:
|
1197 |
+
current_arg = rest_of_args[0]
|
1198 |
+
rest_of_args = rest_of_args[1:]
|
1199 |
+
if self._is_flag_file_directive(current_arg):
|
1200 |
+
# This handles the case of -(-)flagfile foo. In this case the
|
1201 |
+
# next arg really is part of this one.
|
1202 |
+
if current_arg == '--flagfile' or current_arg == '-flagfile':
|
1203 |
+
if not rest_of_args:
|
1204 |
+
raise _exceptions.IllegalFlagValueError(
|
1205 |
+
'--flagfile with no argument')
|
1206 |
+
flag_filename = os.path.expanduser(rest_of_args[0])
|
1207 |
+
rest_of_args = rest_of_args[1:]
|
1208 |
+
else:
|
1209 |
+
# This handles the case of (-)-flagfile=foo.
|
1210 |
+
flag_filename = self._extract_filename(current_arg)
|
1211 |
+
new_argv.extend(self._get_flag_file_lines(flag_filename))
|
1212 |
+
else:
|
1213 |
+
new_argv.append(current_arg)
|
1214 |
+
# Stop parsing after '--', like getopt and gnu_getopt.
|
1215 |
+
if current_arg == '--':
|
1216 |
+
break
|
1217 |
+
# Stop parsing after a non-flag, like getopt.
|
1218 |
+
if not current_arg.startswith('-'):
|
1219 |
+
if not force_gnu and not self.__dict__['__use_gnu_getopt']:
|
1220 |
+
break
|
1221 |
+
else:
|
1222 |
+
if ('=' not in current_arg and rest_of_args and
|
1223 |
+
not rest_of_args[0].startswith('-')):
|
1224 |
+
# If this is an occurrence of a legitimate --x y, skip the value
|
1225 |
+
# so that it won't be mistaken for a standalone arg.
|
1226 |
+
fl = self._flags()
|
1227 |
+
name = current_arg.lstrip('-')
|
1228 |
+
if name in fl and not fl[name].boolean:
|
1229 |
+
current_arg = rest_of_args[0]
|
1230 |
+
rest_of_args = rest_of_args[1:]
|
1231 |
+
new_argv.append(current_arg)
|
1232 |
+
|
1233 |
+
if rest_of_args:
|
1234 |
+
new_argv.extend(rest_of_args)
|
1235 |
+
|
1236 |
+
return new_argv
|
1237 |
+
|
1238 |
+
def flags_into_string(self) -> Text:
|
1239 |
+
"""Returns a string with the flags assignments from this FlagValues object.
|
1240 |
+
|
1241 |
+
This function ignores flags whose value is None. Each flag
|
1242 |
+
assignment is separated by a newline.
|
1243 |
+
|
1244 |
+
NOTE: MUST mirror the behavior of the C++ CommandlineFlagsIntoString
|
1245 |
+
from https://github.com/gflags/gflags.
|
1246 |
+
|
1247 |
+
Returns:
|
1248 |
+
str, the string with the flags assignments from this FlagValues object.
|
1249 |
+
The flags are ordered by (module_name, flag_name).
|
1250 |
+
"""
|
1251 |
+
module_flags = sorted(self.flags_by_module_dict().items())
|
1252 |
+
s = ''
|
1253 |
+
for unused_module_name, flags in module_flags:
|
1254 |
+
flags = sorted(flags, key=lambda f: f.name)
|
1255 |
+
for flag in flags:
|
1256 |
+
if flag.value is not None:
|
1257 |
+
s += flag.serialize() + '\n'
|
1258 |
+
return s
|
1259 |
+
|
1260 |
+
def append_flags_into_file(self, filename: Text) -> None:
|
1261 |
+
"""Appends all flags assignments from this FlagInfo object to a file.
|
1262 |
+
|
1263 |
+
Output will be in the format of a flagfile.
|
1264 |
+
|
1265 |
+
NOTE: MUST mirror the behavior of the C++ AppendFlagsIntoFile
|
1266 |
+
from https://github.com/gflags/gflags.
|
1267 |
+
|
1268 |
+
Args:
|
1269 |
+
filename: str, name of the file.
|
1270 |
+
"""
|
1271 |
+
with open(filename, 'a') as out_file:
|
1272 |
+
out_file.write(self.flags_into_string())
|
1273 |
+
|
1274 |
+
def write_help_in_xml_format(self, outfile: Optional[TextIO] = None) -> None:
|
1275 |
+
"""Outputs flag documentation in XML format.
|
1276 |
+
|
1277 |
+
NOTE: We use element names that are consistent with those used by
|
1278 |
+
the C++ command-line flag library, from
|
1279 |
+
https://github.com/gflags/gflags.
|
1280 |
+
We also use a few new elements (e.g., <key>), but we do not
|
1281 |
+
interfere / overlap with existing XML elements used by the C++
|
1282 |
+
library. Please maintain this consistency.
|
1283 |
+
|
1284 |
+
Args:
|
1285 |
+
outfile: File object we write to. Default None means sys.stdout.
|
1286 |
+
"""
|
1287 |
+
doc = minidom.Document()
|
1288 |
+
all_flag = doc.createElement('AllFlags')
|
1289 |
+
doc.appendChild(all_flag)
|
1290 |
+
|
1291 |
+
all_flag.appendChild(
|
1292 |
+
_helpers.create_xml_dom_element(doc, 'program',
|
1293 |
+
os.path.basename(sys.argv[0])))
|
1294 |
+
|
1295 |
+
usage_doc = sys.modules['__main__'].__doc__
|
1296 |
+
if not usage_doc:
|
1297 |
+
usage_doc = '\nUSAGE: %s [flags]\n' % sys.argv[0]
|
1298 |
+
else:
|
1299 |
+
usage_doc = usage_doc.replace('%s', sys.argv[0])
|
1300 |
+
all_flag.appendChild(
|
1301 |
+
_helpers.create_xml_dom_element(doc, 'usage', usage_doc))
|
1302 |
+
|
1303 |
+
# Get list of key flags for the main module.
|
1304 |
+
key_flags = self.get_key_flags_for_module(sys.argv[0])
|
1305 |
+
|
1306 |
+
# Sort flags by declaring module name and next by flag name.
|
1307 |
+
flags_by_module = self.flags_by_module_dict()
|
1308 |
+
all_module_names = list(flags_by_module.keys())
|
1309 |
+
all_module_names.sort()
|
1310 |
+
for module_name in all_module_names:
|
1311 |
+
flag_list = [(f.name, f) for f in flags_by_module[module_name]]
|
1312 |
+
flag_list.sort()
|
1313 |
+
for unused_flag_name, flag in flag_list:
|
1314 |
+
is_key = flag in key_flags
|
1315 |
+
all_flag.appendChild(
|
1316 |
+
flag._create_xml_dom_element( # pylint: disable=protected-access
|
1317 |
+
doc,
|
1318 |
+
module_name,
|
1319 |
+
is_key=is_key))
|
1320 |
+
|
1321 |
+
outfile = outfile or sys.stdout
|
1322 |
+
outfile.write(
|
1323 |
+
doc.toprettyxml(indent=' ', encoding='utf-8').decode('utf-8'))
|
1324 |
+
outfile.flush()
|
1325 |
+
|
1326 |
+
def _check_method_name_conflicts(self, name: str, flag: Flag):
|
1327 |
+
if flag.allow_using_method_names:
|
1328 |
+
return
|
1329 |
+
short_name = flag.short_name
|
1330 |
+
flag_names = {name} if short_name is None else {name, short_name}
|
1331 |
+
for flag_name in flag_names:
|
1332 |
+
if flag_name in self.__dict__['__banned_flag_names']:
|
1333 |
+
raise _exceptions.FlagNameConflictsWithMethodError(
|
1334 |
+
'Cannot define a flag named "{name}". It conflicts with a method '
|
1335 |
+
'on class "{class_name}". To allow defining it, use '
|
1336 |
+
'allow_using_method_names and access the flag value with '
|
1337 |
+
"FLAGS['{name}'].value. FLAGS.{name} returns the method, "
|
1338 |
+
'not the flag value.'.format(
|
1339 |
+
name=flag_name, class_name=type(self).__name__))
|
1340 |
+
|
1341 |
+
|
1342 |
+
FLAGS = FlagValues()
|
1343 |
+
|
1344 |
+
|
1345 |
+
class FlagHolder(Generic[_T]):
|
1346 |
+
"""Holds a defined flag.
|
1347 |
+
|
1348 |
+
This facilitates a cleaner api around global state. Instead of::
|
1349 |
+
|
1350 |
+
flags.DEFINE_integer('foo', ...)
|
1351 |
+
flags.DEFINE_integer('bar', ...)
|
1352 |
+
|
1353 |
+
def method():
|
1354 |
+
# prints parsed value of 'bar' flag
|
1355 |
+
print(flags.FLAGS.foo)
|
1356 |
+
# runtime error due to typo or possibly bad coding style.
|
1357 |
+
print(flags.FLAGS.baz)
|
1358 |
+
|
1359 |
+
it encourages code like::
|
1360 |
+
|
1361 |
+
_FOO_FLAG = flags.DEFINE_integer('foo', ...)
|
1362 |
+
_BAR_FLAG = flags.DEFINE_integer('bar', ...)
|
1363 |
+
|
1364 |
+
def method():
|
1365 |
+
print(_FOO_FLAG.value)
|
1366 |
+
print(_BAR_FLAG.value)
|
1367 |
+
|
1368 |
+
since the name of the flag appears only once in the source code.
|
1369 |
+
"""
|
1370 |
+
|
1371 |
+
value: _T
|
1372 |
+
|
1373 |
+
def __init__(
|
1374 |
+
self,
|
1375 |
+
flag_values: FlagValues,
|
1376 |
+
flag: Flag[_T],
|
1377 |
+
ensure_non_none_value: bool = False,
|
1378 |
+
):
|
1379 |
+
"""Constructs a FlagHolder instance providing typesafe access to flag.
|
1380 |
+
|
1381 |
+
Args:
|
1382 |
+
flag_values: The container the flag is registered to.
|
1383 |
+
flag: The flag object for this flag.
|
1384 |
+
ensure_non_none_value: Is the value of the flag allowed to be None.
|
1385 |
+
"""
|
1386 |
+
self._flagvalues = flag_values
|
1387 |
+
# We take the entire flag object, but only keep the name. Why?
|
1388 |
+
# - We want FlagHolder[T] to be generic container
|
1389 |
+
# - flag_values contains all flags, so has no reference to T.
|
1390 |
+
# - typecheckers don't like to see a generic class where none of the ctor
|
1391 |
+
# arguments refer to the generic type.
|
1392 |
+
self._name = flag.name
|
1393 |
+
# We intentionally do NOT check if the default value is None.
|
1394 |
+
# This allows future use of this for "required flags with None default"
|
1395 |
+
self._ensure_non_none_value = ensure_non_none_value
|
1396 |
+
|
1397 |
+
def __eq__(self, other):
|
1398 |
+
raise TypeError(
|
1399 |
+
"unsupported operand type(s) for ==: '{0}' and '{1}' "
|
1400 |
+
"(did you mean to use '{0}.value' instead?)".format(
|
1401 |
+
type(self).__name__, type(other).__name__))
|
1402 |
+
|
1403 |
+
def __bool__(self):
|
1404 |
+
raise TypeError(
|
1405 |
+
"bool() not supported for instances of type '{0}' "
|
1406 |
+
"(did you mean to use '{0}.value' instead?)".format(
|
1407 |
+
type(self).__name__))
|
1408 |
+
|
1409 |
+
__nonzero__ = __bool__
|
1410 |
+
|
1411 |
+
@property
|
1412 |
+
def name(self) -> Text:
|
1413 |
+
return self._name
|
1414 |
+
|
1415 |
+
@property
|
1416 |
+
def value(self) -> _T:
|
1417 |
+
"""Returns the value of the flag.
|
1418 |
+
|
1419 |
+
If ``_ensure_non_none_value`` is ``True``, then return value is not
|
1420 |
+
``None``.
|
1421 |
+
|
1422 |
+
Raises:
|
1423 |
+
UnparsedFlagAccessError: if flag parsing has not finished.
|
1424 |
+
IllegalFlagValueError: if value is None unexpectedly.
|
1425 |
+
"""
|
1426 |
+
val = getattr(self._flagvalues, self._name)
|
1427 |
+
if self._ensure_non_none_value and val is None:
|
1428 |
+
raise _exceptions.IllegalFlagValueError(
|
1429 |
+
'Unexpected None value for flag %s' % self._name)
|
1430 |
+
return val
|
1431 |
+
|
1432 |
+
@property
|
1433 |
+
def default(self) -> _T:
|
1434 |
+
"""Returns the default value of the flag."""
|
1435 |
+
return self._flagvalues[self._name].default
|
1436 |
+
|
1437 |
+
@property
|
1438 |
+
def present(self) -> bool:
|
1439 |
+
"""Returns True if the flag was parsed from command-line flags."""
|
1440 |
+
return bool(self._flagvalues[self._name].present)
|
1441 |
+
|
1442 |
+
def serialize(self) -> Text:
|
1443 |
+
"""Returns a serialized representation of the flag."""
|
1444 |
+
return self._flagvalues[self._name].serialize()
|
1445 |
+
|
1446 |
+
|
1447 |
+
def resolve_flag_ref(
|
1448 |
+
flag_ref: Union[str, FlagHolder], flag_values: FlagValues
|
1449 |
+
) -> Tuple[str, FlagValues]:
|
1450 |
+
"""Helper to validate and resolve a flag reference argument."""
|
1451 |
+
if isinstance(flag_ref, FlagHolder):
|
1452 |
+
new_flag_values = flag_ref._flagvalues # pylint: disable=protected-access
|
1453 |
+
if flag_values != FLAGS and flag_values != new_flag_values:
|
1454 |
+
raise ValueError(
|
1455 |
+
'flag_values must not be customized when operating on a FlagHolder')
|
1456 |
+
return flag_ref.name, new_flag_values
|
1457 |
+
return flag_ref, flag_values
|
1458 |
+
|
1459 |
+
|
1460 |
+
def resolve_flag_refs(
|
1461 |
+
flag_refs: Sequence[Union[str, FlagHolder]], flag_values: FlagValues
|
1462 |
+
) -> Tuple[List[str], FlagValues]:
|
1463 |
+
"""Helper to validate and resolve flag reference list arguments."""
|
1464 |
+
fv = None
|
1465 |
+
names = []
|
1466 |
+
for ref in flag_refs:
|
1467 |
+
if isinstance(ref, FlagHolder):
|
1468 |
+
newfv = ref._flagvalues # pylint: disable=protected-access
|
1469 |
+
name = ref.name
|
1470 |
+
else:
|
1471 |
+
newfv = flag_values
|
1472 |
+
name = ref
|
1473 |
+
if fv and fv != newfv:
|
1474 |
+
raise ValueError(
|
1475 |
+
'multiple FlagValues instances used in invocation. '
|
1476 |
+
'FlagHolders must be registered to the same FlagValues instance as '
|
1477 |
+
'do flag names, if provided.')
|
1478 |
+
fv = newfv
|
1479 |
+
names.append(name)
|
1480 |
+
return names, fv
|
MLPY/Lib/site-packages/absl/flags/_helpers.py
ADDED
@@ -0,0 +1,421 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
try:
|
27 |
+
import fcntl
|
28 |
+
except ImportError:
|
29 |
+
fcntl = None
|
30 |
+
try:
|
31 |
+
# Importing termios will fail on non-unix platforms.
|
32 |
+
import termios
|
33 |
+
except ImportError:
|
34 |
+
termios = None
|
35 |
+
# pylint: enable=g-import-not-at-top
|
36 |
+
|
37 |
+
|
38 |
+
_DEFAULT_HELP_WIDTH = 80 # Default width of help output.
|
39 |
+
# Minimal "sane" width of help output. We assume that any value below 40 is
|
40 |
+
# unreasonable.
|
41 |
+
_MIN_HELP_WIDTH = 40
|
42 |
+
|
43 |
+
# Define the allowed error rate in an input string to get suggestions.
|
44 |
+
#
|
45 |
+
# We lean towards a high threshold because we tend to be matching a phrase,
|
46 |
+
# and the simple algorithm used here is geared towards correcting word
|
47 |
+
# spellings.
|
48 |
+
#
|
49 |
+
# For manual testing, consider "<command> --list" which produced a large number
|
50 |
+
# of spurious suggestions when we used "least_errors > 0.5" instead of
|
51 |
+
# "least_erros >= 0.5".
|
52 |
+
_SUGGESTION_ERROR_RATE_THRESHOLD = 0.50
|
53 |
+
|
54 |
+
# Characters that cannot appear or are highly discouraged in an XML 1.0
|
55 |
+
# document. (See http://www.w3.org/TR/REC-xml/#charsets or
|
56 |
+
# https://en.wikipedia.org/wiki/Valid_characters_in_XML#XML_1.0)
|
57 |
+
_ILLEGAL_XML_CHARS_REGEX = re.compile(
|
58 |
+
u'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]')
|
59 |
+
|
60 |
+
# This is a set of module ids for the modules that disclaim key flags.
|
61 |
+
# This module is explicitly added to this set so that we never consider it to
|
62 |
+
# define key flag.
|
63 |
+
disclaim_module_ids: Set[int] = set([id(sys.modules[__name__])])
|
64 |
+
|
65 |
+
|
66 |
+
# Define special flags here so that help may be generated for them.
|
67 |
+
# NOTE: Please do NOT use SPECIAL_FLAGS from outside flags module.
|
68 |
+
# Initialized inside flagvalues.py.
|
69 |
+
# NOTE: This cannot be annotated as its actual FlagValues type since this would
|
70 |
+
# create a circular dependency.
|
71 |
+
SPECIAL_FLAGS: Any = None
|
72 |
+
|
73 |
+
|
74 |
+
# This points to the flags module, initialized in flags/__init__.py.
|
75 |
+
# This should only be used in adopt_module_key_flags to take SPECIAL_FLAGS into
|
76 |
+
# account.
|
77 |
+
FLAGS_MODULE: types.ModuleType = None
|
78 |
+
|
79 |
+
|
80 |
+
class _ModuleObjectAndName(NamedTuple):
|
81 |
+
"""Module object and name.
|
82 |
+
|
83 |
+
Fields:
|
84 |
+
- module: object, module object.
|
85 |
+
- module_name: str, module name.
|
86 |
+
"""
|
87 |
+
module: types.ModuleType
|
88 |
+
module_name: str
|
89 |
+
|
90 |
+
|
91 |
+
def get_module_object_and_name(
|
92 |
+
globals_dict: Dict[str, Any]
|
93 |
+
) -> _ModuleObjectAndName:
|
94 |
+
"""Returns the module that defines a global environment, and its name.
|
95 |
+
|
96 |
+
Args:
|
97 |
+
globals_dict: A dictionary that should correspond to an environment
|
98 |
+
providing the values of the globals.
|
99 |
+
|
100 |
+
Returns:
|
101 |
+
_ModuleObjectAndName - pair of module object & module name.
|
102 |
+
Returns (None, None) if the module could not be identified.
|
103 |
+
"""
|
104 |
+
name = globals_dict.get('__name__', None)
|
105 |
+
module = sys.modules.get(name, None)
|
106 |
+
# Pick a more informative name for the main module.
|
107 |
+
return _ModuleObjectAndName(module,
|
108 |
+
(sys.argv[0] if name == '__main__' else name))
|
109 |
+
|
110 |
+
|
111 |
+
def get_calling_module_object_and_name() -> _ModuleObjectAndName:
|
112 |
+
"""Returns the module that's calling into this module.
|
113 |
+
|
114 |
+
We generally use this function to get the name of the module calling a
|
115 |
+
DEFINE_foo... function.
|
116 |
+
|
117 |
+
Returns:
|
118 |
+
The module object that called into this one.
|
119 |
+
|
120 |
+
Raises:
|
121 |
+
AssertionError: Raised when no calling module could be identified.
|
122 |
+
"""
|
123 |
+
for depth in range(1, sys.getrecursionlimit()):
|
124 |
+
# sys._getframe is the right thing to use here, as it's the best
|
125 |
+
# way to walk up the call stack.
|
126 |
+
globals_for_frame = sys._getframe(depth).f_globals # pylint: disable=protected-access
|
127 |
+
module, module_name = get_module_object_and_name(globals_for_frame)
|
128 |
+
if id(module) not in disclaim_module_ids and module_name is not None:
|
129 |
+
return _ModuleObjectAndName(module, module_name)
|
130 |
+
raise AssertionError('No module was found')
|
131 |
+
|
132 |
+
|
133 |
+
def get_calling_module() -> str:
|
134 |
+
"""Returns the name of the module that's calling into this module."""
|
135 |
+
return get_calling_module_object_and_name().module_name
|
136 |
+
|
137 |
+
|
138 |
+
def create_xml_dom_element(
|
139 |
+
doc: minidom.Document, name: str, value: Any
|
140 |
+
) -> minidom.Element:
|
141 |
+
"""Returns an XML DOM element with name and text value.
|
142 |
+
|
143 |
+
Args:
|
144 |
+
doc: minidom.Document, the DOM document it should create nodes from.
|
145 |
+
name: str, the tag of XML element.
|
146 |
+
value: object, whose string representation will be used
|
147 |
+
as the value of the XML element. Illegal or highly discouraged xml 1.0
|
148 |
+
characters are stripped.
|
149 |
+
|
150 |
+
Returns:
|
151 |
+
An instance of minidom.Element.
|
152 |
+
"""
|
153 |
+
s = str(value)
|
154 |
+
if isinstance(value, bool):
|
155 |
+
# Display boolean values as the C++ flag library does: no caps.
|
156 |
+
s = s.lower()
|
157 |
+
# Remove illegal xml characters.
|
158 |
+
s = _ILLEGAL_XML_CHARS_REGEX.sub(u'', s)
|
159 |
+
|
160 |
+
e = doc.createElement(name)
|
161 |
+
e.appendChild(doc.createTextNode(s))
|
162 |
+
return e
|
163 |
+
|
164 |
+
|
165 |
+
def get_help_width() -> int:
|
166 |
+
"""Returns the integer width of help lines that is used in TextWrap."""
|
167 |
+
if not sys.stdout.isatty() or termios is None or fcntl is None:
|
168 |
+
return _DEFAULT_HELP_WIDTH
|
169 |
+
try:
|
170 |
+
data = fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, b'1234')
|
171 |
+
columns = struct.unpack('hh', data)[1]
|
172 |
+
# Emacs mode returns 0.
|
173 |
+
# Here we assume that any value below 40 is unreasonable.
|
174 |
+
if columns >= _MIN_HELP_WIDTH:
|
175 |
+
return columns
|
176 |
+
# Returning an int as default is fine, int(int) just return the int.
|
177 |
+
return int(os.getenv('COLUMNS', _DEFAULT_HELP_WIDTH))
|
178 |
+
|
179 |
+
except (TypeError, IOError, struct.error):
|
180 |
+
return _DEFAULT_HELP_WIDTH
|
181 |
+
|
182 |
+
|
183 |
+
def get_flag_suggestions(
|
184 |
+
attempt: Optional[str], longopt_list: Sequence[str]
|
185 |
+
) -> List[str]:
|
186 |
+
"""Returns helpful similar matches for an invalid flag."""
|
187 |
+
# Don't suggest on very short strings, or if no longopts are specified.
|
188 |
+
if len(attempt) <= 2 or not longopt_list:
|
189 |
+
return []
|
190 |
+
|
191 |
+
option_names = [v.split('=')[0] for v in longopt_list]
|
192 |
+
|
193 |
+
# Find close approximations in flag prefixes.
|
194 |
+
# This also handles the case where the flag is spelled right but ambiguous.
|
195 |
+
distances = [(_damerau_levenshtein(attempt, option[0:len(attempt)]), option)
|
196 |
+
for option in option_names]
|
197 |
+
# t[0] is distance, and sorting by t[1] allows us to have stable output.
|
198 |
+
distances.sort()
|
199 |
+
|
200 |
+
least_errors, _ = distances[0]
|
201 |
+
# Don't suggest excessively bad matches.
|
202 |
+
if least_errors >= _SUGGESTION_ERROR_RATE_THRESHOLD * len(attempt):
|
203 |
+
return []
|
204 |
+
|
205 |
+
suggestions = []
|
206 |
+
for errors, name in distances:
|
207 |
+
if errors == least_errors:
|
208 |
+
suggestions.append(name)
|
209 |
+
else:
|
210 |
+
break
|
211 |
+
return suggestions
|
212 |
+
|
213 |
+
|
214 |
+
def _damerau_levenshtein(a, b):
|
215 |
+
"""Returns Damerau-Levenshtein edit distance from a to b."""
|
216 |
+
memo = {}
|
217 |
+
|
218 |
+
def distance(x, y):
|
219 |
+
"""Recursively defined string distance with memoization."""
|
220 |
+
if (x, y) in memo:
|
221 |
+
return memo[x, y]
|
222 |
+
if not x:
|
223 |
+
d = len(y)
|
224 |
+
elif not y:
|
225 |
+
d = len(x)
|
226 |
+
else:
|
227 |
+
d = min(
|
228 |
+
distance(x[1:], y) + 1, # correct an insertion error
|
229 |
+
distance(x, y[1:]) + 1, # correct a deletion error
|
230 |
+
distance(x[1:], y[1:]) + (x[0] != y[0])) # correct a wrong character
|
231 |
+
if len(x) >= 2 and len(y) >= 2 and x[0] == y[1] and x[1] == y[0]:
|
232 |
+
# Correct a transposition.
|
233 |
+
t = distance(x[2:], y[2:]) + 1
|
234 |
+
if d > t:
|
235 |
+
d = t
|
236 |
+
|
237 |
+
memo[x, y] = d
|
238 |
+
return d
|
239 |
+
return distance(a, b)
|
240 |
+
|
241 |
+
|
242 |
+
def text_wrap(
|
243 |
+
text: str,
|
244 |
+
length: Optional[int] = None,
|
245 |
+
indent: str = '',
|
246 |
+
firstline_indent: Optional[str] = None,
|
247 |
+
) -> str:
|
248 |
+
"""Wraps a given text to a maximum line length and returns it.
|
249 |
+
|
250 |
+
It turns lines that only contain whitespace into empty lines, keeps new lines,
|
251 |
+
and expands tabs using 4 spaces.
|
252 |
+
|
253 |
+
Args:
|
254 |
+
text: str, text to wrap.
|
255 |
+
length: int, maximum length of a line, includes indentation.
|
256 |
+
If this is None then use get_help_width()
|
257 |
+
indent: str, indent for all but first line.
|
258 |
+
firstline_indent: str, indent for first line; if None, fall back to indent.
|
259 |
+
|
260 |
+
Returns:
|
261 |
+
str, the wrapped text.
|
262 |
+
|
263 |
+
Raises:
|
264 |
+
ValueError: Raised if indent or firstline_indent not shorter than length.
|
265 |
+
"""
|
266 |
+
# Get defaults where callee used None
|
267 |
+
if length is None:
|
268 |
+
length = get_help_width()
|
269 |
+
if indent is None:
|
270 |
+
indent = ''
|
271 |
+
if firstline_indent is None:
|
272 |
+
firstline_indent = indent
|
273 |
+
|
274 |
+
if len(indent) >= length:
|
275 |
+
raise ValueError('Length of indent exceeds length')
|
276 |
+
if len(firstline_indent) >= length:
|
277 |
+
raise ValueError('Length of first line indent exceeds length')
|
278 |
+
|
279 |
+
text = text.expandtabs(4)
|
280 |
+
|
281 |
+
result = []
|
282 |
+
# Create one wrapper for the first paragraph and one for subsequent
|
283 |
+
# paragraphs that does not have the initial wrapping.
|
284 |
+
wrapper = textwrap.TextWrapper(
|
285 |
+
width=length, initial_indent=firstline_indent, subsequent_indent=indent)
|
286 |
+
subsequent_wrapper = textwrap.TextWrapper(
|
287 |
+
width=length, initial_indent=indent, subsequent_indent=indent)
|
288 |
+
|
289 |
+
# textwrap does not have any special treatment for newlines. From the docs:
|
290 |
+
# "...newlines may appear in the middle of a line and cause strange output.
|
291 |
+
# For this reason, text should be split into paragraphs (using
|
292 |
+
# str.splitlines() or similar) which are wrapped separately."
|
293 |
+
for paragraph in (p.strip() for p in text.splitlines()):
|
294 |
+
if paragraph:
|
295 |
+
result.extend(wrapper.wrap(paragraph))
|
296 |
+
else:
|
297 |
+
result.append('') # Keep empty lines.
|
298 |
+
# Replace initial wrapper with wrapper for subsequent paragraphs.
|
299 |
+
wrapper = subsequent_wrapper
|
300 |
+
|
301 |
+
return '\n'.join(result)
|
302 |
+
|
303 |
+
|
304 |
+
def flag_dict_to_args(
|
305 |
+
flag_map: Dict[str, Any], multi_flags: Optional[Set[str]] = None
|
306 |
+
) -> Iterable[str]:
|
307 |
+
"""Convert a dict of values into process call parameters.
|
308 |
+
|
309 |
+
This method is used to convert a dictionary into a sequence of parameters
|
310 |
+
for a binary that parses arguments using this module.
|
311 |
+
|
312 |
+
Args:
|
313 |
+
flag_map: dict, a mapping where the keys are flag names (strings).
|
314 |
+
values are treated according to their type:
|
315 |
+
|
316 |
+
* If value is ``None``, then only the name is emitted.
|
317 |
+
* If value is ``True``, then only the name is emitted.
|
318 |
+
* If value is ``False``, then only the name prepended with 'no' is
|
319 |
+
emitted.
|
320 |
+
* If value is a string then ``--name=value`` is emitted.
|
321 |
+
* If value is a collection, this will emit
|
322 |
+
``--name=value1,value2,value3``, unless the flag name is in
|
323 |
+
``multi_flags``, in which case this will emit
|
324 |
+
``--name=value1 --name=value2 --name=value3``.
|
325 |
+
* Everything else is converted to string an passed as such.
|
326 |
+
|
327 |
+
multi_flags: set, names (strings) of flags that should be treated as
|
328 |
+
multi-flags.
|
329 |
+
Yields:
|
330 |
+
sequence of string suitable for a subprocess execution.
|
331 |
+
"""
|
332 |
+
for key, value in flag_map.items():
|
333 |
+
if value is None:
|
334 |
+
yield '--%s' % key
|
335 |
+
elif isinstance(value, bool):
|
336 |
+
if value:
|
337 |
+
yield '--%s' % key
|
338 |
+
else:
|
339 |
+
yield '--no%s' % key
|
340 |
+
elif isinstance(value, (bytes, type(u''))):
|
341 |
+
# We don't want strings to be handled like python collections.
|
342 |
+
yield '--%s=%s' % (key, value)
|
343 |
+
else:
|
344 |
+
# Now we attempt to deal with collections.
|
345 |
+
try:
|
346 |
+
if multi_flags and key in multi_flags:
|
347 |
+
for item in value:
|
348 |
+
yield '--%s=%s' % (key, str(item))
|
349 |
+
else:
|
350 |
+
yield '--%s=%s' % (key, ','.join(str(item) for item in value))
|
351 |
+
except TypeError:
|
352 |
+
# Default case.
|
353 |
+
yield '--%s=%s' % (key, value)
|
354 |
+
|
355 |
+
|
356 |
+
def trim_docstring(docstring: str) -> str:
|
357 |
+
"""Removes indentation from triple-quoted strings.
|
358 |
+
|
359 |
+
This is the function specified in PEP 257 to handle docstrings:
|
360 |
+
https://www.python.org/dev/peps/pep-0257/.
|
361 |
+
|
362 |
+
Args:
|
363 |
+
docstring: str, a python docstring.
|
364 |
+
|
365 |
+
Returns:
|
366 |
+
str, docstring with indentation removed.
|
367 |
+
"""
|
368 |
+
if not docstring:
|
369 |
+
return ''
|
370 |
+
|
371 |
+
# If you've got a line longer than this you have other problems...
|
372 |
+
max_indent = 1 << 29
|
373 |
+
|
374 |
+
# Convert tabs to spaces (following the normal Python rules)
|
375 |
+
# and split into a list of lines:
|
376 |
+
lines = docstring.expandtabs().splitlines()
|
377 |
+
|
378 |
+
# Determine minimum indentation (first line doesn't count):
|
379 |
+
indent = max_indent
|
380 |
+
for line in lines[1:]:
|
381 |
+
stripped = line.lstrip()
|
382 |
+
if stripped:
|
383 |
+
indent = min(indent, len(line) - len(stripped))
|
384 |
+
# Remove indentation (first line is special):
|
385 |
+
trimmed = [lines[0].strip()]
|
386 |
+
if indent < max_indent:
|
387 |
+
for line in lines[1:]:
|
388 |
+
trimmed.append(line[indent:].rstrip())
|
389 |
+
# Strip off trailing and leading blank lines:
|
390 |
+
while trimmed and not trimmed[-1]:
|
391 |
+
trimmed.pop()
|
392 |
+
while trimmed and not trimmed[0]:
|
393 |
+
trimmed.pop(0)
|
394 |
+
# Return a single string:
|
395 |
+
return '\n'.join(trimmed)
|
396 |
+
|
397 |
+
|
398 |
+
def doc_to_help(doc: str) -> str:
|
399 |
+
"""Takes a __doc__ string and reformats it as help."""
|
400 |
+
|
401 |
+
# Get rid of starting and ending white space. Using lstrip() or even
|
402 |
+
# strip() could drop more than maximum of first line and right space
|
403 |
+
# of last line.
|
404 |
+
doc = doc.strip()
|
405 |
+
|
406 |
+
# Get rid of all empty lines.
|
407 |
+
whitespace_only_line = re.compile('^[ \t]+$', re.M)
|
408 |
+
doc = whitespace_only_line.sub('', doc)
|
409 |
+
|
410 |
+
# Cut out common space at line beginnings.
|
411 |
+
doc = trim_docstring(doc)
|
412 |
+
|
413 |
+
# Just like this module's comment, comments tend to be aligned somehow.
|
414 |
+
# In other words they all start with the same amount of white space.
|
415 |
+
# 1) keep double new lines;
|
416 |
+
# 2) keep ws after new lines if not empty line;
|
417 |
+
# 3) all other new lines shall be changed to a space;
|
418 |
+
# Solution: Match new lines between non white space and replace with space.
|
419 |
+
doc = re.sub(r'(?<=\S)\n(?=\S)', ' ', doc, flags=re.M)
|
420 |
+
|
421 |
+
return doc
|
MLPY/Lib/site-packages/absl/flags/_validators.py
ADDED
@@ -0,0 +1,352 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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='Flag --{} must have a value other than None.'.format(flag_name),
|
233 |
+
flag_values=flag_values)
|
234 |
+
|
235 |
+
|
236 |
+
def mark_flags_as_required(flag_names, flag_values=_flagvalues.FLAGS):
|
237 |
+
"""Ensures that flags are not None during program execution.
|
238 |
+
|
239 |
+
If your module might be imported by others, and you only wish to make the flag
|
240 |
+
required when the module is directly executed, call this method like this::
|
241 |
+
|
242 |
+
if __name__ == '__main__':
|
243 |
+
flags.mark_flags_as_required(['flag1', 'flag2', 'flag3'])
|
244 |
+
app.run()
|
245 |
+
|
246 |
+
Args:
|
247 |
+
flag_names: Sequence[str | FlagHolder], names or holders of the flags.
|
248 |
+
flag_values: flags.FlagValues, optional FlagValues instance where the flags
|
249 |
+
are defined.
|
250 |
+
Raises:
|
251 |
+
AttributeError: If any of flag name has not already been defined as a flag.
|
252 |
+
"""
|
253 |
+
for flag_name in flag_names:
|
254 |
+
mark_flag_as_required(flag_name, flag_values)
|
255 |
+
|
256 |
+
|
257 |
+
def mark_flags_as_mutual_exclusive(flag_names, required=False,
|
258 |
+
flag_values=_flagvalues.FLAGS):
|
259 |
+
"""Ensures that only one flag among flag_names is not None.
|
260 |
+
|
261 |
+
Important note: This validator checks if flag values are ``None``, and it does
|
262 |
+
not distinguish between default and explicit values. Therefore, this validator
|
263 |
+
does not make sense when applied to flags with default values other than None,
|
264 |
+
including other false values (e.g. ``False``, ``0``, ``''``, ``[]``). That
|
265 |
+
includes multi flags with a default value of ``[]`` instead of None.
|
266 |
+
|
267 |
+
Args:
|
268 |
+
flag_names: [str | FlagHolder], names or holders of flags.
|
269 |
+
Positional-only parameter.
|
270 |
+
required: bool. If true, exactly one of the flags must have a value other
|
271 |
+
than None. Otherwise, at most one of the flags can have a value other
|
272 |
+
than None, and it is valid for all of the flags to be None.
|
273 |
+
flag_values: flags.FlagValues, optional FlagValues instance where the flags
|
274 |
+
are defined.
|
275 |
+
|
276 |
+
Raises:
|
277 |
+
ValueError: Raised when multiple FlagValues are used in the same
|
278 |
+
invocation. This can occur when FlagHolders have different `_flagvalues`
|
279 |
+
or when str-type flag_names entries are present and the `flag_values`
|
280 |
+
argument does not match that of provided FlagHolder(s).
|
281 |
+
"""
|
282 |
+
flag_names, flag_values = _flagvalues.resolve_flag_refs(
|
283 |
+
flag_names, flag_values)
|
284 |
+
for flag_name in flag_names:
|
285 |
+
if flag_values[flag_name].default is not None:
|
286 |
+
warnings.warn(
|
287 |
+
'Flag --{} has a non-None default value. That does not make sense '
|
288 |
+
'with mark_flags_as_mutual_exclusive, which checks whether the '
|
289 |
+
'listed flags have a value other than None.'.format(flag_name),
|
290 |
+
stacklevel=2)
|
291 |
+
|
292 |
+
def validate_mutual_exclusion(flags_dict):
|
293 |
+
flag_count = sum(1 for val in flags_dict.values() if val is not None)
|
294 |
+
if flag_count == 1 or (not required and flag_count == 0):
|
295 |
+
return True
|
296 |
+
raise _exceptions.ValidationError(
|
297 |
+
'{} one of ({}) must have a value other than None.'.format(
|
298 |
+
'Exactly' if required else 'At most', ', '.join(flag_names)))
|
299 |
+
|
300 |
+
register_multi_flags_validator(
|
301 |
+
flag_names, validate_mutual_exclusion, flag_values=flag_values)
|
302 |
+
|
303 |
+
|
304 |
+
def mark_bool_flags_as_mutual_exclusive(flag_names, required=False,
|
305 |
+
flag_values=_flagvalues.FLAGS):
|
306 |
+
"""Ensures that only one flag among flag_names is True.
|
307 |
+
|
308 |
+
Args:
|
309 |
+
flag_names: [str | FlagHolder], names or holders of flags.
|
310 |
+
Positional-only parameter.
|
311 |
+
required: bool. If true, exactly one flag must be True. Otherwise, at most
|
312 |
+
one flag can be True, and it is valid for all flags to be False.
|
313 |
+
flag_values: flags.FlagValues, optional FlagValues instance where the flags
|
314 |
+
are defined.
|
315 |
+
|
316 |
+
Raises:
|
317 |
+
ValueError: Raised when multiple FlagValues are used in the same
|
318 |
+
invocation. This can occur when FlagHolders have different `_flagvalues`
|
319 |
+
or when str-type flag_names entries are present and the `flag_values`
|
320 |
+
argument does not match that of provided FlagHolder(s).
|
321 |
+
"""
|
322 |
+
flag_names, flag_values = _flagvalues.resolve_flag_refs(
|
323 |
+
flag_names, flag_values)
|
324 |
+
for flag_name in flag_names:
|
325 |
+
if not flag_values[flag_name].boolean:
|
326 |
+
raise _exceptions.ValidationError(
|
327 |
+
'Flag --{} is not Boolean, which is required for flags used in '
|
328 |
+
'mark_bool_flags_as_mutual_exclusive.'.format(flag_name))
|
329 |
+
|
330 |
+
def validate_boolean_mutual_exclusion(flags_dict):
|
331 |
+
flag_count = sum(bool(val) for val in flags_dict.values())
|
332 |
+
if flag_count == 1 or (not required and flag_count == 0):
|
333 |
+
return True
|
334 |
+
raise _exceptions.ValidationError(
|
335 |
+
'{} one of ({}) must be True.'.format(
|
336 |
+
'Exactly' if required else 'At most', ', '.join(flag_names)))
|
337 |
+
|
338 |
+
register_multi_flags_validator(
|
339 |
+
flag_names, validate_boolean_mutual_exclusion, flag_values=flag_values)
|
340 |
+
|
341 |
+
|
342 |
+
def _add_validator(fv, validator_instance):
|
343 |
+
"""Register new flags validator to be checked.
|
344 |
+
|
345 |
+
Args:
|
346 |
+
fv: flags.FlagValues, the FlagValues instance to add the validator.
|
347 |
+
validator_instance: validators.Validator, the validator to add.
|
348 |
+
Raises:
|
349 |
+
KeyError: Raised when validators work with a non-existing flag.
|
350 |
+
"""
|
351 |
+
for flag_name in validator_instance.get_flags_names():
|
352 |
+
fv[flag_name].validators.append(validator_instance)
|
MLPY/Lib/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(object):
|
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(SingleFlagValidator, self).__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(MultiFlagsValidator, self).__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 dict([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
|
MLPY/Lib/site-packages/absl/flags/argparse_flags.py
ADDED
@@ -0,0 +1,388 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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(ArgumentParser, self).__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(ArgumentParser, self).parse_known_args(
|
167 |
+
args, namespace)
|
168 |
+
|
169 |
+
# For Python <= 2.7.8: https://bugs.python.org/issue9351, a bug where
|
170 |
+
# sub-parsers don't preserve existing namespace attributes.
|
171 |
+
# Restore the undefok attribute if a sub-parser dropped it.
|
172 |
+
if undefok is not undefok_missing:
|
173 |
+
namespace.undefok = undefok
|
174 |
+
|
175 |
+
if self._inherited_absl_flags is not None:
|
176 |
+
# Handle --undefok. At this point, `args` only contains unknown flags,
|
177 |
+
# so it won't strip defined flags that are also specified with --undefok.
|
178 |
+
# For Python <= 2.7.8: https://bugs.python.org/issue9351, a bug where
|
179 |
+
# sub-parsers don't preserve existing namespace attributes. The undefok
|
180 |
+
# attribute might not exist because a subparser dropped it.
|
181 |
+
if hasattr(namespace, 'undefok'):
|
182 |
+
args = _strip_undefok_args(namespace.undefok, args)
|
183 |
+
# absl flags are not exposed in the Namespace object. See Namespace:
|
184 |
+
# https://docs.python.org/3/library/argparse.html#argparse.Namespace.
|
185 |
+
del namespace.undefok
|
186 |
+
self._inherited_absl_flags.mark_as_parsed()
|
187 |
+
try:
|
188 |
+
self._inherited_absl_flags.validate_all_flags()
|
189 |
+
except flags.IllegalFlagValueError as e:
|
190 |
+
self.error(str(e))
|
191 |
+
|
192 |
+
return namespace, args
|
193 |
+
|
194 |
+
def _define_absl_flags(self, absl_flags):
|
195 |
+
"""Defines flags from absl_flags."""
|
196 |
+
key_flags = set(absl_flags.get_key_flags_for_module(sys.argv[0]))
|
197 |
+
for name in absl_flags:
|
198 |
+
if name in _BUILT_IN_FLAGS:
|
199 |
+
# Do not inherit built-in flags.
|
200 |
+
continue
|
201 |
+
flag_instance = absl_flags[name]
|
202 |
+
# Each flags with short_name appears in FLAGS twice, so only define
|
203 |
+
# when the dictionary key is equal to the regular name.
|
204 |
+
if name == flag_instance.name:
|
205 |
+
# Suppress the flag in the help short message if it's not a main
|
206 |
+
# module's key flag.
|
207 |
+
suppress = flag_instance not in key_flags
|
208 |
+
self._define_absl_flag(flag_instance, suppress)
|
209 |
+
|
210 |
+
def _define_absl_flag(self, flag_instance, suppress):
|
211 |
+
"""Defines a flag from the flag_instance."""
|
212 |
+
flag_name = flag_instance.name
|
213 |
+
short_name = flag_instance.short_name
|
214 |
+
argument_names = ['--' + flag_name]
|
215 |
+
if short_name:
|
216 |
+
argument_names.insert(0, '-' + short_name)
|
217 |
+
if suppress:
|
218 |
+
helptext = argparse.SUPPRESS
|
219 |
+
else:
|
220 |
+
# argparse help string uses %-formatting. Escape the literal %'s.
|
221 |
+
helptext = flag_instance.help.replace('%', '%%')
|
222 |
+
if flag_instance.boolean:
|
223 |
+
# Only add the `no` form to the long name.
|
224 |
+
argument_names.append('--no' + flag_name)
|
225 |
+
self.add_argument(
|
226 |
+
*argument_names, action=_BooleanFlagAction, help=helptext,
|
227 |
+
metavar=flag_instance.name.upper(),
|
228 |
+
flag_instance=flag_instance)
|
229 |
+
else:
|
230 |
+
self.add_argument(
|
231 |
+
*argument_names, action=_FlagAction, help=helptext,
|
232 |
+
metavar=flag_instance.name.upper(),
|
233 |
+
flag_instance=flag_instance)
|
234 |
+
|
235 |
+
|
236 |
+
class _FlagAction(argparse.Action):
|
237 |
+
"""Action class for Abseil non-boolean flags."""
|
238 |
+
|
239 |
+
def __init__(
|
240 |
+
self,
|
241 |
+
option_strings,
|
242 |
+
dest,
|
243 |
+
help, # pylint: disable=redefined-builtin
|
244 |
+
metavar,
|
245 |
+
flag_instance,
|
246 |
+
default=argparse.SUPPRESS):
|
247 |
+
"""Initializes _FlagAction.
|
248 |
+
|
249 |
+
Args:
|
250 |
+
option_strings: See argparse.Action.
|
251 |
+
dest: Ignored. The flag is always defined with dest=argparse.SUPPRESS.
|
252 |
+
help: See argparse.Action.
|
253 |
+
metavar: See argparse.Action.
|
254 |
+
flag_instance: absl.flags.Flag, the absl flag instance.
|
255 |
+
default: Ignored. The flag always uses dest=argparse.SUPPRESS so it
|
256 |
+
doesn't affect the parsing result.
|
257 |
+
"""
|
258 |
+
del dest
|
259 |
+
self._flag_instance = flag_instance
|
260 |
+
super(_FlagAction, self).__init__(
|
261 |
+
option_strings=option_strings,
|
262 |
+
dest=argparse.SUPPRESS,
|
263 |
+
help=help,
|
264 |
+
metavar=metavar)
|
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(_BooleanFlagAction, self).__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 |
+
def __call__(self, parser, namespace, values, option_string=None):
|
308 |
+
"""See https://docs.python.org/3/library/argparse.html#action-classes."""
|
309 |
+
if not isinstance(values, list) or values:
|
310 |
+
raise ValueError('values must be an empty list.')
|
311 |
+
if option_string.startswith('--'):
|
312 |
+
option = option_string[2:]
|
313 |
+
else:
|
314 |
+
option = option_string[1:]
|
315 |
+
if option in self._flag_names:
|
316 |
+
self._flag_instance.parse('true')
|
317 |
+
else:
|
318 |
+
if not option.startswith('no') or option[2:] not in self._flag_names:
|
319 |
+
raise ValueError('invalid option_string: ' + option_string)
|
320 |
+
self._flag_instance.parse('false')
|
321 |
+
self._flag_instance.using_default_value = False
|
322 |
+
|
323 |
+
|
324 |
+
class _HelpFullAction(argparse.Action):
|
325 |
+
"""Action class for --helpfull flag."""
|
326 |
+
|
327 |
+
def __init__(self, option_strings, dest, default, help): # pylint: disable=redefined-builtin
|
328 |
+
"""Initializes _HelpFullAction.
|
329 |
+
|
330 |
+
Args:
|
331 |
+
option_strings: See argparse.Action.
|
332 |
+
dest: Ignored. The flag is always defined with dest=argparse.SUPPRESS.
|
333 |
+
default: Ignored.
|
334 |
+
help: See argparse.Action.
|
335 |
+
"""
|
336 |
+
del dest, default
|
337 |
+
super(_HelpFullAction, self).__init__(
|
338 |
+
option_strings=option_strings,
|
339 |
+
dest=argparse.SUPPRESS,
|
340 |
+
default=argparse.SUPPRESS,
|
341 |
+
nargs=0,
|
342 |
+
help=help)
|
343 |
+
|
344 |
+
def __call__(self, parser, namespace, values, option_string=None):
|
345 |
+
"""See https://docs.python.org/3/library/argparse.html#action-classes."""
|
346 |
+
# This only prints flags when help is not argparse.SUPPRESS.
|
347 |
+
# It includes user defined argparse flags, as well as main module's
|
348 |
+
# key absl flags. Other absl flags use argparse.SUPPRESS, so they aren't
|
349 |
+
# printed here.
|
350 |
+
parser.print_help()
|
351 |
+
|
352 |
+
absl_flags = parser._inherited_absl_flags # pylint: disable=protected-access
|
353 |
+
if absl_flags is not None:
|
354 |
+
modules = sorted(absl_flags.flags_by_module_dict())
|
355 |
+
main_module = sys.argv[0]
|
356 |
+
if main_module in modules:
|
357 |
+
# The main module flags are already printed in parser.print_help().
|
358 |
+
modules.remove(main_module)
|
359 |
+
print(absl_flags._get_help_for_modules( # pylint: disable=protected-access
|
360 |
+
modules, prefix='', include_special_flags=True))
|
361 |
+
parser.exit()
|
362 |
+
|
363 |
+
|
364 |
+
def _strip_undefok_args(undefok, args):
|
365 |
+
"""Returns a new list of args after removing flags in --undefok."""
|
366 |
+
if undefok:
|
367 |
+
undefok_names = set(name.strip() for name in undefok.split(','))
|
368 |
+
undefok_names |= set('no' + name for name in undefok_names)
|
369 |
+
# Remove undefok flags.
|
370 |
+
args = [arg for arg in args if not _is_undefok(arg, undefok_names)]
|
371 |
+
return args
|
372 |
+
|
373 |
+
|
374 |
+
def _is_undefok(arg, undefok_names):
|
375 |
+
"""Returns whether we can ignore arg based on a set of undefok flag names."""
|
376 |
+
if not arg.startswith('-'):
|
377 |
+
return False
|
378 |
+
if arg.startswith('--'):
|
379 |
+
arg_without_dash = arg[2:]
|
380 |
+
else:
|
381 |
+
arg_without_dash = arg[1:]
|
382 |
+
if '=' in arg_without_dash:
|
383 |
+
name, _ = arg_without_dash.split('=', 1)
|
384 |
+
else:
|
385 |
+
name = arg_without_dash
|
386 |
+
if name in undefok_names:
|
387 |
+
return True
|
388 |
+
return False
|
MLPY/Lib/site-packages/absl/logging/__init__.py
ADDED
@@ -0,0 +1,1281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 itertools
|
84 |
+
import logging
|
85 |
+
import os
|
86 |
+
import socket
|
87 |
+
import struct
|
88 |
+
import sys
|
89 |
+
import tempfile
|
90 |
+
import threading
|
91 |
+
import time
|
92 |
+
import timeit
|
93 |
+
import traceback
|
94 |
+
import types
|
95 |
+
import warnings
|
96 |
+
|
97 |
+
from absl import flags
|
98 |
+
from absl.logging import converter
|
99 |
+
|
100 |
+
# pylint: disable=g-import-not-at-top
|
101 |
+
try:
|
102 |
+
from typing import NoReturn
|
103 |
+
except ImportError:
|
104 |
+
pass
|
105 |
+
|
106 |
+
# pylint: enable=g-import-not-at-top
|
107 |
+
|
108 |
+
FLAGS = flags.FLAGS
|
109 |
+
|
110 |
+
|
111 |
+
# Logging levels.
|
112 |
+
FATAL = converter.ABSL_FATAL
|
113 |
+
ERROR = converter.ABSL_ERROR
|
114 |
+
WARNING = converter.ABSL_WARNING
|
115 |
+
WARN = converter.ABSL_WARNING # Deprecated name.
|
116 |
+
INFO = converter.ABSL_INFO
|
117 |
+
DEBUG = converter.ABSL_DEBUG
|
118 |
+
|
119 |
+
# Regex to match/parse log line prefixes.
|
120 |
+
ABSL_LOGGING_PREFIX_REGEX = (
|
121 |
+
r'^(?P<severity>[IWEF])'
|
122 |
+
r'(?P<month>\d\d)(?P<day>\d\d) '
|
123 |
+
r'(?P<hour>\d\d):(?P<minute>\d\d):(?P<second>\d\d)'
|
124 |
+
r'\.(?P<microsecond>\d\d\d\d\d\d) +'
|
125 |
+
r'(?P<thread_id>-?\d+) '
|
126 |
+
r'(?P<filename>[a-zA-Z<][\w._<>-]+):(?P<line>\d+)')
|
127 |
+
|
128 |
+
|
129 |
+
# Mask to convert integer thread ids to unsigned quantities for logging purposes
|
130 |
+
_THREAD_ID_MASK = 2 ** (struct.calcsize('L') * 8) - 1
|
131 |
+
|
132 |
+
# Extra property set on the LogRecord created by ABSLLogger when its level is
|
133 |
+
# CRITICAL/FATAL.
|
134 |
+
_ABSL_LOG_FATAL = '_absl_log_fatal'
|
135 |
+
# Extra prefix added to the log message when a non-absl logger logs a
|
136 |
+
# CRITICAL/FATAL message.
|
137 |
+
_CRITICAL_PREFIX = 'CRITICAL - '
|
138 |
+
|
139 |
+
# Used by findCaller to skip callers from */logging/__init__.py.
|
140 |
+
_LOGGING_FILE_PREFIX = os.path.join('logging', '__init__.')
|
141 |
+
|
142 |
+
# The ABSL logger instance, initialized in _initialize().
|
143 |
+
_absl_logger = None
|
144 |
+
# The ABSL handler instance, initialized in _initialize().
|
145 |
+
_absl_handler = None
|
146 |
+
|
147 |
+
|
148 |
+
_CPP_NAME_TO_LEVELS = {
|
149 |
+
'debug': '0', # Abseil C++ has no DEBUG level, mapping it to INFO here.
|
150 |
+
'info': '0',
|
151 |
+
'warning': '1',
|
152 |
+
'warn': '1',
|
153 |
+
'error': '2',
|
154 |
+
'fatal': '3'
|
155 |
+
}
|
156 |
+
|
157 |
+
_CPP_LEVEL_TO_NAMES = {
|
158 |
+
'0': 'info',
|
159 |
+
'1': 'warning',
|
160 |
+
'2': 'error',
|
161 |
+
'3': 'fatal',
|
162 |
+
}
|
163 |
+
|
164 |
+
|
165 |
+
class _VerbosityFlag(flags.Flag):
|
166 |
+
"""Flag class for -v/--verbosity."""
|
167 |
+
|
168 |
+
def __init__(self, *args, **kwargs):
|
169 |
+
super(_VerbosityFlag, self).__init__(
|
170 |
+
flags.IntegerParser(),
|
171 |
+
flags.ArgumentSerializer(),
|
172 |
+
*args, **kwargs)
|
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(_LoggerLevelsFlag, self).__init__(
|
212 |
+
_LoggerLevelsParser(),
|
213 |
+
_LoggerLevelsSerializer(),
|
214 |
+
*args, **kwargs)
|
215 |
+
|
216 |
+
@property
|
217 |
+
def value(self):
|
218 |
+
# For lack of an immutable type, be defensive and return a copy.
|
219 |
+
# Modifications to the dict aren't supported and won't have any affect.
|
220 |
+
# While Py3 could use MappingProxyType, that isn't deepcopy friendly, so
|
221 |
+
# just return a copy.
|
222 |
+
return self._value.copy()
|
223 |
+
|
224 |
+
@value.setter
|
225 |
+
def value(self, v):
|
226 |
+
self._value = {} if v is None else v
|
227 |
+
self._update_logger_levels()
|
228 |
+
|
229 |
+
def _update_logger_levels(self):
|
230 |
+
# Visibility: module-private.
|
231 |
+
# This is called by absl.app.run() during initialization.
|
232 |
+
for name, level in self._value.items():
|
233 |
+
logging.getLogger(name).setLevel(level)
|
234 |
+
|
235 |
+
|
236 |
+
class _LoggerLevelsParser(flags.ArgumentParser):
|
237 |
+
"""Parser for --logger_levels flag."""
|
238 |
+
|
239 |
+
def parse(self, value):
|
240 |
+
if isinstance(value, abc.Mapping):
|
241 |
+
return value
|
242 |
+
|
243 |
+
pairs = [pair.strip() for pair in value.split(',') if pair.strip()]
|
244 |
+
|
245 |
+
# Preserve the order so that serialization is deterministic.
|
246 |
+
levels = collections.OrderedDict()
|
247 |
+
for name_level in pairs:
|
248 |
+
name, level = name_level.split(':', 1)
|
249 |
+
name = name.strip()
|
250 |
+
level = level.strip()
|
251 |
+
levels[name] = level
|
252 |
+
return levels
|
253 |
+
|
254 |
+
|
255 |
+
class _LoggerLevelsSerializer(object):
|
256 |
+
"""Serializer for --logger_levels flag."""
|
257 |
+
|
258 |
+
def serialize(self, value):
|
259 |
+
if isinstance(value, str):
|
260 |
+
return value
|
261 |
+
return ','.join(
|
262 |
+
'{}:{}'.format(name, level) for name, level in value.items())
|
263 |
+
|
264 |
+
|
265 |
+
class _StderrthresholdFlag(flags.Flag):
|
266 |
+
"""Flag class for --stderrthreshold."""
|
267 |
+
|
268 |
+
def __init__(self, *args, **kwargs):
|
269 |
+
super(_StderrthresholdFlag, self).__init__(
|
270 |
+
flags.ArgumentParser(),
|
271 |
+
flags.ArgumentSerializer(),
|
272 |
+
*args, **kwargs)
|
273 |
+
|
274 |
+
@property
|
275 |
+
def value(self):
|
276 |
+
return self._value
|
277 |
+
|
278 |
+
@value.setter
|
279 |
+
def value(self, v):
|
280 |
+
if v in _CPP_LEVEL_TO_NAMES:
|
281 |
+
# --stderrthreshold also accepts numeric strings whose values are
|
282 |
+
# Abseil C++ log levels.
|
283 |
+
cpp_value = int(v)
|
284 |
+
v = _CPP_LEVEL_TO_NAMES[v] # Normalize to strings.
|
285 |
+
elif v.lower() in _CPP_NAME_TO_LEVELS:
|
286 |
+
v = v.lower()
|
287 |
+
if v == 'warn':
|
288 |
+
v = 'warning' # Use 'warning' as the canonical name.
|
289 |
+
cpp_value = int(_CPP_NAME_TO_LEVELS[v])
|
290 |
+
else:
|
291 |
+
raise ValueError(
|
292 |
+
'--stderrthreshold must be one of (case-insensitive) '
|
293 |
+
"'debug', 'info', 'warning', 'error', 'fatal', "
|
294 |
+
"or '0', '1', '2', '3', not '%s'" % v)
|
295 |
+
|
296 |
+
self._value = v
|
297 |
+
|
298 |
+
|
299 |
+
LOGTOSTDERR = flags.DEFINE_boolean(
|
300 |
+
'logtostderr',
|
301 |
+
False,
|
302 |
+
'Should only log to stderr?',
|
303 |
+
allow_override_cpp=True,
|
304 |
+
)
|
305 |
+
ALSOLOGTOSTDERR = flags.DEFINE_boolean(
|
306 |
+
'alsologtostderr',
|
307 |
+
False,
|
308 |
+
'also log to stderr?',
|
309 |
+
allow_override_cpp=True,
|
310 |
+
)
|
311 |
+
LOG_DIR = flags.DEFINE_string(
|
312 |
+
'log_dir',
|
313 |
+
os.getenv('TEST_TMPDIR', ''),
|
314 |
+
'directory to write logfiles into',
|
315 |
+
allow_override_cpp=True,
|
316 |
+
)
|
317 |
+
VERBOSITY = flags.DEFINE_flag(
|
318 |
+
_VerbosityFlag(
|
319 |
+
'verbosity',
|
320 |
+
-1,
|
321 |
+
(
|
322 |
+
'Logging verbosity level. Messages logged at this level or lower'
|
323 |
+
' will be included. Set to 1 for debug logging. If the flag was not'
|
324 |
+
' set or supplied, the value will be changed from the default of -1'
|
325 |
+
' (warning) to 0 (info) after flags are parsed.'
|
326 |
+
),
|
327 |
+
short_name='v',
|
328 |
+
allow_hide_cpp=True,
|
329 |
+
)
|
330 |
+
)
|
331 |
+
LOGGER_LEVELS = flags.DEFINE_flag(
|
332 |
+
_LoggerLevelsFlag(
|
333 |
+
'logger_levels',
|
334 |
+
{},
|
335 |
+
(
|
336 |
+
'Specify log level of loggers. The format is a CSV list of '
|
337 |
+
'`name:level`. Where `name` is the logger name used with '
|
338 |
+
'`logging.getLogger()`, and `level` is a level name (INFO, DEBUG, '
|
339 |
+
'etc). e.g. `myapp.foo:INFO,other.logger:DEBUG`'
|
340 |
+
),
|
341 |
+
)
|
342 |
+
)
|
343 |
+
STDERRTHRESHOLD = flags.DEFINE_flag(
|
344 |
+
_StderrthresholdFlag(
|
345 |
+
'stderrthreshold',
|
346 |
+
'fatal',
|
347 |
+
(
|
348 |
+
'log messages at this level, or more severe, to stderr in '
|
349 |
+
'addition to the logfile. Possible values are '
|
350 |
+
"'debug', 'info', 'warning', 'error', and 'fatal'. "
|
351 |
+
'Obsoletes --alsologtostderr. Using --alsologtostderr '
|
352 |
+
'cancels the effect of this flag. Please also note that '
|
353 |
+
'this flag is subject to --verbosity and requires logfile '
|
354 |
+
'not be stderr.'
|
355 |
+
),
|
356 |
+
allow_hide_cpp=True,
|
357 |
+
)
|
358 |
+
)
|
359 |
+
SHOWPREFIXFORINFO = flags.DEFINE_boolean(
|
360 |
+
'showprefixforinfo',
|
361 |
+
True,
|
362 |
+
(
|
363 |
+
'If False, do not prepend prefix to info messages '
|
364 |
+
"when it's logged to stderr, "
|
365 |
+
'--verbosity is set to INFO level, '
|
366 |
+
'and python logging is used.'
|
367 |
+
),
|
368 |
+
)
|
369 |
+
|
370 |
+
|
371 |
+
def get_verbosity():
|
372 |
+
"""Returns the logging verbosity."""
|
373 |
+
return FLAGS['verbosity'].value
|
374 |
+
|
375 |
+
|
376 |
+
def set_verbosity(v):
|
377 |
+
"""Sets the logging verbosity.
|
378 |
+
|
379 |
+
Causes all messages of level <= v to be logged,
|
380 |
+
and all messages of level > v to be silently discarded.
|
381 |
+
|
382 |
+
Args:
|
383 |
+
v: int|str, the verbosity level as an integer or string. Legal string values
|
384 |
+
are those that can be coerced to an integer as well as case-insensitive
|
385 |
+
'debug', 'info', 'warning', 'error', and 'fatal'.
|
386 |
+
"""
|
387 |
+
try:
|
388 |
+
new_level = int(v)
|
389 |
+
except ValueError:
|
390 |
+
new_level = converter.ABSL_NAMES[v.upper()]
|
391 |
+
FLAGS.verbosity = new_level
|
392 |
+
|
393 |
+
|
394 |
+
def set_stderrthreshold(s):
|
395 |
+
"""Sets the stderr threshold to the value passed in.
|
396 |
+
|
397 |
+
Args:
|
398 |
+
s: str|int, valid strings values are case-insensitive 'debug',
|
399 |
+
'info', 'warning', 'error', and 'fatal'; valid integer values are
|
400 |
+
logging.DEBUG|INFO|WARNING|ERROR|FATAL.
|
401 |
+
|
402 |
+
Raises:
|
403 |
+
ValueError: Raised when s is an invalid value.
|
404 |
+
"""
|
405 |
+
if s in converter.ABSL_LEVELS:
|
406 |
+
FLAGS.stderrthreshold = converter.ABSL_LEVELS[s]
|
407 |
+
elif isinstance(s, str) and s.upper() in converter.ABSL_NAMES:
|
408 |
+
FLAGS.stderrthreshold = s
|
409 |
+
else:
|
410 |
+
raise ValueError(
|
411 |
+
'set_stderrthreshold only accepts integer absl logging level '
|
412 |
+
'from -3 to 1, or case-insensitive string values '
|
413 |
+
"'debug', 'info', 'warning', 'error', and 'fatal'. "
|
414 |
+
'But found "{}" ({}).'.format(s, type(s)))
|
415 |
+
|
416 |
+
|
417 |
+
def fatal(msg, *args, **kwargs):
|
418 |
+
# type: (Any, Any, Any) -> NoReturn
|
419 |
+
"""Logs a fatal message."""
|
420 |
+
log(FATAL, msg, *args, **kwargs)
|
421 |
+
|
422 |
+
|
423 |
+
def error(msg, *args, **kwargs):
|
424 |
+
"""Logs an error message."""
|
425 |
+
log(ERROR, msg, *args, **kwargs)
|
426 |
+
|
427 |
+
|
428 |
+
def warning(msg, *args, **kwargs):
|
429 |
+
"""Logs a warning message."""
|
430 |
+
log(WARNING, msg, *args, **kwargs)
|
431 |
+
|
432 |
+
|
433 |
+
def warn(msg, *args, **kwargs):
|
434 |
+
"""Deprecated, use 'warning' instead."""
|
435 |
+
warnings.warn("The 'warn' function is deprecated, use 'warning' instead",
|
436 |
+
DeprecationWarning, 2)
|
437 |
+
log(WARNING, msg, *args, **kwargs)
|
438 |
+
|
439 |
+
|
440 |
+
def info(msg, *args, **kwargs):
|
441 |
+
"""Logs an info message."""
|
442 |
+
log(INFO, msg, *args, **kwargs)
|
443 |
+
|
444 |
+
|
445 |
+
def debug(msg, *args, **kwargs):
|
446 |
+
"""Logs a debug message."""
|
447 |
+
log(DEBUG, msg, *args, **kwargs)
|
448 |
+
|
449 |
+
|
450 |
+
def exception(msg, *args, exc_info=True, **kwargs):
|
451 |
+
"""Logs an exception, with traceback and message."""
|
452 |
+
error(msg, *args, exc_info=exc_info, **kwargs)
|
453 |
+
|
454 |
+
|
455 |
+
# Counter to keep track of number of log entries per token.
|
456 |
+
_log_counter_per_token = {}
|
457 |
+
|
458 |
+
|
459 |
+
def _get_next_log_count_per_token(token):
|
460 |
+
"""Wrapper for _log_counter_per_token. Thread-safe.
|
461 |
+
|
462 |
+
Args:
|
463 |
+
token: The token for which to look up the count.
|
464 |
+
|
465 |
+
Returns:
|
466 |
+
The number of times this function has been called with
|
467 |
+
*token* as an argument (starting at 0).
|
468 |
+
"""
|
469 |
+
# Can't use a defaultdict because defaultdict isn't atomic, whereas
|
470 |
+
# setdefault is.
|
471 |
+
return next(_log_counter_per_token.setdefault(token, itertools.count()))
|
472 |
+
|
473 |
+
|
474 |
+
def log_every_n(level, msg, n, *args):
|
475 |
+
"""Logs ``msg % args`` at level 'level' once per 'n' times.
|
476 |
+
|
477 |
+
Logs the 1st call, (N+1)st call, (2N+1)st call, etc.
|
478 |
+
Not threadsafe.
|
479 |
+
|
480 |
+
Args:
|
481 |
+
level: int, the absl logging level at which to log.
|
482 |
+
msg: str, the message to be logged.
|
483 |
+
n: int, the number of times this should be called before it is logged.
|
484 |
+
*args: The args to be substituted into the msg.
|
485 |
+
"""
|
486 |
+
count = _get_next_log_count_per_token(get_absl_logger().findCaller())
|
487 |
+
log_if(level, msg, not (count % n), *args)
|
488 |
+
|
489 |
+
|
490 |
+
# Keeps track of the last log time of the given token.
|
491 |
+
# Note: must be a dict since set/get is atomic in CPython.
|
492 |
+
# Note: entries are never released as their number is expected to be low.
|
493 |
+
_log_timer_per_token = {}
|
494 |
+
|
495 |
+
|
496 |
+
def _seconds_have_elapsed(token, num_seconds):
|
497 |
+
"""Tests if 'num_seconds' have passed since 'token' was requested.
|
498 |
+
|
499 |
+
Not strictly thread-safe - may log with the wrong frequency if called
|
500 |
+
concurrently from multiple threads. Accuracy depends on resolution of
|
501 |
+
'timeit.default_timer()'.
|
502 |
+
|
503 |
+
Always returns True on the first call for a given 'token'.
|
504 |
+
|
505 |
+
Args:
|
506 |
+
token: The token for which to look up the count.
|
507 |
+
num_seconds: The number of seconds to test for.
|
508 |
+
|
509 |
+
Returns:
|
510 |
+
Whether it has been >= 'num_seconds' since 'token' was last requested.
|
511 |
+
"""
|
512 |
+
now = timeit.default_timer()
|
513 |
+
then = _log_timer_per_token.get(token, None)
|
514 |
+
if then is None or (now - then) >= num_seconds:
|
515 |
+
_log_timer_per_token[token] = now
|
516 |
+
return True
|
517 |
+
else:
|
518 |
+
return False
|
519 |
+
|
520 |
+
|
521 |
+
def log_every_n_seconds(level, msg, n_seconds, *args):
|
522 |
+
"""Logs ``msg % args`` at level ``level`` iff ``n_seconds`` elapsed since last call.
|
523 |
+
|
524 |
+
Logs the first call, logs subsequent calls if 'n' seconds have elapsed since
|
525 |
+
the last logging call from the same call site (file + line). Not thread-safe.
|
526 |
+
|
527 |
+
Args:
|
528 |
+
level: int, the absl logging level at which to log.
|
529 |
+
msg: str, the message to be logged.
|
530 |
+
n_seconds: float or int, seconds which should elapse before logging again.
|
531 |
+
*args: The args to be substituted into the msg.
|
532 |
+
"""
|
533 |
+
should_log = _seconds_have_elapsed(get_absl_logger().findCaller(), n_seconds)
|
534 |
+
log_if(level, msg, should_log, *args)
|
535 |
+
|
536 |
+
|
537 |
+
def log_first_n(level, msg, n, *args):
|
538 |
+
"""Logs ``msg % args`` at level ``level`` only first ``n`` times.
|
539 |
+
|
540 |
+
Not threadsafe.
|
541 |
+
|
542 |
+
Args:
|
543 |
+
level: int, the absl logging level at which to log.
|
544 |
+
msg: str, the message to be logged.
|
545 |
+
n: int, the maximal number of times the message is logged.
|
546 |
+
*args: The args to be substituted into the msg.
|
547 |
+
"""
|
548 |
+
count = _get_next_log_count_per_token(get_absl_logger().findCaller())
|
549 |
+
log_if(level, msg, count < n, *args)
|
550 |
+
|
551 |
+
|
552 |
+
def log_if(level, msg, condition, *args):
|
553 |
+
"""Logs ``msg % args`` at level ``level`` only if condition is fulfilled."""
|
554 |
+
if condition:
|
555 |
+
log(level, msg, *args)
|
556 |
+
|
557 |
+
|
558 |
+
def log(level, msg, *args, **kwargs):
|
559 |
+
"""Logs ``msg % args`` at absl logging level ``level``.
|
560 |
+
|
561 |
+
If no args are given just print msg, ignoring any interpolation specifiers.
|
562 |
+
|
563 |
+
Args:
|
564 |
+
level: int, the absl logging level at which to log the message
|
565 |
+
(logging.DEBUG|INFO|WARNING|ERROR|FATAL). While some C++ verbose logging
|
566 |
+
level constants are also supported, callers should prefer explicit
|
567 |
+
logging.vlog() calls for such purpose.
|
568 |
+
|
569 |
+
msg: str, the message to be logged.
|
570 |
+
*args: The args to be substituted into the msg.
|
571 |
+
**kwargs: May contain exc_info to add exception traceback to message.
|
572 |
+
"""
|
573 |
+
if level > converter.ABSL_DEBUG:
|
574 |
+
# Even though this function supports level that is greater than 1, users
|
575 |
+
# should use logging.vlog instead for such cases.
|
576 |
+
# Treat this as vlog, 1 is equivalent to DEBUG.
|
577 |
+
standard_level = converter.STANDARD_DEBUG - (level - 1)
|
578 |
+
else:
|
579 |
+
if level < converter.ABSL_FATAL:
|
580 |
+
level = converter.ABSL_FATAL
|
581 |
+
standard_level = converter.absl_to_standard(level)
|
582 |
+
|
583 |
+
# Match standard logging's behavior. Before use_absl_handler() and
|
584 |
+
# logging is configured, there is no handler attached on _absl_logger nor
|
585 |
+
# logging.root. So logs go no where.
|
586 |
+
if not logging.root.handlers:
|
587 |
+
logging.basicConfig()
|
588 |
+
|
589 |
+
_absl_logger.log(standard_level, msg, *args, **kwargs)
|
590 |
+
|
591 |
+
|
592 |
+
def vlog(level, msg, *args, **kwargs):
|
593 |
+
"""Log ``msg % args`` at C++ vlog level ``level``.
|
594 |
+
|
595 |
+
Args:
|
596 |
+
level: int, the C++ verbose logging level at which to log the message,
|
597 |
+
e.g. 1, 2, 3, 4... While absl level constants are also supported,
|
598 |
+
callers should prefer logging.log|debug|info|... calls for such purpose.
|
599 |
+
msg: str, the message to be logged.
|
600 |
+
*args: The args to be substituted into the msg.
|
601 |
+
**kwargs: May contain exc_info to add exception traceback to message.
|
602 |
+
"""
|
603 |
+
log(level, msg, *args, **kwargs)
|
604 |
+
|
605 |
+
|
606 |
+
def vlog_is_on(level):
|
607 |
+
"""Checks if vlog is enabled for the given level in caller's source file.
|
608 |
+
|
609 |
+
Args:
|
610 |
+
level: int, the C++ verbose logging level at which to log the message,
|
611 |
+
e.g. 1, 2, 3, 4... While absl level constants are also supported,
|
612 |
+
callers should prefer level_debug|level_info|... calls for
|
613 |
+
checking those.
|
614 |
+
|
615 |
+
Returns:
|
616 |
+
True if logging is turned on for that level.
|
617 |
+
"""
|
618 |
+
|
619 |
+
if level > converter.ABSL_DEBUG:
|
620 |
+
# Even though this function supports level that is greater than 1, users
|
621 |
+
# should use logging.vlog instead for such cases.
|
622 |
+
# Treat this as vlog, 1 is equivalent to DEBUG.
|
623 |
+
standard_level = converter.STANDARD_DEBUG - (level - 1)
|
624 |
+
else:
|
625 |
+
if level < converter.ABSL_FATAL:
|
626 |
+
level = converter.ABSL_FATAL
|
627 |
+
standard_level = converter.absl_to_standard(level)
|
628 |
+
return _absl_logger.isEnabledFor(standard_level)
|
629 |
+
|
630 |
+
|
631 |
+
def flush():
|
632 |
+
"""Flushes all log files."""
|
633 |
+
get_absl_handler().flush()
|
634 |
+
|
635 |
+
|
636 |
+
def level_debug():
|
637 |
+
"""Returns True if debug logging is turned on."""
|
638 |
+
return get_verbosity() >= DEBUG
|
639 |
+
|
640 |
+
|
641 |
+
def level_info():
|
642 |
+
"""Returns True if info logging is turned on."""
|
643 |
+
return get_verbosity() >= INFO
|
644 |
+
|
645 |
+
|
646 |
+
def level_warning():
|
647 |
+
"""Returns True if warning logging is turned on."""
|
648 |
+
return get_verbosity() >= WARNING
|
649 |
+
|
650 |
+
|
651 |
+
level_warn = level_warning # Deprecated function.
|
652 |
+
|
653 |
+
|
654 |
+
def level_error():
|
655 |
+
"""Returns True if error logging is turned on."""
|
656 |
+
return get_verbosity() >= ERROR
|
657 |
+
|
658 |
+
|
659 |
+
def get_log_file_name(level=INFO):
|
660 |
+
"""Returns the name of the log file.
|
661 |
+
|
662 |
+
For Python logging, only one file is used and level is ignored. And it returns
|
663 |
+
empty string if it logs to stderr/stdout or the log stream has no `name`
|
664 |
+
attribute.
|
665 |
+
|
666 |
+
Args:
|
667 |
+
level: int, the absl.logging level.
|
668 |
+
|
669 |
+
Raises:
|
670 |
+
ValueError: Raised when `level` has an invalid value.
|
671 |
+
"""
|
672 |
+
if level not in converter.ABSL_LEVELS:
|
673 |
+
raise ValueError('Invalid absl.logging level {}'.format(level))
|
674 |
+
stream = get_absl_handler().python_handler.stream
|
675 |
+
if (stream == sys.stderr or stream == sys.stdout or
|
676 |
+
not hasattr(stream, 'name')):
|
677 |
+
return ''
|
678 |
+
else:
|
679 |
+
return stream.name
|
680 |
+
|
681 |
+
|
682 |
+
def find_log_dir_and_names(program_name=None, log_dir=None):
|
683 |
+
"""Computes the directory and filename prefix for log file.
|
684 |
+
|
685 |
+
Args:
|
686 |
+
program_name: str|None, the filename part of the path to the program that
|
687 |
+
is running without its extension. e.g: if your program is called
|
688 |
+
``usr/bin/foobar.py`` this method should probably be called with
|
689 |
+
``program_name='foobar`` However, this is just a convention, you can
|
690 |
+
pass in any string you want, and it will be used as part of the
|
691 |
+
log filename. If you don't pass in anything, the default behavior
|
692 |
+
is as described in the example. In python standard logging mode,
|
693 |
+
the program_name will be prepended with ``py_`` if it is the
|
694 |
+
``program_name`` argument is omitted.
|
695 |
+
log_dir: str|None, the desired log directory.
|
696 |
+
|
697 |
+
Returns:
|
698 |
+
(log_dir, file_prefix, symlink_prefix)
|
699 |
+
|
700 |
+
Raises:
|
701 |
+
FileNotFoundError: raised in Python 3 when it cannot find a log directory.
|
702 |
+
OSError: raised in Python 2 when it cannot find a log directory.
|
703 |
+
"""
|
704 |
+
if not program_name:
|
705 |
+
# Strip the extension (foobar.par becomes foobar, and
|
706 |
+
# fubar.py becomes fubar). We do this so that the log
|
707 |
+
# file names are similar to C++ log file names.
|
708 |
+
program_name = os.path.splitext(os.path.basename(sys.argv[0]))[0]
|
709 |
+
|
710 |
+
# Prepend py_ to files so that python code gets a unique file, and
|
711 |
+
# so that C++ libraries do not try to write to the same log files as us.
|
712 |
+
program_name = 'py_%s' % program_name
|
713 |
+
|
714 |
+
actual_log_dir = find_log_dir(log_dir=log_dir)
|
715 |
+
|
716 |
+
try:
|
717 |
+
username = getpass.getuser()
|
718 |
+
except KeyError:
|
719 |
+
# This can happen, e.g. when running under docker w/o passwd file.
|
720 |
+
if hasattr(os, 'getuid'):
|
721 |
+
# Windows doesn't have os.getuid
|
722 |
+
username = str(os.getuid())
|
723 |
+
else:
|
724 |
+
username = 'unknown'
|
725 |
+
hostname = socket.gethostname()
|
726 |
+
file_prefix = '%s.%s.%s.log' % (program_name, hostname, username)
|
727 |
+
|
728 |
+
return actual_log_dir, file_prefix, program_name
|
729 |
+
|
730 |
+
|
731 |
+
def find_log_dir(log_dir=None):
|
732 |
+
"""Returns the most suitable directory to put log files into.
|
733 |
+
|
734 |
+
Args:
|
735 |
+
log_dir: str|None, if specified, the logfile(s) will be created in that
|
736 |
+
directory. Otherwise if the --log_dir command-line flag is provided,
|
737 |
+
the logfile will be created in that directory. Otherwise the logfile
|
738 |
+
will be created in a standard location.
|
739 |
+
|
740 |
+
Raises:
|
741 |
+
FileNotFoundError: raised in Python 3 when it cannot find a log directory.
|
742 |
+
OSError: raised in Python 2 when it cannot find a log directory.
|
743 |
+
"""
|
744 |
+
# Get a list of possible log dirs (will try to use them in order).
|
745 |
+
# NOTE: Google's internal implementation has a special handling for Google
|
746 |
+
# machines, which uses a list of directories. Hence the following uses `dirs`
|
747 |
+
# instead of a single directory.
|
748 |
+
if log_dir:
|
749 |
+
# log_dir was explicitly specified as an arg, so use it and it alone.
|
750 |
+
dirs = [log_dir]
|
751 |
+
elif FLAGS['log_dir'].value:
|
752 |
+
# log_dir flag was provided, so use it and it alone (this mimics the
|
753 |
+
# behavior of the same flag in logging.cc).
|
754 |
+
dirs = [FLAGS['log_dir'].value]
|
755 |
+
else:
|
756 |
+
dirs = [tempfile.gettempdir()]
|
757 |
+
|
758 |
+
# Find the first usable log dir.
|
759 |
+
for d in dirs:
|
760 |
+
if os.path.isdir(d) and os.access(d, os.W_OK):
|
761 |
+
return d
|
762 |
+
raise FileNotFoundError(
|
763 |
+
"Can't find a writable directory for logs, tried %s" % dirs)
|
764 |
+
|
765 |
+
|
766 |
+
def get_absl_log_prefix(record):
|
767 |
+
"""Returns the absl log prefix for the log record.
|
768 |
+
|
769 |
+
Args:
|
770 |
+
record: logging.LogRecord, the record to get prefix for.
|
771 |
+
"""
|
772 |
+
created_tuple = time.localtime(record.created)
|
773 |
+
created_microsecond = int(record.created % 1.0 * 1e6)
|
774 |
+
|
775 |
+
critical_prefix = ''
|
776 |
+
level = record.levelno
|
777 |
+
if _is_non_absl_fatal_record(record):
|
778 |
+
# When the level is FATAL, but not logged from absl, lower the level so
|
779 |
+
# it's treated as ERROR.
|
780 |
+
level = logging.ERROR
|
781 |
+
critical_prefix = _CRITICAL_PREFIX
|
782 |
+
severity = converter.get_initial_for_level(level)
|
783 |
+
|
784 |
+
return '%c%02d%02d %02d:%02d:%02d.%06d %5d %s:%d] %s' % (
|
785 |
+
severity,
|
786 |
+
created_tuple.tm_mon,
|
787 |
+
created_tuple.tm_mday,
|
788 |
+
created_tuple.tm_hour,
|
789 |
+
created_tuple.tm_min,
|
790 |
+
created_tuple.tm_sec,
|
791 |
+
created_microsecond,
|
792 |
+
_get_thread_id(),
|
793 |
+
record.filename,
|
794 |
+
record.lineno,
|
795 |
+
critical_prefix)
|
796 |
+
|
797 |
+
|
798 |
+
def skip_log_prefix(func):
|
799 |
+
"""Skips reporting the prefix of a given function or name by :class:`~absl.logging.ABSLLogger`.
|
800 |
+
|
801 |
+
This is a convenience wrapper function / decorator for
|
802 |
+
:meth:`~absl.logging.ABSLLogger.register_frame_to_skip`.
|
803 |
+
|
804 |
+
If a callable function is provided, only that function will be skipped.
|
805 |
+
If a function name is provided, all functions with the same name in the
|
806 |
+
file that this is called in will be skipped.
|
807 |
+
|
808 |
+
This can be used as a decorator of the intended function to be skipped.
|
809 |
+
|
810 |
+
Args:
|
811 |
+
func: Callable function or its name as a string.
|
812 |
+
|
813 |
+
Returns:
|
814 |
+
func (the input, unchanged).
|
815 |
+
|
816 |
+
Raises:
|
817 |
+
ValueError: The input is callable but does not have a function code object.
|
818 |
+
TypeError: The input is neither callable nor a string.
|
819 |
+
"""
|
820 |
+
if callable(func):
|
821 |
+
func_code = getattr(func, '__code__', None)
|
822 |
+
if func_code is None:
|
823 |
+
raise ValueError('Input callable does not have a function code object.')
|
824 |
+
file_name = func_code.co_filename
|
825 |
+
func_name = func_code.co_name
|
826 |
+
func_lineno = func_code.co_firstlineno
|
827 |
+
elif isinstance(func, str):
|
828 |
+
file_name = get_absl_logger().findCaller()[0]
|
829 |
+
func_name = func
|
830 |
+
func_lineno = None
|
831 |
+
else:
|
832 |
+
raise TypeError('Input is neither callable nor a string.')
|
833 |
+
ABSLLogger.register_frame_to_skip(file_name, func_name, func_lineno)
|
834 |
+
return func
|
835 |
+
|
836 |
+
|
837 |
+
def _is_non_absl_fatal_record(log_record):
|
838 |
+
return (log_record.levelno >= logging.FATAL and
|
839 |
+
not log_record.__dict__.get(_ABSL_LOG_FATAL, False))
|
840 |
+
|
841 |
+
|
842 |
+
def _is_absl_fatal_record(log_record):
|
843 |
+
return (log_record.levelno >= logging.FATAL and
|
844 |
+
log_record.__dict__.get(_ABSL_LOG_FATAL, False))
|
845 |
+
|
846 |
+
|
847 |
+
# Indicates if we still need to warn about pre-init logs going to stderr.
|
848 |
+
_warn_preinit_stderr = True
|
849 |
+
|
850 |
+
|
851 |
+
class PythonHandler(logging.StreamHandler):
|
852 |
+
"""The handler class used by Abseil Python logging implementation."""
|
853 |
+
|
854 |
+
def __init__(self, stream=None, formatter=None):
|
855 |
+
super(PythonHandler, self).__init__(stream)
|
856 |
+
self.setFormatter(formatter or PythonFormatter())
|
857 |
+
|
858 |
+
def start_logging_to_file(self, program_name=None, log_dir=None):
|
859 |
+
"""Starts logging messages to files instead of standard error."""
|
860 |
+
FLAGS.logtostderr = False
|
861 |
+
|
862 |
+
actual_log_dir, file_prefix, symlink_prefix = find_log_dir_and_names(
|
863 |
+
program_name=program_name, log_dir=log_dir)
|
864 |
+
|
865 |
+
basename = '%s.INFO.%s.%d' % (
|
866 |
+
file_prefix,
|
867 |
+
time.strftime('%Y%m%d-%H%M%S', time.localtime(time.time())),
|
868 |
+
os.getpid())
|
869 |
+
filename = os.path.join(actual_log_dir, basename)
|
870 |
+
|
871 |
+
self.stream = open(filename, 'a', encoding='utf-8')
|
872 |
+
|
873 |
+
# os.symlink is not available on Windows Python 2.
|
874 |
+
if getattr(os, 'symlink', None):
|
875 |
+
# Create a symlink to the log file with a canonical name.
|
876 |
+
symlink = os.path.join(actual_log_dir, symlink_prefix + '.INFO')
|
877 |
+
try:
|
878 |
+
if os.path.islink(symlink):
|
879 |
+
os.unlink(symlink)
|
880 |
+
os.symlink(os.path.basename(filename), symlink)
|
881 |
+
except EnvironmentError:
|
882 |
+
# If it fails, we're sad but it's no error. Commonly, this
|
883 |
+
# fails because the symlink was created by another user and so
|
884 |
+
# we can't modify it
|
885 |
+
pass
|
886 |
+
|
887 |
+
def use_absl_log_file(self, program_name=None, log_dir=None):
|
888 |
+
"""Conditionally logs to files, based on --logtostderr."""
|
889 |
+
if FLAGS['logtostderr'].value:
|
890 |
+
self.stream = sys.stderr
|
891 |
+
else:
|
892 |
+
self.start_logging_to_file(program_name=program_name, log_dir=log_dir)
|
893 |
+
|
894 |
+
def flush(self):
|
895 |
+
"""Flushes all log files."""
|
896 |
+
self.acquire()
|
897 |
+
try:
|
898 |
+
if self.stream and hasattr(self.stream, 'flush'):
|
899 |
+
self.stream.flush()
|
900 |
+
except (EnvironmentError, ValueError):
|
901 |
+
# A ValueError is thrown if we try to flush a closed file.
|
902 |
+
pass
|
903 |
+
finally:
|
904 |
+
self.release()
|
905 |
+
|
906 |
+
def _log_to_stderr(self, record):
|
907 |
+
"""Emits the record to stderr.
|
908 |
+
|
909 |
+
This temporarily sets the handler stream to stderr, calls
|
910 |
+
StreamHandler.emit, then reverts the stream back.
|
911 |
+
|
912 |
+
Args:
|
913 |
+
record: logging.LogRecord, the record to log.
|
914 |
+
"""
|
915 |
+
# emit() is protected by a lock in logging.Handler, so we don't need to
|
916 |
+
# protect here again.
|
917 |
+
old_stream = self.stream
|
918 |
+
self.stream = sys.stderr
|
919 |
+
try:
|
920 |
+
super(PythonHandler, self).emit(record)
|
921 |
+
finally:
|
922 |
+
self.stream = old_stream
|
923 |
+
|
924 |
+
def emit(self, record):
|
925 |
+
"""Prints a record out to some streams.
|
926 |
+
|
927 |
+
1. If ``FLAGS.logtostderr`` is set, it will print to ``sys.stderr`` ONLY.
|
928 |
+
2. If ``FLAGS.alsologtostderr`` is set, it will print to ``sys.stderr``.
|
929 |
+
3. If ``FLAGS.logtostderr`` is not set, it will log to the stream
|
930 |
+
associated with the current thread.
|
931 |
+
|
932 |
+
Args:
|
933 |
+
record: :class:`logging.LogRecord`, the record to emit.
|
934 |
+
"""
|
935 |
+
# People occasionally call logging functions at import time before
|
936 |
+
# our flags may have even been defined yet, let alone even parsed, as we
|
937 |
+
# rely on the C++ side to define some flags for us and app init to
|
938 |
+
# deal with parsing. Match the C++ library behavior of notify and emit
|
939 |
+
# such messages to stderr. It encourages people to clean-up and does
|
940 |
+
# not hide the message.
|
941 |
+
level = record.levelno
|
942 |
+
if not FLAGS.is_parsed(): # Also implies "before flag has been defined".
|
943 |
+
global _warn_preinit_stderr
|
944 |
+
if _warn_preinit_stderr:
|
945 |
+
sys.stderr.write(
|
946 |
+
'WARNING: Logging before flag parsing goes to stderr.\n')
|
947 |
+
_warn_preinit_stderr = False
|
948 |
+
self._log_to_stderr(record)
|
949 |
+
elif FLAGS['logtostderr'].value:
|
950 |
+
self._log_to_stderr(record)
|
951 |
+
else:
|
952 |
+
super(PythonHandler, self).emit(record)
|
953 |
+
stderr_threshold = converter.string_to_standard(
|
954 |
+
FLAGS['stderrthreshold'].value)
|
955 |
+
if ((FLAGS['alsologtostderr'].value or level >= stderr_threshold) and
|
956 |
+
self.stream != sys.stderr):
|
957 |
+
self._log_to_stderr(record)
|
958 |
+
# Die when the record is created from ABSLLogger and level is FATAL.
|
959 |
+
if _is_absl_fatal_record(record):
|
960 |
+
self.flush() # Flush the log before dying.
|
961 |
+
|
962 |
+
# In threaded python, sys.exit() from a non-main thread only
|
963 |
+
# exits the thread in question.
|
964 |
+
os.abort()
|
965 |
+
|
966 |
+
def close(self):
|
967 |
+
"""Closes the stream to which we are writing."""
|
968 |
+
self.acquire()
|
969 |
+
try:
|
970 |
+
self.flush()
|
971 |
+
try:
|
972 |
+
# Do not close the stream if it's sys.stderr|stdout. They may be
|
973 |
+
# redirected or overridden to files, which should be managed by users
|
974 |
+
# explicitly.
|
975 |
+
user_managed = sys.stderr, sys.stdout, sys.__stderr__, sys.__stdout__
|
976 |
+
if self.stream not in user_managed and (
|
977 |
+
not hasattr(self.stream, 'isatty') or not self.stream.isatty()):
|
978 |
+
self.stream.close()
|
979 |
+
except ValueError:
|
980 |
+
# A ValueError is thrown if we try to run isatty() on a closed file.
|
981 |
+
pass
|
982 |
+
super(PythonHandler, self).close()
|
983 |
+
finally:
|
984 |
+
self.release()
|
985 |
+
|
986 |
+
|
987 |
+
class ABSLHandler(logging.Handler):
|
988 |
+
"""Abseil Python logging module's log handler."""
|
989 |
+
|
990 |
+
def __init__(self, python_logging_formatter):
|
991 |
+
super(ABSLHandler, self).__init__()
|
992 |
+
|
993 |
+
self._python_handler = PythonHandler(formatter=python_logging_formatter)
|
994 |
+
self.activate_python_handler()
|
995 |
+
|
996 |
+
def format(self, record):
|
997 |
+
return self._current_handler.format(record)
|
998 |
+
|
999 |
+
def setFormatter(self, fmt):
|
1000 |
+
self._current_handler.setFormatter(fmt)
|
1001 |
+
|
1002 |
+
def emit(self, record):
|
1003 |
+
self._current_handler.emit(record)
|
1004 |
+
|
1005 |
+
def flush(self):
|
1006 |
+
self._current_handler.flush()
|
1007 |
+
|
1008 |
+
def close(self):
|
1009 |
+
super(ABSLHandler, self).close()
|
1010 |
+
self._current_handler.close()
|
1011 |
+
|
1012 |
+
def handle(self, record):
|
1013 |
+
rv = self.filter(record)
|
1014 |
+
if rv:
|
1015 |
+
return self._current_handler.handle(record)
|
1016 |
+
return rv
|
1017 |
+
|
1018 |
+
@property
|
1019 |
+
def python_handler(self):
|
1020 |
+
return self._python_handler
|
1021 |
+
|
1022 |
+
def activate_python_handler(self):
|
1023 |
+
"""Uses the Python logging handler as the current logging handler."""
|
1024 |
+
self._current_handler = self._python_handler
|
1025 |
+
|
1026 |
+
def use_absl_log_file(self, program_name=None, log_dir=None):
|
1027 |
+
self._current_handler.use_absl_log_file(program_name, log_dir)
|
1028 |
+
|
1029 |
+
def start_logging_to_file(self, program_name=None, log_dir=None):
|
1030 |
+
self._current_handler.start_logging_to_file(program_name, log_dir)
|
1031 |
+
|
1032 |
+
|
1033 |
+
class PythonFormatter(logging.Formatter):
|
1034 |
+
"""Formatter class used by :class:`~absl.logging.PythonHandler`."""
|
1035 |
+
|
1036 |
+
def format(self, record):
|
1037 |
+
"""Appends the message from the record to the results of the prefix.
|
1038 |
+
|
1039 |
+
Args:
|
1040 |
+
record: logging.LogRecord, the record to be formatted.
|
1041 |
+
|
1042 |
+
Returns:
|
1043 |
+
The formatted string representing the record.
|
1044 |
+
"""
|
1045 |
+
if (not FLAGS['showprefixforinfo'].value and
|
1046 |
+
FLAGS['verbosity'].value == converter.ABSL_INFO and
|
1047 |
+
record.levelno == logging.INFO and
|
1048 |
+
_absl_handler.python_handler.stream == sys.stderr):
|
1049 |
+
prefix = ''
|
1050 |
+
else:
|
1051 |
+
prefix = get_absl_log_prefix(record)
|
1052 |
+
return prefix + super(PythonFormatter, self).format(record)
|
1053 |
+
|
1054 |
+
|
1055 |
+
class ABSLLogger(logging.getLoggerClass()):
|
1056 |
+
"""A logger that will create LogRecords while skipping some stack frames.
|
1057 |
+
|
1058 |
+
This class maintains an internal list of filenames and method names
|
1059 |
+
for use when determining who called the currently executing stack
|
1060 |
+
frame. Any method names from specific source files are skipped when
|
1061 |
+
walking backwards through the stack.
|
1062 |
+
|
1063 |
+
Client code should use the register_frame_to_skip method to let the
|
1064 |
+
ABSLLogger know which method from which file should be
|
1065 |
+
excluded from the walk backwards through the stack.
|
1066 |
+
"""
|
1067 |
+
_frames_to_skip = set()
|
1068 |
+
|
1069 |
+
def findCaller(self, stack_info=False, stacklevel=1):
|
1070 |
+
"""Finds the frame of the calling method on the stack.
|
1071 |
+
|
1072 |
+
This method skips any frames registered with the
|
1073 |
+
ABSLLogger and any methods from this file, and whatever
|
1074 |
+
method is currently being used to generate the prefix for the log
|
1075 |
+
line. Then it returns the file name, line number, and method name
|
1076 |
+
of the calling method. An optional fourth item may be returned,
|
1077 |
+
callers who only need things from the first three are advised to
|
1078 |
+
always slice or index the result rather than using direct unpacking
|
1079 |
+
assignment.
|
1080 |
+
|
1081 |
+
Args:
|
1082 |
+
stack_info: bool, when True, include the stack trace as a fourth item
|
1083 |
+
returned. On Python 3 there are always four items returned - the
|
1084 |
+
fourth will be None when this is False. On Python 2 the stdlib
|
1085 |
+
base class API only returns three items. We do the same when this
|
1086 |
+
new parameter is unspecified or False for compatibility.
|
1087 |
+
|
1088 |
+
Returns:
|
1089 |
+
(filename, lineno, methodname[, sinfo]) of the calling method.
|
1090 |
+
"""
|
1091 |
+
f_to_skip = ABSLLogger._frames_to_skip
|
1092 |
+
# Use sys._getframe(2) instead of logging.currentframe(), it's slightly
|
1093 |
+
# faster because there is one less frame to traverse.
|
1094 |
+
frame = sys._getframe(2) # pylint: disable=protected-access
|
1095 |
+
|
1096 |
+
while frame:
|
1097 |
+
code = frame.f_code
|
1098 |
+
if (_LOGGING_FILE_PREFIX not in code.co_filename and
|
1099 |
+
(code.co_filename, code.co_name,
|
1100 |
+
code.co_firstlineno) not in f_to_skip and
|
1101 |
+
(code.co_filename, code.co_name) not in f_to_skip):
|
1102 |
+
sinfo = None
|
1103 |
+
if stack_info:
|
1104 |
+
out = io.StringIO()
|
1105 |
+
out.write(u'Stack (most recent call last):\n')
|
1106 |
+
traceback.print_stack(frame, file=out)
|
1107 |
+
sinfo = out.getvalue().rstrip(u'\n')
|
1108 |
+
return (code.co_filename, frame.f_lineno, code.co_name, sinfo)
|
1109 |
+
frame = frame.f_back
|
1110 |
+
|
1111 |
+
def critical(self, msg, *args, **kwargs):
|
1112 |
+
"""Logs ``msg % args`` with severity ``CRITICAL``."""
|
1113 |
+
self.log(logging.CRITICAL, msg, *args, **kwargs)
|
1114 |
+
|
1115 |
+
def fatal(self, msg, *args, **kwargs):
|
1116 |
+
"""Logs ``msg % args`` with severity ``FATAL``."""
|
1117 |
+
self.log(logging.FATAL, msg, *args, **kwargs)
|
1118 |
+
|
1119 |
+
def error(self, msg, *args, **kwargs):
|
1120 |
+
"""Logs ``msg % args`` with severity ``ERROR``."""
|
1121 |
+
self.log(logging.ERROR, msg, *args, **kwargs)
|
1122 |
+
|
1123 |
+
def warn(self, msg, *args, **kwargs):
|
1124 |
+
"""Logs ``msg % args`` with severity ``WARN``."""
|
1125 |
+
warnings.warn("The 'warn' method is deprecated, use 'warning' instead",
|
1126 |
+
DeprecationWarning, 2)
|
1127 |
+
self.log(logging.WARN, msg, *args, **kwargs)
|
1128 |
+
|
1129 |
+
def warning(self, msg, *args, **kwargs):
|
1130 |
+
"""Logs ``msg % args`` with severity ``WARNING``."""
|
1131 |
+
self.log(logging.WARNING, msg, *args, **kwargs)
|
1132 |
+
|
1133 |
+
def info(self, msg, *args, **kwargs):
|
1134 |
+
"""Logs ``msg % args`` with severity ``INFO``."""
|
1135 |
+
self.log(logging.INFO, msg, *args, **kwargs)
|
1136 |
+
|
1137 |
+
def debug(self, msg, *args, **kwargs):
|
1138 |
+
"""Logs ``msg % args`` with severity ``DEBUG``."""
|
1139 |
+
self.log(logging.DEBUG, msg, *args, **kwargs)
|
1140 |
+
|
1141 |
+
def log(self, level, msg, *args, **kwargs):
|
1142 |
+
"""Logs a message at a cetain level substituting in the supplied arguments.
|
1143 |
+
|
1144 |
+
This method behaves differently in python and c++ modes.
|
1145 |
+
|
1146 |
+
Args:
|
1147 |
+
level: int, the standard logging level at which to log the message.
|
1148 |
+
msg: str, the text of the message to log.
|
1149 |
+
*args: The arguments to substitute in the message.
|
1150 |
+
**kwargs: The keyword arguments to substitute in the message.
|
1151 |
+
"""
|
1152 |
+
if level >= logging.FATAL:
|
1153 |
+
# Add property to the LogRecord created by this logger.
|
1154 |
+
# This will be used by the ABSLHandler to determine whether it should
|
1155 |
+
# treat CRITICAL/FATAL logs as really FATAL.
|
1156 |
+
extra = kwargs.setdefault('extra', {})
|
1157 |
+
extra[_ABSL_LOG_FATAL] = True
|
1158 |
+
super(ABSLLogger, self).log(level, msg, *args, **kwargs)
|
1159 |
+
|
1160 |
+
def handle(self, record):
|
1161 |
+
"""Calls handlers without checking ``Logger.disabled``.
|
1162 |
+
|
1163 |
+
Non-root loggers are set to disabled after setup with :func:`logging.config`
|
1164 |
+
if it's not explicitly specified. Historically, absl logging will not be
|
1165 |
+
disabled by that. To maintaining this behavior, this function skips
|
1166 |
+
checking the ``Logger.disabled`` bit.
|
1167 |
+
|
1168 |
+
This logger can still be disabled by adding a filter that filters out
|
1169 |
+
everything.
|
1170 |
+
|
1171 |
+
Args:
|
1172 |
+
record: logging.LogRecord, the record to handle.
|
1173 |
+
"""
|
1174 |
+
if self.filter(record):
|
1175 |
+
self.callHandlers(record)
|
1176 |
+
|
1177 |
+
@classmethod
|
1178 |
+
def register_frame_to_skip(cls, file_name, function_name, line_number=None):
|
1179 |
+
"""Registers a function name to skip when walking the stack.
|
1180 |
+
|
1181 |
+
The :class:`~absl.logging.ABSLLogger` sometimes skips method calls on the
|
1182 |
+
stack to make the log messages meaningful in their appropriate context.
|
1183 |
+
This method registers a function from a particular file as one
|
1184 |
+
which should be skipped.
|
1185 |
+
|
1186 |
+
Args:
|
1187 |
+
file_name: str, the name of the file that contains the function.
|
1188 |
+
function_name: str, the name of the function to skip.
|
1189 |
+
line_number: int, if provided, only the function with this starting line
|
1190 |
+
number will be skipped. Otherwise, all functions with the same name
|
1191 |
+
in the file will be skipped.
|
1192 |
+
"""
|
1193 |
+
if line_number is not None:
|
1194 |
+
cls._frames_to_skip.add((file_name, function_name, line_number))
|
1195 |
+
else:
|
1196 |
+
cls._frames_to_skip.add((file_name, function_name))
|
1197 |
+
|
1198 |
+
|
1199 |
+
def _get_thread_id():
|
1200 |
+
"""Gets id of current thread, suitable for logging as an unsigned quantity.
|
1201 |
+
|
1202 |
+
If pywrapbase is linked, returns GetTID() for the thread ID to be
|
1203 |
+
consistent with C++ logging. Otherwise, returns the numeric thread id.
|
1204 |
+
The quantities are made unsigned by masking with 2*sys.maxint + 1.
|
1205 |
+
|
1206 |
+
Returns:
|
1207 |
+
Thread ID unique to this process (unsigned)
|
1208 |
+
"""
|
1209 |
+
thread_id = threading.get_ident()
|
1210 |
+
return thread_id & _THREAD_ID_MASK
|
1211 |
+
|
1212 |
+
|
1213 |
+
def get_absl_logger():
|
1214 |
+
"""Returns the absl logger instance."""
|
1215 |
+
assert _absl_logger is not None
|
1216 |
+
return _absl_logger
|
1217 |
+
|
1218 |
+
|
1219 |
+
def get_absl_handler():
|
1220 |
+
"""Returns the absl handler instance."""
|
1221 |
+
assert _absl_handler is not None
|
1222 |
+
return _absl_handler
|
1223 |
+
|
1224 |
+
|
1225 |
+
def use_python_logging(quiet=False):
|
1226 |
+
"""Uses the python implementation of the logging code.
|
1227 |
+
|
1228 |
+
Args:
|
1229 |
+
quiet: No logging message about switching logging type.
|
1230 |
+
"""
|
1231 |
+
get_absl_handler().activate_python_handler()
|
1232 |
+
if not quiet:
|
1233 |
+
info('Restoring pure python logging')
|
1234 |
+
|
1235 |
+
|
1236 |
+
_attempted_to_remove_stderr_stream_handlers = False
|
1237 |
+
|
1238 |
+
|
1239 |
+
def use_absl_handler():
|
1240 |
+
"""Uses the ABSL logging handler for logging.
|
1241 |
+
|
1242 |
+
This method is called in :func:`app.run()<absl.app.run>` so the absl handler
|
1243 |
+
is used in absl apps.
|
1244 |
+
"""
|
1245 |
+
global _attempted_to_remove_stderr_stream_handlers
|
1246 |
+
if not _attempted_to_remove_stderr_stream_handlers:
|
1247 |
+
# The absl handler logs to stderr by default. To prevent double logging to
|
1248 |
+
# stderr, the following code tries its best to remove other handlers that
|
1249 |
+
# emit to stderr. Those handlers are most commonly added when
|
1250 |
+
# logging.info/debug is called before calling use_absl_handler().
|
1251 |
+
handlers = [
|
1252 |
+
h for h in logging.root.handlers
|
1253 |
+
if isinstance(h, logging.StreamHandler) and h.stream == sys.stderr]
|
1254 |
+
for h in handlers:
|
1255 |
+
logging.root.removeHandler(h)
|
1256 |
+
_attempted_to_remove_stderr_stream_handlers = True
|
1257 |
+
|
1258 |
+
absl_handler = get_absl_handler()
|
1259 |
+
if absl_handler not in logging.root.handlers:
|
1260 |
+
logging.root.addHandler(absl_handler)
|
1261 |
+
FLAGS['verbosity']._update_logging_levels() # pylint: disable=protected-access
|
1262 |
+
FLAGS['logger_levels']._update_logger_levels() # pylint: disable=protected-access
|
1263 |
+
|
1264 |
+
|
1265 |
+
def _initialize():
|
1266 |
+
"""Initializes loggers and handlers."""
|
1267 |
+
global _absl_logger, _absl_handler
|
1268 |
+
|
1269 |
+
if _absl_logger:
|
1270 |
+
return
|
1271 |
+
|
1272 |
+
original_logger_class = logging.getLoggerClass()
|
1273 |
+
logging.setLoggerClass(ABSLLogger)
|
1274 |
+
_absl_logger = logging.getLogger('absl')
|
1275 |
+
logging.setLoggerClass(original_logger_class)
|
1276 |
+
|
1277 |
+
python_logging_formatter = PythonFormatter()
|
1278 |
+
_absl_handler = ABSLHandler(python_logging_formatter)
|
1279 |
+
|
1280 |
+
|
1281 |
+
_initialize()
|
MLPY/Lib/site-packages/absl/logging/__init__.pyi
ADDED
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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, 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 |
+
|
39 |
+
def get_verbosity() -> int:
|
40 |
+
...
|
41 |
+
|
42 |
+
|
43 |
+
def set_verbosity(v: Union[int, str]) -> None:
|
44 |
+
...
|
45 |
+
|
46 |
+
|
47 |
+
def set_stderrthreshold(s: Union[int, str]) -> None:
|
48 |
+
...
|
49 |
+
|
50 |
+
|
51 |
+
# TODO(b/277607978): Provide actual args+kwargs shadowing stdlib's logging functions.
|
52 |
+
def fatal(msg: Any, *args: Any, **kwargs: Any) -> NoReturn:
|
53 |
+
...
|
54 |
+
|
55 |
+
|
56 |
+
def error(msg: Any, *args: Any, **kwargs: Any) -> None:
|
57 |
+
...
|
58 |
+
|
59 |
+
|
60 |
+
def warning(msg: Any, *args: Any, **kwargs: Any) -> None:
|
61 |
+
...
|
62 |
+
|
63 |
+
|
64 |
+
def warn(msg: Any, *args: Any, **kwargs: Any) -> None:
|
65 |
+
...
|
66 |
+
|
67 |
+
|
68 |
+
def info(msg: Any, *args: Any, **kwargs: Any) -> None:
|
69 |
+
...
|
70 |
+
|
71 |
+
|
72 |
+
def debug(msg: Any, *args: Any, **kwargs: Any) -> None:
|
73 |
+
...
|
74 |
+
|
75 |
+
|
76 |
+
def exception(msg: Any, *args: Any, **kwargs: Any) -> None:
|
77 |
+
...
|
78 |
+
|
79 |
+
|
80 |
+
def log_every_n(level: int, msg: Any, n: int, *args: Any) -> None:
|
81 |
+
...
|
82 |
+
|
83 |
+
|
84 |
+
def log_every_n_seconds(
|
85 |
+
level: int, msg: Any, n_seconds: float, *args: Any
|
86 |
+
) -> None:
|
87 |
+
...
|
88 |
+
|
89 |
+
|
90 |
+
def log_first_n(level: int, msg: Any, n: int, *args: Any) -> None:
|
91 |
+
...
|
92 |
+
|
93 |
+
|
94 |
+
def log_if(level: int, msg: Any, condition: Any, *args: Any) -> None:
|
95 |
+
...
|
96 |
+
|
97 |
+
|
98 |
+
def log(level: int, msg: Any, *args: Any, **kwargs: Any) -> None:
|
99 |
+
...
|
100 |
+
|
101 |
+
|
102 |
+
def vlog(level: int, msg: Any, *args: Any, **kwargs: Any) -> None:
|
103 |
+
...
|
104 |
+
|
105 |
+
|
106 |
+
def vlog_is_on(level: int) -> bool:
|
107 |
+
...
|
108 |
+
|
109 |
+
|
110 |
+
def flush() -> None:
|
111 |
+
...
|
112 |
+
|
113 |
+
|
114 |
+
def level_debug() -> bool:
|
115 |
+
...
|
116 |
+
|
117 |
+
|
118 |
+
def level_info() -> bool:
|
119 |
+
...
|
120 |
+
|
121 |
+
|
122 |
+
def level_warning() -> bool:
|
123 |
+
...
|
124 |
+
|
125 |
+
|
126 |
+
level_warn = level_warning # Deprecated function.
|
127 |
+
|
128 |
+
|
129 |
+
def level_error() -> bool:
|
130 |
+
...
|
131 |
+
|
132 |
+
|
133 |
+
def get_log_file_name(level: int = ...) -> str:
|
134 |
+
...
|
135 |
+
|
136 |
+
|
137 |
+
def find_log_dir_and_names(
|
138 |
+
program_name: Optional[str] = ..., log_dir: Optional[str] = ...
|
139 |
+
) -> Tuple[str, str, str]:
|
140 |
+
...
|
141 |
+
|
142 |
+
|
143 |
+
def find_log_dir(log_dir: Optional[str] = ...) -> str:
|
144 |
+
...
|
145 |
+
|
146 |
+
|
147 |
+
def get_absl_log_prefix(record: logging.LogRecord) -> str:
|
148 |
+
...
|
149 |
+
|
150 |
+
|
151 |
+
_SkipLogT = TypeVar('_SkipLogT', str, Callable[..., Any])
|
152 |
+
|
153 |
+
def skip_log_prefix(func: _SkipLogT) -> _SkipLogT:
|
154 |
+
...
|
155 |
+
|
156 |
+
|
157 |
+
_StreamT = TypeVar("_StreamT")
|
158 |
+
|
159 |
+
|
160 |
+
class PythonHandler(logging.StreamHandler[_StreamT]):
|
161 |
+
|
162 |
+
def __init__(
|
163 |
+
self,
|
164 |
+
stream: Optional[_StreamT] = ...,
|
165 |
+
formatter: Optional[logging.Formatter] = ...,
|
166 |
+
) -> None:
|
167 |
+
...
|
168 |
+
|
169 |
+
def start_logging_to_file(
|
170 |
+
self, program_name: Optional[str] = ..., log_dir: Optional[str] = ...
|
171 |
+
) -> None:
|
172 |
+
...
|
173 |
+
|
174 |
+
def use_absl_log_file(
|
175 |
+
self, program_name: Optional[str] = ..., log_dir: Optional[str] = ...
|
176 |
+
) -> None:
|
177 |
+
...
|
178 |
+
|
179 |
+
def flush(self) -> None:
|
180 |
+
...
|
181 |
+
|
182 |
+
def emit(self, record: logging.LogRecord) -> None:
|
183 |
+
...
|
184 |
+
|
185 |
+
def close(self) -> None:
|
186 |
+
...
|
187 |
+
|
188 |
+
|
189 |
+
class ABSLHandler(logging.Handler):
|
190 |
+
|
191 |
+
def __init__(self, python_logging_formatter: PythonFormatter) -> None:
|
192 |
+
...
|
193 |
+
|
194 |
+
def format(self, record: logging.LogRecord) -> str:
|
195 |
+
...
|
196 |
+
|
197 |
+
def setFormatter(self, fmt) -> None:
|
198 |
+
...
|
199 |
+
|
200 |
+
def emit(self, record: logging.LogRecord) -> None:
|
201 |
+
...
|
202 |
+
|
203 |
+
def flush(self) -> None:
|
204 |
+
...
|
205 |
+
|
206 |
+
def close(self) -> None:
|
207 |
+
...
|
208 |
+
|
209 |
+
def handle(self, record: logging.LogRecord) -> bool:
|
210 |
+
...
|
211 |
+
|
212 |
+
@property
|
213 |
+
def python_handler(self) -> PythonHandler:
|
214 |
+
...
|
215 |
+
|
216 |
+
def activate_python_handler(self) -> None:
|
217 |
+
...
|
218 |
+
|
219 |
+
def use_absl_log_file(
|
220 |
+
self, program_name: Optional[str] = ..., log_dir: Optional[str] = ...
|
221 |
+
) -> None:
|
222 |
+
...
|
223 |
+
|
224 |
+
def start_logging_to_file(self, program_name=None, log_dir=None) -> None:
|
225 |
+
...
|
226 |
+
|
227 |
+
|
228 |
+
class PythonFormatter(logging.Formatter):
|
229 |
+
|
230 |
+
def format(self, record: logging.LogRecord) -> str:
|
231 |
+
...
|
232 |
+
|
233 |
+
|
234 |
+
class ABSLLogger(logging.Logger):
|
235 |
+
|
236 |
+
def findCaller(
|
237 |
+
self, stack_info: bool = ..., stacklevel: int = ...
|
238 |
+
) -> Tuple[str, int, str, Optional[str]]:
|
239 |
+
...
|
240 |
+
|
241 |
+
def critical(self, msg: Any, *args: Any, **kwargs: Any) -> None:
|
242 |
+
...
|
243 |
+
|
244 |
+
def fatal(self, msg: Any, *args: Any, **kwargs: Any) -> NoReturn:
|
245 |
+
...
|
246 |
+
|
247 |
+
def error(self, msg: Any, *args: Any, **kwargs: Any) -> None:
|
248 |
+
...
|
249 |
+
|
250 |
+
def warn(self, msg: Any, *args: Any, **kwargs: Any) -> None:
|
251 |
+
...
|
252 |
+
|
253 |
+
def warning(self, msg: Any, *args: Any, **kwargs: Any) -> None:
|
254 |
+
...
|
255 |
+
|
256 |
+
def info(self, msg: Any, *args: Any, **kwargs: Any) -> None:
|
257 |
+
...
|
258 |
+
|
259 |
+
def debug(self, msg: Any, *args: Any, **kwargs: Any) -> None:
|
260 |
+
...
|
261 |
+
|
262 |
+
def log(self, level: int, msg: Any, *args: Any, **kwargs: Any) -> None:
|
263 |
+
...
|
264 |
+
|
265 |
+
def handle(self, record: logging.LogRecord) -> None:
|
266 |
+
...
|
267 |
+
|
268 |
+
@classmethod
|
269 |
+
def register_frame_to_skip(
|
270 |
+
cls, file_name: str, function_name: str, line_number: Optional[int] = ...
|
271 |
+
) -> None:
|
272 |
+
...
|
273 |
+
|
274 |
+
|
275 |
+
# NOTE: Returns None before _initialize called but shouldn't occur after import.
|
276 |
+
def get_absl_logger() -> ABSLLogger:
|
277 |
+
...
|
278 |
+
|
279 |
+
|
280 |
+
# NOTE: Returns None before _initialize called but shouldn't occur after import.
|
281 |
+
def get_absl_handler() -> ABSLHandler:
|
282 |
+
...
|
283 |
+
|
284 |
+
|
285 |
+
def use_python_logging(quiet: bool = ...) -> None:
|
286 |
+
...
|
287 |
+
|
288 |
+
|
289 |
+
def use_absl_handler() -> None:
|
290 |
+
...
|
MLPY/Lib/site-packages/absl/logging/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (38.3 kB). View file
|
|
MLPY/Lib/site-packages/absl/logging/__pycache__/converter.cpython-39.pyc
ADDED
Binary file (5.24 kB). View file
|
|
MLPY/Lib/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 = dict((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('Expect an int level, found {}'.format(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('Expect an int level, found {}'.format(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('Expect an int level, found {}'.format(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))
|
MLPY/Lib/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.
|
MLPY/Lib/site-packages/absl/testing/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (149 Bytes). View file
|
|
MLPY/Lib/site-packages/absl/testing/__pycache__/_bazelize_command.cpython-39.pyc
ADDED
Binary file (1.61 kB). View file
|
|
MLPY/Lib/site-packages/absl/testing/__pycache__/_pretty_print_reporter.cpython-39.pyc
ADDED
Binary file (3.2 kB). View file
|
|
MLPY/Lib/site-packages/absl/testing/__pycache__/absltest.cpython-39.pyc
ADDED
Binary file (81.7 kB). View file
|
|
MLPY/Lib/site-packages/absl/testing/__pycache__/flagsaver.cpython-39.pyc
ADDED
Binary file (12.7 kB). View file
|
|
MLPY/Lib/site-packages/absl/testing/__pycache__/parameterized.cpython-39.pyc
ADDED
Binary file (23.6 kB). View file
|
|