The Class API extends the Symbol API to support methods, attributes, and inheritance hierarchies.

Methods and Method Usages

Classes provide access to their methods and method usages through an intuitive API:

# Access methods
for method in class_def.methods:
    print(f"Method: {method.name}")
    # Find all usages of this method
    for usage in method.usages:
        print(f"Used in {usage.file.name}")

# Get specific methods
init_method = class_def.constructor  # Get __init__ method
process_method = class_def.get_method("process_data")

# Filter methods
public_methods = class_def.methods(private=False)  # Exclude private methods
regular_methods = class_def.methods(magic=False)   # Exclude magic methods

Methods are typed as Function objects.

Class Attributes

Attributes can be accessed and modified easily:

# Access all attributes
for attr in class_def.attributes:
    print(f"Attribute: {attr.name}")

# Add new attributes
class_def.add_attribute_from_source("count: int = 0")

# Get specific attribute
name_attr = class_def.get_attribute("name")

# Add attribute from another class
other_class = codebase.get_class("OtherClass")
class_def.add_attribute(
    other_class.get_attribute("config"),
    include_dependencies=True  # Also adds required imports
)

Manipulating Attributes

Attributes expose their own API for modification and analysis:

# Modify attribute values and types
attr = class_def.get_attribute("count")
attr.set_value("42")  # Change value
attr.assignment.set_type_annotation("float")  # Change type
attr.assignment.type.remove()  # Remove type annotation

# Find attribute usages
for usage in attr.usages:
    print(f"Used in {usage.file.name}")

# Find local usages (within the class)
for usage in attr.local_usages:
    print(f"Used in method: {usage.parent_function.name}")

# Rename attributes (updates all references)
attr.rename("new_name")  # Also updates self.count -> self.new_name

# Remove attributes
attr.remove()  # Removes the attribute definition

# Check attribute properties
if attr.is_private:  # Starts with underscore
    print("Private attribute")
if attr.is_optional:  # Optional[Type] or Type | None
    print("Optional attribute")

# Access underlying value
if attr.value:  # The expression assigned to the attribute
    print(f"Default value: {attr.value.source}")

Attribute operations automatically handle all references, including self.attribute usages in methods and string references.

Working with Inheritance

You can navigate inheritance hierarchies with APIs including:

class_def = codebase.get_class("Cube")

# View ancestors
all_ancestors = class_def.superclasses # All classes inherited
immediate_parents = class_def.superclasses(max_depth=1)  # Direct parents only

# Inheritance-aware method lookup
method = class_def.get_method("process")  # Searches up inheritance chain
if method.parent_class != class_def:
    print(f"Method inherited from {method.parent_class.name}")

# Handle external dependencies
if class_def.is_subclass_of("Enum"):  # Works with stdlib/external classes
    print("This is an enum class")

Likewise, you can modify inheritance by accessing:

Which return lists of Name objects.

# Modify inheritance
parent_names = class_def.parent_class_names
if parent_names[0] == 'BaseClass':
    parent_names[0].edit("NewBaseClass")  # Change parent class

# Get specific parent class
parent_class = class_def.get_parent_class("BaseClass")
if parent_class:
    parent_class.edit("NewBaseClass")  # Change parent class

When working with inheritance, use max_depth to control how far up the inheritance chain to look. max_depth=0 means current class only, max_depth=None means traverse entire hierarchy.

Codegen handles both internal and external parent classes (like stdlib classes). The superclasses property follows the language’s MRO rules for method resolution.

Method Resolution Order (MRO)

Codegen follows the target language’s method resolution order (MRO) for inheritance:

# Access superclasses
for parent in class_def.superclasses:
    print(f"Parent: {parent.name}")

# Check inheritance
if class_def.is_subclass_of("BaseClass"):
    print("This is a subclass of BaseClass")

# Get all subclasses
for child in class_def.subclasses:
    print(f"Child class: {child.name}")

# Access inherited methods/attributes
all_methods = class_def.methods(max_depth=None)  # Include inherited methods
all_attrs = class_def.attributes(max_depth=None)  # Include inherited attributes

Was this page helpful?