Skip to content

Commit

Permalink
A set of mlboost.python functions to work with PIP3
Browse files Browse the repository at this point in the history
  • Loading branch information
rpurser47 committed Oct 12, 2024
1 parent 94b4e9e commit d741d5d
Show file tree
Hide file tree
Showing 8 changed files with 676 additions and 347 deletions.
755 changes: 408 additions & 347 deletions resources/project/Project.xml

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions toolbox/+mlboost/+python/ensurepip.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
function ensurepip(option)
%ENSUREPIP Downloads and runs get-pip.py to ensure pip is installed
%
% ensurepip() downloads and runs get-pip.py to install pip.
%
% ensurepip(Name,Value) specifies additional options using one or more
% name-value pair arguments:
%
% 'ShowSuccessMessage' Logical value indicating whether to display a
% success message after installation. Default is false.
%
% Example:
% ensurepip('ShowSuccessMessage', true)
%
% See also mlboost.python.getPythonExecutable, mlboost.python.getPipPath

arguments
option.ShowSuccessMessage (1,1) logical = false;
end

% Create a temporary directory
tempDir = tempname;
mkdir(tempDir);

% Set up cleanup object to
cleanupObj = onCleanup(@() rmdir(tempDir, 's'));

% Download get-pip.py
url = "https://bootstrap.pypa.io/get-pip.py";
outputFile = fullfile(tempDir, "get-pip.py");
websave(outputFile, url);

% Run get-pip.py
pythonExe = mlboost.python.getPythonExecutable();
command = sprintf('"%s" "%s"', pythonExe, outputFile);

[status, output] = system(command);

if status == 0
if option.ShowSuccessMessage
successMessage = extract(string(output),"Successfully installed" + wildcardPattern(3,inf) + whitespaceBoundary("start"));
disp(successMessage);
end
else
error("mlboost:pipinstallfailed","Failed to install pip. Error: %s", output);
end

% Cleanup will be automatically performed when the function exits
end
36 changes: 36 additions & 0 deletions toolbox/+mlboost/+python/getPipPath.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
function pipPath = getPipPath()
%GETPIPPATH Get the location of the pip3 executable
% pipPath = getPipPath() returns the full path to the pip3 executable
% using the Python environment information obtained from pyenv.
%
% This function constructs the path to the pip3 executable, verifies its
% existence, and returns the full path. If the pip executable is not found,
% it throws an error.
%
% Returns:
% getPipPath (string): Full path to the pip3 executable
%
% Throws:
% mlboost:python:PIPNotFound: If the pip executable cannot be located
%
% See Also:
% mlboost.python.getPythonPath, mlboost.python.pipCommand, mlboost.python.ensurepip

% Get the Python environment
pyEnv = pyenv;

% Get the Python executable path
pythonHomePath = pyEnv.Home;

% Construct the pip3 executable path
pythonScriptsPath = fullfile(pythonHomePath, "Scripts"); % Construct the path to the Scripts directory where pip is typically located
pipPath = dir(fullfile(pythonScriptsPath,"pip3.*")); % Search for pip3 executable files in the Scripts directory
pipPath = string({pipPath.name}); % Convert the found file names to a string array
pipPath = pipPath(matches(pipPath,"pip3." + lettersPattern + textBoundary("end"))); % Filter the array to keep only valid pip3 executable names
pipPath = fullfile(pythonScriptsPath,pipPath); % Construct the full path to the pip3 executable

% Verify that the pip executable exists
if ~exist(pipPath, 'file')
error('mlboost:python:PIPNotFound', 'Unable to locate pip executable.');
end
end
14 changes: 14 additions & 0 deletions toolbox/+mlboost/+python/getPythonPath.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
%GETPYTHONPATH Get the Python executable path
% pythonPath = getPythonPath() returns the full path to the Python
% executable currently used by MATLAB.
%
% This function uses the pyenv command to retrieve information about the
% Python environment and extracts the path to the Python executable.
%
% Returns:
% pythonPath - A string containing the full path to the Python executable
function pythonPath = getPythonPath()
% Get the Python executable path using pyenv
pyEnv = pyenv;
pythonPath = pyEnv.Executable;
end
38 changes: 38 additions & 0 deletions toolbox/+mlboost/+python/pipCommand.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
function commandOutput = pipCommand(pipArguments)
% Execute a pip command
% This function executes a pip command using the specified pip executable path.
%
% Syntax:
% outputResult = pipCommand(pipArguments)
%
% Inputs:
% pipArguments - A string containing the command for pip and its arguments
%
% Outputs:
% outputResult - The output of the executed pip command
%
% Throws:
% An error if no arguments are provided or if the pip command fails
%
% Example:
% outputResult = pipCommand('install cdsapi')
%
% See also:
% mlboost.python.getPipPath

