Port everything to work with Python 2.6 and (hopefully) 3.0.

Phew, this was harder than I expected, mostly because I 
noticed I never grokked metaclasses all that well. Now it's 
slightly better ;-).



git-svn-id: svn://svn.gna.org/svn/sgpemv2/trunk@1344 3ecf2c5c-341e-0410-92b4-d18e462d057c
This commit is contained in:
tchernobog 2009-05-28 19:58:32 +00:00
parent 59ebcace2a
commit cd10080cca
8 changed files with 77 additions and 138 deletions

View File

@ -95,7 +95,6 @@ noinst_HEADERS += \
src/python_cpu_policy_manager.hh src/python_cpu_policy_manager.hh
share_PYTHON = \ share_PYTHON = \
src/Abstract.py \
src/CPUPolicy.py \ src/CPUPolicy.py \
src/ScriptAdapter.py src/ScriptAdapter.py

View File

@ -52,7 +52,7 @@ AM_GNU_GETTEXT_VERSION([0.17])
dnl PYTHON_VERSION is declared precious by AC_PYTHON_DEVEL, dnl PYTHON_VERSION is declared precious by AC_PYTHON_DEVEL,
dnl so don't use it here dnl so don't use it here
PY_VERSION=2.3 PY_VERSION=2.6
GTKMM_VERSION=2.8.0 GTKMM_VERSION=2.8.0
SGPEMV2_VERSION=1.0 SGPEMV2_VERSION=1.0

View File

@ -1,96 +0,0 @@
## @brief Defines a class to create abstract methods
#
# @author Ivo Timmermans
# @date 2004/01/23
# @version 1.1
#
# Example:
# @code
# import Abstract;
# class Foo:
# __metaclass__ = Abstract.Metaclass
# foo = Abstract.AbstractMethod('foo')
# @endcode
class AbstractMethod (object):
## @brief Constructor
#
# @param func name of the function (used when raising an
# exception). Its type is str.
def __init__(self, func):
self._function = func
## @brief Get callable object
#
# @return An instance of AbstractMethodHelper.
# This trickery is needed to get the name of the class for which
# an abstract method was requested, otherwise it would be
# sufficient to include a __call__ method in the AbstractMethod
# class itself.
def __get__(self, obj, type):
return self.AbstractMethodHelper(self._function, type)
## @brief Abstract method helper class
#
# An AbstractMethodHelper instance is a callable object that
# represents an abstract method.
class AbstractMethodHelper (object):
def __init__(self, func, cls):
self._function = func
self._class = cls
## @brief Call abstract method
#
# Raises a TypeError, because abstract methods can not be
# called.
def __call__(self, *args, **kwargs):
raise TypeError('Abstract method `' + self._class.__name__ \
+ '.' + self._function + '\' called')
## @brief Configure a new class to be abstract
#
# @author Ivo Timmermans
# @date 2004/01/23
# @version 1.1
class Metaclass (type):
## Configure a new class
#
# @param cls Class object
# @param name Name of the class
# @param bases All base classes for cls
def __init__(cls, name, bases, *args, **kwargs):
super(Metaclass, cls).__init__(cls, name, bases, *args, **kwargs)
# Detach cls.new() from class Metaclass, and make it a method
# of cls.
cls.__new__ = staticmethod(cls.new)
# Find all abstract methods, and assign the resulting list to
# cls.__abstractmethods__, so we can read that variable when a
# request for allocation (__new__) is done.
abstractmethods = []
ancestors = list(cls.__mro__)
ancestors.reverse() # Start with __builtin__.object
for ancestor in ancestors:
for clsname, clst in ancestor.__dict__.items():
if isinstance(clst, AbstractMethod):
abstractmethods.append(clsname)
else:
if clsname in abstractmethods:
abstractmethods.remove(clsname)
abstractmethods.sort()
setattr(cls, '__abstractmethods__', abstractmethods)
## @brief Allocator for class cls
#
# @param self Class object for which an instance should be
# created.
# @param cls Same as self.
def new(self, cls):
if len(cls.__abstractmethods__):
raise NotImplementedError('Can\'t instantiate class `' + \
cls.__name__ + '\';\n' + \
'Abstract methods: ' + \
", ".join(cls.__abstractmethods__))
return object.__new__(self)

View File

