1+ #!/usr/bin/env python3
2+ """
3+ Workflow and Activity Registry for Cadence Python Client.
4+
5+ This module provides a registry system for managing workflows and activities,
6+ similar to the Go client's registry.go implementation.
7+ """
8+
9+ import logging
10+ from typing import Callable , Dict , Optional , Unpack , TypedDict
11+
12+
13+ logger = logging .getLogger (__name__ )
14+
15+
16+ class RegisterWorkflowOptions (TypedDict , total = False ):
17+ """Options for registering a workflow."""
18+ name : Optional [str ]
19+ alias : Optional [str ]
20+
21+
22+ class RegisterActivityOptions (TypedDict , total = False ):
23+ """Options for registering an activity."""
24+ name : Optional [str ]
25+ alias : Optional [str ]
26+
27+
28+ class Registry :
29+ """
30+ Registry for managing workflows and activities.
31+
32+ This class provides functionality to register, retrieve, and manage
33+ workflows and activities in a Cadence application.
34+ """
35+
36+ def __init__ (self ):
37+ """Initialize the registry."""
38+ self ._workflows : Dict [str , Callable ] = {}
39+ self ._activities : Dict [str , Callable ] = {}
40+ self ._workflow_aliases : Dict [str , str ] = {} # alias -> name mapping
41+ self ._activity_aliases : Dict [str , str ] = {} # alias -> name mapping
42+
43+ def workflow (
44+ self ,
45+ func : Optional [Callable ] = None ,
46+ ** kwargs : Unpack [RegisterWorkflowOptions ]
47+ ) -> Callable :
48+ """
49+ Register a workflow function.
50+
51+ This method can be used as a decorator or called directly.
52+
53+ Args:
54+ func: The workflow function to register
55+ **kwargs: Options for registration (name, alias)
56+
57+ Returns:
58+ The decorated function or the function itself
59+
60+ Raises:
61+ KeyError: If workflow name already exists
62+ """
63+ options = RegisterWorkflowOptions (** kwargs )
64+
65+ def decorator (f : Callable ) -> Callable :
66+ workflow_name = options .get ('name' ) or f .__name__
67+
68+ if workflow_name in self ._workflows :
69+ raise KeyError (f"Workflow '{ workflow_name } ' is already registered" )
70+
71+ self ._workflows [workflow_name ] = f
72+
73+ # Register alias if provided
74+ alias = options .get ('alias' )
75+ if alias :
76+ if alias in self ._workflow_aliases :
77+ raise KeyError (f"Workflow alias '{ alias } ' is already registered" )
78+ self ._workflow_aliases [alias ] = workflow_name
79+
80+ logger .info (f"Registered workflow '{ workflow_name } '" )
81+ return f
82+
83+ if func is None :
84+ return decorator
85+ return decorator (func )
86+
87+ def activity (
88+ self ,
89+ func : Optional [Callable ] = None ,
90+ ** kwargs : Unpack [RegisterActivityOptions ]
91+ ) -> Callable :
92+ """
93+ Register an activity function.
94+
95+ This method can be used as a decorator or called directly.
96+
97+ Args:
98+ func: The activity function to register
99+ **kwargs: Options for registration (name, alias)
100+
101+ Returns:
102+ The decorated function or the function itself
103+
104+ Raises:
105+ KeyError: If activity name already exists
106+ """
107+ options = RegisterActivityOptions (** kwargs )
108+
109+ def decorator (f : Callable ) -> Callable :
110+ activity_name = options .get ('name' ) or f .__name__
111+
112+ if activity_name in self ._activities :
113+ raise KeyError (f"Activity '{ activity_name } ' is already registered" )
114+
115+ self ._activities [activity_name ] = f
116+
117+ # Register alias if provided
118+ alias = options .get ('alias' )
119+ if alias :
120+ if alias in self ._activity_aliases :
121+ raise KeyError (f"Activity alias '{ alias } ' is already registered" )
122+ self ._activity_aliases [alias ] = activity_name
123+
124+ logger .info (f"Registered activity '{ activity_name } '" )
125+ return f
126+
127+ if func is None :
128+ return decorator
129+ return decorator (func )
130+
131+ def get_workflow (self , name : str ) -> Callable :
132+ """
133+ Get a registered workflow by name.
134+
135+ Args:
136+ name: Name or alias of the workflow
137+
138+ Returns:
139+ The workflow function
140+
141+ Raises:
142+ KeyError: If workflow is not found
143+ """
144+ # Check if it's an alias
145+ actual_name = self ._workflow_aliases .get (name , name )
146+
147+ if actual_name not in self ._workflows :
148+ raise KeyError (f"Workflow '{ name } ' not found in registry" )
149+
150+ return self ._workflows [actual_name ]
151+
152+ def get_activity (self , name : str ) -> Callable :
153+ """
154+ Get a registered activity by name.
155+
156+ Args:
157+ name: Name or alias of the activity
158+
159+ Returns:
160+ The activity function
161+
162+ Raises:
163+ KeyError: If activity is not found
164+ """
165+ # Check if it's an alias
166+ actual_name = self ._activity_aliases .get (name , name )
167+
168+ if actual_name not in self ._activities :
169+ raise KeyError (f"Activity '{ name } ' not found in registry" )
170+
171+ return self ._activities [actual_name ]
172+
173+
174+
0 commit comments