|  | #!/usr/bin/env python3 | 
|  |  | 
|  | # Copyright (c) Facebook, Inc. and its affiliates. | 
|  | # All rights reserved. | 
|  | # | 
|  | # This source code is licensed under the BSD-style license found in the | 
|  | # LICENSE file in the root directory of this source tree. | 
|  | import os | 
|  | from argparse import Action | 
|  |  | 
|  |  | 
|  | class env(Action): | 
|  | """ | 
|  | Gets argument values from ``PET_{dest}`` before defaulting | 
|  | to the given ``default`` value. For flags (e.g. ``--standalone``) | 
|  | use ``check_env`` instead. | 
|  |  | 
|  | .. note:: when multiple option strings are specified, ``dest`` is | 
|  | the longest option string (e.g. for ``"-f", "--foo"`` | 
|  | the env var to set is ``PET_FOO`` not ``PET_F``) | 
|  |  | 
|  | Example: | 
|  |  | 
|  | :: | 
|  |  | 
|  | parser.add_argument("-f", "--foo", action=env, default="bar") | 
|  |  | 
|  | ./program                                      -> args.foo="bar" | 
|  | ./program -f baz                               -> args.foo="baz" | 
|  | ./program --foo baz                            -> args.foo="baz" | 
|  | PET_FOO="env_bar" ./program -f baz    -> args.foo="baz" | 
|  | PET_FOO="env_bar" ./program --foo baz -> args.foo="baz" | 
|  | PET_FOO="env_bar" ./program           -> args.foo="env_bar" | 
|  |  | 
|  | parser.add_argument("-f", "--foo", action=env, required=True) | 
|  |  | 
|  | ./program                                      -> fails | 
|  | ./program -f baz                               -> args.foo="baz" | 
|  | PET_FOO="env_bar" ./program           -> args.foo="env_bar" | 
|  | PET_FOO="env_bar" ./program -f baz    -> args.foo="baz" | 
|  | """ | 
|  |  | 
|  | def __init__(self, dest, default=None, required=False, **kwargs) -> None: | 
|  | env_name = f"PET_{dest.upper()}" | 
|  | default = os.environ.get(env_name, default) | 
|  |  | 
|  | # ``required`` means that it NEEDS to be present  in the command-line args | 
|  | # rather than "this option requires a value (either set explicitly or default" | 
|  | # so if we found default then we don't "require" it to be in the command-line | 
|  | # so set it to False | 
|  | if default: | 
|  | required = False | 
|  |  | 
|  | super().__init__(dest=dest, default=default, required=required, **kwargs) | 
|  |  | 
|  | def __call__(self, parser, namespace, values, option_string=None): | 
|  | setattr(namespace, self.dest, values) | 
|  |  | 
|  |  | 
|  | class check_env(Action): | 
|  | """ | 
|  | For flags, checks whether the env var ``PET_{dest}`` exists | 
|  | before defaulting to the given ``default`` value. Equivalent to | 
|  | ``store_true`` argparse built-in action except that the argument can | 
|  | be omitted from the commandline if the env var is present and has a | 
|  | non-zero value. | 
|  |  | 
|  | .. note:: it is redundant to pass ``default=True`` for arguments | 
|  | that use this action because a flag should be ``True`` | 
|  | when present and ``False`` otherwise. | 
|  |  | 
|  | Example: | 
|  |  | 
|  | :: | 
|  |  | 
|  | parser.add_argument("--verbose", action=check_env) | 
|  |  | 
|  | ./program                                  -> args.verbose=False | 
|  | ./program --verbose                        -> args.verbose=True | 
|  | PET_VERBOSE=1 ./program           -> args.verbose=True | 
|  | PET_VERBOSE=0 ./program           -> args.verbose=False | 
|  | PET_VERBOSE=0 ./program --verbose -> args.verbose=True | 
|  |  | 
|  | Anti-pattern (don't do this): | 
|  |  | 
|  | :: | 
|  |  | 
|  | parser.add_argument("--verbose", action=check_env, default=True) | 
|  |  | 
|  | ./program                                  -> args.verbose=True | 
|  | ./program --verbose                        -> args.verbose=True | 
|  | PET_VERBOSE=1 ./program           -> args.verbose=True | 
|  | PET_VERBOSE=0 ./program           -> args.verbose=False | 
|  |  | 
|  | """ | 
|  |  | 
|  | def __init__(self, dest, default=False, **kwargs) -> None: | 
|  | env_name = f"PET_{dest.upper()}" | 
|  | default = bool(int(os.environ.get(env_name, "1" if default else "0"))) | 
|  | super().__init__(dest=dest, const=True, default=default, nargs=0, **kwargs) | 
|  |  | 
|  | def __call__(self, parser, namespace, values, option_string=None): | 
|  | setattr(namespace, self.dest, self.const) |