Skip to content

Commit 922da20

Browse files
authored
meta,api: lazy load fact and operation modules (#1609)
1 parent 4c0bc32 commit 922da20

6 files changed

Lines changed: 53 additions & 29 deletions

File tree

src/pyinfra/api/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from .command import FileDownloadCommand # noqa: F401 # pragma: no cover
21
from .command import ( # noqa: F401
2+
FileDownloadCommand, # noqa: F401 # pragma: no cover
33
FileUploadCommand,
44
FunctionCommand,
55
MaskString,
@@ -9,12 +9,12 @@
99
)
1010
from .config import Config # noqa: F401 # pragma: no cover
1111
from .deploy import deploy # noqa: F401 # pragma: no cover
12-
from .exceptions import DeployError # noqa: F401 # pragma: no cover
1312
from .exceptions import ( # noqa: F401
13+
DeployError, # noqa: F401 # pragma: no cover
1414
FactError,
15+
FactProcessError,
1516
FactTypeError,
1617
FactValueError,
17-
FactProcessError,
1818
InventoryError,
1919
OperationError,
2020
OperationTypeError,

src/pyinfra/api/operations.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ def _run_host_op(state: "State", host: "Host", op_hash: str) -> bool:
200200
if retry_attempt > 0:
201201
_status_text = f"{_status_text} on retry {retry_attempt}"
202202

203-
_click_log_status = click.style(_status_text, "green" if executed_commands > 0 else "cyan")
204-
logger.info("{0}{1}".format(host.print_prefix, _click_log_status))
203+
_log_status = click.style(_status_text, "green" if executed_commands > 0 else "cyan")
204+
logger.info("{0}{1}".format(host.print_prefix, _log_status))
205205

206206
state.trigger_callbacks("operation_host_success", host, op_hash, retry_attempt)
207207
else:

src/pyinfra/facts/__init__.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
1-
# This file only exists to support:
2-
# from pyinfra import facts
3-
# facts.X.Y
4-
1+
import importlib
52
from glob import glob
63
from os import path
74

8-
module_filenames = glob(path.join(path.dirname(__file__), "*.py"))
9-
module_names = [path.basename(name)[:-3] for name in module_filenames]
10-
__all__ = [name for name in module_names if name != "__init__"]
5+
_module_filenames = glob(path.join(path.dirname(__file__), "*.py"))
6+
__all__ = sorted(
7+
set(path.basename(name)[:-3] for name in _module_filenames if not name.endswith("__init__.py"))
8+
)
9+
10+
11+
def __getattr__(name):
12+
# On-demand import of facts modules, so we don't have to import them all at once
13+
# this forces py3.7>=, but that's fine as py2 is EOL and py3.6 is also EOL
14+
# Also, Pyinfra is py3.11>=, so this is not a breaking change.
15+
if name in __all__:
16+
return importlib.import_module(f".{name}", __package__)
17+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
18+
1119

12-
from . import * # noqa
20+
def __dir__():
21+
return __all__

src/pyinfra/operations/__init__.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
1-
# This file only exists to support:
2-
# from pyinfra import operations
3-
# operations.X.Y
4-
1+
import importlib
52
from glob import glob
63
from os import path
74

8-
module_filenames = glob(path.join(path.dirname(__file__), "*.py"))
9-
module_names = [path.basename(name)[:-3] for name in module_filenames]
10-
__all__ = [name for name in module_names if name != "__init__"]
5+
_module_filenames = glob(path.join(path.dirname(__file__), "*.py"))
6+
__all__ = sorted(
7+
set(path.basename(name)[:-3] for name in _module_filenames if not name.endswith("__init__.py"))
8+
)
9+
10+
11+
def __getattr__(name):
12+
# On-demand import of operations modules, so we don't have to import them all at once
13+
# this forces py3.7>=, but that's fine as py2 is EOL and py3.6 is also EOL
14+
# Also, Pyinfra is py3.11>=, so this is not a breaking change.
15+
if name in __all__:
16+
return importlib.import_module(f".{name}", __package__)
17+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
18+
1119

12-
from . import * # noqa
20+
def __dir__():
21+
return __all__
Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1-
# This file only exists to support:
2-
# from pyinfra.operations import freebsd
3-
# freebsd.X.Y
4-
1+
import importlib
52
from glob import glob
63
from os import path
74

8-
module_filenames = glob(path.join(path.dirname(__file__), "*.py"))
9-
module_names = [path.basename(name)[:-3] for name in module_filenames]
10-
__all__ = [name for name in module_names if name != "__init__"]
5+
_module_filenames = glob(path.join(path.dirname(__file__), "*.py"))
6+
__all__ = sorted(
7+
set(path.basename(name)[:-3] for name in _module_filenames if not name.endswith("__init__.py"))
8+
)
9+
1110

12-
from . import * # noqa
11+
def __getattr__(name):
12+
# On-demand import of operations modules, so we don't have to import them all at once
13+
# this forces py3.7>=, but that's fine as py2 is EOL and py3.6 is also EOL
14+
# Also, Pyinfra is py3.11>=, so this is not a breaking change.
15+
if name in __all__:
16+
return importlib.import_module(f".{name}", __package__)
17+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

tests/test_operations.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def assert_commands(commands, wanted_commands):
8888
def make_operation_tests(arg):
8989
# Get the operation we're testing against
9090
module_name, op_name = arg.rsplit(".", 1)
91+
9192
module = import_module("pyinfra.operations.{0}".format(module_name))
9293
op = getattr(module, op_name)
9394

0 commit comments

Comments
 (0)