ryland 0.1.0__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.
ryland-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: ryland
3
+ Version: 0.1.0
4
+ Summary: A simple static site generation library
5
+ Author: James Tauber
6
+ Author-email: James Tauber <jtauber@jtauber.com>
7
+ License-Expression: MIT
8
+ Requires-Dist: jinja2>=3.1.6
9
+ Requires-Dist: markdown>=3.8.2
10
+ Requires-Dist: pyyaml>=6.0.2
11
+ Requires-Python: >=3.12
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Ryland
15
+
16
+ A simple static site generation library
17
+
18
+
19
+ ## Current Features
20
+
21
+ - Jinja2 templates and a basic markdown filter
22
+ - copying static files and directory trees (for stylesheets, scripts, fonts, images)
23
+ - cache-busting with hashes
24
+
25
+
26
+ ## History
27
+
28
+ I've generally found most static site generation libraries to either be far too complex for my needs or be too restricted to just blogs so, over the years, I've generated many static sites with lightweight, bespoke Python code and hosted them on GitHub pages. However, I've ended up repeating myself a lot so I'm now cleaning it all up and generalizing my prior work as this library.
29
+
30
+
31
+ ## Example Usage
32
+
33
+ For now, clone this repo and use as an editable requirement.
34
+
35
+ Write a build script of the following form:
36
+
37
+ ```python
38
+ from ryland import Ryland
39
+
40
+ ROOT_DIR = Path(__file__).parent.parent
41
+ DIST_DIR = ROOT_DIR / "dist"
42
+ PANTRY_DIR = ROOT_DIR / "pantry"
43
+ TEMPLATE_DIR = ROOT_DIR / "templates"
44
+
45
+ ryland = Ryland(dist_dir=DIST_DIR, template_dir=TEMPLATE_DIR)
46
+
47
+ ryland.clear_dist()
48
+ ryland.copy_to_dist(PANTRY_DIR / "style.css")
49
+ ryland.calc_hash("style.css")
50
+
51
+ ryland.render_template("404.html", "404.html")
52
+ ryland.render_template("about_us.html", "about-us/index.html")
53
+
54
+ # construct context variables
55
+
56
+ ryland.render_template("homepage.html", "index.html", {
57
+ # context variables
58
+ })
59
+ ```
60
+
61
+ ## Cache-Busting Hashes
62
+
63
+ The `calc_hash` makes it possible to do
64
+
65
+ ```html
66
+ <link rel="stylesheet" href="/style.css?{{ HASHES['style.css'] }}">
67
+ ```
68
+
69
+ in the templates.
70
+
71
+
72
+ ## Markdown Filter
73
+
74
+ To render a markdown context variable:
75
+
76
+ ```
77
+ {{ content | markdown }}
78
+ ```
79
+
80
+ ## Sites Currently Using Ryland
81
+
82
+ - <https://projectamaze.com>
83
+
84
+
85
+ ## Roadmap
86
+
87
+ - move over other sites to use Ryland
88
+ - incorporate more common elements that emerge
89
+ - produce a Ryland-generated website for Ryland
90
+ - document how to automatically build with GitHub actions
91
+ - write up a cookbook
92
+ - add a command-line too for starting a Ryland-based site
93
+
ryland-0.1.0/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # Ryland
2
+
3
+ A simple static site generation library
4
+
5
+
6
+ ## Current Features
7
+
8
+ - Jinja2 templates and a basic markdown filter
9
+ - copying static files and directory trees (for stylesheets, scripts, fonts, images)
10
+ - cache-busting with hashes
11
+
12
+
13
+ ## History
14
+
15
+ I've generally found most static site generation libraries to either be far too complex for my needs or be too restricted to just blogs so, over the years, I've generated many static sites with lightweight, bespoke Python code and hosted them on GitHub pages. However, I've ended up repeating myself a lot so I'm now cleaning it all up and generalizing my prior work as this library.
16
+
17
+
18
+ ## Example Usage
19
+
20
+ For now, clone this repo and use as an editable requirement.
21
+
22
+ Write a build script of the following form:
23
+
24
+ ```python
25
+ from ryland import Ryland
26
+
27
+ ROOT_DIR = Path(__file__).parent.parent
28
+ DIST_DIR = ROOT_DIR / "dist"
29
+ PANTRY_DIR = ROOT_DIR / "pantry"
30
+ TEMPLATE_DIR = ROOT_DIR / "templates"
31
+
32
+ ryland = Ryland(dist_dir=DIST_DIR, template_dir=TEMPLATE_DIR)
33
+
34
+ ryland.clear_dist()
35
+ ryland.copy_to_dist(PANTRY_DIR / "style.css")
36
+ ryland.calc_hash("style.css")
37
+
38
+ ryland.render_template("404.html", "404.html")
39
+ ryland.render_template("about_us.html", "about-us/index.html")
40
+
41
+ # construct context variables
42
+
43
+ ryland.render_template("homepage.html", "index.html", {
44
+ # context variables
45
+ })
46
+ ```
47
+
48
+ ## Cache-Busting Hashes
49
+
50
+ The `calc_hash` makes it possible to do
51
+
52
+ ```html
53
+ <link rel="stylesheet" href="/style.css?{{ HASHES['style.css'] }}">
54
+ ```
55
+
56
+ in the templates.
57
+
58
+
59
+ ## Markdown Filter
60
+
61
+ To render a markdown context variable:
62
+
63
+ ```
64
+ {{ content | markdown }}
65
+ ```
66
+
67
+ ## Sites Currently Using Ryland
68
+
69
+ - <https://projectamaze.com>
70
+
71
+
72
+ ## Roadmap
73
+
74
+ - move over other sites to use Ryland
75
+ - incorporate more common elements that emerge
76
+ - produce a Ryland-generated website for Ryland
77
+ - document how to automatically build with GitHub actions
78
+ - write up a cookbook
79
+ - add a command-line too for starting a Ryland-based site
80
+
@@ -0,0 +1,24 @@
1
+ [project]
2
+ name = "ryland"
3
+ version = "0.1.0"
4
+ description = "A simple static site generation library"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ authors = [
8
+ { name = "James Tauber", email = "jtauber@jtauber.com" }
9
+ ]
10
+ requires-python = ">=3.12"
11
+ dependencies = [
12
+ "jinja2>=3.1.6",
13
+ "markdown>=3.8.2",
14
+ "pyyaml>=6.0.2",
15
+ ]
16
+
17
+ [build-system]
18
+ requires = ["uv_build>=0.8.14,<0.9.0"]
19
+ build-backend = "uv_build"
20
+
21
+ [dependency-groups]
22
+ dev = [
23
+ "ruff>=0.12.11",
24
+ ]
@@ -0,0 +1 @@
1
+ from .core import *
@@ -0,0 +1,60 @@
1
+ from hashlib import md5
2
+ from os import makedirs
3
+ from shutil import copy, copytree, rmtree
4
+
5
+ import jinja2
6
+ import markdown
7
+
8
+
9
+ class Ryland:
10
+ def __init__(self, dist_dir, template_dir):
11
+ self.dist_dir = dist_dir
12
+ self.template_dir = template_dir
13
+ self.hashes = {}
14
+
15
+ self.jinja_env = jinja2.Environment(
16
+ loader=jinja2.FileSystemLoader(template_dir)
17
+ )
18
+ self.jinja_env.filters["markdown"] = markdown_filter
19
+
20
+ def clear_dist(self):
21
+ for child in self.dist_dir.iterdir():
22
+ if child.is_dir():
23
+ rmtree(child)
24
+ else:
25
+ child.unlink()
26
+
27
+ def copy_to_dist(self, source):
28
+ if source.is_dir():
29
+ dest = self.dist_dir / source.name
30
+ copytree(source, dest, dirs_exist_ok=True)
31
+ else:
32
+ copy(source, self.dist_dir / source.name)
33
+
34
+ def calc_hash(self, filename):
35
+ self.hashes[filename] = make_hash(self.dist_dir / filename)
36
+
37
+ def render_template(self, template_name, output_filename, context=None):
38
+ context = context or {}
39
+ template = self.jinja_env.get_template(template_name)
40
+ output_path = self.dist_dir / output_filename
41
+ makedirs(output_path.parent, exist_ok=True)
42
+ with open(output_path, "w") as f:
43
+ f.write(
44
+ template.render(
45
+ {
46
+ "HASHES": self.hashes,
47
+ **context,
48
+ }
49
+ )
50
+ )
51
+
52
+
53
+ def make_hash(path):
54
+ hasher = md5()
55
+ hasher.update(path.read_bytes())
56
+ return hasher.hexdigest()
57
+
58
+
59
+ def markdown_filter(text):
60
+ return markdown.markdown(text, extensions=["fenced_code", "codehilite", "tables"])
File without changes