Qt or PyQt - check when file is used by another process. Wait until finish copy - qt

Good morning,
What is the best strategy for check when a big file o big directory has finished to copy?
I want wait until a file has finish fully to copy. Is there a code example in q
I'm working on mac os x.
thanks
Update
I use QFileSystemWatcher. the problem is that I receive file or directory change notification when o copy it is in progress. So user copy a big folder (inside many files), the operating system copy process start, it take 5 minuts, but in same times my application receive file changed notification. This is a problem because when i receive a change notification my application start for doing some operations on that files, but the copy is already in progress!!!!

There is only one reliable way to do this: Change the copy process to write to temporary files and then rename them after the copy is finished.
That way, you can ignore new files which end with .tmp and rename is an atomic operation.
If you can't change the copy process, all you can do is add a timer to wait for, say, half an hour to make sure the copy is really finished.
A more fine grained (and more risky) approach is to add a loop that check the file size and stops when the file size doesn't change for a certain time but that's also hard to get right.
Worse, this doesn't prevent you from reading partial files (when the copy process was terminated in the middle).

I think that the QFileSystemWatcher is the right start for you to get to the point of monitoring for changes, but as you have found, these changes are ANY changes. From this point, I think it should be easy enough for you to just check the modification time of the file.
Here is a simple example of a Watcher class that will let you specify a file to monitor and see if it has been modified after a given time. It can run a callback or emit a signal that anyone can watch:
import os.path
import time
from PyQt4 import QtCore
class Watcher(QtCore.QObject):
fileNotModified = QtCore.pyqtSignal(str)
MOD_TIME_DIFF = 5 #seconds
def __init__(self, aFile, callback=None, checkEvery=5):
super(Watcher, self).__init__()
self.file = aFile
self.callback = callback
self._timer = QtCore.QTimer(self)
self._timer.setInterval(checkEvery*1000)
self._timer.timeout.connect(self._checkFile)
def _checkFile(self):
diff = time.time() - os.path.getmtime(self.file)
if diff > self.MOD_TIME_DIFF:
self._timer.stop()
self.fileNotModified.emit(self.file)
if self.callback:
self.callback()
def start(self):
self._timer.start()
def stop(self):
self._timer.stop()
An example of using it:
def callbackNotify():
print "Callback!"
def signalNotify(f):
print "Signal: %s was modified!" % f
# You could directly give it a callback
watcher = Watcher("/path/to/file.file", callback=callbackNotify)
# Or could use a signal
watcher.fileNotModified.connect(signalNotify)
# tell the watcher timer to start checking
watcher.start()
## after the file hasnt been modified in 5 seconds ##
# Signal: /path/to/file.file was modified!
# Callback!

Try using QtConcurrent framework.
In particular, check out QFuture and QFutureWatcher. You can execute asynchronous copy operations inside a QFuture object and monitor its progress through signals and slots with a watcher.
bool copyFunction() {
// copy operations here, return true on success
}
MyHandlerClass myObject;
QFutureWatcher<bool> watcher;
connect(&watcher, SIGNAL(finished()), &myObject, SLOT(handleFinished()));
QFuture<bool> future = QtConcurrent::run(copyFunction);

Since you have no control on the external application, my suggestion is that you lock the files while you work on them. In this way other programs will not be able to access them while locked.
Alternatively, if you have access to the other program's source, you should implement some form of inter process communication,via sockets, messages or whatever method you prefer.

Related

WatchOS Background URLSession handle(_:) not called when app is not closed (lowered wrist)

