v0.142.0
 1from __future__ import annotations
 2
 3from .types import Source, TableOwner
 4
 5
 6def build_table_owners() -> dict[str, TableOwner]:
 7    """Map table names to their owning package, source, and model class."""
 8    import inspect
 9
10    from plain.packages import packages_registry
11    from plain.postgres import models_registry
12
13    def _source_file(cls: type) -> str:
14        try:
15            path = inspect.getsourcefile(cls)
16        except (TypeError, OSError):
17            return ""
18        return path or ""
19
20    owners: dict[str, TableOwner] = {}
21    for package_config in packages_registry.get_package_configs():
22        source = "app" if package_config.name.startswith("app.") else "package"
23        for model in models_registry.get_models(
24            package_label=package_config.package_label
25        ):
26            owners[model.model_options.db_table] = TableOwner(
27                package_label=package_config.package_label,
28                source=source,
29                model_class=model.__name__,
30                model_file=_source_file(model),
31            )
32            for field in model._model_meta.local_many_to_many:
33                m2m_table = field.m2m_db_table()
34                if m2m_table in owners:
35                    # Explicit "through" model already registered with its class.
36                    continue
37                owners[m2m_table] = TableOwner(
38                    package_label=package_config.package_label,
39                    source=source,
40                    model_class="",  # auto-generated join table, no class
41                    model_file="",
42                )
43    return owners
44
45
46def _table_info(
47    table_name: str, table_owners: dict[str, TableOwner]
48) -> tuple[Source, str, str, str]:
49    """Return (source, package, model_class, model_file) for a table name.
50
51    model_class and model_file are populated only for app-owned tables so
52    findings can suggest exact model edits. Package tables have a model class
53    but the user can't edit it from their app.
54    """
55    owner = table_owners.get(table_name)
56    if not owner:
57        return "", "", "", ""
58    if owner["source"] == "app":
59        return (
60            owner["source"],
61            owner["package_label"],
62            owner["model_class"],
63            owner["model_file"],
64        )
65    return owner["source"], owner["package_label"], "", ""