Skip to content

Commit f481529

Browse files
github-actions[bot]Copilotdbrattliclaude
authored
[Repo Assist] [Python] Fix CLIEvent property causing unimplementable abstract Protocol member in object expressions (#4492)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Dag Brattli <dag@brattli.net> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 11579ec commit f481529

4 files changed

Lines changed: 43 additions & 17 deletions

File tree

src/Fable.Cli/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
### Fixed
11+
12+
* [Python] Fix object expressions implementing interfaces with `[<CLIEvent>]` members no longer produce unimplementable abstract Protocol members (fixes #3039)
13+
1014
## 5.0.0-rc.7 - 2026-04-07
1115

1216
### Added

src/Fable.Compiler/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
### Fixed
11+
12+
* [Python] Fix object expressions implementing interfaces with `[<CLIEvent>]` members no longer produce unimplementable abstract Protocol members (fixes #3039)
13+
1014
## 5.0.0-rc.13 - 2026-04-07
1115

1216
### Added

src/Fable.Transforms/Python/Fable2Python.Transforms.fs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4428,6 +4428,24 @@ let transformInterface (com: IPythonCompiler) ctx (classEnt: Fable.Entity) (_cla
44284428
|> List.filter (fun memb -> gr.Length = 1 || (memb.IsGetter || memb.IsSetter))
44294429
)
44304430

4431+
// [<CLIEvent>] properties are represented in FCS as both an event property getter (e.g.
4432+
// "Event" with CompiledName "get_Event") and add_/remove_ accessor methods. Object
4433+
// expressions only implement the add_/remove_ methods, so we must exclude the event
4434+
// property getter from the Protocol to avoid an unimplementable abstract member.
4435+
let eventPropertyNames =
4436+
members
4437+
|> List.choose (fun m ->
4438+
if m.CompiledName.StartsWith("add_", System.StringComparison.Ordinal) then
4439+
Some(m.CompiledName.Substring(4))
4440+
else
4441+
None
4442+
)
4443+
|> Set.ofList
4444+
4445+
let members =
4446+
members
4447+
|> List.filter (fun m -> not (eventPropertyNames.Contains(m.DisplayName)))
4448+
44314449
let classMembers =
44324450
[
44334451
for memb in members do

tests/Python/TestEvent.fs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -225,23 +225,23 @@ let ``test Classes can trigger CLI events on interfaces`` () =
225225
equal 5 result
226226
equal (box classWithEvent) sender
227227

228-
// [<Fact>]
229-
// let ``test Generic interface expression can have CLI events`` () =
230-
// let mutable actualSender = ""
231-
// let mutable result = false
232-
// let event = Event<_,_>()
233-
// let ifaceWIthEvent =
234-
// { new InterfaceWithCLIEvent<_> with
235-
// [<CLIEvent>]
236-
// member _.Event = event.Publish }
237-
// ifaceWIthEvent.Event.AddHandler(fun sender arg ->
238-
// actualSender <- string sender
239-
// result <- arg)
240-
// let expectedSender = "SENDER"
241-
// let expectedResult = true
242-
// event.Trigger(expectedSender, expectedResult)
243-
// equal expectedSender actualSender
244-
// equal expectedResult result
228+
[<Fact>]
229+
let ``test Generic interface expression can have CLI events`` () = // See #3039
230+
let mutable actualSender = ""
231+
let mutable result = false
232+
let event = Event<_,_>()
233+
let ifaceWIthEvent =
234+
{ new InterfaceWithCLIEvent<_> with
235+
[<CLIEvent>]
236+
member _.Event = event.Publish }
237+
ifaceWIthEvent.Event.AddHandler(fun sender arg ->
238+
actualSender <- string sender
239+
result <- arg)
240+
let expectedSender = "SENDER"
241+
let expectedResult = true
242+
event.Trigger(expectedSender, expectedResult)
243+
equal expectedSender actualSender
244+
equal expectedResult result
245245

246246
[<Fact>]
247247
let ``test Events are unsubscribed correctly`` () = // See #609

0 commit comments

Comments
 (0)