[med-svn] [Git][med-team/q2-cutadapt][upstream] New upstream version 2023.7.0

Étienne Mollier (@emollier) gitlab at salsa.debian.org
Sat Aug 19 10:05:44 BST 2023



Étienne Mollier pushed to branch upstream at Debian Med / q2-cutadapt


Commits:
2bb7a491 by Étienne Mollier at 2023-08-19T10:40:28+02:00
New upstream version 2023.7.0
- - - - -


18 changed files:

- + .github/workflows/ci-dev.yaml
- − .github/workflows/ci.yml
- + .github/workflows/join-release.yaml
- + .github/workflows/tag-release.yaml
- LICENSE
- ci/recipe/meta.yaml
- q2_cutadapt/__init__.py
- q2_cutadapt/_demux.py
- q2_cutadapt/_examples.py
- q2_cutadapt/_trim.py
- q2_cutadapt/_version.py
- q2_cutadapt/plugin_setup.py
- q2_cutadapt/tests/__init__.py
- + q2_cutadapt/tests/data/dual-index-mixed-orientation/forward.fastq.gz
- + q2_cutadapt/tests/data/dual-index-mixed-orientation/reverse.fastq.gz
- q2_cutadapt/tests/test_demux.py
- q2_cutadapt/tests/test_trim.py
- setup.py


Changes:

=====================================
.github/workflows/ci-dev.yaml
=====================================
@@ -0,0 +1,12 @@
+# Example of workflow trigger for calling workflow (the client).
+name: ci-dev
+on:
+  pull_request:
+    branches: ["dev"]
+  push:
+    branches: ["dev"]
+jobs:
+  ci:
+    uses: qiime2/distributions/.github/workflows/lib-ci-dev.yaml at dev
+    with:
+      distro: core
\ No newline at end of file


=====================================
.github/workflows/ci.yml deleted
=====================================
@@ -1,55 +0,0 @@
-# This file is automatically generated by busywork.qiime2.org and
-# template-repos - any manual edits made to this file will be erased when
-# busywork performs maintenance updates.
-
-name: ci
-
-on:
-  pull_request:
-  push:
-    branches:
-      - master
-
-jobs:
-  lint:
-    runs-on: ubuntu-latest
-    steps:
-    - name: checkout source
-      uses: actions/checkout at v2
-
-    - name: set up python 3.8
-      uses: actions/setup-python at v1
-      with:
-        python-version: 3.8
-
-    - name: install dependencies
-      run: python -m pip install --upgrade pip
-
-    - name: lint
-      run: |
-        pip install -q https://github.com/qiime2/q2lint/archive/master.zip
-        q2lint
-        pip install -q flake8
-        flake8
-
-  build-and-test:
-    needs: lint
-    strategy:
-      matrix:
-        os: [ubuntu-latest, macos-latest]
-    runs-on: ${{ matrix.os }}
-    steps:
-    - name: checkout source
-      uses: actions/checkout at v2
-      with:
-        fetch-depth: 0
-
-    - name: set up git repo for versioneer
-      run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
-
-    - uses: qiime2/action-library-packaging at alpha1
-      with:
-        package-name: q2-cutadapt
-        build-target: dev
-        additional-tests: py.test --pyargs q2_cutadapt
-        library-token: ${{ secrets.LIBRARY_TOKEN }}


=====================================
.github/workflows/join-release.yaml
=====================================
@@ -0,0 +1,6 @@
+name: join-release
+on:
+  workflow_dispatch: {}
+jobs:
+  release:
+    uses: qiime2/distributions/.github/workflows/lib-join-release.yaml at dev
\ No newline at end of file


=====================================
.github/workflows/tag-release.yaml
=====================================
@@ -0,0 +1,7 @@
+name: tag-release
+on:
+  push:
+    branches: ["Release-*"]
+jobs:
+  tag:
+    uses: qiime2/distributions/.github/workflows/lib-tag-release.yaml at dev
\ No newline at end of file


=====================================
LICENSE
=====================================
@@ -1,6 +1,6 @@
 BSD 3-Clause License
 
