ADDED   pluginconf/flit.py
Index: pluginconf/flit.py
==================================================================
--- pluginconf/flit.py
+++ pluginconf/flit.py
@@ -0,0 +1,179 @@
+# encoding: utf-8
+# api: pep517
+# title: flit backend
+# description: wraps flit_core.buildapi
+# version: 0.1
+# depends: python:flit (>=3.0, <4.0)
+# license: BSD-3-Clause
+# priority: extra
+# src: ~/.local/lib/python3.8/site-packages/flit_core/
+#
+# This is supposed to become an alternative to pluginconf.setup,
+# using flit as pep517 build backend. But adding automagic field
+# lookup of course.
+# 
+#
+# [build-system]
+# requires = ["flit_core", "pluginconf"]
+# build-backend = "pluginconf.flit"
+#
+# [project]
+# name = "foobar"
+# dynamic = ["version", "description"]
+#
+#
+
+import os
+import re
+import os.path
+import pathlib
+import functools
+
+import pluginconf
+import pluginconf.setup
+
+import flit_core.common
+
+
+#-- patch functions
+
+def patch_flit_config(path):
+    """ read_flit_config() with preset dynamic fields """
+    d = tomllib.loads(path.read_text('utf-8'))
+    
+    # make fields dynamic
+    if not "dynamic" in d["project"]:
+        d["project"]["dynamic"] = []
+    for dyn in ['description', 'version']: 
+        if dyn in d["project"]:
+            del d["project"][dyn]
+        if not dyn in d["project"]["dynamic"]:
+            d["project"]["dynamic"].append(dyn)
+    print(d)
+
+    # turn it into LoadedConfig
+    return prep_toml_config(d, path)
+
+# override make_metadata
+def patch_metadata(module, ini_info):
+    meta = {
+        "name": module.name,
+        "provides": [module.name]
+    }
+    meta.update(ini_info.metadata)
+    meta.update(
+        pmd_meta(filename=module.file)
+    )
+    return flit_core.common.Metadata(meta)
+
+# inject
+flit_core.common.make_metadata = patch_metadata
+
+
+#-- map plugin meta to flit Metadata
+
+def pmd_meta(filename):
+    """ enjoin PMD fields with flit meta data """
+    pmd  = pluginconf.plugin_meta(filename=filename)
+    
+    meta = dict(
+        summary = pmd.get("description"),
+        version = pmd.get("version"),
+        home_page = pmd.get("url"),
+        author = pmd.get("author"),  # should split this into mail and name
+        author_email = None,
+        maintainer = None,
+        maintainer_email = None,
+        license = pmd.get("license"),
+        keywords = pmd.get("keywords"),
+        download_url = None,
+        requires_python = pluginconf.setup._python_requires(pmd).get("python_requires", ">= 2.7"),
+        platform = (),
+        supported_platform = (),
+        classifiers = list(pluginconf.setup._classifiers(pmd))
+                    + pluginconf.setup._trove_license(pmd)
+                    + pluginconf.setup._trove_status(pmd),
+        provides = (),
+        requires = pluginconf.setup._install_requires(pmd).get("install_requires") or (),
+        obsoletes = (),
+        project_urls = [f"{k}, {v}" for k,v in pluginconf.setup._project_urls(pmd).items()],
+        provides_dist = (),
+        requires_dist = pluginconf.setup._install_requires(pmd).get("install_requires") or (),
+        obsoletes_dist = (),
+        requires_external = (),
+        provides_extra = (),
+    )
+    meta.update({k[5:]: v for k,v in pluginconf.setup._plugin_doc(pmd).items()})
+    meta.update({k[5:]: v for k,v in pluginconf.setup._get_readme().items()})
+
+    return meta
+
+
+# 'metadata', 'module', 'referenced_files', 'reqs_by_extra',
+# 'sdist_exclude_patterns', 'sdist_include_patterns']
+#
+# ini.metadata =
+#   {'name': 'basename', 'requires_dist': []}
+#
+# ini.module =
+#   basename
+#
+# ini.dynamic_metadata =
+#   {'version', 'description'}
+#
+# ini.__dict__ =
+# {
+# 'module': 'pluginconf',
+# 'metadata': {
+#   'name': 'pluginconf',
+#   'version': '1.0',
+#   'summary': '...',
+#   'requires_dist': []
+# },
+# 'reqs_by_extra': {},
+# 'entrypoints': {},
+# 'referenced_files': [],
+# 'sdist_include_patterns': [],
+# 'sdist_exclude_patterns': [],
+# 'dynamic_metadata': [],
+# 'data_directory': None
+# }
+
+#module = Module(ini.module, pathlib.Path.cwd())
+#print(module.__dict__)
+#print(module.file)
+# {'name': 'pluginconf', 'path':
+# PosixPath('/home/mario/projects/pluginconf/pluginconf'), 'is_package':
+# True, 'prefix': '', 'source_dir':
+# PosixPath('/home/mario/projects/pluginconf')}
+
+#MD = patch_metadata(module, ini)
+#print(MD.__dict__)
+
+
+import flit_core.buildapi
+
+flit_core.buildapi.prepare_metadata_for_build_wheel("./build/")
+
+
+
+#-- buildapi
+#
+# These need to be late imports;
+# else they'll bind the original helper functions
+from flit_core.buildapi import (
+    get_requires_for_build_wheel,
+    get_requires_for_build_sdist,
+    get_requires_for_build_editable,
+    prepare_metadata_for_build_wheel,
+    prepare_metadata_for_build_editable,
+    build_wheel,
+    build_editable,
+    build_sdist,
+)
+
+import flit
+
+# as invocation point
+def main(argv=None):
+    return flit.main(argv)

