New behavior for filling it output streams: if required==true for a field and the field

is an output stream, we'll automatically create it and point it to stdout.  Otherwise, 
we'll leave it empty.  
I think about it like this: marking a field 'required' indicates to the GATK that the 
walker author requires a value for this field, and if the GATK can provide one without 
end user intervention, it will.  Maybe this is hackish.  We'll try it and see.


git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@4091 348d0f76-0448-11de-a6fe-93d51630548a
This commit is contained in:
hanna 2010-08-23 23:39:13 +00:00
parent 90aef66ec5
commit 5d6a6420a9
10 changed files with 89 additions and 117 deletions

View File

@ -45,7 +45,7 @@ import java.lang.annotation.Target;
@Documented @Documented
@Inherited @Inherited
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD}) @Target(ElementType.FIELD)
public @interface Argument { public @interface Argument {
/** /**
* The full name of the command-line argument. Full names should be * The full name of the command-line argument. Full names should be
@ -70,8 +70,9 @@ public @interface Argument {
String doc(); String doc();
/** /**
* Is this command-line argument required. The application should exit * Is this argument required. If true, the command-line argument system will
* printing help if this command-line argument is not specified. * make a best guess for populating this argument based on the type descriptor,
* and will fail if the type can't be populated.
* @return True if the argument is required. False otherwise. * @return True if the argument is required. False otherwise.
*/ */
boolean required() default true; boolean required() default true;

View File

@ -61,7 +61,13 @@ public class ArgumentDefinition {
public final String doc; public final String doc;
/** /**
* Is this argument required? * Must this argument be specified on the command-line? Note that there's a
* critical difference between the meaning of a required argument from the
* perspective of the argument source and the perspective of the argument
* definition: the argument source's required field indicates that the field
* should somehow be populated by the GATK (and fail if there's an error).
* The ArgumentDefinition required element means that the required element
* must be specified on the command-line.
*/ */
public final boolean required; public final boolean required;
@ -137,8 +143,8 @@ public class ArgumentDefinition {
this.required = required; this.required = required;
this.isFlag = isFlag; this.isFlag = isFlag;
this.isMultiValued = isMultiValued; this.isMultiValued = isMultiValued;
this.componentType = componentType;
this.isHidden = isHidden; this.isHidden = isHidden;
this.componentType = componentType;
this.exclusiveOf = exclusiveOf; this.exclusiveOf = exclusiveOf;
this.validation = validation; this.validation = validation;
this.validOptions = validOptions; this.validOptions = validOptions;
@ -157,17 +163,22 @@ public class ArgumentDefinition {
* @param validOptions is there a particular list of options that's valid for this argument definition? List them if so, otherwise set this to null. * @param validOptions is there a particular list of options that's valid for this argument definition? List them if so, otherwise set this to null.
*/ */
public ArgumentDefinition( Annotation annotation, public ArgumentDefinition( Annotation annotation,
ArgumentIOType ioType,
Class argumentType, Class argumentType,
String defaultFullName, String defaultFullName,
String defaultShortName, String defaultShortName,
String doc,
boolean isRequired,
boolean isFlag, boolean isFlag,
boolean isMultiValued, boolean isMultiValued,
boolean isHidden, boolean isHidden,
Class componentType, Class componentType,
String exclusiveOf,
String validation,
List<String> validOptions) { List<String> validOptions) {
String fullName = (String)getValue(annotation, "fullName"); String fullName = (String)CommandLineUtils.getValue(annotation, "fullName");
String shortName = (String)getValue(annotation, "shortName"); String shortName = (String)CommandLineUtils.getValue(annotation, "shortName");
boolean isFullNameProvided = fullName.trim().length() > 0; boolean isFullNameProvided = fullName.trim().length() > 0;
boolean isShortNameProvided = shortName.trim().length() > 0; boolean isShortNameProvided = shortName.trim().length() > 0;
@ -182,55 +193,21 @@ public class ArgumentDefinition {
else else
shortName = null; shortName = null;
this.ioType = ArgumentIOType.getIOType(annotation); this.ioType = ioType;
this.argumentType = argumentType; this.argumentType = argumentType;
this.fullName = fullName; this.fullName = fullName;
this.shortName = shortName; this.shortName = shortName;
this.doc = getDoc(annotation); this.doc = doc;
this.required = isRequired(annotation, isFlag); this.required = isRequired;
this.isFlag = isFlag; this.isFlag = isFlag;
this.isMultiValued = isMultiValued; this.isMultiValued = isMultiValued;
this.isHidden = isHidden; this.isHidden = isHidden;
this.componentType = componentType; this.componentType = componentType;
this.exclusiveOf = getExclusiveOf(annotation); this.exclusiveOf = exclusiveOf;
this.validation = getValidationRegex(annotation); this.validation = validation;
this.validOptions = validOptions; this.validOptions = validOptions;
} }
/**
* Creates a new argument definition.
* @param annotation The annotation on the field.
* @param argumentType The class of the field.
* @param fieldName Default full name for this argument definition.
* @param isFlag Whether or not this argument should be treated as a flag.
* @param isMultiValued Whether or not this argument supports multiple values.
* @param componentType For multivalued arguments the type of the components.
* @param isHidden Whether or not this argument should be hidden from the command-line argument system.
* @param validOptions is there a particular list of options that's valid for this argument definition? List them if so, otherwise set this to null.
*/
public ArgumentDefinition( Annotation annotation,
Class argumentType,
String fieldName,
boolean isFlag,
boolean isMultiValued,
boolean isHidden,
Class componentType,
List<String> validOptions) {
this.ioType = ArgumentIOType.getIOType(annotation);
this.argumentType = argumentType;
this.fullName = getFullName(annotation, fieldName);
this.shortName = getShortName(annotation);
this.doc = getDoc(annotation);
this.required = isRequired(annotation, isFlag);
this.isFlag = isFlag;
this.isMultiValued = isMultiValued;
this.isHidden = isHidden;
this.componentType = componentType;
this.exclusiveOf = getExclusiveOf(annotation);
this.validation = getValidationRegex(annotation);
this.validOptions = validOptions;
}
@Override @Override
public int hashCode() { public int hashCode() {
int hashCode = fullName.hashCode(); int hashCode = fullName.hashCode();
@ -250,20 +227,6 @@ public class ArgumentDefinition {
Utils.equals(shortName,other.shortName); Utils.equals(shortName,other.shortName);
} }
/**
* A hack to get around the fact that Java doesn't like inheritance in Annotations.
* @param annotation to run the method on
* @param method the method to invoke
* @return the return value of the method
*/
private static Object getValue(Annotation annotation, String method) {
try {
return annotation.getClass().getMethod(method).invoke(annotation);
} catch (Exception e) {
throw new StingException("Unable to access method " + method + " on annotation " + annotation.getClass(), e);
}
}
/** /**
* Retrieves the full name of the argument, specifiable with the '--' prefix. The full name can be * Retrieves the full name of the argument, specifiable with the '--' prefix. The full name can be
* either specified explicitly with the fullName annotation parameter or implied by the field name. * either specified explicitly with the fullName annotation parameter or implied by the field name.
@ -271,8 +234,8 @@ public class ArgumentDefinition {
* @param fieldName Original field name. * @param fieldName Original field name.
* @return full name of the argument. Never null. * @return full name of the argument. Never null.
*/ */
private static String getFullName( Annotation annotation, String fieldName ) { public static String getFullName( Annotation annotation, String fieldName ) {
String fullName = (String)getValue(annotation, "fullName"); String fullName = (String)CommandLineUtils.getValue(annotation, "fullName");
return fullName.trim().length() > 0 ? fullName.trim() : fieldName.toLowerCase(); return fullName.trim().length() > 0 ? fullName.trim() : fieldName.toLowerCase();
} }
@ -282,8 +245,8 @@ public class ArgumentDefinition {
* @param annotation Original field annotation. * @param annotation Original field annotation.
* @return short name of the argument. Null if no short name exists. * @return short name of the argument. Null if no short name exists.
*/ */
private static String getShortName( Annotation annotation ) { public static String getShortName( Annotation annotation ) {
String shortName = (String)getValue(annotation, "shortName"); String shortName = (String)CommandLineUtils.getValue(annotation, "shortName");
return shortName.trim().length() > 0 ? shortName.trim() : null; return shortName.trim().length() > 0 ? shortName.trim() : null;
} }
@ -292,19 +255,8 @@ public class ArgumentDefinition {
* @param annotation Original field annotation. * @param annotation Original field annotation.
* @return Documentation for this argument. * @return Documentation for this argument.
*/ */
private static String getDoc( Annotation annotation ) { public static String getDoc( Annotation annotation ) {
return (String)getValue(annotation, "doc"); return (String)CommandLineUtils.getValue(annotation, "doc");
}
/**
* Returns whether this field is required. Note that flag fields are always forced to 'not required'.
* @param annotation Original field annotation.
* @param isFlag True if the field is a flag.
* @return True if the field is mandatory and not a boolean flag. False otherwise.
*/
private static boolean isRequired( Annotation annotation, boolean isFlag ) {
boolean required = (Boolean)getValue(annotation, "required");
return required && !isFlag;
} }
/** /**
@ -312,8 +264,8 @@ public class ArgumentDefinition {
* @param annotation Original field annotation. * @param annotation Original field annotation.
* @return A comma-separated list of exclusive arguments, or null if none are present. * @return A comma-separated list of exclusive arguments, or null if none are present.
*/ */
private static String getExclusiveOf( Annotation annotation ) { public static String getExclusiveOf( Annotation annotation ) {
String exclusiveOf = (String)getValue(annotation, "exclusiveOf"); String exclusiveOf = (String)CommandLineUtils.getValue(annotation, "exclusiveOf");
return exclusiveOf.trim().length() > 0 ? exclusiveOf.trim() : null; return exclusiveOf.trim().length() > 0 ? exclusiveOf.trim() : null;
} }
@ -322,8 +274,8 @@ public class ArgumentDefinition {
* @param annotation Original field annotation. * @param annotation Original field annotation.
* @return a JVM regex-compatible regular expression, or null to permit any possible value. * @return a JVM regex-compatible regular expression, or null to permit any possible value.
*/ */
private static String getValidationRegex( Annotation annotation ) { public static String getValidationRegex( Annotation annotation ) {
String validation = (String)getValue(annotation, "validation"); String validation = (String)CommandLineUtils.getValue(annotation, "validation");
return validation.trim().length() > 0 ? validation.trim() : null; return validation.trim().length() > 0 ? validation.trim() : null;
} }
} }

View File

@ -28,6 +28,7 @@ package org.broadinstitute.sting.commandline;
import org.broadinstitute.sting.utils.StingException; import org.broadinstitute.sting.utils.StingException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.annotation.Annotation;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -152,6 +153,14 @@ public class ArgumentSource {
return typeDescriptor.parse( this, values ); return typeDescriptor.parse( this, values );
} }
/**
* Returns whether this field is required. Note that flag fields are always forced to 'not required'.
* @return True if the field is mandatory and not a boolean flag. False otherwise.
*/
public boolean isRequired() {
return (Boolean)CommandLineUtils.getValue(ArgumentTypeDescriptor.getArgumentAnnotation(this),"required");
}
/** /**
* Returns true if the argument is a flag (a 0-valued argument). * Returns true if the argument is a flag (a 0-valued argument).
* @return True if argument is a flag; false otherwise. * @return True if argument is a flag; false otherwise.

View File

@ -43,7 +43,7 @@ import java.io.OutputStream;
* @author mhanna * @author mhanna
* @version 0.1 * @version 0.1
*/ */
public abstract class ArgumentTypeDescriptor { public abstract class ArgumentTypeDescriptor {
private static Class[] ARGUMENT_ANNOTATIONS = {Input.class, Output.class, Argument.class}; private static Class[] ARGUMENT_ANNOTATIONS = {Input.class, Output.class, Argument.class};
/** /**
@ -142,13 +142,19 @@ public abstract class ArgumentTypeDescriptor {
* @return The default definition for this argument source. * @return The default definition for this argument source.
*/ */
protected ArgumentDefinition createDefaultArgumentDefinition( ArgumentSource source ) { protected ArgumentDefinition createDefaultArgumentDefinition( ArgumentSource source ) {
return new ArgumentDefinition( getArgumentAnnotation(source), Annotation argumentAnnotation = getArgumentAnnotation(source);
return new ArgumentDefinition( ArgumentIOType.getIOType(argumentAnnotation),
source.field.getType(), source.field.getType(),
source.field.getName(), ArgumentDefinition.getFullName(argumentAnnotation, source.field.getName()),
ArgumentDefinition.getShortName(argumentAnnotation),
ArgumentDefinition.getDoc(argumentAnnotation),
source.isRequired() && !source.overridesDefault() && !source.isFlag(),
source.isFlag(), source.isFlag(),
source.isMultiValued(), source.isMultiValued(),
source.isHidden(), source.isHidden(),
getCollectionComponentType(source.field), getCollectionComponentType(source.field),
ArgumentDefinition.getExclusiveOf(argumentAnnotation),
ArgumentDefinition.getValidationRegex(argumentAnnotation),
getValidOptions(source) ); getValidOptions(source) );
} }
@ -222,7 +228,7 @@ public abstract class ArgumentTypeDescriptor {
* @return Argument description annotation associated with the given field. * @return Argument description annotation associated with the given field.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected Annotation getArgumentAnnotation( ArgumentSource source ) { protected static Annotation getArgumentAnnotation( ArgumentSource source ) {
for (Class annotation: ARGUMENT_ANNOTATIONS) for (Class annotation: ARGUMENT_ANNOTATIONS)
if (source.field.isAnnotationPresent(annotation)) if (source.field.isAnnotationPresent(annotation))
return source.field.getAnnotation(annotation); return source.field.getAnnotation(annotation);
@ -463,9 +469,7 @@ class MultiplexArgumentTypeDescriptor extends ArgumentTypeDescriptor {
@Override @Override
public boolean createsTypeDefault(ArgumentSource source,Class type) { public boolean createsTypeDefault(ArgumentSource source,Class type) {
if(multiplexer == null || multiplexedIds == null) // Multiplexing always creates a type default.
throw new StingException("No multiplexed ids available");
// Always create a multiplexed mapping.
return true; return true;
} }

View File

@ -26,10 +26,12 @@
package org.broadinstitute.sting.commandline; package org.broadinstitute.sting.commandline;
import org.broadinstitute.sting.utils.classloader.JVMUtils; import org.broadinstitute.sting.utils.classloader.JVMUtils;
import org.broadinstitute.sting.utils.StingException;
import org.broadinstitute.sting.gatk.GenomeAnalysisEngine; import org.broadinstitute.sting.gatk.GenomeAnalysisEngine;
import org.broadinstitute.sting.gatk.walkers.Walker; import org.broadinstitute.sting.gatk.walkers.Walker;
import java.util.*; import java.util.*;
import java.lang.annotation.Annotation;
/** /**
* Static utility methods for working with command-line arguments. * Static utility methods for working with command-line arguments.
@ -86,6 +88,19 @@ public class CommandLineUtils {
} }
return sb.toString(); return sb.toString();
} }
/**
* A hack to get around the fact that Java doesn't like inheritance in Annotations.
* @param annotation to run the method on
* @param method the method to invoke
* @return the return value of the method
*/
public static Object getValue(Annotation annotation, String method) {
try {
return annotation.getClass().getMethod(method).invoke(annotation);
} catch (Exception e) {
throw new StingException("Unable to access method " + method + " on annotation " + annotation.getClass(), e);
}
}
} }

View File

@ -33,7 +33,7 @@ import java.lang.annotation.*;
@Documented @Documented
@Inherited @Inherited
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD}) @Target(ElementType.FIELD)
public @interface Input { public @interface Input {
/** /**
* The full name of the command-line argument. Full names should be * The full name of the command-line argument. Full names should be
@ -58,8 +58,9 @@ public @interface Input {
String doc(); String doc();
/** /**
* Is this command-line argument required. The application should exit * Is this argument required. If true, the command-line argument system will
* printing help if this command-line argument is not specified. * make a best guess for populating this argument based on the type descriptor,
* and will fail if the type can't be populated.
* @return True if the argument is required. False otherwise. * @return True if the argument is required. False otherwise.
*/ */
boolean required() default true; boolean required() default true;

View File

@ -33,7 +33,7 @@ import java.lang.annotation.*;
@Documented @Documented
@Inherited @Inherited
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD}) @Target(ElementType.FIELD)
public @interface Output { public @interface Output {
/** /**
* The full name of the command-line argument. Full names should be * The full name of the command-line argument. Full names should be
@ -58,11 +58,12 @@ public @interface Output {
String doc() default "An output file presented to the walker. Will overwrite contents if file exists."; String doc() default "An output file presented to the walker. Will overwrite contents if file exists.";
/** /**
* Is this command-line argument required. The application should exit * Is this argument required. If true, the command-line argument system will
* printing help if this command-line argument is not specified. * make a best guess for populating this argument based on the type, and will
* fail if the type can't be populated.
* @return True if the argument is required. False otherwise. * @return True if the argument is required. False otherwise.
*/ */
boolean required() default false; boolean required() default true;
/** /**
* Should this command-line argument be exclusive of others. Should be * Should this command-line argument be exclusive of others. Should be

View File

@ -297,7 +297,7 @@ public class ParsingEngine {
*/ */
private void loadValueIntoObject( ArgumentSource source, Object instance, ArgumentMatches argumentMatches ) { private void loadValueIntoObject( ArgumentSource source, Object instance, ArgumentMatches argumentMatches ) {
// Nothing to load // Nothing to load
if( argumentMatches.size() == 0 && !source.overridesDefault()) if( argumentMatches.size() == 0 && !(source.overridesDefault() && source.isRequired()))
return; return;
// Target instance into which to inject the value. // Target instance into which to inject the value.

View File

@ -116,14 +116,19 @@ public class SAMFileWriterArgumentTypeDescriptor extends ArgumentTypeDescriptor
private ArgumentDefinition createBAMArgumentDefinition(ArgumentSource source) { private ArgumentDefinition createBAMArgumentDefinition(ArgumentSource source) {
Annotation annotation = this.getArgumentAnnotation(source); Annotation annotation = this.getArgumentAnnotation(source);
return new ArgumentDefinition( annotation, return new ArgumentDefinition( annotation,
ArgumentIOType.getIOType(annotation),
source.field.getType(), source.field.getType(),
DEFAULT_ARGUMENT_FULLNAME, DEFAULT_ARGUMENT_FULLNAME,
DEFAULT_ARGUMENT_SHORTNAME, DEFAULT_ARGUMENT_SHORTNAME,
ArgumentDefinition.getDoc(annotation),
true,
false, false,
source.isMultiValued(), source.isMultiValued(),
source.isHidden(), source.isHidden(),
getCollectionComponentType(source.field), null,
null ); null,
null,
null);
} }
/** /**

View File

@ -60,10 +60,10 @@ public class UnifiedGenotyper extends LocusWalker<VariantCallContext, UnifiedGen
protected String varout; protected String varout;
@Argument(fullName = "verbose_mode", shortName = "verbose", doc = "File to print all of the annotated and detailed debugging output", required = false) @Argument(fullName = "verbose_mode", shortName = "verbose", doc = "File to print all of the annotated and detailed debugging output", required = false)
protected File verboseFile = null; protected PrintStream verboseWriter = null;
@Argument(fullName = "metrics_file", shortName = "metrics", doc = "File to print any relevant callability metrics output", required = false) @Argument(fullName = "metrics_file", shortName = "metrics", doc = "File to print any relevant callability metrics output", required = false)
protected File metricsFile = null; protected PrintStream metricsWriter = null;
@Argument(fullName="annotation", shortName="A", doc="One or more specific annotations to apply to variant calls", required=false) @Argument(fullName="annotation", shortName="A", doc="One or more specific annotations to apply to variant calls", required=false)
protected List<String> annotationsToUse = new ArrayList<String>(); protected List<String> annotationsToUse = new ArrayList<String>();
@ -87,9 +87,6 @@ public class UnifiedGenotyper extends LocusWalker<VariantCallContext, UnifiedGen
// enable extended events for indels // enable extended events for indels
public boolean generateExtendedEvents() { return UAC.genotypeModel == GenotypeCalculationModel.Model.INDELS; } public boolean generateExtendedEvents() { return UAC.genotypeModel == GenotypeCalculationModel.Model.INDELS; }
private PrintStream verboseWriter;
private PrintStream metricsWriter;
/** /**
* Inner class for collecting output statistics from the UG * Inner class for collecting output statistics from the UG
*/ */
@ -119,19 +116,6 @@ public class UnifiedGenotyper extends LocusWalker<VariantCallContext, UnifiedGen
* *
**/ **/
public void initialize() { public void initialize() {
try {
if(verboseWriter != null) verboseWriter = new PrintStream(verboseFile);
}
catch(FileNotFoundException ex) {
throw new StingException("Unable to create verbose writer from provided file "+verboseFile,ex);
}
try {
if(metricsWriter != null) metricsWriter = new PrintStream(metricsFile);
}
catch(FileNotFoundException ex) {
throw new StingException("Unable to create metrics writer from provided file "+metricsFile,ex);
}
annotationEngine = new VariantAnnotatorEngine(getToolkit(), Arrays.asList(annotationClassesToUse), annotationsToUse); annotationEngine = new VariantAnnotatorEngine(getToolkit(), Arrays.asList(annotationClassesToUse), annotationsToUse);
UG_engine = new UnifiedGenotyperEngine(getToolkit(), UAC, logger, writer, verboseWriter, annotationEngine); UG_engine = new UnifiedGenotyperEngine(getToolkit(), UAC, logger, writer, verboseWriter, annotationEngine);