def create_blueprint(endpoints):
    """Create Invenio-Deposit-REST blueprint.

    See: :data:`invenio_deposit.config.DEPOSIT_REST_ENDPOINTS`.

    :param endpoints: List of endpoints configuration.
    :returns: The configured blueprint.
    """
    blueprint = Blueprint(
        'invenio_deposit_rest',
        __name__,
        url_prefix='',
    )
    create_error_handlers(blueprint)

    for endpoint, options in (endpoints or {}).items():
        options = deepcopy(options)

        if 'files_serializers' in options:
            files_serializers = options.get('files_serializers')
            files_serializers = {mime: obj_or_import_string(func)
                                 for mime, func in files_serializers.items()}
            del options['files_serializers']
        else:
            files_serializers = {}

        if 'record_serializers' in options:
            serializers = options.get('record_serializers')
            serializers = {mime: obj_or_import_string(func)
                           for mime, func in serializers.items()}
        else:
            serializers = {}

        file_list_route = options.pop(
            'file_list_route',
            '{0}/files'.format(options['item_route'])
        )
        file_item_route = options.pop(
            'file_item_route',
            '{0}/files/<path:key>'.format(options['item_route'])
        )

        options.setdefault('search_class', DepositSearch)
        search_class = obj_or_import_string(options['search_class'])

        # records rest endpoints will use the deposit class as record class
        options.setdefault('record_class', Deposit)
        record_class = obj_or_import_string(options['record_class'])

        # backward compatibility for indexer class
        options.setdefault('indexer_class', None)

        for rule in records_rest_url_rules(endpoint, **options):
            blueprint.add_url_rule(**rule)

        search_class_kwargs = {}
        if options.get('search_index'):
            search_class_kwargs['index'] = options['search_index']

        if options.get('search_type'):
            search_class_kwargs['doc_type'] = options['search_type']

        ctx = dict(
            read_permission_factory=obj_or_import_string(
                options.get('read_permission_factory_imp')
            ),
            create_permission_factory=obj_or_import_string(
                options.get('create_permission_factory_imp')
            ),
            update_permission_factory=obj_or_import_string(
                options.get('update_permission_factory_imp')
            ),
            delete_permission_factory=obj_or_import_string(
                options.get('delete_permission_factory_imp')
            ),
            record_class=record_class,
            search_class=partial(search_class, **search_class_kwargs),
            default_media_type=options.get('default_media_type'),
        )

        deposit_actions = DepositActionResource.as_view(
            DepositActionResource.view_name.format(endpoint),
            serializers=serializers,
            pid_type=options['pid_type'],
            ctx=ctx,
        )

        blueprint.add_url_rule(
            '{0}/actions/<any({1}):action>'.format(
                options['item_route'],
                ','.join(extract_actions_from_class(record_class)),
            ),
            view_func=deposit_actions,
            methods=['POST'],
        )

        deposit_files = DepositFilesResource.as_view(
            DepositFilesResource.view_name.format(endpoint),
            serializers=files_serializers,
            pid_type=options['pid_type'],
            ctx=ctx,
        )

        blueprint.add_url_rule(
            file_list_route,
            view_func=deposit_files,
            methods=['GET', 'POST', 'PUT'],
        )

        deposit_file = DepositFileResource.as_view(
            DepositFileResource.view_name.format(endpoint),
            serializers=files_serializers,
            pid_type=options['pid_type'],
            ctx=ctx,
        )

        blueprint.add_url_rule(
            file_item_route,
            view_func=deposit_file,
            methods=['GET', 'PUT', 'DELETE'],
        )
    return blueprint

def create_blueprint ( endpoints ) : blueprint = Blueprint ( 'invenio_deposit_rest' , __name__ , url_prefix = '' , ) create_error_handlers ( blueprint ) for endpoint , options in ( endpoints or { } ) . items ( ) : options = deepcopy ( options ) if 'files_serializers' in options : files_serializers = options . get ( 'files_serializers' ) files_serializers = { mime : obj_or_import_string ( func ) for mime , func in files_serializers . items ( ) } del options [ 'files_serializers' ] else : files_serializers = { } if 'record_serializers' in options : serializers = options . get ( 'record_serializers' ) serializers = { mime : obj_or_import_string ( func ) for mime , func in serializers . items ( ) } else : serializers = { } file_list_route = options . pop ( 'file_list_route' , '{0}/files' . format ( options [ 'item_route' ] ) ) file_item_route = options . pop ( 'file_item_route' , '{0}/files/<path:key>' . format ( options [ 'item_route' ] ) ) options . setdefault ( 'search_class' , DepositSearch ) search_class = obj_or_import_string ( options [ 'search_class' ] ) options . setdefault ( 'record_class' , Deposit ) record_class = obj_or_import_string ( options [ 'record_class' ] ) options . setdefault ( 'indexer_class' , None ) for rule in records_rest_url_rules ( endpoint , ** options ) : blueprint . add_url_rule ( ** rule ) search_class_kwargs = { } if options . get ( 'search_index' ) : search_class_kwargs [ 'index' ] = options [ 'search_index' ] if options . get ( 'search_type' ) : search_class_kwargs [ 'doc_type' ] = options [ 'search_type' ] ctx = dict ( read_permission_factory = obj_or_import_string ( options . get ( 'read_permission_factory_imp' ) ) , create_permission_factory = obj_or_import_string ( options . get ( 'create_permission_factory_imp' ) ) , update_permission_factory = obj_or_import_string ( options . get ( 'update_permission_factory_imp' ) ) , delete_permission_factory = obj_or_import_string ( options . get ( 'delete_permission_factory_imp' ) ) , record_class = record_class , search_class = partial ( search_class , ** search_class_kwargs ) , default_media_type = options . get ( 'default_media_type' ) , ) deposit_actions = DepositActionResource . as_view ( DepositActionResource . view_name . format ( endpoint ) , serializers = serializers , pid_type = options [ 'pid_type' ] , ctx = ctx , ) blueprint . add_url_rule ( '{0}/actions/<any({1}):action>' . format ( options [ 'item_route' ] , ',' . join ( extract_actions_from_class ( record_class ) ) , ) , view_func = deposit_actions , methods = [ 'POST' ] , ) deposit_files = DepositFilesResource . as_view ( DepositFilesResource . view_name . format ( endpoint ) , serializers = files_serializers , pid_type = options [ 'pid_type' ] , ctx = ctx , ) blueprint . add_url_rule ( file_list_route , view_func = deposit_files , methods = [ 'GET' , 'POST' , 'PUT' ] , ) deposit_file = DepositFileResource . as_view ( DepositFileResource . view_name . format ( endpoint ) , serializers = files_serializers , pid_type = options [ 'pid_type' ] , ctx = ctx , ) blueprint . add_url_rule ( file_item_route , view_func = deposit_file , methods = [ 'GET' , 'PUT' , 'DELETE' ] , ) return blueprint

Create Invenio - Deposit - REST blueprint .


def post(self, pid, record, action):
        """Handle deposit action.

        After the action is executed, a
        :class:`invenio_deposit.signals.post_action` signal is sent.

        Permission required: `update_permission_factory`.

        :param pid: Pid object (from url).
        :param record: Record object resolved from the pid.
        :param action: The action to execute.
        """
        record = getattr(record, action)(pid=pid)

        db.session.commit()
        # Refresh the PID and record metadata
        db.session.refresh(pid)
        db.session.refresh(record.model)
        post_action.send(current_app._get_current_object(), action=action,
                         pid=pid, deposit=record)
        response = self.make_response(pid, record,
                                      202 if action == 'publish' else 201)
        endpoint = '.{0}_item'.format(pid.pid_type)
        location = url_for(endpoint, pid_value=pid.pid_value, _external=True)
        response.headers.extend(dict(Location=location))
        return response

def post ( self , pid , record , action ) : record = getattr ( record , action ) ( pid = pid ) db . session . commit ( ) db . session . refresh ( pid ) db . session . refresh ( record . model ) post_action . send ( current_app . _get_current_object ( ) , action = action , pid = pid , deposit = record ) response = self . make_response ( pid , record , 202 if action == 'publish' else 201 ) endpoint = '.{0}_item' . format ( pid . pid_type ) location = url_for ( endpoint , pid_value = pid . pid_value , _external = True ) response . headers . extend ( dict ( Location = location ) ) return response


def get(self, pid, record):
        """Get files.

        Permission required: `read_permission_factory`.

        :param pid: Pid object (from url).
        :param record: Record object resolved from the pid.
        :returns: The files.
        """
        return self.make_response(obj=record.files, pid=pid, record=record)

def get ( self , pid , record ) : return self . make_response ( obj = record . files , pid = pid , record = record )


def post(self, pid, record):
        """Handle POST deposit files.

        Permission required: `update_permission_factory`.

        :param pid: Pid object (from url).
        :param record: Record object resolved from the pid.
        """
        # load the file
        uploaded_file = request.files['file']
        # file name
        key = secure_filename(
            request.form.get('name') or uploaded_file.filename
        )
        # check if already exists a file with this name
        if key in record.files:
            raise FileAlreadyExists()
        # add it to the deposit
        record.files[key] = uploaded_file.stream
        record.commit()
        db.session.commit()
        return self.make_response(
            obj=record.files[key].obj, pid=pid, record=record, status=201)

def post ( self , pid , record ) : uploaded_file = request . files [ 'file' ] key = secure_filename ( request . form . get ( 'name' ) or uploaded_file . filename ) if key in record . files : raise FileAlreadyExists ( ) record . files [ key ] = uploaded_file . stream record . commit ( ) db . session . commit ( ) return self . make_response ( obj = record . files [ key ] . obj , pid = pid , record = record , status = 201 )


def put(self, pid, record):
        """Handle the sort of the files through the PUT deposit files.

        Expected input in body PUT:

        .. code-block:: javascript

            [
                {
                    "id": 1
                },
                {
                    "id": 2
                },
                ...
            }

        Permission required: `update_permission_factory`.

        :param pid: Pid object (from url).
        :param record: Record object resolved from the pid.
        :returns: The files.
        """
        try:
            ids = [data['id'] for data in json.loads(
                request.data.decode('utf-8'))]
        except KeyError:
            raise WrongFile()

        record.files.sort_by(*ids)
        record.commit()
        db.session.commit()
        return self.make_response(obj=record.files, pid=pid, record=record)

def put ( self , pid , record ) : try : ids = [ data [ 'id' ] for data in json . loads ( request . data . decode ( 'utf-8' ) ) ] except KeyError : raise WrongFile ( ) record . files . sort_by ( * ids ) record . commit ( ) db . session . commit ( ) return self . make_response ( obj = record . files , pid = pid , record = record )

Handle the sort of the files through the PUT deposit files .


def get(self, pid, record, key, version_id, **kwargs):
        """Get file.

        Permission required: `read_permission_factory`.

        :param pid: Pid object (from url).
        :param record: Record object resolved from the pid.
        :param key: Unique identifier for the file in the deposit.
        :param version_id: File version. Optional. If no version is provided,
            the last version is retrieved.
        :returns: the file content.
        """
        try:
            obj = record.files[str(key)].get_version(version_id=version_id)
            return self.make_response(
                obj=obj or abort(404), pid=pid, record=record)
        except KeyError:
            abort(404)

def get ( self , pid , record , key , version_id , ** kwargs ) : try : obj = record . files [ str ( key ) ] . get_version ( version_id = version_id ) return self . make_response ( obj = obj or abort ( 404 ) , pid = pid , record = record ) except KeyError : abort ( 404 )


