CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-astroid

An abstract syntax tree for Python with inference support.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

exceptions.mddocs/

Exception Handling

Comprehensive exception hierarchy for handling various error conditions during AST building, inference, and analysis operations. Understanding these exceptions is crucial for robust astroid-based tools.

Capabilities

Core Exception Classes

Base exceptions that form the foundation of astroid's error handling system.

class AstroidError(Exception):
    """Base class for all astroid exceptions."""

class AstroidBuildingError(AstroidError):
    """
    Raised when AST building fails.
    
    This includes failures to:
    - Read source files
    - Parse Python syntax
    - Import modules
    - Introspect live objects
    """

class AstroidSyntaxError(AstroidError):
    """
    Raised when Python source code contains syntax errors.
    
    Attributes:
    - lineno: Line number of syntax error
    - offset: Character offset of error
    - text: Source line containing error
    - filename: File containing the error
    """

class AstroidImportError(AstroidError):
    """
    Raised when module imports fail.
    
    This includes:
    - Module not found
    - Import permission errors
    - Circular import detection
    """

Type-Related Exceptions

Exceptions for type checking and validation errors.

class AstroidTypeError(AstroidError):
    """
    Raised when type-related operations fail.
    
    Examples:
    - Invalid type annotations
    - Unsupported type operations
    - Type constraint violations
    """

class AstroidValueError(AstroidError):
    """
    Raised when value-related operations fail.
    
    Examples:
    - Invalid constant values
    - Value conversion errors
    - Range/boundary violations
    """

class AstroidIndexError(AstroidError):
    """
    Raised when indexing operations fail.
    
    Examples:
    - List/tuple index out of range
    - Invalid sequence access
    - Dictionary key errors
    """

Inference Exception Hierarchy

Specialized exceptions for the inference system.

class InferenceError(AstroidError):
    """
    Base class for all inference failures.
    
    Inference can fail for many reasons:
    - Unresolvable names
    - Complex control flow
    - Dynamic attribute access
    - Runtime-dependent values
    """

class NameInferenceError(InferenceError):
    """
    Raised when name lookup fails during inference.
    
    Common causes:
    - Undefined variables
    - Names not in scope
    - Import resolution failures
    """

class AttributeInferenceError(InferenceError):
    """
    Raised when attribute access cannot be inferred.
    
    Common causes:
    - Dynamic attribute creation
    - Descriptor protocol complexity
    - Missing attribute definitions
    """

class InferenceOverwriteError(InferenceError):
    """
    Raised when trying to overwrite existing inference tips.
    
    This prevents accidental replacement of inference behavior
    for built-in or previously registered functions.
    """

class UseInferenceDefault(InferenceError):
    """
    Special exception to request fallback to default inference.
    
    Used in custom inference tips to delegate back to
    the standard inference mechanism.
    """

MRO and Inheritance Exceptions

Exceptions related to method resolution order and class inheritance.

class MroError(AstroidError):
    """
    Base class for Method Resolution Order errors.
    
    The MRO determines the order in which base classes
    are searched for methods and attributes.
    """

class DuplicateBasesError(MroError):
    """
    Raised when a class has duplicate base classes.
    
    Example:
    class Bad(Base, Base):  # Duplicate base
        pass
    """

class InconsistentMroError(MroError):
    """
    Raised when MRO cannot be computed consistently.
    
    This occurs with complex multiple inheritance
    hierarchies that violate Python's MRO rules.
    """

class SuperError(AstroidError):
    """
    Raised when super() calls cannot be resolved.
    
    Common causes:
    - Invalid super() usage
    - Missing method in parent classes
    - Complex MRO scenarios
    """

class SuperArgumentTypeError(SuperError):
    """
    Raised when super() arguments have wrong types.
    
    super() expects specific argument types depending
    on the calling context.
    """

Resolution and Lookup Exceptions

Exceptions for name and symbol resolution failures.

class ResolveError(AstroidError):
    """
    Raised when symbol resolution fails.
    
    This covers various resolution failures beyond
    simple name lookup.
    """

class NotFoundError(AttributeInferenceError):
    """
    Alias for AttributeInferenceError.
    
    Maintained for backward compatibility.
    """

class UnresolvableName(NameInferenceError):
    """
    Alias for NameInferenceError.
    
    Raised when a name cannot be resolved in any scope.
    """

Structural and Validation Exceptions

Exceptions for AST structure and validation issues.

class ParentMissingError(AstroidError):
    """
    Raised when a node is missing its required parent.
    
    Some operations require nodes to be properly
    connected in the AST hierarchy.
    """

class StatementMissing(AstroidError):
    """
    Raised when a required statement cannot be found.
    
    Some analyses require specific statement types
    to be present in the AST.
    """

class TooManyLevelsError(AstroidError):
    """
    Raised when relative imports go too deep.
    
    Example:
    from ....module import something  # Too many levels
    """

Special Value Exceptions

Exceptions representing special states rather than errors.

class NoDefault(AstroidError):
    """
    Raised when no default value is available.
    
    Used in contexts where a default value is requested
    but none exists (e.g., function parameters).
    """

Usage Examples

Basic Exception Handling

import astroid

# Handle building errors
try:
    module = astroid.parse("invalid syntax here $$")
