Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a443e80
initial conversion of important classes to subclasses of BHoMObject
Tom-Kingstone Jun 1, 2026
e92c72f
save point as changing laptops
Tom-Kingstone Jun 2, 2026
552f955
fix init methods and serialisation for all classes that were converte…
Tom-Kingstone Jun 2, 2026
9cff00b
lots of changes to get serialisation working for objects in round tri…
Tom-Kingstone Jun 4, 2026
d28570a
remove whitespace
Tom-Kingstone Jun 9, 2026
909c4ad
remove unnecessary type hinting and converters as they are handled in…
Tom-Kingstone Jun 9, 2026
90a6510
bhom object fixes, and decorator for bhom callable methods
Tom-Kingstone Jul 2, 2026
a61c9bd
Update assembly file version to 9.3.0.0
BHoMBot Jul 6, 2026
2dc5ecd
Start of milestone changes for 9.3 (#351)
sakanni Jul 9, 2026
0132a71
put the bhom wrapper on everything in bhom/wrapped!
Tom-Kingstone Jul 31, 2026
53abb85
implement new execute methods for all adapter commands except run sim…
Tom-Kingstone Aug 18, 2026
96b09c4
fix silly mistakes
Tom-Kingstone Aug 18, 2026
593c97a
add simulation commands to standard execute structure
Tom-Kingstone Aug 18, 2026
e47c31b
ci: onboard new CI checks (beta tier)
sakanni Aug 23, 2026
c0d93ac
clean up execute and run_wrapped. Make Execute use the given python e…
Tom-Kingstone Aug 24, 2026
bd8fce6
fix versioning and unit test/milestone test failures
Tom-Kingstone Aug 24, 2026
3611285
rename versioning file
Tom-Kingstone Aug 26, 2026
2f41d27
name -> identifier
Tom-Kingstone Aug 26, 2026
08e0e44
Onboard new CI checks (beta tier) (#353)
Tom-Kingstone Aug 26, 2026
9c86bef
fix epw comparison and make calling methods simpler
Tom-Kingstone Sep 3, 2026
199d4f7
Implemented BHoMObject python class to simplify c#/python interop (#354)
jamesramsden-bh Sep 8, 2026
bec1d51
remove original versioning for Identifier
Tom-Kingstone Sep 15, 2026
17429d8
hopefully external comfort epw files are properly located.
Tom-Kingstone Sep 15, 2026
d06a536
Fix invalid epw file for utci and walkability heatmap wrapped methods…
Tom-Kingstone Sep 16, 2026
dee4f1d
Fix versioning for LBT (#357)
peterjamesnugent Sep 16, 2026
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
138 changes: 138 additions & 0 deletions .github/workflows/ci-beta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Beta-tier proxy, BHoM variant. Bundles the tier's checks plus
# copyright-compliance (BHoM enforces OSS copyright; the BHE variant omits it).
# Copy to .github/workflows/ci-beta.yml in each BHoM beta repo.
# Runs on pull_request, non-blocking until a ruleset requires its checks.
# Workflow name CI keeps check contexts bare: required contexts are the job names.

name: CI

on:
pull_request:
branches:
- develop

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true

jobs:
ci-build:
runs-on: windows-2025-vs2026
timeout-minutes: 30
steps:
- name: Run build
uses: BHoM/CI_Toolkit/.github/actions/ci-build@develop
with:
app_id: ${{ secrets.BHOM_APP_ID }}
private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}

ci-code-compliance:
runs-on: windows-2025-vs2026
timeout-minutes: 20
permissions:
contents: read
pull-requests: read
actions: write
steps:
- name: Run code compliance
uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop
with:
check_type: code
patterns: '*.cs'
app_id: ${{ secrets.BHOM_APP_ID }}
private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}

ci-copyright-compliance:
runs-on: windows-2025-vs2026
timeout-minutes: 20
permissions:
contents: read
pull-requests: read
actions: write
steps:
- name: Run copyright compliance
uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop
with:
check_type: copyright
patterns: '*.cs'
app_id: ${{ secrets.BHOM_APP_ID }}
private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}

