Skip to content

Commit

Permalink
Add "relative_offset" field
Browse files Browse the repository at this point in the history
  • Loading branch information
UnHumbleBen committed May 2, 2022
1 parent de44f47 commit e06ac96
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 18 deletions.
1 change: 1 addition & 0 deletions scadnano/scadnano.py
Original file line number Diff line number Diff line change
Expand Up @@ -2048,6 +2048,7 @@ def get_seq_start_idx(self) -> int:
@dataclass
class Extension(_JSONSerializable, Generic[DomainLabel]):
length: int
relative_offset: Tuple[float, float]
label: Optional[DomainLabel] = None
name: Optional[str] = None
dna_sequence: Optional[str] = None
Expand Down
64 changes: 46 additions & 18 deletions tests/scadnano_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def test_strand__3p_extension(self) -> None:

expected_strand: sc.Strand = sc.Strand([
sc.Domain(0, True, 0, 10),
sc.Extension(5),
sc.Extension(5, (1, -1)),
])
self.assertEqual(1, len(design.strands))
self.assertEqual(expected_strand, design.strands[0])
Expand All @@ -113,7 +113,7 @@ def test_strand__5p_extension(self) -> None:
sb.to(10)

expected_strand: sc.Strand = sc.Strand([
sc.Extension(5),
sc.Extension(5, (-1, -1)),
sc.Domain(0, True, 0, 10),
])

Expand All @@ -129,7 +129,7 @@ def test_strand__update_to_after_5p_extension_ok(self) -> None:
sb.update_to(15)

expected_strand: sc.Strand = sc.Strand([
sc.Extension(5),
sc.Extension(5, (-1, -1)),
sc.Domain(0, True, 0, 15),
])

Expand All @@ -144,7 +144,7 @@ def test_strand__move_after_5p_extension_ok(self) -> None:
sb.move(15)

expected_strand: sc.Strand = sc.Strand([
sc.Extension(5),
sc.Extension(5, (-1, -1)),
sc.Domain(0, True, 0, 15),
])

Expand Down Expand Up @@ -239,7 +239,7 @@ def test_strand__extension_with_label(self) -> None:

expected_strand: sc.Strand = sc.Strand([
sc.Domain(0, True, 0, 10),
sc.Extension(5, label="ext1"),
sc.Extension(5, (1, -1), label="ext1"),
])
self.assertEqual(1, len(design.strands))
self.assertEqual(expected_strand, design.strands[0])
Expand All @@ -253,7 +253,7 @@ def test_strand__with_sequence_on_extension(self) -> None:

expected_strand: sc.Strand = sc.Strand([
sc.Domain(0, True, 0, 10, dna_sequence="A"*10),
sc.Extension(5, dna_sequence="G"*5),
sc.Extension(5, (1, -1), dna_sequence="G"*5),
])
self.assertEqual(1, len(design.strands))
self.assertEqual(expected_strand, design.strands[0])
Expand All @@ -267,7 +267,7 @@ def test_strand__with_domain_sequence_on_extension(self) -> None:

expected_strand: sc.Strand = sc.Strand([
sc.Domain(0, True, 0, 10, dna_sequence="?"*10),
sc.Extension(5, dna_sequence="G"*5),
sc.Extension(5, (1, -1), dna_sequence="G"*5),
])
self.assertEqual(1, len(design.strands))
self.assertEqual(expected_strand, design.strands[0])
Expand All @@ -281,7 +281,7 @@ def test_strand__extension_with_name(self) -> None:

expected_strand: sc.Strand = sc.Strand([
sc.Domain(0, True, 0, 10),
sc.Extension(5, name="ext1"),
sc.Extension(5, (1, -1), name="ext1"),
])
self.assertEqual(1, len(design.strands))
self.assertEqual(expected_strand, design.strands[0])
Expand Down Expand Up @@ -889,14 +889,13 @@ def test_paranemic_crossover(self) -> None:
#
design.write_scadnano_file(directory=self.output_path,
filename=f'{file_name}.{sc.default_scadnano_file_extension}')

def test_same_helix_crossover(self) -> None:
file_name = "test_paranemic_crossover"
design = sc.Design.from_cadnano_v2(directory=self.input_path,
filename=file_name + ".json")
self.assertEqual(4, len(design.helices))


