Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions python/grass/pygrass/messages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from __future__ import annotations

import os
import sys
from typing import TYPE_CHECKING, Literal, NoReturn

Expand All @@ -31,14 +32,16 @@
]


def message_server(lock: _LockLike, conn: Connection) -> NoReturn:
def message_server(lock: _LockLike, conn: Connection, env=None) -> NoReturn:
"""The GRASS message server function designed to be a target for
multiprocessing.Process


:param lock: A multiprocessing.Lock
:param conn: A multiprocessing.connection.Connection object obtained from
multiprocessing.Pipe
:param env: The environment of the server process, if None, the process
keeps the environment it inherited

This function will use the G_* message C-functions from grass.lib.gis
to provide an interface to the GRASS C-library messaging system.
Expand Down Expand Up @@ -69,6 +72,17 @@ def message_server(lock: _LockLike, conn: Connection) -> NoReturn:
- Percent: ["PERCENT", n, d, s]

"""
# The C library reads the session from the environment on first use,
# so the environment has to be replaced before that.
if env is not None:
os.environ.clear()
os.environ.update(env)
if "GISRC" in env:
# On Windows, the C library can have its own copy of the environment.
libgis.G_putenv("GISRC", env["GISRC"])
# With fork (e.g. Linux), the C library may hold the parent's session.
libgis.G__read_gisrc_path()
libgis.G__read_gisrc_env()
libgis.G_debug(1, "Start messenger server")

while True:
Expand Down Expand Up @@ -178,13 +192,20 @@ class Messenger:
server_conn: Connection
server: BaseProcess

def __init__(self, raise_on_error: bool = False) -> None:
def __init__(self, raise_on_error: bool = False, env=None) -> None:
"""
:param raise_on_error: If True, fatal() raises a FatalError exception
instead of calling sys.exit(1)
:param env: The environment of the server process, if None, the process
inherits os.environ
"""
self.raise_on_error = raise_on_error
self.env = None if env is None else dict(env)
ctx = _get_multiprocessing_context()
self.client_conn, self.server_conn = ctx.Pipe()
self.lock = ctx.Lock()
self.server = ctx.Process(
target=message_server, args=(self.lock, self.server_conn)
target=message_server, args=(self.lock, self.server_conn, self.env)
)
self.server.daemon = True
self.server.start()
Expand All @@ -195,7 +216,7 @@ def start_server(self) -> None:
self.client_conn, self.server_conn = ctx.Pipe()
self.lock = ctx.Lock()
self.server = ctx.Process(
target=message_server, args=(self.lock, self.server_conn)
target=message_server, args=(self.lock, self.server_conn, self.env)
)
self.server.daemon = True
self.server.start()
Expand Down
25 changes: 22 additions & 3 deletions python/grass/temporal/c_libraries_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import logging
import math
import os
import sys
from ctypes import CFUNCTYPE, POINTER, byref, c_int, c_void_p, cast
from datetime import datetime
Expand Down Expand Up @@ -1183,14 +1184,27 @@ def _stop(lock: _LockLike, conn: Connection, data) -> None:
###############################################################################


def c_library_server(lock: _LockLike, conn: Connection) -> None:
def c_library_server(lock: _LockLike, conn: Connection, env=None) -> None:
"""The GRASS C-libraries server function designed to be a target for
multiprocessing.Process

:param lock: A multiprocessing.Lock
:param conn: A multiprocessing.connection.Connection object obtained from
multiprocessing.Pipe
:param env: The environment of the server process, if None, the process
keeps the environment it inherited
"""
# The C libraries read the session from the environment on first use,
# so the environment has to be replaced before that.
if env is not None:
os.environ.clear()
os.environ.update(env)
if "GISRC" in env:
# On Windows, the C library can have its own copy of the environment.
libgis.G_putenv("GISRC", env["GISRC"])
# With fork (e.g. Linux), the C library may hold the parent's session.
libgis.G__read_gisrc_path()
libgis.G__read_gisrc_env()

def error_handler(data) -> None:
"""This function will be called in case of a fatal error in libgis"""
Expand Down Expand Up @@ -1462,15 +1476,20 @@ class CLibrariesInterface(RPCServerBase):

""" # noqa: E501

def __init__(self) -> None:
def __init__(self, env=None) -> None:
"""
:param env: The environment of the server process, if None, the process
inherits os.environ
"""
self.env = None if env is None else dict(env)
RPCServerBase.__init__(self)

def start_server(self) -> None:
ctx = _get_multiprocessing_context()
self.client_conn, self.server_conn = ctx.Pipe(True)
self.lock = ctx.Lock()
self.server = ctx.Process(
target=c_library_server, args=(self.lock, self.server_conn)
target=c_library_server, args=(self.lock, self.server_conn, self.env)
)
self.server.daemon = True
self.server.start()
Expand Down
Loading
Loading