Hi Henning,

Your question about abstract classes in pythonnet reposted at stackoverflow received a lot of attention recently:

https://stackoverflow.com/questions/39659469/how-to-inherit-from-an-abstract-base-class-written-in-c-sharp

Thanks,
Denis

On Tue, Sep 27, 2016 at 11:56 AM, Denis Akhiyarov <denis.akhiyarov@gmail.com> wrote:
Henning,

It is very questionable if "protected" should be available for overriding in Python, since we are not really doing compile time overriding in a .NET class with all sorts of differences in class compilation vs runtime emission.

But as a quick workaround you can add protected in this method in pythonnet:

private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuilder typeBuilder)
Let us know about the result.

Cheers,
Denis

On Tue, Sep 27, 2016 at 2:49 AM, Henning Moeller <HMoeller@comprion.com> wrote:

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@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@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@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=comprion.com@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@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@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@python.org
https://mail.python.org/mailman/listinfo/pythondotnet

 


_________________________________________________
Python.NET mailing list - PythonDotNet@python.org
https://mail.python.org/mailman/listinfo/pythondotnet

 


_________________________________________________
Python.NET mailing list - PythonDotNet@python.org
https://mail.python.org/mailman/listinfo/pythondotnet