summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild-concerts.py114
-rw-r--r--helpers.py112
2 files changed, 113 insertions, 113 deletions
diff --git a/build-concerts.py b/build-concerts.py
index 43dce57..7b0f75d 100755
--- a/build-concerts.py
+++ b/build-concerts.py
@@ -1,16 +1,13 @@
#!/usr/bin/env python3
from contextlib import contextmanager
-from dataclasses import dataclass
from datetime import datetime
import locale
-from operator import attrgetter
from pathlib import Path
import re
from sys import argv
-from typing import Iterator, Optional
-from helpers import relative_path
+from helpers import guess_language, read_concerts, relative_path
# TODO: change some jargon:
@@ -18,115 +15,6 @@ from helpers import relative_path
# - canceled => warning
-LICENSE_URLS = {
- 'CC0': 'https://creativecommons.org/publicdomain/zero',
- 'CC BY': 'https://creativecommons.org/licenses/by',
- 'CC BY-SA': 'https://creativecommons.org/licenses/by-sa',
-}
-
-LICENSE_RE = re.compile(
- '('+'|'.join(LICENSE_URLS.keys())+')' + ' ([0-9.]+)'
-)
-
-
-@dataclass
-class LicenseInfo:
- tag: str
- version: str
-
- @classmethod
- def deserialize(cls, info):
- if info is None:
- return None
- return cls(*LICENSE_RE.fullmatch(info).groups())
-
- def format(self):
- url = f'{LICENSE_URLS[self.tag]}/{self.version}/'
-
- return f'<a href="{url}" target="_blank">{self.tag}</a>'
-
-
-@dataclass
-class Illustration:
- file: str
- alt_text: str
- source_name: str
- source_link: Optional[str]
- license_info: Optional[LicenseInfo]
-
- @classmethod
- def deserialize(cls, d):
- return cls(d['pic_file'],
- d['pic_alt'],
- d['pic_src'],
- d['pic_link'],
- LicenseInfo.deserialize(d['pic_license']))
-
-
-@dataclass
-class Concert:
- time: datetime
- place: str
- address: str
- pieces: Iterator[str]
- instructions: str
- illustration: Illustration
- warning: Optional[str]
-
- @classmethod
- def deserialize(cls, d):
- return cls(
- time=datetime.strptime(d['time'], '%d/%m/%Y %Hh%M'),
- place=d['place'],
- address=d['address'],
- pieces=d['pieces'],
- instructions=d['instructions'],
- illustration=Illustration.deserialize(d),
- warning=d['warning']
- )
-
-
-def optional(line):
- return f'(?:{line})?'
-
-
-CONCERT_LINES = (
- r'QUAND : (?P<time>[^\n]+)\n',
- r'O[UÙ] : (?P<place>[^\n]+)\n',
- 'ADRESSE :\n',
- '(?P<address>.+?)\n',
- 'PROGRAMME :\n',
- '(?P<pieces>.+?)\n',
- 'INSTRUCTIONS :\n',
- '(?P<instructions>.+?)\n',
- 'ILLUSTRATION :\n',
- r'fichier : (?P<pic_file>[^\n]+)\n',
- r'légende : (?P<pic_alt>[^\n]+)\n',
- r'source : (?P<pic_src>[^\n]+)\n',
- optional(r'lien : (?P<pic_link>[^\n]+)\n'),
- optional(r'licence : (?P<pic_license>[^\n]+)\n'),
- optional(r'AVERTISSEMENT : (?P<warning>[^\n]+)\n'),
-)
-
-CONCERT_RE = re.compile(''.join(CONCERT_LINES), flags=re.DOTALL)
-
-
-def guess_language(filename):
- parent = str(Path(filename).parent)
- if parent == '.':
- return 'fr'
- return parent
-
-
-def read_concerts(filename):
- with open(filename) as f:
- concerts = (
- Concert.deserialize(match)
- for match in re.finditer(CONCERT_RE, f.read())
- )
- return tuple(sorted(concerts, key=attrgetter('time')))
-
-
def split_concerts(concerts, threshold):
cutoff = len(concerts)
diff --git a/helpers.py b/helpers.py
index faf14e7..162d39e 100644
--- a/helpers.py
+++ b/helpers.py
@@ -1,5 +1,17 @@
+from dataclasses import dataclass
+from datetime import datetime
+from operator import attrgetter
from os import path
from pathlib import Path
+import re
+from typing import Iterator, Optional
+
+
+def guess_language(filename):
+ parent = str(Path(filename).parent)
+ if parent == '.':
+ return 'fr'
+ return parent
def relative_path(*, to, ref):
@@ -7,3 +19,103 @@ def relative_path(*, to, ref):
# os.path.dirname('x') yields '' rather than '.'.
# 😮‍💨
return path.relpath(to, Path(ref).parent)
+
+
+_LICENSE_URLS = {
+ 'CC0': 'https://creativecommons.org/publicdomain/zero',
+ 'CC BY': 'https://creativecommons.org/licenses/by',
+ 'CC BY-SA': 'https://creativecommons.org/licenses/by-sa',
+}
+
+_LICENSE_RE = re.compile(
+ '('+'|'.join(_LICENSE_URLS.keys())+')' + ' ([0-9.]+)'
+)
+
+@dataclass
+class LicenseInfo:
+ tag: str
+ version: str
+
+ @classmethod
+ def deserialize(cls, info):
+ if info is None:
+ return None
+ return cls(*_LICENSE_RE.fullmatch(info).groups())
+
+ def format(self):
+ url = f'{_LICENSE_URLS[self.tag]}/{self.version}/'
+
+ return f'<a href="{url}" target="_blank">{self.tag}</a>'
+
+
+@dataclass
+class Illustration:
+ file: str
+ alt_text: str
+ source_name: str
+ source_link: Optional[str]
+ license_info: Optional[LicenseInfo]
+
+ @classmethod
+ def deserialize(cls, d):
+ return cls(d['pic_file'],
+ d['pic_alt'],
+ d['pic_src'],
+ d['pic_link'],
+ LicenseInfo.deserialize(d['pic_license']))
+
+
+@dataclass
+class Concert:
+ time: datetime
+ place: str
+ address: str
+ pieces: Iterator[str]
+ instructions: str
+ illustration: Illustration
+ warning: Optional[str]
+
+ @classmethod
+ def deserialize(cls, d):
+ return cls(
+ time=datetime.strptime(d['time'], '%d/%m/%Y %Hh%M'),
+ place=d['place'],
+ address=d['address'],
+ pieces=d['pieces'],
+ instructions=d['instructions'],
+ illustration=Illustration.deserialize(d),
+ warning=d['warning']
+ )
+
+
+def _optional(line):
+ return f'(?:{line})?'
+
+_CONCERT_LINES = (
+ r'QUAND : (?P<time>[^\n]+)\n',
+ r'O[UÙ] : (?P<place>[^\n]+)\n',
+ 'ADRESSE :\n',
+ '(?P<address>.+?)\n',
+ 'PROGRAMME :\n',
+ '(?P<pieces>.+?)\n',
+ 'INSTRUCTIONS :\n',
+ '(?P<instructions>.+?)\n',
+ 'ILLUSTRATION :\n',
+ r'fichier : (?P<pic_file>[^\n]+)\n',
+ r'légende : (?P<pic_alt>[^\n]+)\n',
+ r'source : (?P<pic_src>[^\n]+)\n',
+ _optional(r'lien : (?P<pic_link>[^\n]+)\n'),
+ _optional(r'licence : (?P<pic_license>[^\n]+)\n'),
+ _optional(r'AVERTISSEMENT : (?P<warning>[^\n]+)\n'),
+)
+
+_CONCERT_RE = re.compile(''.join(_CONCERT_LINES), flags=re.DOTALL)
+
+
+def read_concerts(filename):
+ with open(filename) as f:
+ concerts = (
+ Concert.deserialize(match)
+ for match in re.finditer(_CONCERT_RE, f.read())
+ )
+ return tuple(sorted(concerts, key=attrgetter('time')))