Ejemplo n.º 1
0
def get_interface_description(cmd):
    """Returns the XML description for the GRASS cmd (force text encoding to
    "utf-8").

    The DTD must be located in $GISBASE/gui/xml/grass-interface.dtd,
    otherwise the parser will not succeed.

    :param cmd: command (name of GRASS module)
    """
    try:
        p = Popen([cmd, "--interface-description"], stdout=PIPE, stderr=PIPE)
        cmdout, cmderr = p.communicate()

        # TODO: do it better (?)
        if not cmdout and sys.platform == "win32":
            # we in fact expect pure module name (without extension)
            # so, lets remove extension
            if cmd.endswith(".py"):
                cmd = os.path.splitext(cmd)[0]

            if cmd == "d.rast3d":
                sys.path.insert(0, os.path.join(os.getenv("GISBASE"), "gui", "scripts"))

            p = Popen(
                [sys.executable, get_real_command(cmd), "--interface-description"],
                stdout=PIPE,
                stderr=PIPE,
            )
            cmdout, cmderr = p.communicate()

            if cmd == "d.rast3d":
                del sys.path[0]  # remove gui/scripts from the path

        if p.returncode != 0:
            raise ScriptError(
                _(
                    "Unable to fetch interface description for command '<{cmd}>'."
                    "\n\nDetails: <{det}>"
                ).format(cmd=cmd, det=decode(cmderr))
            )

    except OSError as e:
        raise ScriptError(
            _(
                "Unable to fetch interface description for command '<{cmd}>'."
                "\n\nDetails: <{det}>"
            ).format(cmd=cmd, det=e)
        )

    desc = convert_xml_to_utf8(cmdout)
    desc = desc.replace(
        b"grass-interface.dtd",
        os.path.join(os.getenv("GISBASE"), "gui", "xml", "grass-interface.dtd").encode(
            "utf-8"
        ),
    )
    return desc
Ejemplo n.º 2
0
def _create_location_xy(database, location):
    """Create unprojected location

    Raise ScriptError on error.

    :param database: GRASS database where to create new location
    :param location: location name
    """
    cur_dir = os.getcwd()
    try:
        os.chdir(database)
        os.mkdir(location)
        os.mkdir(os.path.join(location, 'PERMANENT'))

        # create DEFAULT_WIND and WIND files
        regioninfo = [
            'proj:       0', 'zone:       0', 'north:      1', 'south:      0',
            'east:       1', 'west:       0', 'cols:       1', 'rows:       1',
            'e-w resol:  1', 'n-s resol:  1', 'top:        1', 'bottom:     0',
            'cols3:      1', 'rows3:      1', 'depths:     1', 'e-w resol3: 1',
            'n-s resol3: 1', 't-b resol:  1'
        ]

        defwind = open(os.path.join(location, "PERMANENT", "DEFAULT_WIND"),
                       'w')
        for param in regioninfo:
            defwind.write(param + '%s' % os.linesep)
        defwind.close()

        shutil.copy(os.path.join(location, "PERMANENT", "DEFAULT_WIND"),
                    os.path.join(location, "PERMANENT", "WIND"))

        os.chdir(cur_dir)
    except OSError as e:
        raise ScriptError(repr(e))
Ejemplo n.º 3
0
def parse_interface(name, parser=processTask, blackList=None):
    """Parse interface of given GRASS module

    The *name* is either GRASS module name (of a module on path) or
    a full or relative path to an executable.

    :param str name: name of GRASS module to be parsed
    :param parser:
    :param blackList:
    """
    try:
        tree = etree.fromstring(get_interface_description(name))
    except ETREE_EXCEPTIONS as error:
        raise ScriptError(
            _(
                "Cannot parse interface description of" "<{name}> module: {error}"
            ).format(name=name, error=error)
        )
    task = parser(tree, blackList=blackList).get_task()
    # if name from interface is different than the originally
    # provided name, then the provided name is likely a full path needed
    # to actually run the module later
    # (processTask uses only the XML which does not contain the original
    # path used to execute the module)
    if task.name != name:
        task.path = name
    return task
Ejemplo n.º 4
0
def fatal(msg):
    """Display an error message using `g.message -e`, then abort

    Raise exception when raise_on_error is 'True'.

    :param str msg: error message to be displayed
    """
    global raise_on_error
    if raise_on_error:
        raise ScriptError(msg)

    error(msg)
    sys.exit(1)
Ejemplo n.º 5
0
def make_command(prog,
                 flags="",
                 overwrite=False,
                 quiet=False,
                 verbose=False,
                 **options):
    """Return a list of strings suitable for use as the args parameter to
    Popen() or call(). Example:


    >>> make_command("g.message", flags = 'w', message = 'this is a warning')
    ['g.message', '-w', 'message=this is a warning']


    :param str prog: GRASS module
    :param str flags: flags to be used (given as a string)
    :param bool overwrite: True to enable overwriting the output (<tt>--o</tt>)
    :param bool quiet: True to run quietly (<tt>--q</tt>)
    :param bool verbose: True to run verbosely (<tt>--v</tt>)
    :param options: module's parameters

    :return: list of arguments
    """
    args = [prog]
    if overwrite:
        args.append("--o")
    if quiet:
        args.append("--q")
    if verbose:
        args.append("--v")
    if flags:
        if '-' in flags:
            raise ScriptError("'-' is not a valid flag")
        args.append("-%s" % flags)
    for opt, val in options.iteritems():
        if val != None:
            if opt.startswith('_'):
                opt = opt[1:]
                warning(
                    _("To run the module add underscore at the end"
                      " of the option <%s> to avoid conflict with Python"
                      " keywords. Underscore at the beginning is"
                      " depreciated in GRASS GIS 7.0 and will be removed"
                      " in version 7.1.") % opt)
            elif opt.endswith('_'):
                opt = opt[:-1]
            args.append("%s=%s" % (opt, _make_val(val)))
    return args
Ejemplo n.º 6
0
 def test_get_value(self):
     error = ScriptError('error')
     self.assertEqual('error', error.value)
Ejemplo n.º 7
0
 def test_str(self):
     error = ScriptError('error')
     self.assertEqual('error', str(error))
Ejemplo n.º 8
0
 def test_get_value(self):
     error = ScriptError("error")
     self.assertEqual("error", error.value)
Ejemplo n.º 9
0
 def test_str(self):
     error = ScriptError("error")
     self.assertEqual("error", str(error))
Ejemplo n.º 10
0
def vector_what(
    map,
    coord,
    distance=0.0,
    ttype=None,
    encoding=None,
    skip_attributes=False,
    layer=None,
    multiple=False,
    env=None,
):
    """Query vector map at given locations

    To query one vector map at one location

    ::

        print grass.vector_what(map='archsites', coord=(595743, 4925281),
                                distance=250)

        [{'Category': 8, 'Map': 'archsites', 'Layer': 1, 'Key_column': 'cat',
          'Database': '/home/martin/grassdata/spearfish60/PERMANENT/dbf/',
          'Mapset': 'PERMANENT', 'Driver': 'dbf',
          'Attributes': {'str1': 'No_Name', 'cat': '8'},
          'Table': 'archsites', 'Type': 'Point', 'Id': 8}]

    To query one vector map with multiple layers (no additional parameters
    required)

    ::

        for q in grass.vector_what(map='some_map', distance=100.0,
                                   coord=(596532.357143,4920486.21429)):
            print q['Map'], q['Layer'], q['Attributes']

        new_bug_sites 1 {'str1': 'Beetle_site', 'GRASSRGB': '', 'cat': '80'}
        new_bug_sites 2 {'cat': '80'}

    To query more vector maps at one location

    ::

        for q in grass.vector_what(map=('archsites', 'roads'),
                                   coord=(595743, 4925281), distance=250):
            print q['Map'], q['Attributes']

        archsites {'str1': 'No_Name', 'cat': '8'}
        roads {'label': 'interstate', 'cat': '1'}

    To query one vector map at more locations

    ::

        for q in grass.vector_what(map='archsites', distance=250,
                                   coord=[(595743, 4925281), (597950, 4918898)]):
            print q['Map'], q['Attributes']

        archsites {'str1': 'No_Name', 'cat': '8'}
        archsites {'str1': 'Bob_Miller', 'cat': '22'}

    :param map: vector map(s) to query given as string or list/tuple
    :param coord: coordinates of query given as tuple (easting, northing) or
                  list of tuples
    :param distance: query threshold distance (in map units)
    :param ttype: list of topology types (default of v.what are point, line,
                  area, face)
    :param encoding: attributes encoding
    :param skip_attributes: True to skip quering attributes
    :param layer: layer number or list of layers (one for each vector),
                  if None, all layers (-1) are used
    :param multiple: find multiple features within threshold distance
    :param env: environment

    :return: parsed list
    """
    if not env:
        env = os.environ.copy()
    if "LC_ALL" in env:
        env["LC_ALL"] = "C"

    if isinstance(map, (bytes, unicode)):
        map_list = [map]
    else:
        map_list = map

    if layer:
        if isinstance(layer, (tuple, list)):
            layer_list = [str(item) for item in layer]
        else:
            layer_list = [str(layer)]
        if len(layer_list) != len(map_list):
            raise ScriptError(
                _("Number of given vector maps ({m}) "
                  "differs from number of layers ({l})").format(
                      m=len(map_list), l=len(layer_list)))
    else:
        layer_list = ["-1"] * len(map_list)

    coord_list = list()
    if isinstance(coord, tuple):
        coord_list.append("%f,%f" % (coord[0], coord[1]))
    else:
        for e, n in coord:
            coord_list.append("%f,%f" % (e, n))

    flags = "j"
    if not skip_attributes:
        flags += "a"
    if multiple:
        flags += "m"
    cmdParams = dict(
        quiet=True,
        flags=flags,
        map=",".join(map_list),
        layer=",".join(layer_list),
        coordinates=",".join(coord_list),
        distance=float(distance),
    )
    if ttype:
        cmdParams["type"] = ",".join(ttype)

    try:
        ret = read_command("v.what", env=env, **cmdParams).strip()
    except CalledModuleError as e:
        raise ScriptError(e.msg)

    data = list()
    if not ret:
        return data

    # lazy import
    global json
    global orderedDict
    if json is None:
        import json
    if orderedDict is None:
        try:
            from collections import OrderedDict

            orderedDict = OrderedDict
        except ImportError:
            orderedDict = dict

    kwargs = {}
    if encoding:
        kwargs["encoding"] = encoding

    if sys.version_info[0:2] > (2, 6):
        kwargs["object_pairs_hook"] = orderedDict

    try:
        result = json.loads(ret, **kwargs)
    except ValueError:
        raise ScriptError(
            _("v.what output is not valid JSON format:\n {ret}").format(
                ret=ret))

    if multiple:
        for vmap in result["Maps"]:
            features = vmap.pop("Features", None)
            if features:
                for feature in features:
                    cats = feature.pop("Categories", None)
                    if cats:
                        for cat in cats:
                            tmp = feature.copy()
                            tmp.update(cat)
                            tmp2 = vmap.copy()
                            tmp2.update(tmp)
                            data.append(tmp2)
    else:
        for vmap in result["Maps"]:
            cats = vmap.pop("Categories", None)
            if cats:
                for cat in cats:
                    tmp = vmap.copy()
                    tmp.update(cat)
                    data.append(tmp)
            else:
                data.append(vmap)
    return data
