Class Decorator Compatible for Mypy - python

Say I have the following simple example without any typehints:
def wrapper(cls):
class Subclass(cls):
def subclass_method(self):
pass
return Subclass
#wrapper
class Parent:
def parent_method(self):
pass
p = Parent()
p.parent_method()
p.subclass_method()
How can I restructure this code using typehints, such that when I run mypy against an instance of Parent, it will recognize both subclass_method and parent_method?
Possible solutions:
Using a mixin Parent(Mixin): Works, but avoids the decorator. Is it possible to achieve without?
Patching the method onto the existing class: Still has the same issue of resolving subclass_method in mypy
Custom Mypy plugin: Wouldn't be sure where to start with this one, or if it would be possible without one.

This would be much simpler without the wrapper at all.
class SomeMixin:
def subclass_method(self):
pass
class Parent(SomeMixin):
def parent_method(self):
pass
p = Parent()
p.parent_method()
p.subclass_method()
Here, you define SomeMixin once, not once per call to a wrapper, and the class SomeMixin is known statically. All the various classes with the name Subclass are created dynamically, and mypy can't know statically which class the name Parent is actually bound to.

Related

Python 2.7 inheritance - can i wrap overriden mehods without changing child code?

I have the following code classes:
Class Parent:
def func(self):
pass
Class ChildA(Parent):
def func(self):
<ChildA Func Implementation>
Class ChildA(Parent):
def func(self):
<ChildB Func Implementation>
Is there a way to "wrap" every implementation of "func", to make it behave as follows:
def func(self):
with send_metrics:
<ChildA Func Implementation>
without changing any of the child classes code?
I have looked into creating a descriptor for the parent class, but in order for that to work i need to change every child class to also use this descriptor. i'm trying to avoid it as there can be a ton of child classes. - i saw that it's possible to do somehting similar in Python 3.7, but i'm working with 2.7
I'll note that i can't change the actual interface, meaning - a 3rd party scheduler calls "func", and I can't make it call a different method.
Thanks in advance!

Skip inheritance order call in odoo

I have a class inherited from project.task named ProjectTask
The class has a copy method that overrides the copy function from project.task it's named Task
I need to run the base copy function from my class instead of the one of the parents class
this is my class code:
#api.multi
#api.returns('self', lambda value: value.id)
def copy(self, default=None):
if default is None:
default = {}
if not default.get('name'):
default['name'] = self.name.id
return super(ProjectTask, self).copy(default) #<-- I don't want to call the inherited class method I want to call the base class method instead
This is the copy method from the base class (Task)
#api.multi
#api.returns('self', lambda value: value.id)
def copy(self, default=None):
if default is None:
default = {}
if not default.get('name'):
default['name'] = _("%s (copy)") % self.name
return super(Task, self).copy(default) # <-- I want to run this method from my class (ProjectTask) which is the child class
Any advice will be more than welcome
With the parent class implementation you show, calling it with your own default should do what you want, as it will just pass it through to its own parent with no changes. (At least, that's true with the bare method code, I don't know what the odoo decorators do to change things.)
But if you really do need to skip over it for some non-obvious reason, you probably can do it. Generally speaking, these approaches will only work as intended if you don't expect your class to ever be used with multiple inheritance. If your MRO gets complicated, then you really want to be doing the normal thing with super and making all your methods play nicely together.
One option for skipping an inherited method is to directly name the class you want your call to go to (i.e. your grandparent class).
class Base():
def foo(self):
print("Base")
class Parent(Base):
def foo(self):
print("Parent")
super().foo() # super() in Python 3 is equivalent to super(Parent, self)
class Child(Parent):
def foo(self):
print("Child")
Base.foo(self) # call Base.foo directly, we need to pass the self argument ourselves
Another option would be to change the argument you give to super to name the parent class instead of your own class. Usually that's a newbie error, but if that's really what you want, it's allowed (though I'd strongly recommend adding a comment to the code explaining that you really do want that behavior!
class Child(Parent):
def foo(self):
print("Child")
super(Parent, self).foo() # Note: Deliberately skipping over Parent.foo here!
A final note: If you find yourself wanting to skip a parent class's implementation of some of its methods, perhaps you should reconsider if you should really be inheriting from it at all. It may be that you really want to be inheriting from the same base class as it instead, and skipping the middle class altogether. Obviously, this has its own limitations (maybe some library code does type checking for that class), but if you find yourself fighting the inheritance machinery, it may be that you're doing things the hard way, and there's an easier alternative.

How to call non abstract method in a abstract class?

