How to use `__declare_last__` in SQLAlchemy 1.0? - python

I used to register sqlalchemy events in the classmethod __declare_last__.
My code looked like this:
#classmethod
def __declare_last__(cls):
#event.listens_for(cls, 'after_udpate')
def receive_after_update(mapper, conn, target):
...
This worked correctly until I upgraded to SQLAlchemy 1.0, with which this hook was not called and my events were thus not registered.
I've read the 1.0 document about __declare_last__ and discovered nothing related.

After searching the source code of SQLAlchemy1.0.4 for __declare_last__, I've located the place where both __declare_last__ and __declare_first__ is found and registered.
def _setup_declared_events(self):
if _get_immediate_cls_attr(self.cls, '__declare_last__'):
#event.listens_for(mapper, "after_configured")
def after_configured():
self.cls.__declare_last__()
if _get_immediate_cls_attr(self.cls, '__declare_first__'):
#event.listens_for(mapper, "before_configured")
def before_configured():
self.cls.__declare_first__()
Then I used pdb to step through this method and found that _get_immediate_cls_attr(self.cls, '__declare_last__') was returning None for a class with this hook method inherited.
So I jumped to the definition of _get_immediate_cls_attr which contained a docstring that solved my problem:
def _get_immediate_cls_attr(cls, attrname, strict=False):
"""return an attribute of the class that is either present directly
on the class, e.g. not on a superclass, or is from a superclass but
this superclass is a mixin, that is, not a descendant of
the declarative base.
This is used to detect attributes that indicate something about
a mapped class independently from any mapped classes that it may
inherit from.
So I just added a mixin class, moved __declare_last__ to it and made the original base class inherit the mixin, and now __declare_last__ finally got called again.

Related

How to access Child Class members in Parent class in Python

Short version: For normal Object members, this is simple - you just use self.member in the parent, and the child can override the member and everything is happily object orientated. But what about class members that may get overriden by a child class?
To make that clear:
I know in Python I can just give Classname.membername but how do I allow Class members to be overriden? For example I have
class BaseDB:
user_table = "users"
# Class member function
def make_sql():
return f'SELECT * from {BaseDB.user_table};'
# Boilerplate functions that use "user_table"
def load_users(self):
return db.connection.cursor.execute(BaseDB.make_sql())
class SomeDatabase(BaseDB):
user_table = "the_users_table"
# Somewhere else in the code....
dbwrapper = SomeDatabase()
dbwrapper.load_users() # This does not use the overwridden value in SomeDatabase, it uses the value form the parent class
What I'm looking for something like self, but for the Class, not for the object.
At first I thought I could try and use type(self).class_member .... Not sure if that would even work, but self might not be available, eg in a non-class member method.
My workaround at present is to use normal object members - right now I don't have a requirement to access these from a class method. The only reason why I want to make these into Class members is because the values are constant for the class, not the object.
Edit: Added the somewhat contrived Class member function make_sql and used it in the normal member function.
Note: The derived class only sets the class member - Nothing else is overridden.
Note #2 - This is not a major obstacle. If there is a solution, I am sure I can use it ... if not, I've been getting along without it fine, so I'm just asking to find out if I'm missing out on something.
EDIT #2:
I just thought I should put the code into my IDE and see if I had any errors (I'm lazy). The IDE told me I need to have a "self" on the class member so I annotated it with #classmember. The IDE told me "Well then you should have a cls parameter. VOILA! This solves the problem, of course.

How to typehint mixins if the target class for the mixin inherits from a metaclass?

Consider the following class and mixin:
class Target(ClassThatUsesAMetaclass):
def foo(self):
pass
class Mixin:
def __init__(self):
self.foo() # type error: type checker doesn't know Mixin will have
# access to foo once in use.
class Combined(Mixin, Target):
def __init__(self):
Target.__init__(self)
Mixin.__init__(self)
I'm trying to avoid the type checker error in the above scenario. One option is this:
from typing import Protocol
class Fooable(Protocol):
def foo(self): ...
class Mixin(Fooable):
def __init__(self):
self.foo()
Would've worked great, except that Target inherits from a class that uses a metaclass, so Combined can't inherit from both Target and Mixin.
So now I'm trying an alternative, annotating self in Mixin:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .this import Mixin, Target
Mixin_T = type('Mixin_T', (Mixin, Target), {})
class Mixin:
def __init__(self: Mixin_T):
self.foo() # No longer an error
class Combined(Mixin, Target):
def __init__(self):
Target.__init__(self)
Mixin.__init__(self) # Now this is an error: "Type[Mixin]" is not
# assignable to parameter "self"
# "Mixin" is incompatible with "Mixin_T"
So how am I supposed to win this aside from using # type: ignore?
I found a very simple solution:
if TYPE_CHECKING:
from .this import Target
Mixin_T = Target
else:
Mixin_T = object
class Mixin(Mixin_T):
...
Now all of Target's methods are recognized within Mixin by the type checker, and there's no need to override the type of self into something imcompatible with Mixin. This might be a little awkward if the mixin is destined to all kinds of Target classes, but for my uses this is perfectly acceptable, since my case is a group of mixins extending a very specific target class.
Other than that, there is to little code and some msconceptions above that make this question not answrable at all, apart from providing some clarifications.
To start, are you sure you are "inheriting from a metaclass"?? It does not make sense to inherit a metaclass unless to create another metaclass. Your snippets show you inhriting froma supposed metaclass (with no code given), to create Target and them attempting to use Target as a parent to a normal class (a non-meta class). That makes no sense.
You might just have confused the terms and the hidden InheritFromMetaclass class actually just uses the metaclass, and do not "inherit" from it. Then your problem does not have to do with metaclasses at all.
So, the real visible problem in the snippet is that the static checkr does not "see" a self.foo method in the Mixin class - and guess what? There is no self.foo method in Mixin - the checker is just throwing a cold truth in your face: while Python does allow one to reference methods and attributes that are not available in a class, knowing that it will be used along other classes that do have those attributes, that is no good design and error prone. The kind of bad design static type checking exists to weed-off.
So, what you need is to have a base of Mixin that is an abstract class and have Foo as an abstract method. (Or have Mixin itself be that abstract class).
If - due to usage of other metaclass you can't have Mixin inheit from abc.ABC due to metaclass conflict, you have to either: create a combined metaclass from the metaclass acutually used by InheritsFromMetaclass with ABCMeta , nd use that as the metaclass for Mixin - or just create a stub foo method in Mixin as is (which could raise a NotImplementedError - thus having the same behavior of an abstract method, but without really having to inherit from it.
The important part to have in and is that an methods and attributes you access in code inside a class body have to exist in that class, without depending on attributes that will exist in a subclass of it.
If that does not solve your problem, you need to provide more data - including a reproducible complete example involving your actual metaclass. (and it mgt be solved just by combining the metaclasses as mentioned above)

How to create a mock that behaves like sub-classes from abstract class

I'm trying to create mocks from scratch that can pass the test issubclass(class_mock, base_class) where the base class is an abstract class derived from abc.ABC. Before you ask the question, I will answer why I'm trying to do it.
I have an internal package containing a base class and a collection of sub-classes that properly implement the abstract interface. Besides, I have a factory class that can instantiate the sub-classes. The factory is built is such a way that it can inspect its own package and have access to the existing sub-classes. The factory is meant to be always in the same package as the derived and base class (constraint). I think you guessed that I'm actually testing the factory... However, since the sub-classes can change in number, their name or their package name, etc., I cannot implement a correct unit test that directly refers to the actual cub-classes (because it introduces a coupling) and I need mocks.
The problem is that I didn't succeed to create a mock that satisfies the above conditions for a class derived from an abstract class. What I was able to achieve is for a class derived from another non-abstract class.
Here is the code that illustrates the problem more concretely.
import unittest.mock
import inspect
import abc
class A:
pass
class B(A):
pass
class TestSubClass(unittest.TestCase):
def test_sub_class(self):
b_class_mock = self._create_class_mock("B", A)
print(isinstance(b_class_mock, type))
print(inspect.isclass(b_class_mock))
print(issubclass(b_class_mock, A))
#staticmethod
def _create_class_mock(mock_name, base_class):
class_mock = unittest.mock.MagicMock(spec=type(base_class), name=mock_name)
class_mock.__bases__ = (base_class,)
return class_mock
So, for this code, everything is ok. It prints 3 True as wanted.
But as long as the class A is defined as abstract (class A(abc.ABC)), the last test is failing with an error saying that the mock is not a class even if the 2 previous tests are saying the opposite.
I dived a bit into the implementation of abc.ABCMeta and found out that __subclasscheck__ is overridden. I tried to know the process behind it but when I reached the C code and everything became a way more complicated, I tried to rather track when the error message is generated. Unfortunately, I didn't succeed to understand why it is actually not working.

Python Extending Classes with Same Method Name

In Python if you have a class that extends 2 or more classes, how does it know which class method to call if they all have a method titled save?
class File(models.Model, Storage, SomethingElse):
def run(self):
self.save()
What if Storage has a save(), and what is SomethingElse() has a save()?
Can anyone briefly explain?
Python supports a limited form of multiple inheritance as well. A
class definition with multiple base classes looks as follows:
class DerivedClassName(Base1, Base2, Base3):
.
.
.
The only rule necessary to explain the semantics is the resolution rule used for class attribute references. This is
depth-first, left-to-right. Thus, if an attribute is not found in
DerivedClassName, it is searched in Base1, then (recursively) in the
base classes of Base1, and only if it is not found there, it is
searched in Base2, and so on.
So in your example if all 3 classes have method save instances of File will use method save from models.Model
In practice, when this occurs, you'll likely want to write your own save which either replaces or uses one of the base class methods.
Let's say you want to just call them:
class MyFile(models.Model, Storage, SomethingElse): #file is a builtin class. Confusion will abound
def run(self):
self.save()
def save():
super(Storage, self).save() # start search for method in Storage
super(models.Model,self).save() # start search for method in models.Model
NOTE HOWEVER that if the mro (see: http://www.python.org/download/releases/2.3/mro/) of models.Model doesn't contain a save, and Storage does, you'll end up calling the same method twice.
A fuller exploration is here: http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ (and now linked to from the official docs).

pick a subclass based on a parameter

I have a module (db.py) which loads data from different database types (sqlite,mysql etc..) the module contains a class db_loader and subclasses (sqlite_loader,mysql_loader) which inherit from it.
The type of database being used is in a separate params file,
How does the user get the right object back?
i.e how do I do:
loader = db.loader()
Do I use a method called loader in the db.py module or is there a more elegant way whereby a class can pick its own subclass based on a parameter? Is there a standard way to do this kind of thing?
Sounds like you want the Factory Pattern. You define a factory method (either in your module, or perhaps in a common parent class for all the objects it can produce) that you pass the parameter to, and it will return an instance of the correct class. In python the problem is a bit simpler than perhaps some of the details on the wikipedia article as your types are dynamic.
class Animal(object):
#staticmethod
def get_animal_which_makes_noise(noise):
if noise == 'meow':
return Cat()
elif noise == 'woof':
return Dog()
class Cat(Animal):
...
class Dog(Animal):
...
is there a more elegant way whereby a class can pick its own subclass based on a parameter?
You can do this by overriding your base class's __new__ method. This will allow you to simply go loader = db_loader(db_type) and loader will magically be the correct subclass for the database type. This solution is mildly more complicated than the other answers, but IMHO it is surely the most elegant.
In its simplest form:
class Parent():
def __new__(cls, feature):
subclass_map = {subclass.feature: subclass for subclass in cls.__subclasses__()}
subclass = subclass_map[feature]
instance = super(Parent, subclass).__new__(subclass)
return instance
class Child1(Parent):
feature = 1
class Child2(Parent):
feature = 2
type(Parent(1)) # <class '__main__.Child1'>
type(Parent(2)) # <class '__main__.Child2'>
(Note that as long as __new__ returns an instance of cls, the instance's __init__ method will automatically be called for you.)
This simple version has issues though and would need to be expanded upon and tailored to fit your desired behaviour. Most notably, this is something you'd probably want to address:
Parent(3) # KeyError
Child1(1) # KeyError
So I'd recommend either adding cls to subclass_map or using it as the default, like so subclass_map.get(feature, cls). If your base class isn't meant to be instantiated -- maybe it even has abstract methods? -- then I'd recommend giving Parent the metaclass abc.ABCMeta.
If you have grandchild classes too, then I'd recommend putting the gathering of subclasses into a recursive class method that follows each lineage to the end, adding all descendants.
This solution is more beautiful than the factory method pattern IMHO. And unlike some of the other answers, it's self-maintaining because the list of subclasses is created dynamically, instead of being kept in a hardcoded mapping. And this will only instantiate subclasses, unlike one of the other answers, which would instantiate anything in the global namespace matching the given parameter.
I'd store the name of the subclass in the params file, and have a factory method that would instantiate the class given its name:
class loader(object):
#staticmethod
def get_loader(name):
return globals()[name]()
class sqlite_loader(loader): pass
class mysql_loader(loader): pass
print type(loader.get_loader('sqlite_loader'))
print type(loader.get_loader('mysql_loader'))
Store the classes in a dict, instantiate the correct one based on your param:
db_loaders = dict(sqlite=sqlite_loader, mysql=mysql_loader)
loader = db_loaders.get(db_type, default_loader)()
where db_type is the paramter you are switching on, and sqlite_loader and mysql_loader are the "loader" classes.

Categories