[GRASS-SVN] r58201 - in grass/trunk/lib/python/pygrass: . messages
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Nov 12 06:01:05 PST 2013
Author: huhabla
Date: 2013-11-12 06:00:53 -0800 (Tue, 12 Nov 2013)
New Revision: 58201
Added:
grass/trunk/lib/python/pygrass/messages/
grass/trunk/lib/python/pygrass/messages/Makefile
grass/trunk/lib/python/pygrass/messages/__init__.py
Modified:
grass/trunk/lib/python/pygrass/Makefile
grass/trunk/lib/python/pygrass/__init__.py
Log:
Fast and exit-safe interface to GRASS C-library message functions
Modified: grass/trunk/lib/python/pygrass/Makefile
===================================================================
--- grass/trunk/lib/python/pygrass/Makefile 2013-11-12 13:49:10 UTC (rev 58200)
+++ grass/trunk/lib/python/pygrass/Makefile 2013-11-12 14:00:53 UTC (rev 58201)
@@ -10,12 +10,13 @@
MODULES = errors functions orderdict
-CLEAN_SUBDIRS = modules raster vector gis shell tests
+CLEAN_SUBDIRS = messages modules raster vector gis shell tests
PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
+ -$(MAKE) -C messages || echo $(CURDIR)/messages >> $(ERRORLOG)
-$(MAKE) -C modules || echo $(CURDIR)/modules >> $(ERRORLOG)
-$(MAKE) -C raster || echo $(CURDIR)/raster >> $(ERRORLOG)
-$(MAKE) -C vector || echo $(CURDIR)/vector >> $(ERRORLOG)
Modified: grass/trunk/lib/python/pygrass/__init__.py
===================================================================
--- grass/trunk/lib/python/pygrass/__init__.py 2013-11-12 13:49:10 UTC (rev 58200)
+++ grass/trunk/lib/python/pygrass/__init__.py 2013-11-12 14:00:53 UTC (rev 58201)
@@ -16,3 +16,4 @@
import vector
import modules
import shell
+import messages
Added: grass/trunk/lib/python/pygrass/messages/Makefile
===================================================================
--- grass/trunk/lib/python/pygrass/messages/Makefile (rev 0)
+++ grass/trunk/lib/python/pygrass/messages/Makefile 2013-11-12 14:00:53 UTC (rev 58201)
@@ -0,0 +1,32 @@
+MODULE_TOPDIR = ../../../..
+
+include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+include $(MODULE_TOPDIR)/include/Make/Doxygen.make
+
+PYDIR = $(ETC)/python
+GDIR = $(PYDIR)/grass
+PGDIR = $(GDIR)/pygrass
+DSTDIR= $(PGDIR)/messages
+
+MODULES =
+
+PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
+PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
+
+default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
+
+$(PYDIR):
+ $(MKDIR) $@
+
+$(GDIR): | $(PYDIR)
+ $(MKDIR) $@
+
+$(DSTDIR): | $(GDIR)
+ $(MKDIR) $@
+
+$(DSTDIR)/%: % | $(DSTDIR)
+ $(INSTALL_DATA) $< $@
+
+#doxygen:
+DOXNAME = pythonpygrass
Added: grass/trunk/lib/python/pygrass/messages/__init__.py
===================================================================
--- grass/trunk/lib/python/pygrass/messages/__init__.py (rev 0)
+++ grass/trunk/lib/python/pygrass/messages/__init__.py 2013-11-12 14:00:53 UTC (rev 58201)
@@ -0,0 +1,238 @@
+# -*- coding: utf-8 -*-
+"""!@package grass.pygrass.massages
+
+ at brief PyGRASS message interface
+
+Fast and exit-safe interface to GRASS C-library message functions
+
+
+(C) 2013 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Soeren Gebbert
+"""
+
+import grass.lib.gis as libgis
+from multiprocessing import Process, Lock, Pipe
+
+def message_server(lock, conn):
+ """!The GRASS message server function designed to be a target for
+ multiprocessing.Process
+
+ @param lock A multiprocessing.Lock
+ @param conn A multiprocessing.Pipe
+
+ This function will use the G_* message C-functions from grass.lib.gis
+ to provide an interface to the GRASS C-library messaging system.
+
+ The data that is send through the pipe must provide an
+ identifier string to specify which C-function should be called.
+
+ The following identifers are supported:
+
+ - "INFO" Prints an info message, see G_message() for details
+ - "IMPORTANT" Prints an important info message,
+ see G_important_message() for details
+ - "VERBOSE" Prints a verbose message if the verbosity level is
+ set accordingly, see G_verbose_message() for details
+ - "WARNING" Prints a warning message, see G_warning() for details
+ - "ERROR" Prints a message with a leading "ERROR: " string,
+ see G_important_message() for details
+ - "PERCENT" Prints a percent value based on three integer values: n, d and s
+ see G_percent() for details
+ - "STOP" Stops the server function and closes the pipe
+ - "FATAL" Calls G_fatal_error(), this functions is only for
+ testing purpose
+
+ The that is end through the pipe must be a list of values:
+ - Messages: ["INFO|VERBOSE|WARNING|ERROR|FATAL", "MESSAGE"]
+ - Debug: ["DEBUG", level, "MESSAGE"]
+ - Percent: ["PERCENT", n, d, s]
+ """
+ while True:
+ # Avoid busy waiting
+ conn.poll(None)
+ data = conn.recv()
+ message_type = data[0]
+
+ # Only one process is allowed to write to stdout
+ lock.acquire()
+
+ # Stop the pipe and the infinite loop
+ if message_type == "STOP":
+ conn.close()
+ lock.release()
+ return
+
+ message = data[1]
+
+ if message_type == "PERCENT":
+ n = int(data[1])
+ d = int(data[2])
+ s = int(data[3])
+ libgis.G_percent(n, d, s)
+ elif message_type == "DEBUG":
+ level = data[1]
+ message = data[2]
+ libgis.G_debug(level, message)
+ elif message_type == "VERBOSE":
+ libgis.G_verbose_message(message)
+ elif message_type == "INFO":
+ libgis.G_message(message)
+ elif message_type == "IMPORTANT":
+ libgis.G_important_message(message)
+ elif message_type == "WARNING":
+ libgis.G_warning(message)
+ elif message_type == "ERROR":
+ libgis.G_important_message("ERROR: %s"%message)
+ # This is for testing only
+ elif message_type == "FATAL":
+ libgis.G_fatal_error(message)
+
+ lock.release()
+
+class Messenger(object):
+ """!Fast and exit-safe interface to GRASS C-library message functions
+
+ This class implements a fast and exit-safe interface to the GRASS
+ C-library message functions like: G_message(), G_warning(),
+ G_important_message(), G_verbose_message(), G_percent() and G_debug().
+
+ Note:
+
+ The C-library message functions a called via ctypes in a subprocess
+ using a pipe (multiprocessing.Pipe) to transfer the text messages.
+ Hence, the process that uses the Messenger interface will not be
+ exited, if a G_fatal_error() was invoked in the subprocess.
+ In this case the Messenger object will simply start a new subprocess
+ and restarts the pipeline.
+
+
+ Usage:
+
+ @code
+ >>> msgr = Messenger()
+ >>> msgr.debug(0, "debug 0")
+ >>> msgr.verbose("verbose message")
+ >>> msgr.message("message")
+ >>> msgr.important("important message")
+ >>> msgr.percent(1, 1, 1)
+ >>> msgr.warning("Ohh")
+ >>> msgr.error("Ohh no")
+
+ D0/0: debug 0
+ message
+ important message
+ 100%
+ WARNING: Ohh
+ ERROR: Ohh no
+
+ @endcode
+ """
+ def __init__(self):
+ self.client_conn = None
+ self.server_conn = None
+ self.server = None
+ self.start_server()
+
+ def __del__(self):
+ self.stop()
+
+ def start_server(self):
+ self.client_conn, self.server_conn = Pipe()
+ self.lock = Lock()
+ self.server = Process(target=message_server, args=(self.lock,
+ self.server_conn))
+ self.server.daemon = True
+ self.server.start()
+
+ def _check_restart_server(self):
+ """!Restart the server if it was terminated
+ """
+ if self.server.is_alive() is True:
+ return
+ self.client_conn.close()
+ self.server_conn.close()
+ self.start_server()
+ self.warning("Needed to restart the messenger server")
+
+ def message(self, message):
+ """!Send a message to stdout
+
+ G_message() will be called in the messenger server process
+ """
+ self._check_restart_server()
+ self.client_conn.send(["INFO", message])
+
+ def verbose(self, message):
+ """!Send a verbose message to stdout
+
+ G_verbose_message() will be called in the messenger server process
+ """
+ self._check_restart_server()
+ self.client_conn.send(["VERBOSE", message])
+
+ def important(self, message):
+ """!Send an important message to stdout
+
+ G_important_message() will be called in the messenger server process
+ """
+ self._check_restart_server()
+ self.client_conn.send(["IMPORTANT", message])
+
+ def warning(self, message):
+ """!Send a warning message to stdout
+
+ G_warning() will be called in the messenger server process
+ """
+ self._check_restart_server()
+ self.client_conn.send(["WARNING", message])
+
+ def error(self, message):
+ """!Send an error message to stdout
+
+ G_important_message() with an additional "ERROR:" string at
+ the start will be called in the messenger server process
+ """
+ self._check_restart_server()
+ self.client_conn.send(["ERROR", message])
+
+ def debug(self, level, message):
+ """!Send a debug message to stdout
+
+ G_debug() will be called in the messenger server process
+ """
+ self._check_restart_server()
+ self.client_conn.send(["DEBUG", level, message])
+
+ def percent(self, n, d, s):
+ """!Send a percentage to stdout
+
+ G_percent() will be called in the messenger server process
+ """
+ self._check_restart_server()
+ self.client_conn.send(["PERCENT", n, d, s])
+
+ def stop(self):
+ """!Stop the messenger server and close the pipe
+ """
+ if self.server is not None and self.server.is_alive():
+ self.client_conn.send(["STOP",])
+ self.server.join(5)
+ self.server.terminate()
+ if self.client_conn is not None:
+ self.client_conn.close()
+
+ def test_fatal_error(self, message):
+ """!Force the messenger server to call G_fatal_error()
+ """
+ import time
+ self._check_restart_server()
+ self.client_conn.send(["FATAL", message])
+ time.sleep(1)
+
+if __name__ == "__main__":
+ import doctest
+ doctest.testmod()
More information about the grass-commit
mailing list