RNApolis 0.8.3__tar.gz → 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {rnapolis-0.8.3/src/RNApolis.egg-info → rnapolis-0.9.0}/PKG-INFO +1 -1
  2. {rnapolis-0.8.3 → rnapolis-0.9.0}/setup.py +1 -1
  3. {rnapolis-0.8.3 → rnapolis-0.9.0/src/RNApolis.egg-info}/PKG-INFO +1 -1
  4. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/RNApolis.egg-info/SOURCES.txt +1 -0
  5. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/adapter.py +11 -67
  6. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/annotator.py +23 -55
  7. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/common.py +24 -13
  8. rnapolis-0.9.0/src/rnapolis/py.typed +0 -0
  9. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/tertiary.py +53 -47
  10. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_annotator.py +7 -6
  11. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_bugfixes.py +6 -6
  12. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_common.py +6 -6
  13. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_quadruplexes.py +5 -5
  14. {rnapolis-0.8.3 → rnapolis-0.9.0}/LICENSE +0 -0
  15. {rnapolis-0.8.3 → rnapolis-0.9.0}/README.md +0 -0
  16. {rnapolis-0.8.3 → rnapolis-0.9.0}/pyproject.toml +0 -0
  17. {rnapolis-0.8.3 → rnapolis-0.9.0}/setup.cfg +0 -0
  18. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/RNApolis.egg-info/dependency_links.txt +0 -0
  19. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/RNApolis.egg-info/entry_points.txt +0 -0
  20. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/RNApolis.egg-info/requires.txt +0 -0
  21. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/RNApolis.egg-info/top_level.txt +0 -0
  22. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/aligner.py +0 -0
  23. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/clashfinder.py +0 -0
  24. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/component_A.csv +0 -0
  25. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/component_C.csv +0 -0
  26. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/component_G.csv +0 -0
  27. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/component_U.csv +0 -0
  28. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/metareader.py +0 -0
  29. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/mmcif_pdbx_v50.dic +0 -0
  30. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/molecule_filter.py +0 -0
  31. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/motif_extractor.py +0 -0
  32. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/parser.py +0 -0
  33. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/parser_v2.py +0 -0
  34. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/rfam_folder.py +0 -0
  35. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/splitter.py +0 -0
  36. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/tertiary_v2.py +0 -0
  37. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/transformer.py +0 -0
  38. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/unifier.py +0 -0
  39. {rnapolis-0.8.3 → rnapolis-0.9.0}/src/rnapolis/util.py +0 -0
  40. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_adapter.py +0 -0
  41. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_metareader.py +0 -0
  42. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_molecule_filter.py +0 -0
  43. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_parser.py +0 -0
  44. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_rfam_folder.py +0 -0
  45. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_tertiary.py +0 -0
  46. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_transformer.py +0 -0
  47. {rnapolis-0.8.3 → rnapolis-0.9.0}/tests/test_v2.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RNApolis
3
- Version: 0.8.3
3
+ Version: 0.9.0
4
4
  Summary: A Python library containing RNA-related bioinformatics functions and classes
5
5
  Home-page: https://github.com/tzok/rnapolis-py
6
6
  Author: Tomasz Zok
@@ -5,7 +5,7 @@ with open("README.md") as f:
5
5
 
