Skip to content

8.0 Deployment #152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 38 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
4b06bbb
Update assembly file version to 8.0.0.0 and AssemblyVersion to 8.0.0.0
BHoMBot Sep 20, 2024
21c3ce8
Start of milestone changes for 8.0 (#144)
adecler Sep 23, 2024
7fa170b
initial solution for the refactor. python installer now used instead …
Tom-Kingstone Sep 5, 2024
2d61d79
rename the python versions to be just the major numbers to avoid conf…
Tom-Kingstone Sep 5, 2024
bbb5621
fixed remove method
Tom-Kingstone Sep 9, 2024
badc7a9
fixed base environment install location
Tom-Kingstone Sep 9, 2024
15d41fe
use DirectoryBaseEnvironment properly everywhere
Tom-Kingstone Sep 9, 2024
1131f9e
added bhom analytics logger, and added the interpreter path (sys.exec…
Tom-Kingstone Sep 13, 2024
09247c4
changed log entry type to be the same as the one in BHoM
Tom-Kingstone Sep 13, 2024
604532a
add method separator for Download.cs
Tom-Kingstone Oct 1, 2024
a674209
update versioning for removed/updated methods.
Tom-Kingstone Oct 1, 2024
01eb894
fix versioning keys
Tom-Kingstone Oct 1, 2024
4413c31
rename versioning file
Tom-Kingstone Oct 1, 2024
162cf42
updated wrong versioning key :P
Tom-Kingstone Oct 1, 2024
895c4e8
fix key for DownloadGetPip
Tom-Kingstone Oct 1, 2024
9fc085a
updated DirectoryBaseEnvironment and BasePythonEnvironment
Tom-Kingstone Oct 1, 2024
fc0513d
add local package to base environment on install
Tom-Kingstone Oct 1, 2024
db51afc
mistake in method signature
Tom-Kingstone Oct 1, 2024
71a1a7c
general compliance changes
Tom-Kingstone Oct 1, 2024
f1b93e8
revert ToPython removal (versioning doesn't play nice)
Tom-Kingstone Oct 2, 2024
642f2f5
Update Python_Engine/Compute/BasePythonEnvironment.cs
Tom-Kingstone Oct 2, 2024
660a338
Made the warning for creating virtual environments clearer (need the …
Tom-Kingstone Oct 22, 2024
631ad9e
Removed error if the environment didn't exist - now downloads the req…
Tom-Kingstone Oct 29, 2024
6561cb0
add a comment and if spacing
Tom-Kingstone Oct 29, 2024
3ba64bb
properly install the base environment when asked for
Tom-Kingstone Oct 29, 2024
37eb521
change to run installer check again
Tom-Kingstone Oct 30, 2024
618dfb0
Refactor to use the windows installer when creating a base environmen…
jamesramsden-bh Nov 6, 2024
c236610
moved base plots and bhom_analytics to this toolkit
Tom-Kingstone Sep 2, 2024
50695ce
correct path for the timeseries helper method
Tom-Kingstone Sep 9, 2024
cfa194f
added python library to nuspec content files
Tom-Kingstone Nov 7, 2024
42a5c8d
added todo for histogram, and fixed heatmap xaxis date formatter
Tom-Kingstone Nov 7, 2024
a3031b7
moved helpers and plot/utilities methods (and split out helpers using…
Tom-Kingstone Nov 7, 2024
0e93b53
use ax = plt.gca() if ax isn't provided in histogram
Tom-Kingstone Nov 12, 2024
61d1ada
added docstring to histogram method
Tom-Kingstone Nov 12, 2024
148923a
added python unit tests
Tom-Kingstone Nov 12, 2024
cd52274
update gitignore to include python parts
Tom-Kingstone Nov 13, 2024
ab59437
Add python code to nuspec as content files (#148)
jamesramsden-bh Nov 13, 2024
891b039
Move base plots from LadybugTools_Toolkit (#147)
jamesramsden-bh Dec 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .ci/BHoMBot/Nuget/BHoM.Interop.Python.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
</dependencies>
</metadata>
<files>
<file src="C:\ProgramData\BHoM\Extensions\PythonCode\Python_Toolkit\src\python_toolkit\bhom\wrapped\**\*.*" exclude="**\__pycache__\*;**\docs\**\*" target="contentFiles\any\any\PythonCode\Python_Toolkit\src\python_toolkit\bhom\wrapped"/>
<file src="C:\ProgramData\BHoM\Extensions\PythonCode\Python_Toolkit\src\**\*.*" exclude="**\__pycache__\*;**\docs\**\*" target="contentFiles\any\any\PythonEnvironment\Lib\site-packages" />
<file src="licence/licence.txt" target="" />
<file src="images/icon.png" target="" />
<file src="docs/readme.md" target="" />
Expand Down
121 changes: 120 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,123 @@ Alligator/Alligator_REMOTE_9848.csproj

# User defined files #
######################
build.ps1
build.ps1

# Testing files
.dev/
prototypes/

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
*.ipynb
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# unignored files
!example.sql
55 changes: 11 additions & 44 deletions Python_Engine/Compute/BasePythonEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@ namespace BH.Engine.Python
{
public static partial class Compute
{
[PreviousVersion("8.0", "BH.Engine.Python.Compute.BasePythonEnvironment(System.Boolean, System.Boolean)")]
[Description("Retrieve or reinstall the base Python Environment for BHoM workflows.")]
[Input("version", "The target version of python to be installed or retrieved.")]
[Input("reload", "Reload the base Python environment rather than recreating it, if it already exists.")]
[Input("run", "Start the installation/retrieval of the BHoM Base Python Environment.")]
[Output("env", "The base Python Environment for all BHoM workflows.")]
public static PythonEnvironment BasePythonEnvironment(
PythonVersion version = PythonVersion.v3_10,
bool reload = true,
bool run = false
)
Expand All @@ -52,10 +55,10 @@ public static PythonEnvironment BasePythonEnvironment(
// create PythonEnvironments directory if it doesnt already exist
Directory.CreateDirectory(Query.DirectoryEnvironments());
}

// determine whether the base environment already exists
string targetExecutable = Path.Combine(Query.DirectoryBaseEnvironment(), "python.exe");
bool exists = Directory.Exists(Query.DirectoryBaseEnvironment()) && File.Exists(targetExecutable);
string targetExecutable = Path.Combine(Query.DirectoryBaseEnvironment(version), "python.exe");
bool exists = File.Exists(targetExecutable);

if (exists && reload)
return new PythonEnvironment() { Name = Query.ToolkitName(), Executable = targetExecutable };
Expand All @@ -64,50 +67,14 @@ public static PythonEnvironment BasePythonEnvironment(
// remove all existing environments and kernels
RemoveEverything();

// download the target Python version and convert into a "full" python installation bypassing admin rights
string executable = PythonVersion.v3_10_5.DownloadPython(Query.ToolkitName());
string pipInstaller = DownloadGetPip(Path.GetDirectoryName(executable));
string baseEnvironmentDirectory = Path.GetDirectoryName(executable);

// install pip into the python installation
Process process = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = Modify.AddQuotesIfRequired(executable),
Arguments = Modify.AddQuotesIfRequired(pipInstaller) + " --no-warn-script-location",
RedirectStandardError=true,
UseShellExecute=false,
}
};
using (Process p = Process.Start(process.StartInfo))
{
string standardError = p.StandardError.ReadToEnd();
p.WaitForExit();
if (p.ExitCode != 0)
BH.Engine.Base.Compute.RecordError($"Error installing pip.\n{standardError}");
File.Delete(pipInstaller);
}

// delete files with the suffix ._pth from installedDirectory
List<string> pthFiles = Directory.GetFiles(baseEnvironmentDirectory, "*.*", SearchOption.TopDirectoryOnly).Where(s => s.EndsWith("._pth")).ToList();
foreach (string pthFile in pthFiles)
{
File.Delete(pthFile);
}

// move files with the suffix .dll and .pyd from installedDirectory into a DLLs directory
string libDirectory = Directory.CreateDirectory(Path.Combine(baseEnvironmentDirectory, "DLLs")).FullName;
List<string> libFiles = Directory.GetFiles(baseEnvironmentDirectory, "*.*", SearchOption.TopDirectoryOnly).Where(s => (s.EndsWith(".dll") || s.EndsWith(".pyd")) && !Path.GetFileName(s).Contains("python") && !Path.GetFileName(s).Contains("vcruntime")).ToList();
foreach (string libFile in libFiles)
{
File.Move(libFile, Path.Combine(libDirectory, Path.GetFileName(libFile)));
}
// download and run the installer for the target Python version
string exe = version.DownloadPythonVersion();

// install essential packages into base environment
InstallPackages(executable, new List<string>() { "virtualenv", "jupyterlab", "black", "pylint" });
InstallPackages(exe, new List<string>() { "virtualenv", "jupyterlab", "black", "pylint" });
InstallPackageLocal(exe, Path.Combine(Query.DirectoryCode(), Query.ToolkitName()));

return new PythonEnvironment() { Name = Query.ToolkitName(), Executable = executable };
return new PythonEnvironment() { Name = Query.ToolkitName(), Executable = exe };
}
}
}
Expand Down
71 changes: 46 additions & 25 deletions Python_Engine/Compute/Download.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
using BH.oM.Python.Enums;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Xml.Linq;

namespace BH.Engine.Python
Expand Down Expand Up @@ -85,34 +87,53 @@
return filePath;
}

// TODO - THIS METHOD HAS CHANGED BUT IS STILL USED, SO NEEDS DEPRECATING
// changed from what to what ?
[Description("Download the target version of Python.")]
[Input("version", "A Python version.")]
[Input("name", "Name of target exe file.")]
[Output("executablePath", "The path of the executable for the downloaded Python.")]
public static string DownloadPython(this PythonVersion version, string name = null)
/******************************************************/

[PreviousVersion("8.0", "BH.Engine.Python.Compute.DownloadPython(BH.oM.Python.Enums.PythonVersion, System.String)")]
[Description("Download and install a specified version of python, and return the executable for it.")]
[Input("version", "The version of python to download.")]
[Output("pythonExecutable", "The executable (python.exe) for the python version that was installed")]

Check warning on line 95 in Python_Engine/Compute/Download.cs

View check run for this annotation

BHoMBot-CI / beta-documentation-compliance

Python_Engine/Compute/Download.cs#L95

Documentation attribute should end with grammatically correct punctuation (., !, or ?) - For more information see https://bhom.xyz/documentation/DevOps/Code%20Compliance%20and%20CI/Compliance%20Checks/AttributeHasEndingPunctuation
public static string DownloadPythonVersion(this PythonVersion version)
{
string url = version.EmbeddableURL();
if (string.IsNullOrEmpty(name))
name = Path.GetFileNameWithoutExtension(url);
string targetExecutable = Path.Combine(Query.DirectoryEnvironments(), name, "python.exe");

if (File.Exists(targetExecutable))
return targetExecutable;

string zipfile = DownloadFile(url, Query.DirectoryEnvironments());
UnzipFile(zipfile, Query.DirectoryEnvironments(), name, true);

return targetExecutable;
}

[Description("Download the pip installer")]
[Input("targetDirectory", "The directory into which get-pip.py will be downloaded.")]
[Output("getpipPath", "The path of the file used to install pip into an embedded Python environment.")]
public static string DownloadGetPip(string targetDirectory)
{
return DownloadFile("https://bootstrap.pypa.io/get-pip.py", targetDirectory);
string basePath = Path.Combine(Query.DirectoryBaseEnvironment(version));

if (File.Exists(Path.Combine(basePath, "python.exe")))
return Path.Combine(basePath, "python.exe");

if (!Directory.Exists(basePath))
Directory.CreateDirectory(basePath);
else
{
Directory.Delete(basePath, true); //if there are any files here already for some reason, remove them.
Directory.CreateDirectory(basePath);
}

string installerFile = DownloadFile(url, basePath, "installer.exe");

using (Process install = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = installerFile,
Arguments = $"/passive InstallAllUsers=0 InstallLauncherAllUsers=0 Include_launcher=0 Shortcuts=0 AssociateFiles=0 Include_tools=0 Include_test=0 TargetDir={Modify.AddQuotesIfRequired(basePath)}",
RedirectStandardError = true,
UseShellExecute = false,
}
})
{
install.Start();
string stderr = install.StandardError.ReadToEnd();
install.WaitForExit();
if (install.ExitCode != 0)
{
BH.Engine.Base.Compute.RecordError($"Error installing python: {stderr}");
return null;
}
}

return Path.Combine(basePath, "python.exe");
}
}
}
Expand Down
55 changes: 50 additions & 5 deletions Python_Engine/Compute/Remove.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@
*/

