crieur 2.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crieur/__init__.py +4 -0
- crieur/__main__.py +3 -0
- crieur/cli.py +169 -0
- crieur/generator.py +181 -0
- crieur/models.py +408 -0
- crieur/plugins.py +110 -0
- crieur/statics/font_caslon_pro.css +26 -0
- crieur/statics/font_noto_sans.css +33 -0
- crieur/statics/pico.css +2835 -0
- crieur/styles/apa.csl +2133 -0
- crieur/templates/article.html +44 -0
- crieur/templates/author.html +52 -0
- crieur/templates/authors.html +21 -0
- crieur/templates/base.html +307 -0
- crieur/templates/blog.html +23 -0
- crieur/templates/homepage.html +99 -0
- crieur/templates/keyword.html +49 -0
- crieur/templates/keywords.html +24 -0
- crieur/templates/numero.html +46 -0
- crieur/templates/numeros.html +24 -0
- crieur/typography.py +93 -0
- crieur/utils.py +56 -0
- crieur-2.0.2.dist-info/METADATA +838 -0
- crieur-2.0.2.dist-info/RECORD +27 -0
- crieur-2.0.2.dist-info/WHEEL +4 -0
- crieur-2.0.2.dist-info/entry_points.txt +2 -0
- crieur-2.0.2.dist-info/licenses/LICENSE +661 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block content %}
|
|
4
|
+
{% for numero in numeros|reverse %}
|
|
5
|
+
<div class="aside">
|
|
6
|
+
<hgroup>
|
|
7
|
+
<h2><a href="{{ base_url }}numero/{{ numero.slug }}/">{{ numero.title_f }}</a></h2>
|
|
8
|
+
<p class="muted"><small>{{ numero.date.strftime('%d %B %Y') }}</small></p>
|
|
9
|
+
</hgroup>
|
|
10
|
+
<ul>
|
|
11
|
+
{% for article in numero.articles %}
|
|
12
|
+
<li>
|
|
13
|
+
<a href="{{ base_url }}{{ article.url }}">{{ article.title_f }}</a>
|
|
14
|
+
par
|
|
15
|
+
{% for author in article.authors -%}
|
|
16
|
+
<em>{{ author.forname }} {{ author.surname }}{%- if not loop.last -%}, {% endif %}</em>
|
|
17
|
+
{%- endfor %}
|
|
18
|
+
<nobr><span class="muted"><small>({{ article.date.strftime('%d %B %Y') }})</small></span></nobr>
|
|
19
|
+
</li>
|
|
20
|
+
{% endfor %}
|
|
21
|
+
</ul>
|
|
22
|
+
</div>
|
|
23
|
+
{% endfor %}
|
|
24
|
+
{% endblock content %}
|
crieur/typography.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import html.entities
|
|
2
|
+
import unicodedata
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
import regex # pour le support de "\p{}"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class Caractere:
|
|
10
|
+
unicode: str
|
|
11
|
+
html: str
|
|
12
|
+
|
|
13
|
+
def __init__(self, name: str):
|
|
14
|
+
self.unicode = unicodedata.lookup(name)
|
|
15
|
+
codepoint = ord(self.unicode)
|
|
16
|
+
html_name = html.entities.codepoint2name.get(codepoint, f"#{codepoint}")
|
|
17
|
+
self.html = f"&{html_name};"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
ESPACE_INSECABLE = Caractere(name="NO-BREAK SPACE")
|
|
21
|
+
ESPACE_FINE_INSECABLE = Caractere(name="NARROW NO-BREAK SPACE")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def assemble_regexes(*regexes):
|
|
25
|
+
return "|".join(regexes)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def build_regex(avant, apres):
|
|
29
|
+
# \p{} permet de reconnaître un caractère par sa catégorie Unicode
|
|
30
|
+
# "Zs" est la catégorie "Separator, space".
|
|
31
|
+
return (
|
|
32
|
+
rf"((?P<avant>{avant})"
|
|
33
|
+
+ rf"(\p{{Zs}}|{ESPACE_INSECABLE.html})"
|
|
34
|
+
+ rf"(?P<apres>{apres}))"
|
|
35
|
+
+ r"(?!(.(?!<svg))*<\/svg>)"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
RE_ESPACE_FINE_INSECABLE = regex.compile(
|
|
40
|
+
assemble_regexes(
|
|
41
|
+
build_regex(r"\w?", r"[;\?!]"), # Ponctuations doubles.
|
|
42
|
+
build_regex(
|
|
43
|
+
r"\d", r"([ghj]|min|sec|images|mm|hab|kg|mg|µg|L|km|°C|GHz)(\b|$)"
|
|
44
|
+
), # Unités.
|
|
45
|
+
build_regex(r"\d", r"(Mo|Ko|Go|Mb|Kb|Gb)(\b|$)"), # Tailles de fichiers.
|
|
46
|
+
build_regex(r"\d", r"%"), # Pourcentages.
|
|
47
|
+
build_regex(r"\d", r"€"), # Symboles monétaires.
|
|
48
|
+
build_regex(r"\d", r"\d"), # Séparateurs de milliers.
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def insere_espaces_fines_insecables(texte):
|
|
54
|
+
return RE_ESPACE_FINE_INSECABLE.sub(
|
|
55
|
+
r"\g<avant>" + ESPACE_FINE_INSECABLE.unicode + r"\g<apres>", texte
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
RE_ESPACE_INSECABLE = regex.compile(
|
|
60
|
+
assemble_regexes(
|
|
61
|
+
build_regex(r"\w?", r":"), # Deux points.
|
|
62
|
+
build_regex(r"«", r""), # Guillemets en chevrons.
|
|
63
|
+
build_regex(r"", r"»"), # Guillemets en chevrons.
|
|
64
|
+
build_regex(
|
|
65
|
+
rf"\b(\d|{ESPACE_FINE_INSECABLE.html})+", r"(?!\d)\w"
|
|
66
|
+
), # Nombre suivi de lettres.
|
|
67
|
+
build_regex(r"(M\.|Mme)", r"\w"), # Titres (Monsieur, Madame).
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def insere_espaces_insecables(texte):
|
|
73
|
+
return RE_ESPACE_INSECABLE.sub(
|
|
74
|
+
r"\g<avant>" + ESPACE_INSECABLE.unicode + r"\g<apres>", texte
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def encode_espaces_insecables_en_html(texte):
|
|
79
|
+
for caractere in (ESPACE_INSECABLE, ESPACE_FINE_INSECABLE):
|
|
80
|
+
texte = texte.replace(caractere.unicode, caractere.html)
|
|
81
|
+
return texte
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def typographie(texte, html=False):
|
|
85
|
+
"""
|
|
86
|
+
Utilise les espaces insécables fines ou normales lorsque c’est approprié
|
|
87
|
+
|
|
88
|
+
https://fr.wikipedia.org/wiki/Espace_ins%C3%A9cable#En_France
|
|
89
|
+
"""
|
|
90
|
+
res = insere_espaces_fines_insecables(insere_espaces_insecables(texte))
|
|
91
|
+
if html:
|
|
92
|
+
res = encode_espaces_insecables_en_html(res)
|
|
93
|
+
return res
|
crieur/utils.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
html_comments_re = re.compile(r"<!--.*?-->")
|
|
5
|
+
html_tags_re = re.compile(r"<[^>]*>")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def strip_html_comments(value):
|
|
9
|
+
if not value:
|
|
10
|
+
return ""
|
|
11
|
+
return html_comments_re.sub("", value)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def strip_html_tags(value):
|
|
15
|
+
if not value:
|
|
16
|
+
return ""
|
|
17
|
+
return html_tags_re.sub("", value)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def each_file_from(source_dir, pattern="*.html", exclude=None):
|
|
21
|
+
"""Walk across the `source_dir` and return the html file paths."""
|
|
22
|
+
for path in _each_path_from(source_dir, pattern=pattern, exclude=exclude):
|
|
23
|
+
if path.is_file():
|
|
24
|
+
yield path
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def each_folder_from(source_dir, exclude=None):
|
|
28
|
+
"""Walk across the `source_dir` and return the folder paths."""
|
|
29
|
+
for path in _each_path_from(source_dir, exclude=exclude):
|
|
30
|
+
if path.is_dir():
|
|
31
|
+
yield path
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _each_path_from(source_dir, pattern="*", exclude=None):
|
|
35
|
+
for path in sorted(Path(source_dir).glob(pattern)):
|
|
36
|
+
if exclude is not None and path.name in exclude:
|
|
37
|
+
continue
|
|
38
|
+
yield path
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def neighborhood(iterable, first=None, last=None):
|
|
42
|
+
"""
|
|
43
|
+
Yield the (index, previous, current, next) items given an iterable.
|
|
44
|
+
|
|
45
|
+
You can specify a `first` and/or `last` item for bounds.
|
|
46
|
+
"""
|
|
47
|
+
index = 1
|
|
48
|
+
iterator = iter(iterable)
|
|
49
|
+
previous = first
|
|
50
|
+
current = next(iterator) # Throws StopIteration if empty.
|
|
51
|
+
for next_ in iterator:
|
|
52
|
+
yield (index, previous, current, next_)
|
|
53
|
+
previous = current
|
|
54
|
+
index += 1
|
|
55
|
+
current = next_
|
|
56
|
+
yield (index, previous, current, last)
|