Fill in missing "Author" project metadata from "Author-Email" (#349)
* Fill in missing "Author" project metadata from "Author-Email"
This commit is contained in:
parent
789fe34ebd
commit
c74abf2402
|
@ -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 <author@example.org>"``), 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<mdspec_>`_ 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('<a href="mailto:{addr_specs}">{link_text}</a>').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,
|
||||
}
|
||||
)
|
|
@ -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',
|
||||
]
|
||||
}
|
||||
)
|
|
@ -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ö", '<a href="mailto:joe@example.net">Joe Blö</a>'),
|
||||
("joe@example.net", "Joe & Co", '<a href="mailto:joe@example.net">Joe & Co</a>'),
|
||||
("Joe & Co <joe@example.com>", "", '<a href="mailto:joe@example.com">Joe & Co</a>'),
|
||||
("Joe <joe@example.com>, Mary <mary@example.net>", "", '<a href="mailto:joe@example.com, mary@example.net">Joe, Mary</a>'),
|
||||
("joe@example.net", "", '<a href="mailto:joe@example.net">joe@example.net</a>'),
|
||||
("joe@example.net", None, '<a href="mailto:joe@example.net">joe@example.net</a>'),
|
||||
("", "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() == '<a href="mailto:joe@example.com">Joseph</a>'
|
|
@ -0,0 +1,6 @@
|
|||
[testenv]
|
||||
deps =
|
||||
lektor
|
||||
pytest
|
||||
commands =
|
||||
pytest tests
|
|
@ -50,7 +50,7 @@
|
|||
<p><strong>Version:</strong> {{ pd.version }}</p>
|
||||
<p><strong>Author:</strong>
|
||||
{% if pd.author_email %}
|
||||
<a href = "mailto:{{ pd.author_email }}">{{ pd.author }}</a>
|
||||
{{ mailto_link(pd.author_email, pd.author) }}
|
||||
{% else %}
|
||||
{{ pd.author }}
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in New Issue