Repository navigation
Description
Summary
Make key_source a restrict-only surface. Today key_source can be overridden freely, including in ways that redefine the parent join — the source of subtle, hard-to-diagnose bugs. In 2.4, overriding key_source raises an error, and a new property key_scope becomes the only supported way to narrow the source, by restriction.
Background
key_source defaults to the join of the tables referenced by the foreign keys in a computed/imported table's primary key (Autopopulate → Key Source Calculation). populate() iterates it, passing each key to make(key).
The default is almost always correct. The only legitimate reason to change it is to restrict it — compute a subset of the default source (e.g. a completion barrier that fires only when every member of a batch has results). Restricting keeps the parents and the grain intact; each make(key) still receives a fully-formed primary key.
Overriding key_source to redefine the parent join — dropping a parent, adding one, or rebuilding the key from an aggregate — is a different and dangerous operation: it can change or drop primary-key attributes, so make(key) receives a key missing part of its identity or carrying attributes the table's primary key doesn't declare. populate's pending-work bookkeeping (key_source minus rows already present) then breaks too: a key coarser than the primary key is marked done as soon as one row for it exists, so later members never compute. The downstream effects — partial inserts, mismatched keys, silent miscomputation — are hard to reason about, and the framework was not designed for it.
Proposal
-
Add
key_scope— a declared restriction condition applied to the defaultkey_source. It holds the restriction itself, not a query:- a string:
key_scope = 'quality = "good"' - a mapping:
key_scope = {"quality": "good"} - several conditions:
key_scope = dj.AndList('quality = "good"', 'session_date > "2026-01-01"') - a restriction by another table (a dependency visible in the source but not necessarily a formal FK edge).
The framework computes the source as
default_key_source & key_scope. The parents and grain are never changed, so everymake(key)is fully keyed. (The name replaces the earlier working namekey_source_restriction: shorter, and it doesn't point users back at the internal they should stop touching.) - a string:
-
Make
key_sourcerestrict-only. Treatkey_sourceas an internal of the auto-populate machinery. In 2.4, a subclass that overrideskey_sourceraises aDataJointErrordirecting it tokey_scope. -
Batching is a master–part concern, not a
key_sourceconcern. A run- or cohort-level batch should be a master keyed on the batch with per-member results on a part — consistent with the DataJoint 2 rule that an auto-populated table introduces no new dimension (only its parts may). This removes the historical "batch by overridingkey_source" motivation.
Rollout
- 2.4: add
key_scope; overridingkey_sourceraises an error. - Docs: remove any guidance that recommends overriding
key_source; documentkey_scopeas the supported way to narrow a source, and "batch via master–part."
Docs task (coordinated)
datajoint-docs: pull any recommendation to override key_source, and document key_scope + the "batch via master–part" guidance (Autopopulate spec §2 and the how-to pages).
Activity
dimitri-yatsenko commentedon Aug 17, 2026
A second, independent justification for restrict-only: it is exactly what makes refreshing the jobs table without importing pipeline code possible.
Today
refresh()requires the pipeline codebase because an overriddenkey_sourceis arbitrary Python — unserializable in general. Any orchestration around DataJoint (a cron, a scheduler, a dashboard) must therefore run refresh inside an environment with the pipeline installed, just to materialize pending jobs.After this change,
key_source = default FK-join & key_source_restriction, and the two halves have very different portability:That suggests a small addition to this proposal: at declaration (or worker registration), write the rendered
key_source_restrictionSQL into the jobs table's metadata, with a stamp for staleness. Every jobs table becomes self-describing for refresh, andbecomes a generic operation any actor with DB credentials can run — a plain cron, an external scheduler, or eventually a trigger/CDC event restricted to the arriving key. Restrictions whose values must be recomputed at refresh time (moving clock windows, external-state probes) remain the one case needing code, and under restrict-only they are visibly deviant rather than structurally indistinguishable from normal overrides.
Staleness also narrows: re-registration is needed only when the declared restriction changes, not on every code deployment.
Worth weighing in the 2.4 design: whether the stored/rendered restriction (and a
refresh()mode that executes from it) lands together withkey_source_restrictionor as a follow-up.github-actions commentedon Oct 2, 2026
This issue is stale because it has been open for 45 days with no activity.
[-]Make key_source restrict-only: add key_source_restriction, deprecate parent-redefining overrides[/-][+]Make key_source restrict-only: add key_scope, deprecate parent-redefining overrides[/+]