Skip to content

Commit 3908395

Browse files
committed
feat(silo)!: support multiple lineage systems
BREAKING CHANGE: Multiple breaking changes to lineage configuration: - PreprocessingConfig: `lineageDefinitionsFilename` renamed to `lineageDefinitionFilenames` and changed from string to list - DatabaseConfig: `generateLineageIndex` changed from boolean to string (expects lineage definition filename)
1 parent 6baeaec commit 3908395

37 files changed

Lines changed: 416 additions & 138 deletions

src/config/config_specification.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ ConfigValue ConfigAttributeSpecification::parseValueFromString(std::string value
152152
throw ConfigException(
153153
fmt::format("'{}' is not a valid string for a boolean", value_string)
154154
);
155+
case ConfigValueType::LIST:
156+
throw ConfigException("List values can currently no be specified as strings.");
155157
}
156158
SILO_UNREACHABLE();
157159
} catch (boost::bad_lexical_cast&) {

src/config/config_value.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "config/config_value.h"
22

3+
#include <fmt/ranges.h>
34
#include <boost/functional/hash.hpp>
45
#include <boost/lexical_cast.hpp>
56

@@ -28,6 +29,9 @@ ConfigValueType ConfigValue::getValueType() const {
2829
if (std::holds_alternative<bool>(value)) {
2930
return ConfigValueType::BOOL;
3031
}
32+
if (std::holds_alternative<std::vector<std::string>>(value)) {
33+
return ConfigValueType::LIST;
34+
}
3135
SILO_UNREACHABLE();
3236
}
3337

@@ -39,6 +43,8 @@ std::string ConfigValue::toString() const {
3943
return fmt::format("'{}'", value);
4044
} else if constexpr (std::is_same_v<T, std::filesystem::path>) {
4145
return fmt::format("'{}'", value.string());
46+
} else if constexpr (std::is_same_v<T, std::vector<std::string>>) {
47+
return fmt::format("{}", fmt::join(value, ","));
4248
} else {
4349
return fmt::format("{}", value);
4450
}

src/config/config_value.h

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
namespace silo::config {
1414

15-
enum class ConfigValueType { STRING, PATH, INT32, UINT32, UINT16, BOOL };
15+
enum class ConfigValueType { STRING, PATH, INT32, UINT32, UINT16, BOOL, LIST };
1616

1717
constexpr std::string_view configValueTypeToString(ConfigValueType type) {
1818
switch (type) {
@@ -28,18 +28,33 @@ constexpr std::string_view configValueTypeToString(ConfigValueType type) {
2828
return "u16";
2929
case ConfigValueType::BOOL:
3030
return "bool";
31+
case ConfigValueType::LIST:
32+
return "list";
3133
}
3234
SILO_UNREACHABLE();
3335
}
3436

3537
class ConfigValue {
36-
explicit ConfigValue(
37-
std::variant<std::string, std::filesystem::path, int32_t, uint32_t, uint16_t, bool> value
38-
)
38+
explicit ConfigValue(std::variant<
39+
std::string,
40+
std::filesystem::path,
41+
int32_t,
42+
uint32_t,
43+
uint16_t,
44+
bool,
45+
std::vector<std::string>> value)
3946
: value(std::move(value)) {}
4047

4148
public:
42-
std::variant<std::string, std::filesystem::path, int32_t, uint32_t, uint16_t, bool> value;
49+
std::variant<
50+
std::string,
51+
std::filesystem::path,
52+
int32_t,
53+
uint32_t,
54+
uint16_t,
55+
bool,
56+
std::vector<std::string>>
57+
value;
4358

4459
static ConfigValue fromString(const std::string& value) { return ConfigValue{value}; }
4560

@@ -57,6 +72,8 @@ class ConfigValue {
5772

5873
static ConfigValue fromBool(bool value) { return ConfigValue{value}; }
5974

75+
static ConfigValue fromList(const std::vector<std::string>& value) { return ConfigValue{value}; }
76+
6077
[[nodiscard]] ConfigValueType getValueType() const;
6178

6279
[[nodiscard]] std::string toString() const;

src/config/source/yaml_file.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ using silo::config::ConfigKeyPath;
1717

1818
namespace {
1919

20+
bool isSequenceOfScalars(const YAML::Node& node) {
21+
if (!node.IsSequence()) {
22+
return false;
23+
}
24+
return std::ranges::all_of(node, [](const auto& element) { return element.IsScalar(); });
25+
}
26+
2027
bool isProperSingularValue(const YAML::Node& node) {
2128
if (node.IsMap()) {
2229
SPDLOG_TRACE("isProperSingularValue = false, node is a map");
@@ -26,8 +33,8 @@ bool isProperSingularValue(const YAML::Node& node) {
2633
SPDLOG_TRACE("isProperSingularValue = false, node is not defined");
2734
return false;
2835
}
29-
if (!node.IsScalar()) {
30-
SPDLOG_TRACE("isProperSingularValue = false, node is not a scalar");
36+
if (!node.IsScalar() && !isSequenceOfScalars(node)) {
37+
SPDLOG_TRACE("isProperSingularValue = false, node is not a scalar or sequence of strings");
3138
return false;
3239
}
3340
return true;
@@ -211,6 +218,8 @@ ConfigValue yamlNodeToConfigValue(
211218
return ConfigValue::fromUint16(yaml.as<uint16_t>());
212219
case ConfigValueType::BOOL:
213220
return ConfigValue::fromBool(yaml.as<bool>());
221+
case ConfigValueType::LIST:
222+
return ConfigValue::fromList(yaml.as<std::vector<std::string>>());
214223
}
215224
SILO_UNREACHABLE();
216225
} catch (YAML::BadConversion& error) {

src/config/source/yaml_file.test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ TEST(YamlFile, containsCorrectFieldsFromFlatYAML) {
5757
inputDirectory: "./testBaseData/exampleDataset/"
5858
outputDirectory: "./output/"
5959
ndjsonInputFilename: "input_file.ndjson"
60-
lineageDefinitionsFilename: "lineage_definitions.yaml"
60+
lineageDefinitionFilenames: "lineage_definition.yaml"
6161
phyloTreeFilename: "phylogenetic_tree.yaml"
6262
referenceGenomeFilename: "reference_genomes.json"
6363
)"
@@ -69,8 +69,8 @@ referenceGenomeFilename: "reference_genomes.json"
6969
YAML::Node{"./testBaseData/exampleDataset/"}},
7070
{YamlFile::stringToConfigKeyPath("outputDirectory"), YAML::Node{"./output/"}},
7171
{YamlFile::stringToConfigKeyPath("ndjsonInputFilename"), YAML::Node{"input_file.ndjson"}},
72-
{YamlFile::stringToConfigKeyPath("lineageDefinitionsFilename"),
73-
YAML::Node{"lineage_definitions.yaml"}},
72+
{YamlFile::stringToConfigKeyPath("lineageDefinitionFilenames"),
73+
YAML::Node{"lineage_definition.yaml"}},
7474
{YamlFile::stringToConfigKeyPath("phyloTreeFilename"), YAML::Node{"phylogenetic_tree.yaml"}},
7575
{YamlFile::stringToConfigKeyPath("referenceGenomeFilename"),
7676
YAML::Node{"reference_genomes.json"}},

src/config/verified_config_attributes.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ std::optional<bool> VerifiedConfigAttributes::getBool(const ConfigKeyPath& confi
8888
return std::nullopt;
8989
}
9090

91+
std::optional<std::vector<std::string>> VerifiedConfigAttributes::getList(
92+
const ConfigKeyPath& config_key_path
93+
) const {
94+
return getValue<std::vector<std::string>, ConfigValueType::LIST>(config_key_path, config_values);
95+
}
96+
9197
VerifiedCommandLineArguments VerifiedCommandLineArguments::askingForHelp() {
9298
VerifiedCommandLineArguments result;
9399
result.asks_for_help = true;

src/config/verified_config_attributes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ class VerifiedConfigAttributes {
3333
[[nodiscard]] std::optional<uint16_t> getUint16(const ConfigKeyPath& config_key_path) const;
3434

3535
[[nodiscard]] std::optional<bool> getBool(const ConfigKeyPath& config_key_path) const;
36+
37+
[[nodiscard]] std::optional<std::vector<std::string>> getList(
38+
const ConfigKeyPath& config_key_path
39+
) const;
3640
};
3741

3842
class VerifiedCommandLineArguments : public VerifiedConfigAttributes {

src/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ int runPreprocessor(const silo::config::PreprocessingConfig& preprocessing_confi
4747
database.saveDatabaseState(preprocessing_config.output_directory);
4848
return 0;
4949
} catch (const silo::preprocessing::PreprocessingException& preprocessing_exception) {
50-
SPDLOG_ERROR("initialize - error: {}", preprocessing_exception.what());
50+
SPDLOG_ERROR("preprocessing - error: {}", preprocessing_exception.what());
5151
return 1;
5252
}
5353
}

src/silo/common/lineage_tree.test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ TEST(LineageDefinitionFile, errorOnLineageAsAlias) {
254254

255255
TEST(containsCycle, doesNotFindCycleInPangoLineageTree) {
256256
ASSERT_NO_THROW(LineageTreeAndIdMap::fromLineageDefinitionFilePath(
257-
"testBaseData/exampleDataset/lineage_definitions.yaml"
257+
"testBaseData/exampleDataset/lineage_definition.yaml"
258258
));
259259
}
260260

src/silo/config/database_config.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ bool YAML::convert<silo::config::DatabaseMetadata>::decode(
138138
metadata.generate_index = false;
139139
}
140140
if (node["generateLineageIndex"].IsDefined()) {
141-
metadata.generate_lineage_index = node["generateLineageIndex"].as<bool>();
141+
metadata.generate_lineage_index = node["generateLineageIndex"].as<std::string>();
142142
} else {
143-
metadata.generate_lineage_index = false;
143+
metadata.generate_lineage_index = std::nullopt;
144144
}
145145
if (node["isPhyloTreeField"].IsDefined()) {
146146
metadata.phylo_tree_node_identifier = node["isPhyloTreeField"].as<bool>();

0 commit comments

Comments
 (0)