As I can´t get this to work in the lib file I tried to reload in the hook file directly, and have a guess, also with no success:
IronPython Traceback:
Traceback (most recent call last):
File "C:\connect.extension\hooks\connect_doc-created.py", line 23, in <module>
File "C:\Users\nyk060\AppData\Roaming\pyRevit-Master\pyrevitlib\pyrevit\loader\sessionmgr.py", line 327, in reload_pyrevit
File "C:\Users\nyk060\AppData\Roaming\pyRevit-Master\pyrevitlib\pyrevit\loader\sessionmgr.py", line 288, in load_session
File "C:\Users\nyk060\AppData\Roaming\pyRevit-Master\pyrevitlib\pyrevit\loader\sessionmgr.py", line 222, in _new_session
File "C:\Users\nyk060\AppData\Roaming\pyRevit-Master\pyrevitlib\pyrevit\loader\sessionmgr.py", line 604, in execute_extension_startup_script
SystemError: Object reference not set to an instance of an object.
# -*- coding=utf-8 -*-
#pylint: disable=import-error,invalid-name,broad-except
import connect
from pyrevit import EXEC_PARAMS
from pyrevit import script
from pyrevit.loader import sessionmgr
from pyrevit.loader import sessioninfo
from Autodesk.Revit.UI import TaskDialog
doc = EXEC_PARAMS.event_args.Document
app = __revit__
if not doc.IsFamilyDocument:
connected = connect.connect()
if connected:
logger = script.get_logger()
results = script.get_results()
# re-load pyrevit session.
logger.info('Reloading....')
sessionmgr.reload_pyrevit()
results.newsession = sessioninfo.get_session_uuid()
taskdialog.show("AFRY","Success: The network drive X: has been connected and the AFRY toolbar has been loaded.")
I can successful reload the network drives on startup now.
But it seems there is no way to reload pyRevit then, because I can not reload on startup and I can not reload within a hook script. So how can I get my desperately desired extension loading?
Built an Eventhandler that starts the reload as soon as revit is idle, i run it on startup.py
While it works as expected, the start of the reloading triggers this error:
IronPython Traceback:
Traceback (most recent call last):
File "C:\connect.extension\startup.py", line 5, in <module>
File "C:\connect.extension\lib\reload\__init__.py", line 68, in reload
File "C:\connect.extension\lib\reload\__init__.py", line 36, in __init__
File "C:\connect.extension\lib\reload\__init__.py", line 14, in __init__
File "C:\connect.extension\lib\reload\__init__.py", line 17, in _register_event
StandardError: Exception has been thrown by the target of an invocation.
Script Executor Traceback:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Autodesk.Revit.Exceptions.InvalidOperationException: Can not subscribe to an event during execution of that event!
at Autodesk.Revit.UI.UIApplication.add_Idling(EventHandler`1 handler)
--- End of inner exception stack trace ---
Spent the whole day with trying to get rid of this error and now I´m really out of ideas, any suggestions what I can try?
import pyevent
from Autodesk.Revit.UI import UIApplication
from Autodesk.Revit.UI.Events import IdlingEventArgs
from Autodesk.Revit.UI import (TaskDialog, TaskDialogCommonButtons, TaskDialogResult, TaskDialogIcon)
def reload():
class RevitIdlingEventHandler(object):
"""
This class handles the Idling event of the Revit application.
"""
def __init__(self, ui_app):
self.ui_app = ui_app # Store it as an instance variable
self.idling_event, self.trigger_idling_event = pyevent.make_event()
self._register_event()
def _register_event(self):
self.ui_app.Idling += self._on_idling
def _unregister_event(self):
self.ui_app.Idling -= self._on_idling
def _on_idling(self, sender, args):
# First, unregister the event to prevent it from being triggered again
self._unregister_event()
# Now, execute other tasks
self.trigger_idling_event(self, args)
class RevitIdleMonitor(object):
"""
This class creates an instance of the RevitIdlingEventHandler and provides a means
to register and unregister this handler with the Revit application.
"""
def __init__(self, ui_app):
self.idling_handler = RevitIdlingEventHandler(ui_app)
self.on_idle = self.idling_handler.idling_event
def register_handler(self):
self.idling_handler._register_event()
def unregister_handler(self):
self.idling_handler._unregister_event()
def on_revit_idle(sender, args):
"""
Function to be executed when Revit goes idle.
"""
#pylint: disable=import-error,invalid-name,broad-except
from pyrevit import EXEC_PARAMS
from pyrevit import script
from pyrevit import forms
from pyrevit.loader import sessionmgr
from pyrevit.loader import sessioninfo
logger = script.get_logger()
results = script.get_results()
# re-load pyrevit session.
logger.info('Reloading....')
sessionmgr.reload_pyrevit()
results.newsession = sessioninfo.get_session_uuid()
# Initialize the idle monitor and attach the on_revit_idle function to the idling event.
idle_monitor = RevitIdleMonitor(__revit__)
idle_monitor.on_idle += on_revit_idle
I think this is not possible without admin rights? If it is, then thats maybe a project for the future, thanks for pointing that out, it´s interresting to see what kind of different workflows are possible.
But for now I really really would like to just get rid of my error!
New day, new Event (ApplicationInitialized ), new EventHandler, but still the same error
The code works 100% fine. And the Event I´m using should make sure everything is initialized, so why will a reload trigger that error?
def reload():
import Autodesk
import clr
clr.AddReference('System')
clr.AddReference('RevitAPIUI')
from Autodesk.Revit import DB
from Autodesk.Revit.UI import (TaskDialog, TaskDialogCommonButtons, TaskDialogResult, TaskDialogCommandLinkId, TaskDialogIcon)
def user_message(line1,line2):
taskDialog = TaskDialog("AFRY")
taskDialog.MainInstruction = line1
taskDialog.MainContent = line2
taskDialog.TitleAutoPrefix = False
taskDialog.MainIcon = TaskDialogIcon.TaskDialogIconInformation
taskDialog.CommonButtons = TaskDialogCommonButtons.Close #| TaskDialogCommonButtons.Yes
#taskDialog.FooterText = "Help"
return taskDialog.Show()
def reload_pyrevit():
#pylint: disable=import-error,invalid-name,broad-except
from pyrevit import EXEC_PARAMS
from pyrevit import script
from pyrevit import forms
from pyrevit.loader import sessionmgr
from pyrevit.loader import sessioninfo
logger = script.get_logger()
results = script.get_results()
# re-load pyrevit session.
logger.info('Reloading....')
try:
sessionmgr.reload_pyrevit()
user_message("Success", "pyRevit has been reloaded.")
except Exception as e:
user_message("Error", str(e))
def app_initialized_handler(sender, args):
reload_pyrevit()
# Register the event handler during a separate phase of your script
def register_event_handler():
controlled_app = __revit__.Application
controlled_app.ApplicationInitialized += app_initialized_handler
# Call the function to register the event handler
register_event_handler()
After 50 attempts of trying to check if an event has occured afterwards, I now start to understand a little what going on.
Setting and checking a variable does not work:
# Flag to check if event was triggered
event_triggered = False
def event_handler_function(sender, args):
global event_triggered
print "triggered"
event_triggered = True
__revit__.Idling += EventHandler[IdlingEventArgs](event_handler_function)
# Later in your code when you want to check if the event has been triggered
if event_triggered:
print("The event has been triggered!")
else:
print("The event has not been triggered yet.")
This is because the script just runs to the end and is over long time before the event happens.
So I added a while loop, can`t tell why that also failed:
event_triggered = False
def event_handler_function(sender, args):
global event_triggered
print "triggered"
event_triggered = True
__revit__.Idling -= EventHandler[IdlingEventArgs](event_handler_function)
__revit__.Idling += EventHandler[IdlingEventArgs](event_handler_function)
timeout = 10 # in seconds
start_time = time.time()
while not event_triggered:
if time.time() - start_time > timeout:
print("Timeout waiting for the event to trigger.")
break
time.sleep(0.1) # sleep for 100 milliseconds
if event_triggered:
print("The event has been triggered!")
else:
print("The event has not been triggered.")
Threading Event also failed:
import time
import threading
event_triggered = threading.Event()
def event_handler_function(sender, args):
print "triggered"
event_triggered.set()
__revit__.Idling -= EventHandler[IdlingEventArgs](event_handler_function)
__revit__.Idling += EventHandler[IdlingEventArgs](event_handler_function)
timeout = 10 # in seconds
# The wait method will block until the event is set or the timeout expires
event_triggered.wait(timeout)
if event_triggered.is_set():
print("The event has been triggered!")
else:
print("The event has not been triggered or timed out.")
Whatever I do the variable always tells me the the event handler did not run.
So even my idling event gets triggered to infinity, there is no way to verify that it has been running:
OK, I give up the event handler, turns out they get triggered after all my code has finished. I didnt even work to write/read to a file to check if an event has ocured.
Turns out in the startup.py this simple approach works:
import connect
import reload
connected = connect.connect()
if connected:
reload.reload()
But again with errors
**ERROR** [pyrevit.loader.uimaker] UI error: Can not create tab: The tab with the input name exists already.
Parameter name: tabName
**ERROR** [pyrevit.loader.uimaker] UI error: Can not create tab: The tab with the input name exists already.
Parameter name: tabName
**ERROR** [pyrevit.loader.uimaker] UI error: Can not create tab: The tab with the input name exists already.
Parameter name: tabName
But for some reason the errors are gone anyway, don´t ask me why.
This was a really hard piece, need a few days off now
#-*- coding: utf-8 -*-
import clr
clr.AddReference('System')
clr.AddReference('RevitAPIUI')
from System.IO import DriveInfo
from System.Diagnostics import Process
clr.AddReference('System.Management')
import System.Management
from Autodesk.Revit.UI import (
TaskDialog,
TaskDialogCommonButtons,
TaskDialogIcon
)
def is_drive_connected(drive_letter):
# Checks if a given drive letter corresponds to a connected network drive.
drives = DriveInfo.GetDrives()
connected_drives = [drive.Name[0].upper() for drive in drives if drive.DriveType.ToString() == "Network"]
return drive_letter.upper().strip(":") in connected_drives
def get_all_network_paths():
# Retrieves all network paths.
searcher = System.Management.ManagementObjectSearcher("SELECT * FROM Win32_NetworkConnection")
network_paths = {}
for item in searcher.Get():
local_name = item["LocalName"]
if local_name:
remote_name = item["RemoteName"]
network_paths[local_name.lower()] = remote_name
return network_paths
def user_message(line1, line2):
# Displays a message to the user.
taskDialog = TaskDialog("")
taskDialog.MainInstruction = line1
taskDialog.MainContent = line2
taskDialog.TitleAutoPrefix = False
taskDialog.MainIcon = TaskDialogIcon.TaskDialogIconInformation
taskDialog.CommonButtons = TaskDialogCommonButtons.Close
return taskDialog.Show()
def connection():
# Checks connection status for a given drive.
drive_letter = "X"
all_paths = get_all_network_paths()
network_path = all_paths.get(drive_letter.lower() + ":")
return is_drive_connected(drive_letter) if network_path else False
def connect():
def connect_network_drive(drive_letter, network_path):
# Connects to a specific network drive.
TIMEOUT_IN_MS = 10000 # For example, 10 seconds
process = Process()
process.StartInfo.FileName = "net.exe"
process.StartInfo.Arguments = "use {0}: {1}".format(drive_letter, network_path)
process.StartInfo.CreateNoWindow = True
process.StartInfo.UseShellExecute = False
process.Start()
# Wait for the timeout period
process_exited = process.WaitForExit(TIMEOUT_IN_MS)
if not process_exited: # If the process didn't exit within the timeout period
process.Kill() # Forcefully terminate the process
user_message("Timeout", "DNS server not available, can´t connect to drive X.")
drive_letter = "X"
all_paths = get_all_network_paths()
network_path = all_paths.get(drive_letter.lower() + ":")
try:
connect_network_drive(drive_letter, network_path)
if is_drive_connected(drive_letter):
return True
else:
user_message("Fail", "Failed to connect to the network drive X. pyRevit could not be loaded, please reload pyRevit manually.")
return False
except Exception as e:
user_message("Error", str(e))
return False
def reload():
# Reload pyRevit.
from pyrevit.loader import sessionmgr
try:
sessionmgr.reload_pyrevit()
user_message("Success", "Network drive X has been reconnected and pyRevit has been loaded.")
except Exception as e:
user_message("Failed", str(e))
def app_initialized_handler(sender, args):
"""
This function is executed when the application is fully initialized.
It first unsubscribes itself from the ApplicationInitialized event
to avoid being executed again. Then, it tries to connect to the
network drive and, if successful, reloads the associated toolbar.
"""
# Unsubscribe from the ApplicationInitialized event to avoid
# this handler being triggered multiple times.
controlled_app.ApplicationInitialized -= app_initialized_handler
# Try to connect to the network drive and reload the toolbar if successful.
if connect():
reload()
# Check the status of the network drive connection.
is_drive_connected_status = connection()
if not is_drive_connected_status:
try:
# Subscribe to the ApplicationInitialized event.
controlled_app = __revit__.Application
controlled_app.ApplicationInitialized += app_initialized_handler
except Exception as e:
pass