Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
repos:
- repo: https://github.com/ambv/black
rev: 21.12b0
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.9.9
hooks:
- id: black
- repo: https://github.com/asottile/reorder_python_imports
rev: v2.6.0
hooks:
- id: reorder-python-imports
# Run the linter.
- id: ruff
# Run the formatter.
- id: ruff-format
12 changes: 9 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@

## Development environment

Create a development environment with `Python>=3.6`.
Create a development environment with `Python>=3.8`.

Please do not create a venv directly in the project directory.
else pytest will find too many tests.

You can then install the development and test dependencies with:

```bash
python -m pip install lektor
python -m pip install --editable .[test]
python -m pip install --group dev --editable .
```

[!WARNING]
This example only works with pip in version 25.1 or newer.
Version 25.1 has a planned release date of 2025-04-30

## Tests

To run the test suite, we use `pytest`:
Expand Down
18 changes: 16 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
test:
tox
.DEFAULT_GOAL := help

test-python: ## Run tests on Python files.
@echo "---> running python tests"
tox p

.PHONY: lint
lint: ## Lint code.
pre-commit run -a

.PHONY: test
test: lint test-python

.PHONY: help
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
14 changes: 8 additions & 6 deletions lektor_atom.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import hashlib
import uuid
from datetime import date
from datetime import datetime
import hashlib
import uuid

import click
from feedgenerator.django.utils.feedgenerator import Atom1Feed
Expand Down Expand Up @@ -67,7 +67,7 @@ def get_item_title(item, field):

def get_item_body(item, field):
if field not in item:
raise RuntimeError("Body field %r not found in %r" % (field, item))
raise RuntimeError(f"Body field {field!r} not found in {item!r}")
with get_ctx().changed_base_url(item.url_path):
return str(escape(item[field]))

Expand Down Expand Up @@ -132,14 +132,16 @@ def build_artifact(self, artifact):
content=get_item_body(item, feed_source.item_body_field),
link=url_to(item, external=True),
unique_id=get_id(
"%s/%s" % (ctx.env.project.id, item["_path"].encode("utf-8"))
"{}/{}".format(
ctx.env.project.id, item["_path"].encode("utf-8")
)
),
author_name=item_author,
updateddate=get_item_updated(item, feed_source.item_date_field),
)

except Exception as exc:
msg = "%s: %s" % (item["_id"], exc)
msg = "{}: {}".format(item["_id"], exc)
click.echo(click.style("E", fg="red") + " " + msg)

with artifact.open("wb") as f:
Expand Down Expand Up @@ -168,7 +170,7 @@ class AtomPlugin(Plugin):

def get_atom_config(self, feed_id, key):
default_value = self.defaults[key]
return self.get_config().get("%s.%s" % (feed_id, key), default_value)
return self.get_config().get(f"{feed_id}.{key}", default_value)

def on_setup_env(self, **extra):
self.env.add_build_program(AtomFeedSource, AtomFeedBuilderProgram)
Expand Down
85 changes: 82 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,84 @@
[build-system]
requires = ["setuptools>=45", "wheel", "setuptools_scm[toml]>=6"]
build-backend = "setuptools.build_meta"
requires = ["hatchling>=1.13.0,<2.0.0", "hatch-vcs"]
build-backend = "hatchling.build"

[tool.setuptools_scm]
[project]
name = "lektor-atom"
description = "Lektor plugin that generates Atom feeds."
keywords = ["Lektor", "plugin", "static-site", "blog", "atom", "rss"]
version = "0.4.0"
readme = "README.md"
authors = [
{name = "A. Jesse Jiryu Davis", email = "[email protected]"},
]
requires-python = ">=3.8"
license-expression = "MIT"
classifiers = [
"Environment :: Plugins",
"Environment :: Web Environment",
"Framework :: Lektor",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
]
dependencies = [
"MarkupSafe",
"feedgenerator",
"tox>=4.24.1",
]

[dependency-groups]
dev = [
"pytest",
"ruff",
"lektor",
"lxml"

]
[project.urls]
Homepage = "https://github.com/lektor/lektor-atom"

[project.entry-points."lektor.plugins"]
atom = "lektor_atom:AtomPlugin"

[tool.hatch.build.targets.sdist]
exclude = [
".github",
]

################################################################
#
# pylint
#
[tool.pylint.main]
ignore = [".git"]
load-plugins = "pylint.extensions.no_self_use"
extension-pkg-allow-list = "lxml"

[tool.pylint.format]
max-line-length = 91
max-module-lines = 2000

[tool.pylint."messages control"]
disable = [
"missing-docstring",
]


[tool.tox]
requires = ["tox>=4.22"]
env_list = [
"3.14",
"3.13",
"3.12",
"3.11",
"3.10",
"3.9",
"3.8",
]

[tool.tox.env_run_base]
description = "Run test under {base_python}"
dependency_groups = [
"dev",
]
commands = [["pytest"]]
29 changes: 0 additions & 29 deletions setup.cfg

This file was deleted.

29 changes: 11 additions & 18 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from datetime import datetime
import os
import shutil
import tempfile
from datetime import datetime

import pytest
from lektor import db
from lektor.builder import Builder
from lektor.environment import Environment
from lektor.project import Project
from lektor.reporter import BufferReporter
from lektor.types import Type
import pytest


class DatetimeType(Type):
Expand All @@ -14,37 +19,29 @@ def value_from_raw(self, raw):

@pytest.fixture(scope="function")
def project(request):
from lektor.project import Project

return Project.from_path(os.path.join(os.path.dirname(__file__), "demo-project"))


@pytest.fixture(scope="function")
def env(request, project):
from lektor.environment import Environment

e = Environment(project)
e.types["datetime"] = DatetimeType # As if we had a datetime plugin.
return e


@pytest.fixture(scope="function")
def pad(request, env):
from lektor.db import Database

return Database(env).new_pad()
return db.Database(env).new_pad()


def make_builder(request, pad):
from lektor.builder import Builder

out = tempfile.mkdtemp()
b = Builder(pad, out)

def cleanup():
try:
shutil.rmtree(out)
except (OSError, IOError):
except OSError:
pass

request.addfinalizer(cleanup)
Expand All @@ -57,16 +54,12 @@ def builder(request, pad):


@pytest.fixture(scope="function")
def F():
from lektor.db import F

return F
def F(): # pylint: disable=invalid-name
return db.F


@pytest.fixture(scope="function")
def reporter(request, env):
from lektor.reporter import BufferReporter

r = BufferReporter(env)
r.push()
request.addfinalizer(r.pop)
Expand Down
34 changes: 17 additions & 17 deletions tests/test_lektor_atom.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
from urlparse import urljoin


def test_typical_feed(pad, builder):
def test_typical_feed(builder):
failures = builder.build_all()
assert not failures
feed_path = os.path.join(builder.destination_path, "typical-blog/feed.xml")
feed = objectify.parse(open(feed_path)).getroot()
with open(feed_path, encoding="utf-8") as feed_stream:
feed = objectify.parse(feed_stream).getroot()

assert "Feed One" == feed.title
assert "My Summary" == feed.subtitle
Expand Down Expand Up @@ -51,11 +52,12 @@ def test_typical_feed(pad, builder):
assert "A. Jesse Jiryu Davis" == post1.author.name


def test_custom_feed(pad, builder):
def test_custom_feed(builder):
failures = builder.build_all()
assert not failures
feed_path = os.path.join(builder.destination_path, "custom-blog/atom.xml")
feed = objectify.parse(open(feed_path)).getroot()
with open(feed_path, encoding="utf-8") as feed_stream:
feed = objectify.parse(feed_stream).getroot()

assert "Feed Three" == feed.title
assert "<p>My Description</p>" == str(feed.subtitle).strip()
Expand Down Expand Up @@ -92,7 +94,7 @@ def test_custom_feed(pad, builder):
assert "A. Jesse Jiryu Davis" == post1.author.name


def test_virtual_resolver(pad, builder):
def test_virtual_resolver(pad):
# Pass a virtual source path to url_to().
feed_path = "/typical-blog@atom/feed-one"
url_path = pad.get("typical-blog/post1").url_to(feed_path)
Expand All @@ -117,15 +119,13 @@ def test_dependencies(pad, builder, reporter):
reporter.clear()
builder.build(pad.get("typical-blog@atom/feed-one"))

assert set(reporter.get_recorded_dependencies()) == set(
[
"Website.lektorproject",
"content/typical-blog",
"content/typical-blog/contents.lr",
"content/typical-blog/post1/contents.lr",
"content/typical-blog/post2/contents.lr",
"models/blog.ini",
"models/blog-post.ini",
"configs/atom.ini",
]
)
assert set(reporter.get_recorded_dependencies()) == {
"Website.lektorproject",
"content/typical-blog",
"content/typical-blog/contents.lr",
"content/typical-blog/post1/contents.lr",
"content/typical-blog/post2/contents.lr",
"models/blog.ini",
"models/blog-post.ini",
"configs/atom.ini",
}
20 changes: 0 additions & 20 deletions tox.ini

This file was deleted.