crieur 1.4.0__py3-none-any.whl → 1.6.0__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.4.0"
3
+ VERSION = "1.6.0"
4
4
  ROOT_DIR = Path(__file__).parent
crieur/cli.py CHANGED
@@ -29,6 +29,7 @@ def generate(
29
29
  source_path: Path = Path() / "sources",
30
30
  templates_path: Path = Path(__file__).parent / "templates",
31
31
  without_statics: bool = False,
32
+ feed_limit: int = 10,
32
33
  ):
33
34
  """Generate a new revue website.
34
35
 
@@ -39,11 +40,12 @@ def generate(
39
40
  :source_path: Path where stylo source were downloaded (default: /sources/).
40
41
  :template_path: Path where templates are located (default: @crieur/templates/).
41
42
  :without_statics: Do not copy statics if True (default: False).
43
+ :feed_limit: Number of max items in the feed (default: 10).
42
44
  """
43
45
  numeros = []
44
46
  for numero in each_folder_from(source_path):
45
47
  for corpus_yaml in each_file_from(numero, pattern="*.yaml"):
46
- numero = configure_numero(corpus_yaml)
48
+ numero = configure_numero(corpus_yaml, base_url)
47
49
  numeros.append(numero)
48
50
 
49
51
  keywords = collect_keywords(numeros)
@@ -58,9 +60,7 @@ def generate(
58
60
  target_path,
59
61
  templates_path,
60
62
  )
61
- generate_feed(
62
- title, base_url, numeros, extra_vars, target_path, number=10, lang="fr"
63
- )
63
+ generate_feed(title, base_url, numeros, extra_vars, target_path, number=feed_limit)
64
64
 
65
65
  if not without_statics:
66
66
  static_path_local = Path(__file__).parent / "statics"
