From 63909215a9676eff508859e902cadcff7c12df17 Mon Sep 17 00:00:00 2001 From: Yogesh Pandit Date: Fri, 18 Oct 2013 12:03:25 -0500 Subject: [PATCH 1/3] Script to generate dicty GPI file --- maint/generate_dicty_gpi.pl | 275 ++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 maint/generate_dicty_gpi.pl diff --git a/maint/generate_dicty_gpi.pl b/maint/generate_dicty_gpi.pl new file mode 100644 index 0000000..4e3aef1 --- /dev/null +++ b/maint/generate_dicty_gpi.pl @@ -0,0 +1,275 @@ + +package generate_dicty_gpi; + +use strict; +use feature 'say'; + +use Carp; +use Bio::Chado::Schema; +use IO::String; +use Modware::Legacy::Schema; +use Moose; +use namespace::autoclean; +use Text::CSV; +use Time::Piece; +with 'MooseX::Getopt'; + +has output => ( + is => 'rw', + isa => 'Str', + required => 1, + default => 'dicty_gpi.tsv', + documentation => 'Outfile file to write dictyBase GPI' +); + +has _gpi_header => ( + is => 'ro', + isa => 'Str', + default => sub { + return sprintf "%s\n%s", '!gpi-version: 1.1', '!namespace: dictyBase'; + } +); + +has [qw/dsn user password/] => ( + is => 'rw', + isa => 'Str', + required => 1, + documentation => 'dsn, user password for Oracle Chado schema' +); + +has _schema => ( + is => 'rw', + isa => 'Bio::Chado::Schema', + lazy => 1, + builder => '_build_schema' +); + +sub _build_schema { + my ($self) = @_; + return Bio::Chado::Schema->connect( $self->dsn, $self->user, + $self->password, { LongReadLen => 2**25 } ); +} + +has [qw/legacy_dsn legacy_user legacy_password/] => ( + is => 'rw', + isa => 'Str', + required => 1, + documentation => 'dsn, user, password for legacy Oracle schema' +); + +has _legacy_schema => ( + is => 'rw', + isa => 'Modware::Legacy::Schema', + lazy => 1, + builder => '_build_legacy_schema' +); + +sub _build_legacy_schema { + my ($self) = @_; + return Modware::Legacy::Schema->connect( + $self->legacy_dsn, $self->legacy_user, + $self->legacy_password, { LongReadLen => 2**25 } + ); +} + +has _gene_desc => ( + is => 'rw', + isa => 'HashRef', + traits => [qw/Hash/], + handles => { + get_gene_desc => 'get', + has_gene_desc => 'defined' + }, + lazy => 1, + builder => '_build_gene_desc' +); + +sub _build_gene_desc { + my ($self) = @_; + + my $rs = $self->_legacy_schema->resultset('LocusGp') + ->search( {}, { prefetch => 'locus_gene_product' } ); + + my $hash; + my $desc; + my $date_created; + while ( my $row = $rs->next ) { + if ($date_created) { + my $t + = Time::Piece->strptime( + $row->locus_gene_product->date_created, "%d-%b-%y" ); + if ( $date_created < $t ) { + $desc = $row->locus_gene_product->gene_product; + $date_created = $t; + } + } + else { + $desc = $row->locus_gene_product->gene_product; + $date_created = Time::Piece->strptime( + $row->locus_gene_product->date_created, "%d-%b-%y" ); + } + $hash->{ $row->locus_no } = $desc; + } + return $hash; +} + +has _syns => ( + is => 'rw', + isa => 'HashRef', + traits => [qw/Hash/], + handles => { + get_synonyms => 'get', + has_synonyms => 'defined' + }, + lazy => 1, + builder => '_build_synonyms' +); + +sub _build_synonyms { + my ($self) = @_; + + my $hash; + my $syns = $self->_schema->storage->dbh->selectall_arrayref( + qq{ + SELECT DISTINCT fsyn.feature_id, syn.name + FROM feature_synonym fsyn + JOIN synonym_ syn ON syn.synonym_id = fsyn.synonym_id + } + ); + for my $syn ( @{$syns} ) { + if ( !exists $hash->{ $syn->[0] } ) { + $hash->{ $syn->[0] } = []; + } + push $hash->{ $syn->[0] }, $syn->[1]; + } + return $hash; +} + +has _taxon => ( + is => 'ro', + isa => 'Str', + default => 'taxon:44689' +); + +has uniprot_map_file => ( + is => 'rw', + isa => 'Str', + default => + 'http://dictybase.org/db/cgi-bin/dictyBase/download/download.pl?area=general&ID=DDB-GeneID-UniProt.txt', + lazy => 1 +); + +has _uniprot_map => ( + is => 'rw', + isa => 'HashRef', + traits => [qw/Hash/], + handles => { + get_uniprot => 'get', + has_uniprot => 'defined' + }, + builder => '_build_uniprot_map' +); + +sub _build_uniprot_map { + my ($self) = @_; + my $hash; + my $ua = LWP::UserAgent->new; + my $response = $ua->get( $self->uniprot_map_file ); + if ( $response->is_success ) { + my $content = $response->decoded_content; + my $csv = Text::CSV->new( { binary => 1 } ) + or croak "Cannot use CSV: " . Text::CSV->error_diag(); + $csv->sep_char("\t"); + my $io = IO::String->new( $content, 'r' ); + while ( my $line = $io->getline() ) { + if ( $csv->parse($line) ) { + my @fields = $csv->fields(); + if ( !exists $hash->{ $fields[1] } ) { + $hash->{ $fields[1] } = []; + } + push $hash->{ $fields[1] }, 'UniProtKB:' . $fields[3] + if $fields[3]; + } + } + $io->close(); + } + else { + croak $response->status_line; + } + return $hash; +} + +sub run { + my ($self) = @_; + + my $out = IO::File->new( $self->output, 'w' ); + $out->print( $self->_gpi_header . "\n" ); + + my $feats = $self->_schema->storage->dbh->selectall_arrayref( + qq{ + SELECT DISTINCT f.feature_id, d.accession, f.name, typ.name + FROM feature f + JOIN dbxref d ON d.dbxref_id = f.dbxref_id + JOIN cvterm typ ON typ.cvterm_id = f.type_id + JOIN organism o ON o.organism_id = f.organism_id + WHERE typ.name = 'gene' + AND o.common_name = 'dicty' + } + ); + + for my $feat ( @{$feats} ) { + + my $gp = ''; + $gp = $self->get_gene_desc( $feat->[0] ) + if $self->has_gene_desc( $feat->[0] ); + + my $syn = ''; + my @syns = @{ $self->get_synonyms( $feat->[0] ) } + if $self->has_synonyms( $feat->[0] ); + $syn = join( '|', @syns ); + + my $db_xref = ''; + my @uniprots = @{ $self->get_uniprot( $feat->[1] ) } + if $self->has_uniprot( $feat->[1] ); + $db_xref = join( '|', @uniprots ); + + my $parent_obj_id = ''; + my $gp_prop = ''; + + my $outstr = sprintf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + $feat->[1], + $feat->[2], $gp, + $syn, $feat->[3], $self->_taxon, $parent_obj_id, $db_xref, + $gp_prop; + $out->print($outstr); + } + $out->close(); + say "dicty GPI with " + . scalar @{$feats} + . " entries written to " + . $self->output; + return; +} + +1; + +package main; +generate_dicty_gpi->new_with_options->run(); + +1; + +__END__ + +=head1 NAME + +generate_dicty_gpi - Script to generate a dictyBase GPI file + +=head1 DESCRIPTION + +GPI is a gene product information file. dictyBase uses it to enhance the literature curation pipeline. + +=head1 SYNOPSIS + +perl -Ilib maint/generate_dicty_gpi.pl --dsn '' --user '' --password '' --legacy_dsn '' --legacy_user '' --legacy_password '' + +=cut From 271486d2c7b363df3a3025200156619b6892667c Mon Sep 17 00:00:00 2001 From: Siddhartha Basu Date: Mon, 2 Dec 2013 17:00:29 -0600 Subject: [PATCH 2/3] Removed underscore attributes Refactored building of gene products and synonyms --- maint/generate_dicty_gpi.pl | 111 ++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/maint/generate_dicty_gpi.pl b/maint/generate_dicty_gpi.pl index 4e3aef1..44839cd 100644 --- a/maint/generate_dicty_gpi.pl +++ b/maint/generate_dicty_gpi.pl @@ -3,8 +3,6 @@ package generate_dicty_gpi; use strict; use feature 'say'; - -use Carp; use Bio::Chado::Schema; use IO::String; use Modware::Legacy::Schema; @@ -12,6 +10,8 @@ package generate_dicty_gpi; use namespace::autoclean; use Text::CSV; use Time::Piece; +use autodie qw/open close/; +use Modware::DataSource::Chado::BCS::Engine::Oracle; with 'MooseX::Getopt'; has output => ( @@ -22,9 +22,10 @@ package generate_dicty_gpi; documentation => 'Outfile file to write dictyBase GPI' ); -has _gpi_header => ( +has gpi_header => ( is => 'ro', isa => 'Str', + traits => [qw/NoGetopt/], default => sub { return sprintf "%s\n%s", '!gpi-version: 1.1', '!namespace: dictyBase'; } @@ -37,19 +38,20 @@ package generate_dicty_gpi; documentation => 'dsn, user password for Oracle Chado schema' ); -has _schema => ( +has schema => ( is => 'rw', + traits => [qw/NoGetopt/], isa => 'Bio::Chado::Schema', lazy => 1, - builder => '_build_schema' + default => sub { + my ($self) = @_; + my $schema = Bio::Chado::Schema->connect( $self->dsn, $self->user, + $self->password, { LongReadLen => 2**25 } ); + Modware::DataSource::Chado::BCS::Engine::Oracle->transform($schema); + return $schema; + } ); -sub _build_schema { - my ($self) = @_; - return Bio::Chado::Schema->connect( $self->dsn, $self->user, - $self->password, { LongReadLen => 2**25 } ); -} - has [qw/legacy_dsn legacy_user legacy_password/] => ( is => 'rw', isa => 'Str', @@ -57,25 +59,25 @@ sub _build_schema { documentation => 'dsn, user, password for legacy Oracle schema' ); -has _legacy_schema => ( +has legacy_schema => ( is => 'rw', isa => 'Modware::Legacy::Schema', + traits => [qw/NoGetopt/], lazy => 1, - builder => '_build_legacy_schema' + default => sub { + my ($self) = @_; + return Modware::Legacy::Schema->connect( + $self->legacy_dsn, $self->legacy_user, + $self->legacy_password, { LongReadLen => 2**25 } + ); + } ); -sub _build_legacy_schema { - my ($self) = @_; - return Modware::Legacy::Schema->connect( - $self->legacy_dsn, $self->legacy_user, - $self->legacy_password, { LongReadLen => 2**25 } - ); -} - -has _gene_desc => ( +has gene_desc => ( is => 'rw', isa => 'HashRef', traits => [qw/Hash/], + traits => [qw/NoGetopt/], handles => { get_gene_desc => 'get', has_gene_desc => 'defined' @@ -90,31 +92,32 @@ sub _build_gene_desc { my $rs = $self->_legacy_schema->resultset('LocusGp') ->search( {}, { prefetch => 'locus_gene_product' } ); - my $hash; - my $desc; - my $date_created; + my $gene_desc_cache; while ( my $row = $rs->next ) { - if ($date_created) { - my $t - = Time::Piece->strptime( + if ( exists $gene_desc_cache->{ $row->locus_no } ) { + my $date_created = Time::Piece->strptime( $row->locus_gene_product->date_created, "%d-%b-%y" ); - if ( $date_created < $t ) { - $desc = $row->locus_gene_product->gene_product; - $date_created = $t; + if ( $date_created > $gene_desc_cache->{ $row->locus_no }->[1] ) { + $gene_desc_cache->{ $row->locus_no } + = [ $row->locus_gene_product->gene_product, + $date_created ]; } } else { - $desc = $row->locus_gene_product->gene_product; - $date_created = Time::Piece->strptime( - $row->locus_gene_product->date_created, "%d-%b-%y" ); + $gene_desc_cache->{ $row->locus_no } = [ + $row->locus_gene_product->gene_product, + = Time::Piece->strptime( + $row->locus_gene_product->date_created, "%d-%b-%y" + ) + ]; } - $hash->{ $row->locus_no } = $desc; } - return $hash; + return { map { $_ => $_->[0] } keys %$gene_desc_cache }; } -has _syns => ( +has syns => ( is => 'rw', + traits => [qw/NoGetopt/], isa => 'HashRef', traits => [qw/Hash/], handles => { @@ -127,33 +130,27 @@ sub _build_gene_desc { sub _build_synonyms { my ($self) = @_; - - my $hash; - my $syns = $self->_schema->storage->dbh->selectall_arrayref( - qq{ - SELECT DISTINCT fsyn.feature_id, syn.name - FROM feature_synonym fsyn - JOIN synonym_ syn ON syn.synonym_id = fsyn.synonym_id - } - ); - for my $syn ( @{$syns} ) { - if ( !exists $hash->{ $syn->[0] } ) { - $hash->{ $syn->[0] } = []; - } - push $hash->{ $syn->[0] }, $syn->[1]; - } - return $hash; + my $synonym_cache; + my $rs = $self->schema->resultset('Sequence::FeatureSynonym')->search({}, {prefetch => 'alternate_names'}); + while (my $row = $rs->next) { + my $syns = [map {$_->name} $row->alternate_names]; + $synonym_cache->{$row->feature_id} = $syns if defined $syns; + } + return $synonym_cache; } has _taxon => ( is => 'ro', isa => 'Str', + traits => [qw/NoGetopt/], + lazy => 1, default => 'taxon:44689' ); has uniprot_map_file => ( - is => 'rw', - isa => 'Str', + is => 'rw', + traits => [qw/NoGetopt/], + isa => 'Str', default => 'http://dictybase.org/db/cgi-bin/dictyBase/download/download.pl?area=general&ID=DDB-GeneID-UniProt.txt', lazy => 1 @@ -161,8 +158,10 @@ sub _build_synonyms { has _uniprot_map => ( is => 'rw', + traits => [qw/NoGetopt/], isa => 'HashRef', traits => [qw/Hash/], + lazy => 1, handles => { get_uniprot => 'get', has_uniprot => 'defined' @@ -203,7 +202,7 @@ sub run { my ($self) = @_; my $out = IO::File->new( $self->output, 'w' ); - $out->print( $self->_gpi_header . "\n" ); + $out->print( $self->gpi_header . "\n" ); my $feats = $self->_schema->storage->dbh->selectall_arrayref( qq{ From 17166dc029e9ed92df02be9503adbcbc00f7af7f Mon Sep 17 00:00:00 2001 From: Siddhartha Basu Date: Thu, 5 Dec 2013 13:29:20 -0600 Subject: [PATCH 3/3] Call the class method to properly register the extra relationship accessor Use BCS to get list of genes Filter for pseudogene Read a compressed gp2protein file for fetching uniprot ids --- .../DataSource/Chado/BCS/Engine/Oracle.pm | 13 +- maint/generate_dicty_gpi.pl | 144 +++++++++--------- 2 files changed, 81 insertions(+), 76 deletions(-) diff --git a/lib/Modware/DataSource/Chado/BCS/Engine/Oracle.pm b/lib/Modware/DataSource/Chado/BCS/Engine/Oracle.pm index f53d45a..f67eb10 100644 --- a/lib/Modware/DataSource/Chado/BCS/Engine/Oracle.pm +++ b/lib/Modware/DataSource/Chado/BCS/Engine/Oracle.pm @@ -19,10 +19,17 @@ sub transform { $schema->source('Sequence::Synonym')->name('synonym_'); $schema->source('Sequence::FeatureSynonym')->add_relationship( - 'alternate_names', - 'Bio::Chado::Schema::Result::Sequence::Synonym', + 'alternate_name', + 'Sequence::Synonym', { 'foreign.synonym_id' => 'self.synonym_id' }, - { accessor => 'single' } + { accessor => 'single' , join_type => 'INNER' } + ); + + $schema->class('Sequence::FeatureSynonym')->add_relationship( + 'alternate_name', + 'Sequence::Synonym', + { 'foreign.synonym_id' => 'self.synonym_id' }, + { accessor => 'single' , join_type => 'INNER' } ); my $syn_source = $schema->source('Cv::Cvtermsynonym'); diff --git a/maint/generate_dicty_gpi.pl b/maint/generate_dicty_gpi.pl index 44839cd..eee2bed 100644 --- a/maint/generate_dicty_gpi.pl +++ b/maint/generate_dicty_gpi.pl @@ -5,10 +5,10 @@ package generate_dicty_gpi; use feature 'say'; use Bio::Chado::Schema; use IO::String; +use IO::Uncompress::Gunzip qw/gunzip $GunzipError/; use Modware::Legacy::Schema; use Moose; use namespace::autoclean; -use Text::CSV; use Time::Piece; use autodie qw/open close/; use Modware::DataSource::Chado::BCS::Engine::Oracle; @@ -35,7 +35,7 @@ package generate_dicty_gpi; is => 'rw', isa => 'Str', required => 1, - documentation => 'dsn, user password for Oracle Chado schema' + documentation => 'credentials for Oracle Chado schema' ); has schema => ( @@ -47,7 +47,8 @@ package generate_dicty_gpi; my ($self) = @_; my $schema = Bio::Chado::Schema->connect( $self->dsn, $self->user, $self->password, { LongReadLen => 2**25 } ); - Modware::DataSource::Chado::BCS::Engine::Oracle->transform($schema); + Modware::DataSource::Chado::BCS::Engine::Oracle->new->transform( + $schema); return $schema; } ); @@ -56,7 +57,7 @@ package generate_dicty_gpi; is => 'rw', isa => 'Str', required => 1, - documentation => 'dsn, user, password for legacy Oracle schema' + documentation => 'credentials for legacy Oracle schema' ); has legacy_schema => ( @@ -76,8 +77,7 @@ package generate_dicty_gpi; has gene_desc => ( is => 'rw', isa => 'HashRef', - traits => [qw/Hash/], - traits => [qw/NoGetopt/], + traits => [qw/NoGetopt Hash/], handles => { get_gene_desc => 'get', has_gene_desc => 'defined' @@ -89,7 +89,7 @@ package generate_dicty_gpi; sub _build_gene_desc { my ($self) = @_; - my $rs = $self->_legacy_schema->resultset('LocusGp') + my $rs = $self->legacy_schema->resultset('LocusGp') ->search( {}, { prefetch => 'locus_gene_product' } ); my $gene_desc_cache; @@ -106,20 +106,22 @@ sub _build_gene_desc { else { $gene_desc_cache->{ $row->locus_no } = [ $row->locus_gene_product->gene_product, - = Time::Piece->strptime( + Time::Piece->strptime( $row->locus_gene_product->date_created, "%d-%b-%y" ) ]; } } - return { map { $_ => $_->[0] } keys %$gene_desc_cache }; + return { + map { $_ => $gene_desc_cache->{$_}->[0] } + keys %$gene_desc_cache + }; } has syns => ( is => 'rw', - traits => [qw/NoGetopt/], + traits => [qw/NoGetopt Hash/], isa => 'HashRef', - traits => [qw/Hash/], handles => { get_synonyms => 'get', has_synonyms => 'defined' @@ -131,15 +133,16 @@ sub _build_gene_desc { sub _build_synonyms { my ($self) = @_; my $synonym_cache; - my $rs = $self->schema->resultset('Sequence::FeatureSynonym')->search({}, {prefetch => 'alternate_names'}); - while (my $row = $rs->next) { - my $syns = [map {$_->name} $row->alternate_names]; - $synonym_cache->{$row->feature_id} = $syns if defined $syns; - } - return $synonym_cache; + my $rs = $self->schema->resultset('Sequence::FeatureSynonym') + ->search( {}, { prefetch => 'alternate_name' } ); + while ( my $row = $rs->next ) { + push @{ $synonym_cache->{ $row->feature_id } }, + $row->alternate_name->name; + } + return $synonym_cache; } -has _taxon => ( +has taxon => ( is => 'ro', isa => 'Str', traits => [qw/NoGetopt/], @@ -152,15 +155,14 @@ sub _build_synonyms { traits => [qw/NoGetopt/], isa => 'Str', default => - 'http://dictybase.org/db/cgi-bin/dictyBase/download/download.pl?area=general&ID=DDB-GeneID-UniProt.txt', + 'http://www.geneontology.org/gp2protein/gp2protein.dictyBase.gz', lazy => 1 ); -has _uniprot_map => ( +has uniprot_map => ( is => 'rw', - traits => [qw/NoGetopt/], + traits => [qw/NoGetopt Hash/], isa => 'HashRef', - traits => [qw/Hash/], lazy => 1, handles => { get_uniprot => 'get', @@ -170,32 +172,37 @@ sub _build_synonyms { ); sub _build_uniprot_map { - my ($self) = @_; - my $hash; + my ($self) = @_; my $ua = LWP::UserAgent->new; my $response = $ua->get( $self->uniprot_map_file ); + my $id_cache; if ( $response->is_success ) { my $content = $response->decoded_content; - my $csv = Text::CSV->new( { binary => 1 } ) - or croak "Cannot use CSV: " . Text::CSV->error_diag(); - $csv->sep_char("\t"); - my $io = IO::String->new( $content, 'r' ); + my $output; + gunzip \$content => \$output or die "gunzip failed: $GunzipError\n"; + my $io = IO::String->new( $output, 'r' ); + LINE: while ( my $line = $io->getline() ) { - if ( $csv->parse($line) ) { - my @fields = $csv->fields(); - if ( !exists $hash->{ $fields[1] } ) { - $hash->{ $fields[1] } = []; + next LINE if $line =~ /^!/; + chomp $line; + my ( $mod, $map ) = split /\t/, $line; + my ($mod_id) = ( ( split /:/, $mod ) )[1]; + if ( $map =~ /\;/ ) { + for my $other ( split /\;/, $map ) { + push @{ $id_cache->{$mod_id} }, $other if $other =~ /UniProt/; } - push $hash->{ $fields[1] }, 'UniProtKB:' . $fields[3] - if $fields[3]; } + else { + push @{ $id_cache->{$mod_id} }, $map; + } + } $io->close(); } else { - croak $response->status_line; + die $response->status_line; } - return $hash; + return $id_cache; } sub run { @@ -204,50 +211,41 @@ sub run { my $out = IO::File->new( $self->output, 'w' ); $out->print( $self->gpi_header . "\n" ); - my $feats = $self->_schema->storage->dbh->selectall_arrayref( - qq{ - SELECT DISTINCT f.feature_id, d.accession, f.name, typ.name - FROM feature f - JOIN dbxref d ON d.dbxref_id = f.dbxref_id - JOIN cvterm typ ON typ.cvterm_id = f.type_id - JOIN organism o ON o.organism_id = f.organism_id - WHERE typ.name = 'gene' - AND o.common_name = 'dicty' - } + my $rs = $self->schema->resultset('Sequence::Feature')->search( + { 'organism.common_name' => 'dicty', + 'type.name' => 'gene', + 'is_deleted' => 0 + }, + { join => [qw/type organism/], prefetch => 'dbxref' } ); - for my $feat ( @{$feats} ) { - - my $gp = ''; - $gp = $self->get_gene_desc( $feat->[0] ) - if $self->has_gene_desc( $feat->[0] ); - - my $syn = ''; - my @syns = @{ $self->get_synonyms( $feat->[0] ) } - if $self->has_synonyms( $feat->[0] ); - $syn = join( '|', @syns ); - - my $db_xref = ''; - my @uniprots = @{ $self->get_uniprot( $feat->[1] ) } - if $self->has_uniprot( $feat->[1] ); - $db_xref = join( '|', @uniprots ); - - my $parent_obj_id = ''; - my $gp_prop = ''; + my $empty_column = ''; + GENE: + while ( my $row = $rs->next ) { + next GENE if $row->name =~ /_ps\d{0,1}$/; + my $feature_id = $row->feature_id; + my $gene_id = $row->dbxref->accession; + my $gp + = $self->has_gene_desc($feature_id) + ? $self->get_gene_desc($feature_id) + : ''; + my $syn + = $self->has_synonyms($feature_id) + ? join( '|', @{ $self->get_synonyms($feature_id) } ) + : ''; + my $dbxref + = $self->has_uniprot($gene_id) + ? join( '|', @{ $self->get_uniprot($gene_id) } ) + : ''; my $outstr = sprintf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", - $feat->[1], - $feat->[2], $gp, - $syn, $feat->[3], $self->_taxon, $parent_obj_id, $db_xref, - $gp_prop; + $row->dbxref->accession, + $row->name, $gp, + $syn, 'gene', $self->taxon, $empty_column, $dbxref, + $empty_column; $out->print($outstr); } $out->close(); - say "dicty GPI with " - . scalar @{$feats} - . " entries written to " - . $self->output; - return; } 1;