This commit is contained in:
parent
4f8979ae9b
commit
1bd5225fb6
8 changed files with 195 additions and 21 deletions
|
@ -11,6 +11,7 @@ authors = [
|
|||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"dacite>=1.9.2",
|
||||
"feedgen>=1.0.0",
|
||||
"jinja2>=3.1.6",
|
||||
"l2m4m>=1.0.4",
|
||||
"markdown>=3.8.2",
|
||||
|
@ -57,7 +58,7 @@ reportUnusedCallResult = false
|
|||
reportCallInDefaultInitializer = false
|
||||
enableTypeIgnoreComments = true
|
||||
reportIgnoreCommentWithoutRule = false
|
||||
allowedUntypedLibraries = ["frontmatter", "pygments", "pymdownx", "l2m4m"]
|
||||
allowedUntypedLibraries = ["frontmatter", "pygments", "pymdownx", "l2m4m", "feedgen", "feedgen.feed"]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 70
|
||||
|
|
|
@ -2,6 +2,8 @@ import shutil
|
|||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
from feedgen.feed import FeedGenerator
|
||||
|
||||
from zona import markdown as zmd
|
||||
from zona import util
|
||||
from zona.config import ZonaConfig
|
||||
|
@ -55,7 +57,9 @@ class ZonaBuilder:
|
|||
layout.root / "content" / "static"
|
||||
):
|
||||
logger.debug(f"Parsing {path.name}.")
|
||||
item.metadata, item.content = parse_metadata(path)
|
||||
item.metadata, item.content = parse_metadata(
|
||||
path, config=self.config
|
||||
)
|
||||
if item.metadata.ignore or (
|
||||
item.metadata.draft
|
||||
and not self.config.build.include_drafts
|
||||
|
@ -97,7 +101,45 @@ class ZonaBuilder:
|
|||
items.append(item)
|
||||
self.items = items
|
||||
|
||||
def _build(self):
|
||||
def generate_feed(self) -> bytes:
|
||||
post_list = self._get_post_list()
|
||||
config = self.config.feed
|
||||
if config.link.endswith("/"):
|
||||
config.link = config.link[:-2]
|
||||
fg = FeedGenerator()
|
||||
fg.id(config.link)
|
||||
fg.title(config.title)
|
||||
author = {
|
||||
"name": config.author.name,
|
||||
"email": config.author.email,
|
||||
}
|
||||
fg.author(author)
|
||||
fg.link(
|
||||
href=f"{config.link}/{config.path}",
|
||||
rel="self",
|
||||
type="application/rss+xml",
|
||||
)
|
||||
fg.language(config.language)
|
||||
fg.description(config.description)
|
||||
|
||||
for post in post_list:
|
||||
assert post.metadata
|
||||
fe = fg.add_entry() # pyright: ignore[reportUnknownVariableType]
|
||||
fe.id(f"{config.link}{util.normalize_url(post.url)}") # pyright: ignore[reportUnknownMemberType]
|
||||
fe.link( # pyright: ignore[reportUnknownMemberType]
|
||||
href=f"{config.link}{util.normalize_url(post.url)}"
|
||||
)
|
||||
fe.title(post.metadata.title) # pyright: ignore[reportUnknownMemberType]
|
||||
fe.author(author) # pyright: ignore[reportUnknownMemberType]
|
||||
desc = post.metadata.description
|
||||
fe.description(desc) # pyright: ignore[reportUnknownMemberType]
|
||||
date = post.metadata.date
|
||||
fe.pubDate(date) # pyright: ignore[reportUnknownMemberType]
|
||||
out: bytes = fg.rss_str(pretty=True) # pyright: ignore[reportUnknownVariableType]
|
||||
assert isinstance(out, bytes)
|
||||
return out
|
||||
|
||||
def _get_post_list(self) -> list[Item]:
|
||||
assert self.items
|
||||
# sort according to date
|
||||
# descending order
|
||||
|
@ -108,7 +150,12 @@ class ZonaBuilder:
|
|||
else date.min,
|
||||
reverse=True,
|
||||
)
|
||||
return post_list
|
||||
|
||||
def _build(self):
|
||||
post_list = self._get_post_list()
|
||||
# number of posts
|
||||
# generate RSS here
|
||||
posts = len(post_list)
|
||||
# link post chronology
|
||||
for i, item in enumerate(post_list):
|
||||
|
@ -180,4 +227,9 @@ class ZonaBuilder:
|
|||
self._discover()
|
||||
logger.debug("Building...")
|
||||
self._build()
|
||||
if self.config.feed.enabled:
|
||||
rss = self.generate_feed()
|
||||
path = self.layout.content / self.config.feed.path
|
||||
util.ensure_parents(path)
|
||||
path.write_bytes(rss)
|
||||
self.fresh = False
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, tzinfo
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import yaml
|
||||
from dacite import Config as DaciteConfig
|
||||
from dacite import from_dict
|
||||
|
||||
from zona.log import get_logger
|
||||
|
@ -25,9 +31,17 @@ def find_config(start: Path | None = None) -> Path | None:
|
|||
SitemapConfig = dict[str, str]
|
||||
|
||||
|
||||
@dataclass
|
||||
class PostDefaultsConfig:
|
||||
description: str = "A blog post"
|
||||
|
||||
|
||||
@dataclass
|
||||
class BlogConfig:
|
||||
dir: str = "blog"
|
||||
defaults: PostDefaultsConfig = field(
|
||||
default_factory=PostDefaultsConfig
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -69,12 +83,40 @@ class ServerConfig:
|
|||
reload: ReloadConfig = field(default_factory=ReloadConfig)
|
||||
|
||||
|
||||
@dataclass
|
||||
class AuthorConfig:
|
||||
name: str = "John Doe"
|
||||
email: str = "john@doe.net"
|
||||
|
||||
|
||||
@dataclass
|
||||
class FeedConfig:
|
||||
enabled: bool = True
|
||||
timezone: tzinfo = field(default_factory=lambda: ZoneInfo("UTC"))
|
||||
path: str = "rss.xml"
|
||||
link: str = "https://example.com"
|
||||
title: str = "Zona Website"
|
||||
description: str = "My zona website."
|
||||
language: str = "en"
|
||||
author: AuthorConfig = field(default_factory=AuthorConfig)
|
||||
|
||||
|
||||
IGNORELIST = [".marksman.toml"]
|
||||
|
||||
|
||||
def parse_timezone(s: Any) -> tzinfo:
|
||||
if isinstance(s, str):
|
||||
return ZoneInfo(s)
|
||||
else:
|
||||
raise TypeError(
|
||||
f"Expected {str}, got {type(s)} for config key timezone"
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ZonaConfig:
|
||||
base_url: str = "/"
|
||||
feed: FeedConfig = field(default_factory=FeedConfig)
|
||||
# dictionary where key is name, value is url
|
||||
sitemap: SitemapConfig = field(
|
||||
default_factory=lambda: {"Home": "/"}
|
||||
|
@ -87,7 +129,12 @@ class ZonaConfig:
|
|||
server: ServerConfig = field(default_factory=ServerConfig)
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, path: Path) -> "ZonaConfig":
|
||||
def from_file(cls, path: Path) -> ZonaConfig:
|
||||
with open(path, "r") as f:
|
||||
raw = yaml.safe_load(f)
|
||||
return from_dict(data_class=cls, data=raw)
|
||||
config: ZonaConfig = from_dict(
|
||||
data_class=cls,
|
||||
data=raw,
|
||||
config=DaciteConfig(type_hooks={tzinfo: parse_timezone}),
|
||||
)
|
||||
return config
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{% extends "base.html" %} {% block content %} {% if metadata.show_title %} {%
|
||||
include "title.html" %} {% if metadata.date %}
|
||||
include "title.html" %} {% if metadata.date.date() %}
|
||||
<center>
|
||||
<time class="post-date" datetime="{{ metadata.date | safe }}"
|
||||
>{{ metadata.date | safe}}</time>
|
||||
<time class="post-date" datetime="{{ metadata.date.date() | safe }}"
|
||||
>{{ metadata.date.date() | safe}}</time>
|
||||
</center>
|
||||
{% endif %} {% endif %} {% if is_post %} {% include "post_nav.html" %} {% endif
|
||||
%}
|
||||
|
|
|
@ -8,8 +8,8 @@ include "title.html" %} {% endif %}
|
|||
<ul>
|
||||
{% for item in post_list %}
|
||||
<li>
|
||||
<time class="post-list-date" datetime="{{ item.metadata.date | safe }}"
|
||||
>{{ item.metadata.date | safe}}</time>: <a href="/{{ item.url }}"
|
||||
<time class="post-list-date" datetime="{{ item.metadata.date.date() | safe }}"
|
||||
>{{ item.metadata.date.date() | safe}}</time>: <a href="/{{ item.url }}"
|
||||
>{{ item.metadata.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from dataclasses import asdict, dataclass
|
||||
from pathlib import Path
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import typer
|
||||
import yaml
|
||||
|
@ -145,9 +146,13 @@ def initialize_site(root: Path | None = None):
|
|||
logger.debug("Loading default configuation.")
|
||||
config = ZonaConfig()
|
||||
logger.debug(f"Writing default configuration to {config_path}.")
|
||||
config_dict = asdict(config)
|
||||
if "feed" in config_dict and "timezone" in config_dict["feed"]:
|
||||
tz: ZoneInfo = config_dict["feed"]["timezone"]
|
||||
config_dict["feed"]["timezone"] = tz.key
|
||||
with open(config_path, "w") as f:
|
||||
yaml.dump(
|
||||
asdict(config),
|
||||
config_dict,
|
||||
f,
|
||||
sort_keys=False,
|
||||
default_flow_style=False,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from dataclasses import dataclass
|
||||
from datetime import date
|
||||
from datetime import date, datetime, time, tzinfo
|
||||
from pathlib import Path
|
||||
|
||||
import frontmatter
|
||||
|
@ -10,13 +10,14 @@ from dateutil import parser as date_parser
|
|||
from yaml import YAMLError
|
||||
|
||||
import zona.util
|
||||
from zona.config import ZonaConfig
|
||||
|
||||
|
||||
@dataclass
|
||||
class Metadata:
|
||||
title: str
|
||||
date: date
|
||||
description: str | None
|
||||
date: datetime
|
||||
description: str
|
||||
show_title: bool = True
|
||||
show_date: bool = True
|
||||
show_nav: bool = True
|
||||
|
@ -30,14 +31,29 @@ class Metadata:
|
|||
math: bool = True
|
||||
|
||||
|
||||
def parse_date(raw_date: str | date | object) -> date:
|
||||
if isinstance(raw_date, date):
|
||||
return raw_date
|
||||
def ensure_timezone(dt: datetime, tz: tzinfo) -> datetime:
|
||||
if dt.tzinfo is None or dt.utcoffset() is None:
|
||||
dt = dt.replace(tzinfo=tz)
|
||||
return dt
|
||||
|
||||
|
||||
# TODO: migrate to using datetime, where user can optionall specify
|
||||
# a time as well. if only date is given, default to time.min
|
||||
def parse_date(
|
||||
raw_date: str | datetime | date | object, tz: tzinfo
|
||||
) -> datetime:
|
||||
if isinstance(raw_date, datetime):
|
||||
return ensure_timezone(raw_date, tz)
|
||||
elif isinstance(raw_date, date):
|
||||
return datetime.combine(raw_date, time.min, tzinfo=tz)
|
||||
assert isinstance(raw_date, str)
|
||||
return date_parser.parse(raw_date).date()
|
||||
dt = date_parser.parse(raw_date)
|
||||
return ensure_timezone(dt, tz)
|
||||
|
||||
|
||||
def parse_metadata(path: Path) -> tuple[Metadata, str]:
|
||||
def parse_metadata(
|
||||
path: Path, config: ZonaConfig
|
||||
) -> tuple[Metadata, str]:
|
||||
"""
|
||||
Parses a file and returns parsed Metadata and its content. Defaults
|
||||
are applied for missing fields. If there is no metadata, a Metadata
|
||||
|
@ -53,10 +69,11 @@ def parse_metadata(path: Path) -> tuple[Metadata, str]:
|
|||
raw_meta = post.metadata or {}
|
||||
defaults = {
|
||||
"title": zona.util.filename_to_title(path),
|
||||
"date": date.fromtimestamp(path.stat().st_ctime),
|
||||
"date": datetime.fromtimestamp(path.stat().st_ctime),
|
||||
"description": config.blog.defaults.description,
|
||||
}
|
||||
meta = {**defaults, **raw_meta}
|
||||
meta["date"] = parse_date(meta.get("date"))
|
||||
meta["date"] = parse_date(meta.get("date"), config.feed.timezone)
|
||||
try:
|
||||
metadata = from_dict(
|
||||
data_class=Metadata,
|
||||
|
|
52
uv.lock
generated
52
uv.lock
generated
|
@ -44,6 +44,16 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "feedgen"
|
||||
version = "1.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "lxml" },
|
||||
{ name = "python-dateutil" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6b/59/be0a6f852b5dfbf19e6c8e962c8f41407697f9f52a7902250ed98683ae89/feedgen-1.0.0.tar.gz", hash = "sha256:d9bd51c3b5e956a2a52998c3708c4d2c729f2fcc311188e1e5d3b9726393546a", size = 258496, upload-time = "2023-12-25T18:04:08.421Z" }
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.1.0"
|
||||
|
@ -87,6 +97,46 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/1e/fd/aba08bb9e527168efad57985d7db9a853eb2384b1efa5ca5f3a3794c9cef/latex2mathml-3.78.0-py3-none-any.whl", hash = "sha256:1aeca3dc027b3006ad7b301b7f4a15ffbb4c1451e3dc8c3389e97b37b497e1d6", size = 73673, upload-time = "2025-05-03T16:51:51.991Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lxml"
|
||||
version = "6.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c5/ed/60eb6fa2923602fba988d9ca7c5cdbd7cf25faa795162ed538b527a35411/lxml-6.0.0.tar.gz", hash = "sha256:032e65120339d44cdc3efc326c9f660f5f7205f3a535c1fdbf898b29ea01fb72", size = 4096938, upload-time = "2025-06-26T16:28:19.373Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/89/c3/d01d735c298d7e0ddcedf6f028bf556577e5ab4f4da45175ecd909c79378/lxml-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78718d8454a6e928470d511bf8ac93f469283a45c354995f7d19e77292f26108", size = 8429515, upload-time = "2025-06-26T16:26:06.776Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/37/0e3eae3043d366b73da55a86274a590bae76dc45aa004b7042e6f97803b1/lxml-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:84ef591495ffd3f9dcabffd6391db7bb70d7230b5c35ef5148354a134f56f2be", size = 4601387, upload-time = "2025-06-26T16:26:09.511Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/28/e1a9a881e6d6e29dda13d633885d13acb0058f65e95da67841c8dd02b4a8/lxml-6.0.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:2930aa001a3776c3e2601cb8e0a15d21b8270528d89cc308be4843ade546b9ab", size = 5228928, upload-time = "2025-06-26T16:26:12.337Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/55/2cb24ea48aa30c99f805921c1c7860c1f45c0e811e44ee4e6a155668de06/lxml-6.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:219e0431ea8006e15005767f0351e3f7f9143e793e58519dc97fe9e07fae5563", size = 4952289, upload-time = "2025-06-28T18:47:25.602Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/c0/b25d9528df296b9a3306ba21ff982fc5b698c45ab78b94d18c2d6ae71fd9/lxml-6.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bd5913b4972681ffc9718bc2d4c53cde39ef81415e1671ff93e9aa30b46595e7", size = 5111310, upload-time = "2025-06-28T18:47:28.136Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/af/681a8b3e4f668bea6e6514cbcb297beb6de2b641e70f09d3d78655f4f44c/lxml-6.0.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:390240baeb9f415a82eefc2e13285016f9c8b5ad71ec80574ae8fa9605093cd7", size = 5025457, upload-time = "2025-06-26T16:26:15.068Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/b6/3a7971aa05b7be7dfebc7ab57262ec527775c2c3c5b2f43675cac0458cad/lxml-6.0.0-cp312-cp312-manylinux_2_27_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d6e200909a119626744dd81bae409fc44134389e03fbf1d68ed2a55a2fb10991", size = 5657016, upload-time = "2025-07-03T19:19:06.008Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/f8/693b1a10a891197143c0673fcce5b75fc69132afa81a36e4568c12c8faba/lxml-6.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ca50bd612438258a91b5b3788c6621c1f05c8c478e7951899f492be42defc0da", size = 5257565, upload-time = "2025-06-26T16:26:17.906Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/96/e08ff98f2c6426c98c8964513c5dab8d6eb81dadcd0af6f0c538ada78d33/lxml-6.0.0-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:c24b8efd9c0f62bad0439283c2c795ef916c5a6b75f03c17799775c7ae3c0c9e", size = 4713390, upload-time = "2025-06-26T16:26:20.292Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/83/6184aba6cc94d7413959f6f8f54807dc318fdcd4985c347fe3ea6937f772/lxml-6.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:afd27d8629ae94c5d863e32ab0e1d5590371d296b87dae0a751fb22bf3685741", size = 5066103, upload-time = "2025-06-26T16:26:22.765Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/01/8bf1f4035852d0ff2e36a4d9aacdbcc57e93a6cd35a54e05fa984cdf73ab/lxml-6.0.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:54c4855eabd9fc29707d30141be99e5cd1102e7d2258d2892314cf4c110726c3", size = 4791428, upload-time = "2025-06-26T16:26:26.461Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/31/c0267d03b16954a85ed6b065116b621d37f559553d9339c7dcc4943a76f1/lxml-6.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c907516d49f77f6cd8ead1322198bdfd902003c3c330c77a1c5f3cc32a0e4d16", size = 5678523, upload-time = "2025-07-03T19:19:09.837Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/f7/5495829a864bc5f8b0798d2b52a807c89966523140f3d6fa3a58ab6720ea/lxml-6.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36531f81c8214e293097cd2b7873f178997dae33d3667caaae8bdfb9666b76c0", size = 5281290, upload-time = "2025-06-26T16:26:29.406Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/56/6b8edb79d9ed294ccc4e881f4db1023af56ba451909b9ce79f2a2cd7c532/lxml-6.0.0-cp312-cp312-win32.whl", hash = "sha256:690b20e3388a7ec98e899fd54c924e50ba6693874aa65ef9cb53de7f7de9d64a", size = 3613495, upload-time = "2025-06-26T16:26:31.588Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/1e/cc32034b40ad6af80b6fd9b66301fc0f180f300002e5c3eb5a6110a93317/lxml-6.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:310b719b695b3dd442cdfbbe64936b2f2e231bb91d998e99e6f0daf991a3eba3", size = 4014711, upload-time = "2025-06-26T16:26:33.723Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/10/dc8e5290ae4c94bdc1a4c55865be7e1f31dfd857a88b21cbba68b5fea61b/lxml-6.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:8cb26f51c82d77483cdcd2b4a53cda55bbee29b3c2f3ddeb47182a2a9064e4eb", size = 3674431, upload-time = "2025-06-26T16:26:35.959Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/21/6e7c060822a3c954ff085e5e1b94b4a25757c06529eac91e550f3f5cd8b8/lxml-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6da7cd4f405fd7db56e51e96bff0865b9853ae70df0e6720624049da76bde2da", size = 8414372, upload-time = "2025-06-26T16:26:39.079Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/f6/051b1607a459db670fc3a244fa4f06f101a8adf86cda263d1a56b3a4f9d5/lxml-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b34339898bb556a2351a1830f88f751679f343eabf9cf05841c95b165152c9e7", size = 4593940, upload-time = "2025-06-26T16:26:41.891Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/74/dd595d92a40bda3c687d70d4487b2c7eff93fd63b568acd64fedd2ba00fe/lxml-6.0.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:51a5e4c61a4541bd1cd3ba74766d0c9b6c12d6a1a4964ef60026832aac8e79b3", size = 5214329, upload-time = "2025-06-26T16:26:44.669Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/46/3572761efc1bd45fcafb44a63b3b0feeb5b3f0066886821e94b0254f9253/lxml-6.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d18a25b19ca7307045581b18b3ec9ead2b1db5ccd8719c291f0cd0a5cec6cb81", size = 4947559, upload-time = "2025-06-28T18:47:31.091Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/8a/5e40de920e67c4f2eef9151097deb9b52d86c95762d8ee238134aff2125d/lxml-6.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d4f0c66df4386b75d2ab1e20a489f30dc7fd9a06a896d64980541506086be1f1", size = 5102143, upload-time = "2025-06-28T18:47:33.612Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/4b/20555bdd75d57945bdabfbc45fdb1a36a1a0ff9eae4653e951b2b79c9209/lxml-6.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f4b481b6cc3a897adb4279216695150bbe7a44c03daba3c894f49d2037e0a24", size = 5021931, upload-time = "2025-06-26T16:26:47.503Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/6e/cf03b412f3763d4ca23b25e70c96a74cfece64cec3addf1c4ec639586b13/lxml-6.0.0-cp313-cp313-manylinux_2_27_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a78d6c9168f5bcb20971bf3329c2b83078611fbe1f807baadc64afc70523b3a", size = 5645469, upload-time = "2025-07-03T19:19:13.32Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/dd/39c8507c16db6031f8c1ddf70ed95dbb0a6d466a40002a3522c128aba472/lxml-6.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae06fbab4f1bb7db4f7c8ca9897dc8db4447d1a2b9bee78474ad403437bcc29", size = 5247467, upload-time = "2025-06-26T16:26:49.998Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/56/732d49def0631ad633844cfb2664563c830173a98d5efd9b172e89a4800d/lxml-6.0.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:1fa377b827ca2023244a06554c6e7dc6828a10aaf74ca41965c5d8a4925aebb4", size = 4720601, upload-time = "2025-06-26T16:26:52.564Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/7f/6b956fab95fa73462bca25d1ea7fc8274ddf68fb8e60b78d56c03b65278e/lxml-6.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1676b56d48048a62ef77a250428d1f31f610763636e0784ba67a9740823988ca", size = 5060227, upload-time = "2025-06-26T16:26:55.054Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/06/e851ac2924447e8b15a294855caf3d543424364a143c001014d22c8ca94c/lxml-6.0.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:0e32698462aacc5c1cf6bdfebc9c781821b7e74c79f13e5ffc8bfe27c42b1abf", size = 4790637, upload-time = "2025-06-26T16:26:57.384Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/d4/fd216f3cd6625022c25b336c7570d11f4a43adbaf0a56106d3d496f727a7/lxml-6.0.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4d6036c3a296707357efb375cfc24bb64cd955b9ec731abf11ebb1e40063949f", size = 5662049, upload-time = "2025-07-03T19:19:16.409Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/03/0e764ce00b95e008d76b99d432f1807f3574fb2945b496a17807a1645dbd/lxml-6.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7488a43033c958637b1a08cddc9188eb06d3ad36582cebc7d4815980b47e27ef", size = 5272430, upload-time = "2025-06-26T16:27:00.031Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/01/d48cc141bc47bc1644d20fe97bbd5e8afb30415ec94f146f2f76d0d9d098/lxml-6.0.0-cp313-cp313-win32.whl", hash = "sha256:5fcd7d3b1d8ecb91445bd71b9c88bdbeae528fefee4f379895becfc72298d181", size = 3612896, upload-time = "2025-06-26T16:27:04.251Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/87/6456b9541d186ee7d4cb53bf1b9a0d7f3b1068532676940fdd594ac90865/lxml-6.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e", size = 4013132, upload-time = "2025-06-26T16:27:06.415Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/42/85b3aa8f06ca0d24962f8100f001828e1f1f1a38c954c16e71154ed7d53a/lxml-6.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:21db1ec5525780fd07251636eb5f7acb84003e9382c72c18c542a87c416ade03", size = 3672642, upload-time = "2025-06-26T16:27:09.888Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown"
|
||||
version = "3.8.2"
|
||||
|
@ -463,6 +513,7 @@ version = "1.2.1"
|
|||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "dacite" },
|
||||
{ name = "feedgen" },
|
||||
{ name = "jinja2" },
|
||||
{ name = "l2m4m" },
|
||||
{ name = "markdown" },
|
||||
|
@ -489,6 +540,7 @@ dev = [
|
|||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "dacite", specifier = ">=1.9.2" },
|
||||
{ name = "feedgen", specifier = ">=1.0.0" },
|
||||
{ name = "jinja2", specifier = ">=3.1.6" },
|
||||
{ name = "l2m4m", specifier = ">=1.0.4" },
|
||||
{ name = "markdown", specifier = ">=3.8.2" },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue