crieur 1.3.1__py3-none-any.whl → 1.4.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.3.1"
3
+ VERSION = "1.4.0"
4
4
  ROOT_DIR = Path(__file__).parent
crieur/cli.py CHANGED
@@ -9,7 +9,7 @@ import httpx
9
9
  from minicli import cli, run
10
10
 
11
11
  from . import VERSION
12
- from .generator import generate_html
12
+ from .generator import generate_feed, generate_html
13
13
  from .models import collect_authors, collect_keywords, configure_numero
14
14
  from .utils import each_file_from, each_folder_from
15
15
 
@@ -58,6 +58,9 @@ def generate(
58
58
  target_path,
59
59
  templates_path,
60
60
  )
61
+ generate_feed(
62
+ title, base_url, numeros, extra_vars, target_path, number=10, lang="fr"
63
+ )
61
64
 
62
65
  if not without_statics:
63
66
  static_path_local = Path(__file__).parent / "statics"
@@ -101,14 +104,27 @@ def stylo(
101
104
  with httpx.stream("GET", url, timeout=None) as r:
102
105
  for data in r.iter_bytes():
103
106
  fd.write(data)
107
+ else:
108
+ print(
109
+ f"Source already exists: `{zip_path}` (no download). "
110
+ "Use the `--force` option to download it again"
111
+ )
104
112
 
105
113
  target_path = sources_path / f"{i + 1}-{stylo_id}"
106
114
  try:
107
115
  with zipfile.ZipFile(zip_path, "r") as zip_ref:
108
116
  zip_ref.extractall(target_path)
109
- print(f"Data downloaded and extracted to {target_path}")
117
+ print(f"Data extracted to {target_path}")
110
118
  except zipfile.BadZipFile:
119
+ zip_problematic_path = Path() / f"problematic-export-{i + 1}-{stylo_id}.zip"
120
+ zip_path.rename(zip_problematic_path)
111
121
  print(f"Unable to find corpus with id {stylo_id}!")
122
+ print(
123
+ f"Check out the content of {zip_problematic_path} to try to understand."
124
+ )
125
+ print(
126
+ "Either you use a wrong corpus id or there is an issue with the export."
127
+ )
112
128
  return
113
129
 
114
130
 
crieur/generator.py CHANGED
@@ -1,8 +1,10 @@
1
1
  import json
2
2
  import locale
3
3
  import shutil
4
+ from datetime import datetime, timedelta, timezone
4
5
 
5
6
  import mistune
7
+ from feedgen.feed import FeedGenerator
6
8
  from jinja2 import Environment as Env
7
9
  from jinja2 import FileSystemLoader
8
10
  from slugify import slugify
@@ -83,3 +85,40 @@ def generate_html(
83
85
  author_folder = target_path / "auteur" / author.slug
84
86
  author_folder.mkdir(parents=True, exist_ok=True)
85
87
  (author_folder / "index.html").write_text(content)
88
+
89
+
90
+ def generate_feed(
91
+ title, base_url, numeros, extra_vars, target_path, number=10, lang="fr"
92
+ ):
93
+ feed = FeedGenerator()
94
+ feed.id(base_url)
95
+ feed.title(title)
96
+ feed.link(href=base_url, rel="alternate")
97
+ feed.link(href=f"{base_url}feed.xml", rel="self")
98
+ feed.language(lang)
99
+
100
+ articles = sorted(
101
+ [article for numero in numeros for article in numero.articles], reverse=True
102
+ )
103
+
104
+ for article in articles[:number]:
105
+ feed_entry = feed.add_entry(order="append")
106
+ feed_entry.id(f"{base_url}{article.url}")
107
+ feed_entry.title(article.title_f)
108
+ feed_entry.link(href=f"{base_url}{article.url}")
109
+ feed_entry.updated(
110
+ datetime.combine(
111
+ article.date,
112
+ datetime.min.time(),
113
+ tzinfo=timezone(timedelta(hours=-4), "ET"),
114
+ )
115
+ )
116
+ for author in article.authors:
117
+ feed_entry.author(name=str(author))
118
+ feed_entry.summary(summary=md(article.content_md), type="html")
119
+ if article.keywords:
120
+ for keyword in article.keywords:
121
+ feed_entry.category(term=keyword.name)
122
+
123
+ feed.atom_file(target_path / "feed.xml", pretty=True)
124
+ print(f"Generated meta-feed with {number} items.")
crieur/models.py CHANGED
@@ -2,6 +2,7 @@ from dataclasses import dataclass
2
2
  from typing import Optional
3
3
 
4
4
  from dataclass_wizard import DatePattern, DumpMeta, YAMLWizard
5
+ from dataclass_wizard import errors as dw_errors
5
6
  from slugify import slugify
6
7
  from yaml.composer import ComposerError
7
8
 
@@ -29,11 +30,16 @@ class Numero(YAMLWizard):
29
30
  )
30
31
  article_yaml_path = article_folder / f"{article_slug}.yaml"
31
32
  try:
32
- loaded_article = Article.from_yaml_file(article_yaml_path)
33
- except ComposerError:
34
- loaded_article = Article.from_yaml(
35
- article_yaml_path.read_text().split("---")[1]
36
- )
33
+ try:
34
+ loaded_article = Article.from_yaml_file(article_yaml_path)
35
+ except ComposerError:
36
+ loaded_article = Article.from_yaml(
37
+ article_yaml_path.read_text().split("---")[1]
38
+ )
39
+ except dw_errors.ParseError as e:
40
+ print(f"Metadata error in `{article['article']['title']}`:")
41
+ print(e)
42
+ exit(1)
37
43
  if not loaded_article.id:
38
44
  loaded_article.id = article_slug
39
45
  loaded_article.content_md = (
@@ -46,7 +52,7 @@ class Numero(YAMLWizard):
46
52
  )
47
53
  loaded_article.numero = self
48
54
  loaded_articles.append(loaded_article)
49
- self.articles = loaded_articles
55
+ self.articles = sorted(loaded_articles, reverse=True)
50
56
 
51
57
 
52
58
  @dataclass
@@ -65,6 +71,18 @@ class Article(YAMLWizard):
65
71
  def __post_init__(self):
66
72
  self.slug = slugify(self.title)
67
73
 
74
+ def __eq__(self, other):
75
+ return self.id == other.id
76
+
77
+ def __lt__(self, other: "Article"):
78
+ if not isinstance(other, Article):
79
+ return NotImplemented
80
+ return self.date < other.date
81
+
82
+ @property
83
+ def url(self):
84
+ return f"numero/{self.numero.slug}/article/{self.id}/"
85
+
68
86
 
69
87
  def configure_numero(yaml_path):
70
88
  # Preserves abstract_fr key (vs. abstract-fr) when converting to_yaml()
@@ -17,6 +17,8 @@
17
17
  <link rel="icon" href="data:;base64,iVBORw0KGgo=" />
18
18
  <link rel="stylesheet"
19
19
  href="{{ base_url }}statics/pico.css" />
20
+ <link rel="alternate" type="application/atom+xml"
21
+ title="Feed" href="{{ base_url }}feed.xml">
20
22
  <style>
21
23
  h1 {
22
24
  text-align: center;
@@ -97,7 +97,7 @@
97
97
  </header>
98
98
  <ul>
99
99
  {% for article in numero.articles %}
100
- <li><a href="{{ base_url }}numero/{{ numero.slug }}/article/{{ article.id }}/">{{ article.title_f }}</a></li>
100
+ <li><a href="{{ base_url }}{{ article.url }}">{{ article.title_f }}</a></li>
101
101
  {% endfor %}
102
102
  </ul>
103
103
  </article>
@@ -59,7 +59,7 @@
59
59
  {% for article in numero.articles %}
60
60
  <article>
61
61
  <header>
62
- <h3><a href="{{ base_url }}numero/{{ numero.slug }}/article/{{ article.id }}/">{{ article.title_f }}</a></h3>
62
+ <h3><a href="{{ base_url }}{{ article.url }}">{{ article.title_f }}</a></h3>
63
63
  </header>
64
64
  {{ article.subtitle_f|markdown }}
65
65
  {% if article.authors %}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crieur
3
- Version: 1.3.1
3
+ Version: 1.4.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
@@ -684,6 +684,7 @@ Classifier: Topic :: Software Development :: Build Tools
684
684
  Classifier: Topic :: Text Processing :: Markup :: Markdown
685
685
  Requires-Python: >=3.8
686
686
  Requires-Dist: dataclass-wizard
687
+ Requires-Dist: feedgen>=1.0.0
687
688
  Requires-Dist: httpx
688
689
  Requires-Dist: jinja2
689
690
  Requires-Dist: minicli
@@ -0,0 +1,18 @@
1
+ crieur/__init__.py,sha256=Ut-79HZyf4hogXKB4_5_Cu9obcl9NOf1RCIU5PtDC14,77
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
6
+ crieur/utils.py,sha256=kIdxpd5LgVv13Lx2aEXzjQttBDtcppRlwNsH0vwX8f0,1566
7
+ crieur/statics/pico.css,sha256=VdrimW9PLcEIzqJ__s062OrwBj_Jb6jZIwbtdqOtM-w,93407
8
+ crieur/templates/article.html,sha256=4Y1sjBR1nM_ff4yVGgiVlZU1tmnfBMXAjTTSAhqoiA4,1288
9
+ crieur/templates/author.html,sha256=1VHZi6Wld1gWYPfeW3cEJ2ULOKrp9xoCVRhDjPUDdHg,420
10
+ crieur/templates/base.html,sha256=4ZOLAnmle0_m8Y3lWT6wcH8f-_7SymxEDeIUzDQNnks,1626
11
+ crieur/templates/homepage.html,sha256=7YG7kA4AFuyrSuqWeFAVj09ogwsybE7w0-NKMLWms5s,2994
12
+ crieur/templates/keyword.html,sha256=Hv3Ep3R6oN5pBw14gfQT-aeqEiuFiatmVZLWn5hR1e4,428
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,,
@@ -1,18 +0,0 @@
1
- crieur/__init__.py,sha256=yOEK782pE6JekTATU6_RAyoO2v5wdzTmwTwYjrsaqco,77
2
- crieur/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30
3
- crieur/cli.py,sha256=172Rac-Tjm6idS7Uh3OKdpAJNVieN0ntm9-KdzQA6ao,4984
4
- crieur/generator.py,sha256=Vc0oOLsQMcKWQLkzHLrJf5f1W_qmoxwYsc_ktHFZjtg,3046
5
- crieur/models.py,sha256=C3ixU19G-569qv88qJQzcZSuojJezCAjtBjcNn2ksr0,5537
6
- crieur/utils.py,sha256=kIdxpd5LgVv13Lx2aEXzjQttBDtcppRlwNsH0vwX8f0,1566
7
- crieur/statics/pico.css,sha256=VdrimW9PLcEIzqJ__s062OrwBj_Jb6jZIwbtdqOtM-w,93407
8
- crieur/templates/article.html,sha256=4Y1sjBR1nM_ff4yVGgiVlZU1tmnfBMXAjTTSAhqoiA4,1288
9
- crieur/templates/author.html,sha256=1VHZi6Wld1gWYPfeW3cEJ2ULOKrp9xoCVRhDjPUDdHg,420
10
- crieur/templates/base.html,sha256=6ih6RryTPXZxR6tqlbRHPpOFUNRu90SPvdfKNLHcRRM,1522
11
- crieur/templates/homepage.html,sha256=IgYc3cyw-52U3HN1oada0drkzT0fPNyFcdiG6Pwcr9o,3027
12
- crieur/templates/keyword.html,sha256=Hv3Ep3R6oN5pBw14gfQT-aeqEiuFiatmVZLWn5hR1e4,428
13
- crieur/templates/numero.html,sha256=b9J6aW_h9ao7XlWA0Xc390ahOH5lHDI8A4iDq6tEZTo,1882
14
- crieur-1.3.1.dist-info/METADATA,sha256=FjTCJtmcpzthN9ulp96DTnu68qduEQidXFQmmr7nb44,44848
15
- crieur-1.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- crieur-1.3.1.dist-info/entry_points.txt,sha256=edmbmPxs9QXyvSMpPJBDPGw3vZOJEKqXJhysYNx3QSM,43
17
- crieur-1.3.1.dist-info/licenses/LICENSE,sha256=F5acw9_laHeyi4wPmQyf_ttyz81VqCIwScwO8C1FhXU,34519
18
- crieur-1.3.1.dist-info/RECORD,,
File without changes