I'm trying to create a Watch-App where I download data (around 30 MB).
Therefore I create a URLSession with a background configuration like so:
let config = URLSessionConfiguration.background(withIdentifier: "<some-id>")
self.session = URLSession(configuration: config, delegate: self, delegateQueue: .main)
and then start the download:
let request = URLRequest(url: "<some-url>", method: .GET)
self.task = session.downloadTask(with: request)
self.task.resume()
Since the user is not gonna stare at the watch for 5 minutes, I want to notify him with some haptic feedback when the download finished.
Therefore I wanted to use the handle(_:) function of the ExtensionDelegate. According to the documentation, this should be called with a WKURLSessionRefreshBackgroundTask when the download finished:
The system creates a background URLSession task when any of the following events occur:
Authentication is required to complete a background transfer.
All background transfers associated with a session identifier have completed (either successfully or unsuccessfully). https://developer.apple.com/documentation/watchkit/wkurlsessionrefreshbackgroundtask
This handle(_:) method is only called if I close my app though (pressing the crown), not when i lower my wrist to lock the screen.
I also noticed, that if I look at the watch again, the callbacks for urlSession(.. didWriteData ..) are not working anymore.
Am I missing something or is this even expected behaviour? I'm testing on a real Apple-Watch Series 4 with WatchOS 5 installed.

Mocking datetime.now() midway through a unittest.TestCase in Python 2.7

I'm trying to test a bit of debouncing logic - these are local unittests I run for a Google App Engine webapp, using the 2.7 runtime environment. All my other tests are going well but this one has me stumped!
def testThat_emailDebouncingWorks(self):
# Do something, it triggers an email.
doSomething()
self.assertEqual(emails_sent, 1)
# Do something again, the new email is debounced.
doSomething()
self.assertEqual(emails_sent, 1)
# After an hour, the emails should start working again...
mockWaitingAnHour()
doSomething()
self.assertEqual(emails_sent, 2)
# ... and so should the debouncing.
doSomething()
self.assertEqual(emails_sent, 2)
The file under test logs the time an email was sent using datetime.now(), then reruns datetime.now() on all future attempts and returns early if under an hour has elapsed.
There are two things going wrong:
I think the unittest library only added mock support in 3.X, and I'm not keen on updating my whole app.
Even if I was using 3.X, all the examples I see are about faking a datetime response for your entire test case (using a mock decorator above the test def). Whereas I want to change that behaviour midway through my test, not for the entire case.
Any tips? Thanks in advance!
Okay, I got to the bottom of it and wanted to document the answers for anyone who finds this on Google ;)
1. Enable mocking on AppEngine for Python 2.7
You need to follow the instructions for copying a third party library (in our case, "mock") from the official docs. It's worth noting that on Ubuntu, the suggested command:
pip install -t lib/ mock
Will fail. You'll get an error like this:
DistutilsOptionError: can't combine user with prefix, exec_prefix/home, or install_(plat)base
This is to do with a weird conflict with Ubuntu which seems to have gone unfixed for years, and you'll see a lot of people suggesting a virtualenv workaround. I added the --system flag instead:
pip install --system -t lib/ mock
and it worked fine. Remember to follow the rest of the instructions with appengine_config, and you should be set. "import mock" is a good way to check.
2. Mocking the datetime.now() call
My module under test uses:
from datetime import datetime
In my test module, import some stuff:
from mock import patch, Mock
import my_module #Also known as my_module.py
import datetime
Then the actual test case:
#patch.object(my_module, 'datetime', Mock(wraps=datetime.datetime))
def testThat_myModule_debouncesEmails(self):
fake_time = datetime.datetime.now()
# This is the first time the thing happened. It should send an email.
doSomething()
self.assertEqual(1, emails_sent)
# Five minutes later, the thing happens again. Should be debounced.
fake_time += datetime.timedelta(minutes=5)
my_module.datetime.now.return_value = fake_time
doSomething()
self.assertEqual(1, emails_sent)
# Another 56 minutes pass, the thing happens again. An hour has elapsed, so don't debounce.
fake_time += datetime.timedelta(minutes=56)
my_module.datetime.now.return_value = fake_time
doSomething()
self.assertEqual(2, emails_sent)
# Give it another 15 minutes to check the debouncing kicks back in.
fake_time += datetime.timedelta(minutes=15)
my_module.datetime.now.return_value = fake_time
doSomething()
self.assertEqual(2, emails_sent)
Hope this helps someone!

System.Io.Directory::GetFiles() Polling from AX 2009, Only Seeing New Files Every 10s