@ -1,17 +1,11 @@
from Abstract import * from abc import *
import sgpem import sgpem
## @brief This is the abstract class a user-defined policy ## @brief The abstract base class needed for compatibility between
# should inherit from # Python 2.6 and Python 3.x.
# #
# This class also exposes the method sort(), which can be # @see CPUPolicy
# used to easily sort the queue of ready process with a class CPUPolicyBase(object):
# user-defined given compare function.
class CPUPolicy:
## @var Avoid instantiation of an abstract class.
# @see Abstract.Metaclass
__metaclass__ = Metaclass
## @brief Configure policy to initial values ## @brief Configure policy to initial values
# #
# This is called just before a simulation starts, and is responsible # This is called just before a simulation starts, and is responsible
@ -26,7 +20,9 @@ class CPUPolicy:
# @endcode # @endcode
# #
# @see sgpem::Policy::get_parameters() # @see sgpem::Policy::get_parameters()
configure = AbstractMethod('configure') @abstractmethod
def configure(self):
pass
## @brief Sort ready processes queue ## @brief Sort ready processes queue
# #
@ -46,7 +42,9 @@ class CPUPolicy:
# swap(positionA, positionB) and size(). # swap(positionA, positionB) and size().
# #
# @see Policy::Policy::sort() # @see Policy::Policy::sort()
sort_queue = AbstractMethod('sort_queue') @abstractmethod
def sort_queue(self, queue):
pass
## @brief Returns whether the policy wants to be preemptive, ## @brief Returns whether the policy wants to be preemptive,
# other than by normal time slice termination # other than by normal time slice termination
@ -70,7 +68,9 @@ class CPUPolicy:
# slice (or a process blocking/termination, of course) before # slice (or a process blocking/termination, of course) before
# selecting a new running process, even if it has greater priority # selecting a new running process, even if it has greater priority
# than the current one # than the current one
is_preemptive = AbstractMethod('is_preemptive') @abstractmethod
def is_preemptive(self):
pass
## @brief Returns how long is a time-slice for this policy ## @brief Returns how long is a time-slice for this policy
# #
@ -90,7 +90,9 @@ class CPUPolicy:
# #
# @return -1 If the policy doesn't want to use time slices # @return -1 If the policy doesn't want to use time slices
# @return 0+ To specify a time slice duration for this policy # @return 0+ To specify a time slice duration for this policy
get_time_slice = AbstractMethod('get_time_slice') @abstractmethod
def get_time_slice(self):
pass
## @brief Returns the PolicyParameters instance you can use in ## @brief Returns the PolicyParameters instance you can use in
# Policy::Policy::configure() # Policy::Policy::configure()
@ -178,3 +180,18 @@ class CPUPolicy:
# puts pivot in place # puts pivot in place
queue.swap(i,b) queue.swap(i,b)
return i return i
## @brief This is the abstract class a user-defined policy
# should inherit from
#
# This class also exposes the method sort(), which can be
# used to easily sort the queue of ready process with a
# user-defined given compare function.
#
# @see CPUPolicyBase
CPUPolicy = ABCMeta('CPUPolicy', (CPUPolicyBase, ), {})
print (dir (CPUPolicy))

View File

