<commit_before>import itertools
import options as opt
import plot
import quantifiers
import schema
import textwrap

_INDENT = "    "


class _PiquantOption:
    INDEX = 0

    _OPTIONS = []
    _QUANT_RUN_OPTIONS = []
    _MULTI_QUANT_RUN_OPTIONS = []

    _BASIC_OPTION_TYPE = "BASIC"
    _QUANT_RUN_OPTION_TYPE = "QUANT_RUN"
    _MULTIPLE_QUANT_RUN_OPTION_TYPE = "MULTI_QUANT_RUN"

    def __init__(self, name, description, default_value=None,
                 option_validator=lambda x: True, has_value=True,
                 title=None, is_numeric=False, value_namer=None,
                 file_namer=None, option_type=_BASIC_OPTION_TYPE):

        self.name = name
        self.description = description
        self.default_value = default_value
        self.option_validator = option_validator
        self.has_value = has_value
        self.title = title
        self.is_numeric = is_numeric
        self.value_namer = value_namer if value_namer else lambda x: x
        self.file_namer = file_namer if file_namer else self.value_namer
        self.option_type = option_type

        _PiquantOption._OPTIONS.append(self)

        if option_type != _PiquantOption._BASIC_OPTION_TYPE:
            _PiquantOption._QUANT_RUN_OPTIONS.append(self)
            if option_type == _PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE:
                _PiquantOption._MULTI_QUANT_RUN_OPTIONS.append(self)

        self.index = _PiquantOption.INDEX
        _PiquantOption.INDEX += 1

    def is_quant_run_option(self):
        return self.option_type != _PiquantOption._BASIC_OPTION_TYPE

    def is_multiple_quant_run_option(self):
        return self.option_type == \
            _PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE

    def get_usage_string(self):
        ret = self.get_option_name()
        if self.has_value:
            ret += "=<{val}>".format(
                val=self.get_option_name(include_dashes=False))
        return ret

    def get_option_name(self, include_dashes=True):
        ret = self.name.replace("_", "-")
        if include_dashes:
            ret = "--" + ret
        return ret

    def get_option_description(self):
        ret = self.get_usage_string() + "\n"
        ret += "\n".join(textwrap.wrap(
            self.description, width=75, initial_indent=_INDENT,
            subsequent_indent=_INDENT))
        if self.default_value:
            ret += "\n{ind}[default: {def_val}]".format(
                ind=_INDENT, def_val=self.default_value)
        ret += ".\n"
        return ret

    def get_value_name(self, value):
        return self.value_namer(value)

    def get_file_name_part(self, value):
        return self.file_namer(value)


OPTIONS_FILE = _PiquantOption(
    "options_file",
    "File containing specification of command-line options and values",
    option_validator=lambda x: opt.validate_file_option(
        x, "Option specification file should exist", nullable=True))

READS_OUTPUT_DIR = _PiquantOption(
    "reads_dir",
    "Parent output directory to which read simulation directories will be " +
    "written",
    default_value="output")

QUANT_OUTPUT_DIR = _PiquantOption(
    "quant_dir",
    "Parent output directory to which quantification run directories will be " +
    "written",
    default_value="output")

STATS_DIRECTORY = _PiquantOption(
    "stats_dir",
    "Directory to output assembled stats and graphs to",
    default_value="output/analysis")

NUM_MOLECULES = _PiquantOption(
    "num_molecules",
    "Flux Simulator parameters will be set for the main simulation to start " +
    "with this number of transcript molecules in the initial population",
    default_value="30000000",
    option_validator=lambda x: opt.validate_int_option(
        x, "Number of molecules must be a positive integer", min_val=1),
    option_type=_PiquantOption._QUANT_RUN_OPTION_TYPE)

NUM_NOISE_MOLECULES = _PiquantOption(
    "num_noise_molecules",
    "Flux Simulator parameters will be set for the noise simulation to start " +
    "with this number of noise transcript molecules in the initial population",
    default_value="2000000",
    option_validator=lambda x: opt.validate_int_option(
        x, "Number of noise molecules must be a positive integer", min_val=1),
    option_type=_PiquantOption._QUANT_RUN_OPTION_TYPE)

