diff --git a/scadnano/scadnano.py b/scadnano/scadnano.py
index 9b4e869..e0902ee 100644
--- a/scadnano/scadnano.py
+++ b/scadnano/scadnano.py
@@ -54,7 +54,7 @@ so the user must take care not to set them.
 # needed to use forward annotations: https://docs.python.org/3/whatsnew/3.7.html#whatsnew37-pep563
 from __future__ import annotations
 
-__version__ = "0.19.0"  # version line; WARNING: do not remove or change this line or comment
+__version__ = "0.19.1"  # version line; WARNING: do not remove or change this line or comment
 
 import collections
 import dataclasses
@@ -2016,6 +2016,40 @@ def _is_close(x1: float, x2: float) -> bool:
     return abs(x1 - x2) < _floating_point_tolerance
 
 
+def _vendor_dna_sequence_substrand(substrand: Union[Domain, Loopout, Extension]) -> Optional[str]:
+    # used to share code between Domain, Loopout Extension
+    # for adding modification codes to exported DNA sequence
+    if substrand.dna_sequence is None:
+        return None
+
+    strand = substrand.strand()
+    len_dna_prior = 0
+    for other_substrand in strand.domains:
+        if other_substrand is substrand:
+            break
+        len_dna_prior += other_substrand.dna_length()
+
+    new_seq_list = []
+    for pos, base in enumerate(substrand.dna_sequence):
+        new_seq_list.append(base)
+        strand_pos = pos + len_dna_prior
+        if strand_pos in strand.modifications_int:  # if internal mod attached to base, replace base
+            mod = strand.modifications_int[strand_pos]
+            if mod.vendor_code is not None:
+                vendor_code_with_delim = mod.vendor_code
+                if mod.allowed_bases is not None:
+                    if base not in mod.allowed_bases:
+                        msg = (f'internal modification {mod} can only replace one of these bases: '
+                               f'{",".join(mod.allowed_bases)}, '
+                               f'but the base at position {strand_pos} is {base}')
+                        raise IllegalDesignError(msg)
+                    new_seq_list[-1] = vendor_code_with_delim  # replace base with modified base
+                else:
+                    new_seq_list.append(vendor_code_with_delim)  # append modification between two bases
+
+    return ''.join(new_seq_list)
+
+
 @dataclass
 class Domain(_JSONSerializable):
     """
@@ -2167,35 +2201,7 @@ class Domain(_JSONSerializable):
             The difference between this and the field :data:`Domain.dna_sequence` is that this
             will add internal modification codes.
         """
-        if self.dna_sequence is None:
-            return None
-
-        strand = self.strand()
-        len_dna_prior = 0
-        for domain in strand.domains:
-            if domain is self:
-                break
-            len_dna_prior += domain.dna_length()
-
-        new_seq_list = []
-        for pos, base in enumerate(self.dna_sequence):
-            new_seq_list.append(base)
-            strand_pos = pos + len_dna_prior
-            if strand_pos in strand.modifications_int:  # if internal mod attached to base, replace base
-                mod = strand.modifications_int[strand_pos]
-                if mod.vendor_code is not None:
-                    vendor_code_with_delim = mod.vendor_code
-                    if mod.allowed_bases is not None:
-                        if base not in mod.allowed_bases:
-                            msg = (f'internal modification {mod} can only replace one of these bases: '
-                                   f'{",".join(mod.allowed_bases)}, '
-                                   f'but the base at position {strand_pos} is {base}')
-                            raise IllegalDesignError(msg)
-                        new_seq_list[-1] = vendor_code_with_delim  # replace base with modified base
-                    else:
-                        new_seq_list.append(vendor_code_with_delim)  # append modification between two bases
-
-        return ''.join(new_seq_list)
+        return _vendor_dna_sequence_substrand(self)
 
     def set_name(self, name: str) -> None:
         """Sets name of this :any:`Domain`."""
@@ -2565,6 +2571,15 @@ class Loopout(_JSONSerializable):
     def __str__(self) -> str:
         return repr(self) if self.name is None else self.name
 
+    def vendor_dna_sequence(self) -> Optional[str]:
+        """
+        :return:
+            vendor DNA sequence of this :any:`Loopout`, or ``None`` if no DNA sequence has been assigned.
+            The difference between this and the field :data:`Loopout.dna_sequence` is that this
+            will add internal modification codes.
+        """
+        return _vendor_dna_sequence_substrand(self)
+
     def set_name(self, name: str) -> None:
         """Sets name of this :any:`Loopout`."""
         self.name = name
@@ -2617,8 +2632,8 @@ class Extension(_JSONSerializable):
         import scadnano as sc
 
         domain = sc.Domain(helix=0, forward=True, start=0, end=10)
-        left_toehold = sc.Extension(num_bases=6)
-        right_toehold = sc.Extension(num_bases=5)
+        left_toehold = sc.Extension(num_bases=3)
+        right_toehold = sc.Extension(num_bases=2)
         strand = sc.Strand([left_toehold, domain, right_toehold])
 
     It can also be created with chained method calls
