-
-
Notifications
You must be signed in to change notification settings - Fork 423
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
Executed lines reported as missing in threads #582
Comments
Thanks for writing this up. When I run your code with Python 3.6, and coverage.py 4.4.1, I get 100% every time. Can you give me some details of your environment? The output of "coverage debug sys" will have information. Also, can you run "coverage report -m" to show what lines are being missed? Thanks. |
Original comment by k3it (Bitbucket: k3it, GitHub: k3it)
I'm also getting missing coverage when deploying a python 3.5 project to Travis CI, which is linux based. so this does not look like a windows issue. I have not checked other releases of Python yet |
I'm sorry, I cannot reproduce what you are seeing. Can you provide a link to the failing travis builds? |
Original comment by k3it (Bitbucket: k3it, GitHub: k3it) Hi Ned coverage report you are right. it seems that in some environments the issue does not exist. but I don't see what triggers it. |
Original comment by Will S (Bitbucket: wsha, GitHub: wsha) I came across this ticket searching for information on using coverage.py with Qt's QThreads and PyQt (nothing else really came up). I think a QThread is totally different from a Python Thread because QThread is a Qt C++ class that PyQt is binding (but I haven't tried to understand how PyQt runs Python code from different QThreads). So I think the qsorder coverage issue is different from the example in the opening post. I am guessing there is no easy way for coverage.py to track code run in QThreads? Workarounds (for me) would be to refactor the application to have a single threaded testing mode or to use function-level tests for the functions that get run from QThreads. |
Hi @nedbat, I am facing the same issue as the previous comment. |
@hhslepicka I don't have a way to reproduce the problem. Can you provide me with instructions? I need specific code, environment (OS, versions, etc), and step-by-step instructions. |
@nedbat I will prepare and send you a link. Thank you for your attention. |
@nedbat here is a gist file for the test: Environment:
Dependencies:
Some useful information:
Documentation for QThread in case it is useful: http://doc.qt.io/qt-5/qthread.html Just let me know if you need additional info from my system. |
Thanks, this reproduces the issue. I have to learn more about what tools are available in Qt for hooking the creation of threads to enable coverage. Do you have any idea? |
BTW, this is the content of the gist:
|
Asked on the PyQt list: Any way to run code before each QThread?. From there: an example of monkey-patching QThread to add debugging support: http://die-offenbachs.homelinux.org:48888/hg/eric/file/87b1626eb49b/DebugClients/Python/ThreadExtension.py#l361 |
Thank you for the follow up @nedbat . |
@hhslepicka I haven't tried this at all. I think the best approach would be to write a plugin for coverage that would apply the QThread monkeypatch at startup. Is that something you can take a stab at? |
@nedbat sure! I will take a look at that... do you happen to have some sort of guide/docs/sample for me to take a look? |
Found it in here: https://coverage.readthedocs.io/en/latest/api_plugin.html#api-plugin |
@hhslepicka Right. This is an unusual use case, since you don't need any events, just some code to run at startup. BTW: i'd like to make plugins use real entry points so that users can just install them without having to change their configuration file, but that is in the future. Let me know if you make any progress on it. |
@nedbat sounds good! I will send an update next week... |
Hello @nedbat
the problem seems to be reproducible here without adding the complexity of QT. Please let me know if can do anything to help debug. |
@k3it Thanks, but it still doesn't happen for me. I am on Mac 10.13.6, with Python 3.6.6, and coverage 4.5.1. How are you running it? |
this time it was under anaconda virtual env on windows 10 Python 3.6.5 :: Anaconda, Inc. |
@k3it can you show the output of "coverage report -m" so we can see what lines are missed? |
also here is the annotated file
|
@hhslepicka Would you do me a favor and write a new issue about the QThread problem? it's clearly separate from the original report here. |
Sure! 👍
…On Thu, Jul 26, 2018 at 6:39 PM Ned Batchelder ***@***.***> wrote:
@hhslepicka <https://github.com/hhslepicka> Would you do me a favor and
write a new issue about the QThread problem? it's clearly separate from the
original report here.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#582 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AHzmUS4Yyr_N4VryeqMp8YHX5iAmn1XCks5uKm9AgaJpZM4VMGfA>
.
|
The original issue I ran into was with QT threads coverage just like @hhslepicka . they must be at least related.. :) I noticed that missed lines are reported when the parent "main" threads finish first, followed by the three "nested" threads.. But if at least one nested thread gets a chance to run ahead of the main thread, then the coverage is correct. ie it is very timing dependent. seems like a non thread safe structure is being overwritten somewhere. Edit: adding a |
@k3it, is there any reason why you can’t .join the Threads and only finish
execution when they all finish?
…On Thu, Jul 26, 2018 at 8:35 PM k3it ***@***.***> wrote:
The original issue I ran into was with QT threads coverage just like
@hhslepicka <https://github.com/hhslepicka> . they must be at least
related.. :)
I noticed that missed lines are reported when the parent "main" threads
finish first, followed by the three "nested" threads.. But if at least one
nested thread gets a chance to run ahead of the main thread, then the
coverage is correct. ie it is very timing dependent. seems like a non
thread safe structure is being overwritten somewhere.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#582 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AHzmUVGrxSy_hSRADa5_JIy04KDtRr3lks5uKop2gaJpZM4VMGfA>
.
|
@k3it The QThread issue is that measurement is never started on QThreads. You can see that all of the lines that run in the thread are reported as missing. That problem is easily reproduced. The original problem looks like a race condition, since it appears differently even for different runs by the same person. I don't understand exactly what is going wrong, but it does seem like joining the threads to remove race conditions might fix it. Can you give that a try? |
not sure if I can use join. would join serialize execution and make the parent thread block? wonder if adding time.sleep as above makes the problem reproducible on your mac. |
@k3it Adding the sleep does show the problem, but adding join() fixes the problem. I'm using this code:
I think starting threads and not joining them is a mistake: it causes a race condition that makes it impossible to know that the thread has completed. |
I don't believe not using join is a mistake . in the real code "MyThread" monitors for an external event (arrival of a particular UDP packet) and dispatches a child thread for execution. The child thread then lives its own life. The next trigger for a new thread may and does often arrive before the previous child thread(s) have finished running. Putting a join there would totally break this logic. I believe join is used when threads have some sort of dependency and need to be serialized, but it's not the case here. |
OK. Another way to fix the problem is to add |
@nedbat this program runs in a loop and never exists, until keyboard interrupted or killed. Any remaining worker thread would die with the main process in that case. Each worker usually runs for 45 seconds and there could be more than one running at the same time. They are scheduled with the python thread Timer mechanism. but I don't mean to distract with the discussion of what my code does :). I was just thinking this problem may help with resolving some type of thread safety issue within coverall... |
@k3it I'm not trying to pester you about how your code works. I'm trying to understand the heart of the problem. So I have to ask you more about the code in which you've experienced the problem. Coverage only writes its data at the exit of the program. But your program never exits. How are you recording the coverage? |
@nedbat at the end of each unit tests a special 'deadbeef' UDP packet is being sent which makes the main thread (and the whole program) exit instead of spawning another child thread. I think the code boils down to the example posted here if you remove all of the non-relevant parts .. |
@k3it I see, thanks. It sounds like you have a race condition: when the UDP packet arrives, the main program is ending before the worker thread is completely finished. Can you add synchronization to ensure that doesn't happen? |
It's possible for MyThread to exit before MyNestedThread but it's not possible for the entire program to quit with some thread still hanging out there, since threads are part of the main process In the QT app I'm calling QCoreApplication::Quit method which I believe waits for all threads to exit. |
@k3it the examples you showed earlier were not using QT. But it sounds like your real application is? If you could give me a reproducible example that we can agree on, it would make this a lot easier. |
If this is still a problem, and you can provide more information, feel free to re-open the issue. |
Hi, I found this thread when looking for a solution to a problem I wrote up here. I am also having trouble measuring coverage in threads. I do |
Threads won't be measured unless you specify them as part of your concurrency setting:
|
This adds some basic tests to cover the sub-widgets that make up the main data portal widget. Note that coverage likely doesn't cover lines that are run via QThreads, which explains some of the uncovered lines: nedbat/coveragepy#582 (comment) This also removes the preview widget, which isn't being actively used, and ignores coverage of test code itself.
Originally reported by k3it (Bitbucket: k3it, GitHub: k3it)
I apologize for a cross post from http://stackoverflow.com/q/43991865/1653558 but it looks like this is a better place for the report
I'm getting some low coverage numbers on script with threads activated with a run() method. It seems that the coverage module is unable to keep track of all hits. Here is the code that demonstrates the problem. Running it should produce 100% coverage, but I'm getting 71.
re-running 'coverage run foo.py' sometimes gives a different %, and even 100% on occasion.
The text was updated successfully, but these errors were encountered: