# Copyright 2007-2008 Nanorex, Inc. See LICENSE file for details. """ dna_updater_main.py - enforce rules on newly changed DNA-related model objects, including DnaGroups, AxisChunks, PAM atoms, etc. @author: Bruce @version: $Id$ @copyright: 2007-2008 Nanorex, Inc. See LICENSE file for details. """ from dna.updater.dna_updater_globals import get_changes_and_clear from dna.updater.dna_updater_globals import ignore_new_changes from dna.updater.dna_updater_globals import clear_updater_run_globals from dna.updater.dna_updater_globals import _f_invalid_dna_ladders from dna.updater.dna_updater_globals import restore_dnaladder_inval_policy from dna.updater.dna_updater_globals import DNALADDER_INVAL_IS_OK from utilities import debug_flags from dna.updater.dna_updater_utils import remove_killed_atoms from dna.updater.dna_updater_utils import remove_closed_or_disabled_assy_atoms from dna.updater.dna_updater_atoms import update_PAM_atoms_and_bonds from dna.updater.dna_updater_chunks import update_PAM_chunks from dna.updater.dna_updater_groups import update_DNA_groups from dna.updater.dna_updater_debug import debug_prints_as_dna_updater_starts from dna.updater.dna_updater_debug import debug_prints_as_dna_updater_ends from dna.model.DnaMarker import _f_are_there_any_homeless_dna_markers from dna.model.DnaMarker import _f_get_homeless_dna_markers # == _runcount = 0 # for debugging [bruce 080227] def full_dna_update(): """ [meant to be called from _master_model_updater] Enforce rules on all newly changed DNA-related model objects, including DnaGroups, AxisChunks, PAM atoms, etc. @warning: external calls to any smaller parts of the dna updater would probably have bugs, due to the lack of beginning and ending calls to clear_updater_run_globals, and possibly for many other reasons. In fact, external calls to this function rather than to update_parts (which calls it) are risky, since it's not reviewed how much this function depends on things that update_parts has normally done by the time it calls this. @note: The newly changed objects are not necessarily all in the same assy (class assembly). E.g. there might be some from an open mmp file and some from a just-opened part library part. @return: None """ global _runcount _runcount += 1 clear_updater_run_globals() try: _full_dna_update_0( _runcount) # includes debug_prints_as_dna_updater_starts finally: debug_prints_as_dna_updater_ends( _runcount) clear_updater_run_globals() return def _full_dna_update_0( _runcount): """ [private helper for full_dna_update -- do all the work] """ # TODO: process _f_baseatom_wants_pam: (or maybe a bit later, after delete bare, and error finding?) # - extend to well-structured basepairs; drop structure error atoms (as whole basepairs) # - these and their baseatom neighbors in our changed atoms, maybe even real .changed_structure changed_atoms = get_changes_and_clear() debug_prints_as_dna_updater_starts( _runcount, changed_atoms) # note: this function should not modify changed_atoms. # note: the corresponding _ends call is in our caller. if not changed_atoms and not _f_are_there_any_homeless_dna_markers(): # maybe: also check _f_baseatom_wants_pam, invalid ladders, here and elsewhere # (or it might be more efficient to officially require _changed_structure on representative atoms, # which we're already doing now as a kluge workaround for the lack of testing those here) # [bruce 080413 comment] # # note: adding marker check (2 places) fixed bug 2673 [bruce 080317] return # optimization (might not be redundant with caller) # print debug info about the set of changed_atoms (and markers needing update) if debug_flags.DEBUG_DNA_UPDATER_MINIMAL: print "\ndna updater: %d changed atoms to scan%s" % \ ( len(changed_atoms), _f_are_there_any_homeless_dna_markers() and " (and some DnaMarkers)" or "" ) if debug_flags.DEBUG_DNA_UPDATER and changed_atoms: # someday: should be _VERBOSE, but has been useful enough to keep seeing for awhile items = changed_atoms.items() items.sort() atoms = [item[1] for item in items] NUMBER_TO_PRINT = 10 if debug_flags.DEBUG_DNA_UPDATER_VERBOSE or len(atoms) <= NUMBER_TO_PRINT: print " they are: %r" % atoms else: print " the first %d of them are: %r ..." % \ (NUMBER_TO_PRINT, atoms[:NUMBER_TO_PRINT]) if changed_atoms: remove_killed_atoms( changed_atoms) # only affects this dict, not the atoms if changed_atoms: remove_closed_or_disabled_assy_atoms( changed_atoms) # This should remove all remaining atoms from closed files. # Note: only allowed when no killed atoms are present in changed_atoms; # raises exceptions otherwise. if changed_atoms: update_PAM_atoms_and_bonds( changed_atoms) # this can invalidate DnaLadders as it changes various things # which call atom._changed_structure -- that's necessary to allow, # so we don't change dnaladder_inval_policy until below, # inside update_PAM_chunks [bruce 080413 comment] # (REVIEW: atom._changed_structure does not directly invalidate # dna ladders, so I'm not sure if this comment is just wrong, # or if it meant something not exactly what it said, like, # this can cause more ladders to be invalidated than otherwise # in an upcoming step -- though if it meant that, it seems # wrong too, since the existence of that upcoming step # might be enough reason to not be able to change the policy yet. # [bruce 080529 addendum/Q]) if not changed_atoms and not _f_are_there_any_homeless_dna_markers() and not _f_invalid_dna_ladders: return # optimization homeless_markers = _f_get_homeless_dna_markers() #e rename, homeless is an obs misleading term #### # this includes markers whose atoms got killed (which calls marker.remove_atom) # or got changed in structure (which calls marker.changed_structure) # so it should not be necessary to also add to this all markers noticed # on changed_atoms, even though that might include more markers than # we have so far (especially after we add atoms from invalid ladders below). # # NOTE: it can include fewer markers than are noticed by _f_are_there_any_homeless_dna_markers # since that does not check whether they are truly homeless. assert not _f_are_there_any_homeless_dna_markers() # since getting them cleared them new_chunks, new_wholechains = update_PAM_chunks( changed_atoms, homeless_markers) # note: at the right time during this or a subroutine, it sets # dnaladder_inval_policy to DNALADDER_INVAL_IS_ERROR # review: if not new_chunks, return? wait and see if there are also new_markers, etc... update_DNA_groups( new_chunks, new_wholechains) # review: # args? a list of nodes, old and new, whose parents should be ok? or just find them all, scanning MT? # the underlying nodes we need to place are just chunks and jigs. we can ignore old ones... # so we need a list of new or moved ones... chunks got made in update_PAM_chunks; jigs, in update_PAM_atoms_and_bonds... # maybe pass some dicts into these for them to add things to? ignore_new_changes("as full_dna_update returns", changes_ok = False ) if debug_flags.DEBUG_DNA_UPDATER_MINIMAL: if _f_are_there_any_homeless_dna_markers(): print "dna updater fyi: as updater returns, some DnaMarkers await processing by next run" # might be normal...don't know. find out, by printing it even # in minimal debug output. [bruce 080317] if _f_invalid_dna_ladders: #bruce 080413 print "\n*** likely bug: some invalid ladders are recorded, as dna updater returns:", _f_invalid_dna_ladders # but don't clear them, in case this was sometimes routine and we were # working around bugs (unknowingly) by invalidating them next time around restore_dnaladder_inval_policy( DNALADDER_INVAL_IS_OK) return # from _full_dna_update_0 # end