def put(self, pid, record, key):
        """Handle the file rename through the PUT deposit file.

        Permission required: `update_permission_factory`.

        :param pid: Pid object (from url).
        :param record: Record object resolved from the pid.
        :param key: Unique identifier for the file in the deposit.
        """
        try:
            data = json.loads(request.data.decode('utf-8'))
            new_key = data['filename']
        except KeyError:
            raise WrongFile()
        new_key_secure = secure_filename(new_key)
        if not new_key_secure or new_key != new_key_secure:
            raise WrongFile()
        try:
            obj = record.files.rename(str(key), new_key_secure)
        except KeyError:
            abort(404)
        record.commit()
        db.session.commit()
        return self.make_response(obj=obj, pid=pid, record=record)

def put ( self , pid , record , key ) : try : data = json . loads ( request . data . decode ( 'utf-8' ) ) new_key = data [ 'filename' ] except KeyError : raise WrongFile ( ) new_key_secure = secure_filename ( new_key ) if not new_key_secure or new_key != new_key_secure : raise WrongFile ( ) try : obj = record . files . rename ( str ( key ) , new_key_secure ) except KeyError : abort ( 404 ) record . commit ( ) db . session . commit ( ) return self . make_response ( obj = obj , pid = pid , record = record )

Handle the file rename through the PUT deposit file .


def delete(self, pid, record, key):
        """Handle DELETE deposit file.

        Permission required: `update_permission_factory`.

        :param pid: Pid object (from url).
        :param record: Record object resolved from the pid.
        :param key: Unique identifier for the file in the deposit.
        """
        try:
            del record.files[str(key)]
            record.commit()
            db.session.commit()
            return make_response('', 204)
        except KeyError:
            abort(404, 'The specified object does not exist or has already '
                  'been deleted.')


def records():
    """Load records."""
    import pkg_resources
    from dojson.contrib.marc21 import marc21
    from dojson.contrib.marc21.utils import create_record, split_blob
    from flask_login import login_user, logout_user
    from invenio_accounts.models import User
    from invenio_deposit.api import Deposit

    users = User.query.all()

    # pkg resources the demodata
    data_path = pkg_resources.resource_filename(
        'invenio_records', 'data/marc21/bibliographic.xml'
    )
    with open(data_path) as source:
        with current_app.test_request_context():
            indexer = RecordIndexer()
            with db.session.begin_nested():
                for index, data in enumerate(split_blob(source.read()),
                                             start=1):
                    login_user(users[index % len(users)])
                    # do translate
                    record = marc21.do(create_record(data))
                    # create record
                    indexer.index(Deposit.create(record))
                    logout_user()
            db.session.commit()

def records ( ) : import pkg_resources from dojson . contrib . marc21 import marc21 from dojson . contrib . marc21 . utils import create_record , split_blob from flask_login import login_user , logout_user from invenio_accounts . models import User from invenio_deposit . api import Deposit users = User . query . all ( ) data_path = pkg_resources . resource_filename ( 'invenio_records' , 'data/marc21/bibliographic.xml' ) with open ( data_path ) as source : with current_app . test_request_context ( ) : indexer = RecordIndexer ( ) with db . session . begin_nested ( ) : for index , data in enumerate ( split_blob ( source . read ( ) ) , start = 1 ) : login_user ( users [ index % len ( users ) ] ) record = marc21 . do ( create_record ( data ) ) indexer . index ( Deposit . create ( record ) ) logout_user ( ) db . session . commit ( )


def location():
    """Load default location."""
    d = current_app.config['DATADIR']
    with db.session.begin_nested():
        Location.query.delete()
        loc = Location(name='local', uri=d, default=True)
        db.session.add(loc)
    db.session.commit()

def location ( ) : d = current_app . config [ 'DATADIR' ] with db . session . begin_nested ( ) : Location . query . delete ( ) loc = Location ( name = 'local' , uri = d , default = True ) db . session . add ( loc ) db . session . commit ( )


def jsonschemas(self):
        """Load deposit JSON schemas."""
        _jsonschemas = {
            k: v['jsonschema']
            for k, v in self.app.config['DEPOSIT_RECORDS_UI_ENDPOINTS'].items()
            if 'jsonschema' in v
        }
        return defaultdict(
            lambda: self.app.config['DEPOSIT_DEFAULT_JSONSCHEMA'], _jsonschemas
        )

def jsonschemas ( self ) : _jsonschemas = { k : v [ 'jsonschema' ] for k , v in self . app . config [ 'DEPOSIT_RECORDS_UI_ENDPOINTS' ] . items ( ) if 'jsonschema' in v } return defaultdict ( lambda : self . app . config [ 'DEPOSIT_DEFAULT_JSONSCHEMA' ] , _jsonschemas )


def schemaforms(self):
        """Load deposit schema forms."""
        _schemaforms = {
            k: v['schemaform']
            for k, v in self.app.config['DEPOSIT_RECORDS_UI_ENDPOINTS'].items()
            if 'schemaform' in v
        }
        return defaultdict(
            lambda: self.app.config['DEPOSIT_DEFAULT_SCHEMAFORM'], _schemaforms
        )

def schemaforms ( self ) : _schemaforms = { k : v [ 'schemaform' ] for k , v in self . app . config [ 'DEPOSIT_RECORDS_UI_ENDPOINTS' ] . items ( ) if 'schemaform' in v } return defaultdict ( lambda : self . app . config [ 'DEPOSIT_DEFAULT_SCHEMAFORM' ] , _schemaforms )


def deposit_links_factory(pid):
    """Factory for record links generation.

    The dictionary is formed as:

    .. code-block:: python

        {
            'files': '/url/to/files',
            'publish': '/url/to/publish',
            'edit': '/url/to/edit',
            'discard': '/url/to/discard',
            ...
        }

    :param pid: The record PID object.
    :returns: A dictionary that contains all the links.
    """
    links = default_links_factory(pid)

    def _url(name, **kwargs):
        """URL builder."""
        endpoint = '.{0}_{1}'.format(
            current_records_rest.default_endpoint_prefixes[pid.pid_type],
            name,
        )
        return url_for(endpoint, pid_value=pid.pid_value, _external=True,
                       **kwargs)

    links['files'] = _url('files')

    ui_endpoint = current_app.config.get('DEPOSIT_UI_ENDPOINT')
    if ui_endpoint is not None:
        links['html'] = ui_endpoint.format(
            host=request.host,
            scheme=request.scheme,
            pid_value=pid.pid_value,
        )

    deposit_cls = Deposit
    if 'pid_value' in request.view_args:
        deposit_cls = request.view_args['pid_value'].data[1].__class__

    for action in extract_actions_from_class(deposit_cls):
        links[action] = _url('actions', action=action)
    return links

def deposit_links_factory ( pid ) : links = default_links_factory ( pid ) def _url ( name , ** kwargs ) : endpoint = '.{0}_{1}' . format ( current_records_rest . default_endpoint_prefixes [ pid . pid_type ] , name , ) return url_for ( endpoint , pid_value = pid . pid_value , _external = True , ** kwargs ) links [ 'files' ] = _url ( 'files' ) ui_endpoint = current_app . config . get ( 'DEPOSIT_UI_ENDPOINT' ) if ui_endpoint is not None : links [ 'html' ] = ui_endpoint . format ( host = request . host , scheme = request . scheme , pid_value = pid . pid_value , ) deposit_cls = Deposit if 'pid_value' in request . view_args : deposit_cls = request . view_args [ 'pid_value' ] . data [ 1 ] . __class__ for action in extract_actions_from_class ( deposit_cls ) : links [ action ] = _url ( 'actions' , action = action ) return links


def process_minter(value):
    """Load minter from PIDStore registry based on given value.

    :param value: Name of the minter.
    :returns: The minter.
    """
    try:
        return current_pidstore.minters[value]
    except KeyError:
        raise click.BadParameter(
            'Unknown minter {0}. Please use one of {1}.'.format(
                value, ', '.join(current_pidstore.minters.keys())
            )
        )

Load minter from PIDStore registry based on given value .


def process_schema(value):
    """Load schema from JSONSchema registry based on given value.

    :param value: Schema path, relative to the directory when it was
        registered.
    :returns: The schema absolute path.
    """
    schemas = current_app.extensions['invenio-jsonschemas'].schemas
    try:
        return schemas[value]
    except KeyError:
        raise click.BadParameter(
            'Unknown schema {0}. Please use one of:\n {1}'.format(
                value, '\n'.join(schemas.keys())
            )
        )

Load schema from JSONSchema registry based on given value .


def json_serializer(pid, data, *args):
    """Build a JSON Flask response using the given data.

    :param pid: The `invenio_pidstore.models.PersistentIdentifier` of the
        record.
    :param data: The record metadata.
    :returns: A Flask response with JSON data.
    :rtype: :py:class:`flask.Response`.
    """
    if data is not None:
        response = Response(
            json.dumps(data.dumps()),
            mimetype='application/json'
        )
    else:
        response = Response(mimetype='application/json')
    return response

def json_serializer ( pid , data , * args ) : if data is not None : response = Response ( json . dumps ( data . dumps ( ) ) , mimetype = 'application/json' ) else : response = Response ( mimetype = 'application/json' ) return response

Build a JSON Flask response using the given data .


def file_serializer(obj):
    """Serialize a object.

    :param obj: A :class:`invenio_files_rest.models.ObjectVersion` instance.
    :returns: A dictionary with the fields to serialize.
    """
    return {
        "id": str(obj.file_id),
        "filename": obj.key,
        "filesize": obj.file.size,
        "checksum": obj.file.checksum,
    }

def file_serializer ( obj ) : return { "id" : str ( obj . file_id ) , "filename" : obj . key , "filesize" : obj . file . size , "checksum" : obj . file . checksum , }


def json_files_serializer(objs, status=None):
    """JSON Files Serializer.

    :parma objs: A list of:class:`invenio_files_rest.models.ObjectVersion`
        instances.
    :param status: A HTTP Status. (Default: ``None``)
    :returns: A Flask response with JSON data.
    :rtype: :py:class:`flask.Response`.
    """
    files = [file_serializer(obj) for obj in objs]
    return make_response(json.dumps(files), status)

def json_files_serializer ( objs , status = None ) : files = [ file_serializer ( obj ) for obj in objs ] return make_response ( json . dumps ( files ) , status )


def index_deposit_after_publish(sender, action=None, pid=None, deposit=None):
    """Index the record after publishing.

    .. note:: if the record is not published, it doesn't index.

    :param sender: Who send the signal.
    :param action: Action executed by the sender. (Default: ``None``)
    :param pid: PID object. (Default: ``None``)
    :param deposit: Deposit object. (Default: ``None``)
    """
    if action == 'publish':
        _, record = deposit.fetch_published()
        index_record.delay(str(record.id))

def index_deposit_after_publish ( sender , action = None , pid = None , deposit = None ) : if action == 'publish' : _ , record = deposit . fetch_published ( ) index_record . delay ( str ( record . id ) )


def index(method=None, delete=False):
    """Decorator to update index.

    :param method: Function wrapped. (Default: ``None``)
    :param delete: If `True` delete the indexed record. (Default: ``None``)
    """
    if method is None:
        return partial(index, delete=delete)

    @wraps(method)
    def wrapper(self_or_cls, *args, **kwargs):
        """Send record for indexing."""
        result = method(self_or_cls, *args, **kwargs)
        try:
            if delete:
                self_or_cls.indexer.delete(result)
            else:
                self_or_cls.indexer.index(result)
        except RequestError:
            current_app.logger.exception('Could not index {0}.'.format(result))
        return result
    return wrapper

