Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: add option -m / --metadata (rename -m / --mode to -t /--type) #87

Merged
merged 3 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ contain the following:
## Usage

```
usage: java -jar vcf-decision-tree.jar -i <arg> -c <arg> [-o <arg>] [-f]
usage: java -jar vcf-decision-tree.jar -i <arg> -c <arg> [-m <arg>] [-o <arg>] [-f]
[-s] [-l] [-p] [-d] [-pb <arg>] [-pd <arg>] [-ph <arg>] [-m <arg>]
-i,--input <arg> VEP* annotated input VCF file.
-m,--metadata <arg> VCF metadata file (.json).
-c,--config <arg> Input decision tree file (.json).
-o,--output <arg> Output VCF file (.vcf or .vcf.gz).
-f,--force Override the output file if it already exists.
Expand Down Expand Up @@ -85,9 +86,9 @@ usage: java -jar vcf-decision-tree.jar -v

## Examples
```
java -jar vcf-decision-tree.jar -i my.vcf -c decision_tree.json -o out.vcf
java -jar vcf-decision-tree.jar -i my.vcf.gz -c decision_tree.json -o out.vcf.gz
java -jar vcf-decision-tree.jar -i my.vcf.gz -c decision_tree.json -o out.vcf.gz -f -l -p
java -jar vcf-decision-tree.jar -i my.vcf -m field_metadata.json -c decision_tree.json -o out.vcf
java -jar vcf-decision-tree.jar -i my.vcf.gz -m field_metadata.json -c decision_tree.json -o out.vcf.gz
java -jar vcf-decision-tree.jar -i my.vcf.gz -m field_metadata.json -c decision_tree.json -o out.vcf.gz -f -l -p
java -jar vcf-decision-tree.jar -v
```

Expand Down
8 changes: 4 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<version>3.2.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<groupId>org.molgenis</groupId>
<artifactId>vip-decision-tree</artifactId>
<version>3.9.0</version>
<version>4.0.0</version>

<name>vip-decision-tree</name>
<description>Decision tree module for filtering and labelling VCF files</description>
Expand Down Expand Up @@ -41,9 +41,9 @@
<properties>
<java.version>17</java.version>
<commons.cli.version>1.6.0</commons.cli.version>
<samtools.htsjdk.version>4.0.2</samtools.htsjdk.version>
<samtools.htsjdk.version>4.1.0</samtools.htsjdk.version>
<jacoco-maven-plugin.version>0.8.11</jacoco-maven-plugin.version>
<vip.utils.version>1.4.5</vip.utils.version>
<vip.utils.version>2.0.0</vip.utils.version>
</properties>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class AppCommandLineOptions {

static final String OPT_INPUT = "i";
static final String OPT_INPUT_LONG = "input";
static final String OPT_METADATA = "m";
static final String OPT_METADATA_LONG = "metadata";
static final String OPT_CONFIG = "c";
static final String OPT_CONFIG_LONG = "config";
static final String OPT_OUTPUT = "o";
Expand All @@ -37,8 +39,8 @@ class AppCommandLineOptions {
static final String OPT_PED_LONG = "pedigree";
static final String OPT_PHENOTYPES = "ph";
static final String OPT_PHENOTYPES_LONG = "phenotypes";
static final String OPT_MODE = "m";
static final String OPT_MODE_LONG = "mode";
static final String OPT_TYPE = "t";
static final String OPT_TYPE_LONG = "type";
private static final Options APP_OPTIONS;
private static final Options APP_VERSION_OPTIONS;

Expand All @@ -58,6 +60,13 @@ class AppCommandLineOptions {
.longOpt(OPT_CONFIG_LONG)
.desc("Input decision tree file (.json).")
.build());
appOptions.addOption(
Option.builder(OPT_METADATA)
.hasArg(true)
.required()
.longOpt(OPT_METADATA_LONG)
.desc("VCF metadata file (.json).")
.build());
appOptions.addOption(
Option.builder(OPT_OUTPUT)
.hasArg(true)
Expand Down Expand Up @@ -110,11 +119,11 @@ class AppCommandLineOptions {
"Comma-separated list of sample-phenotypes (e.g. HP:123 or HP:123;HP:234 or sample0/HP:123,sample1/HP:234). Phenotypes are CURIE formatted (prefix:reference) and separated by a semicolon.")
.build());
appOptions.addOption(
Option.builder(OPT_MODE)
Option.builder(OPT_TYPE)
.hasArg(true)
.longOpt(OPT_MODE_LONG)
.longOpt(OPT_TYPE_LONG)
.desc(
"Run mode: 'variant' (default) or 'sample', 'sample' mode classifies provided probands, or all samples if no probands given.")
"Type: 'variant' (default) or 'sample', 'sample' classifies provided probands, or all samples if no probands given.")
.build());
APP_OPTIONS = appOptions;
Options appVersionOptions = new Options();
Expand All @@ -139,9 +148,10 @@ static Options getAppVersionOptions() {

static void validateCommandLine(CommandLine commandLine) {
validateInput(commandLine);
validateMetadata(commandLine);
validateConfig(commandLine);
validateOutput(commandLine);
validateMode(commandLine);
validateType(commandLine);
}

private static void validateInput(CommandLine commandLine) {
Expand All @@ -165,19 +175,39 @@ private static void validateInput(CommandLine commandLine) {
}
}

private static void validateMetadata(CommandLine commandLine) {
Path metadataPath = Path.of(commandLine.getOptionValue(OPT_METADATA));
if (!Files.exists(metadataPath)) {
throw new IllegalArgumentException(
format("Metadata file '%s' does not exist.", metadataPath));
}
if (Files.isDirectory(metadataPath)) {
throw new IllegalArgumentException(
format("Metadata file '%s' is a directory.", metadataPath));
}
if (!Files.isReadable(metadataPath)) {
throw new IllegalArgumentException(
format("Metadata file '%s' is not readable.", metadataPath));
}
String inputPathStr = metadataPath.toString();
if (!inputPathStr.endsWith(".json")) {
throw new IllegalArgumentException(
format("Metadata file '%s' is not a .json file.", inputPathStr));
}
}
private static void validateConfig(CommandLine commandLine) {
Path configPath = Path.of(commandLine.getOptionValue(OPT_CONFIG));
if (!Files.exists(configPath)) {
throw new IllegalArgumentException(
format("Config file '%s' does not exist.", configPath.toString()));
format("Config file '%s' does not exist.", configPath));
}
if (Files.isDirectory(configPath)) {
throw new IllegalArgumentException(
format("Config file '%s' is a directory.", configPath.toString()));
format("Config file '%s' is a directory.", configPath));
}
if (!Files.isReadable(configPath)) {
throw new IllegalArgumentException(
format("Config file '%s' is not readable.", configPath.toString()));
format("Config file '%s' is not readable.", configPath));
}
String inputPathStr = configPath.toString();
if (!inputPathStr.endsWith(".json")) {
Expand All @@ -199,18 +229,18 @@ private static void validateOutput(CommandLine commandLine) {
}
}

private static void validateMode(CommandLine commandLine) {
if (!commandLine.hasOption(OPT_MODE)) {
private static void validateType(CommandLine commandLine) {
if (!commandLine.hasOption(OPT_TYPE)) {
return;
}

String mode = commandLine.getOptionValue(OPT_MODE);
String mode = commandLine.getOptionValue(OPT_TYPE);
List<String> modes = Arrays.stream(Mode.values()).map(Mode::toString)
.toList();

if (!modes.contains(mode.toUpperCase())) {
throw new IllegalArgumentException(
"Illegal 'mode' argument '%s', only 'variant' and 'sample' are allowed.".formatted(mode));
"Illegal 'type' argument '%s', only 'variant' and 'sample' are allowed.".formatted(mode));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
package org.molgenis.vcf.decisiontree;

import static java.util.Arrays.asList;
import static java.util.Objects.requireNonNull;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_CONFIG;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_FORCE;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_INPUT;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_LABELS;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_MODE;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_OUTPUT;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_PATH;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_PED;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_PHENOTYPES;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_PROBANDS;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.OPT_STRICT;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.cli.CommandLine;
import org.molgenis.vcf.decisiontree.filter.model.Mode;
import org.molgenis.vcf.decisiontree.loader.ConfigDecisionTreeLoader;
import org.molgenis.vcf.decisiontree.loader.model.ConfigDecisionTree;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static java.util.Arrays.asList;
import static java.util.Objects.requireNonNull;
import static org.molgenis.vcf.decisiontree.AppCommandLineOptions.*;

@Component
class AppCommandLineToSettingsMapper {

Expand All @@ -45,15 +36,17 @@ class AppCommandLineToSettingsMapper {
Settings map(CommandLine commandLine, String... args) {
AppSettings appSettings = createAppSettings(args);
Path inputPath = Path.of(commandLine.getOptionValue(OPT_INPUT));
Path metadataPath = Path.of(commandLine.getOptionValue(OPT_METADATA));
ConfigDecisionTree configDecisionTree = createDecisionTree(commandLine);
WriterSettings writerSettings = createWriterSettings(commandLine);
boolean strict = commandLine.hasOption(OPT_STRICT);
Mode mode = getMode(commandLine);
Mode mode = getType(commandLine);
SampleSettings sampleSettings = createSampleSettings(commandLine);

return Settings.builder()
.mode(mode)
.inputVcfPath(inputPath)
.metadataPath(metadataPath)
.configDecisionTree(configDecisionTree)
.appSettings(appSettings)
.writerSettings(writerSettings)
Expand All @@ -62,10 +55,10 @@ Settings map(CommandLine commandLine, String... args) {
.build();
}

private Mode getMode(CommandLine commandLine) {
private Mode getType(CommandLine commandLine) {
Mode mode;
if (commandLine.hasOption(OPT_MODE)) {
mode = Mode.valueOf(commandLine.getOptionValue(OPT_MODE).toUpperCase());
if (commandLine.hasOption(OPT_TYPE)) {
mode = Mode.valueOf(commandLine.getOptionValue(OPT_TYPE).toUpperCase());
} else {
mode = Mode.VARIANT;
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/molgenis/vcf/decisiontree/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class Settings {

Mode mode;
Path inputVcfPath;
Path metadataPath;
ConfigDecisionTree configDecisionTree;
AppSettings appSettings;
WriterSettings writerSettings;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,25 @@
import org.molgenis.vcf.decisiontree.filter.VcfReader;
import org.molgenis.vcf.decisiontree.runner.info.GenotypeMetadataMapper;
import org.molgenis.vcf.decisiontree.runner.info.VepMetadataParser;
import org.molgenis.vcf.decisiontree.runner.info.VepMetadataParserFactory;
import org.springframework.stereotype.Component;

@Component
class VcfReaderFactoryImpl implements VcfReaderFactory {

private final VepMetadataParserFactory vepMetadataParserFactory;
private final GenotypeMetadataMapper genotypeMetadataMapper;
private VepMetadataParser vepMetadataParser;

VcfReaderFactoryImpl(VepMetadataParser vepMetadataParser,
GenotypeMetadataMapper genotypeMetadataMapper) {
this.vepMetadataParser = requireNonNull(vepMetadataParser);
VcfReaderFactoryImpl(VepMetadataParserFactory vepMetadataParserFactory,
GenotypeMetadataMapper genotypeMetadataMapper) {
this.vepMetadataParserFactory = requireNonNull(vepMetadataParserFactory);
this.genotypeMetadataMapper = requireNonNull(genotypeMetadataMapper);
}

@Override
public VcfReader create(Settings settings) {
VepMetadataParser vepMetadataParser = vepMetadataParserFactory.create(settings);

Path inputVcfPath = settings.getInputVcfPath();
boolean strict = settings.isStrict();
return new VcfReader(new VCFFileReader(inputVcfPath.toFile(), false), vepMetadataParser,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.molgenis.vcf.decisiontree.runner;

import static java.util.Collections.singletonList;
import static org.molgenis.vcf.decisiontree.runner.info.VepInfoMetadataMapper.ALLELE_NUM;
import static org.molgenis.vcf.decisiontree.runner.info.VepMetadataMapperImpl.ALLELE_NUM;

import htsjdk.variant.variantcontext.VariantContext;
import htsjdk.variant.variantcontext.VariantContextBuilder;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.molgenis.vcf.decisiontree.runner.info;

import org.molgenis.vcf.decisiontree.Settings;

public interface VepMetadataMapperFactory {
VepMetadataMapper create(Settings settings);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.molgenis.vcf.decisiontree.runner.info;

import htsjdk.variant.vcf.VCFInfoHeaderLine;
import org.molgenis.vcf.decisiontree.Settings;
import org.molgenis.vcf.utils.metadata.FieldMetadataService;
import org.molgenis.vcf.utils.metadata.AbstractFieldMetadataService;
import org.molgenis.vcf.utils.model.FieldMetadata;
import org.molgenis.vcf.utils.vep.VepMetadataService;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static java.util.Objects.requireNonNull;

@Component
public class VepMetadataMapperFactoryImpl implements VepMetadataMapperFactory {
@Override
public VepMetadataMapper create(Settings settings) {
Path metadataPath = settings.getMetadataPath();
FieldMetadataService fieldMetadataService = new CustomFieldMetadataService(metadataPath);
VepMetadataService vepMetadataService = new VepMetadataService(fieldMetadataService);
return new VepMetadataMapperImpl(vepMetadataService);
}

private static class CustomFieldMetadataService extends AbstractFieldMetadataService {
private final Path metadataPath;

public CustomFieldMetadataService(Path metadataPath) {
this.metadataPath = requireNonNull(metadataPath);
}

@Override
public FieldMetadata load(VCFInfoHeaderLine vcfInfoHeaderLine) {
try(InputStream inputStream = Files.newInputStream(metadataPath)) {
return this.load(inputStream, vcfInfoHeaderLine);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
}
Loading