La respuesta anterior da el resultado correcto, pero me permití mejorar el código para evitar muchas líneas innecesarias, además de iterar en los índices en lugar de los valores en la lista.
import geopandas as gpd
from shapely.geometry import Polygon
import numpy as np
points = gpd.read_file('points.shp')
xmin, ymin, xmax, ymax = points.total_bounds
length = 1000
wide = 1200
cols = list(np.arange(xmin, xmax + wide, wide))
rows = list(np.arange(ymin, ymax + length, length))
polygons = []
for x in cols[:-1]:
for y in rows[:-1]:
polygons.append(Polygon([(x,y), (x+wide, y), (x+wide, y+length), (x, y+length)]))
grid = gpd.GeoDataFrame({'geometry':polygons})
grid.to_file("grid.shp")
La idea principal puede ser la misma, pero ahora estamos creando variables mucho menos inútiles y el código completo es más claro de entender.