Implement async abstract method synchronously - python

I have an abstract Python class that defined an abstract async method:
class ConversionResultsReporter(ABC):
#abstractmethod
async def report(
self, conversion_spec: ConversionSpec, results: Sequence[PositiveFloat]
) -> None:
pass
I'd like to implement a derived class where the implementation is synchronous, doesn't need to use await - for simplicity let's say it should do print "Hello World" and exit, how would it be written?

Related

Pass instance attribute as a decorator parameter

I am creating a class Encuesta to create multiple surveys via user commands for a discord bot using discord.py.
To achieve this, I have to pass the attribute "self.buttonid" as the 'custom_id' parameter for the decorator #discord.ui.button (already defined by discord.py).
class Encuesta(discord.ui.View):
def __init__(self, pregunta, buttonid):
super().__init__(timeout=None)
self.pregunta = pregunta
self.buttonid = buttonid
#discord.ui.button(label="Realizar encuesta", style=discord.ButtonStyle.grey, custom_id=self.buttonid)
async def encuesta(self, interaction: discord.Interaction, button: discord.ui.Button):
await interaction.response.send_modal(await crear_modal(self.pregunta, interaction.user))
But I get the error "self is not defined", since 'self' only exists inside class methods, and cant access it from the decorator calling.
I just need to get access to self.buttonid while calling the decorator.
I tried directly calling self.buttonid, without success. Other answers rely on modifyng the decorator, and I would want to avoid that.
Since a discord View class is meant to be instantiated only once, one viable workaround would be to use a class factory function to create a singleton class with buttonid preserved in the closure of the factory function rather than storing it as an instance attribute:
def Encuesta(pregunta, buttonid):
class _Encuesta(discord.ui.View):
def __init__(self):
super().__init__(timeout=None)
#discord.ui.button(
label="Realizar encuesta",
style=discord.ButtonStyle.grey,
custom_id=buttonid)
async def encuesta(self, interaction: discord.Interaction, button: discord.ui.Button):
await interaction.response.send_modal(await crear_modal(pregunta, interaction.user))
return _Encuesta()

Listing all references in a python method

I have classes like these
class Test:
def __str__(self):
return "Test"
class Test1(Test):
def __str__(self):
return "Test1"
class Test2(Test):
def __str__(self):
return "Test2"
class Runner:
pass
class Runner1(Runner):
def run(self):
print("I'm a method, doing this and that")
print(f"And I use {Test1()}")
class Runner2(Runner):
def func2(self):
print("I'm a method, doing this and that")
test = Test2()
print(f"And I use {test}")
and I would like to discover all Runner classes, which use Test instances, like this:
for klass, func, ref in get_all_references(Runner):
if isinstance(ref, Test):
print(f"{klass.__name}.{func.__name} uses Test!")
That is, I'm looking for the get_all_references method, which returns all referenced objects of any classes of type Runner (and their methods), which I can inspect for class type/inheritance.
The motivation behind this is to discover all places (class/method names) where instances of Test are used.
I think part of the problem is solved by static analyzers/doc creators/cross reference builders, but I couldn't find any which could be used to get this information via an API.
i think gc module has several useful functions in that matter, but it sounds like gc.get_referrers() is what you need.

Test abstract class calls parent method in Python

I'm currently refactoring features and I ended up with this abstractions
I have this classes
class AbstractClassA(SomeOtherAbstractClass):
#abstractmethod
def some_abstract_method(self):
pass
def my_method(self)):
service.some_method
class AbstractClassB(AbstractClassA):
#abstractmethod
def another_abstract_method(self):
pass
def some_abstract_method(self):
some_implementation
def my_method(self):
super().my_method()
do_any_other_stuff
And I need to test if the AbstractClassB.my_method calls super().my_method().
I've tried to test this by creating some ImplementationClass that inherits from AbstractClassB and then mocking the AbstractClassA.my_method and checking if it was called but it didn't work...
class AbstractClassBImplementation(AbstractClassB):
def some_abstract_method(self):
calls_service()
class TestAbstractClassB(TestCase):
#patch('module.submodule.AbstractClassA.my_method')
def test_class_b_calls_class_a_my_method(self, my_method_mock):
instance = AbstractClassBImplementation()
instance.my_method()
self.assertTrue(my_method_mock.called)
Someone know how to test this?

Celery: how to set the status of a Task

