PyRevitRunner: honor cpython hashbang#3029
Conversation
- route runner execution through runtime ScriptExecutor - preserve runner builtins and log capture via runtime ScriptIO - emit EngineConfigs in the journal and normalize runtime defaults
|
Unable to trigger custom agent "Code Reviewer"You have run out of credits 😔 |
There was a problem hiding this comment.
Pull request overview
This PR enhances the pyRevit runner to honor CPython hashbang directives by routing script execution through the runtime ScriptExecutor. This enables consistent engine selection logic (explicit config > hashbang > IronPython default) for both UI and runner contexts.
Changes:
- Refactored PyRevitRunnerCommand to use the runtime ScriptExecutor instead of the legacy IronPython-only executor
- Added support for custom variables injection into Python builtins (batchexec, logfile, models)
- Implemented log file capture via ScriptIO with optional output suppression for runner context
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| dev/pyRevitLoader/Source/PyRevitRunnerCommand.cs | Refactored to use runtime ScriptExecutor with engine config support; added helper methods for journal data parsing, script metadata building, and environment seeding |
| dev/pyRevitLoader/Directory.Build.targets | Added assembly references for pyRevitLabs.Json, pyRevitLabs.PyRevit, and pyRevitLabs.PyRevit.Runtime when UseRunner is enabled |
| dev/pyRevitLabs/pyRevitLabs.PyRevit/PyRevitRunner.cs | Updated journal template to include EngineConfigs parameter (5 parameters instead of 4) with default full_frame configuration |
| dev/pyRevitLabs.PyRevit.Runtime/scriptruntime.cs | Added Variables, LogFilePath, and SuppressOutput properties to ScriptRuntimeConfigs for runner-specific behavior |
| dev/pyRevitLabs.PyRevit.Runtime/ScriptIO.cs | Implemented log file capture by appending output to LogFilePath; added output suppression check via SuppressOutput flag |
| dev/pyRevitLabs.PyRevit.Runtime/IronPythonEngine.cs | Added logic to inject custom variables from ScriptRuntimeConfigs.Variables into Python builtins |
| dev/pyRevitLabs.PyRevit.Runtime/CPythonEngine.cs | Added logic to inject custom variables from ScriptRuntimeConfigs.Variables into Python builtins |
- lock log file writes and emit debug traces on log failures - guard runner search path nulls and remove redundant null-coalesce - add debug traces for best-effort JSON/log file operations
|
Re-ran runner smoke tests after the review fixes:
|
@romangolev this is your playground ☝️ 🙏 |
pipenv run pyrevit build labs pipenv run pyrevit build products Debug copy .\release\.pyrevitargs . --- refactor: update ScriptRuntimeConfigs properties for better encapsulation - Changed LogFilePath and SuppressOutput from fields to properties in ScriptRuntimeConfigs for improved encapsulation. - Updated PyRevitRunnerCommand to set these properties dynamically, enhancing flexibility and maintainability.
Have a look at https://docs.pyrevitlabs.io/dev-guide/ broken tesing approach
Test 1Made it work.
Details
' pyrevitrunner generated journal No print statement in the log 🔴 python ran: |
|
... Continuation from yesterday session of testing. Note to future self: first test 🟢
second test 🟢third test 🟢
skipping four and five test sixirrelevant for this PR Details
py -3.10 -m pytest dev/modules/pyRevitLabs.Python.Net/tests -v La génération a réussi. CSC : warning AD0001: L'analyseur 'NonCopyable.NonCopyableAnalyzer' a levé une exception de type 'System.NullReferenceException' avec le message 'Object reference not set to an instance of an object.'. [C:\Users\Local Admin\Documents\GitHub\pyRevit\dev\modules\pyRevitLabs.Python.Net\src\runtime\Python.Runtime.csproj::TargetFramework=netstandard2.0] Temps écoulé 00:00:06.52 |
- Introduced a new build entry for Autodesk Revit 2026.4 with version 26.4.0.32. - Included metadata and release notes links for better reference and documentation.
- Removed comments regarding the availability of LogFilePath, SuppressOutput, and Variables properties in the referenced DLL version to improve code clarity and maintainability.
- Updated comments to provide clearer context regarding model file handling and Revit version determination. - Improved readability by specifying conditions under which model files are verified and versions are used.
- route runner execution through runtime ScriptExecutor - preserve runner builtins and log capture via runtime ScriptIO - emit EngineConfigs in the journal and normalize runtime defaults
- lock log file writes and emit debug traces on log failures - guard runner search path nulls and remove redundant null-coalesce - add debug traces for best-effort JSON/log file operations
pipenv run pyrevit build labs pipenv run pyrevit build products Debug copy .\release\.pyrevitargs . --- refactor: update ScriptRuntimeConfigs properties for better encapsulation - Changed LogFilePath and SuppressOutput from fields to properties in ScriptRuntimeConfigs for improved encapsulation. - Updated PyRevitRunnerCommand to set these properties dynamically, enhancing flexibility and maintainability.
- Introduced a new build entry for Autodesk Revit 2026.4 with version 26.4.0.32. - Included metadata and release notes links for better reference and documentation.
@OriAshkenazi sure, and that would be great. Please open a specific Issue describing the plan and pain point with sub-issues and ping these people, they may be willing or capable to chip in:
sounds good, go for it Thank you! |
|
I've tried it once, but never managed to follow up with it: https://discourse.pyrevitlabs.io/t/pyrevit-cpython-wpf-support-saga/8394 Ehsan told us about pythonnet patches made internally by mcneel, same thing by dynamo guys, I don't know if any of it reach upstream... |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26025+1329-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26025+1418-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26030+2037-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26030+2039-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26030+2101-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26030+2136-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26030+2147-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26030+2212-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1043-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1111-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1304-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1323-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1433-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1538-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1543-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1553-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1612-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1624-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1738-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1743-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1829-wip |
|
📦 New work-in-progress (wip) builds are available for 5.3.1.26032+1937-wip |
|
📦 New work-in-progress (wip) builds are available for 6.0.0.26032+1956-wip |
|
📦 New work-in-progress (wip) builds are available for 6.0.0.26032+2005-wip |
|
📦 New work-in-progress (wip) builds are available for 6.0.0.26032+2008-wip |
|
📦 New public release are available for 6.0.0.26032+2040 |
|
📦 New public release are available for 6.0.0.26032+2040 |
PR: pyRevitRunner CPython hashbang
Summary
pyrevit runexecution through runtimeScriptExecutorso engine selection matches the UI precedence (explicit config > hashbang > IronPython), and CPython-missing errors surface clearly.__batchexec__,__logfile__, and__models__into builtins and by capturing log output via runtimeScriptIO(with optional output suppression).EngineConfigsin the journal (defaultfull_frame) and normalize runtime config inputs (env dict seeding, log path, search paths/args defaults).#! python3, one IronPython) that print builtins and write to the runner log; confirmed engine selection and log capture.Testing
pyrevit runwith a local CPython hashbang smoke script (prints builtins, writes to log) - passpyrevit runwith a local IronPython smoke script (prints builtins, writes to log) - pass (stderr not captured in IPY)dotnet test dev/pyRevitLabs/pyRevitLabs.UnitTests/pyRevitLabs.UnitTests.csproj -c Debug- passdotnet test dev/pyRevitLoader/pyRevitExtensionParserTester/pyRevitExtensionParserTest.csproj -c Debug --logger "trx;LogFileName=pyrevitextensionparser-tests.trx"- fail (pre-existing on develop):TestPanelButtonWithMultilingualBundle(dev/pyRevitLoader/pyRevitExtensionParserTester/PanelButtonBundleTests.cs:292)python -m unittest discover -s pyrevitlib/pyrevit/unittests- 0 testspy -3.12 -m pytest dev/modules/pyRevitLabs.Python.Net/tests- fail (pythonnet loader init)Notes / follow-ups
pyrevit run --models --revit=2025can throw when the build string is missing from the cached host map (pyrevit-hosts.json), even thoughBasicFileInforeports Format 2025. Consider falling back to Format/product-version or refreshing the host map before failing when--revitis explicit.develop):TestPanelButtonWithMultilingualBundlefails indev/pyRevitLoader/pyRevitExtensionParserTester/PanelButtonBundleTests.csbecauseDebugDialogConfigreportsHasLocalizedContent == falseand missing localized titles/tooltips foren_us/fr/de. Needs separate investigation.