Commit 225d0bf1 authored by Roland Denis's avatar Roland Denis
Browse files

Some refactoring of meso plugin, fixes and improvements

parent 760c3ef5
Pipeline #6572 passed with stages
in 1 minute and 56 seconds
from .directives import *
from .json import *
from .html_translator import *
from docutils.parsers.rst import directives, Directive
from docutils.parsers.rst.directives.parts import Contents
from docutils.transforms import frontmatter
from docutils.statemachine import StringList
from docutils import io, nodes
import dateutil.parser
from pelican import readers
from pelican.readers import PelicanHTMLTranslator
from pelican.utils import slugify
import re
from jinja2 import Environment, FileSystemLoader
import os
from . import json
###############################################################################
# Tools and filters
# Directive's options converter
def csv_converter(s):
def csv_list(s):
""" Comma separated values as a list. """
return [value.strip() for value in s.split(',')]
def names_list(names):
""" Format a list of names separated by a comma and a final 'et' """
if len(names) > 1:
return ', '.join(names[:-1]) + ' et ' + names[-1]
elif len(names) == 1:
return names[-1]
else:
return ''
def multiline_list(s):
""" List formatted as a multi-line string """
return s.splitlines()
###############################################################################
......@@ -97,18 +83,18 @@ class Meso(Directive):
optional_arguments = 10
final_argument_whitespace = True
option_spec = {
'institutesname': csv_converter,
'institutesname': multiline_list,
'url': directives.uri,
'financersname': csv_converter,
'financersname': multiline_list,
'location': str,
'gpscoordinates': csv_converter,
'gpscoordinates': multiline_list,
'contactname': str,
'contactaddress': str,
'totalcorenumber': int,
'totalstorage': int,
'totalgpunumber': int,
'totalram': int,
'accesspolicy': str,
'accesspolicy': multiline_list,
'etptnumber': float,
}
has_content = True
......@@ -130,43 +116,3 @@ def register():
directives.register_directive('meso_list', MesoList)
directives.register_directive('meso', Meso)
###############################################################################
# HTML Translator
# Extend default translator
class myHTMLTranslator(PelicanHTMLTranslator):
def __init__(self, *args, **kwargs):
# Pre-loading Jinja2 templates and filters
env = Environment(
loader=FileSystemLoader(os.path.dirname(__file__)+'/templates/'),
)
env.filters['names_list'] = names_list
self.meso_template = env.get_template('meso.tpl')
super().__init__(*args, *kwargs)
def visit_region(self, node):
self.body.append(f'<div class="region"><h3>{node["name"]}</h3>')
def depart_region(self, node):
self.body.append('</div>')
def visit_meso_list(self, node):
super().visit_section(node)
self.body.append('<div class="meso_list">')
def depart_meso_list(self, node):
self.body.append('</div>')
super().depart_section(node)
def visit_meso(self, node):
self.body.extend(self.meso_template.render(meso=node, header=True).splitlines(True))
def depart_meso(self, node):
self.body.extend(self.meso_template.render(meso=node, footer=True).splitlines(True))
# Overwrite default translator so that extensions can be chained
readers.PelicanHTMLTranslator = myHTMLTranslator
from pelican import readers
from pelican.readers import PelicanHTMLTranslator
from jinja2 import Environment, FileSystemLoader
import os
def jinja2_join_names(names, separator=', ', final_separator=' et ', end=''):
""" Join a list of names using and a final 'et' """
if len(names) > 1:
return separator.join(names[:-1]) + final_separator + names[-1] + end
elif len(names) == 1:
return names[-1] + end
else:
return ''
def jinja2_join_sentences(sentences, separator='. ', end='', trim_separator=True):
""" Join multiple sentences by given separator """
if trim_separator:
for i in range(len(sentences)):
while sentences[i][-1] == separator[0]:
sentences[i] = sentences[i][:-1]
return separator.join(sentences) + end
def jinja2_format_storage(value, power=0, units=['o', 'Kio', 'Mio', 'Gio', 'Tio', 'Pio', 'Eio'], base=1000):
""" Format storage quantity with appropriate suffix """
# The old way
while value >= base:
value /= base
power += 1
return f"{value:.3g} {units[power]}"
# Extend default translator
class myHTMLTranslator(PelicanHTMLTranslator):
def __init__(self, *args, **kwargs):
# Pre-loading Jinja2 templates and filters
env = Environment(
loader=FileSystemLoader(os.path.dirname(__file__)+'/templates/'),
)
env.filters.update({
'join_names': jinja2_join_names,
'join_sentences': jinja2_join_sentences,
'format_storage': jinja2_format_storage,
})
self.meso_template = env.get_template('meso.tpl')
super().__init__(*args, *kwargs)
def visit_region(self, node):
self.body.append(f'<div class="region"><h3>{node["name"]}</h3>')
def depart_region(self, node):
self.body.append('</div>')
def visit_meso_list(self, node):
super().visit_section(node)
self.body.append('<div class="meso_list">')
def depart_meso_list(self, node):
self.body.append('</div>')
super().depart_section(node)
def visit_meso(self, node):
self.body.extend(self.meso_template.render(meso=node, header=True).splitlines(True))
def depart_meso(self, node):
self.body.extend(self.meso_template.render(meso=node, footer=True).splitlines(True))
# Overwrite default translator so that extensions can be chained
readers.PelicanHTMLTranslator = myHTMLTranslator
from jinja2 import Template
from jinja2 import Environment, BaseLoader, Template
from textwrap import dedent
from . import directives
# set locale in order to have french date for output string
import locale
locale.setlocale(locale.LC_TIME, "fr_FR.UTF-8")
def jinja2_splitlines(s):
""" Split string by lines """
return s.splitlines()
def jinja2_rst_options(options):
""" Return lines of rst representation of given options """
for key, value in options.items():
yield f":{key}: {list_head(value)}"
for line in list_tail(value):
yield f" {line}"
def list_head(l):
""" Return first element of a list, itself if it is not a list """
if isinstance(l, list):
return l[0] if len(l) > 0 else None
else:
return l
def list_tail(l):
""" Return elements other than the first of a list, empty list if it is not a list """
if isinstance(l, list):
return l[1:]
else:
return []
def filter_options(directive, options):
""" Filters keys of given dict depending on option_sep of the directive """
return dict(((key, value) for key, value in options.items() if key.lower() in directive.option_spec))
def build_meso(meso):
""" Filters and formats attributes of a meso depending on the Meso directive """
return {
'name': meso['name'],
'options': filter_options(directives.Meso, meso),
'content': meso['fullDescription'],
}
def json_mesolist_to_rst(url):
"""
Parses a json file containing the list of mesocenters and returns an rst like describing them.
Parameters
----------
url: url
url of the json file
Returns
-------
string: the list of the mesocenters in a rst format
"""
......@@ -33,53 +70,32 @@ def json_mesolist_to_rst(url):
meso_list = {}
for meso in data['mesocentreList']:
region = meso['location']
if region in meso_list:
meso_list[region].append(meso)
else:
meso_list[region] = [meso]
keys_list = ["institutesName", "financersName", "GPSCoordinates", "accessPolicy"]
rst = "\n"
for region, mesocenters in meso_list.items():
rst += f".. region:: {region}\n\n"
for meso in mesocenters:
rst += " "*4 + f".. meso:: {meso['name']}\n"
del meso['name']
for key, val in meso.items():
if not isinstance(val, list) and key != 'fullDescription':
rst += " "*8 + f":{key}: {val}\n"
else:
if key in keys_list:
rst += " "*8 + f":{key}: {', '.join(map(str, val))}\n"
meso_list.setdefault(region, []).append(build_meso(meso))
if 'fullDescription' in meso.keys():
rst += "\n" + " "*8 + f"{meso['fullDescription']}\n"
rst += "\n"
return _json_mesolist_rst_template.render(meso_by_region=meso_list)
return rst
'''
# Pre-loading Jinja2 template as static variable
_json_mesolist_rst_template = Template(dedent("""
{%- for meso in mesolist %}
_json_mesolist_rst_env = Environment(loader=BaseLoader)
_json_mesolist_rst_env.filters.update({
'splitlines': jinja2_splitlines,
'rst_options': jinja2_rst_options,
})
_json_mesolist_rst_template = _json_mesolist_rst_env.from_string(dedent("""
{% for region, mesolist in meso_by_region.items() -%}
.. region:: {{ region }}
{% for meso in mesolist %}
.. meso:: {{ meso['name'] }}
{%- for key, val in meso.items() -%}
{%- if key not in ["name", "institutesName", "
:{{ key }}:
{%- for l in meso["options"] | rst_options %}
{{ l }}
{%- endfor %}
:institutesname:
{%- for institute in meso['institutesName'] %}
{{ institute }}
{% for l in meso["content"] | splitlines %}
{{ l }}
{%- endfor %}
:url: <{{ meso['url'] }}>
:financersname:
{%- for financer in meso['financersName'] %}
{{ financer }}
{%- endfor %}
:location: {{ meso['location'] }}
:gpscoordinates: {{ meso['GPSCoordinates'] }}
:contactname: {{ meso['contactName'] }}
{%- endfor -%}
"""))
'''
{% endfor %}
"""))
......@@ -34,17 +34,17 @@
{% endif %}
{% if meso['institutesname'] %}
<p><img src="../theme/img/employer.png" alt="Institutions" title="Institutions" />
{{ meso['institutesname'] | names_list }}
{{ meso['institutesname'] | join_names }}
</p>
{% endif %}
{% if meso['financersname'] %}
<p class="collapse"><img src="../theme/img/piggy_bank.png" alt="Financeurs" title="Financeurs" />
{{ meso['financersname'] | names_list }}
{{ meso['financersname'] | join_names }}
</p>
{% endif %}
{% if meso['accesspolicy'] %}
<p class="collapse"><img src="../theme/img/contract.png" alt="Conditions d'accès" title="Conditions d'accès" />
{{ meso['accesspolicy'] }}
{{ meso['accesspolicy'] | join_sentences }}
</p>
{% endif %}
</div>
......@@ -56,7 +56,7 @@
{% endif %}
{% if meso['totalram'] %}
<p class="col-sm"><img src="../theme/img/memory.png" alt="Mémoire" title="Mémoire" />
{{ meso['totalram'] }} Go
{{ meso['totalram'] | format_storage(3) }}
</p>
{% endif %}
{% if meso['totalgpunumber'] %}
......@@ -66,7 +66,7 @@
{% endif %}
{% if meso['totalstorage'] %}
<p class="col-sm"><img src="../theme/img/floppy.png" alt="Stockage" title="Stockage"/>
{{ meso['totalstorage'] }} To
{{ meso['totalstorage'] | format_storage(4) }}
</p>
{% endif %}
</div>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment