1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2024-10-05 18:31:12 +01:00

wa: Remove dependency on "imp" module

Python 3.12 removed the "imp" module, so use importlib instead.
This commit is contained in:
Douglas Raillard 2023-10-05 12:10:41 +01:00 committed by Marc Bonnici
parent 41f7984243
commit 77ebefba08
3 changed files with 47 additions and 28 deletions

View File

@ -79,6 +79,7 @@ params = dict(
license='Apache v2', license='Apache v2',
maintainer='ARM Architecture & Technology Device Lab', maintainer='ARM Architecture & Technology Device Lab',
maintainer_email='workload-automation@arm.com', maintainer_email='workload-automation@arm.com',
python_requires='>= 3.7',
setup_requires=[ setup_requires=[
'numpy<=1.16.4; python_version<"3"', 'numpy<=1.16.4; python_version<"3"',
'numpy; python_version>="3"', 'numpy; python_version>="3"',

View File

@ -18,8 +18,6 @@
import os import os
import sys import sys
import inspect import inspect
import imp
import string
import logging import logging
from collections import OrderedDict, defaultdict from collections import OrderedDict, defaultdict
from itertools import chain from itertools import chain
@ -32,16 +30,10 @@ from wa.framework.exception import (NotFoundError, PluginLoaderError, TargetErro
ValidationError, ConfigError, HostError) ValidationError, ConfigError, HostError)
from wa.utils import log from wa.utils import log
from wa.utils.misc import (ensure_directory_exists as _d, walk_modules, load_class, from wa.utils.misc import (ensure_directory_exists as _d, walk_modules, load_class,
merge_dicts_simple, get_article) merge_dicts_simple, get_article, import_path)
from wa.utils.types import identifier from wa.utils.types import identifier
if sys.version_info[0] == 3:
MODNAME_TRANS = str.maketrans(':/\\.', '____')
else:
MODNAME_TRANS = string.maketrans(':/\\.', '____')
class AttributeCollection(object): class AttributeCollection(object):
""" """
Accumulator for plugin attribute objects (such as Parameters or Artifacts). Accumulator for plugin attribute objects (such as Parameters or Artifacts).
@ -645,8 +637,7 @@ class PluginLoader(object):
def _discover_from_file(self, filepath): def _discover_from_file(self, filepath):
try: try:
modname = os.path.splitext(filepath[1:])[0].translate(MODNAME_TRANS) module = import_path(filepath)
module = imp.load_source(modname, filepath)
self._discover_in_module(module) self._discover_in_module(module)
except (SystemExit, ImportError) as e: except (SystemExit, ImportError) as e:
if self.keep_going: if self.keep_going:

View File

@ -21,10 +21,12 @@ Miscellaneous functions that don't fit anywhere else.
import errno import errno
import hashlib import hashlib
import imp import importlib
import inspect
import logging import logging
import math import math
import os import os
import pathlib
import random import random
import re import re
import shutil import shutil
@ -308,32 +310,57 @@ class LoadSyntaxError(Exception):
RAND_MOD_NAME_LEN = 30 RAND_MOD_NAME_LEN = 30
def load_struct_from_python(filepath=None, text=None): def import_path(filepath, module_name=None):
"""
Programmatically import the given Python source file under the name
``module_name``. If ``module_name`` is not provided, a stable name based on
``filepath`` will be created. Note that this module name cannot be relied
on, so don't make write import statements assuming this will be stable in
the future.
"""
if not module_name:
path = pathlib.Path(filepath).resolve()
id_ = to_identifier(str(path))
module_name = f'wa._user_import.{id_}'
try:
return sys.modules[module_name]
except KeyError:
spec = importlib.util.spec_from_file_location(module_name, filepath)
module = importlib.util.module_from_spec(spec)
try:
sys.modules[module_name] = module
spec.loader.exec_module(module)
except BaseException:
sys.modules.pop(module_name, None)
raise
else:
# We could return the "module" object, but that would not take into
# account any manipulation the module did on sys.modules when
# executing. To be consistent with the import statement, re-lookup
# the module name.
return sys.modules[module_name]
def load_struct_from_python(filepath):
"""Parses a config structure from a .py file. The structure should be composed """Parses a config structure from a .py file. The structure should be composed
of basic Python types (strings, ints, lists, dicts, etc.).""" of basic Python types (strings, ints, lists, dicts, etc.)."""
if not (filepath or text) or (filepath and text):
raise ValueError('Exactly one of filepath or text must be specified.')
try: try:
if filepath: mod = import_path(filepath)
modname = to_identifier(filepath)
mod = imp.load_source(modname, filepath)
else:
modname = get_random_string(RAND_MOD_NAME_LEN)
while modname in sys.modules: # highly unlikely, but...
modname = get_random_string(RAND_MOD_NAME_LEN)
mod = imp.new_module(modname)
exec(text, mod.__dict__) # pylint: disable=exec-used
return dict((k, v)
for k, v in mod.__dict__.items()
if not k.startswith('_'))
except SyntaxError as e: except SyntaxError as e:
raise LoadSyntaxError(e.message, filepath, e.lineno) raise LoadSyntaxError(e.message, filepath, e.lineno)
else:
return {
k: v
for k, v in inspect.getmembers(mod)
if not k.startswith('_')
}
def load_struct_from_yaml(filepath=None, text=None): def load_struct_from_yaml(filepath=None, text=None):
"""Parses a config structure from a .yaml file. The structure should be composed """Parses a config structure from a .yaml file. The structure should be composed
of basic Python types (strings, ints, lists, dicts, etc.).""" of basic Python types (strings, ints, lists, dicts, etc.)."""
# Import here to avoid circular imports # Import here to avoid circular imports
# pylint: disable=wrong-import-position,cyclic-import, import-outside-toplevel # pylint: disable=wrong-import-position,cyclic-import, import-outside-toplevel
from wa.utils.serializer import yaml from wa.utils.serializer import yaml