-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdecorators.py
More file actions
140 lines (118 loc) · 5.71 KB
/
decorators.py
File metadata and controls
140 lines (118 loc) · 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import logging
import re
import adsk.core, adsk.fusion
from typing import ClassVar
from dataclasses import dataclass
import pprint
from functools import wraps
pp = pprint.PrettyPrinter()
logger = logging.getLogger('customCove.decorators')
logger.setLevel(logging.DEBUG)
_app = adsk.core.Application.get()
des: adsk.fusion.Design = _app.activeProduct
@dataclass
class HandlerContext():
handler: adsk.core.Base
event: adsk.core.Event
@dataclass
class HandlerCollection(HandlerContext):
'''
class to keep event handlers persistent
It's not apparent if it's possible to figure which event each handler is attached to
If you want to remove a handler selectively, you need both event and handler together.
'''
handlers: ClassVar = {}
groupId: str = 'default'
def __post_init__(self):
try:
HandlerCollection.handlers.setdefault(self.groupId, []).append(HandlerContext(self.handler, self.event))
except KeyError:
HandlerCollection.handlers[self.groupId] = [HandlerContext(self.event, self.handler)]
@classmethod
def remove(cls, groupId=None):
'''
Simple remove of group key and its values - python GC will clean up any orphaned handlers
If parameter is None then do a complete HandlerCollection reset
'''
if not groupId:
cls.handlers = None
return
try:
del cls.handlers[groupId]
except KeyError:
return
# TODO - add selective eventHandler removal - might be more trouble than it's worth
# Decorator to add eventHandler
def eventHandler(handler_cls=adsk.core.Base):
'''
handler_cls is a subClass of EventHandler base class, which is not explicitly available.
It must be user provided, and thus you can't declare the handler_cls to be of EventHandler type
EventHandler Classes such as CommandCreatedEventHandler, or MouseEventHandler etc. are provided to ensure type safety
'''
def decoratorWrapper(notify_method):
@wraps(notify_method) #spoofs wrapped method so that __name__, __doc__ (ie docstring) etc. behaves like it came from the method that is being wrapped.
def handlerWrapper( *handler_args, event=adsk.core.Event, groupId:str='default',**handler_kwargs):
'''When called returns instantiated _Handler
- assumes that the method being wrapped comes from an instantiated Class method
- inherently passes the "self" argument, if called method is in an instantiated class
- kwarg "event" throws an error if not provided '''
logger.debug(f'notify method created: {notify_method.__name__}')
try:
class _Handler(handler_cls):
def __init__(self):
self._disabled = False
self._disabledOnce = False
super().__init__()
def disableOnce(self):
self._disabledOnce = True
logger.debug(f'{notify_method.__name__} handler disabledOnce set to {self._disabledOnce}')
def enable(self):
self._disabled = False
def disable(self):
self._disabled = True
def notify( self, eventArgs):
try:
logger.debug(f'{notify_method.__name__} handler notified: {eventArgs.firingEvent.name}')
logger.debug(f'{notify_method.__name__} Once is {"Disabled".upper() if not self._disabledOnce else "Enabled".upper()} ')
if self._disabledOnce or self._disabled:
self._disabledOnce = False
logger.debug(f'{notify_method.__name__} handler disabledOnce {self._disabledOnce}')
return
notify_method(*handler_args, eventArgs) #notify_method_self and eventArgs come from the parent scope
except Exception as e:
print(e)
logger.exception(f'{eventArgs.firingEvent.name} error termination')
h = _Handler() #instantiates handler with the arguments provided by the decorator
event.add(h) #this is where the handler is added to the event
# HandlerCollection.handlers.append(HandlerCollection(h, event))
HandlerCollection(groupId=groupId, handler=h, event=event)
logger.debug(f'\n{pp.pformat(HandlerCollection.handlers)}')
# adds to class handlers list, needs to be persistent otherwise GC will remove the handler
# - deleting handlers (if necessary) will ensure that garbage collection will happen.
except Exception as e:
print(e)
logger.exception(f'handler creation error')
return h
return handlerWrapper
return decoratorWrapper
def timelineMarkers(func):
''' logs timeline marker before and after eventHandler call'''
# func = decoratorArgs[0]
@wraps(func)
def inner(*args, **kwargs):
global _app
des: adsk.fusion.Design = _app.activeProduct
logger.debug(f'Start - {func.__name__} = {des.timeline.markerPosition}')
r = func(*args, **kwargs)
logger.debug(f'End - {func.__name__} = {des.timeline.markerPosition}')
return r
return inner
# def disable_compute_event(func, event_handler):
# @wraps(func)
# def inner(*args, **kwargs):
# global _compute_handler
# event_handler.disable()
# result = func()
# event_handler.enable()
# return result
# return inner