@@ -2701,6 +2716,23 @@ class Extension(_JSONSerializable):
         """Length of this :any:`Extension`; same as field :data:`Extension.num_bases`."""
         return self.num_bases
 
+    def strand(self) -> Strand:
+        """
+        :return: The :any:`Strand` that contains this :any:`Extension`.
+        """
+        if self._parent_strand is None:
+            raise ValueError('_parent_strand has not yet been set')
+        return self._parent_strand
+
+    def vendor_dna_sequence(self) -> Optional[str]:
+        """
+        :return:
+            vendor DNA sequence of this :any:`Extension`, or ``None`` if no DNA sequence has been assigned.
+            The difference between this and the field :data:`Extension.dna_sequence` is that this
+            will add internal modification codes.
+        """
+        return _vendor_dna_sequence_substrand(self)
+
     def set_label(self, label: Optional[str]) -> None:
         """Sets label of this :any:`Extension`."""
         self.label = label
@@ -3709,7 +3741,7 @@ class Strand(_JSONSerializable):
     def __post_init__(self) -> None:
         self._ensure_domains_not_none()
 
-        self.set_domains(self.domains)
+        self.set_domains(self.domains)  # some error-checking code is in this method
 
         self._ensure_modifications_legal()
         self._ensure_domains_nonoverlapping()
@@ -3886,15 +3918,18 @@ class Strand(_JSONSerializable):
 
     def set_domains(self, domains: Iterable[Union[Domain, Loopout]]) -> None:
         """
-        Sets the :any:`Domain`'s/:any:`Loopout`'s of this :any:`Strand` to be `domains`,
-        which can contain a mix of :any:`Domain`'s and :any:`Loopout`'s,
+        Sets the :any:`Domain`'s/:any:`Loopout`'s/:any:`Extension`'s of this :any:`Strand` to be `domains`,
+        which can contain a mix of :any:`Domain`'s, :any:`Loopout`'s, and :any:`Extension`'s,
         just like the field :py:data:`Strand.domains`.
 
         :param domains:
-            The new sequence of :any:`Domain`'s/:any:`Loopout`'s to use for this :any:`Strand`.
+            The new sequence of :any:`Domain`'s/:any:`Loopout`'s/:any:`Extension`'s to use for this
+            :any:`Strand`.
         :raises StrandError:
-            if domains has two consecutive :any:`Loopout`'s, consists of just a single :any:`Loopout`'s,
-            or starts or ends with a :any:`Loopout`
+            if domains has two consecutive :any:`Loopout`'s, consists of just a single :any:`Loopout`'s
+            or a single :any:`Extension`, or starts or ends with a :any:`Loopout`,
+            or has an :any:`Extension` on a circular :any:`Strand`,
+            or has an :any:`Extension` not as the first or last element of `domains`.
         """
         self.domains = domains if isinstance(domains, list) else list(domains)
 
@@ -3912,6 +3947,10 @@ class Strand(_JSONSerializable):
         if len(self.domains) == 0:
             raise StrandError(self, 'domains cannot be empty')
 
+        for domain in self.domains[1:-1]:
+            if isinstance(domain, Extension):
+                raise StrandError(self, 'cannot have an Extension in the middle of domains')
+
         for domain1, domain2 in _pairwise(self.domains):
             if isinstance(domain1, Loopout) and isinstance(domain2, Loopout):
                 raise StrandError(self, 'cannot have two consecutive Loopouts in a strand')

diff --git a/tests/scadnano_tests.py b/tests/scadnano_tests.py
index 62c0472..61350cc 100644
--- a/tests/scadnano_tests.py
+++ b/tests/scadnano_tests.py
@@ -1309,6 +1309,37 @@ col major top-left domain start: ABCDEFLHJGIKMNOPQR
 
             os.remove(filename)
 