ci-dataset-compliance:
runs-on: windows-2025-vs2026
timeout-minutes: 20
permissions:
contents: read
pull-requests: read
actions: write
steps:
- name: Run dataset compliance
uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop
with:
check_type: dataset
patterns: ':(icase)*datasets*.json'
app_id: ${{ secrets.BHOM_APP_ID }}
private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}

ci-documentation-compliance:
runs-on: windows-2025-vs2026
timeout-minutes: 20
permissions:
contents: read
pull-requests: read
actions: write
steps:
- name: Run documentation compliance
uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop
with:
check_type: documentation
patterns: '*.cs'
app_id: ${{ secrets.BHOM_APP_ID }}
private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}

ci-project-compliance:
runs-on: windows-2025-vs2026
timeout-minutes: 20
permissions:
contents: read
pull-requests: read
actions: write
steps:
- name: Run project compliance
uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop
with:
check_type: project
patterns: '*AssemblyInfo.cs *.csproj'
app_id: ${{ secrets.BHOM_APP_ID }}
private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}

ci-dataset-tests:
runs-on: windows-2025-vs2026
timeout-minutes: 30
steps:
- name: Run dataset tests
uses: BHoM/CI_Toolkit/.github/actions/ci-dataset-tests@develop
with:
app_id: ${{ secrets.BHOM_APP_ID }}
private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}

ci-serialisation:
runs-on: windows-2025-vs2026
timeout-minutes: 90
steps:
- name: Run serialisation
uses: BHoM/CI_Toolkit/.github/actions/ci-serialisation@develop
with:
app_id: ${{ secrets.BHOM_APP_ID }}
private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
base_ref: ${{ github.base_ref }}

ci-versioning:
runs-on: windows-2025-vs2026
timeout-minutes: 90
steps:
- name: Run versioning
uses: BHoM/CI_Toolkit/.github/actions/ci-versioning@develop
with:
app_id: ${{ secrets.BHOM_APP_ID }}
private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }}
40 changes: 34 additions & 6 deletions LadybugTools_Adapter/AdapterActions/Execute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,25 @@
*/

using BH.Engine.Adapter;
using BH.Engine.Base;
using BH.Engine.LadybugTools;
using BH.Engine.Python;
using BH.Engine.Serialiser;
using BH.oM.Adapter;
using BH.oM.Adapter.Commands;
using BH.oM.Base;
using BH.oM.Data.Requests;
using BH.oM.LadybugTools;
using BH.oM.Python;
using BH.Engine.Python;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using BH.Engine.Base;
using System.Drawing;
using BH.Engine.Serialiser;
using System.Reflection;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace BH.Adapter.LadybugTools
{
Expand Down Expand Up @@ -85,6 +86,33 @@ private List<object> RunCommand(IExecuteCommand command, ActionConfig actionConf
BH.Engine.Base.Compute.RecordError($"The command {command.GetType().FullName} is not valid for the LadybugTools Adapter. Please use a LadybugCommand, or use the correct adapter for the input command.");
return new List<object>();
}

private (string, bool) ExecutePython(List<string> args, string json)
{
string result = "";
bool success;

if (m_httpClient != null)
{
Task<(string, bool)> task = Compute.SendHttp(m_httpClient, args, json);
task.Wait();
(result, success) = task.Result;
}
else
{
//if the server was not running or some other error happened, try running the python directly.
string script = Path.Combine(Engine.Python.Query.DirectoryCode(), m_environment.Name, "src", m_environment.Name.ToLower() , "bhom", "run_wrapped.py");
string tempFileName = System.IO.Path.GetTempFileName();
System.IO.File.WriteAllText(tempFileName, json);
string cmdCommand = $"{m_environment.Executable} {script} {args.Select(x => x.Contains(' ') || string.IsNullOrEmpty(x) ? '"' + x + '"' : x).Aggregate((a, b) => a + " " + b)} -in \"{tempFileName}\"";
result = Engine.Python.Compute.RunCommandStdout(command: cmdCommand, hideWindows: true);
System.IO.File.Delete(tempFileName);
}

success = !result.Contains("Traceback (most recent call last):");

return (result, success);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

using BH.Engine.Adapter;
using BH.Engine.Base;
using BH.Engine.Serialiser;
using BH.oM.Adapter;
using BH.oM.Base;
using BH.oM.LadybugTools;
Expand Down Expand Up @@ -75,48 +76,43 @@ private List<object> RunCommand(CompareEPWKeyPlotCommand command, ActionConfig a
string epwFile = System.IO.Path.GetFullPath(command.EPWFile.GetFullFileName()).Replace('\\', '/');
List<string> epwFileList = command.EPWCompareFiles.Select(e => e.GetFullFileName().Replace('\\', '/')).ToList();

Dictionary<string, object> dict = new Dictionary<string, object>()
{
{ "epw_file", epwFile },
{ "epw_list", epwFileList },
{ "data_type_key", command.EPWKey.ToText() },
{ "line", command.PlotTimeseries },
{ "save_path", command.OutputLocation.Replace('\\', '/') }
};

string json = dict.ToJson();

// run the process
List<string> args = new List<string>
{
"--command", "plot/epw_comparison",
"-e", epwFile,
"-dtk", command.EPWKey.ToText(),
"-p", command.OutputLocation.Replace('\\', '/'),
"-el" //append compare epw file list here
"--command", "plot/epw_comparison"
};
args.AddRange(epwFileList);

if (command.PlotTimeseries)
args.Add("-l");
(string result, bool success) = ExecutePython(args, json);
m_executeSuccess = success;

string result = "";
bool success;

if (m_httpClient != null)
if (!success)
{
Task<(string, bool)> task = Compute.SendHttp(m_httpClient, args);
task.Wait();
(result, success) = task.Result;
BH.Engine.Base.Compute.RecordError($"A python error occurred while running the command `{command.GetType().Name}`. Python output:\n{result}");
return new List<object>();
}
else
{
//if the server was not running or some other error happened, try running the python directly.
string script = Path.Combine(Engine.LadybugTools.Query.PythonCodeDirectory(), "LadybugTools_Toolkit\\src\\ladybugtools_toolkit\\bhom", "run_wrapped.py");
string cmdCommand = $"{m_environment.Executable} {script} {args.Select(x => x.Contains(' ') || string.IsNullOrEmpty(x) ? '"' + x + '"' : x).Aggregate((a, b) => a + " " + b)}";

result = Engine.Python.Compute.RunCommandStdout(command: cmdCommand, hideWindows: true).Split('\n').Last();
}
result = result.Split('\n').Last();

try
{
CustomObject obj = (CustomObject)BH.Engine.Serialiser.Convert.FromJson(result);
PlotInformation info = Convert.ToPlotInformation(obj, new NoData()); //this plot type doesn't have collection metadata yet...
m_executeSuccess = true;
PlotInformation info = (PlotInformation)BH.Engine.Serialiser.Convert.FromJson(result);
return new List<object>() { info };
}
catch (Exception ex)
{
BH.Engine.Base.Compute.RecordError(ex, $"An error occurred when deserialising the output from the script.\n Python output: {result}");
m_executeSuccess = false;
return new List<object>();
}
}
Expand Down
42 changes: 25 additions & 17 deletions LadybugTools_Adapter/AdapterActions/Execute/DiurnalPlotCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using BH.Engine.Adapter;
using BH.Engine.Base;
using BH.Engine.LadybugTools;
using BH.Engine.Serialiser;
using BH.oM.Adapter;
using BH.oM.Base;
using BH.oM.LadybugTools;
Expand Down Expand Up @@ -73,37 +74,44 @@ private List<object> RunCommand(DiurnalPlotCommand command, ActionConfig actionC

//string returnFile = Path.GetTempFileName();

Dictionary<string, object> dict = new Dictionary<string, object>()
{
{ "epw_file", epwFile.Replace('\\', '/') },
{ "data_type_key", command.EPWKey.ToText() },
{ "colour", command.Colour.ToHexCode() },
{ "title", command.Title },
{ "period", command.Period.ToString().ToLower() },
{ "save_path", command.OutputLocation.Replace('\\', '/') }
};

string json = dict.ToJson();

// run the process
List<string> args = new List<string>() { "--command", "plot/diurnal", "-e", epwFile.Replace('\\', '/'), "-dtk", command.EPWKey.ToText(), "--colour", command.Colour.ToHexCode(), "-t", command.Title, "-ap", command.Period.ToString().ToLower(), "-p", command.OutputLocation.Replace('\\', '/') };
List<string> args = new List<string>()
{
"--command", "plot/epw_diurnal"
};

string result = "";
bool success;
(string result, bool success) = ExecutePython(args, json);
m_executeSuccess = success;

if (m_httpClient != null)
if (!success)
{
Task<(string, bool)> task = Compute.SendHttp(m_httpClient, args);
task.Wait();
(result, success) = task.Result;
BH.Engine.Base.Compute.RecordError($"A python error occurred while running the command `{command.GetType().Name}`. Python output:\n{result}");
return new List<object>();
}
else
{
//if the server was not running or some other error happened, try running the python directly.
string script = Path.Combine(Engine.LadybugTools.Query.PythonCodeDirectory(), "LadybugTools_Toolkit\\src\\ladybugtools_toolkit\\bhom", "run_wrapped.py");
string cmdCommand = $"{m_environment.Executable} {script} {args.Select(x => x.Contains(' ') || string.IsNullOrEmpty(x) ? '"' + x + '"' : x).Aggregate((a, b) => a + " " + b)}";

result = Engine.Python.Compute.RunCommandStdout(command: cmdCommand, hideWindows: true).Split('\n').Last();
}
result = result.Split('\n').Last();

try
{
CustomObject obj = (CustomObject)BH.Engine.Serialiser.Convert.FromJson(result);
PlotInformation info = Convert.ToPlotInformation(obj, new CollectionData());
m_executeSuccess = true;
PlotInformation info = (PlotInformation)BH.Engine.Serialiser.Convert.FromJson(result);
return new List<object>() { info };
}
catch (Exception ex)
{
BH.Engine.Base.Compute.RecordError(ex, $"An error occurred when deserialising the output from the script.\n Python output: {result}");
m_executeSuccess = false;
return new List<object>();
}
}
Expand Down
29 changes: 11 additions & 18 deletions LadybugTools_Adapter/AdapterActions/Execute/EPWToCSVCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/

using BH.Engine.Adapter;
using BH.Engine.Serialiser;
using BH.oM.Adapter;
using BH.oM.LadybugTools;
using System;
Expand Down Expand Up @@ -59,28 +60,20 @@ private List<object> RunCommand(EPWToCSVCommand command, ActionConfig actionConf
return null;
}

List<string> args = new List<string>() { "--command", "epw_to_csv", "-e", command.EPWFile.GetFullFileName().Replace('\\', '/'), "-a", command.IncludeAdditionalCalculated.ToString() };
Dictionary<string, object> dict = new Dictionary<string, object>()
{
{ "epw_file", command.EPWFile.GetFullFileName().Replace('\\', '/') },
{ "include_additional", command.IncludeAdditionalCalculated }
};

string result = "";
bool success = true;
string json = dict.ToJson();

if (m_httpClient != null)
{
Task<(string, bool)> task = Compute.SendHttp(m_httpClient, args);
task.Wait();
(result, success) = task.Result; //in this case, result is the text of the csv file.
}
else
List<string> args = new List<string>()
{
//if the server was not running or some other error happened, try running the python directly.
string script = Path.Combine(Engine.LadybugTools.Query.PythonCodeDirectory(), "LadybugTools_Toolkit\\src\\ladybugtools_toolkit\\bhom", "run_wrapped.py");
string cmdCommand = $"{m_environment.Executable} {script} {args.Select(x => x.Contains(' ') || string.IsNullOrEmpty(x) ? '"' + x + '"' : x).Aggregate((a, b) => a + " " + b)}";

result = Engine.Python.Compute.RunCommandStdout(command: cmdCommand, hideWindows: true);
}
"--command", "epw_to_csv"
};

//as the file output is hard to verify by itself, check that no errors got output to stderr log
success &= !result.Contains("Traceback (most recent call last):");
(string result, bool success) = ExecutePython(args, json);

if (!success)
{
Expand Down
Loading