def
index
(
method
=
,
delete
=
False
)
:
if
method
is
:
return
partial
(
index
,
delete
=
delete
)
@
wraps
(
method
)
def
wrapper
(
self_or_cls
,
*
args
,
**
kwargs
)
:
result
=
method
(
self_or_cls
,
*
args
,
**
kwargs
)
try
:
if
delete
:
self_or_cls
.
indexer
.
delete
(
result
)
else
:
self_or_cls
.
indexer
.
index
(
result
)
except
RequestError
:
current_app
.
logger
.
exception
(
'Could not index {0}.'
.
format
(
result
)
)
return
result
return
wrapper


def preserve(method=None, result=True, fields=None):
    """Preserve fields in deposit.

    :param method: Function to execute. (Default: ``None``)
    :param result: If `True` returns the result of method execution,
        otherwise `self`. (Default: ``True``)
    :param fields: List of fields to preserve (default: ``('_deposit',)``).
    """
    if method is None:
        return partial(preserve, result=result, fields=fields)

    fields = fields or ('_deposit', )

    @wraps(method)
    def wrapper(self, *args, **kwargs):
        """Check current deposit status."""
        data = {field: self[field] for field in fields if field in self}
        result_ = method(self, *args, **kwargs)
        replace = result_ if result else self
        for field in data:
            replace[field] = data[field]
        return result_
    return wrapper

def preserve ( method = None , result = True , fields = None ) : if method is None : return partial ( preserve , result = result , fields = fields ) fields = fields or ( '_deposit' , ) @ wraps ( method ) def wrapper ( self , * args , ** kwargs ) : data = { field : self [ field ] for field in fields if field in self } result_ = method ( self , * args , ** kwargs ) replace = result_ if result else self for field in data : replace [ field ] = data [ field ] return result_ return wrapper


def pid(self):
        """Return an instance of deposit PID."""
        pid = self.deposit_fetcher(self.id, self)
        return PersistentIdentifier.get(pid.pid_type,
                                        pid.pid_value)

def pid ( self ) : pid = self . deposit_fetcher ( self . id , self ) return PersistentIdentifier . get ( pid . pid_type , pid . pid_value )


def record_schema(self):
        """Convert deposit schema to a valid record schema."""
        schema_path = current_jsonschemas.url_to_path(self['$schema'])
        schema_prefix = current_app.config['DEPOSIT_JSONSCHEMAS_PREFIX']
        if schema_path and schema_path.startswith(schema_prefix):
            return current_jsonschemas.path_to_url(
                schema_path[len(schema_prefix):]
            )

def record_schema ( self ) : schema_path = current_jsonschemas . url_to_path ( self [ '$schema' ] ) schema_prefix = current_app . config [ 'DEPOSIT_JSONSCHEMAS_PREFIX' ] if schema_path and schema_path . startswith ( schema_prefix ) : return current_jsonschemas . path_to_url ( schema_path [ len ( schema_prefix ) : ] )

Convert deposit schema to a valid record schema .


def build_deposit_schema(self, record):
        """Convert record schema to a valid deposit schema.

        :param record: The record used to build deposit schema.
        :returns: The absolute URL to the schema or `None`.
        """
        schema_path = current_jsonschemas.url_to_path(record['$schema'])
        schema_prefix = current_app.config['DEPOSIT_JSONSCHEMAS_PREFIX']
        if schema_path:
            return current_jsonschemas.path_to_url(
                schema_prefix + schema_path
            )

def build_deposit_schema ( self , record ) : schema_path = current_jsonschemas . url_to_path ( record [ '$schema' ] ) schema_prefix = current_app . config [ 'DEPOSIT_JSONSCHEMAS_PREFIX' ] if schema_path : return current_jsonschemas . path_to_url ( schema_prefix + schema_path )

Convert record schema to a valid deposit schema .


def fetch_published(self):
        """Return a tuple with PID and published record."""
        pid_type = self['_deposit']['pid']['type']
        pid_value = self['_deposit']['pid']['value']

        resolver = Resolver(
            pid_type=pid_type, object_type='rec',
            getter=partial(self.published_record_class.get_record,
                           with_deleted=True)
        )
        return resolver.resolve(pid_value)

def fetch_published ( self ) : pid_type = self [ '_deposit' ] [ 'pid' ] [ 'type' ] pid_value = self [ '_deposit' ] [ 'pid' ] [ 'value' ] resolver = Resolver ( pid_type = pid_type , object_type = 'rec' , getter = partial ( self . published_record_class . get_record , with_deleted = True ) ) return resolver . resolve ( pid_value )

Return a tuple with PID and published record .


def merge_with_published(self):
        """Merge changes with latest published version."""
        pid, first = self.fetch_published()
        lca = first.revisions[self['_deposit']['pid']['revision_id']]
        # ignore _deposit and $schema field
        args = [lca.dumps(), first.dumps(), self.dumps()]
        for arg in args:
            del arg['$schema'], arg['_deposit']
        args.append({})
        m = Merger(*args)
        try:
            m.run()
        except UnresolvedConflictsException:
            raise MergeConflict()
        return patch(m.unified_patches, lca)

def merge_with_published ( self ) : pid , first = self . fetch_published ( ) lca = first . revisions [ self [ '_deposit' ] [ 'pid' ] [ 'revision_id' ] ] args = [ lca . dumps ( ) , first . dumps ( ) , self . dumps ( ) ] for arg in args : del arg [ '$schema' ] , arg [ '_deposit' ] args . append ( { } ) m = Merger ( * args ) try : m . run ( ) except UnresolvedConflictsException : raise MergeConflict ( ) return patch ( m . unified_patches , lca )

Merge changes with latest published version .


def commit(self, *args, **kwargs):
        """Store changes on current instance in database and index it."""
        return super(Deposit, self).commit(*args, **kwargs)

def commit ( self , * args , ** kwargs ) : return super ( Deposit , self ) . commit ( * args , ** kwargs )

Store changes on current instance in database and index it .


def create(cls, data, id_=None):
        """Create a deposit.

        Initialize the follow information inside the deposit:

        .. code-block:: python

            deposit['_deposit'] = {
                'id': pid_value,
                'status': 'draft',
                'owners': [user_id],
                'created_by': user_id,
            }

        The deposit index is updated.

        :param data: Input dictionary to fill the deposit.
        :param id_: Default uuid for the deposit.
        :returns: The new created deposit.
        """
        data.setdefault('$schema', current_jsonschemas.path_to_url(
            current_app.config['DEPOSIT_DEFAULT_JSONSCHEMA']
        ))
        if '_deposit' not in data:
            id_ = id_ or uuid.uuid4()
            cls.deposit_minter(id_, data)

        data['_deposit'].setdefault('owners', list())
        if current_user and current_user.is_authenticated:
            creator_id = int(current_user.get_id())

            if creator_id not in data['_deposit']['owners']:
                data['_deposit']['owners'].append(creator_id)

            data['_deposit']['created_by'] = creator_id

        return super(Deposit, cls).create(data, id_=id_)

def create ( cls , data , id_ = None ) : data . setdefault ( '$schema' , current_jsonschemas . path_to_url ( current_app . config [ 'DEPOSIT_DEFAULT_JSONSCHEMA' ] ) ) if '_deposit' not in data : id_ = id_ or uuid . uuid4 ( ) cls . deposit_minter ( id_ , data ) data [ '_deposit' ] . setdefault ( 'owners' , list ( ) ) if current_user and current_user . is_authenticated : creator_id = int ( current_user . get_id ( ) ) if creator_id not in data [ '_deposit' ] [ 'owners' ] : data [ '_deposit' ] [ 'owners' ] . append ( creator_id ) data [ '_deposit' ] [ 'created_by' ] = creator_id return super ( Deposit , cls ) . create ( data , id_ = id_ )


def _process_files(self, record_id, data):
        """Snapshot bucket and add files in record during first publishing."""
        if self.files:
            assert not self.files.bucket.locked
            self.files.bucket.locked = True
            snapshot = self.files.bucket.snapshot(lock=True)
            data['_files'] = self.files.dumps(bucket=snapshot.id)
            yield data
            db.session.add(RecordsBuckets(
                record_id=record_id, bucket_id=snapshot.id
            ))
        else:
            yield data

def _process_files ( self , record_id , data ) : if self . files : assert not self . files . bucket . locked self . files . bucket . locked = True snapshot = self . files . bucket . snapshot ( lock = True ) data [ '_files' ] = self . files . dumps ( bucket = snapshot . id ) yield data db . session . add ( RecordsBuckets ( record_id = record_id , bucket_id = snapshot . id ) ) else : yield data

Snapshot bucket and add files in record during first publishing .


def _publish_new(self, id_=None):
        """Publish new deposit.

        :param id_: The forced record UUID.
        """
        minter = current_pidstore.minters[
            current_app.config['DEPOSIT_PID_MINTER']
        ]
        id_ = id_ or uuid.uuid4()
        record_pid = minter(id_, self)

        self['_deposit']['pid'] = {
            'type': record_pid.pid_type,
            'value': record_pid.pid_value,
            'revision_id': 0,
        }

        data = dict(self.dumps())
        data['$schema'] = self.record_schema

        with self._process_files(id_, data):
            record = self.published_record_class.create(data, id_=id_)

        return record

def _publish_new ( self , id_ = None ) : minter = current_pidstore . minters [ current_app . config [ 'DEPOSIT_PID_MINTER' ] ] id_ = id_ or uuid . uuid4 ( ) record_pid = minter ( id_ , self ) self [ '_deposit' ] [ 'pid' ] = { 'type' : record_pid . pid_type , 'value' : record_pid . pid_value , 'revision_id' : 0 , } data = dict ( self . dumps ( ) ) data [ '$schema' ] = self . record_schema with self . _process_files ( id_ , data ) : record = self . published_record_class . create ( data , id_ = id_ ) return record


def _publish_edited(self):
        """Publish the deposit after for editing."""
        record_pid, record = self.fetch_published()
        if record.revision_id == self['_deposit']['pid']['revision_id']:
            data = dict(self.dumps())
        else:
            data = self.merge_with_published()

        data['$schema'] = self.record_schema
        data['_deposit'] = self['_deposit']
        record = record.__class__(data, model=record.model)
        return record

def _publish_edited ( self ) : record_pid , record = self . fetch_published ( ) if record . revision_id == self [ '_deposit' ] [ 'pid' ] [ 'revision_id' ] : data = dict ( self . dumps ( ) ) else : data = self . merge_with_published ( ) data [ '$schema' ] = self . record_schema data [ '_deposit' ] = self [ '_deposit' ] record = record . __class__ ( data , model = record . model ) return record


def publish(self, pid=None, id_=None):
        """Publish a deposit.

        If it's the first time:

        * it calls the minter and set the following meta information inside
            the deposit:

        .. code-block:: python

            deposit['_deposit'] = {
                'type': pid_type,
                'value': pid_value,
                'revision_id': 0,
            }

        * A dump of all information inside the deposit is done.

        * A snapshot of the files is done.

        Otherwise, published the new edited version.
        In this case, if in the mainwhile someone already published a new
        version, it'll try to merge the changes with the latest version.

        .. note:: no need for indexing as it calls `self.commit()`.

        Status required: ``'draft'``.

        :param pid: Force the new pid value. (Default: ``None``)
        :param id_: Force the new uuid value as deposit id. (Default: ``None``)
        :returns: Returns itself.
        """
        pid = pid or self.pid

        if not pid.is_registered():
            raise PIDInvalidAction()

        self['_deposit']['status'] = 'published'

        if self['_deposit'].get('pid') is None:  # First publishing
            self._publish_new(id_=id_)
        else:  # Update after edit
            record = self._publish_edited()
            record.commit()
        self.commit()
        return self

