SoftBank Robotics documentation What's new in NAOqi 2.8?

qicore.File

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.

Summary

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.

Reference

See qi::File C++ API for complete API reference.

Detailed Usage Description

The following examples are partial for clarity. For a complete working example, see section Complete example : Alice’s Image Store Service.

Opening a file in read-only mode for sharing access

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.

File access lifetime

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.

Request or provide read-only access to the content of a file

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.
      # ...

Make a local copy of a provided file

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)

Observe the progression of a file copy, transfer or other long operations

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.

Complete example : Alice’s Image Store Service

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.

ImageStore

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.

ImageStore User Code

Meanwhile, Bob wrote his application to acquire Alice’s ImageStore instance, then do some basic work with it.

Full Sources

imagestore.py:

file_example.py: