Example #1
0
 def test_valid_mapset(self):
     """Test that different parameter combinations work and return true"""
     db_path = call_module("g.gisenv", get="GISDBASE").strip()
     loc_name = call_module("g.gisenv", get="LOCATION_NAME").strip()
     mapset_name = call_module("g.gisenv", get="MAPSET").strip()
     self.assertTrue(is_mapset_valid(db_path, loc_name, mapset_name))
     self.assertTrue(
         is_mapset_valid(os.path.join(db_path, loc_name, mapset_name)))
     self.assertTrue(is_mapset_valid(Path(db_path), loc_name, mapset_name))
     self.assertTrue(is_mapset_valid(
         Path(db_path) / loc_name / mapset_name))
Example #2
0
    def switch_mapset(self, path, location=None, mapset=None):
        """Switch to a mapset provided as a name or path.

        The mapset can be provided as a name, as a path,
        or as database, location, and mapset.
        Specifically, the *path* positional-only parameter can be either
        name of a mapset in the current location or a full path to a mapset.
        When location and mapset are provided using the additional parameters,
        the *path* parameter is path to a database.

        Raises ValueError if the mapset does not exist (e.g., when the name is
        misspelled or the mapset is invalid).
        """
        # The method could be a function, but this is more general (would work even for
        # a non-global session).
        # pylint: disable=no-self-use
        # Functions needed only here.
        # pylint: disable=import-outside-toplevel
        from grass.grassdb.checks import (
            get_mapset_invalid_reason,
            is_mapset_valid,
            mapset_exists,
        )
        from grass.grassdb.manage import resolve_mapset_path

        # For only one parameter, try if it is a mapset in the current location to
        # support switching only by its name.
        gisenv = gs.gisenv()
        if (
            not location
            and not mapset
            and mapset_exists(
                path=gisenv["GISDBASE"], location=gisenv["LOCATION_NAME"], mapset=path
            )
        ):
            gs.run_command("g.gisenv", set=f"MAPSET={path}")
            return

        mapset_path = resolve_mapset_path(path=path, location=location, mapset=mapset)
        if not is_mapset_valid(mapset_path):
            raise ValueError(
                _("Mapset {path} is not valid: {reason}").format(
                    path=mapset_path.path,
                    reason=get_mapset_invalid_reason(
                        mapset_path.directory, mapset_path.location, mapset_path.mapset
                    ),
                )
            )
        # This requires direct session file modification using g.gisenv because
        # g.mapset locks the mapset which is not how init and finish behave.
        # For code simplicity, we just change all even when only mapset is changed.
        gs.run_command("g.gisenv", set=f"GISDBASE={mapset_path.directory}")
        gs.run_command("g.gisenv", set=f"LOCATION_NAME={mapset_path.location}")
        gs.run_command("g.gisenv", set=f"MAPSET={mapset_path.mapset}")
