| 
									
										
										
										
											2023-05-04 15:49:26 +02:00
										 |  |  | # SPDX-FileCopyrightText: 2023-present deepset <info@deepset.ai> | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # SPDX-License-Identifier: Apache-2.0 | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2023-02-23 20:42:42 +01:00
										 |  |  | # https://pylint.pycqa.org/en/latest/development_guide/how_tos/custom_checkers.html | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from typing import TYPE_CHECKING, Optional, List, Any | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from astroid import nodes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from pylint.checkers import BaseChecker | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if TYPE_CHECKING: | 
					
						
							|  |  |  |     from pylint.lint import PyLinter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DirectLoggingChecker(BaseChecker): | 
					
						
							|  |  |  |     name = "no-direct-logging" | 
					
						
							|  |  |  |     msgs = { | 
					
						
							|  |  |  |         "W9001": ( | 
					
						
							|  |  |  |             "Use a logger object instead of a direct logging function like 'logging.%s()'", | 
					
						
							|  |  |  |             "no-direct-logging", | 
					
						
							|  |  |  |             "Do not use direct calls to logging functions like logging.info(), " | 
					
						
							|  |  |  |             "rather create a logger object with getLogger and use it instead. " | 
					
						
							|  |  |  |             "See https://github.com/deepset-ai/haystack/issues/4202.", | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, linter: Optional["PyLinter"] = None) -> None: | 
					
						
							|  |  |  |         super().__init__(linter) | 
					
						
							|  |  |  |         self._function_stack: List[Any] = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def visit_functiondef(self, node: nodes.FunctionDef) -> None: | 
					
						
							|  |  |  |         self._function_stack.append([]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def leave_functiondef(self, node: nodes.FunctionDef) -> None: | 
					
						
							|  |  |  |         self._function_stack.pop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def visit_call(self, node: nodes.Call) -> None: | 
					
						
							| 
									
										
										
										
											2023-09-20 08:32:44 +02:00
										 |  |  |         if ( | 
					
						
							|  |  |  |             isinstance(node.func, nodes.Attribute) | 
					
						
							|  |  |  |             and isinstance(node.func.expr, nodes.Name) | 
					
						
							|  |  |  |             and node.func.expr.name == "logging" | 
					
						
							|  |  |  |             and node.func.attrname in ["debug", "info", "warning", "error", "critical", "exception"] | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             self.add_message("no-direct-logging", args=node.func.attrname, node=node) | 
					
						
							| 
									
										
										
										
											2023-02-23 20:42:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class NoLoggingConfigurationChecker(BaseChecker): | 
					
						
							|  |  |  |     name = "no-logging-basicconfig" | 
					
						
							|  |  |  |     msgs = { | 
					
						
							|  |  |  |         "W9002": ( | 
					
						
							|  |  |  |             "Do not use 'logging.basicConfig' in Haystack code: Haystack should not configure any loggers.", | 
					
						
							|  |  |  |             "no-logging-basicconfig", | 
					
						
							|  |  |  |             "Do not configure the logger explicitly, because this would be problematic for users. " | 
					
						
							|  |  |  |             "Always configure the loggers only in scripts that use Haystack, like tutorials, rather than Haystack itself.", | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, linter: Optional["PyLinter"] = None) -> None: | 
					
						
							|  |  |  |         super().__init__(linter) | 
					
						
							|  |  |  |         self._function_stack: List[Any] = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def visit_functiondef(self, node: nodes.FunctionDef) -> None: | 
					
						
							|  |  |  |         self._function_stack.append([]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def leave_functiondef(self, node: nodes.FunctionDef) -> None: | 
					
						
							|  |  |  |         self._function_stack.pop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def visit_call(self, node: nodes.Call) -> None: | 
					
						
							| 
									
										
										
										
											2023-09-20 08:32:44 +02:00
										 |  |  |         if ( | 
					
						
							|  |  |  |             isinstance(node.func, nodes.Attribute) | 
					
						
							|  |  |  |             and isinstance(node.func.expr, nodes.Name) | 
					
						
							|  |  |  |             and node.func.expr.name == "logging" | 
					
						
							|  |  |  |             and node.func.attrname in ["basicConfig"] | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             self.add_message("no-logging-basicconfig", node=node) | 
					
						
							| 
									
										
										
										
											2023-02-23 20:42:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def register(linter: "PyLinter") -> None: | 
					
						
							|  |  |  |     """This required method auto registers the checker during initialization.
 | 
					
						
							|  |  |  |     :param linter: The linter to register the checker to. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     linter.register_checker(DirectLoggingChecker(linter)) | 
					
						
							|  |  |  |     linter.register_checker(NoLoggingConfigurationChecker(linter)) |