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

[FEATURE] Add filedate to VCF file #30

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
30 changes: 30 additions & 0 deletions include/bio/var_io/header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

#pragma once

#include <chrono>
#include <ctime>
#include <iomanip>
#include <map>
#include <regex>
#include <string>
Expand Down Expand Up @@ -163,6 +166,7 @@ class header
* \{
*/
std::string file_format = "VCFv4.3"; //!< The file format version.
std::string file_date = transTime(); //!< The file date.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having file_date as an extra member seems like a good thing! However, I am not sure if I want it to be set automatically, because this results in output not being reproducible by default, which is really annoying when you are checking whether output has changed or not.

Related to this question is also whether BIO should add a line that says that the file was created with BIO. On the one hand, I would like this (advertising for the library); on the other hand, I am often annoyed by bcftools adding so many of those lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So another solution would be to add a field which will be set by the user, e.g. the transTime() function would move to iGenVar. Would also be fine for me.

To your related question, I understand the desire to promote the library, but the important question should be whether it helps the user. At first I thought no, because why do I need to know who created it, since I am interested in the results from the tool itself. But then I thought if I don't understand a VCF line or there are errors in it (something like that) I might want to contact BIO instead of the tool creator that just uses the library. Hmm...

std::vector<filter_t> filters; //!< Header lines describing FILTER fields.
std::vector<info_t> infos; //!< Header lines describing INFO fields.
std::vector<format_t> formats; //!< Header lines describing FORMAT fields.
Expand Down Expand Up @@ -214,6 +218,19 @@ class header
/*!\name Update, reset and inspect
* \{
*/
/*! \brief Gets the current time and transforms it in a nice readable way for the vcf header line fileDate.
*
* \returns a time string in the format: YYYY-MM-DD HH:MM:SS.
*/
std::string transTime()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function seems a little bit out-of-place here, because it is a generic "make a nice date"-function and not specific

I am also not sure what the name implies? 🏳️‍⚧️ 🕐 ? 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that was just a name copy of some funktions I found in the wild wild web.. 🙈 If we ceep the function, we can of course rename it to transformTime for example.

{
std::stringstream text_stream;
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
const std::time_t rawtime = std::chrono::system_clock::to_time_t(now);
text_stream << std::put_time(std::localtime(&rawtime), "%F %T");
std::string time_string = text_stream.str();
return time_string;
}
/*!\brief Add missing IDX fields to header entries and ensure that everything has proper hash-entries.
*
* \details
Expand Down Expand Up @@ -478,6 +495,9 @@ class header
// file format
((raw_data += "##fileformat=") += file_format) += "\n";

// file date
((raw_data += "##fileDate=") += file_date) += "\n";

// filters
for (auto const & filter : filters)
{
Expand Down Expand Up @@ -611,6 +631,10 @@ class header
{
throw format_error{"File has two lines that begin with \"##fileformat\"."};
}
else if (l.starts_with("##fileDate="))
{
parse_file_date_line(l.substr(11));
}
else if (l.starts_with("##INFO="))
{
parse_info_or_format_line(strip_angular_brackets(l.substr(7)), true);
Expand Down Expand Up @@ -641,6 +665,12 @@ class header
}
}

//!\brief Parse an INFO or FORMAT line.
void parse_file_date_line(std::string_view const l)
{
file_date = static_cast<std::string>(l);
}

//!\brief Parse an INFO or FORMAT line.
void parse_info_or_format_line(std::string_view const l, bool const is_info)
{
Expand Down
2 changes: 2 additions & 0 deletions test/snippet/var_io/var_io_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ using namespace seqan3::literals;
// a plaintext header
std::string_view const text_header =
R"(##fileformat=VCFv4.3
##fileDate=2022-03-02 14:18:22
##contig=<ID=20,length=62435964,assembly=B36,md5=f126cdf8a6e0c7f379d618ff66beb2da,species="Homo sapiens",taxonomy=x>
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total Depth">
##INFO=<ID=AF,Number=A,Type=Float,Description="Allele Frequency">
Expand Down Expand Up @@ -92,6 +93,7 @@ bio::var_io::writer writer{"example2.vcf",
// add header so destructor works
std::string_view const text_header =
R"(##fileformat=VCFv4.3
##fileDate=2022-03-02 14:18:22
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT NA00001 NA00002 NA00003
)";
writer.set_header(bio::var_io::header{text_header});
Expand Down
2 changes: 1 addition & 1 deletion test/unit/format/bcf_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ inline constexpr std::string_view example_from_spec_bcf_unbgzf_our{

inline constexpr std::string_view example_from_spec_bcf_header =
R"(##fileformat=VCFv4.3
##fileDate=2022-03-02 14:18:22
##FILTER=<ID=PASS,Description="All filters passed",IDX=0>
##fileDate=20090805
##source=myImputationProgramV3.1
##reference=file:///seq/references/1000GenomesPilot-NCBI36.fasta
##contig=<ID=20,length=62435964,assembly=B36,md5=f126cdf8a6e0c7f379d618ff66beb2da,species="Homo sapiens",taxonomy=x,IDX=0>
Expand Down
10 changes: 5 additions & 5 deletions test/unit/format/vcf_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ inline std::string const example_from_spec_records =

inline std::string const example_from_spec_header =
R"(##fileformat=VCFv4.3
##fileDate=20090805
##fileDate=2022-03-02 14:18:22
##source=myImputationProgramV3.1
##reference=file:///seq/references/1000GenomesPilot-NCBI36.fasta
##contig=<ID=20,length=62435964,assembly=B36,md5=f126cdf8a6e0c7f379d618ff66beb2da,species="Homo sapiens",taxonomy=x>
Expand All @@ -55,6 +55,7 @@ inline std::string const example_from_spec = example_from_spec_header + example_

inline std::string const example_from_spec_header_regenerated =
R"(##fileformat=VCFv4.3
##fileDate=2022-03-02 14:18:22
##FILTER=<ID=PASS,Description="All filters passed",IDX=0>
##FILTER=<ID=q10,Description="Quality below 10",IDX=7>
##FILTER=<ID=s50,Description="Less than 50% of samples have data",IDX=8>
Expand All @@ -69,7 +70,6 @@ inline std::string const example_from_spec_header_regenerated =
##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read Depth",IDX=2>
##FORMAT=<ID=HQ,Number=2,Type=Integer,Description="Haplotype Quality",IDX=11>
##contig=<ID=20,length=62435964,assembly=B36,md5=f126cdf8a6e0c7f379d618ff66beb2da,species="Homo sapiens",taxonomy=x,IDX=0>
##fileDate=20090805
##source=myImputationProgramV3.1
##reference=file:///seq/references/1000GenomesPilot-NCBI36.fasta
##phasing=partial
Expand All @@ -78,6 +78,7 @@ inline std::string const example_from_spec_header_regenerated =

inline std::string const example_from_spec_header_regenerated_no_IDX =
R"(##fileformat=VCFv4.3
##fileDate=2022-03-02 14:18:22
##FILTER=<ID=PASS,Description="All filters passed">
##FILTER=<ID=q10,Description="Quality below 10">
##FILTER=<ID=s50,Description="Less than 50% of samples have data">
Expand All @@ -92,7 +93,6 @@ inline std::string const example_from_spec_header_regenerated_no_IDX =
##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read Depth">
##FORMAT=<ID=HQ,Number=2,Type=Integer,Description="Haplotype Quality">
##contig=<ID=20,length=62435964,assembly=B36,md5=f126cdf8a6e0c7f379d618ff66beb2da,species="Homo sapiens",taxonomy=x>
##fileDate=20090805
##source=myImputationProgramV3.1
##reference=file:///seq/references/1000GenomesPilot-NCBI36.fasta
##phasing=partial
Expand Down Expand Up @@ -165,10 +165,10 @@ inline std::string const minimal_field_rows =

inline std::string const incomplete_header_before =
R"(##fileformat=VCFv4.3
##fileDate=2022-03-02 14:18:22
##FILTER=<ID=PASS,Description="All filters passed",IDX=0>
##INFO=<ID=NS,Number=1,Type=Integer,Description="Number of Samples With Data",IDX=1>
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype",IDX=2>
##fileDate=20090805
##source=myImputationProgramV3.1
##reference=file:///seq/references/1000GenomesPilot-NCBI36.fasta
##phasing=partial
Expand All @@ -177,6 +177,7 @@ inline std::string const incomplete_header_before =

inline std::string const incomplete_header_after =
R"(##fileformat=VCFv4.3
##fileDate=2022-03-02 14:18:22
##FILTER=<ID=PASS,Description="All filters passed",IDX=0>
##FILTER=<ID=q10,Description="Automatically added by SeqAn3.",IDX=9>
##INFO=<ID=NS,Number=1,Type=Integer,Description="Number of Samples With Data",IDX=1>
Expand All @@ -190,7 +191,6 @@ inline std::string const incomplete_header_after =
##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read depth",IDX=3>
##FORMAT=<ID=HQ,Number=2,Type=Integer,Description="Haplotype quality",IDX=8>
##contig=<ID=20,IDX=0>
##fileDate=20090805
##source=myImputationProgramV3.1
##reference=file:///seq/references/1000GenomesPilot-NCBI36.fasta
##phasing=partial
Expand Down
4 changes: 2 additions & 2 deletions test/unit/var_io/var_io_header_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ TEST(var_io_header, spec_from_text)
bio::var_io::header hdr{example_from_spec_header};

EXPECT_EQ(hdr.file_format, "VCFv4.3");
EXPECT_EQ(hdr.file_date, "2022-03-02 14:18:22");

// filters
ASSERT_EQ(hdr.filters.size(), 3);
Expand Down Expand Up @@ -143,8 +144,7 @@ TEST(var_io_header, spec_from_text)
EXPECT_TRUE(*++it == (svpair{"taxonomy", "x"}));

// other lines in header
std::vector<std::string_view> other_lines_cmp{"fileDate=20090805",
"source=myImputationProgramV3.1",
std::vector<std::string_view> other_lines_cmp{"source=myImputationProgramV3.1",
"reference=file:///seq/references/1000GenomesPilot-NCBI36.fasta",
"phasing=partial"};
ASSERT_EQ(hdr.other_lines.size(), other_lines_cmp.size());
Expand Down