sgelt 4.8.1__tar.gz

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.
Files changed (76) hide show
  1. sgelt-4.8.1/LICENSE +21 -0
  2. sgelt-4.8.1/MANIFEST.in +6 -0
  3. sgelt-4.8.1/PKG-INFO +117 -0
  4. sgelt-4.8.1/README.md +85 -0
  5. sgelt-4.8.1/pyproject.toml +69 -0
  6. sgelt-4.8.1/setup.cfg +4 -0
  7. sgelt-4.8.1/src/sgelt/__init__.py +11 -0
  8. sgelt-4.8.1/src/sgelt/__main__.py +6 -0
  9. sgelt-4.8.1/src/sgelt/__version__.py +1 -0
  10. sgelt-4.8.1/src/sgelt/calendar.py +105 -0
  11. sgelt-4.8.1/src/sgelt/config.py +179 -0
  12. sgelt-4.8.1/src/sgelt/data.py +42 -0
  13. sgelt-4.8.1/src/sgelt/filters.py +282 -0
  14. sgelt-4.8.1/src/sgelt/main.py +94 -0
  15. sgelt-4.8.1/src/sgelt/mdextend.py +16 -0
  16. sgelt-4.8.1/src/sgelt/mdparse.py +138 -0
  17. sgelt-4.8.1/src/sgelt/pages.py +973 -0
  18. sgelt-4.8.1/src/sgelt/py.typed +0 -0
  19. sgelt-4.8.1/src/sgelt/serve.py +81 -0
  20. sgelt-4.8.1/src/sgelt/sgelt.py +330 -0
  21. sgelt-4.8.1/src/sgelt/theme/LICENSE +21 -0
  22. sgelt-4.8.1/src/sgelt/theme/css/materialize.css +9058 -0
  23. sgelt-4.8.1/src/sgelt/theme/css/materialize.min.css +13 -0
  24. sgelt-4.8.1/src/sgelt/theme/css/style.css +695 -0
  25. sgelt-4.8.1/src/sgelt/theme/img/favicon.ico +0 -0
  26. sgelt-4.8.1/src/sgelt/theme/img/iss.jpg +0 -0
  27. sgelt-4.8.1/src/sgelt/theme/img/logo_jinja.png +0 -0
  28. sgelt-4.8.1/src/sgelt/theme/img/logo_materialize.png +0 -0
  29. sgelt-4.8.1/src/sgelt/theme/img/logo_pi.png +0 -0
  30. sgelt-4.8.1/src/sgelt/theme/img/logo_python.png +0 -0
  31. sgelt-4.8.1/src/sgelt/theme/js/delaunay.js +65 -0
  32. sgelt-4.8.1/src/sgelt/theme/js/init.js +30 -0
  33. sgelt-4.8.1/src/sgelt/theme/js/lunr-search-result.js +106 -0
  34. sgelt-4.8.1/src/sgelt/theme/js/lunr.js +3573 -0
  35. sgelt-4.8.1/src/sgelt/theme/js/materialize.js +12337 -0
  36. sgelt-4.8.1/src/sgelt/theme/js/materialize.min.js +6 -0
  37. sgelt-4.8.1/src/sgelt/theme/js/parallax.js +412 -0
  38. sgelt-4.8.1/src/sgelt/theme/js/parallax.min.js +6 -0
  39. sgelt-4.8.1/src/sgelt/theme/templates/actualites-bib.html +13 -0
  40. sgelt-4.8.1/src/sgelt/theme/templates/actualites.html +39 -0
  41. sgelt-4.8.1/src/sgelt/theme/templates/agenda.html +25 -0
  42. sgelt-4.8.1/src/sgelt/theme/templates/article.html +44 -0
  43. sgelt-4.8.1/src/sgelt/theme/templates/base.html +126 -0
  44. sgelt-4.8.1/src/sgelt/theme/templates/conference.html +119 -0
  45. sgelt-4.8.1/src/sgelt/theme/templates/equipe.html +14 -0
  46. sgelt-4.8.1/src/sgelt/theme/templates/index.html +85 -0
  47. sgelt-4.8.1/src/sgelt/theme/templates/macros.jinja.html +182 -0
  48. sgelt-4.8.1/src/sgelt/theme/templates/page.html +24 -0
  49. sgelt-4.8.1/src/sgelt/theme/templates/partial/date_place.html +17 -0
  50. sgelt-4.8.1/src/sgelt/theme/templates/partial/footer.html +54 -0
  51. sgelt-4.8.1/src/sgelt/theme/templates/partial/nav.html +46 -0
  52. sgelt-4.8.1/src/sgelt/theme/templates/partial/news_button.html +16 -0
  53. sgelt-4.8.1/src/sgelt/theme/templates/search.html +45 -0
  54. sgelt-4.8.1/src/sgelt/theme/templates/seminaire.html +56 -0
  55. sgelt-4.8.1/src/sgelt/theme/templates/seminaires.html +56 -0
  56. sgelt-4.8.1/src/sgelt/theme/templates/soutenance.html +58 -0
  57. sgelt-4.8.1/src/sgelt/utils.py +208 -0
  58. sgelt-4.8.1/src/sgelt/watch.py +81 -0
  59. sgelt-4.8.1/src/sgelt.egg-info/PKG-INFO +117 -0
  60. sgelt-4.8.1/src/sgelt.egg-info/SOURCES.txt +74 -0
  61. sgelt-4.8.1/src/sgelt.egg-info/dependency_links.txt +1 -0
  62. sgelt-4.8.1/src/sgelt.egg-info/entry_points.txt +2 -0
  63. sgelt-4.8.1/src/sgelt.egg-info/requires.txt +19 -0
  64. sgelt-4.8.1/src/sgelt.egg-info/top_level.txt +1 -0
  65. sgelt-4.8.1/tests/test_calendar.py +206 -0
  66. sgelt-4.8.1/tests/test_config.py +125 -0
  67. sgelt-4.8.1/tests/test_data.py +31 -0
  68. sgelt-4.8.1/tests/test_filters.py +397 -0
  69. sgelt-4.8.1/tests/test_main.py +160 -0
  70. sgelt-4.8.1/tests/test_mdparse.py +228 -0
  71. sgelt-4.8.1/tests/test_pages.py +824 -0
  72. sgelt-4.8.1/tests/test_serve.py +64 -0
  73. sgelt-4.8.1/tests/test_serverwatch.py +14 -0
  74. sgelt-4.8.1/tests/test_site.py +166 -0
  75. sgelt-4.8.1/tests/test_utils.py +205 -0
  76. sgelt-4.8.1/tests/test_watch.py +15 -0
