Rename the import package app to fluksio
A wheel whose top-level module is `app` collides with anything else in a user's venv, so the package that is about to be published takes the name it is published under. Only the Python package moves; the repo, the Docker WORKDIR and the compose project keep theirs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
"""Loading connector plugins from installed packages.
|
||||
|
||||
A connector is an ordinary Python package that advertises its node class under
|
||||
the ``fluksio.node_types`` entry point group. The entry point's name is the
|
||||
node type as it appears on the canvas, and the package's own metadata — name
|
||||
and version — is the manifest; there is no second format to keep in step.
|
||||
|
||||
Discovery happens once, at startup: a connector's code is imported, and Python
|
||||
does not re-import a changed module, so a rescan would promise more than it
|
||||
delivers. Installing or upgrading one means restarting the engine.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from importlib.metadata import entry_points
|
||||
|
||||
from fluksio.flow.connector import CONTRACT_VERSION, ConnectorNode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ENTRY_POINT_GROUP = "fluksio.node_types"
|
||||
|
||||
|
||||
def load_plugins() -> list[str]:
|
||||
"""Register every installed connector. Returns the type names it added."""
|
||||
from fluksio.flow.controller import NODE_TYPES, NodeType, _schema_of
|
||||
|
||||
added: list[str] = []
|
||||
for entry in entry_points(group=ENTRY_POINT_GROUP):
|
||||
if entry.name in NODE_TYPES:
|
||||
logger.warning(
|
||||
"Ignoring connector '%s': that node type already exists", entry.name
|
||||
)
|
||||
continue
|
||||
try:
|
||||
cls = entry.load()
|
||||
except Exception:
|
||||
logger.exception("Could not load connector '%s'", entry.name)
|
||||
continue
|
||||
|
||||
if not (isinstance(cls, type) and issubclass(cls, ConnectorNode)):
|
||||
logger.warning(
|
||||
"Ignoring connector '%s': %r is not a ConnectorNode", entry.name, cls
|
||||
)
|
||||
continue
|
||||
# Checked on the class itself: inheriting a version from a base class
|
||||
# would let a connector written against an older contract look current.
|
||||
if cls.__dict__.get("contract") != CONTRACT_VERSION:
|
||||
logger.warning(
|
||||
"Ignoring connector '%s': written for contract version %s, "
|
||||
"this engine speaks %s",
|
||||
entry.name,
|
||||
cls.__dict__.get("contract"),
|
||||
CONTRACT_VERSION,
|
||||
)
|
||||
continue
|
||||
|
||||
NODE_TYPES[entry.name] = NodeType(
|
||||
title=cls.title or entry.name,
|
||||
description=cls.description,
|
||||
cls=cls,
|
||||
params_schema=_schema_of(cls),
|
||||
plugin=_provenance(entry),
|
||||
)
|
||||
added.append(entry.name)
|
||||
logger.info("Loaded connector '%s' from %s", entry.name, _provenance(entry))
|
||||
|
||||
return added
|
||||
|
||||
|
||||
def _provenance(entry: object) -> str:
|
||||
"""Which package this node type came from, for the editor to show."""
|
||||
dist = getattr(entry, "dist", None)
|
||||
if dist is None:
|
||||
return "unknown"
|
||||
return f"{dist.name} {dist.version}"
|
||||
Reference in New Issue
Block a user