def test_2_stape_2_helix_origami_deletions_insertions(self) -> None:
file_name = "test_2_stape_2_helix_origami_deletions_insertions"
design = sc.Design.from_cadnano_v2(directory=self.input_path,
Expand Down Expand Up @@ -3229,12 +3228,25 @@ def test_ligate_on_extension_side_should_error(self) -> None:
design.ligate(0, 10, True)

def test_ligate_on_non_extension_side_ok(self) -> None:
"""
Before:
\
\
0 --------->[-------->
After:
Before:
\
\
0 ------------------->
"""
design: sc.Design = sc.Design(helices=[sc.Helix(max_offset=100)])
design.draw_strand(0, 0).extension(5).to(10)
design.draw_strand(0, 10).to(20)
design.ligate(0, 10, True)
expected_strand: sc.Strand = sc.Strand([
sc.Extension(5),
sc.Extension(5, (-1, -1)),
sc.Domain(0, True, 0, 20)
])
self.assertEqual(1, len(design.strands))
Expand Down Expand Up @@ -3279,7 +3291,7 @@ def test_add_full_crossover_extension_ok(self) -> None:
expected_strand_1: sc.Strand = sc.Strand([
sc.Domain(1, False, 8, 16),
sc.Domain(0, True, 8, 16),
sc.Extension(5)
sc.Extension(5, (1, -1))
])
self.assertEqual(2, len(design.strands))
self.assertIn(expected_strand_0, design.strands)
Expand Down Expand Up @@ -3346,7 +3358,7 @@ def test_add_half_crossover_on_extension_ok(self) -> None:

# Validation
expected_strand: sc.Strand = sc.Strand([
sc.Extension(5),
sc.Extension(5, (-1, -1)),
sc.Domain(0, True, 0, 8),
sc.Domain(1, False, 0, 8)
])
Expand Down Expand Up @@ -3410,12 +3422,13 @@ def test_nick_on_extension(self) -> None:
])
expected_strand2: sc.Strand = sc.Strand([
sc.Domain(0, True, 4, 8),
sc.Extension(5)
sc.Extension(5, (1, -1))
])
self.assertEquals(2, len(design.strands))
self.assertIn(expected_strand1, design.strands)
self.assertIn(expected_strand2, design.strands)


class TestAutocalculatedData(unittest.TestCase):

def test_helix_min_max_offsets_illegal_explicitly_specified(self) -> None:
Expand Down Expand Up @@ -4796,17 +4809,17 @@ def test_from_json_extension_design(self) -> None:
{
"domains": [
{"helix": 0, "forward": true, "start": 0, "end": 10},
{"extension": 5}
{"extension": 5, "relative_offset": [1.4, -0.3]}
],
"is_scaffold": true
}
]
}
"""
design = sc.Design.from_scadnano_json_str(json_str)
self.assertEqual(sc.Extension(5), design.strands[0].domains[1])
self.assertEqual(sc.Extension(5, (1.4, -0.3)), design.strands[0].domains[1])

def test_to_json_extension_design(self) -> None:
def test_to_json_extension_design__extension(self) -> None:
# Setup
design = sc.Design(helices=[sc.Helix(max_offset=100)], strands=[], grid=sc.square)
design.draw_strand(0, 0).to(10).extension(5)
Expand All @@ -4817,9 +4830,23 @@ def test_to_json_extension_design(self) -> None:
# Verify
document = json.loads(result)
self.assertEqual(2, len(document["strands"][0]["domains"]))
self.assertIn("extension")
self.assertIn("extension", document["strands"][0]["domains"][1])
self.assertEqual(5, document["strands"][0]["domains"][1]["extension"])

def test_to_json_extension_design__relative_offset(self) -> None:
# Setup
design = sc.Design(helices=[sc.Helix(max_offset=100)], strands=[], grid=sc.square)
design.draw_strand(0, 0).to(10).extension(5).with_relative_offset((1.4, -0.3))

# Action
result = design.to_json()

# Verify
document = json.loads(result)
self.assertEqual(2, len(document["strands"][0]["domains"]))
self.assertIn("relative_offset", document["strands"][0]["domains"][1])
self.assertEqual([1.4, -0.3], document["strands"][0]["domains"][1]["relative_offset"])


class TestIllegalStructuresPrevented(unittest.TestCase):

Expand Down Expand Up @@ -7265,6 +7292,7 @@ def test_loopout_design(self) -> None:

self.assertAlmostEqual(self.EXPECTED_ADJ_NUC_CM_DIST2, sqr_dist2)


class TestPlateMaps(unittest.TestCase):

def setUp(self) -> None:
Expand Down

0 comments on commit e06ac96

Please sign in to comment.