def test_dependence_sort07(self): DS = self.DepSortable A = DS('End', ['Middle']) B = DS('Start') C = DS('Middle', ['Start']) self.assertEqual([B, C, A], dependence_sort([A, B, C], DS.key, DS.deps))
def test_dependence_sort03(self): DS = self.DepSortable A = DS('A', ['B']) B = DS('B') self.assertEqual([B, A], dependence_sort([A, B], DS.key, DS.deps) )
def test_dependence_sort02(self): A = self.DepSortable('A') B = self.DepSortable('B') self.assertListEqual( [A, B], dependence_sort([A, B], lambda ds: ds.name, lambda ds: ds.dependencies), )
def test_dependence_sort05(self): DS = self.DepSortable A = DS('A', ['C', 'D']) B = DS('B') C = DS('C', ['B']) D = DS('D') self.assertIn(dependence_sort([A, B, C, D], DS.key, DS.deps), ( [B, D, C, A], [B, C, D, A], [D, B, C, A], ))
def test_dependence_sort01(self): self.assertEqual([], dependence_sort([], lambda ds: ds.name, lambda ds: ds.dependencies))
def ordered_models_to_delete(app_config, connection): """Models of the given app to delete. @return A tuple (models, loop_error). 'models' is a list of the models classes to delete ; the order respects the dependencies between the models. 'loop_error' is a boolean which indicates dependencies loop error. """ from django.db import router from django.utils.datastructures import OrderedSet from creme.creme_core.utils.dependence_sort import dependence_sort, DependenciesLoopError class ModelInfo: # def __init__(self, model, dependencies, sql_cmd): def __init__(self, model, dependencies): self.model = model self.dependencies = dependencies # self.sql_cmd = sql_cmd def __str__(self): return 'ModelInfo(model={model}, dependencies={dependencies})'.format( model=self.model.__name__, dependencies=[d.__name__ for d in self.dependencies], ) models_info = [] cursor = connection.cursor() try: table_names = set(connection.introspection.table_names(cursor)) app_models = OrderedSet( router.get_migratable_models( app_config, connection.alias, # include_auto_created=True, # NB: the auto created tables are automatically # deleted by schema_editor.delete_model(model) include_auto_created=False, )) for model in app_models: meta = model._meta if connection.introspection.table_name_converter( meta.db_table) in table_names: # dependencies = [] dependencies = set() # We use a set to avoid duplicates for f in meta.local_fields: # if f.rel: if f.remote_field: # related_model = f.rel.to related_model = f.remote_field.model # if related_model in app_models: # NB: we avoid self-referencing (TODO: improve dependence_sort() ?) if related_model is not model and related_model in app_models: # dependencies.append(related_model) dependencies.add(related_model) models_info.append( ModelInfo( model=model, dependencies=dependencies, # sql_cmd=connection.creation.sql_destroy_model(model, [], style)[0], )) finally: cursor.close() dep_error = False try: models_info = dependence_sort( models_info, get_key=lambda mi: mi.model, get_dependencies=lambda mi: mi.dependencies, ) except DependenciesLoopError: dep_error = True else: models_info.reverse() # The dependencies must be deleted _after_ # return [mi.sql_cmd for mi in models_info], dep_error return [mi.model for mi in models_info], dep_error
def handle(self, *app_labels, **options): verbosity = options.get('verbosity') # eg: 'persons', 'creme_core'... all_apps = OrderedSet(app_config.label for app_config in creme_app_configs()) apps_2_populate = all_apps if not app_labels else \ [_checked_app_label(app, all_apps) for app in app_labels] # ---------------------------------------------------------------------- populators = [] populators_names = set() # Names of populators that will be run total_deps = set( ) # Populators names that are needed by our populators total_missing_deps = set() # All populators names that are added by # this script because of dependencies while True: changed = False for app_label in apps_2_populate: populator = self._get_populator(app_label=app_label, verbosity=verbosity, all_apps=all_apps, options=options) if populator is not None: populators.append(populator) populators_names.add(app_label) total_deps.update(populator.dependencies) changed = True if not changed: break apps_2_populate = total_deps - populators_names total_missing_deps |= apps_2_populate if total_missing_deps and verbosity >= 1: self.stdout.write( 'Additional dependencies will be populated: {}'.format( ', '.join(total_missing_deps)), self.style.NOTICE) # Clean the dependencies (avoid dependencies that do not exist in # 'populators', which would cause Exception raising) for populator in populators: populator.build_dependencies(populators_names) populators = dependence_sort( populators, BasePopulator.get_app, BasePopulator.get_dependencies, ) # ---------------------------------------------------------------------- self.models = set() dispatch_uid = 'creme_core-populate_command' pre_save.connect(self._signal_handler, dispatch_uid=dispatch_uid) for populator in populators: if verbosity >= 1: self.stdout.write('Populate "{}" ...'.format(populator.app), ending='') self.stdout.flush() try: populator.populate() except Exception as e: self.stderr.write(' Populate "{}" failed ({})'.format( populator.app, e)) if verbosity >= 1: exc_type, exc_value, exc_traceback = sys.exc_info() self.stderr.write(''.join( format_exception(exc_type, exc_value, exc_traceback))) if verbosity >= 1: self.stdout.write(' OK', self.style.SUCCESS) pre_save.disconnect(dispatch_uid=dispatch_uid) # ---------------------------------------------------------------------- if self.models: if verbosity >= 1: self.stdout.write( 'Update sequences for models : {}'.format( [model.__name__ for model in self.models]), ending='', ) self.stdout.flush() connection = connections[options.get('database', DEFAULT_DB_ALIAS)] cursor = connection.cursor() for line in connection.ops.sequence_reset_sql( no_style(), self.models): cursor.execute(line) # connection.close() #seems useless (& does not work with mysql) if verbosity >= 1: self.stdout.write(self.style.SUCCESS(' OK')) elif verbosity >= 1: self.stdout.write('No sequence to update.') if verbosity >= 1: self.stdout.write(self.style.SUCCESS('Populate is OK.'))