[Python.NET] Inheriting from abstract .NET class

Denis Akhiyarov denis.akhiyarov at gmail.com
Tue Sep 27 12:56:41 EDT 2016


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 at 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 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>
> 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 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>
> *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>
> 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
> https://mail.python.org/mailman/listinfo/pythondotnet
>
>
>
>
> _________________________________________________
> Python.NET mailing list - PythonDotNet at python.org
> https://mail.python.org/mailman/listinfo/pythondotnet
>
>
>
> _________________________________________________
> Python.NET mailing list - 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/358df36e/attachment-0001.html>


More information about the PythonDotNet mailing list