'Append columns to a Plotly grid.
`columns` is an iterable of plotly.grid_objs.Column objects
and only one of `grid` and `grid_url` needs to specified.
`grid` is a ploty.grid_objs.Grid object that has already been
uploaded to plotly with the grid_ops.upload method.
`grid_url` is a unique URL of a `grid` in your plotly account.
Usage example 1: Upload a grid to Plotly, and then append a column
from plotly.grid_objs import Grid, Column
import plotly.plotly as py
column_1 = Column([1, 2, 3], \'time\')
grid = Grid([column_1])
py.grid_ops.upload(grid, \'time vs voltage\')
# append a column to the grid
column_2 = Column([4, 2, 5], \'voltage\')
py.grid_ops.append_columns([column_2], grid=grid)
Usage example 2: Append a column to a grid that already exists on
Plotly
from plotly.grid_objs import Grid, Column
import plotly.plotly as py
grid_url = \'https://plot.ly/~chris/3143\'
column_1 = Column([1, 2, 3], \'time\')
py.grid_ops.append_columns([column_1], grid_url=grid_url)'

@classmethod
def append_columns(cls, columns, grid=None, grid_url=None):

    grid_id = parse_grid_id_args(grid, grid_url)
    grid_ops.ensure_uploaded(grid_id)
    column_names = [c.name for c in columns]
    if grid:
        existing_column_names = [c.name for c in grid]
        column_names.extend(existing_column_names)
    duplicate_name = utils.get_first_duplicate(column_names)
    if duplicate_name:
        err = exceptions.NON_UNIQUE_COLUMN_MESSAGE.format(duplicate_name)
        raise exceptions.InputError(err)
    body = {'cols': _json.dumps(columns, cls=utils.PlotlyJSONEncoder)}
    fid = grid_id
    response = v2.grids.col_create(fid, body)
    parsed_content = response.json()
    cls._fill_in_response_column_ids(columns, parsed_content['cols'], fid)
    if grid:
        grid.extend(columns)
