Usage¶
Declaring Flags¶
Many constant values should be declared as flags. Obtained a
NamespaceFlagSet
from the GLOBAL_FLAGS
singleton GlobalFlagSet
object via the
namespace()
function.
from oscar import flag
FLAGS = flag.namespace(__name__)
There should not be a need to create a GlobalFlagSet
object manually
in typical usage. Flag primitives predefined in the flag module:
-
class
oscar.flag.
String
(description, default=None, secure=False)[source] String-valued flag.
-
class
oscar.flag.
Int
(description, default=None, secure=False)[source] Integer-valued flag.
-
class
oscar.flag.
Float
(description, default=None, secure=False)[source] Float-valued flag.
-
class
oscar.flag.
Bool
(description, default=None, secure=False)[source] Boolean-valued flag.
-
class
oscar.flag.
List
(inner_type, separator, description, default=None, secure=False)[source] Flag that is a list of another flag type.
These are all constructed with at least a description. default
and
secure
are optional.
Flags must be declared at module level, and can only be declared once. Redefining a flag results in an error.
FLAGS.some_int = flag.Int('some int value')
FLAGS.some_string = flag.String('some string value', 'default string')
FLAGS.some_bool = flag.Bool('secure bool (why?)', secure=True)
Required values are indicated by setting default
to
REQUIRED
.
FLAGS.required_float = flag.Float('some required float', flag.REQUIRED)
Finally, List
is provided which can be used to define a
flag which is a list (cannot be polymorphic). It requires two
additional arguments: a Var
subclass defining the
primitive type, and a separator:
FLAGS.int_list = flag.List(flag.Int, ',', 'a list of integer values')
Using flag values in Python¶
Getting¶
Flag values can be read directly from the
NamespaceFlagSet
object (FLAGS
above).
FLAGS.some_int = flag.Int('some int value')
print FLAGS.some_int * 10
Setting¶
Setting is almost the same, but values should be parseable strings, not raw values (since the setter is how the various parsers actually set the values).
>>> FLAGS.some_int = '42'
>>> FLAGS.some_int
42
Positional Arguments¶
Finally, the flag module may expose positional arguments if a
command-line was parsed. These are available via args()
:
-
oscar.flag.
args
()[source] Return positional
args
fromGLOBAL_FLAGS
.Return type: list[str]
Parsing in __main__
¶
There are three parsers provided, a command-line parser, an environment
parser and a parser based on ConfigParser
.
-
oscar.flag.
parse_commandline
(args)[source] Parse commandline
args
withGLOBAL_FLAGS
.
-
oscar.flag.
parse_environment
(args)[source] Parse environment
args
withGLOBAL_FLAGS
.
-
oscar.flag.
parse_ini
(file_p)[source] Parse a
ConfigParser
compatible file withGLOBAL_FLAGS
.
Flag parsing must be done explicitly. Each parser can be used independently or with another parser. It is suggested to use the environment parser first followed by the command-line parser, since the environment parser can read SECURED_ settings, and flags can further be overridden by the command line.
import os
import sys
from oscar import flag
if __name__ == '__main__':
flag.parse_environment(os.environ.items())
flag.parse_commandline(sys.argv[1:])
The ConfigParser
parser requires an object providing
readline()
, which includes a standard opened file.
Note that required flags must be explicitly checked via
die_on_missing_required()
. If a config file is read, but the
path to that config file can be set on the command line, it is useful
to refrain from checking if required flags have been set until after
the config file is parsed.
import os
import sys
from oscar import flag
FLAGS = flag.namespace(__name__)
FLAGS.config_file = flag.String('path to config file')
if __name__ == '__main__':
flag.parse_commandline(sys.argv[1:])
if FLAGS.config_file:
with open(FLAGS.config_file) as config:
flag.parse_ini(config)
die_on_missing_required()
Setting Flags from The Outside¶
Short Names and Full Names¶
All flags are fully namespaced and are available by referencing them
through their module path. For instance, if a flag baz
is declared
in module foo.bar
, it can be referenced on the command line or in
the environment through foo.bar.baz
.
As a convenience, any uniquely named flag can be referenced on the
command line or in the environment through a short name. The short name
is for convenience and should not be used in scripts or configuration
files. Referencing an ambiguous short name will raise a
KeyError
.
Environment Variables¶
If parse_environment()
is called on
os.environ.items()
, environment variables will be mapped onto
flags. As noted, the environment parser supports short and full names.
The environment parser will recognize SECURED_SETTING_* environment
variables. These are base64 decoded and set on the appropriate flag if
present (while also setting the secure
attribute on the flag to
True
).
The environment parser will ignore extraneous environment variables that do not map to a flag.
Note
The last parse method called may overwrite flags set by previous
parse methods. It is probably preferable to call
parse_environment()
before calling
parse_commandline()
.
Command Line¶
Command-line flags are expected to precede any positional arguments. The presence of a single “–” argument can be used to denote the end of command-line flags. A single “-” or a double “–” are equivalent in denoting a flag. A flag and its value can be separated into separate arguments (i.e. via whitespace on the command line) or a single “=”.
# A single '-' is acceptable.
$ ./my_bin.pex -foo=bar
$ ./my_bin.pex -foo bar
# A double '--' is also acceptable.
$ ./my_bin.pex --foo=bar
$ ./my_bin.pex --foo bar
# Everything after '--' becomes a positional argument.
$ ./my_bin.pex -- --foo --bar --baz
Bool
flags are special-cased in the command-line parser. A
standalone Bool
flag with no value indicates
True
. A Bool
flag can only be set explicitly
using “=”, and a space between the flag and the value is
invalid. Valid boolean values are any case folded variation of
yes
, true
, on
, 1
for True
, and no
,
false
, off
, 0
for False
. Other values result in
an error.
./my_bin.pex --some_bool # some_bool is set to True
./my_bin.pex --some_bool=False # some_bool is set to False
./my_bin.pex --some_bool False # this is invalid and will throw a parse error
Command-line flags also may be referenced by their short name if it’s non-ambiguous, though this is provided as a shortcut for users, and the fully qualified flag name should be used in configuration and scripting.
Finally, if any flags are encountered that do not map to a flag in the application, an error will be raised. All command-line flags must map to a declared flag.
ConfigParser
ini files¶
There is also support for ini files. Sections map to namespaces, and key/value pairs within the sections map to flags within those namespaces.
[__main__]
output=output.txt
[utils.zookeeper]
ensemble=zookeeper-1,zookeeper-2,zookeeper-3
The ini parser will need to be ran against a file-like object.
with open('~/.config.ini') as config:
flag.parse_ini(config)
Finally, every section and key/value within an ini file must map to a namespace and flag. Unexpected sections and keys will raise an error.
Additional Public API for flag¶
-
oscar.flag.
GLOBAL_FLAGS
= <oscar.flag.GlobalFlagSet object> GlobalFlagSet is a collection of namespaces and flag logic.
-
GLOBAL_FLAGS.
usage
¶ This attribute can be replaced with a function that will print usage (invoked automatically by –help on the command line). The function accepts a single parameter: the
GlobalFlagSet
object calling it. The default implementation callsGlobalFlagSet.write_flags()
. Default value isdefault_usage()
.
-
GLOBAL_FLAGS.
usage_long
¶ This attribute can be replaced with a function that will print long usage (invoked automatically by –helplong on the command line). The function accepts a single parameter: the
GlobalFlagSet
object calling it. The default implementation callsGlobalFlagSet.write_flags_long()
. Default value isdefault_usage_long()
.
-