Skip to content

Resolve reverse links using the forward property's path, not its Python name - #160

Merged
apdavison merged 1 commit into
HumanBrainProject:masterfrom
apdavison:fix-reverse-link-resolution
Oct 18, 2026
Merged

apdavison merged 1 commit into
HumanBrainProject:masterfrom
apdavison:fix-reverse-link-resolution

Conversation

@apdavison

Copy link
Copy Markdown
Member

Fixes #92.

Currently, resolving or counting a reverse property (e.g. license.is_applied_to.resolve(client)) sends the same filter, keyed by a single Python name, to every target class. The forward property that makes the link does not always have the same Python name in each class: it is license in DatasetVersion but licenses in ModelVersion and SoftwareVersion. For such classes query generation raises ValueError: Invalid filter, so the whole reverse property cannot be resolved. On master this affects 17 (reverse property, target class) pairs in v4 and 14 in v5.

In addition, 72 reverse properties stand for several forward properties (e.g. BehavioralProtocol.used_in covers associated_protocols, behavioral_protocols and protocols), but only the first is queried, which fails for any target class that lacks it.

This PR adds KGQuery.from_reverse_property(), which identifies the forward properties by their path (the same in every class) rather than by Python name. It builds one filter for each matching forward property in each target class. resolve() and count() use these per-class filters, and resolve() returns each node once even when it links through more than one property (as ProtocolExecution can, via both behavioral_protocols and protocols, in v5). count() counts such a node once per property, as documented in its docstring.

It also removes the reverse-KGQuery block in KGObject.__init__, which never runs: KGNode.__init__ has already set every reverse property, and it passes a callback argument that KGQuery does not accept.

Tests:

  • every reverse property in v4 and v5 gets a filter for each target class, and each filter generates a valid query
  • the license/licenses case, the v5 two-property case, and de-duplication in resolve()
  • a live test that CC-BY-4.0's is_applied_to.count() succeeds

Not covered here: reverse links whose targets are embedded classes (#82), and MRIScannerUsage, whose query generation fails for a separate reason.

…on name (#92)

Resolving or counting a reverse property sent the same filter, keyed by a single Python name, to every target class. The forward property that makes the link does not always have the same name in each class (e.g. "license" in DatasetVersion, "licenses" in ModelVersion), so query generation raised "Invalid filter" and nothing was returned. Where a reverse property stands for several forward properties, only the first was queried.

KGQuery.from_reverse_property() now builds one filter for each forward property whose path matches, in each target class, and resolve() returns each node once even if it links through more than one of them.

Also remove the reverse-KGQuery block in `KGObject.__init__`, which never ran: `KGNode.__init__` has already set every reverse property, and it passed a `callback` argument that `KGQuery` does not accept.
@apdavison
apdavison merged commit a0703b5 into HumanBrainProject:master Oct 18, 2026
6 checks passed
@apdavison apdavison added this to the 0.16 milestone Oct 18, 2026
@apdavison apdavison added the bug Something isn't working label Oct 18, 2026
@apdavison
apdavison deleted the fix-reverse-link-resolution branch October 18, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

Development

Successfully merging this pull request may close these issues.

Resolving certain reverse links is broken

1 participant