Skip to content
This repository was archived by the owner on Nov 2, 2024. It is now read-only.

Commit d7ccbbc

Browse files
aryan-bhokareMichalsus
authored andcommitted
[WIP] Adding docstrings in IntelOwl Codebase. (intelowlproject#2430)
* Added docstrings in Authentication Signed-off-by: aryan <aryan1bhokare@gmail.com> * Added docstrings in api_app module. Signed-off-by: aryan <aryan1bhokare@gmail.com> * fixed linters Signed-off-by: aryan <aryan1bhokare@gmail.com> --------- Signed-off-by: aryan <aryan1bhokare@gmail.com>
1 parent 5ca21e5 commit d7ccbbc

22 files changed

+1833
-19
lines changed

.flake8

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[flake8]
2-
max-line-length = 88
2+
max-line-length = 140
33
ignore =
44
W503,
55
E231,

api_app/analyzers_manager/classes.py

+15
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,24 @@ class BaseAnalyzerMixin(Plugin, metaclass=ABCMeta):
3838
@classmethod
3939
@property
4040
def config_exception(cls):
41+
"""Returns the AnalyzerConfigurationException class."""
4142
return AnalyzerConfigurationException
4243

4344
@property
4445
def analyzer_name(self) -> str:
46+
"""Returns the name of the analyzer."""
4547
return self._config.name
4648

4749
@classmethod
4850
@property
4951
def report_model(cls):
52+
"""Returns the AnalyzerReport model."""
5053
return AnalyzerReport
5154

5255
@classmethod
5356
@property
5457
def config_model(cls):
58+
"""Returns the AnalyzerConfig model."""
5559
return AnalyzerConfig
5660

5761
def get_exceptions_to_catch(self):
@@ -98,6 +102,12 @@ def _validate_result(self, result, level=0, max_recursion=190):
98102
return result
99103

100104
def after_run_success(self, content):
105+
"""
106+
Handles actions after a successful run.
107+
108+
Args:
109+
content (any): The content to process after a successful run.
110+
"""
101111
super().after_run_success(self._validate_result(content, max_recursion=15))
102112

103113

@@ -194,6 +204,11 @@ def read_file_bytes(self) -> bytes:
194204

195205
@property
196206
def filepath(self) -> str:
207+
"""Returns the file path, retrieving the file from storage if necessary.
208+
209+
Returns:
210+
str: The file path.
211+
"""
197212
if not self.__filepath:
198213
self.__filepath = self._job.file.storage.retrieve(
199214
file=self._job.file, analyzer=self.analyzer_name

api_app/classes.py

+118-7
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@
2121

2222
class 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(

api_app/decorators.py

+16
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ def decorator_deprecated(func):
1919

2020
@functools.wraps(func)
2121
def wrapper_deprecated(*args, **kwargs):
22+
"""
23+
Wrapper function to log a warning and amend the response with
24+
deprecation headers.
25+
"""
2226
# do something before handling the request, could e.g. issue a django signal
2327
logger.warning("Deprecated endpoint %s called", func.__name__)
2428

@@ -39,6 +43,18 @@ def wrapper_deprecated(*args, **kwargs):
3943

4044

4145
def prevent_signal_recursion(func):
46+
"""
47+
Decorator to prevent recursion issues when saving Django model instances.
48+
It ensures that the decorated function does not cause a recursion loop
49+
during model save operations.
50+
51+
Args:
52+
func (function): The function to be decorated.
53+
54+
Returns:
55+
function: The wrapper function that prevents recursion.
56+
"""
57+
4258
@functools.wraps(func)
4359
def no_recursion(sender, instance=None, **kwargs):
4460
if not instance:

0 commit comments

Comments
 (0)