diff --git a/README.md b/README.md index fd3b3de8a..ccb17f9d3 100644 --- a/README.md +++ b/README.md @@ -43,13 +43,13 @@ You will be prompted to install the Python dependencies during the first use. - _**[Python 3.7.4](https://www.python.org/downloads/)**_: Make sure you've added python and pip to your PATH in your environment variables. (1) - _**[Python VS Code extension](https://marketplace.visualstudio.com/items?itemName=ms-python.python)**_: This will be installed automatically from the marketplace when you install Pacifica. -The following dependecies can be installed for you by the extension by clicking yes when you are prompted to. (2) +The following dependecies can be installed for you by the extension by clicking yes when you are prompted to (**except** `pywin32` which is needed only on Windows platform). (2) - _**Playsound**_ install by typing the following commands in a console: `pip install playsound` - _**Pywin 32**_ - install by typing the following commands in a console: `pip install pywin32` + install by typing the following commands in a console (only for Windows computers, you must run it manually): `pip install pywin32` - _**Python-Socketio**_ install by typing the following commands in a console: `pip install python-socketio` - _**Requests**_ diff --git a/docs/developers-setup.md b/docs/developers-setup.md index fca7481db..79bd9556b 100644 --- a/docs/developers-setup.md +++ b/docs/developers-setup.md @@ -8,21 +8,21 @@ - Python 3.7.4 (or latest) - - Download link : https://www.python.org/downloads/ - - **NOTE :** Make sure Python is in your path under an environment variable named `python` (during installation or insert it manually afterwards) - - **NOTE :** Make sure pip is added to your environment variables as well - (for example it could be found at : `c:\users\<...>\appdata\local\programs\python\python37\lib\site-packages\pip`) - - Run in a console `python -m pip install --upgrade pip` +- Download link : https://www.python.org/downloads/ +- **NOTE :** Make sure Python is in your path under an environment variable named `python` or `python3.7` (during installation or insert it manually afterwards) +- **NOTE :** Make sure pip is added to your environment variables as well + (for example it could be found at : `c:\users\<...>\appdata\local\programs\python\python37\lib\site-packages\pip`) +- Run in a console `python -m pip install --upgrade pip` * Python Modules - - **Note:** On extension activation you will be prompted asking if you want the modules to be automatically installed for you + - **Note:** On extension activation you will be prompted a popup asking if you want the modules to be automatically installed for you, **except** `pywin32` which is needed only on Windows platform. - Playsound - Run the command in a console : `pip install playsound` - pytest - Run the command in a console : `pip install pytest` - Pywin32 - - **Note:** This is only needed for Windows computers + - **Note:** This is only needed for Windows computers. You must install it manually with the above command! - Run the command in a console : `pip install pywin32` - Python-Socketio - Run the command in a console : `pip install python-socketio` diff --git a/docs/install.md b/docs/install.md index 39513f59a..b0d782d2d 100644 --- a/docs/install.md +++ b/docs/install.md @@ -18,15 +18,15 @@ _Note: You need to install all the dependencies in order to use the extension._ - [VS Code](https://code.visualstudio.com/Download) - [Node](https://nodejs.org/en/download/) - [Python 3.7.4](https://www.python.org/downloads/) - - **Warning :** Make sure you've included `python` and `pip` to your `PATH` in your **environment variables**. - _(Note: the easiest way to do it might be when you install Python, you can select the "Add to PATH" option directly. Otherwise you can search how to insert it manually, but make sure that when you type `python` in a terminal, the command is recognized.)_ + - **Warning :** Make sure you've included `python` (or `python3.7`) and `pip` to your `PATH` in your **environment variables**. + _(Note: the easiest way to do it might be when you install Python, you can select the "Add to PATH" option directly. Otherwise you can search how to insert it manually, but make sure that when you type `python` (or `python3.7`) in a terminal, the command is recognized.)_ - [Python VS Code extension](https://marketplace.visualstudio.com/items?itemName=ms-python.python) - **Note:** This extension is installed automatically from the marketplace when you install our extension - Python Modules - - **Note:** On extension activation you will be prompted asking if you want the modules to be automatically installed for you. + - **Note:** On extension activation you will be prompted a popup asking if you want the modules to be automatically installed for you, **except** `pywin32` which is needed only on Windows platform. - Playsound : `pip install playsound` - Pywin32 : `pip install pywin32` - - **Note:** This is only needed for Windows computers + - **Note:** This is only needed for Windows computers. You must install it manually with the above command! - Python-Socketio : `pip install python-socketio` - Requests : `pip install requests` - Application Insights: `pip install applicationinsights` diff --git a/gulpfile.js b/gulpfile.js index a4e68bbcf..8be19e2ca 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -24,7 +24,11 @@ const languages = [{ folderName: "en", id: "en" }]; gulp.task("clean", () => { return del( - ["out/**", "package.nls.*.json", "../../dist/*0.0.0-UNTRACKEDVERSION.vsix"], + [ + "out/!(python_libs)", + "package.nls.*.json", + "../../dist/*0.0.0-UNTRACKEDVERSION.vsix" + ], { force: true } ); }); diff --git a/src/adafruit_circuitplayground/utils.py b/src/adafruit_circuitplayground/utils.py index c36e344d9..6fded1127 100644 --- a/src/adafruit_circuitplayground/utils.py +++ b/src/adafruit_circuitplayground/utils.py @@ -13,6 +13,7 @@ telemetry_client = TelemetryClient('__AIKEY__') EXTENSION_NAME = '__EXTENSIONNAME__' + def show(state, debug_mode=False): global previous_state if state != previous_state: @@ -30,15 +31,18 @@ def remove_leading_slashes(string): string = string.lstrip('\\/') return string + def escape_if_OSX(file_name): if sys.platform.startswith(CONSTANTS.MAC_OS): file_name = file_name.replace(" ", "%20") return file_name + def send_telemetry(event_name): telemetry_client.track_event( '{}/{}'.format(EXTENSION_NAME, CONSTANTS.TELEMETRY_EVENT_NAMES[event_name])) telemetry_client.flush() + def telemetry_available(): - return telemetry_client.context.instrumentation_key != '__AIKEY__' \ No newline at end of file + return telemetry_client.context.instrumentation_key != '__AIKEY__' diff --git a/src/constants.ts b/src/constants.ts index 95105263e..db66326a0 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -26,8 +26,7 @@ export const CONSTANTS = { DEPENDENCY_CHECKER: { PIP3: "pip3", PYTHON: "python", - PYTHON3: "python3", - PYTHON_LAUNCHER: "py -3" + PYTHON3: "python3.7", }, ERROR: { COMPORT_UNKNOWN_ERROR: @@ -148,6 +147,10 @@ export const CONSTANTS = { "info.incorrectFileNameForSimulatorPopup", 'We want your code to work on your actual board as well. Make sure you name your file "code.py" or "main.py" to be able to run your code on an actual physical device' ), + INSTALLING_PYTHON_DEPENDENCIES: localize( + "info.installingPythonDependencies", + "The Python packages are currently being installed. You will be prompt a message telling you when the installation is done." + ), INSTALL_PYTHON_DEPENDENCIES: localize( "info.installPythonDependencies", "Do you want us to try and install this extensions dependencies for you?" diff --git a/src/debug_user_code.py b/src/debug_user_code.py index 68bdb4d70..3a5297c21 100644 --- a/src/debug_user_code.py +++ b/src/debug_user_code.py @@ -6,8 +6,7 @@ import traceback from pathlib import Path import python_constants as CONSTANTS -from adafruit_circuitplayground.express import cpx -from adafruit_circuitplayground import debugger_communication_client + # Insert absolute path to Adafruit library into sys.path @@ -15,6 +14,16 @@ abs_path_to_lib = os.path.join(abs_path_to_parent_dir, CONSTANTS.LIBRARY_NAME) sys.path.insert(0, abs_path_to_lib) +# Insert absolute path to python libraries into sys.path +abs_path_to_parent_dir = os.path.dirname(os.path.abspath(__file__)) +abs_path_to_lib = os.path.join( + abs_path_to_parent_dir, CONSTANTS.PYTHON_LIBS_DIR) +sys.path.insert(0, abs_path_to_lib) + +# This import must happen after the sys.path is modified +from adafruit_circuitplayground.express import cpx +from adafruit_circuitplayground import debugger_communication_client + ## Execute User Code ## diff --git a/src/extension.ts b/src/extension.ts index fe5a590fe..5baf6bcd8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -68,7 +68,9 @@ export async function activate(context: vscode.ExtensionContext) { // Add our library path to settings.json for autocomplete functionality updatePythonExtraPaths(); - await utils.checkPythonDependencies(context) + pythonExecutableName = await utils.setPythonExectuableName(); + + await utils.checkPythonDependencies(context, pythonExecutableName) // Generate cpx.json try { @@ -79,7 +81,6 @@ export async function activate(context: vscode.ExtensionContext) { configFileCreated = false; } - pythonExecutableName = await utils.setPythonExectuableName(); if (pythonExecutableName === "") { return; diff --git a/src/extension_utils/dependencyChecker.ts b/src/extension_utils/dependencyChecker.ts index d595b2dcd..4881dc8e8 100644 --- a/src/extension_utils/dependencyChecker.ts +++ b/src/extension_utils/dependencyChecker.ts @@ -16,7 +16,7 @@ interface IDependency { } const PYTHON3_REGEX = RegExp("^(Python )(3\\.[0-9]+\\.[0-9]+)"); -const MINIMUM_PYTHON_VERSION = "3.5.0" +const MINIMUM_PYTHON_VERSION = "3.7.0" export class DependencyChecker { constructor() { } @@ -24,8 +24,6 @@ export class DependencyChecker { public async checkDependency(dependencyName: string): Promise { let state: boolean = false; if (dependencyName === CONSTANTS.DEPENDENCY_CHECKER.PYTHON) { - const userOS: string = os.platform(); - const userOnWin: boolean = userOS.indexOf("win") === 0; if ( await this.runCommandVersion(CONSTANTS.DEPENDENCY_CHECKER.PYTHON3, MINIMUM_PYTHON_VERSION) @@ -37,24 +35,6 @@ export class DependencyChecker { ) { state = true; dependencyName = CONSTANTS.DEPENDENCY_CHECKER.PYTHON; - } else if ( - userOnWin && - (await this.runCommandVersion( - CONSTANTS.DEPENDENCY_CHECKER.PYTHON_LAUNCHER, - MINIMUM_PYTHON_VERSION - )) - ) { - state = true; - dependencyName = CONSTANTS.DEPENDENCY_CHECKER.PYTHON; - } else { - state = false; - } - } else if (dependencyName === CONSTANTS.DEPENDENCY_CHECKER.PIP3) { - if ( - await this.runCommandVersion(CONSTANTS.DEPENDENCY_CHECKER.PIP3) - ) { - state = true; - dependencyName = CONSTANTS.DEPENDENCY_CHECKER.PYTHON3; } else { state = false; } diff --git a/src/extension_utils/utils.ts b/src/extension_utils/utils.ts index c8800dbbf..1d156745d 100644 --- a/src/extension_utils/utils.ts +++ b/src/extension_utils/utils.ts @@ -3,6 +3,7 @@ import * as fs from "fs"; import * as path from "path"; +import * as os from "os"; import { DependencyChecker } from "./dependencyChecker"; import { DeviceContext } from "../deviceContext"; import * as vscode from "vscode"; @@ -234,11 +235,11 @@ export const checkConfig = (configName: string): boolean => { return vscode.workspace.getConfiguration().get(configName) === true; } -export const checkPythonDependencies = async (context: vscode.ExtensionContext) => { +export const checkPythonDependencies = async (context: vscode.ExtensionContext, pythonExecutable: string) => { let hasInstalledDependencies: boolean = false; if (checkPipDependency() && checkPythonDependency()) { if (checkConfig(CONFIG.SHOW_DEPENDENCY_INSTALL)) { - hasInstalledDependencies = await promptInstallPythonDependencies(context); + hasInstalledDependencies = await promptInstallPythonDependencies(context, pythonExecutable); if (hasInstalledDependencies) { await vscode.workspace.getConfiguration().update(CONFIG.SHOW_DEPENDENCY_INSTALL, false); } @@ -250,14 +251,14 @@ export const checkPythonDependencies = async (context: vscode.ExtensionContext) } -export const promptInstallPythonDependencies = (context: vscode.ExtensionContext) => { +export const promptInstallPythonDependencies = (context: vscode.ExtensionContext, pythonExecutable: string) => { return vscode.window.showInformationMessage( CONSTANTS.INFO.INSTALL_PYTHON_DEPENDENCIES, DialogResponses.YES, DialogResponses.NO) .then((selection: vscode.MessageItem | undefined) => { if (selection === DialogResponses.YES) { - return installPythonDependencies(context); + return installPythonDependencies(context, pythonExecutable); } else if (selection === DialogResponses.NO) { return vscode.window.showInformationMessage( CONSTANTS.INFO.ARE_YOU_SURE, @@ -265,7 +266,7 @@ export const promptInstallPythonDependencies = (context: vscode.ExtensionContext DialogResponses.DONT_INSTALL ).then((installChoice: vscode.MessageItem | undefined) => { if (installChoice === DialogResponses.INSTALL_NOW) { - return installPythonDependencies(context); + return installPythonDependencies(context, pythonExecutable); } else { return false; } @@ -274,16 +275,19 @@ export const promptInstallPythonDependencies = (context: vscode.ExtensionContext }); } -export const installPythonDependencies = async (context: vscode.ExtensionContext) => { +export const installPythonDependencies = async (context: vscode.ExtensionContext, pythonExecutable: string) => { let installed: boolean = false; try { + vscode.window.showInformationMessage(CONSTANTS.INFO.INSTALLING_PYTHON_DEPENDENCIES); const requirementsPath: string = getPathToScript(context, "out", "requirements.txt"); - const { stdout } = await exec(`pip3 install -r ${requirementsPath}`); + const pathToLibs: string = getPathToScript(context, "out", "python_libs"); + const { stdout } = await exec(`${pythonExecutable} -m pip install -r ${requirementsPath} -t ${pathToLibs}`); + console.info(stdout); installed = true; - vscode.window.showInformationMessage(CONSTANTS.INFO.SUCCESSFUL_INSTALL) + vscode.window.showInformationMessage(CONSTANTS.INFO.SUCCESSFUL_INSTALL); } catch (err) { console.error(err); installed = false; } return installed -} \ No newline at end of file +} diff --git a/src/process_user_code.py b/src/process_user_code.py index 28bf37482..7c1a50cbf 100644 --- a/src/process_user_code.py +++ b/src/process_user_code.py @@ -10,7 +10,12 @@ import traceback import python_constants as CONSTANTS from pathlib import Path -from adafruit_circuitplayground.express import cpx + +# Insert absolute path to python libraries into sys.path +abs_path_to_parent_dir = os.path.dirname(os.path.abspath(__file__)) +abs_path_to_lib = os.path.join( + abs_path_to_parent_dir, CONSTANTS.PYTHON_LIBS_DIR) +sys.path.insert(0, abs_path_to_lib) read_val = "" threads = [] @@ -24,6 +29,9 @@ abs_path_to_parent_dir, CONSTANTS.LIBRARY_NAME) sys.path.insert(0, abs_path_to_lib) +# This import must happen after the sys.path is modified +from adafruit_circuitplayground.express import cpx + # Handle User Inputs Thread class UserInput(threading.Thread): diff --git a/src/python_constants.py b/src/python_constants.py index 2a1020278..68d6c7788 100644 --- a/src/python_constants.py +++ b/src/python_constants.py @@ -33,6 +33,8 @@ NOT_SUPPORTED_OS = 'The OS "{}" not supported.' NOT_IMPLEMENTED_ERROR = "This method is not implemented by the simulator" +PYTHON_LIBS_DIR = "python_libs" + UTF_FORMAT = "utf-8" WINDOWS_OS = "win32" diff --git a/src/requirements.txt b/src/requirements.txt index 8750fe81f..b39b0bc1e 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,5 +1,6 @@ -playsound -pytest -applicationinsights -python-socketio -requests +playsound==1.2.2 +pytest==5.0.1 +applicationinsights==0.11.9 +python-socketio==4.3.1 +requests==2.22.0 +pywin32==224