I have an abstract class in python and want to call non-abstract methods in it. Is it possible to do it?
from abc import ABC, abstractmethod
class MyAbstract(ABC):
# Can I call method get_state() from get_current() ?
def get_state():
get_current() # gives me error?
def get_current():
#abstractmethod
def get_time():
I have another python file, Temp.py implement this interface.
In Temp.py, I call the get_state using MyAbstract.get_state(), I get the error stating that get_current() is undefined.
Not sure why.
Any help is appreciated.
In general, all methods have a namespace which is the class or object they're attached to. If you have an instance of a class floating around (e.g. self, most of the time), you can call methods on that instance that automatically pass the instance itself as the first parameter - the instance acts as the namespace for an instance method.
If you're using a class method or a static method, then the namespace is almost always going to be the class they're attached to. If you don't specify a namespace, then python assumes that whatever function you're trying to call is in the global namespace, and if it isn't, then you get a NameError.
In this case, the following should work for you:
class MyAbstract(ABC):
def get_current():
print("current")
def get_state():
MyAbstract.get_current()
#abstractmethod
def get_time():
pass
You can just imagine that you have a little invisible #staticmethod decorator hanging above get_current() that marks it as such. The problem with this is that now you don't get to change the behavior of get_current() in subclasses to affect change in get_state(). The solution to this is to make get_state() a class method:
#classmethod
def get_state(cls):
cls.get_current()
Calling a static method uses identical syntax to calling a class method (in both cases you would do MyAbstract.get_state(), but the latter passes the class you're calling it on as the first argument. You can then use this class as a namespace to find the method get_current() for whatever subclass has most recently defined it, which is how you implement polymorphism with method that would otherwise be static.

Access the python class from method while defining it

I wanted to access the class on which method is to be defined. This can be used, for example, to create alias for methods with decorator. This particular case could be implemented without using decorator (alias = original_name), but I would like to use decorator, primarily so because the aliasing will be visible along side the method definition at the top, useful when the method definition is long.
def method_alias(*aliases):
def aliased(m):
class_of_m = ??? # GET class of this method
for alias in aliases:
setattr(class_of_m, alias, m)
return m
return aliased
class Test():
#method_alias('check', 'examine')
def test():
print('I am implemented with name "test"')
Later, I found here that the above could be implemented by using two decorators (first store the aliases as method attributes, later when the class is already created, add the attributes to class). Can it be done without decorating the class, i.e. only decorating the method? This requires getting access to the class name in the decorator.
The short answer is no. The contents of the class body are evaluated before the class object is created, i.e. the function test is created and passed to the decorator without class Test already existing. The decorator is therefore unable to obtain a reference to it.
To solve the problem of method aliasing, I reckon three approaches:
Using a class decorator as described by your link.
Using a metaclass, which lets you modifies the class' __dict__ before the class object is created. (Implementing a metaclass class is acutally overriding the default constructor for class objects, see here. Also the metaclass usage syntax has changed in Python 3.)
Creating the aliases in the __init__ method for each instance of Test.
The first approach is probably the most straightforward. I wrote another example. It basically does the same as your link, but is more stripped down to make it a bit clearer.
def alias(*aliases):
def decorator(f):
f.aliases = set(aliases)
return f
return decorator
def apply_aliases(cls):
for name, elem in list(cls.__dict__.items()):
if not hasattr(elem, 'aliases'):
continue
for alias in elem.aliases:
setattr(cls, alias, elem)
return cls
#apply_aliases
class Test(object):
#alias('check', 'examine')
def test(self):
print('I am implemented with name "test"')
Test().test()
Test().check()
Test().examine()

Subclasses in Python 2.7

I'm trying to do something I consider pretty ordinary in Object Oriented programming
but can't find any documentation on it for Python 2.7
I want to create a subclass of a superclass where, when I'm done
superclass
is bound to the superclass
superclass.subclass is bound to the subclass and
subclass is bound to nothing.
Here's the best solution I can come up with:
class superclass:
pass
class subclass(superclass):
pass
superclass.subclass = subclass
del subclass
Sometimes I want subclass to be in its own file, other times not.
Is there a more elgant solution where I don't have to manually perform the
last two lines?
Although
class superclass:
class subclass:
pass
almost does the right thing, subclass doesn't actually inherit from superclass.
And if I try to do:
class superclass:
class subclass(superclass):
pass
I get an error message that superclass is unbound.
I agree with everyone else that this is a silly thing to do and I don't think you should do it, but in the interest of knowledge:
class Superclass(object):
pass
Superclass.Subclass = type('Subclass', (Superclass,), {
'foo': lambda self: self,
})
where the dictionary argument contains any methods. I don't think there's a nice way to do this with the class syntax, but that's really just syntactic sugar for calling type anyway.
You don't have to define the methods as lambdas; they can be normal functions with def as long as they have the self argument. You'll probably want to hide their definitions if you do that, though....
Here's a simple class decorator to do the referencing:
def refer(cls):
cls.__bases__[0].subclass = cls
return cls
Here's how you use it:
>>> class Superclass:
pass
>>> #refer
class Subclass(SuperClass):
pass
You will still need to delete Subclass if you don't want the name in the module namespace.

Categories

Resources