Define flags on `fv` by recursively invoking `cfg.klass.define_flags`. Flags are defined in topological order, i.e., parent flags will be defined prior to defining child flags. Args: cfg: A config instance. It does not need to be a `FlagConfigurable` config. fv: Parsed
(cfg: ConfigBase, fv: flags.FlagValues)
| 487 | |
| 488 | |
| 489 | def define_flags(cfg: ConfigBase, fv: flags.FlagValues): |
| 490 | """Define flags on `fv` by recursively invoking `cfg.klass.define_flags`. |
| 491 | |
| 492 | Flags are defined in topological order, i.e., parent flags will be defined prior to defining |
| 493 | child flags. |
| 494 | |
| 495 | Args: |
| 496 | cfg: A config instance. It does not need to be a `FlagConfigurable` config. |
| 497 | fv: Parsed flag values instance. The same `fv` is used for the entire config hierarchy. |
| 498 | |
| 499 | Raises: |
| 500 | ValueError: If `cfg` is not a config. |
| 501 | """ |
| 502 | # pylint: disable=protected-access |
| 503 | if not isinstance(cfg, ConfigBase): |
| 504 | raise ValueError(f"Expected {ConfigBase}, got: {type(cfg)}") |
| 505 | |
| 506 | def visit_fn(_, value): |
| 507 | if not isinstance(value, FlagConfigurable.Config): |
| 508 | return |
| 509 | for namespace, child in _get_namespaced_config(value).items(): |
| 510 | sub_fv = flags.FlagValues() |
| 511 | define_flags(child, sub_fv) |
| 512 | # Flatten the child flags into `fv`. See `FlagValues.append_flag_values` for ref. |
| 513 | # The main difference is that we namespace the flags by child name. |
| 514 | for flag_name, flag in sub_fv._flags().items(): |
| 515 | # absl flattens short names into `fv` during __setattr__. |
| 516 | # Keep things simple for now by limiting to verbose names. |
| 517 | if flag.short_name: |
| 518 | raise NotImplementedError( |
| 519 | f"Short names are currently not supported: {flag.short_name}" |
| 520 | ) |
| 521 | fv[f"{namespace}.{flag_name}"] = flag |
| 522 | |
| 523 | def enter_fn(_, value, default_kv): |
| 524 | if not isinstance(value, Configurable.Config) or not hasattr(value.klass, "define_flags"): |
| 525 | return default_kv |
| 526 | klass: FlagConfigurable = value.klass |
| 527 | klass.define_flags(fv) |
| 528 | if hasattr(klass, _FLAG_NAMESPACE_ATTRIBUTE): |
| 529 | return None # Enter visit_fn. |
| 530 | return default_kv |
| 531 | |
| 532 | cfg.visit(visit_fn=visit_fn, enter_fn=enter_fn) |
| 533 | |
| 534 | |
| 535 | _C = TypeVar("_C", bound=ConfigBase) |