@ -34,13 +34,39 @@ using namespace std;
Glib::StaticRecMutex PythonCPUPolicy::_mtx = GLIBMM_STATIC_REC_MUTEX_INIT; Glib::StaticRecMutex PythonCPUPolicy::_mtx = GLIBMM_STATIC_REC_MUTEX_INIT;
// Convenience porting function for converting from Python 3.0
// UCS-(2|4) strings to glib::ustring
namespace sgpem
{
static Glib::ustring
PyString_AsString (PyObject* obj)
{
using ::PyString_AsString;
Glib::ustring ret;
PyObject *str = PyObject_Str (obj);
if (PyUnicode_Check (str))
{
PyObject *ustr = PyUnicode_AsUTF8String (str);
ret = PyBytes_AsString (ustr);
Py_DECREF (ustr);
}
else
ret = PyString_AS_STRING (str);
Py_DECREF (str);
return ret;
}
}
// WARNING : this class needs extensive and above all // WARNING : this class needs extensive and above all
// *strong* exception checking / handling! // *strong* exception checking / handling!
PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyException) PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyException)
: _upolicy_dict(NULL), _adapter(NULL), _name(name), _description() : _upolicy_dict(NULL), _adapter(NULL), _name(name), _description()
{ {
PyObject* pLoadmeStr = PyString_FromString(name); PyObject* pLoadmeStr = PyUnicode_FromString (name);
PyObject* pUserCPUPolicyModule = PyImport_Import(pLoadmeStr); PyObject* pUserCPUPolicyModule = PyImport_Import(pLoadmeStr);
Py_DECREF(pLoadmeStr); Py_DECREF(pLoadmeStr);
@ -52,7 +78,7 @@ PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyExceptio
assert(_upolicy_dict); assert(_upolicy_dict);
// Loads ScriptAdapter module and get its dictionary // Loads ScriptAdapter module and get its dictionary
pLoadmeStr = PyString_FromString("ScriptAdapter"); pLoadmeStr = PyUnicode_FromString("ScriptAdapter");
PyObject* pScriptAdapterModule = PyImport_Import(pLoadmeStr); PyObject* pScriptAdapterModule = PyImport_Import(pLoadmeStr);
Py_DECREF(pLoadmeStr); Py_DECREF(pLoadmeStr);
assert(pScriptAdapterModule); assert(pScriptAdapterModule);
@ -68,7 +94,7 @@ PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyExceptio
// Retrieve a description for the policy using the __doc__ attribute // Retrieve a description for the policy using the __doc__ attribute
PyObject* pDescriptionString = PyObject_GetAttrString(pCPUPolicyClass, "__doc__"); PyObject* pDescriptionString = PyObject_GetAttrString(pCPUPolicyClass, "__doc__");
if(pDescriptionString != Py_None) if(pDescriptionString != Py_None)
_description = PyString_AsString(pDescriptionString); _description = sgpem::PyString_AsString(pDescriptionString);
Py_DECREF(pDescriptionString); Py_DECREF(pDescriptionString);
// Creates a new object of type ScriptAdapter : // Creates a new object of type ScriptAdapter :
@ -77,7 +103,7 @@ PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyExceptio
PyObject* pAdapterCtorParam = PyTuple_New(1); PyObject* pAdapterCtorParam = PyTuple_New(1);
Py_INCREF(pCPUPolicyClass); // PyTuple_SetItem steals a reference Py_INCREF(pCPUPolicyClass); // PyTuple_SetItem steals a reference
PyTuple_SetItem(pAdapterCtorParam, 0, pCPUPolicyClass); PyTuple_SetItem(pAdapterCtorParam, 0, pCPUPolicyClass);
_adapter = PyInstance_New(pAdapterClass, pAdapterCtorParam, NULL); _adapter = PyObject_CallObject((PyObject*) pAdapterClass, pAdapterCtorParam);
Py_DECREF(pAdapterCtorParam); Py_DECREF(pAdapterCtorParam);
Py_DECREF(pScriptAdapterModule); Py_DECREF(pScriptAdapterModule);
@ -214,7 +240,7 @@ PythonCPUPolicy::get_time_slice() const throw(UserInterruptException, MalformedP
// Parse return value stored in global Python object // Parse return value stored in global Python object
retval = PyObject_CallMethod(_adapter, const_cast<char*>("get_return_value"), NULL); retval = PyObject_CallMethod(_adapter, const_cast<char*>("get_return_value"), NULL);
assert(retval); assert(retval);
long tmp = PyInt_AsLong(retval); long tmp = PyLong_AsLong(retval);
Py_DECREF(retval); Py_DECREF(retval);
set_callback_policy(NULL); set_callback_policy(NULL);
@ -269,12 +295,8 @@ PythonCPUPolicy::wait_unlock() const throw(UserInterruptException, MalformedPoli
{ {
if(pException != Py_None) if(pException != Py_None)
{ {
PyObject* pExceptStr = PyObject_Str(pException);
string msg = _("unhandled exception in user policy: "); string msg = _("unhandled exception in user policy: ");
msg += PyString_AsString(pExceptStr); msg += sgpem::PyString_AsString(pException);
Py_DECREF(pExceptStr);
Py_DECREF(pException); Py_DECREF(pException);
throw MalformedPolicyException(msg); throw MalformedPolicyException(msg);
@ -316,11 +338,8 @@ PythonCPUPolicy::get_exception_information()
if (pValue != NULL) if (pValue != NULL)
{ {
PyObject* pValueStr = PyObject_Str(pValue); msg = sgpem::PyString_AsString(pValue) + "\n";
PyErr_PrintEx (false);
msg = PyString_AsString(pValueStr);
Py_DECREF(pValueStr);
} }
else else
msg = string(_("no available information for this error")); msg = string(_("no available information for this error"));

View File

@ -70,8 +70,8 @@ PythonCPUPolicyManager::PythonCPUPolicyManager()
// environment variables. // environment variables.
GlobalPreferences& prefs = GlobalPreferences::get_instance(); GlobalPreferences& prefs = GlobalPreferences::get_instance();
Glib::ustring importdirs = "import sys\n"
"sys.path[:0] = [ "; Glib::ustring importdirs = "import sys; sys.path[:0] = [ ";
for_each(prefs.get_policy_dirs().begin(), for_each(prefs.get_policy_dirs().begin(),
prefs.get_policy_dirs().end(), prefs.get_policy_dirs().end(),
pol_dirs_concat(importdirs)); pol_dirs_concat(importdirs));