details:   https://code.tryton.org/hatch-tryton/commit/c1e376fe1766
branch:    default
user:      Cédric Krier <[email protected]>
date:      Thu Mar 12 13:19:52 2026 +0100
description:
        Add dynamic authors from copyright file
diffstat:

 hatch_tryton/plugin.py              |  28 ++++++++++++++++-
 hatch_tryton/tests/test_metadata.py |  59 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 85 insertions(+), 2 deletions(-)

diffs (127 lines):

diff -r 4fdd86f378e3 -r c1e376fe1766 hatch_tryton/plugin.py
--- a/hatch_tryton/plugin.py    Wed Mar 11 23:29:20 2026 +0100
+++ b/hatch_tryton/plugin.py    Thu Mar 12 13:19:52 2026 +0100
@@ -4,12 +4,15 @@
 import re
 from collections import namedtuple
 from configparser import ConfigParser
+from email.utils import parseaddr
 from pathlib import Path
-from typing import Optional
+from typing import Generator, Optional
 
 from hatchling.metadata.plugin.interface import MetadataHookInterface
 
 TrytonConfig = namedtuple('TrytonConfig', ['version', 'depends'])
+Author = namedtuple('Author', ['name', 'email'])
+_COPYRIGHT_PREFIX = "Copyright (C) "
 
 
 def _get_tryton_cfg(
@@ -57,6 +60,24 @@
         }
 
 
+def _get_authors(root: str, path: str) -> Generator[Author, None, None]:
+    copyright_path = Path(root) / path
+    with copyright_path.open() as f:
+        for line in f:
+            line = line.strip()
+            if not line.lower().startswith(_COPYRIGHT_PREFIX.lower()):
+                continue
+            try:
+                _, name = line[len(_COPYRIGHT_PREFIX):].split(' ', 1)
+            except ValueError:
+                continue
+            if '@' in name:
+                name, email = parseaddr(name)
+            else:
+                email = ''
+            yield Author(name=name, email=email)
+
+
 class TrytonMetadataHook(MetadataHookInterface):
     PLUGIN_NAME = 'tryton'
 
@@ -112,3 +133,8 @@
                     or 'readme' not in metadata.get('dynamic', [])):
                 raise ValueError("'readme' must be dynamic")
             metadata['readme'] = _get_readme(self.root, readme)
+
+        if ((copyright := self.config.get('copyright'))
+                and 'authors' in metadata.get('dynamic', [])):
+            metadata['authors'] = list(
+                map(Author._asdict, _get_authors(self.root, copyright)))
diff -r 4fdd86f378e3 -r c1e376fe1766 hatch_tryton/tests/test_metadata.py
--- a/hatch_tryton/tests/test_metadata.py       Wed Mar 11 23:29:20 2026 +0100
+++ b/hatch_tryton/tests/test_metadata.py       Thu Mar 12 13:19:52 2026 +0100
@@ -5,7 +5,7 @@
 from textwrap import dedent
 from typing import TYPE_CHECKING
 
-from hatch_tryton.plugin import TrytonMetadataHook
+from hatch_tryton.plugin import Author, TrytonMetadataHook, _get_authors
 
 from .tools import with_temporay_directory
 
@@ -256,3 +256,60 @@
         hook = TrytonMetadataHook(directory, config)
         with self.assertRaisesRegex(ValueError, r"readme.*dynamic"):
             hook.update(metadata)
+
+    @with_temporay_directory
+    def test_authors_from_copyright(self, directory: Path):
+        "Test authors from copyright file"
+        config = {
+            'copyright': 'COPYRIGHT',
+            }
+        metadata = {
+            'dynamic': ['authors'],
+            }
+        (directory / 'COPYRIGHT').write_text(dedent("""\
+                Copyright (C) 9999 John Doe
+
+                Text"""))
+        hook = TrytonMetadataHook(directory, config)
+        hook.update(metadata)
+        self.assertEqual(
+            [{'name': "John Doe", 'email': ''}],
+            metadata.get('authors'))
+
+    @with_temporay_directory
+    def test_authors_from_copyright_not_dynamic(self, directory: Path):
+        "Test authors from copyright file not dynamic"
+        config = {
+            'copyright': 'COPYRIGHT',
+            }
+        metadata = {
+            'authors': [{'name': "Jane Doe", 'email': ''}],
+            }
+        (directory / 'COPYRIGHT').write_text(dedent("""\
+                Copyright (C) 9999 John Doe
+
+                Text"""))
+        hook = TrytonMetadataHook(directory, config)
+        hook.update(metadata)
+        self.assertEqual(
+            [{'name': "Jane Doe", 'email': ''}],
+            metadata.get('authors'))
+
+    @with_temporay_directory
+    def test_get_authors(self, directory: Path):
+        "Test get authors from copyright file"
+        (directory / 'COPYRIGHT').write_text(dedent("""\
+                Copyright (C) 9999 John Doe
+                Copyright (C) 0000-9999 Jane Doe
+                Copyright (C) 9999 John Doe <[email protected]>
+                Copyright (C) 9999 <[email protected]>
+                junk"""))
+        authors = list(_get_authors(directory, 'COPYRIGHT'))
+
+        self.assertEqual([
+                Author("John Doe", ''),
+                Author("Jane Doe", ''),
+                Author("John Doe", '[email protected]'),
+                Author('', '[email protected]'),
+                ],
+            authors)

Reply via email to