cli/config_differ.py (61 lines of code) (raw):

# Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Tools for diffing two NodeConfigs.""" import config DIFF_EXPLANATION_TEMPLATE = "(Current) %s -> (Golden) %s" CONFIG_DIFF_EXPLANATION_TEMPLATE = "%s -> %s" def diff_configs( experiment: config.NodeConfig, golden: config.NodeConfig ) -> config.NodeDiff: """Diffs an experiment config against a golden config. Args: experiment: The experiment config to diff. golden: The golden config to diff against. Returns: A NodeConfig named after the experiment config, populated with differences between the experiment and golden configs. If the configs are the same, a NodeConfig with no dependencies is returned. """ diffs = {} for golden_dep in golden.dependencies.values(): experiment_dep = experiment.dependencies.get( golden_dep.name, config.DependencyConfig(name="", version="None") ) dependency_diff = config.DependencyDiff(name=golden_dep.name) should_diff_version = ( not experiment_dep.config_settings and not golden_dep.config_settings and golden_dep.version != experiment_dep.version ) if should_diff_version: dependency_diff.diff_explanation = DIFF_EXPLANATION_TEMPLATE % ( experiment_dep.version, golden_dep.version, ) dependency_diff.experiment_dependency = experiment_dep dependency_diff.golden_dependency = golden_dep elif experiment_dep.config_settings and golden_dep.config_settings: diff_explanation = "" for golden_key, golden_value in golden_dep.config_settings.items(): if golden_value != experiment_dep.config_settings.get(golden_key): diff_explanation += ( f"{golden_key}: " + CONFIG_DIFF_EXPLANATION_TEMPLATE % ( experiment_dep.config_settings.get(golden_key), golden_value, ) + "\n" ) if diff_explanation: dependency_diff.diff_explanation = diff_explanation dependency_diff.experiment_dependency = experiment_dep dependency_diff.golden_dependency = golden_dep elif experiment_dep.version == golden_dep.version: dependency_diff.diff_explanation = ( f"{experiment_dep.version} ({config.DependencyDiff.DEFAULT_DIFF_EXPLANATION})" ) else: dependency_diff.diff_explanation = experiment_dep.version diffs[golden_dep.name] = dependency_diff skipped_deps = experiment.dependencies.keys() - golden.dependencies.keys() for skipped_dep in skipped_deps: dep = experiment.dependencies[skipped_dep] diffs[skipped_dep] = config.DependencyDiff( name=skipped_dep, diff_explanation=dep.version, experiment_dependency=dep, golden_dependency=None, ) return config.NodeDiff( name=experiment.name, dependency_diffs=diffs, )