Skip to content

Commit

Permalink
Fixed Salt's deferred imports to allow onedir builds while not breaki…
Browse files Browse the repository at this point in the history
…ng non-onedir builds

Fixes saltstack#146
Closes saltstack#144

Signed-off-by: Pedro Algarvio <palgarvio@vmware.com>
  • Loading branch information
s0undt3ch committed Dec 11, 2022
1 parent 8b044cc commit f41e293
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 15 deletions.
1 change: 1 addition & 0 deletions .pylint-spelling-words
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ nocover
nodeid
noqa
nox
onedir
openbsd
ordereddict
os
Expand Down
1 change: 1 addition & 0 deletions changelog/146.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed Salt's deferred imports to allow onedir builds while not breaking non-onedir builds
5 changes: 4 additions & 1 deletion src/saltfactories/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import pytest
import pytestskipmarkers.utils.platform
import salt.version

import saltfactories.utils.tempfiles

Expand Down Expand Up @@ -81,6 +80,10 @@ def pytest_load_initial_conftests(*_):
"""
Register our pytest helpers.
"""
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
import salt.version # pylint: disable=import-outside-toplevel

if salt.version.__saltstack_version__ < "3004":
raise pytest.UsageError("Only salt>=3004 is supported")
if "temp_directory" not in pytest.helpers:
Expand Down
5 changes: 4 additions & 1 deletion src/saltfactories/plugins/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import pytest