-Copyright (c) 2017-2022, QIIME 2 development team.
+Copyright (c) 2017-2023, QIIME 2 development team.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without


=====================================
ci/recipe/meta.yaml
=====================================
@@ -35,6 +35,9 @@ test:
     - q2_cutadapt
     - qiime2.plugins.cutadapt
 
+  commands:
+    - py.test --pyargs q2_cutadapt
+
 about:
   home: https://qiime2.org
   license: BSD-3-Clause


=====================================
q2_cutadapt/__init__.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2017-2022, QIIME 2 development team.
+# Copyright (c) 2017-2023, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2_cutadapt/_demux.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2017-2022, QIIME 2 development team.
+# Copyright (c) 2017-2023, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #
@@ -11,6 +11,7 @@ import os
 import shutil
 import subprocess
 import tempfile
+import warnings
 
 import qiime2
 from q2_types.per_sample_sequences import (
@@ -79,7 +80,7 @@ def _rename_files(seqs_dir_fmt, per_sample_dir_fmt, barcode_series):
         # PAIRED-END
         read_directions.append(2)
 
-    for (sample_id, barcode_id) in barcode_series.iteritems():
+    for (sample_id, barcode_id) in barcode_series.items():
         for read_direction in read_directions:
             out_fp = per_sample_dir_fmt.sequences.path_maker(
                 sample_id=sample_id, barcode_id=barcode_id,
@@ -105,7 +106,7 @@ def _merge_files(src, dst):
 
 def _write_barcode_fasta(barcode_series, barcode_fasta):
     with open(barcode_fasta.name, 'w') as fh:
-        for (sample_id, barcode) in barcode_series.iteritems():
+        for (sample_id, barcode) in barcode_series.items():
             fh.write('>%s\n%s\n' % (sample_id, barcode))
 
 
@@ -122,40 +123,83 @@ def _write_empty_fastq_to_mux_barcode_in_seq_fmt(seqs_dir_fmt):
         seqs_dir_fmt.file.write_data(fastq, FastqGzFormat)
 
 
+def _check_barcodes_uniqueness(
+        forward_barcodes: qiime2.CategoricalMetadataColumn,
+        reverse_barcodes: qiime2.CategoricalMetadataColumn = None,
+        mixed_orientation: bool = False,
+):
+    barcodes = forward_barcodes.to_series().to_frame()
+    # Sets with problematic samples
+    barcode_pairs = set()
+    samples_w_missing_barcodes = set()
+    samples_w_dup_barcode_pairs = set()
+    samples_w_identical_f_r = set()
+    # Test if all barcodes are unique when working with single index for both
+    #  single and mixed orientation
+    if reverse_barcodes is None:
+        for sample_id, fwd_barcode in barcodes.itertuples():
+            if pd.isnull(fwd_barcode):
+                samples_w_missing_barcodes.add(sample_id)
+            if fwd_barcode in barcode_pairs:
+                samples_w_dup_barcode_pairs.add(sample_id)
+            barcode_pairs.add(fwd_barcode)
+        # Raise if issues detected
+        if samples_w_missing_barcodes:
+            raise ValueError('The following samples do not have barcodes '
+                             '(note: if your reads are using single index in '
+                             'mixed orientation, try again with all of your '
+                             'barcodes in a single metadata column): %s'
+                             % ', '.join(sorted(samples_w_missing_barcodes)))
+        if samples_w_dup_barcode_pairs:
+            raise ValueError('The following samples have duplicate barcode: %s'
+                             % ', '.join(sorted(samples_w_dup_barcode_pairs)))
+    # Test if all barcodes are unique when working with dual index for both
+    #  single and mixed orientation
+    else:
+        rev_barcodes = reverse_barcodes.to_series()
+        barcodes = pd.concat([barcodes, rev_barcodes], axis=1, sort=False)
+        for sample_id, fwd_barcode, rev_barcode in barcodes.itertuples():
+            if pd.isnull(fwd_barcode) or pd.isnull(rev_barcode):
+                samples_w_missing_barcodes.add(sample_id)
+            if (fwd_barcode, rev_barcode) in barcode_pairs:
+                samples_w_dup_barcode_pairs.add(sample_id)
+            barcode_pairs.add((fwd_barcode, rev_barcode))
+            if mixed_orientation:
+                barcode_pairs.add((rev_barcode, fwd_barcode))
+                if fwd_barcode == rev_barcode:
+                    samples_w_identical_f_r.add(sample_id)
+        # Raise if issues detected
+        if samples_w_missing_barcodes:
+            raise ValueError('The following samples do not have both forward '
+                             'and reverse barcodes: %s'
+                             % ', '.join(sorted(samples_w_missing_barcodes)))
+        if samples_w_dup_barcode_pairs:
+            raise ValueError('The following samples have duplicate barcode '
+                             '(note: if your reads are in mixed orientation, '
+                             'forward-reverse pairs are also used as '
+                             'reverse-forward pairs): %s'
+                             % ', '.join(sorted(samples_w_dup_barcode_pairs)))
+        if samples_w_identical_f_r:
+            warnings.warn("The following samples are using identical barcode "
+                          "for forward and reverse. Your resulting sequences "
+                          "might have sequences both in their forward and "
+                          "reverse form (you might use the vsearch plugin and "
+                          "perform a de novo clustering with an identity "
+                          "threshold of '1' and the strand parameter set to "
+                          "'both' to merge such sequences together): %s"
+                          % ', '.join(sorted(samples_w_identical_f_r)))
+
+
 def _demux(seqs, per_sample_sequences, forward_barcodes, reverse_barcodes,
            error_tolerance, mux_fmt, batch_size, minimum_length, cores):
     fwd_barcode_name = forward_barcodes.name
     forward_barcodes = forward_barcodes.drop_missing_values()
     barcodes = forward_barcodes.to_series().to_frame()
     if reverse_barcodes is not None:
-        barcode_pairs = set()
-        samples_w_missing_barcodes = set()
-        samples_w_dup_barcode_pairs = set()
         rev_barcode_name = reverse_barcodes.name
         rev_barcodes = reverse_barcodes.to_series()
-        # 'sort = false' below prevents a warning about future behavior changes
-        # by selecting the future behavior explicitly
         barcodes = pd.concat([barcodes, rev_barcodes], axis=1, sort=False)
 
-        for sample_id, f_barcode, r_barcode in barcodes.itertuples():
-            if pd.isnull(f_barcode) or pd.isnull(r_barcode):
-                samples_w_missing_barcodes.add(sample_id)
-            if (f_barcode, r_barcode) in barcode_pairs:
-                samples_w_dup_barcode_pairs.add(sample_id)
-            barcode_pairs.add((f_barcode, r_barcode))
-
-        if samples_w_missing_barcodes:
-            raise ValueError('The following samples do not have both '
-                             'forward and reverse barcodes (note: if your '
-                             'reads are in single index mixed orientation, '
-                             'try again with all of your barcodes in a single '
-                             'metadata column): %s'
-                             % ', '.join(sorted(samples_w_missing_barcodes)))
-        if samples_w_dup_barcode_pairs:
-            raise ValueError('The following samples have duplicate barcode'
-                             ' pairs: %s' %
-                             ', '.join(sorted(samples_w_dup_barcode_pairs)))
-
     n_samples = len(barcodes)
     if batch_size > n_samples:
         raise ValueError('The batch_size (%d) cannot be greater than the '
@@ -199,6 +243,7 @@ def demux_single(seqs: MultiplexedSingleEndBarcodeInSequenceDirFmt,
                  cores: int = 1) -> \
                  (CasavaOneEightSingleLanePerSampleDirFmt,
                   MultiplexedSingleEndBarcodeInSequenceDirFmt):
+    _check_barcodes_uniqueness(barcodes, None, False)
     per_sample_sequences = CasavaOneEightSingleLanePerSampleDirFmt()
     mux_fmt = MultiplexedSingleEndBarcodeInSequenceDirFmt
 
@@ -219,9 +264,8 @@ def demux_paired(seqs: MultiplexedPairedEndBarcodeInSequenceDirFmt,
                  cores: int = 1) -> \
                     (CasavaOneEightSingleLanePerSampleDirFmt,
                      MultiplexedPairedEndBarcodeInSequenceDirFmt):
-    if mixed_orientation and reverse_barcodes is not None:
-        raise ValueError('Dual-indexed barcodes for mixed orientation '
-                         'reads are not supported.')
+    _check_barcodes_uniqueness(
+        forward_barcodes, reverse_barcodes, mixed_orientation)
 
     per_sample_sequences = CasavaOneEightSingleLanePerSampleDirFmt()
     mux_fmt = MultiplexedPairedEndBarcodeInSequenceDirFmt


=====================================
q2_cutadapt/_examples.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2022, QIIME 2 development team.
+# Copyright (c) 2022-2023, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2_cutadapt/_trim.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2017-2022, QIIME 2 development team.
+# Copyright (c) 2017-2023, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2_cutadapt/_version.py
=====================================
@@ -23,9 +23,9 @@ def get_keywords():
     # setup.py/versioneer.py will grep for the variable names, so they must
     # each be defined on a line of their own. _version.py will just call
     # get_keywords().
-    git_refnames = " (HEAD -> master, tag: 2022.11.1)"
-    git_full = "09874d44b1fcbdfe317eef04944e8593d43b03a0"
-    git_date = "2022-12-21 22:17:04 +0000"
+    git_refnames = " (tag: 2023.7.0, Release-2023.7)"
+    git_full = "43cece4fc00d51c08030cfca85f8a615d9d885de"
+    git_date = "2023-08-17 18:35:42 +0000"
     keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
     return keywords
 


=====================================
q2_cutadapt/plugin_setup.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2017-2022, QIIME 2 development team.
+# Copyright (c) 2017-2023, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2_cutadapt/tests/__init__.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2017-2022, QIIME 2 development team.
+# Copyright (c) 2017-2023, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2_cutadapt/tests/data/dual-index-mixed-orientation/forward.fastq.gz
=====================================
Binary files /dev/null and b/q2_cutadapt/tests/data/dual-index-mixed-orientation/forward.fastq.gz differ


=====================================
q2_cutadapt/tests/data/dual-index-mixed-orientation/reverse.fastq.gz
=====================================
Binary files /dev/null and b/q2_cutadapt/tests/data/dual-index-mixed-orientation/reverse.fastq.gz differ


=====================================
q2_cutadapt/tests/test_demux.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2017-2022, QIIME 2 development team.
+# Copyright (c) 2017-2023, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #
@@ -39,7 +39,7 @@ class TestDemuxSingle(TestPluginBase):
         obs_demuxed = obs_demuxed_art.view(
             SingleLanePerSampleSingleEndFastqDirFmt)
         obs_demuxed_seqs = obs_demuxed.sequences.iter_views(FastqGzFormat)
-        zipped = itertools.zip_longest(exp_samples_and_barcodes.iteritems(),
+        zipped = itertools.zip_longest(exp_samples_and_barcodes.items(),
                                        exp_results, obs_demuxed_seqs)
         for (sample_id, barcode), exp, (filename, fmt) in zipped:
             filename = str(filename)
@@ -326,7 +326,7 @@ class TestDemuxPaired(TestPluginBase):
             SingleLanePerSamplePairedEndFastqDirFmt)
         obs_demuxed_seqs = obs_demuxed.sequences.iter_views(FastqGzFormat)
         # Since we are working with fwd/rev reads, duplicate each list elem
-        exp = [x for x in exp_samples_and_barcodes.iteritems() for _ in (0, 1)]
+        exp = [x for x in exp_samples_and_barcodes.items() for _ in (0, 1)]
         zipped = itertools.zip_longest(exp, exp_results, obs_demuxed_seqs)
         for (sample_id, barcode), exp, (filename, fmt) in zipped:
             filename = str(filename)
@@ -382,7 +382,7 @@ class TestDemuxPaired(TestPluginBase):
             '@id2\nACGTACGT\n+\nzzzzzzzz\n'
             '@id4\nACGTACGT\n+\nzzzzzzzz\n'
             '@id5\nACGTACGT\n+\nzzzzzzzz\n',
-            # sample b, fwd
+            # sample b, rev
             '@id2\nTTTTTGCATGCA\n+\nzzzzzzzzzzzz\n'
             '@id4\nTTTTTGCATGCA\n+\nzzzzzzzzzzzz\n'
             '@id5\nTTTTTGCATGCA\n+\nzzzzzzzzzzzz\n', ]
@@ -396,7 +396,7 @@ class TestDemuxPaired(TestPluginBase):
         self.assert_demux_results(metadata.to_series(), exp, obs_demuxed_art)
         self.assert_untrimmed_results(exp_untrimmed, obs_untrimmed_art)
 
-    def test_di_typical(self):
+    def test_dual_index_success(self):
         forward_barcodes = CategoricalMetadataColumn(
             pd.Series(['AAAA', 'CCCC'], name='ForwardBarcode',
                       index=pd.Index(['sample_a', 'sample_b'], name='id')))
@@ -414,7 +414,7 @@ class TestDemuxPaired(TestPluginBase):
             '@id2\nACGTACGT\n+\nzzzzzzzz\n'
             '@id4\nACGTACGT\n+\nzzzzzzzz\n'
             '@id5\nACGTACGT\n+\nzzzzzzzz\n',
-            # sample a, fwd
+            # sample a, rev
             '@id2\nTGCATGCA\n+\nzzzzzzzz\n'
             '@id4\nTGCATGCA\n+\nzzzzzzzz\n'
             '@id5\nTGCATGCA\n+\nzzzzzzzz\n', ]
@@ -431,6 +431,55 @@ class TestDemuxPaired(TestPluginBase):
                                   obs_demuxed_art)
         self.assert_untrimmed_results(exp_untrimmed, obs_untrimmed_art)
 