Example #3
0
def init(path, location=None, mapset=None, grass_path=None):
    """Initialize system variables to run GRASS modules

    This function is for running GRASS GIS without starting it with the
    standard main executable grass. No GRASS modules shall be called before
    call of this function but any module or user script can be called
    afterwards because a GRASS session has been set up. GRASS Python
    libraries are usable as well in general but the ones using C
    libraries through ``ctypes`` are not (which is caused by library
    path not being updated for the current process which is a common
    operating system limitation).

    When the path or specified mapset does not exist, ValueError is raised.

    The :func:`get_install_path` function is used to determine where
    the rest of GRASS files is installed. The *grass_path* parameter is
    passed to it if provided. If the path cannot be determined,
    ValueError is raised. Exceptions from the underlying function are propagated.

    To create a GRASS session a session file (aka gisrc file) is created.
    Caller is responsible for deleting the file which is normally done
    with the function :func:`finish`.

    Basic usage::

        # ... setup GISBASE and sys.path before import
        import grass.script as gs
        gs.setup.init(
            "~/grassdata/nc_spm_08/user1",
            grass_path="/usr/lib/grass",
        )
        # ... use GRASS modules here
        # end the session
        gs.setup.finish()

    :param path: path to GRASS database
    :param location: location name
    :param mapset: mapset within given location (default: 'PERMANENT')
    :param grass_path: path to GRASS installation or executable

    :returns: path to ``gisrc`` file (may change in future versions)
    """
    grass_path = get_install_path(grass_path)
    if not grass_path:
        raise ValueError(
            _("Parameter grass_path or GISBASE environmental variable must be set")
        )
    # We reduce the top-level imports because this is initialization code.
    # pylint: disable=import-outside-toplevel
    from grass.grassdb.checks import get_mapset_invalid_reason, is_mapset_valid
    from grass.grassdb.manage import resolve_mapset_path

    # Support ~ in the path for user home directory.
    path = Path(path).expanduser()
    # A simple existence test. The directory, whatever it is, should exist.
    if not path.exists():
        raise ValueError(_("Path '{path}' does not exist").format(path=path))
    # A specific message when it exists, but it is a file.
    if path.is_file():
        raise ValueError(
            _("Path '{path}' is a file, but a directory is needed").format(path=path)
        )
    mapset_path = resolve_mapset_path(path=path, location=location, mapset=mapset)
    if not is_mapset_valid(mapset_path):
        raise ValueError(
            _("Mapset {path} is not valid: {reason}").format(
                path=mapset_path.path,
                reason=get_mapset_invalid_reason(
                    mapset_path.directory, mapset_path.location, mapset_path.mapset
                ),
            )
        )

    setup_runtime_env(grass_path)

    # TODO: lock the mapset?
    os.environ["GIS_LOCK"] = str(os.getpid())

    os.environ["GISRC"] = write_gisrc(
        mapset_path.directory, mapset_path.location, mapset_path.mapset
    )
    return os.environ["GISRC"]
Example #4
0
def resolve_mapset_path(path, location=None, mapset=None):
    """Resolve full path to mapset from given combination of parameters.

    Full or relative path to mapset can be provided as *path*. If the *path*
    points to a valid location instead of a valid mapset, the mapset defaults
    to PERMANENT.

    Alternatively, location and mapset can be provided separately. In that case,
    location and mapset are added to the path. If location is provided and mapset
    is not, mapset defaults to PERMANENT.

    Home represented by ``~`` (tilde) and relative paths are resolved
    and the result contains absolute paths.

    The function does not enforce the existence of the directory or that it
    is a mapset. It only manipulates the paths except for internal checks
    which help to determine the result in some cases. On Windows, if the path
    does not exist and ``..`` is present in the path, it will be not be resolved
    due to path resolution limitation in the Python pathlib package.

    Returns a MapsetPath object.
    """
    # We reduce the top-level imports because this is initialization code.
    # pylint: disable=import-outside-toplevel

    path = Path(path).expanduser()
    if not sys.platform.startswith("win") or path.exists():
        # The resolve function works just fine on Windows when the path exists
        # and everywhere even if it does not.
        # This also resolves symlinks which may or may not be desired.
        path = path.resolve()
    else:
        # On Windows when the path does not exist, resolve does not work.
        # This does not resolve `..` which is not desired.
        path = Path.cwd() / path
    default_mapset = grass.grassdb.config.permanent_mapset
    if location and mapset:
        directory = str(path)
        path = path / location / mapset
    elif location:
        mapset = default_mapset
        directory = str(path)
        path = path / location / mapset
    elif mapset:
        # mapset, but not location
        raise ValueError(
            _("Provide only path, or path and location, "
              "or path, location, and mapset, but not mapset without location")
        )
    else:
        from grass.grassdb.checks import is_mapset_valid

        if not is_mapset_valid(path) and is_mapset_valid(
                path / default_mapset):
            path = path / default_mapset
        parts = path.parts
        if len(parts) < 3:
            raise ValueError(
                _("Parameter path needs to be 'path/to/location/mapset' "
                  "or location and mapset need to be set"))
        directory, location, mapset = split_mapset_path(path)
    return MapsetPath(path=path,
                      directory=directory,
                      location=location,
                      mapset=mapset)