diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a60a78e9..304ba49f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,6 +27,7 @@ Changed: - `AsyncioDispatcher cleanup tasks atexit <../../pull/138>`_ - `Ensure returned numpy arrays are not writeable <../../pull/164>`_ - `Ensure records do not get stuck in processing state <../../pull/175>`_ +- `Remove __super attribute <../../pull/187>`_ Fixed: diff --git a/softioc/device.py b/softioc/device.py index 332de014..e468d46b 100644 --- a/softioc/device.py +++ b/softioc/device.py @@ -57,7 +57,7 @@ class ProcessDeviceSupportCore(DeviceSupportCore, RecordLookup): def __init__(self, name, **kargs): autosave_fields = kargs.pop("autosave", None) autosave.add_pv_to_autosave(self, name, autosave_fields) - self.__super.__init__(name, **kargs) + super().__init__(name, **kargs) # Most subclasses (all except waveforms) define a ctypes constructor for the # underlying EPICS compatible value. @@ -127,7 +127,7 @@ def __init__(self, name, **kargs): # The tuple contains everything needed to be written: the value, # severity, alarm and optional timestamp. self._value = (value, alarm.NO_ALARM, alarm.UDF_ALARM, None) - self.__super.__init__(name, **kargs) + super().__init__(name, **kargs) def _process(self, record): # For input process we copy the value stored in the instance to the @@ -197,7 +197,7 @@ def __init__(self, name, **kargs): if self._blocking: self._callback = create_callback_capsule() - self.__super.__init__(name, **kargs) + super().__init__(name, **kargs) def init_record(self, record): '''Special record initialisation for out records only: implements @@ -385,7 +385,7 @@ def _process(self, record): # Because we're returning NO_CONVERT we need to do the .UDF updating # ourself (otherwise the record support layer does this). record.UDF = int(numpy.isnan(self._value[0])) - return self.__super._process(record) + return super()._process(record) class ao(ProcessDeviceSupportOut): _record_type_ = 'ao' @@ -439,11 +439,11 @@ class WaveformBase(ProcessDeviceSupportCore): def __init__(self, name, _wf_nelm, _wf_dtype, **kargs): self._dtype = _wf_dtype self._nelm = _wf_nelm - self.__super.__init__(name, **kargs) + super().__init__(name, **kargs) def init_record(self, record): self._dbf_type_ = record.FTVL - return self.__super.init_record(record) + return super().init_record(record) def _read_value(self, record): nord = record.NORD diff --git a/softioc/device_core.py b/softioc/device_core.py index da81c5d1..cfc5e8c3 100644 --- a/softioc/device_core.py +++ b/softioc/device_core.py @@ -1,46 +1,11 @@ from __future__ import print_function -import sys from . import imports from .fields import RecordFactory from ctypes import * -# Black magic lifted from six.py (http://pypi.python.org/pypi/six/) to replace -# use of __metaclass__ for metaclass definition -def with_metaclass(meta, *bases): - class metaclass(meta): - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - return type.__new__(metaclass, 'temporary_class', (), {}) - - -class InitClass(type): - def __new__(cls, name, bases, dict): - if '__init_class__' in dict: - dict['__init_class__'] = classmethod(dict['__init_class__']) - return type.__new__(cls, name, bases, dict) - - def __init__(cls, name, bases, dict): - type.__init__(cls, name, bases, dict) - # Binds self.__super.method to the appropriate superclass method - setattr(cls, '_%s__super' % name.lstrip('_'), super(cls)) - # Binds cls.__super_cls().method to the appropriate superclass - # class method. Unfortunately the .__super form doesn't work - # with class methods, only instance methods. - setattr( - cls, '_%s__super_cls' % name, - classmethod(lambda child: super(cls, child))) - # Finally call the class initialisatio nmethod. - cls.__init_class__() - -class DeviceCommon(with_metaclass(InitClass)): - '''Adds support for an __init_class__ method called when the class or any - of its subclasses is constructed. Also adds auto-super functionality - (see iocbuilder.support.autosuper).''' - - def __init_class__(cls): pass - +class DeviceCommon: # By requiring that DeviceCommon be a common base class for the entire # Python device hierarchy, we can use this __init__ to test for unused # keyword arguments. @@ -83,20 +48,16 @@ class DeviceSupportCore(DeviceCommon): # treatment) are then bound to the appropriate class instance and the # appropriate method is invoked. - def __init_class__(cls): + def __init_subclass__(cls): '''Record support initialisation, called once during class initialisation for each sub-class. This registers record support for the specified device name.''' + if not hasattr(cls, '_record_type_'): # If no record type has been specified then we're a base class # with nothing to do. return - # Create an empty device directory. - # (Potentially this belongs in a mix-in for resolving the linkage - # between record and instances, but for now this is hard-wired here.) - cls.__device_directory = {} - # Convert the list of fields into a dictionary suitable for record # lookup. fields = set([cls._link_] + cls.__preset_fields + cls._fields_) @@ -194,7 +155,7 @@ def __init__(self, name, **kargs): # a call to get_ioinit_info. This is only a trivial attempt to # reduce resource consumption. self.__ioscanpvt = imports.IOSCANPVT() - self.__super.__init__(name, **kargs) + super().__init__(name, **kargs) def init_record(self, record): @@ -245,7 +206,7 @@ def __init__(self, name, **kargs): 'Record %s already registered' % name self._name = name self._RecordDirectory[name] = self - self.__super.__init__(name, **kargs) + super().__init__(name, **kargs) LookupRecord = RecordLookup.LookupRecord