I'm able to authenticate against some RESTful API with one of the following methods:
password
certificate
anonymous
I've created AuthenticationBase class and its subclassess:
PasswordAuthentication
CertificateAuthentication
AnonymousAuthentication
Basically authentication take two steps:
get_rsts_token
set_access_token - You need RSTS token first
set_access_token has the same implementation across subclasses but get_rsts_token differs so I've tried something like this:
import abc
ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()})
class AuthenticationBase(ABC):
#abc.abstractmethod
def get_rsts_token(self):
pass
def set_access_token()
rsts_token = self.get_rsts_token()
access_token = retrieve_token(rsts_token)
but it leads to an error:
TypeError: Can't instantiate abstract class AuthenticationBase with abstract methods get_rsts_token
I wish to avoid rewriting set_access_token in all subclasses. How to achieve this?
Related
I want to make my unit tests setUp function clear from repeating tons of model creation lines like 1) create user 2) now create employee with fk to this user and etc.
In order to do that I've made a simple factory of dummy objects but I might've done some mistakes or just misunderstood something. Here's a piece of factory (dummy_data is just a bunch of dicts):
from abc import ABC
from users.models import User
from employees.models import Employee
from .dummy_data import(
user_data,
employee_data,
)
class DummyObjectFactory(ABC):
"""Fabric representing dummy test objects"""
def get_dummy_object(self):
"""Return dummy object"""
class DummyUser(DummyObjectFactory):
def get_dummy_object(self) -> User:
return User.objects.create_user(**user_data)
class DummyEmployee(DummyObjectFactory):
def get_dummy_object(self) -> Employee:
user = DummyUser().get_dummy_object()
return Employee.objects.create(**employee_data, user=user)
dummy_factory = {
"User": DummyUser().get_dummy_object(),
"Employee": DummyEmployee().get_dummy_object(),
}
dummy_factory = dot_dict(dummy_factory)
Then I make a dot notaion dictionary of all kinds of fabrics for easy calling them buy dummy_factory.Name . My intetion was that I call fabric with the desired model name and it creates it's instance.
The problem is: when I call it in some test's setUp method like so test_user = dummy_factory.User it creates object in actual database but I want it to be in test database.
Example of test:
class TestEmployeesListView(TestCase):
def setUp(self):
self.test_user = dummy_factory.User
self.test_employee = dummy_factory.Employee
self.client = Client()
def test_listview_deny_anonymous_user(self):
response = self.client.get(reverse('employees:employees-list'))
self.assertRedirects(response, '/login/?next=/employees/')
Yes, I've searched for the solution and found Factory boy and Faker libraries, but I want to complete my fabric, make it work properly. Thanks for your attention.
So I made it work. What I did was:
Added #abstractmethod decorator in the abstract class.
Every concrete factory methods must have a #classmethod decorator and recieve cls as an argument:
class DummyUser(DummyObjectFactory):
#classmethod
def get_dummy_object(cls) -> User:
return User.objects.create_user(**user_data)
It just work as intended: factory creates objects in test db. Thank you folks for participation.
I have a class I would like to add typehints to that looks as following:
import yaml
class TestClass(dict):
#classmethod
def load(cls, fname) -> "TestClass":
return cls(yaml.safe_load(""))
#property
#abc.abstractmethod
def test(self):
raise
when I run mypy on a module containing only this class I get the following error message:
error: Cannot instantiate abstract class 'TestClass' with abstract attribute 'test'
From what I have understood from other posts this has something to do with when the 'test' method is instantiated when executing the load method. Is there a way to fix this issue using typehints alone or would I need to adjust my code here?
What mypy is telling you is that TestClass.load(...) will fail, because it will try to create an instance of the abstract class TestClass.
We can fix this by requiring that cls can be called with whatever yaml.safe_load returns (I'm assuming dict here), and returns an instance of TestClass:
from typing import Callable
import abc
import yaml
class TestClass(dict):
#classmethod
def load(cls: Callable[[dict], TestClass], fname) -> "TestClass":
return cls(yaml.safe_load(""))
#property
#abc.abstractmethod
def test(self):
raise
Note that TestClass.load("foo") will now also pass type checking. This is fair to some extent, because it's also fine at runtime, until you call test() on the created instance. I think this might be a limitation of how mypy implements protocols.
The background
In python, if you were defining an Abstract Base Class which requires that its methods be overwritten, you'd do:
from abc import ABC, abstractmethod
class MyAbstractClass(ABC):
#abstractmethod
def my_method(self):
pass
The following code would then fail because it doesn't implement my_method.
class MyConcreteClass(MyAbstractClass):
pass
But what if I want to define the method requirements of a mixin class?
class MyMixin:
def my_mixin_method(self):
self.a_required_method()
The following code is then valid:
class MyBase:
def a_required_method(self):
pass
class MyFull(MyMixin, MyBase):
pass
The following code is also valid...
class MyDubious(MyMixin):
pass
But exposes an error at runtime:
MyFull().my_mixin_method() # Works
MyDubious().my_mixin_method() # Runtime error
The Question
Is there something like AbstractBaseClass which can be added to Mixin classes, to ensure that a derived class can't be instantiated unless it inherits correctly?
I'm thinking a nice API would look like:
from asc import ASC, requiredmethod
class MyRobustMixin(ASC):
#requiredmethod
def a_required_method(self):
pass
def my_mixin_method(self):
self.a_required_method()
I am trying to test the following method:
def my_method(self, request, context):
context.set_details('Already exists')
context.set_code(grpc.StatusCode.ALREADY_EXISTS)
To test it, I must pass in a request and a context (which is a grpc.ServicerContext object), like so:
import grcp
def test_my_method(self):
request = {"something": "something-else"}
context = grpc.ServicerContext()
my_method(request, context)
# Assert something here
The problem is, I get the following error when I run my tests:
TypeError: Can't instantiate abstract class ServicerContext with abstract methods add_callback, cancel, invocation_metadata, is_active, peer, send_initial_metadata, set_code, set_details, set_trailing_metadata, time_remaining
How can I get a grpc.ServicerContext object? If I can't, how do I test the method?
grpc.ServicerContext is an abstract class defined with the abc module. In your test you need to write your own concrete subclass of it and pass an instance of that to the method you are testing.
I have some code like this for Django-Tastypie:
class SpecializedResource(ModelResource):
class Meta:
authentication = MyCustomAuthentication()
class TestResource(SpecializedResource):
class Meta:
# the following style works:
authentication = SpecializedResource.authentication
# but the following style does not:
super(TestResource, meta).authentication
I would like to know what would be the right method of accessing meta attributes of the superclass without hard-coding the name of the superclass.
In your example it seems that you are trying to override the attribute of the meta of the super class. Why not use meta inheritance?
class MyCustomAuthentication(Authentication):
pass
class SpecializedResource(ModelResource):
class Meta:
authentication = MyCustomAuthentication()
class TestResource(SpecializedResource):
class Meta(SpecializedResource.Meta):
# just inheriting from parent meta
pass
print Meta.authentication
Output:
<__main__.MyCustomAuthentication object at 0x6160d10>
so that the TestResource's meta are inheriting from parent meta (here the authentication attribute).
Finally answering the question:
If you really want to access it (for example to append stuff to a parent list and so on), you can use your example:
class TestResource(SpecializedResource):
class Meta(SpecializedResource.Meta):
authentication = SpecializedResource.Meta.authentication # works (but hardcoding)
or without hard coding the super class:
class TestResource(SpecializedResource):
class Meta(SpecializedResource.Meta):
authentication = TestResource.Meta.authentication # works (because of the inheritance)