Asyncio testing a function which uses loop.call_soon_threadsafe - python-3.x

I have the following function:
def send_command(self, cmd):
self.loop.call_soon_threadsafe(
functools.partial(
self._transport.write, str(cmd).encode() + b"\n"
)
)
The system under test (sut) is a class inheriting from asyncio.Protocol which sends some commands to a piece of hardware on a socket. I have to use threads since this is part of a GUI under wxPython. Finally, if I call self._transport.write the code works fine on Linux but crashes on Windows™.
When running the test:
#pytest.mark.asyncio
async def test_send_command(self):
self.sut._transport = Mock()
self.sut.send_command("ook eek")
assert self.sut._transport.write.called is True
I get an assert error. The self.sut._transport.write is never called. If I call self._transport.write directly in the function, the code crashes on Windows™ but the test passes just fine.
What am I missing here?
Anyone?…
Surely, this is not such an edge case…

A work around…
After reading and experimenting with even loops, using this:
import asyncio
import selectors
selector = selectors.SelectSelector()
loop = asyncio.SelectorEventLoop(selector)
asyncio.set_event_loop(loop)
by passes the problem. Of course, it means using a sub-efficient loop on Windows. ☹ PHA!
Anyone with a better solution is welcome to some fake internet points.

Related

python mock find where method was called

I am working on a project that has some pytests, in one of the tests I have the following line:
mocked_class = Mock()
assert mocked_class.send.call_count == 1
Now I can not find the place in code where someone is calling the send method.
I tried to add
mocked_class.send=my_method
and added prints on that or put breakpoint, but it did not work.
So it seems that I am missing something
The tests are working on python 3.8
with
import pytest
from mock import Mock
How can I find who calls this method?
Any other help of debuging this
send might not exist in your code since its part of a Mock instance and you can call arbitrary methods from a Mock instance:
from unittest.mock import Mock
def test_1():
mocked_class = Mock()
mocked_class.wasda()
assert mocked_class.wasda.call_count == 1
test_1()
There are plenty of examples in the docs: https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock
Your code should also raise an "AssertionError" since there are no calls to send before the assertions statement.

monkeypatch in python, leaking mocks to other tests causing them to fail

I am monkeypatching the other function calls while writing pytest unittests as below:
from _pytest.monkeypatch import MonkeyPatch
from third_party import ThirdParty
def test_my_func():
resp1= "resp1"
monkeypatch = MonkeyPatch()
def mock_other_method(*args, **kwargs):
return resp1
monkeypatch.setattr(ThirdParty, "other_method", mock_other_method)
assert ThirdParty().other_method() == "resp1"
# Some assertions
def test_my_func2():
monkeypatch = MonkeyPatch()
expected_result = "This is expected"
result_third_party = ThirdParty().other_method()
assert result_third_party == expected_result
where,
third_party.py has:
class ThirdParty:
def other_method(self):
return "This is expected"
These tests when ran independently run fine (I just wrote it, so there might be some syntax error). But when I run it as pytest -v, 2nd test will fail. The reason is that on calling other_method, it will return the mocked method: mock_other_method, and since the response is different it will fail. Please suggest some solution to this
monkeypatch is a pytest fixture and as such
not supposed to be imported. Instead, you have to provide it as an argument in the test functions. Pytest loads all fixtures at test start and looks them up by name, so the correct usage would be:
from third_party import ThirdParty
# no import from pytest internal module!
def test_my_func(monkeypatch):
resp1 = "resp1"
def mock_other_method(*args, **kwargs):
return resp1
monkeypatch.setattr(ThirdParty, "other_method", mock_other_method)
assert ThirdParty().other_method() == resp1
The monkeypatch fixture has function scope, meaning that the patching will be reverted after each test function automatically.
Note that using the internal pytest API (e.g. importing _pytest) is discouraged, both because it may change with a new version, and because there are more convenient and secure methods to use the features (and not last because these are documented). You should never bother about fixture cleanup yourself, if you use a fixture provided by pytest or a pytest plugin - it would be too easy to forget the cleanup and get unwanted side effects.
I found the solution by adding monkeypatch.undo() at the end of every test. This will prevent the monkeypatch() from leaking into other functions

