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

@ -268,7 +268,7 @@ EOD`
AC_MSG_RESULT([$pythonexists]) AC_MSG_RESULT([$pythonexists])
if test ! "x$pythonexists" = "xyes"; then if test ! "x$pythonexists" = "xyes"; then
AC_MSG_FAILURE([ AC_MSG_FAILURE([
Could not link test program to Python. Maybe the main Python library has been Could not link test program to Python. Maybe the main Python library has been
installed in some non-standard library path. If so, pass it to configure, installed in some non-standard library path. If so, pass it to configure,

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

@ -21,7 +21,7 @@
from CPUPolicy import CPUPolicy from CPUPolicy import CPUPolicy
class rr(CPUPolicy) : class rr(CPUPolicy):
"""Round Robin scheduling policy """Round Robin scheduling policy
This policy executes a thread for a given amount This policy executes a thread for a given amount

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);
@ -236,7 +262,7 @@ PythonCPUPolicy::wait_unlock() const throw(UserInterruptException, MalformedPoli
do do
{ {
Py_UNBLOCK_THREADS; Py_UNBLOCK_THREADS;
Glib::usleep(wait_for); // hack'a'ton! magggggiccc nummmbeeerrrrrs!! Glib::usleep(wait_for); // hack'a'ton! magggggiccc nummmbeeerrrrrs!!
Py_BLOCK_THREADS; Py_BLOCK_THREADS;
PyObject* retval = PyObject_CallMethod(_adapter, const_cast<char*>("mutex_test_lock"), NULL); PyObject* retval = PyObject_CallMethod(_adapter, const_cast<char*>("mutex_test_lock"), 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);
@ -292,10 +314,10 @@ PythonCPUPolicy::wait_unlock() const throw(UserInterruptException, MalformedPoli
syncronized variable... syncronized variable...
...if he has, break ...if he has, break
...else: ...else:
if the global lock is set: if the global lock is set:
stay in this loop stay in this loop
else: else:
all's went okay, can exit loop all's went okay, can exit loop
} */ } */
} }
@ -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));