code: def alter_columns(op, name, *columns, **kwargs):
      
      selection_string = kwargs.pop('selection_string', None)
      if kwargs:
          raise TypeError(
              'alter_columns received extra arguments: %r' % sorted(kwargs),
          )
      if selection_string is None:
          selection_string = ', '.join(column.name for column in columns)
  
      tmp_name = '_alter_columns_' + name
      op.rename_table(name, tmp_name)
  
      for column in columns:
          # Clear any indices that already exist on this table, otherwise we will
          # fail to create the table because the indices will already be present.
          # When we create the table below, the indices that we want to preserve
          # will just get recreated.
          for table in name, tmp_name:
              try:
                  op.drop_index('ix_%s_%s' % (table, column.name))
              except sa.exc.OperationalError:
                  pass
  
      op.create_table(name, *columns)
      op.execute(
          'insert into %s select %s from %s' % (
              name,
              selection_string,
              tmp_name,
          ),
      )
      op.drop_table(tmp_name)
docs: Alter columns from a table.
  
      Parameters
      ----------
      name : str
          The name of the table.
      *columns
          The new columns to have.
      selection_string : str, optional
          The string to use in the selection. If not provided, it will select all
          of the new columns from the old table.
  
      Notes
      -----
      The columns are passed explicitly because this should only be used in a
      downgrade where ``zipline.assets.asset_db_schema`` could change.