{# loop over all events and create types for each #}
{%- for name, event_data in events.items() -%}
class {{contract_name}}{{event_data.capitalized_name}}ContractEvent(ContractEvent):
    """ContractEvent for {{event_data.name}}."""
    # super() get_logs and create_filter methods are generic, while our version adds values & types
    # pylint: disable=arguments-differ

    # @combomethod destroys return types, so we are redefining functions as both class and instance
    # pylint: disable=function-redefined

    {# TODO: add type-hints for argument_names #}
    {# TODO: remove pylint disable when we add a type-hint for argument_names #}
    # pylint: disable=useless-parent-delegation
    def __init__(self, *argument_names: tuple[str]) -> None:
        super().__init__(*argument_names)

    {# TODO: add type-hints for argument_filters -#}
    {# TODO: add dataclass for [EventName]Data return value -#}
    def get_logs( # type: ignore
        self: "{{contract_name}}{{event_data.capitalized_name}}ContractEvent",
        argument_filters: dict[str, Any] | None = None,
        fromBlock: BlockIdentifier | None = None,
        toBlock: BlockIdentifier | None = None,
        block_hash: HexBytes | None = None,
    ) -> Iterable[EventData]:
        return cast(Iterable[EventData], super().get_logs(argument_filters=argument_filters, fromBlock=fromBlock, toBlock=toBlock, block_hash=block_hash))

    @classmethod
    def get_logs( # type: ignore
        cls: Type["{{contract_name}}{{event_data.capitalized_name}}ContractEvent"],
        argument_filters: dict[str, Any] | None = None,
        fromBlock: BlockIdentifier | None = None,
        toBlock: BlockIdentifier | None = None,
        block_hash: HexBytes | None = None,
    ) -> Iterable[EventData]:
        return cast(Iterable[EventData], super().get_logs(argument_filters=argument_filters, fromBlock=fromBlock, toBlock=toBlock, block_hash=block_hash))

    {# TODO: add type-hints for argument_filters -#}
    {# TODO: add dataclass for [EventName]Data return value -#}
    def create_filter( # type: ignore
        self: "{{contract_name}}{{event_data.capitalized_name}}ContractEvent",
        *,  # PEP 3102
        argument_filters: dict[str, Any] | None = None,
        fromBlock: BlockIdentifier | None = None,
        toBlock: BlockIdentifier = "latest",
        address: ChecksumAddress | None = None,
        topics: Sequence[Any] | None = None,
    ) -> LogFilter:
        return cast(LogFilter, super().create_filter(argument_filters=argument_filters, fromBlock=fromBlock, toBlock=toBlock, address=address, topics=topics))

    @classmethod
    def create_filter( # type: ignore
        cls: Type["{{contract_name}}{{event_data.capitalized_name}}ContractEvent"],
        *,  # PEP 3102
        argument_filters: dict[str, Any] | None = None,
        fromBlock: BlockIdentifier | None = None,
        toBlock: BlockIdentifier = "latest",
        address: ChecksumAddress | None = None,
        topics: Sequence[Any] | None = None,
    ) -> LogFilter:
        return cast(LogFilter, super().create_filter(argument_filters=argument_filters, fromBlock=fromBlock, toBlock=toBlock, address=address, topics=topics))

{% endfor %}

class {{contract_name}}ContractEvents(ContractEvents):
    """ContractEvents for the {{contract_name}} contract."""
{% for event_data in events.values() %}
    {{event_data.name}}: {{contract_name}}{{event_data.capitalized_name}}ContractEvent
{% endfor %}

    def __init__(
        self,
        abi: ABI,
        w3: "Web3",
        address: ChecksumAddress | None = None,
    ) -> None:
        super().__init__(abi, w3, address)
        {% for event_data in events.values() -%}
        self.{{event_data.name}} = cast({{contract_name}}{{event_data.capitalized_name}}ContractEvent, {{contract_name}}{{event_data.capitalized_name}}ContractEvent.factory(
            "{{event_data.name}}",
            w3=w3,
            contract_abi=abi,
            address=address,
            event_name="{{event_data.name}}"
        ))
        {% endfor %}