def publish ( self , pid = None , id_ = None ) : pid = pid or self . pid if not pid . is_registered ( ) : raise PIDInvalidAction ( ) self [ '_deposit' ] [ 'status' ] = 'published' if self [ '_deposit' ] . get ( 'pid' ) is None : self . _publish_new ( id_ = id_ ) else : record = self . _publish_edited ( ) record . commit ( ) self . commit ( ) return self


def _prepare_edit(self, record):
        """Update selected keys.

        :param record: The record to prepare.
        """
        data = record.dumps()
        # Keep current record revision for merging.
        data['_deposit']['pid']['revision_id'] = record.revision_id
        data['_deposit']['status'] = 'draft'
        data['$schema'] = self.build_deposit_schema(record)
        return data

def _prepare_edit ( self , record ) : data = record . dumps ( ) data [ '_deposit' ] [ 'pid' ] [ 'revision_id' ] = record . revision_id data [ '_deposit' ] [ 'status' ] = 'draft' data [ '$schema' ] = self . build_deposit_schema ( record ) return data


def edit(self, pid=None):
        """Edit deposit.

        #. The signal :data:`invenio_records.signals.before_record_update`
           is sent before the edit execution.

        #. The following meta information are saved inside the deposit:

        .. code-block:: python

            deposit['_deposit']['pid'] = record.revision_id
            deposit['_deposit']['status'] = 'draft'
            deposit['$schema'] = deposit_schema_from_record_schema

        #. The signal :data:`invenio_records.signals.after_record_update` is
            sent after the edit execution.

        #. The deposit index is updated.

        Status required: `published`.

        .. note:: the process fails if the pid has status
            :attr:`invenio_pidstore.models.PIDStatus.REGISTERED`.

        :param pid: Force a pid object. (Default: ``None``)
        :returns: A new Deposit object.
        """
        pid = pid or self.pid

        with db.session.begin_nested():
            before_record_update.send(
                current_app._get_current_object(), record=self)

            record_pid, record = self.fetch_published()
            assert PIDStatus.REGISTERED == record_pid.status
            assert record['_deposit'] == self['_deposit']

            self.model.json = self._prepare_edit(record)

            flag_modified(self.model, 'json')
            db.session.merge(self.model)

        after_record_update.send(
            current_app._get_current_object(), record=self)
        return self.__class__(self.model.json, model=self.model)

def edit ( self , pid = None ) : pid = pid or self . pid with db . session . begin_nested ( ) : before_record_update . send ( current_app . _get_current_object ( ) , record = self ) record_pid , record = self . fetch_published ( ) assert PIDStatus . REGISTERED == record_pid . status assert record [ '_deposit' ] == self [ '_deposit' ] self . model . json = self . _prepare_edit ( record ) flag_modified ( self . model , 'json' ) db . session . merge ( self . model ) after_record_update . send ( current_app . _get_current_object ( ) , record = self ) return self . __class__ ( self . model . json , model = self . model )


def discard(self, pid=None):
        """Discard deposit changes.

        #. The signal :data:`invenio_records.signals.before_record_update` is
            sent before the edit execution.

        #. It restores the last published version.

        #. The following meta information are saved inside the deposit:

        .. code-block:: python

            deposit['$schema'] = deposit_schema_from_record_schema

        #. The signal :data:`invenio_records.signals.after_record_update` is
            sent after the edit execution.

        #. The deposit index is updated.

        Status required: ``'draft'``.

        :param pid: Force a pid object. (Default: ``None``)
        :returns: A new Deposit object.
        """
        pid = pid or self.pid

        with db.session.begin_nested():
            before_record_update.send(
                current_app._get_current_object(), record=self)

            _, record = self.fetch_published()
            self.model.json = deepcopy(record.model.json)
            self.model.json['$schema'] = self.build_deposit_schema(record)

            flag_modified(self.model, 'json')
            db.session.merge(self.model)

        after_record_update.send(
            current_app._get_current_object(), record=self)
        return self.__class__(self.model.json, model=self.model)

def discard ( self , pid = None ) : pid = pid or self . pid with db . session . begin_nested ( ) : before_record_update . send ( current_app . _get_current_object ( ) , record = self ) _ , record = self . fetch_published ( ) self . model . json = deepcopy ( record . model . json ) self . model . json [ '$schema' ] = self . build_deposit_schema ( record ) flag_modified ( self . model , 'json' ) db . session . merge ( self . model ) after_record_update . send ( current_app . _get_current_object ( ) , record = self ) return self . __class__ ( self . model . json , model = self . model )


def delete(self, force=True, pid=None):
        """Delete deposit.

        Status required: ``'draft'``.

        :param force: Force deposit delete.  (Default: ``True``)
        :param pid: Force pid object.  (Default: ``None``)
        :returns: A new Deposit object.
        """
        pid = pid or self.pid

        if self['_deposit'].get('pid'):
            raise PIDInvalidAction()
        if pid:
            pid.delete()
        return super(Deposit, self).delete(force=force)

def delete ( self , force = True , pid = None ) : pid = pid or self . pid if self [ '_deposit' ] . get ( 'pid' ) : raise PIDInvalidAction ( ) if pid : pid . delete ( ) return super ( Deposit , self ) . delete ( force = force )


def clear(self, *args, **kwargs):
        """Clear only drafts.

        Status required: ``'draft'``.

        Meta information inside `_deposit` are preserved.
        """
        super(Deposit, self).clear(*args, **kwargs)

def clear ( self , * args , ** kwargs ) : super ( Deposit , self ) . clear ( * args , ** kwargs )


def update(self, *args, **kwargs):
        """Update only drafts.

        Status required: ``'draft'``.

        Meta information inside `_deposit` are preserved.
        """
        super(Deposit, self).update(*args, **kwargs)

def update ( self , * args , ** kwargs ) : super ( Deposit , self ) . update ( * args , ** kwargs )


def patch(self, *args, **kwargs):
        """Patch only drafts.

        Status required: ``'draft'``.

        Meta information inside `_deposit` are preserved.
        """
        return super(Deposit, self).patch(*args, **kwargs)

def patch ( self , * args , ** kwargs ) : return super ( Deposit , self ) . patch ( * args , ** kwargs )


def files(self):
        """List of Files inside the deposit.

        Add validation on ``sort_by`` method: if, at the time of files access,
        the record is not a ``'draft'`` then a
        :exc:`invenio_pidstore.errors.PIDInvalidAction` is rised.
        """
        files_ = super(Deposit, self).files

        if files_:
            sort_by_ = files_.sort_by

            def sort_by(*args, **kwargs):
                """Only in draft state."""
                if 'draft' != self.status:
                    raise PIDInvalidAction()
                return sort_by_(*args, **kwargs)

            files_.sort_by = sort_by

        return files_

def files ( self ) : files_ = super ( Deposit , self ) . files if files_ : sort_by_ = files_ . sort_by def sort_by ( * args , ** kwargs ) : if 'draft' != self . status : raise PIDInvalidAction ( ) return sort_by_ ( * args , ** kwargs ) files_ . sort_by = sort_by return files_


def rst2node(doc_name, data):
    """Converts a reStructuredText into its node
    """
    if not data:
        return
    parser = docutils.parsers.rst.Parser()
    document = docutils.utils.new_document('<%s>' % doc_name)
    document.settings = docutils.frontend.OptionParser().get_default_values()
    document.settings.tab_width = 4
    document.settings.pep_references = False
    document.settings.rfc_references = False
    document.settings.env = Env()
    parser.parse(data, document)
    if len(document.children) == 1:
        return document.children[0]
    else:
        par = docutils.nodes.paragraph()
        for child in document.children:
            par += child
        return par

def rst2node ( doc_name , data ) : if not data : return parser = docutils . parsers . rst . Parser ( ) document = docutils . utils . new_document ( '<%s>' % doc_name ) document . settings = docutils . frontend . OptionParser ( ) . get_default_values ( ) document . settings . tab_width = 4 document . settings . pep_references = False document . settings . rfc_references = False document . settings . env = Env ( ) parser . parse ( data , document ) if len ( document . children ) == 1 : return document . children [ 0 ] else : par = docutils . nodes . paragraph ( ) for child in document . children : par += child return par


def setup(app):
    """Hook the directives when Sphinx ask for it."""
    if 'http' not in app.domains:
        httpdomain.setup(app)

    app.add_directive('autopyramid', RouteDirective)

def setup ( app ) : if 'http' not in app . domains : httpdomain . setup ( app ) app . add_directive ( 'autopyramid' , RouteDirective )

Hook the directives when Sphinx ask for it .


def _parse_response(self, response):
        """Parses the API response and raises appropriate errors if
        raise_errors was set to True
        """
        if not self._raise_errors:
            return response

        is_4xx_error = str(response.status_code)[0] == '4'
        is_5xx_error = str(response.status_code)[0] == '5'
        content = response.content

        if response.status_code == 403:
            raise AuthenticationError(content)
        elif is_4xx_error:
            raise APIError(content)
        elif is_5xx_error:
            raise ServerError(content)

        return response

def _parse_response ( self , response ) : if not self . _raise_errors : return response is_4xx_error = str ( response . status_code ) [ 0 ] == '4' is_5xx_error = str ( response . status_code ) [ 0 ] == '5' content = response . content if response . status_code == 403 : raise AuthenticationError ( content ) elif is_4xx_error : raise APIError ( content ) elif is_5xx_error : raise ServerError ( content ) return response


def templates(self, timeout=None):
        """ API call to get a list of templates """
        return self._api_request(
            self.TEMPLATES_ENDPOINT,
            self.HTTP_GET,
            timeout=timeout
        )

def templates ( self , timeout = None ) : return self . _api_request ( self . TEMPLATES_ENDPOINT , self . HTTP_GET , timeout = timeout )


def get_template(self, template_id, version=None, timeout=None):
        """ API call to get a specific template """
        if (version):
            return self._api_request(
                self.TEMPLATES_VERSION_ENDPOINT % (template_id, version),
                self.HTTP_GET,
                timeout=timeout
            )
        else:
            return self._api_request(
                self.TEMPLATES_SPECIFIC_ENDPOINT % template_id,
                self.HTTP_GET,
                timeout=timeout
            )

def get_template ( self , template_id , version = None , timeout = None ) : if ( version ) : return self . _api_request ( self . TEMPLATES_VERSION_ENDPOINT % ( template_id , version ) , self . HTTP_GET , timeout = timeout ) else : return self . _api_request ( self . TEMPLATES_SPECIFIC_ENDPOINT % template_id , self . HTTP_GET , timeout = timeout )


def create_template(
        self,
        name,
        subject,
        html,
        text='',
        timeout=None
    ):
        """ API call to create a template """
        payload = {
            'name': name,
            'subject': subject,
            'html': html,
            'text': text
        }

        return self._api_request(
            self.TEMPLATES_ENDPOINT,
            self.HTTP_POST,
            payload=payload,
            timeout=timeout
        )