NO_CLEANUP = _PiquantOption(
    "nocleanup",
    "If not specified, files non-essential for subsequent quantification " +
    "(when creating reads) and assessing quantification accuracy (when " +
    "quantifying) will be deleted",
    has_value=False)

NUM_THREADS = _PiquantOption(
    "num_threads",
    "Number of threads to be used by multi-threaded quantification methods",
    default_value=1,
    option_validator=lambda x: opt.validate_int_option(
        x, "Number of threads must be a positive integer", min_val=1),
    option_type=_PiquantOption._QUANT_RUN_OPTION_TYPE)

QUANT_METHOD = _PiquantOption(
    "quant_method",
    "Comma-separated list of quantification methods to run",
    title="Quantifier",
    option_validator=lambda x: quantifiers.get_quantification_methods()[x],
    value_namer=lambda x: str(x),
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

READ_DEPTH = _PiquantOption(
    "read_depth",
    "Comma-separated list of read-depths to perform quantification for",
    title="Read depth", option_validator=int, is_numeric=True,
    value_namer=lambda x: "{d}x".format(d=x),
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

READ_LENGTH = _PiquantOption(
    "read_length",
    "Comma-separated list of read-lengths to perform quantification for",
    title="Read length", option_validator=int, is_numeric=True,
    value_namer=lambda x: "{l}b".format(l=x),
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

PAIRED_END = _PiquantOption(
    "paired_end",
    "Comma-separated list of True/False strings indicating whether " +
    "quantification should be performed for single or paired-end reads",
    title="End type", option_validator=opt.check_boolean_value,
    value_namer=lambda x: "paired-end" if x else "single-end",
    file_namer=lambda x: "pe" if x else "se",
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

ERRORS = _PiquantOption(
    "errors",
    "Comma-separated list of True/False strings indicating whether " +
    "quantification should be performed with or without read errors",
    title="Error type", option_validator=opt.check_boolean_value,
    value_namer=lambda x: "with errors" if x else "no errors",
    file_namer=lambda x: "errors" if x else "no_errors",
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

BIAS = _PiquantOption(
    "bias",
    "Comma-separated list of True/False strings indicating whether " +
    "quantification should be performed with or without read sequence bias",
    title="Bias", option_validator=opt.check_boolean_value,
    value_namer=lambda x: "with bias" if x else "no bias",
    file_namer=lambda x: "bias" if x else "no_bias",
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

STRANDED = _PiquantOption(
    "stranded",
    "Comma-separated list of True/False strings indicating whether reads " +
    "should be generated, or quantification performed, simulating a " +
    "protocol that produces stranded reads",
    title="Strandedness", option_validator=opt.check_boolean_value,
    value_namer=lambda x: "stranded" if x else "unstranded",
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

NOISE_DEPTH_PERCENT = _PiquantOption(
    "noise_perc",
    "Comma-separated list of percentages of the overall read-depth: " +
    "quantification will be performed on sets of reads containing noise " +
    "from a specified set of transcripts at these depths",
    title="Noise depth percentage", option_validator=int, is_numeric=True,
    value_namer=lambda x: "no_noise" if x == 0 else "noise-{d}x".format(d=x),
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

TRANSCRIPT_GTF = _PiquantOption(
    "transcript_gtf",
    "GTF formatted file describing the transcripts to be simulated",
    option_validator=lambda x: opt.validate_file_option(
        x, "Transript GTF file does not exist"),
    option_type=_PiquantOption._QUANT_RUN_OPTION_TYPE)

NOISE_TRANSCRIPT_GTF = _PiquantOption(
    "noise_transcript_gtf",
    "GTF formatted file describing transcripts to be simulated as background " +<commit_msg>Reinstate previous of stranded and bias options.<commit_after>import itertools
import options as opt
import plot
import quantifiers
import schema
import textwrap

_INDENT = "    "


class _PiquantOption:
    INDEX = 0

    _OPTIONS = []
    _QUANT_RUN_OPTIONS = []
    _MULTI_QUANT_RUN_OPTIONS = []

    _BASIC_OPTION_TYPE = "BASIC"
    _QUANT_RUN_OPTION_TYPE = "QUANT_RUN"
    _MULTIPLE_QUANT_RUN_OPTION_TYPE = "MULTI_QUANT_RUN"

    def __init__(self, name, description, default_value=None,
                 option_validator=lambda x: True, has_value=True,
                 title=None, is_numeric=False, value_namer=None,
                 file_namer=None, option_type=_BASIC_OPTION_TYPE):

        self.name = name
        self.description = description
        self.default_value = default_value
        self.option_validator = option_validator
        self.has_value = has_value
        self.title = title
        self.is_numeric = is_numeric
        self.value_namer = value_namer if value_namer else lambda x: x
        self.file_namer = file_namer if file_namer else self.value_namer
        self.option_type = option_type

        _PiquantOption._OPTIONS.append(self)

        if option_type != _PiquantOption._BASIC_OPTION_TYPE:
            _PiquantOption._QUANT_RUN_OPTIONS.append(self)
            if option_type == _PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE:
                _PiquantOption._MULTI_QUANT_RUN_OPTIONS.append(self)

        self.index = _PiquantOption.INDEX
        _PiquantOption.INDEX += 1

    def is_quant_run_option(self):
        return self.option_type != _PiquantOption._BASIC_OPTION_TYPE

    def is_multiple_quant_run_option(self):
        return self.option_type == \
            _PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE

    def get_usage_string(self):
        ret = self.get_option_name()
        if self.has_value:
            ret += "=<{val}>".format(
                val=self.get_option_name(include_dashes=False))
        return ret

    def get_option_name(self, include_dashes=True):
        ret = self.name.replace("_", "-")
        if include_dashes:
            ret = "--" + ret
        return ret

    def get_option_description(self):
        ret = self.get_usage_string() + "\n"
        ret += "\n".join(textwrap.wrap(
            self.description, width=75, initial_indent=_INDENT,
            subsequent_indent=_INDENT))
        if self.default_value:
            ret += "\n{ind}[default: {def_val}]".format(
                ind=_INDENT, def_val=self.default_value)
        ret += ".\n"
        return ret

    def get_value_name(self, value):
        return self.value_namer(value)

    def get_file_name_part(self, value):
        return self.file_namer(value)


OPTIONS_FILE = _PiquantOption(
    "options_file",
    "File containing specification of command-line options and values",
    option_validator=lambda x: opt.validate_file_option(
        x, "Option specification file should exist", nullable=True))

READS_OUTPUT_DIR = _PiquantOption(
    "reads_dir",
    "Parent output directory to which read simulation directories will be " +
    "written",
    default_value="output")

QUANT_OUTPUT_DIR = _PiquantOption(
    "quant_dir",
    "Parent output directory to which quantification run directories will be " +
    "written",
    default_value="output")

STATS_DIRECTORY = _PiquantOption(
    "stats_dir",
    "Directory to output assembled stats and graphs to",
    default_value="output/analysis")

NUM_MOLECULES = _PiquantOption(
    "num_molecules",
    "Flux Simulator parameters will be set for the main simulation to start " +
    "with this number of transcript molecules in the initial population",
    default_value="30000000",
    option_validator=lambda x: opt.validate_int_option(
        x, "Number of molecules must be a positive integer", min_val=1),
    option_type=_PiquantOption._QUANT_RUN_OPTION_TYPE)

NUM_NOISE_MOLECULES = _PiquantOption(
    "num_noise_molecules",
    "Flux Simulator parameters will be set for the noise simulation to start " +
    "with this number of noise transcript molecules in the initial population",
    default_value="2000000",
    option_validator=lambda x: opt.validate_int_option(
        x, "Number of noise molecules must be a positive integer", min_val=1),
    option_type=_PiquantOption._QUANT_RUN_OPTION_TYPE)

NO_CLEANUP = _PiquantOption(
    "nocleanup",
    "If not specified, files non-essential for subsequent quantification " +
    "(when creating reads) and assessing quantification accuracy (when " +
    "quantifying) will be deleted",
    has_value=False)

NUM_THREADS = _PiquantOption(
    "num_threads",
    "Number of threads to be used by multi-threaded quantification methods",
    default_value=1,
    option_validator=lambda x: opt.validate_int_option(
        x, "Number of threads must be a positive integer", min_val=1),
    option_type=_PiquantOption._QUANT_RUN_OPTION_TYPE)

QUANT_METHOD = _PiquantOption(
    "quant_method",
    "Comma-separated list of quantification methods to run",
    title="Quantifier",
    option_validator=lambda x: quantifiers.get_quantification_methods()[x],
    value_namer=lambda x: str(x),
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

READ_DEPTH = _PiquantOption(
    "read_depth",
    "Comma-separated list of read-depths to perform quantification for",
    title="Read depth", option_validator=int, is_numeric=True,
    value_namer=lambda x: "{d}x".format(d=x),
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

READ_LENGTH = _PiquantOption(
    "read_length",
    "Comma-separated list of read-lengths to perform quantification for",
    title="Read length", option_validator=int, is_numeric=True,
    value_namer=lambda x: "{l}b".format(l=x),
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

PAIRED_END = _PiquantOption(
    "paired_end",
    "Comma-separated list of True/False strings indicating whether " +
    "quantification should be performed for single or paired-end reads",
    title="End type", option_validator=opt.check_boolean_value,
    value_namer=lambda x: "paired-end" if x else "single-end",
    file_namer=lambda x: "pe" if x else "se",
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

ERRORS = _PiquantOption(
    "errors",
    "Comma-separated list of True/False strings indicating whether " +
    "quantification should be performed with or without read errors",
    title="Error type", option_validator=opt.check_boolean_value,
    value_namer=lambda x: "with errors" if x else "no errors",
    file_namer=lambda x: "errors" if x else "no_errors",
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

STRANDED = _PiquantOption(
    "stranded",
    "Comma-separated list of True/False strings indicating whether reads " +
    "should be generated, or quantification performed, simulating a " +
    "protocol that produces stranded reads",
    title="Strandedness", option_validator=opt.check_boolean_value,
    value_namer=lambda x: "stranded" if x else "unstranded",
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

BIAS = _PiquantOption(
    "bias",
    "Comma-separated list of True/False strings indicating whether " +
    "quantification should be performed with or without read sequence bias",
    title="Bias", option_validator=opt.check_boolean_value,
    value_namer=lambda x: "with bias" if x else "no bias",
    file_namer=lambda x: "bias" if x else "no_bias",
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

NOISE_DEPTH_PERCENT = _PiquantOption(
    "noise_perc",
    "Comma-separated list of percentages of the overall read-depth: " +
    "quantification will be performed on sets of reads containing noise " +
    "from a specified set of transcripts at these depths",
    title="Noise depth percentage", option_validator=int, is_numeric=True,
    value_namer=lambda x: "no_noise" if x == 0 else "noise-{d}x".format(d=x),
    option_type=_PiquantOption._MULTIPLE_QUANT_RUN_OPTION_TYPE)

TRANSCRIPT_GTF = _PiquantOption(
    "transcript_gtf",
    "GTF formatted file describing the transcripts to be simulated",
    option_validator=lambda x: opt.validate_file_option(
        x, "Transript GTF file does not exist"),
    option_type=_PiquantOption._QUANT_RUN_OPTION_TYPE)

NOISE_TRANSCRIPT_GTF = _PiquantOption(
    "noise_transcript_gtf",
    "GTF formatted file describing transcripts to be simulated as background " +
{'fraction_non_alphanumeric': 0.08443443740001184, 'fraction_numerical': 0.0028441073650530306, 'mean_word_length': 3.7976122797043774, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3596230', 'n_tokens_mistral': 5432, 'n_tokens_neox': 5304, 'n_words': 1268}