I have defined a Celery task like this:
#app.task()
def my_task():
# Do things...
I'm using Flower, so I want to see the final state of the task, according to some rules created by me:
if condition_1:
return task_status_success
elif condition_2:
return task_status_fail
How can I do this?
I've seen some people do something like this:
class AbstractTask(Task):
abstract = True
def __init__(self):
self.last_error_log = ErrorLog(logger)
Task.__init__(self)
def _task_error(self, message):
logger.error(message)
self.update_state(state=states.FAILURE)
raise Exception(message)
But that method seems to define classes as Tasks, not as functions.
Any help on how to set manually the state of a Celery task defined as a function?
To use the method you saw that uses an abstract class, you just need to pass the class as base to your decorator:
#app.task(base=AbstractClass, bind=True)
def my_task(self):
pass
bind=True will allow you to use self to access the members of your class.

How do I refer to a class method outside a function body in Python?

I want to do a one time callback registration within Observer. I don't want to do the registration inside init or other function. I don't know if there is a class level equivalent for init
class Observer:
#classmethod
def on_new_user_registration(new_user):
#body of handler...
# first I try
NewUserRegistered().subscribe \
(Observer.on_new_user_registration) #gives NameError for Observer
#so I try
NewUserRegistered().subscribe(on_new_user_registration) #says not callable
#neither does this work
NewUserRegistered().subscribe(__metaclass__.on_new_user_registration)
class BaseEvent(object):
_subscriptions = {}
def __init__(self, event_info = None):
self.info = event_info
def fire(self):
for callback in self._subscriptions[event_type]:
callback(event_info)
def subscribe(self, callback):
if not callable(callback):
raise Exception(str(callback) + 'is not callable')
existing = self._subscriptions.get(self.__class__, None)
if not existing:
existing = set()
self._subscriptions[self.__class__] = existing
existing.add(callback)
class NewUserRegistered(BaseEvent):
pass
I suggest to cut down on the number of classes -- remember that Python isn't Java. Every time you use #classmethod or #staticmethod you should stop and think about it since these keywords are quite rare in Python.
Doing it like this works:
class BaseEvent(object):
def __init__(self, event_info=None):
self._subscriptions = set()
self.info = event_info
def fire(self, data):
for callback in self._subscriptions:
callback(self.info, data)
def subscribe(self, callback):
if not callable(callback):
raise ValueError("%r is not callable" % callback)
self._subscriptions.add(callback)
return callback
new_user = BaseEvent()
#new_user.subscribe
def on_new_user_registration(info, username):
print "new user: %s" % username
new_user.fire("Martin")
If you want an Observer class, then you can do it like this:
class Observer:
#staticmethod
#new_user.subscribe
def on_new_user_registration(info, username):
print "new user: %s" % username
But note that the static method does not have access to the protocol instance, so this is probably not very useful. You can not subscribe a method bound to an object instance like this since the object wont exist when the class definition is executed.
But you can of course do this:
class Observer:
def on_new_user_registration(self, info, username):
print "new user: %s" % username
o = Observer()
new_user.subscribe(o.on_new_user_registration)
where we use the bound o.on_new_user_registration as argument to subscribe.
I've come to accept that python isn't very intuitive when it comes to functional programming within class definitions. See this question. The problem with the first method is that Observer doesn't exist as a namespace until the class has been built. The problem with the second is that you've made a class method that doesn't really do what it's supposed to until after the namespace has been created. (I have no idea why you're trying the third.) In both case neither of these things occurs until after the class definition of Observer has been populated.
This might sound like a sad constraint, but it's really not so bad. Just register after the class definition. Once you realize that it's not bad style to perform certain initialization routines on classes in the body of the module but outside the body of the class, python becomes a lot friendlier. Try:
class Observer:
# Define the other classes first
class Observer:
#classmethod
def on_new_user_registration(new_user):
#body of handler...
NewUserRegistered().subscribe(Observer.on_new_user_registration)
Because of the way modules work in python, you are guaranteed that this registration will be performed once and only once (barring process forking and maybe some other irrelevant boundary cases) wherever Observer is imported.
oops. sorry about that.
All I had to do was to move the subscription outside the class definition
class Observer:
#classmethod
def on_new_user_registration(new_user):
#body of handler...
#after end of class
NewUserRegistered().subscribe(Observer.on_new_user_registration)
Guess it is a side-effect of too much Java that one doesn't immediately think of this.
What you're doing should work:
>>> class foo:
... #classmethod
... def func(cls):
... print 'func called!'
...
>>> foo.func()
func called!
>>> class foo:
... #classmethod
... def func(cls):
... print 'func called!'
... foo.func()
...
func called!
One thing to note though, class methods take a cls argument instead of a self argument. Thus, your class definition should look like this:
class Observer:
#classmethod
def on_new_user_registration(cls, new_user):
#body of handler...

Categories

Resources