crieur 1.6.0__py3-none-any.whl → 1.8.1__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.

Potentially problematic release.


This version of crieur might be problematic. Click here for more details.

crieur/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  from pathlib import Path
2
2
 
3
- VERSION = "1.6.0"
3
+ VERSION = "1.8.1"
4
4
  ROOT_DIR = Path(__file__).parent
crieur/cli.py CHANGED
@@ -27,6 +27,7 @@ def generate(
27
27
  extra_vars: str = "",
28
28
  target_path: Path = Path() / "public",
29
29
  source_path: Path = Path() / "sources",
30
+ statics_path: Path = Path(__file__).parent / "statics",
30
31
  templates_path: Path = Path(__file__).parent / "templates",
31
32
  without_statics: bool = False,
32
33
  feed_limit: int = 10,
@@ -38,6 +39,7 @@ def generate(
38
39
  :extra_vars: stringified JSON extra vars passed to the templates.
39
40
  :target_path: Path where site is built (default: /public/).
40
41
  :source_path: Path where stylo source were downloaded (default: /sources/).
42
+ :statics_path: Path where statics are located (default: @crieur/statics/).
41
43
  :template_path: Path where templates are located (default: @crieur/templates/).
42
44
  :without_statics: Do not copy statics if True (default: False).
43
45
  :feed_limit: Number of max items in the feed (default: 10).
@@ -63,8 +65,7 @@ def generate(
63
65
  generate_feed(title, base_url, numeros, extra_vars, target_path, number=feed_limit)
64
66
 
65
67
  if not without_statics:
66
- static_path_local = Path(__file__).parent / "statics"
67
- shutil.copytree(static_path_local, target_path / "statics", dirs_exist_ok=True)
68
+ shutil.copytree(statics_path, target_path / "statics", dirs_exist_ok=True)
68
69
 
69
70
 
70
71
  @cli
crieur/generator.py CHANGED
@@ -2,6 +2,7 @@ import json
2
2
  import locale
3
3
  import shutil
4
4
  from datetime import datetime, timedelta, timezone
5
+ from pathlib import Path
5
6
 
6
7
  import mistune
7
8
  from feedgen.feed import FeedGenerator
@@ -10,6 +11,7 @@ from jinja2 import FileSystemLoader
10
11
  from slugify import slugify
11
12
 
12
13
  from . import VERSION
14
+ from .typography import typographie
13
15
  from .utils import neighborhood
14
16
 
15
17
  locale.setlocale(locale.LC_ALL, "")
@@ -24,12 +26,22 @@ def markdown(value):
24
26
  return md(value) if value else ""
25
27
 
26
28
 
29
+ def typography(value):
30
+ value = value.replace("\\ ", " ")
31
+ return typographie(value) if value else ""
32
+
33
+
27
34
  def generate_html(
28
35
  title, base_url, numeros, keywords, authors, extra_vars, target_path, templates_path
29
36
  ):
30
- environment = Env(loader=FileSystemLoader(str(templates_path)))
37
+ environment = Env(
38
+ loader=FileSystemLoader(
39
+ [str(templates_path), str(Path(__file__).parent / "templates")]
40
+ )
41
+ )
31
42
  environment.filters["slugify"] = slugify_
32
43
  environment.filters["markdown"] = markdown
44
+ environment.filters["typography"] = typography
33
45
 
34
46
  extra_vars = json.loads(extra_vars) if extra_vars else {}
35
47
 
crieur/models.py CHANGED
@@ -10,8 +10,22 @@ from PIL import Image, UnidentifiedImageError
10
10
  from slugify import slugify
11
11
  from yaml.composer import ComposerError
12
12
 
13
+ from .typography import typographie
13
14
 
14
- class ImgsWithSizesRenderer(mistune.HTMLRenderer):
15
+
16
+ class FrenchTypographyRenderer(mistune.HTMLRenderer):
17
+ """Apply French typographic rules to text."""
18
+
19
+ def text(self, text):
20
+ text = text.replace("\\ ", " ")
21
+ return typographie(super().text(text), html=True)
22
+
23
+ def block_html(self, html):
24
+ html = html.replace("\\ ", " ")
25
+ return typographie(super().block_html(html), html=True)
26
+
27
+
28
+ class ImgsWithSizesRenderer(FrenchTypographyRenderer):
15
29
  """Renders images as <figure>s and add sizes."""
16
30
 
17
31
  def __init__(
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crieur
3
- Version: 1.6.0
3
+ Version: 1.8.1
4
4
  Summary: A Static Revue Generator.
5
5
  Project-URL: Homepage, https://gitlab.huma-num.fr/ecrinum/crieur
6
6
  Project-URL: Issues, https://gitlab.huma-num.fr/ecrinum/crieur/-/issues
@@ -693,6 +693,7 @@ Requires-Dist: pillow
693
693
  Requires-Dist: python-slugify
694
694
  Requires-Dist: pytz>=2025.2
695
695
  Requires-Dist: pyyaml>=6.0.2
696
+ Requires-Dist: regex>=2024.11.6
696
697
  Requires-Dist: tzdata>=2025.2
697
698
  Requires-Dist: unidecode
698
699
  Provides-Extra: dev
@@ -754,6 +755,7 @@ cog.out(f"```\n{help}\n```")
754
755
  ```
755
756
  [--extra-vars EXTRA_VARS] [--target-path TARGET_PATH]
756
757
  [--source-path SOURCE_PATH]
758
+ [--statics-path STATICS_PATH]
757
759
  [--templates-path TEMPLATES_PATH] [--without-statics]
758
760
  [--feed-limit FEED_LIMIT]
759
761
 
@@ -768,6 +770,9 @@ options:
768
770
  --source-path SOURCE_PATH
769
771
  Path where stylo source were downloaded (default:
770
772
  /sources/).
773
+ --statics-path STATICS_PATH
774
+ Path where statics are located (default:
775
+ @crieur/statics/).
771
776
  --templates-path TEMPLATES_PATH
772
777
  --without-statics Do not copy statics if True (default: False).
773
778
  --feed-limit FEED_LIMIT
@@ -1,8 +1,9 @@
1
- crieur/__init__.py,sha256=OTKpyo3mBk05AW9jx7vHsWhKpHveyDwTU6fnJyxLxWo,77
1
+ crieur/__init__.py,sha256=O8R0eSSNMbXSylnPd6kYLTSZhVo0917hSfC31AX71f0,77
2
2
  crieur/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30
3
- crieur/cli.py,sha256=MyqGylQE691ILFnR_58925erUbluC30FrOLuok0PAB8,5737
4
- crieur/generator.py,sha256=wbMeE0jCEy7kw8jhjscoeTjj8nyRPv6jqA76ZQeCdg8,4386
5
- crieur/models.py,sha256=KrW6gy7z0RzDBdUAd2VgwzcNkMOpdRPnu9JxvkNGZ8c,8727
3
+ crieur/cli.py,sha256=trYYSwcYsyPoWluZSVLoSA-8w86uQy3Wnw_w6724g8k,5809
4
+ crieur/generator.py,sha256=5vryuODzvfvVQv7eUrMzIsjPWBAY3ZOFplFn6VW6SE8,4688
5
+ crieur/models.py,sha256=I9lOLvNxCyQq-Yot69TkWsZGRAUYdv68i-qzjQ8nevk,9136
6
+ crieur/typography.py,sha256=zZHJLZ8aUslMuiNX6z4buKNDZuj7gcrUxcIGACWmIHw,2759
6
7
  crieur/utils.py,sha256=kIdxpd5LgVv13Lx2aEXzjQttBDtcppRlwNsH0vwX8f0,1566
7
8
  crieur/statics/pico.css,sha256=VdrimW9PLcEIzqJ__s062OrwBj_Jb6jZIwbtdqOtM-w,93407
8
9
  crieur/templates/article.html,sha256=AgqMIM0HG9IDFZ8tArsCLgbLmx86oY-HC6Jj2lgzUMg,1281
@@ -11,8 +12,8 @@ crieur/templates/base.html,sha256=4ZOLAnmle0_m8Y3lWT6wcH8f-_7SymxEDeIUzDQNnks,16
11
12
  crieur/templates/homepage.html,sha256=7YG7kA4AFuyrSuqWeFAVj09ogwsybE7w0-NKMLWms5s,2994
12
13
  crieur/templates/keyword.html,sha256=Hv3Ep3R6oN5pBw14gfQT-aeqEiuFiatmVZLWn5hR1e4,428
13
14
  crieur/templates/numero.html,sha256=F7hCaAHJ1WRWxD_zfhJzyLaiwXblJWJF7DUTy41Mnu8,1849
14
- crieur-1.6.0.dist-info/METADATA,sha256=OCG3y13RZyHppOrUhjvC5v_WO7e1bJj6Vd1TedJYRNk,45046
15
- crieur-1.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- crieur-1.6.0.dist-info/entry_points.txt,sha256=edmbmPxs9QXyvSMpPJBDPGw3vZOJEKqXJhysYNx3QSM,43
17
- crieur-1.6.0.dist-info/licenses/LICENSE,sha256=F5acw9_laHeyi4wPmQyf_ttyz81VqCIwScwO8C1FhXU,34519
18
- crieur-1.6.0.dist-info/RECORD,,
15
+ crieur-1.8.1.dist-info/METADATA,sha256=HORg94MhKI8ug2soyYvj9RtLYaJD9ZUGuk3ITxx4A5c,45269
16
+ crieur-1.8.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
17
+ crieur-1.8.1.dist-info/entry_points.txt,sha256=edmbmPxs9QXyvSMpPJBDPGw3vZOJEKqXJhysYNx3QSM,43
18
+ crieur-1.8.1.dist-info/licenses/LICENSE,sha256=F5acw9_laHeyi4wPmQyf_ttyz81VqCIwScwO8C1FhXU,34519
19
+ crieur-1.8.1.dist-info/RECORD,,
File without changes