/ tools / check_python_dependencies.py
check_python_dependencies.py
  1  #!/usr/bin/env python
  2  #
  3  # Copyright 2018 Espressif Systems (Shanghai) PTE LTD
  4  #
  5  # Licensed under the Apache License, Version 2.0 (the "License");
  6  # you may not use this file except in compliance with the License.
  7  # You may obtain a copy of the License at
  8  #
  9  #     http://www.apache.org/licenses/LICENSE-2.0
 10  #
 11  # Unless required by applicable law or agreed to in writing, software
 12  # distributed under the License is distributed on an "AS IS" BASIS,
 13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  # See the License for the specific language governing permissions and
 15  # limitations under the License.
 16  
 17  import argparse
 18  import os
 19  import re
 20  import sys
 21  
 22  try:
 23      import pkg_resources
 24  except Exception:
 25      print('pkg_resources cannot be imported probably because the pip package is not installed and/or using a '
 26            'legacy Python interpreter. Please refer to the Get Started section of the ESP-IDF Programming Guide for '
 27            'setting up the required packages.')
 28      sys.exit(1)
 29  
 30  
 31  def escape_backslash(path):
 32      if sys.platform == "win32":
 33          # escaped backslashes are necessary in order to be able to copy-paste the printed path
 34          return path.replace("\\", "\\\\")
 35      else:
 36          return path
 37  
 38  
 39  if __name__ == "__main__":
 40      idf_path = os.getenv("IDF_PATH")
 41  
 42      default_requirements_path = os.path.join(idf_path, 'requirements.txt')
 43  
 44      parser = argparse.ArgumentParser(description='ESP-IDF Python package dependency checker')
 45      parser.add_argument('--requirements', '-r',
 46                          help='Path to the requirements file',
 47                          default=default_requirements_path)
 48      args = parser.parse_args()
 49  
 50      not_satisfied = []
 51      with open(args.requirements) as f:
 52          for line in f:
 53              line = line.strip()
 54              # pkg_resources.require() cannot handle the full requirements file syntax so we need to make
 55              # adjustments for options which we use.
 56              if line.startswith('file://'):
 57                  line = os.path.basename(line)
 58              if line.startswith('-e') and '#egg=' in line:  # version control URLs, take the egg= part at the end only
 59                  line = re.search(r'#egg=([^\s]+)', line).group(1)
 60              try:
 61                  pkg_resources.require(line)
 62              except Exception:
 63                  not_satisfied.append(line)
 64  
 65      if len(not_satisfied) > 0:
 66          print('The following Python requirements are not satisfied:')
 67          for requirement in not_satisfied:
 68              print(requirement)
 69          if os.path.realpath(args.requirements) != os.path.realpath(default_requirements_path):
 70              # we're using this script to check non-default requirements.txt, so tell the user to run pip
 71              print('Please check the documentation for the feature you are using, or run "%s -m pip install -r %s"' % (sys.executable, args.requirements))
 72          elif os.environ.get('IDF_PYTHON_ENV_PATH'):
 73              # We are running inside a private virtual environment under IDF_TOOLS_PATH,
 74              # ask the user to run install.bat again.
 75              if sys.platform == "win32" and not os.environ.get("MSYSTEM"):
 76                  install_script = 'install.bat'
 77              else:
 78                  install_script = 'install.sh'
 79              print('To install the missing packages, please run "%s"' % os.path.join(idf_path, install_script))
 80          elif sys.platform == "win32" and os.environ.get("MSYSTEM", None) == "MINGW32" and "/mingw32/bin/python" in sys.executable:
 81              print("The recommended way to install a packages is via \"pacman\". Please run \"pacman -Ss <package_name>\" for"
 82                    " searching the package database and if found then "
 83                    "\"pacman -S mingw-w64-i686-python-<package_name>\" for installing it.")
 84              print("NOTE: You may need to run \"pacman -Syu\" if your package database is older and run twice if the "
 85                    "previous run updated \"pacman\" itself.")
 86              print("Please read https://github.com/msys2/msys2/wiki/Using-packages for further information about using "
 87                    "\"pacman\"")
 88              # Special case for MINGW32 Python, needs some packages
 89              # via MSYS2 not via pip or system breaks...
 90              for requirement in not_satisfied:
 91                  if requirement.startswith('cryptography'):
 92                      print("WARNING: The cryptography package have dependencies on system packages so please make sure "
 93                            "you run \"pacman -Syu\" followed by \"pacman -S mingw-w64-i686-python{}-cryptography\"."
 94                            "".format(sys.version_info[0],))
 95                      continue
 96                  elif requirement.startswith('setuptools'):
 97                      print("Please run the following command to install MSYS2's MINGW Python setuptools package:")
 98                      print("pacman -S mingw-w64-i686-python-setuptools")
 99                      continue
100          else:
101              print('Please follow the instructions found in the "Set up the tools" section of '
102                    'ESP-IDF Getting Started Guide')
103  
104          print('Diagnostic information:')
105          idf_python_env_path = os.environ.get('IDF_PYTHON_ENV_PATH')
106          print('    IDF_PYTHON_ENV_PATH: {}'.format(idf_python_env_path or '(not set)'))
107          print('    Python interpreter used: {}'.format(sys.executable))
108          if not idf_python_env_path or idf_python_env_path not in sys.executable:
109              print('    Warning: python interpreter not running from IDF_PYTHON_ENV_PATH')
110              print('    PATH: {}'.format(os.getenv('PATH')))
111          sys.exit(1)
112  
113      print('Python requirements from {} are satisfied.'.format(args.requirements))