I'm quite stuck on structuring the code in this scenario. Can anyone help me with this?
| module.py
import asyncio
class Server:
def __init__(self):
self.d = {}
#classmethod
async def create(cls):
self = cls()
await self.func()
return self
async def func(self):
await asyncio.sleep(5) # Some other async code here
self.a = 12
def reg(self, ev):
def decorator(func):
self.d[ev] = func()
retun func
return decorator
def reg2(self, ev, func):
self.d[ev] = func
| main.py
import asyncio
from module import Server
async def main():
ser = await Server.create()
# This would be another way... but i find the other way one neater
serv.reg2('msg', some_handler)
# I want to decorate and register this using
# reg func; but since object is not created yet
# how do i acomplish this?
# #ser.reg('msg')
async def some_handler():
...
if __name__ == "__main__":
asyncio.run(main())
Some key points of my aim:
The function 'some_handler' is never used other than the time for register. That is, the function soley exists to be registered and is not used anywhere else.
Since Server class needs an asynchronous initialisation, it cannot be done globally.
(I dont know whether this point is helpful) Generally only one Server instance is created for a single program. There wont be any other instance even in other modules.
How do I model my code to satisfy this senario? I have mentioned an alternate way to register the function, but I feel I am missing something, as some_handler isn't used anywhere else. I have thought about making Server class into a metaclass to do registering and converting the main() and some_handler() as parts of the metclass's class but I'm seeking for different views and opinions.
Related
Let's say I have this
class Test():
def __init__(self, number):
self.number = number
await self.TestPrint()
async def TestPrint(self):
print(self.number)
As you can see this won't work since __init__ is not async and I cannot call await for the function
I want to be able to run TestPrint within __init__ assuming I want to maintain this function async
I also want this to have nothing to do with anything else other than the class (other function, other classes, main, etc.)
Thank you for your time.
Like chepner mentioned in the comments:
An asynchronous class method that creates the object and then calls the TestPrint method before returning it sounds more appropriate.
This is the preferred way above all else and why a lot of there are a lot of functions that initialize internal asyncio classes rather than you directly instantiating them.
That said, if you wish to have this close to the class you can use a #classmethod which can be async. Your code would look like this:
class Test():
def __init__(self, number):
self.number = number
async def TestPrint(self):
print(self.number)
#classmethod
async def with_print(cls, number):
self = cls(number)
await self.TestPrint()
return self
async def main():
t = await Test.with_print(123)
# 't' is now your Test instance.
...
I have a project that includes me using some SQL, I am wondering how can I call a function in the DB file?
class testing_db(commands.Cog):
def __init__(self, bot):
self.bot=bot
async def create_db_pool():
conn = await asyncpg.create_pool(database="db", user="user", host="nunyabusiness", password=DB_PW)
async def get_account_id(other_id):
mhm = "Do whatever I do here (I know how to do it but not call it from another file)"
loop.run_until_complete(create_db_pool())
def setup(bot):
bot.add_cog(testing_db(bot))
I'm not sure if this is the best/right way, but this is the first result on google so I wanted to share my workaround.
Add a function called run_main or whatever you want to call it. The function just needs to return your async run command:
def run_main():
return asyncio.run(main())
You can then call the run_main() function as normal from outside this file. Of course, substitute main() as necessary.
In your case, I would assume it's along the lines of adding a method like this:
def run_get_account_id(other_id):
return get_account_id(other_id)
Then import that method like normal. Note that this is probably a blocking call. I'm feeding a list to my main() so all the async stuff is happening inside main(). I would assume if you call run_get_account_id() individually, you will not get async behavior.
I come from Java background and most of my thinking comes from there. Recently started learning Python. I have a case where I want to just create one connection to Redis and use it everywhere in the project. Here is how my structure and code looks.
module: state.domain_objects.py
class MyRedis():
global redis_instance
def __init__(self):
redis_instance = redis.Redis(host='localhost', port=6379, db=0)
print("Redus instance created", redis_instance)
#staticmethod
def get_instance():
return redis_instance
def save_to_redis(self, key, object_to_cache):
pickleObj = pickle.dumps(object_to_cache)
redis_instance.set(key, pickleObj)
def get_from_redis(self, key):
pickled_obj = redis_instance.get(key)
return pickle.loads(pickled_obj)
class ABC():
....
Now I want to use this from other modules.
module service.some_module.py
from state.domain_objects import MyRedis
from flask import Flask, request
#app.route('/chat/v1/', methods=['GET'])
def chat_service():
userid = request.args.get('id')
message_string = request.args.get('message')
message = Message(message_string, datetime.datetime.now())
r = MyRedis.get_instance()
user = r.get(userid)
if __name__ == '__main__':
global redis_instance
MyRedis()
app.run()
When I start the server, MyRedis() __init__ method gets called and the instance gets created which I have declared as global. Still when the service tries to access it when the service is called, it says NameError: name 'redis_instance' is not defined I am sure this is because I am trying to java-fy the approach but not sure how exactly to achieve it. I read about globals and my understanding of it is, it acts like single variable to the module and thus the way I have tried doing it. Please help me clear my confusion. Thanks!
I writing unit tests and for testing I want to mock a method of already existing object.
But looks like with asyncio corutines it is not so simple as it looks.
I tried to use MagickMock but it just doesn't work. There is no errors or exceptions, but with debugger I can see that f() is never being called.
My tests and object I want to patch look like this:
from unittest.mock import patch, MagicMock
class Service(object):
async def callback_handler(self, msg):
pass
async def handle(self, msg):
await self.callback_handler(msg)
class TestCase(object):
def setUp(self):
self.service = Service()
#patch('module.msg')
def test_my_case(self, msg_mock):
f_was_called = False
async def f():
global f_was_called
f_was_called = True
self.service.callback_handler = MagicMock(wraps=f) # here I try to mock
await self.service.handle(msg_mock)
assert f_was_called is True
How can I patch already instantiated object method with some custom one? Is there some issues with corutines?
Try using a context manager by replacing this line:
self.service.callback_handler = MagicMock(wraps=f) # here I try to mock
With this:
with mock.patch.object(self.service, 'callback_handler', side_effect=f) as mock_cb:
... # rest of code indented
I also faced the problem trying to mock asyncio and want into a lot of troubles,
I ended using pytest.asycio plugin .
#pytest.mark.asyncio
async def test_some_asyncio_code():
res = await library.do_something()
assert b'expected result' == res
In class Wizard, I would like to set attribute wand to the value returned by coroutine magic.
class Wizard:
async def acquire_wand(self):
self.wand = await magic()
This code is considered "bad Python", however, because wand is not defined in __init__. I cannot define it in __init__, though, because await may only be used in asynchronous functions.
class Wizard:
def __init__(self):
self.wand = None
async def acquire_wand(self):
self.wand = await magic()
async def perform_spell(self):
if self.wand is None:
await self.acquire_wand()
self.wand.wave()
I could set wand to None in __init__ and use if self.wand is None: wherever it is accessed, but this seems messy and unwieldy.
How can I ensure that wand is defined throughout the class?
Technically there is a trick with overriding __new__ method:
class InitCoroMixin:
""" Mixin for create initialization coroutine
"""
def __new__(cls, *args, **kwargs):
""" This is magic!
"""
instance = super().__new__(cls)
#asyncio.coroutine
def coro():
instance.__init__(*args, **kwargs)
yield from instance.__ainit__()
return instance
return coro()
#asyncio.coroutine
def __ainit__(self):
raise NotImplementedError
see aiohttp_traversal code for full example.
But I highly discourage the method: having I/O in constructor is usually a bad idea, please think about it.
Wrap your functions that need self.wand inside a decorator, that will yield a clean and workable solution:
def with_wand(fn):
def wrapper(self):
if not self.wand:
await self.acquire_wand()
fn(self)
return wrapper
#with_wand
async def perform_spell(self):
self.wand.wave()
Haven't tested the code, let us know if it works!
It seems that using the following is the best way of going about this problem.
class Wizard:
def __init__(self):
self.wand = None
async def learn(self):
self.wand = await magic()
async def perform_spell(self):
if self.wand is None:
raise Exception("You must first learn to use a wand!")
self.wand.wave()
I think you got your advice, but I would like to question your premise. Who told you it's "considered bad Python"? I give my objects attributes all the time, whenever I need them to remember something. They have __dict__s for a reason. Python is not Java.