1#!/usr/bin/env python3 2# 3# Copyright 2017 - The Android Open Source Project 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. 16from distutils import cmd 17from distutils import log 18import subprocess 19import os 20import shutil 21import setuptools 22from setuptools.command import test 23import sys 24 25install_requires = [ 26 # Require an older version of setuptools that does not enforce PEP 440. 27 # This must be added first. 28 'setuptools<66.0.0', 29 # Future needs to have a newer version that contains urllib. 30 'future>=0.16.0', 31 'mobly==1.12.0', 32 # Latest version of mock (4.0.0b) causes a number of compatibility issues with ACTS unit tests 33 # b/148695846, b/148814743 34 'mock==3.0.5', 35 'Monsoon', 36 'paramiko[ed25519]', 37 'pylibftdi', 38 'pyserial', 39 'pyyaml>=5.1', 40 'requests', 41 'retry', 42 'scapy', 43 'scp', 44 'usbinfo', 45 'zeroconf' 46] 47 48versioned_deps = { 49 'backoff': 'backoff', 50 'numpy': 'numpy', 51 'scipy': 'scipy', 52 'protobuf': 'protobuf==4.21.5', 53 'grpcio': 'grpcio', 54} 55 56# numpy and scipy version matrix per: 57# https://docs.scipy.org/doc/scipy/dev/toolchain.html 58if sys.version_info < (3, 11): 59 versioned_deps['numpy'] = 'numpy<2.0.0b1' 60if sys.version_info < (3, 9): 61 versioned_deps['scipy'] = 'scipy<1.11' 62if sys.version_info < (3, 8): 63 versioned_deps['numpy'] = 'numpy<1.22' 64 versioned_deps['scipy'] = 'scipy<1.8' 65if sys.version_info < (3, 7): 66 versioned_deps['backoff'] = 'backoff<2.0' 67 versioned_deps['numpy'] = 'numpy<1.20' 68 versioned_deps['scipy'] = 'scipy<1.6' 69 versioned_deps['protobuf'] = 'protobuf==3.20.1' 70 versioned_deps['grpcio'] = 'grpcio==1.48.2' 71 versioned_deps['typing_extensions'] = 'typing_extensions==4.1.1' 72 versioned_deps['cryptography'] = 'cryptography<41.0' 73if (sys.version_info.major, sys.version_info.minor) == (3, 6): 74 versioned_deps['dataclasses'] = 'dataclasses==0.8' 75if sys.version_info < (3, 6): 76 versioned_deps['numpy'] = 'numpy<1.19' 77 versioned_deps['scipy'] = 'scipy<1.5' 78 versioned_deps['typing_extensions'] = 'typing_extensions<4.0.0' 79 80install_requires += list(versioned_deps.values()) 81 82if sys.version_info < (3, ): 83 install_requires.append('enum34') 84 install_requires.append('statistics') 85 # "futures" is needed for py2 compatibility and it only works in 2.7 86 install_requires.append('futures') 87 install_requires.append('py2-ipaddress') 88 install_requires.append('subprocess32') 89 90DEV_PACKAGES = ['shiv'] 91 92framework_dir = os.path.dirname(os.path.realpath(__file__)) 93 94 95class PyTest(test.test): 96 """Class used to execute unit tests using PyTest. This allows us to execute 97 unit tests without having to install the package. 98 """ 99 100 def finalize_options(self): 101 test.test.finalize_options(self) 102 self.test_args = ['-x', "tests"] 103 self.test_suite = True 104 105 def run_tests(self): 106 test_path = os.path.join(framework_dir, 107 '../tests/meta/ActsUnitTest.py') 108 result = subprocess.Popen('python3 %s' % test_path, 109 stdout=sys.stdout, 110 stderr=sys.stderr, 111 shell=True) 112 result.communicate() 113 sys.exit(result.returncode) 114 115 116class ActsUninstall(cmd.Command): 117 """Acts uninstaller. 118 119 Uninstalls acts from the current version of python. This will attempt to 120 import acts from any of the python egg locations. If it finds an import 121 it will use the modules file location to delete it. This is repeated until 122 acts can no longer be imported and thus is uninstalled. 123 """ 124 125 description = 'Uninstall acts from the local machine.' 126 user_options = [] 127 128 def initialize_options(self): 129 pass 130 131 def finalize_options(self): 132 pass 133 134 def uninstall_acts_module(self, acts_module): 135 """Uninstalls acts from a module. 136 137 Args: 138 acts_module: The acts module to uninstall. 139 """ 140 for acts_install_dir in acts_module.__path__: 141 self.announce('Deleting acts from: %s' % acts_install_dir, 142 log.INFO) 143 shutil.rmtree(acts_install_dir) 144 145 def run(self): 146 """Entry point for the uninstaller.""" 147 # Remove the working directory from the python path. This ensures that 148 # Source code is not accidentally targeted. 149 if framework_dir in sys.path: 150 sys.path.remove(framework_dir) 151 152 if os.getcwd() in sys.path: 153 sys.path.remove(os.getcwd()) 154 155 try: 156 import acts as acts_module 157 except ImportError: 158 self.announce('Acts is not installed, nothing to uninstall.', 159 level=log.ERROR) 160 return 161 162 while acts_module: 163 self.uninstall_acts_module(acts_module) 164 try: 165 del sys.modules['acts'] 166 import acts as acts_module 167 except ImportError: 168 acts_module = None 169 170 self.announce('Finished uninstalling acts.') 171 172 173def main(): 174 scripts = [ 175 os.path.join('acts', 'bin', 'act.py'), 176 os.path.join('acts', 'bin', 'monsoon.py') 177 ] 178 # cd to framework directory so the correct package namespace is found 179 os.chdir(framework_dir) 180 setuptools.setup(name='acts', 181 version='0.9', 182 description='Android Comms Test Suite', 183 license='Apache2.0', 184 packages=setuptools.find_packages(), 185 include_package_data=True, 186 tests_require=['pytest'], 187 install_requires=install_requires, 188 extras_require={ 189 'dev': DEV_PACKAGES, 190 'digital_loggers_pdu': ['dlipower'], 191 }, 192 scripts=scripts, 193 cmdclass={ 194 'test': PyTest, 195 'uninstall': ActsUninstall 196 }, 197 url="http://www.android.com/") 198 199 if {'-u', '--uninstall', 'uninstall'}.intersection(sys.argv): 200 installed_scripts = [ 201 '/usr/local/bin/act.py', '/usr/local/bin/monsoon.py' 202 ] 203 for act_file in installed_scripts: 204 if os.path.islink(act_file): 205 os.unlink(act_file) 206 elif os.path.exists(act_file): 207 os.remove(act_file) 208 209 210if __name__ == '__main__': 211 main() 212