Index: pluginconf/setup.py
==================================================================
--- pluginconf/setup.py
+++ pluginconf/setup.py
@@ -1,11 +1,11 @@
 # encoding: utf-8
 # api: setuptools
 # type: functions
 # title: setup() wrapper
 # description: utilizes PMD to populate some package fields
-# version: 0.3
+# version: 0.4
 # license: PD
 #
 # Utilizes plugin meta data to cut down setup.py incantations
 # to basically just:
 #
@@ -58,23 +58,124 @@
 def _get_readme():
     """ get README.md contents """
     for fn,mime in ("README.md", "text/markdown"), ("README.rst", "text/x-rst"), ("README.txt", "text/plain"):
         if os.path.exists(fn):
             with open(fn, "r") as f:
-                return f.read(), mime
-    #system("pandoc -f markdown -t rst README.md  > README.rst")
-    return "", "text/plain"
+                return {
+                    "long_description": f.read(),
+                    "long_description_content_type": mime,
+                }
+    return {
+        "long_description": "",
+        "long_description_content_type": "text/plain",
+    }
+
+def _plugin_doc(pmd):
+    """ use comment block """
+    return {
+        "long_description": pmd["doc"],
+        "long_description_content_type": pmd.get("doc_format", "text/plain"),
+    }
+
+def _python_requires(pmd):
+    """ # depends: python >= 3.5 """
+    deps = re.findall("python\s*\(?(>=?\s?[\d.]+)", pmd.get("depends", ""))
+    if deps:
+        return {"python_requires": deps[0]}
+    return {}
+
+def _install_requires(pmd):
+    """ # depends: python:module, pip:module """
+    deps = re.findall("(?:python|pip):([\w\-]+)\s*(\(?[<=>\s\d.\-]+)?", pmd.get("depends", ""))
+    if deps:
+        return {"install_requires": [name+re.sub("[^<=>\d.\-]", "", ver) for name,ver in deps]}
+    return {}
+
+def _extras_require(pmd):
+    """ # suggest: line """
+    deps = re.findall("(?:python|pip):([\w\-]+)\s*\(?\s*([>=<]+\s*[\d.\-]+)", pmd.get("suggests", ""))
+    if deps:
+        return dict(deps)
+    return {}
+
+def _project_urls(pmd, exclude=["url"]):
+    """ # other-url: https://... """
+    urls = {}
+    for k,url in pmd.items():
+        if type(url) is str and k not in exclude and re.match("https?://\S+", url):
+            urls[k.title()] = url
+    return urls
+
+def _classifiers(pmd):
+    """ # classifiers: / keywords: / category: """
+    for field in ("api", "category", "type", "keywords", "classifiers"):
+        field = pmd.get(field, "")
+        field = re.findall("(\w{4,})", field)
+        rx = "|".join(field)
+        if not rx:
+            continue
+        for line in topic_trove:
+            if re.search("::[^:]*("+rx+")[^:]*$", line, re.I):
+                yield line
+
+def _trove_license(pmd):
+    """ license: to License :: """
+    trove_licenses = {
+        "MITL?": "License :: OSI Approved :: MIT License",
+        "PD|Public Domain": "License :: Public Domain",
+        "ASL": "License :: OSI Approved :: Apache Software License",
+        "art": "License :: OSI Approved :: Artistic License",
+        "BSDL?": "License :: OSI Approved :: BSD License",
+        "CPL": "License :: OSI Approved :: Common Public License",
+        "AGPL.*3": "License :: OSI Approved :: GNU Affero General Public License v3",
+        "AGPLv*3\+": "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
+        "GPL": "License :: OSI Approved :: GNU General Public License (GPL)",
+        "GPL.*3": "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
+        "LGPL": "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
+        "MPL": "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
+        "Pyth": "License :: OSI Approved :: Python Software Foundation License"
+    }
+    for rx, trove in trove_licenses.items():
+        if re.search(rx, pmd["license"], re.I):
+            return [trove]
+    return []
+
+def _trove_status(pmd):
+    """ state: to DevStatus :: """
+    trove_status = {
+        "pre|release|cand": "Development Status :: 2 - Pre-Alpha",
+        "alpha": "Development Status :: 3 - Alpha",
+        "beta": "Development Status :: 4 - Beta",
+        "stable": "Development Status :: 5 - Production/Stable",
+        "mature": "Development Status :: 6 - Mature"
+    }
+    for rx, trove in trove_status.items():
+        state = pmd.get("state") or pmd.get("status") or "alpha"
+        if re.search(rx, state, re.I):
+            return [trove]
+    return []
+
+def _datafiles_man():
+    """ data_files= """
+    for man in glob.glob("man*/*.[12345678]"):
+        section = man[-1]
+        yield ("man/man"+section, [man],)
+
+def _keywords(pmd):
+    """ keywords= """
+    return pmd.get("keywords") or pmd.get("category")
+
 
 def setup(debug=0, **kwargs):
     """
-        Wrapper around `setuptools.setup()` which adds some defaults
-        and plugin meta data import, with two shortcut params:
-        
-          fn="pkg/main.py",
-          long_description="@README.md"
+    Wrapper around `setuptools.setup()` which adds some defaults
+    and plugin meta data import, with two shortcut params:
+    
+      fn="pkg/main.py",
+      long_description="@README.md"
 
-        Other setup() params work as usual.
+    Other setup() params work as usual.
     """
 
     # stub values
     stub = {
         "classifiers": [],
@@ -91,24 +192,27 @@
     for k,v in stub.items():
         if not k in kwargs:
             kwargs[k] = v
 
     # package name
-    if not "name" in kwargs:
+    if "name" not in kwargs and kwargs.get("packages"):
         kwargs["name"] = kwargs["packages"][0]
 
     # read README
-    if not "long_description" in kwargs or re.match("^@?([.\w]+/)*README.(\w+)$", kwargs.get("long_description", "-")):
-        kwargs["long_description"], kwargs["long_description_content_type"] = _get_readme()
+    if not "long_description" in kwargs:
+        kwargs.update(_get_readme())
 
     # search name= package if no fn= given
+    if kwargs.get("filename"):
+        kwargs["fn"] = kwargs["filename"]
+        del kwargs["filename"]
     if not kwargs.get("fn") and kwargs.get("name"):
         kwargs["fn"] = _name_to_fn(kwargs["name"])
 
     # read plugin meta data (PMD)  
     pmd = {}
-    pmd = pluginconf.plugin_meta(fn=kwargs["fn"])
+    pmd = pluginconf.plugin_meta(filename=kwargs["fn"])
     
     # id: if no name= still
     if pmd.get("id") and not kwargs.get("name"):
         if pmd["id"] == "__init__":
             pmd["id"] = re.findall("([\w\.\-]+)/__init__.+$", kwargs["fn"])[0]
@@ -119,87 +223,41 @@
 
     # version:, description:, author:
     for field in "version", "description", "license", "author", "url":
         if field in pmd and not field in kwargs:
             kwargs[field] = pmd[field]
+
     # other urls:
-    for k,url in pmd.items():
-        if type(url) is str and k != "url" and re.match("https?://\S+", url):
-            kwargs["project_urls"][k.title()] = url
+    kwargs["project_urls"].update(_project_urls(pmd))
     # depends:
     if "depends" in pmd:
-        deps = re.findall("python\s*\(?(>=?\s?[\d.]+)", pmd["depends"])
-        if deps:
-            kwargs["python_requires"] = deps[0]
+        kwargs.update(_python_requires(pmd))
     if "depends" in pmd and not kwargs["install_requires"]:
-        deps = re.findall("(?:python|pip):([\w\-]+)\s*(\(?[<=>\s\d.\-]+)?", pmd["depends"])
-        if deps:
-            kwargs["install_requires"] = [name+re.sub("[^<=>\d.\-]", "", ver) for name,ver in deps]
+        kwargs.update(_install_requires(pmd))
     # suggests:
     if "suggests" in pmd and not kwargs["extras_require"]:
-        deps = re.findall("(?:python|pip):([\w\-]+)\s*\(?\s*([>=<]+\s*[\d.\-]+)", pmd["suggests"])
-        if deps:
-            kwargs["extras_require"].update(dict(deps))
+        kwargs["extras_require"].update(_extras_require(pmd))
     # doc:
     if not kwargs.get("long_description"):
-        kwargs["long_description"] = pmd["doc"]
-        kwargs["long_description_content_type"] = pmd.get("doc_format", "text/plain")
+        kwargs.update(_plugin_doc(pmd))
+
     # keywords=
     if not "keywords" in kwargs:
-        if "keywords" in pmd:
-            kwargs["keywords"] = pmd["keywords"]
-        elif "category" in pmd:
-            kwargs["keywords"] = pmd["category"]
+        kwargs["keywords"] = _keywords(pmd)
     
     # automatic inclusions
-    if not "data_files" in kwargs:
-        kwargs["data_files"] = []
-    for man in glob.glob("man*/*.[12345678]"):
-        section = man[-1]
-        kwargs["data_files"].append(("man/man"+section, [man],))
+    kwargs["data_files"] = kwargs.get("data_files", []) + list(_datafiles_man())
 
     # classifiers=
-    trove_map = {
-        "license": {
-            "MITL?": "License :: OSI Approved :: MIT License",
-            "PD|Public Domain": "License :: Public Domain",
-            "ASL": "License :: OSI Approved :: Apache Software License",
-            "art": "License :: OSI Approved :: Artistic License",
-            "BSDL?": "License :: OSI Approved :: BSD License",
-            "CPL": "License :: OSI Approved :: Common Public License",
-            "AGPL.*3": "License :: OSI Approved :: GNU Affero General Public License v3",
-            "AGPLv*3\+": "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
-            "GPL": "License :: OSI Approved :: GNU General Public License (GPL)",
-            "GPL.*3": "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
-            "LGPL": "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
-            "MPL": "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
-            "Pyth": "License :: OSI Approved :: Python Software Foundation License"
-        },
-        "state": {
-            "pre|release|cand": "Development Status :: 2 - Pre-Alpha",
-            "alpha": "Development Status :: 3 - Alpha",
-            "beta": "Development Status :: 4 - Beta",
-            "stable": "Development Status :: 5 - Production/Stable",
-            "mature": "Development Status :: 6 - Mature"
-        }
-    }
     # license:
     if pmd.get("license") and not any(re.match("License ::", l) for l in kwargs["classifiers"]):
-        for rx,trove in trove_map["license"].items():
-            if re.search(rx, pmd["license"], re.I):
-                kwargs["classifiers"].append(trove)
+        kwargs["classifiers"].extend(_trove_license(pmd))
     # state:
     if pmd.get("state", pmd.get("status")) and not any(re.match("Development Status ::", l) for l in kwargs["classifiers"]):
-        for rx,trove in trove_map["state"].items():
-            if re.search(rx, pmd.get("state", pmd.get("status", "stable")), re.I):
-                kwargs["classifiers"].append(trove)
+        kwargs["classifiers"].extend(_trove_status(pmd))
     # topics::
-    rx = "|".join(re.findall("(\w{4,})", " | ".join([pmd.get(f, "---") for f in ("api", "category", "type", "keywords", "classifiers")])))
-    for line in topic_trove:
-        if re.search("::[^:]*("+rx+")[^:]*$", line, re.I):
-            if line not in kwargs["classifiers"]:
-                kwargs["classifiers"].append(line)
+    kwargs["classifiers"].extend(list(_classifiers(pmd)))
 
     # handover
     if debug:
         import pprint
         pprint.pprint(kwargs)