+    def test_dual_index_mixed_orientation_success(self):
+        forward_barcodes = CategoricalMetadataColumn(
+            pd.Series(['AAAA', 'CCCC'], name='ForwardBarcode',
+                      index=pd.Index(['sample_a', 'sample_b'], name='id')))
+        reverse_barcodes = CategoricalMetadataColumn(
+            pd.Series(['GGGG', 'TTTT'], name='ReverseBarcode',
+                      index=pd.Index(['sample_a', 'sample_b'], name='id')))
+
+        muxed_mixed_orientation_sequences_f_fp = self.get_data_path(
+            'dual-index-mixed-orientation/forward.fastq.gz')
+        muxed_mixed_orientation_sequences_r_fp = self.get_data_path(
+            'dual-index-mixed-orientation/reverse.fastq.gz')
+        with tempfile.TemporaryDirectory() as temp:
+            shutil.copy(muxed_mixed_orientation_sequences_f_fp, temp)
+            shutil.copy(muxed_mixed_orientation_sequences_r_fp, temp)
+            muxed_mixed_orientation_sequences = Artifact.import_data(
+                'MultiplexedPairedEndBarcodeInSequence', temp)
+
+        with redirected_stdio(stderr=os.devnull):
+            obs_demuxed_art, obs_untrimmed_art = \
+                self.demux_paired_fn(muxed_mixed_orientation_sequences,
+                                     forward_barcodes=forward_barcodes,
+                                     reverse_barcodes=reverse_barcodes,
+                                     mixed_orientation=True)
+        exp = [
+            # sample a, fwd
+            '@id1\nACGTACGT\n+\nzzzzzzzz\n'
+            '@id3\nACGTACGT\n+\nzzzzzzzz\n',
+            # sample a, rev
+            '@id1\nTGCATGCA\n+\nzzzzzzzz\n'
+            '@id3\nTGCATGCA\n+\nzzzzzzzz\n',
+            # sample b, fwd
+            '@id2\nACGTACGT\n+\nzzzzzzzz\n'
+            '@id4\nACGTACGT\n+\nzzzzzzzz\n'
+            '@id5\nACGTACGT\n+\nzzzzzzzz\n',
+            # sample a, rev
+            '@id2\nTGCATGCA\n+\nzzzzzzzz\n'
+            '@id4\nTGCATGCA\n+\nzzzzzzzz\n'
+            '@id5\nTGCATGCA\n+\nzzzzzzzz\n', ]
+        exp_untrimmed = ['@id6\nTTTTTGCATGCA\n+\nzzzzzzzzzzzz\n',
+                         '@id6\nGGGGACGTACGT\n+\nzzzzzzzzzzzz\n', ]
+        # Rem: untrimmed sequences are in reverse order compared to
+        # `test_dual_index_success` because `demux_paired()` exchange forward
+        # reverse sequence after a first demux when `mixed_orientation` is used
+
+        self.assert_demux_results(forward_barcodes.to_series(), exp,
+                                  obs_demuxed_art)
+        self.assert_untrimmed_results(exp_untrimmed, obs_untrimmed_art)
+
     def test_mixed_orientation_success(self):
         # sample_a and sample_b have reads in both fwd and rev directions.
         # sample_c only has reads in the fwd direction.
