Import:
import qi
app = qi.Application() # qi.Application must be instantiated first
qicore = qi.module("qicore") # Load and import the qicore module
See qi.Module API and qi.Application API documentation for more details about importing modules.
Note: In the following code examples, this previous import code sample is assumed to prefix the example code. For a complete working example, see Complete example : Alice’s Image Store Service.
File
provides a way to open a file in read-only mode on the local file system
and share the content of this file with potentially remote services.
We provide algorithms to copy a remote file’s content to make a local copy of it,
using the copyToLocal
function or FileCopyToLocal
type.
See qi::File C++ API for complete API reference.
The following examples are partial for clarity. For a complete working example, see section Complete example : Alice’s Image Store Service.
Once qicore module is loaded, use openLocalFile
to open the file in sharing read-only mode:
file = qicore.openLocalFile("valid/path/to/file.ext")
In this example, the file
object can be passed to a service API requesting a File
,
making the content of the file available to the service even if remote.
If the file does not exist, an exception will be thrown.
The lifetime of the file access is extended by the shared ownership between all
the File
, even if the instance is remote.
The File
object is kept alive and the file access open by default until
all File
objects referring owning it are destroyed.
The file access is automatically closed when File
is destroyed.
Once you don’t need it anymore and want to explicitly stop owning the access, you can stop referencing the file access. The file access will be closed if there is no other owner still using it.
def someServiceOperation(file):
# Do some work with file...
# No need to work with the file anymore.
del file # From now on, `file` is not usable anymore.
# If we were the only one accessing this file,
# access to it's content is now closed.
A service can request read-only access to the content of a file by using
File
as argument.
Similarly, a service can provide read-only access to a file by having
a function return a File
.
For example (after loading qicore module):
class MyService:
#...
# Store a copy of the provided file, associated with the provided name.
def storeFile(fileToStore, name):
#...
# Provide access to a stored file found by name.
def getFile(name):
#...
#...
(This is a partial example, see Complete example : Alice’s Image Store Service for complete working examples.)
In this example, the user of the service can provide access to a file this way:
def backup(name, pathFileToStore):
service = app.session.service('MyService')
file = qicore.openLocalFile(pathFileToStore)
# Now we can share reading access to this file.
service.storeFile(file, name)
# At this point, the service have a copy of the file and can start to work with it.
and acquire access to a file content provided by the service this way:
def restore(name): # service is a MyService instance
service = app.session.service('MyService')
# Get Access to the file.
file = service.getFile(name)
if file:
# Then work with the file content.
# ...
We can use the copyToLocal
function to make a local copy of the file provided
through a File
.
The copyToLocal
function will transfer a copy of the content of the file to the
local file system, even if the original file is on a remote file system.
For example, if we want a service function to make a full copy of a provided file, in a local temporary location, before doing any more work (after loading qicore module):
class MyService:
#...
def storeFile(fileToStore, name): # fileToStore is a qicore.File instance
# First, make a local copy in a temporary files directory:
tempFilePath = generateTemporaryFilePath()
qicore.copyToLocal(fileToStore, tempFilePath) # This call wait for the end of the copy.
# We now have a local copy of the remote file,
# we don't need the remote access anymore.
fileToStore = None
# Now we can work with the local copy of the file:
storeFileInDatabase(name, tempFilePath)
In the same way, we can provide access to the data of the file by returning a File
:
class MyService:
#...
def getFile(name):
fileLocation = findFileLocation(name)
if os.path.isfile(fileLocation):
# Now we can open it and provide it to the user for reading.
return qicore.openLocalFile(fileLocation)
# We didn't find the file!
return None
Then the user can retrieve a copy of the file and work with it:
def restore(service, name, fileLocation):
# Get access to the file.
file = service.getFile(name)
if file: # The file was found.
# We want to make a local copy before working on the file.
qicore.copyToLocal(file, fileLocation)
# We don't need the remote access anymore.
del file
# Now work on the file located at `fileLocation`.
workOnFile(fileLocation)
Potentially long file operations like copyToLocal
block until the end of the operation except if it is called with _async=True
as parameter
which will make the function return a qi.Future.
To wait for the end of the operation, we just wait for the future to be set (after loading qicore module):
def printFinished():
printf("File Transfer Finished!")
def fetchFile(file): # file is a qicore.File instance
temporaryFilePath = qi.makeTemporaryFilePath()
# We copy the file on a temporary work location on the local filesystem,
# but we don't wait for the transfer to end.
transfer = qicore.copyToLocal(file, temporaryFilePath) # transfer is a qi.Future
# We want to log the end of the transfer:
transfer.then(printFinished)
# Do some additional work while the file is transfered.
someAdditionalWork()
# Now we wait until the end of the operation if it's not finished yet.
transfer.wait() # Don't wait for futures in real code, you should use .then() instead.
del file
del transfer
workOnFile(temporaryFilePath)
(This is a partial example, see Complete example : Alice’s Image Store Service for complete working examples.)
In this example we want to be notified about the end of the operation, so we can connect a callback to the future. However, using only a future, we cannot get progress information about the transfer.
To get progress information and be able to connect callbacks to the different steps of the operation
before the operation starts,
we can use the FileCopyToLocal
type instead
of copyToLocal
function:
def printStatus(status): # see C++ API qi.FileOperation.Status for values
if status == 2: # Status_Finished
qi.info("File Transfer Finished!")
elif status == 3: # Status_Failed
qi.info("File Transfer Failed!")
elif status == 4: # Status_Canceled
qi.info("File Transfer Canceled!")
# We ignore the other status.
def printProgress(progress):
qi.info("#### File Transfer Progress = {0}%".format(progressValue * 100) )
def fetchFile(file): # file is a qicore.File instance
temporaryFilePath = makeTemporaryFilePath()
# Instead of launching the copy immediately, we prepare it by setting up
# the object which represent that operation.
fileCopy = qicore.FileCopyToLocal(file, temporaryFilePath)
# We extract the progress notifier associated with the operation.
notifier = fileCopy.notifier()
# We want to log the state changes of the transfer.
notifier.status.connect(printStatus)
# We also to log the progress of the transfer.
notifier.progress.connect(printProgress)
# We are ready to launch the copy now.
ft = fileCopy.start()
# Do some additional work while the file is transfered.
someAdditionalWork()
# Now we wait until the end of the operation if it's not finished yet.
ft.wait() # Don't wait for futures in real code, you should .connect()
# or its alternatives instead.
# We don't need the file access anymore.
del file
workOnFile(temporaryFilePath)
The FileCopyToLocal
type is an implementation
of FileOperation
which represents the copy/transfer
operation which is not started upon creation.
As this example demonstrates, the user can then plug callbacks to signals and properties provided
by ProgressNotifier
which is provided by
the FileOperation.notifier()
member function.
The user can then start the copy operation by calling the
FileOperation.start()
member function.
Similarly, the side of the code which opened the file and provided access to it can also follow
the progression of the on-going operations on the file by using
the File.operationProgress()
member function.
This function provides access to a ProgressNotifier
which is updated by the
current file operation on the file.
def printStatus(status) # as before
def printProgress(progress) # as before
def storeFile(service, name, pathToFileToStore):
file = qicore.openLocalFile(pathToFileToStore)
# Before sending the access to the file, connect progress logging callbacks.
copyProgress = file.operationProgress()
copyProgress.status.connect(printStatus)
copyProgress.progress.connect(printProgress)
# Now we can share reading access to this file.
service.storeFile(file, name)
# At this point, the service have a copy of the file and can start to work with it.
The following code samples are extracted from the complete example project located in the worktree at sdk/libqicore/libqicore/example/file/
In this example, Alice designs a service which provides storage for image files. Then Bob writes an application which accesses Alice’s image storage service and works with it.
Alice’s ImageStore service is simple and straightforward. It is very similar to the example code in previous sections.
In particular:
Note the File
usage which allows the user to provide access to a file,
or to acquire a stored file access. See api-py-file-import for importing qicore module.
To implement the store_image
function, Alice first acquires and copies the user file
in a temporary location, then does some work to register it in the store’s database.
This is of course a simpler implementation, similar to the get_image()
function implementation.
Meanwhile, Bob wrote his application to acquire Alice’s ImageStore instance, then do some basic work with it.