[Python.NET] Inheriting from abstract .NET class

Henning Moeller HMoeller at comprion.com
Tue Sep 27 03:49:02 EDT 2016


Hi Denis,

thank you again. That helped a lot.

But – I’m sorry to bother you again. In the classes I really have to use, some of the virtual methods are protected. Those are not resolved by pythonnet. Only public virtual is recognized and overridden by the inherited class. See the (only slightly) altered example:

namespace PythonBaseClass
{
    using System;

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

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

        public virtual bool IsOpen()
        {
            Console.WriteLine("Door.IsOpen()");
            return false;
        }

        protected virtual void Toggle()
        {
            Console.WriteLine("Door.Toggle()");
        }
    }
}

The Python code has just been altered so that the namespace is properly set. Running the example comes with the following output:

Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:19:22) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from PythonInheritedClass import *
>>> d = StringDoor()
>>> d.status
'closed'
>>> d.Open()
StringDoor.IsOpen()
Door.Toggle()
>>>

Any ideas? This looks a little bit more “doable” than the abstract thing.

BR,

Henning

From: PythonDotNet [mailto:pythondotnet-bounces+hmoeller=comprion.com at python.org] On Behalf Of Denis Akhiyarov
Sent: Montag, 26. September 2016 20:16
To: A list for users and developers of Python for .NET <pythondotnet at python.org>
Subject: Re: [Python.NET] Inheriting from abstract .NET class

Hi Henning,

This feature was implemented by @tonyroberts in 2013 and is tested in CI with test_subclass.py file.

According to these tests, the missing piece in your code is defining explicitly __namespace__ on the .NET class derived in Python:

In [11]: class StringDoor1(Door):
   ....:     __namespace__ = "PythonBaseClass"
   ....:     def __init__(self):
   ....:         self.status = "closed"
   ....:
   ....:     def IsOpen(self):
   ....:         print "StringDoor.IsOpen()"
   ....:         return self.status == "open"
   ....:
   ....:     def Toggle(self):
   ....:         print "StringDoor.Toggle()"
   ....:         if self.status == "open":
   ....:             self.status = "closed"
   ....:         else:
   ....:             self.status = "open"

In [12]: d = StringDoor1()

In [13]: d.status
Out[13]: 'closed'

In [14]: d.Open()
StringDoor.IsOpen()
StringDoor.Toggle()

In [15]: d.status
Out[15]: 'open'



Thanks,
Denis

On Mon, Sep 26, 2016 at 9:19 AM, Henning Moeller <HMoeller at comprion.com<mailto:HMoeller at comprion.com>> wrote:
Hi Denis,

Thanks for your fast response. Sounds completely reasonable to me. And this has not been too much of an issue for me.

I got rid of the abstract base class simply by providing an “empty” implementation and using a non-abstract base class. No need for meta classes any more. This way, I got rid of error messages. Great!

Unfortunately, there seem to be an issue when calling a virtual method inside the C# implementation. Even when overriding this virtual method in Python, it’s still the base class’ implementation which is called.

See the new simple base class defined in C#:

namespace PythonBaseClass
{
    using System;

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

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

        public virtual bool IsOpen()
        {
            Console.WriteLine("Door.IsOpen()");
            return false;
        }

        public virtual void Toggle()
        {
            Console.WriteLine("Door.Toggle()");
        }
    }
}

The consuming Python code now looks like this:

import clr
from PythonBaseClass import Door

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

    def IsOpen(self):
        print "StringDoor.IsOpen()"
        return self.status == "open"

    def Toggle(self):
        print "StringDoor.Toggle()"
        if self.status == "open":
            self.status = "closed"
        else:
            self.status = "open"

But the output does not look like expected:

Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:19:22) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from PythonInheritedClass import StringDoor
>>> d = StringDoor()
>>> d.status
'closed'
>>> d.Open()
Door.IsOpen()
Door.Toggle()
>>> d.status
'closed'
>>>

From my understanding, the output should rather read “StringDoor.<something>()” instead of “Door.<something>()”. Obviously, only the base implementation is called but the overridden methods are ignored.

Also a limitation of inheriting C# classes in pythonnet?

BR,

Henning

From: PythonDotNet [mailto:pythondotnet-bounces+hmoeller<mailto:pythondotnet-bounces%2Bhmoeller>=comprion.com at python.org<mailto:comprion.com at python.org>] On Behalf Of Denis Akhiyarov
Sent: Donnerstag, 22. September 2016 19:38
To: A list for users and developers of Python for .NET <pythondotnet at python.org<mailto:pythondotnet at python.org>>
Subject: Re: [Python.NET] Inheriting from abstract .NET class

You are not a "Python n00b" based on metaclass usage!

My recommendation is to keep simple integration layer between CPython and .NET, hence metaclasses were/are not supported.

But contributions are welcome! Although I expect this to be a tremendous undertaking based on reviewing multiple sources.

Note that metaclass is a very different low-level concept from higher-level abstract classes in .NET, hence direct mapping (e.g. `.register()` ) is not feasible.

Thanks,
Denis

On Thu, Sep 22, 2016 at 10:04 AM, Henning Moeller <HMoeller at comprion.com<mailto:HMoeller at comprion.com>> wrote:
Hello out there,

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

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

[File: room.py] -------
import abc

class Room(object):
    def __init__(self, door):
        self.door = door

    def open(self):
        self.door.open()

    def close(self):
        self.door.close()

    def is_open(self):
        return self.door.is_open()

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:

[File: PythonAbstractBaseClass.dll] -------
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:

[File: room2.py] -------
import clr
import abc
from PythonAbstractBaseClass import Door

class Room(object):
    def __init__(self, door):
        self.door = door

    def open(self):
        self.door.open()

    def close(self):
        self.door.close()

    def is_open(self):
        return self.door.is_open()

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 is missing feature?

Thanks in advance,

Henning


_________________________________________________
Python.NET mailing list - PythonDotNet at python.org<mailto:PythonDotNet at python.org>
https://mail.python.org/mailman/listinfo/pythondotnet


_________________________________________________
Python.NET mailing list - PythonDotNet at python.org<mailto:PythonDotNet at python.org>
https://mail.python.org/mailman/listinfo/pythondotnet

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/pythondotnet/attachments/20160927/6baa76cb/attachment-0001.html>


More information about the PythonDotNet mailing list