6
6
  setup(
7
7
  name="RNApolis",
8
- version="0.8.3",
8
+ version="0.9.0",
9
9
  packages=["rnapolis"],
10
10
  package_dir={"": "src"},
11
11
  author="Tomasz Zok",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RNApolis
3
- Version: 0.8.3
3
+ Version: 0.9.0
4
4
  Summary: A Python library containing RNA-related bioinformatics functions and classes
5
5
  Home-page: https://github.com/tzok/rnapolis-py
6
6
  Author: Tomasz Zok
@@ -23,6 +23,7 @@ src/rnapolis/molecule_filter.py
23
23
  src/rnapolis/motif_extractor.py
24
24
  src/rnapolis/parser.py
25
25
  src/rnapolis/parser_v2.py
26
+ src/rnapolis/py.typed
26
27
  src/rnapolis/rfam_folder.py
27
28
  src/rnapolis/splitter.py
28
29
  src/rnapolis/tertiary.py
@@ -29,8 +29,7 @@ from rnapolis.common import (
29
29
  from rnapolis.parser import read_3d_structure
30
30
  from rnapolis.tertiary import (
31
31
  Mapping2D3D,
32
- Structure3D,
33
- calculate_all_inter_stem_parameters, # Import the new helper function
32
+ Structure3D, # Import the new helper function
34
33
  )
35
34
  from rnapolis.util import handle_input_file
36
35
 
@@ -288,7 +287,7 @@ def parse_fr3d_output(file_path: str) -> BaseInteractions:
288
287
  BaseInteractions object containing the interactions found by FR3D
289
288
  """
290
289
  # Initialize the interaction data dictionary
291
- interactions_data = {
290
+ interactions_data: Dict[str, list] = {
292
291
  "base_pairs": [],
293
292
  "stackings": [],
294
293
  "base_ribose_interactions": [],
@@ -320,10 +319,8 @@ def process_external_tool_output(
320
319
  structure3d: Structure3D,
321
320
  external_file_path: str,
322
321
  tool: ExternalTool,
323
- model: Optional[int] = None,
324
322
  find_gaps: bool = False,
325
- all_dot_brackets: bool = False,
326
- ) -> Tuple[Structure2D, List[str], Mapping2D3D]: # Added Mapping2D3D to return tuple
323
+ ) -> Tuple[Structure2D, Mapping2D3D]: # Added Mapping2D3D to return tuple
327
324
  """
328
325
  Process external tool output and create a secondary structure representation.
329
326
 
@@ -336,71 +333,15 @@ def process_external_tool_output(
336
333
  tool: The external tool that generated the output (FR3D, DSSR, etc.)
337
334
  model: Model number to use (if None, use first model)
338
335
  find_gaps: Whether to detect gaps in the structure
339
- all_dot_brackets: Whether to return all possible dot-bracket notations
340
336
 
341
337
  Returns:
342
- A tuple containing the Structure2D object, a list of dot-bracket notations,
343
- and the Mapping2D3D object.
338
+ A tuple containing the Structure2D object and the Mapping2D3D object.
344
339
  """
345
340
  # Parse external tool output
346
341
  base_interactions = parse_external_output(external_file_path, tool, structure3d)
347
342
 
348
343
  # Extract secondary structure using the external tool's interactions
349
- return extract_secondary_structure_from_external(
350
- structure3d, base_interactions, model, find_gaps, all_dot_brackets
351
- )
352
-
353
-
354
- def extract_secondary_structure_from_external(
355
- tertiary_structure: Structure3D,
356
- base_interactions: BaseInteractions,
357
- model: Optional[int] = None,
358
- find_gaps: bool = False,
359
- all_dot_brackets: bool = False,
360
- ) -> Tuple[Structure2D, List[str], Mapping2D3D]: # Added Mapping2D3D to return tuple
361
- """
362
- Create a secondary structure representation using interactions from an external tool.
363
-
364
- Args:
365
- tertiary_structure: The 3D structure parsed from PDB/mmCIF
366
- base_interactions: Interactions parsed from external tool output
367
- model: Model number to use (if None, use all models)
368
- find_gaps: Whether to detect gaps in the structure
369
- all_dot_brackets: Whether to return all possible dot-bracket notations
370
-
371
- Returns:
372
- A tuple containing the Structure2D object, a list of dot-bracket notations,
373
- and the Mapping2D3D object.
374
- """
375
- mapping = Mapping2D3D(
376
- tertiary_structure,
377
- base_interactions.basePairs,
378
- base_interactions.stackings,
379
- find_gaps,
380
- )
381
- stems, single_strands, hairpins, loops = mapping.bpseq.elements
382
-
383
- # Calculate inter-stem parameters using the helper function
384
- inter_stem_params = calculate_all_inter_stem_parameters(mapping)
385
-
386
- structure2d = Structure2D(
387
- base_interactions,
388
- str(mapping.bpseq),
389
- mapping.dot_bracket,
390
- mapping.extended_dot_bracket,
391
- stems,
392
- single_strands,
393
- hairpins,
394
- loops,
395
- inter_stem_params, # Added inter-stem parameters
396
- )
397
- if all_dot_brackets:
398
- return structure2d, mapping.all_dot_brackets, mapping # Return mapping
399
- else:
400
- return structure2d, [structure2d.dotBracket], mapping # Return mapping
401
-
402
-
403
- # Removed duplicate functions - now imported from annotator
344
+ return structure3d.extract_secondary_structure(base_interactions, find_gaps)
404
345
 
405
346
 
406
347
  def main():
@@ -431,15 +372,18 @@ def main():
431
372
  structure3d = read_3d_structure(file, None)
432
373
 
433
374
  # Process external tool output and get secondary structure
434
- structure2d, dot_brackets, mapping = process_external_tool_output(
375
+ structure2d, mapping = process_external_tool_output(
435
376
  structure3d,
436
377
  args.external,
437
378
  ExternalTool(args.tool),
438
- None,
439
379
  args.find_gaps,
440
- args.all_dot_brackets,
441
380
  )
442
381
 
382
+ if args.all_dot_brackets:
383
+ dot_brackets = mapping.all_dot_brackets
384
+ else:
385
+ dot_brackets = [mapping.dot_bracket]
386
+
443
387
  handle_output_arguments(args, structure2d, dot_brackets, mapping, args.input)
444
388
 
445
389
 
@@ -1,5 +1,6 @@
1
1
  #! /usr/bin/env python
2
2
  import argparse
3
+ import copy
3
4
  import csv
4
5
  import logging
5
6
  import math
@@ -43,7 +44,6 @@ from rnapolis.tertiary import (
43
44
  Mapping2D3D, # Added import
44
45
  Residue3D,
45
46
  Structure3D,
46
- calculate_all_inter_stem_parameters, # Import the new helper function
47
47
  torsion_angle,
48
48
  )
49
49
  from rnapolis.util import handle_input_file
@@ -485,41 +485,6 @@ def extract_base_interactions(
485
485
  return BaseInteractions(base_pairs, stackings, base_ribose, base_phosphate, [])
486
486
 
487
487
 
488
- def extract_secondary_structure(
489
- tertiary_structure: Structure3D,
490
- model: Optional[int] = None,
491
- find_gaps: bool = False,
492
- all_dot_brackets: bool = False,
493
- ) -> Tuple[Structure2D, List[str]]:
494
- base_interactions = extract_base_interactions(tertiary_structure, model)
495
- mapping = Mapping2D3D(
496
- tertiary_structure,
497
- base_interactions.basePairs,
498
- base_interactions.stackings,
499
- find_gaps,
500
- )
501
- stems, single_strands, hairpins, loops = mapping.bpseq.elements
502
-
503
- # Calculate inter-stem parameters using the helper function
504
- inter_stem_params = calculate_all_inter_stem_parameters(mapping)
505
-
506
- structure2d = Structure2D(
507
- base_interactions,
508
- str(mapping.bpseq),
509
- mapping.dot_bracket,
510
- mapping.extended_dot_bracket,
511
- stems,
512
- single_strands,
513
- hairpins,
514
- loops,
515
- inter_stem_params, # Added inter-stem parameters
516
- )
517
- if all_dot_brackets:
518
- return structure2d, mapping.all_dot_brackets
519
- else:
520
- return structure2d, [structure2d.dotBracket]
521
-
522
-
523
488
  def generate_pymol_script(mapping: Mapping2D3D, stems: List[Stem]) -> str:
524
489
  """Generates a PyMOL script to draw stems as cylinders."""
525
490
  pymol_commands = []
@@ -613,16 +578,26 @@ def generate_pymol_script(mapping: Mapping2D3D, stems: List[Stem]) -> str:
613
578
 
614
579
 
615
580
  def write_json(path: str, structure2d: Structure2D):
581
+ processed = copy.deepcopy(structure2d)
582
+ processed.bpseq_index = {
583
+ k: Residue(v.label, v.auth) for k, v in structure2d.bpseq_index.items()
584
+ }
585
+
616
586
  with open(path, "wb") as f:
617
587
  # Add OPT_SERIALIZE_NUMPY to handle numpy types like float64
618
- f.write(orjson.dumps(structure2d, option=orjson.OPT_SERIALIZE_NUMPY))
588
+ # Add OPT_NON_STR_KEYS to preserve integer keys in dictionaries
589
+ f.write(
590
+ orjson.dumps(
591
+ processed, option=orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_NON_STR_KEYS
592
+ )
593
+ )
619
594
 
620
595
 
621
596
  def write_csv(path: str, structure2d: Structure2D):
622
597
  with open(path, "w") as f:
623
598
  writer = csv.writer(f)
624
599
  writer.writerow(["nt1", "nt2", "type", "classification-1", "classification-2"])
625
- for base_pair in structure2d.baseInteractions.basePairs:
600
+ for base_pair in structure2d.base_pairs:
626
601
  writer.writerow(
627
602
  [
628
603
  base_pair.nt1.full_name,
@@ -636,7 +611,7 @@ def write_csv(path: str, structure2d: Structure2D):
636
611
  ),
637
612
  ]
638
613
  )
639
- for stacking in structure2d.baseInteractions.stackings:
614
+ for stacking in structure2d.stackings:
640
615
  writer.writerow(
641
616
  [
642
617
  stacking.nt1.full_name,
@@ -646,7 +621,7 @@ def write_csv(path: str, structure2d: Structure2D):
646
621
  "",
647
622
  ]
648
623
  )
649
- for base_phosphate in structure2d.baseInteractions.basePhosphateInteractions:
624
+ for base_phosphate in structure2d.base_phosphate_interactions:
650
625
  writer.writerow(
651
626
  [
652
627
  base_phosphate.nt1.full_name,
@@ -656,7 +631,7 @@ def write_csv(path: str, structure2d: Structure2D):
656
631
  "",
657
632
  ]
658
633
  )
659
- for base_ribose in structure2d.baseInteractions.baseRiboseInteractions:
634
+ for base_ribose in structure2d.base_ribose_interactions:
660
635
  writer.writerow(
661
636
  [
662
637
  base_ribose.nt1.full_name,
@@ -666,7 +641,7 @@ def write_csv(path: str, structure2d: Structure2D):
666
641
  "",
667
642
  ]
668
643
  )
669
- for other in structure2d.baseInteractions.otherInteractions:
644
+ for other in structure2d.other_interactions:
670
645
  writer.writerow(
671
646
  [
672
647
  other.nt1.full_name,
@@ -737,12 +712,12 @@ def handle_output_arguments(
737
712
  write_bpseq(args.bpseq, structure2d.bpseq)
738
713
 
739
714
  if args.extended:
740
- print(structure2d.extendedDotBracket)
715
+ print(structure2d.extended_dot_bracket)
741
716
  elif args.all_dot_brackets:
742
717
  for dot_bracket in dot_brackets:
743
718
  print(dot_bracket)
744
719
  else:
745
- print(structure2d.dotBracket)
720
+ print(structure2d.dot_bracket)
746
721
 
747
722
  if args.dot:
748
723
  print(BpSeq.from_string(structure2d.bpseq).graphviz)
@@ -753,7 +728,7 @@ def handle_output_arguments(
753
728
  f.write(pml_script)
754
729
 
755
730
  if args.inter_stem_csv:
756
- if structure2d.interStemParameters:
731
+ if structure2d.inter_stem_parameters:
757
732
  # Convert list of dataclasses to list of dicts
758
733
  params_list = [
759
734
  {
@@ -862,16 +837,9 @@ def main():
862
837
 
863
838
  file = handle_input_file(args.input)
864
839
  structure3d = read_3d_structure(file, None)
865
- structure2d, dot_brackets = extract_secondary_structure(
866
- structure3d, None, args.find_gaps, args.all_dot_brackets
867
- )
868
-
869
- # Need the mapping object for PML generation
870
- mapping = Mapping2D3D(
871
- structure3d,
872
- structure2d.baseInteractions.basePairs,
873
- structure2d.baseInteractions.stackings,
874
- args.find_gaps,
840
+ base_interactions = extract_base_interactions(structure3d)
841
+ structure2d, dot_brackets, mapping = structure3d.extract_secondary_structure(
842
+ base_interactions, args.find_gaps, args.all_dot_brackets
875
843
  )
876
844
 
877
845
  handle_output_arguments(args, structure2d, dot_brackets, mapping, args.input)
@@ -1021,7 +1021,13 @@ class MultiStrandDotBracket(DotBracket):
1021
1021
  strands: List[Strand]
1022
1022
 
1023
1023
  @staticmethod
1024
- def from_string(input: str):
1024
+ def from_string(sequence: str, structure: str):
1025
+ # Provide compatibility with DotBracket.from_string
1026
+ strand = Strand(1, len(sequence), sequence, structure)
1027
+ return MultiStrandDotBracket(sequence, structure, [strand])
1028
+
1029
+ @staticmethod
1030
+ def from_multiline_string(input: str):
1025
1031
  strands = []
1026
1032
  first = 1
1027
1033
 
@@ -1045,16 +1051,16 @@ class MultiStrandDotBracket(DotBracket):
1045
1051
  @staticmethod
1046
1052
  def from_file(path: str):
1047
1053
  with open(path) as f:
1048
- return MultiStrandDotBracket.from_string(f.read())
1054
+ return MultiStrandDotBracket.from_multiline_string(f.read())
1049
1055
 
1050
1056
 
1051
1057
  @dataclass(frozen=True, order=True)
1052
1058
  class BaseInteractions:
1053
- basePairs: List[BasePair]
1059
+ base_pairs: List[BasePair]
1054
1060
  stackings: List[Stacking]
1055
- baseRiboseInteractions: List[BaseRibose]
1056
- basePhosphateInteractions: List[BasePhosphate]
1057
- otherInteractions: List[OtherInteraction]
1061
+ base_ribose_interactions: List[BaseRibose]
1062
+ base_phosphate_interactions: List[BasePhosphate]
1063
+ other_interactions: List[OtherInteraction]
1058
1064
 
1059
1065
 
1060
1066
  @dataclass(frozen=True, order=True)
@@ -1069,14 +1075,19 @@ class InterStemParameters:
1069
1075
  coaxial_probability: Optional[float] # Probability of stems being coaxial (0-1)
1070
1076
 
1071
1077
 
1072
- @dataclass(frozen=True, order=True)
1078
+ @dataclass
1073
1079
  class Structure2D:
1074
- baseInteractions: BaseInteractions
1075
- bpseq: str
1076
- dotBracket: str
1077
- extendedDotBracket: str
1080
+ base_pairs: List[BasePair]
1081
+ stackings: List[Stacking]
1082
+ base_ribose_interactions: List[BaseRibose]
1083
+ base_phosphate_interactions: List[BasePhosphate]
1084
+ other_interactions: List[OtherInteraction]
1085
+ bpseq: BpSeq
1086
+ bpseq_index: Dict[int, Residue]
1087
+ dot_bracket: MultiStrandDotBracket
1088
+ extended_dot_bracket: str
1078
1089
  stems: List[Stem]
1079
- singleStrands: List[SingleStrand]
1090
+ single_strands: List[SingleStrand]
1080
1091
  hairpins: List[Hairpin]
1081
1092
  loops: List[Loop]
1082
- interStemParameters: List[InterStemParameters]
1093
+ inter_stem_parameters: List[InterStemParameters]
File without changes
@@ -11,6 +11,7 @@ import numpy.typing
11
11
  from scipy.stats import vonmises
12
12
 
13
13
  from rnapolis.common import (
14
+ BaseInteractions,
14
15
  BasePair,
15
16
  BpSeq,
16
17
  Entry,
@@ -24,6 +25,7 @@ from rnapolis.common import (
24
25
  Stacking,
25
26
  Stem,
26
27
  Strand,
28
+ Structure2D,
27
29
  )
28
30
 
29
31
  BASE_ATOMS = {
@@ -456,6 +458,50 @@ class Structure3D:
456
458
  return self.residue_map.get(auth)
457
459
  return None
458
460
 
461
+ def extract_secondary_structure(
462
+ self, base_interactions: BaseInteractions, find_gaps: bool = False
463
+ ) -> Tuple[Structure2D, "Mapping2D3D"]:
464
+ """
465
+ Create a secondary structure representation.
466
+
467
+ Args:
468
+ base_interactions: Interactions
469
+ find_gaps: Whether to detect gaps in the structure
470
+ all_dot_brackets: Whether to return all possible dot-bracket notations
471
+
472
+ Returns:
473
+ A tuple containing the Structure2D object, a list of dot-bracket notations,
474
+ and the Mapping2D3D object.
475
+ """
476
+ mapping = Mapping2D3D(
477
+ self,
478
+ base_interactions.base_pairs,
479
+ base_interactions.stackings,
480
+ find_gaps,
481
+ )
482
+ stems, single_strands, hairpins, loops = mapping.bpseq.elements
483
+
484
+ # Calculate inter-stem parameters using the helper function
485
+ inter_stem_params = calculate_all_inter_stem_parameters(mapping)
486
+
487
+ structure2d = Structure2D(
488
+ base_interactions.base_pairs,
489
+ base_interactions.stackings,
490
+ base_interactions.base_ribose_interactions,
491
+ base_interactions.base_phosphate_interactions,
492
+ base_interactions.other_interactions,
493
+ mapping.bpseq,
494
+ mapping.bpseq_index_to_residue_map,
495
+ mapping.dot_bracket,
496
+ mapping.extended_dot_bracket,
497
+ stems,
498
+ single_strands,
499
+ hairpins,
500
+ loops,
501
+ inter_stem_params,
502
+ )
503
+ return structure2d, mapping
504
+
459
505
 
460
506
  @dataclass
461
507
  class Mapping2D3D:
@@ -559,46 +605,6 @@ class Mapping2D3D:
559
605
 
560
606
  @cached_property
561
607
  def bpseq(self) -> BpSeq:
562
- def pair_scoring_function(pair: BasePair3D) -> int:
563
- if pair.saenger is not None:
564
- if pair.saenger in (Saenger.XIX, Saenger.XX):
565
- return 0, pair.nt1, pair.nt2
566
- else:
567
- return 1, pair.nt1, pair.nt2
568
-
569
- sequence = "".join(
570
- sorted(
571
- [
572
- pair.nt1_3d.one_letter_name.upper(),
573
- pair.nt2_3d.one_letter_name.upper(),
574
- ]
575
- )
576
- )
577
- if sequence in ("AU", "AT", "CG"):
578
- return 0, pair.nt1, pair.nt2
579
- return 1, pair.nt1, pair.nt2
580
-
581
- canonical = [
582
- base_pair
583
- for base_pair in self.base_pairs
584
- if base_pair.is_canonical and base_pair.nt1 < base_pair.nt2
585
- ]
586
-
587
- while True:
588
- matches = defaultdict(set)
589
-
590
- for base_pair in canonical:
591
- matches[base_pair.nt1_3d].add(base_pair)
592
- matches[base_pair.nt2_3d].add(base_pair)
593
-
594
- for pairs in matches.values():
595
- if len(pairs) > 1:
596
- pairs = sorted(pairs, key=pair_scoring_function)
597
- canonical.remove(pairs[-1])
598
- break
599
- else:
600
- break
601
-
602
608
  return self._generated_bpseq_data[0]
603
609
 
604
610
  @cached_property
@@ -613,9 +619,9 @@ class Mapping2D3D:
613
619
  def pair_scoring_function(pair: BasePair3D) -> int:
614
620
  if pair.saenger is not None:
615
621
  if pair.saenger in (Saenger.XIX, Saenger.XX):
616
- return 0, pair.nt1, pair.nt2
622
+ return 0
617
623
  else:
618
- return 1, pair.nt1, pair.nt2
624
+ return 1
619
625
 
620
626
  sequence = "".join(
621
627
  sorted(
@@ -626,8 +632,8 @@ class Mapping2D3D:
626
632
  )
627
633
  )
628
634
  if sequence in ("AU", "AT", "CG"):
629
- return 0, pair.nt1, pair.nt2
630
- return 1, pair.nt1, pair.nt2
635
+ return 0
636
+ return 1
631
637
 
632
638
  canonical = [
633
639
  base_pair
@@ -636,11 +642,11 @@ class Mapping2D3D:
636
642
  ]
637
643
 
638
644
  while True:
639
- matches = defaultdict(set)
645
+ matches = defaultdict(list)
640
646
 
641
647
  for base_pair in canonical:
642
- matches[base_pair.nt1_3d].add(base_pair)
643
- matches[base_pair.nt2_3d].add(base_pair)
648
+ matches[base_pair.nt1_3d].append(base_pair)
649
+ matches[base_pair.nt2_3d].append(base_pair)
644
650
 
645
651
  for pairs in matches.values():
646
652
  if len(pairs) > 1:
@@ -1,6 +1,6 @@
1
1
  from collections import Counter
2
2
 
3
- from rnapolis.annotator import extract_base_interactions, extract_secondary_structure
3
+ from rnapolis.annotator import extract_base_interactions
4
4
  from rnapolis.parser import read_3d_structure
5
5
 
6
6
 
@@ -13,11 +13,11 @@ def test_1ehz():
13
13
  base_interactions = extract_base_interactions(structure3d, 1)
14
14
 
15
15
  interactions = [
16
- base_interactions.basePairs,
16
+ base_interactions.base_pairs,
17
17
  base_interactions.stackings,
18
- base_interactions.baseRiboseInteractions,
19
- base_interactions.basePhosphateInteractions,
20
- base_interactions.otherInteractions,
18
+ base_interactions.base_ribose_interactions,
19
+ base_interactions.base_phosphate_interactions,
20
+ base_interactions.other_interactions,
21
21
  ]
22
22
  labels = ["base pairs", "stackings", "base-ribose", "base-phosphate", "other"]
23
23
  for i in range(len(interactions)):
@@ -44,7 +44,8 @@ def test_1ehz():
44
44
  def test_8btk():
45
45
  with open("tests/8btk_B7.cif") as f:
46
46
  structure3d = read_3d_structure(f, 1)
47
- assert extract_secondary_structure(structure3d, 1) is not None
47
+ base_interactions = extract_base_interactions(structure3d, 1)
48
+ assert structure3d.extract_secondary_structure(base_interactions) is not None
48
49
 
49
50
 
50
51
  def test_488d():
@@ -10,7 +10,7 @@ def test_1E7K():
10
10
  structure3d = read_3d_structure(f, 1)
11
11
  base_interaction = extract_base_interactions(structure3d)
12
12
  mapping = Mapping2D3D(
13
- structure3d, base_interaction.basePairs, base_interaction.stackings, True
13
+ structure3d, base_interaction.base_pairs, base_interaction.stackings, True
14
14
  )
15
15
  assert len(mapping.strands_sequences) == 1
16
16
 
@@ -28,7 +28,7 @@ def test_1DFU():
28
28
 
29
29
  base_interactions = extract_base_interactions(structure3d)
30
30
  mapping = Mapping2D3D(
31
- structure3d, base_interactions.basePairs, base_interactions.stackings, True
31
+ structure3d, base_interactions.base_pairs, base_interactions.stackings, True
32
32
  )
33
33
  assert b2g not in mapping.base_pair_graph[b1u]
34
34
  assert b1u not in mapping.base_pair_graph[b2g]
@@ -40,7 +40,7 @@ def test_4WTI():
40
40
  structure3d = read_3d_structure(f, 1)
41
41
  base_interactions = extract_base_interactions(structure3d)
42
42
  mapping = Mapping2D3D(
43
- structure3d, base_interactions.basePairs, base_interactions.stackings, True
43
+ structure3d, base_interactions.base_pairs, base_interactions.stackings, True
44
44
  )
45
45
  assert mapping.dot_bracket == ">strand_T\nCGG\n.((\n>strand_P\nCC\n))"
46
46
 
@@ -51,7 +51,7 @@ def test_1HMH():
51
51
  structure3d = read_3d_structure(f, 1)
52
52
  base_interactions = extract_base_interactions(structure3d)
53
53
  mapping = Mapping2D3D(
54
- structure3d, base_interactions.basePairs, base_interactions.stackings, True
54
+ structure3d, base_interactions.base_pairs, base_interactions.stackings, True
55
55
  )
56
56
  assert mapping.dot_bracket == ">strand_E\nUG\n.."
57
57
 
@@ -80,7 +80,7 @@ def test_6g90():
80
80
 
81
81
  # without gaps
82
82
  mapping = Mapping2D3D(
83
- structure3d, base_interactions.basePairs, base_interactions.stackings, False
83
+ structure3d, base_interactions.base_pairs, base_interactions.stackings, False
84
84
  )
85
85
  assert (
86
86
  mapping.bpseq.sequence
@@ -90,7 +90,7 @@ def test_6g90():
90
90
 
91
91
  # with gaps
92
92
  mapping = Mapping2D3D(
93
- structure3d, base_interactions.basePairs, base_interactions.stackings, True
93
+ structure3d, base_interactions.base_pairs, base_interactions.stackings, True
94
94
  )
95
95
  assert (
96
96
  mapping.bpseq.sequence
@@ -90,11 +90,11 @@ def test_rnapdbee_adapters_api_compliance_other(obj):
90
90
  @settings(max_examples=10)
91
91
  def test_rnapdbee_adapters_api_compliance_structure2d(obj):
92
92
  assert obj.__dict__.keys() >= {
93
- "basePairs",
93
+ "base_pairs",
94
94
  "stackings",
95
- "baseRiboseInteractions",
96
- "basePhosphateInteractions",
97
- "otherInteractions",
95
+ "base_ribose_interactions",
96
+ "base_phosphate_interactions",
97
+ "other_interactions",
98
98
  }
99
99
 
100
100
 
@@ -134,7 +134,7 @@ def test_pseudoknot_order_assignment():
134
134
 
135
135
  def test_multi_strand_dot_bracket():
136
136
  input = ">strand_A\nAGCGCCUGGACUUAAAGCCAU\n..((((.((((((((((((..\n>strand_B\nGGCUUUAAGUUGACGAGGGCAGGGUUUAUCGAGACAUCGGCGGGUGCCCUGCGGUCUUCCUGCGACCGUUAGAGGACUGGUAAAACCACAGGCGACUGUGGCAUAGAGCAGUCCGGGCAGGAA\n)))))))))))..(((...[[[[[[...)))......)))))...]]]]]][[[[[.((((((]]]]].....((((((......((((((....)))))).......))))))..))))))."
137
- dot_bracket = MultiStrandDotBracket.from_string(input)
137
+ dot_bracket = MultiStrandDotBracket.from_multiline_string(input)
138
138
  assert len(dot_bracket.strands) == 2
139
139
  assert dot_bracket.strands[0].sequence == "AGCGCCUGGACUUAAAGCCAU"
140
140
  assert dot_bracket.strands[1].sequence == (
@@ -152,7 +152,7 @@ def test_conflicted_base_pairs():
152
152
 
153
153
  base_pairs = []
154
154
 
155
- for obj in data.get("basePairs", []):
155
+ for obj in data.get("base_pairs", []):
156
156
  nt1 = Residue(
157
157
  None,
158
158
  ResidueAuth(
@@ -10,7 +10,7 @@ def test_2HY9():
10
10
  structure3d = read_3d_structure(f, 1)
11
11
  base_interactions = extract_base_interactions(structure3d)
12
12
  mapping = Mapping2D3D(
13
- structure3d, base_interactions.basePairs, base_interactions.stackings, True
13
+ structure3d, base_interactions.base_pairs, base_interactions.stackings, True
14
14
  )
15
15
 
16
16
  # tract 1
@@ -63,7 +63,7 @@ def test_6RS3():
63
63
  structure3d = read_3d_structure(f, 1)
64
64
  base_interactions = extract_base_interactions(structure3d)
65
65
  mapping = Mapping2D3D(
66
- structure3d, base_interactions.basePairs, base_interactions.stackings, True
66
+ structure3d, base_interactions.base_pairs, base_interactions.stackings, True
67
67
  )
68
68
 
69
69
  g1 = structure3d.find_residue(ResidueLabel("A", 1, "DG"), None)
@@ -108,7 +108,7 @@ def test_1JJP():
108
108
  structure3d = read_3d_structure(f, 1)
109
109
  base_interactions = extract_base_interactions(structure3d)
110
110
  mapping = Mapping2D3D(
111
- structure3d, base_interactions.basePairs, base_interactions.stackings, True
111
+ structure3d, base_interactions.base_pairs, base_interactions.stackings, True
112
112
  )
113
113
 
114
114
  ag1 = structure3d.find_residue(ResidueLabel("A", 1, "DG"), None)
@@ -182,7 +182,7 @@ def test_6FC9():
182
182
  structure3d = read_3d_structure(f, 1)
183
183
  base_interactions = extract_base_interactions(structure3d)
184
184
  mapping = Mapping2D3D(
185
- structure3d, base_interactions.basePairs, base_interactions.stackings, True
185
+ structure3d, base_interactions.base_pairs, base_interactions.stackings, True
186
186
  )
187
187
 
188
188
  g1 = structure3d.find_residue(ResidueLabel("A", 1, "DG"), None)
@@ -258,7 +258,7 @@ def test_UGG_md():
258
258
  structure3d = read_3d_structure(f, 1)
259
259
  base_interactions = extract_base_interactions(structure3d)
260
260
  mapping = Mapping2D3D(
261
- structure3d, base_interactions.basePairs, base_interactions.stackings, True
261
+ structure3d, base_interactions.base_pairs, base_interactions.stackings, True
262
262
  )
263
263
 
264
264
  u1 = structure3d.find_residue(None, ResidueAuth(" ", 1, None, "U5"))
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes