-
Notifications
You must be signed in to change notification settings - Fork 949
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Be able to create asyncio modbusclients from within a coroutine #604
Conversation
You are right about the "function" of The docs of 3.9 say: I prefere skipping 3.6 anyway if we want to switch to Version 3.x in the future. 3.6 is a good base to built up, but there is still some ugly stuff to handle, which is not anymore in 3.7+ (where everything is a bit easier to handle over multiply versions). |
What do you suggest replacing it with then? |
Well your snippet wasn't so bad. It would work the way as intended. Like the docs say to get_event_loop():
I think replacing If I remember it right, if we take your snippit again, you would need to execute |
I assume you meant to say replacing loop = asyncio.new_event_loop() with loop = asyncio.get_running_loop() is better? Simply replacing |
No no, I realy mean, what I wrote. try:
loop = kwargs.get("loop") or asyncio.get_running_loop() # just checks if coroutine is running and get existing loop, if it exist. Otherwise raise RuntimeError
except RuntimeError: # "if loop does not exist"
loop = asyncio.get_event_loop() # create a new event loop and run it on the current OS Thread. This will give you always a legit loop without any problem. Then it doesn't matter if you are in a Coroutine or not! I am not sure what |
Ok, I'll update the pull request. I don't really know about the |
Updated the code as requested. I also changed |
SonarCloud Quality Gate failed. 4 Bugs No Coverage information |
@Emilv2 the best way to check is to run the example
|
@Emilv2 ah...python 3.6 hasn't got the get_running_loop feature. You have to check the python version at that point. :/ |
Hmmm, I tested the 3 conditions (4 now with running in a coroutine) and there are still some small issues. The simplest would indeed be to drop both python <= 3.6 and the loop argument. Python 3.6 is eol by the end of the year anyway and as I understand it making the loop argument implicit and relying on get_running_loop() or get_event_loop() is recommended nowadays. @dhoomakethu I think making an integration test of those examples would be a good idea, no? |
@Emilv2 Hey, are you still planning on merging this change? Just wondering as it will be indeed quite useful ;) |
Yes I'm still willing to work on it, but I'm not sure which python versions the maintainers want to support |
@Emilv2 for 3.x python |
Ok. If only python 3.7 and above is supported, is it also the plan to drop the explicit loop argument or not? Dropping it would mean the code could be simplified a lot but would be a much bigger change to the code base (and documentation) than this pull request. |
@Emilv2 I have kind picked your changes in to 3.0.0 branch already, I am yet to push the changes. JFYI |
@dhoomakethu Ok great! Right now my code doesn't work with all 4 conditions, I hope you fixed that if you keep the loop argument. It's a small change I didn't push yet. |
@Emilv2 What is the status of this PR, are you still working on it? I just ran into this problem as well. |
@arjen-hiemstra As I understood it @dhoomakethu was going to implement this himself. I can continue with it, but I will need to know from the maintainers where they want to go with the code (drop python 3.6? drop the loop argument?). |
JFYI Python 3.6.x is going to be supported for some more time. |
What about Python 3.10? It will deprecate the loop argument as I understand it correctly. |
Additional info to be more clear: 3.6 will be dropped 23rd Dec. 2021. I would recommened to go on with 3.7, since the async stuff is more compatible with newer releases. 3.6 was revolutionary in that topic, but still had some parts not solved well. |
Dropping Python <3.6 seems the most reasonable to me as well since I don't think pymodbus 3.0 is going to be released before then, or will it? I checked the Python 3.10 docs, and for the low level api the loop argument will remain, so nothing has to be changed for Python 3.10. I think dropping the loop argument would simplify the code a lot, and from Python >3.7 it's not really necessary anymore. Or are there some special use cases for keeping the loop argument? If everyone agrees on what has to be done I can give it a try since I have some time now. |
I hope you mean Dropping Python <=Python3.6 😉
I guess this depends on the progress on the milestones (?).
If I have it right in my mind, only one eventloop shall exist and that was the reason to drop the loop argument, since multiple loops can cause trouble. Whom who wants to use multiple loops, either doesn't understand asyncio or (hopefully) defitnitly knows what to do in multi/subprocessing enviroments...but that is such a special case, we should not think about. |
@Emilv2 python3.6 forms the major version where pymodbus is being used and that is the only reason why I am planning to support it for some more time. In any case, if you are willing and have bandwidth please give it a try and let us know your findings. |
I think I'm hitting this same issue as well when trying to setup an async client from a task inside an already running loop (i.e. passing in I did try modifying the library as outlined in another issue which solves the problem but I'm a bit wary of having to manage a local modified copy of the library, not sure if there's any other workaround at present? More than happy to offer any help as it's a bit of a blocker for us the moment |
@track02 My current work around is to circumvent the factory and create a client myself within my coroutine with:
Hope this helps |
I see that in |
@arjen-hiemstra - Thank you, that's a lot simpler and so far so good after a little testing today @Emilv2 - I'm still picking through how things fit together so apologies if I have missed something Or consider changing |
All changes merged to 3.0.0 branch refer #658 |
Based on PR #558 from @tiagocoutinho since that work seems to be stalled.
@memetb : I think calling
get_event_loop()
is the right call here, since the code still needs to work when no loop is present. The alternative of callingget_event_loop()
would be something like:But that is exactly what
get_event_loop()
does.There were some small style differences between
tcp
,udp
,tls
andserial
, I made the the code more similar to make it easier to compare. I noticed that fortcp
andtls
asyncio.set_event_loop(loop)
is called, but not forudp
andserial
, is that intended? I don't know enough of asyncio to say.I don't think this way of also returning the loop and the client when running in a coroutine is particularly elegant since you can't await part of a returned tuple so you'll need to do something like this:
I added some tests, but I expect they can be improved.
I also noticed that only the
tls
code would fail when callingget_event_loop()
without catchingRuntimeError
, so the other code doesn't seem to be tested without a loop argument or a running loop.