@@ -487,7 +536,7 @@ class TestDemuxPaired(TestPluginBase):
         # Everything should match, so untrimmed should be empty
         self.assert_untrimmed_results(['', ''], obs_untrimmed_art)
 
-    def test_di_mismatched_barcodes(self):
+    def test_dual_index_mismatched_barcodes(self):
         forward_barcodes = CategoricalMetadataColumn(
             pd.Series(['AAAA', 'CCCC', 'ACGT'], name='ForwardBarcode',
                       index=pd.Index(['sample_a', 'sample_b', 'sample_c'],
@@ -501,7 +550,7 @@ class TestDemuxPaired(TestPluginBase):
                                  forward_barcodes=forward_barcodes,
                                  reverse_barcodes=reverse_barcodes)
 
-    def test_di_duplicate_barcode_pairs(self):
+    def test_dual_index_duplicate_barcode_pairs_not_mixed(self):
         forward_barcodes = CategoricalMetadataColumn(
             pd.Series(['AAAA', 'CCCC', 'AAAA', 'CCCC'], name='ForwardBarcode',
                       index=pd.Index(
@@ -519,35 +568,24 @@ class TestDemuxPaired(TestPluginBase):
                                  forward_barcodes=forward_barcodes,
                                  reverse_barcodes=reverse_barcodes)
 
-    def test_multiple_orientations_dual_indices(self):
+    def test_dual_index_duplicate_barcode_pairs_mixed(self):
         forward_barcodes = CategoricalMetadataColumn(
-            pd.Series(['AAAA', 'CCCC'], name='ForwardBarcode',
-                      index=pd.Index(['sample_a', 'sample_b'], name='id')))
+            pd.Series(['AAAA', 'CCCC', 'GGGG', 'TTTT'], name='ForwardBarcode',
+                      index=pd.Index(
+                            ['sample_a', 'sample_b', 'sample_d', 'sample_c'],
+                            name='id')))
         reverse_barcodes = CategoricalMetadataColumn(
-            pd.Series(['GGGG', 'TTTT'], name='ReverseBarcode',
-                      index=pd.Index(['sample_a', 'sample_b'], name='id')))
-
-        mixed_orientation_sequences_f_fp = self.get_data_path(
-            'mixed-orientation/forward.fastq.gz')
-        mixed_orientation_sequences_r_fp = self.get_data_path(
-            'mixed-orientation/reverse.fastq.gz')
-
-        # These files have forward and reverse reads mixed together in the same
-        # file
-        with tempfile.TemporaryDirectory() as temp:
-            shutil.copy(mixed_orientation_sequences_f_fp, temp)
-            shutil.copy(mixed_orientation_sequences_r_fp, temp)
-            mixed_orientation_sequences = Artifact.import_data(
-                'MultiplexedPairedEndBarcodeInSequence', temp)
+            pd.Series(['GGGG', 'TTTT', 'AAAA', 'CCCC'], name='ReverseBarcode',
+                      index=pd.Index(
+                            ['sample_a', 'sample_b', 'sample_d', 'sample_c'],
+                            name='id')))
 
-        with self.assertRaisesRegex(ValueError,
-                                    'Dual-indexed barcodes for mixed '
-                                    'orientation reads are not supported.'):
-            obs_demuxed_art, obs_untrimmed_art = \
-                self.demux_paired_fn(mixed_orientation_sequences,
-                                     forward_barcodes=forward_barcodes,
-                                     reverse_barcodes=reverse_barcodes,
-                                     mixed_orientation=True)
+        with self.assertRaisesRegex(
+                ValueError, 'duplicate barcode.*sample_c.*sample_d'):
+            self.demux_paired_fn(self.muxed_sequences,
+                                 forward_barcodes=forward_barcodes,
+                                 reverse_barcodes=reverse_barcodes,
+                                 mixed_orientation=True)
 
 
 class TestDemuxUtilsSingleEnd(TestPluginBase):
@@ -594,7 +632,7 @@ class TestDemuxUtilsSingleEnd(TestPluginBase):
         seqs = self.per_sample_dir_fmt.sequences.iter_views(FastqGzFormat)
         counter = 0
         for fn, (sample_id, barcode) in zip(seqs,
-                                            self.barcode_series.iteritems()):
+                                            self.barcode_series.items()):
             self.assertTrue(sample_id in str(fn))
             self.assertTrue(barcode in str(fn))
             counter += 1
@@ -613,7 +651,7 @@ class TestDemuxUtilsSingleEnd(TestPluginBase):
 
         seqs = self.per_sample_dir_fmt.sequences.iter_views(FastqGzFormat)
         counter = 0
-        for fn, (sample_id, barcode) in zip(seqs, barcode_series.iteritems()):
+        for fn, (sample_id, barcode) in zip(seqs, barcode_series.items()):
             self.assertTrue(sample_id in str(fn))
             self.assertTrue(barcode in str(fn))
             counter += 1
@@ -631,7 +669,7 @@ class TestDemuxUtilsSingleEnd(TestPluginBase):
         with tempfile.NamedTemporaryFile() as fh:
             _write_barcode_fasta(self.barcode_series, fh)
             fasta = open(fh.name).read()
-            for (sample_id, barcode) in self.barcode_series.iteritems():
+            for (sample_id, barcode) in self.barcode_series.items():
                 self.assertTrue(sample_id in fasta)
                 self.assertTrue(barcode in fasta)
 
@@ -675,7 +713,7 @@ class TestDemuxUtilsPairedEnd(TestPluginBase):
         exp_r = str(self.seqs_dir_fmt.reverse_sequences.view(FastqGzFormat))
         self.assertEqual(exp_r, obs[16])
 
-    def test_build_di_demux_command(self):
+    def test_build_dual_index_demux_command(self):
         with tempfile.NamedTemporaryFile() as barcode_fasta_f:
             with tempfile.NamedTemporaryFile() as barcode_fasta_r:
                 obs = _build_demux_command(self.seqs_dir_fmt,


=====================================
q2_cutadapt/tests/test_trim.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2017-2022, QIIME 2 development team.
+# Copyright (c) 2017-2023, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
setup.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2017-2022, QIIME 2 development team.
+# Copyright (c) 2017-2023, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #
@@ -33,6 +33,7 @@ setup(
             'data/single-end-quality/*',
             'data/paired-end-unordered/*',
             'data/mixed-orientation/*',
+            'data/dual-index-mixed-orientation/*',
         ],
     },
     zip_safe=False,



View it on GitLab: https://salsa.debian.org/med-team/q2-cutadapt/-/commit/2bb7a491efc4cbb716413a3fff4b47c053002288

-- 
View it on GitLab: https://salsa.debian.org/med-team/q2-cutadapt/-/commit/2bb7a491efc4cbb716413a3fff4b47c053002288
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20230819/af5a7471/attachment-0001.htm>


More information about the debian-med-commit mailing list