I wrote code in AX 2009 to poll a directory on a network drive, every 1 second, waiting for a response file from another system. I noticed that using a file explorer window, I could see the file appear, yet my code was not seeing and processing the file for several seconds - up to 9 seconds (and 9 polls) after the file appeared!
The AX code calls System.IO.Directory::GetFiles() using ClrInterop:
interopPerm = new InteropPermission(InteropKind::ClrInterop);
interopPerm.assert();
files = System.IO.Directory::GetFiles(#POLLDIR,'*.csv');
// etc...
CodeAccessPermission::revertAssert();
After much experimentation, it emerges that the first time in my program's lifetime, that I call ::GetFiles(), it starts a notional "ticking clock" with a period of 10 seconds. Only calls every 10 seconds find any new files that may have appeared, though they do still report files that were found on an earlier 10s "tick" since the first call to ::GetFiles().
If, when I start the program, the file is not there, then all the other calls to ::GetFiles(), 1 second after the first call, 2 seconds after, etc., up to 9 seconds after, simply do not see the file, even though it may have sitting there since 0.5s after the first call!
Then, reliably, and repeatably, the call 10s after the first call, will find the file. Then no calls from 11s to 19s will see any new file that might have appeared, yet the call 20s after the first call, will reliably see any new files. And so on, every 10 seconds.
Further investigation revealed that if the polled directory is on the AX AOS machine, this does not happen, and the file is found immediately, as one would expect, on the call after the file appears in the directory.
But this figure of 10s is reliable and repeatable, no matter what network drive I poll, no matter what server it's on.
Our network certainly doesn't have 10s of latency to see files; as I said, a file explorer window on the polled directory sees the file immediately.
What is going on?
Sounds like your issue is due to SMB caching - from this technet page:
Name, type, and ID
Directory Cache [DWORD] DirectoryCacheLifetime
Registry key the cache setting is controlled by
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Lanmanworkstation\Parameters
This is a cache of recent directory enumerations performed by the
client. Subsequent enumeration requests made by client applications as
well as metadata queries for files in the directory can be satisfied
from the cache. The client also uses the directory cache to determine
the presence or absence of a file in the directory and uses that
information to prevent clients from repeatedly attempting to open
files which are known not to exist on the server. This cache is likely
to affect distributed applications running on multiple computers
accessing a set of files on a server – where the applications use an
out of band mechanism to signal each other about
modification/addition/deletion of files on the server.
In short try to set the registry key
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Lanmanworkstation\Parameters\DirectoryCacheLifetime
to 0
Thanks to #Jan B. Kjeldsen , I have been able to solve my problem using FileSystemWatcher. Here is my implementation in X++ :
class SelTestThreadDirPolling
{
}
public server static Container SetStaticFileWatcher(str _dirPath,str _filenamePattern,int _timeoutMs)
{
InteropPermission interopPerm;
System.IO.FileSystemWatcher fw;
System.IO.WatcherChangeTypes watcherChangeType;
System.IO.WaitForChangedResult res;
Container cont;
str fileName;
str oldFileName;
str changeType;
;
interopPerm = new InteropPermission(InteropKind::ClrInterop);
interopPerm.assert();
fw = new System.IO.FileSystemWatcher();
fw.set_Path(_dirPath);
fw.set_IncludeSubdirectories(false);
fw.set_Filter(_filenamePattern);
watcherChangeType = ClrInterop::parseClrEnum('System.IO.WatcherChangeTypes', 'Created');
res = fw.WaitForChanged(watcherChangeType,_timeoutMs);
if (res.get_TimedOut()) return conNull();
fileName = res.get_Name();
//ChangeTypeName can be: Created, Deleted, Renamed and Changed
changeType = System.Enum::GetName(watcherChangeType.GetType(), res.get_ChangeType());
fw.Dispose();
CodeAccessPermission::revertAssert();
if (changeType == 'Renamed') oldFileName = res.get_OldName();
cont += fileName;
cont += changeType;
cont += oldFileName;
return cont;
}
void waitFileSystemWatcher(str _dirPath,str _filenamePattern,int _timeoutMs)
{
container cResult;
str filename,changeType,oldFilename;
;
cResult=SelTestThreadDirPolling::SetStaticFileWatcher(_dirPath,_filenamePattern,_timeoutMs);
if (cResult)
{
[filename,changeType,oldFilename]=cResult;
info(strfmt("filename=%1, changeType=%2, oldFilename=%3",filename,changeType,oldFilename));
}
else
{
info("TIMED OUT");
}
}
void run()
{;
this.waitFileSystemWatcher(#'\\myserver\mydir','filepattern*.csv',10000);
}
I should acknowledge the following for forming the basis of my X++ implementation:
https://blogs.msdn.microsoft.com/floditt/2008/09/01/how-to-implement-filesystemwatcher-with-x/
I would guess DAXaholic's answer is correct, but you could try other solutions like EnumerateFiles.
In your case I would rather wait for the files rather than poll for the files.
Using FileSystemWatcher there will be a minimal delay from file creation till your process wakes up. It is more tricky to use, but avoiding polling is a good thing. I have never used it over a network.

PyQt5 QtMultimedia

So I'm trying to create a GUI that searches a dictionary for a word, returns the entries and suggestions and downloads the audio, returning "related words" (sometimes more than one) that have audio. Then, the user clicks on one of three buttons to play the audio, based on the dialect. I can get the words to play, but I can't get the last played one to close so I can download another.
Here is the relevant code:
#staticmethod
def munster():
""" This method plays the Munster recording, if it exists"""
url = QtCore.QUrl.fromLocalFile("./CanM.mp3")
content = QtMultimedia.QMediaContent(url)
player = QtMultimedia.QMediaPlayer()
player.setMedia(content)
player.play()
player.stateChanged(app.quit)
When it gets to the last line it gives me this error:
TypeError: native Qt signal is not callable
Is there any way to close the player to allow downloading of another audio file with the same name?
For the record, I'm using the latest release of PyQt5, and Qt5.4 on Python 3.4 with Windows 81. However, I'm also working on this project (with the same Qt and PyQt) on an Archlinux system as well, and would like it to be portable easily.
Edit: Quite easy, once I started looking at what all was contained within the Player class. Just needed to use the disconnect method.
Edit2: Edited to show complete working code
#staticmethod
def play_audio(dialect):
file_names = {'Munster': './CanM.mp3', 'Connacht': './CanC.mp3', 'Ulster': './CanU.mp3'}
url = QtCore.QUrl.fromLocalFile(os.path.abspath(file_names[dialect]))
content = QtMultimedia.QMediaContent(url)
player = QtMultimedia.QMediaPlayer()
player.setMedia(content)
player.play()
player.stateChanged.connect(lambda: player.disconnect())

Asterisk: Record application is generating empty files

User making the call is asked to dial an extension. This is done by 1#playing a prompt with Background and then 2#wait_for_digit. Based on the extension that has been dialed, the destination number is determined and the call is forwarded to that number.
If the called person doesn't not answer, then Playback is used to play a prompt that asks the user to record the voice message; recording the voice message is done with the Record application.
This Record application is always generating empty wav files, size 44 bytes. If I remove the 1#playing a prompt with Background the Record application is generating proper files. If the Background is included, all recordings are empty.
I am using Perl Asterisk::AGI module.
$agi->exec('Answer');
....
.....
$agi->exec('Background', 'en/extra/please-enter-the-extension,n'); # this is the troubling part
my $my_extension = $agi->wait_for_digit(5000);
....
.....
$agi->exec('Playback', 'en/extra/the-party-you-are-calling&en/extra/is-curntly-busy,noanswer');
$agi->exec('Playback', 'en/vm-intro,noanswer');
my $file = 'xyz.wav';
$agi->exec('Record', "$file,0,10,k");
...
...
What should I do to make it work as I want it to?
Thank you.
UPDATE 1:
The same script is working without glitches now. Not sure if something unrelated to the script has changed.
Most likly you have check your codecs. IF you use g729 or g723 and no transcoder,it just can't write in wav format.

Resources