38 def load_yaml_with_base(filename: str, allow_unsafe: bool = False):
39 """
40 Just like `yaml.load(open(filename))`, but inherit attributes from its
41 `_BASE_`.
42 Args:
43 filename (str): the file name of the current config. Will be used to
44 find the base config file.
45 allow_unsafe (bool): whether to allow loading the config file with
46 `yaml.unsafe_load`.
47 Returns:
48 (dict): the loaded yaml
49 """
50 with PathManager.open(filename, "r") as f:
51 try:
52 cfg = yaml.safe_load(f)
53 except yaml.constructor.ConstructorError:
54 if not allow_unsafe:
55 raise
56 logger = logging.getLogger(__name__)
57 logger.warning(
58 "Loading config {} with yaml.unsafe_load. Your machine may "
59 "be at risk if the file contains malicious content.".format(
60 filename
61 )
62 )
63 f.close()
64 with open(filename, "r") as f:
65 cfg = yaml.unsafe_load(f)
66
67 def merge_a_into_b(a, b):
68
69 for k, v in a.items():
70 if isinstance(v, dict) and k in b:
71 assert isinstance(
72 b[k], dict
73 ), "Cannot inherit key '{}' from base!".format(k)
74 merge_a_into_b(v, b[k])
75 else:
76 b[k] = v
77
78 if BASE_KEY in cfg:
79 base_cfg_file = cfg[BASE_KEY]
80 if base_cfg_file.startswith("~"):
81 base_cfg_file = os.path.expanduser(base_cfg_file)
82 if not any(
83 map(base_cfg_file.startswith, ["/", "https://", "http://"])
84 ):
85
86 base_cfg_file = os.path.join(
87 os.path.dirname(filename), base_cfg_file
88 )
89 base_cfg = CfgNode.load_yaml_with_base(
90 base_cfg_file, allow_unsafe=allow_unsafe
91 )
92 del cfg[BASE_KEY]
93
94 merge_a_into_b(cfg, base_cfg)
95 return base_cfg
96 return cfg
97