t-bug-catcher 0.5.4__tar.gz → 0.5.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/PKG-INFO +1 -1
  2. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/setup.cfg +1 -1
  3. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/setup.py +1 -1
  4. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/__init__.py +3 -1
  5. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/bug_catcher.py +10 -7
  6. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/bug_snag.py +0 -2
  7. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/jira.py +29 -17
  8. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/workitems.py +0 -3
  9. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher.egg-info/PKG-INFO +1 -1
  10. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher.egg-info/SOURCES.txt +0 -1
  11. t_bug_catcher-0.5.4/t_bug_catcher/validation.py +0 -123
  12. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/MANIFEST.in +0 -0
  13. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/README.rst +0 -0
  14. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/pyproject.toml +0 -0
  15. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/requirements.txt +0 -0
  16. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/config.py +0 -0
  17. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/exceptions.py +0 -0
  18. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/resources/whispers_config.yml +0 -0
  19. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/stack_saver.py +0 -0
  20. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/utils/__init__.py +0 -0
  21. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/utils/common.py +0 -0
  22. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher/utils/logger.py +0 -0
  23. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher.egg-info/dependency_links.txt +0 -0
  24. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher.egg-info/not-zip-safe +0 -0
  25. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher.egg-info/requires.txt +0 -0
  26. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/t_bug_catcher.egg-info/top_level.txt +0 -0
  27. {t_bug_catcher-0.5.4 → t_bug_catcher-0.5.6}/tests/test_t_bug_catcher.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: t_bug_catcher
3
- Version: 0.5.4
3
+ Version: 0.5.6
4
4
  Summary: Bug catcher
5
5
  Home-page: https://www.thoughtful.ai/
6
6
  Author: Thoughtful
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 0.5.4
2
+ current_version = 0.5.6
3
3
  commit = True
4
4
  tag = False
5
5
 
