def start_grass_linux_newLocation(gisdb, location, srs, grassBin=None, overwrite=True): """ Method to open GRASS GIS on Linux Systems Creates a new location Parameters: * gisdb - abs path to grass workspace * location - name for the grass location * srs - epsg or file to define spatial reference system of the location that will be created """ location_path = os.path.join(gisdb, location) # Delete location if exists if os.path.exists(location_path): if overwrite: del_folder(location_path) else: raise ValueError('GRASS GIS 7 Location already exists') grassbin = grassBin if grassBin else 'grass76' startcmd = grassbin + ' --config path' outcmd = exec_cmd(startcmd) gisbase = outcmd.strip('\n') # Set GISBASE environment variable os.environ['GISBASE'] = gisbase # the following not needed with trunk os.environ['PATH'] += os.pathsep + os.path.join(gisbase, 'extrabin') # add path to GRASS addons home = os.path.expanduser("~") os.environ['PATH'] += os.pathsep + os.path.join(home, '.grass7', 'addons', 'scripts') # define GRASS-Python environment gpydir = os.path.join(gisbase, "etc", "python") sys.path.append(gpydir) if type(srs) == int: startcmd = '{} -c epsg:{} -e {}' elif type(srs) == str or type(srs) == unicode: startcmd = '{} -c {} -e {}' outcmd = exec_cmd(startcmd.format(grassbin, str(srs), location_path)) # Set GISDBASE environment variable os.environ['GISDBASE'] = gisdb # See if there is location if not os.path.exists(location_path): raise ValueError('NoError, but location is not created') return gisbase
def intersection(inShp, intersectShp, outShp, api='geopandas'): """ Intersection between ESRI Shapefile 'API's Available: * geopandas * saga; * pygrass; * grass; """ if api == 'geopandas': import geopandas from gasp.gt.fmshp import shp_to_obj from gasp.gt.toshp import df_to_shp dfShp = shp_to_obj(inShp) dfIntersect = shp_to_obj(intersectShp) res_interse = geopandas.overlay(dfShp, dfIntersect, how='intersection') df_to_shp(res_interse, outShp) elif api == 'saga': from gasp import exec_cmd cmdout = exec_cmd( ("saga_cmd shapes_polygons 14 -A {} -B {} -RESULT {} -SPLIT 1" ).format(inShp, intersectShp, outShp)) elif api == 'pygrass': from grass.pygrass.modules import Module clip = Module("v.overlay", ainput=inShp, atype="area", binput=intersectShp, btype="area", operator="and", output=outShp, overwrite=True, run_=False, quiet=True) clip() elif api == 'grass': from gasp import exec_cmd rcmd = exec_cmd( ("v.overlay ainput={} atype=area, binput={} btype=area " "operator=and output={} --overwrite --quiet").format( inShp, intersectShp, outShp)) else: raise ValueError("{} is not available!".format(api)) return outShp
def sel_by_attr(inShp, sql, outShp, geomType="area", lyrN=1, api_gis='ogr'): """ Select vectorial file and export to new file If api_gis == 'grass' or 'pygrass', sql is not a query but the where clause API's Available: * ogr; * grass; * pygrass """ if api_gis == 'ogr': from gasp import exec_cmd from gasp.prop.ff import drv_name out_driver = drv_name(outShp) cmd = 'ogr2ogr -f "{drv}" {o} {i} -dialect sqlite -sql "{s}"'.format( o=outShp, i=inShp, s=sql, drv=out_driver) # Execute command outcmd = exec_cmd(cmd) elif api_gis == 'pygrass': """ v.extract via pygrass """ from grass.pygrass.modules import Module m = Module("v.extract", input=inShp, type=geomType, layer=lyrN, where=sql, output=outShp, overwrite=True, run_=False, quiet=True) m() elif api_gis == 'grass': """ v.extract via command shell """ from gasp import exec_cmd rcmd = exec_cmd( ("v.extract input={} type={} layer={} where={} " "output={} --overwrite --quiet").format(inShp, geomType, str(lyrN), sql, outShp)) else: raise ValueError('API {} is not available'.format(api_gis)) return outShp
def rstcalc(expression, output, template=None, api='arcpy', grids=None): """ Basic Raster Calculator """ if api == 'arcpy': import arcpy if template: tempEnvironment0 = arcpy.env.extent arcpy.env.extent = template arcpy.gp.RasterCalculator_sa(expression, output) if template: arcpy.env.extent = tempEnvironment0 elif api == 'saga': # Using SAGA GIS import os from gasp.oss import get_filename from gasp import exec_cmd from gasp.to.rst.saga import saga_to_geotiff SAGA_RASTER = os.path.join(os.path.dirname(output), "sag_{}.sgrd".format(get_filename(output))) cmd = ("saga_cmd grid_calculus 1 -FORMULA \"{}\" -GRIDS \"{}\" " "-RESULT {} -RESAMPLING 0").format(expression, ";".join(grids), SAGA_RASTER) outcmd = exec_cmd(cmd) # Convert to tiff saga_to_geotiff(SAGA_RASTER, output) elif api == 'pygrass': from grass.pygrass.modules import Module rc = Module('r.mapcalc', '{} = {}'.format(output, expression), overwrite=True, run_=False, quiet=True) rc() elif api == 'grass': from gasp import exec_cmd rcmd = exec_cmd(("r.mapcalc \"{} = {}\" --overwrite --quiet").format( output, expression)) else: raise ValueError("{} is not available!".format(api)) return output
def union(lyrA, lyrB, outShp, api_gis="arcpy"): """ Calculates the geometric union of the overlayed polygon layers, i.e. the intersection plus the symmetrical difference of layers A and B. API's Available: * arcpy; * saga; * grass_cmd; * grass_cmd; """ if api_gis == "arcpy": import arcpy if type(lyrB) == list: lst = [lyrA] + lyrB else: lst = [lyrA, lyrB] arcpy.Union_analysis(";".join(lst), outShp, "ALL", "", "GAPS") elif api_gis == "saga": from gasp import exec_cmd rcmd = exec_cmd( ("saga_cmd shapes_polygons 17 -A {} -B {} -RESULT {} -SPLIT 1" ).format(lyrA, lyrB, outShp)) elif api_gis == "grass": from grass.pygrass.modules import Module un = Module("v.overlay", ainput=lyrA, atype="area", binput=lyrB, btype="area", operator="or", output=outShp, overwrite=True, run_=False, quiet=True) un() elif api_gis == "grass_cmd": from gasp import exec_cmd outcmd = exec_cmd( ("v.overlay ainput={} atype=area binput={} btype=area " "operator=or output={} --overwrite --quiet").format( lyrA, lyrB, outShp)) else: raise ValueError("{} is not available!".format(api_gis)) return outShp
def clip(inFeat, clipFeat, outFeat, api_gis="grass", clip_by_region=None): """ Clip Analysis api_gis Options: * grass * pygrass * ogr2ogr """ if api_gis == "pygrass": from grass.pygrass.modules import Module if not clip_by_region: vclip = Module("v.clip", input=inFeat, clip=clipFeat, output=outFeat, overwrite=True, run_=False, quiet=True) else: vclip = Module("v.clip", input=inFeat, output=outFeat, overwrite=True, flags='r', run_=False, quiet=True) vclip() elif api_gis == "grass": from gasp import exec_cmd rcmd = exec_cmd( "v.clip input={}{} output={} {}--overwrite --quiet".format( inFeat, " clip={}".format(clipFeat) if clipFeat else "", outFeat, "-r " if not clipFeat else "")) elif api_gis == 'ogr2ogr': from gasp import exec_cmd from gasp.pyt.oss import fprop from gasp.gt.prop.ff import drv_name rcmd = exec_cmd( ("ogr2ogr -f \"{}\" {} {} -clipsrc {} -clipsrclayer {}").format( drv_name(outFeat), outFeat, inFeat, clipFeat, fprop(clipFeat, 'fn'))) else: raise ValueError("{} is not available!".format(api_gis)) return outFeat
def merge_feat(shps, outShp, api="ogr2ogr"): """ Get all features in several Shapefiles and save them in one file """ if api == "ogr2ogr": from gasp import exec_cmd from gasp.prop.ff import drv_name out_drv = drv_name(outShp) # Create output and copy some features of one layer (first in shps) cmdout = exec_cmd('ogr2ogr -f "{}" {} {}'.format( out_drv, outShp, shps[0] )) # Append remaining layers lcmd = [exec_cmd( 'ogr2ogr -f "{}" -update -append {} {}'.format( out_drv, outShp, shps[i] ) ) for i in range(1, len(shps))] elif api == 'pandas': """ Merge SHP using pandas """ from gasp.fm import tbl_to_obj from gasp.to.shp import df_to_shp if type(shps) != list: raise ValueError('shps should be a list with paths for Feature Classes') dfs = [tbl_to_obj(shp) for shp in shps] result = dfs[0] for df in dfs[1:]: result = result.append(df, ignore_index=True, sort=True) df_to_shp(result, outShp) else: raise ValueError( "{} API is not available" ) return outShp
def rst_to_grs(rst, grsRst, as_cmd=None): """ Raster to GRASS GIS Raster """ if not as_cmd: from grass.pygrass.modules import Module m = Module("r.in.gdal", input=rst, output=grsRst, flags='o', overwrite=True, run_=False, quiet=True) m() else: from gasp import exec_cmd rcmd = exec_cmd(("r.in.gdal input={} output={} -o --overwrite " "--quiet").format(rst, grsRst)) return grsRst
def clip(inFeat, clipFeat, outFeat, api_gis="grass"): """ Clip Analysis api_gis Options: * grass * grass_cmd """ if api_gis == "grass": from grass.pygrass.modules import Module vclip = Module("v.clip", input=inFeat, clip=clipFeat, output=outFeat, overwrite=True, run_=False, quiet=True) vclip() elif api_gis == "grass_cmd": from gasp import exec_cmd rcmd = exec_cmd( "v.clip input={} clip={} output={} --overwrite --quiet".format( inFeat, clipFeat, outFeat)) else: raise ValueError("{} is not available!".format(api_gis)) return outFeat
def psql_cmd(db_name, sqlfile, dbcon=None): """ Run a sql file do whatever is on that script """ import os from gasp import exec_cmd from gasp.cons.psql import con_psql cdb = con_psql(db_set=dbcon) if os.path.isdir(sqlfile): from gasp.pyt.oss import lst_ff sqls = lst_ff(sqlfile, file_format='.sql') else: sqls = [sqlfile] cmd = 'psql -h {} -U {} -p {} -w {} < {}' for s in sqls: outcmd = exec_cmd( cmd.format(cdb['HOST'], cdb['USER'], cdb['PORT'], db_name, s)) return db_name
def summarize_table_fields(table, outFld, fld_name_fld_name=None, __upper=False): """ Summarize all fields in a table """ from gasp import exec_cmd from gasp.oss.ops import create_folder # List table fields: fields = lst_fld(table) # For each field, query data to summarize the values in the field cmd = 'ogr2ogr {o} {i} -dialect sqlite -sql "{s};"' if not os.path.exists(outFld): tmp = create_folder(outFld) for field in fields: outTbl = os.path.join(outFld, '{}.dbf'.format(field)) outcmd = exec_cmd( cmd.format(i=table, o=outTbl, s='SELECT {f_}{f} FROM {t} GROUP BY {f}'.format( f=field, t=os.path.splitext(os.path.basename(table))[0], f_='' if not fld_name_fld_name else '{}, '.format(fld_name_fld_name))))
def dump_db(db, outSQL, api='psql'): """ DB to SQL Script """ from gasp import exec_cmd if api == 'psql': from gasp.cons.psql import con_psql condb = con_psql() cmd = "pg_dump -U {} -h {} -p {} -w {} > {}".format( condb["USER"], condb["HOST"], condb["PORT"], db, outSQL) elif api == 'mysql': from gasp.cons.mysql import con_mysql condb = con_mysql() cmd = ("mysqldump -u {} --port {} -p{} --host {} " "{} > {}").format(condb["USER"], condb["PORT"], condb["PASSWORD"], condb["HOST"], db, outSQL) else: raise ValueError('{} API is not available'.format(api)) outcmd = exec_cmd(cmd) return outSQL
def start_grass_linux_existLocation(gisdb, grassBin=None): """ Method to start a GRASS GIS Session on Linux Systems Use a existing location """ grassbin = grassBin if grassBin else GRASS_BIN startcmd = grassbin + ' --config path' outcmd = exec_cmd(startcmd) gisbase = outcmd.strip('\n') # Set GISBASE environment variable os.environ['GISBASE'] = gisbase # the following not needed with trunk os.environ['PATH'] += os.pathsep + os.path.join(gisbase, 'extrabin') # add path to GRASS addons home = os.path.expanduser("~") os.environ['PATH'] += os.pathsep + os.path.join(home, '.grass7', 'addons', 'scripts') # define GRASS-Python environment gpydir = os.path.join(gisbase, "etc", "python") sys.path.append(gpydir) # Set GISDBASE environment variable os.environ['GISDBASE'] = gisdb return gisbase
def restore_db(conDB, sqlScript, api='psql'): """ Restore Database using SQL Script TODO: add mysql option """ from gasp import exec_cmd if api == 'psql': cmd = 'psql -h {} -U {} -p {} -w {} < {}'.format( conDB['HOST'], conDB['USER'], conDB['PORT'], conDB["DATABASE"], sqlScript ) elif api == 'mysql': cmd = 'mysql -u {} -p{} {} < {}'.format( conDB['USER'], conDB['PASSWORD'], conDB["DATABASE"], sqlScript ) else: raise ValueError('{} API is not available'.format(api)) outcmd = exec_cmd(cmd) return conDB["DATABASE"]
def viewshed(demrst, obsShp, output): """ This tool computes a visibility analysis using observer points from a point shapefile. """ import os from gasp.oss import get_filename from gasp import exec_cmd from gasp.to.rst.saga import saga_to_geotiff SAGA_RASTER = os.path.join( os.path.dirname(output), "sg_{}.sgrd".format(get_filename(output)) ) cmd = ( "saga_cmd ta_lighting 6 -ELEVATION {elv} -POINTS {pnt} " "-VISIBILITY {out} -METHOD 0" ).format( elv=demrst, pnt=obsShp, out=SAGA_RASTER ) outcmd = exec_cmd(cmd) # Convert to Tiif saga_to_geotiff(SAGA_RASTER, output) return output
def copy_insame_vector(inShp, colToBePopulated, srcColumn, destinyLayer, geomType="point,line,boundary,centroid", asCMD=None): """ Copy Field values from one layer to another in the same GRASS Vector """ if not asCMD: vtodb = Module("v.to.db", map=inShp, layer=destinyLayer, type=geomType, option="query", columns=colToBePopulated, query_column=srcColumn, run_=False, quiet=True) vtodb() else: from gasp import exec_cmd rcmd = exec_cmd( ("v.to.db map={} layer={} type={} option=query columns={} " "query_column={} --quiet").format(inShp, destinyLayer, geomType, colToBePopulated, srcColumn))
def grow_distance(inRst, outRst, api="pygrass"): """ Generates a raster map containing distance to nearest raster features """ if api == 'pygrass': from grass.pygrass.modules import Module m = Module('r.grow.distance', input=inRst, distance=outRst, metric='euclidean', overwrite=True, quiet=True, run_=False) m() elif api == "grass": from gasp import exec_cmd rcmd = exec_cmd( ("r.grow.distance input={} distance={} metric=euclidean " "--overwrite --quiet").format(inRst, outRst)) else: raise ValueError("API {} is not available".format(api)) return outRst
def kernel_density(pnt_feat, popField, radius, template, outRst): """ Kernel density estimation. If any point is currently in selection only selected points are taken into account. """ import os from gasp.prop.ext import rst_ext from gasp.prop.rst import get_cellsize from gasp.oss import get_filename from gasp.to.rst.saga import saga_to_geotiff left, right, bottom, top = rst_ext(template, gisApi='gdal') cellsize = get_cellsize(template, gisApi='gdal') SAGA_RASTER = os.path.join(os.path.dirname(outRst), 'saga_{}.sgrd'.format(get_filename(outRst))) cmd = ("saga_cmd grid_gridding 6 -POINTS {} -POPULATION {} " "-RADIUS {} -TARGET_DEFINITION 0 -TARGET_USER_SIZE {} " "-TARGET_USER_XMIN {} -TARGET_USER_XMAX {} " "-TARGET_USER_YMIN {} -TARGET_USER_YMAX {} " "-TARGET_OUT_GRID {}").format(pnt_feat, popField, str(radius), str(abs(cellsize)), str(left), str(right), str(bottom), str(top), SAGA_RASTER) outcmd = exec_cmd(cmd) # Convert to tiff saga_to_geotiff(SAGA_RASTER, outRst) return outRst
def osm_extract(in_osm, out_osm, left, right, bottom, top): """ Extract OSM Data from a xml/pbf with osmosis using some bounding box """ import os from gasp import exec_cmd in_fn, in_ff = fn, ff = os.path.splitext(os.path.basename(in_osm)) out_fn, out_ff = fn, ff = os.path.splitext(os.path.basename(out_osm)) cmd = ("osmosis --read-{_f} {dtparse}file={_in} " "--bounding-box top={t} left={l} bottom={b} right={r} " "--write-{outext} file={_out}").format( _f='pbf' if in_ff == '.pbf' else 'xml', _in=in_osm, t=str(top), l=str(left), b=str(bottom), r=str(right), _out=out_osm, outext='pbf' if out_ff == '.pbf' else 'xml', dtparse="" if in_ff == '.pbf' else 'enableDataParsing=no ') rcmd = exec_cmd(cmd) return out_osm
def surfrst(inPnt, attrCol, output, lyrN=1, ascmd=None): """ v.surf.rst - Performs surface interpolation from vector points map by splines. Spatial approximation and topographic analysis from given point or isoline data in vector format to floating point raster format using regularized spline with tension. """ if not ascmd: t = Module("v.surf.rst", input=inPnt, layer=lyrN, zcolumn=attrCol, elevation=output, overwrite=True, quiet=True, run_=False) t() else: from gasp import exec_cmd tcmd = ("v.surf.rst input={} layer={} zcolumn={} " "elevation={} --overwrite --quiet").format( inPnt, lyrN, attrCol, output) rcmd = exec_cmd(tcmd) return output
def restore_tbls(dbn, sql, tablenames=None): """ Restore tables from a sql Script TODO: add mysql option """ from gasp import exec_cmd from gasp.cons.psql import con_psql from gasp.pyt import obj_to_lst condb = con_psql() tbls = obj_to_lst(tablenames) tblStr = "" if not tablenames else " {}".format(" ".join([ "-t {}".format(t) for t in tbls])) outcmd = exec_cmd(( "pg_restore -U {user} -h {host} -p {port} " "-w{tbl} -d {db} {sqls}" ).format( user=condb["USER"], host=condb["HOST"], port=condb["PORT"], db=dbn, sqls=sql, tbl=tblStr )) return tablenames
def raster_report(rst, rel, _units=None, ascmd=None): """ Units options: * Options: mi, me, k, a, h, c, p ** mi: area in square miles ** me: area in square meters ** k: area in square kilometers ** a: area in acres ** h: area in hectares ** c: number of cells ** p: percent cover """ if not ascmd: from grass.pygrass.modules import Module report = Module( "r.report", map=rst, flags="h", output=rel, units=_units, run_=False, quiet=True ) report() else: from gasp.pyt import obj_to_lst from gasp import exec_cmd rcmd = exec_cmd("r.report map={} output={}{} -h".format( rst, rel, " units={}".format(",".join(obj_to_lst(_units))) if _units else "" )) return rel
def osm_to_psql(osmXml, osmdb): """ Use GDAL to import osmfile into PostGIS database """ from gasp import exec_cmd from gasp.cons.psql import con_psql from gasp.sql.i import db_exists is_db = db_exists(osmdb) if not is_db: from gasp.sql.db import create_db create_db(osmdb, api='psql') con = con_psql() cmd = ("ogr2ogr -f PostgreSQL \"PG:dbname='{}' host='{}' port='{}' " "user='******' password='******'\" {} -lco COLUM_TYPES=other_tags=hstore" ).format(osmdb, con["HOST"], con["PORT"], con["USER"], con["PASSWORD"], osmXml) cmdout = exec_cmd(cmd) return osmdb
def grs_near(fromShp, toShp, nearCatCol='tocat', nearDistCol="todistance", maxDist=-1, as_cmd=None): """ v.distance - Finds the nearest element in vector map 'to' for elements in vector map 'from'. """ from gasp.mng.grstbl import add_field add_field(fromShp, nearCatCol, 'INTEGER', ascmd=as_cmd) add_field(fromShp, nearDistCol, 'DOUBLE PRECISION', ascmd=as_cmd) if not as_cmd: import grass.script as grass grass.run_command("v.distance", _from=fromShp, to=toShp, upload='cat,dist', column='{},{}'.format(nearCatCol, nearDistCol), dmax=maxDist) else: from gasp import exec_cmd rcmd = exec_cmd( ("v.distance from={} to={} upload=cat,dist " "column={},{} dmax={}").format(fromShp, toShp, nearCatCol, nearDistCol, maxDist))
def grs_to_rst(grsRst, rst, as_cmd=None, allBands=None): """ GRASS Raster to Raster """ from gasp.prop.ff import RasterDrivers from gasp.oss import get_fileformat rstDrv = RasterDrivers() rstExt = get_fileformat(rst) if not as_cmd: from grass.pygrass.modules import Module m = Module( "r.out.gdal", input=grsRst, output=rst, format=rstDrv[rstExt], flags='c' if not allBands else '', createopt="INTERLEAVE=PIXEL,TFW=YES" if allBands else '', overwrite=True, run_=False, quiet=True ) m() else: from gasp import exec_cmd rcmd = exec_cmd(( "r.out.gdal input={} output={} format={} " "{} --overwrite --quiet" ).format( grsRst, rst, rstDrv[rstExt], "-c" if not allBands else "createopt=\"INTERLEAVE=PIXEL,TFW=YES\"" )) return rst
def add_pnts_to_network(network, pntLyr, outNetwork, __threshold=200, asCMD=None): """ Connect points to GRASS GIS Network """ if not asCMD: from grass.pygrass.modules import Module m = Module("v.net", input=network, points=pntLyr, operation="connect", threshold=__threshold, output=outNetwork, overwrite=True, run_=False) m() else: from gasp import exec_cmd rcmd = exec_cmd( ("v.net input={} points={} operation=connect threshold={} " "output={} --overwrite --quiet").format(network, pntLyr, __threshold, outNetwork)) return outNetwork
def geomtype_to_geomtype(inShp, outShp, fm_type, to_type, cmd=None): """ v.type - Changes type of vector features. v.type changes the type of geometry primitives. """ if not cmd: from grass.pygrass.modules import Module m = Module("v.type", input=inShp, output=outShp, from_type=fm_type, to_type=to_type, overwrite=True, run_=False, quiet=True) m() else: from gasp import exec_cmd rcmd = exec_cmd(("v.type input={} output={} from_type={} to_type={} " "--overwrite --quiet").format(inShp, outShp, fm_type, to_type)) return outShp
def shp_to_grs(inLyr, outLyr, filterByReg=None, asCMD=None): """ Add Shape to GRASS GIS """ if not asCMD: from grass.pygrass.modules import Module f = 'o' if not filterByReg else 'ro' m = Module( "v.in.ogr", input=inLyr, output=outLyr, flags='o', overwrite=True, run_=False, quiet=True ) m() else: from gasp import exec_cmd rcmd = exec_cmd(( "v.in.ogr input={} output={} -o{} --overwrite --quiet" ).format(inLyr, outLyr, " -r" if filterByReg else "")) return outLyr
def update_table(table, new_values, ref_values=None): """ Update a feature class table with new values Where with OR condition new_values and ref_values are dict with fields as keys and values as keys values. """ from gasp import exec_cmd if ref_values: update_query = 'UPDATE {tbl} SET {pair_new} WHERE {pair_ref};'.format( tbl=os.path.splitext(os.path.basename(table))[0], pair_new=','.join([ "{fld}={v}".format(fld=x, v=new_values[x]) for x in new_values ]), pair_ref=' OR '.join([ "{fld}='{v}'".format(fld=x, v=ref_values[x]) for x in ref_values ])) else: update_query = 'UPDATE {tbl} SET {pair};'.format( tbl=os.path.splitext(os.path.basename(table))[0], pair=','.join([ "{fld}={v}".format(fld=x, v=new_values[x]) for x in new_values ])) ogrinfo = 'ogrinfo {i} -dialect sqlite -sql "{s}"'.format(i=table, s=update_query) # Run command outcmd = exec_cmd(ogrinfo)
def del_cols(lyr, cols, api='grass', lyrn=1): """ Remove Columns from Tables """ from gasp.pyt import obj_to_lst cols = obj_to_lst(cols) if api == 'grass': from gasp import exec_cmd rcmd = exec_cmd(("v.db.dropcolumn map={} layer={} columns={} " "--quiet").format(lyr, str(lyrn), ','.join(cols))) elif api == 'pygrass': from grass.pygrass.modules import Module m = Module("v.db.dropcolumn", map=lyr, layer=lyrn, columns=cols, quiet=True, run_=True) else: raise ValueError("API {} is not available".format(api)) return lyr