fix: resolve pyRevit/IPY version showing Unknown in output window#3260
Conversation
SeedEnvironmentDictionary() was called before _pyRevitRoot was resolved,
so EnvDictionarySeeder.Seed() received an empty string for pyRevitRoot.
Both ReadPyRevitVersion() and ReadIPYVersion() returned "Unknown" because
the repo root path was empty, skipping the version file and IronPython.dll
lookup entirely.
Fix: eagerly resolve _pyRevitRoot from _binDir inside InitializeScriptExecutor(),
which runs immediately before SeedEnvironmentDictionary() in LoadSession().
The executing assembly lives at {pyRevitRoot}/bin/, so FindPyRevitRoot(_binDir)
walks up one level and finds pyrevitlib/. If it fails (non-standard layout),
_pyRevitRoot stays null and BuildSearchPaths() retries later with the extension
directory as an additional hint.
There was a problem hiding this comment.
PR Summary:
Fixes the output window displaying Unknown:Unknown:{revitYear} for pyRevit/IronPython version info. Root cause: SeedEnvironmentDictionary() was called before _pyRevitRoot was populated. Fix: one line added in InitializeScriptExecutor() to eagerly resolve _pyRevitRoot from _binDir, ensuring it's available when the env dictionary is seeded.
Review Summary:
The fix is correct and minimal. The ordering bug is real — _pyRevitRoot was only populated lazily inside BuildSearchPaths(), which runs well after SeedEnvironmentDictionary() had already passed an empty string to ReadPyRevitVersion and ReadIPYVersion. The new eager resolution from _binDir (assembly lives at {root}/bin/) is the right approach. The lazy fallback in BuildSearchPaths() is preserved as a safety net for non-standard installs, and the string.Empty null-coalescing in SeedEnvironmentDictionary continues to degrade gracefully. One minor observability gap: there's no debug log emitted when the eager resolution fails, making future regression on non-standard layouts hard to diagnose.
Suggestions
- Add a debug log in
InitializeScriptExecutor()after theFindPyRevitRootcall to record whether resolution succeeded or fell back to null. Apply - Add a unit/integration test that verifies
EnvDictionarySeeder.Seed()receives a non-emptypyRevitRootduring a standard session load, to prevent regression of this ordering bug. Apply
dev/pyRevitLoader/pyRevitAssemblyBuilder/UIManager/SessionManagerService.cs
Show resolved
Hide resolved
Log whether pyRevit root resolution succeeded or fell back to null, making it easier to diagnose version-display issues in the output window.
|
Implemented the suggestion to add a debug log after the Change ( _pyRevitRoot = FindPyRevitRoot(_binDir);
if (_pyRevitRoot != null)
_logger.Debug($"pyRevit root resolved to: {_pyRevitRoot}");
else
_logger.Debug("pyRevit root could not be resolved from bin directory; will retry during BuildSearchPaths");This logs the resolved path on success, or records that the fallback path (via Commit: 3669ff0 |
…yrevitlabs#3260) Add PyRevitRootResolutionTests to verify that FindPyRevitRoot correctly resolves the repo root from a bin/ subdirectory (via pyRevitfile marker or pyrevitlib/ directory), and that ReadPyRevitVersion/ReadIPYVersion return actual values (not 'Unknown') when given a valid root. End-to-end tests replicate the exact bug scenario: without early resolution of _pyRevitRoot in InitializeScriptExecutor(), the SeedEnvironmentDictionary() call receives an empty string, causing both version reads to short-circuit to 'Unknown'. Changes: - SessionManagerService.FindPyRevitRoot: private → internal (testable) - EnvDictionarySeeder.ReadPyRevitVersion: private → internal (testable) - New PyRevitRootResolutionTests.cs with 11 test cases - Updated .csproj to include the new test file
✅ Added regression tests for pyRevitRoot resolution ordering bugImplemented the review suggestion to add tests that prevent regression of the ordering bug where Changes (commit
|
| Category | Tests | What they verify |
|---|---|---|
| FindPyRevitRoot | 5 tests | Resolves root from bin/ via pyRevitfile marker; resolves via pyrevitlib/ directory; returns null for missing markers, null hint, and empty hint |
| ReadPyRevitVersion | 4 tests | Returns "Unknown" for empty/null root (the exact bug path); returns actual version from file; trims whitespace; degrades gracefully when version file is missing |
| ReadIPYVersion | 1 test | Returns "Unknown" for empty root (same bug path) |
| End-to-end | 2 tests | FindPyRevitRoot(binDir) → ReadPyRevitVersion(root) produces real version (post-fix); null root → "Unknown" (demonstrates pre-fix bug) |
Visibility changes (needed for testability via existing InternalsVisibleTo):
SessionManagerService.FindPyRevitRoot:private→internalEnvDictionarySeeder.ReadPyRevitVersion:private→internalEnvDictionarySeeder.ReadIPYVersionwas already changed tointernalin a prior commit
All tests use the existing TempFileTestBase helper for temp directory management, consistent with the rest of the test suite.
|
📦 New work-in-progress (wip) builds are available for 6.3.0.26095+0645-wip |
1 similar comment
|
📦 New work-in-progress (wip) builds are available for 6.3.0.26095+0645-wip |
|
📦 New public release are available for 6.3.0.26095+0830 |
1 similar comment
|
📦 New public release are available for 6.3.0.26095+0830 |
SeedEnvironmentDictionary() was called before _pyRevitRoot was resolved, so EnvDictionarySeeder.Seed() received an empty string for pyRevitRoot. Both ReadPyRevitVersion() and ReadIPYVersion() returned "Unknown" because the repo root path was empty, skipping the version file and IronPython.dll lookup entirely.
Fix: eagerly resolve _pyRevitRoot from _binDir inside InitializeScriptExecutor(), which runs immediately before SeedEnvironmentDictionary() in LoadSession(). The executing assembly lives at {pyRevitRoot}/bin/, so FindPyRevitRoot(_binDir) walks up one level and finds pyrevitlib/. If it fails (non-standard layout), _pyRevitRoot stays null and BuildSearchPaths() retries later with the extension directory as an additional hint.
## fix: resolve pyRevit/IPY version showing "Unknown" in output window
Problem
The ScriptConsole output window displays

Unknown:Unknown:{revitYear}for the version header instead of the actual pyRevit and IronPython versions. This affects every script run under the new C# loader.Root Cause
SeedEnvironmentDictionary()is called at the top ofLoadSession()(line 114) before_pyRevitRoothas been resolved. The field_pyRevitRootwas only populated lazily insideBuildSearchPaths(), which runs during startup script execution — well after the environment dictionary was already seeded.With
_pyRevitRoot == null,EnvDictionarySeeder.Seed()receives an empty string, and bothReadPyRevitVersion("")andReadIPYVersion("")short-circuit to"Unknown".Fix
Eagerly resolve
_pyRevitRootfrom_binDirinsideInitializeScriptExecutor(), which runs immediately beforeSeedEnvironmentDictionary(). The executing assembly lives at{pyRevitRoot}/bin/, soFindPyRevitRoot(_binDir)walks up one level and findspyrevitlib/.If resolution fails (non-standard install layout),

_pyRevitRootstaysnullandBuildSearchPaths()retries later with the extension directory as an additional hint — no worse than before.Changes
SessionManagerService.cs— 1 functional line + comments added after_binDirassignment (line 266):Testing
6.1.0.0) instead ofUnknown