Coverage for src/lumen/cortex/contract.py: 88%

17 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-08-31 18:46 +0000

1""" 

2The Cortex contract: what a plugin may rely on, and for how long. 

3 

4Everything importable from ``lumen.cortex`` is public and covered by the 

5versioning rule below. Everything else in this package — module layout, 

6private helpers, the internals of the ports — is implementation and may change 

7in any release. 

8 

9Versioning 

10---------- 

11``CORTEX_API_VERSION`` is ``MAJOR.MINOR``: 

12 

13* **MINOR** rises for additive changes (a new hook event, a new port method, a 

14 new optional argument). Existing plugins keep working. 

15* **MAJOR** rises for a breaking change. A breaking change requires the old 

16 form to keep working, deprecated and warning, for one MAJOR release. 

17 

18A plugin may declare ``requires_cortex = "1.0"``; the loader refuses to 

19register it when the running server offers an older or a 

20different-major surface, rather than failing later at a call site. 

21""" 

22 

23from __future__ import annotations 

24 

25CORTEX_API_VERSION = "1.0" 

26 

27#: Fired once per resource that a committed write created or updated. 

28EVENT_RESOURCE_WRITTEN = "resource.written" 

29#: Fired once per resource that a committed write deleted. 

30EVENT_RESOURCE_DELETED = "resource.deleted" 

31 

32KNOWN_EVENTS = frozenset({EVENT_RESOURCE_WRITTEN, EVENT_RESOURCE_DELETED}) 

33 

34 

35class CortexError(Exception): 

36 """Base class for errors raised by the plugin host itself.""" 

37 

38 

39class PluginRegistrationError(CortexError): 

40 """A plugin could not be registered (bad declaration, name clash, version).""" 

41 

42 

43def check_version(required: str | None) -> None: 

44 """Raise :class:`PluginRegistrationError` unless this server satisfies ``required``.""" 

45 if required is None: 

46 return 

47 try: 

48 want_major, want_minor = (int(part) for part in required.split(".", 1)) 

49 have_major, have_minor = (int(part) for part in CORTEX_API_VERSION.split(".", 1)) 

50 except ValueError as exc: 

51 raise PluginRegistrationError( 

52 f"requires_cortex must look like '1.0', got {required!r}" 

53 ) from exc 

54 if want_major != have_major or want_minor > have_minor: 

55 raise PluginRegistrationError( 

56 f"Plugin requires Cortex {required}, this server offers {CORTEX_API_VERSION}" 

57 )