+    def test_export_dna_sequences_extension_5p(self) -> None:
+        design = sc.Design(helices=[sc.Helix(max_offset=100)])
+        design.draw_strand(0, 0) \
+            .extension_5p(3) \
+            .move(5) \
+            .with_sequence('TTT' + 'AAAAA') \
+            .with_name('strand')
+        contents = design.to_idt_bulk_input_format()
+        self.assertEqual('strand,TTTAAAAA,25nm,STD', contents)
+
+    def test_export_dna_sequences_extension_3p(self) -> None:
+        design = sc.Design(helices=[sc.Helix(max_offset=100)])
+        design.draw_strand(0, 0) \
+            .move(5) \
+            .extension_3p(3) \
+            .with_sequence('AAAAA' + 'TTT') \
+            .with_name('strand')
+        contents = design.to_idt_bulk_input_format()
+        self.assertEqual('strand,AAAAATTT,25nm,STD', contents)
+
+    def test_export_dna_sequences_loopout(self) -> None:
+        design = sc.Design(helices=[sc.Helix(max_offset=100), sc.Helix(max_offset=100)])
+        design.draw_strand(0, 0) \
+            .move(5) \
+            .loopout(1, 3) \
+            .move(-5) \
+            .with_sequence('AAAAA' + 'TTT' + 'AAAAA') \
+            .with_name('strand')
+        contents = design.to_idt_bulk_input_format()
+        self.assertEqual('strand,AAAAATTTAAAAA,25nm,STD', contents)
+
 
 class TestExportCadnanoV2(unittest.TestCase):
     """

export DNA sequences from extensions and loopouts
This code crashes:

```python
design = sc.Design(helices=[sc.Helix(max_offset=100)])
design.draw_strand(0, 0).extension_5p(3).move(5).with_sequence('TTT' + 'AAAAA')
contents = design.to_idt_bulk_input_format()
```

with this exception:

```
..\scadnano\scadnano.py:7369: in to_idt_bulk_input_format
    [strand.vendor_export_name(), strand.vendor_dna_sequence(domain_delimiter=domain_delimiter),
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = Strand(domains=[Extension(num_bases=3, display_length=1.0, display_angle=35.0, label=None, name=None, dna_sequence='TT...ields=None, is_scaffold=False, modification_5p=None, modification_3p=None, modifications_int={}, name=None, label=None)
domain_delimiter = ''

    def vendor_dna_sequence(self, domain_delimiter: str = '') -> str:
        """
        :param domain_delimiter:
            string to put in between DNA sequences of each domain, and between 5'/3' modifications and DNA.
            Note that the delimiter is not put between internal modifications and the next base(s)
            in the same domain.
        :return: DNA sequence as it needs to be typed to order from a DNA synthesis vendor, with
            :py:data:`Modification5Prime`'s,
            :py:data:`Modification3Prime`'s,
            and
            :py:data:`ModificationInternal`'s represented with text codes, e.g., for IDT DNA, using
            "/5Biosg/ACGT" for sequence ACGT with a 5' biotin modification.
        """
        self._ensure_modifications_legal(check_offsets_legal=True)
    
        if self.dna_sequence is None:
            raise ValueError('DNA sequence has not been assigned yet')
    
        ret_list: List[str] = []
    
        if self.modification_5p is not None and self.modification_5p.vendor_code is not None:
            ret_list.append(self.modification_5p.vendor_code)
    
        for substrand in self.domains:
>           ret_list.append(substrand.vendor_dna_sequence())
E           AttributeError: 'Extension' object has no attribute 'vendor_dna_sequence'

..\scadnano\scadnano.py:4362: AttributeError
```

This code also crashes:

```python
design = sc.Design(helices=[sc.Helix(max_offset=100), sc.Helix(max_offset=100)])
design.draw_strand(0, 0).move(5).loopout(1, 3).move(-5).with_sequence('AAAAA' + 'TTT' + 'AAAAA')
contents = design.to_idt_bulk_input_format()
```

It's not happening in the web interface, yay strongly typed languages.
tests/scadnano_tests.py::TestExportDNASequences::test_export_dna_sequences_extension_3p tests/scadnano_tests.py::TestExportDNASequences::test_export_dna_sequences_extension_5p tests/scadnano_tests.py::TestExportDNASequences::test_export_dna_sequences_loopout
tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__0_0_to_10_cross_1_to_5 tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__0_0_to_10_cross_1_to_5__reverse tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__3p_extension tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__5p_extension tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__as_circular_with_3p_extension_should_raise_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__as_circular_with_5p_extension_should_raise_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__call_to_then_update_to_legally tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__call_to_twice_decrease_increase_reverse tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__call_to_twice_increase_decrease_forward tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__call_to_twice_legally tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__call_update_to_twice_legally tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__cross_after_3p_extension_should_raise_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__cross_after_5p_extension_should_raise_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__extension_3p_after_extension_should_raise_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__extension_3p_after_loopout_should_raise_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__extension_3p_on_circular_strand_should_raise_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__extension_3p_with_label tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__extension_5p_with_label tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__extension_with_name tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__h0_off0_to_off10_cross_h1_to_off5_loopout_length3_h2_to_off15 tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__loopouts_with_labels tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__loopouts_with_labels_and_colors_to_json tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__move_after_3p_extension_should_raise_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__move_after_5p_extension_ok tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__multiple_strands tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__multiple_strands_other_order tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__multiple_strands_overlap_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__multiple_strands_overlap_no_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__to_after_3p_extension_should_raise_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__two_forward_paranemic_crossovers tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__two_reverse_paranemic_crossovers tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__update_to_after_3p_extension_should_raise_error tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__update_to_after_5p_extension_ok tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__with_domain_sequence_on_extension tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__with_relative_offset tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__with_sequence_on_3p_extension tests/scadnano_tests.py::TestCreateStrandChainedMethods::test_strand__with_sequence_on_5p_extension tests/scadnano_tests.py::TestCreateHelix::test_helix_constructor_no_max_offset_with_major_ticks tests/scadnano_tests.py::TestM13::test_p7249 tests/scadnano_tests.py::TestM13::test_p7560 tests/scadnano_tests.py::TestM13::test_p8064 tests/scadnano_tests.py::TestModifications::test_Cy3 tests/scadnano_tests.py::TestModifications::test_biotin tests/scadnano_tests.py::TestModifications::test_mod_illegal_exceptions_raised tests/scadnano_tests.py::TestModifications::test_to_json__names_not_unique_for_modifications_5p_raises_error tests/scadnano_tests.py::TestModifications::test_to_json__names_unique_for_modifications_raises_no_error tests/scadnano_tests.py::TestModifications::test_to_json_serializable tests/scadnano_tests.py::TestImportCadnanoV2::test_2_stape_2_helix_origami_deletions_insertions tests/scadnano_tests.py::TestImportCadnanoV2::test_32_helix_rectangle tests/scadnano_tests.py::TestImportCadnanoV2::test_Nature09_monolith tests/scadnano_tests.py::TestImportCadnanoV2::test_Science09_prot120_98_v3 tests/scadnano_tests.py::TestImportCadnanoV2::test_circular_auto_staple tests/scadnano_tests.py::TestImportCadnanoV2::test_circular_auto_staple_hex tests/scadnano_tests.py::TestImportCadnanoV2::test_helices_order tests/scadnano_tests.py::TestImportCadnanoV2::test_helices_order2 tests/scadnano_tests.py::TestImportCadnanoV2::test_huge_hex tests/scadnano_tests.py::TestImportCadnanoV2::test_paranemic_crossover tests/scadnano_tests.py::TestImportCadnanoV2::test_same_helix_crossover tests/scadnano_tests.py::TestExportDNASequences::test_domain_delimiters tests/scadnano_tests.py::TestExportDNASequences::test_domain_delimiters_internal_nonbase_modifications tests/scadnano_tests.py::TestExportDNASequences::test_domain_delimiters_modifications tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__col_major_3p tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__col_major_5p tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__col_major_5p_or_3p tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__col_major_top_left_domain_start tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__duplicate_names_different_purifications tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__duplicate_names_different_scales tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__duplicate_names_different_sequences tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__duplicate_names_same_sequence tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__row_major_3p tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__row_major_5p tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__row_major_5p_or_3p tests/scadnano_tests.py::TestExportDNASequences::test_to_idt_bulk_input_format__row_major_top_left_domain_start tests/scadnano_tests.py::TestExportDNASequences::test_write_idt_plate_excel_file tests/scadnano_tests.py::TestExportCadnanoV2::test_16_helix_origami_rectangle_no_twist tests/scadnano_tests.py::TestExportCadnanoV2::test_2_staple_2_helix_origami_deletions_insertions tests/scadnano_tests.py::TestExportCadnanoV2::test_2_staple_2_helix_origami_extremely_simple tests/scadnano_tests.py::TestExportCadnanoV2::test_2_staple_2_helix_origami_extremely_simple_2 tests/scadnano_tests.py::TestExportCadnanoV2::test_6_helix_bundle_honeycomb tests/scadnano_tests.py::TestExportCadnanoV2::test_6_helix_origami_rectangle tests/scadnano_tests.py::TestExportCadnanoV2::test_big_circular_staples tests/scadnano_tests.py::TestExportCadnanoV2::test_big_circular_staples_hex tests/scadnano_tests.py::TestExportCadnanoV2::test_circular_strand tests/scadnano_tests.py::TestExportCadnanoV2::test_export_design_with_helix_group tests/scadnano_tests.py::TestExportCadnanoV2::test_export_design_with_helix_group_not_same_grid tests/scadnano_tests.py::TestExportCadnanoV2::test_export_no_whitespace tests/scadnano_tests.py::TestExportCadnanoV2::test_extension tests/scadnano_tests.py::TestExportCadnanoV2::test_loopout tests/scadnano_tests.py::TestExportCadnanoV2::test_paranemic_crossover tests/scadnano_tests.py::TestExportCadnanoV2::test_parity_issue tests/scadnano_tests.py::TestDesignFromJson::test_from_json__from_and_to_file_contents tests/scadnano_tests.py::TestDesignFromJson::test_from_json__helices_non_default_error_if_some_have_idx_not_others tests/scadnano_tests.py::TestDesignFromJson::test_from_json__helices_non_default_error_if_some_have_idx_not_others_mixed_default tests/scadnano_tests.py::TestDesignFromJson::test_from_json__helices_non_default_indices tests/scadnano_tests.py::TestDesignFromJson::test_from_json__helices_non_default_indices_mixed_with_default tests/scadnano_tests.py::TestDesignFromJson::test_from_json__three_strands tests/scadnano_tests.py::TestStrandReversePolarity::test_reverse_all__one_strand tests/scadnano_tests.py::TestStrandReversePolarity::test_reverse_all__three_strands tests/scadnano_tests.py::TestInlineInsDel::test_deletion_above_range tests/scadnano_tests.py::TestInlineInsDel::test_deletion_below_range tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__deletions_insertions_in_multiple_domains tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__deletions_insertions_in_multiple_domains_two_strands tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__one_deletion tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__one_deletion_left_of_major_tick tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__one_deletion_on_major_tick tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__one_deletion_one_insertion tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__one_deletion_right_of_major_tick tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__one_insertion tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__one_insertion_left_of_major_tick tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__one_insertion_on_major_tick tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__one_insertion_right_of_major_tick tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__two_deletions tests/scadnano_tests.py::TestInlineInsDel::test_inline_deletions_insertions__two_insertions tests/scadnano_tests.py::TestInlineInsDel::test_insertion_above_range tests/scadnano_tests.py::TestInlineInsDel::test_insertion_below_range tests/scadnano_tests.py::TestInlineInsDel::test_no_deletion_after_loopout tests/scadnano_tests.py::TestInlineInsDel::test_no_insertion_after_loopout tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_full_crossover__bottom_horizontal_crossover_already_there tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_full_crossover__horizontal_crossovers_already_there tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_full_crossover__small_design_H0_forward tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_full_crossover__small_design_H0_reverse tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_full_crossover__small_design_illegal tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_full_crossover__small_design_illegal_only_one_helix_has_domain tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_full_crossover__top_horizontal_crossover_already_there tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_full_crossover_extension_ok tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_full_crossover_on_extension_error tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__both_scaffolds_preserved tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__bottom_horizontal_crossover_already_there tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__first_scaffold_preserved tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__horizontal_crossovers_already_there tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__neither_scaffold_preserved tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__second_scaffold_preserved tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__small_design_H0_reverse_0 tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__small_design_H0_reverse_15 tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__small_design_H0_reverse_8 tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__small_design_illegal tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover__top_horizontal_crossover_already_there tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover_on_existing_crossover_should_error_3p_case tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover_on_existing_crossover_should_error_5p_case tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover_on_extension_error tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_half_crossover_on_extension_ok tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_nick__6_helix_rectangle tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_nick__small_design_H0_forward tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_nick__small_design_H0_reverse tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_nick__small_design_H1_forward tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_nick__small_design_H1_reverse tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_nick__small_design_no_nicks_added_yet tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_nick__twice_on_same_domain tests/scadnano_tests.py::TestNickLigateAndCrossover::test_add_nick_then_add_crossovers__6_helix_rectangle tests/scadnano_tests.py::TestNickLigateAndCrossover::test_ligate__small_nicked_design_ligate_all tests/scadnano_tests.py::TestNickLigateAndCrossover::test_ligate__small_nicked_design_no_ligation_yet tests/scadnano_tests.py::TestNickLigateAndCrossover::test_ligate__twice_on_same_domain tests/scadnano_tests.py::TestNickLigateAndCrossover::test_ligate_on_extension_side_should_error tests/scadnano_tests.py::TestNickLigateAndCrossover::test_ligate_on_middle_domain_should_error_3p_case tests/scadnano_tests.py::TestNickLigateAndCrossover::test_ligate_on_middle_domain_should_error_5p_case tests/scadnano_tests.py::TestNickLigateAndCrossover::test_ligate_on_non_extension_side_ok tests/scadnano_tests.py::TestNickLigateAndCrossover::test_nick_on_extension tests/scadnano_tests.py::TestAutocalculatedData::test_helix_max_offset tests/scadnano_tests.py::TestAutocalculatedData::test_helix_min_max_offsets tests/scadnano_tests.py::TestAutocalculatedData::test_helix_min_max_offsets_illegal_autocalculated tests/scadnano_tests.py::TestAutocalculatedData::test_helix_min_max_offsets_illegal_explicitly_specified tests/scadnano_tests.py::TestSetHelixIdx::test_set_helix_idx tests/scadnano_tests.py::TestDesignPitchYawRollOfHelix::test_design_pitch_of_helix tests/scadnano_tests.py::TestDesignPitchYawRollOfHelix::test_design_roll_of_helix tests/scadnano_tests.py::TestDesignPitchYawRollOfHelix::test_design_yaw_of_helix tests/scadnano_tests.py::TestHelixGroups::test_JSON_bad_no_groups_but_helices_reference_groups tests/scadnano_tests.py::TestHelixGroups::test_JSON_bad_uses_groups_and_top_level_grid tests/scadnano_tests.py::TestHelixGroups::test_JSON_bad_uses_groups_and_top_level_helices_view_order tests/scadnano_tests.py::TestHelixGroups::test_helix_groups tests/scadnano_tests.py::TestHelixGroups::test_helix_groups_fail_nonexistent tests/scadnano_tests.py::TestHelixGroups::test_helix_groups_to_from_JSON tests/scadnano_tests.py::TestNames::test_strand_domain_names_json tests/scadnano_tests.py::TestNames::test_strand_names_can_be_nonunique tests/scadnano_tests.py::TestJSON::test_Helix_major_tick_periodic_distances tests/scadnano_tests.py::TestJSON::test_Helix_major_tick_start_default_min_offset tests/scadnano_tests.py::TestJSON::test_NoIndent_on_helix_without_position_or_major_ticks_present tests/scadnano_tests.py::TestJSON::test_both_helix_groups_and_helices_do_not_specify_pitch_nor_yaw tests/scadnano_tests.py::TestJSON::test_color_specified_with_integer tests/scadnano_tests.py::TestJSON::test_default_helices_view_order_with_nondefault_helix_idxs_in_default_order tests/scadnano_tests.py::TestJSON::test_default_helices_view_order_with_nondefault_helix_idxs_in_nondefault_order tests/scadnano_tests.py::TestJSON::test_domain_labels tests/scadnano_tests.py::TestJSON::test_error_when_domain_end_missing tests/scadnano_tests.py::TestJSON::test_error_when_domain_forward_and_right_missing tests/scadnano_tests.py::TestJSON::test_error_when_domain_helix_missing tests/scadnano_tests.py::TestJSON::test_error_when_domain_start_missing tests/scadnano_tests.py::TestJSON::test_error_when_grid_missing tests/scadnano_tests.py::TestJSON::test_error_when_strands_missing tests/scadnano_tests.py::TestJSON::test_from_json_extension_design tests/scadnano_tests.py::TestJSON::test_grid_design_level_converted_to_enum_from_string tests/scadnano_tests.py::TestJSON::test_grid_helix_group_level_converted_to_enum_from_string tests/scadnano_tests.py::TestJSON::test_json_tristan_example_issue_32 tests/scadnano_tests.py::TestJSON::test_lack_of_NoIndent_on_helix_if_position_or_major_ticks_present tests/scadnano_tests.py::TestJSON::test_legacy_dna_sequence_key tests/scadnano_tests.py::TestJSON::test_legacy_idt_name_import__no_strand_name tests/scadnano_tests.py::TestJSON::test_legacy_idt_name_import__strand_name_exists tests/scadnano_tests.py::TestJSON::test_legacy_right_key tests/scadnano_tests.py::TestJSON::test_legacy_substrands_key tests/scadnano_tests.py::TestJSON::test_multiple_helix_groups_helices_specify_pitch_and_yaw tests/scadnano_tests.py::TestJSON::test_multiple_helix_groups_helices_specify_pitch_and_yaw_invalid tests/scadnano_tests.py::TestJSON::test_nondefault_geometry tests/scadnano_tests.py::TestJSON::test_nondefault_geometry_some_default tests/scadnano_tests.py::TestJSON::test_only_helix_groups_specify_pitch_and_yaw tests/scadnano_tests.py::TestJSON::test_only_individual_helices_specify_pitch_and_yaw tests/scadnano_tests.py::TestJSON::test_position_specified_with_origin_keyword tests/scadnano_tests.py::TestJSON::test_single_helix_group_and_helices_specify_pitch_and_yaw tests/scadnano_tests.py::TestJSON::test_strand_idt tests/scadnano_tests.py::TestJSON::test_strand_labels tests/scadnano_tests.py::TestJSON::test_to_json__hairpin tests/scadnano_tests.py::TestJSON::test_to_json__roll tests/scadnano_tests.py::TestJSON::test_to_json_extension_design__extension tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_assign_dna__conflicting_sequences_directly_assigned tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_assign_dna__conflicting_sequences_indirectly_assigned tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_consecutive_domains_loopout tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_domains_not_none_in_Strand_constructor tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_four_legally_leapfrogging_strands tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_helices_not_specified_in_Design_constructor tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_major_tick_just_inside_range tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_major_tick_outside_range tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_overlapping_caught_in_strange_counterexample tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_singleton_loopout tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_strand_offset_beyond_maxbases tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_strand_references_nonexistent_helix tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_strands_and_helices_not_specified_in_Design_constructor tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_strands_not_specified_in_Design_constructor tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_two_illegally_overlapping_strands tests/scadnano_tests.py::TestIllegalStructuresPrevented::test_two_nonconsecutive_illegally_overlapping_strands tests/scadnano_tests.py::TestInsertRemoveDomains::test_3_helix_before_design tests/scadnano_tests.py::TestInsertRemoveDomains::test_append_domain_with_sequence tests/scadnano_tests.py::TestInsertRemoveDomains::test_insert_domain_with_sequence tests/scadnano_tests.py::TestInsertRemoveDomains::test_remove_first_domain_with_sequence tests/scadnano_tests.py::TestInsertRemoveDomains::test_remove_last_domain_with_sequence tests/scadnano_tests.py::TestInsertRemoveDomains::test_remove_middle_domain_with_sequence tests/scadnano_tests.py::TestLabels::test_with_domain_label tests/scadnano_tests.py::TestLabels::test_with_domain_label__and__with_label tests/scadnano_tests.py::TestLabels::test_with_label__dict tests/scadnano_tests.py::TestLabels::test_with_label__str tests/scadnano_tests.py::TestCircularStrandsLegalMods::test_add_3p_mod_to_circular_strand tests/scadnano_tests.py::TestCircularStrandsLegalMods::test_add_5p_mod_to_circular_strand tests/scadnano_tests.py::TestCircularStrandsLegalMods::test_can_add_internal_mod_to_circular_strand tests/scadnano_tests.py::TestCircularStrandsLegalMods::test_cannot_make_strand_circular_if_3p_mod tests/scadnano_tests.py::TestCircularStrandsLegalMods::test_cannot_make_strand_circular_if_5p_mod tests/scadnano_tests.py::TestCircularStrandEdits::test_add_crossover_from_linear_strand_to_itself_makes_it_circular tests/scadnano_tests.py::TestCircularStrandEdits::test_add_nick_to_2_domain_circular_strand_makes_it_linear_nick_first_domain tests/scadnano_tests.py::TestCircularStrandEdits::test_add_nick_to_2_domain_circular_strand_makes_it_linear_nick_second_domain tests/scadnano_tests.py::TestCircularStrandEdits::test_add_nick_to_3_domain_circular_strand_makes_it_linear_nick_first_domain tests/scadnano_tests.py::TestCircularStrandEdits::test_add_nick_to_3_domain_circular_strand_makes_it_linear_nick_last_domain tests/scadnano_tests.py::TestCircularStrandEdits::test_add_nick_to_3_domain_circular_strand_makes_it_linear_nick_middle_domain tests/scadnano_tests.py::TestCircularStrandEdits::test_ligate_linear_strand_to_itself_makes_it_circular tests/scadnano_tests.py::TestAddStrand::test_add_strand__illegal_overlapping_domains tests/scadnano_tests.py::TestAddStrand::test_add_strand__with_loopout tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__2helix_with_deletions tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__adapter_assigned_from_scaffold_and_tiles tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__adapter_assigned_from_scaffold_and_tiles_with_deletions tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__adapter_assigned_from_scaffold_and_tiles_with_insertions tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__assign_from_strand_multi_other_single tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__assign_seq_with_wildcards tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__assign_to_strand_multi_other_single tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__dna_sequence_shorter_than_complementary_strand_left_strand_longer tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__dna_sequence_shorter_than_complementary_strand_right_strand_longer tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__dna_sequence_with_uncomplemented_domain_on_different_helix tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__dna_sequence_with_uncomplemented_domain_on_different_helix_wildcards_both_ends tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__from_strand_with_loopout tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__hairpin tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__one_bound_strand__with_deletions__complement_true tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__one_bound_strand__with_insertions__complement_true tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__one_helix_with_one_bottom_strand_and_three_top_strands tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__one_strand_assigned_by_complement_from_two_other_strands tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__other_strand_fully_defined_already tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__other_strand_fully_defined_already_and_other_extends_beyond tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__other_strand_fully_defined_already_and_self_extends_beyond tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__to_strand_with_loopout tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__two_bound_strands__with_deletions__complement_true tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__two_bound_strands__with_insertions__complement_true tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__two_equal_length_strands_on_one_helix tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__two_helices_with_multiple_domain_intersections tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__upper_left_edge_staple_of_16H_origami_rectangle tests/scadnano_tests.py::TestAssignDNA::test_assign_dna__wildcards_simple tests/scadnano_tests.py::TestAssignDNAToDomains::test_assign_dna__domain_sequence_too_long_error tests/scadnano_tests.py::TestAssignDNAToDomains::test_assign_dna__to_individual_domains__wildcards_multiple_overlaps tests/scadnano_tests.py::TestAssignDNAToDomains::test_assign_dna__wildcards_multiple_overlaps tests/scadnano_tests.py::TestAssignDNAToDomains::test_method_chaining_with_domain_sequence tests/scadnano_tests.py::TestSubstrandDNASequenceIn::test_dna_sequence_in__right_then_left tests/scadnano_tests.py::TestSubstrandDNASequenceIn::test_dna_sequence_in__right_then_left_deletions tests/scadnano_tests.py::TestSubstrandDNASequenceIn::test_dna_sequence_in__right_then_left_deletions_and_insertions tests/scadnano_tests.py::TestSubstrandDNASequenceIn::test_dna_sequence_in__right_then_left_insertions tests/scadnano_tests.py::TestOxviewExport::test_bp tests/scadnano_tests.py::TestOxviewExport::test_export tests/scadnano_tests.py::TestOxviewExport::test_export_file tests/scadnano_tests.py::TestOxdnaExport::test_basic_design tests/scadnano_tests.py::TestOxdnaExport::test_deletion_design tests/scadnano_tests.py::TestOxdnaExport::test_file_output tests/scadnano_tests.py::TestOxdnaExport::test_helix_groups tests/scadnano_tests.py::TestOxdnaExport::test_honeycomb_design tests/scadnano_tests.py::TestOxdnaExport::test_insertion_design tests/scadnano_tests.py::TestOxdnaExport::test_loopout_design tests/scadnano_tests.py::TestPlateMaps::test_plate_map_markdown tests/scadnano_tests.py::TestExtension::test_to_json_serializable__display_angle_key_contains_non_default_display_angle tests/scadnano_tests.py::TestExtension::test_to_json_serializable__display_length_key_contains_non_default_display_length tests/scadnano_tests.py::TestExtension::test_to_json_serializable__extension_key_contains_num_bases tests/scadnano_tests.py::TestExtension::test_to_json_serializable__label_key_contains_non_default_name tests/scadnano_tests.py::TestExtension::test_to_json_serializable__name_key_contains_non_default_name tests/scadnano_tests.py::TestExtension::test_to_json_serializable__no_display_angle_key_when_default_display_angle tests/scadnano_tests.py::TestExtension::test_to_json_serializable__no_display_length_key_when_default_display_length tests/scadnano_tests.py::TestExtension::test_to_json_serializable__no_label_key_when_default_label tests/scadnano_tests.py::TestExtension::test_to_json_serializable__no_name_key_when_default_name tests/scadnano_tests.py::TestBasePairs::test_base_pairs_on_forward_strand_ahead_of_reverse_strand tests/scadnano_tests.py::TestBasePairs::test_design_base_pairs_deletions_insertions tests/scadnano_tests.py::TestBasePairs::test_design_base_pairs_deletions_insertions_mismatch_in_insertion tests/scadnano_tests.py::TestBasePairs::test_design_base_pairs_dna_on_some_strands_and_mismatches tests/scadnano_tests.py::TestBasePairs::test_design_base_pairs_mismatches tests/scadnano_tests.py::TestBasePairs::test_design_base_pairs_no_dna tests/scadnano_tests.py::TestBasePairs::test_design_base_pairs_no_mismatches tests/scadnano_tests.py::TestBasePairs::test_find_overlapping_domains tests/scadnano_tests.py::TestBasePairs::test_no_base_pairs tests/scadnano_tests.py::TestBasePairs::test_no_base_pairs_only_forward_strand tests/scadnano_tests.py::TestBasePairs::test_no_base_pairs_only_reverse_strand tests/scadnano_tests.py::TestHelixRollRelax::test_2_helix_2_crossovers_call_relax_twice tests/scadnano_tests.py::TestHelixRollRelax::test_2_helix_3_crossover tests/scadnano_tests.py::TestHelixRollRelax::test_2_helix_3_crossover_and_intrahelix_crossovers tests/scadnano_tests.py::TestHelixRollRelax::test_2_helix_no_crossover tests/scadnano_tests.py::TestHelixRollRelax::test_3_helix_2_crossovers tests/scadnano_tests.py::TestHelixRollRelax::test_3_helix_2_crossovers_1_loopout tests/scadnano_tests.py::TestHelixRollRelax::test_3_helix_2_crossovers_1_loopout_crossovers_method tests/scadnano_tests.py::TestHelixRollRelax::test_3_helix_6_crossover tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_0_0_90 tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_0_10_20 tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_0_10_50 tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_0_10_80 tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_0_45_90 tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_10_350 tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_1_359 tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_30_350 tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_330_40_50 tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_330_40_80 tests/scadnano_tests.py::TestHelixRollRelax::test_average_angle_350_0_40 tests/scadnano_tests.py::TestHelixRollRelax::test_helix_crossover_addresses_2_helix_3_strand tests/scadnano_tests.py::TestHelixRollRelax::test_helix_crossover_addresses_2_helix_allow_intrahelix_crossovers tests/scadnano_tests.py::TestHelixRollRelax::test_helix_crossover_addresses_2_helix_disallow_intergroup_crossovers tests/scadnano_tests.py::TestHelixRollRelax::test_helix_crossover_addresses_2_helix_disallow_intrahelix_crossovers tests/scadnano_tests.py::TestHelixRollRelax::test_helix_crossover_addresses_3_helix_3_strand tests/scadnano_tests.py::TestHelixRollRelax::test_minimum_strain_angle_0_10_20_relative_to_0 tests/scadnano_tests.py::TestHelixRollRelax::test_minimum_strain_angle_0_10_50_relative_to_0 tests/scadnano_tests.py::TestHelixRollRelax::test_minimum_strain_angle_0_10_80_relative_to_0 tests/scadnano_tests.py::TestHelixRollRelax::test_minimum_strain_angle_174_179_184_relative_to_0 tests/scadnano_tests.py::TestHelixRollRelax::test_minimum_strain_angle_179_181_relative_to_0 tests/scadnano_tests.py::TestHelixRollRelax::test_minimum_strain_angle_181_183_relative_to_0 tests/scadnano_tests.py::TestHelixRollRelax::test_minimum_strain_angle_350_0_10_relative_to_0 tests/scadnano_tests.py::TestHelixRollRelax::test_minimum_strain_angle_350_0_40_relative_to_0 tests/scadnano_tests.py::TestHelixRollRelax::test_minimum_strain_angle_350_10_60_relative_to_0 tests/scadnano_tests.py::TestHelixRollRelax::test_minimum_strain_angle_350_10_60_relative_to_0_and_20_0_310_relative_to_10