diff --git a/src/apify/events/_types.py b/src/apify/events/_types.py index c7ba0ada..04a58b2b 100644 --- a/src/apify/events/_types.py +++ b/src/apify/events/_types.py @@ -1,7 +1,7 @@ from __future__ import annotations from datetime import datetime -from typing import Annotated, Any, Literal +from typing import TYPE_CHECKING, Annotated, Any, Literal from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel @@ -17,12 +17,36 @@ from apify._utils import docs_group -ActorEventTypes = Literal['systemInfo', 'persistState', 'migrating', 'aborting'] -"""Event types emitted by the Apify platform during an Actor run. - -This is the Apify-specific subset of `Event`. For the full set (including framework-level events -like `SESSION_RETIRED` or `BROWSER_LAUNCHED`), use `Event` from `apify`. -""" +if TYPE_CHECKING: + ActorEventTypes = Literal['systemInfo', 'persistState', 'migrating', 'aborting'] + """Event types emitted by the Apify platform during an Actor run. + + This is the Apify-specific subset of `Event`. For the full set (including framework-level events + like `SESSION_RETIRED` or `BROWSER_LAUNCHED`), use `Event` from `apify`. + """ +else: + + class _ActorEventTypes: + """Event types emitted by the Apify platform during an Actor run. + + This is the Apify-specific subset of `Event`. For the full set (including framework-level events + like `SESSION_RETIRED` or `BROWSER_LAUNCHED`), use `Event` from `apify`. + """ + + # For type checkers `ActorEventTypes` is a `Literal[...]` alias (see the `TYPE_CHECKING` branch), so it + # keeps working in annotations. At runtime it is this object, which turns pre-v4 enum-member access + # (`ActorEventTypes.SYSTEM_INFO`) into an error pointing at `apify.Event` and the upgrade guide instead + # of a bare `AttributeError`. + def __getattr__(self, name: str) -> Any: + if name.startswith('__') and name.endswith('__'): + raise AttributeError(name) + raise AttributeError( + f'`ActorEventTypes` is no longer an enum; its members were removed in Apify SDK v4. Use ' + f'`apify.Event.{name}` for runtime event values, or the plain string. See ' + f'https://docs.apify.com/sdk/python/docs/upgrading/upgrading-to-v4' + ) + + ActorEventTypes = _ActorEventTypes() @docs_group('Event data') diff --git a/tests/unit/events/test_types.py b/tests/unit/events/test_types.py new file mode 100644 index 00000000..3b059e29 --- /dev/null +++ b/tests/unit/events/test_types.py @@ -0,0 +1,20 @@ +from __future__ import annotations + +import pytest + +from apify import ActorEventTypes + + +@pytest.mark.parametrize( + 'member', + [ + pytest.param('SYSTEM_INFO', id='system-info'), + pytest.param('PERSIST_STATE', id='persist-state'), + pytest.param('MIGRATING', id='migrating'), + pytest.param('ABORTING', id='aborting'), + ], +) +def test_actor_event_types_enum_member_access_points_to_migration(member: str) -> None: + """Pre-v4 enum-member access on `ActorEventTypes` errors with a pointer to `apify.Event`, not a bare error.""" + with pytest.raises(AttributeError, match=r'apify\.Event'): + getattr(ActorEventTypes, member)