Usage

Modules that simplifies management of file URIs stored in metadata.

Invenio-Documents is an integration layer between pyfilesystem and Invenio-Records libraries. It handles URIs stored in JSON metadata specified using jsonpointer.

Documents proxy following operations:

  • open: for working with file handler.
  • setcontents: given a source file write its content.
  • move, copy, remove: simple proxies for standard file operations while keeping the stored URI updated.

Initialization

First create a Flask application (Flask-CLI is not needed for Flask version 1.0+):

>>> from flask import Flask
>>> from flask_cli import FlaskCLI
>>> app = Flask('myapp')
>>> app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
>>> ext_cli = FlaskCLI(app)

You initialize Documents like a normal Flask extension, however Invenio-Documents depends on Invenio-Records which also depends on Invenio-DB so you need to initialize following extensions:

>>> from invenio_db import InvenioDB
>>> from invenio_records import InvenioRecords
>>> from invenio_documents import InvenioDocuments
>>> ext_db = InvenioDB(app)
>>> ext_records = InvenioRecords(app)
>>> ext_documents = InvenioDocuments(app)

In order for the following examples to work, you need to work within an Flask application context so let’s push one:

>>> ctx = app.app_context()
>>> ctx.push()

Also, for the examples to work we need to create the database and tables (note, in this example we use an in-memory SQLite database):

>>> from invenio_db import db
>>> db.create_all()

Document

Document provides easy access to a file handler stored as URI inside a record metadata.

The example will work with following metadata record:

>>> from invenio_records.api import Record
>>> record = Record.create(
... {'title': 'Test', 'files': [{'uri': '/tmp/hello.txt'}]})

Creating Documents

First we need the pointer to URI stored in the metadata.

>>> uri_pointer = '/files/0/uri'

With given the uri_pointer we can instantiate a Document class and write something to it.

>>> from invenio_documents.api import Document
>>> document = Document(record, uri_pointer)
>>> hello = document.open('wb+')
>>> assert hello.write(b'Hello world!') == 12
>>> hello.close()
>>> assert open('/tmp/hello.txt').read() == 'Hello world!'

Copying Documents

You can simply copy the file by providing destination URI that can be handled by pyfilesystem library. The copy method will return a JSON patch with new destination of the file that can be applied to original record metadata.

>>> import os
>>> patch = document.copy('/tmp/hello_copy.txt')
>>> assert os.path.exists('/tmp/hello_copy.txt')
>>> record_copy = record.patch(patch).commit()
>>> document_copy = Document(record_copy, uri_pointer)
>>> assert document_copy.uri == '/tmp/hello_copy.txt'

Moving Documents

It is preferable to use copy method instead of move because it is easier to recover for filesystem errors without modifying record metadata.

>>> document_copy.move('/tmp/hello_move.txt')
>>> assert document_copy.uri == '/tmp/hello_move.txt'
>>> assert not os.path.exists('/tmp/hello_copy.txt')
>>> assert os.path.exists('/tmp/hello_move.txt')
>>> record_copy['files'][0]['uri']
'/tmp/hello_move.txt'

Removing Documents

>>> document_copy.remove(force=True)
>>> record_copy['files'][0]['uri']
>>> assert not os.path.exists('/tmp/hello_move.txt')
>>> os.remove('/tmp/hello.txt')