2121
2222class Plugin (metaclass = ABCMeta ):
2323 """
24- Abstract Base class for plugins.
25- For internal use only.
24+ Abstract Base class for plugins. Provides a framework for defining and running
25+ plugins within a specified configuration.
26+
27+ Attributes:
28+ config (PythonConfig): Configuration for the plugin.
29+ kwargs: Additional keyword arguments.
2630 """
2731
2832 def __init__ (
@@ -40,6 +44,12 @@ def __init__(
4044
4145 @property
4246 def name (self ):
47+ """
48+ Get the name of the plugin.
49+
50+ Returns:
51+ str: The name of the plugin.
52+ """
4353 return self ._config .name
4454
4555 @classmethod
@@ -50,6 +60,12 @@ def python_base_path(cls) -> PosixPath:
5060
5161 @classmethod
5262 def all_subclasses (cls ):
63+ """
64+ Retrieve all subclasses of the plugin class.
65+
66+ Returns:
67+ list: Sorted list of plugin subclasses.
68+ """
5369 posix_dir = PosixPath (str (cls .python_base_path ).replace ("." , "/" ))
5470 for plugin in posix_dir .rglob ("*.py" ):
5571 if plugin .stem == "__init__" :
@@ -65,30 +81,72 @@ def all_subclasses(cls):
6581
6682 @cached_property
6783 def _job (self ) -> "Job" :
84+ """
85+ Get the job associated with the plugin.
86+
87+ Returns:
88+ Job: The job instance.
89+ """
6890 return Job .objects .get (pk = self .job_id )
6991
7092 @property
7193 def job_id (self ) -> int :
94+ """
95+ Get the job ID.
96+
97+ Returns:
98+ int: The job ID.
99+ """
72100 return self ._job_id
73101
74102 @job_id .setter
75103 def job_id (self , value ):
104+ """
105+ Set the job ID.
106+
107+ Args:
108+ value (int): The job ID.
109+ """
76110 self ._job_id = value
77111
78112 @cached_property
79113 def _user (self ):
114+ """
115+ Get the user associated with the job.
116+
117+ Returns:
118+ User: The user instance.
119+ """
80120 return self ._job .user
81121
82122 def __repr__ (self ):
123+ """
124+ Get the string representation of the plugin.
125+
126+ Returns:
127+ str: The string representation of the plugin.
128+ """
83129 return str (self )
84130
85131 def __str__ (self ):
132+ """
133+ Get the string representation of the plugin.
134+
135+ Returns:
136+ str: The string representation of the plugin.
137+ """
86138 try :
87139 return f"({ self .__class__ .__name__ } , job: #{ self .job_id } )"
88140 except AttributeError :
89141 return f"{ self .__class__ .__name__ } "
90142
91143 def config (self , runtime_configuration : typing .Dict ):
144+ """
145+ Configure the plugin with runtime parameters.
146+
147+ Args:
148+ runtime_configuration (dict): Runtime configuration parameters.
149+ """
92150 self .__parameters = self ._config .read_configured_params (
93151 self ._user , runtime_configuration
94152 )
@@ -104,25 +162,33 @@ def config(self, runtime_configuration: typing.Dict):
104162
105163 def before_run (self ):
106164 """
107- function called directly before run function.
165+ Function called directly before the run function.
108166 """
109167
110168 @abstractmethod
111169 def run (self ) -> dict :
112170 """
113- Called from *start* fn and wrapped in a try-catch block.
114- Should be overwritten in child class
115- :returns report
171+ Called from *start* function and wrapped in a try-catch block.
172+ Should be overwritten in child class.
173+
174+ Returns:
175+ dict: Report generated by the plugin.
116176 """
117177
118178 def after_run (self ):
119179 """
120- function called after run function.
180+ Function called after the run function.
121181 """
122182 self .report .end_time = timezone .now ()
123183 self .report .save ()
124184
125185 def after_run_success (self , content : typing .Any ):
186+ """
187+ Handle the successful completion of the run function.
188+
189+ Args:
190+ content (Any): Content generated by the plugin.
191+ """
126192 # avoiding JSON serialization errors for types: File and bytes
127193 report_content = content
128194 if isinstance (report_content , typing .List ):
@@ -140,6 +206,12 @@ def after_run_success(self, content: typing.Any):
140206 self .report .save (update_fields = ["status" , "report" ])
141207
142208 def log_error (self , e ):
209+ """
210+ Log an error encountered during the run function.
211+
212+ Args:
213+ e (Exception): The exception to log.
214+ """
143215 if isinstance (
144216 e , (* self .get_exceptions_to_catch (), SoftTimeLimitExceeded , HTTPError )
145217 ):
@@ -151,6 +223,12 @@ def log_error(self, e):
151223 logger .exception (error_message )
152224
153225 def after_run_failed (self , e : Exception ):
226+ """
227+ Handle the failure of the run function.
228+
229+ Args:
230+ e (Exception): The exception that caused the failure.
231+ """
154232 self .report .errors .append (str (e ))
155233 self .report .status = self .report .Status .FAILED
156234 self .report .save (update_fields = ["status" , "errors" ])
@@ -246,6 +324,12 @@ def _monkeypatch(cls, patches: list = None) -> None:
246324 @classmethod
247325 @property
248326 def python_module (cls ) -> PythonModule :
327+ """
328+ Get the Python module associated with the plugin.
329+
330+ Returns:
331+ PythonModule: The Python module instance.
332+ """
249333 valid_module = cls .__module__ .replace (str (cls .python_base_path ), "" )
250334 # remove the starting dot
251335 valid_module = valid_module [1 :]
@@ -255,9 +339,24 @@ def python_module(cls) -> PythonModule:
255339
256340 @classmethod
257341 def update (cls ) -> bool :
342+ """
343+ Update the plugin. Must be implemented by subclasses.
344+
345+ Returns:
346+ bool: Whether the update was successful.
347+ """
258348 raise NotImplementedError ("No update implemented" )
259349
260350 def _get_health_check_url (self , user : User = None ) -> typing .Optional [str ]:
351+ """
352+ Get the URL for performing a health check.
353+
354+ Args:
355+ user (User): The user instance.
356+
357+ Returns:
358+ typing.Optional[str]: The health check URL.
359+ """
261360 params = (
262361 self ._config .parameters .annotate_configured (self ._config , user )
263362 .annotate_value_for_user (self ._config , user )
@@ -274,6 +373,15 @@ def _get_health_check_url(self, user: User = None) -> typing.Optional[str]:
274373 return None
275374
276375 def health_check (self , user : User = None ) -> bool :
376+ """
377+ Perform a health check for the plugin.
378+
379+ Args:
380+ user (User): The user instance.
381+
382+ Returns:
383+ bool: Whether the health check was successful.
384+ """
277385 url = self ._get_health_check_url (user )
278386 if url and url .startswith ("http" ):
279387 if settings .STAGE_CI or settings .MOCK_CONNECTIONS :
@@ -296,6 +404,9 @@ def health_check(self, user: User = None) -> bool:
296404 raise NotImplementedError ()
297405
298406 def disable_for_rate_limit (self ):
407+ """
408+ Disable the plugin due to rate limiting.
409+ """
299410 logger .info (f"Trying to disable for rate limit { self } " )
300411 if self ._user .has_membership ():
301412 org_configuration = self ._config .get_or_create_org_configuration (
0 commit comments