Currently facts are loaded "by magic" into a global namespace (available via host.fact.X). Importing a module containing a fact automatically adds it to the fact list while converting the camel cased class name into snake case. This presents a few issues:
Potential alternative API:
from pyinfra import host
from pyinfra.facts.apt import AptSources
# Legacy
sources = host.fact.apt_sources
# New
sources = host.get_fact(AptSources)
I like this idea but I think the "all-facts" command will be harder to implement without registering all the facts classes somewhere. Maybe with entrypoints? Or just drop the all-facts command? (I don't understand what is the use-case for this).
The all facts should still work so long as the base class FactBase is used (the metaclass collects all the facts). Agreed there's not really a proper use-case for all facts other than debugging. Potentially useful to batch collect information about a server, if pyinfra was to output only valid JSON...
That's true for pyinfra built-in facts because they are imported when the CLI is started but not for facts declared in external packages. That's why I talked about entry points. I know we can import things in the config file, but IMO it's a hack, not a proper way to register external facts (e.g. python linters emit warnings for unused imports)
Ah yes, good point - entrypoints would work well I think. I'm not against simply removing all facts as well, I think it's a bit of an edge case and having the explicit imports removes all the magic entirely (and makes facts consistent with external/custom operations).
Removing "all facts" would not be a loss. It's information overload and doesn't serve a practical purpose.
having the explicit imports removes all the magic entirely (and makes facts consistent with external/custom operations).
This is actually much more valuable.
This has now been released in v1.4!
Most helpful comment
Ah yes, good point - entrypoints would work well I think. I'm not against simply removing all facts as well, I think it's a bit of an edge case and having the explicit imports removes all the magic entirely (and makes facts consistent with external/custom operations).