From cd10080cca3a99bff564865db02700c9837f13be Mon Sep 17 00:00:00 2001 From: tchernobog Date: Thu, 28 May 2009 19:58:32 +0000 Subject: [PATCH] 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 --- plugins/pyloader/Makefile.am | 1 - plugins/pyloader/configure.ac | 2 +- plugins/pyloader/m4/ac_python_devel.m4 | 2 +- plugins/pyloader/src/Abstract.py | 96 ------------------- plugins/pyloader/src/CPUPolicy.py | 49 ++++++---- plugins/pyloader/src/builtin-policies/rr.py | 2 +- plugins/pyloader/src/python_cpu_policy.cc | 59 ++++++++---- .../pyloader/src/python_cpu_policy_manager.cc | 4 +- 8 files changed, 77 insertions(+), 138 deletions(-) delete mode 100644 plugins/pyloader/src/Abstract.py diff --git a/plugins/pyloader/Makefile.am b/plugins/pyloader/Makefile.am index d09bf04..ad0116f 100644 --- a/plugins/pyloader/Makefile.am +++ b/plugins/pyloader/Makefile.am @@ -95,7 +95,6 @@ noinst_HEADERS += \ src/python_cpu_policy_manager.hh share_PYTHON = \ - src/Abstract.py \ src/CPUPolicy.py \ src/ScriptAdapter.py diff --git a/plugins/pyloader/configure.ac b/plugins/pyloader/configure.ac index 10c60d3..a515a57 100644 --- a/plugins/pyloader/configure.ac +++ b/plugins/pyloader/configure.ac @@ -52,7 +52,7 @@ AM_GNU_GETTEXT_VERSION([0.17]) dnl PYTHON_VERSION is declared precious by AC_PYTHON_DEVEL, dnl so don't use it here -PY_VERSION=2.3 +PY_VERSION=2.6 GTKMM_VERSION=2.8.0 SGPEMV2_VERSION=1.0 diff --git a/plugins/pyloader/m4/ac_python_devel.m4 b/plugins/pyloader/m4/ac_python_devel.m4 index bc3dd77..682aad5 100644 --- a/plugins/pyloader/m4/ac_python_devel.m4 +++ b/plugins/pyloader/m4/ac_python_devel.m4 @@ -268,7 +268,7 @@ EOD` AC_MSG_RESULT([$pythonexists]) - if test ! "x$pythonexists" = "xyes"; then + if test ! "x$pythonexists" = "xyes"; then AC_MSG_FAILURE([ 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, diff --git a/plugins/pyloader/src/Abstract.py b/plugins/pyloader/src/Abstract.py deleted file mode 100644 index 2356e23..0000000 --- a/plugins/pyloader/src/Abstract.py +++ /dev/null @@ -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) diff --git a/plugins/pyloader/src/CPUPolicy.py b/plugins/pyloader/src/CPUPolicy.py index ce37660..848b071 100644 --- a/plugins/pyloader/src/CPUPolicy.py +++ b/plugins/pyloader/src/CPUPolicy.py @@ -1,17 +1,11 @@ -from Abstract import * +from abc import * import sgpem -## @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. -class CPUPolicy: - ## @var Avoid instantiation of an abstract class. - # @see Abstract.Metaclass - __metaclass__ = Metaclass - +## @brief The abstract base class needed for compatibility between +# Python 2.6 and Python 3.x. +# +# @see CPUPolicy +class CPUPolicyBase(object): ## @brief Configure policy to initial values # # This is called just before a simulation starts, and is responsible @@ -26,7 +20,9 @@ class CPUPolicy: # @endcode # # @see sgpem::Policy::get_parameters() - configure = AbstractMethod('configure') + @abstractmethod + def configure(self): + pass ## @brief Sort ready processes queue # @@ -46,7 +42,9 @@ class CPUPolicy: # swap(positionA, positionB) and size(). # # @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, # other than by normal time slice termination @@ -70,7 +68,9 @@ class CPUPolicy: # slice (or a process blocking/termination, of course) before # selecting a new running process, even if it has greater priority # 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 # @@ -90,7 +90,9 @@ class CPUPolicy: # # @return -1 If the policy doesn't want to use time slices # @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 # Policy::Policy::configure() @@ -178,3 +180,18 @@ class CPUPolicy: # puts pivot in place queue.swap(i,b) 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)) diff --git a/plugins/pyloader/src/builtin-policies/rr.py b/plugins/pyloader/src/builtin-policies/rr.py index 1beef3e..a5626a0 100644 --- a/plugins/pyloader/src/builtin-policies/rr.py +++ b/plugins/pyloader/src/builtin-policies/rr.py @@ -21,7 +21,7 @@ from CPUPolicy import CPUPolicy -class rr(CPUPolicy) : +class rr(CPUPolicy): """Round Robin scheduling policy This policy executes a thread for a given amount diff --git a/plugins/pyloader/src/python_cpu_policy.cc b/plugins/pyloader/src/python_cpu_policy.cc index 50acb0b..a1fdbca 100644 --- a/plugins/pyloader/src/python_cpu_policy.cc +++ b/plugins/pyloader/src/python_cpu_policy.cc @@ -34,13 +34,39 @@ using namespace std; 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 // *strong* exception checking / handling! PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyException) : _upolicy_dict(NULL), _adapter(NULL), _name(name), _description() { - PyObject* pLoadmeStr = PyString_FromString(name); + PyObject* pLoadmeStr = PyUnicode_FromString (name); PyObject* pUserCPUPolicyModule = PyImport_Import(pLoadmeStr); Py_DECREF(pLoadmeStr); @@ -52,7 +78,7 @@ PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyExceptio assert(_upolicy_dict); // Loads ScriptAdapter module and get its dictionary - pLoadmeStr = PyString_FromString("ScriptAdapter"); + pLoadmeStr = PyUnicode_FromString("ScriptAdapter"); PyObject* pScriptAdapterModule = PyImport_Import(pLoadmeStr); Py_DECREF(pLoadmeStr); assert(pScriptAdapterModule); @@ -68,7 +94,7 @@ PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyExceptio // Retrieve a description for the policy using the __doc__ attribute PyObject* pDescriptionString = PyObject_GetAttrString(pCPUPolicyClass, "__doc__"); if(pDescriptionString != Py_None) - _description = PyString_AsString(pDescriptionString); + _description = sgpem::PyString_AsString(pDescriptionString); Py_DECREF(pDescriptionString); // Creates a new object of type ScriptAdapter : @@ -77,7 +103,7 @@ PythonCPUPolicy::PythonCPUPolicy(const char* name) throw(MalformedPolicyExceptio PyObject* pAdapterCtorParam = PyTuple_New(1); Py_INCREF(pCPUPolicyClass); // PyTuple_SetItem steals a reference PyTuple_SetItem(pAdapterCtorParam, 0, pCPUPolicyClass); - _adapter = PyInstance_New(pAdapterClass, pAdapterCtorParam, NULL); + _adapter = PyObject_CallObject((PyObject*) pAdapterClass, pAdapterCtorParam); Py_DECREF(pAdapterCtorParam); Py_DECREF(pScriptAdapterModule); @@ -214,7 +240,7 @@ PythonCPUPolicy::get_time_slice() const throw(UserInterruptException, MalformedP // Parse return value stored in global Python object retval = PyObject_CallMethod(_adapter, const_cast("get_return_value"), NULL); assert(retval); - long tmp = PyInt_AsLong(retval); + long tmp = PyLong_AsLong(retval); Py_DECREF(retval); set_callback_policy(NULL); @@ -236,7 +262,7 @@ PythonCPUPolicy::wait_unlock() const throw(UserInterruptException, MalformedPoli do { Py_UNBLOCK_THREADS; - Glib::usleep(wait_for); // hack'a'ton! magggggiccc nummmbeeerrrrrs!! + Glib::usleep(wait_for); // hack'a'ton! magggggiccc nummmbeeerrrrrs!! Py_BLOCK_THREADS; PyObject* retval = PyObject_CallMethod(_adapter, const_cast("mutex_test_lock"), NULL); @@ -269,12 +295,8 @@ PythonCPUPolicy::wait_unlock() const throw(UserInterruptException, MalformedPoli { if(pException != Py_None) { - PyObject* pExceptStr = PyObject_Str(pException); - string msg = _("unhandled exception in user policy: "); - msg += PyString_AsString(pExceptStr); - - Py_DECREF(pExceptStr); + msg += sgpem::PyString_AsString(pException); Py_DECREF(pException); throw MalformedPolicyException(msg); @@ -292,10 +314,10 @@ PythonCPUPolicy::wait_unlock() const throw(UserInterruptException, MalformedPoli syncronized variable... ...if he has, break ...else: - if the global lock is set: - stay in this loop - else: - all's went okay, can exit loop + if the global lock is set: + stay in this loop + else: + all's went okay, can exit loop } */ } @@ -316,11 +338,8 @@ PythonCPUPolicy::get_exception_information() if (pValue != NULL) { - PyObject* pValueStr = PyObject_Str(pValue); - - msg = PyString_AsString(pValueStr); - - Py_DECREF(pValueStr); + msg = sgpem::PyString_AsString(pValue) + "\n"; + PyErr_PrintEx (false); } else msg = string(_("no available information for this error")); diff --git a/plugins/pyloader/src/python_cpu_policy_manager.cc b/plugins/pyloader/src/python_cpu_policy_manager.cc index bd3f343..c548394 100644 --- a/plugins/pyloader/src/python_cpu_policy_manager.cc +++ b/plugins/pyloader/src/python_cpu_policy_manager.cc @@ -70,8 +70,8 @@ PythonCPUPolicyManager::PythonCPUPolicyManager() // environment variables. 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(), prefs.get_policy_dirs().end(), pol_dirs_concat(importdirs));