Trigger middleware within the call method using Python and uWSGI

I was confused at one point when I was developing an application to run on wsgi - more specifically on uwsgi.
After building my example application:
class MyCustomApp():
def __call__(self, environ, start_response):
start_response('200 OK', [('Content-Type','application/json')])
return "a".encode('utf-8')
application = MyCustomApp()
Everything works perfectly as expected.
I use a class instead of a method, I need to use it for other reasons.
Now let's get to the problem. I am using middleware called beaker and if I replace my application with:
application = SessionMiddleware(MyCustomApp(),options)
Everything is normal, but I don't want to modify my call, despite for the sake of study and understanding.
I would like to do the following:
class MyCustomApp():
def __call__(self, environ, start_response):
start_response('200 OK', [('Content-Type','application/json')])
...
here i want to implement SessionMiddleware without modify
application = MyCustomApp()
...
return "a".encode('utf-8')
application = MyCustomApp()
But nothing I try, my middleware replaces my environment with its defaults. I wish they could guide me to understand and try to implement keeping the logic above.

What is the preferred way to call synchronous code from async routes in Sanic?

I'm researching Sanic as we're looking for alternatives to our flask-based rest services. I'm intriguied by the async nature of sanic, but I know that we'll bump into a lot of code that simply won't support async (we use a ton of boto3 and also some ORMs on top of DynamoDB for example, none of which support awaiting).
So: I need to find the cleanest way of being able to run synchronous code inside an async framework like Sanic. In python 3.7 there's the asyncio.create_task call which I'm finding interesting.
Wondering if this would be a possible way to go:
main.py:
#default boilerplate sanic code excluded for brevity
from app_logic import AppLogic
#app.route("/")
async def test(request):
task = await asyncio.create_task(AppLogic.sync_request('https://stuff.com'))
return json({"hello": "world", 'status_code': task.status_code})
app_logic.py:
import requests
class AppLogic(object):
#staticmethod
async def sync_request(url='https://myurl.com'):
#Some non-async library/code thingy
print('requesting the thing')
return requests.get(url)
This seems to work, and the the returned task object is a regular requests response.
However, I have no idea if this is "safe" - eg I'm not sure how I can investigate the event loop and verify that it's not blocking in any way. I'm sure there's also other reasons for this approach being completely dumb, so lay them on me :-)

Forcing single threaded request handling with web.py

I'm using web.py framework. For debugging purposes, I'd like to force all requests to be handled by a single thread, or simulate such behaviour with a mutex. How can I do that?
Let me suggest something like this, but it will lock only current application stack over your controller method.
import web
from threading import Lock
urls = ("/", "Index")
class Index:
def GET(self):
# This will be locked
return "hello world"
def mutex_processor():
mutex = Lock()
def processor_func(handle):
mutex.acquire()
try:
return handle()
finally:
mutex.release()
return processor_func
app = web.application(urls, globals())
app.add_processor(mutex_processor())
if __name__ == "__main__":
app.run()
UPD: if you need to lock the whole application stack then you probably have to wrap app.wsgifunc with your own WSGI middleware. To get an idea check my answer to this question.
To get things decently into a single thread debugging mode, the web.py app can be run with a single threaded WSGI server.
Such server is "almost" offered by web.py itself as web.httpserver.runbasic() which uses Python's builtin BaseHTTPServer.HTTPServer - but also SocketServer.ThreadingMixIn .
This ThreadingMixIn however can be blocked by something like this:
# single threaded execution of web.py app
app = web.application(urls, globals())
# suppress ThreadingMixIn in web.httpserver.runbasic()
import SocketServer
class NoThreadingMixIn:
pass
assert SocketServer.ThreadingMixIn
SocketServer.ThreadingMixIn = NoThreadingMixIn
web.httpserver.runbasic(app.wsgifunc())
Or you could replicate the rather short web.httpserver.runbasic() code.

Resources