[med-svn] [python-cutadapt] 01/04: New upstream version 1.13

Olivier Sallou osallou at debian.org
Mon May 15 11:26:45 UTC 2017


This is an automated email from the git hooks/post-receive script.

osallou pushed a commit to branch master
in repository python-cutadapt.

commit 9b0e316b7075cc3ec0bbddabef0f7fef354cad73
Author: root <root at 601410a29ab0>
Date:   Mon May 15 11:11:00 2017 +0000

    New upstream version 1.13
---
 CHANGES.rst                                        |   21 +
 LICENSE                                            |    2 +-
 PKG-INFO                                           |    2 +-
 cutadapt.egg-info/PKG-INFO                         |    2 +-
 cutadapt.egg-info/SOURCES.txt                      |    5 +
 cutadapt.egg-info/requires.txt                     |    2 +-
 cutadapt/__init__.py                               |    1 +
 cutadapt/_align.c                                  | 1255 +++++++++---
 cutadapt/_align.pyx                                |    4 +-
 cutadapt/_qualtrim.c                               | 1038 +++++-----
 cutadapt/_seqio.c                                  | 1998 +++++++++++++-------
 cutadapt/_seqio.pyx                                |   12 +-
 cutadapt/_version.py                               |    4 +-
 cutadapt/adapters.py                               |  440 +++--
 cutadapt/filters.py                                |   10 +-
 cutadapt/modifiers.py                              |   65 +-
 cutadapt/qualtrim.py                               |   32 +-
 cutadapt/report.py                                 |  157 +-
 cutadapt/scripts/cutadapt.py                       |  215 ++-
 cutadapt/seqio.py                                  |   26 +-
 doc/conf.py                                        |    4 +-
 doc/guide.rst                                      |  123 +-
 doc/installation.rst                               |    3 +-
 setup.py                                           |   26 +-
 .../linked.fasta => cut/linked-anchored.fasta}     |   14 +-
 .../{linked.fasta => linked-not-anchored.fasta}    |   14 +-
 tests/cut/linked.fasta                             |   12 +-
 tests/data/block1.fastq.bz2                        |  Bin 0 -> 87 bytes
 tests/data/block2.fastq.bz2                        |  Bin 0 -> 206 bytes
 tests/data/linked.fasta                            |   12 +-
 tests/data/multiblock.fastq.bz2                    |  Bin 0 -> 293 bytes
 tests/testadapters.py                              |   26 +-
 tests/testcolorspace.py                            |   26 +-
 tests/testpaired.py                                |  134 +-
 tests/tests.py                                     |  194 +-
 tests/testtrim.py                                  |    5 +-
 tests/utils.py                                     |   19 +-
 37 files changed, 3706 insertions(+), 2197 deletions(-)

diff --git a/CHANGES.rst b/CHANGES.rst
index e8b0a39..1ffb8dd 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -2,6 +2,27 @@
 Changes
 =======
 
+v1.13 (2017-03-16)
+------------------
+
+* The 3' adapter of linked adapters can now be anchored. Write
+  ``-a ADAPTER1...ADAPTER2$`` to enable this. Note that the
+  5' adapter is always anchored in this notation.
+* Issue #224: If you want the 5' part of a linked adapter *not* to be
+  anchored, you can now write ``-g ADAPTER...ADAPTER2`` (note ``-g``
+  instead of ``-a``).
+* Issue #236: For more accurate statistics, it is now possible to specify the
+  GC content of the input reads with ``--gc-content``. This does
+  not change trimming results, only the number in the "expect"
+  column of the report. Since this is probably not needed by many
+  people, the option is not listed when running ``cutadapt --help``.
+* Issue #235: Adapter sequences are now required to contain only
+  valid IUPAC codes (lowercase is also allowed, ``U`` is an alias
+  for ``T``). This should help to catch hard-to-find bugs, especially
+  in scripts. Use option ``-N`` to match characters literally
+  (possibly useful for amino acid sequences).
+* Documentation updates and some refactoring of the code
+
 v1.12 (2016-11-28)
 ------------------
 
diff --git a/LICENSE b/LICENSE
index df04e21..1a75412 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2010-2016 Marcel Martin <marcel.martin at scilifelab.se>
+Copyright (c) 2010-2017 Marcel Martin <marcel.martin at scilifelab.se>
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/PKG-INFO b/PKG-INFO
index 2004e95..41bb393 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cutadapt
-Version: 1.12
+Version: 1.13
 Summary: trim adapters from high-throughput sequencing reads
 Home-page: https://cutadapt.readthedocs.io/
 Author: Marcel Martin
diff --git a/cutadapt.egg-info/PKG-INFO b/cutadapt.egg-info/PKG-INFO
index 2004e95..41bb393 100644
--- a/cutadapt.egg-info/PKG-INFO
+++ b/cutadapt.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cutadapt
-Version: 1.12
+Version: 1.13
 Summary: trim adapters from high-throughput sequencing reads
 Home-page: https://cutadapt.readthedocs.io/
 Author: Marcel Martin
diff --git a/cutadapt.egg-info/SOURCES.txt b/cutadapt.egg-info/SOURCES.txt
index 17c943b..6bf83fc 100644
--- a/cutadapt.egg-info/SOURCES.txt
+++ b/cutadapt.egg-info/SOURCES.txt
@@ -71,6 +71,8 @@ tests/cut/illumina5.info.txt
 tests/cut/illumina64.fastq
 tests/cut/interleaved.fastq
 tests/cut/issue46.fasta
+tests/cut/linked-anchored.fasta
+tests/cut/linked-not-anchored.fasta
 tests/cut/linked.fasta
 tests/cut/lowercase.fastq
 tests/cut/lowqual.fastq
@@ -157,6 +159,8 @@ tests/data/anchored-back.fasta
 tests/data/anchored.fasta
 tests/data/anchored_no_indels.fasta
 tests/data/anywhere_repeat.fastq
+tests/data/block1.fastq.bz2
+tests/data/block2.fastq.bz2
 tests/data/dos.fastq
 tests/data/empty.fastq
 tests/data/example.fa
@@ -169,6 +173,7 @@ tests/data/lengths.fa
 tests/data/linked.fasta
 tests/data/lowqual.fastq
 tests/data/maxn.fasta
+tests/data/multiblock.fastq.bz2
 tests/data/multiblock.fastq.gz
 tests/data/nextseq.fastq
 tests/data/no_indels.fasta
diff --git a/cutadapt.egg-info/requires.txt b/cutadapt.egg-info/requires.txt
index 855e83a..313bdeb 100644
--- a/cutadapt.egg-info/requires.txt
+++ b/cutadapt.egg-info/requires.txt
@@ -1 +1 @@
-xopen>=0.1.0
+xopen>=0.1.1
diff --git a/cutadapt/__init__.py b/cutadapt/__init__.py
index b2fcf94..4208614 100644
--- a/cutadapt/__init__.py
+++ b/cutadapt/__init__.py
@@ -6,6 +6,7 @@ from ._version import get_versions
 __version__ = get_versions()['version']
 del get_versions
 
+
 def check_importability():  # pragma: no cover
 	try:
 		import cutadapt._align
diff --git a/cutadapt/_align.c b/cutadapt/_align.c
index 51ea974..414667f 100644
--- a/cutadapt/_align.c
+++ b/cutadapt/_align.c
@@ -1,4 +1,4 @@
-/* Generated by Cython 0.24.1 */
+/* Generated by Cython 0.25.2 */
 
 /* BEGIN: Cython Metadata
 {
@@ -16,7 +16,7 @@ END: Cython Metadata */
 #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03020000)
     #error Cython requires Python 2.6+ or Python 3.2+.
 #else
-#define CYTHON_ABI "0_24_1"
+#define CYTHON_ABI "0_25_2"
 #include <stddef.h>
 #ifndef offsetof
   #define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
@@ -38,6 +38,11 @@ END: Cython Metadata */
 #ifndef DL_EXPORT
   #define DL_EXPORT(t) t
 #endif
+#ifndef HAVE_LONG_LONG
+  #if PY_VERSION_HEX >= 0x03030000 || (PY_MAJOR_VERSION == 2 && PY_VERSION_HEX >= 0x02070000)
+    #define HAVE_LONG_LONG
+  #endif
+#endif
 #ifndef PY_LONG_LONG
   #define PY_LONG_LONG LONG_LONG
 #endif
@@ -46,13 +51,110 @@ END: Cython Metadata */
 #endif
 #ifdef PYPY_VERSION
   #define CYTHON_COMPILING_IN_PYPY 1
+  #define CYTHON_COMPILING_IN_PYSTON 0
+  #define CYTHON_COMPILING_IN_CPYTHON 0
+  #undef CYTHON_USE_TYPE_SLOTS
+  #define CYTHON_USE_TYPE_SLOTS 0
+  #undef CYTHON_USE_ASYNC_SLOTS
+  #define CYTHON_USE_ASYNC_SLOTS 0
+  #undef CYTHON_USE_PYLIST_INTERNALS
+  #define CYTHON_USE_PYLIST_INTERNALS 0
+  #undef CYTHON_USE_UNICODE_INTERNALS
+  #define CYTHON_USE_UNICODE_INTERNALS 0
+  #undef CYTHON_USE_UNICODE_WRITER
+  #define CYTHON_USE_UNICODE_WRITER 0
+  #undef CYTHON_USE_PYLONG_INTERNALS
+  #define CYTHON_USE_PYLONG_INTERNALS 0
+  #undef CYTHON_AVOID_BORROWED_REFS
+  #define CYTHON_AVOID_BORROWED_REFS 1
+  #undef CYTHON_ASSUME_SAFE_MACROS
+  #define CYTHON_ASSUME_SAFE_MACROS 0
+  #undef CYTHON_UNPACK_METHODS
+  #define CYTHON_UNPACK_METHODS 0
+  #undef CYTHON_FAST_THREAD_STATE
+  #define CYTHON_FAST_THREAD_STATE 0
+  #undef CYTHON_FAST_PYCALL
+  #define CYTHON_FAST_PYCALL 0
+#elif defined(PYSTON_VERSION)
+  #define CYTHON_COMPILING_IN_PYPY 0
+  #define CYTHON_COMPILING_IN_PYSTON 1
   #define CYTHON_COMPILING_IN_CPYTHON 0
+  #ifndef CYTHON_USE_TYPE_SLOTS
+    #define CYTHON_USE_TYPE_SLOTS 1
+  #endif
+  #undef CYTHON_USE_ASYNC_SLOTS
+  #define CYTHON_USE_ASYNC_SLOTS 0
+  #undef CYTHON_USE_PYLIST_INTERNALS
+  #define CYTHON_USE_PYLIST_INTERNALS 0
+  #ifndef CYTHON_USE_UNICODE_INTERNALS
+    #define CYTHON_USE_UNICODE_INTERNALS 1
+  #endif
+  #undef CYTHON_USE_UNICODE_WRITER
+  #define CYTHON_USE_UNICODE_WRITER 0
+  #undef CYTHON_USE_PYLONG_INTERNALS
+  #define CYTHON_USE_PYLONG_INTERNALS 0
+  #ifndef CYTHON_AVOID_BORROWED_REFS
+    #define CYTHON_AVOID_BORROWED_REFS 0
+  #endif
+  #ifndef CYTHON_ASSUME_SAFE_MACROS
+    #define CYTHON_ASSUME_SAFE_MACROS 1
+  #endif
+  #ifndef CYTHON_UNPACK_METHODS
+    #define CYTHON_UNPACK_METHODS 1
+  #endif
+  #undef CYTHON_FAST_THREAD_STATE
+  #define CYTHON_FAST_THREAD_STATE 0
+  #undef CYTHON_FAST_PYCALL
+  #define CYTHON_FAST_PYCALL 0
 #else
   #define CYTHON_COMPILING_IN_PYPY 0
+  #define CYTHON_COMPILING_IN_PYSTON 0
   #define CYTHON_COMPILING_IN_CPYTHON 1
+  #ifndef CYTHON_USE_TYPE_SLOTS
+    #define CYTHON_USE_TYPE_SLOTS 1
+  #endif
+  #if PY_MAJOR_VERSION < 3
+    #undef CYTHON_USE_ASYNC_SLOTS
+    #define CYTHON_USE_ASYNC_SLOTS 0
+  #elif !defined(CYTHON_USE_ASYNC_SLOTS)
+    #define CYTHON_USE_ASYNC_SLOTS 1
+  #endif
+  #if PY_VERSION_HEX < 0x02070000
+    #undef CYTHON_USE_PYLONG_INTERNALS
+    #define CYTHON_USE_PYLONG_INTERNALS 0
+  #elif !defined(CYTHON_USE_PYLONG_INTERNALS)
+    #define CYTHON_USE_PYLONG_INTERNALS 1
+  #endif
+  #ifndef CYTHON_USE_PYLIST_INTERNALS
+    #define CYTHON_USE_PYLIST_INTERNALS 1
+  #endif
+  #ifndef CYTHON_USE_UNICODE_INTERNALS
+    #define CYTHON_USE_UNICODE_INTERNALS 1
+  #endif
+  #if PY_VERSION_HEX < 0x030300F0
+    #undef CYTHON_USE_UNICODE_WRITER
+    #define CYTHON_USE_UNICODE_WRITER 0
+  #elif !defined(CYTHON_USE_UNICODE_WRITER)
+    #define CYTHON_USE_UNICODE_WRITER 1
+  #endif
+  #ifndef CYTHON_AVOID_BORROWED_REFS
+    #define CYTHON_AVOID_BORROWED_REFS 0
+  #endif
+  #ifndef CYTHON_ASSUME_SAFE_MACROS
+    #define CYTHON_ASSUME_SAFE_MACROS 1
+  #endif
+  #ifndef CYTHON_UNPACK_METHODS
+    #define CYTHON_UNPACK_METHODS 1
+  #endif
+  #ifndef CYTHON_FAST_THREAD_STATE
+    #define CYTHON_FAST_THREAD_STATE 1
+  #endif
+  #ifndef CYTHON_FAST_PYCALL
+    #define CYTHON_FAST_PYCALL 1
+  #endif
 #endif
-#if !defined(CYTHON_USE_PYLONG_INTERNALS) && CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070000
-  #define CYTHON_USE_PYLONG_INTERNALS 1
+#if !defined(CYTHON_FAST_PYCCALL)
+#define CYTHON_FAST_PYCCALL  (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1)
 #endif
 #if CYTHON_USE_PYLONG_INTERNALS
   #include "longintrepr.h"
@@ -88,24 +190,44 @@ END: Cython Metadata */
 #ifndef Py_TPFLAGS_HAVE_FINALIZE
   #define Py_TPFLAGS_HAVE_FINALIZE 0
 #endif
+#ifndef METH_FASTCALL
+  #define METH_FASTCALL 0x80
+  typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject **args,
+                                              Py_ssize_t nargs, PyObject *kwnames);
+#else
+  #define __Pyx_PyCFunctionFast _PyCFunctionFast
+#endif
+#if CYTHON_FAST_PYCCALL
+#define __Pyx_PyFastCFunction_Check(func)\
+    ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)))))
+#else
+#define __Pyx_PyFastCFunction_Check(func) 0
+#endif
 #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND)
   #define CYTHON_PEP393_ENABLED 1
   #define __Pyx_PyUnicode_READY(op)       (likely(PyUnicode_IS_READY(op)) ?\
                                               0 : _PyUnicode_Ready((PyObject *)(op)))
   #define __Pyx_PyUnicode_GET_LENGTH(u)   PyUnicode_GET_LENGTH(u)
   #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i)
+  #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u)   PyUnicode_MAX_CHAR_VALUE(u)
   #define __Pyx_PyUnicode_KIND(u)         PyUnicode_KIND(u)
   #define __Pyx_PyUnicode_DATA(u)         PyUnicode_DATA(u)
   #define __Pyx_PyUnicode_READ(k, d, i)   PyUnicode_READ(k, d, i)
+  #define __Pyx_PyUnicode_WRITE(k, d, i, ch)  PyUnicode_WRITE(k, d, i, ch)
   #define __Pyx_PyUnicode_IS_TRUE(u)      (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u)))
 #else
   #define CYTHON_PEP393_ENABLED 0
+  #define PyUnicode_1BYTE_KIND  1
+  #define PyUnicode_2BYTE_KIND  2
+  #define PyUnicode_4BYTE_KIND  4
   #define __Pyx_PyUnicode_READY(op)       (0)
   #define __Pyx_PyUnicode_GET_LENGTH(u)   PyUnicode_GET_SIZE(u)
   #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i]))
+  #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u)   ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111)
   #define __Pyx_PyUnicode_KIND(u)         (sizeof(Py_UNICODE))
   #define __Pyx_PyUnicode_DATA(u)         ((void*)PyUnicode_AS_UNICODE(u))
   #define __Pyx_PyUnicode_READ(k, d, i)   ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i]))
+  #define __Pyx_PyUnicode_WRITE(k, d, i, ch)  (((void)(k)), ((Py_UNICODE*)d)[i] = ch)
   #define __Pyx_PyUnicode_IS_TRUE(u)      (0 != PyUnicode_GET_SIZE(u))
 #endif
 #if CYTHON_COMPILING_IN_PYPY
@@ -130,6 +252,13 @@ END: Cython Metadata */
   #define PyObject_Free(p)     PyMem_Free(p)
   #define PyObject_Realloc(p)  PyMem_Realloc(p)
 #endif
+#if CYTHON_COMPILING_IN_PYSTON
+  #define __Pyx_PyCode_HasFreeVars(co)  PyCode_HasFreeVars(co)
+  #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno)
+#else
+  #define __Pyx_PyCode_HasFreeVars(co)  (PyCode_GetNumFree(co) > 0)
+  #define __Pyx_PyFrame_SetLineNumber(frame, lineno)  (frame)->f_lineno = (lineno)
+#endif
 #define __Pyx_PyString_FormatSafe(a, b)   ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b))
 #define __Pyx_PyUnicode_FormatSafe(a, b)  ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b))
 #if PY_MAJOR_VERSION >= 3
@@ -158,6 +287,7 @@ END: Cython Metadata */
   #define PySet_CheckExact(obj)        (Py_TYPE(obj) == &PySet_Type)
 #endif
 #define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type)
+#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception)
 #if PY_MAJOR_VERSION >= 3
   #define PyIntObject                  PyLongObject
   #define PyInt_Type                   PyLong_Type
@@ -196,18 +326,20 @@ END: Cython Metadata */
 #else
   #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass)
 #endif
-#if PY_VERSION_HEX >= 0x030500B1
-#define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
-#define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
-#elif CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
-typedef struct {
-    unaryfunc am_await;
-    unaryfunc am_aiter;
-    unaryfunc am_anext;
-} __Pyx_PyAsyncMethodsStruct;
-#define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
+#if CYTHON_USE_ASYNC_SLOTS
+  #if PY_VERSION_HEX >= 0x030500B1
+    #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
+    #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
+  #else
+    typedef struct {
+        unaryfunc am_await;
+        unaryfunc am_aiter;
+        unaryfunc am_anext;
+    } __Pyx_PyAsyncMethodsStruct;
+    #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
+  #endif
 #else
-#define __Pyx_PyType_AsAsync(obj) NULL
+  #define __Pyx_PyType_AsAsync(obj) NULL
 #endif
 #ifndef CYTHON_RESTRICT
   #if defined(__GNUC__)
@@ -220,10 +352,39 @@ typedef struct {
     #define CYTHON_RESTRICT
   #endif
 #endif
+#ifndef CYTHON_UNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define CYTHON_UNUSED __attribute__ ((__unused__))
+#   else
+#     define CYTHON_UNUSED
+#   endif
+# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
+#   define CYTHON_UNUSED __attribute__ ((__unused__))
+# else
+#   define CYTHON_UNUSED
+# endif
+#endif
+#ifndef CYTHON_MAYBE_UNUSED_VAR
+#  if defined(__cplusplus)
+     template<class T> void CYTHON_MAYBE_UNUSED_VAR( const T& ) { }
+#  else
+#    define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x)
+#  endif
+#endif
+#ifndef CYTHON_NCP_UNUSED
+# if CYTHON_COMPILING_IN_CPYTHON
+#  define CYTHON_NCP_UNUSED
+# else
+#  define CYTHON_NCP_UNUSED CYTHON_UNUSED
+# endif
+#endif
 #define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None)
 
 #ifndef CYTHON_INLINE
-  #if defined(__GNUC__)
+  #if defined(__clang__)
+    #define CYTHON_INLINE __inline__ __attribute__ ((__unused__))
+  #elif defined(__GNUC__)
     #define CYTHON_INLINE __inline__
   #elif defined(_MSC_VER)
     #define CYTHON_INLINE __inline
@@ -285,26 +446,6 @@ static CYTHON_INLINE float __PYX_NAN() {
 #define CYTHON_WITHOUT_ASSERTIONS
 #endif
 
-#ifndef CYTHON_UNUSED
-# if defined(__GNUC__)
-#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
-#     define CYTHON_UNUSED __attribute__ ((__unused__))
-#   else
-#     define CYTHON_UNUSED
-#   endif
-# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
-#   define CYTHON_UNUSED __attribute__ ((__unused__))
-# else
-#   define CYTHON_UNUSED
-# endif
-#endif
-#ifndef CYTHON_NCP_UNUSED
-# if CYTHON_COMPILING_IN_CPYTHON
-#  define CYTHON_NCP_UNUSED
-# else
-#  define CYTHON_NCP_UNUSED CYTHON_UNUSED
-# endif
-#endif
 typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding;
                 const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry;
 
@@ -382,7 +523,7 @@ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
 static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
 static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
 static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS
 #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
 #else
 #define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x)
@@ -629,7 +770,7 @@ struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_2_genexpr {
 #define __Pyx_XCLEAR(r)   do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0)
 
 /* PyObjectGetAttrStr.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_USE_TYPE_SLOTS
 static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) {
     PyTypeObject* tp = Py_TYPE(obj);
     if (likely(tp->tp_getattro))
@@ -673,7 +814,9 @@ static PyObject* __Pyx__CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObje
     ((likely((cfunc)->func)) ?\
         (likely((cfunc)->flag == METH_NOARGS) ?  (*((cfunc)->func))(self, NULL) :\
          (likely((cfunc)->flag == (METH_VARARGS | METH_KEYWORDS)) ?  ((*(PyCFunctionWithKeywords)(cfunc)->func)(self, __pyx_empty_tuple, NULL)) :\
-             ((cfunc)->flag == METH_VARARGS ?  (*((cfunc)->func))(self, __pyx_empty_tuple) : __Pyx__CallUnboundCMethod0(cfunc, self)))) :\
+             ((cfunc)->flag == METH_VARARGS ?  (*((cfunc)->func))(self, __pyx_empty_tuple) :\
+              (PY_VERSION_HEX >= 0x030600B1 && (cfunc)->flag == METH_FASTCALL ?  (*(__Pyx_PyCFunctionFast)(cfunc)->func)(self, &PyTuple_GET_ITEM(__pyx_empty_tuple, 0), 0, NULL) :\
+                __Pyx__CallUnboundCMethod0(cfunc, self))))) :\
         __Pyx__CallUnboundCMethod0(cfunc, self))
 #else
 #define __Pyx_CallUnboundCMethod0(cfunc, self)  __Pyx__CallUnboundCMethod0(cfunc, self)
@@ -711,6 +854,24 @@ static long __Pyx__PyObject_Ord(PyObject* c);
 static CYTHON_INLINE int __Pyx_SetItemInt_ByteArray_Fast(PyObject* string, Py_ssize_t i, unsigned char v,
                                                          int wraparound, int boundscheck);
 
+/* PyCFunctionFastCall.proto */
+#if CYTHON_FAST_PYCCALL
+static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs);
+#else
+#define __Pyx_PyCFunction_FastCall(func, args, nargs)  (assert(0), NULL)
+#endif
+
+/* PyFunctionFastCall.proto */
+#if CYTHON_FAST_PYCALL
+#define __Pyx_PyFunction_FastCall(func, args, nargs)\
+    __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL)
+#if 1 || PY_VERSION_HEX < 0x030600B1
+static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs);
+#else
+#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs)
+#endif
+#endif
+
 /* PyObjectCallMethO.proto */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg);
@@ -739,7 +900,7 @@ static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\
     const char* function_name);
 
 /* PyIntBinop.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if !CYTHON_COMPILING_IN_PYPY
 static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace);
 #else
 #define __Pyx_PyInt_AddObjC(op1, op2, intval, inplace)\
@@ -747,7 +908,7 @@ static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, long intval,
 #endif
 
 /* ListCompAppend.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS
 static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) {
     PyListObject* L = (PyListObject*) list;
     Py_ssize_t len = Py_SIZE(list);
@@ -764,7 +925,7 @@ static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) {
 #endif
 
 /* PyObjectSetAttrStr.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_USE_TYPE_SLOTS
 #define __Pyx_PyObject_DelAttrStr(o,n) __Pyx_PyObject_SetAttrStr(o,n,NULL)
 static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value) {
     PyTypeObject* tp = Py_TYPE(obj);
@@ -835,7 +996,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyBytes_Join(PyObject* sep, PyObject* value
 #endif
 
 /* ListAppend.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS
 static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) {
     PyListObject* L = (PyListObject*) list;
     Py_ssize_t len = Py_SIZE(list);
@@ -856,7 +1017,7 @@ static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, in
     const char *name, int exact);
 
 /* PyThreadStateGet.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_FAST_THREAD_STATE
 #define __Pyx_PyThreadState_declare  PyThreadState *__pyx_tstate;
 #define __Pyx_PyThreadState_assign  __pyx_tstate = PyThreadState_GET();
 #else
@@ -865,7 +1026,7 @@ static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, in
 #endif
 
 /* PyErrFetchRestore.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_FAST_THREAD_STATE
 #define __Pyx_ErrRestoreWithState(type, value, tb)  __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb)
 #define __Pyx_ErrFetchWithState(type, value, tb)    __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb)
 #define __Pyx_ErrRestore(type, value, tb)  __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb)
@@ -994,7 +1155,7 @@ static CYTHON_INLINE unsigned char __Pyx_PyInt_As_unsigned_char(PyObject *);
 static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *);
 
 /* SwapException.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_FAST_THREAD_STATE
 #define __Pyx_ExceptionSwap(type, value, tb)  __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb)
 static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
 #else
@@ -1122,6 +1283,7 @@ static const char __pyx_k_ascii[] = "ascii";
 static const char __pyx_k_close[] = "close";
 static const char __pyx_k_flags[] = "flags";
 static const char __pyx_k_items[] = "items";
+static const char __pyx_k_iupac[] = "iupac";
 static const char __pyx_k_lower[] = "lower";
 static const char __pyx_k_q_ptr[] = "q_ptr";
 static const char __pyx_k_query[] = "query";
@@ -1220,6 +1382,7 @@ static PyObject *__pyx_kp_s_home_marcel_scm_cutadapt_cutada;
 static PyObject *__pyx_n_s_i;
 static PyObject *__pyx_n_s_init;
 static PyObject *__pyx_n_s_items;
+static PyObject *__pyx_n_s_iupac;
 static PyObject *__pyx_n_s_iupac_table;
 static PyObject *__pyx_n_s_j;
 static PyObject *__pyx_n_s_join;
@@ -1384,7 +1547,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
     if (likely(!__pyx_t_4)) {
       if (likely(PyList_CheckExact(__pyx_t_1))) {
         if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_1)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 35, __pyx_L1_error)
         #else
         __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 35, __pyx_L1_error)
@@ -1392,7 +1555,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
         #endif
       } else {
         if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 35, __pyx_L1_error)
         #else
         __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 35, __pyx_L1_error)
@@ -1413,7 +1576,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
     }
     if ((likely(PyTuple_CheckExact(__pyx_t_2))) || (PyList_CheckExact(__pyx_t_2))) {
       PyObject* sequence = __pyx_t_2;
-      #if CYTHON_COMPILING_IN_CPYTHON
+      #if !CYTHON_COMPILING_IN_PYPY
       Py_ssize_t size = Py_SIZE(sequence);
       #else
       Py_ssize_t size = PySequence_Size(sequence);
@@ -1423,7 +1586,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
         else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
         __PYX_ERR(0, 35, __pyx_L1_error)
       }
-      #if CYTHON_COMPILING_IN_CPYTHON
+      #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
       if (likely(PyTuple_CheckExact(sequence))) {
         __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0); 
         __pyx_t_6 = PyTuple_GET_ITEM(sequence, 1); 
@@ -1474,7 +1637,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align__acgt_table(CYTHON_UNUSED PyObject *
     __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_c, __pyx_n_s_lower); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 37, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
     __pyx_t_5 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_6))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_6))) {
       __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6);
       if (likely(__pyx_t_5)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
@@ -1552,7 +1715,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
   long __pyx_v_C;
   long __pyx_v_G;
   long __pyx_v_T;
-  PyObject *__pyx_v_d = NULL;
+  PyObject *__pyx_v_iupac = NULL;
   PyObject *__pyx_v_t = NULL;
   PyObject *__pyx_v_c = NULL;
   PyObject *__pyx_v_v = NULL;
@@ -1661,7 +1824,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
   __Pyx_GOTREF(__pyx_t_2);
   if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_N, __pyx_t_2) < 0) __PYX_ERR(0, 56, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_v_d = ((PyObject*)__pyx_t_1);
+  __pyx_v_iupac = ((PyObject*)__pyx_t_1);
   __pyx_t_1 = 0;
 
   __pyx_t_1 = __Pyx_PyObject_Call(((PyObject *)(&PyByteArray_Type)), __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error)
@@ -1673,7 +1836,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
   __pyx_v_t = ((PyObject*)__pyx_t_2);
   __pyx_t_2 = 0;
 
-  __pyx_t_2 = __Pyx_PyDict_Items(__pyx_v_d); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 75, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyDict_Items(__pyx_v_iupac); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 75, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) {
     __pyx_t_1 = __pyx_t_2; __Pyx_INCREF(__pyx_t_1); __pyx_t_3 = 0;
@@ -1688,7 +1851,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
     if (likely(!__pyx_t_4)) {
       if (likely(PyList_CheckExact(__pyx_t_1))) {
         if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_1)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 75, __pyx_L1_error)
         #else
         __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 75, __pyx_L1_error)
@@ -1696,7 +1859,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
         #endif
       } else {
         if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 75, __pyx_L1_error)
         #else
         __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 75, __pyx_L1_error)
@@ -1717,7 +1880,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
     }
     if ((likely(PyTuple_CheckExact(__pyx_t_2))) || (PyList_CheckExact(__pyx_t_2))) {
       PyObject* sequence = __pyx_t_2;
-      #if CYTHON_COMPILING_IN_CPYTHON
+      #if !CYTHON_COMPILING_IN_PYPY
       Py_ssize_t size = Py_SIZE(sequence);
       #else
       Py_ssize_t size = PySequence_Size(sequence);
@@ -1727,7 +1890,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
         else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
         __PYX_ERR(0, 75, __pyx_L1_error)
       }
-      #if CYTHON_COMPILING_IN_CPYTHON
+      #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
       if (likely(PyTuple_CheckExact(sequence))) {
         __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0); 
         __pyx_t_6 = PyTuple_GET_ITEM(sequence, 1); 
@@ -1778,7 +1941,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
     __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_c, __pyx_n_s_lower); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 77, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
     __pyx_t_5 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_6))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_6))) {
       __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6);
       if (likely(__pyx_t_5)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
@@ -1826,7 +1989,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_2_iupac_table(CYTHON_UNUSED PyObject
   __Pyx_AddTraceback("cutadapt._align._iupac_table", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_d);
+  __Pyx_XDECREF(__pyx_v_iupac);
   __Pyx_XDECREF(__pyx_v_t);
   __Pyx_XDECREF(__pyx_v_c);
   __Pyx_XDECREF(__pyx_v_v);
@@ -1955,7 +2118,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix___init__(CYTHON_UNUSED PyO
     if (likely(!__pyx_t_5)) {
       if (likely(PyList_CheckExact(__pyx_t_4))) {
         if (__pyx_t_1 >= PyList_GET_SIZE(__pyx_t_4)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_3 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_1); __Pyx_INCREF(__pyx_t_3); __pyx_t_1++; if (unlikely(0 < 0)) __PYX_ERR(0, 98, __pyx_L1_error)
         #else
         __pyx_t_3 = PySequence_ITEM(__pyx_t_4, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 98, __pyx_L1_error)
@@ -1963,7 +2126,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix___init__(CYTHON_UNUSED PyO
         #endif
       } else {
         if (__pyx_t_1 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_1); __Pyx_INCREF(__pyx_t_3); __pyx_t_1++; if (unlikely(0 < 0)) __PYX_ERR(0, 98, __pyx_L1_error)
         #else
         __pyx_t_3 = PySequence_ITEM(__pyx_t_4, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 98, __pyx_L1_error)
@@ -2162,10 +2325,12 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_7__str___genexpr(PyObject
   __Pyx_RefNannySetupContext("genexpr", 0);
   __pyx_cur_scope = (struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_1_genexpr *)__pyx_tp_new_8cutadapt_6_align___pyx_scope_struct_1_genexpr(__pyx_ptype_8cutadapt_6_align___pyx_scope_struct_1_genexpr, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
+    __pyx_cur_scope = ((struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_1_genexpr *)Py_None);
+    __Pyx_INCREF(Py_None);
+    __PYX_ERR(0, 112, __pyx_L1_error)
+  } else {
+    __Pyx_GOTREF(__pyx_cur_scope);
   }
-  __Pyx_GOTREF(__pyx_cur_scope);
   __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct____str__ *) __pyx_self;
   __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
   __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
@@ -2222,7 +2387,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_
     if (likely(!__pyx_t_4)) {
       if (likely(PyList_CheckExact(__pyx_t_2))) {
         if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_2)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 112, __pyx_L1_error)
         #else
         __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 112, __pyx_L1_error)
@@ -2230,7 +2395,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_
         #endif
       } else {
         if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 112, __pyx_L1_error)
         #else
         __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 112, __pyx_L1_error)
@@ -2278,6 +2443,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___2generator(__pyx_
     if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 112, __pyx_L1_error)
   }
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope);
 
   /* function exit code */
   PyErr_SetNone(PyExc_StopIteration);
@@ -2304,10 +2470,12 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_7__str___3genexpr(PyObject
   __Pyx_RefNannySetupContext("genexpr", 0);
   __pyx_cur_scope = (struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_2_genexpr *)__pyx_tp_new_8cutadapt_6_align___pyx_scope_struct_2_genexpr(__pyx_ptype_8cutadapt_6_align___pyx_scope_struct_2_genexpr, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
+    __pyx_cur_scope = ((struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct_2_genexpr *)Py_None);
+    __Pyx_INCREF(Py_None);
+    __PYX_ERR(0, 114, __pyx_L1_error)
+  } else {
+    __Pyx_GOTREF(__pyx_cur_scope);
   }
-  __Pyx_GOTREF(__pyx_cur_scope);
   __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct____str__ *) __pyx_self;
   __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
   __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
@@ -2365,7 +2533,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
     if (likely(!__pyx_t_3)) {
       if (likely(PyList_CheckExact(__pyx_t_1))) {
         if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_1)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(0, 114, __pyx_L1_error)
         #else
         __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 114, __pyx_L1_error)
@@ -2373,7 +2541,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
         #endif
       } else {
         if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(0, 114, __pyx_L1_error)
         #else
         __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 114, __pyx_L1_error)
@@ -2404,7 +2572,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
       __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_0_2d, __pyx_n_s_format); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 114, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_7);
       __pyx_t_8 = NULL;
-      if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_7))) {
+      if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) {
         __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7);
         if (likely(__pyx_t_8)) {
           PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7);
@@ -2417,15 +2585,33 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
         __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_cur_scope->__pyx_v_v); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_6);
       } else {
-        __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 114, __pyx_L1_error)
-        __Pyx_GOTREF(__pyx_t_9);
-        __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
-        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_v);
-        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_v);
-        PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_cur_scope->__pyx_v_v);
-        __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error)
-        __Pyx_GOTREF(__pyx_t_6);
-        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+        #if CYTHON_FAST_PYCALL
+        if (PyFunction_Check(__pyx_t_7)) {
+          PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_cur_scope->__pyx_v_v};
+          __pyx_t_6 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error)
+          __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+          __Pyx_GOTREF(__pyx_t_6);
+        } else
+        #endif
+        #if CYTHON_FAST_PYCCALL
+        if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) {
+          PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_cur_scope->__pyx_v_v};
+          __pyx_t_6 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error)
+          __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+          __Pyx_GOTREF(__pyx_t_6);
+        } else
+        #endif
+        {
+          __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 114, __pyx_L1_error)
+          __Pyx_GOTREF(__pyx_t_9);
+          __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
+          __Pyx_INCREF(__pyx_cur_scope->__pyx_v_v);
+          __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_v);
+          PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_cur_scope->__pyx_v_v);
+          __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error)
+          __Pyx_GOTREF(__pyx_t_6);
+          __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+        }
       }
       __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
       __pyx_t_4 = __pyx_t_6;
@@ -2451,6 +2637,7 @@ static PyObject *__pyx_gb_8cutadapt_6_align_8DPMatrix_7__str___5generator1(__pyx
     if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 114, __pyx_L1_error)
   }
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope);
 
   /* function exit code */
   PyErr_SetNone(PyExc_StopIteration);
@@ -2491,10 +2678,12 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
   __Pyx_RefNannySetupContext("__str__", 0);
   __pyx_cur_scope = (struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct____str__ *)__pyx_tp_new_8cutadapt_6_align___pyx_scope_struct____str__(__pyx_ptype_8cutadapt_6_align___pyx_scope_struct____str__, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
+    __pyx_cur_scope = ((struct __pyx_obj_8cutadapt_6_align___pyx_scope_struct____str__ *)Py_None);
+    __Pyx_INCREF(Py_None);
+    __PYX_ERR(0, 108, __pyx_L1_error)
+  } else {
+    __Pyx_GOTREF(__pyx_cur_scope);
   }
-  __Pyx_GOTREF(__pyx_cur_scope);
   __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
   __Pyx_INCREF(__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_self);
@@ -2546,7 +2735,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
     if (likely(!__pyx_t_5)) {
       if (likely(PyList_CheckExact(__pyx_t_3))) {
         if (__pyx_t_4 >= PyList_GET_SIZE(__pyx_t_3)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) __PYX_ERR(0, 113, __pyx_L1_error)
         #else
         __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error)
@@ -2554,7 +2743,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
         #endif
       } else {
         if (__pyx_t_4 >= PyTuple_GET_SIZE(__pyx_t_3)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
         __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) __PYX_ERR(0, 113, __pyx_L1_error)
         #else
         __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error)
@@ -2575,7 +2764,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
     }
     if ((likely(PyTuple_CheckExact(__pyx_t_2))) || (PyList_CheckExact(__pyx_t_2))) {
       PyObject* sequence = __pyx_t_2;
-      #if CYTHON_COMPILING_IN_CPYTHON
+      #if !CYTHON_COMPILING_IN_PYPY
       Py_ssize_t size = Py_SIZE(sequence);
       #else
       Py_ssize_t size = PySequence_Size(sequence);
@@ -2585,7 +2774,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_8DPMatrix_4__str__(CYTHON_UNUSED PyO
         else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
         __PYX_ERR(0, 113, __pyx_L1_error)
       }
-      #if CYTHON_COMPILING_IN_CPYTHON
+      #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
       if (likely(PyTuple_CheckExact(sequence))) {
         __pyx_t_1 = PyTuple_GET_ITEM(sequence, 0); 
         __pyx_t_6 = PyTuple_GET_ITEM(sequence, 1); 
@@ -3074,7 +3263,7 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_9reference_2__set__(struct __pyx_
     __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self->_reference, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 240, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_5 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
       __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_3);
       if (likely(__pyx_t_5)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -3087,15 +3276,33 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_9reference_2__set__(struct __pyx_
       __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 240, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_4);
     } else {
-      __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 240, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_6);
-      __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __pyx_t_5 = NULL;
-      __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 240, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_4);
-      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_v_8cutadapt_6_align_IUPAC_TABLE};
+        __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 240, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
+        __Pyx_GOTREF(__pyx_t_4);
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_v_8cutadapt_6_align_IUPAC_TABLE};
+        __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 240, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
+        __Pyx_GOTREF(__pyx_t_4);
+      } else
+      #endif
+      {
+        __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 240, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __pyx_t_5 = NULL;
+        __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 240, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_4);
+        __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     if (!(likely(PyBytes_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_4)->tp_name), 0))) __PYX_ERR(0, 240, __pyx_L1_error)
@@ -3114,7 +3321,7 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_9reference_2__set__(struct __pyx_
     __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self->_reference, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 242, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_6 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
       __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_3);
       if (likely(__pyx_t_6)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -3127,15 +3334,33 @@ static int __pyx_pf_8cutadapt_6_align_7Aligner_9reference_2__set__(struct __pyx_
       __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 242, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_4);
     } else {
-      __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 242, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_5);
-      __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_6); __pyx_t_6 = NULL;
-      __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 242, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_4);
-      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_v_8cutadapt_6_align_ACGT_TABLE};
+        __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 242, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __Pyx_GOTREF(__pyx_t_4);
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_v_8cutadapt_6_align_ACGT_TABLE};
+        __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 242, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __Pyx_GOTREF(__pyx_t_4);
+      } else
+      #endif
+      {
+        __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 242, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_5);
+        __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_6); __pyx_t_6 = NULL;
+        __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 242, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_4);
+        __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     if (!(likely(PyBytes_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_4)->tp_name), 0))) __PYX_ERR(0, 242, __pyx_L1_error)
@@ -3349,7 +3574,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
     __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 287, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_t_9 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
       __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_2);
       if (likely(__pyx_t_9)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -3362,15 +3587,33 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 287, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_3);
     } else {
-      __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 287, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_10);
-      __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_9); __pyx_t_9 = NULL;
-      __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 287, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_3);
-      __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_2)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_v_8cutadapt_6_align_IUPAC_TABLE};
+        __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 287, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+        __Pyx_GOTREF(__pyx_t_3);
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_v_8cutadapt_6_align_IUPAC_TABLE};
+        __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 287, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+        __Pyx_GOTREF(__pyx_t_3);
+      } else
+      #endif
+      {
+        __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 287, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_10);
+        __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_9); __pyx_t_9 = NULL;
+        __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 287, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_3);
+        __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(0, 287, __pyx_L1_error)
@@ -3389,7 +3632,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
     __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 290, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_t_10 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
       __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_2);
       if (likely(__pyx_t_10)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -3402,15 +3645,33 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 290, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_3);
     } else {
-      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 290, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_9);
-      __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_10); __pyx_t_10 = NULL;
-      __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 290, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_3);
-      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_2)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_10, __pyx_v_8cutadapt_6_align_ACGT_TABLE};
+        __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 290, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
+        __Pyx_GOTREF(__pyx_t_3);
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_10, __pyx_v_8cutadapt_6_align_ACGT_TABLE};
+        __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 290, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
+        __Pyx_GOTREF(__pyx_t_3);
+      } else
+      #endif
+      {
+        __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 290, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_9);
+        __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_10); __pyx_t_10 = NULL;
+        __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 290, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_3);
+        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(0, 290, __pyx_L1_error)
@@ -3591,31 +3852,49 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
     __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_DPMatrix); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 349, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_t_9 = NULL;
-    __pyx_t_5 = 0;
-    if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_2))) {
+    __pyx_t_13 = 0;
+    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
       __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_2);
       if (likely(__pyx_t_9)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
         __Pyx_INCREF(__pyx_t_9);
         __Pyx_INCREF(function);
         __Pyx_DECREF_SET(__pyx_t_2, function);
-        __pyx_t_5 = 1;
+        __pyx_t_13 = 1;
       }
     }
-    __pyx_t_10 = PyTuple_New(2+__pyx_t_5); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 349, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_10);
-    if (__pyx_t_9) {
-      __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_9); __pyx_t_9 = NULL;
-    }
-    __Pyx_INCREF(__pyx_v_self->str_reference);
-    __Pyx_GIVEREF(__pyx_v_self->str_reference);
-    PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_5, __pyx_v_self->str_reference);
-    __Pyx_INCREF(__pyx_v_query);
-    __Pyx_GIVEREF(__pyx_v_query);
-    PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_5, __pyx_v_query);
-    __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 349, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+    #if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(__pyx_t_2)) {
+      PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_v_self->str_reference, __pyx_v_query};
+      __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_13, 2+__pyx_t_13); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 349, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+      __Pyx_GOTREF(__pyx_t_3);
+    } else
+    #endif
+    #if CYTHON_FAST_PYCCALL
+    if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
+      PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_v_self->str_reference, __pyx_v_query};
+      __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_13, 2+__pyx_t_13); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 349, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+      __Pyx_GOTREF(__pyx_t_3);
+    } else
+    #endif
+    {
+      __pyx_t_10 = PyTuple_New(2+__pyx_t_13); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 349, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_10);
+      if (__pyx_t_9) {
+        __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_9); __pyx_t_9 = NULL;
+      }
+      __Pyx_INCREF(__pyx_v_self->str_reference);
+      __Pyx_GIVEREF(__pyx_v_self->str_reference);
+      PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_13, __pyx_v_self->str_reference);
+      __Pyx_INCREF(__pyx_v_query);
+      __Pyx_GIVEREF(__pyx_v_query);
+      PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_13, __pyx_v_query);
+      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 349, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_3);
+      __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+    }
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     __Pyx_GIVEREF(__pyx_t_3);
     __Pyx_GOTREF(__pyx_v_self->_dpmatrix);
@@ -3636,34 +3915,58 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
       __pyx_t_18 = __Pyx_PyInt_From_int((__pyx_v_column[__pyx_v_i]).cost); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 351, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_18);
       __pyx_t_19 = NULL;
-      __pyx_t_5 = 0;
-      if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
+      __pyx_t_12 = 0;
+      if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
         __pyx_t_19 = PyMethod_GET_SELF(__pyx_t_2);
         if (likely(__pyx_t_19)) {
           PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
           __Pyx_INCREF(__pyx_t_19);
           __Pyx_INCREF(function);
           __Pyx_DECREF_SET(__pyx_t_2, function);
-          __pyx_t_5 = 1;
+          __pyx_t_12 = 1;
         }
       }
-      __pyx_t_20 = PyTuple_New(3+__pyx_t_5); if (unlikely(!__pyx_t_20)) __PYX_ERR(0, 351, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_20);
-      if (__pyx_t_19) {
-        __Pyx_GIVEREF(__pyx_t_19); PyTuple_SET_ITEM(__pyx_t_20, 0, __pyx_t_19); __pyx_t_19 = NULL;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_2)) {
+        PyObject *__pyx_temp[4] = {__pyx_t_19, __pyx_t_10, __pyx_t_9, __pyx_t_18};
+        __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_12, 3+__pyx_t_12); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 351, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_19); __pyx_t_19 = 0;
+        __Pyx_GOTREF(__pyx_t_3);
+        __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+        __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0;
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
+        PyObject *__pyx_temp[4] = {__pyx_t_19, __pyx_t_10, __pyx_t_9, __pyx_t_18};
+        __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_12, 3+__pyx_t_12); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 351, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_19); __pyx_t_19 = 0;
+        __Pyx_GOTREF(__pyx_t_3);
+        __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+        __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0;
+      } else
+      #endif
+      {
+        __pyx_t_20 = PyTuple_New(3+__pyx_t_12); if (unlikely(!__pyx_t_20)) __PYX_ERR(0, 351, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_20);
+        if (__pyx_t_19) {
+          __Pyx_GIVEREF(__pyx_t_19); PyTuple_SET_ITEM(__pyx_t_20, 0, __pyx_t_19); __pyx_t_19 = NULL;
+        }
+        __Pyx_GIVEREF(__pyx_t_10);
+        PyTuple_SET_ITEM(__pyx_t_20, 0+__pyx_t_12, __pyx_t_10);
+        __Pyx_GIVEREF(__pyx_t_9);
+        PyTuple_SET_ITEM(__pyx_t_20, 1+__pyx_t_12, __pyx_t_9);
+        __Pyx_GIVEREF(__pyx_t_18);
+        PyTuple_SET_ITEM(__pyx_t_20, 2+__pyx_t_12, __pyx_t_18);
+        __pyx_t_10 = 0;
+        __pyx_t_9 = 0;
+        __pyx_t_18 = 0;
+        __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_20, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 351, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_3);
+        __Pyx_DECREF(__pyx_t_20); __pyx_t_20 = 0;
       }
-      __Pyx_GIVEREF(__pyx_t_10);
-      PyTuple_SET_ITEM(__pyx_t_20, 0+__pyx_t_5, __pyx_t_10);
-      __Pyx_GIVEREF(__pyx_t_9);
-      PyTuple_SET_ITEM(__pyx_t_20, 1+__pyx_t_5, __pyx_t_9);
-      __Pyx_GIVEREF(__pyx_t_18);
-      PyTuple_SET_ITEM(__pyx_t_20, 2+__pyx_t_5, __pyx_t_18);
-      __pyx_t_10 = 0;
-      __pyx_t_9 = 0;
-      __pyx_t_18 = 0;
-      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_20, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 351, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_3);
-      __Pyx_DECREF(__pyx_t_20); __pyx_t_20 = 0;
       __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
       __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     }
@@ -3840,34 +4143,58 @@ static PyObject *__pyx_pf_8cutadapt_6_align_7Aligner_4locate(struct __pyx_obj_8c
                     __pyx_t_9 = __Pyx_PyInt_From_int((__pyx_v_column[__pyx_v_i]).cost); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 424, __pyx_L44_error)
                     __Pyx_GOTREF(__pyx_t_9);
                     __pyx_t_10 = NULL;
-                    __pyx_t_5 = 0;
-                    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
+                    __pyx_t_16 = 0;
+                    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
                       __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_2);
                       if (likely(__pyx_t_10)) {
                         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
                         __Pyx_INCREF(__pyx_t_10);
                         __Pyx_INCREF(function);
                         __Pyx_DECREF_SET(__pyx_t_2, function);
-                        __pyx_t_5 = 1;
+                        __pyx_t_16 = 1;
                       }
                     }
-                    __pyx_t_19 = PyTuple_New(3+__pyx_t_5); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 424, __pyx_L44_error)
-                    __Pyx_GOTREF(__pyx_t_19);
-                    if (__pyx_t_10) {
-                      __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_19, 0, __pyx_t_10); __pyx_t_10 = NULL;
+                    #if CYTHON_FAST_PYCALL
+                    if (PyFunction_Check(__pyx_t_2)) {
+                      PyObject *__pyx_temp[4] = {__pyx_t_10, __pyx_t_20, __pyx_t_18, __pyx_t_9};
+                      __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_16, 3+__pyx_t_16); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 424, __pyx_L44_error)
+                      __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
+                      __Pyx_GOTREF(__pyx_t_3);
+                      __Pyx_DECREF(__pyx_t_20); __pyx_t_20 = 0;
+                      __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0;
+                      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+                    } else
+                    #endif
+                    #if CYTHON_FAST_PYCCALL
+                    if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
+                      PyObject *__pyx_temp[4] = {__pyx_t_10, __pyx_t_20, __pyx_t_18, __pyx_t_9};
+                      __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_16, 3+__pyx_t_16); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 424, __pyx_L44_error)
+                      __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
+                      __Pyx_GOTREF(__pyx_t_3);
+                      __Pyx_DECREF(__pyx_t_20); __pyx_t_20 = 0;
+                      __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0;
+                      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+                    } else
+                    #endif
+                    {
+                      __pyx_t_19 = PyTuple_New(3+__pyx_t_16); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 424, __pyx_L44_error)
+                      __Pyx_GOTREF(__pyx_t_19);
+                      if (__pyx_t_10) {
+                        __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_19, 0, __pyx_t_10); __pyx_t_10 = NULL;
+                      }
+                      __Pyx_GIVEREF(__pyx_t_20);
+                      PyTuple_SET_ITEM(__pyx_t_19, 0+__pyx_t_16, __pyx_t_20);
+                      __Pyx_GIVEREF(__pyx_t_18);
+                      PyTuple_SET_ITEM(__pyx_t_19, 1+__pyx_t_16, __pyx_t_18);
+                      __Pyx_GIVEREF(__pyx_t_9);
+                      PyTuple_SET_ITEM(__pyx_t_19, 2+__pyx_t_16, __pyx_t_9);
+                      __pyx_t_20 = 0;
+                      __pyx_t_18 = 0;
+                      __pyx_t_9 = 0;
+                      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_19, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 424, __pyx_L44_error)
+                      __Pyx_GOTREF(__pyx_t_3);
+                      __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0;
                     }
-                    __Pyx_GIVEREF(__pyx_t_20);
-                    PyTuple_SET_ITEM(__pyx_t_19, 0+__pyx_t_5, __pyx_t_20);
-                    __Pyx_GIVEREF(__pyx_t_18);
-                    PyTuple_SET_ITEM(__pyx_t_19, 1+__pyx_t_5, __pyx_t_18);
-                    __Pyx_GIVEREF(__pyx_t_9);
-                    PyTuple_SET_ITEM(__pyx_t_19, 2+__pyx_t_5, __pyx_t_9);
-                    __pyx_t_20 = 0;
-                    __pyx_t_18 = 0;
-                    __pyx_t_9 = 0;
-                    __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_19, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 424, __pyx_L44_error)
-                    __Pyx_GOTREF(__pyx_t_3);
-                    __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0;
                     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
                     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
                   }
@@ -4383,7 +4710,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_4locate(CYTHON_UNUSED PyObject *__py
   __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_aligner), __pyx_n_s_locate); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 487, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_5);
   __pyx_t_3 = NULL;
-  if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_5))) {
+  if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) {
     __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_5);
     if (likely(__pyx_t_3)) {
       PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
@@ -4396,15 +4723,33 @@ static PyObject *__pyx_pf_8cutadapt_6_align_4locate(CYTHON_UNUSED PyObject *__py
     __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_query); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 487, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_4);
   } else {
-    __pyx_t_2 = PyTuple_New(1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 487, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_2);
-    __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); __pyx_t_3 = NULL;
-    __Pyx_INCREF(__pyx_v_query);
-    __Pyx_GIVEREF(__pyx_v_query);
-    PyTuple_SET_ITEM(__pyx_t_2, 0+1, __pyx_v_query);
-    __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_2, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 487, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    #if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(__pyx_t_5)) {
+      PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_query};
+      __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 487, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
+      __Pyx_GOTREF(__pyx_t_4);
+    } else
+    #endif
+    #if CYTHON_FAST_PYCCALL
+    if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
+      PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_query};
+      __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 487, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
+      __Pyx_GOTREF(__pyx_t_4);
+    } else
+    #endif
+    {
+      __pyx_t_2 = PyTuple_New(1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 487, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_2);
+      __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); __pyx_t_3 = NULL;
+      __Pyx_INCREF(__pyx_v_query);
+      __Pyx_GIVEREF(__pyx_v_query);
+      PyTuple_SET_ITEM(__pyx_t_2, 0+1, __pyx_v_query);
+      __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_2, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 487, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_4);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    }
   }
   __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
   __pyx_r = __pyx_t_4;
@@ -4592,7 +4937,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
     __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_ref_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 511, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_8 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
       __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_3);
       if (likely(__pyx_t_8)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -4605,15 +4950,33 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
       __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 511, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
     } else {
-      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 511, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_9);
-      __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
-      __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 511, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_2);
-      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_v_8cutadapt_6_align_IUPAC_TABLE};
+        __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 511, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+        __Pyx_GOTREF(__pyx_t_2);
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_v_8cutadapt_6_align_IUPAC_TABLE};
+        __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 511, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+        __Pyx_GOTREF(__pyx_t_2);
+      } else
+      #endif
+      {
+        __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 511, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_9);
+        __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
+        __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 511, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_2);
+        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 511, __pyx_L1_error)
@@ -4629,7 +4992,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
     __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_ref_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 513, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_9 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
       __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_3);
       if (likely(__pyx_t_9)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -4642,15 +5005,33 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
       __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 513, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
     } else {
-      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 513, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_8);
-      __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_9); __pyx_t_9 = NULL;
-      __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 513, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_2);
-      __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_v_8cutadapt_6_align_ACGT_TABLE};
+        __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 513, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+        __Pyx_GOTREF(__pyx_t_2);
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_v_8cutadapt_6_align_ACGT_TABLE};
+        __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 513, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+        __Pyx_GOTREF(__pyx_t_2);
+      } else
+      #endif
+      {
+        __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 513, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_8);
+        __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_9); __pyx_t_9 = NULL;
+        __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 513, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_2);
+        __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 513, __pyx_L1_error)
@@ -4671,7 +5052,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
     __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 517, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_8 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
       __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_3);
       if (likely(__pyx_t_8)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -4684,15 +5065,33 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
       __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_IUPAC_TABLE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 517, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
     } else {
-      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 517, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_9);
-      __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
-      __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
-      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 517, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_2);
-      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_v_8cutadapt_6_align_IUPAC_TABLE};
+        __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 517, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+        __Pyx_GOTREF(__pyx_t_2);
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_v_8cutadapt_6_align_IUPAC_TABLE};
+        __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 517, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+        __Pyx_GOTREF(__pyx_t_2);
+      } else
+      #endif
+      {
+        __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 517, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_9);
+        __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
+        __Pyx_INCREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_8cutadapt_6_align_IUPAC_TABLE);
+        __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 517, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_2);
+        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 517, __pyx_L1_error)
@@ -4708,7 +5107,7 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
     __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_query_bytes, __pyx_n_s_translate); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 519, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_9 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
       __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_3);
       if (likely(__pyx_t_9)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -4721,15 +5120,33 @@ static PyObject *__pyx_pf_8cutadapt_6_align_6compare_prefixes(CYTHON_UNUSED PyOb
       __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_8cutadapt_6_align_ACGT_TABLE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 519, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_2);
     } else {
-      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 519, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_8);
-      __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_9); __pyx_t_9 = NULL;
-      __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
-      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 519, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_2);
-      __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_v_8cutadapt_6_align_ACGT_TABLE};
+        __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 519, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+        __Pyx_GOTREF(__pyx_t_2);
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_9, __pyx_v_8cutadapt_6_align_ACGT_TABLE};
+        __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 519, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+        __Pyx_GOTREF(__pyx_t_2);
+      } else
+      #endif
+      {
+        __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 519, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_8);
+        __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_9); __pyx_t_9 = NULL;
+        __Pyx_INCREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        __Pyx_GIVEREF(__pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_v_8cutadapt_6_align_ACGT_TABLE);
+        __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 519, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_2);
+        __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "bytes", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 519, __pyx_L1_error)
@@ -4850,10 +5267,11 @@ static PyObject *__pyx_tp_new_8cutadapt_6_align_Aligner(PyTypeObject *t, PyObjec
   p->_dpmatrix = Py_None; Py_INCREF(Py_None);
   p->_reference = ((PyObject*)Py_None); Py_INCREF(Py_None);
   p->str_reference = ((PyObject*)Py_None); Py_INCREF(Py_None);
-  if (unlikely(__pyx_pw_8cutadapt_6_align_7Aligner_1__cinit__(o, a, k) < 0)) {
-    Py_DECREF(o); o = 0;
-  }
+  if (unlikely(__pyx_pw_8cutadapt_6_align_7Aligner_1__cinit__(o, a, k) < 0)) goto bad;
   return o;
+  bad:
+  Py_DECREF(o); o = 0;
+  return NULL;
 }
 
 static void __pyx_tp_dealloc_8cutadapt_6_align_Aligner(PyObject *o) {
@@ -5434,6 +5852,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s_i, __pyx_k_i, sizeof(__pyx_k_i), 0, 0, 1, 1},
   {&__pyx_n_s_init, __pyx_k_init, sizeof(__pyx_k_init), 0, 0, 1, 1},
   {&__pyx_n_s_items, __pyx_k_items, sizeof(__pyx_k_items), 0, 0, 1, 1},
+  {&__pyx_n_s_iupac, __pyx_k_iupac, sizeof(__pyx_k_iupac), 0, 0, 1, 1},
   {&__pyx_n_s_iupac_table, __pyx_k_iupac_table, sizeof(__pyx_k_iupac_table), 0, 0, 1, 1},
   {&__pyx_n_s_j, __pyx_k_j, sizeof(__pyx_k_j), 0, 0, 1, 1},
   {&__pyx_n_s_join, __pyx_k_join, sizeof(__pyx_k_join), 0, 0, 1, 1},
@@ -5532,7 +5951,7 @@ static int __Pyx_InitCachedConstants(void) {
   __Pyx_GIVEREF(__pyx_tuple__15);
   __pyx_codeobj__16 = (PyObject*)__Pyx_PyCode_New(0, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__15, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_acgt_table, 25, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__16)) __PYX_ERR(0, 25, __pyx_L1_error)
 
-  __pyx_tuple__17 = PyTuple_Pack(8, __pyx_n_s_A, __pyx_n_s_C, __pyx_n_s_G, __pyx_n_s_T, __pyx_n_s_d, __pyx_n_s_t, __pyx_n_s_c, __pyx_n_s_v); if (unlikely(!__pyx_tuple__17)) __PYX_ERR(0, 41, __pyx_L1_error)
+  __pyx_tuple__17 = PyTuple_Pack(8, __pyx_n_s_A, __pyx_n_s_C, __pyx_n_s_G, __pyx_n_s_T, __pyx_n_s_iupac, __pyx_n_s_t, __pyx_n_s_c, __pyx_n_s_v); if (unlikely(!__pyx_tuple__17)) __PYX_ERR(0, 41, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__17);
   __Pyx_GIVEREF(__pyx_tuple__17);
   __pyx_codeobj__18 = (PyObject*)__Pyx_PyCode_New(0, 0, 8, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__17, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_iupac_table, 41, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__18)) __PYX_ERR(0, 41, __pyx_L1_error)
@@ -5704,7 +6123,7 @@ PyMODINIT_FUNC PyInit__align(void)
   __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_acgt_table); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 81, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __pyx_t_3 = NULL;
-  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_2))) {
+  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
     __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
     if (likely(__pyx_t_3)) {
       PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -5730,7 +6149,7 @@ PyMODINIT_FUNC PyInit__align(void)
   __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_iupac_table); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 82, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __pyx_t_3 = NULL;
-  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_2))) {
+  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
     __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
     if (likely(__pyx_t_3)) {
       PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -5882,7 +6301,7 @@ static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) {
     {
         PyMethodDescrObject *descr = (PyMethodDescrObject*) method;
         target->func = descr->d_method->ml_meth;
-        target->flag = descr->d_method->ml_flags & (METH_VARARGS | METH_KEYWORDS | METH_O | METH_NOARGS);
+        target->flag = descr->d_method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
     }
 #endif
     return 0;
@@ -5892,7 +6311,7 @@ static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) {
 static PyObject* __Pyx__CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObject* self) {
     PyObject *args, *result = NULL;
     if (unlikely(!cfunc->method) && unlikely(__Pyx_TryUnpackUnboundCMethod(cfunc) < 0)) return NULL;
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS
     args = PyTuple_New(1);
     if (unlikely(!args)) goto bad;
     Py_INCREF(self);
@@ -5930,7 +6349,7 @@ static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
 
 /* IterFinish */
 static CYTHON_INLINE int __Pyx_IterFinish(void) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_FAST_THREAD_STATE
     PyThreadState *tstate = PyThreadState_GET();
     PyObject* exc_type = tstate->curexc_type;
     if (unlikely(exc_type)) {
@@ -6055,6 +6474,144 @@ static CYTHON_INLINE int __Pyx_SetItemInt_ByteArray_Fast(PyObject* string, Py_ss
     }
 }
 
+/* PyCFunctionFastCall */
+#if CYTHON_FAST_PYCCALL
+static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) {
+    PyCFunctionObject *func = (PyCFunctionObject*)func_obj;
+    PyCFunction meth = PyCFunction_GET_FUNCTION(func);
+    PyObject *self = PyCFunction_GET_SELF(func);
+    assert(PyCFunction_Check(func));
+    assert(METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)));
+    assert(nargs >= 0);
+    assert(nargs == 0 || args != NULL);
+    /* _PyCFunction_FastCallDict() must not be called with an exception set,
+       because it may clear it (directly or indirectly) and so the
+       caller loses its exception */
+    assert(!PyErr_Occurred());
+    return (*((__Pyx_PyCFunctionFast)meth)) (self, args, nargs, NULL);
+}
+#endif  // CYTHON_FAST_PYCCALL
+
+/* PyFunctionFastCall */
+#if CYTHON_FAST_PYCALL
+#include "frameobject.h"
+static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na,
+                                               PyObject *globals) {
+    PyFrameObject *f;
+    PyThreadState *tstate = PyThreadState_GET();
+    PyObject **fastlocals;
+    Py_ssize_t i;
+    PyObject *result;
+    assert(globals != NULL);
+    /* XXX Perhaps we should create a specialized
+       PyFrame_New() that doesn't take locals, but does
+       take builtins without sanity checking them.
+       */
+    assert(tstate != NULL);
+    f = PyFrame_New(tstate, co, globals, NULL);
+    if (f == NULL) {
+        return NULL;
+    }
+    fastlocals = f->f_localsplus;
+    for (i = 0; i < na; i++) {
+        Py_INCREF(*args);
+        fastlocals[i] = *args++;
+    }
+    result = PyEval_EvalFrameEx(f,0);
+    ++tstate->recursion_depth;
+    Py_DECREF(f);
+    --tstate->recursion_depth;
+    return result;
+}
+#if 1 || PY_VERSION_HEX < 0x030600B1
+static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) {
+    PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
+    PyObject *globals = PyFunction_GET_GLOBALS(func);
+    PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
+    PyObject *closure;
+#if PY_MAJOR_VERSION >= 3
+    PyObject *kwdefs;
+#endif
+    PyObject *kwtuple, **k;
+    PyObject **d;
+    Py_ssize_t nd;
+    Py_ssize_t nk;
+    PyObject *result;
+    assert(kwargs == NULL || PyDict_Check(kwargs));
+    nk = kwargs ? PyDict_Size(kwargs) : 0;
+    if (Py_EnterRecursiveCall((char*)" while calling a Python object")) {
+        return NULL;
+    }
+    if (
+#if PY_MAJOR_VERSION >= 3
+            co->co_kwonlyargcount == 0 &&
+#endif
+            likely(kwargs == NULL || nk == 0) &&
+            co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) {
+        if (argdefs == NULL && co->co_argcount == nargs) {
+            result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals);
+            goto done;
+        }
+        else if (nargs == 0 && argdefs != NULL
+                 && co->co_argcount == Py_SIZE(argdefs)) {
+            /* function called with no arguments, but all parameters have
+               a default value: use default values as arguments .*/
+            args = &PyTuple_GET_ITEM(argdefs, 0);
+            result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals);
+            goto done;
+        }
+    }
+    if (kwargs != NULL) {
+        Py_ssize_t pos, i;
+        kwtuple = PyTuple_New(2 * nk);
+        if (kwtuple == NULL) {
+            result = NULL;
+            goto done;
+        }
+        k = &PyTuple_GET_ITEM(kwtuple, 0);
+        pos = i = 0;
+        while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) {
+            Py_INCREF(k[i]);
+            Py_INCREF(k[i+1]);
+            i += 2;
+        }
+        nk = i / 2;
+    }
+    else {
+        kwtuple = NULL;
+        k = NULL;
+    }
+    closure = PyFunction_GET_CLOSURE(func);
+#if PY_MAJOR_VERSION >= 3
+    kwdefs = PyFunction_GET_KW_DEFAULTS(func);
+#endif
+    if (argdefs != NULL) {
+        d = &PyTuple_GET_ITEM(argdefs, 0);
+        nd = Py_SIZE(argdefs);
+    }
+    else {
+        d = NULL;
+        nd = 0;
+    }
+#if PY_MAJOR_VERSION >= 3
+    result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL,
+                               args, nargs,
+                               k, (int)nk,
+                               d, (int)nd, kwdefs, closure);
+#else
+    result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL,
+                               args, nargs,
+                               k, (int)nk,
+                               d, (int)nd, closure);
+#endif
+    Py_XDECREF(kwtuple);
+done:
+    Py_LeaveRecursiveCall();
+    return result;
+}
+#endif  // CPython < 3.6
+#endif  // CYTHON_FAST_PYCALL
+
 /* PyObjectCallMethO */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) {
@@ -6088,6 +6645,11 @@ static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) {
     return result;
 }
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) {
+#if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(func)) {
+        return __Pyx_PyFunction_FastCall(func, &arg, 1);
+    }
+#endif
 #ifdef __Pyx_CyFunction_USED
     if (likely(PyCFunction_Check(func) || PyObject_TypeCheck(func, __pyx_CyFunctionType))) {
 #else
@@ -6095,6 +6657,10 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec
 #endif
         if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) {
             return __Pyx_PyObject_CallMethO(func, arg);
+#if CYTHON_FAST_PYCCALL
+        } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) {
+            return __Pyx_PyCFunction_FastCall(func, &arg, 1);
+#endif
         }
     }
     return __Pyx__PyObject_CallOneArg(func, arg);
@@ -6113,6 +6679,11 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec
 /* PyObjectCallNoArg */
   #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
+#if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(func)) {
+        return __Pyx_PyFunction_FastCall(func, NULL, 0);
+    }
+#endif
 #ifdef __Pyx_CyFunction_USED
     if (likely(PyCFunction_Check(func) || PyObject_TypeCheck(func, __pyx_CyFunctionType))) {
 #else
@@ -6269,7 +6840,7 @@ bad:
 }
 
 /* PyIntBinop */
-    #if CYTHON_COMPILING_IN_CPYTHON
+    #if !CYTHON_COMPILING_IN_PYPY
 static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) {
     #if PY_MAJOR_VERSION < 3
     if (likely(PyInt_CheckExact(op1))) {
@@ -6282,12 +6853,14 @@ static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED
             return PyLong_Type.tp_as_number->nb_add(op1, op2);
     }
     #endif
-    #if CYTHON_USE_PYLONG_INTERNALS && PY_MAJOR_VERSION >= 3
+    #if CYTHON_USE_PYLONG_INTERNALS
     if (likely(PyLong_CheckExact(op1))) {
         const long b = intval;
         long a, x;
+#ifdef HAVE_LONG_LONG
         const PY_LONG_LONG llb = intval;
         PY_LONG_LONG lla, llx;
+#endif
         const digit* digits = ((PyLongObject*)op1)->ob_digit;
         const Py_ssize_t size = Py_SIZE(op1);
         if (likely(__Pyx_sst_abs(size) <= 1)) {
@@ -6299,58 +6872,74 @@ static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED
                     if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
                         a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
                         break;
+#ifdef HAVE_LONG_LONG
                     } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) {
                         lla = -(PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
                         goto long_long;
+#endif
                     }
                 case 2:
                     if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
                         a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
                         break;
+#ifdef HAVE_LONG_LONG
                     } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) {
                         lla = (PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
                         goto long_long;
+#endif
                     }
                 case -3:
                     if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
                         a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
                         break;
+#ifdef HAVE_LONG_LONG
                     } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) {
                         lla = -(PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
                         goto long_long;
+#endif
                     }
                 case 3:
                     if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
                         a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
                         break;
+#ifdef HAVE_LONG_LONG
                     } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) {
                         lla = (PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
                         goto long_long;
+#endif
                     }
                 case -4:
                     if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
                         a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
                         break;
+#ifdef HAVE_LONG_LONG
                     } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) {
                         lla = -(PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
                         goto long_long;
+#endif
                     }
                 case 4:
                     if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
                         a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
                         break;
+#ifdef HAVE_LONG_LONG
                     } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) {
                         lla = (PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
                         goto long_long;
+#endif
                     }
                 default: return PyLong_Type.tp_as_number->nb_add(op1, op2);
             }
         }
                 x = a + b;
             return PyLong_FromLong(x);
+#ifdef HAVE_LONG_LONG
         long_long:
                 llx = lla + llb;
             return PyLong_FromLongLong(llx);
+#endif
+        
+        
     }
     #endif
     if (PyFloat_CheckExact(op1)) {
@@ -6377,7 +6966,7 @@ static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i,
                                                               CYTHON_NCP_UNUSED int wraparound,
                                                               CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
     if (wraparound & unlikely(i < 0)) i += PyList_GET_SIZE(o);
     if ((!boundscheck) || likely((0 <= i) & (i < PyList_GET_SIZE(o)))) {
         PyObject *r = PyList_GET_ITEM(o, i);
@@ -6392,7 +6981,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i,
                                                               CYTHON_NCP_UNUSED int wraparound,
                                                               CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
     if (wraparound & unlikely(i < 0)) i += PyTuple_GET_SIZE(o);
     if ((!boundscheck) || likely((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
         PyObject *r = PyTuple_GET_ITEM(o, i);
@@ -6407,7 +6996,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list,
                                                      CYTHON_NCP_UNUSED int wraparound,
                                                      CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS
     if (is_list || PyList_CheckExact(o)) {
         Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o);
         if ((!boundscheck) || (likely((n >= 0) & (n < PyList_GET_SIZE(o))))) {
@@ -6457,7 +7046,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
 }
 static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int is_list,
                                                CYTHON_NCP_UNUSED int wraparound, CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS
     if (is_list || PyList_CheckExact(o)) {
         Py_ssize_t n = (!wraparound) ? i : ((likely(i >= 0)) ? i : i + PyList_GET_SIZE(o));
         if ((!boundscheck) || likely((n >= 0) & (n < PyList_GET_SIZE(o)))) {
@@ -6535,7 +7124,7 @@ static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, in
 }
 
 /* PyErrFetchRestore */
-      #if CYTHON_COMPILING_IN_CPYTHON
+      #if CYTHON_FAST_THREAD_STATE
 static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) {
     PyObject *tmp_type, *tmp_value, *tmp_tb;
     tmp_type = tstate->curexc_type;
@@ -6724,7 +7313,7 @@ bad:
 /* GetModuleGlobalName */
         static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) {
     PyObject *result;
-#if CYTHON_COMPILING_IN_CPYTHON
+#if !CYTHON_AVOID_BORROWED_REFS
     result = PyDict_GetItem(__pyx_d, name);
     if (likely(result)) {
         Py_INCREF(result);
@@ -6936,7 +7525,7 @@ __Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) {
     PyObject *res = op->defaults_getter((PyObject *) op);
     if (unlikely(!res))
         return -1;
-    #if CYTHON_COMPILING_IN_CPYTHON
+    #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
     op->defaults_tuple = PyTuple_GET_ITEM(res, 0);
     Py_INCREF(op->defaults_tuple);
     op->defaults_kwdict = PyTuple_GET_ITEM(res, 1);
@@ -7195,11 +7784,9 @@ __Pyx_CyFunction_repr(__pyx_CyFunctionObject *op)
                                PyString_AsString(op->func_qualname), (void *)op);
 #endif
 }
-#if CYTHON_COMPILING_IN_PYPY
-static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) {
+static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) {
     PyCFunctionObject* f = (PyCFunctionObject*)func;
     PyCFunction meth = f->m_ml->ml_meth;
-    PyObject *self = f->m_self;
     Py_ssize_t size;
     switch (f->m_ml->ml_flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) {
     case METH_VARARGS:
@@ -7245,11 +7832,32 @@ static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject
                  f->m_ml->ml_name);
     return NULL;
 }
-#else
-static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) {
-	return PyCFunction_Call(func, arg, kw);
+static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) {
+    return __Pyx_CyFunction_CallMethod(func, ((PyCFunctionObject*)func)->m_self, arg, kw);
+}
+static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) {
+    PyObject *result;
+    __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func;
+    if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) {
+        Py_ssize_t argc;
+        PyObject *new_args;
+        PyObject *self;
+        argc = PyTuple_GET_SIZE(args);
+        new_args = PyTuple_GetSlice(args, 1, argc);
+        if (unlikely(!new_args))
+            return NULL;
+        self = PyTuple_GetItem(args, 0);
+        if (unlikely(!self)) {
+            Py_DECREF(new_args);
+            return NULL;
+        }
+        result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw);
+        Py_DECREF(new_args);
+    } else {
+        result = __Pyx_CyFunction_Call(func, args, kw);
+    }
+    return result;
 }
-#endif
 static PyTypeObject __pyx_CyFunctionType_type = {
     PyVarObject_HEAD_INIT(0, 0)
     "cython_function_or_method",
@@ -7269,7 +7877,7 @@ static PyTypeObject __pyx_CyFunctionType_type = {
     0,
     0,
     0,
-    __Pyx_CyFunction_Call,
+    __Pyx_CyFunction_CallAsMethod,
     0,
     0,
     0,
@@ -7311,9 +7919,6 @@ static PyTypeObject __pyx_CyFunctionType_type = {
 #endif
 };
 static int __pyx_CyFunction_init(void) {
-#if !CYTHON_COMPILING_IN_PYPY
-    __pyx_CyFunctionType_type.tp_call = PyCFunction_Call;
-#endif
     __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type);
     if (__pyx_CyFunctionType == NULL) {
         return -1;
@@ -7605,7 +8210,7 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
         0                    /*PyObject *locals*/
     );
     if (!py_frame) goto bad;
-    py_frame->f_lineno = py_line;
+    __Pyx_PyFrame_SetLineNumber(py_frame, py_line);
     PyTraceBack_Here(py_frame);
 bad:
     Py_XDECREF(py_code);
@@ -7643,14 +8248,18 @@ bad:
             return PyInt_FromLong((long) value);
         } else if (sizeof(long) <= sizeof(unsigned long)) {
             return PyLong_FromUnsignedLong((unsigned long) value);
+#ifdef HAVE_LONG_LONG
         } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
             return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
+#endif
         }
     } else {
         if (sizeof(long) <= sizeof(long)) {
             return PyInt_FromLong((long) value);
+#ifdef HAVE_LONG_LONG
         } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
             return PyLong_FromLongLong((PY_LONG_LONG) value);
+#endif
         }
     }
     {
@@ -7670,14 +8279,18 @@ bad:
             return PyInt_FromLong((long) value);
         } else if (sizeof(int) <= sizeof(unsigned long)) {
             return PyLong_FromUnsignedLong((unsigned long) value);
+#ifdef HAVE_LONG_LONG
         } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
             return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
+#endif
         }
     } else {
         if (sizeof(int) <= sizeof(long)) {
             return PyInt_FromLong((long) value);
+#ifdef HAVE_LONG_LONG
         } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) {
             return PyLong_FromLongLong((PY_LONG_LONG) value);
+#endif
         }
     }
     {
@@ -7756,8 +8369,10 @@ bad:
 #endif
             if (sizeof(int) <= sizeof(unsigned long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x))
+#endif
             }
         } else {
 #if CYTHON_USE_PYLONG_INTERNALS
@@ -7824,8 +8439,10 @@ bad:
 #endif
             if (sizeof(int) <= sizeof(long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x))
+#endif
             }
         }
         {
@@ -7941,8 +8558,10 @@ raise_neg_overflow:
 #endif
             if (sizeof(unsigned char) <= sizeof(unsigned long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(unsigned char, unsigned long, PyLong_AsUnsignedLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(unsigned char) <= sizeof(unsigned PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(unsigned char, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x))
+#endif
             }
         } else {
 #if CYTHON_USE_PYLONG_INTERNALS
@@ -8009,8 +8628,10 @@ raise_neg_overflow:
 #endif
             if (sizeof(unsigned char) <= sizeof(long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(unsigned char, long, PyLong_AsLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(unsigned char) <= sizeof(PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(unsigned char, PY_LONG_LONG, PyLong_AsLongLong(x))
+#endif
             }
         }
         {
@@ -8126,8 +8747,10 @@ raise_neg_overflow:
 #endif
             if (sizeof(long) <= sizeof(unsigned long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x))
+#endif
             }
         } else {
 #if CYTHON_USE_PYLONG_INTERNALS
@@ -8194,8 +8817,10 @@ raise_neg_overflow:
 #endif
             if (sizeof(long) <= sizeof(long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x))
+#endif
             }
         }
         {
@@ -8244,7 +8869,7 @@ raise_neg_overflow:
 }
 
 /* SwapException */
-              #if CYTHON_COMPILING_IN_CPYTHON
+              #if CYTHON_FAST_THREAD_STATE
 static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
     PyObject *tmp_type, *tmp_value, *tmp_tb;
     tmp_type = tstate->exc_type;
@@ -8272,15 +8897,29 @@ static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value,
               static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) {
     PyObject *method, *result = NULL;
     method = __Pyx_PyObject_GetAttrStr(obj, method_name);
-    if (unlikely(!method)) goto bad;
-#if CYTHON_COMPILING_IN_CPYTHON
+    if (unlikely(!method)) goto done;
+#if CYTHON_UNPACK_METHODS
     if (likely(PyMethod_Check(method))) {
         PyObject *self = PyMethod_GET_SELF(method);
         if (likely(self)) {
             PyObject *args;
             PyObject *function = PyMethod_GET_FUNCTION(method);
+            #if CYTHON_FAST_PYCALL
+            if (PyFunction_Check(function)) {
+                PyObject *args[2] = {self, arg};
+                result = __Pyx_PyFunction_FastCall(function, args, 2);
+                goto done;
+            }
+            #endif
+            #if CYTHON_FAST_PYCCALL
+            if (__Pyx_PyFastCFunction_Check(function)) {
+                PyObject *args[2] = {self, arg};
+                result = __Pyx_PyCFunction_FastCall(function, args, 2);
+                goto done;
+            }
+            #endif
             args = PyTuple_New(2);
-            if (unlikely(!args)) goto bad;
+            if (unlikely(!args)) goto done;
             Py_INCREF(self);
             PyTuple_SET_ITEM(args, 0, self);
             Py_INCREF(arg);
@@ -8295,7 +8934,7 @@ static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value,
     }
 #endif
     result = __Pyx_PyObject_CallOneArg(method, arg);
-bad:
+done:
     Py_XDECREF(method);
     return result;
 }
@@ -8322,41 +8961,38 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) {
         return 0;
     }
     if (likely(et == PyExc_StopIteration)) {
+        if (!ev) {
+            Py_INCREF(Py_None);
+            value = Py_None;
+        }
 #if PY_VERSION_HEX >= 0x030300A0
-        if (ev && Py_TYPE(ev) == (PyTypeObject*)PyExc_StopIteration) {
+        else if (Py_TYPE(ev) == (PyTypeObject*)PyExc_StopIteration) {
             value = ((PyStopIterationObject *)ev)->value;
             Py_INCREF(value);
             Py_DECREF(ev);
-            Py_XDECREF(tb);
-            Py_DECREF(et);
-            *pvalue = value;
-            return 0;
         }
 #endif
-        if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) {
-            if (!ev) {
-                Py_INCREF(Py_None);
-                ev = Py_None;
-            } else if (PyTuple_Check(ev)) {
-                if (PyTuple_GET_SIZE(ev) >= 1) {
-                    PyObject *value;
-#if CYTHON_COMPILING_IN_CPYTHON
-                    value = PySequence_ITEM(ev, 0);
+        else if (unlikely(PyTuple_Check(ev))) {
+            if (PyTuple_GET_SIZE(ev) >= 1) {
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+                value = PyTuple_GET_ITEM(ev, 0);
+                Py_INCREF(value);
 #else
-                    value = PyTuple_GET_ITEM(ev, 0);
-                    Py_INCREF(value);
+                value = PySequence_ITEM(ev, 0);
 #endif
-                    Py_DECREF(ev);
-                    ev = value;
-                } else {
-                    Py_INCREF(Py_None);
-                    Py_DECREF(ev);
-                    ev = Py_None;
-                }
+            } else {
+                Py_INCREF(Py_None);
+                value = Py_None;
             }
+            Py_DECREF(ev);
+        }
+        else if (!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) {
+            value = ev;
+        }
+        if (likely(value)) {
             Py_XDECREF(tb);
             Py_DECREF(et);
-            *pvalue = ev;
+            *pvalue = value;
             return 0;
         }
     } else if (!PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) {
@@ -8433,7 +9069,7 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
     }
     __Pyx_PyThreadState_assign
     if (value) {
-#if CYTHON_COMPILING_IN_PYPY
+#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
 #else
         if (self->exc_traceback) {
             PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback;
@@ -8454,7 +9090,7 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
     if (retval) {
         __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value,
                             &self->exc_traceback);
-#if CYTHON_COMPILING_IN_PYPY
+#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
 #else
         if (self->exc_traceback) {
             PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback;
@@ -8564,7 +9200,12 @@ static PyObject *__Pyx_Generator_Next(PyObject *self) {
     if (yf) {
         PyObject *ret;
         gen->is_running = 1;
-        ret = Py_TYPE(yf)->tp_iternext(yf);
+        #ifdef __Pyx_Generator_USED
+        if (__Pyx_Generator_CheckExact(yf)) {
+            ret = __Pyx_Generator_Next(yf);
+        } else
+        #endif
+            ret = Py_TYPE(yf)->tp_iternext(yf);
         gen->is_running = 0;
         if (likely(ret)) {
             return ret;
@@ -8753,8 +9394,10 @@ static void __Pyx_Coroutine_del(PyObject *self) {
 static PyObject *
 __Pyx_Coroutine_get_name(__pyx_CoroutineObject *self)
 {
-    Py_INCREF(self->gi_name);
-    return self->gi_name;
+    PyObject *name = self->gi_name;
+    if (unlikely(!name)) name = Py_None;
+    Py_INCREF(name);
+    return name;
 }
 static int
 __Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value)
@@ -8778,8 +9421,10 @@ __Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value)
 static PyObject *
 __Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self)
 {
-    Py_INCREF(self->gi_qualname);
-    return self->gi_qualname;
+    PyObject *name = self->gi_qualname;
+    if (unlikely(!name)) name = Py_None;
+    Py_INCREF(name);
+    return name;
 }
 static int
 __Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value)
@@ -9128,7 +9773,9 @@ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
    else return PyObject_IsTrue(x);
 }
 static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
+#if CYTHON_USE_TYPE_SLOTS
   PyNumberMethods *m;
+#endif
   const char *name = NULL;
   PyObject *res = NULL;
 #if PY_MAJOR_VERSION < 3
@@ -9137,8 +9784,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
   if (PyLong_Check(x))
 #endif
     return __Pyx_NewRef(x);
+#if CYTHON_USE_TYPE_SLOTS
   m = Py_TYPE(x)->tp_as_number;
-#if PY_MAJOR_VERSION < 3
+  #if PY_MAJOR_VERSION < 3
   if (m && m->nb_int) {
     name = "int";
     res = PyNumber_Int(x);
@@ -9147,11 +9795,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
     name = "long";
     res = PyNumber_Long(x);
   }
-#else
+  #else
   if (m && m->nb_int) {
     name = "int";
     res = PyNumber_Long(x);
   }
+  #endif
+#else
+  res = PyNumber_Int(x);
 #endif
   if (res) {
 #if PY_MAJOR_VERSION < 3
diff --git a/cutadapt/_align.pyx b/cutadapt/_align.pyx
index 57bc0f8..477a676 100644
--- a/cutadapt/_align.pyx
+++ b/cutadapt/_align.pyx
@@ -52,7 +52,7 @@ def _iupac_table():
 	C = 2
 	G = 4
 	T = 8
-	d = dict(
+	iupac = dict(
 		X=0,
 		A=A,
 		C=C,
@@ -72,7 +72,7 @@ def _iupac_table():
 		N=A|C|G|T
 	)
 	t = bytearray(b'\0') * 256
-	for c, v in d.items():
+	for c, v in iupac.items():
 		t[ord(c)] = v
 		t[ord(c.lower())] = v
 	return bytes(t)
diff --git a/cutadapt/_qualtrim.c b/cutadapt/_qualtrim.c
index d95f16a..a0a36f9 100644
--- a/cutadapt/_qualtrim.c
+++ b/cutadapt/_qualtrim.c
@@ -1,8 +1,9 @@
-/* Generated by Cython 0.23.4 */
+/* Generated by Cython 0.25.2 */
 
 /* BEGIN: Cython Metadata
 {
-    "distutils": {}
+    "distutils": {},
+    "module_name": "cutadapt._qualtrim"
 }
 END: Cython Metadata */
 
@@ -13,10 +14,10 @@ END: Cython Metadata */
 #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03020000)
     #error Cython requires Python 2.6+ or Python 3.2+.
 #else
-#define CYTHON_ABI "0_23_4"
+#define CYTHON_ABI "0_25_2"
 #include <stddef.h>
 #ifndef offsetof
-#define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
+  #define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
 #endif
 #if !defined(WIN32) && !defined(MS_WINDOWS)
   #ifndef __stdcall
@@ -35,6 +36,11 @@ END: Cython Metadata */
 #ifndef DL_EXPORT
   #define DL_EXPORT(t) t
 #endif
+#ifndef HAVE_LONG_LONG
+  #if PY_VERSION_HEX >= 0x03030000 || (PY_MAJOR_VERSION == 2 && PY_VERSION_HEX >= 0x02070000)
+    #define HAVE_LONG_LONG
+  #endif
+#endif
 #ifndef PY_LONG_LONG
   #define PY_LONG_LONG LONG_LONG
 #endif
@@ -42,17 +48,120 @@ END: Cython Metadata */
   #define Py_HUGE_VAL HUGE_VAL
 #endif
 #ifdef PYPY_VERSION
-#define CYTHON_COMPILING_IN_PYPY 1
-#define CYTHON_COMPILING_IN_CPYTHON 0
+  #define CYTHON_COMPILING_IN_PYPY 1
+  #define CYTHON_COMPILING_IN_PYSTON 0
+  #define CYTHON_COMPILING_IN_CPYTHON 0
+  #undef CYTHON_USE_TYPE_SLOTS
+  #define CYTHON_USE_TYPE_SLOTS 0
+  #undef CYTHON_USE_ASYNC_SLOTS
+  #define CYTHON_USE_ASYNC_SLOTS 0
+  #undef CYTHON_USE_PYLIST_INTERNALS
+  #define CYTHON_USE_PYLIST_INTERNALS 0
+  #undef CYTHON_USE_UNICODE_INTERNALS
+  #define CYTHON_USE_UNICODE_INTERNALS 0
+  #undef CYTHON_USE_UNICODE_WRITER
+  #define CYTHON_USE_UNICODE_WRITER 0
+  #undef CYTHON_USE_PYLONG_INTERNALS
+  #define CYTHON_USE_PYLONG_INTERNALS 0
+  #undef CYTHON_AVOID_BORROWED_REFS
+  #define CYTHON_AVOID_BORROWED_REFS 1
+  #undef CYTHON_ASSUME_SAFE_MACROS
+  #define CYTHON_ASSUME_SAFE_MACROS 0
+  #undef CYTHON_UNPACK_METHODS
+  #define CYTHON_UNPACK_METHODS 0
+  #undef CYTHON_FAST_THREAD_STATE
+  #define CYTHON_FAST_THREAD_STATE 0
+  #undef CYTHON_FAST_PYCALL
+  #define CYTHON_FAST_PYCALL 0
+#elif defined(PYSTON_VERSION)
+  #define CYTHON_COMPILING_IN_PYPY 0
+  #define CYTHON_COMPILING_IN_PYSTON 1
+  #define CYTHON_COMPILING_IN_CPYTHON 0
+  #ifndef CYTHON_USE_TYPE_SLOTS
+    #define CYTHON_USE_TYPE_SLOTS 1
+  #endif
+  #undef CYTHON_USE_ASYNC_SLOTS
+  #define CYTHON_USE_ASYNC_SLOTS 0
+  #undef CYTHON_USE_PYLIST_INTERNALS
+  #define CYTHON_USE_PYLIST_INTERNALS 0
+  #ifndef CYTHON_USE_UNICODE_INTERNALS
+    #define CYTHON_USE_UNICODE_INTERNALS 1
+  #endif
+  #undef CYTHON_USE_UNICODE_WRITER
+  #define CYTHON_USE_UNICODE_WRITER 0
+  #undef CYTHON_USE_PYLONG_INTERNALS
+  #define CYTHON_USE_PYLONG_INTERNALS 0
+  #ifndef CYTHON_AVOID_BORROWED_REFS
+    #define CYTHON_AVOID_BORROWED_REFS 0
+  #endif
+  #ifndef CYTHON_ASSUME_SAFE_MACROS
+    #define CYTHON_ASSUME_SAFE_MACROS 1
+  #endif
+  #ifndef CYTHON_UNPACK_METHODS
+    #define CYTHON_UNPACK_METHODS 1
+  #endif
+  #undef CYTHON_FAST_THREAD_STATE
+  #define CYTHON_FAST_THREAD_STATE 0
+  #undef CYTHON_FAST_PYCALL
+  #define CYTHON_FAST_PYCALL 0
 #else
-#define CYTHON_COMPILING_IN_PYPY 0
-#define CYTHON_COMPILING_IN_CPYTHON 1
+  #define CYTHON_COMPILING_IN_PYPY 0
+  #define CYTHON_COMPILING_IN_PYSTON 0
+  #define CYTHON_COMPILING_IN_CPYTHON 1
+  #ifndef CYTHON_USE_TYPE_SLOTS
+    #define CYTHON_USE_TYPE_SLOTS 1
+  #endif
+  #if PY_MAJOR_VERSION < 3
+    #undef CYTHON_USE_ASYNC_SLOTS
+    #define CYTHON_USE_ASYNC_SLOTS 0
+  #elif !defined(CYTHON_USE_ASYNC_SLOTS)
+    #define CYTHON_USE_ASYNC_SLOTS 1
+  #endif
+  #if PY_VERSION_HEX < 0x02070000
+    #undef CYTHON_USE_PYLONG_INTERNALS
+    #define CYTHON_USE_PYLONG_INTERNALS 0
+  #elif !defined(CYTHON_USE_PYLONG_INTERNALS)
+    #define CYTHON_USE_PYLONG_INTERNALS 1
+  #endif
+  #ifndef CYTHON_USE_PYLIST_INTERNALS
+    #define CYTHON_USE_PYLIST_INTERNALS 1
+  #endif
+  #ifndef CYTHON_USE_UNICODE_INTERNALS
+    #define CYTHON_USE_UNICODE_INTERNALS 1
+  #endif
+  #if PY_VERSION_HEX < 0x030300F0
+    #undef CYTHON_USE_UNICODE_WRITER
+    #define CYTHON_USE_UNICODE_WRITER 0
+  #elif !defined(CYTHON_USE_UNICODE_WRITER)
+    #define CYTHON_USE_UNICODE_WRITER 1
+  #endif
+  #ifndef CYTHON_AVOID_BORROWED_REFS
+    #define CYTHON_AVOID_BORROWED_REFS 0
+  #endif
+  #ifndef CYTHON_ASSUME_SAFE_MACROS
+    #define CYTHON_ASSUME_SAFE_MACROS 1
+  #endif
+  #ifndef CYTHON_UNPACK_METHODS
+    #define CYTHON_UNPACK_METHODS 1
+  #endif
+  #ifndef CYTHON_FAST_THREAD_STATE
+    #define CYTHON_FAST_THREAD_STATE 1
+  #endif
+  #ifndef CYTHON_FAST_PYCALL
+    #define CYTHON_FAST_PYCALL 1
+  #endif
 #endif
-#if !defined(CYTHON_USE_PYLONG_INTERNALS) && CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070000
-#define CYTHON_USE_PYLONG_INTERNALS 1
+#if !defined(CYTHON_FAST_PYCCALL)
+#define CYTHON_FAST_PYCCALL  (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1)
+#endif
+#if CYTHON_USE_PYLONG_INTERNALS
+  #include "longintrepr.h"
+  #undef SHIFT
+  #undef BASE
+  #undef MASK
 #endif
 #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag)
-#define Py_OptimizeFlag 0
+  #define Py_OptimizeFlag 0
 #endif
 #define __PYX_BUILD_PY_SSIZE_T "n"
 #define CYTHON_FORMAT_SSIZE_T "z"
@@ -79,23 +188,45 @@ END: Cython Metadata */
 #ifndef Py_TPFLAGS_HAVE_FINALIZE
   #define Py_TPFLAGS_HAVE_FINALIZE 0
 #endif
+#ifndef METH_FASTCALL
+  #define METH_FASTCALL 0x80
+  typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject **args,
+                                              Py_ssize_t nargs, PyObject *kwnames);
+#else
+  #define __Pyx_PyCFunctionFast _PyCFunctionFast
+#endif
+#if CYTHON_FAST_PYCCALL
+#define __Pyx_PyFastCFunction_Check(func)\
+    ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)))))
+#else
+#define __Pyx_PyFastCFunction_Check(func) 0
+#endif
 #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND)
   #define CYTHON_PEP393_ENABLED 1
   #define __Pyx_PyUnicode_READY(op)       (likely(PyUnicode_IS_READY(op)) ?\
                                               0 : _PyUnicode_Ready((PyObject *)(op)))
   #define __Pyx_PyUnicode_GET_LENGTH(u)   PyUnicode_GET_LENGTH(u)
   #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i)
+  #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u)   PyUnicode_MAX_CHAR_VALUE(u)
   #define __Pyx_PyUnicode_KIND(u)         PyUnicode_KIND(u)
   #define __Pyx_PyUnicode_DATA(u)         PyUnicode_DATA(u)
   #define __Pyx_PyUnicode_READ(k, d, i)   PyUnicode_READ(k, d, i)
+  #define __Pyx_PyUnicode_WRITE(k, d, i, ch)  PyUnicode_WRITE(k, d, i, ch)
+  #define __Pyx_PyUnicode_IS_TRUE(u)      (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u)))
 #else
   #define CYTHON_PEP393_ENABLED 0
+  #define PyUnicode_1BYTE_KIND  1
+  #define PyUnicode_2BYTE_KIND  2
+  #define PyUnicode_4BYTE_KIND  4
   #define __Pyx_PyUnicode_READY(op)       (0)
   #define __Pyx_PyUnicode_GET_LENGTH(u)   PyUnicode_GET_SIZE(u)
   #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i]))
+  #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u)   ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111)
   #define __Pyx_PyUnicode_KIND(u)         (sizeof(Py_UNICODE))
   #define __Pyx_PyUnicode_DATA(u)         ((void*)PyUnicode_AS_UNICODE(u))
   #define __Pyx_PyUnicode_READ(k, d, i)   ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i]))
+  #define __Pyx_PyUnicode_WRITE(k, d, i, ch)  (((void)(k)), ((Py_UNICODE*)d)[i] = ch)
+  #define __Pyx_PyUnicode_IS_TRUE(u)      (0 != PyUnicode_GET_SIZE(u))
 #endif
 #if CYTHON_COMPILING_IN_PYPY
   #define __Pyx_PyUnicode_Concat(a, b)      PyNumber_Add(a, b)
@@ -108,6 +239,24 @@ END: Cython Metadata */
 #if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains)
   #define PyUnicode_Contains(u, s)  PySequence_Contains(u, s)
 #endif
+#if CYTHON_COMPILING_IN_PYPY && !defined(PyByteArray_Check)
+  #define PyByteArray_Check(obj)  PyObject_TypeCheck(obj, &PyByteArray_Type)
+#endif
+#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format)
+  #define PyObject_Format(obj, fmt)  PyObject_CallMethod(obj, "__format__", "O", fmt)
+#endif
+#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc)
+  #define PyObject_Malloc(s)   PyMem_Malloc(s)
+  #define PyObject_Free(p)     PyMem_Free(p)
+  #define PyObject_Realloc(p)  PyMem_Realloc(p)
+#endif
+#if CYTHON_COMPILING_IN_PYSTON
+  #define __Pyx_PyCode_HasFreeVars(co)  PyCode_HasFreeVars(co)
+  #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno)
+#else
+  #define __Pyx_PyCode_HasFreeVars(co)  (PyCode_GetNumFree(co) > 0)
+  #define __Pyx_PyFrame_SetLineNumber(frame, lineno)  (frame)->f_lineno = (lineno)
+#endif
 #define __Pyx_PyString_FormatSafe(a, b)   ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b))
 #define __Pyx_PyUnicode_FormatSafe(a, b)  ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b))
 #if PY_MAJOR_VERSION >= 3
@@ -115,6 +264,9 @@ END: Cython Metadata */
 #else
   #define __Pyx_PyString_Format(a, b)  PyString_Format(a, b)
 #endif
+#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII)
+  #define PyObject_ASCII(o)            PyObject_Repr(o)
+#endif
 #if PY_MAJOR_VERSION >= 3
   #define PyBaseString_Type            PyUnicode_Type
   #define PyStringObject               PyUnicodeObject
@@ -133,6 +285,7 @@ END: Cython Metadata */
   #define PySet_CheckExact(obj)        (Py_TYPE(obj) == &PySet_Type)
 #endif
 #define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type)
+#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception)
 #if PY_MAJOR_VERSION >= 3
   #define PyIntObject                  PyLongObject
   #define PyInt_Type                   PyLong_Type
@@ -171,18 +324,20 @@ END: Cython Metadata */
 #else
   #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass)
 #endif
-#if PY_VERSION_HEX >= 0x030500B1
-#define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
-#define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
-#elif CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
-typedef struct {
-    unaryfunc am_await;
-    unaryfunc am_aiter;
-    unaryfunc am_anext;
-} __Pyx_PyAsyncMethodsStruct;
-#define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
+#if CYTHON_USE_ASYNC_SLOTS
+  #if PY_VERSION_HEX >= 0x030500B1
+    #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
+    #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
+  #else
+    typedef struct {
+        unaryfunc am_await;
+        unaryfunc am_aiter;
+        unaryfunc am_anext;
+    } __Pyx_PyAsyncMethodsStruct;
+    #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
+  #endif
 #else
-#define __Pyx_PyType_AsAsync(obj) NULL
+  #define __Pyx_PyType_AsAsync(obj) NULL
 #endif
 #ifndef CYTHON_RESTRICT
   #if defined(__GNUC__)
@@ -195,10 +350,39 @@ typedef struct {
     #define CYTHON_RESTRICT
   #endif
 #endif
+#ifndef CYTHON_UNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define CYTHON_UNUSED __attribute__ ((__unused__))
+#   else
+#     define CYTHON_UNUSED
+#   endif
+# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
+#   define CYTHON_UNUSED __attribute__ ((__unused__))
+# else
+#   define CYTHON_UNUSED
+# endif
+#endif
+#ifndef CYTHON_MAYBE_UNUSED_VAR
+#  if defined(__cplusplus)
+     template<class T> void CYTHON_MAYBE_UNUSED_VAR( const T& ) { }
+#  else
+#    define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x)
+#  endif
+#endif
+#ifndef CYTHON_NCP_UNUSED
+# if CYTHON_COMPILING_IN_CPYTHON
+#  define CYTHON_NCP_UNUSED
+# else
+#  define CYTHON_NCP_UNUSED CYTHON_UNUSED
+# endif
+#endif
 #define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None)
 
 #ifndef CYTHON_INLINE
-  #if defined(__GNUC__)
+  #if defined(__clang__)
+    #define CYTHON_INLINE __inline__ __attribute__ ((__unused__))
+  #elif defined(__GNUC__)
     #define CYTHON_INLINE __inline__
   #elif defined(_MSC_VER)
     #define CYTHON_INLINE __inline
@@ -222,8 +406,18 @@ static CYTHON_INLINE float __PYX_NAN() {
   return value;
 }
 #endif
+#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL)
+#define __Pyx_truncl trunc
+#else
+#define __Pyx_truncl truncl
+#endif
 
 
+#define __PYX_ERR(f_index, lineno, Ln_error) \
+{ \
+  __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \
+}
+
 #if PY_MAJOR_VERSION >= 3
   #define __Pyx_PyNumber_Divide(x,y)         PyNumber_TrueDivide(x,y)
   #define __Pyx_PyNumber_InPlaceDivide(x,y)  PyNumber_InPlaceTrueDivide(x,y)
@@ -250,27 +444,7 @@ static CYTHON_INLINE float __PYX_NAN() {
 #define CYTHON_WITHOUT_ASSERTIONS
 #endif
 
-#ifndef CYTHON_UNUSED
-# if defined(__GNUC__)
-#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
-#     define CYTHON_UNUSED __attribute__ ((__unused__))
-#   else
-#     define CYTHON_UNUSED
-#   endif
-# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
-#   define CYTHON_UNUSED __attribute__ ((__unused__))
-# else
-#   define CYTHON_UNUSED
-# endif
-#endif
-#ifndef CYTHON_NCP_UNUSED
-# if CYTHON_COMPILING_IN_CPYTHON
-#  define CYTHON_NCP_UNUSED
-# else
-#  define CYTHON_NCP_UNUSED CYTHON_UNUSED
-# endif
-#endif
-typedef struct {PyObject **p; char *s; const Py_ssize_t n; const char* encoding;
+typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding;
                 const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry;
 
 #define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0
@@ -344,15 +518,21 @@ static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)
 #define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None)
 #define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False))
 static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
-static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x);
+static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
 static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
 static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS
 #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
 #else
 #define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x)
 #endif
 #define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x))
+#if PY_MAJOR_VERSION >= 3
+#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x))
+#else
+#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x))
+#endif
+#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Float(x))
 #if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII
 static int __Pyx_sys_getdefaultencoding_not_ascii;
 static int __Pyx_init_sys_getdefaultencoding_params(void) {
@@ -443,6 +623,7 @@ static PyObject *__pyx_d;
 static PyObject *__pyx_b;
 static PyObject *__pyx_empty_tuple;
 static PyObject *__pyx_empty_bytes;
+static PyObject *__pyx_empty_unicode;
 static int __pyx_lineno;
 static int __pyx_clineno = 0;
 static const char * __pyx_cfilenm= __FILE__;
@@ -456,6 +637,7 @@ static const char *__pyx_f[] = {
 /*--- Type declarations ---*/
 
 /* --- Runtime support code (head) --- */
+/* Refnanny.proto */
 #ifndef CYTHON_REFNANNY
   #define CYTHON_REFNANNY 0
 #endif
@@ -518,7 +700,8 @@ static const char *__pyx_f[] = {
 #define __Pyx_CLEAR(r)    do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0)
 #define __Pyx_XCLEAR(r)   do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0)
 
-#if CYTHON_COMPILING_IN_CPYTHON
+/* PyObjectGetAttrStr.proto */
+#if CYTHON_USE_TYPE_SLOTS
 static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) {
     PyTypeObject* tp = Py_TYPE(obj);
     if (likely(tp->tp_getattro))
@@ -533,20 +716,26 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject
 #define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n)
 #endif
 
+/* GetBuiltinName.proto */
 static PyObject *__Pyx_GetBuiltinName(PyObject *name);
 
+/* RaiseArgTupleInvalid.proto */
 static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
     Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found);
 
+/* RaiseDoubleKeywords.proto */
 static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name);
 
+/* ParseKeywords.proto */
 static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\
     PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\
     const char* function_name);
 
+/* ArgTypeTest.proto */
 static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
     const char *name, int exact);
 
+/* GetItemInt.proto */
 #define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
     (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
     __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\
@@ -568,8 +757,10 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
                                                      int is_list, int wraparound, int boundscheck);
 
+/* UnicodeAsUCS4.proto */
 static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject*);
 
+/* object_ord.proto */
 #if PY_MAJOR_VERSION >= 3
 #define __Pyx_PyObject_Ord(c)\
     (likely(PyUnicode_Check(c)) ? (long)__Pyx_PyUnicode_AsPy_UCS4(c) : __Pyx__PyObject_Ord(c))
@@ -578,21 +769,26 @@ static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject*);
 #endif
 static long __Pyx__PyObject_Ord(PyObject* c);
 
+/* IncludeStringH.proto */
 #include <string.h>
 
+/* BytesEquals.proto */
 static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals);
 
+/* UnicodeEquals.proto */
 static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals);
 
+/* StrEquals.proto */
 #if PY_MAJOR_VERSION >= 3
 #define __Pyx_PyString_Equals __Pyx_PyUnicode_Equals
 #else
 #define __Pyx_PyString_Equals __Pyx_PyBytes_Equals
 #endif
 
+/* CodeObjectCache.proto */
 typedef struct {
-    int code_line;
     PyCodeObject* code_object;
+    int code_line;
 } __Pyx_CodeObjectCacheEntry;
 struct __Pyx_CodeObjectCache {
     int count;
@@ -604,19 +800,26 @@ static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int co
 static PyCodeObject *__pyx_find_code_object(int code_line);
 static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object);
 
+/* AddTraceback.proto */
 static void __Pyx_AddTraceback(const char *funcname, int c_line,
                                int py_line, const char *filename);
 
-static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *);
-
+/* CIntToPy.proto */
 static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value);
 
+/* CIntFromPy.proto */
+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *);
+
+/* CIntToPy.proto */
 static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value);
 
+/* CIntFromPy.proto */
 static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *);
 
+/* CheckBinaryVersion.proto */
 static int __Pyx_check_binary_version(void);
 
+/* InitStrings.proto */
 static int __Pyx_InitStrings(__Pyx_StringTabEntry *t);
 
 
@@ -628,31 +831,31 @@ int __pyx_module_is_main_cutadapt___qualtrim = 0;
 static PyObject *__pyx_builtin_range;
 static PyObject *__pyx_builtin_reversed;
 static PyObject *__pyx_builtin_xrange;
-static char __pyx_k_G[] = "G";
-static char __pyx_k_i[] = "i";
-static char __pyx_k_q[] = "q";
-static char __pyx_k_s[] = "s";
-static char __pyx_k_base[] = "base";
-static char __pyx_k_main[] = "__main__";
-static char __pyx_k_stop[] = "stop";
-static char __pyx_k_test[] = "__test__";
-static char __pyx_k_bases[] = "bases";
-static char __pyx_k_max_i[] = "max_i";
-static char __pyx_k_range[] = "range";
-static char __pyx_k_start[] = "start";
-static char __pyx_k_cutoff[] = "cutoff";
-static char __pyx_k_xrange[] = "xrange";
-static char __pyx_k_max_qual[] = "max_qual";
-static char __pyx_k_reversed[] = "reversed";
-static char __pyx_k_sequence[] = "sequence";
-static char __pyx_k_qualities[] = "qualities";
-static char __pyx_k_cutoff_back[] = "cutoff_back";
-static char __pyx_k_cutoff_front[] = "cutoff_front";
-static char __pyx_k_Quality_trimming[] = "\nQuality trimming.\n";
-static char __pyx_k_cutadapt__qualtrim[] = "cutadapt._qualtrim";
-static char __pyx_k_nextseq_trim_index[] = "nextseq_trim_index";
-static char __pyx_k_quality_trim_index[] = "quality_trim_index";
-static char __pyx_k_home_marcel_scm_cutadapt_cutada[] = "/home/marcel/scm/cutadapt/cutadapt/_qualtrim.pyx";
+static const char __pyx_k_G[] = "G";
+static const char __pyx_k_i[] = "i";
+static const char __pyx_k_q[] = "q";
+static const char __pyx_k_s[] = "s";
+static const char __pyx_k_base[] = "base";
+static const char __pyx_k_main[] = "__main__";
+static const char __pyx_k_stop[] = "stop";
+static const char __pyx_k_test[] = "__test__";
+static const char __pyx_k_bases[] = "bases";
+static const char __pyx_k_max_i[] = "max_i";
+static const char __pyx_k_range[] = "range";
+static const char __pyx_k_start[] = "start";
+static const char __pyx_k_cutoff[] = "cutoff";
+static const char __pyx_k_xrange[] = "xrange";
+static const char __pyx_k_max_qual[] = "max_qual";
+static const char __pyx_k_reversed[] = "reversed";
+static const char __pyx_k_sequence[] = "sequence";
+static const char __pyx_k_qualities[] = "qualities";
+static const char __pyx_k_cutoff_back[] = "cutoff_back";
+static const char __pyx_k_cutoff_front[] = "cutoff_front";
+static const char __pyx_k_Quality_trimming[] = "\nQuality trimming.\n";
+static const char __pyx_k_cutadapt__qualtrim[] = "cutadapt._qualtrim";
+static const char __pyx_k_nextseq_trim_index[] = "nextseq_trim_index";
+static const char __pyx_k_quality_trim_index[] = "quality_trim_index";
+static const char __pyx_k_home_marcel_scm_cutadapt_cutada[] = "/home/marcel/scm/cutadapt/cutadapt/_qualtrim.pyx";
 static PyObject *__pyx_n_s_G;
 static PyObject *__pyx_n_s_base;
 static PyObject *__pyx_n_s_bases;
@@ -684,13 +887,6 @@ static PyObject *__pyx_tuple__3;
 static PyObject *__pyx_codeobj__2;
 static PyObject *__pyx_codeobj__4;
 
-/* "cutadapt/_qualtrim.pyx":7
- * """
- * 
- * def quality_trim_index(str qualities, int cutoff_front, int cutoff_back, int base=33):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Find the positions at which to trim low-quality ends from a nucleotide sequence.
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_9_qualtrim_1quality_trim_index(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
@@ -701,9 +897,6 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_1quality_trim_index(PyObject *__p
   int __pyx_v_cutoff_front;
   int __pyx_v_cutoff_back;
   int __pyx_v_base;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("quality_trim_index (wrapper)", 0);
@@ -729,12 +922,12 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_1quality_trim_index(PyObject *__p
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_cutoff_front)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, 1); __PYX_ERR(0, 7, __pyx_L3_error)
         }
         case  2:
         if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_cutoff_back)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, 2); __PYX_ERR(0, 7, __pyx_L3_error)
         }
         case  3:
         if (kw_args > 0) {
@@ -743,7 +936,7 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_1quality_trim_index(PyObject *__p
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "quality_trim_index") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "quality_trim_index") < 0)) __PYX_ERR(0, 7, __pyx_L3_error)
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -756,23 +949,23 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_1quality_trim_index(PyObject *__p
       }
     }
     __pyx_v_qualities = ((PyObject*)values[0]);
-    __pyx_v_cutoff_front = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_cutoff_front == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-    __pyx_v_cutoff_back = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_cutoff_back == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_cutoff_front = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_cutoff_front == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 7, __pyx_L3_error)
+    __pyx_v_cutoff_back = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_cutoff_back == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 7, __pyx_L3_error)
     if (values[3]) {
-      __pyx_v_base = __Pyx_PyInt_As_int(values[3]); if (unlikely((__pyx_v_base == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_base = __Pyx_PyInt_As_int(values[3]); if (unlikely((__pyx_v_base == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 7, __pyx_L3_error)
     } else {
       __pyx_v_base = ((int)33);
     }
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("quality_trim_index", 0, 3, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 7, __pyx_L3_error)
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._qualtrim.quality_trim_index", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_qualities), (&PyString_Type), 1, "qualities", 1))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_qualities), (&PyString_Type), 1, "qualities", 1))) __PYX_ERR(0, 7, __pyx_L1_error)
   __pyx_r = __pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(__pyx_self, __pyx_v_qualities, __pyx_v_cutoff_front, __pyx_v_cutoff_back, __pyx_v_base);
 
   /* function exit code */
@@ -800,292 +993,93 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
   int __pyx_t_6;
   PyObject *__pyx_t_7 = NULL;
   PyObject *__pyx_t_8 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("quality_trim_index", 0);
 
-  /* "cutadapt/_qualtrim.pyx":22
- * 	cdef int s
- * 	cdef int max_qual
- * 	cdef int stop = len(qualities)             # <<<<<<<<<<<<<<
- * 	cdef int start = 0
- * 	cdef int i
- */
-  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 22, __pyx_L1_error)
   __pyx_v_stop = __pyx_t_1;
 
-  /* "cutadapt/_qualtrim.pyx":23
- * 	cdef int max_qual
- * 	cdef int stop = len(qualities)
- * 	cdef int start = 0             # <<<<<<<<<<<<<<
- * 	cdef int i
- * 
- */
   __pyx_v_start = 0;
 
-  /* "cutadapt/_qualtrim.pyx":27
- * 
- * 	# find trim position for 5' end
- * 	s = 0             # <<<<<<<<<<<<<<
- * 	max_qual = 0
- * 	for i in range(len(qualities)):
- */
   __pyx_v_s = 0;
 
-  /* "cutadapt/_qualtrim.pyx":28
- * 	# find trim position for 5' end
- * 	s = 0
- * 	max_qual = 0             # <<<<<<<<<<<<<<
- * 	for i in range(len(qualities)):
- * 		s += cutoff_front - (ord(qualities[i]) - base)
- */
   __pyx_v_max_qual = 0;
 
-  /* "cutadapt/_qualtrim.pyx":29
- * 	s = 0
- * 	max_qual = 0
- * 	for i in range(len(qualities)):             # <<<<<<<<<<<<<<
- * 		s += cutoff_front - (ord(qualities[i]) - base)
- * 		if s < 0:
- */
-  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 29, __pyx_L1_error)
   for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
     __pyx_v_i = __pyx_t_2;
 
-    /* "cutadapt/_qualtrim.pyx":30
- * 	max_qual = 0
- * 	for i in range(len(qualities)):
- * 		s += cutoff_front - (ord(qualities[i]) - base)             # <<<<<<<<<<<<<<
- * 		if s < 0:
- * 			break
- */
-    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 30, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_3); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_3); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) __PYX_ERR(0, 30, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     __pyx_v_s = (__pyx_v_s + (__pyx_v_cutoff_front - (__pyx_t_4 - __pyx_v_base)));
 
-    /* "cutadapt/_qualtrim.pyx":31
- * 	for i in range(len(qualities)):
- * 		s += cutoff_front - (ord(qualities[i]) - base)
- * 		if s < 0:             # <<<<<<<<<<<<<<
- * 			break
- * 		if s > max_qual:
- */
     __pyx_t_5 = ((__pyx_v_s < 0) != 0);
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":32
- * 		s += cutoff_front - (ord(qualities[i]) - base)
- * 		if s < 0:
- * 			break             # <<<<<<<<<<<<<<
- * 		if s > max_qual:
- * 			max_qual = s
- */
       goto __pyx_L4_break;
 
-      /* "cutadapt/_qualtrim.pyx":31
- * 	for i in range(len(qualities)):
- * 		s += cutoff_front - (ord(qualities[i]) - base)
- * 		if s < 0:             # <<<<<<<<<<<<<<
- * 			break
- * 		if s > max_qual:
- */
     }
 
-    /* "cutadapt/_qualtrim.pyx":33
- * 		if s < 0:
- * 			break
- * 		if s > max_qual:             # <<<<<<<<<<<<<<
- * 			max_qual = s
- * 			start = i + 1
- */
     __pyx_t_5 = ((__pyx_v_s > __pyx_v_max_qual) != 0);
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":34
- * 			break
- * 		if s > max_qual:
- * 			max_qual = s             # <<<<<<<<<<<<<<
- * 			start = i + 1
- * 
- */
       __pyx_v_max_qual = __pyx_v_s;
 
-      /* "cutadapt/_qualtrim.pyx":35
- * 		if s > max_qual:
- * 			max_qual = s
- * 			start = i + 1             # <<<<<<<<<<<<<<
- * 
- * 	# same for 3' end
- */
       __pyx_v_start = (__pyx_v_i + 1);
 
-      /* "cutadapt/_qualtrim.pyx":33
- * 		if s < 0:
- * 			break
- * 		if s > max_qual:             # <<<<<<<<<<<<<<
- * 			max_qual = s
- * 			start = i + 1
- */
     }
   }
   __pyx_L4_break:;
 
-  /* "cutadapt/_qualtrim.pyx":38
- * 
- * 	# same for 3' end
- * 	max_qual = 0             # <<<<<<<<<<<<<<
- * 	s = 0
- * 	for i in reversed(xrange(len(qualities))):
- */
   __pyx_v_max_qual = 0;
 
-  /* "cutadapt/_qualtrim.pyx":39
- * 	# same for 3' end
- * 	max_qual = 0
- * 	s = 0             # <<<<<<<<<<<<<<
- * 	for i in reversed(xrange(len(qualities))):
- * 		s += cutoff_back - (ord(qualities[i]) - base)
- */
   __pyx_v_s = 0;
 
-  /* "cutadapt/_qualtrim.pyx":40
- * 	max_qual = 0
- * 	s = 0
- * 	for i in reversed(xrange(len(qualities))):             # <<<<<<<<<<<<<<
- * 		s += cutoff_back - (ord(qualities[i]) - base)
- * 		if s < 0:
- */
-  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 40, __pyx_L1_error)
   for (__pyx_t_2 = __pyx_t_1-1; __pyx_t_2 >= 0; __pyx_t_2-=1) {
     __pyx_v_i = __pyx_t_2;
 
-    /* "cutadapt/_qualtrim.pyx":41
- * 	s = 0
- * 	for i in reversed(xrange(len(qualities))):
- * 		s += cutoff_back - (ord(qualities[i]) - base)             # <<<<<<<<<<<<<<
- * 		if s < 0:
- * 			break
- */
-    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 41, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_3); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_3); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) __PYX_ERR(0, 41, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
     __pyx_v_s = (__pyx_v_s + (__pyx_v_cutoff_back - (__pyx_t_4 - __pyx_v_base)));
 
-    /* "cutadapt/_qualtrim.pyx":42
- * 	for i in reversed(xrange(len(qualities))):
- * 		s += cutoff_back - (ord(qualities[i]) - base)
- * 		if s < 0:             # <<<<<<<<<<<<<<
- * 			break
- * 		if s > max_qual:
- */
     __pyx_t_5 = ((__pyx_v_s < 0) != 0);
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":43
- * 		s += cutoff_back - (ord(qualities[i]) - base)
- * 		if s < 0:
- * 			break             # <<<<<<<<<<<<<<
- * 		if s > max_qual:
- * 			max_qual = s
- */
       goto __pyx_L8_break;
 
-      /* "cutadapt/_qualtrim.pyx":42
- * 	for i in reversed(xrange(len(qualities))):
- * 		s += cutoff_back - (ord(qualities[i]) - base)
- * 		if s < 0:             # <<<<<<<<<<<<<<
- * 			break
- * 		if s > max_qual:
- */
     }
 
-    /* "cutadapt/_qualtrim.pyx":44
- * 		if s < 0:
- * 			break
- * 		if s > max_qual:             # <<<<<<<<<<<<<<
- * 			max_qual = s
- * 			stop = i
- */
     __pyx_t_5 = ((__pyx_v_s > __pyx_v_max_qual) != 0);
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":45
- * 			break
- * 		if s > max_qual:
- * 			max_qual = s             # <<<<<<<<<<<<<<
- * 			stop = i
- * 	if start >= stop:
- */
       __pyx_v_max_qual = __pyx_v_s;
 
-      /* "cutadapt/_qualtrim.pyx":46
- * 		if s > max_qual:
- * 			max_qual = s
- * 			stop = i             # <<<<<<<<<<<<<<
- * 	if start >= stop:
- * 		start, stop = 0, 0
- */
       __pyx_v_stop = __pyx_v_i;
 
-      /* "cutadapt/_qualtrim.pyx":44
- * 		if s < 0:
- * 			break
- * 		if s > max_qual:             # <<<<<<<<<<<<<<
- * 			max_qual = s
- * 			stop = i
- */
     }
   }
   __pyx_L8_break:;
 
-  /* "cutadapt/_qualtrim.pyx":47
- * 			max_qual = s
- * 			stop = i
- * 	if start >= stop:             # <<<<<<<<<<<<<<
- * 		start, stop = 0, 0
- * 	return (start, stop)
- */
   __pyx_t_5 = ((__pyx_v_start >= __pyx_v_stop) != 0);
   if (__pyx_t_5) {
 
-    /* "cutadapt/_qualtrim.pyx":48
- * 			stop = i
- * 	if start >= stop:
- * 		start, stop = 0, 0             # <<<<<<<<<<<<<<
- * 	return (start, stop)
- * 
- */
     __pyx_t_2 = 0;
     __pyx_t_6 = 0;
     __pyx_v_start = __pyx_t_2;
     __pyx_v_stop = __pyx_t_6;
 
-    /* "cutadapt/_qualtrim.pyx":47
- * 			max_qual = s
- * 			stop = i
- * 	if start >= stop:             # <<<<<<<<<<<<<<
- * 		start, stop = 0, 0
- * 	return (start, stop)
- */
   }
 
-  /* "cutadapt/_qualtrim.pyx":49
- * 	if start >= stop:
- * 		start, stop = 0, 0
- * 	return (start, stop)             # <<<<<<<<<<<<<<
- * 
- * 
- */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_start); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_start); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 49, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_7 = __Pyx_PyInt_From_int(__pyx_v_stop); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_7 = __Pyx_PyInt_From_int(__pyx_v_stop); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 49, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_7);
-  __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 49, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_8);
   __Pyx_GIVEREF(__pyx_t_3);
   PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_3);
@@ -1097,13 +1091,6 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
   __pyx_t_8 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_qualtrim.pyx":7
- * """
- * 
- * def quality_trim_index(str qualities, int cutoff_front, int cutoff_back, int base=33):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Find the positions at which to trim low-quality ends from a nucleotide sequence.
- */
 
   /* function exit code */
   __pyx_L1_error:;
@@ -1118,13 +1105,6 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_quality_trim_index(CYTHON_UNUSED
   return __pyx_r;
 }
 
-/* "cutadapt/_qualtrim.pyx":52
- * 
- * 
- * def nextseq_trim_index(sequence, int cutoff, int base=33):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Variant of the above quality trimming routine that works on NextSeq data.
- */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_8cutadapt_9_qualtrim_3nextseq_trim_index(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
@@ -1134,9 +1114,6 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_3nextseq_trim_index(PyObject *__p
   PyObject *__pyx_v_sequence = 0;
   int __pyx_v_cutoff;
   int __pyx_v_base;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("nextseq_trim_index (wrapper)", 0);
@@ -1161,7 +1138,7 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_3nextseq_trim_index(PyObject *__p
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_cutoff)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("nextseq_trim_index", 0, 2, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("nextseq_trim_index", 0, 2, 3, 1); __PYX_ERR(0, 52, __pyx_L3_error)
         }
         case  2:
         if (kw_args > 0) {
@@ -1170,7 +1147,7 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_3nextseq_trim_index(PyObject *__p
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "nextseq_trim_index") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "nextseq_trim_index") < 0)) __PYX_ERR(0, 52, __pyx_L3_error)
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -1182,16 +1159,16 @@ static PyObject *__pyx_pw_8cutadapt_9_qualtrim_3nextseq_trim_index(PyObject *__p
       }
     }
     __pyx_v_sequence = values[0];
-    __pyx_v_cutoff = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_cutoff == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_cutoff = __Pyx_PyInt_As_int(values[1]); if (unlikely((__pyx_v_cutoff == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 52, __pyx_L3_error)
     if (values[2]) {
-      __pyx_v_base = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_base == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      __pyx_v_base = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_base == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 52, __pyx_L3_error)
     } else {
       __pyx_v_base = ((int)33);
     }
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("nextseq_trim_index", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("nextseq_trim_index", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 52, __pyx_L3_error)
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._qualtrim.nextseq_trim_index", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
@@ -1219,239 +1196,78 @@ static PyObject *__pyx_pf_8cutadapt_9_qualtrim_2nextseq_trim_index(CYTHON_UNUSED
   int __pyx_t_3;
   long __pyx_t_4;
   int __pyx_t_5;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("nextseq_trim_index", 0);
 
-  /* "cutadapt/_qualtrim.pyx":63
- * 	bases as being equal to cutoff - 1.
- * 	"""
- * 	bases = sequence.sequence             # <<<<<<<<<<<<<<
- * 	qualities = sequence.qualities
- * 	cdef:
- */
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_sequence, __pyx_n_s_sequence); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_sequence, __pyx_n_s_sequence); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 63, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_bases = __pyx_t_1;
   __pyx_t_1 = 0;
 
-  /* "cutadapt/_qualtrim.pyx":64
- * 	"""
- * 	bases = sequence.sequence
- * 	qualities = sequence.qualities             # <<<<<<<<<<<<<<
- * 	cdef:
- * 		int s = 0
- */
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_sequence, __pyx_n_s_qualities); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_sequence, __pyx_n_s_qualities); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 64, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_qualities = __pyx_t_1;
   __pyx_t_1 = 0;
 
-  /* "cutadapt/_qualtrim.pyx":66
- * 	qualities = sequence.qualities
- * 	cdef:
- * 		int s = 0             # <<<<<<<<<<<<<<
- * 		int max_qual = 0
- * 		int max_i = len(qualities)
- */
   __pyx_v_s = 0;
 
-  /* "cutadapt/_qualtrim.pyx":67
- * 	cdef:
- * 		int s = 0
- * 		int max_qual = 0             # <<<<<<<<<<<<<<
- * 		int max_i = len(qualities)
- * 		int i, q
- */
   __pyx_v_max_qual = 0;
 
-  /* "cutadapt/_qualtrim.pyx":68
- * 		int s = 0
- * 		int max_qual = 0
- * 		int max_i = len(qualities)             # <<<<<<<<<<<<<<
- * 		int i, q
- * 
- */
-  __pyx_t_2 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 68; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_2 == -1)) __PYX_ERR(0, 68, __pyx_L1_error)
   __pyx_v_max_i = __pyx_t_2;
 
-  /* "cutadapt/_qualtrim.pyx":71
- * 		int i, q
- * 
- * 	s = 0             # <<<<<<<<<<<<<<
- * 	max_qual = 0
- * 	max_i = len(qualities)
- */
   __pyx_v_s = 0;
 
-  /* "cutadapt/_qualtrim.pyx":72
- * 
- * 	s = 0
- * 	max_qual = 0             # <<<<<<<<<<<<<<
- * 	max_i = len(qualities)
- * 	for i in reversed(xrange(max_i)):
- */
   __pyx_v_max_qual = 0;
 
-  /* "cutadapt/_qualtrim.pyx":73
- * 	s = 0
- * 	max_qual = 0
- * 	max_i = len(qualities)             # <<<<<<<<<<<<<<
- * 	for i in reversed(xrange(max_i)):
- * 		q = ord(qualities[i]) - base
- */
-  __pyx_t_2 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_2 == -1)) __PYX_ERR(0, 73, __pyx_L1_error)
   __pyx_v_max_i = __pyx_t_2;
 
-  /* "cutadapt/_qualtrim.pyx":74
- * 	max_qual = 0
- * 	max_i = len(qualities)
- * 	for i in reversed(xrange(max_i)):             # <<<<<<<<<<<<<<
- * 		q = ord(qualities[i]) - base
- * 		if bases[i] == 'G':
- */
   for (__pyx_t_3 = __pyx_v_max_i-1; __pyx_t_3 >= 0; __pyx_t_3-=1) {
     __pyx_v_i = __pyx_t_3;
 
-    /* "cutadapt/_qualtrim.pyx":75
- * 	max_i = len(qualities)
- * 	for i in reversed(xrange(max_i)):
- * 		q = ord(qualities[i]) - base             # <<<<<<<<<<<<<<
- * 		if bases[i] == 'G':
- * 			q = cutoff - 1
- */
-    __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+    __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_qualities, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 75, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_1); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = __Pyx_PyObject_Ord(__pyx_t_1); if (unlikely(__pyx_t_4 == (long)(Py_UCS4)-1)) __PYX_ERR(0, 75, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
     __pyx_v_q = (__pyx_t_4 - __pyx_v_base);
 
-    /* "cutadapt/_qualtrim.pyx":76
- * 	for i in reversed(xrange(max_i)):
- * 		q = ord(qualities[i]) - base
- * 		if bases[i] == 'G':             # <<<<<<<<<<<<<<
- * 			q = cutoff - 1
- * 		s += cutoff - q
- */
-    __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_bases, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+    __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_bases, __pyx_v_i, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 76, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_5 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_n_s_G, Py_EQ)); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_n_s_G, Py_EQ)); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 76, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":77
- * 		q = ord(qualities[i]) - base
- * 		if bases[i] == 'G':
- * 			q = cutoff - 1             # <<<<<<<<<<<<<<
- * 		s += cutoff - q
- * 		if s < 0:
- */
       __pyx_v_q = (__pyx_v_cutoff - 1);
 
-      /* "cutadapt/_qualtrim.pyx":76
- * 	for i in reversed(xrange(max_i)):
- * 		q = ord(qualities[i]) - base
- * 		if bases[i] == 'G':             # <<<<<<<<<<<<<<
- * 			q = cutoff - 1
- * 		s += cutoff - q
- */
     }
 
-    /* "cutadapt/_qualtrim.pyx":78
- * 		if bases[i] == 'G':
- * 			q = cutoff - 1
- * 		s += cutoff - q             # <<<<<<<<<<<<<<
- * 		if s < 0:
- * 			break
- */
     __pyx_v_s = (__pyx_v_s + (__pyx_v_cutoff - __pyx_v_q));
 
-    /* "cutadapt/_qualtrim.pyx":79
- * 			q = cutoff - 1
- * 		s += cutoff - q
- * 		if s < 0:             # <<<<<<<<<<<<<<
- * 			break
- * 		if s > max_qual:
- */
     __pyx_t_5 = ((__pyx_v_s < 0) != 0);
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":80
- * 		s += cutoff - q
- * 		if s < 0:
- * 			break             # <<<<<<<<<<<<<<
- * 		if s > max_qual:
- * 			max_qual = s
- */
       goto __pyx_L4_break;
 
-      /* "cutadapt/_qualtrim.pyx":79
- * 			q = cutoff - 1
- * 		s += cutoff - q
- * 		if s < 0:             # <<<<<<<<<<<<<<
- * 			break
- * 		if s > max_qual:
- */
     }
 
-    /* "cutadapt/_qualtrim.pyx":81
- * 		if s < 0:
- * 			break
- * 		if s > max_qual:             # <<<<<<<<<<<<<<
- * 			max_qual = s
- * 			max_i = i
- */
     __pyx_t_5 = ((__pyx_v_s > __pyx_v_max_qual) != 0);
     if (__pyx_t_5) {
 
-      /* "cutadapt/_qualtrim.pyx":82
- * 			break
- * 		if s > max_qual:
- * 			max_qual = s             # <<<<<<<<<<<<<<
- * 			max_i = i
- * 	return max_i
- */
       __pyx_v_max_qual = __pyx_v_s;
 
-      /* "cutadapt/_qualtrim.pyx":83
- * 		if s > max_qual:
- * 			max_qual = s
- * 			max_i = i             # <<<<<<<<<<<<<<
- * 	return max_i
- */
       __pyx_v_max_i = __pyx_v_i;
 
-      /* "cutadapt/_qualtrim.pyx":81
- * 		if s < 0:
- * 			break
- * 		if s > max_qual:             # <<<<<<<<<<<<<<
- * 			max_qual = s
- * 			max_i = i
- */
     }
   }
   __pyx_L4_break:;
 
-  /* "cutadapt/_qualtrim.pyx":84
- * 			max_qual = s
- * 			max_i = i
- * 	return max_i             # <<<<<<<<<<<<<<
- */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_max_i); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_max_i); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 84, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
-  /* "cutadapt/_qualtrim.pyx":52
- * 
- * 
- * def nextseq_trim_index(sequence, int cutoff, int base=33):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Variant of the above quality trimming routine that works on NextSeq data.
- */
 
   /* function exit code */
   __pyx_L1_error:;
@@ -1516,12 +1332,12 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {0, 0, 0, 0, 0, 0, 0}
 };
 static int __Pyx_InitCachedBuiltins(void) {
-  __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_reversed = __Pyx_GetBuiltinName(__pyx_n_s_reversed); if (!__pyx_builtin_reversed) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 29, __pyx_L1_error)
+  __pyx_builtin_reversed = __Pyx_GetBuiltinName(__pyx_n_s_reversed); if (!__pyx_builtin_reversed) __PYX_ERR(0, 40, __pyx_L1_error)
   #if PY_MAJOR_VERSION >= 3
-  __pyx_builtin_xrange = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_xrange) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_xrange = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_xrange) __PYX_ERR(0, 40, __pyx_L1_error)
   #else
-  __pyx_builtin_xrange = __Pyx_GetBuiltinName(__pyx_n_s_xrange); if (!__pyx_builtin_xrange) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_xrange = __Pyx_GetBuiltinName(__pyx_n_s_xrange); if (!__pyx_builtin_xrange) __PYX_ERR(0, 40, __pyx_L1_error)
   #endif
   return 0;
   __pyx_L1_error:;
@@ -1532,29 +1348,15 @@ static int __Pyx_InitCachedConstants(void) {
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0);
 
-  /* "cutadapt/_qualtrim.pyx":7
- * """
- * 
- * def quality_trim_index(str qualities, int cutoff_front, int cutoff_back, int base=33):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Find the positions at which to trim low-quality ends from a nucleotide sequence.
- */
-  __pyx_tuple_ = PyTuple_Pack(9, __pyx_n_s_qualities, __pyx_n_s_cutoff_front, __pyx_n_s_cutoff_back, __pyx_n_s_base, __pyx_n_s_s, __pyx_n_s_max_qual, __pyx_n_s_stop, __pyx_n_s_start, __pyx_n_s_i); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_tuple_ = PyTuple_Pack(9, __pyx_n_s_qualities, __pyx_n_s_cutoff_front, __pyx_n_s_cutoff_back, __pyx_n_s_base, __pyx_n_s_s, __pyx_n_s_max_qual, __pyx_n_s_stop, __pyx_n_s_start, __pyx_n_s_i); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 7, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple_);
   __Pyx_GIVEREF(__pyx_tuple_);
-  __pyx_codeobj__2 = (PyObject*)__Pyx_PyCode_New(4, 0, 9, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple_, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_quality_trim_index, 7, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "cutadapt/_qualtrim.pyx":52
- * 
- * 
- * def nextseq_trim_index(sequence, int cutoff, int base=33):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Variant of the above quality trimming routine that works on NextSeq data.
- */
-  __pyx_tuple__3 = PyTuple_Pack(10, __pyx_n_s_sequence, __pyx_n_s_cutoff, __pyx_n_s_base, __pyx_n_s_bases, __pyx_n_s_qualities, __pyx_n_s_s, __pyx_n_s_max_qual, __pyx_n_s_max_i, __pyx_n_s_i, __pyx_n_s_q); if (unlikely(!__pyx_tuple__3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_codeobj__2 = (PyObject*)__Pyx_PyCode_New(4, 0, 9, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple_, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_quality_trim_index, 7, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__2)) __PYX_ERR(0, 7, __pyx_L1_error)
+
+  __pyx_tuple__3 = PyTuple_Pack(10, __pyx_n_s_sequence, __pyx_n_s_cutoff, __pyx_n_s_base, __pyx_n_s_bases, __pyx_n_s_qualities, __pyx_n_s_s, __pyx_n_s_max_qual, __pyx_n_s_max_i, __pyx_n_s_i, __pyx_n_s_q); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 52, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__3);
   __Pyx_GIVEREF(__pyx_tuple__3);
-  __pyx_codeobj__4 = (PyObject*)__Pyx_PyCode_New(3, 0, 10, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__3, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_nextseq_trim_index, 52, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_codeobj__4 = (PyObject*)__Pyx_PyCode_New(3, 0, 10, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__3, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_nextseq_trim_index, 52, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__4)) __PYX_ERR(0, 52, __pyx_L1_error)
   __Pyx_RefNannyFinishContext();
   return 0;
   __pyx_L1_error:;
@@ -1563,7 +1365,7 @@ static int __Pyx_InitCachedConstants(void) {
 }
 
 static int __Pyx_InitGlobals(void) {
-  if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error);
   return 0;
   __pyx_L1_error:;
   return -1;
@@ -1578,9 +1380,6 @@ PyMODINIT_FUNC PyInit__qualtrim(void)
 #endif
 {
   PyObject *__pyx_t_1 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannyDeclarations
   #if CYTHON_REFNANNY
   __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny");
@@ -1592,23 +1391,24 @@ PyMODINIT_FUNC PyInit__qualtrim(void)
   }
   #endif
   __Pyx_RefNannySetupContext("PyMODINIT_FUNC PyInit__qualtrim(void)", 0);
-  if (__Pyx_check_binary_version() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_check_binary_version() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error)
   #ifdef __Pyx_CyFunction_USED
-  if (__pyx_CyFunction_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_CyFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   #ifdef __Pyx_FusedFunction_USED
-  if (__pyx_FusedFunction_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_FusedFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   #ifdef __Pyx_Coroutine_USED
-  if (__pyx_Coroutine_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_Coroutine_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   #ifdef __Pyx_Generator_USED
-  if (__pyx_Generator_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_Generator_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   #ifdef __Pyx_StopAsyncIteration_USED
-  if (__pyx_StopAsyncIteration_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_StopAsyncIteration_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   /*--- Library function declarations ---*/
   /*--- Threads initialization code ---*/
@@ -1623,34 +1423,34 @@ PyMODINIT_FUNC PyInit__qualtrim(void)
   #else
   __pyx_m = PyModule_Create(&__pyx_moduledef);
   #endif
-  if (unlikely(!__pyx_m)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error)
+  __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error)
   Py_INCREF(__pyx_d);
-  __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error)
   #if CYTHON_COMPILING_IN_PYPY
   Py_INCREF(__pyx_b);
   #endif
-  if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error);
   /*--- Initialize various global constants etc. ---*/
-  if (__Pyx_InitGlobals() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT)
-  if (__Pyx_init_sys_getdefaultencoding_params() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
   if (__pyx_module_is_main_cutadapt___qualtrim) {
-    if (PyObject_SetAttrString(__pyx_m, "__name__", __pyx_n_s_main) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (PyObject_SetAttrString(__pyx_m, "__name__", __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   }
   #if PY_MAJOR_VERSION >= 3
   {
-    PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error)
     if (!PyDict_GetItemString(modules, "cutadapt._qualtrim")) {
-      if (unlikely(PyDict_SetItemString(modules, "cutadapt._qualtrim", __pyx_m) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      if (unlikely(PyDict_SetItemString(modules, "cutadapt._qualtrim", __pyx_m) < 0)) __PYX_ERR(0, 1, __pyx_L1_error)
     }
   }
   #endif
   /*--- Builtin init code ---*/
-  if (__Pyx_InitCachedBuiltins() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   /*--- Constants init code ---*/
-  if (__Pyx_InitCachedConstants() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   /*--- Global init code ---*/
   /*--- Variable export code ---*/
   /*--- Function export code ---*/
@@ -1660,41 +1460,22 @@ PyMODINIT_FUNC PyInit__qualtrim(void)
   /*--- Function import code ---*/
   /*--- Execution code ---*/
   #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
-  if (__Pyx_patch_abc() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   #endif
 
-  /* "cutadapt/_qualtrim.pyx":7
- * """
- * 
- * def quality_trim_index(str qualities, int cutoff_front, int cutoff_back, int base=33):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Find the positions at which to trim low-quality ends from a nucleotide sequence.
- */
-  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_9_qualtrim_1quality_trim_index, NULL, __pyx_n_s_cutadapt__qualtrim); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_9_qualtrim_1quality_trim_index, NULL, __pyx_n_s_cutadapt__qualtrim); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 7, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_quality_trim_index, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_quality_trim_index, __pyx_t_1) < 0) __PYX_ERR(0, 7, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_qualtrim.pyx":52
- * 
- * 
- * def nextseq_trim_index(sequence, int cutoff, int base=33):             # <<<<<<<<<<<<<<
- * 	"""
- * 	Variant of the above quality trimming routine that works on NextSeq data.
- */
-  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_9_qualtrim_3nextseq_trim_index, NULL, __pyx_n_s_cutadapt__qualtrim); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_8cutadapt_9_qualtrim_3nextseq_trim_index, NULL, __pyx_n_s_cutadapt__qualtrim); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 52, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_nextseq_trim_index, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_nextseq_trim_index, __pyx_t_1) < 0) __PYX_ERR(0, 52, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "cutadapt/_qualtrim.pyx":1
- * # kate: syntax Python;             # <<<<<<<<<<<<<<
- * # cython: profile=False, emit_code_comments=False
- * """
- */
-  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
   /*--- Wrapped vars code ---*/
@@ -1720,6 +1501,7 @@ PyMODINIT_FUNC PyInit__qualtrim(void)
 }
 
 /* --- Runtime support code --- */
+/* Refnanny */
 #if CYTHON_REFNANNY
 static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) {
     PyObject *m = NULL, *p = NULL;
@@ -1736,6 +1518,7 @@ end:
 }
 #endif
 
+/* GetBuiltinName */
 static PyObject *__Pyx_GetBuiltinName(PyObject *name) {
     PyObject* result = __Pyx_PyObject_GetAttrStr(__pyx_b, name);
     if (unlikely(!result)) {
@@ -1749,6 +1532,7 @@ static PyObject *__Pyx_GetBuiltinName(PyObject *name) {
     return result;
 }
 
+/* RaiseArgTupleInvalid */
 static void __Pyx_RaiseArgtupleInvalid(
     const char* func_name,
     int exact,
@@ -1774,6 +1558,7 @@ static void __Pyx_RaiseArgtupleInvalid(
                  (num_expected == 1) ? "" : "s", num_found);
 }
 
+/* RaiseDoubleKeywords */
 static void __Pyx_RaiseDoubleKeywordsError(
     const char* func_name,
     PyObject* kw_name)
@@ -1787,6 +1572,7 @@ static void __Pyx_RaiseDoubleKeywordsError(
         #endif
 }
 
+/* ParseKeywords */
 static int __Pyx_ParseOptionalKeywords(
     PyObject *kwds,
     PyObject **argnames[],
@@ -1888,6 +1674,7 @@ bad:
     return -1;
 }
 
+/* ArgTypeTest */
 static void __Pyx_RaiseArgumentTypeInvalid(const char* name, PyObject *obj, PyTypeObject *type) {
     PyErr_Format(PyExc_TypeError,
         "Argument '%.200s' has incorrect type (expected %.200s, got %.200s)",
@@ -1914,6 +1701,7 @@ static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, in
     return 0;
 }
 
+/* GetItemInt */
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
     PyObject *r;
     if (!j) return NULL;
@@ -1924,7 +1712,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i,
                                                               CYTHON_NCP_UNUSED int wraparound,
                                                               CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
     if (wraparound & unlikely(i < 0)) i += PyList_GET_SIZE(o);
     if ((!boundscheck) || likely((0 <= i) & (i < PyList_GET_SIZE(o)))) {
         PyObject *r = PyList_GET_ITEM(o, i);
@@ -1939,7 +1727,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i,
                                                               CYTHON_NCP_UNUSED int wraparound,
                                                               CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
     if (wraparound & unlikely(i < 0)) i += PyTuple_GET_SIZE(o);
     if ((!boundscheck) || likely((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
         PyObject *r = PyTuple_GET_ITEM(o, i);
@@ -1954,7 +1742,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list,
                                                      CYTHON_NCP_UNUSED int wraparound,
                                                      CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS
     if (is_list || PyList_CheckExact(o)) {
         Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o);
         if ((!boundscheck) || (likely((n >= 0) & (n < PyList_GET_SIZE(o))))) {
@@ -1978,10 +1766,9 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
                 if (likely(l >= 0)) {
                     i += l;
                 } else {
-                    if (PyErr_ExceptionMatches(PyExc_OverflowError))
-                        PyErr_Clear();
-                    else
+                    if (!PyErr_ExceptionMatches(PyExc_OverflowError))
                         return NULL;
+                    PyErr_Clear();
                 }
             }
             return m->sq_item(o, i);
@@ -1995,6 +1782,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
     return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
 }
 
+/* UnicodeAsUCS4 */
 static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject* x) {
    Py_ssize_t length;
    #if CYTHON_PEP393_ENABLED
@@ -2025,6 +1813,7 @@ static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject* x) {
    return (Py_UCS4)-1;
 }
 
+/* object_ord */
 static long __Pyx__PyObject_Ord(PyObject* c) {
     Py_ssize_t size;
     if (PyBytes_Check(c)) {
@@ -2053,6 +1842,7 @@ static long __Pyx__PyObject_Ord(PyObject* c) {
     return (long)(Py_UCS4)-1;
 }
 
+/* BytesEquals */
 static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) {
 #if CYTHON_COMPILING_IN_PYPY
     return PyObject_RichCompareBool(s1, s2, equals);
@@ -2090,6 +1880,7 @@ static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int eq
 #endif
 }
 
+/* UnicodeEquals */
 static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) {
 #if CYTHON_COMPILING_IN_PYPY
     return PyObject_RichCompareBool(s1, s2, equals);
@@ -2173,6 +1964,7 @@ return_ne:
 #endif
 }
 
+/* CodeObjectCache */
 static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) {
     int start = 0, mid = 0, end = count - 1;
     if (end >= 0 && code_line > entries[end].code_line) {
@@ -2252,6 +2044,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) {
     Py_INCREF(code_object);
 }
 
+/* AddTraceback */
 #include "compile.h"
 #include "frameobject.h"
 #include "traceback.h"
@@ -2325,13 +2118,14 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
         0                    /*PyObject *locals*/
     );
     if (!py_frame) goto bad;
-    py_frame->f_lineno = py_line;
+    __Pyx_PyFrame_SetLineNumber(py_frame, py_line);
     PyTraceBack_Here(py_frame);
 bad:
     Py_XDECREF(py_code);
     Py_XDECREF(py_frame);
 }
 
+/* CIntFromPyVerify */
 #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\
     __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0)
 #define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\
@@ -2353,10 +2147,38 @@ bad:
         return (target_type) value;\
     }
 
-#if CYTHON_USE_PYLONG_INTERNALS
-  #include "longintrepr.h"
+/* CIntToPy */
+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) {
+    const int neg_one = (int) -1, const_zero = (int) 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (is_unsigned) {
+        if (sizeof(int) < sizeof(long)) {
+            return PyInt_FromLong((long) value);
+        } else if (sizeof(int) <= sizeof(unsigned long)) {
+            return PyLong_FromUnsignedLong((unsigned long) value);
+#ifdef HAVE_LONG_LONG
+        } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
+            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
+#endif
+        }
+    } else {
+        if (sizeof(int) <= sizeof(long)) {
+            return PyInt_FromLong((long) value);
+#ifdef HAVE_LONG_LONG
+        } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) {
+            return PyLong_FromLongLong((PY_LONG_LONG) value);
 #endif
+        }
+    }
+    {
+        int one = 1; int little = (int)*(unsigned char *)&one;
+        unsigned char *bytes = (unsigned char *)&value;
+        return _PyLong_FromByteArray(bytes, sizeof(int),
+                                     little, !is_unsigned);
+    }
+}
 
+/* CIntFromPy */
 static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
     const int neg_one = (int) -1, const_zero = (int) 0;
     const int is_unsigned = neg_one > const_zero;
@@ -2424,15 +2246,17 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
 #endif
             if (sizeof(int) <= sizeof(unsigned long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x))
+#endif
             }
         } else {
 #if CYTHON_USE_PYLONG_INTERNALS
             const digit* digits = ((PyLongObject*)x)->ob_digit;
             switch (Py_SIZE(x)) {
                 case  0: return (int) 0;
-                case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, -(sdigit) digits[0])
+                case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0]))
                 case  1: __PYX_VERIFY_RETURN_INT(int,  digit, +digits[0])
                 case -2:
                     if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) {
@@ -2492,8 +2316,10 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
 #endif
             if (sizeof(int) <= sizeof(long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x))
+#endif
             }
         }
         {
@@ -2502,7 +2328,7 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
                             "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers");
 #else
             int val;
-            PyObject *v = __Pyx_PyNumber_Int(x);
+            PyObject *v = __Pyx_PyNumber_IntOrLong(x);
  #if PY_MAJOR_VERSION < 3
             if (likely(v) && !PyLong_Check(v)) {
                 PyObject *tmp = v;
@@ -2525,7 +2351,7 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
         }
     } else {
         int val;
-        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        PyObject *tmp = __Pyx_PyNumber_IntOrLong(x);
         if (!tmp) return (int) -1;
         val = __Pyx_PyInt_As_int(tmp);
         Py_DECREF(tmp);
@@ -2541,32 +2367,7 @@ raise_neg_overflow:
     return (int) -1;
 }
 
-static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) {
-    const int neg_one = (int) -1, const_zero = (int) 0;
-    const int is_unsigned = neg_one > const_zero;
-    if (is_unsigned) {
-        if (sizeof(int) < sizeof(long)) {
-            return PyInt_FromLong((long) value);
-        } else if (sizeof(int) <= sizeof(unsigned long)) {
-            return PyLong_FromUnsignedLong((unsigned long) value);
-        } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
-            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
-        }
-    } else {
-        if (sizeof(int) <= sizeof(long)) {
-            return PyInt_FromLong((long) value);
-        } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) {
-            return PyLong_FromLongLong((PY_LONG_LONG) value);
-        }
-    }
-    {
-        int one = 1; int little = (int)*(unsigned char *)&one;
-        unsigned char *bytes = (unsigned char *)&value;
-        return _PyLong_FromByteArray(bytes, sizeof(int),
-                                     little, !is_unsigned);
-    }
-}
-
+/* CIntToPy */
 static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
     const long neg_one = (long) -1, const_zero = (long) 0;
     const int is_unsigned = neg_one > const_zero;
@@ -2575,14 +2376,18 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
             return PyInt_FromLong((long) value);
         } else if (sizeof(long) <= sizeof(unsigned long)) {
             return PyLong_FromUnsignedLong((unsigned long) value);
+#ifdef HAVE_LONG_LONG
         } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
             return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
+#endif
         }
     } else {
         if (sizeof(long) <= sizeof(long)) {
             return PyInt_FromLong((long) value);
+#ifdef HAVE_LONG_LONG
         } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
             return PyLong_FromLongLong((PY_LONG_LONG) value);
+#endif
         }
     }
     {
@@ -2593,6 +2398,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
     }
 }
 
+/* CIntFromPy */
 static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
     const long neg_one = (long) -1, const_zero = (long) 0;
     const int is_unsigned = neg_one > const_zero;
@@ -2660,15 +2466,17 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
 #endif
             if (sizeof(long) <= sizeof(unsigned long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x))
+#endif
             }
         } else {
 #if CYTHON_USE_PYLONG_INTERNALS
             const digit* digits = ((PyLongObject*)x)->ob_digit;
             switch (Py_SIZE(x)) {
                 case  0: return (long) 0;
-                case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, -(sdigit) digits[0])
+                case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0]))
                 case  1: __PYX_VERIFY_RETURN_INT(long,  digit, +digits[0])
                 case -2:
                     if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) {
@@ -2728,8 +2536,10 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
 #endif
             if (sizeof(long) <= sizeof(long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x))
+#endif
             }
         }
         {
@@ -2738,7 +2548,7 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
                             "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers");
 #else
             long val;
-            PyObject *v = __Pyx_PyNumber_Int(x);
+            PyObject *v = __Pyx_PyNumber_IntOrLong(x);
  #if PY_MAJOR_VERSION < 3
             if (likely(v) && !PyLong_Check(v)) {
                 PyObject *tmp = v;
@@ -2761,7 +2571,7 @@ static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
         }
     } else {
         long val;
-        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        PyObject *tmp = __Pyx_PyNumber_IntOrLong(x);
         if (!tmp) return (long) -1;
         val = __Pyx_PyInt_As_long(tmp);
         Py_DECREF(tmp);
@@ -2777,6 +2587,7 @@ raise_neg_overflow:
     return (long) -1;
 }
 
+/* CheckBinaryVersion */
 static int __Pyx_check_binary_version(void) {
     char ctversion[4], rtversion[4];
     PyOS_snprintf(ctversion, 4, "%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION);
@@ -2792,6 +2603,7 @@ static int __Pyx_check_binary_version(void) {
     return 0;
 }
 
+/* InitStrings */
 static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
     while (t->p) {
         #if PY_MAJOR_VERSION < 3
@@ -2892,8 +2704,10 @@ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
    if (is_true | (x == Py_False) | (x == Py_None)) return is_true;
    else return PyObject_IsTrue(x);
 }
-static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) {
+static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
+#if CYTHON_USE_TYPE_SLOTS
   PyNumberMethods *m;
+#endif
   const char *name = NULL;
   PyObject *res = NULL;
 #if PY_MAJOR_VERSION < 3
@@ -2902,8 +2716,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) {
   if (PyLong_Check(x))
 #endif
     return __Pyx_NewRef(x);
+#if CYTHON_USE_TYPE_SLOTS
   m = Py_TYPE(x)->tp_as_number;
-#if PY_MAJOR_VERSION < 3
+  #if PY_MAJOR_VERSION < 3
   if (m && m->nb_int) {
     name = "int";
     res = PyNumber_Int(x);
@@ -2912,11 +2727,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) {
     name = "long";
     res = PyNumber_Long(x);
   }
-#else
+  #else
   if (m && m->nb_int) {
     name = "int";
     res = PyNumber_Long(x);
   }
+  #endif
+#else
+  res = PyNumber_Int(x);
 #endif
   if (res) {
 #if PY_MAJOR_VERSION < 3
diff --git a/cutadapt/_seqio.c b/cutadapt/_seqio.c
index 04eacc2..923bc46 100644
--- a/cutadapt/_seqio.c
+++ b/cutadapt/_seqio.c
@@ -1,8 +1,9 @@
-/* Generated by Cython 0.24 */
+/* Generated by Cython 0.25.2 */
 
 /* BEGIN: Cython Metadata
 {
-    "distutils": {}
+    "distutils": {},
+    "module_name": "cutadapt._seqio"
 }
 END: Cython Metadata */
 
@@ -13,7 +14,7 @@ END: Cython Metadata */
 #elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03020000)
     #error Cython requires Python 2.6+ or Python 3.2+.
 #else
-#define CYTHON_ABI "0_24"
+#define CYTHON_ABI "0_25_2"
 #include <stddef.h>
 #ifndef offsetof
   #define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
@@ -35,6 +36,11 @@ END: Cython Metadata */
 #ifndef DL_EXPORT
   #define DL_EXPORT(t) t
 #endif
+#ifndef HAVE_LONG_LONG
+  #if PY_VERSION_HEX >= 0x03030000 || (PY_MAJOR_VERSION == 2 && PY_VERSION_HEX >= 0x02070000)
+    #define HAVE_LONG_LONG
+  #endif
+#endif
 #ifndef PY_LONG_LONG
   #define PY_LONG_LONG LONG_LONG
 #endif
@@ -43,13 +49,110 @@ END: Cython Metadata */
 #endif
 #ifdef PYPY_VERSION
   #define CYTHON_COMPILING_IN_PYPY 1
+  #define CYTHON_COMPILING_IN_PYSTON 0
+  #define CYTHON_COMPILING_IN_CPYTHON 0
+  #undef CYTHON_USE_TYPE_SLOTS
+  #define CYTHON_USE_TYPE_SLOTS 0
+  #undef CYTHON_USE_ASYNC_SLOTS
+  #define CYTHON_USE_ASYNC_SLOTS 0
+  #undef CYTHON_USE_PYLIST_INTERNALS
+  #define CYTHON_USE_PYLIST_INTERNALS 0
+  #undef CYTHON_USE_UNICODE_INTERNALS
+  #define CYTHON_USE_UNICODE_INTERNALS 0
+  #undef CYTHON_USE_UNICODE_WRITER
+  #define CYTHON_USE_UNICODE_WRITER 0
+  #undef CYTHON_USE_PYLONG_INTERNALS
+  #define CYTHON_USE_PYLONG_INTERNALS 0
+  #undef CYTHON_AVOID_BORROWED_REFS
+  #define CYTHON_AVOID_BORROWED_REFS 1
+  #undef CYTHON_ASSUME_SAFE_MACROS
+  #define CYTHON_ASSUME_SAFE_MACROS 0
+  #undef CYTHON_UNPACK_METHODS
+  #define CYTHON_UNPACK_METHODS 0
+  #undef CYTHON_FAST_THREAD_STATE
+  #define CYTHON_FAST_THREAD_STATE 0
+  #undef CYTHON_FAST_PYCALL
+  #define CYTHON_FAST_PYCALL 0
+#elif defined(PYSTON_VERSION)
+  #define CYTHON_COMPILING_IN_PYPY 0
+  #define CYTHON_COMPILING_IN_PYSTON 1
   #define CYTHON_COMPILING_IN_CPYTHON 0
+  #ifndef CYTHON_USE_TYPE_SLOTS
+    #define CYTHON_USE_TYPE_SLOTS 1
+  #endif
+  #undef CYTHON_USE_ASYNC_SLOTS
+  #define CYTHON_USE_ASYNC_SLOTS 0
+  #undef CYTHON_USE_PYLIST_INTERNALS
+  #define CYTHON_USE_PYLIST_INTERNALS 0
+  #ifndef CYTHON_USE_UNICODE_INTERNALS
+    #define CYTHON_USE_UNICODE_INTERNALS 1
+  #endif
+  #undef CYTHON_USE_UNICODE_WRITER
+  #define CYTHON_USE_UNICODE_WRITER 0
+  #undef CYTHON_USE_PYLONG_INTERNALS
+  #define CYTHON_USE_PYLONG_INTERNALS 0
+  #ifndef CYTHON_AVOID_BORROWED_REFS
+    #define CYTHON_AVOID_BORROWED_REFS 0
+  #endif
+  #ifndef CYTHON_ASSUME_SAFE_MACROS
+    #define CYTHON_ASSUME_SAFE_MACROS 1
+  #endif
+  #ifndef CYTHON_UNPACK_METHODS
+    #define CYTHON_UNPACK_METHODS 1
+  #endif
+  #undef CYTHON_FAST_THREAD_STATE
+  #define CYTHON_FAST_THREAD_STATE 0
+  #undef CYTHON_FAST_PYCALL
+  #define CYTHON_FAST_PYCALL 0
 #else
   #define CYTHON_COMPILING_IN_PYPY 0
+  #define CYTHON_COMPILING_IN_PYSTON 0
   #define CYTHON_COMPILING_IN_CPYTHON 1
+  #ifndef CYTHON_USE_TYPE_SLOTS
+    #define CYTHON_USE_TYPE_SLOTS 1
+  #endif
+  #if PY_MAJOR_VERSION < 3
+    #undef CYTHON_USE_ASYNC_SLOTS
+    #define CYTHON_USE_ASYNC_SLOTS 0
+  #elif !defined(CYTHON_USE_ASYNC_SLOTS)
+    #define CYTHON_USE_ASYNC_SLOTS 1
+  #endif
+  #if PY_VERSION_HEX < 0x02070000
+    #undef CYTHON_USE_PYLONG_INTERNALS
+    #define CYTHON_USE_PYLONG_INTERNALS 0
+  #elif !defined(CYTHON_USE_PYLONG_INTERNALS)
+    #define CYTHON_USE_PYLONG_INTERNALS 1
+  #endif
+  #ifndef CYTHON_USE_PYLIST_INTERNALS
+    #define CYTHON_USE_PYLIST_INTERNALS 1
+  #endif
+  #ifndef CYTHON_USE_UNICODE_INTERNALS
+    #define CYTHON_USE_UNICODE_INTERNALS 1
+  #endif
+  #if PY_VERSION_HEX < 0x030300F0
+    #undef CYTHON_USE_UNICODE_WRITER
+    #define CYTHON_USE_UNICODE_WRITER 0
+  #elif !defined(CYTHON_USE_UNICODE_WRITER)
+    #define CYTHON_USE_UNICODE_WRITER 1
+  #endif
+  #ifndef CYTHON_AVOID_BORROWED_REFS
+    #define CYTHON_AVOID_BORROWED_REFS 0
+  #endif
+  #ifndef CYTHON_ASSUME_SAFE_MACROS
+    #define CYTHON_ASSUME_SAFE_MACROS 1
+  #endif
+  #ifndef CYTHON_UNPACK_METHODS
+    #define CYTHON_UNPACK_METHODS 1
+  #endif
+  #ifndef CYTHON_FAST_THREAD_STATE
+    #define CYTHON_FAST_THREAD_STATE 1
+  #endif
+  #ifndef CYTHON_FAST_PYCALL
+    #define CYTHON_FAST_PYCALL 1
+  #endif
 #endif
-#if !defined(CYTHON_USE_PYLONG_INTERNALS) && CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070000
-  #define CYTHON_USE_PYLONG_INTERNALS 1
+#if !defined(CYTHON_FAST_PYCCALL)
+#define CYTHON_FAST_PYCCALL  (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1)
 #endif
 #if CYTHON_USE_PYLONG_INTERNALS
   #include "longintrepr.h"
@@ -85,24 +188,44 @@ END: Cython Metadata */
 #ifndef Py_TPFLAGS_HAVE_FINALIZE
   #define Py_TPFLAGS_HAVE_FINALIZE 0
 #endif
+#ifndef METH_FASTCALL
+  #define METH_FASTCALL 0x80
+  typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject **args,
+                                              Py_ssize_t nargs, PyObject *kwnames);
+#else
+  #define __Pyx_PyCFunctionFast _PyCFunctionFast
+#endif
+#if CYTHON_FAST_PYCCALL
+#define __Pyx_PyFastCFunction_Check(func)\
+    ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)))))
+#else
+#define __Pyx_PyFastCFunction_Check(func) 0
+#endif
 #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND)
   #define CYTHON_PEP393_ENABLED 1
   #define __Pyx_PyUnicode_READY(op)       (likely(PyUnicode_IS_READY(op)) ?\
                                               0 : _PyUnicode_Ready((PyObject *)(op)))
   #define __Pyx_PyUnicode_GET_LENGTH(u)   PyUnicode_GET_LENGTH(u)
   #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i)
+  #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u)   PyUnicode_MAX_CHAR_VALUE(u)
   #define __Pyx_PyUnicode_KIND(u)         PyUnicode_KIND(u)
   #define __Pyx_PyUnicode_DATA(u)         PyUnicode_DATA(u)
   #define __Pyx_PyUnicode_READ(k, d, i)   PyUnicode_READ(k, d, i)
+  #define __Pyx_PyUnicode_WRITE(k, d, i, ch)  PyUnicode_WRITE(k, d, i, ch)
   #define __Pyx_PyUnicode_IS_TRUE(u)      (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u)))
 #else
   #define CYTHON_PEP393_ENABLED 0
+  #define PyUnicode_1BYTE_KIND  1
+  #define PyUnicode_2BYTE_KIND  2
+  #define PyUnicode_4BYTE_KIND  4
   #define __Pyx_PyUnicode_READY(op)       (0)
   #define __Pyx_PyUnicode_GET_LENGTH(u)   PyUnicode_GET_SIZE(u)
   #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i]))
+  #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u)   ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111)
   #define __Pyx_PyUnicode_KIND(u)         (sizeof(Py_UNICODE))
   #define __Pyx_PyUnicode_DATA(u)         ((void*)PyUnicode_AS_UNICODE(u))
   #define __Pyx_PyUnicode_READ(k, d, i)   ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i]))
+  #define __Pyx_PyUnicode_WRITE(k, d, i, ch)  (((void)(k)), ((Py_UNICODE*)d)[i] = ch)
   #define __Pyx_PyUnicode_IS_TRUE(u)      (0 != PyUnicode_GET_SIZE(u))
 #endif
 #if CYTHON_COMPILING_IN_PYPY
@@ -116,6 +239,9 @@ END: Cython Metadata */
 #if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains)
   #define PyUnicode_Contains(u, s)  PySequence_Contains(u, s)
 #endif
+#if CYTHON_COMPILING_IN_PYPY && !defined(PyByteArray_Check)
+  #define PyByteArray_Check(obj)  PyObject_TypeCheck(obj, &PyByteArray_Type)
+#endif
 #if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format)
   #define PyObject_Format(obj, fmt)  PyObject_CallMethod(obj, "__format__", "O", fmt)
 #endif
@@ -124,6 +250,13 @@ END: Cython Metadata */
   #define PyObject_Free(p)     PyMem_Free(p)
   #define PyObject_Realloc(p)  PyMem_Realloc(p)
 #endif
+#if CYTHON_COMPILING_IN_PYSTON
+  #define __Pyx_PyCode_HasFreeVars(co)  PyCode_HasFreeVars(co)
+  #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno)
+#else
+  #define __Pyx_PyCode_HasFreeVars(co)  (PyCode_GetNumFree(co) > 0)
+  #define __Pyx_PyFrame_SetLineNumber(frame, lineno)  (frame)->f_lineno = (lineno)
+#endif
 #define __Pyx_PyString_FormatSafe(a, b)   ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b))
 #define __Pyx_PyUnicode_FormatSafe(a, b)  ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b))
 #if PY_MAJOR_VERSION >= 3
@@ -152,6 +285,7 @@ END: Cython Metadata */
   #define PySet_CheckExact(obj)        (Py_TYPE(obj) == &PySet_Type)
 #endif
 #define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type)
+#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception)
 #if PY_MAJOR_VERSION >= 3
   #define PyIntObject                  PyLongObject
   #define PyInt_Type                   PyLong_Type
@@ -190,18 +324,20 @@ END: Cython Metadata */
 #else
   #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass)
 #endif
-#if PY_VERSION_HEX >= 0x030500B1
-#define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
-#define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
-#elif CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
-typedef struct {
-    unaryfunc am_await;
-    unaryfunc am_aiter;
-    unaryfunc am_anext;
-} __Pyx_PyAsyncMethodsStruct;
-#define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
+#if CYTHON_USE_ASYNC_SLOTS
+  #if PY_VERSION_HEX >= 0x030500B1
+    #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
+    #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
+  #else
+    typedef struct {
+        unaryfunc am_await;
+        unaryfunc am_aiter;
+        unaryfunc am_anext;
+    } __Pyx_PyAsyncMethodsStruct;
+    #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
+  #endif
 #else
-#define __Pyx_PyType_AsAsync(obj) NULL
+  #define __Pyx_PyType_AsAsync(obj) NULL
 #endif
 #ifndef CYTHON_RESTRICT
   #if defined(__GNUC__)
@@ -214,10 +350,39 @@ typedef struct {
     #define CYTHON_RESTRICT
   #endif
 #endif
+#ifndef CYTHON_UNUSED
+# if defined(__GNUC__)
+#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#     define CYTHON_UNUSED __attribute__ ((__unused__))
+#   else
+#     define CYTHON_UNUSED
+#   endif
+# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
+#   define CYTHON_UNUSED __attribute__ ((__unused__))
+# else
+#   define CYTHON_UNUSED
+# endif
+#endif
+#ifndef CYTHON_MAYBE_UNUSED_VAR
+#  if defined(__cplusplus)
+     template<class T> void CYTHON_MAYBE_UNUSED_VAR( const T& ) { }
+#  else
+#    define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x)
+#  endif
+#endif
+#ifndef CYTHON_NCP_UNUSED
+# if CYTHON_COMPILING_IN_CPYTHON
+#  define CYTHON_NCP_UNUSED
+# else
+#  define CYTHON_NCP_UNUSED CYTHON_UNUSED
+# endif
+#endif
 #define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None)
 
 #ifndef CYTHON_INLINE
-  #if defined(__GNUC__)
+  #if defined(__clang__)
+    #define CYTHON_INLINE __inline__ __attribute__ ((__unused__))
+  #elif defined(__GNUC__)
     #define CYTHON_INLINE __inline__
   #elif defined(_MSC_VER)
     #define CYTHON_INLINE __inline
@@ -241,6 +406,11 @@ static CYTHON_INLINE float __PYX_NAN() {
   return value;
 }
 #endif
+#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL)
+#define __Pyx_truncl trunc
+#else
+#define __Pyx_truncl truncl
+#endif
 
 
 #define __PYX_ERR(f_index, lineno, Ln_error) \
@@ -274,26 +444,6 @@ static CYTHON_INLINE float __PYX_NAN() {
 #define CYTHON_WITHOUT_ASSERTIONS
 #endif
 
-#ifndef CYTHON_UNUSED
-# if defined(__GNUC__)
-#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
-#     define CYTHON_UNUSED __attribute__ ((__unused__))
-#   else
-#     define CYTHON_UNUSED
-#   endif
-# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
-#   define CYTHON_UNUSED __attribute__ ((__unused__))
-# else
-#   define CYTHON_UNUSED
-# endif
-#endif
-#ifndef CYTHON_NCP_UNUSED
-# if CYTHON_COMPILING_IN_CPYTHON
-#  define CYTHON_NCP_UNUSED
-# else
-#  define CYTHON_NCP_UNUSED CYTHON_UNUSED
-# endif
-#endif
 typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding;
                 const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry;
 
@@ -371,7 +521,7 @@ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
 static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
 static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
 static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS
 #define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
 #else
 #define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x)
@@ -500,7 +650,6 @@ struct __pyx_obj_8cutadapt_6_seqio_Sequence {
   PyObject *qualities;
   int second_header;
   PyObject *match;
-  PyObject *match_info;
 };
 
 
@@ -588,7 +737,7 @@ struct __pyx_obj_8cutadapt_6_seqio___pyx_scope_struct____iter__ {
 #define __Pyx_XCLEAR(r)   do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0)
 
 /* PyObjectGetAttrStr.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_USE_TYPE_SLOTS
 static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) {
     PyTypeObject* tp = Py_TYPE(obj);
     if (likely(tp->tp_getattro))
@@ -625,6 +774,24 @@ static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, in
 /* GetModuleGlobalName.proto */
 static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name);
 
+/* PyCFunctionFastCall.proto */
+#if CYTHON_FAST_PYCCALL
+static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs);
+#else
+#define __Pyx_PyCFunction_FastCall(func, args, nargs)  (assert(0), NULL)
+#endif
+
+/* PyFunctionFastCall.proto */
+#if CYTHON_FAST_PYCALL
+#define __Pyx_PyFunction_FastCall(func, args, nargs)\
+    __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL)
+#if 1 || PY_VERSION_HEX < 0x030600B1
+static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs);
+#else
+#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs)
+#endif
+#endif
+
 /* PyObjectCall.proto */
 #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw);
@@ -641,7 +808,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg);
 
 /* PyThreadStateGet.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_FAST_THREAD_STATE
 #define __Pyx_PyThreadState_declare  PyThreadState *__pyx_tstate;
 #define __Pyx_PyThreadState_assign  __pyx_tstate = PyThreadState_GET();
 #else
@@ -650,7 +817,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec
 #endif
 
 /* PyErrFetchRestore.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_FAST_THREAD_STATE
 #define __Pyx_ErrRestoreWithState(type, value, tb)  __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb)
 #define __Pyx_ErrFetchWithState(type, value, tb)    __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb)
 #define __Pyx_ErrRestore(type, value, tb)  __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb)
@@ -675,7 +842,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func);
 #endif
 
 /* PyObjectSetAttrStr.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_USE_TYPE_SLOTS
 #define __Pyx_PyObject_DelAttrStr(o,n) __Pyx_PyObject_SetAttrStr(o,n,NULL)
 static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value) {
     PyTypeObject* tp = Py_TYPE(obj);
@@ -855,7 +1022,7 @@ static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *);
 static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *);
 
 /* SwapException.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_FAST_THREAD_STATE
 #define __Pyx_ExceptionSwap(type, value, tb)  __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb)
 static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
 #else
@@ -879,11 +1046,13 @@ typedef struct {
     PyObject *yieldfrom;
     PyObject *gi_name;
     PyObject *gi_qualname;
+    PyObject *gi_modulename;
     int resume_label;
     char is_running;
 } __pyx_CoroutineObject;
-static __pyx_CoroutineObject *__Pyx__Coroutine_New(PyTypeObject *type, __pyx_coroutine_body_t body,
-                                                   PyObject *closure, PyObject *name, PyObject *qualname);
+static __pyx_CoroutineObject *__Pyx__Coroutine_New(
+    PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *closure,
+    PyObject *name, PyObject *qualname, PyObject *module_name);
 static int __Pyx_Coroutine_clear(PyObject *self);
 #if 1 || PY_VERSION_HEX < 0x030300B0
 static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue);
@@ -901,8 +1070,8 @@ static int __Pyx_patch_abc(void);
 #define __Pyx_Generator_USED
 static PyTypeObject *__pyx_GeneratorType = 0;
 #define __Pyx_Generator_CheckExact(obj) (Py_TYPE(obj) == __pyx_GeneratorType)
-#define __Pyx_Generator_New(body, closure, name, qualname)\
-    __Pyx__Coroutine_New(__pyx_GeneratorType, body, closure, name, qualname)
+#define __Pyx_Generator_New(body, closure, name, qualname, module_name)\
+    __Pyx__Coroutine_New(__pyx_GeneratorType, body, closure, name, qualname, module_name)
 static PyObject *__Pyx_Generator_Next(PyObject *self);
 static int __pyx_Generator_init(void);
 
@@ -960,7 +1129,6 @@ static const char __pyx_k_qualname[] = "__qualname__";
 static const char __pyx_k_sequence[] = "sequence";
 static const char __pyx_k_metaclass[] = "__metaclass__";
 static const char __pyx_k_qualities[] = "qualities";
-static const char __pyx_k_match_info[] = "match_info";
 static const char __pyx_k_FastqReader[] = "FastqReader";
 static const char __pyx_k_FormatError[] = "FormatError";
 static const char __pyx_k_qualities_0_r[] = ", qualities={0!r}";
@@ -1016,7 +1184,6 @@ static PyObject *__pyx_n_s_iter;
 static PyObject *__pyx_n_s_line;
 static PyObject *__pyx_n_s_main;
 static PyObject *__pyx_n_s_match;
-static PyObject *__pyx_n_s_match_info;
 static PyObject *__pyx_n_s_metaclass;
 static PyObject *__pyx_n_s_module;
 static PyObject *__pyx_n_s_name;
@@ -1038,7 +1205,7 @@ static PyObject *__pyx_n_s_super;
 static PyObject *__pyx_n_s_test;
 static PyObject *__pyx_n_s_throw;
 static PyObject *__pyx_n_s_xopen;
-static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_name, PyObject *__pyx_v_sequence, PyObject *__pyx_v_qualities, int __pyx_v_second_header, PyObject *__pyx_v_match, PyObject *__pyx_v_match_info); /* proto */
+static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_name, PyObject *__pyx_v_sequence, PyObject *__pyx_v_qualities, int __pyx_v_second_header, PyObject *__pyx_v_match); /* proto */
 static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_key); /* proto */
 static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
 static Py_ssize_t __pyx_pf_8cutadapt_6_seqio_8Sequence_6__len__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
@@ -1058,10 +1225,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_13second_header_2__set__(struct
 static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_5match___get__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
 static int __pyx_pf_8cutadapt_6_seqio_8Sequence_5match_2__set__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_value); /* proto */
 static int __pyx_pf_8cutadapt_6_seqio_8Sequence_5match_4__del__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info___get__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
-static int __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_2__set__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_value); /* proto */
-static int __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_4__del__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_5__defaults__(CYTHON_UNUSED PyObject *__pyx_self); /* proto */
+static PyObject *__pyx_pf_8cutadapt_6_seqio___defaults__(CYTHON_UNUSED PyObject *__pyx_self); /* proto */
 static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_file, PyObject *__pyx_v_sequence_class); /* proto */
 static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_2__iter__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
 static PyObject *__pyx_tp_new_8cutadapt_6_seqio_Sequence(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
@@ -1086,22 +1250,19 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
   PyObject *__pyx_v_qualities = 0;
   int __pyx_v_second_header;
   PyObject *__pyx_v_match = 0;
-  PyObject *__pyx_v_match_info = 0;
   int __pyx_r;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__init__ (wrapper)", 0);
   {
-    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_name,&__pyx_n_s_sequence,&__pyx_n_s_qualities,&__pyx_n_s_second_header,&__pyx_n_s_match,&__pyx_n_s_match_info,0};
-    PyObject* values[6] = {0,0,0,0,0,0};
+    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_name,&__pyx_n_s_sequence,&__pyx_n_s_qualities,&__pyx_n_s_second_header,&__pyx_n_s_match,0};
+    PyObject* values[5] = {0,0,0,0,0};
     values[2] = ((PyObject*)Py_None);
-    values[4] = ((PyObject *)Py_None);
 
-    values[5] = ((PyObject *)Py_None);
+    values[4] = ((PyObject *)Py_None);
     if (unlikely(__pyx_kwds)) {
       Py_ssize_t kw_args;
       const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
       switch (pos_args) {
-        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
         case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
         case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
         case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
@@ -1118,7 +1279,7 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_sequence)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 6, 1); __PYX_ERR(0, 25, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 5, 1); __PYX_ERR(0, 24, __pyx_L3_error)
         }
         case  2:
         if (kw_args > 0) {
@@ -1135,18 +1296,12 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
           PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_match);
           if (value) { values[4] = value; kw_args--; }
         }
-        case  5:
-        if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_match_info);
-          if (value) { values[5] = value; kw_args--; }
-        }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 25, __pyx_L3_error)
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 24, __pyx_L3_error)
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
-        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
         case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
         case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
         case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
@@ -1160,26 +1315,25 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
     __pyx_v_sequence = ((PyObject*)values[1]);
     __pyx_v_qualities = ((PyObject*)values[2]);
     if (values[3]) {
-      __pyx_v_second_header = __Pyx_PyObject_IsTrue(values[3]); if (unlikely((__pyx_v_second_header == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 25, __pyx_L3_error)
+      __pyx_v_second_header = __Pyx_PyObject_IsTrue(values[3]); if (unlikely((__pyx_v_second_header == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 24, __pyx_L3_error)
     } else {
 
       __pyx_v_second_header = ((int)0);
     }
     __pyx_v_match = values[4];
-    __pyx_v_match_info = values[5];
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 6, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 25, __pyx_L3_error)
+  __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 5, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 24, __pyx_L3_error)
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._seqio.Sequence.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return -1;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyString_Type), 1, "name", 1))) __PYX_ERR(0, 25, __pyx_L1_error)
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_sequence), (&PyString_Type), 1, "sequence", 1))) __PYX_ERR(0, 25, __pyx_L1_error)
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_qualities), (&PyString_Type), 1, "qualities", 1))) __PYX_ERR(0, 25, __pyx_L1_error)
-  __pyx_r = __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(((struct __pyx_obj_8cutadapt_6_seqio_Sequence *)__pyx_v_self), __pyx_v_name, __pyx_v_sequence, __pyx_v_qualities, __pyx_v_second_header, __pyx_v_match, __pyx_v_match_info);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyString_Type), 1, "name", 1))) __PYX_ERR(0, 24, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_sequence), (&PyString_Type), 1, "sequence", 1))) __PYX_ERR(0, 24, __pyx_L1_error)
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_qualities), (&PyString_Type), 1, "qualities", 1))) __PYX_ERR(0, 24, __pyx_L1_error)
+  __pyx_r = __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(((struct __pyx_obj_8cutadapt_6_seqio_Sequence *)__pyx_v_self), __pyx_v_name, __pyx_v_sequence, __pyx_v_qualities, __pyx_v_second_header, __pyx_v_match);
 
   /* function exit code */
   goto __pyx_L0;
@@ -1190,7 +1344,7 @@ static int __pyx_pw_8cutadapt_6_seqio_8Sequence_1__init__(PyObject *__pyx_v_self
   return __pyx_r;
 }
 
-static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_name, PyObject *__pyx_v_sequence, PyObject *__pyx_v_qualities, int __pyx_v_second_header, PyObject *__pyx_v_match, PyObject *__pyx_v_match_info) {
+static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_name, PyObject *__pyx_v_sequence, PyObject *__pyx_v_qualities, int __pyx_v_second_header, PyObject *__pyx_v_match) {
   PyObject *__pyx_v_rname = NULL;
   int __pyx_r;
   __Pyx_RefNannyDeclarations
@@ -1206,7 +1360,8 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
   PyObject *__pyx_t_10 = NULL;
   PyObject *__pyx_t_11 = NULL;
   PyObject *__pyx_t_12 = NULL;
-  PyObject *__pyx_t_13 = NULL;
+  int __pyx_t_13;
+  PyObject *__pyx_t_14 = NULL;
   __Pyx_RefNannySetupContext("__init__", 0);
 
   __Pyx_INCREF(__pyx_v_name);
@@ -1235,12 +1390,6 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
   __Pyx_DECREF(__pyx_v_self->match);
   __pyx_v_self->match = __pyx_v_match;
 
-  __Pyx_INCREF(__pyx_v_match_info);
-  __Pyx_GIVEREF(__pyx_v_match_info);
-  __Pyx_GOTREF(__pyx_v_self->match_info);
-  __Pyx_DECREF(__pyx_v_self->match_info);
-  __pyx_v_self->match_info = __pyx_v_match_info;
-
   __pyx_t_2 = (__pyx_v_qualities != ((PyObject*)Py_None));
   __pyx_t_3 = (__pyx_t_2 != 0);
   if (__pyx_t_3) {
@@ -1248,17 +1397,17 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
     __pyx_t_1 = __pyx_t_3;
     goto __pyx_L4_bool_binop_done;
   }
-  __pyx_t_4 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(0, 34, __pyx_L1_error)
-  __pyx_t_5 = PyObject_Length(__pyx_v_sequence); if (unlikely(__pyx_t_5 == -1)) __PYX_ERR(0, 34, __pyx_L1_error)
+  __pyx_t_4 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(0, 32, __pyx_L1_error)
+  __pyx_t_5 = PyObject_Length(__pyx_v_sequence); if (unlikely(__pyx_t_5 == -1)) __PYX_ERR(0, 32, __pyx_L1_error)
   __pyx_t_3 = ((__pyx_t_4 != __pyx_t_5) != 0);
   __pyx_t_1 = __pyx_t_3;
   __pyx_L4_bool_binop_done:;
   if (__pyx_t_1) {
 
-    __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 35, __pyx_L1_error)
+    __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 33, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_7);
     __pyx_t_8 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_7))) {
+    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) {
       __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7);
       if (likely(__pyx_t_8)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7);
@@ -1268,67 +1417,107 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
       }
     }
     if (!__pyx_t_8) {
-      __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_v_name); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 35, __pyx_L1_error)
+      __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_v_name); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 33, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_6);
     } else {
-      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 35, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_9);
-      __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
-      __Pyx_INCREF(__pyx_v_name);
-      __Pyx_GIVEREF(__pyx_v_name);
-      PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_name);
-      __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 35, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_6);
-      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_7)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_v_name};
+        __pyx_t_6 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 33, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+        __Pyx_GOTREF(__pyx_t_6);
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_v_name};
+        __pyx_t_6 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 33, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+        __Pyx_GOTREF(__pyx_t_6);
+      } else
+      #endif
+      {
+        __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 33, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_9);
+        __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
+        __Pyx_INCREF(__pyx_v_name);
+        __Pyx_GIVEREF(__pyx_v_name);
+        PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_name);
+        __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 33, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
     __pyx_v_rname = __pyx_t_6;
     __pyx_t_6 = 0;
 
-    __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 36, __pyx_L1_error)
+    __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 34, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_7);
 
-    __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_In_read_named_0_r_length_of_qual, __pyx_n_s_format); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 37, __pyx_L1_error)
+    __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_In_read_named_0_r_length_of_qual, __pyx_n_s_format); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 35, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_8);
 
-    __pyx_t_5 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_5 == -1)) __PYX_ERR(0, 38, __pyx_L1_error)
-    __pyx_t_10 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 38, __pyx_L1_error)
+    __pyx_t_5 = PyObject_Length(__pyx_v_qualities); if (unlikely(__pyx_t_5 == -1)) __PYX_ERR(0, 36, __pyx_L1_error)
+    __pyx_t_10 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 36, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_10);
-    __pyx_t_5 = PyObject_Length(__pyx_v_sequence); if (unlikely(__pyx_t_5 == -1)) __PYX_ERR(0, 38, __pyx_L1_error)
-    __pyx_t_11 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 38, __pyx_L1_error)
+    __pyx_t_5 = PyObject_Length(__pyx_v_sequence); if (unlikely(__pyx_t_5 == -1)) __PYX_ERR(0, 36, __pyx_L1_error)
+    __pyx_t_11 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 36, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_11);
     __pyx_t_12 = NULL;
-    __pyx_t_5 = 0;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_8))) {
+    __pyx_t_13 = 0;
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_8))) {
       __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_8);
       if (likely(__pyx_t_12)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8);
         __Pyx_INCREF(__pyx_t_12);
         __Pyx_INCREF(function);
         __Pyx_DECREF_SET(__pyx_t_8, function);
-        __pyx_t_5 = 1;
+        __pyx_t_13 = 1;
       }
     }
-    __pyx_t_13 = PyTuple_New(3+__pyx_t_5); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 37, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_13);
-    if (__pyx_t_12) {
-      __Pyx_GIVEREF(__pyx_t_12); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_12); __pyx_t_12 = NULL;
-    }
-    __Pyx_INCREF(__pyx_v_rname);
-    __Pyx_GIVEREF(__pyx_v_rname);
-    PyTuple_SET_ITEM(__pyx_t_13, 0+__pyx_t_5, __pyx_v_rname);
-    __Pyx_GIVEREF(__pyx_t_10);
-    PyTuple_SET_ITEM(__pyx_t_13, 1+__pyx_t_5, __pyx_t_10);
-    __Pyx_GIVEREF(__pyx_t_11);
-    PyTuple_SET_ITEM(__pyx_t_13, 2+__pyx_t_5, __pyx_t_11);
-    __pyx_t_10 = 0;
-    __pyx_t_11 = 0;
-    __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_13, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 37, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_9);
-    __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
+    #if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(__pyx_t_8)) {
+      PyObject *__pyx_temp[4] = {__pyx_t_12, __pyx_v_rname, __pyx_t_10, __pyx_t_11};
+      __pyx_t_9 = __Pyx_PyFunction_FastCall(__pyx_t_8, __pyx_temp+1-__pyx_t_13, 3+__pyx_t_13); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 35, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0;
+      __Pyx_GOTREF(__pyx_t_9);
+      __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+      __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+    } else
+    #endif
+    #if CYTHON_FAST_PYCCALL
+    if (__Pyx_PyFastCFunction_Check(__pyx_t_8)) {
+      PyObject *__pyx_temp[4] = {__pyx_t_12, __pyx_v_rname, __pyx_t_10, __pyx_t_11};
+      __pyx_t_9 = __Pyx_PyCFunction_FastCall(__pyx_t_8, __pyx_temp+1-__pyx_t_13, 3+__pyx_t_13); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 35, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0;
+      __Pyx_GOTREF(__pyx_t_9);
+      __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+      __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+    } else
+    #endif
+    {
+      __pyx_t_14 = PyTuple_New(3+__pyx_t_13); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 35, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_14);
+      if (__pyx_t_12) {
+        __Pyx_GIVEREF(__pyx_t_12); PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_t_12); __pyx_t_12 = NULL;
+      }
+      __Pyx_INCREF(__pyx_v_rname);
+      __Pyx_GIVEREF(__pyx_v_rname);
+      PyTuple_SET_ITEM(__pyx_t_14, 0+__pyx_t_13, __pyx_v_rname);
+      __Pyx_GIVEREF(__pyx_t_10);
+      PyTuple_SET_ITEM(__pyx_t_14, 1+__pyx_t_13, __pyx_t_10);
+      __Pyx_GIVEREF(__pyx_t_11);
+      PyTuple_SET_ITEM(__pyx_t_14, 2+__pyx_t_13, __pyx_t_11);
+      __pyx_t_10 = 0;
+      __pyx_t_11 = 0;
+      __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_8, __pyx_t_14, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 35, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_9);
+      __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
+    }
     __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
     __pyx_t_8 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_7))) {
+    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) {
       __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7);
       if (likely(__pyx_t_8)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7);
@@ -1338,24 +1527,44 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
       }
     }
     if (!__pyx_t_8) {
-      __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_9); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 36, __pyx_L1_error)
+      __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_9); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 34, __pyx_L1_error)
       __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
       __Pyx_GOTREF(__pyx_t_6);
     } else {
-      __pyx_t_13 = PyTuple_New(1+1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 36, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_13);
-      __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_8); __pyx_t_8 = NULL;
-      __Pyx_GIVEREF(__pyx_t_9);
-      PyTuple_SET_ITEM(__pyx_t_13, 0+1, __pyx_t_9);
-      __pyx_t_9 = 0;
-      __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_13, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 36, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_6);
-      __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_7)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_9};
+        __pyx_t_6 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 34, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_9};
+        __pyx_t_6 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 34, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      } else
+      #endif
+      {
+        __pyx_t_14 = PyTuple_New(1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 34, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_14);
+        __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_t_8); __pyx_t_8 = NULL;
+        __Pyx_GIVEREF(__pyx_t_9);
+        PyTuple_SET_ITEM(__pyx_t_14, 0+1, __pyx_t_9);
+        __pyx_t_9 = 0;
+        __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_14, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 34, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
     __Pyx_Raise(__pyx_t_6, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-    __PYX_ERR(0, 36, __pyx_L1_error)
+    __PYX_ERR(0, 34, __pyx_L1_error)
 
   }
 
@@ -1371,7 +1580,7 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence___init__(struct __pyx_obj_8cutad
   __Pyx_XDECREF(__pyx_t_10);
   __Pyx_XDECREF(__pyx_t_11);
   __Pyx_XDECREF(__pyx_t_12);
-  __Pyx_XDECREF(__pyx_t_13);
+  __Pyx_XDECREF(__pyx_t_14);
   __Pyx_AddTraceback("cutadapt._seqio.Sequence.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = -1;
   __pyx_L0:;
@@ -1408,20 +1617,20 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_
   int __pyx_t_5;
   PyObject *__pyx_t_6 = NULL;
   PyObject *__pyx_t_7 = NULL;
-  Py_ssize_t __pyx_t_8;
+  int __pyx_t_8;
   PyObject *__pyx_t_9 = NULL;
   __Pyx_RefNannySetupContext("__getitem__", 0);
 
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_class); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 42, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_class); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 40, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
 
-  __pyx_t_3 = PyObject_GetItem(__pyx_v_self->sequence, __pyx_v_key); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 44, __pyx_L1_error)
+  __pyx_t_3 = PyObject_GetItem(__pyx_v_self->sequence, __pyx_v_key); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 42, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
 
   __pyx_t_5 = (__pyx_v_self->qualities != ((PyObject*)Py_None));
   if ((__pyx_t_5 != 0)) {
-    __pyx_t_6 = PyObject_GetItem(__pyx_v_self->qualities, __pyx_v_key); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 45, __pyx_L1_error)
+    __pyx_t_6 = PyObject_GetItem(__pyx_v_self->qualities, __pyx_v_key); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 43, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
     __pyx_t_4 = __pyx_t_6;
     __pyx_t_6 = 0;
@@ -1430,12 +1639,12 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_
     __pyx_t_4 = Py_None;
   }
 
-  __pyx_t_6 = __Pyx_PyBool_FromLong(__pyx_v_self->second_header); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 46, __pyx_L1_error)
+  __pyx_t_6 = __Pyx_PyBool_FromLong(__pyx_v_self->second_header); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 44, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_6);
 
   __pyx_t_7 = NULL;
   __pyx_t_8 = 0;
-  if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
+  if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
     __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_2);
     if (likely(__pyx_t_7)) {
       PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -1445,32 +1654,53 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_2__getitem__(struct __pyx_
       __pyx_t_8 = 1;
     }
   }
-  __pyx_t_9 = PyTuple_New(6+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 42, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_9);
-  if (__pyx_t_7) {
-    __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL;
+  #if CYTHON_FAST_PYCALL
+  if (PyFunction_Check(__pyx_t_2)) {
+    PyObject *__pyx_temp[6] = {__pyx_t_7, __pyx_v_self->name, __pyx_t_3, __pyx_t_4, __pyx_t_6, __pyx_v_self->match};
+    __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_8, 5+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 40, __pyx_L1_error)
+    __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+  } else
+  #endif
+  #if CYTHON_FAST_PYCCALL
+  if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
+    PyObject *__pyx_temp[6] = {__pyx_t_7, __pyx_v_self->name, __pyx_t_3, __pyx_t_4, __pyx_t_6, __pyx_v_self->match};
+    __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_8, 5+__pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 40, __pyx_L1_error)
+    __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+  } else
+  #endif
+  {
+    __pyx_t_9 = PyTuple_New(5+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 40, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_9);
+    if (__pyx_t_7) {
+      __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL;
+    }
+    __Pyx_INCREF(__pyx_v_self->name);
+    __Pyx_GIVEREF(__pyx_v_self->name);
+    PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_v_self->name);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_4);
+    PyTuple_SET_ITEM(__pyx_t_9, 2+__pyx_t_8, __pyx_t_4);
+    __Pyx_GIVEREF(__pyx_t_6);
+    PyTuple_SET_ITEM(__pyx_t_9, 3+__pyx_t_8, __pyx_t_6);
+    __Pyx_INCREF(__pyx_v_self->match);
+    __Pyx_GIVEREF(__pyx_v_self->match);
+    PyTuple_SET_ITEM(__pyx_t_9, 4+__pyx_t_8, __pyx_v_self->match);
+    __pyx_t_3 = 0;
+    __pyx_t_4 = 0;
+    __pyx_t_6 = 0;
+    __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 40, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
   }
-  __Pyx_INCREF(__pyx_v_self->name);
-  __Pyx_GIVEREF(__pyx_v_self->name);
-  PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_v_self->name);
-  __Pyx_GIVEREF(__pyx_t_3);
-  PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_t_3);
-  __Pyx_GIVEREF(__pyx_t_4);
-  PyTuple_SET_ITEM(__pyx_t_9, 2+__pyx_t_8, __pyx_t_4);
-  __Pyx_GIVEREF(__pyx_t_6);
-  PyTuple_SET_ITEM(__pyx_t_9, 3+__pyx_t_8, __pyx_t_6);
-  __Pyx_INCREF(__pyx_v_self->match);
-  __Pyx_GIVEREF(__pyx_v_self->match);
-  PyTuple_SET_ITEM(__pyx_t_9, 4+__pyx_t_8, __pyx_v_self->match);
-  __Pyx_INCREF(__pyx_v_self->match_info);
-  __Pyx_GIVEREF(__pyx_v_self->match_info);
-  PyTuple_SET_ITEM(__pyx_t_9, 5+__pyx_t_8, __pyx_v_self->match_info);
-  __pyx_t_3 = 0;
-  __pyx_t_4 = 0;
-  __pyx_t_6 = 0;
-  __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 42, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
@@ -1521,7 +1751,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
   PyObject *__pyx_t_7 = NULL;
   PyObject *__pyx_t_8 = NULL;
   PyObject *__pyx_t_9 = NULL;
-  Py_ssize_t __pyx_t_10;
+  int __pyx_t_10;
   __Pyx_RefNannySetupContext("__repr__", 0);
 
   __Pyx_INCREF(__pyx_kp_s_);
@@ -1531,12 +1761,12 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
   __pyx_t_2 = (__pyx_t_1 != 0);
   if (__pyx_t_2) {
 
-    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_qualities_0_r, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 53, __pyx_L1_error)
+    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_qualities_0_r, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 50, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_4);
-    __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 53, __pyx_L1_error)
+    __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 50, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
     __pyx_t_7 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_6))) {
+    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) {
       __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_6);
       if (likely(__pyx_t_7)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
@@ -1546,22 +1776,40 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
       }
     }
     if (!__pyx_t_7) {
-      __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_v_self->qualities); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 53, __pyx_L1_error)
+      __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_v_self->qualities); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 50, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_5);
     } else {
-      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 53, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_8);
-      __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL;
-      __Pyx_INCREF(__pyx_v_self->qualities);
-      __Pyx_GIVEREF(__pyx_v_self->qualities);
-      PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_v_self->qualities);
-      __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 53, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_5);
-      __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_6)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_v_self->qualities};
+        __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 50, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
+        __Pyx_GOTREF(__pyx_t_5);
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_v_self->qualities};
+        __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 50, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
+        __Pyx_GOTREF(__pyx_t_5);
+      } else
+      #endif
+      {
+        __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 50, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_8);
+        __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL;
+        __Pyx_INCREF(__pyx_v_self->qualities);
+        __Pyx_GIVEREF(__pyx_v_self->qualities);
+        PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_v_self->qualities);
+        __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_8, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 50, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_5);
+        __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
     __pyx_t_6 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
       __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
       if (likely(__pyx_t_6)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -1571,19 +1819,39 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
       }
     }
     if (!__pyx_t_6) {
-      __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 53, __pyx_L1_error)
+      __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 50, __pyx_L1_error)
       __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
       __Pyx_GOTREF(__pyx_t_3);
     } else {
-      __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 53, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_8);
-      __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL;
-      __Pyx_GIVEREF(__pyx_t_5);
-      PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_5);
-      __pyx_t_5 = 0;
-      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 53, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_3);
-      __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_4)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
+        __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 50, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __Pyx_GOTREF(__pyx_t_3);
+        __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
+        __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 50, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __Pyx_GOTREF(__pyx_t_3);
+        __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      } else
+      #endif
+      {
+        __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 50, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_8);
+        __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL;
+        __Pyx_GIVEREF(__pyx_t_5);
+        PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_5);
+        __pyx_t_5 = 0;
+        __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 50, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_3);
+        __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
     __Pyx_DECREF_SET(__pyx_v_qstr, __pyx_t_3);
@@ -1592,12 +1860,12 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
   }
 
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Sequence_name_0_r_sequence_1_r, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 54, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Sequence_name_0_r_sequence_1_r, __pyx_n_s_format); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 51, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
-  __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 54, __pyx_L1_error)
+  __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 51, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_5);
   __pyx_t_6 = NULL;
-  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_5))) {
+  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) {
     __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5);
     if (likely(__pyx_t_6)) {
       PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
@@ -1607,24 +1875,42 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
     }
   }
   if (!__pyx_t_6) {
-    __pyx_t_8 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_self->name); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 54, __pyx_L1_error)
+    __pyx_t_8 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_v_self->name); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 51, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_8);
   } else {
-    __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 54, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_7);
-    __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
-    __Pyx_INCREF(__pyx_v_self->name);
-    __Pyx_GIVEREF(__pyx_v_self->name);
-    PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_v_self->name);
-    __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 54, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_8);
-    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+    #if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(__pyx_t_5)) {
+      PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_v_self->name};
+      __pyx_t_8 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 51, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+      __Pyx_GOTREF(__pyx_t_8);
+    } else
+    #endif
+    #if CYTHON_FAST_PYCCALL
+    if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
+      PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_v_self->name};
+      __pyx_t_8 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 51, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+      __Pyx_GOTREF(__pyx_t_8);
+    } else
+    #endif
+    {
+      __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 51, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_7);
+      __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
+      __Pyx_INCREF(__pyx_v_self->name);
+      __Pyx_GIVEREF(__pyx_v_self->name);
+      PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_v_self->name);
+      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 51, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_8);
+      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+    }
   }
   __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-  __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 54, __pyx_L1_error)
+  __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_shorten); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 51, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_7);
   __pyx_t_6 = NULL;
-  if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_7))) {
+  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) {
     __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7);
     if (likely(__pyx_t_6)) {
       PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7);
@@ -1634,23 +1920,41 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
     }
   }
   if (!__pyx_t_6) {
-    __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_v_self->sequence); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 54, __pyx_L1_error)
+    __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_v_self->sequence); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 51, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_5);
   } else {
-    __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 54, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_9);
-    __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL;
-    __Pyx_INCREF(__pyx_v_self->sequence);
-    __Pyx_GIVEREF(__pyx_v_self->sequence);
-    PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_self->sequence);
-    __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 54, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_5);
-    __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+    #if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(__pyx_t_7)) {
+      PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_v_self->sequence};
+      __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 51, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+      __Pyx_GOTREF(__pyx_t_5);
+    } else
+    #endif
+    #if CYTHON_FAST_PYCCALL
+    if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) {
+      PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_v_self->sequence};
+      __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 51, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+      __Pyx_GOTREF(__pyx_t_5);
+    } else
+    #endif
+    {
+      __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 51, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_9);
+      __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_6); __pyx_t_6 = NULL;
+      __Pyx_INCREF(__pyx_v_self->sequence);
+      __Pyx_GIVEREF(__pyx_v_self->sequence);
+      PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_v_self->sequence);
+      __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 51, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_5);
+      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+    }
   }
   __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
   __pyx_t_7 = NULL;
   __pyx_t_10 = 0;
-  if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
+  if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
     __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_4);
     if (likely(__pyx_t_7)) {
       PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -1660,23 +1964,45 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_4__repr__(struct __pyx_obj
       __pyx_t_10 = 1;
     }
   }
-  __pyx_t_9 = PyTuple_New(3+__pyx_t_10); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 54, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_9);
-  if (__pyx_t_7) {
-    __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL;
+  #if CYTHON_FAST_PYCALL
+  if (PyFunction_Check(__pyx_t_4)) {
+    PyObject *__pyx_temp[4] = {__pyx_t_7, __pyx_t_8, __pyx_t_5, __pyx_v_qstr};
+    __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_10, 3+__pyx_t_10); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 51, __pyx_L1_error)
+    __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+  } else
+  #endif
+  #if CYTHON_FAST_PYCCALL
+  if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
+    PyObject *__pyx_temp[4] = {__pyx_t_7, __pyx_t_8, __pyx_t_5, __pyx_v_qstr};
+    __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_10, 3+__pyx_t_10); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 51, __pyx_L1_error)
+    __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+  } else
+  #endif
+  {
+    __pyx_t_9 = PyTuple_New(3+__pyx_t_10); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 51, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_9);
+    if (__pyx_t_7) {
+      __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL;
+    }
+    __Pyx_GIVEREF(__pyx_t_8);
+    PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_10, __pyx_t_8);
+    __Pyx_GIVEREF(__pyx_t_5);
+    PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_10, __pyx_t_5);
+    __Pyx_INCREF(__pyx_v_qstr);
+    __Pyx_GIVEREF(__pyx_v_qstr);
+    PyTuple_SET_ITEM(__pyx_t_9, 2+__pyx_t_10, __pyx_v_qstr);
+    __pyx_t_8 = 0;
+    __pyx_t_5 = 0;
+    __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 51, __pyx_L1_error)
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
   }
-  __Pyx_GIVEREF(__pyx_t_8);
-  PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_10, __pyx_t_8);
-  __Pyx_GIVEREF(__pyx_t_5);
-  PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_10, __pyx_t_5);
-  __Pyx_INCREF(__pyx_v_qstr);
-  __Pyx_GIVEREF(__pyx_v_qstr);
-  PyTuple_SET_ITEM(__pyx_t_9, 2+__pyx_t_10, __pyx_v_qstr);
-  __pyx_t_8 = 0;
-  __pyx_t_5 = 0;
-  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 54, __pyx_L1_error)
-  __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
   __pyx_r = __pyx_t_3;
   __pyx_t_3 = 0;
@@ -1724,7 +2050,7 @@ static Py_ssize_t __pyx_pf_8cutadapt_6_seqio_8Sequence_6__len__(struct __pyx_obj
 
   __pyx_t_1 = __pyx_v_self->sequence;
   __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = PyObject_Length(__pyx_t_1); if (unlikely(__pyx_t_2 == -1)) __PYX_ERR(0, 57, __pyx_L1_error)
+  __pyx_t_2 = PyObject_Length(__pyx_t_1); if (unlikely(__pyx_t_2 == -1)) __PYX_ERR(0, 54, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __pyx_r = __pyx_t_2;
   goto __pyx_L0;
@@ -1773,14 +2099,14 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
   __pyx_t_2 = (__pyx_t_1 != 0);
   if (__pyx_t_2) {
 
-    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_name); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 61, __pyx_L1_error)
+    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_name); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 58, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_4);
-    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_name); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 61, __pyx_L1_error)
+    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_name); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 58, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_5);
-    __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 61, __pyx_L1_error)
+    __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 58, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
     __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 61, __pyx_L1_error)
+    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 58, __pyx_L1_error)
     if (__pyx_t_2) {
       __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
     } else {
@@ -1790,14 +2116,14 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
       goto __pyx_L4_bool_binop_done;
     }
 
-    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_sequence); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 62, __pyx_L1_error)
+    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_sequence); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 59, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
-    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_sequence); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 62, __pyx_L1_error)
+    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_sequence); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 59, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_5);
-    __pyx_t_4 = PyObject_RichCompare(__pyx_t_6, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 62, __pyx_L1_error)
+    __pyx_t_4 = PyObject_RichCompare(__pyx_t_6, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 59, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
     __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 62, __pyx_L1_error)
+    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 59, __pyx_L1_error)
     if (__pyx_t_2) {
       __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
     } else {
@@ -1807,11 +2133,11 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
       goto __pyx_L4_bool_binop_done;
     }
 
-    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_qualities); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 63, __pyx_L1_error)
+    __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_qualities); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 60, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_4);
-    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_qualities); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 63, __pyx_L1_error)
+    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_other, __pyx_n_s_qualities); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 60, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_5);
-    __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 63, __pyx_L1_error)
+    __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 60, __pyx_L1_error)
     __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
     __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
     __Pyx_INCREF(__pyx_t_6);
@@ -1833,8 +2159,8 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
 
     /*else*/ {
       __Pyx_XDECREF(__pyx_r);
-      __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_v_eq); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 67, __pyx_L1_error)
-      __pyx_t_3 = __Pyx_PyBool_FromLong((!__pyx_t_2)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 67, __pyx_L1_error)
+      __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_v_eq); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 64, __pyx_L1_error)
+      __pyx_t_3 = __Pyx_PyBool_FromLong((!__pyx_t_2)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 64, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_3);
       __pyx_r = __pyx_t_3;
       __pyx_t_3 = 0;
@@ -1844,11 +2170,11 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_8__richcmp__(PyObject *__p
   }
 
   /*else*/ {
-    __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_builtin_NotImplementedError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 69, __pyx_L1_error)
+    __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_builtin_NotImplementedError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 66, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_3);
     __Pyx_Raise(__pyx_t_3, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __PYX_ERR(0, 69, __pyx_L1_error)
+    __PYX_ERR(0, 66, __pyx_L1_error)
   }
 
 
@@ -1889,9 +2215,10 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10__reduce__(struct __pyx_
   __Pyx_RefNannySetupContext("__reduce__", 0);
 
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = __Pyx_PyBool_FromLong(__pyx_v_self->second_header); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 72, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_PyBool_FromLong(__pyx_v_self->second_header); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 69, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyTuple_New(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 72, __pyx_L1_error)
+
+  __pyx_t_2 = PyTuple_New(5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 69, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_INCREF(__pyx_v_self->name);
   __Pyx_GIVEREF(__pyx_v_self->name);
@@ -1904,8 +2231,12 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10__reduce__(struct __pyx_
   PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_v_self->qualities);
   __Pyx_GIVEREF(__pyx_t_1);
   PyTuple_SET_ITEM(__pyx_t_2, 3, __pyx_t_1);
+  __Pyx_INCREF(__pyx_v_self->match);
+  __Pyx_GIVEREF(__pyx_v_self->match);
+  PyTuple_SET_ITEM(__pyx_t_2, 4, __pyx_v_self->match);
   __pyx_t_1 = 0;
-  __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 72, __pyx_L1_error)
+
+  __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 69, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(((PyObject *)__pyx_ptype_8cutadapt_6_seqio_Sequence));
   __Pyx_GIVEREF(((PyObject *)__pyx_ptype_8cutadapt_6_seqio_Sequence));
@@ -2382,107 +2713,19 @@ static int __pyx_pf_8cutadapt_6_seqio_8Sequence_5match_4__del__(struct __pyx_obj
 }
 
 
-/* Python wrapper */
-static PyObject *__pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info___get__(((struct __pyx_obj_8cutadapt_6_seqio_Sequence *)__pyx_v_self));
-
-  /* function exit code */
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-static PyObject *__pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info___get__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self) {
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__", 0);
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(__pyx_v_self->match_info);
-  __pyx_r = __pyx_v_self->match_info;
-  goto __pyx_L0;
-
-  /* function exit code */
-  __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* Python wrapper */
-static int __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
-static int __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_2__set__(((struct __pyx_obj_8cutadapt_6_seqio_Sequence *)__pyx_v_self), ((PyObject *)__pyx_v_value));
-
-  /* function exit code */
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-static int __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_2__set__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self, PyObject *__pyx_v_value) {
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__set__", 0);
-  __Pyx_INCREF(__pyx_v_value);
-  __Pyx_GIVEREF(__pyx_v_value);
-  __Pyx_GOTREF(__pyx_v_self->match_info);
-  __Pyx_DECREF(__pyx_v_self->match_info);
-  __pyx_v_self->match_info = __pyx_v_value;
-
-  /* function exit code */
-  __pyx_r = 0;
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* Python wrapper */
-static int __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_5__del__(PyObject *__pyx_v_self); /*proto*/
-static int __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_5__del__(PyObject *__pyx_v_self) {
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__del__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_4__del__(((struct __pyx_obj_8cutadapt_6_seqio_Sequence *)__pyx_v_self));
-
-  /* function exit code */
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-static int __pyx_pf_8cutadapt_6_seqio_8Sequence_10match_info_4__del__(struct __pyx_obj_8cutadapt_6_seqio_Sequence *__pyx_v_self) {
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__del__", 0);
-  __Pyx_INCREF(Py_None);
-  __Pyx_GIVEREF(Py_None);
-  __Pyx_GOTREF(__pyx_v_self->match_info);
-  __Pyx_DECREF(__pyx_v_self->match_info);
-  __pyx_v_self->match_info = Py_None;
-
-  /* function exit code */
-  __pyx_r = 0;
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-
-static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_5__defaults__(CYTHON_UNUSED PyObject *__pyx_self) {
+static PyObject *__pyx_pf_8cutadapt_6_seqio___defaults__(CYTHON_UNUSED PyObject *__pyx_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
   PyObject *__pyx_t_2 = NULL;
   __Pyx_RefNannySetupContext("__defaults__", 0);
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 79, __pyx_L1_error)
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 77, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(__Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_sequence_class);
   __Pyx_GIVEREF(__Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_sequence_class);
   PyTuple_SET_ITEM(__pyx_t_1, 0, __Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_self)->__pyx_arg_sequence_class);
-  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 79, __pyx_L1_error)
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 77, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_GIVEREF(__pyx_t_1);
   PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1);
@@ -2498,7 +2741,7 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_5__defaults__(CYTHON_U
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
   __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_AddTraceback("cutadapt._seqio.FastqReader.__defaults__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("cutadapt._seqio.__defaults__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
@@ -2540,7 +2783,7 @@ static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_1__init__(PyObject *__
         case  1:
         if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_file)) != 0)) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 3, 1); __PYX_ERR(0, 79, __pyx_L3_error)
+          __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 3, 1); __PYX_ERR(0, 77, __pyx_L3_error)
         }
         case  2:
         if (kw_args > 0) {
@@ -2549,7 +2792,7 @@ static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_1__init__(PyObject *__
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 79, __pyx_L3_error)
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 77, __pyx_L3_error)
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -2566,7 +2809,7 @@ static PyObject *__pyx_pw_8cutadapt_6_seqio_11FastqReader_1__init__(PyObject *__
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 79, __pyx_L3_error)
+  __Pyx_RaiseArgtupleInvalid("__init__", 0, 2, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 77, __pyx_L3_error)
   __pyx_L3_error:;
   __Pyx_AddTraceback("cutadapt._seqio.FastqReader.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
@@ -2588,9 +2831,9 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader___init__(CYTHON_UNUSED
   PyObject *__pyx_t_4 = NULL;
   __Pyx_RefNannySetupContext("__init__", 0);
 
-  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_FastqReader); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 84, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_FastqReader); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 82, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 84, __pyx_L1_error)
+  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 82, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_GIVEREF(__pyx_t_2);
   PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
@@ -2598,14 +2841,14 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader___init__(CYTHON_UNUSED
   __Pyx_GIVEREF(__pyx_v_self);
   PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_self);
   __pyx_t_2 = 0;
-  __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_super, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 84, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_super, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 82, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_init); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 84, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_init); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 82, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __pyx_t_2 = NULL;
-  if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
+  if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
     __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3);
     if (likely(__pyx_t_2)) {
       PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -2615,25 +2858,43 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader___init__(CYTHON_UNUSED
     }
   }
   if (!__pyx_t_2) {
-    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_file); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 84, __pyx_L1_error)
+    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_file); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 82, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
   } else {
-    __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 84, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __pyx_t_2 = NULL;
-    __Pyx_INCREF(__pyx_v_file);
-    __Pyx_GIVEREF(__pyx_v_file);
-    PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_file);
-    __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 84, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    #if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(__pyx_t_3)) {
+      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_v_file};
+      __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 82, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __Pyx_GOTREF(__pyx_t_1);
+    } else
+    #endif
+    #if CYTHON_FAST_PYCCALL
+    if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
+      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_v_file};
+      __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 82, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __Pyx_GOTREF(__pyx_t_1);
+    } else
+    #endif
+    {
+      __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 82, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_4);
+      __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __pyx_t_2 = NULL;
+      __Pyx_INCREF(__pyx_v_file);
+      __Pyx_GIVEREF(__pyx_v_file);
+      PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_file);
+      __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 82, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_1);
+      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    }
   }
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_sequence_class, __pyx_v_sequence_class) < 0) __PYX_ERR(0, 85, __pyx_L1_error)
+  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_sequence_class, __pyx_v_sequence_class) < 0) __PYX_ERR(0, 83, __pyx_L1_error)
 
-  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_delivers_qualities, Py_True) < 0) __PYX_ERR(0, 86, __pyx_L1_error)
+  if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_delivers_qualities, Py_True) < 0) __PYX_ERR(0, 84, __pyx_L1_error)
 
 
   /* function exit code */
@@ -2676,15 +2937,17 @@ static PyObject *__pyx_pf_8cutadapt_6_seqio_11FastqReader_2__iter__(CYTHON_UNUSE
   __Pyx_RefNannySetupContext("__iter__", 0);
   __pyx_cur_scope = (struct __pyx_obj_8cutadapt_6_seqio___pyx_scope_struct____iter__ *)__pyx_tp_new_8cutadapt_6_seqio___pyx_scope_struct____iter__(__pyx_ptype_8cutadapt_6_seqio___pyx_scope_struct____iter__, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
+    __pyx_cur_scope = ((struct __pyx_obj_8cutadapt_6_seqio___pyx_scope_struct____iter__ *)Py_None);
+    __Pyx_INCREF(Py_None);
+    __PYX_ERR(0, 86, __pyx_L1_error)
+  } else {
+    __Pyx_GOTREF(__pyx_cur_scope);
   }
-  __Pyx_GOTREF(__pyx_cur_scope);
   __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
   __Pyx_INCREF(__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_self);
   {
-    __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_FastqReader___iter); if (unlikely(!gen)) __PYX_ERR(0, 88, __pyx_L1_error)
+    __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_FastqReader___iter, __pyx_n_s_cutadapt__seqio); if (unlikely(!gen)) __PYX_ERR(0, 86, __pyx_L1_error)
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -2713,12 +2976,12 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
   PyObject *__pyx_t_7 = NULL;
   PyObject *__pyx_t_8 = NULL;
   PyObject *__pyx_t_9 = NULL;
-  Py_ssize_t __pyx_t_10;
+  int __pyx_t_10;
   PyObject *__pyx_t_11 = NULL;
-  int __pyx_t_12;
+  Py_ssize_t __pyx_t_12;
   PyObject *(*__pyx_t_13)(PyObject *);
-  Py_ssize_t __pyx_t_14;
-  PyObject *__pyx_t_15 = NULL;
+  PyObject *__pyx_t_14 = NULL;
+  Py_ssize_t __pyx_t_15;
   Py_ssize_t __pyx_t_16;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
@@ -2730,62 +2993,62 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 88, __pyx_L1_error)
+  if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 86, __pyx_L1_error)
 
   __pyx_cur_scope->__pyx_v_i = 0;
 
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_sequence_class); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 95, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_sequence_class); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 93, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_GIVEREF(__pyx_t_1);
   __pyx_cur_scope->__pyx_v_sequence_class = __pyx_t_1;
   __pyx_t_1 = 0;
 
-  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_file_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 97, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_file_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 95, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 97, __pyx_L1_error)
+  __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 95, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   __Pyx_GIVEREF(__pyx_t_2);
   __pyx_cur_scope->__pyx_v_it = __pyx_t_2;
   __pyx_t_2 = 0;
 
-  __pyx_t_2 = __Pyx_PyIter_Next(__pyx_cur_scope->__pyx_v_it); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 98, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_PyIter_Next(__pyx_cur_scope->__pyx_v_it); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 96, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  if (!(likely(PyString_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 98, __pyx_L1_error)
+  if (!(likely(PyString_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_2)->tp_name), 0))) __PYX_ERR(0, 96, __pyx_L1_error)
   __Pyx_GIVEREF(__pyx_t_2);
   __pyx_cur_scope->__pyx_v_line = ((PyObject*)__pyx_t_2);
   __pyx_t_2 = 0;
 
-  __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 99, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 97, __pyx_L1_error)
   if (__pyx_t_4) {
   } else {
     __pyx_t_3 = __pyx_t_4;
     goto __pyx_L5_bool_binop_done;
   }
-  __pyx_t_2 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 99, __pyx_L1_error)
+  __pyx_t_2 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 97, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_4 = (__Pyx_PyString_Equals(__pyx_t_2, __pyx_kp_s__2, Py_EQ)); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 99, __pyx_L1_error)
+  __pyx_t_4 = (__Pyx_PyString_Equals(__pyx_t_2, __pyx_kp_s__2, Py_EQ)); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 97, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __pyx_t_3 = __pyx_t_4;
   __pyx_L5_bool_binop_done:;
   __pyx_t_4 = ((!__pyx_t_3) != 0);
   if (__pyx_t_4) {
 
-    __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 100, __pyx_L1_error)
+    __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 98, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected, __pyx_n_s_format); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 100, __pyx_L1_error)
+    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected, __pyx_n_s_format); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 98, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_6);
-    __pyx_t_7 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 100, __pyx_L1_error)
+    __pyx_t_7 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 98, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_7);
     if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
       PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-      __PYX_ERR(0, 100, __pyx_L1_error)
+      __PYX_ERR(0, 98, __pyx_L1_error)
     }
-    __pyx_t_8 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 100, __pyx_L1_error)
+    __pyx_t_8 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 98, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_8);
     __pyx_t_9 = NULL;
     __pyx_t_10 = 0;
-    if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_6))) {
+    if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_6))) {
       __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_6);
       if (likely(__pyx_t_9)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
@@ -2795,23 +3058,45 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
         __pyx_t_10 = 1;
       }
     }
-    __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 100, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_11);
-    if (__pyx_t_9) {
-      __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_9); __pyx_t_9 = NULL;
+    #if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(__pyx_t_6)) {
+      PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_7, __pyx_t_8};
+      __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 98, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+      __Pyx_GOTREF(__pyx_t_5);
+      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+      __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+    } else
+    #endif
+    #if CYTHON_FAST_PYCCALL
+    if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) {
+      PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_7, __pyx_t_8};
+      __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 98, __pyx_L1_error)
+      __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+      __Pyx_GOTREF(__pyx_t_5);
+      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+      __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+    } else
+    #endif
+    {
+      __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 98, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_11);
+      if (__pyx_t_9) {
+        __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_9); __pyx_t_9 = NULL;
+      }
+      __Pyx_GIVEREF(__pyx_t_7);
+      PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_10, __pyx_t_7);
+      __Pyx_GIVEREF(__pyx_t_8);
+      PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_10, __pyx_t_8);
+      __pyx_t_7 = 0;
+      __pyx_t_8 = 0;
+      __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 98, __pyx_L1_error)
+      __Pyx_GOTREF(__pyx_t_5);
+      __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
     }
-    __Pyx_GIVEREF(__pyx_t_7);
-    PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_10, __pyx_t_7);
-    __Pyx_GIVEREF(__pyx_t_8);
-    PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_10, __pyx_t_8);
-    __pyx_t_7 = 0;
-    __pyx_t_8 = 0;
-    __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 100, __pyx_L1_error)
-    __Pyx_GOTREF(__pyx_t_5);
-    __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
     __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
     __pyx_t_6 = NULL;
-    if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_1))) {
+    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) {
       __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1);
       if (likely(__pyx_t_6)) {
         PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
@@ -2821,44 +3106,64 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       }
     }
     if (!__pyx_t_6) {
-      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 100, __pyx_L1_error)
+      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 98, __pyx_L1_error)
       __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
       __Pyx_GOTREF(__pyx_t_2);
     } else {
-      __pyx_t_11 = PyTuple_New(1+1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 100, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_11);
-      __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_6); __pyx_t_6 = NULL;
-      __Pyx_GIVEREF(__pyx_t_5);
-      PyTuple_SET_ITEM(__pyx_t_11, 0+1, __pyx_t_5);
-      __pyx_t_5 = 0;
-      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_11, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 100, __pyx_L1_error)
-      __Pyx_GOTREF(__pyx_t_2);
-      __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+      #if CYTHON_FAST_PYCALL
+      if (PyFunction_Check(__pyx_t_1)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
+        __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 98, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __Pyx_GOTREF(__pyx_t_2);
+        __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      } else
+      #endif
+      #if CYTHON_FAST_PYCCALL
+      if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) {
+        PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
+        __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 98, __pyx_L1_error)
+        __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __Pyx_GOTREF(__pyx_t_2);
+        __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      } else
+      #endif
+      {
+        __pyx_t_11 = PyTuple_New(1+1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 98, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_11);
+        __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_6); __pyx_t_6 = NULL;
+        __Pyx_GIVEREF(__pyx_t_5);
+        PyTuple_SET_ITEM(__pyx_t_11, 0+1, __pyx_t_5);
+        __pyx_t_5 = 0;
+        __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_11, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 98, __pyx_L1_error)
+        __Pyx_GOTREF(__pyx_t_2);
+        __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+      }
     }
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
     __Pyx_Raise(__pyx_t_2, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __PYX_ERR(0, 100, __pyx_L1_error)
+    __PYX_ERR(0, 98, __pyx_L1_error)
 
   }
 
   if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
     PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", "endswith");
-    __PYX_ERR(0, 101, __pyx_L1_error)
+    __PYX_ERR(0, 99, __pyx_L1_error)
   }
-  __pyx_t_4 = __Pyx_PyStr_Tailmatch(__pyx_cur_scope->__pyx_v_line, __pyx_kp_s__3, 0, PY_SSIZE_T_MAX, 1); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(0, 101, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_PyStr_Tailmatch(__pyx_cur_scope->__pyx_v_line, __pyx_kp_s__3, 0, PY_SSIZE_T_MAX, 1); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(0, 99, __pyx_L1_error)
   if ((__pyx_t_4 != 0)) {
-    __pyx_t_12 = -2;
+    __pyx_t_10 = -2;
   } else {
-    __pyx_t_12 = -1;
+    __pyx_t_10 = -1;
   }
-  __pyx_cur_scope->__pyx_v_strip = __pyx_t_12;
+  __pyx_cur_scope->__pyx_v_strip = __pyx_t_10;
 
   if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
     PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-    __PYX_ERR(0, 102, __pyx_L1_error)
+    __PYX_ERR(0, 100, __pyx_L1_error)
   }
-  __pyx_t_2 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 102, __pyx_L1_error)
+  __pyx_t_2 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 100, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_GIVEREF(__pyx_t_2);
   __pyx_cur_scope->__pyx_v_name = ((PyObject*)__pyx_t_2);
@@ -2867,29 +3172,29 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
   __pyx_cur_scope->__pyx_v_i = 1;
 
   if (likely(PyList_CheckExact(__pyx_cur_scope->__pyx_v_it)) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_v_it)) {
-    __pyx_t_2 = __pyx_cur_scope->__pyx_v_it; __Pyx_INCREF(__pyx_t_2); __pyx_t_10 = 0;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_v_it; __Pyx_INCREF(__pyx_t_2); __pyx_t_12 = 0;
     __pyx_t_13 = NULL;
   } else {
-    __pyx_t_10 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_it); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 105, __pyx_L1_error)
+    __pyx_t_12 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_it); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 103, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_13 = Py_TYPE(__pyx_t_2)->tp_iternext; if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 105, __pyx_L1_error)
+    __pyx_t_13 = Py_TYPE(__pyx_t_2)->tp_iternext; if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 103, __pyx_L1_error)
   }
   for (;;) {
     if (likely(!__pyx_t_13)) {
       if (likely(PyList_CheckExact(__pyx_t_2))) {
-        if (__pyx_t_10 >= PyList_GET_SIZE(__pyx_t_2)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_1); __pyx_t_10++; if (unlikely(0 < 0)) __PYX_ERR(0, 105, __pyx_L1_error)
+        if (__pyx_t_12 >= PyList_GET_SIZE(__pyx_t_2)) break;
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+        __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_12); __Pyx_INCREF(__pyx_t_1); __pyx_t_12++; if (unlikely(0 < 0)) __PYX_ERR(0, 103, __pyx_L1_error)
         #else
-        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_10); __pyx_t_10++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 105, __pyx_L1_error)
+        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_12); __pyx_t_12++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 103, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_1);
         #endif
       } else {
-        if (__pyx_t_10 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
-        #if CYTHON_COMPILING_IN_CPYTHON
-        __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_1); __pyx_t_10++; if (unlikely(0 < 0)) __PYX_ERR(0, 105, __pyx_L1_error)
+        if (__pyx_t_12 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
+        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+        __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_12); __Pyx_INCREF(__pyx_t_1); __pyx_t_12++; if (unlikely(0 < 0)) __PYX_ERR(0, 103, __pyx_L1_error)
         #else
-        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_10); __pyx_t_10++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 105, __pyx_L1_error)
+        __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_12); __pyx_t_12++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 103, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_1);
         #endif
       }
@@ -2899,13 +3204,13 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
         PyObject* exc_type = PyErr_Occurred();
         if (exc_type) {
           if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
-          else __PYX_ERR(0, 105, __pyx_L1_error)
+          else __PYX_ERR(0, 103, __pyx_L1_error)
         }
         break;
       }
       __Pyx_GOTREF(__pyx_t_1);
     }
-    if (!(likely(PyString_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_1)->tp_name), 0))) __PYX_ERR(0, 105, __pyx_L1_error)
+    if (!(likely(PyString_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_1)->tp_name), 0))) __PYX_ERR(0, 103, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_cur_scope->__pyx_v_line);
     __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_line, ((PyObject*)__pyx_t_1));
     __Pyx_GIVEREF(__pyx_t_1);
@@ -2914,62 +3219,84 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
     switch (__pyx_cur_scope->__pyx_v_i) {
       case 0:
 
-      __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 107, __pyx_L1_error)
+      __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 105, __pyx_L1_error)
       if (__pyx_t_3) {
       } else {
         __pyx_t_4 = __pyx_t_3;
         goto __pyx_L10_bool_binop_done;
       }
-      __pyx_t_1 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 107, __pyx_L1_error)
+      __pyx_t_1 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 105, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_1);
-      __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_kp_s__2, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 107, __pyx_L1_error)
+      __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_kp_s__2, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 105, __pyx_L1_error)
       __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
       __pyx_t_4 = __pyx_t_3;
       __pyx_L10_bool_binop_done:;
       __pyx_t_3 = ((!__pyx_t_4) != 0);
       if (__pyx_t_3) {
 
-        __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 108, __pyx_L1_error)
+        __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 106, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_11);
-        __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected, __pyx_n_s_format); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 108, __pyx_L1_error)
+        __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected, __pyx_n_s_format); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 106, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_6);
-        __pyx_t_8 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 108, __pyx_L1_error)
+        __pyx_t_8 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 106, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_8);
         if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
           PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-          __PYX_ERR(0, 108, __pyx_L1_error)
+          __PYX_ERR(0, 106, __pyx_L1_error)
         }
-        __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 108, __pyx_L1_error)
+        __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 106, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_7);
         __pyx_t_9 = NULL;
-        __pyx_t_14 = 0;
-        if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_6))) {
+        __pyx_t_10 = 0;
+        if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_6))) {
           __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_6);
           if (likely(__pyx_t_9)) {
             PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
             __Pyx_INCREF(__pyx_t_9);
             __Pyx_INCREF(function);
             __Pyx_DECREF_SET(__pyx_t_6, function);
-            __pyx_t_14 = 1;
+            __pyx_t_10 = 1;
           }
         }
-        __pyx_t_15 = PyTuple_New(2+__pyx_t_14); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 108, __pyx_L1_error)
-        __Pyx_GOTREF(__pyx_t_15);
-        if (__pyx_t_9) {
-          __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_15, 0, __pyx_t_9); __pyx_t_9 = NULL;
+        #if CYTHON_FAST_PYCALL
+        if (PyFunction_Check(__pyx_t_6)) {
+          PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_8, __pyx_t_7};
+          __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 106, __pyx_L1_error)
+          __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+          __Pyx_GOTREF(__pyx_t_5);
+          __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+          __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+        } else
+        #endif
+        #if CYTHON_FAST_PYCCALL
+        if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) {
+          PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_8, __pyx_t_7};
+          __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 106, __pyx_L1_error)
+          __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+          __Pyx_GOTREF(__pyx_t_5);
+          __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+          __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+        } else
+        #endif
+        {
+          __pyx_t_14 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 106, __pyx_L1_error)
+          __Pyx_GOTREF(__pyx_t_14);
+          if (__pyx_t_9) {
+            __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_t_9); __pyx_t_9 = NULL;
+          }
+          __Pyx_GIVEREF(__pyx_t_8);
+          PyTuple_SET_ITEM(__pyx_t_14, 0+__pyx_t_10, __pyx_t_8);
+          __Pyx_GIVEREF(__pyx_t_7);
+          PyTuple_SET_ITEM(__pyx_t_14, 1+__pyx_t_10, __pyx_t_7);
+          __pyx_t_8 = 0;
+          __pyx_t_7 = 0;
+          __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_14, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 106, __pyx_L1_error)
+          __Pyx_GOTREF(__pyx_t_5);
+          __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
         }
-        __Pyx_GIVEREF(__pyx_t_8);
-        PyTuple_SET_ITEM(__pyx_t_15, 0+__pyx_t_14, __pyx_t_8);
-        __Pyx_GIVEREF(__pyx_t_7);
-        PyTuple_SET_ITEM(__pyx_t_15, 1+__pyx_t_14, __pyx_t_7);
-        __pyx_t_8 = 0;
-        __pyx_t_7 = 0;
-        __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_15, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 108, __pyx_L1_error)
-        __Pyx_GOTREF(__pyx_t_5);
-        __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
         __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
         __pyx_t_6 = NULL;
-        if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_11))) {
+        if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_11))) {
           __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_11);
           if (likely(__pyx_t_6)) {
             PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11);
@@ -2979,32 +3306,52 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
           }
         }
         if (!__pyx_t_6) {
-          __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 108, __pyx_L1_error)
+          __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error)
           __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
           __Pyx_GOTREF(__pyx_t_1);
         } else {
-          __pyx_t_15 = PyTuple_New(1+1); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 108, __pyx_L1_error)
-          __Pyx_GOTREF(__pyx_t_15);
-          __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_15, 0, __pyx_t_6); __pyx_t_6 = NULL;
-          __Pyx_GIVEREF(__pyx_t_5);
-          PyTuple_SET_ITEM(__pyx_t_15, 0+1, __pyx_t_5);
-          __pyx_t_5 = 0;
-          __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_15, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 108, __pyx_L1_error)
-          __Pyx_GOTREF(__pyx_t_1);
-          __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
+          #if CYTHON_FAST_PYCALL
+          if (PyFunction_Check(__pyx_t_11)) {
+            PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
+            __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_11, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error)
+            __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+            __Pyx_GOTREF(__pyx_t_1);
+            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+          } else
+          #endif
+          #if CYTHON_FAST_PYCCALL
+          if (__Pyx_PyFastCFunction_Check(__pyx_t_11)) {
+            PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
+            __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_11, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error)
+            __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+            __Pyx_GOTREF(__pyx_t_1);
+            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+          } else
+          #endif
+          {
+            __pyx_t_14 = PyTuple_New(1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 106, __pyx_L1_error)
+            __Pyx_GOTREF(__pyx_t_14);
+            __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_t_6); __pyx_t_6 = NULL;
+            __Pyx_GIVEREF(__pyx_t_5);
+            PyTuple_SET_ITEM(__pyx_t_14, 0+1, __pyx_t_5);
+            __pyx_t_5 = 0;
+            __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_14, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error)
+            __Pyx_GOTREF(__pyx_t_1);
+            __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
+          }
         }
         __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
         __Pyx_Raise(__pyx_t_1, 0, 0, 0);
         __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-        __PYX_ERR(0, 108, __pyx_L1_error)
+        __PYX_ERR(0, 106, __pyx_L1_error)
 
       }
 
       if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
         PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-        __PYX_ERR(0, 109, __pyx_L1_error)
+        __PYX_ERR(0, 107, __pyx_L1_error)
       }
-      __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 109, __pyx_L1_error)
+      __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 107, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_1);
       __Pyx_GOTREF(__pyx_cur_scope->__pyx_v_name);
       __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_name, ((PyObject*)__pyx_t_1));
@@ -3017,9 +3364,9 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
 
       if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
         PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-        __PYX_ERR(0, 111, __pyx_L1_error)
+        __PYX_ERR(0, 109, __pyx_L1_error)
       }
-      __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 111, __pyx_L1_error)
+      __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 109, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_1);
       __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_sequence);
       __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_sequence, ((PyObject*)__pyx_t_1));
@@ -3030,7 +3377,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
 
       case 2:
 
-      __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_cur_scope->__pyx_v_line, __pyx_kp_s__4, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 113, __pyx_L1_error)
+      __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_cur_scope->__pyx_v_line, __pyx_kp_s__4, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 111, __pyx_L1_error)
       __pyx_t_4 = (__pyx_t_3 != 0);
       if (__pyx_t_4) {
 
@@ -3045,67 +3392,89 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       /*else*/ {
         if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
           PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-          __PYX_ERR(0, 116, __pyx_L1_error)
+          __PYX_ERR(0, 114, __pyx_L1_error)
         }
-        __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error)
+        __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 114, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_1);
         __Pyx_GOTREF(__pyx_cur_scope->__pyx_v_line);
         __Pyx_DECREF_SET(__pyx_cur_scope->__pyx_v_line, ((PyObject*)__pyx_t_1));
         __Pyx_GIVEREF(__pyx_t_1);
         __pyx_t_1 = 0;
 
-        __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 117, __pyx_L1_error)
+        __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 115, __pyx_L1_error)
         if (__pyx_t_3) {
         } else {
           __pyx_t_4 = __pyx_t_3;
           goto __pyx_L14_bool_binop_done;
         }
-        __pyx_t_1 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 117, __pyx_L1_error)
+        __pyx_t_1 = __Pyx_GetItemInt(__pyx_cur_scope->__pyx_v_line, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 115, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_1);
-        __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_kp_s__5, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 117, __pyx_L1_error)
+        __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_kp_s__5, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 115, __pyx_L1_error)
         __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
         __pyx_t_4 = __pyx_t_3;
         __pyx_L14_bool_binop_done:;
         __pyx_t_3 = ((!__pyx_t_4) != 0);
         if (__pyx_t_3) {
 
-          __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 118, __pyx_L1_error)
+          __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 116, __pyx_L1_error)
           __Pyx_GOTREF(__pyx_t_11);
-          __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected_2, __pyx_n_s_format); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 118, __pyx_L1_error)
+          __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_Line_0_in_FASTQ_file_is_expected_2, __pyx_n_s_format); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 116, __pyx_L1_error)
           __Pyx_GOTREF(__pyx_t_5);
-          __pyx_t_6 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 118, __pyx_L1_error)
+          __pyx_t_6 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 116, __pyx_L1_error)
           __Pyx_GOTREF(__pyx_t_6);
-          __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 118, __pyx_L1_error)
+          __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, 10); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 116, __pyx_L1_error)
           __Pyx_GOTREF(__pyx_t_7);
           __pyx_t_8 = NULL;
-          __pyx_t_14 = 0;
-          if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_5))) {
+          __pyx_t_10 = 0;
+          if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) {
             __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_5);
             if (likely(__pyx_t_8)) {
               PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
               __Pyx_INCREF(__pyx_t_8);
               __Pyx_INCREF(function);
               __Pyx_DECREF_SET(__pyx_t_5, function);
-              __pyx_t_14 = 1;
+              __pyx_t_10 = 1;
             }
           }
-          __pyx_t_9 = PyTuple_New(2+__pyx_t_14); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 118, __pyx_L1_error)
-          __Pyx_GOTREF(__pyx_t_9);
-          if (__pyx_t_8) {
-            __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
+          #if CYTHON_FAST_PYCALL
+          if (PyFunction_Check(__pyx_t_5)) {
+            PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_t_6, __pyx_t_7};
+            __pyx_t_14 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 116, __pyx_L1_error)
+            __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+            __Pyx_GOTREF(__pyx_t_14);
+            __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+          } else
+          #endif
+          #if CYTHON_FAST_PYCCALL
+          if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
+            PyObject *__pyx_temp[3] = {__pyx_t_8, __pyx_t_6, __pyx_t_7};
+            __pyx_t_14 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 116, __pyx_L1_error)
+            __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+            __Pyx_GOTREF(__pyx_t_14);
+            __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+          } else
+          #endif
+          {
+            __pyx_t_9 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 116, __pyx_L1_error)
+            __Pyx_GOTREF(__pyx_t_9);
+            if (__pyx_t_8) {
+              __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
+            }
+            __Pyx_GIVEREF(__pyx_t_6);
+            PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_10, __pyx_t_6);
+            __Pyx_GIVEREF(__pyx_t_7);
+            PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_10, __pyx_t_7);
+            __pyx_t_6 = 0;
+            __pyx_t_7 = 0;
+            __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 116, __pyx_L1_error)
+            __Pyx_GOTREF(__pyx_t_14);
+            __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
           }
-          __Pyx_GIVEREF(__pyx_t_6);
-          PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_14, __pyx_t_6);
-          __Pyx_GIVEREF(__pyx_t_7);
-          PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_14, __pyx_t_7);
-          __pyx_t_6 = 0;
-          __pyx_t_7 = 0;
-          __pyx_t_15 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 118, __pyx_L1_error)
-          __Pyx_GOTREF(__pyx_t_15);
-          __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
           __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
           __pyx_t_5 = NULL;
-          if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_11))) {
+          if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_11))) {
             __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_11);
             if (likely(__pyx_t_5)) {
               PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11);
@@ -3115,107 +3484,169 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
             }
           }
           if (!__pyx_t_5) {
-            __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_15); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 118, __pyx_L1_error)
-            __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
+            __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_14); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error)
+            __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
             __Pyx_GOTREF(__pyx_t_1);
           } else {
-            __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 118, __pyx_L1_error)
-            __Pyx_GOTREF(__pyx_t_9);
-            __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_5); __pyx_t_5 = NULL;
-            __Pyx_GIVEREF(__pyx_t_15);
-            PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_15);
-            __pyx_t_15 = 0;
-            __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 118, __pyx_L1_error)
-            __Pyx_GOTREF(__pyx_t_1);
-            __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+            #if CYTHON_FAST_PYCALL
+            if (PyFunction_Check(__pyx_t_11)) {
+              PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_14};
+              __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_11, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error)
+              __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
+              __Pyx_GOTREF(__pyx_t_1);
+              __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
+            } else
+            #endif
+            #if CYTHON_FAST_PYCCALL
+            if (__Pyx_PyFastCFunction_Check(__pyx_t_11)) {
+              PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_14};
+              __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_11, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error)
+              __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
+              __Pyx_GOTREF(__pyx_t_1);
+              __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
+            } else
+            #endif
+            {
+              __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 116, __pyx_L1_error)
+              __Pyx_GOTREF(__pyx_t_9);
+              __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_5); __pyx_t_5 = NULL;
+              __Pyx_GIVEREF(__pyx_t_14);
+              PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_14);
+              __pyx_t_14 = 0;
+              __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error)
+              __Pyx_GOTREF(__pyx_t_1);
+              __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+            }
           }
           __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
           __Pyx_Raise(__pyx_t_1, 0, 0, 0);
           __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-          __PYX_ERR(0, 118, __pyx_L1_error)
+          __PYX_ERR(0, 116, __pyx_L1_error)
 
         }
 
-        __pyx_t_14 = PyObject_Length(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_14 == -1)) __PYX_ERR(0, 119, __pyx_L1_error)
-        __pyx_t_3 = ((__pyx_t_14 > 1) != 0);
+        __pyx_t_15 = PyObject_Length(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_15 == -1)) __PYX_ERR(0, 117, __pyx_L1_error)
+        __pyx_t_3 = ((__pyx_t_15 > 1) != 0);
         if (__pyx_t_3) {
 
-          __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 120, __pyx_L1_error)
+          __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 118, __pyx_L1_error)
           __Pyx_GOTREF(__pyx_t_1);
-          __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_cur_scope->__pyx_v_name, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 120, __pyx_L1_error)
+          __pyx_t_3 = (__Pyx_PyString_Equals(__pyx_t_1, __pyx_cur_scope->__pyx_v_name, Py_EQ)); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 118, __pyx_L1_error)
           __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
           __pyx_t_4 = ((!(__pyx_t_3 != 0)) != 0);
           if (__pyx_t_4) {
 
-            __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 121, __pyx_L1_error)
+            __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 119, __pyx_L1_error)
             __Pyx_GOTREF(__pyx_t_11);
 
-            __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_At_line_0_Sequence_descriptions, __pyx_n_s_format); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 125, __pyx_L1_error)
-            __Pyx_GOTREF(__pyx_t_15);
-            __pyx_t_5 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 125, __pyx_L1_error)
+            __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_kp_s_At_line_0_Sequence_descriptions, __pyx_n_s_format); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 123, __pyx_L1_error)
+            __Pyx_GOTREF(__pyx_t_14);
+            __pyx_t_5 = __Pyx_PyInt_From_long((__pyx_cur_scope->__pyx_v_i + 1)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 123, __pyx_L1_error)
             __Pyx_GOTREF(__pyx_t_5);
 
-            __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 126, __pyx_L1_error)
+            __pyx_t_7 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 1, PY_SSIZE_T_MAX); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 124, __pyx_L1_error)
             __Pyx_GOTREF(__pyx_t_7);
             __pyx_t_6 = NULL;
-            __pyx_t_14 = 0;
-            if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_15))) {
-              __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_15);
+            __pyx_t_10 = 0;
+            if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_14))) {
+              __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_14);
               if (likely(__pyx_t_6)) {
-                PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_15);
+                PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_14);
                 __Pyx_INCREF(__pyx_t_6);
                 __Pyx_INCREF(function);
-                __Pyx_DECREF_SET(__pyx_t_15, function);
-                __pyx_t_14 = 1;
+                __Pyx_DECREF_SET(__pyx_t_14, function);
+                __pyx_t_10 = 1;
               }
             }
-            __pyx_t_8 = PyTuple_New(3+__pyx_t_14); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 125, __pyx_L1_error)
-            __Pyx_GOTREF(__pyx_t_8);
-            if (__pyx_t_6) {
-              __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL;
+            #if CYTHON_FAST_PYCALL
+            if (PyFunction_Check(__pyx_t_14)) {
+              PyObject *__pyx_temp[4] = {__pyx_t_6, __pyx_t_5, __pyx_cur_scope->__pyx_v_name, __pyx_t_7};
+              __pyx_t_9 = __Pyx_PyFunction_FastCall(__pyx_t_14, __pyx_temp+1-__pyx_t_10, 3+__pyx_t_10); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 123, __pyx_L1_error)
+              __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+              __Pyx_GOTREF(__pyx_t_9);
+              __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+              __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+            } else
+            #endif
+            #if CYTHON_FAST_PYCCALL
+            if (__Pyx_PyFastCFunction_Check(__pyx_t_14)) {
+              PyObject *__pyx_temp[4] = {__pyx_t_6, __pyx_t_5, __pyx_cur_scope->__pyx_v_name, __pyx_t_7};
+              __pyx_t_9 = __Pyx_PyCFunction_FastCall(__pyx_t_14, __pyx_temp+1-__pyx_t_10, 3+__pyx_t_10); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 123, __pyx_L1_error)
+              __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+              __Pyx_GOTREF(__pyx_t_9);
+              __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+              __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+            } else
+            #endif
+            {
+              __pyx_t_8 = PyTuple_New(3+__pyx_t_10); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 123, __pyx_L1_error)
+              __Pyx_GOTREF(__pyx_t_8);
+              if (__pyx_t_6) {
+                __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL;
+              }
+              __Pyx_GIVEREF(__pyx_t_5);
+              PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_10, __pyx_t_5);
+              __Pyx_INCREF(__pyx_cur_scope->__pyx_v_name);
+              __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_name);
+              PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_10, __pyx_cur_scope->__pyx_v_name);
+              __Pyx_GIVEREF(__pyx_t_7);
+              PyTuple_SET_ITEM(__pyx_t_8, 2+__pyx_t_10, __pyx_t_7);
+              __pyx_t_5 = 0;
+              __pyx_t_7 = 0;
+              __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_14, __pyx_t_8, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 123, __pyx_L1_error)
+              __Pyx_GOTREF(__pyx_t_9);
+              __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
             }
-            __Pyx_GIVEREF(__pyx_t_5);
-            PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_14, __pyx_t_5);
-            __Pyx_INCREF(__pyx_cur_scope->__pyx_v_name);
-            __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_name);
-            PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_14, __pyx_cur_scope->__pyx_v_name);
-            __Pyx_GIVEREF(__pyx_t_7);
-            PyTuple_SET_ITEM(__pyx_t_8, 2+__pyx_t_14, __pyx_t_7);
-            __pyx_t_5 = 0;
-            __pyx_t_7 = 0;
-            __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_15, __pyx_t_8, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 125, __pyx_L1_error)
-            __Pyx_GOTREF(__pyx_t_9);
-            __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
-            __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
-            __pyx_t_15 = NULL;
-            if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_11))) {
-              __pyx_t_15 = PyMethod_GET_SELF(__pyx_t_11);
-              if (likely(__pyx_t_15)) {
+            __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
+            __pyx_t_14 = NULL;
+            if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_11))) {
+              __pyx_t_14 = PyMethod_GET_SELF(__pyx_t_11);
+              if (likely(__pyx_t_14)) {
                 PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11);
-                __Pyx_INCREF(__pyx_t_15);
+                __Pyx_INCREF(__pyx_t_14);
                 __Pyx_INCREF(function);
                 __Pyx_DECREF_SET(__pyx_t_11, function);
               }
             }
-            if (!__pyx_t_15) {
-              __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 121, __pyx_L1_error)
+            if (!__pyx_t_14) {
+              __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 119, __pyx_L1_error)
               __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
               __Pyx_GOTREF(__pyx_t_1);
             } else {
-              __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 121, __pyx_L1_error)
-              __Pyx_GOTREF(__pyx_t_8);
-              __Pyx_GIVEREF(__pyx_t_15); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_15); __pyx_t_15 = NULL;
-              __Pyx_GIVEREF(__pyx_t_9);
-              PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_9);
-              __pyx_t_9 = 0;
-              __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 121, __pyx_L1_error)
-              __Pyx_GOTREF(__pyx_t_1);
-              __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+              #if CYTHON_FAST_PYCALL
+              if (PyFunction_Check(__pyx_t_11)) {
+                PyObject *__pyx_temp[2] = {__pyx_t_14, __pyx_t_9};
+                __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_11, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 119, __pyx_L1_error)
+                __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0;
+                __Pyx_GOTREF(__pyx_t_1);
+                __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+              } else
+              #endif
+              #if CYTHON_FAST_PYCCALL
+              if (__Pyx_PyFastCFunction_Check(__pyx_t_11)) {
+                PyObject *__pyx_temp[2] = {__pyx_t_14, __pyx_t_9};
+                __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_11, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 119, __pyx_L1_error)
+                __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0;
+                __Pyx_GOTREF(__pyx_t_1);
+                __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+              } else
+              #endif
+              {
+                __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 119, __pyx_L1_error)
+                __Pyx_GOTREF(__pyx_t_8);
+                __Pyx_GIVEREF(__pyx_t_14); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_14); __pyx_t_14 = NULL;
+                __Pyx_GIVEREF(__pyx_t_9);
+                PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_9);
+                __pyx_t_9 = 0;
+                __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 119, __pyx_L1_error)
+                __Pyx_GOTREF(__pyx_t_1);
+                __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+              }
             }
             __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
             __Pyx_Raise(__pyx_t_1, 0, 0, 0);
             __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-            __PYX_ERR(0, 121, __pyx_L1_error)
+            __PYX_ERR(0, 119, __pyx_L1_error)
 
           }
 
@@ -3235,17 +3666,17 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
 
       case 3:
 
-      __pyx_t_14 = PyObject_Length(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_14 == -1)) __PYX_ERR(0, 131, __pyx_L1_error)
-      if (unlikely(!__pyx_cur_scope->__pyx_v_sequence)) { __Pyx_RaiseUnboundLocalError("sequence"); __PYX_ERR(0, 131, __pyx_L1_error) }
-      __pyx_t_16 = PyObject_Length(__pyx_cur_scope->__pyx_v_sequence); if (unlikely(__pyx_t_16 == -1)) __PYX_ERR(0, 131, __pyx_L1_error)
-      __pyx_t_4 = ((__pyx_t_14 == (__pyx_t_16 - __pyx_cur_scope->__pyx_v_strip)) != 0);
+      __pyx_t_15 = PyObject_Length(__pyx_cur_scope->__pyx_v_line); if (unlikely(__pyx_t_15 == -1)) __PYX_ERR(0, 129, __pyx_L1_error)
+      if (unlikely(!__pyx_cur_scope->__pyx_v_sequence)) { __Pyx_RaiseUnboundLocalError("sequence"); __PYX_ERR(0, 129, __pyx_L1_error) }
+      __pyx_t_16 = PyObject_Length(__pyx_cur_scope->__pyx_v_sequence); if (unlikely(__pyx_t_16 == -1)) __PYX_ERR(0, 129, __pyx_L1_error)
+      __pyx_t_4 = ((__pyx_t_15 == (__pyx_t_16 - __pyx_cur_scope->__pyx_v_strip)) != 0);
       if (__pyx_t_4) {
 
         if (unlikely(__pyx_cur_scope->__pyx_v_line == Py_None)) {
           PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
-          __PYX_ERR(0, 132, __pyx_L1_error)
+          __PYX_ERR(0, 130, __pyx_L1_error)
         }
-        __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 132, __pyx_L1_error)
+        __pyx_t_1 = PySequence_GetSlice(__pyx_cur_scope->__pyx_v_line, 0, __pyx_cur_scope->__pyx_v_strip); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 130, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_1);
         __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_qualities);
         __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_qualities, ((PyObject*)__pyx_t_1));
@@ -3256,12 +3687,12 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       }
 
       /*else*/ {
-        __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_line, __pyx_n_s_rstrip); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 134, __pyx_L1_error)
+        __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_line, __pyx_n_s_rstrip); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 132, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_1);
-        __pyx_t_11 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 134, __pyx_L1_error)
+        __pyx_t_11 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 132, __pyx_L1_error)
         __Pyx_GOTREF(__pyx_t_11);
         __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-        if (!(likely(PyString_CheckExact(__pyx_t_11))||((__pyx_t_11) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_11)->tp_name), 0))) __PYX_ERR(0, 134, __pyx_L1_error)
+        if (!(likely(PyString_CheckExact(__pyx_t_11))||((__pyx_t_11) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_11)->tp_name), 0))) __PYX_ERR(0, 132, __pyx_L1_error)
         __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_qualities);
         __Pyx_XDECREF_SET(__pyx_cur_scope->__pyx_v_qualities, ((PyObject*)__pyx_t_11));
         __Pyx_GIVEREF(__pyx_t_11);
@@ -3269,8 +3700,8 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       }
       __pyx_L18:;
 
-      if (unlikely(!__pyx_cur_scope->__pyx_v_sequence)) { __Pyx_RaiseUnboundLocalError("sequence"); __PYX_ERR(0, 135, __pyx_L1_error) }
-      __pyx_t_11 = PyTuple_New(3); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 135, __pyx_L1_error)
+      if (unlikely(!__pyx_cur_scope->__pyx_v_sequence)) { __Pyx_RaiseUnboundLocalError("sequence"); __PYX_ERR(0, 133, __pyx_L1_error) }
+      __pyx_t_11 = PyTuple_New(3); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 133, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_11);
       __Pyx_INCREF(__pyx_cur_scope->__pyx_v_name);
       __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_name);
@@ -3281,13 +3712,13 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       __Pyx_INCREF(__pyx_cur_scope->__pyx_v_qualities);
       __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_qualities);
       PyTuple_SET_ITEM(__pyx_t_11, 2, __pyx_cur_scope->__pyx_v_qualities);
-      __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 135, __pyx_L1_error)
+      __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 133, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_1);
-      __pyx_t_8 = __Pyx_PyBool_FromLong(__pyx_cur_scope->__pyx_v_second_header); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 135, __pyx_L1_error)
+      __pyx_t_8 = __Pyx_PyBool_FromLong(__pyx_cur_scope->__pyx_v_second_header); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 133, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_8);
-      if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_second_header, __pyx_t_8) < 0) __PYX_ERR(0, 135, __pyx_L1_error)
+      if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_second_header, __pyx_t_8) < 0) __PYX_ERR(0, 133, __pyx_L1_error)
       __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
-      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_cur_scope->__pyx_v_sequence_class, __pyx_t_11, __pyx_t_1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 135, __pyx_L1_error)
+      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_cur_scope->__pyx_v_sequence_class, __pyx_t_11, __pyx_t_1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 133, __pyx_L1_error)
       __Pyx_GOTREF(__pyx_t_8);
       __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
       __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -3295,7 +3726,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       __pyx_t_8 = 0;
       __Pyx_XGIVEREF(__pyx_t_2);
       __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
-      __pyx_cur_scope->__pyx_t_1 = __pyx_t_10;
+      __pyx_cur_scope->__pyx_t_1 = __pyx_t_12;
       __pyx_cur_scope->__pyx_t_2 = __pyx_t_13;
       __Pyx_XGIVEREF(__pyx_r);
       __Pyx_RefNannyFinishContext();
@@ -3306,9 +3737,9 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
       __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
       __pyx_cur_scope->__pyx_t_0 = 0;
       __Pyx_XGOTREF(__pyx_t_2);
-      __pyx_t_10 = __pyx_cur_scope->__pyx_t_1;
+      __pyx_t_12 = __pyx_cur_scope->__pyx_t_1;
       __pyx_t_13 = __pyx_cur_scope->__pyx_t_2;
-      if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 135, __pyx_L1_error)
+      if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 133, __pyx_L1_error)
 
       break;
       default: break;
@@ -3322,16 +3753,17 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
   __pyx_t_4 = ((__pyx_cur_scope->__pyx_v_i != 0) != 0);
   if (__pyx_t_4) {
 
-    __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 138, __pyx_L1_error)
+    __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_FormatError); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 136, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 138, __pyx_L1_error)
+    __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 136, __pyx_L1_error)
     __Pyx_GOTREF(__pyx_t_8);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     __Pyx_Raise(__pyx_t_8, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
-    __PYX_ERR(0, 138, __pyx_L1_error)
+    __PYX_ERR(0, 136, __pyx_L1_error)
 
   }
+  CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope);
 
 
   /* function exit code */
@@ -3346,7 +3778,7 @@ static PyObject *__pyx_gb_8cutadapt_6_seqio_11FastqReader_4generator(__pyx_Corou
   __Pyx_XDECREF(__pyx_t_8);
   __Pyx_XDECREF(__pyx_t_9);
   __Pyx_XDECREF(__pyx_t_11);
-  __Pyx_XDECREF(__pyx_t_15);
+  __Pyx_XDECREF(__pyx_t_14);
   __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_L0:;
   __Pyx_XDECREF(__pyx_r); __pyx_r = 0;
@@ -3370,7 +3802,6 @@ static PyObject *__pyx_tp_new_8cutadapt_6_seqio_Sequence(PyTypeObject *t, CYTHON
   p->sequence = ((PyObject*)Py_None); Py_INCREF(Py_None);
   p->qualities = ((PyObject*)Py_None); Py_INCREF(Py_None);
   p->match = Py_None; Py_INCREF(Py_None);
-  p->match_info = Py_None; Py_INCREF(Py_None);
   return o;
 }
 
@@ -3386,7 +3817,6 @@ static void __pyx_tp_dealloc_8cutadapt_6_seqio_Sequence(PyObject *o) {
   Py_CLEAR(p->sequence);
   Py_CLEAR(p->qualities);
   Py_CLEAR(p->match);
-  Py_CLEAR(p->match_info);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
@@ -3396,9 +3826,6 @@ static int __pyx_tp_traverse_8cutadapt_6_seqio_Sequence(PyObject *o, visitproc v
   if (p->match) {
     e = (*v)(p->match, a); if (e) return e;
   }
-  if (p->match_info) {
-    e = (*v)(p->match_info, a); if (e) return e;
-  }
   return 0;
 }
 
@@ -3408,9 +3835,6 @@ static int __pyx_tp_clear_8cutadapt_6_seqio_Sequence(PyObject *o) {
   tmp = ((PyObject*)p->match);
   p->match = Py_None; Py_INCREF(Py_None);
   Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->match_info);
-  p->match_info = Py_None; Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
   return 0;
 }
 static PyObject *__pyx_sq_item_8cutadapt_6_seqio_Sequence(PyObject *o, Py_ssize_t i) {
@@ -3487,19 +3911,6 @@ static int __pyx_setprop_8cutadapt_6_seqio_8Sequence_match(PyObject *o, PyObject
   }
 }
 
-static PyObject *__pyx_getprop_8cutadapt_6_seqio_8Sequence_match_info(PyObject *o, CYTHON_UNUSED void *x) {
-  return __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_1__get__(o);
-}
-
-static int __pyx_setprop_8cutadapt_6_seqio_8Sequence_match_info(PyObject *o, PyObject *v, CYTHON_UNUSED void *x) {
-  if (v) {
-    return __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_3__set__(o, v);
-  }
-  else {
-    return __pyx_pw_8cutadapt_6_seqio_8Sequence_10match_info_5__del__(o);
-  }
-}
-
 static PyMethodDef __pyx_methods_8cutadapt_6_seqio_Sequence[] = {
   {"__reduce__", (PyCFunction)__pyx_pw_8cutadapt_6_seqio_8Sequence_11__reduce__, METH_NOARGS, 0},
   {0, 0, 0, 0}
@@ -3511,7 +3922,6 @@ static struct PyGetSetDef __pyx_getsets_8cutadapt_6_seqio_Sequence[] = {
   {(char *)"qualities", __pyx_getprop_8cutadapt_6_seqio_8Sequence_qualities, __pyx_setprop_8cutadapt_6_seqio_8Sequence_qualities, (char *)0, 0},
   {(char *)"second_header", __pyx_getprop_8cutadapt_6_seqio_8Sequence_second_header, __pyx_setprop_8cutadapt_6_seqio_8Sequence_second_header, (char *)0, 0},
   {(char *)"match", __pyx_getprop_8cutadapt_6_seqio_8Sequence_match, __pyx_setprop_8cutadapt_6_seqio_8Sequence_match, (char *)0, 0},
-  {(char *)"match_info", __pyx_getprop_8cutadapt_6_seqio_8Sequence_match_info, __pyx_setprop_8cutadapt_6_seqio_8Sequence_match_info, (char *)0, 0},
   {0, 0, 0, 0, 0}
 };
 
@@ -3781,7 +4191,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s_line, __pyx_k_line, sizeof(__pyx_k_line), 0, 0, 1, 1},
   {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1},
   {&__pyx_n_s_match, __pyx_k_match, sizeof(__pyx_k_match), 0, 0, 1, 1},
-  {&__pyx_n_s_match_info, __pyx_k_match_info, sizeof(__pyx_k_match_info), 0, 0, 1, 1},
   {&__pyx_n_s_metaclass, __pyx_k_metaclass, sizeof(__pyx_k_metaclass), 0, 0, 1, 1},
   {&__pyx_n_s_module, __pyx_k_module, sizeof(__pyx_k_module), 0, 0, 1, 1},
   {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1},
@@ -3806,8 +4215,8 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {0, 0, 0, 0, 0, 0, 0}
 };
 static int __Pyx_InitCachedBuiltins(void) {
-  __pyx_builtin_NotImplementedError = __Pyx_GetBuiltinName(__pyx_n_s_NotImplementedError); if (!__pyx_builtin_NotImplementedError) __PYX_ERR(0, 69, __pyx_L1_error)
-  __pyx_builtin_super = __Pyx_GetBuiltinName(__pyx_n_s_super); if (!__pyx_builtin_super) __PYX_ERR(0, 84, __pyx_L1_error)
+  __pyx_builtin_NotImplementedError = __Pyx_GetBuiltinName(__pyx_n_s_NotImplementedError); if (!__pyx_builtin_NotImplementedError) __PYX_ERR(0, 66, __pyx_L1_error)
+  __pyx_builtin_super = __Pyx_GetBuiltinName(__pyx_n_s_super); if (!__pyx_builtin_super) __PYX_ERR(0, 82, __pyx_L1_error)
   return 0;
   __pyx_L1_error:;
   return -1;
@@ -3817,23 +4226,23 @@ static int __Pyx_InitCachedConstants(void) {
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0);
 
-  __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_s__3); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(0, 134, __pyx_L1_error)
+  __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_s__3); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(0, 132, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__6);
   __Pyx_GIVEREF(__pyx_tuple__6);
 
-  __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_s_FASTQ_file_ended_prematurely); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(0, 138, __pyx_L1_error)
+  __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_s_FASTQ_file_ended_prematurely); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(0, 136, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__7);
   __Pyx_GIVEREF(__pyx_tuple__7);
 
-  __pyx_tuple__8 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_file, __pyx_n_s_sequence_class); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 79, __pyx_L1_error)
+  __pyx_tuple__8 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_file, __pyx_n_s_sequence_class); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 77, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__8);
   __Pyx_GIVEREF(__pyx_tuple__8);
-  __pyx_codeobj__9 = (PyObject*)__Pyx_PyCode_New(3, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_init, 79, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__9)) __PYX_ERR(0, 79, __pyx_L1_error)
+  __pyx_codeobj__9 = (PyObject*)__Pyx_PyCode_New(3, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_init, 77, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__9)) __PYX_ERR(0, 77, __pyx_L1_error)
 
-  __pyx_tuple__10 = PyTuple_Pack(11, __pyx_n_s_self, __pyx_n_s_i, __pyx_n_s_strip, __pyx_n_s_line, __pyx_n_s_name, __pyx_n_s_qualities, __pyx_n_s_sequence, __pyx_n_s_name2, __pyx_n_s_sequence_class, __pyx_n_s_it, __pyx_n_s_second_header); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(0, 88, __pyx_L1_error)
+  __pyx_tuple__10 = PyTuple_Pack(11, __pyx_n_s_self, __pyx_n_s_i, __pyx_n_s_strip, __pyx_n_s_line, __pyx_n_s_name, __pyx_n_s_qualities, __pyx_n_s_sequence, __pyx_n_s_name2, __pyx_n_s_sequence_class, __pyx_n_s_it, __pyx_n_s_second_header); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(0, 86, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_tuple__10);
   __Pyx_GIVEREF(__pyx_tuple__10);
-  __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(1, 0, 11, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_iter, 88, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) __PYX_ERR(0, 88, __pyx_L1_error)
+  __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(1, 0, 11, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_marcel_scm_cutadapt_cutada, __pyx_n_s_iter, 86, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) __PYX_ERR(0, 86, __pyx_L1_error)
   __Pyx_RefNannyFinishContext();
   return 0;
   __pyx_L1_error:;
@@ -3959,7 +4368,7 @@ PyMODINIT_FUNC PyInit__seqio(void)
   #endif
   if (PyObject_SetAttrString(__pyx_m, "Sequence", (PyObject *)&__pyx_type_8cutadapt_6_seqio_Sequence) < 0) __PYX_ERR(0, 8, __pyx_L1_error)
   __pyx_ptype_8cutadapt_6_seqio_Sequence = &__pyx_type_8cutadapt_6_seqio_Sequence;
-  if (PyType_Ready(&__pyx_type_8cutadapt_6_seqio___pyx_scope_struct____iter__) < 0) __PYX_ERR(0, 88, __pyx_L1_error)
+  if (PyType_Ready(&__pyx_type_8cutadapt_6_seqio___pyx_scope_struct____iter__) < 0) __PYX_ERR(0, 86, __pyx_L1_error)
   __pyx_type_8cutadapt_6_seqio___pyx_scope_struct____iter__.tp_print = 0;
   __pyx_ptype_8cutadapt_6_seqio___pyx_scope_struct____iter__ = &__pyx_type_8cutadapt_6_seqio___pyx_scope_struct____iter__;
   /*--- Type import code ---*/
@@ -4012,36 +4421,36 @@ PyMODINIT_FUNC PyInit__seqio(void)
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SequenceReader); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 75, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SequenceReader); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 73, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 75, __pyx_L1_error)
+  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 73, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_GIVEREF(__pyx_t_1);
   PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1);
   __pyx_t_1 = 0;
-  __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 75, __pyx_L1_error)
+  __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 73, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_3 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_2, __pyx_n_s_FastqReader, __pyx_n_s_FastqReader, (PyObject *) NULL, __pyx_n_s_cutadapt__seqio, __pyx_kp_s_Reader_for_FASTQ_files_Does_not); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 75, __pyx_L1_error)
+  __pyx_t_3 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_2, __pyx_n_s_FastqReader, __pyx_n_s_FastqReader, (PyObject *) NULL, __pyx_n_s_cutadapt__seqio, __pyx_kp_s_Reader_for_FASTQ_files_Does_not); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 73, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_3);
 
-  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_1__init__, 0, __pyx_n_s_FastqReader___init, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__9)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 79, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_1__init__, 0, __pyx_n_s_FastqReader___init, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__9)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 77, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
-  if (!__Pyx_CyFunction_InitDefaults(__pyx_t_4, sizeof(__pyx_defaults), 1)) __PYX_ERR(0, 79, __pyx_L1_error)
+  if (!__Pyx_CyFunction_InitDefaults(__pyx_t_4, sizeof(__pyx_defaults), 1)) __PYX_ERR(0, 77, __pyx_L1_error)
   __Pyx_INCREF(((PyObject *)__pyx_ptype_8cutadapt_6_seqio_Sequence));
   __Pyx_CyFunction_Defaults(__pyx_defaults, __pyx_t_4)->__pyx_arg_sequence_class = ((PyObject *)__pyx_ptype_8cutadapt_6_seqio_Sequence);
   __Pyx_GIVEREF(__pyx_ptype_8cutadapt_6_seqio_Sequence);
-  __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_4, __pyx_pf_8cutadapt_6_seqio_11FastqReader_5__defaults__);
-  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_init, __pyx_t_4) < 0) __PYX_ERR(0, 79, __pyx_L1_error)
+  __Pyx_CyFunction_SetDefaultsGetter(__pyx_t_4, __pyx_pf_8cutadapt_6_seqio___defaults__);
+  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_init, __pyx_t_4) < 0) __PYX_ERR(0, 77, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_3__iter__, 0, __pyx_n_s_FastqReader___iter, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__11)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 88, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_CyFunction_NewEx(&__pyx_mdef_8cutadapt_6_seqio_11FastqReader_3__iter__, 0, __pyx_n_s_FastqReader___iter, NULL, __pyx_n_s_cutadapt__seqio, __pyx_d, ((PyObject *)__pyx_codeobj__11)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 86, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
-  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_iter, __pyx_t_4) < 0) __PYX_ERR(0, 88, __pyx_L1_error)
+  if (PyObject_SetItem(__pyx_t_3, __pyx_n_s_iter, __pyx_t_4) < 0) __PYX_ERR(0, 86, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
 
-  __pyx_t_4 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_FastqReader, __pyx_t_2, __pyx_t_3, NULL, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 75, __pyx_L1_error)
+  __pyx_t_4 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_FastqReader, __pyx_t_2, __pyx_t_3, NULL, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 73, __pyx_L1_error)
   __Pyx_GOTREF(__pyx_t_4);
-  if (PyDict_SetItem(__pyx_d, __pyx_n_s_FastqReader, __pyx_t_4) < 0) __PYX_ERR(0, 75, __pyx_L1_error)
+  if (PyDict_SetItem(__pyx_d, __pyx_n_s_FastqReader, __pyx_t_4) < 0) __PYX_ERR(0, 73, __pyx_L1_error)
   __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -4281,7 +4690,7 @@ static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, in
 /* GetModuleGlobalName */
 static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) {
     PyObject *result;
-#if CYTHON_COMPILING_IN_CPYTHON
+#if !CYTHON_AVOID_BORROWED_REFS
     result = PyDict_GetItem(__pyx_d, name);
     if (likely(result)) {
         Py_INCREF(result);
@@ -4296,6 +4705,144 @@ static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) {
     return result;
 }
 
+/* PyCFunctionFastCall */
+  #if CYTHON_FAST_PYCCALL
+static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) {
+    PyCFunctionObject *func = (PyCFunctionObject*)func_obj;
+    PyCFunction meth = PyCFunction_GET_FUNCTION(func);
+    PyObject *self = PyCFunction_GET_SELF(func);
+    assert(PyCFunction_Check(func));
+    assert(METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)));
+    assert(nargs >= 0);
+    assert(nargs == 0 || args != NULL);
+    /* _PyCFunction_FastCallDict() must not be called with an exception set,
+       because it may clear it (directly or indirectly) and so the
+       caller loses its exception */
+    assert(!PyErr_Occurred());
+    return (*((__Pyx_PyCFunctionFast)meth)) (self, args, nargs, NULL);
+}
+#endif  // CYTHON_FAST_PYCCALL
+
+/* PyFunctionFastCall */
+  #if CYTHON_FAST_PYCALL
+#include "frameobject.h"
+static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na,
+                                               PyObject *globals) {
+    PyFrameObject *f;
+    PyThreadState *tstate = PyThreadState_GET();
+    PyObject **fastlocals;
+    Py_ssize_t i;
+    PyObject *result;
+    assert(globals != NULL);
+    /* XXX Perhaps we should create a specialized
+       PyFrame_New() that doesn't take locals, but does
+       take builtins without sanity checking them.
+       */
+    assert(tstate != NULL);
+    f = PyFrame_New(tstate, co, globals, NULL);
+    if (f == NULL) {
+        return NULL;
+    }
+    fastlocals = f->f_localsplus;
+    for (i = 0; i < na; i++) {
+        Py_INCREF(*args);
+        fastlocals[i] = *args++;
+    }
+    result = PyEval_EvalFrameEx(f,0);
+    ++tstate->recursion_depth;
+    Py_DECREF(f);
+    --tstate->recursion_depth;
+    return result;
+}
+#if 1 || PY_VERSION_HEX < 0x030600B1
+static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) {
+    PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
+    PyObject *globals = PyFunction_GET_GLOBALS(func);
+    PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
+    PyObject *closure;
+#if PY_MAJOR_VERSION >= 3
+    PyObject *kwdefs;
+#endif
+    PyObject *kwtuple, **k;
+    PyObject **d;
+    Py_ssize_t nd;
+    Py_ssize_t nk;
+    PyObject *result;
+    assert(kwargs == NULL || PyDict_Check(kwargs));
+    nk = kwargs ? PyDict_Size(kwargs) : 0;
+    if (Py_EnterRecursiveCall((char*)" while calling a Python object")) {
+        return NULL;
+    }
+    if (
+#if PY_MAJOR_VERSION >= 3
+            co->co_kwonlyargcount == 0 &&
+#endif
+            likely(kwargs == NULL || nk == 0) &&
+            co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) {
+        if (argdefs == NULL && co->co_argcount == nargs) {
+            result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals);
+            goto done;
+        }
+        else if (nargs == 0 && argdefs != NULL
+                 && co->co_argcount == Py_SIZE(argdefs)) {
+            /* function called with no arguments, but all parameters have
+               a default value: use default values as arguments .*/
+            args = &PyTuple_GET_ITEM(argdefs, 0);
+            result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals);
+            goto done;
+        }
+    }
+    if (kwargs != NULL) {
+        Py_ssize_t pos, i;
+        kwtuple = PyTuple_New(2 * nk);
+        if (kwtuple == NULL) {
+            result = NULL;
+            goto done;
+        }
+        k = &PyTuple_GET_ITEM(kwtuple, 0);
+        pos = i = 0;
+        while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) {
+            Py_INCREF(k[i]);
+            Py_INCREF(k[i+1]);
+            i += 2;
+        }
+        nk = i / 2;
+    }
+    else {
+        kwtuple = NULL;
+        k = NULL;
+    }
+    closure = PyFunction_GET_CLOSURE(func);
+#if PY_MAJOR_VERSION >= 3
+    kwdefs = PyFunction_GET_KW_DEFAULTS(func);
+#endif
+    if (argdefs != NULL) {
+        d = &PyTuple_GET_ITEM(argdefs, 0);
+        nd = Py_SIZE(argdefs);
+    }
+    else {
+        d = NULL;
+        nd = 0;
+    }
+#if PY_MAJOR_VERSION >= 3
+    result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL,
+                               args, nargs,
+                               k, (int)nk,
+                               d, (int)nd, kwdefs, closure);
+#else
+    result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL,
+                               args, nargs,
+                               k, (int)nk,
+                               d, (int)nd, closure);
+#endif
+    Py_XDECREF(kwtuple);
+done:
+    Py_LeaveRecursiveCall();
+    return result;
+}
+#endif  // CPython < 3.6
+#endif  // CYTHON_FAST_PYCALL
+
 /* PyObjectCall */
   #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) {
@@ -4349,6 +4896,11 @@ static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) {
     return result;
 }
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) {
+#if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(func)) {
+        return __Pyx_PyFunction_FastCall(func, &arg, 1);
+    }
+#endif
 #ifdef __Pyx_CyFunction_USED
     if (likely(PyCFunction_Check(func) || PyObject_TypeCheck(func, __pyx_CyFunctionType))) {
 #else
@@ -4356,6 +4908,10 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec
 #endif
         if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) {
             return __Pyx_PyObject_CallMethO(func, arg);
+#if CYTHON_FAST_PYCCALL
+        } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) {
+            return __Pyx_PyCFunction_FastCall(func, &arg, 1);
+#endif
         }
     }
     return __Pyx__PyObject_CallOneArg(func, arg);
@@ -4372,7 +4928,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec
 #endif
 
 /* PyErrFetchRestore */
-    #if CYTHON_COMPILING_IN_CPYTHON
+    #if CYTHON_FAST_THREAD_STATE
 static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) {
     PyObject *tmp_type, *tmp_value, *tmp_tb;
     tmp_type = tstate->curexc_type;
@@ -4561,6 +5117,11 @@ bad:
 /* PyObjectCallNoArg */
       #if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
+#if CYTHON_FAST_PYCALL
+    if (PyFunction_Check(func)) {
+        return __Pyx_PyFunction_FastCall(func, NULL, 0);
+    }
+#endif
 #ifdef __Pyx_CyFunction_USED
     if (likely(PyCFunction_Check(func) || PyObject_TypeCheck(func, __pyx_CyFunctionType))) {
 #else
@@ -4578,7 +5139,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
         static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject* iterator, PyObject* defval) {
     PyObject* next;
     iternextfunc iternext = Py_TYPE(iterator)->tp_iternext;
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_USE_TYPE_SLOTS
     if (unlikely(!iternext)) {
 #else
     if (unlikely(!iternext) || unlikely(!PyIter_Check(iterator))) {
@@ -4590,7 +5151,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
     next = iternext(iterator);
     if (likely(next))
         return next;
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_USE_TYPE_SLOTS
 #if PY_VERSION_HEX >= 0x02070000
     if (unlikely(iternext == &_PyObject_NextNotImplemented))
         return NULL;
@@ -4623,7 +5184,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i,
                                                               CYTHON_NCP_UNUSED int wraparound,
                                                               CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
     if (wraparound & unlikely(i < 0)) i += PyList_GET_SIZE(o);
     if ((!boundscheck) || likely((0 <= i) & (i < PyList_GET_SIZE(o)))) {
         PyObject *r = PyList_GET_ITEM(o, i);
@@ -4638,7 +5199,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i,
                                                               CYTHON_NCP_UNUSED int wraparound,
                                                               CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
     if (wraparound & unlikely(i < 0)) i += PyTuple_GET_SIZE(o);
     if ((!boundscheck) || likely((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
         PyObject *r = PyTuple_GET_ITEM(o, i);
@@ -4653,7 +5214,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list,
                                                      CYTHON_NCP_UNUSED int wraparound,
                                                      CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS
     if (is_list || PyList_CheckExact(o)) {
         Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o);
         if ((!boundscheck) || (likely((n >= 0) & (n < PyList_GET_SIZE(o))))) {
@@ -4868,7 +5429,7 @@ static int __Pyx_PyBytes_Tailmatch(PyObject* self, PyObject* substr,
         Py_ssize_t i, count = PyTuple_GET_SIZE(substr);
         for (i = 0; i < count; i++) {
             int result;
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
             result = __Pyx_PyBytes_SingleTailmatch(self, PyTuple_GET_ITEM(substr, i),
                                                    start, end, direction);
 #else
@@ -4893,7 +5454,7 @@ static int __Pyx_PyBytes_Tailmatch(PyObject* self, PyObject* substr,
         Py_ssize_t i, count = PyTuple_GET_SIZE(substr);
         for (i = 0; i < count; i++) {
             Py_ssize_t result;
-#if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
             result = PyUnicode_Tailmatch(s, PyTuple_GET_ITEM(substr, i),
                                          start, end, direction);
 #else
@@ -5257,7 +5818,7 @@ __Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) {
     PyObject *res = op->defaults_getter((PyObject *) op);
     if (unlikely(!res))
         return -1;
-    #if CYTHON_COMPILING_IN_CPYTHON
+    #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
     op->defaults_tuple = PyTuple_GET_ITEM(res, 0);
     Py_INCREF(op->defaults_tuple);
     op->defaults_kwdict = PyTuple_GET_ITEM(res, 1);
@@ -5516,11 +6077,9 @@ __Pyx_CyFunction_repr(__pyx_CyFunctionObject *op)
                                PyString_AsString(op->func_qualname), (void *)op);
 #endif
 }
-#if CYTHON_COMPILING_IN_PYPY
-static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) {
+static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) {
     PyCFunctionObject* f = (PyCFunctionObject*)func;
     PyCFunction meth = f->m_ml->ml_meth;
-    PyObject *self = f->m_self;
     Py_ssize_t size;
     switch (f->m_ml->ml_flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) {
     case METH_VARARGS:
@@ -5566,11 +6125,32 @@ static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject
                  f->m_ml->ml_name);
     return NULL;
 }
-#else
-static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) {
-	return PyCFunction_Call(func, arg, kw);
+static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) {
+    return __Pyx_CyFunction_CallMethod(func, ((PyCFunctionObject*)func)->m_self, arg, kw);
+}
+static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) {
+    PyObject *result;
+    __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func;
+    if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) {
+        Py_ssize_t argc;
+        PyObject *new_args;
+        PyObject *self;
+        argc = PyTuple_GET_SIZE(args);
+        new_args = PyTuple_GetSlice(args, 1, argc);
+        if (unlikely(!new_args))
+            return NULL;
+        self = PyTuple_GetItem(args, 0);
+        if (unlikely(!self)) {
+            Py_DECREF(new_args);
+            return NULL;
+        }
+        result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw);
+        Py_DECREF(new_args);
+    } else {
+        result = __Pyx_CyFunction_Call(func, args, kw);
+    }
+    return result;
 }
-#endif
 static PyTypeObject __pyx_CyFunctionType_type = {
     PyVarObject_HEAD_INIT(0, 0)
     "cython_function_or_method",
@@ -5590,7 +6170,7 @@ static PyTypeObject __pyx_CyFunctionType_type = {
     0,
     0,
     0,
-    __Pyx_CyFunction_Call,
+    __Pyx_CyFunction_CallAsMethod,
     0,
     0,
     0,
@@ -5632,9 +6212,6 @@ static PyTypeObject __pyx_CyFunctionType_type = {
 #endif
 };
 static int __pyx_CyFunction_init(void) {
-#if !CYTHON_COMPILING_IN_PYPY
-    __pyx_CyFunctionType_type.tp_call = PyCFunction_Call;
-#endif
     __pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type);
     if (__pyx_CyFunctionType == NULL) {
         return -1;
@@ -5887,7 +6464,7 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
         0                    /*PyObject *locals*/
     );
     if (!py_frame) goto bad;
-    py_frame->f_lineno = py_line;
+    __Pyx_PyFrame_SetLineNumber(py_frame, py_line);
     PyTraceBack_Here(py_frame);
 bad:
     Py_XDECREF(py_code);
@@ -5925,14 +6502,18 @@ bad:
             return PyInt_FromLong((long) value);
         } else if (sizeof(long) <= sizeof(unsigned long)) {
             return PyLong_FromUnsignedLong((unsigned long) value);
+#ifdef HAVE_LONG_LONG
         } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
             return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
+#endif
         }
     } else {
         if (sizeof(long) <= sizeof(long)) {
             return PyInt_FromLong((long) value);
+#ifdef HAVE_LONG_LONG
         } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
             return PyLong_FromLongLong((PY_LONG_LONG) value);
+#endif
         }
     }
     {
@@ -6011,8 +6592,10 @@ bad:
 #endif
             if (sizeof(int) <= sizeof(unsigned long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x))
+#endif
             }
         } else {
 #if CYTHON_USE_PYLONG_INTERNALS
@@ -6079,8 +6662,10 @@ bad:
 #endif
             if (sizeof(int) <= sizeof(long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x))
+#endif
             }
         }
         {
@@ -6196,8 +6781,10 @@ raise_neg_overflow:
 #endif
             if (sizeof(long) <= sizeof(unsigned long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x))
+#endif
             }
         } else {
 #if CYTHON_USE_PYLONG_INTERNALS
@@ -6264,8 +6851,10 @@ raise_neg_overflow:
 #endif
             if (sizeof(long) <= sizeof(long)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x))
+#ifdef HAVE_LONG_LONG
             } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
                 __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x))
+#endif
             }
         }
         {
@@ -6314,7 +6903,7 @@ raise_neg_overflow:
 }
 
 /* SwapException */
-              #if CYTHON_COMPILING_IN_CPYTHON
+              #if CYTHON_FAST_THREAD_STATE
 static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
     PyObject *tmp_type, *tmp_value, *tmp_tb;
     tmp_type = tstate->exc_type;
@@ -6342,15 +6931,29 @@ static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value,
               static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) {
     PyObject *method, *result = NULL;
     method = __Pyx_PyObject_GetAttrStr(obj, method_name);
-    if (unlikely(!method)) goto bad;
-#if CYTHON_COMPILING_IN_CPYTHON
+    if (unlikely(!method)) goto done;
+#if CYTHON_UNPACK_METHODS
     if (likely(PyMethod_Check(method))) {
         PyObject *self = PyMethod_GET_SELF(method);
         if (likely(self)) {
             PyObject *args;
             PyObject *function = PyMethod_GET_FUNCTION(method);
+            #if CYTHON_FAST_PYCALL
+            if (PyFunction_Check(function)) {
+                PyObject *args[2] = {self, arg};
+                result = __Pyx_PyFunction_FastCall(function, args, 2);
+                goto done;
+            }
+            #endif
+            #if CYTHON_FAST_PYCCALL
+            if (__Pyx_PyFastCFunction_Check(function)) {
+                PyObject *args[2] = {self, arg};
+                result = __Pyx_PyCFunction_FastCall(function, args, 2);
+                goto done;
+            }
+            #endif
             args = PyTuple_New(2);
-            if (unlikely(!args)) goto bad;
+            if (unlikely(!args)) goto done;
             Py_INCREF(self);
             PyTuple_SET_ITEM(args, 0, self);
             Py_INCREF(arg);
@@ -6365,7 +6968,7 @@ static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value,
     }
 #endif
     result = __Pyx_PyObject_CallOneArg(method, arg);
-bad:
+done:
     Py_XDECREF(method);
     return result;
 }
@@ -6392,41 +6995,38 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) {
         return 0;
     }
     if (likely(et == PyExc_StopIteration)) {
+        if (!ev) {
+            Py_INCREF(Py_None);
+            value = Py_None;
+        }
 #if PY_VERSION_HEX >= 0x030300A0
-        if (ev && Py_TYPE(ev) == (PyTypeObject*)PyExc_StopIteration) {
+        else if (Py_TYPE(ev) == (PyTypeObject*)PyExc_StopIteration) {
             value = ((PyStopIterationObject *)ev)->value;
             Py_INCREF(value);
             Py_DECREF(ev);
-            Py_XDECREF(tb);
-            Py_DECREF(et);
-            *pvalue = value;
-            return 0;
         }
 #endif
-        if (!ev || !PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) {
-            if (!ev) {
-                Py_INCREF(Py_None);
-                ev = Py_None;
-            } else if (PyTuple_Check(ev)) {
-                if (PyTuple_GET_SIZE(ev) >= 1) {
-                    PyObject *value;
-#if CYTHON_COMPILING_IN_CPYTHON
-                    value = PySequence_ITEM(ev, 0);
+        else if (unlikely(PyTuple_Check(ev))) {
+            if (PyTuple_GET_SIZE(ev) >= 1) {
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+                value = PyTuple_GET_ITEM(ev, 0);
+                Py_INCREF(value);
 #else
-                    value = PyTuple_GET_ITEM(ev, 0);
-                    Py_INCREF(value);
+                value = PySequence_ITEM(ev, 0);
 #endif
-                    Py_DECREF(ev);
-                    ev = value;
-                } else {
-                    Py_INCREF(Py_None);
-                    Py_DECREF(ev);
-                    ev = Py_None;
-                }
+            } else {
+                Py_INCREF(Py_None);
+                value = Py_None;
             }
+            Py_DECREF(ev);
+        }
+        else if (!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) {
+            value = ev;
+        }
+        if (likely(value)) {
             Py_XDECREF(tb);
             Py_DECREF(et);
-            *pvalue = ev;
+            *pvalue = value;
             return 0;
         }
     } else if (!PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) {
@@ -6503,7 +7103,7 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
     }
     __Pyx_PyThreadState_assign
     if (value) {
-#if CYTHON_COMPILING_IN_PYPY
+#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
 #else
         if (self->exc_traceback) {
             PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback;
@@ -6524,7 +7124,7 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
     if (retval) {
         __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value,
                             &self->exc_traceback);
-#if CYTHON_COMPILING_IN_PYPY
+#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
 #else
         if (self->exc_traceback) {
             PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback;
@@ -6634,7 +7234,12 @@ static PyObject *__Pyx_Generator_Next(PyObject *self) {
     if (yf) {
         PyObject *ret;
         gen->is_running = 1;
-        ret = Py_TYPE(yf)->tp_iternext(yf);
+        #ifdef __Pyx_Generator_USED
+        if (__Pyx_Generator_CheckExact(yf)) {
+            ret = __Pyx_Generator_Next(yf);
+        } else
+        #endif
+            ret = Py_TYPE(yf)->tp_iternext(yf);
         gen->is_running = 0;
         if (likely(ret)) {
             return ret;
@@ -6823,8 +7428,10 @@ static void __Pyx_Coroutine_del(PyObject *self) {
 static PyObject *
 __Pyx_Coroutine_get_name(__pyx_CoroutineObject *self)
 {
-    Py_INCREF(self->gi_name);
-    return self->gi_name;
+    PyObject *name = self->gi_name;
+    if (unlikely(!name)) name = Py_None;
+    Py_INCREF(name);
+    return name;
 }
 static int
 __Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value)
@@ -6848,8 +7455,10 @@ __Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value)
 static PyObject *
 __Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self)
 {
-    Py_INCREF(self->gi_qualname);
-    return self->gi_qualname;
+    PyObject *name = self->gi_qualname;
+    if (unlikely(!name)) name = Py_None;
+    Py_INCREF(name);
+    return name;
 }
 static int
 __Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value)
@@ -6870,8 +7479,9 @@ __Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value)
     Py_XDECREF(tmp);
     return 0;
 }
-static __pyx_CoroutineObject *__Pyx__Coroutine_New(PyTypeObject* type, __pyx_coroutine_body_t body,
-                                                   PyObject *closure, PyObject *name, PyObject *qualname) {
+static __pyx_CoroutineObject *__Pyx__Coroutine_New(
+            PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *closure,
+            PyObject *name, PyObject *qualname, PyObject *module_name) {
     __pyx_CoroutineObject *gen = PyObject_GC_New(__pyx_CoroutineObject, type);
     if (gen == NULL)
         return NULL;
@@ -6890,6 +7500,8 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_New(PyTypeObject* type, __pyx_cor
     gen->gi_qualname = qualname;
     Py_XINCREF(name);
     gen->gi_name = name;
+    Py_XINCREF(module_name);
+    gen->gi_modulename = module_name;
     PyObject_GC_Track(gen);
     return gen;
 }
@@ -7195,7 +7807,9 @@ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
    else return PyObject_IsTrue(x);
 }
 static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
+#if CYTHON_USE_TYPE_SLOTS
   PyNumberMethods *m;
+#endif
   const char *name = NULL;
   PyObject *res = NULL;
 #if PY_MAJOR_VERSION < 3
@@ -7204,8 +7818,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
   if (PyLong_Check(x))
 #endif
     return __Pyx_NewRef(x);
+#if CYTHON_USE_TYPE_SLOTS
   m = Py_TYPE(x)->tp_as_number;
-#if PY_MAJOR_VERSION < 3
+  #if PY_MAJOR_VERSION < 3
   if (m && m->nb_int) {
     name = "int";
     res = PyNumber_Int(x);
@@ -7214,11 +7829,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
     name = "long";
     res = PyNumber_Long(x);
   }
-#else
+  #else
   if (m && m->nb_int) {
     name = "int";
     res = PyNumber_Long(x);
   }
+  #endif
+#else
+  res = PyNumber_Int(x);
 #endif
   if (res) {
 #if PY_MAJOR_VERSION < 3
diff --git a/cutadapt/_seqio.pyx b/cutadapt/_seqio.pyx
index d038485..f27a359 100644
--- a/cutadapt/_seqio.pyx
+++ b/cutadapt/_seqio.pyx
@@ -20,17 +20,15 @@ cdef class Sequence(object):
 		public str qualities
 		public bint second_header
 		public object match
-		public object match_info
 
-	def __init__(self, str name, str sequence, str qualities=None, bint second_header=False, match=None,
-				 match_info=None):
+	def __init__(self, str name, str sequence, str qualities=None, bint second_header=False,
+	        match=None):
 		"""Set qualities to None if there are no quality values"""
 		self.name = name
 		self.sequence = sequence
 		self.qualities = qualities
 		self.second_header = second_header
 		self.match = match
-		self.match_info = match_info
 		if qualities is not None and len(qualities) != len(sequence):
 			rname = _shorten(name)
 			raise FormatError("In read named {0!r}: length of quality sequence ({1}) and length "
@@ -44,8 +42,7 @@ cdef class Sequence(object):
 			self.sequence[key],
 			self.qualities[key] if self.qualities is not None else None,
 			self.second_header,
-			self.match,
-			self.match_info)
+			self.match)
 
 	def __repr__(self):
 		qstr = ''
@@ -69,7 +66,8 @@ cdef class Sequence(object):
 			raise NotImplementedError()
 
 	def __reduce__(self):
-		return (Sequence, (self.name, self.sequence, self.qualities, self.second_header))
+		return (Sequence, (self.name, self.sequence, self.qualities, self.second_header,
+		    self.match))
 
 
 class FastqReader(SequenceReader):
diff --git a/cutadapt/_version.py b/cutadapt/_version.py
index cd06da1..22c1dd2 100644
--- a/cutadapt/_version.py
+++ b/cutadapt/_version.py
@@ -11,8 +11,8 @@ version_json = '''
 {
  "dirty": false,
  "error": null,
- "full-revisionid": "98f0e2f2f658646a5315f9f54ecc6cc64a5fd660",
- "version": "1.12"
+ "full-revisionid": "8fcb956f115c6c1f404cd2f2da64bcb443ec0c3e",
+ "version": "1.13"
 }
 '''  # END VERSION_JSON
 
diff --git a/cutadapt/adapters.py b/cutadapt/adapters.py
index 8a8fb36..47217ff 100644
--- a/cutadapt/adapters.py
+++ b/cutadapt/adapters.py
@@ -1,6 +1,9 @@
 # coding: utf-8
 """
-Adapters
+Adapter finding and trimming classes
+
+The ...Adapter classes are responsible for finding adapters.
+The ...Match classes trim the reads.
 """
 from __future__ import print_function, division, absolute_import
 import sys
@@ -83,34 +86,65 @@ class AdapterParser(object):
 		"""
 		if name is None:
 			name, spec = self._extract_name(spec)
-		sequence = spec
 		types = dict(back=BACK, front=FRONT, anywhere=ANYWHERE)
 		if cmdline_type not in types:
 			raise ValueError('cmdline_type cannot be {0!r}'.format(cmdline_type))
 		where = types[cmdline_type]
-		if where == FRONT and spec.startswith('^'):  # -g ^ADAPTER
-			sequence, where = spec[1:], PREFIX
-		elif where == BACK:
-			sequence1, middle, sequence2 = spec.partition('...')
+
+		front_anchored, back_anchored = False, False
+		if spec.startswith('^'):
+			spec = spec[1:]
+			front_anchored = True
+		if spec.endswith('$'):
+			spec = spec[:-1]
+			back_anchored = True
+
+		sequence1, middle, sequence2 = spec.partition('...')
+		if where == ANYWHERE:
+			if front_anchored or back_anchored:
+				raise ValueError("'anywhere' (-b) adapters may not be anchored")
 			if middle == '...':
-				if not sequence1:  # -a ...ADAPTER
-					sequence = sequence1[3:]
-				elif not sequence2:  # -a ADAPTER...
-					sequence, where = spec[:-3], PREFIX
-				else:  # -a ADAPTER1...ADAPTER2
-					if self.colorspace:
-						raise NotImplementedError('Using linked adapters in colorspace is not supported')
-					if sequence1.startswith('^') or sequence2.endswith('$'):
-						raise NotImplementedError('Using "$" or "^" when '
-							'specifying a linked adapter is not supported')
-					return LinkedAdapter(sequence1, sequence2, name=name,
-						**self.constructor_args)
-			elif spec.endswith('$'):   # -a ADAPTER$
-				sequence, where = spec[:-1], SUFFIX
-		if not sequence:
-			raise ValueError("The adapter sequence is empty.")
-
-		return self.adapter_class(sequence, where, name=name, **self.constructor_args)
+				raise ValueError("'anywhere' (-b) adapters may not be linked")
+			return self.adapter_class(sequence=spec, where=where, name=name, **self.constructor_args)
+
+		assert where == FRONT or where == BACK
+		if middle == '...':
+			if not sequence1:
+				if where == BACK:  # -a ...ADAPTER
+					spec = sequence2
+				else:  # -g ...ADAPTER
+					raise ValueError('Invalid adapter specification')
+			elif not sequence2:
+				if where == BACK:  # -a ADAPTER...
+					spec = sequence1
+					where = FRONT
+					front_anchored = True
+				else:  # -g ADAPTER...
+					spec = sequence1
+			else:
+				# linked adapter
+				if self.colorspace:
+					raise NotImplementedError(
+						'Using linked adapters in colorspace is not supported')
+				# automatically anchor 5' adapter if -a is used
+				if where == BACK:
+					front_anchored = True
+
+				return LinkedAdapter(sequence1, sequence2, name=name,
+					front_anchored=front_anchored, back_anchored=back_anchored,
+					**self.constructor_args)
+		if front_anchored and back_anchored:
+			raise ValueError('Cannot anchor both ends at the same time')
+		if front_anchored:
+			if where == BACK:
+				raise ValueError("Cannot anchor 3' adapter at 5' end")
+			where = PREFIX
+		elif back_anchored:
+			if where == FRONT:
+				raise ValueError("Cannot anchor 5' adapter at 3' end")
+			where = SUFFIX
+
+		return self.adapter_class(sequence=spec, where=where, name=name, **self.constructor_args)
 
 	def parse(self, spec, cmdline_type='back'):
 		"""
@@ -160,19 +194,30 @@ class AdapterParser(object):
 
 class Match(object):
 	"""
+	Representation of a single adapter matched to a single read.
+
 	TODO creating instances of this class is relatively slow and responsible for quite some runtime.
 	"""
-	__slots__ = ['astart', 'astop', 'rstart', 'rstop', 'matches', 'errors', 'front', 'adapter', 'read', 'length']
-	def __init__(self, astart, astop, rstart, rstop, matches, errors, front, adapter, read):
+	__slots__ = ['astart', 'astop', 'rstart', 'rstop', 'matches', 'errors', 'remove_before',
+		'adapter', 'read', 'length', '_trimmed_read', 'adjacent_base']
+
+	def __init__(self, astart, astop, rstart, rstop, matches, errors, remove_before, adapter, read):
+		"""
+		remove_before -- True: remove bases before adapter. False: remove after
+		"""
 		self.astart = astart
 		self.astop = astop
 		self.rstart = rstart
 		self.rstop = rstop
 		self.matches = matches
 		self.errors = errors
-		self.front = self._guess_is_front() if front is None else front
 		self.adapter = adapter
 		self.read = read
+		if remove_before:
+			self._trim_front()
+		else:
+			self._trim_back()
+		self.remove_before = remove_before
 		# Number of aligned characters in the adapter. If there are
 		# indels, this may be different from the number of characters
 		# in the read.
@@ -181,19 +226,10 @@ class Match(object):
 		assert self.errors / self.length <= self.adapter.max_error_rate
 		assert self.length - self.errors > 0
 
-	def __str__(self):
+	def __repr__(self):
 		return 'Match(astart={0}, astop={1}, rstart={2}, rstop={3}, matches={4}, errors={5})'.format(
 			self.astart, self.astop, self.rstart, self.rstop, self.matches, self.errors)
 
-	def _guess_is_front(self):
-		"""
-		Return whether this is guessed to be a front adapter.
-
-		The match is assumed to be a front adapter when the first base of
-		the read is involved in the alignment to the adapter.
-		"""
-		return self.rstart == 0
-
 	def wildcards(self, wildcard_char='N'):
 		"""
 		Return a string that contains, for each wildcard character,
@@ -203,8 +239,9 @@ class Match(object):
 		If there are indels, this is not reliable as the full alignment
 		is not available.
 		"""
-		wildcards = [ self.read.sequence[self.rstart + i:self.rstart + i + 1] for i in range(self.length)
-			if self.adapter.sequence[self.astart + i] == wildcard_char and self.rstart + i < len(self.read.sequence) ]
+		wildcards = [ self.read.sequence[self.rstart + i] for i in range(self.length)
+			if self.adapter.sequence[self.astart + i] == wildcard_char and
+				self.rstart + i < len(self.read.sequence) ]
 		return ''.join(wildcards)
 
 	def rest(self):
@@ -214,11 +251,11 @@ class Match(object):
 		return the part after the match if this is not a 'front' adapter (3').
 		This can be an empty string.
 		"""
-		if self.front:
+		if self.remove_before:
 			return self.read.sequence[:self.rstart]
 		else:
 			return self.read.sequence[self.rstop:]
-	
+
 	def get_info_record(self):
 		seq = self.read.sequence
 		qualities = self.read.qualities
@@ -239,10 +276,68 @@ class Match(object):
 				qualities[self.rstop:]
 			)
 		else:
-			info += ('','','')
-		
+			info += ('', '', '')
+
 		return info
 
+	def trimmed(self):
+		return self._trimmed_read
+
+	def _trim_front(self):
+		"""Compute the trimmed read, assuming it’s a 'front' adapter"""
+		self._trimmed_read = self.read[self.rstop:]
+		self.adjacent_base = ''
+
+	def _trim_back(self):
+		"""Compute the trimmed read, assuming it’s a 'back' adapter"""
+		adjacent_base = self.read.sequence[self.rstart-1:self.rstart]
+		if adjacent_base not in 'ACGT':
+			adjacent_base = ''
+		self.adjacent_base = adjacent_base
+		self._trimmed_read = self.read[:self.rstart]
+
+	def update_statistics(self, statistics):
+		"""Update AdapterStatistics in place"""
+		if self.remove_before:
+			statistics.errors_front[self.rstop][self.errors] += 1
+		else:
+			statistics.errors_back[len(self.read) - len(self._trimmed_read)][self.errors] += 1
+			statistics.adjacent_bases[self.adjacent_base] += 1
+
+
+class ColorspaceMatch(Match):
+	adjacent_base = ''
+
+	def _trim_front(self):
+		"""Return a trimmed read"""
+		read = self.read
+		# to remove a front adapter, we need to re-encode the first color following the adapter match
+		color_after_adapter = read.sequence[self.rstop:self.rstop + 1]
+		if not color_after_adapter:
+			# the read is empty
+			new_read = read[self.rstop:]
+		else:
+			base_after_adapter = colorspace.DECODE[self.adapter.nucleotide_sequence[-1:] + color_after_adapter]
+			new_first_color = colorspace.ENCODE[read.primer + base_after_adapter]
+			new_read = read[:]
+			new_read.sequence = new_first_color + read.sequence[(self.rstop + 1):]
+			new_read.qualities = read.qualities[self.rstop:] if read.qualities else None
+		self._trimmed_read = new_read
+
+	def _trim_back(self):
+		"""Return a trimmed read"""
+		# trim one more color if long enough
+		adjusted_rstart = max(self.rstart - 1, 0)
+		self._trimmed_read = self.read[:adjusted_rstart]
+
+	def update_statistics(self, statistics):
+		"""Update AdapterStatistics in place"""
+		if self.remove_before:
+			statistics.errors_front[self.rstop][self.errors] += 1
+		else:
+			statistics.errors_back[len(self.read) - len(self._trimmed_read)][self.errors] += 1
+
+
 def _generate_adapter_name(_start=[1]):
 	name = str(_start[0])
 	_start[0] += 1
@@ -251,9 +346,8 @@ def _generate_adapter_name(_start=[1]):
 
 class Adapter(object):
 	"""
-	An adapter knows how to match itself to a read.
-	In particular, it knows where it should be within the read and how to interpret
-	wildcard characters.
+	This class can find a single adapter characterized by sequence, error rate,
+	type etc. within reads.
 
 	where --  One of the BACK, FRONT, PREFIX, SUFFIX or ANYWHERE constants.
 		This influences where the adapter is allowed to appear within in the
@@ -277,37 +371,29 @@ class Adapter(object):
 	name -- optional name of the adapter. If not provided, the name is set to a
 		unique number.
 	"""
+
 	def __init__(self, sequence, where, max_error_rate=0.1, min_overlap=3,
 			read_wildcards=False, adapter_wildcards=True, name=None, indels=True):
 		self.debug = False
 		self.name = _generate_adapter_name() if name is None else name
-		self.sequence = parse_braces(sequence.upper().replace('U', 'T'))
-		assert len(self.sequence) > 0
+		self.sequence = parse_braces(sequence.upper().replace('U', 'T'))  # TODO move away
+		if not self.sequence:
+			raise ValueError('Sequence is empty')
 		self.where = where
 		self.max_error_rate = max_error_rate
 		self.min_overlap = min(min_overlap, len(self.sequence))
 		self.indels = indels
+		iupac = frozenset('XACGTURYSWKMBDHVN')
+		if adapter_wildcards and not set(self.sequence) <= iupac:
+			for c in self.sequence:
+				if c not in iupac:
+					raise ValueError('Character {!r} in adapter sequence {!r} is '
+						'not a valid IUPAC code. Use only characters '
+						'XACGTURYSWKMBDHVN.'.format(c, self.sequence))
+		# Optimization: Use non-wildcard matching if only ACGT is used
 		self.adapter_wildcards = adapter_wildcards and not set(self.sequence) <= set('ACGT')
 		self.read_wildcards = read_wildcards
-		# redirect trimmed() to appropriate function depending on adapter type
-		trimmers = {
-			FRONT: self._trimmed_front,
-			PREFIX: self._trimmed_front,
-			BACK: self._trimmed_back,
-			SUFFIX: self._trimmed_back,
-			ANYWHERE: self._trimmed_anywhere
-		}
-		self.trimmed = trimmers[where]
-		if where == ANYWHERE:
-			self._front_flag = None  # means: guess
-		else:
-			self._front_flag = where not in (BACK, SUFFIX)
-		# statistics about length of removed sequences
-		self.lengths_front = defaultdict(int)
-		self.lengths_back = defaultdict(int)
-		self.errors_front = defaultdict(lambda: defaultdict(int))
-		self.errors_back = defaultdict(lambda: defaultdict(int))
-		self.adjacent_bases = { 'A': 0, 'C': 0, 'G': 0, 'T': 0, '': 0 }
+		self.remove_before = where not in (BACK, SUFFIX)
 
 		self.aligner = align.Aligner(self.sequence, self.max_error_rate,
 			flags=self.where, wildcard_ref=self.adapter_wildcards, wildcard_query=self.read_wildcards)
@@ -319,7 +405,7 @@ class Adapter(object):
 			self.aligner.indel_cost = 100000
 
 	def __repr__(self):
-		return '<Adapter(name="{name}", sequence="{sequence}", where={where}, '\
+		return '<Adapter(name={name!r}, sequence={sequence!r}, where={where}, '\
 			'max_error_rate={max_error_rate}, min_overlap={min_overlap}, '\
 			'read_wildcards={read_wildcards}, '\
 			'adapter_wildcards={adapter_wildcards}, '\
@@ -333,15 +419,16 @@ class Adapter(object):
 		self.debug = True
 		self.aligner.enable_debug()
 
-	def match_to(self, read):
+	def match_to(self, read, match_class=Match):
 		"""
 		Attempt to match this adapter to the given read.
 
-		Return an Match instance if a match was found;
+		Return a Match instance if a match was found;
 		return None if no match was found given the matching criteria (minimum
 		overlap length, maximum error rate).
 		"""
-		read_seq = read.sequence.upper()
+		read_seq = read.sequence.upper()  # temporary copy
+		remove_before = self.remove_before
 		pos = -1
 		# try to find an exact match first unless wildcards are allowed
 		if not self.adapter_wildcards:
@@ -352,9 +439,12 @@ class Adapter(object):
 			else:
 				pos = read_seq.find(self.sequence)
 		if pos >= 0:
-			match = Match(
+			if self.where == ANYWHERE:
+				# guess: if alignment starts at pos 0, it’s a 5' adapter
+				remove_before = pos == 0
+			match = match_class(
 				0, len(self.sequence), pos, pos + len(self.sequence),
-				len(self.sequence), 0, self._front_flag, self, read)
+				len(self.sequence), 0, remove_before, self, read)
 		else:
 			# try approximate matching
 			if not self.indels and self.where in (PREFIX, SUFFIX):
@@ -366,7 +456,7 @@ class Adapter(object):
 						wildcard_ref=self.adapter_wildcards, wildcard_query=self.read_wildcards)
 				astart, astop, rstart, rstop, matches, errors = alignment
 				if astop - astart >= self.min_overlap and errors / (astop - astart) <= self.max_error_rate:
-					match = Match(*(alignment + (self._front_flag, self, read)))
+					match = match_class(*(alignment + (remove_before, self, read)))
 				else:
 					match = None
 			else:
@@ -377,7 +467,10 @@ class Adapter(object):
 					match = None
 				else:
 					astart, astop, rstart, rstop, matches, errors = alignment
-					match = Match(astart, astop, rstart, rstop, matches, errors, self._front_flag, self, read)
+					if self.where == ANYWHERE:
+						# guess: if alignment starts at pos 0, it’s a 5' adapter
+						remove_before = rstart == 0
+					match = match_class(astart, astop, rstart, rstop, matches, errors, remove_before, self, read)
 
 		if match is None:
 			return None
@@ -385,37 +478,48 @@ class Adapter(object):
 		assert match.length >= self.min_overlap
 		return match
 
-	def _trimmed_anywhere(self, match):
-		"""Return a trimmed read"""
-		if match.front:
-			return self._trimmed_front(match)
-		else:
-			return self._trimmed_back(match)
-
-	def _trimmed_front(self, match):
-		"""Return a trimmed read"""
-		# TODO move away
-		self.lengths_front[match.rstop] += 1
-		self.errors_front[match.rstop][match.errors] += 1
-		return match.read[match.rstop:]
-
-	def _trimmed_back(self, match):
-		"""Return a trimmed read without the 3' (back) adapter"""
-		# TODO move away
-		self.lengths_back[len(match.read) - match.rstart] += 1
-		self.errors_back[len(match.read) - match.rstart][match.errors] += 1
-		adjacent_base = match.read.sequence[match.rstart-1:match.rstart]
-		if adjacent_base not in 'ACGT':
-			adjacent_base = ''
-		self.adjacent_bases[adjacent_base] += 1
-		return match.read[:match.rstart]
-
 	def __len__(self):
 		return len(self.sequence)
 
+	def random_match_probabilities(self, gc_content):
+		"""
+		Estimate probabilities that this adapter matches a
+		random sequence. Indels are not taken into account.
+
+		Returns a list p, where p[i] is the probability that
+		i bases of this adapter match a random sequence with
+		GC content gc_content.
+		"""
+		if self.remove_before:
+			seq = self.sequence[::-1]
+		else:
+			seq = self.sequence
+		allowed_bases = 'CGRYSKMBDHVN' if self.adapter_wildcards else 'GC'
+		p = 1
+		probabilities = [p]
+		for i, c in enumerate(seq):
+			if c in allowed_bases:
+				p *= gc_content / 2.
+			else:
+				p *= (1 - gc_content) / 2
+			probabilities.append(p)
+		return probabilities
+
 
 class ColorspaceAdapter(Adapter):
+	"""
+	An Adapter, but in color space. It does not support all adapter types
+	(see the 'where' parameter).
+	"""
+
 	def __init__(self, *args, **kwargs):
+		"""
+		sequence -- the adapter sequence as a str, can be given in nucleotide space or in color space
+		where -- PREFIX, FRONT, BACK
+		"""
+		if kwargs.get('adapter_wildcards', False):
+			raise ValueError('Wildcards not supported for colorspace adapters')
+		kwargs['adapter_wildcards'] = False
 		super(ColorspaceAdapter, self).__init__(*args, **kwargs)
 		has_nucleotide_seq = False
 		if set(self.sequence) <= set('ACGT'):
@@ -427,19 +531,26 @@ class ColorspaceAdapter(Adapter):
 			raise ValueError("A 5' colorspace adapter needs to be given in nucleotide space")
 		self.aligner.reference = self.sequence
 
-	def match_to(self, read):
-		"""Return Match instance"""
+	def __repr__(self):
+		return '<ColorspaceAdapter(sequence={0!r}, where={1})>'.format(self.sequence, self.where)
+
+	def match_to(self, read, match_class=ColorspaceMatch):
+		"""
+		Match the adapter to the given read
+
+		Return a ColorspaceMatch instance or None if the adapter was not found
+		"""
 		if self.where != PREFIX:
-			return super(ColorspaceAdapter, self).match_to(read)
+			return super(ColorspaceAdapter, self).match_to(read, match_class=match_class)
 		# create artificial adapter that includes a first color that encodes the
 		# transition from primer base into adapter
 		asequence = colorspace.ENCODE[read.primer + self.nucleotide_sequence[0:1]] + self.sequence
 
 		pos = 0 if read.sequence.startswith(asequence) else -1
 		if pos >= 0:
-			match = Match(
+			match = ColorspaceMatch(
 				0, len(asequence), pos, pos + len(asequence),
-				len(asequence), 0, self._front_flag, self, read)
+				len(asequence), 0, self.remove_before, self, read)
 		else:
 			# try approximate matching
 			self.aligner.reference = asequence
@@ -447,7 +558,7 @@ class ColorspaceAdapter(Adapter):
 			if self.debug:
 				print(self.aligner.dpmatrix)  # pragma: no cover
 			if alignment is not None:
-				match = Match(*(alignment + (self._front_flag, self, read)))
+				match = ColorspaceMatch(*(alignment + (self.remove_before, self, read)))
 			else:
 				match = None
 
@@ -457,47 +568,52 @@ class ColorspaceAdapter(Adapter):
 		assert match.length >= self.min_overlap
 		return match
 
-	def _trimmed_front(self, match):
-		"""Return a trimmed read"""
-		read = match.read
-		self.lengths_front[match.rstop] += 1
-		self.errors_front[match.rstop][match.errors] += 1
-		# to remove a front adapter, we need to re-encode the first color following the adapter match
-		color_after_adapter = read.sequence[match.rstop:match.rstop + 1]
-		if not color_after_adapter:
-			# the read is empty
-			return read[match.rstop:]
-		base_after_adapter = colorspace.DECODE[self.nucleotide_sequence[-1:] + color_after_adapter]
-		new_first_color = colorspace.ENCODE[read.primer + base_after_adapter]
-		new_read = read[:]
-		new_read.sequence = new_first_color + read.sequence[(match.rstop + 1):]
-		new_read.qualities = read.qualities[match.rstop:] if read.qualities else None
-		return new_read
-
-	def _trimmed_back(self, match):
-		"""Return a trimmed read"""
-		# trim one more color if long enough
-		adjusted_rstart = max(match.rstart - 1, 0)
-		self.lengths_back[len(match.read) - adjusted_rstart] += 1
-		self.errors_back[len(match.read) - adjusted_rstart][match.errors] += 1
-		return match.read[:adjusted_rstart]
-
-	def __repr__(self):
-		return '<ColorspaceAdapter(sequence={0!r}, where={1})>'.format(self.sequence, self.where)
-
 
 class LinkedMatch(object):
 	"""
-	Represent a match of a LinkedAdapter.
-
-	TODO
-	It shouldn’t be necessary to have both a Match and a LinkedMatch class.
+	Represent a match of a LinkedAdapter
 	"""
 	def __init__(self, front_match, back_match, adapter):
+		"""
+		One of front_match and back_match must be not None!
+		"""
 		self.front_match = front_match
 		self.back_match = back_match
 		self.adapter = adapter
-		assert front_match is not None
+		assert not adapter.front_anchored or front_match is not None
+		assert not adapter.back_anchored or back_match is not None
+
+	def __repr__(self):
+		return '<LinkedMatch(front_match={0!r}, back_match={1}, adapter={2})>'.format(
+			self.front_match, self.back_match, self.adapter)
+
+	@property
+	def matches(self):
+		"""Number of matching bases"""
+		m = getattr(self.front_match, 'matches', [])
+		if self.back_match is not None:
+			m += self.back_match.matches
+		return m
+
+	def trimmed(self):
+		if self.back_match:
+			# back match is relative to front match, so even if a front match exists,
+			# this is correct
+			return self.back_match.trimmed()
+		else:
+			assert self.front_match
+			return self.front_match.trimmed()
+
+	@property
+	def adjacent_base(self):
+		return self.back_match.adjacent_base
+
+	def update_statistics(self, statistics):
+		"""Update AdapterStatistics in place"""
+		if self.front_match:
+			statistics.errors_front[self.front_match.rstop][self.front_match.errors] += 1
+		if self.back_match:
+			statistics.errors_back[len(self.back_match.read) - self.back_match.rstop][self.back_match.errors] += 1
 
 
 class LinkedAdapter(object):
@@ -508,7 +624,6 @@ class LinkedAdapter(object):
 		"""
 		kwargs are passed on to individual Adapter constructors
 		"""
-		assert front_anchored and not back_anchored
 		where1 = PREFIX if front_anchored else FRONT
 		where2 = SUFFIX if back_anchored else BACK
 		self.front_anchored = front_anchored
@@ -526,44 +641,17 @@ class LinkedAdapter(object):
 
 	def match_to(self, read):
 		"""
-		Match the linked adapters against the given read. If the 'front' adapter
-		is not found, the 'back' adapter is not searched for.
+		Match the linked adapters against the given read. Any anchored adapters are
+		required to exist for a successful match.
 		"""
 		front_match = self.front_adapter.match_to(read)
-		if front_match is None:
+		if self.front_anchored and front_match is None:
 			return None
-		# TODO use match.trimmed() instead as soon as that does not update
-		# statistics anymore
-		read = read[front_match.rstop:]
+
+		if front_match is not None:
+			# TODO statistics
+			read = front_match.trimmed()
 		back_match = self.back_adapter.match_to(read)
+		if back_match is None and (self.back_anchored or front_match is None):
+			return None
 		return LinkedMatch(front_match, back_match, self)
-
-	def trimmed(self, match):
-		front_trimmed = self.front_adapter.trimmed(match.front_match)
-		if match.back_match:
-			return self.back_adapter.trimmed(match.back_match)
-		else:
-			return front_trimmed
-
-	# Lots of forwarders (needed for the report). I’m sure this can be done
-	# in a better way.
-
-	@property
-	def lengths_front(self):
-		return self.front_adapter.lengths_front
-
-	@property
-	def lengths_back(self):
-		return self.back_adapter.lengths_back
-
-	@property
-	def errors_front(self):
-		return self.front_adapter.errors_front
-
-	@property
-	def errors_back(self):
-		return self.back_adapter.errors_back
-
-	@property
-	def adjacent_bases(self):
-		return self.back_adapter.adjacent_bases
diff --git a/cutadapt/filters.py b/cutadapt/filters.py
index 6bf79c3..1fd0428 100644
--- a/cutadapt/filters.py
+++ b/cutadapt/filters.py
@@ -15,7 +15,6 @@ The read is then assumed to have been "consumed", that is, either written
 somewhere or filtered (should be discarded).
 """
 from __future__ import print_function, division, absolute_import
-from xopen import xopen
 from . import seqio
 
 # Constants used when returning from a Filter’s __call__ method to improve
@@ -31,7 +30,6 @@ class NoFilter(object):
 	def __init__(self, writer):
 		self.filtered = 0
 		self.writer = writer
-		self.filter = filter
 		self.written = 0  # no of written reads  TODO move to writer
 		self.written_bp = [0, 0]
 
@@ -95,7 +93,7 @@ class PairedRedirector(object):
 			1 means: the pair is discarded if any read matches
 			2 means: the pair is discarded if both reads match
 		"""
-		if not min_affected in (1, 2):
+		if min_affected not in (1, 2):
 			raise ValueError("min_affected must be 1 or 2")
 		self.filtered = 0
 		self.writer = writer
@@ -163,9 +161,9 @@ class TooLongReadFilter(object):
 
 class NContentFilter(object):
 	"""
-	Discards a reads that has a number of 'N's over a given threshold. It handles both raw counts of Ns as well
-	as proportions. Note, for raw counts, it is a greater than comparison, so a cutoff
-	of '1' will keep reads with a single N in it.
+	Discards a reads that has a number of 'N's over a given threshold. It handles both raw counts
+	of Ns as well as proportions. Note, for raw counts, it is a 'greater than' comparison,
+	so a cutoff of '1' will keep reads with a single N in it.
 	"""
 	def __init__(self, count):
 		"""
diff --git a/cutadapt/modifiers.py b/cutadapt/modifiers.py
index f2454ae..3c5c64f 100644
--- a/cutadapt/modifiers.py
+++ b/cutadapt/modifiers.py
@@ -7,10 +7,31 @@ need to be stored, and as a class with a __call__ method if there are parameters
 """
 from __future__ import print_function, division, absolute_import
 import re
+from collections import defaultdict
 from cutadapt.qualtrim import quality_trim_index, nextseq_trim_index
 from cutadapt.compat import maketrans
 
 
+class AdapterStatistics(object):
+	def __init__(self, adapter):
+		self.adapter = adapter
+		self.errors_front = defaultdict(lambda: defaultdict(int))
+		self.errors_back = defaultdict(lambda: defaultdict(int))
+		self.adjacent_bases = {'A': 0, 'C': 0, 'G': 0, 'T': 0, '': 0}
+
+	@property
+	def lengths_front(self):
+		# Python 2.6 has no dict comprehension
+		d = dict((length, sum(errors.values())) for length, errors in self.errors_front.items())
+		return d
+
+	@property
+	def lengths_back(self):
+		# Python 2.6 has no dict comprehension
+		d = dict((length, sum(errors.values())) for length, errors in self.errors_back.items())
+		return d
+
+
 class AdapterCutter(object):
 	"""
 	Repeatedly find one of multiple adapters in reads.
@@ -32,7 +53,7 @@ class AdapterCutter(object):
 		self.rest_writer = rest_writer
 		self.action = action
 		self.with_adapters = 0
-		self.keep_match_info = self.info_file is not None
+		self.adapter_statistics = dict((a, AdapterStatistics(a)) for a in adapters)  # Python 2.6
 
 	def _best_match(self, read):
 		"""
@@ -40,6 +61,9 @@ class AdapterCutter(object):
 
 		Return either a Match instance or None if there are no matches.
 		"""
+		# TODO
+		# try to sort adapters by length, longest first, break when current best
+		# match is longer than length of next adapter to try
 		best = None
 		for adapter in self.adapters:
 			match = adapter.match_to(read)
@@ -51,13 +75,13 @@ class AdapterCutter(object):
 				best = match
 		return best
 
-	def _write_info(self, read):
+	def _write_info(self, read, matches):
 		"""
 		Write to the info, wildcard and rest files.
+		"""
 		# TODO
 		# This design with a read having a .match attribute and
 		# a match having a .read attribute is really confusing.
-		"""
 		match = read.match
 		if self.rest_writer and match:
 			self.rest_writer.write(match)
@@ -66,9 +90,10 @@ class AdapterCutter(object):
 			print(match.wildcards(), read.name, file=self.wildcard_file)
 
 		if self.info_file:
-			if read.match_info:
-				for m in read.match_info:
-					print(*m, sep='\t', file=self.info_file)
+			if matches:
+				for match in matches:
+					info_record = match.get_info_record()
+					print(*info_record, sep='\t', file=self.info_file)
 			else:
 				seq = read.sequence
 				qualities = read.qualities if read.qualities is not None else ''
@@ -76,6 +101,8 @@ class AdapterCutter(object):
 
 	def __call__(self, read):
 		"""
+		Cut found adapters from a single read. Return modified read.
+
 		Determine the adapter that best matches the given read.
 		Since the best adapter is searched repeatedly, a list
 		of Match instances is returned, which
@@ -84,8 +111,6 @@ class AdapterCutter(object):
 
 		The read is converted to uppercase before it is compared to the adapter
 		sequences.
-
-		Cut found adapters from a single read. Return modified read.
 		"""
 		matches = []
 
@@ -97,14 +122,14 @@ class AdapterCutter(object):
 				# nothing found
 				break
 			matches.append(match)
-			trimmed_read = match.adapter.trimmed(match)
-		
+			trimmed_read = match.trimmed()
+			match.update_statistics(self.adapter_statistics[match.adapter])
+
 		if not matches:
 			trimmed_read.match = None
-			trimmed_read.match_info = None
-			self._write_info(trimmed_read)
+			self._write_info(trimmed_read, [])
 			return trimmed_read
-		
+
 		if __debug__:
 			assert len(trimmed_read) < len(read), "Trimmed read isn't shorter than original"
 
@@ -116,25 +141,21 @@ class AdapterCutter(object):
 			masked_sequence = trimmed_read.sequence
 			for match in sorted(matches, reverse=True, key=lambda m: m.astart):
 				ns = 'N' * (len(match.read.sequence) -
-							len(match.adapter.trimmed(match).sequence))
+							len(match.trimmed().sequence))  # TODO is this correct? -> stats?
 				# add N depending on match position
-				if match.front:
+				if match.remove_before:
 					masked_sequence = ns + masked_sequence
 				else:
 					masked_sequence += ns
 			# set masked sequence as sequence with original quality
 			trimmed_read.sequence = masked_sequence
 			trimmed_read.qualities = matches[0].read.qualities
-
 			assert len(trimmed_read.sequence) == len(read)
 		elif self.action is None:
 			trimmed_read = read
-		
+
 		trimmed_read.match = matches[-1]
-		if self.keep_match_info:
-			trimmed_read.match_info = [match.get_info_record() for match in matches]
-		self._write_info(trimmed_read)
-		
+		self._write_info(trimmed_read, matches)
 		self.with_adapters += 1
 		return trimmed_read
 
@@ -261,7 +282,7 @@ class QualityTrimmer(object):
 
 
 class Shortener(object):
-	"""Uncoditionally shorten a read to the given length"""
+	"""Unconditionally shorten a read to the given length"""
 	def __init__(self, length):
 		self.length = length
 
diff --git a/cutadapt/qualtrim.py b/cutadapt/qualtrim.py
index ea79132..6996430 100644
--- a/cutadapt/qualtrim.py
+++ b/cutadapt/qualtrim.py
@@ -10,32 +10,6 @@ if sys.version > '3':
 	xrange = range
 
 
-def quality_trim_index(qualities, cutoff, base=33):
-	"""
-	Find the position at which to trim a low-quality end from a nucleotide sequence.
-
-	Qualities are assumed to be ASCII-encoded as chr(qual + base).
-
-	The algorithm is the same as the one used by BWA within the function
-	'bwa_trim_read':
-	- Subtract the cutoff value from all qualities.
-	- Compute partial sums from all indices to the end of the sequence.
-	- Trim sequence at the index at which the sum is minimal.
-	"""
-	s = 0
-	max_qual = 0
-	max_i = len(qualities)
-	for i in reversed(xrange(max_i)):
-		q = ord(qualities[i]) - base
-		s += cutoff - q
-		if s < 0:
-			break
-		if s > max_qual:
-			max_qual = s
-			max_i = i
-	return max_i
-
-
 def nextseq_trim_index(sequence, cutoff, base=33):
 	"""
 	Variant of the above quality trimming routine that works on NextSeq data.
@@ -64,7 +38,5 @@ def nextseq_trim_index(sequence, cutoff, base=33):
 			max_i = i
 	return max_i
 
-try:
-	from cutadapt._qualtrim import quality_trim_index, nextseq_trim_index
-except:
-	pass
+
+from cutadapt._qualtrim import quality_trim_index, nextseq_trim_index
diff --git a/cutadapt/report.py b/cutadapt/report.py
index 35b3641..c3c0e1a 100644
--- a/cutadapt/report.py
+++ b/cutadapt/report.py
@@ -5,7 +5,6 @@ Routines for printing a report.
 from __future__ import print_function, division, absolute_import
 
 import sys
-from collections import namedtuple
 from contextlib import contextmanager
 import textwrap
 from .adapters import BACK, FRONT, PREFIX, SUFFIX, ANYWHERE, LINKED
@@ -14,12 +13,51 @@ from .filters import (NoFilter, PairedNoFilter, TooShortReadFilter, TooLongReadF
 	DiscardTrimmedFilter, DiscardUntrimmedFilter, Demultiplexer, NContentFilter)
 
 
+def safe_divide(numerator, denominator):
+	if numerator is None or not denominator:
+		return 0.0
+	else:
+		return numerator / denominator
+
+
 class Statistics:
-	def __init__(self, n, total_bp1, total_bp2):
+	def __init__(self):
+		"""
+		"""
+		self.n = 0
+		self.total_bp = 0
+		self.total_bp1 = 0
+		self.total_bp2 = 0
+		self.paired = False
+		self.time = 0.01  # CPU time in seconds
+		self.too_short = None
+		self.too_long = None
+		self.written = 0
+		self.written_bp = [0, 0]
+		self.too_many_n = None
+		self.with_adapters = [0, 0]
+		self.quality_trimmed_bp = [0, 0]
+		self.did_quality_trimming = False
+		self.quality_trimmed = 0
+		self.adapter_stats = [None, None]
+		self.adapter_lists = [[], []]
+
+		# These attributes are derived from the ones above
+		self.total_written_bp = 0
+		self.too_short_fraction = 0
+		self.too_long_fraction = 0
+		self.total_written_bp_fraction = 0
+		self.with_adapters_fraction = []
+		self.written_fraction = 0
+		self.quality_trimmed_fraction = 0
+		self.too_many_n_fraction = None
+
+	def collect(self, n, total_bp1, total_bp2, time, modifiers, modifiers2, writers):
 		"""
 		n -- total number of reads
 		total_bp1 -- number of bases in first reads
-		total_bp2 -- number of bases in second reads (set to None for single-end data)
+		total_bp2 -- number of bases in second reads. None for single-end data.
+		time -- CPU time
 		"""
 		self.n = n
 		self.total_bp = total_bp1
@@ -30,21 +68,15 @@ class Statistics:
 			self.paired = True
 			self.total_bp2 = total_bp2
 			self.total_bp += total_bp2
-
-	def collect(self, adapters_pair, time, modifiers, modifiers2, writers):
 		self.time = max(time, 0.01)
-		self.too_short = None
-		self.too_long = None
-		self.written = 0
-		self.written_bp = [0, 0]
-		self.too_many_n = None
+
 		# Collect statistics from writers/filters
 		for w in writers:
-			if isinstance(w, (NoFilter, PairedNoFilter, Demultiplexer)) or isinstance(w.filter, (DiscardTrimmedFilter, DiscardUntrimmedFilter)):
+			if isinstance(w, (NoFilter, PairedNoFilter, Demultiplexer)) or \
+					isinstance(w.filter, (DiscardTrimmedFilter, DiscardUntrimmedFilter)):
 				self.written += w.written
-				if self.n > 0:
-					self.written_fraction = self.written / self.n
-				self.written_bp = self.written_bp[0] + w.written_bp[0], self.written_bp[1] + w.written_bp[1]
+				self.written_bp[0] += w.written_bp[0]
+				self.written_bp[1] += w.written_bp[1]
 			elif isinstance(w.filter, TooShortReadFilter):
 				self.too_short = w.filtered
 			elif isinstance(w.filter, TooLongReadFilter):
@@ -54,9 +86,6 @@ class Statistics:
 		assert self.written is not None
 
 		# Collect statistics from modifiers
-		self.with_adapters = [0, 0]
-		self.quality_trimmed_bp = [0, 0]
-		self.did_quality_trimming = False
 		for i, modifiers_list in [(0, modifiers), (1, modifiers2)]:
 			for modifier in modifiers_list:
 				if isinstance(modifier, QualityTrimmer):
@@ -64,20 +93,19 @@ class Statistics:
 					self.did_quality_trimming = True
 				elif isinstance(modifier, AdapterCutter):
 					self.with_adapters[i] += modifier.with_adapters
-		self.with_adapters_fraction = [ (v / self.n if self.n > 0 else 0) for v in self.with_adapters ]
-		self.quality_trimmed = sum(self.quality_trimmed_bp)
-		self.quality_trimmed_fraction = self.quality_trimmed / self.total_bp if self.total_bp > 0 else 0.0
+					self.adapter_stats[i] = modifier.adapter_statistics
+					self.adapter_lists[i] = modifier.adapters
 
+		# Set the attributes that are derived from the other ones
+		self.quality_trimmed = sum(self.quality_trimmed_bp)
 		self.total_written_bp = sum(self.written_bp)
-		self.total_written_bp_fraction = self.total_written_bp / self.total_bp if self.total_bp > 0 else 0.0
-
-		if self.n > 0:
-			if self.too_short is not None:
-				self.too_short_fraction = self.too_short / self.n
-			if self.too_long is not None:
-				self.too_long_fraction = self.too_long / self.n
-			if self.too_many_n is not None:
-				self.too_many_n_fraction = self.too_many_n / self.n
+		self.written_fraction = safe_divide(self.written, self.n)
+		self.with_adapters_fraction = [safe_divide(v, self.n) for v in self.with_adapters]
+		self.quality_trimmed_fraction = safe_divide(self.quality_trimmed, self.total_bp)
+		self.total_written_bp_fraction = safe_divide(self.total_written_bp, self.total_bp)
+		self.too_short_fraction = safe_divide(self.too_short, self.n)
+		self.too_long_fraction = safe_divide(self.too_long, self.n)
+		self.too_many_n_fraction = safe_divide(self.too_many_n, self.n)
 
 
 ADAPTER_TYPES = {
@@ -104,30 +132,45 @@ def print_error_ranges(adapter_length, error_rate):
 	print()
 
 
-def print_histogram(d, adapter_length, n, error_rate, errors):
+def print_histogram(adapter_statistics, where, adapter, n, gc_content):
 	"""
 	Print a histogram. Also, print the no. of reads expected to be
 	trimmed by chance (assuming a uniform distribution of nucleotides in the reads).
-	d -- a dictionary mapping lengths of trimmed sequences to their respective frequency
+
+	adapter_statistics -- AdapterStatistics object
+	where -- 'front' or 'back'
 	adapter_length -- adapter length
 	n -- total no. of reads.
 	"""
-	h = []
+	if where not in ('front', 'back'):
+		assert ValueError('where must be "front" or "back"')
+	if where == 'front':
+		d = adapter_statistics.lengths_front
+		errors = adapter_statistics.errors_front
+	else:
+		d = adapter_statistics.lengths_back
+		errors = adapter_statistics.errors_back
+
+	match_probabilities = adapter.random_match_probabilities(gc_content=gc_content)
+	print("length", "count", "expect", "max.err", "error counts", sep="\t")
 	for length in sorted(d):
 		# when length surpasses adapter_length, the
 		# probability does not increase anymore
-		estimated = n * 0.25 ** min(length, adapter_length)
-		h.append( (length, d[length], estimated) )
-
-	print("length", "count", "expect", "max.err", "error counts", sep="\t")
-	for length, count, estimate in h:
+		expect = n * match_probabilities[min(len(adapter), length)]
+		count = d[length]
 		max_errors = max(errors[length].keys())
 		errs = ' '.join(str(errors[length][e]) for e in range(max_errors+1))
-		print(length, count, "{0:.1F}".format(estimate), int(error_rate*min(length, adapter_length)), errs, sep="\t")
+		print(
+			length,
+			count,
+			"{0:.1F}".format(expect),
+			int(adapter.max_error_rate*min(length, len(adapter))),
+			errs,
+			sep="\t")
 	print()
 
 
-def print_adjacent_bases(bases, sequence):
+def print_adjacent_bases(bases):
 	"""
 	Print a summary of the bases preceding removed adapter sequences.
 	Print a warning if one of the bases is overrepresented and there are
@@ -168,7 +211,7 @@ def redirect_standard_output(file):
 	sys.stdout = old_stdout
 
 
-def print_report(stats, adapters_pair):
+def print_report(stats, gc_content):
 	"""Print report to standard output."""
 	if stats.n == 0:
 		print("No reads processed! Either your input file is empty or you used the wrong -f/--format parameter.")
@@ -225,9 +268,10 @@ def print_report(stats, adapters_pair):
 
 	warning = False
 	for which_in_pair in (0, 1):
-		for adapter in adapters_pair[which_in_pair]:
-			total_front = sum(adapter.lengths_front.values())
-			total_back = sum(adapter.lengths_back.values())
+		for adapter in stats.adapter_lists[which_in_pair]:
+			adapter_statistics = stats.adapter_stats[which_in_pair][adapter]
+			total_front = sum(adapter_statistics.lengths_front.values())
+			total_back = sum(adapter_statistics.lengths_back.values())
 			total = total_front + total_back
 			where = adapter.where
 			assert where in (ANYWHERE, LINKED) or (where in (BACK, SUFFIX) and total_front == 0) or (where in (FRONT, PREFIX) and total_back == 0)
@@ -239,9 +283,11 @@ def print_report(stats, adapters_pair):
 
 			print("=" * 3, extra + "Adapter", adapter.name, "=" * 3)
 			print()
+
 			if where == LINKED:
-				print("Sequence: {0}...{1}; Type: linked; Length: {2}+{3}; Trimmed: {4} times; Half matches: {5}".
-					format(adapter.front_adapter.sequence,
+				print("Sequence: {0}...{1}; Type: linked; Length: {2}+{3}; "
+					"5' trimmed: {4} times; 3' trimmed: {5} times".format(
+						adapter.front_adapter.sequence,
 						adapter.back_adapter.sequence,
 						len(adapter.front_adapter.sequence),
 						len(adapter.back_adapter.sequence),
@@ -259,36 +305,33 @@ def print_report(stats, adapters_pair):
 				print()
 				print_error_ranges(len(adapter), adapter.max_error_rate)
 				print("Overview of removed sequences (5')")
-				print_histogram(adapter.lengths_front, len(adapter), stats.n, adapter.max_error_rate, adapter.errors_front)
+				print_histogram(adapter_statistics, 'front', adapter, stats.n, gc_content)
 				print()
 				print("Overview of removed sequences (3' or within)")
-				print_histogram(adapter.lengths_back, len(adapter), stats.n, adapter.max_error_rate, adapter.errors_back)
+				print_histogram(adapter_statistics, 'back', adapter, stats.n, gc_content)
 			elif where == LINKED:
 				print()
 				print_error_ranges(len(adapter.front_adapter), adapter.front_adapter.max_error_rate)
 				print_error_ranges(len(adapter.back_adapter), adapter.back_adapter.max_error_rate)
 				print("Overview of removed sequences at 5' end")
-				print_histogram(adapter.front_adapter.lengths_front,
-					len(adapter.front_adapter), stats.n,
-					adapter.front_adapter.max_error_rate,
-					adapter.front_adapter.errors_front)
+				print_histogram(adapter_statistics, 'front',
+					adapter.front_adapter, stats.n, gc_content)
 				print()
 				print("Overview of removed sequences at 3' end")
-				print_histogram(adapter.back_adapter.lengths_back,
-					len(adapter.back_adapter), stats.n,
-					adapter.back_adapter.max_error_rate, adapter.back_adapter.errors_back)
+				print_histogram(adapter_statistics, 'back',
+					adapter.back_adapter, stats.n, gc_content)
 			elif where in (FRONT, PREFIX):
 				print()
 				print_error_ranges(len(adapter), adapter.max_error_rate)
 				print("Overview of removed sequences")
-				print_histogram(adapter.lengths_front, len(adapter), stats.n, adapter.max_error_rate, adapter.errors_front)
+				print_histogram(adapter_statistics, 'front', adapter, stats.n, gc_content)
 			else:
 				assert where in (BACK, SUFFIX)
 				print()
 				print_error_ranges(len(adapter), adapter.max_error_rate)
-				warning = warning or print_adjacent_bases(adapter.adjacent_bases, adapter.sequence)
+				warning = warning or print_adjacent_bases(adapter_statistics.adjacent_bases)
 				print("Overview of removed sequences")
-				print_histogram(adapter.lengths_back, len(adapter), stats.n, adapter.max_error_rate, adapter.errors_back)
+				print_histogram(adapter_statistics, 'back', adapter, stats.n, gc_content)
 
 	if warning:
 		print('WARNING:')
diff --git a/cutadapt/scripts/cutadapt.py b/cutadapt/scripts/cutadapt.py
index bb230d8..87a7b77 100755
--- a/cutadapt/scripts/cutadapt.py
+++ b/cutadapt/scripts/cutadapt.py
@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 # kate: word-wrap off; remove-trailing-spaces all;
 #
-# Copyright (c) 2010-2016 Marcel Martin <marcel.martin at scilifelab.se>
+# Copyright (c) 2010-2017 Marcel Martin <marcel.martin at scilifelab.se>
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -24,7 +24,7 @@
 
 """
 cutadapt version %version
-Copyright (C) 2010-2016 Marcel Martin <marcel.martin at scilifelab.se>
+Copyright (C) 2010-2017 Marcel Martin <marcel.martin at scilifelab.se>
 
 cutadapt removes adapter sequences from high-throughput sequencing reads.
 
@@ -52,7 +52,7 @@ sequencing reads. EMBnet.Journal, 17(1):10-12, May 2011.
 http://dx.doi.org/10.14806/ej.17.1.200
 
 Use "cutadapt --help" to see all command-line options.
-See http://cutadapt.readthedocs.org/ for full documentation.
+See http://cutadapt.readthedocs.io/ for full documentation.
 """
 
 from __future__ import print_function, division, absolute_import
@@ -80,15 +80,20 @@ from cutadapt.filters import (NoFilter, PairedNoFilter, Redirector, PairedRedire
 	LegacyPairedRedirector, TooShortReadFilter, TooLongReadFilter,
 	Demultiplexer, NContentFilter, DiscardUntrimmedFilter, DiscardTrimmedFilter)
 from cutadapt.report import Statistics, print_report, redirect_standard_output
-from cutadapt.compat import next
+
 
 logger = logging.getLogger()
 
+
 class CutadaptOptionParser(OptionParser):
 	def get_usage(self):
 		return self.usage.lstrip().replace('%version', __version__)
 
 
+class CommandlineError(Exception):
+	pass
+
+
 class RestFileWriter(object):
 	def __init__(self, file):
 		self.file = file
@@ -99,18 +104,50 @@ class RestFileWriter(object):
 			print(rest, match.read.name, file=self.file)
 
 
-class SingleEndPipeline:
+class Pipeline(object):
 	"""
 	Processing pipeline that loops over reads and applies modifiers and filters
 	"""
+	def __init__(self):
+		self._close_files = []
+
+	def register_file_to_close(self, file):
+		if file is not None and file is not sys.stdin and file is not sys.stdout:
+			self._close_files.append(file)
+
+	def close_files(self):
+		for f in self._close_files:
+			f.close()
+
+	def process_reads(self):
+		raise NotImplementedError()
+
+	def run(self):
+		start_time = time.clock()
+		(n, total1_bp, total2_bp) = self.process_reads()
+		self.close_files()
+		elapsed_time = time.clock() - start_time
+		# TODO
+		m = self.modifiers if hasattr(self, 'modifiers') else self.modifiers1
+		m2 = getattr(self, 'modifiers2', [])
+		stats = Statistics()
+		stats.collect(n, total1_bp, total2_bp, elapsed_time, m, m2, self.filters)
+		return stats
+
+
+class SingleEndPipeline(Pipeline):
+	"""
+	Processing pipeline for single-end reads
+	"""
 	def __init__(self, reader, modifiers, filters):
+		super(SingleEndPipeline, self).__init__()
 		self.reader = reader
 		self.modifiers = modifiers
 		self.filters = filters
 
-	def run(self):
-		"""Run the pipeline. Return a Statistics object"""
-		n = 0  # no. of processed reads
+	def process_reads(self):
+		"""Run the pipeline. Return statistics"""
+		n = 0  # no. of processed reads  # TODO turn into attribute
 		total_bp = 0
 		for read in self.reader:
 			n += 1
@@ -120,20 +157,21 @@ class SingleEndPipeline:
 			for filter in self.filters:
 				if filter(read):
 					break
-		return Statistics(n=n, total_bp1=total_bp, total_bp2=None)
+		return (n, total_bp, None)
 
 
-class PairedEndPipeline:
+class PairedEndPipeline(Pipeline):
 	"""
 	Processing pipeline for paired-end reads.
 	"""
 	def __init__(self, paired_reader, modifiers1, modifiers2, filters):
+		super(PairedEndPipeline, self).__init__()
 		self.paired_reader = paired_reader
 		self.modifiers1 = modifiers1
 		self.modifiers2 = modifiers2
 		self.filters = filters
 
-	def run(self):
+	def process_reads(self):
 		n = 0  # no. of processed reads
 		total1_bp = 0
 		total2_bp = 0
@@ -149,7 +187,7 @@ class PairedEndPipeline:
 				# Stop writing as soon as one of the filters was successful.
 				if filter(read1, read2):
 					break
-		return Statistics(n=n, total_bp1=total1_bp, total_bp2=total2_bp)
+		return (n, total1_bp, total2_bp)
 
 
 def setup_logging(stdout=False, quiet=False):
@@ -175,6 +213,10 @@ def get_option_parser():
 			"Ignored when reading csfasta/qual files. Default: auto-detect "
 			"from file name extension.")
 
+	# Hidden option for now
+	parser.add_option("--gc-content", type=float, default=50,  # it's a percentage
+		help=SUPPRESS_HELP)
+
 	group = OptionGroup(parser, "Finding adapters:",
 		description="Parameters -a, -g, -b specify adapters to be removed from "
 			"each read (or from the first read in a pair if data is paired). "
@@ -309,7 +351,7 @@ def get_option_parser():
 		help="Write reads that are too long (according to length specified by "
 		"-M) to FILE. Default: discard reads")
 	group.add_option("--untrimmed-output", default=None, metavar="FILE",
-		help="Write reads that do not contain the adapter to FILE. Default: "
+		help="Write reads that do not contain any adapter to FILE. Default: "
 			"output to same file as trimmed reads")
 	parser.add_option_group(group)
 
@@ -375,30 +417,19 @@ def get_option_parser():
 	return parser
 
 
-def main(cmdlineargs=None, default_outfile=sys.stdout):
+def pipeline_from_parsed_args(options, args, default_outfile):
 	"""
-	Main function that evaluates command-line parameters and iterates
-	over all reads.
+	Setup a processing pipeline from parsed command-line options.
 
-	default_outfile is the file to which trimmed reads are sent if the ``-o``
-	parameter is not used.
+	If there are any problems parsing the arguments, a CommandlineError is thrown.
 	"""
-	parser = get_option_parser()
-	if cmdlineargs is None:
-		cmdlineargs = sys.argv[1:]
-	options, args = parser.parse_args(args=cmdlineargs)
-	# Setup logging only if there are not already any handlers (can happen when
-	# this function is being called externally such as from unit tests)
-	if not logging.root.handlers:
-		setup_logging(stdout=bool(options.output), quiet=options.quiet)
-
 	if len(args) == 0:
-		parser.error("At least one parameter needed: name of a FASTA or FASTQ file.")
+		raise CommandlineError("At least one parameter needed: name of a FASTA or FASTQ file.")
 	elif len(args) > 2:
-		parser.error("Too many parameters.")
+		raise CommandlineError("Too many parameters.")
 	input_filename = args[0]
 	if input_filename.endswith('.qual'):
-		parser.error("If a .qual file is given, it must be the second argument.")
+		raise CommandlineError("If a .qual file is given, it must be the second argument.")
 
 	# Find out which 'mode' we need to use.
 	# Default: single-read trimming (neither -p nor -A/-G/-B/-U/--interleaved given)
@@ -416,11 +447,11 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 		paired = 'both'
 
 	if paired and len(args) == 1 and not options.interleaved:
-		parser.error("When paired-end trimming is enabled via -A/-G/-B/-U/"
+		raise CommandlineError("When paired-end trimming is enabled via -A/-G/-B/-U/"
 			"--interleaved or -p, two input files are required.")
 	if not paired:
 		if options.untrimmed_paired_output:
-			parser.error("Option --untrimmed-paired-output can only be used when "
+			raise CommandlineError("Option --untrimmed-paired-output can only be used when "
 				"trimming paired-end reads (with option -p).")
 
 	interleaved_input = False
@@ -429,7 +460,7 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 		interleaved_input = len(args) == 1
 		interleaved_output = not options.paired_output
 		if not interleaved_input and not interleaved_output:
-			parser.error("When --interleaved is used, you cannot provide both two input files and two output files")
+			raise CommandlineError("When --interleaved is used, you cannot provide both two input files and two output files")
 
 	# Assign input_paired_filename and quality_filename
 	input_paired_filename = None
@@ -439,28 +470,28 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 			input_paired_filename = args[1]
 		if not interleaved_output:
 			if not options.paired_output:
-				parser.error("When paired-end trimming is enabled via -A/-G/-B/-U, "
+				raise CommandlineError("When paired-end trimming is enabled via -A/-G/-B/-U, "
 					"a second output file needs to be specified via -p (--paired-output).")
 			if not options.output:
-				parser.error("When you use -p or --paired-output, you must also "
+				raise CommandlineError("When you use -p or --paired-output, you must also "
 					"use the -o option.")
 
 		if bool(options.untrimmed_output) != bool(options.untrimmed_paired_output):
-			parser.error("When trimming paired-end reads, you must use either none "
+			raise CommandlineError("When trimming paired-end reads, you must use either none "
 				"or both of the --untrimmed-output/--untrimmed-paired-output options.")
 		if options.too_short_output and not options.too_short_paired_output:
-			parser.error("When using --too-short-output with paired-end "
+			raise CommandlineError("When using --too-short-output with paired-end "
 				"reads, you also need to use --too-short-paired-output")
 		if options.too_long_output and not options.too_long_paired_output:
-			parser.error("When using --too-long-output with paired-end "
+			raise CommandlineError("When using --too-long-output with paired-end "
 				"reads, you also need to use --too-long-paired-output")
 	elif len(args) == 2:
 		quality_filename = args[1]
 		if options.format is not None:
-			parser.error("If a pair of .fasta and .qual files is given, the -f/--format parameter cannot be used.")
+			raise CommandlineError("If a pair of .fasta and .qual files is given, the -f/--format parameter cannot be used.")
 
 	if options.format is not None and options.format.lower() not in ['fasta', 'fastq', 'sra-fastq']:
-		parser.error("The input file format must be either 'fasta', 'fastq' or "
+		raise CommandlineError("The input file format must be either 'fasta', 'fastq' or "
 			"'sra-fastq' (not '{0}').".format(options.format))
 
 	# Open input file(s)
@@ -469,7 +500,7 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 				qualfile=quality_filename, colorspace=options.colorspace,
 				fileformat=options.format, interleaved=interleaved_input)
 	except (seqio.UnknownFileType, IOError) as e:
-		parser.error(e)
+		raise CommandlineError(e)
 
 	if options.quality_cutoff is not None:
 		cutoffs = options.quality_cutoff.split(',')
@@ -477,14 +508,14 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 			try:
 				cutoffs = [0, int(cutoffs[0])]
 			except ValueError as e:
-				parser.error("Quality cutoff value not recognized: {0}".format(e))
+				raise CommandlineError("Quality cutoff value not recognized: {0}".format(e))
 		elif len(cutoffs) == 2:
 			try:
 				cutoffs = [int(cutoffs[0]), int(cutoffs[1])]
 			except ValueError as e:
-				parser.error("Quality cutoff value not recognized: {0}".format(e))
+				raise CommandlineError("Quality cutoff value not recognized: {0}".format(e))
 		else:
-			parser.error("Expected one value or two values separated by comma for the quality cutoff")
+			raise CommandlineError("Expected one value or two values separated by comma for the quality cutoff")
 	else:
 		cutoffs = None
 
@@ -518,16 +549,16 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 		filters.append(filter_wrapper(None, NContentFilter(options.max_n)))
 
 	if int(options.discard_trimmed) + int(options.discard_untrimmed) + int(options.untrimmed_output is not None) > 1:
-		parser.error("Only one of the --discard-trimmed, --discard-untrimmed "
+		raise CommandlineError("Only one of the --discard-trimmed, --discard-untrimmed "
 			"and --untrimmed-output options can be used at the same time.")
 	demultiplexer = None
 	untrimmed_writer = None
 	writer = None
 	if options.output is not None and '{name}' in options.output:
 		if options.discard_trimmed:
-			parser.error("Do not use --discard-trimmed when demultiplexing.")
+			raise CommandlineError("Do not use --discard-trimmed when demultiplexing.")
 		if paired:
-			parser.error("Demultiplexing not supported for paired-end files, yet.")
+			raise CommandlineError("Demultiplexing not supported for paired-end files, yet.")
 		untrimmed = options.output.replace('{name}', 'unknown')
 		if options.untrimmed_output:
 			untrimmed = options.untrimmed_output
@@ -569,15 +600,15 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 	if options.zero_cap is None:
 		options.zero_cap = options.colorspace
 	if options.trim_primer and not options.colorspace:
-		parser.error("Trimming the primer makes only sense in colorspace.")
+		raise CommandlineError("Trimming the primer makes only sense in colorspace.")
 	if options.double_encode and not options.colorspace:
-		parser.error("Double-encoding makes only sense in colorspace.")
+		raise CommandlineError("Double-encoding makes only sense in colorspace.")
 	if options.anywhere and options.colorspace:
-		parser.error("Using --anywhere with colorspace reads is currently not supported (if you think this may be useful, contact the author).")
+		raise CommandlineError("Using --anywhere with colorspace reads is currently not supported (if you think this may be useful, contact the author).")
 	if not (0 <= options.error_rate <= 1.):
-		parser.error("The maximum error rate must be between 0 and 1.")
+		raise CommandlineError("The maximum error rate must be between 0 and 1.")
 	if options.overlap < 1:
-		parser.error("The overlap must be at least 1.")
+		raise CommandlineError("The overlap must be at least 1.")
 
 	if options.rest_file is not None:
 		options.rest_file = xopen(options.rest_file, 'w')
@@ -591,7 +622,7 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 
 	if options.colorspace:
 		if options.match_read_wildcards:
-			parser.error('IUPAC wildcards not supported in colorspace')
+			raise CommandlineError('IUPAC wildcards not supported in colorspace')
 		options.match_adapter_wildcards = False
 
 	adapter_parser = AdapterParser(
@@ -607,10 +638,10 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 		adapters2 = adapter_parser.parse_multi(options.adapters2, options.anywhere2, options.front2)
 	except IOError as e:
 		if e.errno == errno.ENOENT:
-			parser.error(e)
+			raise CommandlineError(e)
 		raise
 	except ValueError as e:
-		parser.error(e)
+		raise CommandlineError(e)
 	if options.debug:
 		for adapter in adapters + adapters2:
 			adapter.enable_debug()
@@ -619,9 +650,9 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 	modifiers = []
 	if options.cut:
 		if len(options.cut) > 2:
-			parser.error("You cannot remove bases from more than two ends.")
+			raise CommandlineError("You cannot remove bases from more than two ends.")
 		if len(options.cut) == 2 and options.cut[0] * options.cut[1] > 0:
-			parser.error("You cannot remove bases from the same end twice.")
+			raise CommandlineError("You cannot remove bases from the same end twice.")
 		for cut in options.cut:
 			if cut != 0:
 				modifiers.append(UnconditionalCutter(cut))
@@ -666,9 +697,9 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 	if paired == 'both':
 		if options.cut2:
 			if len(options.cut2) > 2:
-				parser.error("You cannot remove bases from more than two ends.")
+				raise CommandlineError("You cannot remove bases from more than two ends.")
 			if len(options.cut2) == 2 and options.cut2[0] * options.cut2[1] > 0:
-				parser.error("You cannot remove bases from the same end twice.")
+				raise CommandlineError("You cannot remove bases from the same end twice.")
 			for cut in options.cut2:
 				if cut != 0:
 					modifiers2.append(UnconditionalCutter(cut))
@@ -679,8 +710,6 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 			adapter_cutter2 = AdapterCutter(adapters2, options.times,
 					None, None, None, options.action)
 			modifiers2.append(adapter_cutter2)
-		else:
-			adapter_cutter2 = None
 		modifiers2.extend(modifiers_both)
 
 	if paired:
@@ -688,21 +717,60 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 	else:
 		pipeline = SingleEndPipeline(reader, modifiers, filters)
 
-	logger.info("This is cutadapt %s with Python %s", __version__, platform.python_version())
+	# TODO the following should be done some other way
+	pipeline.paired = paired
+	pipeline.error_rate = options.error_rate
+	pipeline.n_adapters = len(adapters) + len(adapters2)
+	pipeline.should_print_warning = paired == 'first' and (modifiers_both or cutoffs)
+	for f in [writer, untrimmed_writer,
+			options.rest_file, options.wildcard_file,
+			options.info_file, too_short_writer, too_long_writer,
+			options.info_file, demultiplexer]:
+		pipeline.register_file_to_close(f)
+	return pipeline
+
+
+def main(cmdlineargs=None, default_outfile=sys.stdout):
+	"""
+	Main function that evaluates command-line parameters and iterates
+	over all reads.
+
+	default_outfile is the file to which trimmed reads are sent if the ``-o``
+	parameter is not used.
+	"""
+	parser = get_option_parser()
+	if cmdlineargs is None:
+		cmdlineargs = sys.argv[1:]
+	options, args = parser.parse_args(args=cmdlineargs)
+	# Setup logging only if there are not already any handlers (can happen when
+	# this function is being called externally such as from unit tests)
+	if not logging.root.handlers:
+		setup_logging(stdout=bool(options.output), quiet=options.quiet)
+
+	if not 0 <= options.gc_content <= 100:
+		parser.error("GC content must be given as percentage between 0 and 100")
+	try:
+		pipeline = pipeline_from_parsed_args(options, args, default_outfile)
+	except CommandlineError as e:
+		parser.error(e)
+
+	implementation = platform.python_implementation()
+	opt = ' (' + implementation + ')' if implementation != 'CPython' else ''
+	logger.info("This is cutadapt %s with Python %s%s", __version__,
+		platform.python_version(), opt)
 	logger.info("Command line parameters: %s", " ".join(cmdlineargs))
 	logger.info("Trimming %s adapter%s with at most %.1f%% errors in %s mode ...",
-		len(adapters) + len(adapters2), 's' if len(adapters) + len(adapters2) != 1 else '',
-		options.error_rate * 100,
-		{ False: 'single-end', 'first': 'paired-end legacy', 'both': 'paired-end' }[paired])
+		pipeline.n_adapters, 's' if pipeline.n_adapters != 1 else '',
+		pipeline.error_rate * 100,
+		{ False: 'single-end', 'first': 'paired-end legacy', 'both': 'paired-end' }[pipeline.paired])
 
-	if paired == 'first' and (modifiers_both or cutoffs):
+	if pipeline.should_print_warning:
 		logger.warning('\n'.join(textwrap.wrap('WARNING: Requested read '
 			'modifications are applied only to the first '
 			'read since backwards compatibility mode is enabled. '
 			'To modify both reads, also use any of the -A/-B/-G/-U options. '
 			'Use a dummy adapter sequence when necessary: -A XXX')))
 
-	start_time = time.clock()
 	try:
 		stats = pipeline.run()
 	except KeyboardInterrupt as e:
@@ -715,22 +783,11 @@ def main(cmdlineargs=None, default_outfile=sys.stdout):
 	except (seqio.FormatError, EOFError) as e:
 		sys.exit("cutadapt: error: {0}".format(e))
 
-	# close open files
-	for f in [writer, untrimmed_writer,
-			options.rest_file, options.wildcard_file,
-			options.info_file, too_short_writer, too_long_writer,
-			options.info_file, demultiplexer]:
-		if f is not None and f is not sys.stdin and f is not sys.stdout:
-			f.close()
-
-	elapsed_time = time.clock() - start_time
 	if not options.quiet:
-		stats.collect((adapters, adapters2), elapsed_time,
-			modifiers, modifiers2, filters)
 		# send statistics to stderr if result was sent to stdout
 		stat_file = sys.stderr if options.output is None else None
 		with redirect_standard_output(stat_file):
-			print_report(stats, (adapters, adapters2))
+			print_report(stats, options.gc_content / 100)
 
 
 if __name__ == '__main__':
diff --git a/cutadapt/seqio.py b/cutadapt/seqio.py
index fbb9aef..191bf98 100644
--- a/cutadapt/seqio.py
+++ b/cutadapt/seqio.py
@@ -36,14 +36,13 @@ def _shorten(s, n=100):
 class Sequence(object):
 	"""qualities is a string and it contains the qualities encoded as ascii(qual+33)."""
 
-	def __init__(self, name, sequence, qualities=None, second_header=False, match=None, match_info=None):
+	def __init__(self, name, sequence, qualities=None, second_header=False, match=None):
 		"""Set qualities to None if there are no quality values"""
 		self.name = name
 		self.sequence = sequence
 		self.qualities = qualities
 		self.second_header = second_header
 		self.match = match
-		self.match_info = match_info
 		self.original_length = len(sequence)
 		if qualities is not None:
 			if len(qualities) != len(sequence):
@@ -58,8 +57,7 @@ class Sequence(object):
 			self.sequence[key],
 			self.qualities[key] if self.qualities is not None else None,
 			self.second_header,
-			self.match,
-			self.match_info)
+			self.match)
 
 	def __repr__(self):
 		qstr = ''
@@ -115,7 +113,7 @@ except ImportError:
 
 
 class ColorspaceSequence(Sequence):
-	def __init__(self, name, sequence, qualities, primer=None, second_header=False, match=None, match_info=None):
+	def __init__(self, name, sequence, qualities, primer=None, second_header=False, match=None):
 		# In colorspace, the first character is the last nucleotide of the primer base
 		# and the second character encodes the transition from the primer base to the
 		# first real base of the read.
@@ -129,7 +127,7 @@ class ColorspaceSequence(Sequence):
 			raise FormatError("In read named {0!r}: length of colorspace quality "
 				"sequence ({1}) and length of read ({2}) do not match (primer "
 				"is: {3!r})".format(rname, len(qualities), len(sequence), self.primer))
-		super(ColorspaceSequence, self).__init__(name, sequence, qualities, second_header, match, match_info)
+		super(ColorspaceSequence, self).__init__(name, sequence, qualities, second_header, match)
 		if not self.primer in ('A', 'C', 'G', 'T'):
 			raise FormatError("Primer base is {0!r} in read {1!r}, but it "
 				"should be one of A, C, G, T.".format(
@@ -149,8 +147,11 @@ class ColorspaceSequence(Sequence):
 			self.qualities[key] if self.qualities is not None else None,
 			self.primer,
 			self.second_header,
-			self.match,
-			self.match_info)
+			self.match)
+
+	def __reduce__(self):
+		return (ColorspaceSequence, (self.name, self.sequence, self.qualities, self.primer,
+			self.second_header, self.match))
 
 
 def sra_colorspace_sequence(name, sequence, qualities, second_header):
@@ -241,7 +242,7 @@ class FastqReader(SequenceReader):
 	"""
 	Reader for FASTQ files. Does not support multi-line FASTQ files.
 	"""
-	def __init__(self, file, sequence_class=Sequence): # TODO could be a class attribute
+	def __init__(self, file, sequence_class=Sequence):  # TODO could be a class attribute
 		"""
 		file is a path or a file-like object. compressed files are supported.
 
@@ -455,6 +456,7 @@ class InterleavedSequenceReader(object):
 	def __exit__(self, *args):
 		self.close()
 
+
 class FileWriter(object):
 	def __init__(self, file):
 		if isinstance(file, str):
@@ -476,11 +478,13 @@ class FileWriter(object):
 	def __exit__(self, *args):
 		self.close()
 
+
 class SingleRecordWriter(object):
 	"""Public interface to single-record files"""
 	def write(self, record):
 		raise NotImplementedError()
 
+
 class FastaWriter(FileWriter, SingleRecordWriter):
 	"""
 	Write FASTA-formatted sequences to a file.
@@ -568,6 +572,7 @@ class PairRecordWriter(object):
 	"""Public interface to paired-record files"""
 	def write(self, read1, read2):
 		raise NotImplementedError()
+
 	def close(self):
 		raise NotImplementedError()
 	
@@ -600,7 +605,8 @@ class InterleavedSequenceWriter(PairRecordWriter):
 	Write paired-end reads to an interleaved FASTA or FASTQ file
 	"""
 	def __init__(self, file, colorspace=False, fileformat='fastq', qualities=None):
-		self._writer = open(file, colorspace=colorspace, fileformat=fileformat, mode='w', qualities=qualities)
+		self._writer = open(
+			file, colorspace=colorspace, fileformat=fileformat, mode='w', qualities=qualities)
 
 	def write(self, read1, read2):
 		self._writer.write(read1)
diff --git a/doc/conf.py b/doc/conf.py
index 511465d..bc03c0c 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -46,7 +46,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'cutadapt'
-copyright = u'2010-2016, Marcel Martin'
+copyright = u'2010-2017, Marcel Martin'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -64,7 +64,7 @@ if version.endswith('.dirty') and os.environ.get('READTHEDOCS') == 'True':
 		version = version + '+' + rest[:-6]
 
 # The full version, including alpha/beta/rc tags.
-release = __version__
+release = version
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/doc/guide.rst b/doc/guide.rst
index 676faf8..b68640e 100644
--- a/doc/guide.rst
+++ b/doc/guide.rst
@@ -58,6 +58,11 @@ Files compressed with bzip2 (``.bz2``) or xz (``.xz``) are also supported, but
 only if the Python installation includes the proper modules. xz files require
 Python 3.3 or later.
 
+Concatenated bz2 files are *not supported* on Python versions before 3.3.
+These files are created by utilities such as ``pbzip2`` (parallel bzip2).
+
+Concatenated gz files *are* supported on all supported Python versions.
+
 
 Standard input and output
 -------------------------
@@ -137,7 +142,7 @@ Adapter type                                        Command-line option
 :ref:`Anchored 3' adapter <anchored-3adapters>`     ``-a ADAPTER$``
 :ref:`Anchored 5' adapter <anchored-5adapters>`     ``-g ^ADAPTER``
 :ref:`5' or 3' (both possible) <anywhere-adapters>` ``-b ADAPTER``
-:ref:`Linked adapter <linked-adapters>`              ``-a ADAPTER1...ADAPTER2``
+:ref:`Linked adapter <linked-adapters>`             ``-a ADAPTER1...ADAPTER2``
 =================================================== ===========================
 
 Here is an illustration of the allowed adapter locations relative to the read
@@ -300,16 +305,28 @@ Linked adapters (combined 5' and 3' adapter)
 --------------------------------------------
 
 If your sequence of interest ist “framed” by a 5' and a 3' adapter, and you want
-to remove both adapters, then you may want to use a linked adapter, which
-combines an anchored 5' adapter and a 3' adapter.
+to remove both adapters, then you may want to use a *linked adapter*. A linked
+adapter combines an anchored 5' adapter and a 3' adapter. The 3' adapter can be
+regular or anchored. The idea is that a read is only trimmed if the anchored
+adapters occur. Thus, the 5' adapter is always required, and if the 3' adapter
+was specified as anchored, it also must exist for a successful match.
+
+:ref:`See the previous sections <anchored-5adapters>` for what anchoring means.
 
 Use ``-a ADAPTER1...ADAPTER2`` to search for a linked adapter. ADAPTER1 is
-interpreted as an anchored 5' adapter and ADAPTER2 as a regular 3' adapter.
+always interpreted as an anchored 5' adapter. Here, ADAPTER2 is a
+regular 3' adapter. If you write ``-a ADAPTER1...ADAPTER2$`` instead,
+then the 3' adapter also becomes anchored, that is, for a read to be
+trimmed, both adapters must exist at the respective ends.
+
+Note that the ADAPTER1 is always interpreted as an anchored 5' adapter even though
+there is no ``^`` character in the beginning.
 
-For a read to be trimmed at all, the 5' adapter must occur, but the the 3'
-adapter is optional. In the statistics printed by the program, a read is counted
-as “trimmed” no matter whether the 5' adapter or both the 5' and 3' adapter
-occur.
+In summary:
+
+* ``-a ADAPTER1...ADAPTER2``: The 5' adapter is removed if it occurs. If a 3' adapter
+  occurs, it is removed only when also a 5' adapter is present.
+* ``-a ADAPTER1...ADAPTER2$``: The adapters are removed only if both occur.
 
 As an  example, assume the 5' adapter is *FIRST* and the 3' adapter is *SECOND*
 and you have these input reads::
@@ -331,13 +348,42 @@ will result in ::
     ANOTHERREADSECOND
 
 The 3' adapter in the last read is not trimmed because the read does not contain
-the 5' adapter. Note that ``FIRST`` is always an anchored 5' adapter (:ref:`see
-the previous section <anchored-5adapters>`) although there is no ``^`` character
-in the beginning.
+the 5' adapter.
 
 This feature does not work when used in combination with some other options,
 such as ``--info-file``, ``--mask-adapter``.
 
+.. versionadded:: 1.10
+
+.. versionadded:: 1.13
+   Ability to anchor the 3' adapter.
+
+
+Linked adapters without anchoring
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes, the 5' adapter of a linked adapter pair should not be anchored. It is possible to
+specify linked adapters also with ``-g ADAPTER1...ADAPTER2`` (note that ``-g`` is used instead
+of ``-a``). These work just like the linked adapters described in the previous section,
+*except that the 5' adapter is not anchored by default*.
+
+This feature has been added on a tentative basis. It may change in the next program version.
+
+.. versionadded:: 1.13
+
+
+Linked adapter statistics
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For linked adapters, the statistics report contains a line like this::
+
+    === Adapter 1 ===
+
+    Sequence: AAAAAAAAA...TTTTTTTTTT; Type: linked; Length: 9+10; Trimmed: 3 times; Half matches: 2
+
+The value for “Half matches” tells you how often only the 5'-side of the adapter was found, but not
+the 3'-side of it. This applies only to linked adapters with regular (non-anchored) 3' adapters.
+
 
 .. _anywhere-adapters:
 
@@ -561,7 +607,7 @@ the ``--cut`` is applied *before* any adapter trimming.
 Quality trimming
 ----------------
 
-The ``-q`` (or ``--trim-qualities``) parameter can be used to trim
+The ``-q`` (or ``--quality-cutoff``) parameter can be used to trim
 low-quality ends from reads before adapter removal. For this to work
 correctly, the quality values must be encoded as ascii(phred quality +
 33). If they are encoded as ascii(phred quality + 64), you need to add
@@ -576,9 +622,33 @@ trim the 5' end as well, use the ``-q`` option with two comma-separated cutoffs:
 
     cutadapt -q 15,10 -o output.fastq input.fastq
 
-The 5' end will then be trimmed with a cutoff of 15, and the 3' will be trimmed
-with a cutoff of 10. If you only want to trim the 5' end, then use a cutoff of
-0 for the 3' end, as in ``-q 10,0``.
+The 5' end will then be trimmed with a cutoff of 15, and the 3' end will be
+trimmed with a cutoff of 10. If you only want to trim the 5' end, then use a
+cutoff of 0 for the 3' end, as in ``-q 10,0``.
+
+
+.. _nextseq-trim:
+
+Quality trimming of reads using two-color chemistry (NextSeq)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some Illumina instruments use a two-color chemistry to encode the four bases.
+This includes the NextSeq and the (at the time of this writing) recently
+announced NovaSeq. In those instruments, a 'dark cycle' (with no detected color)
+encodes a ``G``. However, dark cycles also occur when when sequencing "falls
+off" the end of the fragment. The read then `contains a run of high-quality, but
+incorrect ``G`` calls <https://sequencing.qcfail.com/articles/illumina-2-colour-chemistry-can-overcall-high-confidence-g-bases/>`_
+at its 3' end.
+
+Since the regular quality-trimming algorithm cannot deal with this situation,
+you need to use the ``--nextseq-trim`` option::
+
+    cutadapt --nextseq-trim=20 -o out.fastq input.fastq
+
+This works like regular quality trimming (where one would use ``-q 20``
+instead), except that the qualities of ``G`` bases are ignored.
+
+.. versionadded:: 1.10
 
 
 Quality trimming algorithm
@@ -1127,7 +1197,9 @@ If you have paired-end data, trim also read 2 with the reverse complement of the
 See also the :ref:`section about paired-end adapter trimming above <paired-end>`.
 
 If you want to simplify this a bit, you can also use the common prefix
-``AGATCGGAAGAGC`` as the adapter sequence in both cases::
+``AGATCGGAAGAGC`` as the adapter sequence in both cases. However, you should
+be aware that this sequence occurs multiple times in the human genome and it
+could therefore skew your results very slightly at those loci ::
 
     cutadapt \
 		-a AGATCGGAAGAGC -A AGATCGGAAGAGC \
@@ -1137,6 +1209,12 @@ If you want to simplify this a bit, you can also use the common prefix
 The adapter sequences can be found in the document `Illumina TruSeq Adapters
 De-Mystified <http://tucf-genomics.tufts.edu/documents/protocols/TUCF_Understanding_Illumina_TruSeq_Adapters.pdf>`__.
 
+Under some circumstances you may want to consider not trimming adapters at all.
+If you have whole-exome or whole-genome reads, there will be very few reads
+with adapters anyway. And if you use BWA-MEM, the trailing (5') bases of
+a read that do not match the reference are soft-clipped, which  covers those
+cases in which an adapter does occur.
+
 
 .. _warnbase:
 
@@ -1291,11 +1369,14 @@ In the last row, for example, 358 reads matched the adapter with zero
 errors, 36 with 1 error, and 3 matched with 2 errors.
 
 The "expect" column gives only a rough estimate of the number of
-sequences that is expected to match randomly (it assumes a GC content of
-50%, for example), but it can help to estimate whether the matches that
-were found are true adapter matches or if they are due to chance. At
-lengths 6, for example, only 2.4 reads are expected, but 35 do match,
-which hints that most of these matches are due to actual adapters.
+sequences that is expected to match randomly, but it can help to
+estimate whether the matches that were found are true adapter matches
+or if they are due to chance. At lengths 6, for example, only 2.4
+reads are expected, but 35 do match, which hints that most of these
+matches are due to actual adapters.
+For slightly more accurate estimates, you can provide the correct
+GC content (as a percentage) of your reads with the option
+``--gc-content``. The default is ``--gc-content=50``.
 
 Note that the "length" column refers to the length of the removed
 sequence. That is, the actual length of the match in the above row at
diff --git a/doc/installation.rst b/doc/installation.rst
index 305d910..93ab554 100644
--- a/doc/installation.rst
+++ b/doc/installation.rst
@@ -39,8 +39,7 @@ Dependencies
 
 Cutadapt requires this software to be installed:
 
-* One of Python 2.6, 2.7, 3.3, 3.4 or 3.5. Python 2.7 is a bit faster than the
-  other versions.
+* One of Python 2.7, 3.3, 3.4 or 3.5.
 * A C compiler.
 
 Under Ubuntu, you may need to install the packages ``build-essential`` and
diff --git a/setup.py b/setup.py
index dbb2001..f3dc0a0 100644
--- a/setup.py
+++ b/setup.py
@@ -17,30 +17,6 @@ if sys.version_info < (2, 6):
 	sys.exit(1)
 
 
-def out_of_date(extensions):
-	"""
-	Check whether any pyx source is newer than the corresponding generated
-	C source or whether any C source is missing.
-	"""
-	for extension in extensions:
-		for pyx in extension.sources:
-			path, ext = os.path.splitext(pyx)
-			if ext not in ('.pyx', '.py'):
-				continue
-			if extension.language == 'c++':
-				csource = path + '.cpp'
-			else:
-				csource = path + '.c'
-			# When comparing modification times, allow five seconds slack:
-			# If the installation is being run from pip, modification
-			# times are not preserved and therefore depends on the order in
-			# which files were unpacked.
-			if not os.path.exists(csource) or (
-				os.path.getmtime(pyx) > os.path.getmtime(csource) + 5):
-				return True
-	return False
-
-
 def no_cythonize(extensions, **_ignore):
 	"""
 	Change file extensions from .pyx to .c or .cpp.
@@ -131,7 +107,7 @@ setup(
 	cmdclass = cmdclass,
 	ext_modules = extensions,
 	packages = ['cutadapt', 'cutadapt.scripts'],
-	install_requires = ['xopen>=0.1.0'],
+	install_requires = ['xopen>=0.1.1'],
 	entry_points = {'console_scripts': ['cutadapt = cutadapt.scripts.cutadapt:main']},
 	classifiers = [
 		"Development Status :: 5 - Production/Stable",
diff --git a/tests/data/linked.fasta b/tests/cut/linked-anchored.fasta
similarity index 62%
copy from tests/data/linked.fasta
copy to tests/cut/linked-anchored.fasta
index 5d21f89..dd9b613 100644
--- a/tests/data/linked.fasta
+++ b/tests/cut/linked-anchored.fasta
@@ -1,10 +1,14 @@
 >r1 5' adapter and 3' adapter
 AAAAAAAAAACCCCCCCCCCTTTTTTTTTTGGGGGGG
->r5 only 5' adapter
-AAAAAAAAAACCCCCCCCCCGGGGGGG
+>r2 without any adapter
+GGGGGGGGGGGGGGGGGGG
 >r3 5' adapter, partial 3' adapter
-AAAAAAAAAACCCGGCCCCCTTTTT
+CCCGGCCCCC
 >r4 only 3' adapter
 GGGGGGGGGGCCCCCCCCCCTTTTTTTTTTGGGGGGG
->r2 without any adapter
-GGGGGGGGGGGGGGGGGGG
+>r5 only 5' adapter
+AAAAAAAAAACCCCCCCCCCGGGGGGG
+>r6 partial 5' adapter
+AAAAAACCCCCCCCCCTTTTTTTTTTGGGGGGG
+>r7 5' adapter plus preceding bases
+AACCGGTTTTAAAAAAAAAACCCCCCCCCCTTTTTTTTTTGGGGGGG
diff --git a/tests/cut/linked.fasta b/tests/cut/linked-not-anchored.fasta
similarity index 64%
copy from tests/cut/linked.fasta
copy to tests/cut/linked-not-anchored.fasta
index c010e80..34074a7 100644
--- a/tests/cut/linked.fasta
+++ b/tests/cut/linked-not-anchored.fasta
@@ -1,10 +1,14 @@
 >r1 5' adapter and 3' adapter
 CCCCCCCCCC
->r5 only 5' adapter
-CCCCCCCCCCGGGGGGG
+>r2 without any adapter
+GGGGGGGGGGGGGGGGGGG
 >r3 5' adapter, partial 3' adapter
 CCCGGCCCCC
 >r4 only 3' adapter
-GGGGGGGGGGCCCCCCCCCCTTTTTTTTTTGGGGGGG
->r2 without any adapter
-GGGGGGGGGGGGGGGGGGG
+GGGGGGGGGGCCCCCCCCCC
+>r5 only 5' adapter
+CCCCCCCCCCGGGGGGG
+>r6 partial 5' adapter
+CCCCCCCCCC
+>r7 5' adapter plus preceding bases
+CCCCCCCCCC
diff --git a/tests/cut/linked.fasta b/tests/cut/linked.fasta
index c010e80..175c42e 100644
--- a/tests/cut/linked.fasta
+++ b/tests/cut/linked.fasta
@@ -1,10 +1,14 @@
 >r1 5' adapter and 3' adapter
 CCCCCCCCCC
->r5 only 5' adapter
-CCCCCCCCCCGGGGGGG
+>r2 without any adapter
+GGGGGGGGGGGGGGGGGGG
 >r3 5' adapter, partial 3' adapter
 CCCGGCCCCC
 >r4 only 3' adapter
 GGGGGGGGGGCCCCCCCCCCTTTTTTTTTTGGGGGGG
->r2 without any adapter
-GGGGGGGGGGGGGGGGGGG
+>r5 only 5' adapter
+CCCCCCCCCCGGGGGGG
+>r6 partial 5' adapter
+AAAAAACCCCCCCCCCTTTTTTTTTTGGGGGGG
+>r7 5' adapter plus preceding bases
+AACCGGTTTTAAAAAAAAAACCCCCCCCCCTTTTTTTTTTGGGGGGG
diff --git a/tests/data/block1.fastq.bz2 b/tests/data/block1.fastq.bz2
new file mode 100644
index 0000000..8caa5bc
Binary files /dev/null and b/tests/data/block1.fastq.bz2 differ
diff --git a/tests/data/block2.fastq.bz2 b/tests/data/block2.fastq.bz2
new file mode 100644
index 0000000..5ed6b97
Binary files /dev/null and b/tests/data/block2.fastq.bz2 differ
diff --git a/tests/data/linked.fasta b/tests/data/linked.fasta
index 5d21f89..ed15fef 100644
--- a/tests/data/linked.fasta
+++ b/tests/data/linked.fasta
@@ -1,10 +1,14 @@
 >r1 5' adapter and 3' adapter
 AAAAAAAAAACCCCCCCCCCTTTTTTTTTTGGGGGGG
->r5 only 5' adapter
-AAAAAAAAAACCCCCCCCCCGGGGGGG
+>r2 without any adapter
+GGGGGGGGGGGGGGGGGGG
 >r3 5' adapter, partial 3' adapter
 AAAAAAAAAACCCGGCCCCCTTTTT
 >r4 only 3' adapter
 GGGGGGGGGGCCCCCCCCCCTTTTTTTTTTGGGGGGG
->r2 without any adapter
-GGGGGGGGGGGGGGGGGGG
+>r5 only 5' adapter
+AAAAAAAAAACCCCCCCCCCGGGGGGG
+>r6 partial 5' adapter
+AAAAAACCCCCCCCCCTTTTTTTTTTGGGGGGG
+>r7 5' adapter plus preceding bases
+AACCGGTTTTAAAAAAAAAACCCCCCCCCCTTTTTTTTTTGGGGGGG
diff --git a/tests/data/multiblock.fastq.bz2 b/tests/data/multiblock.fastq.bz2
new file mode 100644
index 0000000..e762565
Binary files /dev/null and b/tests/data/multiblock.fastq.bz2 differ
diff --git a/tests/testadapters.py b/tests/testadapters.py
index 4d3147b..f1f38e1 100644
--- a/tests/testadapters.py
+++ b/tests/testadapters.py
@@ -6,6 +6,7 @@ from cutadapt.seqio import Sequence
 from cutadapt.adapters import (Adapter, Match, ColorspaceAdapter, FRONT, BACK,
 	parse_braces, LinkedAdapter)
 
+
 def test_issue_52():
 	adapter = Adapter(
 		sequence='GAACTCCAGTCACNNNNN',
@@ -15,7 +16,8 @@ def test_issue_52():
 		read_wildcards=False,
 		adapter_wildcards=True)
 	read = Sequence(name="abc", sequence='CCCCAGAACTACAGTCCCGGC')
-	am = Match(astart=0, astop=17, rstart=5, rstop=21, matches=15, errors=2, front=None, adapter=adapter, read=read)
+	am = Match(astart=0, astop=17, rstart=5, rstop=21, matches=15, errors=2,
+		remove_before=False, adapter=adapter, read=read)
 	assert am.wildcards() == 'GGC'
 	"""
 	The result above should actually be 'CGGC' since the correct
@@ -91,8 +93,7 @@ def test_parse_braces_fail():
 def test_linked_adapter():
 	linked_adapter = LinkedAdapter('AAAA', 'TTTT')
 	sequence = Sequence(name='seq', sequence='AAAACCCCCTTTT')
-	match = linked_adapter.match_to(sequence)
-	trimmed = linked_adapter.trimmed(match)
+	trimmed = linked_adapter.match_to(sequence).trimmed()
 	assert trimmed.name == 'seq'
 	assert trimmed.sequence == 'CCCCC'
 
@@ -107,9 +108,8 @@ def test_info_record():
 		adapter_wildcards=True,
 		name="Foo")
 	read = Sequence(name="abc", sequence='CCCCAGAACTACAGTCCCGGC')
-	am = Match(astart=0, astop=17, rstart=5, rstop=21, matches=15, errors=2, front=None, 
+	am = Match(astart=0, astop=17, rstart=5, rstop=21, matches=15, errors=2, remove_before=False,
 		adapter=adapter, read=read)
-	print(am.get_info_record())
 	assert am.get_info_record() == (
 		"abc",
 		2,
@@ -123,3 +123,19 @@ def test_info_record():
 		'', 
 		''
 	)
+
+
+def test_random_match_probabilities():
+	a = Adapter('A', where=BACK, max_error_rate=0.1)
+	assert a.random_match_probabilities(0.5) == [1, 0.25]
+	assert a.random_match_probabilities(0.2) == [1, 0.4]
+
+	for s in ('ACTG', 'XMWH'):
+		a = Adapter(s, where=BACK, max_error_rate=0.1)
+		assert a.random_match_probabilities(0.5) == [1, 0.25, 0.25**2, 0.25**3, 0.25**4]
+		assert a.random_match_probabilities(0.2) == [1, 0.4, 0.4*0.1, 0.4*0.1*0.4, 0.4*0.1*0.4*0.1]
+
+	a = Adapter('GTCA', where=FRONT, max_error_rate=0.1)
+	assert a.random_match_probabilities(0.5) == [1, 0.25, 0.25**2, 0.25**3, 0.25**4]
+	assert a.random_match_probabilities(0.2) == [1, 0.4, 0.4*0.1, 0.4*0.1*0.4, 0.4*0.1*0.4*0.1]
+
diff --git a/tests/testcolorspace.py b/tests/testcolorspace.py
index 16a9d88..3ac3c46 100644
--- a/tests/testcolorspace.py
+++ b/tests/testcolorspace.py
@@ -63,28 +63,28 @@ def test_decode():
 
 
 def test_qualtrim_csfastaqual():
-	'''-q with csfasta/qual files'''
+	"""-q with csfasta/qual files"""
 	run("-c -q 10", "solidqual.fastq", "solid.csfasta", 'solid.qual')
 
 
 def test_E3M():
-	'''Read the E3M dataset'''
+	"""Read the E3M dataset"""
 	# not really colorspace, but a fasta/qual file pair
 	main(['-o', '/dev/null', datapath("E3M.fasta"), datapath("E3M.qual")])
 
 
 def test_bwa():
-	'''MAQ-/BWA-compatible output'''
+	"""MAQ-/BWA-compatible output"""
 	run("-c -e 0.12 -a 330201030313112312 -x 552: --maq", "solidmaq.fastq", "solid.csfasta", 'solid.qual')
 
 
 def test_bfast():
-	'''BFAST-compatible output'''
+	"""BFAST-compatible output"""
 	run("-c -e 0.12 -a 330201030313112312 -x abc: --strip-f3", "solidbfast.fastq", "solid.csfasta", 'solid.qual')
 
 
 def test_trim_095():
-	'''some reads properly trimmed since cutadapt 0.9.5'''
+	"""some reads properly trimmed since cutadapt 0.9.5"""
 	run("-c -e 0.122 -a 330201030313112312", "solid.fasta", "solid.fasta")
 
 
@@ -93,46 +93,46 @@ def test_solid():
 
 
 def test_solid_basespace_adapter():
-	'''colorspace adapter given in basespace'''
+	"""colorspace adapter given in basespace"""
 	run("-c -e 0.122 -a CGCCTTGGCCGTACAGCAG", "solid.fastq", "solid.fastq")
 
 
 def test_solid5p():
-	'''test 5' colorspace adapter'''
+	"""test 5' colorspace adapter"""
 	# this is not a real adapter, just a random string
 	# in colorspace: C0302201212322332333
 	run("-c -e 0.1 --trim-primer -g CCGGAGGTCAGCTCGCTATA", "solid5p.fasta", "solid5p.fasta")
 
 
 def test_solid5p_prefix_notrim():
-	'''test anchored 5' colorspace adapter, no primer trimming'''
+	"""test anchored 5' colorspace adapter, no primer trimming"""
 	run("-c -e 0.1 -g ^CCGGAGGTCAGCTCGCTATA", "solid5p-anchored.notrim.fasta", "solid5p.fasta")
 
 
 def test_solid5p_prefix():
-	'''test anchored 5' colorspace adapter'''
+	"""test anchored 5' colorspace adapter"""
 	run("-c -e 0.1 --trim-primer -g ^CCGGAGGTCAGCTCGCTATA", "solid5p-anchored.fasta", "solid5p.fasta")
 
 
 def test_solid5p_fastq():
-	'''test 5' colorspace adapter'''
+	"""test 5' colorspace adapter"""
 	# this is not a real adapter, just a random string
 	# in colorspace: C0302201212322332333
 	run("-c -e 0.1 --trim-primer -g CCGGAGGTCAGCTCGCTATA", "solid5p.fastq", "solid5p.fastq")
 
 
 def test_solid5p_prefix_notrim_fastq():
-	'''test anchored 5' colorspace adapter, no primer trimming'''
+	"""test anchored 5' colorspace adapter, no primer trimming"""
 	run("-c -e 0.1 -g ^CCGGAGGTCAGCTCGCTATA", "solid5p-anchored.notrim.fastq", "solid5p.fastq")
 
 
 def test_solid5p_prefix_fastq():
-	'''test anchored 5' colorspace adapter'''
+	"""test anchored 5' colorspace adapter"""
 	run("-c -e 0.1 --trim-primer -g ^CCGGAGGTCAGCTCGCTATA", "solid5p-anchored.fastq", "solid5p.fastq")
 
 
 def test_sra_fastq():
-	'''test SRA-formatted colorspace FASTQ'''
+	"""test SRA-formatted colorspace FASTQ"""
 	run("-c -e 0.1 --format sra-fastq -a CGCCTTGGCCGTACAGCAG", "sra.fastq", "sra.fastq")
 
 
diff --git a/tests/testpaired.py b/tests/testpaired.py
index f3f687a..5209af3 100644
--- a/tests/testpaired.py
+++ b/tests/testpaired.py
@@ -4,7 +4,8 @@ from __future__ import print_function, division, absolute_import
 import shutil
 from nose.tools import raises
 from cutadapt.scripts import cutadapt
-from .utils import run, files_equal, datapath, cutpath, redirect_stderr, temporary_path
+from .utils import run, assert_files_equal, datapath, cutpath, redirect_stderr, temporary_path
+
 
 def run_paired(params, in1, in2, expected1, expected2):
 	if type(params) is str:
@@ -14,8 +15,8 @@ def run_paired(params, in1, in2, expected1, expected2):
 			params += ['-o', p1, '-p', p2]
 			params += [datapath(in1), datapath(in2)]
 			assert cutadapt.main(params) is None
-			assert files_equal(cutpath(expected1), p1)
-			assert files_equal(cutpath(expected2), p2)
+			assert_files_equal(cutpath(expected1), p1)
+			assert_files_equal(cutpath(expected2), p2)
 
 
 def run_interleaved(params, inpath1, inpath2=None, expected1=None, expected2=None):
@@ -37,24 +38,25 @@ def run_interleaved(params, inpath1, inpath2=None, expected1=None, expected2=Non
 			with temporary_path('tmp2-' + expected2) as tmp2:
 				params += ['-p', tmp2]
 				assert cutadapt.main(params + paths) is None
-				assert files_equal(cutpath(expected2), tmp2)
+				assert_files_equal(cutpath(expected2), tmp2)
 		else:
 			assert cutadapt.main(params + paths) is None
-		assert files_equal(cutpath(expected1), tmp1)
+		assert_files_equal(cutpath(expected1), tmp1)
 
 
 def test_paired_separate():
-	'''test separate trimming of paired-end reads'''
+	"""test separate trimming of paired-end reads"""
 	run('-a TTAGACATAT', 'paired-separate.1.fastq', 'paired.1.fastq')
 	run('-a CAGTGGAGTA', 'paired-separate.2.fastq', 'paired.2.fastq')
 
 
 def test_paired_end_legacy():
-	'''--paired-output, not using -A/-B/-G'''
+	"""--paired-output, not using -A/-B/-G"""
 	# the -m 14 filters out one read, which should then also be filtered out in the second output file
 	# -q 10 should not change anything: qualities in file 1 are high enough,
 	# qualities in file 2 should not be inspected.
-	run_paired('-a TTAGACATAT -m 14 -q 10',
+	run_paired(
+		'-a TTAGACATAT -m 14 -q 10',
 		in1='paired.1.fastq', in2='paired.2.fastq',
 		expected1='paired.m14.1.fastq', expected2='paired.m14.2.fastq'
 	)
@@ -63,14 +65,15 @@ def test_paired_end_legacy():
 def test_untrimmed_paired_output():
 	with temporary_path("tmp-untrimmed.1.fastq") as untrimmed1:
 		with temporary_path("tmp-untrimmed.2.fastq") as untrimmed2:
-			run_paired(['-a', 'TTAGACATAT',
-				'--untrimmed-output', untrimmed1,
-				'--untrimmed-paired-output', untrimmed2],
+			run_paired(
+				['-a', 'TTAGACATAT',
+					'--untrimmed-output', untrimmed1,
+					'--untrimmed-paired-output', untrimmed2],
 				in1='paired.1.fastq', in2='paired.2.fastq',
 				expected1='paired-trimmed.1.fastq', expected2='paired-trimmed.2.fastq'
 			)
-			assert files_equal(cutpath('paired-untrimmed.1.fastq'), untrimmed1)
-			assert files_equal(cutpath('paired-untrimmed.2.fastq'), untrimmed2)
+			assert_files_equal(cutpath('paired-untrimmed.1.fastq'), untrimmed1)
+			assert_files_equal(cutpath('paired-untrimmed.2.fastq'), untrimmed2)
 
 
 def test_explicit_format_with_paired():
@@ -79,7 +82,8 @@ def test_explicit_format_with_paired():
 		with temporary_path("paired.2.txt") as txt2:
 			shutil.copyfile(datapath("paired.1.fastq"), txt1)
 			shutil.copyfile(datapath("paired.2.fastq"), txt2)
-			run_paired('--format=fastq -a TTAGACATAT -m 14',
+			run_paired(
+				'--format=fastq -a TTAGACATAT -m 14',
 				in1=txt1, in2=txt2,
 				expected1='paired.m14.1.fastq',
 				expected2='paired.m14.2.fastq'
@@ -88,12 +92,16 @@ def test_explicit_format_with_paired():
 
 def test_no_trimming_legacy():
 	# make sure that this doesn't divide by zero
-	cutadapt.main(['-a', 'XXXXX', '-o', '/dev/null', '-p', '/dev/null', datapath('paired.1.fastq'), datapath('paired.2.fastq')])
+	cutadapt.main([
+		'-a', 'XXXXX', '-o', '/dev/null', '-p', '/dev/null',
+		datapath('paired.1.fastq'), datapath('paired.2.fastq')])
 
 
 def test_no_trimming():
 	# make sure that this doesn't divide by zero
-	cutadapt.main(['-a', 'XXXXX', '-A', 'XXXXX', '-o', '/dev/null', '-p', '/dev/null', datapath('paired.1.fastq'), datapath('paired.2.fastq')])
+	cutadapt.main([
+		'-a', 'XXXXX', '-A', 'XXXXX', '-o', '/dev/null', '-p', '/dev/null',
+		datapath('paired.1.fastq'), datapath('paired.2.fastq')])
 
 
 @raises(SystemExit)
@@ -112,7 +120,10 @@ def test_first_too_short():
 		with open(trunc1, 'w') as f:
 			f.writelines(lines)
 		with redirect_stderr():
-			cutadapt.main('-a XX -o /dev/null --paired-output out.fastq'.split() + [trunc1, datapath('paired.2.fastq')])
+			cutadapt.main(
+				'-a XX -o /dev/null --paired-output out.fastq'.split() +
+				[trunc1, datapath('paired.2.fastq')]
+			)
 
 
 @raises(SystemExit)
@@ -125,7 +136,8 @@ def test_second_too_short():
 		with open(trunc2, 'w') as f:
 			f.writelines(lines)
 		with redirect_stderr():
-			cutadapt.main('-a XX -o /dev/null --paired-output out.fastq'.split() + [datapath('paired.1.fastq'), trunc2])
+			cutadapt.main('-a XX -o /dev/null --paired-output out.fastq'.split() +
+				[datapath('paired.1.fastq'), trunc2])
 
 
 @raises(SystemExit)
@@ -138,13 +150,15 @@ def test_unmatched_read_names():
 		with open(swapped, 'w') as f:
 			f.writelines(lines)
 		with redirect_stderr():
-			cutadapt.main('-a XX -o out1.fastq --paired-output out2.fastq'.split() + [swapped, datapath('paired.2.fastq')])
+			cutadapt.main('-a XX -o out1.fastq --paired-output out2.fastq'.split() +
+				[swapped, datapath('paired.2.fastq')])
 
 
 @raises(SystemExit)
 def test_p_without_o():
 	"""Option -p given but -o missing"""
-	cutadapt.main('-a XX -p /dev/null'.split() + [datapath('paired.1.fastq'), datapath('paired.2.fastq')])
+	cutadapt.main('-a XX -p /dev/null'.split() +
+		[datapath('paired.1.fastq'), datapath('paired.2.fastq')])
 
 
 @raises(SystemExit)
@@ -154,53 +168,60 @@ def test_paired_but_only_one_input_file():
 
 
 def test_legacy_minlength():
-	'''Ensure -m is not applied to second read in a pair in legacy mode'''
-	run_paired('-a XXX -m 27',
+	"""Ensure -m is not applied to second read in a pair in legacy mode"""
+	run_paired(
+		'-a XXX -m 27',
 		in1='paired.1.fastq', in2='paired.2.fastq',
 		expected1='paired-m27.1.fastq', expected2='paired-m27.2.fastq'
 	)
 
 
 def test_paired_end():
-	'''single-pass paired-end with -m'''
-	run_paired('-a TTAGACATAT -A CAGTGGAGTA -m 14',
+	"""single-pass paired-end with -m"""
+	run_paired(
+		'-a TTAGACATAT -A CAGTGGAGTA -m 14',
 		in1='paired.1.fastq', in2='paired.2.fastq',
 		expected1='paired.1.fastq', expected2='paired.2.fastq'
 	)
 
 
 def test_paired_anchored_back_no_indels():
-	run_paired("-a BACKADAPTER$ -A BACKADAPTER$ -N --no-indels",
+	run_paired(
+		'-a BACKADAPTER$ -A BACKADAPTER$ -N --no-indels',
 		in1='anchored-back.fasta', in2='anchored-back.fasta',
 		expected1='anchored-back.fasta', expected2="anchored-back.fasta"
 	)
 
 
 def test_paired_end_qualtrim():
-	'''single-pass paired-end with -q and -m'''
-	run_paired('-q 20 -a TTAGACATAT -A CAGTGGAGTA -m 14 -M 90',
+	"""single-pass paired-end with -q and -m"""
+	run_paired(
+		'-q 20 -a TTAGACATAT -A CAGTGGAGTA -m 14 -M 90',
 		in1='paired.1.fastq', in2='paired.2.fastq',
 		expected1='pairedq.1.fastq', expected2='pairedq.2.fastq'
 	)
 
 
 def test_paired_end_qualtrim_swapped():
-	'''single-pass paired-end with -q and -m, but files swapped'''
-	run_paired('-q 20 -a CAGTGGAGTA -A TTAGACATAT -m 14',
+	"""single-pass paired-end with -q and -m, but files swapped"""
+	run_paired(
+		'-q 20 -a CAGTGGAGTA -A TTAGACATAT -m 14',
 		in1='paired.2.fastq', in2='paired.1.fastq',
 		expected1='pairedq.2.fastq', expected2='pairedq.1.fastq'
 	)
 
 
 def test_paired_end_cut():
-	run_paired('-u 3 -u -1 -U 4 -U -2',
+	run_paired(
+		'-u 3 -u -1 -U 4 -U -2',
 		in1='paired.1.fastq', in2='paired.2.fastq',
 		expected1='pairedu.1.fastq', expected2='pairedu.2.fastq'
 	)
 
 
-def test_paired_end_A_only():
-	run_paired('-A CAGTGGAGTA',
+def test_paired_end_upper_a_only():
+	run_paired(
+		'-A CAGTGGAGTA',
 		in1='paired.1.fastq', in2='paired.2.fastq',
 		expected1='paired-onlyA.1.fastq', expected2='paired-onlyA.2.fastq'
 	)
@@ -209,37 +230,42 @@ def test_paired_end_A_only():
 def test_discard_untrimmed():
 	# issue #146
 	# the first adapter is a sequence cut out from the first read
-	run_paired('-a CTCCAGCTTAGACATATC -A XXXXXXXX --discard-untrimmed',
+	run_paired(
+		'-a CTCCAGCTTAGACATATC -A XXXXXXXX --discard-untrimmed',
 		in1='paired.1.fastq', in2='paired.2.fastq',
 		expected1='empty.fastq', expected2='empty.fastq'
 	)
 
 
 def test_discard_trimmed():
-	run_paired('-A C -O 1 --discard-trimmed',  # applies everywhere
+	run_paired(
+		'-A C -O 1 --discard-trimmed',  # applies everywhere
 		in1='paired.1.fastq', in2='paired.2.fastq',
 		expected1='empty.fastq', expected2='empty.fastq'
 	)
 
 
 def test_interleaved_in_and_out():
-	'''Single-pass interleaved paired-end with -q and -m'''
-	run_interleaved('-q 20 -a TTAGACATAT -A CAGTGGAGTA -m 14 -M 90',
+	"""Single-pass interleaved paired-end with -q and -m"""
+	run_interleaved(
+		'-q 20 -a TTAGACATAT -A CAGTGGAGTA -m 14 -M 90',
 		inpath1='interleaved.fastq', expected1='interleaved.fastq'
 	)
 
 
 def test_interleaved_in():
-	'''Interleaved input, two files output'''
-	run_interleaved('-q 20 -a TTAGACATAT -A CAGTGGAGTA -m 14 -M 90',
+	"""Interleaved input, two files output"""
+	run_interleaved(
+		'-q 20 -a TTAGACATAT -A CAGTGGAGTA -m 14 -M 90',
 		inpath1='interleaved.fastq',
 		expected1='pairedq.1.fastq', expected2='pairedq.2.fastq'
 	)
 
 
 def test_interleaved_out():
-	'''Two files input, interleaved output'''
-	run_interleaved('-q 20 -a TTAGACATAT -A CAGTGGAGTA -m 14 -M 90',
+	"""Two files input, interleaved output"""
+	run_interleaved(
+		'-q 20 -a TTAGACATAT -A CAGTGGAGTA -m 14 -M 90',
 		inpath1='paired.1.fastq', inpath2='paired.2.fastq',
 		expected1='interleaved.fastq'
 	)
@@ -252,12 +278,13 @@ def test_interleaved_neither_nor():
 		with temporary_path("temp-paired.2.fastq") as p2:
 			params = '-a XX --interleaved'.split()
 			with redirect_stderr():
-				params += [ '-o', p1, '-p1', p2, 'paired.1.fastq', 'paired.2.fastq']
+				params += ['-o', p1, '-p1', p2, 'paired.1.fastq', 'paired.2.fastq']
 				cutadapt.main(params)
 
 
 def test_pair_filter():
-	run_paired('--pair-filter=both -a TTAGACATAT -A GGAGTA -m 14',
+	run_paired(
+		'--pair-filter=both -a TTAGACATAT -A GGAGTA -m 14',
 		in1='paired.1.fastq', in2='paired.2.fastq',
 		expected1='paired-filterboth.1.fastq', expected2='paired-filterboth.2.fastq'
 	)
@@ -266,31 +293,34 @@ def test_pair_filter():
 def test_too_short_paired_output():
 	with temporary_path("temp-too-short.1.fastq") as p1:
 		with temporary_path("temp-too-short.2.fastq") as p2:
-			run_paired('-a TTAGACATAT -A CAGTGGAGTA -m 14 --too-short-output '
+			run_paired(
+				'-a TTAGACATAT -A CAGTGGAGTA -m 14 --too-short-output '
 				'{0} --too-short-paired-output {1}'.format(p1, p2),
 				in1='paired.1.fastq', in2='paired.2.fastq',
 				expected1='paired.1.fastq', expected2='paired.2.fastq'
 			)
-			assert files_equal(cutpath('paired-too-short.1.fastq'), p1)
-			assert files_equal(cutpath('paired-too-short.2.fastq'), p2)
+			assert_files_equal(cutpath('paired-too-short.1.fastq'), p1)
+			assert_files_equal(cutpath('paired-too-short.2.fastq'), p2)
 
 
 def test_too_long_output():
-	with temporary_path("temp-too-long.1.fastq") as p1:
-		with temporary_path("temp-too-long.2.fastq") as p2:
-			run_paired('-a TTAGACATAT -A CAGTGGAGTA -M 14 --too-long-output '
+	with temporary_path('temp-too-long.1.fastq') as p1:
+		with temporary_path('temp-too-long.2.fastq') as p2:
+			run_paired(
+				'-a TTAGACATAT -A CAGTGGAGTA -M 14 --too-long-output '
 				'{0} --too-long-paired-output {1}'.format(p1, p2),
 				in1='paired.1.fastq', in2='paired.2.fastq',
 				expected1='paired-too-short.1.fastq', expected2='paired-too-short.2.fastq'
 			)
-			assert files_equal(cutpath('paired.1.fastq'), p1)
-			assert files_equal(cutpath('paired.2.fastq'), p2)
+			assert_files_equal(cutpath('paired.1.fastq'), p1)
+			assert_files_equal(cutpath('paired.2.fastq'), p2)
 
 
 @raises(SystemExit)
 def test_too_short_output_paired_option_missing():
-	with temporary_path("temp-too-short.1.fastq") as p1:
-		run_paired('-a TTAGACATAT -A CAGTGGAGTA -m 14 --too-short-output '
+	with temporary_path('temp-too-short.1.fastq') as p1:
+		run_paired(
+			'-a TTAGACATAT -A CAGTGGAGTA -m 14 --too-short-output '
 			'{0}'.format(p1),
 			in1='paired.1.fastq', in2='paired.2.fastq',
 			expected1='paired.1.fastq', expected2='paired.2.fastq'
diff --git a/tests/tests.py b/tests/tests.py
index 21f70e1..6406e4c 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -9,152 +9,170 @@ import sys
 from nose.tools import raises
 from cutadapt.scripts import cutadapt
 from cutadapt.compat import StringIO
-from .utils import run, files_equal, datapath, cutpath, redirect_stderr, temporary_path
+from .utils import run, assert_files_equal, datapath, cutpath, redirect_stderr, temporary_path
+
 
 def test_example():
 	run('-N -b ADAPTER', 'example.fa', 'example.fa')
 
+
 def test_small():
 	run('-b TTAGACATATCTCCGTCG', 'small.fastq', 'small.fastq')
 
+
 def test_empty():
-	'''empty input'''
+	"""empty input"""
 	run('-a TTAGACATATCTCCGTCG', 'empty.fastq', 'empty.fastq')
 
+
 def test_newlines():
-	'''DOS/Windows newlines'''
+	"""DOS/Windows newlines"""
 	run('-e 0.12 -b TTAGACATATCTCCGTCG', 'dos.fastq', 'dos.fastq')
 
+
 def test_lowercase():
-	'''lowercase adapter'''
+	"""lowercase adapter"""
 	run('-b ttagacatatctccgtcg', 'lowercase.fastq', 'small.fastq')
 
 
 def test_rest():
-	'''-r/--rest-file'''
+	"""-r/--rest-file"""
 	with temporary_path('rest.tmp') as rest_tmp:
 		run(['-b', 'ADAPTER', '-N', '-r', rest_tmp], "rest.fa", "rest.fa")
-		assert files_equal(datapath('rest.txt'), rest_tmp)
+		assert_files_equal(datapath('rest.txt'), rest_tmp)
 
 
 def test_restfront():
 	with temporary_path("rest.txt") as path:
 		run(['-g', 'ADAPTER', '-N', '-r', path], "restfront.fa", "rest.fa")
-		assert files_equal(datapath('restfront.txt'), path)
+		assert_files_equal(datapath('restfront.txt'), path)
 
 
 def test_discard():
-	'''--discard'''
+	"""--discard"""
 	run("-b TTAGACATATCTCCGTCG --discard", "discard.fastq", "small.fastq")
 
 
 def test_discard_untrimmed():
-	'''--discard-untrimmed'''
+	"""--discard-untrimmed"""
 	run('-b CAAGAT --discard-untrimmed', 'discard-untrimmed.fastq', 'small.fastq')
 
 
 def test_plus():
-	'''test if sequence name after the "+" is retained'''
+	"""test if sequence name after the "+" is retained"""
 	run("-e 0.12 -b TTAGACATATCTCCGTCG", "plus.fastq", "plus.fastq")
 
 
 def test_extensiontxtgz():
-	'''automatic recognition of "_sequence.txt.gz" extension'''
+	"""automatic recognition of "_sequence.txt.gz" extension"""
 	run("-b TTAGACATATCTCCGTCG", "s_1_sequence.txt", "s_1_sequence.txt.gz")
 
 
 def test_format():
-	'''the -f/--format parameter'''
+	"""the -f/--format parameter"""
 	run("-f fastq -b TTAGACATATCTCCGTCG", "small.fastq", "small.myownextension")
 
 
 def test_minimum_length():
-	'''-m/--minimum-length'''
+	"""-m/--minimum-length"""
 	run("-c -m 5 -a 330201030313112312", "minlen.fa", "lengths.fa")
 
 
 def test_too_short():
-	'''--too-short-output'''
+	"""--too-short-output"""
 	run("-c -m 5 -a 330201030313112312 --too-short-output tooshort.tmp.fa", "minlen.fa", "lengths.fa")
-	assert files_equal(datapath('tooshort.fa'), "tooshort.tmp.fa")
+	assert_files_equal(datapath('tooshort.fa'), "tooshort.tmp.fa")
 	os.remove('tooshort.tmp.fa')
 
 
 def test_too_short_no_primer():
-	'''--too-short-output and --trim-primer'''
+	"""--too-short-output and --trim-primer"""
 	run("-c -m 5 -a 330201030313112312 --trim-primer --too-short-output tooshort.tmp.fa", "minlen.noprimer.fa", "lengths.fa")
-	assert files_equal(datapath('tooshort.noprimer.fa'), "tooshort.tmp.fa")
+	assert_files_equal(datapath('tooshort.noprimer.fa'), "tooshort.tmp.fa")
 	os.remove('tooshort.tmp.fa')
 
 
 def test_maximum_length():
-	'''-M/--maximum-length'''
+	"""-M/--maximum-length"""
 	run("-c -M 5 -a 330201030313112312", "maxlen.fa", "lengths.fa")
 
 
 def test_too_long():
-	'''--too-long-output'''
+	"""--too-long-output"""
 	run("-c -M 5 --too-long-output toolong.tmp.fa -a 330201030313112312", "maxlen.fa", "lengths.fa")
-	assert files_equal(datapath('toolong.fa'), "toolong.tmp.fa")
+	assert_files_equal(datapath('toolong.fa'), "toolong.tmp.fa")
 	os.remove('toolong.tmp.fa')
 
 
 def test_length_tag():
-	'''454 data; -n and --length-tag'''
-	run("-n 3 -e 0.1 --length-tag length= " \
-		"-b TGAGACACGCAACAGGGGAAAGGCAAGGCACACAGGGGATAGG "\
+	"""454 data; -n and --length-tag"""
+	run("-n 3 -e 0.1 --length-tag length= "
+		"-b TGAGACACGCAACAGGGGAAAGGCAAGGCACACAGGGGATAGG "
 		"-b TCCATCTCATCCCTGCGTGTCCCATCTGTTCCCTCCCTGTCTCA", '454.fa', '454.fa')
 
+
 def test_overlap_a():
-	'''-O/--overlap with -a (-c omitted on purpose)'''
+	"""-O/--overlap with -a (-c omitted on purpose)"""
 	run("-O 10 -a 330201030313112312 -e 0.0 -N", "overlapa.fa", "overlapa.fa")
 
+
 def test_overlap_b():
-	'''-O/--overlap with -b'''
+	"""-O/--overlap with -b"""
 	run("-O 10 -b TTAGACATATCTCCGTCG -N", "overlapb.fa", "overlapb.fa")
 
+
 def test_qualtrim():
-	'''-q with low qualities'''
+	"""-q with low qualities"""
 	run("-q 10 -a XXXXXX", "lowqual.fastq", "lowqual.fastq")
 
+
 def test_qualbase():
-	'''-q with low qualities, using ascii(quality+64) encoding'''
+	"""-q with low qualities, using ascii(quality+64) encoding"""
 	run("-q 10 --quality-base 64 -a XXXXXX", "illumina64.fastq", "illumina64.fastq")
 
+
 def test_quality_trim_only():
-	'''only trim qualities, do not remove adapters'''
+	"""only trim qualities, do not remove adapters"""
 	run("-q 10 --quality-base 64", "illumina64.fastq", "illumina64.fastq")
 
+
 def test_twoadapters():
-	'''two adapters'''
+	"""two adapters"""
 	run("-a AATTTCAGGAATT -a GTTCTCTAGTTCT", "twoadapters.fasta", "twoadapters.fasta")
 
+
 def test_polya():
-	'''poly-A tails'''
+	"""poly-A tails"""
 	run("-m 24 -O 10 -a AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "polya.fasta", "polya.fasta")
 
+
 def test_polya_brace_notation():
-	'''poly-A tails'''
+	"""poly-A tails"""
 	run("-m 24 -O 10 -a A{35}", "polya.fasta", "polya.fasta")
 
+
 def test_mask_adapter():
-	'''mask adapter with N (reads maintain the same length)'''
+	"""mask adapter with N (reads maintain the same length)"""
 	run("-b CAAG -n 3 --mask-adapter", "anywhere_repeat.fastq", "anywhere_repeat.fastq")
 
+
 def test_gz_multiblock():
-	'''compressed gz file with multiple blocks (created by concatenating two .gz files)'''
+	"""compressed gz file with multiple blocks (created by concatenating two .gz files)"""
 	run("-b TTAGACATATCTCCGTCG", "small.fastq", "multiblock.fastq.gz")
 
+
 def test_suffix():
-	'''-y/--suffix parameter, combined with _F3'''
+	"""-y/--suffix parameter, combined with _F3"""
 	run("-c -e 0.12 -a 1=330201030313112312 -y _my_suffix_{name} --strip-f3", "suffix.fastq", "solid.csfasta", 'solid.qual')
 
+
 def test_read_wildcard():
-	'''test wildcards in reads'''
+	"""test wildcards in reads"""
 	run("--match-read-wildcards -b ACGTACGT", "wildcard.fa", "wildcard.fa")
 
+
 def test_adapter_wildcard():
-	'''wildcards in adapter'''
+	"""wildcards in adapter"""
 	for adapter_type, expected in (
 			("-a", "wildcard_adapter.fa"),
 			("-b", "wildcard_adapter_anywhere.fa")):
@@ -166,40 +184,55 @@ def test_adapter_wildcard():
 			lines = [ line.strip() for line in lines ]
 			assert lines == ['AAA 1', 'GGG 2', 'CCC 3b', 'TTT 4b']
 
+
 def test_wildcard_N():
-	'''test 'N' wildcard matching with no allowed errors'''
+	"""test 'N' wildcard matching with no allowed errors"""
 	run("-e 0 -a GGGGGGG --match-read-wildcards", "wildcardN.fa", "wildcardN.fa")
 
+
 def test_illumina_adapter_wildcard():
 	run("-a VCCGAMCYUCKHRKDCUBBCNUWNSGHCGU", "illumina.fastq", "illumina.fastq.gz")
 
+
 def test_adapter_front():
-	'''test adapter in front'''
+	"""test adapter in front"""
 	run("--front ADAPTER -N", "examplefront.fa", "example.fa")
 
+
 def test_literal_N():
-	'''test matching literal 'N's'''
+	"""test matching literal 'N's"""
 	run("-N -e 0.2 -a NNNNNNNNNNNNNN", "trimN3.fasta", "trimN3.fasta")
 
+
 def test_literal_N2():
 	run("-N -O 1 -g NNNNNNNNNNNNNN", "trimN5.fasta", "trimN5.fasta")
 
+
 def test_literal_N_brace_notation():
-	'''test matching literal 'N's'''
+	"""test matching literal 'N's"""
 	run("-N -e 0.2 -a N{14}", "trimN3.fasta", "trimN3.fasta")
 
+
 def test_literal_N2_brace_notation():
 	run("-N -O 1 -g N{14}", "trimN5.fasta", "trimN5.fasta")
 
+
 def test_anchored_front():
 	run("-g ^FRONTADAPT -N", "anchored.fasta", "anchored.fasta")
 
+
 def test_anchored_front_ellipsis_notation():
 	run("-a FRONTADAPT... -N", "anchored.fasta", "anchored.fasta")
 
+
 def test_anchored_back():
 	run("-a BACKADAPTER$ -N", "anchored-back.fasta", "anchored-back.fasta")
 
+
+def test_anchored_back_ellipsis_notation():
+	run("-a ...BACKADAPTER$ -N", "anchored-back.fasta", "anchored-back.fasta")
+
+
 def test_anchored_back_no_indels():
 	run("-a BACKADAPTER$ -N --no-indels", "anchored-back.fasta", "anchored-back.fasta")
 
@@ -208,11 +241,16 @@ def test_no_indels():
 	run('-a TTAGACATAT -g GAGATTGCCA --no-indels', 'no_indels.fasta', 'no_indels.fasta')
 
 
+def test_ellipsis_notation():
+	run('-a ...TTAGACATAT -g GAGATTGCCA --no-indels', 'no_indels.fasta', 'no_indels.fasta')
+
+
 def test_issue_46():
-	'''issue 46 - IndexError with --wildcard-file'''
+	"""issue 46 - IndexError with --wildcard-file"""
 	with temporary_path("wildcardtmp.txt") as wildcardtmp:
 		run("--anywhere=AACGTN --wildcard-file={0}".format(wildcardtmp), "issue46.fasta", "issue46.fasta")
 
+
 def test_strip_suffix():
 	run("--strip-suffix _sequence -a XXXXXXX", "stripped.fasta", "simple.fasta")
 
@@ -223,13 +261,13 @@ def test_info_file():
 	#
 	with temporary_path("infotmp.txt") as infotmp:
 		run(["--info-file", infotmp, '-a', 'adapt=GCCGAACTTCTTAGACTGCCTTAAGGACGT'], "illumina.fastq", "illumina.fastq.gz")
-		assert files_equal(cutpath('illumina.info.txt'), infotmp)
+		assert_files_equal(cutpath('illumina.info.txt'), infotmp)
 
 
 def test_info_file_times():
 	with temporary_path("infotmp.txt") as infotmp:
 		run(["--info-file", infotmp, '--times', '2', '-a', 'adapt=GCCGAACTTCTTA', '-a', 'adapt2=GACTGCCTTAAGGACGT'], "illumina5.fastq", "illumina5.fastq")
-		assert files_equal(cutpath('illumina5.info.txt'), infotmp)
+		assert_files_equal(cutpath('illumina5.info.txt'), infotmp)
 
 
 def test_info_file_fasta():
@@ -242,25 +280,27 @@ def test_named_adapter():
 	run("-a MY_ADAPTER=GCCGAACTTCTTAGACTGCCTTAAGGACGT", "illumina.fastq", "illumina.fastq.gz")
 
 
-def test_adapter_with_U():
+def test_adapter_with_u():
 	run("-a GCCGAACUUCUUAGACUGCCUUAAGGACGU", "illumina.fastq", "illumina.fastq.gz")
 
 
 def test_no_trim():
-	''' --no-trim '''
 	run("--no-trim --discard-untrimmed -a CCCTAGTTAAAC", 'no-trim.fastq', 'small.fastq')
 
 
 def test_bzip2():
-	'''test bzip2 support'''
 	run('-b TTAGACATATCTCCGTCG', 'small.fastq', 'small.fastq.bz2')
 
 
+if sys.version_info[:2] >= (3, 3):
+	def test_bzip2_multiblock():
+		run('-b TTAGACATATCTCCGTCG', 'small.fastq', 'multiblock.fastq.bz2')
+
+
 try:
 	import lzma
 
 	def test_xz():
-		'''test xz support'''
 		run('-b TTAGACATATCTCCGTCG', 'small.fastq', 'small.fastq.xz')
 except ImportError:
 	pass
@@ -285,20 +325,26 @@ def test_two_fastqs():
 
 
 def test_anchored_no_indels():
-	'''anchored 5' adapter, mismatches only (no indels)'''
+	"""anchored 5' adapter, mismatches only (no indels)"""
 	run('-g ^TTAGACATAT --no-indels -e 0.1', 'anchored_no_indels.fasta', 'anchored_no_indels.fasta')
 
 
 def test_anchored_no_indels_wildcard_read():
-	'''anchored 5' adapter, mismatches only (no indels), but wildcards in the read count as matches'''
+	"""anchored 5' adapter, mismatches only (no indels), but wildcards in the read count as matches"""
 	run('-g ^TTAGACATAT --match-read-wildcards --no-indels -e 0.1', 'anchored_no_indels_wildcard.fasta', 'anchored_no_indels.fasta')
 
 
 def test_anchored_no_indels_wildcard_adapt():
-	'''anchored 5' adapter, mismatches only (no indels), but wildcards in the adapter count as matches'''
+	"""anchored 5' adapter, mismatches only (no indels), but wildcards in the adapter count as matches"""
 	run('-g ^TTAGACANAT --no-indels -e 0.1', 'anchored_no_indels.fasta', 'anchored_no_indels.fasta')
 
 
+ at raises(SystemExit)
+def test_non_iupac_characters():
+	with redirect_stderr():
+		cutadapt.main(['-a', 'ZACGT', datapath('small.fastq')])
+
+
 def test_unconditional_cut_front():
 	run('-u 5', 'unconditional-front.fastq', 'small.fastq')
 
@@ -314,15 +360,17 @@ def test_unconditional_cut_both():
 def test_untrimmed_output():
 	with temporary_path('untrimmed.tmp.fastq') as tmp:
 		run(['-a', 'TTAGACATATCTCCGTCG', '--untrimmed-output', tmp], 'small.trimmed.fastq', 'small.fastq')
-		assert files_equal(cutpath('small.untrimmed.fastq'), tmp)
+		assert_files_equal(cutpath('small.untrimmed.fastq'), tmp)
 
 
 def test_adapter_file():
 	run('-a file:' + datapath('adapter.fasta'), 'illumina.fastq', 'illumina.fastq.gz')
 
+
 def test_adapter_file_5p_anchored():
 	run('-N -g file:' + datapath('prefix-adapter.fasta'), 'anchored.fasta', 'anchored.fasta')
 
+
 def test_adapter_file_3p_anchored():
 	run('-N -a file:' + datapath('suffix-adapter.fasta'), 'anchored-back.fasta', 'anchored-back.fasta')
 
@@ -339,9 +387,9 @@ def test_demultiplex():
 	multiout = os.path.join(os.path.dirname(__file__), 'data', 'tmp-demulti.{name}.fasta')
 	params = ['-a', 'first=AATTTCAGGAATT', '-a', 'second=GTTCTCTAGTTCT', '-o', multiout, datapath('twoadapters.fasta')]
 	assert cutadapt.main(params) is None
-	assert files_equal(cutpath('twoadapters.first.fasta'), multiout.format(name='first'))
-	assert files_equal(cutpath('twoadapters.second.fasta'), multiout.format(name='second'))
-	assert files_equal(cutpath('twoadapters.unknown.fasta'), multiout.format(name='unknown'))
+	assert_files_equal(cutpath('twoadapters.first.fasta'), multiout.format(name='first'))
+	assert_files_equal(cutpath('twoadapters.second.fasta'), multiout.format(name='second'))
+	assert_files_equal(cutpath('twoadapters.unknown.fasta'), multiout.format(name='unknown'))
 	os.remove(multiout.format(name='first'))
 	os.remove(multiout.format(name='second'))
 	os.remove(multiout.format(name='unknown'))
@@ -358,9 +406,9 @@ def test_max_n():
 def test_quiet_is_quiet():
 	captured_standard_output = StringIO()
 	captured_standard_error = StringIO()
+	old_stdout = sys.stdout
+	old_stderr = sys.stderr
 	try:
-		old_stdout = sys.stdout
-		old_stderr = sys.stderr
 		sys.stdout = captured_standard_output
 		sys.stderr = captured_standard_error
 		cutadapt.main(['-o', '/dev/null', '--quiet', '-a', 'XXXX', datapath('illumina.fastq.gz')])
@@ -379,6 +427,40 @@ def test_linked():
 	run('-a AAAAAAAAAA...TTTTTTTTTT', 'linked.fasta', 'linked.fasta')
 
 
+def test_linked_explicitly_anchored():
+	run('-a ^AAAAAAAAAA...TTTTTTTTTT', 'linked.fasta', 'linked.fasta')
+
+
+def test_linked_multiple():
+	run('-a AAAAAAAAAA...TTTTTTTTTT -a AAAAAAAAAA...GCGCGCGCGC', 'linked.fasta', 'linked.fasta')
+
+
+def test_linked_both_anchored():
+	run('-a AAAAAAAAAA...TTTTT$', 'linked-anchored.fasta', 'linked.fasta')
+
+
+def test_linked_5p_not_anchored():
+	run('-g AAAAAAAAAA...TTTTTTTTTT', 'linked-not-anchored.fasta', 'linked.fasta')
+
+
+ at raises(SystemExit)
+def test_linked_anywhere():
+	with redirect_stderr():
+		cutadapt.main(['-b', 'AAA...TTT', datapath('linked.fasta')])
+
+
+ at raises(SystemExit)
+def test_anywhere_anchored_5p():
+	with redirect_stderr():
+		cutadapt.main(['-b', '^AAA', datapath('small.fastq')])
+
+
+ at raises(SystemExit)
+def test_anywhere_anchored_3p():
+	with redirect_stderr():
+		cutadapt.main(['-b', 'TTT$', datapath('small.fastq')])
+
+
 def test_fasta():
 	run('-a TTAGACATATCTCCGTCG', 'small.fasta', 'small.fastq')
 
diff --git a/tests/testtrim.py b/tests/testtrim.py
index 09c3102..6e94004 100644
--- a/tests/testtrim.py
+++ b/tests/testtrim.py
@@ -3,7 +3,8 @@ from __future__ import print_function, division, absolute_import
 
 from cutadapt.seqio import ColorspaceSequence, Sequence
 from cutadapt.adapters import Adapter, ColorspaceAdapter, PREFIX, BACK
-from cutadapt.scripts.cutadapt import AdapterCutter
+from cutadapt.modifiers import AdapterCutter
+
 
 def test_cs_5p():
 	read = ColorspaceSequence("name", "0123", "DEFG", "T")
@@ -22,6 +23,6 @@ def test_statistics():
 	# TODO make this a lot simpler
 	trimmed_bp = 0
 	for adapter in adapters:
-		for d in (adapter.lengths_front, adapter.lengths_back):
+		for d in (cutter.adapter_statistics[adapter].lengths_front, cutter.adapter_statistics[adapter].lengths_back):
 			trimmed_bp += sum(seqlen * count for (seqlen, count) in d.items())
 	assert trimmed_bp <= len(read), trimmed_bp
diff --git a/tests/utils.py b/tests/utils.py
index 473e598..1d82f46 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -2,12 +2,14 @@
 from __future__ import print_function, division, absolute_import
 
 import sys, os
+import subprocess
 from contextlib import contextmanager
 from cutadapt.scripts import cutadapt
 
+
 @contextmanager
 def redirect_stderr():
-	"Send stderr to stdout. Nose doesn't capture stderr, yet."
+	"""Send stderr to stdout. Nose doesn't capture stderr, yet."""
 	old_stderr = sys.stderr
 	sys.stderr = sys.stdout
 	yield
@@ -32,8 +34,17 @@ def cutpath(path):
 	return os.path.join(os.path.dirname(__file__), 'cut', path)
 
 
-def files_equal(path1, path2):
-	return os.system("diff -u {0} {1}".format(path1, path2)) == 0
+class FilesDifferent(Exception):
+	pass
+
+
+def assert_files_equal(path1, path2):
+	try:
+		subprocess.check_output(['diff', '-u', path1, path2], stderr=subprocess.STDOUT)
+	except subprocess.CalledProcessError as e:
+		raise FilesDifferent('\n' + e.output.decode())
+	except AttributeError:  # Python 2.6 does not have check_output
+		assert subprocess.call(['diff', '-u', path1, path2]) == 0
 
 
 def run(params, expected, inpath, inpath2=None):
@@ -46,5 +57,5 @@ def run(params, expected, inpath, inpath2=None):
 			params += [ datapath(inpath2) ]
 		assert cutadapt.main(params) is None
 		# TODO redirect standard output
-		assert files_equal(cutpath(expected), tmp_fastaq)
+		assert_files_equal(cutpath(expected), tmp_fastaq)
 	# TODO diff log files

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/python-cutadapt.git



More information about the debian-med-commit mailing list