21

I’m trying to inherit from an abstract .NET base class in Python (2.7) using Python.NET (2.1.0). I’m a Python n00b but from what I understood…

Here’s what I managed to do in Python only and which works fine:

import abc

class Door(object):
    __metaclass__ = abc.ABCMeta

    def open(self):
        if not self.is_open():
            self.toggle()

    def close(self):
        if self.is_open():
            self.toggle()

    @abc.abstractmethod
    def is_open(self):
        pass

    @abc.abstractmethod
    def toggle(self):
        pass

class StringDoor(Door):
    def __init__(self):
        self.status = "closed"

    def is_open(self):
        return self.status == "open"

    def toggle(self):
        if self.status == "open":
            self.status = "closed"
        else:
            self.status = "open"

class BooleanDoor(Door):
    def __init__(self):
        self.status = True

    def is_open(self):
        return self.status

    def toggle(self):
        self.status = not (self.status)

Door.register(StringDoor)
Door.register(BooleanDoor)

Now, all I did was to replace the abstract base class Door by a C# representation:

namespace PythonAbstractBaseClass
{
    public abstract class Door
    {
        public virtual void Open()
        {
            if (!IsOpen())
                Toggle();
        }

        public virtual void Close()
        {
            if (IsOpen())
                Toggle();
        }

        public abstract bool IsOpen();
        public abstract void Toggle();
    }
}

Removing Door from the Python part and importing it from the .NET assembly instead, I end up with this:

import clr
import abc
from PythonAbstractBaseClass import Door

class StringDoor(Door):
    def __init__(self):
        self.status = "closed"

    def is_open(self):
        return self.status == "open"

    def toggle(self):
        if self.status == "open":
            self.status = "closed"
        else:
            self.status = "open"

class BooleanDoor(Door):
    def __init__(self):
        self.status = True

    def is_open(self):
        return self.status

    def toggle(self):
        self.status = not (self.status)

Door.register(StringDoor)
Door.register(BooleanDoor)

But this fails with the following error message:

    Door.register(StringDoor)
AttributeError: type object 'Door' has no attribute 'register'

From what I understood about abc.ABCMeta, this metaclass contributes the register() method. It seems that abstract C# classes do not come with the same metaclass. They instead come with metaclass CLR Metatype which obviously does not provide register().

But if I drop the call to register(), on instantiating one of the derived classes, I receive the error message

    sdoor = StringDoor()
TypeError: cannot instantiate abstract class

Is there a way to inherit from an abstract .NET class or is this a missing feature?

Thanks in advance,

Henning

denfromufa
  • 5,610
  • 13
  • 81
  • 138
freefall
  • 388
  • 1
  • 14
  • @TomHunter here is the original discussion in the mailing list: https://mail.python.org/pipermail/pythondotnet/2016-September/001813.html – denfromufa Aug 13 '17 at 02:21
  • Hi @denfromufa, seems like you are saying that you cannot inherit from a .NET abstract class using Python and Python.Net.. please could you confirm? Thanks – Tom Hunter Aug 13 '17 at 19:30
  • @TomHunter I don't think this feature was implemented in pythonnet. Feel free to submit a feature request in issue tracker. – denfromufa Aug 13 '17 at 19:59

2 Answers2

7

You cannot create a new instance of an abstract class in C#. that said, Python will require you to use the register, as it will not allow you to use your inherited class without registering it, unless you instantiate it.

if you want to inherit from an C# abstract class in python, you will have to write on your own the representation of register class in python at your C# class, thus will register your abstract call and be able to inherit from it.

I would suggest this site to easily help you convert between the codes if need to:

https://www.varycode.com/converter.html

Barr J
  • 10,636
  • 1
  • 28
  • 46
6

I'm totally not familiar with pythonnet (or python in general for that matter), but I'm curious if something like this might work:

import clr
import abc
from PythonAbstractBaseClass import Door

class DoorWrapper(Door):
    __metaclass__ = abc.ABCMeta

class StringDoor(DoorWrapper):
  ...

class BooleanDoor(DoorWrapper):
  ...

DoorWrapper.register(StringDoor)
DoorWrapper.register(BooleanDoor)
martennis
  • 882
  • 11
  • 20