arguments
pipArguments (1,1) string
end

% Combine the PIP command with the provided arguments
fullCommand = sprintf('"%s" %s', mlboost.python.getPipPath(), pipArguments);

% Execute the command using system
[exitStatus, commandOutput] = system(fullCommand);
commandOutput = string(commandOutput);

% Check if the command was executed successfully
if exitStatus ~= 0
error("mlboost:pipCommandFailed","pip3 command ""%s"" failed: ""%s"" (exit code %d)", pipArguments, strtrim(commandOutput), exitStatus);
end
end
71 changes: 71 additions & 0 deletions toolbox/+mlboost/+python/pipInstall.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
function installResult = pipInstall(packageName, option)
%PIPINSTALL Install a Python package using pip
% INSTALLRESULT = mlboost.python.pipInstall(PACKAGENAME) installs the
% specified Python package using pip and returns the installation result.
%
% INSTALLRESULT = mlboost.python.pipInstall(PACKAGENAME, 'Name', Value)
% specifies additional installation options using one or more name-value
% pair arguments.
%
% Input arguments:
% PACKAGENAME - Name of the Python package to install (string)
%
% Name-value pair arguments:
% 'version' - Specific version of the package to install (string)
% 'upgrade' - Whether to upgrade the package if already installed
% (logical)
%
% Output:
% INSTALLRESULT - Installation result returned by pip (optional)
%
% Example:
% pipInstall('numpy', 'version', '1.21.0', 'upgrade', true)
%
% See also mlboost.python.pipCommand

arguments
% Name of the Python package to install
packageName (1,1) string
% Specific version of the package to install (optional)
option.version (1,1) string = "";
% Whether to upgrade the package if already installed (optional)
option.upgrade (1,1) logical = false
end

% Build the pip command string based on input arguments Start with
% "install" followed by the package name If a version is specified,
% append it to the command If upgrade option is true, add the
% "--upgrade" flag
command = sprintf("install %s",packageName);
if option.version ~= ""
command = command + sprintf("==%s", option.version);
end
if option.upgrade
command = command + " --upgrade";
end

% Execute the pip command using the mlboost.python.pipCommand
% function and store the output in cmdout
cmdout = mlboost.python.pipCommand(command);

% If an output argument is requested, assign the command output to
% installResult
if nargout > 0
installResult = cmdout;
end

% Construct the pip install command
command = sprintf("install %s",packageName);
if option.version ~= ""
command = command + sprintf("==%s", option.version);
end
if option.upgrade
command = command + " --upgrade";
end

cmdout = mlboost.python.pipCommand(command);

if nargout > 0
installResult = cmdout;
end
end
17 changes: 17 additions & 0 deletions toolbox/+mlboost/+python/pipList.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function pipPackages = pipList()
% Call pip freeze using mlboost.python.boost and parse the results
% Returns a table of installed packages and their versions

% Call pip freeze
pipFreeze = mlboost.python.pipCommand("freeze");

% Split the output into lines, remove empty lines
lines = strtrim(splitlines(pipFreeze));
lines(lines == "") = [];

% Split each line into package name and version
parts = split(lines, '==');

% Create a table with the package name and version
pipPackages = table(parts(:,1), parts(:,2), 'VariableNames', {'Package', 'Version'});
end
43 changes: 43 additions & 0 deletions toolbox/+mlboost/+python/pipShow.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
%PIPSHOW Show information about installed Python packages
% RESULT = mlboost.python.pipShow(PACKAGENAME) returns a struct containing information
% about the specified Python package.
%
% Input:
% PACKAGENAME - A string specifying the name of the package to query
%
% Output:
% RESULT - A struct containing package information fields such as
% Name, Version, Summary, Home-page, Author, etc.
%
% This function uses the 'pip show' command to retrieve package
% information and parses the output into a MATLAB struct.
%
% Example:
% info = mlboost.python.pipShow('cdsapi');
% disp(info.Version);
%
% See also mlboost.python.pipCommand
function result = pipShow(packageName)

arguments
packageName (1,1) string
end

% Call pip show on the specified package
pipShowOutput = mlboost.python.pipCommand("show " + packageName);

% Initialize the struct
result = struct();

% Split the output into lines and remove extra whitespace
lines = strsplit(pipShowOutput, '\n');
lines = strtrim(lines);
lines(lines == "") = [];

% Parse each line and add to struct
for i = 1:length(lines)
property = strtrim(extractBefore(lines(i),":"));
value = strtrim(extractAfter(lines(i),":"));
result.(matlab.lang.makeValidName(property)) = value;
end
end

0 comments on commit d741d5d

Please sign in to comment.