sgelt-4.8.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 IRMA
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ # Include the README
2
+ include README.md
3
+
4
+ # Include the data files
5
+ recursive-include src/sgelt/theme *
6
+ include src/sgelt/py.typed
sgelt-4.8.1/PKG-INFO ADDED
@@ -0,0 +1,117 @@
1
+ Metadata-Version: 2.1
2
+ Name: sgelt
3
+ Version: 4.8.1
4
+ Summary: SGELT: Site GEnerator for Labs and Teams
5
+ Author-email: Matthieu Boileau <matthieu.boileau@math.unistra.fr>
6
+ License: MIT
7
+ Project-URL: Homepage, https://gitlab.math.unistra.fr/irma/sgelt
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: bs4
15
+ Requires-Dist: datetimejson
16
+ Requires-Dist: icalendar==4.1.0
17
+ Requires-Dist: jinja2
18
+ Requires-Dist: livereload
19
+ Requires-Dist: markdown
20
+ Requires-Dist: markdown_link_attr_modifier
21
+ Requires-Dist: python-frontmatter
22
+ Requires-Dist: shortcodes
23
+ Requires-Dist: unidecode
24
+ Requires-Dist: watchdog
25
+ Provides-Extra: tests
26
+ Requires-Dist: faker; extra == "tests"
27
+ Requires-Dist: freezegun; extra == "tests"
28
+ Requires-Dist: pytest; extra == "tests"
29
+ Requires-Dist: pytest-cov; extra == "tests"
30
+ Requires-Dist: pytest-xdist[psutil]; extra == "tests"
31
+ Requires-Dist: pytest-mock; extra == "tests"
32
+
33
+ # SGELT: Site GEnerator for Labs and Teams
34
+
35
+ ## Installation
36
+
37
+ * Create a python virtual environment :
38
+
39
+ ```bash
40
+ virtualenv .venv/
41
+ ```
42
+
43
+ * Activate it
44
+
45
+ ```bash
46
+ source .venv/bin/activate
47
+ ```
48
+
49
+ * Install the package and its dependencies :
50
+
51
+ ```bash
52
+ pip install sgelt --index-url https://gitlab.math.unistra.fr/api/v4/projects/653/packages/pypi/simple
53
+ ```
54
+
55
+ ## Build a website
56
+
57
+ ### Files organization
58
+
59
+ * `config.yml` describes the site configuration
60
+ * `content/` dir contains markdown files
61
+ * `agenda.json` contains all events data
62
+ * `teams.json` contains teams data
63
+
64
+ ### Edit content
65
+
66
+ * setup configuration in `config.yml`
67
+ * edit `content/` dir.
68
+ * generate json data files
69
+
70
+ ### Build and serve
71
+
72
+ To build all site files, run :
73
+
74
+ ```bash
75
+ sgelt
76
+ ```
77
+
78
+ in the project directory.
79
+ Output files will be written in `output/` dir.
80
+
81
+ ### Build and serve
82
+
83
+ To serve the website and rebuild automatically when the content has changed:
84
+
85
+ ```bash
86
+ sgelt -a -s
87
+ ```
88
+
89
+ To open the homepage in a web browser, add:
90
+
91
+ ```bash
92
+ sgelt -a -s -b
93
+ ```
94
+
95
+ ### Get help with CLI
96
+
97
+ ```bash
98
+ sgelt -h
99
+ ```
100
+
101
+ ## Tests
102
+
103
+ ### Run tests using tox
104
+
105
+ Tox setup the appropriate environments and run tests using pytest:
106
+
107
+ ```bash
108
+ pip install tox # install tox
109
+ tox # run
110
+ ```
111
+
112
+ ### Run tests using pytest
113
+
114
+ ```bash
115
+ pip install -e .[tests] # install dependencies for tests
116
+ pytest -sv tests/ # run tests
117
+ ```
sgelt-4.8.1/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # SGELT: Site GEnerator for Labs and Teams
2
+
3
+ ## Installation
4
+
5
+ * Create a python virtual environment :
6
+
7
+ ```bash
8
+ virtualenv .venv/
9
+ ```
10
+
11
+ * Activate it
12
+
13
+ ```bash
14
+ source .venv/bin/activate
15
+ ```
16
+
17
+ * Install the package and its dependencies :
18
+
19
+ ```bash
20
+ pip install sgelt --index-url https://gitlab.math.unistra.fr/api/v4/projects/653/packages/pypi/simple
21
+ ```
22
+
23
+ ## Build a website
24
+
25
+ ### Files organization
26
+
27
+ * `config.yml` describes the site configuration
28
+ * `content/` dir contains markdown files
29
+ * `agenda.json` contains all events data
30
+ * `teams.json` contains teams data
31
+
32
+ ### Edit content
33
+
34
+ * setup configuration in `config.yml`
35
+ * edit `content/` dir.
36
+ * generate json data files
37
+
38
+ ### Build and serve
39
+
40
+ To build all site files, run :
41
+
42
+ ```bash
43
+ sgelt
44
+ ```
45
+
46
+ in the project directory.
47
+ Output files will be written in `output/` dir.
48
+
49
+ ### Build and serve
50
+
51
+ To serve the website and rebuild automatically when the content has changed:
52
+
53
+ ```bash
54
+ sgelt -a -s
55
+ ```
56
+
57
+ To open the homepage in a web browser, add:
58
+
59
+ ```bash
60
+ sgelt -a -s -b
61
+ ```
62
+
63
+ ### Get help with CLI
64
+
65
+ ```bash
66
+ sgelt -h
67
+ ```
68
+
69
+ ## Tests
70
+
71
+ ### Run tests using tox
72
+
73
+ Tox setup the appropriate environments and run tests using pytest:
74
+
75
+ ```bash
76
+ pip install tox # install tox
77
+ tox # run
78
+ ```
79
+
80
+ ### Run tests using pytest
81
+
82
+ ```bash
83
+ pip install -e .[tests] # install dependencies for tests
84
+ pytest -sv tests/ # run tests
85
+ ```
@@ -0,0 +1,69 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.2"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sgelt"
7
+ authors = [
8
+ { name = "Matthieu Boileau", email = "matthieu.boileau@math.unistra.fr" },
9
+ ]
10
+ description = "SGELT: Site GEnerator for Labs and Teams"
11
+ classifiers = [
12
+ "Programming Language :: Python :: 3",
13
+ "License :: OSI Approved :: MIT License",
14
+ "Operating System :: OS Independent",
15
+ ]
16
+ requires-python = ">=3.9"
17
+ dependencies = [
18
+ "bs4",
19
+ "datetimejson",
20
+ "icalendar==4.1.0",
21
+ "jinja2",
22
+ "livereload",
23
+ "markdown",
24
+ "markdown_link_attr_modifier",
25
+ "python-frontmatter",
26
+ "shortcodes",
27
+ "unidecode",
28
+ "watchdog",
29
+ ]
30
+ dynamic = ["version"]
31
+
32
+ [project.optional-dependencies]
33
+ tests = [
34
+ "faker",
35
+ "freezegun",
36
+ "pytest",
37
+ "pytest-cov",
38
+ "pytest-xdist[psutil]",
39
+ "pytest-mock",
40
+ ]
41
+
42
+ [project.license]
43
+ text = "MIT"
44
+
45
+ [project.readme]
46
+ file = "README.md"
47
+ content-type = "text/markdown"
48
+
49
+ [project.urls]
50
+ Homepage = "https://gitlab.math.unistra.fr/irma/sgelt"
51
+
52
+ [project.scripts]
53
+ sgelt = "sgelt.main:main"
54
+
55
+ [tool.setuptools]
56
+ include-package-data = true
57
+ license-files = ["LICENSE"]
58
+ package-dir = { "" = "src" }
59
+
60
+
61
+ [tool.setuptools.packages.find]
62
+ where = ["src"]
63
+ namespaces = false
64
+
65
+ [tool.setuptools.dynamic.version]
66
+ attr = "sgelt.__version__"
67
+
68
+ [tool.setuptools.package-data]
69
+ sgelt = ["py.typed", "sgelt/theme/*"]
sgelt-4.8.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,11 @@
1
+ """Set logging, locale and package_dir"""
2
+
3
+ from pathlib import Path
4
+ import locale
5
+ from .__version__ import __version__
6
+
7
+ __all__ = ['__version__', 'package_dir']
8
+
9
+ locale.setlocale(locale.LC_TIME, 'fr_FR.UTF-8')
10
+
11
+ package_dir = Path(__file__).parent
@@ -0,0 +1,6 @@
1
+ """Enable to run with `python -m sgelt`"""
2
+
3
+ from .main import main
4
+
5
+ if __name__ == '__main__':
6
+ main()
@@ -0,0 +1 @@
1
+ __version__ = '4.8.1'
@@ -0,0 +1,105 @@
1
+ """
2
+ A module to export iCalendar events
3
+ """
4
+
5
+ from icalendar import Calendar, Event, vText
6
+ import logging
7
+ from pathlib import Path
8
+ import pytz
9
+ import random
10
+ import re
11
+ import uuid
12
+ import urllib.parse
13
+
14
+ from sgelt.utils import slugify
15
+
16
+ log = logging.getLogger(__name__)
17
+
18
+ rd = random.Random()
19
+ rd.seed(0)
20
+
21
+
22
+ def build_calendar(prodid: str, ical_events: list) -> str:
23
+ """
24
+ Return a string containing the iCalendar events
25
+ """
26
+
27
+ cal = Calendar()
28
+ cal.add('prodid', prodid)
29
+ cal.add('version', '2.0')
30
+
31
+ tz = pytz.timezone('Europe/Paris')
32
+
33
+ for ical_event in ical_events:
34
+ event = Event()
35
+ event.add('summary', ical_event['summary'])
36
+ event.add('dtstart', tz.localize(ical_event['dtstart']).astimezone(tz))
37
+ event.add('dtend', tz.localize(ical_event['dtend']).astimezone(tz))
38
+ event.add('dtstamp', ical_event['dtstamp'])
39
+ try:
40
+ event['uid'] = ical_event['uuid']
41
+ except KeyError:
42
+ event['uid'] = str(uuid.UUID(int=rd.getrandbits(128)))
43
+ try:
44
+ event['location'] = vText(ical_event['location'])
45
+ except KeyError:
46
+ pass
47
+ try:
48
+ event['description'] = vText(ical_event['description'])
49
+ except KeyError:
50
+ pass
51
+ try:
52
+ # Encode URL for Apple Calendar
53
+ event['url'] = vText(urllib.parse.quote(ical_event['url'],
54
+ safe='/:'))
55
+ except KeyError:
56
+ pass
57
+ event.add('priority', 5)
58
+ cal.add_component(event)
59
+
60
+ return cal.to_ical().decode('UTF-8')
61
+
62
+
63
+ def merge_calendars(prodid: str, sem_calendar_paths: list,
64
+ event_types: set) -> str:
65
+ """
66
+ Read a list of seminars iCalendar files and merge them into
67
+ a single iCalendar file
68
+ """
69
+ cal = Calendar()
70
+ cal.add('prodid', prodid)
71
+ cal.add('version', '2.0')
72
+
73
+ for calendar_path in sorted(sem_calendar_paths):
74
+ with open(calendar_path) as f:
75
+ sem_cal = Calendar.from_ical(f.read())
76
+ # Merge only seminars and Colloquium
77
+ pattern = r"^-\/\/.*\/\/((" + "|".join(event_types) + r") .*)\/\/.*$"
78
+ m = re.match(pattern, sem_cal['prodid'])
79
+ if m:
80
+ summary_prefix = m.group(1)
81
+ for event in sem_cal.walk(name='VEVENT'):
82
+ # Prepend seminar title to event summary
83
+ event['summary'] = f"{summary_prefix} - {event.get('summary')}"
84
+ cal.add_component(event)
85
+
86
+ return cal.to_ical().decode('UTF-8')
87
+
88
+
89
+ def write_calendar_file(filename: str, conf,
90
+ ical_content: str) -> str:
91
+ """
92
+ Write calendar content to an .ics file and return encoded url
93
+ """
94
+ ical_filepath = 'cal' / Path(slugify(filename)).with_suffix('.ics')
95
+ ical_outpath = conf.output_path / ical_filepath
96
+ log.debug(f"Export ical file to {ical_outpath}")
97
+ # Create parent directory if not exists
98
+ ical_outpath.parent.mkdir(exist_ok=True, parents=True)
99
+ ical_outpath.write_text(ical_content)
100
+ if 'url' in conf.site:
101
+ ical_url = \
102
+ f"{conf.site['url']}/{ical_filepath}"
103
+ else:
104
+ ical_url = ical_outpath.as_posix()
105
+ return urllib.parse.quote(ical_url, safe='/:')
@@ -0,0 +1,179 @@
1
+ """Define site configuration class and instantiate in a conf object"""
2
+
3
+ from datetime import date, datetime
4
+ import jinja2
5
+ import logging
6
+ from pathlib import Path
7
+ import yaml
8
+
9
+ from . import filters, package_dir, __version__
10
+
11
+ log = logging.getLogger(__name__)
12
+
13
+
14
+ class Config:
15
+ """A class to store site configuration"""
16
+
17
+ # Default config dict that may be overriden by user values
18
+ def_conf = dict(
19
+ default_theme_path=package_dir / 'theme',
20
+ theme_path=None,
21
+ output_path='output',
22
+ content_path='content',
23
+ config_path='config.yml',
24
+ static_payload=('css', 'js', 'img'),
25
+ json_agenda_path='agenda_mysql.json',
26
+ json_teams_path='teams.json',
27
+ search_index=True
28
+ )
29
+
30
+ def __init__(self, args=None, config_path=None):
31
+ """Set class attributes from default"""
32
+ self.args = args
33
+ conf = self.def_conf.copy()
34
+ self._set_attributes(conf)
35
+ # Update config.yml default path
36
+ if config_path is not None:
37
+ self.update(config_path=config_path)
38
+ else:
39
+ try:
40
+ self.update(config_path=self.args.config_path)
41
+ except AttributeError:
42
+ pass
43
+ self.site = None
44
+
45
+ def save_args(self) -> dict:
46
+ """Return a dict of config.__init__() arguments"""
47
+ return {'args': self.args, 'config_path': self.config_path}
48
+
49
+ def update(self, **kwargs):
50
+ """Update object attributes from names args"""
51
+ conf = vars(self) # get attributes as dict
52
+ # Update conf dict with init args if key exists
53
+ for k, v in kwargs.items():
54
+ if k in self.def_conf:
55
+ conf[k] = v
56
+ else:
57
+ log.warning(f"Cannot update conf dict with unknown key: {k}")
58
+ self._set_attributes(conf)
59
+
60
+ def load(self):
61
+ """Parse YAML config file and override with CLI args"""
62
+
63
+ # Read config.yml file
64
+ try:
65
+ with open(self.config_path) as f:
66
+ file_conf = yaml.safe_load(f)
67
+ except FileNotFoundError as e:
68
+ log.error(e)
69
+ log.debug(self)
70
+ import sys
71
+ sys.exit(1)
72
+
73
+ # site dict becomes .site attribute
74
+ self.site = file_conf.pop('site')
75
+
76
+ # Convert path/to/file.md -> path/to/file.html
77
+ for dropdown_items in self.site['nav_items'].values():
78
+ try:
79
+ for dropdown_name, filename in dropdown_items.items():
80
+ filepath = Path(filename)
81
+ # Convert markdown paths to html paths
82
+ if filepath.suffix == '.md':
83
+ dropdown_items[dropdown_name] = filepath.with_suffix(
84
+ '.html').as_posix()
85
+ except AttributeError:
86
+ # dropdown_items is not an actual dropdown dict
87
+ pass
88
+
89
+ if 'today' in self.site:
90
+ # Convert today as date if exists
91
+ if type(self.site['today']) is not date:
92
+ self.site['today'] = self.site['today'].date()
93
+ else:
94
+ # Use today date
95
+ self.site['today'] = date.today()
96
+
97
+ # update other attributes (same as in def_conf)
98
+ self.update(**file_conf)
99
+
100
+ # Override with CLI args
101
+ args = self.args
102
+ if args is not None:
103
+ if args.json_agenda:
104
+ self.update(json_agenda_path=args.json_agenda)
105
+ if args.json_teams:
106
+ self.update(json_teams_path=args.json_teams)
107
+ if args.content:
108
+ self.update(content_path=args.content)
109
+ if args.output:
110
+ self.update(output_path=args.output)
111
+ if not args.search_index:
112
+ self.update(search_index=False)
113
+
114
+ def _set_attributes(self, conf: dict):
115
+ """From conf dict and default values, set class attributes"""
116
+ for k, v in conf.items():
117
+ if k != 'env':
118
+ if isinstance(v, list) or isinstance(v, tuple):
119
+ setattr(self, k, [Path(item) for item in v])
120
+ elif isinstance(v, dict) or isinstance(v, type(None)):
121
+ setattr(self, k, v)
122
+ elif isinstance(v, type(None)):
123
+ pass
124
+ else:
125
+ try:
126
+ setattr(self, k, Path(v))
127
+ except TypeError:
128
+ setattr(self, k, v)
129
+
130
+ self.templates_paths = [self.default_theme_path / Path('templates')]
131
+ try:
132
+ if conf['theme_path'] and conf['theme_path'].is_relative_to(
133
+ self.config_path.parent):
134
+ conf_theme_path = conf['theme_path']
135
+ else:
136
+ conf_theme_path = self.config_path.parent / conf['theme_path']
137
+ user_template_path = conf_theme_path / 'templates'
138
+ if user_template_path.exists(): # Add override template dir
139
+ self.templates_paths.append(user_template_path)
140
+ except TypeError: # self.theme_path is None thus skip
141
+ pass
142
+ self.env = jinja2.Environment(
143
+ loader=jinja2.FileSystemLoader(self.templates_paths)
144
+ )
145
+
146
+ # Add filters
147
+ self.env.filters['homepage'] = filters.homepage
148
+ self.env.filters['agenda'] = filters.agenda
149
+ self.env.filters['event_date_time'] = filters.event_date_time
150
+ self.env.filters['categ_to_target'] = filters.categ_to_target
151
+ self.env.filters['url'] = filters.url
152
+ self.env.filters['external_url'] = filters.external_url
153
+ self.env.filters['event_selector'] = filters.event_selector
154
+ self.env.filters['sort_by_date'] = filters.sort_by_date
155
+ self.env.filters['homepage_news'] = filters.homepage_news
156
+ self.env.filters['news_page'] = filters.news_page
157
+ self.env.filters['dropdown_items'] = filters.dropdown_items
158
+ self.env.filters['real_teams'] = filters.real_teams
159
+ self.env.filters['teams'] = filters.teams
160
+ self.env.filters['organizing_teams'] = filters.organizing_teams
161
+
162
+ # Global variables
163
+ self.env.globals['datetime_min'] = datetime.min
164
+ self.env.globals['sgelt_version'] = __version__
165
+
166
+ def __repr__(self):
167
+ def _format(k, v):
168
+ if isinstance(v, list):
169
+ return "{}:\n{}".format(k, '\n'.join((f" - {item}"
170
+ for item in v)))
171
+ elif isinstance(v, dict):
172
+ import textwrap
173
+ return f"""\
174
+ {k}:\n{textwrap.indent(yaml.dump(v, allow_unicode=True), 2 * ' ')}"""
175
+ else:
176
+ return f"{k}: {v}"
177
+ return '\n'.join((_format(k, v)
178
+ for k, v in vars(self).items()
179
+ if not isinstance(v, jinja2.Environment)))
@@ -0,0 +1,42 @@
1
+ """
2
+ A module to store agenda, news, events and teams data
3
+ To be populated and modified by sgelt module
4
+ """
5
+
6
+ from .utils import read_data
7
+
8
+
9
+ class Data:
10
+ """A class to store site data"""
11
+
12
+ def __init__(self, conf):
13
+ """Initialize with configuration object and empty data"""
14
+
15
+ self.conf = conf # a configuration object
16
+ # read from agenda.json
17
+ self.conferences = []
18
+ self.defenses = []
19
+ self.seminars = []
20
+
21
+ self.teams = {} # read from teams.json
22
+
23
+ self.news = [] # will be populated by registering news
24
+ self.libnews = [] # will be populated by registering libnews
25
+ self.events = [] # will be populated by registering events
26
+
27
+ def read_files(self):
28
+ """Read data from json files"""
29
+
30
+ # Read agenda data from json file
31
+ agenda = read_data(self.conf.json_agenda_path)
32
+ self.conferences = agenda['conferences']
33
+ self.defenses = agenda['defenses']
34
+ self.seminars = agenda['seminars']
35
+
36
+ # Read team data from json file
37
+ self.teams = read_data(self.conf.json_teams_path)
38
+
39
+ def __repr__(self):
40
+ from pprint import pformat
41
+ return '\n'.join((f"{k}: {pformat(v)}"
42
+ for k, v in vars(self).items()))