using BH.oM.Base.Attributes;
using BH.oM.Python.Enums;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;

namespace BH.Engine.Python
Expand Down Expand Up @@ -77,19 +81,60 @@ public static void RemoveAllVirtualEnvironments()
}
}

[Description("Completely remove the base BHoM Python environment.")]
public static void RemoveBaseEnvironment()
[PreviousVersion("8.0", "BH.Engine.Python.Compute.RemoveBaseEnvironment()")]
[Description("Remove the base install for the python version specified.")]
[Input("version", "The base python version to remove.")]
public static void RemoveBaseVersion(PythonVersion version = PythonVersion.v3_10)
{
string basePath = Path.Combine(Query.DirectoryEnvironments(), Query.ToolkitName());
if (Directory.Exists(basePath))
string basePath = Path.Combine(Query.DirectoryEnvironments(), Query.ToolkitName(), version.ToString());
string baseInstaller = Path.Combine(basePath, "installer.exe");

// If the installer does not exist and the folder does - assume a bad/invalid install and just delete the entire folder.
if (!File.Exists(baseInstaller) && Directory.Exists(basePath))
{
Directory.Delete(basePath, true);
return;
}
else if (!Directory.Exists(basePath))
// If the base path doesn't exist there is nothing to remove.
return;

using (Process uninstall = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = baseInstaller,
Arguments = "/uninstall /passive",
RedirectStandardError = true,
UseShellExecute = false,
}
})
{
uninstall.Start();
string stderr = uninstall.StandardError.ReadToEnd();
uninstall.WaitForExit();
if (uninstall.ExitCode != 0)
{
BH.Engine.Base.Compute.RecordError($"Error uninstalling python: {stderr}");
return;
}
}

// Finally remove base folder as the installer may have missed something.
Directory.Delete(basePath, true);
}

[Description("Completely remove all BHoM-related Python environments and kernels.")]
public static void RemoveEverything()
{
RemoveAllVirtualEnvironments();
RemoveBaseEnvironment();

//remove all python versions installed in base directory.
foreach (PythonVersion e in Enum.GetValues(typeof(PythonVersion)))
{
if (e != PythonVersion.Undefined)
RemoveBaseVersion(e);
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions Python_Engine/Compute/UnzipFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ namespace BH.Engine.Python
{
public static partial class Compute
{
//This method is no longer used by python toolkit, and perhaps should be removed or moved to the file toolkit instead.
[Description("Extract the contents of an archive.")]
[Input("archivePath", "The archive to extract.")]
[Input("targetDirectory", "The destination directory to extract into.")]
Expand Down
Loading