Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[sonic-py-common] Add 'general' module with load_module_from_source() function #7167

Merged
merged 3 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/sonic-ctrmgrd/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
tests_require=[
'pytest',
'pytest-cov',
'sonic-py-common',
],
install_requires=['netaddr', 'pyyaml'],
license="GNU General Public License v3",
Expand Down
12 changes: 0 additions & 12 deletions src/sonic-ctrmgrd/tests/common_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import copy
import importlib.machinery
import importlib.util
import json
import os
import subprocess
Expand Down Expand Up @@ -655,13 +653,3 @@ def create_remote_ctr_config_json():
s.write(str_conf)

return fname


def load_mod_from_file(modname, fpath):
spec = importlib.util.spec_from_loader(modname,
importlib.machinery.SourceFileLoader(modname, fpath))
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
sys.modules[modname] = mod
return mod

6 changes: 4 additions & 2 deletions src/sonic-ctrmgrd/tests/container_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
from unittest.mock import MagicMock, patch

import pytest
from sonic_py_common.general import load_module_from_source

from . import common_test

common_test.load_mod_from_file("docker",

load_module_from_source("docker",
os.path.join(os.path.dirname(os.path.realpath(__file__)), "mock_docker.py"))
container = common_test.load_mod_from_file("container",
container = load_module_from_source("container",
os.path.join(os.path.dirname(os.path.realpath(__file__)), "../ctrmgr/container"))


Expand Down
3 changes: 2 additions & 1 deletion src/sonic-ctrmgrd/tests/ctrmgr_tools_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
from unittest.mock import MagicMock, patch

import pytest
from sonic_py_common.general import load_module_from_source

from . import common_test

common_test.load_mod_from_file("docker",
load_module_from_source("docker",
os.path.join(os.path.dirname(os.path.realpath(__file__)), "mock_docker.py"))

sys.path.append("ctrmgr")
Expand Down
1 change: 1 addition & 0 deletions src/sonic-host-services/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
],
tests_require = [
'pytest',
'sonic-py-common'
],
classifiers = [
'Development Status :: 3 - Alpha',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import importlib.machinery
import importlib.util
import sys
import os
import pytest

import swsssdk
from sonic_py_common.general import load_module_from_source

# TODO: Remove this if/else block once we no longer support Python 2
if sys.version_info.major == 3:
Expand All @@ -31,11 +30,7 @@

# Load the file under test
determine_reboot_cause_path = os.path.join(scripts_path, 'determine-reboot-cause')
loader = importlib.machinery.SourceFileLoader('determine_reboot_cause', determine_reboot_cause_path)
spec = importlib.util.spec_from_loader(loader.name, loader)
determine_reboot_cause = importlib.util.module_from_spec(spec)
loader.exec_module(determine_reboot_cause)
sys.modules['determine_reboot_cause'] = determine_reboot_cause
determine_reboot_cause = load_module_from_source('determine_reboot_cause', determine_reboot_cause_path)


PROC_CMDLINE_CONTENTS = """\
Expand Down
14 changes: 5 additions & 9 deletions src/sonic-host-services/tests/hostcfgd/hostcfgd_test.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import importlib.machinery
import importlib.util
import os
import sys
import swsssdk

from parameterized import parameterized
from sonic_py_common.general import load_module_from_source
from unittest import TestCase, mock
from tests.hostcfgd.test_vectors import HOSTCFGD_TEST_VECTOR
from tests.hostcfgd.mock_configdb import MockConfigDb

from .test_vectors import HOSTCFGD_TEST_VECTOR
from .mock_configdb import MockConfigDb


swsssdk.ConfigDBConnector = MockConfigDb
Expand All @@ -18,11 +18,7 @@

# Load the file under test
hostcfgd_path = os.path.join(scripts_path, 'hostcfgd')
loader = importlib.machinery.SourceFileLoader('hostcfgd', hostcfgd_path)
spec = importlib.util.spec_from_loader(loader.name, loader)
hostcfgd = importlib.util.module_from_spec(spec)
loader.exec_module(hostcfgd)
sys.modules['hostcfgd'] = hostcfgd
hostcfgd = load_module_from_source('hostcfgd', hostcfgd_path)


class TestHostcfgd(TestCase):
Expand Down
9 changes: 2 additions & 7 deletions src/sonic-host-services/tests/procdockerstatsd_test.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import importlib.machinery
import importlib.util
import sys
import os
import pytest

import swsssdk
from sonic_py_common.general import load_module_from_source

from .mock_connector import MockConnector

Expand All @@ -17,11 +16,7 @@

# Load the file under test
procdockerstatsd_path = os.path.join(scripts_path, 'procdockerstatsd')
loader = importlib.machinery.SourceFileLoader('procdockerstatsd', procdockerstatsd_path)
spec = importlib.util.spec_from_loader(loader.name, loader)
procdockerstatsd = importlib.util.module_from_spec(spec)
loader.exec_module(procdockerstatsd)
sys.modules['procdockerstatsd'] = procdockerstatsd
procdockerstatsd = load_module_from_source('procdockerstatsd', procdockerstatsd_path)

class TestProcDockerStatsDaemon(object):
def test_convert_to_bytes(self):
Expand Down
26 changes: 2 additions & 24 deletions src/sonic-py-common/sonic_py_common/daemon_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys

from . import device_info
from .general import load_module_from_source
from .logger import Logger

#
Expand All @@ -25,29 +26,6 @@ def db_connect(db_name, namespace=EMPTY_NAMESPACE):
return swsscommon.DBConnector(db_name, REDIS_TIMEOUT_MSECS, True, namespace)


# TODO: Consider moving this logic out of daemon_base and into antoher file
# so that it can be used by non-daemons. We can simply call that function here
# to retain backward compatibility.
def _load_module_from_file(module_name, file_path):
module = None

# TODO: Remove this check once we no longer support Python 2
if sys.version_info.major == 3:
import importlib.machinery
import importlib.util
loader = importlib.machinery.SourceFileLoader(module_name, file_path)
spec = importlib.util.spec_from_loader(loader.name, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
else:
import imp
module = imp.load_source(module_name, file_path)

sys.modules[module_name] = module

return module


#
# DaemonBase ===================================================================
#
Expand Down Expand Up @@ -92,7 +70,7 @@ def load_platform_util(self, module_name, class_name):

try:
module_file = "/".join([platform_path, "plugins", module_name + ".py"])
module = _load_module_from_file(module_name, module_file)
module = load_module_from_source(module_name, module_file)
except IOError as e:
raise IOError("Failed to load platform module '%s': %s" % (module_name, str(e)))

Expand Down
25 changes: 25 additions & 0 deletions src/sonic-py-common/sonic_py_common/general.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import sys


def load_module_from_source(module_name, file_path):
"""
This function will load the Python source file specified by <file_path>
as a module named <module_name> and return an instance of the module
"""
module = None

# TODO: Remove this check once we no longer support Python 2
if sys.version_info.major == 3:
import importlib.machinery
import importlib.util
loader = importlib.machinery.SourceFileLoader(module_name, file_path)
spec = importlib.util.spec_from_loader(loader.name, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
else:
import imp
module = imp.load_source(module_name, file_path)

sys.modules[module_name] = module

return module