From c74abf24024266d345c48e43d4f8849990cdfedd Mon Sep 17 00:00:00 2001 From: Jeff Dairiki Date: Tue, 13 Sep 2022 07:40:55 -0700 Subject: [PATCH] Fill in missing "Author" project metadata from "Author-Email" (#349) * Fill in missing "Author" project metadata from "Author-Email" --- .../jinja-globals/lektor_jinja_globals.py | 70 +++++++++++++++++++ packages/jinja-globals/setup.py | 21 ++++++ .../jinja-globals/tests/test_jinja_globals.py | 37 ++++++++++ packages/jinja-globals/tox.ini | 6 ++ templates/plugin.html | 2 +- 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 packages/jinja-globals/lektor_jinja_globals.py create mode 100644 packages/jinja-globals/setup.py create mode 100644 packages/jinja-globals/tests/test_jinja_globals.py create mode 100644 packages/jinja-globals/tox.ini diff --git a/packages/jinja-globals/lektor_jinja_globals.py b/packages/jinja-globals/lektor_jinja_globals.py new file mode 100644 index 00000000..203ce932 --- /dev/null +++ b/packages/jinja-globals/lektor_jinja_globals.py @@ -0,0 +1,70 @@ +from email.utils import getaddresses +from typing import Optional + +from markupsafe import Markup + +from lektor.pluginsystem import Plugin + + +def mailto_link(email_address: str, default_link_text: Optional[str] = None) -> Markup: + """Format an HTML link to a mailto: URL to ``email_address``. + + ``Email_address`` should be a string containing one or more + comma-separated RFC5322 addresses. Any *display-name*\\s included + in ``email_address`` will be stripped, before use in the + ``mailto:`` URL. (RFC6068_ allows only *addr-spec*\\s in the + ``mailto:`` URI.) + + The link text will be formed from the *display-name*\\s extracted + from ``email_address``. If there are none, they the link text + will be taken from the value of the optional ``display_name`` + parameter. If that is empty, the link text will be the value of + ``email_address``. + + Background + ********** + + This filter is useful for massaging a distributions "Author-email" + and "Author" metadata fields into a valid mailto link. Sometimes + the author's name gets folded into the "Author-email" field + (e.g. ``"Author Name "``), and sometimes it is + separated out into the "Author" field. + + According to PEP621_, when both author ``name`` and ``email`` are + specified in ``pyproject.toml``, both of those wind up in the + "Author-Email" metadata field. In that case, the "Author" metadata + field remains empty. + + In constrast, historically, (e.g. in ``setup.py`` based projects) it + seems to have been common practice to put the author's name in + "Author" and their email in "Author-Email". (Of note, the `Core Metadata + Spec`_ is not particularly opinionated on whether the + author name(s) should go into "Author", "Author-Email", or both.) + + .. _PEP621: https://peps.python.org/pep-0621/#authors-maintainers + .. _mdspec: https://packaging.python.org/en/latest/specifications/core-metadata/#author + .. _RFC6068: https://datatracker.ietf.org/doc/html/rfc6068 + + """ + addresses = getaddresses([email_address]) + addr_specs = ", ".join(addr_spec for name, addr_spec in addresses if addr_spec) + if not addr_specs: + return Markup("") + + link_text = ", ".join(name for name, addr_spec in addresses if name) + if not link_text: + link_text = default_link_text or addr_specs + + return Markup('{link_text}').format(**locals()) + + +class JinjaGlobalsPlugin(Plugin): + name = "Jinja Globals" + description = "Custom Jinja globals and filters for lektor-website." + + def on_setup_env(self, **extra): + self.env.jinja_env.globals.update( + { + "mailto_link": mailto_link, + } + ) diff --git a/packages/jinja-globals/setup.py b/packages/jinja-globals/setup.py new file mode 100644 index 00000000..35c12507 --- /dev/null +++ b/packages/jinja-globals/setup.py @@ -0,0 +1,21 @@ +from setuptools import setup + +setup( + name='lektor-jinja-globals', + author="Jeff Dairiki", + author_email="dairiki@dairiki.org", + description="Custom Jinja globals and filters for lektor-website", + keywords="Lektor plugin", + license="MIT", + py_modules=["lektor_jinja_globals"], + version='0.1', + classifiers=[ + 'Framework :: Lektor', + 'Environment :: Plugins', + ], + entry_points={ + 'lektor.plugins': [ + 'jinja-globals = lektor_jinja_globals:JinjaGlobalsPlugin', + ] + } +) diff --git a/packages/jinja-globals/tests/test_jinja_globals.py b/packages/jinja-globals/tests/test_jinja_globals.py new file mode 100644 index 00000000..326717dd --- /dev/null +++ b/packages/jinja-globals/tests/test_jinja_globals.py @@ -0,0 +1,37 @@ +import pytest + +from lektor.environment import Environment +from lektor.environment import FormatExpression +from lektor.project import Project + +from lektor_jinja_globals import JinjaGlobalsPlugin +from lektor_jinja_globals import mailto_link + + +@pytest.mark.parametrize("email_address, default_link_text, expected", [ + ("joe@example.net", "Joe Blö", 'Joe Blö'), + ("joe@example.net", "Joe & Co", 'Joe & Co'), + ("Joe & Co ", "", 'Joe & Co'), + ("Joe , Mary ", "", 'Joe, Mary'), + ("joe@example.net", "", 'joe@example.net'), + ("joe@example.net", None, 'joe@example.net'), + ("", "Goober", ""), + ("<>", "Goober", ""), +]) +def test_mailto_link(email_address, default_link_text, expected): + assert mailto_link(email_address, default_link_text) == expected + + +@pytest.fixture +def jinja_globals_env(tmp_path): + """A minimal Lektor environment with our plugin registered.""" + project = Project("Test Project", project_file=None, tree=tmp_path) + env = Environment(project, load_plugins=False) + env.plugin_controller.instanciate_plugin("jinja-globals", JinjaGlobalsPlugin) + env.plugin_controller.emit("setup-env") + return env + + +def test_integration(jinja_globals_env): + expr = FormatExpression(jinja_globals_env, '{{ mailto_link("joe@example.com", "Joseph") }}') + assert expr.evaluate() == 'Joseph' diff --git a/packages/jinja-globals/tox.ini b/packages/jinja-globals/tox.ini new file mode 100644 index 00000000..7b3b7243 --- /dev/null +++ b/packages/jinja-globals/tox.ini @@ -0,0 +1,6 @@ +[testenv] +deps = + lektor + pytest +commands = + pytest tests diff --git a/templates/plugin.html b/templates/plugin.html index 00cf82f6..3752bb6e 100644 --- a/templates/plugin.html +++ b/templates/plugin.html @@ -50,7 +50,7 @@

Version: {{ pd.version }}

Author: {% if pd.author_email %} - {{ pd.author }} + {{ mailto_link(pd.author_email, pd.author) }} {% else %} {{ pd.author }} {% endif %}