crieur/generator.py CHANGED
@@ -87,9 +87,7 @@ def generate_html(
87
87
  (author_folder / "index.html").write_text(content)
88
88
 
89
89
 
90
- def generate_feed(
91
- title, base_url, numeros, extra_vars, target_path, number=10, lang="fr"
92
- ):
90
+ def generate_feed(title, base_url, numeros, extra_vars, target_path, number, lang="fr"):
93
91
  feed = FeedGenerator()
94
92
  feed.id(base_url)
95
93
  feed.title(title)
@@ -115,7 +113,7 @@ def generate_feed(
115
113
  )
116
114
  for author in article.authors:
117
115
  feed_entry.author(name=str(author))
118
- feed_entry.summary(summary=md(article.content_md), type="html")
116
+ feed_entry.summary(summary=article.content_html, type="html")
119
117
  if article.keywords:
120
118
  for keyword in article.keywords:
121
119
  feed_entry.category(term=keyword.name)
crieur/models.py CHANGED
@@ -1,12 +1,67 @@
1
1
  from dataclasses import dataclass
2
+ from datetime import datetime
3
+ from textwrap import dedent
2
4
  from typing import Optional
3
5
 
6
+ import mistune
4
7
  from dataclass_wizard import DatePattern, DumpMeta, YAMLWizard
5
8
  from dataclass_wizard import errors as dw_errors
9
+ from PIL import Image, UnidentifiedImageError
6
10
  from slugify import slugify
7
11
  from yaml.composer import ComposerError
8
12
 
9
13
 
14
+ class ImgsWithSizesRenderer(mistune.HTMLRenderer):
15
+ """Renders images as <figure>s and add sizes."""
16
+
17
+ def __init__(
18
+ self,
19
+ escape=True,
20
+ allow_harmful_protocols=None,
21
+ base_url=None,
22
+ article=None,
23
+ ):
24
+ super().__init__()
25
+ self._base_url = base_url
26
+ self._article = article
27
+
28
+ def paragraph(self, text):
29
+ # In case of a figure, we do not want the (non-standard) paragraph.
30
+ if text.strip().startswith("<figure>"):
31
+ return text
32
+ return super().paragraph(text)
33
+
34
+ def image(self, alt, url):
35
+ if self._article.images_path is None:
36
+ print(f"Image with URL `{url}` is discarded.")
37
+ return ""
38
+ full_path = self._article.images_path.resolve().parent / url
39
+ try:
40
+ image = Image.open(full_path)
41
+ except (IsADirectoryError, FileNotFoundError, UnidentifiedImageError):
42
+ print(f"`{full_path}` is not a valid image.")
43
+ return ""
44
+ width, height = image.size
45
+ caption = f"<figcaption>{alt}</figcaption>" if alt else ""
46
+ full_url = f"{self._base_url}{self._article.url}{url}"
47
+ return dedent(
48
+ f"""\
49
+ <figure>
50
+ <a href="{full_url}"
51
+ title="Cliquer pour une version haute résolution">
52
+ <img
53
+ src="{full_url}"
54
+ width="{width}" height="{height}"
55
+ loading="lazy"
56
+ decoding="async"
57
+ alt="{alt}">
58
+ </a>
59
+ {caption}
60
+ </figure>
61
+ """
62
+ )
63
+
64
+
10
65
  @dataclass
11
66
  class Numero(YAMLWizard):
12
67
  _id: str
@@ -18,7 +73,7 @@ class Numero(YAMLWizard):
18
73
  def __post_init__(self):
19
74
  self.slug = slugify(self.name)
20
75
 
21
- def configure_articles(self, yaml_path):
76
+ def configure_articles(self, yaml_path, base_url):
22
77
  # Preserves abstract_fr key (vs. abstract-fr) when converting to_yaml()
23
78
  DumpMeta(key_transform="SNAKE").bind_to(Article)
24
79
 
@@ -40,6 +95,15 @@ class Numero(YAMLWizard):
40
95
  print(f"Metadata error in `{article['article']['title']}`:")
41
96
  print(e)
42
97
  exit(1)
98
+ if not loaded_article.date:
99
+ print(f"Article `{loaded_article.title}` skipped (no date).")
100
+ continue
101
+ if loaded_article.date > datetime.today().date():
102
+ print(
103
+ f"Article `{loaded_article.title}` skipped "
104
+ f"(future date: {loaded_article.date})."
105
+ )
106
+ continue
43
107
  if not loaded_article.id:
44
108
  loaded_article.id = article_slug
45
109
  loaded_article.content_md = (
@@ -51,6 +115,15 @@ class Numero(YAMLWizard):
51
115
  else None
52
116
  )
53
117
  loaded_article.numero = self
118
+ md = mistune.create_markdown(
119
+ renderer=ImgsWithSizesRenderer(
120
+ escape=False,
121
+ base_url=base_url,
122
+ article=loaded_article,
123
+ ),
124
+ plugins=["footnotes", "superscript"],
125
+ )
126
+ loaded_article.content_html = md(loaded_article.content_md)
54
127
  loaded_articles.append(loaded_article)
55
128
  self.articles = sorted(loaded_articles, reverse=True)
56
129
 
@@ -84,7 +157,7 @@ class Article(YAMLWizard):
84
157
  return f"numero/{self.numero.slug}/article/{self.id}/"
85
158
 
86
159
 
87
- def configure_numero(yaml_path):
160
+ def configure_numero(yaml_path, base_url):
88
161
  # Preserves abstract_fr key (vs. abstract-fr) when converting to_yaml()
89
162
  DumpMeta(key_transform="SNAKE").bind_to(Numero)
90
163
 
@@ -93,7 +166,7 @@ def configure_numero(yaml_path):
93
166
  except ComposerError:
94
167
  numero = Numero.from_yaml(yaml_path.read_text().split("---")[1])
95
168
 
96
- numero.configure_articles(yaml_path)
169
+ numero.configure_articles(yaml_path, base_url)
97
170
  return numero
98
171
 
99
172
 
@@ -34,7 +34,7 @@
34
34
  {% endfor %}
35
35
  {% endif %}
36
36
 
37
- {{ article.content_md|markdown }}
37
+ {{ article.content_html }}
38
38
  </div>
39
39
  </article>
40
40
  {% endblock content %}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crieur
3
- Version: 1.4.0
3
+ Version: 1.6.0
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
@@ -689,6 +689,7 @@ Requires-Dist: httpx
689
689
  Requires-Dist: jinja2
690
690
  Requires-Dist: minicli
691
691
  Requires-Dist: mistune
692
+ Requires-Dist: pillow
692
693
  Requires-Dist: python-slugify
693
694
  Requires-Dist: pytz>=2025.2
694
695
  Requires-Dist: pyyaml>=6.0.2
@@ -754,6 +755,7 @@ cog.out(f"```\n{help}\n```")
754
755
  [--extra-vars EXTRA_VARS] [--target-path TARGET_PATH]
755
756
  [--source-path SOURCE_PATH]
756
757
  [--templates-path TEMPLATES_PATH] [--without-statics]
758
+ [--feed-limit FEED_LIMIT]
757
759
 
758
760
  options:
759
761
  -h, --help show this help message and exit
@@ -768,6 +770,8 @@ options:
768
770
  /sources/).
