Abseil Python
Abseil Quickstart (Python) https://abseil.io/docs/python/quickstart.html
  • from absl import app
  • from absl import flags
  • 创建Flags = flags.FLAGS
  • 定义flag,flags.DEFINE_string/DEFINE_integer/DEFINE_boolean("flag_name", default_value, "help")
    DEFINE = _defines.DEFINE
    DEFINE_flag = _defines.DEFINE_flag
    DEFINE_string = _defines.DEFINE_string
    DEFINE_boolean = _defines.DEFINE_boolean
    DEFINE_bool = DEFINE_boolean # Match C++ API.
    DEFINE_float = _defines.DEFINE_float
    DEFINE_integer = _defines.DEFINE_integer
    DEFINE_enum = _defines.DEFINE_enum
    DEFINE_enum_class = _defines.DEFINE_enum_class
    DEFINE_list = _defines.DEFINE_list
    DEFINE_spaceseplist = _defines.DEFINE_spaceseplist
    DEFINE_multi = _defines.DEFINE_multi
    DEFINE_multi_string = _defines.DEFINE_multi_string
    DEFINE_multi_integer = _defines.DEFINE_multi_integer
    DEFINE_multi_float = _defines.DEFINE_multi_float
    DEFINE_multi_enum = _defines.DEFINE_multi_enum
    DEFINE_multi_enum_class = _defines.DEFINE_multi_enum_class
    DEFINE_alias = _defines.DEFINE_alias
  • 设定必选项flag flags.mark_flag_as_required("flag_name")
  • 应用Flags.flag_name
完整的示例:
from absl import app
from absl import flags
Flags = flags.FLAGS
flags.DEFINE_integer("num_times", 1, "Number of print times")
flags.DEFINE_string("name", None, "Your name")
# Required flag
flags.mark_flag_as_required("name")
def main(argv):
del argv # Unused
for _ in range(0, Flags.num_times):
print('Hello %s, from absl' % Flags.name)
if __name__ == "__main__":
app.run(main)
# test run python3 absl-hello.py --name=test

app.py

app.py是Abseil python应用的通用入口,是与一般python应用主要不同的地方,一般情况下运行e.g., $ python my_app.py 。当通过bazel运行的时候,Bazel会通过寻找app.run()确认入口点。
当程序启动, app.run() 处理flags, 打印一个用法信息和错误信息如果指定了非法flags。

Flags

absl.flags定义了一个分布式命令行系统,取代了诸如getopt()optparse和手动参数处理之类的系统。 每个应用程序都不必定义在main()或其附近的所有标志,而由每个Python模块定义对其有用的标志。 当一个Python模块导入另一个模块时,便可以访问另一个模块的标志。 (通过使所有模块共享包含所有标志信息的公共全局注册表对象来实现此行为。)
Abseil标志库包括定义标志类型(布尔值,浮点数,整数,列表),自动生成帮助(以人类和机器可读格式)以及从文件中读取参数的功能。 它还包括从帮助标志自动生成手册页的功能。
标志是通过使用DEFINE_ *函数定义的(标志的类型用于定义值)。
Flag names are globally defined! So in general, we need to be careful to pick names that are unlikely to be used by other libraries. If there is a conflict, we'll get an error at import time.

Example Usage

from absl import app
from absl import flags
FLAGS = flags.FLAGS
# Flag names are globally defined! So in general, we need to be
# careful to pick names that are unlikely to be used by other libraries.
# If there is a conflict, we'll get an error at import time.
flags.DEFINE_string('name', 'Jane Random', 'Your name.')
flags.DEFINE_integer('age', None, 'Your age in years.', lower_bound=0)
flags.DEFINE_boolean('debug', False, 'Produces debugging output.')
flags.DEFINE_enum('job', 'running', ['running', 'stopped'], 'Job status.')
def main(argv):
if FLAGS.debug:
print('non-flag arguments:', argv)
print('Happy Birthday', FLAGS.name)
if FLAGS.age is not None:
print('You are %d years old, and your job is %s' % (FLAGS.age, FLAGS.job))
if __name__ == '__main__':
app.run(main)

Flag 类型

  • DEFINE_string`: takes any input and interprets it as a string.
  • DEFINE_bool or DEFINE_boolean: typically does not take an argument: pass --myflag to set FLAGS.myflag to True, or --nomyflag to set FLAGS.myflag to False. --myflag=true and --myflag=false are also supported, but not recommended.
  • DEFINE_float: takes an input and interprets it as a floating point number. This also takes optional arguments lower_bound and upper_bound; if the number specified on the command line is out of range, it raises a FlagError.
  • DEFINE_integer: takes an input and interprets it as an integer. This also takes optional arguments lower_bound and upper_bound as for floats.
  • DEFINE_enum: takes a list of strings that represents legal values. If the command-line value is not in this list, it raises a flag error; otherwise, it assigns to FLAGS.flag as a string.
  • DEFINE_list: Takes a comma-separated list of strings on the command line and stores them in a Python list object.
  • DEFINE_spaceseplist: Takes a space-separated list of strings on the commandline and stores them in a Python list object. For example: --myspacesepflag "foo bar baz"
  • DEFINE_multi_string: The same as DEFINE_string, except the flag can be specified more than once on the command line. The result is a Python list object (list of strings), even if the flag is only on the command line once.
  • DEFINE_multi_integer: The same as DEFINE_integer, except the flag can be specified more than once on the command line. The result is a Python list object (list of ints), even if the flag is only on the command line once.
  • DEFINE_multi_enum: The same as DEFINE_enum, except the flag can be specified more than once on the command line. The result is a Python list object (list of strings), even if the flag is only on the command line once.

Special Flags

Some flags have special meanings:
  • --help: prints a list of all key flags (see below).
  • --helpshort: alias for --help.
  • --helpfull: prints a list of all the flags in a human-readable fashion.
  • --helpxml: prints a list of all flags, in XML format. Do not parse the output of --helpfull and --helpshort. Instead, parse the output of --helpxml.
  • --flagfile=filename: read flags from file filename.
  • --undefok=f1,f2: ignore unrecognized option errors for f1,f2. For boolean flags, you should use --undefok=boolflag, and --boolflag and --noboolflag will be accepted. Do not use --undefok=noboolflag.
  • --: as in getopt(). This terminates flag-processing.

Logging

​ Abseil has its own library for logging in Python. It is implemented on top of the standard logging module in Python (described in PEP282), which is good if you’re already familiar with that library. This section mentions the basics of Abseil’s logging library. See the source for more details.
Dependencies:
from absl import logging
Example code:
logging.info('Interesting Stuff')
logging.info('Interesting Stuff with Arguments: %d', 42)
logging.set_verbosity(logging.INFO)
logging.log(logging.DEBUG, 'This will *not* be printed')
logging.set_verbosity(logging.DEBUG)
logging.log(logging.DEBUG, 'This will be printed')
logging.warning('Worrying Stuff')
logging.error('Alarming Stuff')
logging.fatal('AAAAHHHHH!!!!') # Process exits
Log levels:
  • logging.FATAL
  • logging.ERROR
  • logging.WARNING
  • logging.INFO
  • logging.DEBUG
Functions:
  • fatal(msg, *args)
  • error(msg, *args)
  • warning(msg, *args)
  • info(msg, *args)
  • debug(msg, *args)
  • vlog(level, msg, *args)
  • exception(msg, *args)

Testing

​ Abseil Python’s testing library is similar to Python’s standard unittest module (sometimes referred to as PyUnit) but offers some additional useful features on top of the standard library, such as interfacing with Abseil Flags.
To use the Abseil testing library, do the following in your unit tests:
  • import the absltest module
  • import the flags module, which gives you access to the variables FLAGS.test_srcdir and FLAGS.test_tmpdir.
  • call absltest.main() instead of unittest.main()