#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
###############################################################################
# #
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.web module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
"""
Reusable help functions
"""
from django.core.exceptions import ValidationError
from django.utils.encoding import force_text
from django.utils import six
from ..ui.templatetags.markup import restructuredtext
[docs]def validate_restructuredtext(value):
"""Validates a piece of restructuredtext for strict conformance"""
try:
from docutils import utils
from docutils.nodes import Element
from docutils.core import Publisher
except ImportError:
raise forms.ValidationError("Error in 'reStructuredText' validator: The Python docutils package isn't installed.")
# Generate a new parser (copying `rst2html.py` flow)
pub = Publisher(None, None, None, settings=None)
pub.set_components('standalone', 'restructuredtext', 'pseudoxml')
# Configure publisher
settings = pub.get_settings(halt_level=5)
pub.set_io()
# Prepare a document to parse
reader = pub.reader
document = utils.new_document(None, settings)
# Disable stdout
# TODO: Find a proper way to do this
# TODO: We might exit the program if a certain error level is reached
document.reporter.stream = None
# Collect errors via an observer
errors = []
def error_collector(data):
# Mutate the data since it was just generated
data.line = data['line']
data.source = data['source']
data.level = data['level']
data.type = data['type']
data.message = Element.astext(data.children[0])
data.full_message = Element.astext(data)
# Save the error
errors.append(data)
document.reporter.attach_observer(error_collector)
# Parse the content (and collect errors)
reader.parser.parse(force_text(value), document)
# Apply transforms (and more collect errors)
document.transformer.populate_from_components(
(pub.source, pub.reader, pub.reader.parser, pub.writer,
pub.destination))
transformer = document.transformer
while transformer.transforms:
if not transformer.sorted:
# Unsorted initially, and whenever a transform is added.
transformer.transforms.sort()
transformer.transforms.reverse()
transformer.sorted = 1
priority, transform_class, pending, kwargs = transformer.transforms.pop()
transform = transform_class(transformer.document, startnode=pending)
transform.apply(**kwargs)
transformer.applied.append((priority, transform_class, pending, kwargs))
# errors should be ready
if errors:
validation_list = []
msg = 'Line %(line)d (severity %(level)d): %(message)s'
for error in errors:
#from docutils.parsers.rst module:
#debug(0), info(1), warning(2), error(3), severe(4)
if error.level > 1:
validation_list.append(ValidationError(
msg, code=error.type.lower(),
params=dict(line=error.line, level=error.level, message=error.message)))
if validation_list:
raise ValidationError(validation_list)
[docs]def ensure_html(text):
try:
validate_restructuredtext(text)
except ValidationError as e:
return '<pre>{}</pre>'.format(text)
else:
return restructuredtext(text)
[docs]def ensure_string(data):
"""
Ensure that we have a str object from data which can be either a str in
python 2 or a bytes in python 3
"""
if data is not None:
if isinstance(data, six.binary_type):
return data.decode('utf-8')
return data
return ''