Edinburgh-Genome-Foundry / DnaCauldron

:alembic: Simple cloning simulator (Golden Gate etc.) for single and combinatorial assemblies
https://edinburgh-genome-foundry.github.io/DnaCauldron/
MIT License
50 stars 11 forks source link

TypeError: StickyEndSeq.reverse_complement() got an unexpected keyword argument 'inplace' #18

Closed antonkulaga closed 1 year ago

antonkulaga commented 1 year ago

I sometimes get the following error:

TypeError: StickyEndSeq.reverse_complement() got an unexpected keyword argument 'inplace'

I use latest version of DnaCauldro, biopython ( 1.8.1 ) and python 3.10, the stacktrace is:

ypeError                                 Traceback (most recent call last)
Input In [8], in <cell line: 5>()
      1 #repository.import_records(folder=str(twist / "A_round"), use_file_names_as_ids=True, topology="circular")
      2 B_assembly_plan = dc.AssemblyPlan.from_spreadsheet(
      3     assembly_class=dc.Type2sRestrictionAssembly, path= str(locations.algae / "B_round_2.csv")
      4 )
----> 5 B_simulation = B_assembly_plan.simulate(sequence_repository=repository)
      6 print("Assembly stats:", B_simulation.compute_stats())
      7 B_simulation.compute_summary_dataframe()

File ~/micromamba/envs/cf-cloning/lib/python3.10/site-packages/dnacauldron/AssemblyPlan/AssemblyPlan.py:257, in AssemblyPlan.simulate(self, sequence_repository)
    255 if assembly.name in cancelled_assemblies:
    256     continue
--> 257 simulation_result = assembly.simulate(sequence_repository)
    258 simulation_results.append(simulation_result)
    259 for record in simulation_result.construct_records:

File ~/micromamba/envs/cf-cloning/lib/python3.10/site-packages/dnacauldron/Assembly/builtin_assembly_classes/Type2sRestrictionAssembly.py:180, in Type2sRestrictionAssembly.simulate(self, sequence_repository, annotate_parts_homologies)
    177 warnings = []
    179 records = sequence_repository.get_records(self.parts)
--> 180 mix = generate_type2s_restriction_mix(
    181     records, enzyme=self.enzyme, name="type2s_mix"
    182 )
    183 if self.enzyme == "auto":
    184     self.enzyme = str(mix.enzymes[0])  # it has been autoselected!

File ~/micromamba/envs/cf-cloning/lib/python3.10/site-packages/dnacauldron/AssemblyMix/RestrictionLigationMix.py:101, in generate_type2s_restriction_mix(parts, enzyme, name)
     99 if enzyme == "auto":
    100     enzyme = autoselect_enzyme(parts)
--> 101 return RestrictionLigationMix(
    102     parts=parts,
    103     enzymes=[enzyme],
    104     fragment_filters=[NoRestrictionSiteFilter(str(enzyme))],
    105     name=name,
    106 )

File ~/micromamba/envs/cf-cloning/lib/python3.10/site-packages/dnacauldron/AssemblyMix/RestrictionLigationMix.py:69, in RestrictionLigationMix.__init__(self, parts, enzymes, fragments, fragment_filters, name, annotate_fragments_with_parts)
     67 self.name = name
     68 self.annotate_fragments_with_parts = annotate_fragments_with_parts
---> 69 self.initialize()

File ~/micromamba/envs/cf-cloning/lib/python3.10/site-packages/dnacauldron/AssemblyMix/AssemblyMix.py:30, in AssemblyMix.initialize(self)
     28 if not hasattr(self, "fragments") or self.fragments is None:
     29     self.compute_fragments()
---> 30 self.compute_reverse_fragments()
     31 self.compute_connections_graph()

File ~/micromamba/envs/cf-cloning/lib/python3.10/site-packages/dnacauldron/AssemblyMix/mixins/FragmentsMixin.py:33, in FragmentsMixin.compute_reverse_fragments(self)
     31 for fragment in self.fragments:
     32     fragment.is_reversed = False
---> 33     new_fragment = fragment.reverse_complement()
     34     new_fragment.is_reversed = True
     35     new_fragment.reverse_fragment = fragment

File ~/micromamba/envs/cf-cloning/lib/python3.10/site-packages/dnacauldron/Fragment/Fragment.py:34, in Fragment.reverse_complement(self)
     31 """Reverse-complement the fragment while keeping its class"""
     32 # Note: if the fragment has a StickyEndSeq, it will be properly
     33 # reverse-complemented with its ends
---> 34 new_record = SeqRecord.reverse_complement(self)
     35 new_record.__class__ = self.__class__
     36 return new_record

File ~/.local/lib/python3.10/site-packages/Bio/SeqRecord.py:1238, in SeqRecord.reverse_complement(self, id, name, description, features, annotations, letter_annotations, dbxrefs)
   1233     seq = self.seq.reverse_complement_rna(
   1234         inplace=False
   1235     )  # TODO: remove inplace=False
   1236 else:
   1237     # Default to DNA)
-> 1238     seq = self.seq.reverse_complement(
   1239         inplace=False
   1240     )  # TODO: remove inplace=False
   1241 if isinstance(self.seq, MutableSeq):
   1242     seq = Seq(seq)

TypeError: StickyEndSeq.reverse_complement() got an unexpected keyword argument 'inplace'
veghp commented 1 year ago

Thank you -- I had come across this before but had no chance to implement a solution yet. The issue seems to be that the reverse_complement() API got changed in Biopython 1.80. There seems to be a bit of inconsistency between the various Seq class types and inconsistency between Seq and SeqRecord's reverse_complement() function. I suspect that in DNA Cauldron the class inheritance causes problem somehow.

Here is the PR of the Biopython change: https://github.com/biopython/biopython/pull/3648

A suggested solution is https://github.com/biopython/biopython/issues/4177#issuecomment-1325784162 but not sure that will be so easy.