Skip to content

Commit

Permalink
Merge pull request wtsi-npg#857 from wtsi-npg/devel
Browse files Browse the repository at this point in the history
pull from devel to master to create release 101.6.0
  • Loading branch information
jmtcsngr authored Oct 24, 2024
2 parents 942a67a + 764a43a commit 70afcd0
Show file tree
Hide file tree
Showing 14 changed files with 419 additions and 199 deletions.
14 changes: 14 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
LIST OF CHANGES

release 101.6.0 (2024-10-24)
- Added sample_uuid and sample_lims methods to st::api::lims
- Patched st::api::lims::samplesheet to allow for scalar attributes
ending with 's'. Previously the values of attributes with names
ending with 's' were automatically converted to lists. In fact,
this was necessary only for comma-separated strings of email addresses.
The part of code that deals with email addresses was changed to
work on attributes with names starting with 'email' rather than
ending with 's'. Prior to applying this patch the value of the
new 'sample_lims' attribute was returned as a list when a samplesheet
was used as a source of LIMS data.
- Documented handling of multiple values in st::api::lims.
- Added is_lane method and composition_object attribute to st::api::lims.

release 101.5.1 (2024-10-04)
- Added .github/dependabot.yml file to auto-update GitHub actions
- Following a release on 07/09/2024, see https://metacpan.org/dist/App-perlbrew/changes,
Expand Down
1 change: 1 addition & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,7 @@ t/data/run_params/runParameters.hiseqx.xml
t/data/run_params/runParameters.miseq.xml
t/data/run_params/RunParameters.novaseq.xp.lite.xml
t/data/run_params/RunParameters.novaseqx.prod.xml
t/data/samplesheet/data4merge.csv
t/data/samplesheet/samplesheet_7753.csv
t/data/samplesheet/samplesheet_27483.csv
t/data/samplesheet/samplesheet_33990.csv
Expand Down
126 changes: 113 additions & 13 deletions lib/st/api/lims.pm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use Class::Load qw/load_class/;

use npg_tracking::util::types;
use npg_tracking::glossary::rpt;
use npg_tracking::glossary::composition::component::illumina;
use npg_tracking::glossary::composition::factory;
use npg_tracking::glossary::composition::factory::rpt_list;
use npg_tracking::data::reference::util qw/parse_reference_genome_name/;

Expand Down Expand Up @@ -44,18 +46,18 @@ st::api::lims
=head1 DESCRIPTION
Generic NPG LIMS wrapper capable of retrieving data from multiple sources via
a number of source-specific drivers. Provides methods implementing business
logic that is independent of data source.
Generic NPG LIMS wrapper capable of retrieving data from multiple sources of
LIMS data via a number of source-specific drivers. Provides source-independent
set of methods for retrieving LIMS data for different types of entities.
A set of valid arguments to the constructor depends on the driver type. The
drivers are implemented as st::api::lims::<driver_name> classes.
The default driver type is 'samplesheet'. The path to the samplesheet can be
set either in the 'path' constructor attribute or by setting the env. variable
NPG_CACHED_SAMPLESHEET_FILE.
The default driver type is C<samplesheet>. The path to the samplesheet can be
set either in the 'path' constructor attribute or by setting the environment
variable NPG_CACHED_SAMPLESHEET_FILE.
All flavours of the ml_warehouse driver require access to the ml warehouse
All flavours of the C<ml_warehouse> driver require access to the ml warehouse
database. If the mlwh_schema constructor argument is not set, a connection
to the database defined in a standard NPG configuration file is be used.
Expand All @@ -74,6 +76,30 @@ through to the driver are be available as this object's attributes. Example:
print $lims->driver_type; # ml_warehouse
print $lims->iseq_flowcell(); # ERROR
=head2 Handling of Properties that Map to Multiple Values
If a LIMS property C<some_prop> is described by a list of values of similar
semantics and data type, the return value of the C<some_prop> method is an
array of distinct values. Emails of followers, managers, etc. are examples of
this kind of properties.
Complex entities like lanes, tag zero and compositions often represent multiple
individual libraries. Below the rules for computing the return values of
properties for complex entities are demonstrated using the C<sample_name>
property as an example.
If all C<sample_name> values for individual libraries are the same, the return
value of the C<sample_name> property of the complex entity is this common
C<sample_name> value.
If any of C<sample_name> values for individual libraries are different, then
the return value of the C<sample_name> property of the complex entity is C<undef>.
For cases when it is necessary to know all C<sample_name> values of the
constituent libraries, this class provides C<sample_names> method and a number
of other similar methods, see comments for C<ATTRIBUTE_LIST_METHODS> variable
in the code below.
=head1 SUBROUTINES/METHODS
=cut
Expand Down Expand Up @@ -118,6 +144,8 @@ Readonly::Hash my %METHODS_PER_CATEGORY => {
/],

'sample' => [qw/ sample_id
sample_uuid
sample_lims
sample_name
organism_taxon_id
organism
Expand Down Expand Up @@ -221,7 +249,7 @@ sub BUILD {
Returns a hash reference that can be used to initialise st::api::lims
objects similar to this object. The driver details, if present in this
object, are returned under the 'driver_type' key and, if relevant,
'mlwh_schema' key.
'mlwh_schema' key.
=cut
sub copy_init_args {
Expand Down Expand Up @@ -764,7 +792,7 @@ sub _build_separate_y_chromosome_data {
Method returning a list of st::api::lims objects that are associated with this object
and belong to the next (one lower) level. An empty list for a non-pool lane and for a plex.
For a pooled lane contains plex-level objects. On a run level, when the position
For a pooled lane contains plex-level objects. On a run level, when the position
accessor is not set, returns lane level objects. For the st::api::lims type object that
was instantiated with an rpt_list attribute, returns a list of st::api::lims type objects
corresponding to individual components of the composition defined by the rpt_list attribute
Expand Down Expand Up @@ -847,6 +875,76 @@ sub is_composition {
return $self->rpt_list ? 1 : 0;
}

=head2 composition_object
A lazy-build attribute, C<npg_tracking::glossary::composition> object for this
LIMS entity. The value is undefined for a run-level object. For some drivers
the value of C<id_run> attribute might be undefined, in which case the value
of this attribute is undefined. This attribute cannot be set via the constructor.
=cut

has 'composition_object' => (
isa => 'Maybe[npg_tracking::glossary::composition]',
is => 'ro',
required => 0,
init_arg => undef,
lazy_build => 1,
);
sub _build_composition_object {
my $self = shift;

if ($self->is_composition) {
return npg_tracking::glossary::composition::factory::rpt_list
->new(rpt_list => $self->rpt_list)->create_composition();
} else {
if (defined $self->id_run && defined $self->position) {
my $component = npg_tracking::glossary::composition::component::illumina
->new(
id_run => $self->id_run,
position => $self->position,
tag_index => $self->tag_index
);

my $factory = npg_tracking::glossary::composition::factory->new();
$factory->add_component($component);
return $factory->create_composition();
}
}

return;
}

=head2 is_lane
Returns true (1) if this entity corresponds to a lane, false (0) otherwise.
Merged lane entities are not considered to be a lane.
To determine whether the entity is a lane regardless of the way the
C<st::api::lims> is constructed, this method inspects the object returned
by the C<composition_object> method. When the C<composition_object> method
returns an undefined value, this method's return value is false.
st::api::lims->new(id_run => 3, position => 4)->is_lane() # true
st::api::lims->new(rpt_list => '3:4')->is_lane() # true
st::api::lims->new(rpt_list => '2:4;3:4')->is_lane() # false
st::api::lims->new(id_run => 3, position => 4, tag_index => 2)->is_lane() # false
st::api::lims->new(id_run => 3, position => 4, tag_index => 0)->is_lane() # false
=cut

sub is_lane {
my $self = shift;

my $obj = $self->composition_object();
if (defined $obj && $obj->num_components() == 1 &&
!defined $obj->get_component(0)->tag_index) {
return 1;
}

return 0;
}

=head2 aggregate_libraries
Given a list of lane-level C<st::api::lims> objects, finds their children,
Expand Down Expand Up @@ -882,7 +980,7 @@ This method can be used both as instance and as a class method.
my $all_lims = st::api::lims->aggregate_libraries($run_lims->children());
for my $l (@{$all_lims->{'singles'}}) {
print 'No merge for ' . $l->to_string;
print 'No merge for ' . $l->to_string;
}
for my $l (@{$all_lims->{'merges'}}) {
print 'Merged entity ' . $l->to_string;
Expand Down Expand Up @@ -1053,7 +1151,7 @@ sub _validate_lane_numbers {
}

=head2 create_tag_zero_object
Using run ID and position values of this object, creates and returns
st::api::lims object for tag zero. The new object has the same driver
settings as the original object.
Expand Down Expand Up @@ -1133,7 +1231,7 @@ sub descendants {
Method providing fast (index-based) access to child lims object.
Returns a hash ref of st::api::lims children objects
An empty hash for a non-pool lane and for a plex.
For a pooled lane contains plex-level objects. On a run level, when the position
For a pooled lane contains plex-level objects. On a run level, when the position
accessor is not set, returns lane level objects. The hash keys are lane numbers (positions)
or tag indices. _ia stands for index access.
Expand Down Expand Up @@ -1335,7 +1433,9 @@ __END__
=item npg_tracking::glossary::rpt
=item npg_tracking::glossary::composition::factory::rpt
=item npg_tracking::glossary::composition::factory
=item npg_tracking::glossary::composition::factory::rpt_list
=item npg_tracking::glossary::composition::component::illumina
Expand Down
4 changes: 3 additions & 1 deletion lib/st/api/lims/samplesheet.pm
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,9 @@ for my $m ( st::api::lims->driver_method_list_short(__PACKAGE__->meta->get_attri
if (defined $value && $value eq q[]) {
$value = undef;
}
if ($m =~ /s$/smx) {
if ($m =~ /^email_addresses/smx) {
# Handle potentially multiple email addressees, return an array of
# one, none or multiple values.
my @temp = $value ? split $SAMPLESHEET_ARRAY_SEPARATOR, $value : ();
$value = \@temp;
} elsif ($m eq 'required_insert_size_range') {
Expand Down
12 changes: 10 additions & 2 deletions t/40-st-lims-ml_warehouse-drivers.t
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ qr/No record retrieved for st::api::lims::ml_warehouse\w* id_flowcell_lims 22043
};

subtest 'lane-level driver from run-level driver' => sub {
plan tests => 108;
plan tests => 124;

my $count = 0;
for my $p ($mlwh_d, $mlwh_auto_d, $mlwh_auto_d, $mlwh_alt_d) {
Expand Down Expand Up @@ -169,6 +169,8 @@ subtest 'lane-level driver from run-level driver' => sub {
ok (!$d->study_name, 'no study name');
ok (!$d->sample_id, 'no sample_id');
ok (!$d->sample_supplier_name, 'no supplier name');
ok (!$d->sample_uuid, 'no sample uuid');
ok (!$d->sample_lims, 'no sample lims');
ok (!$d->sample_cohort, 'no cohort');
ok (!$d->sample_donor_id, 'no donor id');
is ($d->default_tag_sequence, undef, 'first index sequence undefined');
Expand All @@ -184,6 +186,8 @@ subtest 'lane-level driver from run-level driver' => sub {
ok(!$lims1->sample_consent_withdrawn(), 'sample consent not withdrawn');
is ($lims1->sample_id, 7283, 'sample id');
is ($lims1->sample_supplier_name, 'sample_33', 'supplier name');
is ($lims1->sample_uuid, 'fdb13110-6a55-11e4-8e19-68b59977951c', 'sample uuid');
is ($lims1->sample_lims, 'CLARITY', 'sample lims');
is ($lims1->sample_cohort, 'plan2', 'cohort');
is ($lims1->sample_donor_id, 'd5678', 'donor id');
is ($lims1->purpose, 'qc', 'purpose');
Expand Down Expand Up @@ -276,7 +280,7 @@ sub _add2query {
}

subtest 'lane and tag level drivers' => sub {
plan tests => 136;
plan tests => 152;

my $lims_id = 16249;
my $id_run = 45678;
Expand Down Expand Up @@ -323,6 +327,8 @@ subtest 'lane and tag level drivers' => sub {
is (scalar $lims->children, 9, 'tag zero - nine-long children list');
is ($lims->spiked_phix_tag_index, 168, 'spike index');
ok (!$lims->sample_supplier_name, 'no supplier name');
ok (!$lims->sample_uuid, 'no sample uuid');
ok (!$lims->sample_lims, 'no sample lims');
ok (!$lims->sample_cohort, 'no cohort');
ok (!$lims->sample_donor_id, 'no donor id');
is ($lims->default_tag_sequence, undef, 'first index sequence undefined');
Expand All @@ -340,6 +346,8 @@ subtest 'lane and tag level drivers' => sub {
ok (!$lims->is_control, 'tag 2 is not control');
is ($lims->sample_id, 1092803, 'sample id');
is ($lims->sample_supplier_name, 'sample_33', 'supplier name');
is ($lims->sample_uuid, 'f44b2ec0-6f67-11e4-a268-68b59977951c', 'sample uuid');
is ($lims->sample_lims, 'SQSCP', 'sample lims');
is ($lims->sample_cohort, 'plan1', 'cohort');
is ($lims->sample_donor_id, '5678', 'donor id');
is ($lims->default_tag_sequence, 'CGATGT', 'first index sequence');
Expand Down
24 changes: 23 additions & 1 deletion t/40-st-lims-samplesheet.t
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use strict;
use warnings;
use Test::More tests => 11;
use Test::More tests => 12;
use Test::Exception;
use Test::Warn;
use File::Slurp;
Expand Down Expand Up @@ -397,4 +397,26 @@ subtest 'dual index default' => sub {
is($p->default_tagtwo_sequence, undef, 'no second index');
};

subtest 'sample uuid and LIMS id' => sub {
plan tests => 10;

my $path = 't/data/samplesheet/4pool4libs_extended.csv';
my $ss = st::api::lims::samplesheet->new(id_run => 6946, position => 1, path => $path);
ok (!$ss->is_pool, 'lane 1 is not a pool');
is ($ss->sample_uuid, 'c46e1810-e8aa-11e2-aafd-68b59976a382', 'sample uuid');
is ($ss->sample_lims, 'SQSCP', 'sample lims');
$ss = st::api::lims::samplesheet->new(id_run => 6946, position => 6, path => $path);
ok ($ss->is_pool, 'lane 6 is a pool');
is ($ss->sample_uuid, undef, 'sample uuid is not defined');
is ($ss->sample_lims, undef, 'sample lims is not defined');
my @plexes = $ss->children();
is ($plexes[0]->sample_uuid, '62a06c60-2139-11e3-b2c2-68b59976a382',
'sample uuid for a plex');
is ($plexes[0]->sample_lims, 'SQSCP', 'sample lims for a plex');
$ss = st::api::lims::samplesheet->new(
id_run => 6946, position => 6, tag_index => 0, path => $path);
is ($ss->sample_uuid, undef, 'sample uuid is not defined');
is ($ss->sample_lims, undef, 'sample lims is not defined');
};

1;
Loading

0 comments on commit 70afcd0

Please sign in to comment.