Ejemplo n.º 11
0
def create_location(dbase,
                    location,
                    epsg=None,
                    proj4=None,
                    filename=None,
                    wkt=None,
                    datum=None,
                    datum_trans=None,
                    desc=None,
                    overwrite=False):
    """Create new location

    Raise ScriptError on error.

    :param str dbase: path to GRASS database
    :param str location: location name to create
    :param epsg: if given create new location based on EPSG code
    :param proj4: if given create new location based on Proj4 definition
    :param str filename: if given create new location based on georeferenced file
    :param str wkt: if given create new location based on WKT definition
                    (path to PRJ file)
    :param datum: GRASS format datum code
    :param datum_trans: datum transformation parameters (used for epsg and proj4)
    :param desc: description of the location (creates MYNAME file)
    :param bool overwrite: True to overwrite location if exists(WARNING:
                           ALL DATA from existing location ARE DELETED!)
    """
    gisdbase = None
    if epsg or proj4 or filename or wkt:
        # FIXME: changing GISDBASE mid-session is not background-job safe
        gisdbase = gisenv()['GISDBASE']
        run_command('g.gisenv', set='GISDBASE=%s' % dbase)
    # create dbase if not exists
    if not os.path.exists(dbase):
        os.mkdir(dbase)

    # check if location already exists
    if os.path.exists(os.path.join(dbase, location)):
        if not overwrite:
            warning(
                _("Location <%s> already exists. Operation canceled.") %
                location)
            return
        else:
            warning(
                _("Location <%s> already exists and will be overwritten") %
                location)
            shutil.rmtree(os.path.join(dbase, location))

    kwargs = dict()
    if datum:
        kwargs['datum'] = datum
    if datum_trans:
        kwargs['datum_trans'] = datum_trans

    if epsg:
        ps = pipe_command('g.proj',
                          quiet=True,
                          flags='t',
                          epsg=epsg,
                          location=location,
                          stderr=PIPE,
                          **kwargs)
    elif proj4:
        ps = pipe_command('g.proj',
                          quiet=True,
                          flags='t',
                          proj4=proj4,
                          location=location,
                          stderr=PIPE,
                          **kwargs)
    elif filename:
        ps = pipe_command('g.proj',
                          quiet=True,
                          georef=filename,
                          location=location,
                          stderr=PIPE)
    elif wkt:
        ps = pipe_command('g.proj',
                          quiet=True,
                          wkt=wkt,
                          location=location,
                          stderr=PIPE)
    else:
        _create_location_xy(dbase, location)

    if epsg or proj4 or filename or wkt:
        error = ps.communicate()[1]
        run_command('g.gisenv', set='GISDBASE=%s' % gisdbase)

        if ps.returncode != 0 and error:
            raise ScriptError(repr(error))

    try:
        fd = codecs.open(os.path.join(dbase, location, 'PERMANENT', 'MYNAME'),
                         encoding='utf-8',
                         mode='w')
        if desc:
            fd.write(desc + os.linesep)
        else:
            fd.write(os.linesep)
        fd.close()
    except OSError as e:
        raise ScriptError(repr(e))