From 011ce17d9cce2f2c28e380bb87bf581de4744d24 Mon Sep 17 00:00:00 2001 From: David Galiffi Date: Fri, 9 Aug 2024 15:02:51 -0400 Subject: [PATCH] Check Python version on application launch (#393) * Check that the minimum required Python (3.8) version is used. Prints a descriptive error message, rather than a cryptic import failure, if minimum Python version is not met. Internal ticket SWDEV-477233. * Disable the RPM mangling of shebangs. The are changing the `#!/usr/bin/python3` to `#!/usr/libexec/platform-python`. With this set, omniperf is always using the platform installed version of python, which is python 3.6 on RHEL 8. Using virtual environments, like conda, did not work. * Fix pylint issues --------- Signed-off-by: David Galiffi --- CMakeLists.txt | 1 + docs/install/core-install.rst | 24 +++++++++++++++---- src/omniperf | 45 +++++++++++++++++++++++------------ 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb4686459..3d0d1228b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -416,6 +416,7 @@ set(CPACK_RPM_PACKAGE_PROVIDES "${CPACK_PACKAGE_NAME}") set(CPACK_RPM_COMPONENT_INSTALL ON) set(CPACK_RPM_PACKAGE_RELEASE_DIST ON) set(CPACK_RPM_FILE_NAME "RPM-DEFAULT") +set(CPACK_RPM_SPEC_MORE_DEFINE "%undefine __brp_mangle_shebangs") if(DEFINED CPACK_PACKAGING_INSTALL_PREFIX) set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${CPACK_PACKAGING_INSTALL_PREFIX}") diff --git a/docs/install/core-install.rst b/docs/install/core-install.rst index 1d28b07b5..7629644dc 100644 --- a/docs/install/core-install.rst +++ b/docs/install/core-install.rst @@ -32,7 +32,7 @@ right for you. :width: 800 .. _core-install: - + Core installation ================= @@ -44,6 +44,12 @@ installation. * CMake ``>= 3.19`` * ROCm ``>= 5.7.1`` +.. note:: + + Omniperf will use the first version of ``Python3`` found in your system's + ``PATH``. If the default version of Python3 is older than 3.8, you may need to + update your system's ``PATH`` to point to a newer version of Python3. + Omniperf depends on a number of Python packages documented in the top-level ``requirements.txt`` file. Install these *before* configuring Omniperf. @@ -66,6 +72,16 @@ following steps illustrate how to install the necessary Python dependencies using `pip `_ and Omniperf into a shared location controlled by the ``INSTALL_DIR`` environment variable. +.. tip:: + + To always run Omniperf with a particular version of python, you can create a + bash alias. For example, to run Omniperf with Python 3.10, you can run the + following command: + + .. code-block:: shell + + alias omniperf-mypython="/usr/bin/python3.10 /opt/rocm/bin/omniperf" + .. _core-install-cmake-vars: Configuration variables @@ -208,21 +224,21 @@ software stack. .. code-block:: shell $ sudo apt install omniperf - $ pip install -r /opt/rocm/libexec/omniperf/requirements.txt + $ python3 -m pip install -r /opt/rocm/libexec/omniperf/requirements.txt .. tab-item:: Red Hat Enterprise Linux .. code-block:: shell $ sudo dnf install omniperf - $ pip install -r /opt/rocm/libexec/omniperf/requirements.txt + $ python3 -m pip install -r /opt/rocm/libexec/omniperf/requirements.txt .. tab-item:: SUSE Linux Enterprise Server .. code-block:: shell $ sudo zypper install omniperf - $ pip install -r /opt/rocm/libexec/omniperf/requirements.txt + $ python3 -m pip install -r /opt/rocm/libexec/omniperf/requirements.txt .. _core-install-rocprof-var: diff --git a/src/omniperf b/src/omniperf index 6977b54cb..1acff5f07 100755 --- a/src/omniperf +++ b/src/omniperf @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +"""Main entry point for omniperf""" + ##############################################################################bl # MIT License # @@ -24,23 +26,24 @@ # SOFTWARE. ##############################################################################el -import logging +# import logging import os import sys -from pip._internal.req import parse_requirements -from pathlib import Path -from importlib import import_module, metadata import re try: + from pathlib import Path + from importlib import metadata from omniperf_base import Omniperf from utils.utils import console_error -except: +except ImportError as e: + # print("Failed to import required modules: " + str(e)) pass def verify_deps_version(localVer, desiredVer, operator): - """Check package version strings with simple operators used in companion requirements.txt file""" + """Check package version strings with simple operators used in companion + requirements.txt file""" if operator == "==": return localVer == desiredVer elif operator == ">=": @@ -56,15 +59,24 @@ def verify_deps_version(localVer, desiredVer, operator): def verify_deps(): - """Utility to read library dependencies from requirements.txt and endeavor to load them within current execution environment. - Used in top-level omniperf to provide error messages if necessary dependencies are not available. """ + """Utility to read library dependencies from requirements.txt and endeavor + to load them within current execution environment. + Used in top-level omniperf to provide error messages if necessary + dependencies are not available.""" + + # Check which version of python is being used + if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 8): + print("[ERROR] Python 3.8 or higher is required to run omniperf." + f" The current version is {sys.version_info[0]}.{sys.version_info[1]}.") + sys.exit(1) + bindir = Path(__file__).resolve().parent depsLocation = ["requirements.txt", "../requirements.txt"] for location in depsLocation: checkFile = os.path.join(bindir, location) if os.path.exists(checkFile): - with open(checkFile, "r") as file_in: + with open(checkFile, "r", encoding="utf-8") as file_in: dependencies = file_in.read().splitlines() error = False @@ -84,8 +96,8 @@ def verify_deps(): except metadata.PackageNotFoundError: error = True print( - "[ERROR] The '%s' package was not found in the current execution environment." - % dependency + f"[ERROR] The '{dependency}' package was not found " + "in the current execution environment." ) # check version requirement @@ -95,8 +107,8 @@ def verify_deps(): localVersion, desiredVersion, operator ): print( - "[ERROR] the '%s' distribution does not meet version requirements to use omniperf." - % dependency + f"[ERROR] the '{dependency}' distribution does " + "not meet version requirements to use omniperf." ) print(" --> version installed :", localVersion) error = True @@ -104,15 +116,18 @@ def verify_deps(): if error: print("") print( - "Please verify all of the python dependencies called out in the requirements file" + "Please verify all of the python dependencies called out " + "in the requirements file" ) print("are installed locally prior to running omniperf.") print("") - print("See: %s" % checkFile) + print(f"See: {checkFile}") sys.exit(1) return + def main(): + '''Main function for omniperf''' # verify required python dependencies verify_deps()