import saltfactories
from saltfactories.manager import FactoriesManager

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -59,6 +58,10 @@ def salt_factories(
"""
Instantiate the salt factories manager.
"""
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
from saltfactories.manager import FactoriesManager # pylint: disable=import-outside-toplevel

if not isinstance(salt_factories_config, dict):
raise pytest.UsageError("The 'salt_factories_config' fixture MUST return a dictionary")
if salt_factories_config:
Expand Down
14 changes: 10 additions & 4 deletions src/saltfactories/plugins/sysinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,6 @@
import tempfile

import pytest
import salt.config
import salt.loader
import salt.utils.yaml
import salt.version


def pytest_addoption(parser):
Expand All @@ -119,6 +115,16 @@ def pytest_sessionstart(session):
:param _pytest.main.Session session: the pytest session object
"""
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
# pylint: disable=import-outside-toplevel
import salt.config
import salt.loader
import salt.utils.yaml
import salt.version

# pylint: enable=import-outside-toplevel

# Let PyTest do its own thing
yield
if session.config.getoption("--sys-info") is True:
Expand Down
5 changes: 4 additions & 1 deletion src/saltfactories/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from typing import Type

import packaging.version
import salt.utils.user

import saltfactories

Expand Down Expand Up @@ -50,6 +49,10 @@ def running_username():
"""
Return the username that is running the code.
"""
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
import salt.utils.user # pylint: disable=import-outside-toplevel

return salt.utils.user.get_user()


Expand Down
41 changes: 36 additions & 5 deletions src/saltfactories/utils/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@
from unittest import mock

import attr
import salt.features
import salt.loader
import salt.pillar
from pytestshellutils.utils import format_callback_to_string
from pytestshellutils.utils.processes import MatchString
from salt.loader.lazy import LOADED_BASE_NAME

PATCH_TARGET = "salt.loader.lazy.LOADED_BASE_NAME"

Expand Down Expand Up @@ -56,8 +52,14 @@ def reset_loaders_state(loaders):
loaders.reset_state()
"""

def __init__(self, opts, loaded_base_name=LOADED_BASE_NAME):
def __init__(self, opts, loaded_base_name=None):
self.opts = opts
if loaded_base_name is None:
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
from salt.loader.lazy import LOADED_BASE_NAME # pylint: disable=import-outside-toplevel

loaded_base_name = LOADED_BASE_NAME
self.loaded_base_name = loaded_base_name
self.context = {}
self._cachedir = pathlib.Path(opts["cachedir"])
Expand All @@ -70,6 +72,11 @@ def __init__(self, opts, loaded_base_name=LOADED_BASE_NAME):
self._serializers = None
self._states = None
self._utils = None

# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
import salt.features # pylint: disable=import-outside-toplevel

salt.features.setup_features(self.opts)
self.reload_all()
# Force the minion to populate it's cache if need be
Expand Down Expand Up @@ -124,6 +131,10 @@ def grains(self):
"""
The grains loaded by the salt loader.
"""
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
import salt.loader # pylint: disable=import-outside-toplevel

if self._grains is None:
try:
self._grains = salt.loader.grains( # pylint: disable=unexpected-keyword-arg
Expand All @@ -142,6 +153,10 @@ def utils(self):
"""
The utils loaded by the salt loader.
"""
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
import salt.loader # pylint: disable=import-outside-toplevel

if self._utils is None:
try:
self._utils = salt.loader.utils( # pylint: disable=unexpected-keyword-arg
Expand All @@ -160,6 +175,10 @@ def modules(self):
"""
The execution modules loaded by the salt loader.
"""
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
import salt.loader # pylint: disable=import-outside-toplevel

if self._modules is None:
_modules = salt.loader.minion_mods(
self.opts,
Expand Down Expand Up @@ -214,6 +233,10 @@ def serializers(self):
"""
The serializers loaded by the salt loader.
"""
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
import salt.loader # pylint: disable=import-outside-toplevel

if self._serializers is None:
try:
self._serializers = (
Expand All @@ -233,6 +256,10 @@ def states(self):
"""
The state modules loaded by the salt loader.
"""
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
import salt.loader # pylint: disable=import-outside-toplevel

if self._states is None:
try:
_states = salt.loader.states( # pylint: disable=unexpected-keyword-arg
Expand Down Expand Up @@ -296,6 +323,10 @@ def pillar(self):
"""
The pillar loaded by the salt loader.
"""
# Do not move this deferred import. It allows running against a Salt onedir build
# in salt's repo checkout.
import salt.pillar # pylint: disable=import-outside-toplevel

if self._pillar is None:
try:
self._pillar = salt.pillar.get_pillar( # pylint: disable=unexpected-keyword-arg
Expand Down
17 changes: 14 additions & 3 deletions src/saltfactories/utils/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
import pytest
from pytestshellutils.utils import format_callback_to_string

try:
LOGGING_TRACE_LEVEL = logging.TRACE
except AttributeError:
# Salt's logging hasn't been setup yet
LOGGING_TRACE_LEVEL = 5

log = logging.getLogger(__name__)


Expand Down Expand Up @@ -76,7 +82,12 @@ def start(self):
"""
module_globals = {dunder: {} for dunder in self.salt_module_dunders}
for module, globals_to_mock in self.setup_loader_modules.items():
log.trace("Setting up loader globals for %s; globals: %s", module, globals_to_mock)
log.log(
LOGGING_TRACE_LEVEL,
"Setting up loader globals for %s; globals: %s",
module,
globals_to_mock,
)
if not isinstance(module, types.ModuleType):
raise pytest.UsageError(
"The dictionary keys returned by setup_loader_modules() "
Expand Down Expand Up @@ -113,7 +124,7 @@ def stop(self):
func, args, kwargs = self._finalizers.popleft()
func_repr = format_callback_to_string(func, args, kwargs)
try:
log.trace("Calling finalizer %s", func_repr)
log.log(LOGGING_TRACE_LEVEL, "Calling finalizer %s", func_repr)
func(*args, **kwargs)
except Exception as exc: # pragma: no cover pylint: disable=broad-except
log.error(
Expand Down Expand Up @@ -178,7 +189,7 @@ def _patch_module_globals(self, module, mocks, module_globals):
module_globals[key] = mocks[key]

# Patch the module!
log.trace("Patching globals for %s; globals: %s", module, module_globals)
log.log(LOGGING_TRACE_LEVEL, "Patching globals for %s; globals: %s", module, module_globals)
patcher = patch.multiple(module, **module_globals)
patcher.start()
self.addfinalizer(patcher.stop)
Expand Down

0 comments on commit f41e293

Please sign in to comment.