except astroid.AstroidSyntaxError as e:
    print(f"Syntax error at line {e.lineno}: {e.msg}")

# Handle import errors
try:
    module = astroid.MANAGER.ast_from_module_name("nonexistent_module")
except astroid.AstroidImportError as e:
    print(f"Import failed: {e}")

# Handle inference errors
code = "x = unknown_variable"
module = astroid.parse(code)
name_node = next(module.nodes_of_class(astroid.Name))

try:
    list(name_node.infer())
except astroid.NameInferenceError as e:
    print(f"Cannot infer name: {e}")

Specific Error Handling

import astroid

# Handle attribute inference
code = '''
class MyClass:
    pass

obj = MyClass()
value = obj.nonexistent_attr
'''

module = astroid.parse(code)
attr_node = next(module.nodes_of_class(astroid.Attribute))

try:
    list(attr_node.infer())
except astroid.AttributeInferenceError as e:
    print(f"Attribute not found: {e}")
except astroid.InferenceError as e:
    print(f"General inference error: {e}")

MRO Error Handling

import astroid

# This would cause MRO issues in complex hierarchies
complex_code = '''
class A(object): pass
class B(A): pass  
class C(A): pass
class D(B, C): pass  # This is fine
'''

try:
    module = astroid.parse(complex_code)
    d_class = next(node for node in module.body if isinstance(node, astroid.ClassDef) and node.name == 'D')
    mro = d_class.mro()
    print(f"MRO: {[cls.name for cls in mro]}")
except astroid.MroError as e:
    print(f"MRO computation failed: {e}")

Safe Operations with Exception Handling

import astroid

def safe_infer_name(node):
    """Safely infer a name node."""
    try:
        return list(node.infer())
    except astroid.NameInferenceError:
        return []
    except astroid.InferenceError:
        return []

def safe_get_attribute(node, attr_name):
    """Safely get an attribute from a node."""
    try:
        return node[attr_name]
    except (KeyError, astroid.NotFoundError):
        return None

# Usage
code = "x = some_function()"
module = astroid.parse(code)

for name in module.nodes_of_class(astroid.Name):
    inferred = safe_infer_name(name)
    print(f"Name {name.name}: {len(inferred)} inferences")

Custom Exception Handling

import astroid

class CustomAnalysisError(astroid.AstroidError):
    """Custom exception for analysis tools."""
    pass

def analyze_function(func_node):
    """Analyze a function with custom error handling."""
    if not isinstance(func_node, astroid.FunctionDef):
        raise CustomAnalysisError("Expected function definition")
    
    try:
        # Analyze function body
        if not func_node.body:
            raise CustomAnalysisError("Function has no body")
        
        # Check for return statements
        returns = list(func_node.nodes_of_class(astroid.Return))
        if not returns:
            raise CustomAnalysisError("Function has no return statement")
            
    except astroid.InferenceError as e:
        raise CustomAnalysisError(f"Inference failed during analysis: {e}")

# Usage with proper error handling
code = '''
def empty_func():
    pass

def good_func():
    return 42
'''

module = astroid.parse(code)
for func in module.nodes_of_class(astroid.FunctionDef):
    try:
        analyze_function(func)
        print(f"Function {func.name} analyzed successfully")
    except CustomAnalysisError as e:
        print(f"Analysis failed for {func.name}: {e}")

Error Recovery Strategies

Graceful Degradation

import astroid

def robust_analysis(code):
    """Perform analysis with graceful error handling."""
    try:
        module = astroid.parse(code)
    except astroid.AstroidSyntaxError:
        return {"error": "syntax_error", "analysis": None}
    except astroid.AstroidError as e:
        return {"error": "parsing_error", "details": str(e)}
    
    analysis_results = {}
    
    # Safe function analysis
    functions = []
    for func in module.nodes_of_class(astroid.FunctionDef):
        func_info = {"name": func.name, "args": len(func.args.args)}
        try:
            # Try to infer return type
            returns = list(func.nodes_of_class(astroid.Return))
            if returns:
                inferred = astroid.safe_infer(returns[0].value)
                func_info["return_type"] = type(inferred).__name__ if inferred else "unknown"
        except Exception:
            func_info["return_type"] = "error"
        functions.append(func_info)
    
    analysis_results["functions"] = functions
    return {"error": None, "analysis": analysis_results}

Exception Chaining

import astroid

def detailed_error_reporting(code):
    """Provide detailed error information."""
    try:
        module = astroid.parse(code)
        return module
    except astroid.AstroidSyntaxError as e:
        # Chain with more context
        raise astroid.AstroidBuildingError(f"Syntax error in code: {e}") from e
    except Exception as e:
        # Wrap unexpected errors
        raise astroid.AstroidError(f"Unexpected error during parsing: {e}") from e

Best Practices

  1. Always handle AstroidError: Use the base class to catch all astroid-related exceptions
  2. Use safe_infer() when appropriate: Avoid exception handling for simple cases
  3. Provide fallback behavior: Have default actions when operations fail
  4. Log errors appropriately: Capture enough context for debugging
  5. Chain exceptions: Preserve original error information when re-raising

Install with Tessl CLI

npx tessl i tessl/pypi-astroid

docs

bases.md

exceptions.md

index.md

inference.md

manager.md

nodes.md

parsing.md

tile.json