Exemplo n.º 1
0
	def __init__(cls, name, bases, attrs):
		if attrs.get('pickup'):
			datastores = attrs.get('pickup')
			if not isinstance(datastores, list):
				datastores = [datastores]

			# Cycle through all the classes that have been declared in this module, so we can augment this class with those ones
			# Limitation: You have to declare your branches in the same place as this module
			# TODO: Get around above limitation by passing a string and importing that way

			for datastore in datastores:
				find_classes = []
				all_modules = sys.modules.keys()

				# For ease in use, we inspect all modules available at this place in the code
				# and look for the pickups classes
				for module_key in all_modules:
					module = sys.modules[module_key]
					get_all_module_classes = inspect.getmembers(module, inspect.isclass)

					# Now go through all classes in this particular module
					for class_name, class_reference in get_all_module_classes:
						nested_class_name = NS2.string(
							cls.qual_name_format,
							branch=cls.__name__,
							delim=cls.qual_name_delimiter,
							subbranch=class_reference.__name__
							)
						if class_name in attrs.keys():   # first check to see if the programmer declared something else by the same name
							declared_class = attrs[class_name]  # this is now whatever the programmer declared
							if inspect.isclass(declared_class) and issubclass(declared_class, datastore):
								# If we're here, we need to adjust some augment, to match what we would do automatically (like below)
								setattr(declared_class, '__qualname__', nested_class_name)
								setattr(declared_class, '__outerclass__', cls)
						elif class_reference is not datastore:  # check to ensure our heuristic doesn't detect itself
							if 	is_immediate_subclass(class_reference, datastore): # now see if this object is subclass of class represented by `pickup`
								# okay, we need to manually pickup the class and bring it into ours
								# copy the class entirely (won't work otherwise)
								copied_class = type(name, class_reference.__bases__, dict(class_reference.__dict__))
								# set up magic
								copied_class.__qualname__ = nested_class_name
								copied_class.__outerclass__ = cls
								# and assign this brand new class to ours
								setattr(cls, class_reference.__name__, copied_class)
						else:
							pass # nothing to do here, programmer defined a method or object with the same name but not a subclass of class referenced by `pickup`
    def subtract(self):
        """
        Yields ModificationStatements, which get fed back into the go method, which in turn
        dispatches the message to lower-level routines
        The ModfiicationStatements represent the changes that have occured.
        This method inspects meta data and passes on further inspections to the model itself
        """

        # First, process the meta data about the model, which
        # is basically just checking the keys for additions
        # then looking for differences between each item
        # then we check the keys for subtractions

        assert(len(self.left.get_subbranches()) == len(self.right.get_subbranches()))

        # NOTE, removed custom_profile_fields and timetable_datas

        subbranches = [
        'cohorts', 'courses', 'teachers', 'students',
        'groups', 'parents', 'parent_links', 'online_portfolios'
        ] # self.left.get_subbranches()

        for subbranch in subbranches:
            self.default_logger("Subbranch: {}".format(subbranch))

            left_branch = self.get_subbranch(self.left, subbranch)
            right_branch = self.get_subbranch(self.right, subbranch)
            self.default_logger("There are {} items in {}'s left branch".format(len(right_branch), subbranch))
            self.default_logger("There are {} items in {}'s right branch".format(len(right_branch), subbranch))

            self.default_logger("Looking for new {}:".format(subbranch))

            # Loop through missing stuff and do with it what we must
            for key in right_branch.keys() - left_branch.keys():
                yield ModificationStatement(
                    left = left_branch.get(key),
                    right = right_branch.get(key),
                    status = NS2.string("new_{term}", term=subbranch[:-1]),
                    param = key
                    )

        # Now go through the model and inspect the individual items
        # We have to go through each key on the left side, and on the right

        for subbranch in subbranches:
            self.default_logger("Individual items: {}".format(subbranch))
            left_branch = self.get_subbranch(self.left, subbranch)
            right_branch = self.get_subbranch(self.right, subbranch)

            # Left side:
            for item_key in left_branch:
                item_left = left_branch.get(item_key)
                item_right = right_branch.get(item_key)
                if item_left and item_right:

                    # The model itself defines how to look at each item with __sub__
                    # And we just yield that result
                    for left_minus_right in item_left - item_right:
                        yield ModificationStatement(
                            left = left_minus_right.left,
                            right = left_minus_right.right,
                            status = left_minus_right.status,
                            param = left_minus_right.param
                            )

            # short circuit out of this

            if subbranch in ["parent_links", "online_portfolios"]:
                # not compatible with the below, especially with make, because it wants the child
                continue

            # Right side:
            for item_key in right_branch:
                item_left = left_branch.get(item_key)
                item_right = right_branch.get(item_key)

                # Same principal as with the left side, but
                # there is a special case where, there is something on the right
                # but nothing on the left
                # The modification statement for "new_" will be spit out by the above
                # so we can just make a proxy object in order to manufacture the yield statements
                if item_right and not item_left and item_right.idnumber:

                    # Makes an empty, default one
                    fake = getattr(self.left, subbranch).\
                            make(item_right.idnumber)

                    # Notice fake - item_right
                    for right_minus_left in fake - item_right:
                        yield ModificationStatement(
                            left = right_minus_left.left,
                            right = right_minus_left.right,
                            status = right_minus_left.status,
                            param = right_minus_left.param
                            )


        for subbranch in subbranches:
            self.default_logger("Looking for old {}".format(subbranch))
            left_branch = self.get_subbranch(self.left, subbranch)
            right_branch = self.get_subbranch(self.right, subbranch)

            for key in left_branch.keys() - right_branch.keys():
                yield ModificationStatement(
                    left = left_branch.get(key),
                    right = right_branch.get(key),
                    status = NS2.string("old_{term}", term=subbranch[:-1]),
                    param = key
                    )