def create_template ( self , name , subject , html , text = '' , timeout = None ) : payload = { 'name' : name , 'subject' : subject , 'html' : html , 'text' : text } return self . _api_request ( self . TEMPLATES_ENDPOINT , self . HTTP_POST , payload = payload , timeout = timeout )


def create_new_locale(
        self,
        template_id,
        locale,
        version_name,
        subject,
        text='',
        html='',
        timeout=None
    ):
        """ API call to create a new locale and version of a template """
        payload = {
            'locale': locale,
            'name': version_name,
            'subject': subject
        }

        if html:
            payload['html'] = html
        if text:
            payload['text'] = text

        return self._api_request(
            self.TEMPLATES_LOCALES_ENDPOINT % template_id,
            self.HTTP_POST,
            payload=payload,
            timeout=timeout
        )

def create_new_locale ( self , template_id , locale , version_name , subject , text = '' , html = '' , timeout = None ) : payload = { 'locale' : locale , 'name' : version_name , 'subject' : subject } if html : payload [ 'html' ] = html if text : payload [ 'text' ] = text return self . _api_request ( self . TEMPLATES_LOCALES_ENDPOINT % template_id , self . HTTP_POST , payload = payload , timeout = timeout )


def create_new_version(
        self,
        name,
        subject,
        text='',
        template_id=None,
        html=None,
        locale=None,
        timeout=None
    ):
        """ API call to create a new version of a template """
        if(html):
            payload = {
                'name': name,
                'subject': subject,
                'html': html,
                'text': text
            }
        else:
            payload = {
                'name': name,
                'subject': subject,
                'text': text
            }

        if locale:
            url = self.TEMPLATES_SPECIFIC_LOCALE_VERSIONS_ENDPOINT % (
                template_id,
                locale
            )
        else:
            url = self.TEMPLATES_NEW_VERSION_ENDPOINT % template_id

        return self._api_request(
            url,
            self.HTTP_POST,
            payload=payload,
            timeout=timeout
        )


def update_template_version(
        self,
        name,
        subject,
        template_id,
        version_id,
        text='',
        html=None,
        timeout=None
    ):
        """ API call to update a template version """
        if(html):
            payload = {
                'name': name,
                'subject': subject,
                'html': html,
                'text': text
            }
        else:
            payload = {
                'name': name,
                'subject': subject,
                'text': text
            }

        return self._api_request(
            self.TEMPLATES_VERSION_ENDPOINT % (template_id, version_id),
            self.HTTP_PUT,
            payload=payload,
            timeout=timeout
        )

def update_template_version ( self , name , subject , template_id , version_id , text = '' , html = None , timeout = None ) : if ( html ) : payload = { 'name' : name , 'subject' : subject , 'html' : html , 'text' : text } else : payload = { 'name' : name , 'subject' : subject , 'text' : text } return self . _api_request ( self . TEMPLATES_VERSION_ENDPOINT % ( template_id , version_id ) , self . HTTP_PUT , payload = payload , timeout = timeout )


def snippets(self, timeout=None):
        """ API call to get list of snippets """
        return self._api_request(
            self.SNIPPETS_ENDPOINT,
            self.HTTP_GET,
            timeout=timeout
        )

def snippets ( self , timeout = None ) : return self . _api_request ( self . SNIPPETS_ENDPOINT , self . HTTP_GET , timeout = timeout )


def get_snippet(self, snippet_id, timeout=None):
        """ API call to get a specific Snippet """
        return self._api_request(
            self.SNIPPET_ENDPOINT % (snippet_id),
            self.HTTP_GET,
            timeout=timeout
        )

def get_snippet ( self , snippet_id , timeout = None ) : return self . _api_request ( self . SNIPPET_ENDPOINT % ( snippet_id ) , self . HTTP_GET , timeout = timeout )


def create_snippet(self, name, body, timeout=None):
        """ API call to create a Snippet """
        payload = {
            'name': name,
            'body': body
        }
        return self._api_request(
            self.SNIPPETS_ENDPOINT,
            self.HTTP_POST,
            payload=payload,
            timeout=timeout
        )

def create_snippet ( self , name , body , timeout = None ) : payload = { 'name' : name , 'body' : body } return self . _api_request ( self . SNIPPETS_ENDPOINT , self . HTTP_POST , payload = payload , timeout = timeout )


def _make_file_dict(self, f):
        """Make a dictionary with filename and base64 file data"""
        if isinstance(f, dict):
            file_obj = f['file']
            if 'filename' in f:
                file_name = f['filename']
            else:
                file_name = file_obj.name
        else:
            file_obj = f
            file_name = f.name

        b64_data = base64.b64encode(file_obj.read())
        return {
            'id': file_name,
            'data': b64_data.decode() if six.PY3 else b64_data,
        }

def _make_file_dict ( self , f ) : if isinstance ( f , dict ) : file_obj = f [ 'file' ] if 'filename' in f : file_name = f [ 'filename' ] else : file_name = file_obj . name else : file_obj = f file_name = f . name b64_data = base64 . b64encode ( file_obj . read ( ) ) return { 'id' : file_name , 'data' : b64_data . decode ( ) if six . PY3 else b64_data , }


def send(
        self,
        email_id,
        recipient,
        email_data=None,
        sender=None,
        cc=None,
        bcc=None,
        tags=[],
        headers={},
        esp_account=None,
        locale=None,
        email_version_name=None,
        inline=None,
        files=[],
        timeout=None
    ):
        """ API call to send an email """
        if not email_data:
            email_data = {}

        # for backwards compatibility, will be removed
        if isinstance(recipient, string_types):
            warnings.warn(
                "Passing email directly for recipient is deprecated",
                DeprecationWarning)
            recipient = {'address': recipient}

        payload = {
            'email_id': email_id,
            'recipient': recipient,
            'email_data': email_data
        }

        if sender:
            payload['sender'] = sender
        if cc:
            if not type(cc) == list:
                logger.error(
                    'kwarg cc must be type(list), got %s' % type(cc))
            payload['cc'] = cc
        if bcc:
            if not type(bcc) == list:
                logger.error(
                    'kwarg bcc must be type(list), got %s' % type(bcc))
            payload['bcc'] = bcc

        if tags:
            if not type(tags) == list:
                logger.error(
                    'kwarg tags must be type(list), got %s' % (type(tags)))
            payload['tags'] = tags

        if headers:
            if not type(headers) == dict:
                logger.error(
                    'kwarg headers must be type(dict), got %s' % (
                        type(headers)
                    )
                )
            payload['headers'] = headers

        if esp_account:
            if not isinstance(esp_account, string_types):
                logger.error(
                    'kwarg esp_account must be a string, got %s' % (
                        type(esp_account)
                    )
                )
            payload['esp_account'] = esp_account

        if locale:
            if not isinstance(locale, string_types):
                logger.error(
                    'kwarg locale must be a string, got %s' % (type(locale))
                )
            payload['locale'] = locale

        if email_version_name:
            if not isinstance(email_version_name, string_types):
                logger.error(
                    'kwarg email_version_name must be a string, got %s' % (
                        type(email_version_name)))
            payload['version_name'] = email_version_name

        if inline:
            payload['inline'] = self._make_file_dict(inline)

        if files:
            payload['files'] = [self._make_file_dict(f) for f in files]

        return self._api_request(
            self.SEND_ENDPOINT,
            self.HTTP_POST,
            payload=payload,
            timeout=timeout
        )


def execute(self, timeout=None):
        """Execute all currently queued batch commands"""
        logger.debug(' > Batch API request (length %s)' % len(self._commands))

        auth = self._build_http_auth()

        headers = self._build_request_headers()
        logger.debug('\tbatch headers: %s' % headers)

        logger.debug('\tbatch command length: %s' % len(self._commands))

        path = self._build_request_path(self.BATCH_ENDPOINT)

        data = json.dumps(self._commands, cls=self._json_encoder)
        r = requests.post(
            path,
            auth=auth,
            headers=headers,
            data=data,
            timeout=(self.DEFAULT_TIMEOUT if timeout is None else timeout)
        )

        self._commands = []

        logger.debug('\tresponse code:%s' % r.status_code)
        try:
            logger.debug('\tresponse: %s' % r.json())
        except:
            logger.debug('\tresponse: %s' % r.content)

        return r

def
execute
(
self
,
timeout
=
)
:
logger
.
debug
(
' > Batch API request (length %s)'
%
len
(
self
.
_commands
)
)
auth
=
self
.
_build_http_auth
(
)
headers
=
self
.
_build_request_headers
(
)
logger
.
debug
(
'\tbatch headers: %s'
%
headers
)
logger
.
debug
(
'\tbatch command length: %s'
%
len
(
self
.
_commands
)
)
path
=
self
.
_build_request_path
(
self
.
BATCH_ENDPOINT
)
data
=
json
.
dumps
(
self
.
_commands
,
cls
=
self
.
_json_encoder
)
r
=
requests
.
post
(
path
,
auth
=
auth
,
headers
=
headers
,
data
=
data
,
timeout
=
(
self
.
DEFAULT_TIMEOUT
if
timeout
is
else
timeout
)
)
self
.
_commands
=
[
]
logger
.
debug
(
'\tresponse code:%s'
%
r
.
status_code
)
try
:
logger
.
debug
(
'\tresponse: %s'
%
r
.
json
(
)
)
except
:
logger
.
debug
(
'\tresponse: %s'
%
r
.
content
)
return
r


def get_group_tabs(self):
        """
        Return instances of all other tabs that are members of the tab's
        tab group.
        """
        if self.tab_group is None:
            raise ImproperlyConfigured(
                "%s requires a definition of 'tab_group'" %
                self.__class__.__name__)
        group_members = [t for t in self._registry if t.tab_group == self.tab_group]
        return [t() for t in group_members]

Return instances of all other tabs that are members of the tab s tab group .


def _process_tabs(self, tabs, current_tab, group_current_tab):
        """
        Process and prepare tabs.

        This includes steps like updating references to the current tab,
        filtering out hidden tabs, sorting tabs etc...

        Args:
            tabs:
                The list of tabs to process.
            current_tab:
                The reference to the currently loaded tab.
            group_current_tab:
                The reference to the active tab in the current tab group. For
                parent tabs, this is different than for the current tab group.

        Returns:
            Processed list of tabs. Note that the method may have side effects.

        """
        # Update references to the current tab
        for t in tabs:
            t.current_tab = current_tab
            t.group_current_tab = group_current_tab

        # Filter out hidden tabs
        tabs = list(filter(lambda t: t.tab_visible, tabs))

        # Sort remaining tabs in-place
        tabs.sort(key=lambda t: t.weight)

        return tabs

def _process_tabs ( self , tabs , current_tab , group_current_tab ) : for t in tabs : t . current_tab = current_tab t . group_current_tab = group_current_tab tabs = list ( filter ( lambda t : t . tab_visible , tabs ) ) tabs . sort ( key = lambda t : t . weight ) return tabs


def get_context_data(self, **kwargs):
        """
        Adds tab information to context.

        To retrieve a list of all group tab instances, use
        ``{{ tabs }}`` in your template.

        The id of the current tab is added as ``current_tab_id`` to the
        template context.

        If the current tab has a parent tab the parent's id is added to
        the template context as ``parent_tab_id``. Instances of all tabs
        of the parent level are added as ``parent_tabs`` to the context.

        If the current tab has children they are added to the template
        context as ``child_tabs``.

        """
        context = super(TabView, self).get_context_data(**kwargs)

        # Update the context with kwargs, TemplateView doesn't do this.
        context.update(kwargs)

        # Add tabs and "current" references to context
        process_tabs_kwargs = {
            'tabs': self.get_group_tabs(),
            'current_tab': self,
            'group_current_tab': self,
        }
        context['tabs'] = self._process_tabs(**process_tabs_kwargs)
        context['current_tab_id'] = self.tab_id

        # Handle parent tabs
        if self.tab_parent is not None:
            # Verify that tab parent is valid
            if self.tab_parent not in self._registry:
                msg = '%s has no attribute _is_tab' % self.tab_parent.__class__.__name__
                raise ImproperlyConfigured(msg)

            # Get parent tab instance
            parent = self.tab_parent()

            # Add parent tabs to context
            process_parents_kwargs = {
                'tabs': parent.get_group_tabs(),
                'current_tab': self,
                'group_current_tab': parent,
            }
            context['parent_tabs'] = self._process_tabs(**process_parents_kwargs)
            context['parent_tab_id'] = parent.tab_id

        # Handle child tabs
        if self.tab_id in self._children:
            process_children_kwargs = {
                'tabs': [t() for t in self._children[self.tab_id]],
                'current_tab': self,
                'group_current_tab': None,
            }
            context['child_tabs'] = self._process_tabs(**process_children_kwargs)

        return context

def
get_context_data
(
self
,
**
kwargs
)
:
context
=
super
(
TabView
,
self
)
.
get_context_data
(
**
kwargs
)
context
.
update
(
kwargs
)
process_tabs_kwargs
=
{
'tabs'
:
self
.
get_group_tabs
(
)
,
'current_tab'
:
self
,
'group_current_tab'
:
self
,
}
context
[
'tabs'
]
=
self
.
_process_tabs
(
**
process_tabs_kwargs
)
context
[
'current_tab_id'
]
=
self
.
tab_id
if
self
.
tab_parent
is
not
:
if
self
.
tab_parent
not
in
self
.
_registry
:
msg
=
'%s has no attribute _is_tab'
%
self
.
tab_parent
.
__class__
.
__name__
raise
ImproperlyConfigured
(
msg
)
parent
=
self
.
tab_parent
(
)
process_parents_kwargs
=
{
'tabs'
:
parent
.
get_group_tabs
(
)
,
'current_tab'
:
self
,
'group_current_tab'
:
parent
,
}
context
[
'parent_tabs'
]
=
self
.
_process_tabs
(
**
process_parents_kwargs
)
context
[
'parent_tab_id'
]
=
parent
.
tab_id
if
self
.
tab_id
in
self
.
_children
:
process_children_kwargs
=
{
'tabs'
:
[
t
(
)
for
t
in
self
.
_children
[
self
.
tab_id
]
]
,
'current_tab'
:
self
,
'group_current_tab'
:
,
}
context
[
'child_tabs'
]
=
self
.
_process_tabs
(
**
process_children_kwargs
)
return
context


def normalize_name(s):
    """Convert a string into a valid python attribute name.
    This function is called to convert ASCII strings to something that can pass as
    python attribute name, to be used with namedtuples.

    >>> str(normalize_name('class'))
    'class_'
    >>> str(normalize_name('a-name'))
    'a_name'
    >>> str(normalize_name('a n\u00e4me'))
    'a_name'
    >>> str(normalize_name('Name'))
    'Name'
    >>> str(normalize_name(''))
    '_'
    >>> str(normalize_name('1'))
    '_1'
    """
    s = s.replace('-', '_').replace('.', '_').replace(' ', '_')
    if s in keyword.kwlist:
        return s + '_'
    s = '_'.join(slug(ss, lowercase=False) for ss in s.split('_'))
    if not s:
        s = '_'
    if s[0] not in string.ascii_letters + '_':
        s = '_' + s
    return s

def
normalize_name
(
s
)
:
s
=
s
.
replace
(
'-'
,
'_'
)
.
replace
(
'.'
,
'_'
)
.
replace
(
' '
,
'_'
)
if
s
in
keyword
.
kwlist
:
return
s
+
'_'
s
=
'_'
.
join
(
slug
(
ss
,
lowercase
=
False
)
for
ss
in
s
.
split
(
'_'
)
)
if
not
s
:
s
=
'_'
if
s
[
0
]
not
in
string
.
ascii_letters
+
'_'
:
s
=
'_'
+
s
return
s

Convert a string into a valid python attribute name . This function is called to convert ASCII strings to something that can pass as python attribute name to be used with namedtuples .


def schema(tg):
    """
    Convert the table and column descriptions of a `TableGroup` into specifications for the
    DB schema.

    :param ds:
    :return: A pair (tables, reference_tables).
    """
    tables = {}
    for tname, table in tg.tabledict.items():
        t = TableSpec.from_table_metadata(table)
        tables[t.name] = t
        for at in t.many_to_many.values():
            tables[at.name] = at

    # We must determine the order in which tables must be created!
    ordered = OrderedDict()
    i = 0

    # We loop through the tables repeatedly, and whenever we find one, which has all
    # referenced tables already in ordered, we move it from tables to ordered.
    while tables and i < 100:
        i += 1
        for table in list(tables.keys()):
            if all((ref[1] in ordered) or ref[1] == table for ref in tables[table].foreign_keys):
                # All referenced tables are already created (or self-referential).
                ordered[table] = tables.pop(table)
                break
    if tables:  # pragma: no cover
        raise ValueError('there seem to be cyclic dependencies between the tables')

    return list(ordered.values())

Convert the table and column descriptions of a TableGroup into specifications for the DB schema .


def write(self, _force=False, _exists_ok=False, **items):
        """
        Creates a db file with the core schema.

        :param force: If `True` an existing db file will be overwritten.
        """
        if self.fname and self.fname.exists():
            raise ValueError('db file already exists, use force=True to overwrite')

        with self.connection() as db:
            for table in self.tables:
                db.execute(table.sql(translate=self.translate))

            db.execute('PRAGMA foreign_keys = ON;')
            db.commit()

            refs = defaultdict(list)  # collects rows in association tables.
            for t in self.tables:
                if t.name not in items:
                    continue
                rows, keys = [], []
                cols = {c.name: c for c in t.columns}
                for i, row in enumerate(items[t.name]):
                    pk = row[t.primary_key[0]] \
                        if t.primary_key and len(t.primary_key) == 1 else None
                    values = []
                    for k, v in row.items():
                        if k in t.many_to_many:
                            assert pk
                            at = t.many_to_many[k]
                            atkey = tuple([at.name] + [c.name for c in at.columns])
                            for vv in v:
                                fkey, context = self.association_table_context(t, k, vv)
                                refs[atkey].append((pk, fkey, context))
                        else:
                            col = cols[k]
                            if isinstance(v, list):
                                # Note: This assumes list-valued columns are of datatype string!
                                v = (col.separator or ';').join(
                                    col.convert(vv) for vv in v)
                            else:
                                v = col.convert(v) if v is not None else None
                            if i == 0:
                                keys.append(col.name)
                            values.append(v)
                    rows.append(tuple(values))
                insert(db, self.translate, t.name, keys, *rows)

            for atkey, rows in refs.items():
                insert(db, self.translate, atkey[0], atkey[1:], *rows)

            db.commit()

Creates a db file with the core schema .


def iterrows(lines_or_file, namedtuples=False, dicts=False, encoding='utf-8', **kw):
    """Convenience factory function for csv reader.

    :param lines_or_file: Content to be read. Either a file handle, a file path or a list\
    of strings.
    :param namedtuples: Yield namedtuples.
    :param dicts: Yield dicts.
    :param encoding: Encoding of the content.
    :param kw: Keyword parameters are passed through to csv.reader.
    :return: A generator over the rows.
    """
    if namedtuples and dicts:
        raise ValueError('either namedtuples or dicts can be chosen as output format')
    elif namedtuples:
        _reader = NamedTupleReader
    elif dicts:
        _reader = UnicodeDictReader
    else:
        _reader = UnicodeReader

    with _reader(lines_or_file, encoding=encoding, **fix_kw(kw)) as r:
        for item in r:
            yield item

Convenience factory function for csv reader .


def rewrite(fname, visitor, **kw):
    """Utility function to rewrite rows in tsv files.

    :param fname: Path of the dsv file to operate on.
    :param visitor: A callable that takes a line-number and a row as input and returns a \
    (modified) row or None to filter out the row.
    :param kw: Keyword parameters are passed through to csv.reader/csv.writer.
    """
    if not isinstance(fname, pathlib.Path):
        assert isinstance(fname, string_types)
        fname = pathlib.Path(fname)

    assert fname.is_file()
    with tempfile.NamedTemporaryFile(delete=False) as fp:
        tmp = pathlib.Path(fp.name)

    with UnicodeReader(fname, **kw) as reader_:
        with UnicodeWriter(tmp, **kw) as writer:
            for i, row in enumerate(reader_):
                row = visitor(i, row)
                if row is not None:
                    writer.writerow(row)
    shutil.move(str(tmp), str(fname))

def rewrite ( fname , visitor , ** kw ) : if not isinstance ( fname , pathlib . Path ) : assert isinstance ( fname , string_types ) fname = pathlib . Path ( fname ) assert fname . is_file ( ) with tempfile . NamedTemporaryFile ( delete = False ) as fp : tmp = pathlib . Path ( fp . name ) with UnicodeReader ( fname , ** kw ) as reader_ : with UnicodeWriter ( tmp , ** kw ) as writer : for i , row in enumerate ( reader_ ) : row = visitor ( i , row ) if row is not None : writer . writerow ( row ) shutil . move ( str ( tmp ) , str ( fname ) )

Utility function to rewrite rows in tsv files .


def filter_rows_as_dict(fname, filter_, **kw):
    """Rewrite a dsv file, filtering the rows.

    :param fname: Path to dsv file
    :param filter_: callable which accepts a `dict` with a row's data as single argument\
    returning a `Boolean` indicating whether to keep the row (`True`) or to discard it \
    `False`.
    :param kw: Keyword arguments to be passed `UnicodeReader` and `UnicodeWriter`.
    :return: The number of rows that have been removed.
    """
    filter_ = DictFilter(filter_)
    rewrite(fname, filter_, **kw)
    return filter_.removed

def filter_rows_as_dict ( fname , filter_ , ** kw ) : filter_ = DictFilter ( filter_ ) rewrite ( fname , filter_ , ** kw ) return filter_ . removed


def dump_grid(grid):
    """
    Dump a single grid to its ZINC representation.
    """
    header = 'ver:%s' % dump_str(str(grid._version), version=grid._version)
    if bool(grid.metadata):
        header += ' ' + dump_meta(grid.metadata, version=grid._version)
    columns = dump_columns(grid.column, version=grid._version)
    rows = dump_rows(grid)
    return '\n'.join([header, columns] + rows + [''])

def
dump_grid
(
grid
)
:
header
=
'ver:%s'
%
dump_str
(
str
(
grid
.
_version
)
,
version
=
grid
.
_version
)
if
bool
(
grid
.
metadata
)
:
header
+=
' '
+
dump_meta
(
grid
.
metadata
,
version
=
grid
.
_version
)
columns
=
dump_columns
(
grid
.
column
,
version
=
grid
.
_version
)
rows
=
dump_rows
(
grid
)
return
'\n'
.
join
(
[
header
,
columns
]
+
rows
+
[
''
]
)

Dump a single grid to its ZINC representation .


def parse(grid_str, mode=MODE_ZINC, charset='utf-8'):
    '''
    Parse the given Zinc text and return the equivalent data.
    '''
    # Decode incoming text (or python3 will whine!)
    if isinstance(grid_str, six.binary_type):
        grid_str = grid_str.decode(encoding=charset)

    # Split the separate grids up, the grammar definition has trouble splitting
    # them up normally.  This will truncate the newline off the end of the last
    # row.
    _parse = functools.partial(parse_grid, mode=mode,
            charset=charset)
    if mode == MODE_JSON:
        if isinstance(grid_str, six.string_types):
            grid_data = json.loads(grid_str)
        else:
            grid_data = grid_str
        if isinstance(grid_data, dict):
            return _parse(grid_data)
        else:
            return list(map(_parse, grid_data))
    else:
        return list(map(_parse, GRID_SEP.split(grid_str.rstrip())))

def parse ( grid_str , mode = MODE_ZINC , charset = 'utf-8' ) : if isinstance ( grid_str , six . binary_type ) : grid_str = grid_str . decode ( encoding = charset ) _parse = functools . partial ( parse_grid , mode = mode , charset = charset ) if mode == MODE_JSON : if isinstance ( grid_str , six . string_types ) : grid_data = json . loads ( grid_str ) else : grid_data = grid_str if isinstance ( grid_data , dict ) : return _parse ( grid_data ) else : return list ( map ( _parse , grid_data ) ) else : return list ( map ( _parse , GRID_SEP . split ( grid_str . rstrip ( ) ) ) )

Parse the given Zinc text and return the equivalent data .


def append(self, key, value=MARKER, replace=True):
        '''
        Append the item to the metadata.
        '''
        return self.add_item(key, value, replace=replace)

def append ( self , key , value = MARKER , replace = True ) : return self . add_item ( key , value , replace = replace )


def extend(self, items, replace=True):
        '''
        Append the items to the metadata.
        '''
        if isinstance(items, dict) or isinstance(items, SortableDict):
            items = list(items.items())

        for (key, value) in items:
            self.append(key, value, replace=replace)

def extend ( self , items , replace = True ) : if isinstance ( items , dict ) or isinstance ( items , SortableDict ) : items = list ( items . items ( ) ) for ( key , value ) in items : self . append ( key , value , replace = replace )


def regular_polygon(cls, center, radius, n_vertices, start_angle=0, **kwargs):
        """Construct a regular polygon.

        Parameters
        ----------
        center : array-like
        radius : float
        n_vertices : int
        start_angle : float, optional
            Where to put the first point, relative to `center`,
            in radians counter-clockwise starting from the horizontal axis.
        kwargs
            Other keyword arguments are passed to the |Shape| constructor.

        """
        angles = (np.arange(n_vertices) * 2 * np.pi / n_vertices) + start_angle
        return cls(center + radius * np.array([np.cos(angles), np.sin(angles)]).T, **kwargs)

def regular_polygon ( cls , center , radius , n_vertices , start_angle = 0 , ** kwargs ) : angles = ( np . arange ( n_vertices ) * 2 * np . pi / n_vertices ) + start_angle return cls ( center + radius * np . array ( [ np . cos ( angles ) , np . sin ( angles ) ] ) . T , ** kwargs )


def circle(cls, center, radius, n_vertices=50, **kwargs):
        """Construct a circle.

        Parameters
        ----------
        center : array-like
        radius : float
        n_vertices : int, optional
            Number of points to draw.
            Decrease for performance, increase for appearance.
        kwargs
            Other keyword arguments are passed to the |Shape| constructor.

        """
        return cls.regular_polygon(center, radius, n_vertices, **kwargs)

def circle ( cls , center , radius , n_vertices = 50 , ** kwargs ) : return cls . regular_polygon ( center , radius , n_vertices , ** kwargs )


def rectangle(cls, vertices, **kwargs):
        """Shortcut for creating a rectangle aligned with the screen axes from only two corners.

        Parameters
        ----------
        vertices : array-like
            An array containing the ``[x, y]`` positions of two corners.
        kwargs
            Other keyword arguments are passed to the |Shape| constructor.

        """
        bottom_left, top_right = vertices
        top_left = [bottom_left[0], top_right[1]]
        bottom_right = [top_right[0], bottom_left[1]]
        return cls([bottom_left, bottom_right, top_right, top_left], **kwargs)

def rectangle ( cls , vertices , ** kwargs ) : bottom_left , top_right = vertices top_left = [ bottom_left [ 0 ] , top_right [ 1 ] ] bottom_right = [ top_right [ 0 ] , bottom_left [ 1 ] ] return cls ( [ bottom_left , bottom_right , top_right , top_left ] , ** kwargs )

Shortcut for creating a rectangle aligned with the screen axes from only two corners .


def from_dict(cls, spec):
        """Create a |Shape| from a dictionary specification.

        Parameters
        ----------
        spec : dict
            A dictionary with either the fields ``'center'`` and ``'radius'`` (for a circle),
            ``'center'``, ``'radius'``, and ``'n_vertices'`` (for a regular polygon),
            or ``'vertices'``.
            If only two vertices are given, they are assumed to be lower left and top right corners of a rectangle.
            Other fields are interpreted as keyword arguments.

        """
        spec = spec.copy()
        center = spec.pop('center', None)
        radius = spec.pop('radius', None)
        if center and radius:
            return cls.circle(center, radius, **spec)

        vertices = spec.pop('vertices')
        if len(vertices) == 2:
            return cls.rectangle(vertices, **spec)

        return cls(vertices, **spec)

def from_dict ( cls , spec ) : spec = spec . copy ( ) center = spec . pop ( 'center' , None ) radius = spec . pop ( 'radius' , None ) if center and radius : return cls . circle ( center , radius , ** spec ) vertices = spec . pop ( 'vertices' ) if len ( vertices ) == 2 : return cls . rectangle ( vertices , ** spec ) return cls ( vertices , ** spec )

Create a |Shape| from a dictionary specification .


def _kwargs(self):
        """Keyword arguments for recreating the Shape from the vertices.

        """
        return dict(color=self.color, velocity=self.velocity, colors=self.colors)

def _kwargs ( self ) : return dict ( color = self . color , velocity = self . velocity , colors = self . colors )

Keyword arguments for recreating the Shape from the vertices .


def rotate(self, angle, center=None):
        """Rotate the shape, in-place.

        Parameters
        ----------
        angle : float
            Angle to rotate, in radians counter-clockwise.
        center : array-like, optional
            Point about which to rotate.
            If not passed, the center of the shape will be used.

        """
        args = [angle]
        if center is not None:
            args.extend(center)
        self.poly.rotate(*args)
        return self

def rotate ( self , angle , center = None ) : args = [ angle ] if center is not None : args . extend ( center ) self . poly . rotate ( * args ) return self


def flip_x(self, center=None):
        """Flip the shape in the x direction, in-place.

        Parameters
        ----------
        center : array-like, optional
            Point about which to flip.
            If not passed, the center of the shape will be used.

         """
        if center is None:
            self.poly.flip()
        else:
            self.poly.flip(center[0])

def flip_x ( self , center = None ) : if center is None : self . poly . flip ( ) else : self . poly . flip ( center [ 0 ] )

Flip the shape in the x direction in - place .


def flip_y(self, center=None):
        """Flip the shape in the y direction, in-place.

        Parameters
        ----------
        center : array-like, optional
            Point about which to flip.
            If not passed, the center of the shape will be used.

         """
        if center is None:
            self.poly.flop()
        else:
            self.poly.flop(center[1])
        return self

def flip_y ( self , center = None ) : if center is None : self . poly . flop ( ) else : self . poly . flop ( center [ 1 ] ) return self

Flip the shape in the y direction in - place .


def flip(self, angle, center=None):
        """ Flip the shape in an arbitrary direction.

        Parameters
        ----------
        angle : array-like
            The angle, in radians counter-clockwise from the horizontal axis,
            defining the angle about which to flip the shape (of a line through `center`).
        center : array-like, optional
            The point about which to flip.
            If not passed, the center of the shape will be used.

        """
        return self.rotate(-angle, center=center).flip_y(center=center).rotate(angle, center=center)

def flip ( self , angle , center = None ) : return self . rotate ( - angle , center = center ) . flip_y ( center = center ) . rotate ( angle , center = center )

Flip the shape in an arbitrary direction .


def draw(self):
        """Draw the shape in the current OpenGL context.

        """
        if self.enabled:
            self._vertex_list.colors = self._gl_colors
            self._vertex_list.vertices = self._gl_vertices
            self._vertex_list.draw(pyglet.gl.GL_TRIANGLES)

def draw ( self ) : if self . enabled : self . _vertex_list . colors = self . _gl_colors self . _vertex_list . vertices = self . _gl_vertices self . _vertex_list . draw ( pyglet . gl . GL_TRIANGLES )

Draw the shape in the current OpenGL context .


def update(self, dt):
        """Update the shape's position by moving it forward according to its velocity.

        Parameters
        ----------
        dt : float

        """
        self.translate(dt * self.velocity)
        self.rotate(dt * self.angular_velocity)

def update ( self , dt ) : self . translate ( dt * self . velocity ) self . rotate ( dt * self . angular_velocity )

Update the shape s position by moving it forward according to its velocity .


def _map_timezones():
    """
    Map the official Haystack timezone list to those recognised by pytz.
    """
    tz_map = {}
    todo = HAYSTACK_TIMEZONES_SET.copy()
    for full_tz in pytz.all_timezones:
        # Finished case:
        if not bool(todo): # pragma: no cover
            # This is nearly impossible for us to cover, and an unlikely case.
            break

        # Case 1: exact match
        if full_tz in todo:
            tz_map[full_tz] = full_tz   # Exact match
            todo.discard(full_tz)
            continue

        # Case 2: suffix match after '/'
        if '/' not in full_tz:
            continue

        (prefix, suffix) = full_tz.split('/',1)
        # Case 2 exception: full timezone contains more than one '/' -> ignore
        if '/' in suffix:
            continue

        if suffix in todo:
            tz_map[suffix] = full_tz
            todo.discard(suffix)
            continue

    return tz_map

def _map_timezones ( ) : tz_map = { } todo = HAYSTACK_TIMEZONES_SET . copy ( ) for full_tz in pytz . all_timezones : if not bool ( todo ) : break if full_tz in todo : tz_map [ full_tz ] = full_tz todo . discard ( full_tz ) continue if '/' not in full_tz : continue ( prefix , suffix ) = full_tz . split ( '/' , 1 ) if '/' in suffix : continue if suffix in todo : tz_map [ suffix ] = full_tz todo . discard ( suffix ) continue return tz_map

Map the official Haystack timezone list to those recognised by pytz .


def timezone(haystack_tz, version=LATEST_VER):
    """
    Retrieve the Haystack timezone
    """
    tz_map = get_tz_map(version=version)
    try:
        tz_name = tz_map[haystack_tz]
    except KeyError:
        raise ValueError('%s is not a recognised timezone on this host' \
                % haystack_tz)
    return pytz.timezone(tz_name)


def _unescape(s, uri=False):
    """
    Iterative parser for string escapes.
    """
    out = ''
    while len(s) > 0:
        c = s[0]
        if c == '\\':
            # Backslash escape
            esc_c = s[1]

            if esc_c in ('u', 'U'):
                # Unicode escape
                out += six.unichr(int(s[2:6], base=16))
                s = s[6:]
                continue
            else:
                if esc_c == 'b':
                    out += '\b'
                elif esc_c == 'f':
                    out += '\f'
                elif esc_c == 'n':
                    out += '\n'
                elif esc_c == 'r':
                    out += '\r'
                elif esc_c == 't':
                    out += '\t'
                else:
                    if uri and (esc_c == '#'):
                        # \# is passed through with backslash.
                        out += '\\'
                    # Pass through
                    out += esc_c
                s = s[2:]
                continue
        else:
            out += c
            s = s[1:]
    return out

def _unescape ( s , uri = False ) : out = '' while len ( s ) > 0 : c = s [ 0 ] if c == '\\' : esc_c = s [ 1 ] if esc_c in ( 'u' , 'U' ) : out += six . unichr ( int ( s [ 2 : 6 ] , base = 16 ) ) s = s [ 6 : ] continue else : if esc_c == 'b' : out += '\b' elif esc_c == 'f' : out += '\f' elif esc_c == 'n' : out += '\n' elif esc_c == 'r' : out += '\r' elif esc_c == 't' : out += '\t' else : if uri and ( esc_c == '#' ) : out += '\\' out += esc_c s = s [ 2 : ] continue else : out += c s = s [ 1 : ] return out


def parse_grid(grid_data):
    """
    Parse the incoming grid.
    """
    try:
        # Split the grid up.
        grid_parts = NEWLINE_RE.split(grid_data)
        if len(grid_parts) < 2:
            raise ZincParseException('Malformed grid received',
                    grid_data, 1, 1)

        # Grid and column metadata are the first two lines.
        grid_meta_str = grid_parts.pop(0)
        col_meta_str = grid_parts.pop(0)

        # First element is the grid metadata
        ver_match = VERSION_RE.match(grid_meta_str)
        if ver_match is None:
            raise ZincParseException(
                    'Could not determine version from %r' % grid_meta_str,
                    grid_data, 1, 1)
        version = Version(ver_match.group(1))

        # Now parse the rest of the grid accordingly
        try:
            grid_meta = hs_gridMeta[version].parseString(grid_meta_str, parseAll=True)[0]
        except pp.ParseException as pe:
            # Raise a new exception with the appropriate line number.
            raise ZincParseException(
                    'Failed to parse grid metadata: %s' % pe,
                    grid_data, 1, pe.col)
        except: # pragma: no cover
            # Report an error to the log if we fail to parse something.
            LOG.debug('Failed to parse grid meta: %r', grid_meta_str)
            raise

        try:
            col_meta = hs_cols[version].parseString(col_meta_str, parseAll=True)[0]
        except pp.ParseException as pe:
            # Raise a new exception with the appropriate line number.
            raise ZincParseException(
                    'Failed to parse column metadata: %s' \
                            % reformat_exception(pe, 2),
                    grid_data, 2, pe.col)
        except: # pragma: no cover
            # Report an error to the log if we fail to parse something.
            LOG.debug('Failed to parse column meta: %r', col_meta_str)
            raise

        row_grammar = hs_row[version]
        def _parse_row(row_num_and_data):
            (row_num, row) = row_num_and_data
            line_num = row_num + 3

            try:
                return dict(zip(col_meta.keys(),
                    row_grammar.parseString(row, parseAll=True)[0].asList()))
            except pp.ParseException as pe:
                # Raise a new exception with the appropriate line number.
                raise ZincParseException(
                        'Failed to parse row: %s' \
                            % reformat_exception(pe, line_num),
                        grid_data, line_num, pe.col)
            except: # pragma: no cover
                # Report an error to the log if we fail to parse something.
                LOG.debug('Failed to parse row: %r', row)
                raise

        g = Grid(version=grid_meta.pop('ver'),
                metadata=grid_meta,
                columns=list(col_meta.items()))
        g.extend(map(_parse_row, filter(lambda gp : bool(gp[1]), enumerate(grid_parts))))
        return g
    except:
        LOG.debug('Failing grid: %r', grid_data)
        raise

def
parse_grid
(
grid_data
)
:
try
:
grid_parts
=
NEWLINE_RE
.
split
(
grid_data
)
if
len
(
grid_parts
)
<
2
:
raise
ZincParseException
(
'Malformed grid received'
,
grid_data
,
1
,
1
)
grid_meta_str
=
grid_parts
.
pop
(
0
)
col_meta_str
=
grid_parts
.
pop
(
0
)
ver_match
=
VERSION_RE
.
match
(
grid_meta_str
)
if
ver_match
is
:
raise
ZincParseException
(
'Could not determine version from %r'
%
grid_meta_str
,
grid_data
,
1
,
1
)
version
=
Version
(
ver_match
.
group
(
1
)
)
try
:
grid_meta
=
hs_gridMeta
[
version
]
.
parseString
(
grid_meta_str
,
parseAll
=
True
)
[
0
]
except
pp
.
ParseException
as
pe
:
raise
ZincParseException
(
'Failed to parse grid metadata: %s'
%
pe
,
grid_data
,
1
,
pe
.
col
)
except
:
LOG
.
debug
(
'Failed to parse grid meta: %r'
,
grid_meta_str
)
raise
try
:
col_meta
=
hs_cols
[
version
]
.
parseString
(
col_meta_str
,
parseAll
=
True
)
[
0
]
except
pp
.
ParseException
as
pe
:
raise
ZincParseException
(
'Failed to parse column metadata: %s'
%
reformat_exception
(
pe
,
2
)
,
grid_data
,
2
,
pe
.
col
)
except
:
LOG
.
debug
(
'Failed to parse column meta: %r'
,
col_meta_str
)
raise
row_grammar
=
hs_row
[
version
]
def
_parse_row
(
row_num_and_data
)
:
(
row_num
,
row
)
=
row_num_and_data
line_num
=
row_num
+
3
try
:
return
dict
(
zip
(
col_meta
.
keys
(
)
,
row_grammar
.
parseString
(
row
,
parseAll
=
True
)
[
0
]
.
asList
(
)
)
)
except
pp
.
ParseException
as
pe
:
raise
ZincParseException
(
'Failed to parse row: %s'
%
reformat_exception
(
pe
,
line_num
)
,
grid_data
,
line_num
,
pe
.
col
)
except
:
LOG
.
debug
(
'Failed to parse row: %r'
,
row
)
raise
g
=
Grid
(
version
=
grid_meta
.
pop
(
'ver'
)
,
metadata
=
grid_meta
,
columns
=
list
(
col_meta
.
items
(
)
)
)
g
.
extend
(
map
(
_parse_row
,
filter
(
lambda
gp
:
bool
(
gp
[
1
]
)
,
enumerate
(
grid_parts
)
)
)
)
return
g
except
:
LOG
.
debug
(
'Failing grid: %r'
,
grid_data
)
raise


def parse_scalar(scalar_data, version):
    """
    Parse a Project Haystack scalar in ZINC format.
    """
    try:
        return hs_scalar[version].parseString(scalar_data, parseAll=True)[0]
    except pp.ParseException as pe:
        # Raise a new exception with the appropriate line number.
        raise ZincParseException(
                'Failed to parse scalar: %s' % reformat_exception(pe),
                scalar_data, 1, pe.col)
    except:
        LOG.debug('Failing scalar data: %r (version %r)',
                scalar_data, version)

def
parse_scalar
(
scalar_data
,
version
)
:
try
:
return
hs_scalar
[
version
]
.
parseString
(
scalar_data
,
parseAll
=
True
)
[
0
]
except
pp
.
ParseException
as
pe
:
raise
ZincParseException
(
'Failed to parse scalar: %s'
%
reformat_exception
(
pe
)
,
scalar_data
,
1
,
pe
.
col
)
except
:
LOG
.
debug
(
'Failing scalar data: %r (version %r)'
,
scalar_data
,
version
)

Parse a Project Haystack scalar in ZINC format .


def add_item(self, key, value, after=False, index=None, pos_key=None,
            replace=True):
        """
        Add an item at a specific location, possibly replacing the
        existing item.

        If after is True, we insert *after* the given index, otherwise we
        insert before.

        The position is specified using either index or pos_key, the former
        specifies the position from the start of the array (base 0).  pos_key
        specifies the name of another key, and positions the new key relative
        to that key.

        When replacing, the position will be left un-changed unless a location
        is specified explicitly.
        """
        if self._validate_fn:
            self._validate_fn(value)

        if (index is not None) and (pos_key is not None):
            raise ValueError('Either specify index or pos_key, not both.')
        elif pos_key is not None:
            try:
                index = self.index(pos_key)
            except ValueError:
                raise KeyError('%r not found' % pos_key)

        if after and (index is not None):
            # insert inserts *before* index, so increment by one.
            index += 1

        if key in self._values:
            if not replace:
                raise KeyError('%r is duplicate' % key)

            if index is not None:
                # We are re-locating.
                del self[key]
            else:
                # We are updating
                self._values[key] = value
                return

        if index is not None:
            # Place at given position
            self._order.insert(index, key)
        else:
            # Place at end
            self._order.append(key)
        self._values[key] = value

Add an item at a specific location possibly replacing the existing item .


def dump(grids, mode=MODE_ZINC):
    """
    Dump the given grids in the specified over-the-wire format.
    """
    if isinstance(grids, Grid):
        return dump_grid(grids, mode=mode)
    _dump = functools.partial(dump_grid, mode=mode)
    if mode == MODE_ZINC:
        return '\n'.join(map(_dump, grids))
    elif mode == MODE_JSON:
        return '[%s]' % ','.join(map(_dump, grids))
    else: # pragma: no cover
        raise NotImplementedError('Format not implemented: %s' % mode)

def
dump
(
grids
,
mode
=
MODE_ZINC
)
:
if
isinstance
(
grids
,
Grid
)
:
return
dump_grid
(
grids
,
mode
=
mode
)
_dump
=
functools
.
partial
(
dump_grid
,
mode
=
mode
)
if
mode
==
MODE_ZINC
:
return
'\n'
.
join
(
map
(
_dump
,
grids
)
)
elif
mode
==
MODE_JSON
:
return
'[%s]'
%
','
.
join
(
map
(
_dump
,
grids
)
)
else
:
raise
NotImplementedError
(
'Format not implemented: %s'
%
mode
)

Dump the given grids in the specified over - the - wire format .


def _detect_or_validate(self, val):
        '''
        Detect the version used from the row content, or validate against
        the version if given.
        '''
        if isinstance(val, list) \
                or isinstance(val, dict) \
                or isinstance(val, SortableDict) \
                or isinstance(val, Grid):
            # Project Haystack 3.0 type.
            self._assert_version(VER_3_0)

def _detect_or_validate ( self , val ) : if isinstance ( val , list ) or isinstance ( val , dict ) or isinstance ( val , SortableDict ) or isinstance ( val , Grid ) : self . _assert_version ( VER_3_0 )

Detect the version used from the row content or validate against the version if given .


def _assert_version(self, version):
        '''
        Assert that the grid version is equal to or above the given value.
        If no version is set, set the version.
        '''
        if self.nearest_version < version:
            if self._version_given:
                raise ValueError(
                        'Data type requires version %s' \
                        % version)
            else:
                self._version = version

def
_assert_version
(
self
,
version
)
:
if
self
.
nearest_version
<
version
:
if
self
.
_version_given
:
raise
ValueError
(
'Data type requires version %s'
%
version
)
else
:
self
.
_version
=
version

Assert that the grid version is equal to or above the given value . If no version is set set the version .