Skip to content

Commit ee13837

Browse files
authored
[sonic-py-common] Add 'general' module with load_module_from_source() function (#7167)
#### Why I did it To eliminate the need to write duplicate code in order to import a Python module from a source file. #### How I did it Add `general` module to sonic-py-common, which contains a `load_module_from_source()` function which supports both Python 2 and 3. Call this new function in: - sonic-ctrmgrd/tests/container_test.py - sonic-ctrmgrd/tests/ctrmgr_tools_test.py - sonic-host-services/tests/determine-reboot-cause_test.py - sonic-host-services/tests/hostcfgd/hostcfgd_test.py - sonic-host-services/tests/procdockerstatsd_test.py - sonic-py-common/sonic_py_common/daemon_base.py
1 parent 42d22f4 commit ee13837

File tree

10 files changed

+44
-62
lines changed

10 files changed

+44
-62
lines changed

src/sonic-ctrmgrd/setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
tests_require=[
2525
'pytest',
2626
'pytest-cov',
27+
'sonic-py-common',
2728
],
2829
install_requires=['netaddr', 'pyyaml'],
2930
license="GNU General Public License v3",

src/sonic-ctrmgrd/tests/common_test.py

-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import copy
2-
import importlib.machinery
3-
import importlib.util
42
import json
53
import os
64
import subprocess
@@ -655,13 +653,3 @@ def create_remote_ctr_config_json():
655653
s.write(str_conf)
656654

657655
return fname
658-
659-
660-
def load_mod_from_file(modname, fpath):
661-
spec = importlib.util.spec_from_loader(modname,
662-
importlib.machinery.SourceFileLoader(modname, fpath))
663-
mod = importlib.util.module_from_spec(spec)
664-
spec.loader.exec_module(mod)
665-
sys.modules[modname] = mod
666-
return mod
667-

src/sonic-ctrmgrd/tests/container_test.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
from unittest.mock import MagicMock, patch
33

44
import pytest
5+
from sonic_py_common.general import load_module_from_source
56

67
from . import common_test
78

8-
common_test.load_mod_from_file("docker",
9+
10+
load_module_from_source("docker",
911
os.path.join(os.path.dirname(os.path.realpath(__file__)), "mock_docker.py"))
10-
container = common_test.load_mod_from_file("container",
12+
container = load_module_from_source("container",
1113
os.path.join(os.path.dirname(os.path.realpath(__file__)), "../ctrmgr/container"))
1214

1315

src/sonic-ctrmgrd/tests/ctrmgr_tools_test.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
from unittest.mock import MagicMock, patch
44

55
import pytest
6+
from sonic_py_common.general import load_module_from_source
67

78
from . import common_test
89

9-
common_test.load_mod_from_file("docker",
10+
load_module_from_source("docker",
1011
os.path.join(os.path.dirname(os.path.realpath(__file__)), "mock_docker.py"))
1112

1213
sys.path.append("ctrmgr")

src/sonic-host-services/setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
],
3636
tests_require = [
3737
'pytest',
38+
'sonic-py-common'
3839
],
3940
classifiers = [
4041
'Development Status :: 3 - Alpha',

src/sonic-host-services/tests/determine-reboot-cause_test.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import importlib.machinery
2-
import importlib.util
31
import sys
42
import os
53
import pytest
64

75
import swsssdk
6+
from sonic_py_common.general import load_module_from_source
87

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

3231
# Load the file under test
3332
determine_reboot_cause_path = os.path.join(scripts_path, 'determine-reboot-cause')
34-
loader = importlib.machinery.SourceFileLoader('determine_reboot_cause', determine_reboot_cause_path)
35-
spec = importlib.util.spec_from_loader(loader.name, loader)
36-
determine_reboot_cause = importlib.util.module_from_spec(spec)
37-
loader.exec_module(determine_reboot_cause)
38-
sys.modules['determine_reboot_cause'] = determine_reboot_cause
33+
determine_reboot_cause = load_module_from_source('determine_reboot_cause', determine_reboot_cause_path)
3934

4035

4136
PROC_CMDLINE_CONTENTS = """\

src/sonic-host-services/tests/hostcfgd/hostcfgd_test.py

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import importlib.machinery
2-
import importlib.util
31
import os
42
import sys
53
import swsssdk
64

75
from parameterized import parameterized
6+
from sonic_py_common.general import load_module_from_source
87
from unittest import TestCase, mock
9-
from tests.hostcfgd.test_vectors import HOSTCFGD_TEST_VECTOR
10-
from tests.hostcfgd.mock_configdb import MockConfigDb
8+
9+
from .test_vectors import HOSTCFGD_TEST_VECTOR
10+
from .mock_configdb import MockConfigDb
1111

1212

1313
swsssdk.ConfigDBConnector = MockConfigDb
@@ -18,11 +18,7 @@
1818

1919
# Load the file under test
2020
hostcfgd_path = os.path.join(scripts_path, 'hostcfgd')
21-
loader = importlib.machinery.SourceFileLoader('hostcfgd', hostcfgd_path)
22-
spec = importlib.util.spec_from_loader(loader.name, loader)
23-
hostcfgd = importlib.util.module_from_spec(spec)
24-
loader.exec_module(hostcfgd)
25-
sys.modules['hostcfgd'] = hostcfgd
21+
hostcfgd = load_module_from_source('hostcfgd', hostcfgd_path)
2622

2723

2824
class TestHostcfgd(TestCase):

src/sonic-host-services/tests/procdockerstatsd_test.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import importlib.machinery
2-
import importlib.util
31
import sys
42
import os
53
import pytest
64

75
import swsssdk
6+
from sonic_py_common.general import load_module_from_source
87

98
from .mock_connector import MockConnector
109

@@ -17,11 +16,7 @@
1716

1817
# Load the file under test
1918
procdockerstatsd_path = os.path.join(scripts_path, 'procdockerstatsd')
20-
loader = importlib.machinery.SourceFileLoader('procdockerstatsd', procdockerstatsd_path)
21-
spec = importlib.util.spec_from_loader(loader.name, loader)
22-
procdockerstatsd = importlib.util.module_from_spec(spec)
23-
loader.exec_module(procdockerstatsd)
24-
sys.modules['procdockerstatsd'] = procdockerstatsd
19+
procdockerstatsd = load_module_from_source('procdockerstatsd', procdockerstatsd_path)
2520

2621
class TestProcDockerStatsDaemon(object):
2722
def test_convert_to_bytes(self):

src/sonic-py-common/sonic_py_common/daemon_base.py

+2-24
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import sys
33

44
from . import device_info
5+
from .general import load_module_from_source
56
from .logger import Logger
67

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

2728

28-
# TODO: Consider moving this logic out of daemon_base and into antoher file
29-
# so that it can be used by non-daemons. We can simply call that function here
30-
# to retain backward compatibility.
31-
def _load_module_from_file(module_name, file_path):
32-
module = None
33-
34-
# TODO: Remove this check once we no longer support Python 2
35-
if sys.version_info.major == 3:
36-
import importlib.machinery
37-
import importlib.util
38-
loader = importlib.machinery.SourceFileLoader(module_name, file_path)
39-
spec = importlib.util.spec_from_loader(loader.name, loader)
40-
module = importlib.util.module_from_spec(spec)
41-
loader.exec_module(module)
42-
else:
43-
import imp
44-
module = imp.load_source(module_name, file_path)
45-
46-
sys.modules[module_name] = module
47-
48-
return module
49-
50-
5129
#
5230
# DaemonBase ===================================================================
5331
#
@@ -92,7 +70,7 @@ def load_platform_util(self, module_name, class_name):
9270

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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import sys
2+
3+
4+
def load_module_from_source(module_name, file_path):
5+
"""
6+
This function will load the Python source file specified by <file_path>
7+
as a module named <module_name> and return an instance of the module
8+
"""
9+
module = None
10+
11+
# TODO: Remove this check once we no longer support Python 2
12+
if sys.version_info.major == 3:
13+
import importlib.machinery
14+
import importlib.util
15+
loader = importlib.machinery.SourceFileLoader(module_name, file_path)
16+
spec = importlib.util.spec_from_loader(loader.name, loader)
17+
module = importlib.util.module_from_spec(spec)
18+
loader.exec_module(module)
19+
else:
20+
import imp
21+
module = imp.load_source(module_name, file_path)
22+
23+
sys.modules[module_name] = module
24+
25+
return module

0 commit comments

Comments
 (0)