@@ -26,7 +26,7 @@ setup(
26
26
  packages=find_packages(include=["t_bug_catcher", "t_bug_catcher.*"]),
27
27
  test_suite="tests",
28
28
  url="https://www.thoughtful.ai/",
29
- version="0.5.4",
29
+ version="0.5.6",
30
30
  zip_safe=False,
31
31
  install_requires=install_requirements,
32
32
  include_package_data=True,
@@ -3,7 +3,7 @@
3
3
  __author__ = """Thoughtful"""
4
4
  __email__ = "support@thoughtful.ai"
5
5
  # fmt: off
6
- __version__ = '0.5.4'
6
+ __version__ = '0.5.6'
7
7
  # fmt: on
8
8
 
9
9
  from .bug_catcher import (
@@ -12,6 +12,7 @@ from .bug_catcher import (
12
12
  attach_file_to_exception,
13
13
  install_sys_hook,
14
14
  uninstall_sys_hook,
15
+ get_errors_count,
15
16
  )
16
17
 
17
18
  __all__ = [
@@ -20,4 +21,5 @@ __all__ = [
20
21
  "attach_file_to_exception",
21
22
  "install_sys_hook",
22
23
  "uninstall_sys_hook",
24
+ "get_errors_count",
23
25
  ]
@@ -12,7 +12,6 @@ from .jira import Jira
12
12
  from .stack_saver import StackSaver
13
13
  from .utils import logger
14
14
  from .utils.common import get_frames
15
- from .validation import PRE_RUN_VALIDATION
16
15
 
17
16
 
18
17
  class Configurator:
@@ -93,12 +92,17 @@ class BugCatcher:
93
92
  self.__configurator: Configurator = Configurator(self.__jira, self.__bug_snag)
94
93
  self.__sys_excepthook = None
95
94
  self.__stack_saver = StackSaver()
95
+ self.__errors_count = 0
96
96
 
97
97
  @property
98
98
  def configure(self):
99
99
  """Configures the JiraPoster and BugSnag classes."""
100
100
  return self.__configurator
101
101
 
102
+ def get_errors_count(self):
103
+ """Returns the number of exceptions reported."""
104
+ return self.__errors_count
105
+
102
106
  def report_error(
103
107
  self,
104
108
  exception: Optional[Exception] = None,
@@ -187,6 +191,8 @@ class BugCatcher:
187
191
  exc_info = f"{os.path.basename(frames[-1].filename)}:{frames[-1].name}:{frames[-1].lineno}"
188
192
  exception.handled_error = exc_info
189
193
 
194
+ self.__errors_count += 1
195
+
190
196
  def report_error_to_jira(
191
197
  self,
192
198
  exception: Optional[Exception] = None,
@@ -287,6 +293,8 @@ class BugCatcher:
287
293
  if self.__configurator.is_bugsnag_configured:
288
294
  self.__bug_snag.report_unhandled_error(exc_type, exc_value, exc_traceback)
289
295
 
296
+ self.__errors_count += 1
297
+
290
298
  def __get_sys_hook_attribute(self, attribute: str = "bug_catcher_client"):
291
299
  """Checks if the system hook is installed.
292
300
 
@@ -333,9 +341,4 @@ report_error_to_jira = __bug_catcher.report_error_to_jira
333
341
  report_error_to_bugsnag = __bug_catcher.report_error_to_bugsnag
334
342
  install_sys_hook = __bug_catcher.install_sys_hook
335
343
  uninstall_sys_hook = __bug_catcher.uninstall_sys_hook
336
-
337
- if not CONFIG.STAGE:
338
- logger.warning("Implementation Stage is not configured. Please configure it before running.")
339
- else:
340
- if CONFIG.STAGE.lower() == "delivery":
341
- pre_run_validation = PRE_RUN_VALIDATION
344
+ get_errors_count = __bug_catcher.get_errors_count
@@ -1,5 +1,4 @@
1
1
  import sys
2
- from datetime import datetime
3
2
  from typing import Optional
4
3
 
5
4
  import bugsnag
@@ -44,7 +43,6 @@ class BugSnag:
44
43
  "Content-Type": "application/json",
45
44
  "Bugsnag-Api-Key": api_key,
46
45
  "Bugsnag-Payload-Version": "4",
47
- "Bugsnag-Sent-At": f"{datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')}",
48
46
  "Bugsnag-Span-Sampling": "True",
49
47
  },
50
48
  data='{"message": "test"}',
@@ -476,11 +476,32 @@ class Jira:
476
476
  return []
477
477
  frames = get_frames(exc_traceback)
478
478
  file_name, line_no, _, _ = frames[-1]
479
- path = Path.relative_to(Path(file_name), Path.cwd())
480
- code_line = (
481
- f"{self._build_info['repository_url']}/src/{self._build_info['last_commit']}"
482
- f"/{path.as_posix()}?at={self._build_info['branch']}#lines-{line_no}"
483
- )
479
+ try:
480
+ path = Path.relative_to(Path(file_name), Path.cwd())
481
+ code_line = (
482
+ f"{self._build_info['repository_url']}/src/{self._build_info['last_commit']}"
483
+ f"/{path.as_posix()}?at={self._build_info['branch']}#lines-{line_no}"
484
+ )
485
+ payload = [
486
+ {
487
+ "type": "text",
488
+ "text": f"{str(path.as_posix())}:{line_no}",
489
+ "marks": [
490
+ {
491
+ "type": "link",
492
+ "attrs": {"href": code_line},
493
+ }
494
+ ],
495
+ },
496
+ ]
497
+ except ValueError:
498
+ payload = [
499
+ {
500
+ "type": "text",
501
+ "text": "Package error.",
502
+ },
503
+ ]
504
+
484
505
  input_datetime = datetime.strptime(self._build_info["commit_datetime"], "%Y-%m-%d %H:%M:%S").strftime(
485
506
  "%d %B %Y %I:%M:%S %p"
486
507
  )
@@ -521,17 +542,8 @@ class Jira:
521
542
  "type": "text",
522
543
  "text": " > ",
523
544
  },
524
- {
525
- "type": "text",
526
- "text": f"{str(path.as_posix())}:{line_no}",
527
- "marks": [
528
- {
529
- "type": "link",
530
- "attrs": {"href": code_line},
531
- }
532
- ],
533
- },
534
- ],
545
+ ]
546
+ + payload,
535
547
  },
536
548
  {
537
549
  "type": "paragraph",
@@ -1405,7 +1417,7 @@ class Jira:
1405
1417
  labels=["bug_catcher", "fatal_error"],
1406
1418
  priority=priority,
1407
1419
  )
1408
- if os.path.exists(stack_trace):
1420
+ if stack_trace and os.path.exists(stack_trace):
1409
1421
  os.remove(stack_trace)
1410
1422
  return response
1411
1423
  except Exception as ex:
@@ -1,5 +1,3 @@
1
- from .utils import logger
2
-
3
1
  try:
4
2
  from RPA.Robocorp.WorkItems import WorkItems
5
3
 
@@ -9,6 +7,5 @@ try:
9
7
  variables = work_item.get("variables", dict())
10
8
  metadata = work_item.get("metadata", dict())
11
9
  except (ImportError, KeyError):
12
- logger.warning("Workitems unavailable. Variables will be empty.")
13
10
  variables = {}
14
11
  metadata = {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: t_bug_catcher
3
- Version: 0.5.4
3
+ Version: 0.5.6
4
4
  Summary: Bug catcher
5
5
  Home-page: https://www.thoughtful.ai/
6
6
  Author: Thoughtful
@@ -11,7 +11,6 @@ t_bug_catcher/config.py
11
11
  t_bug_catcher/exceptions.py
12
12
  t_bug_catcher/jira.py
13
13
  t_bug_catcher/stack_saver.py
14
- t_bug_catcher/validation.py
15
14
  t_bug_catcher/workitems.py
16
15
  t_bug_catcher.egg-info/PKG-INFO
17
16
  t_bug_catcher.egg-info/SOURCES.txt
@@ -1,123 +0,0 @@
1
- import ast
2
- import logging
3
- import os
4
-
5
- from t_bug_catcher.utils.common import strip_path
6
-
7
- validation_logger = logging.getLogger("t_bug_catcher")
8
-
9
- validation_logger.setLevel(logging.DEBUG)
10
- console_handler = logging.StreamHandler()
11
- console_handler.setLevel(logging.DEBUG)
12
-
13
- formatter = logging.Formatter("%(levelname)s - %(name)s - %(message)s")
14
- validation_logger.addHandler(console_handler)
15
-
16
- EXCLUDED_DIRS = [".venv", "venv", "site-packages"]
17
-
18
-
19
- class IncorrectTryBlockVisitor(ast.NodeVisitor):
20
- """A visitor that checks for incorrect try-except blocks."""
21
-
22
- def __init__(self):
23
- """Initializes the IncorrectTryBlockVisitor class."""
24
- self.errors = {}
25
-
26
- def visit_Try(self, node):
27
- """Visits the try-except block in the AST."""
28
- message = (
29
- "Error not handled: specify the error type or re-raise exception or "
30
- "report it with `t_bug_catcher.report_error()`"
31
- )
32
- for handler in node.handlers:
33
- if isinstance(handler.type, ast.Name) and handler.type.id == "Exception":
34
- if not self._contains_raise(handler.body) and not self._contains_correct_error_handling(handler.body):
35
- self.errors[handler.lineno] = message
36
- elif handler.type is None: # 'except:' that catches everything
37
- if not any(isinstance(x, ast.Raise) for x in handler.body):
38
- self.errors[handler.lineno] = message
39
- self.generic_visit(node)
40
-
41
- @staticmethod
42
- def _contains_correct_error_handling(statements):
43
- for stmt in statements:
44
- if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
45
- func = stmt.value.func
46
- if (isinstance(func, ast.Name) and func.id == "report_error") or (
47
- isinstance(func, ast.Attribute) and func.attr == "report_error"
48
- ):
49
- return True
50
- return False
51
-
52
- @staticmethod
53
- def _contains_raise(statements):
54
- return any(isinstance(stmt, ast.Raise) for stmt in statements)
55
-
56
- def get_errors(self):
57
- """Returns the errors found in the try-except blocks."""
58
- return self.errors
59
-
60
-
61
- class BroadExceptionWarning:
62
- """A class to represent a broad exception warning."""
63
-
64
- def __init__(self, file_path: str, lineno: int, message: str, source_code: str):
65
- """Initializes the BroadExceptionWarning class."""
66
- self.lineno = lineno
67
- self.message = message
68
- self.__source_code_lines = source_code.split("\n")
69
- self.code_line = self.__source_code_lines[lineno - 1]
70
- self.code_lines = "\n".join(self.__source_code_lines[lineno - 3 : lineno + 2])
71
- self.file_path = strip_path(file_path)
72
-
73
-
74
- class PreRunValidation:
75
- """A class to perform pre-run validation checks."""
76
-
77
- def __init__(self):
78
- """Initializes the PreRunValidation class."""
79
- self.broad_exception_warnings: list[BroadExceptionWarning] = []
80
- self.analyze_project(os.getcwd())
81
- self.log_warnings()
82
-
83
- def analyze_project(self, project_dir: str):
84
- """Analyzes the project directory for broad exception warnings."""
85
- for root, dirs, files in os.walk(project_dir):
86
- dirs[:] = [d for d in dirs if d not in EXCLUDED_DIRS]
87
- for file in files:
88
- if file.endswith(".py"):
89
- file_path = os.path.join(root, file)
90
-
91
- self.check_broad_exceptions(file_path)
92
-
93
- def check_broad_exceptions(self, filename):
94
- """Checks for broad exception warnings in the specified file."""
95
- with open(filename, "r", encoding="utf8") as source:
96
- source_code = source.read()
97
- try:
98
- tree = ast.parse(source_code, filename=filename)
99
- except SyntaxError:
100
- return
101
- except Exception as ex:
102
- validation_logger.error(f"Unable to validate: {filename} - {ex}")
103
- return
104
-
105
- visitor = IncorrectTryBlockVisitor()
106
- visitor.visit(tree)
107
-
108
- for line, message in visitor.get_errors().items():
109
- be_warn = BroadExceptionWarning(filename, line, message, source_code=source_code)
110
- self.broad_exception_warnings.append(be_warn)
111
-
112
- def log_warnings(self):
113
- """Logs the broad exception warnings."""
114
- for be_warn in self.broad_exception_warnings:
115
- validation_logger.warning(f"{be_warn.file_path}:{be_warn.lineno}: {be_warn.message}")
116
-
117
- @property
118
- def errors_count(self):
119
- """Property to define the number of errors. Used for pre-commit hook."""
120
- return len(self.broad_exception_warnings)
121
-
122
-
123
- PRE_RUN_VALIDATION = PreRunValidation()
File without changes
File without changes