code: def _propagate(self, package):  # type: (str) -> None
          
          changed = set()
          changed.add(package)
  
          while changed:
              package = changed.pop()
  
              # Iterate in reverse because conflict resolution tends to produce more
              # general incompatibilities as time goes on. If we look at those first,
              # we can derive stronger assignments sooner and more eagerly find
              # conflicts.
              for incompatibility in reversed(self._incompatibilities[package]):
                  result = self._propagate_incompatibility(incompatibility)
  
                  if result is _conflict:
                      # If the incompatibility is satisfied by the solution, we use
                      # _resolve_conflict() to determine the root cause of the conflict as a
                      # new incompatibility.
                      #
                      # It also backjumps to a point in the solution
                      # where that incompatibility will allow us to derive new assignments
                      # that avoid the conflict.
                      root_cause = self._resolve_conflict(incompatibility)
  
                      # Back jumping erases all the assignments we did at the previous
                      # decision level, so we clear [changed] and refill it with the
                      # newly-propagated assignment.
                      changed.clear()
                      changed.add(str(self._propagate_incompatibility(root_cause)))
                      break
                  elif result is not None:
                      changed.add(result)
docs: Performs unit propagation on incompatibilities transitively
          related to package to derive new assignments for _solution.