Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@


exclude: \.(csv|sql)$|devcontainer\.json
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
hooks:
# - id: check-added-large-files
- id: check-case-conflict
- id: check-json
- id: check-merge-conflict
- id: check-yaml
args: [--unsafe]
- id: end-of-file-fixer
exclude: "__snapshots__/"
- id: fix-encoding-pragma
args: [--remove]
- id: mixed-line-ending
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
exclude: "__snapshots__/"

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.4.9
hooks:
# Run the linter.
- id: ruff
args: [--fix]
# Run the formatter.
- id: ruff-format

- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.8.0"
hooks:
- id: mypy
exclude: migrations/|commands/|scripts/|sandbox/|samples|sdk
additional_dependencies:
- "pygithub"
- "pytest"
- "syrupy"
- "typer"
- "jinja2"
- "gitpython"
- "types-PyYAML"
- "devtools"
args:
[
--pretty,
--show-error-codes,
--implicit-optional,
--follow-imports=silent,
--warn-redundant-casts,
--warn-unused-ignores,
--disallow-any-generics,
--check-untyped-defs,
--no-implicit-reexport,
--disallow-untyped-defs,
]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# auto-detect-exceptions
# auto-detect-exceptions
448 changes: 448 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[project]
name = "auto-detect-exceptions"
version = "0.1.0"
description = ""
authors = [
{ name = "lucemia", email = "[email protected]" },
]
readme = "README.md"

[tool.poetry]
packages = [
{ include = "auto_detect_exceptions", from = "src" }
]

[project.scripts]
detect1 = "auto_detect_exceptions.cli:main"

[tool.poetry.dependencies]
python = "^3.10"
libcst = "^1.6.0"
black = "^25.1.0"


[tool.poetry.group.dev.dependencies]
pytest = "^8.2.2"
pre-commit = "^3.7.1"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
8 changes: 8 additions & 0 deletions samples/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
def ze():
"""
Raises:
Exception: Description of when this error is raised.
ValueError: Description of when this error is raised.
"""
raise Exception("ze")
raise ValueError("ze")
Empty file.
61 changes: 61 additions & 0 deletions src/auto_detect_exceptions/ast_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import ast
from typing import Dict, Optional


def parse_python_code(source_code: str) -> ast.Module:
"""
Parses Python source code into an Abstract Syntax Tree (AST).

Args:
source_code (str): The Python source code as a string.

Returns:
ast.Module: The root AST node of the parsed code.
"""
return ast.parse(source_code)


def extract_functions(tree: ast.Module) -> Dict[str, ast.FunctionDef]:
"""
Extracts all function definitions from an AST tree.

Args:
tree (ast.Module): The AST representation of the code.

Returns:
Dict[str, ast.FunctionDef]: A dictionary mapping function names to their AST nodes.
"""
functions = {}
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef): # Include only regular functions
functions[node.name] = node
return functions


def get_docstring(node: ast.FunctionDef) -> Optional[str]:
"""
Retrieves the docstring from a function node.

Args:
node (ast.FunctionDef): The AST node representing a function.

Returns:
Optional[str]: The function's docstring if present, otherwise None.
"""
return ast.get_docstring(node)


def has_exceptions_section(docstring: Optional[str]) -> bool:
"""
Checks if a docstring contains an 'Exceptions' or 'Raises' section.

Args:
docstring (Optional[str]): The docstring text.

Returns:
bool: True if the docstring contains an exceptions section, False otherwise.
"""
if docstring is None:
return False
docstring_lower = docstring.lower()
return "raises:" in docstring_lower or "exceptions:" in docstring_lower
Loading