769
771
  --templates-path TEMPLATES_PATH
770
772
  --without-statics Do not copy statics if True (default: False).
773
+ --feed-limit FEED_LIMIT
774
+ Number of max items in the feed (default: 10).
771
775
 
772
776
  ```
773
777
  <!-- [[[end]]] -->
@@ -1,18 +1,18 @@
1
- crieur/__init__.py,sha256=Ut-79HZyf4hogXKB4_5_Cu9obcl9NOf1RCIU5PtDC14,77
1
+ crieur/__init__.py,sha256=OTKpyo3mBk05AW9jx7vHsWhKpHveyDwTU6fnJyxLxWo,77
2
2
  crieur/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30
3
- crieur/cli.py,sha256=aB_txstc0kVtTl91oyf2181TOhaoB-bNqtEKs9usEUw,5654
4
- crieur/generator.py,sha256=KhsSudLYauHVFvUsZEB5iEbqsnLBZFoSYCM1N3SUzOk,4397
5
- crieur/models.py,sha256=PiLiPR834b7Mrtm4x0kxTtiCx4iC4s7RYbUOY7Xawyo,6139
3
+ crieur/cli.py,sha256=MyqGylQE691ILFnR_58925erUbluC30FrOLuok0PAB8,5737
4
+ crieur/generator.py,sha256=wbMeE0jCEy7kw8jhjscoeTjj8nyRPv6jqA76ZQeCdg8,4386
5
+ crieur/models.py,sha256=KrW6gy7z0RzDBdUAd2VgwzcNkMOpdRPnu9JxvkNGZ8c,8727
6
6
  crieur/utils.py,sha256=kIdxpd5LgVv13Lx2aEXzjQttBDtcppRlwNsH0vwX8f0,1566
7
7
  crieur/statics/pico.css,sha256=VdrimW9PLcEIzqJ__s062OrwBj_Jb6jZIwbtdqOtM-w,93407
8
- crieur/templates/article.html,sha256=4Y1sjBR1nM_ff4yVGgiVlZU1tmnfBMXAjTTSAhqoiA4,1288
8
+ crieur/templates/article.html,sha256=AgqMIM0HG9IDFZ8tArsCLgbLmx86oY-HC6Jj2lgzUMg,1281
9
9
  crieur/templates/author.html,sha256=1VHZi6Wld1gWYPfeW3cEJ2ULOKrp9xoCVRhDjPUDdHg,420
10
10
  crieur/templates/base.html,sha256=4ZOLAnmle0_m8Y3lWT6wcH8f-_7SymxEDeIUzDQNnks,1626
11
11
  crieur/templates/homepage.html,sha256=7YG7kA4AFuyrSuqWeFAVj09ogwsybE7w0-NKMLWms5s,2994
12
12
  crieur/templates/keyword.html,sha256=Hv3Ep3R6oN5pBw14gfQT-aeqEiuFiatmVZLWn5hR1e4,428
13
13
  crieur/templates/numero.html,sha256=F7hCaAHJ1WRWxD_zfhJzyLaiwXblJWJF7DUTy41Mnu8,1849
14
- crieur-1.4.0.dist-info/METADATA,sha256=vUXW6GP2vusNlON3DJgxsg3mp_RhafoohDR-y9DLsrA,44878
15
- crieur-1.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- crieur-1.4.0.dist-info/entry_points.txt,sha256=edmbmPxs9QXyvSMpPJBDPGw3vZOJEKqXJhysYNx3QSM,43
17
- crieur-1.4.0.dist-info/licenses/LICENSE,sha256=F5acw9_laHeyi4wPmQyf_ttyz81VqCIwScwO8C1FhXU,34519
18
- crieur-1.4.0.dist-info/RECORD,,
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,,
File without changes