Skip to content

Move the PinnedDevice viewset and discovery API residue into kolibri/core/discovery/viewsets/ #14825

@rtibbles

Description

@rtibbles

This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.

Overview

Move PinnedDeviceViewSet — migrated to the serializer-derived pattern in #14292 — from kolibri/core/discovery/api.py into kolibri/core/discovery/viewsets/pinned_device.py, with PinnedDeviceSerializer inline. As the last issue touching the discovery app's API modules, it also moves the remaining non-migrating code into the package and deletes api.py and serializers.py, per the File Organization convention in #14036.

Complexity: Low
Target branch: develop

Context

PinnedDeviceViewSet lives in kolibri/core/discovery/api.py with PinnedDeviceSerializer in serializers.py; its migration to the serializer-derived pattern lands via #14292 (PR #14818), so this is a pure relocation with no serialization changes.

The rest of the discovery API is residue that moves as-is: NetworkLocationViewSet and its Dynamic/Static subclasses (with NetworkLocationSerializer), and NetworkLocationFacilitiesView (with its inline _RemoteFacilityPicturePasswordSerializer/_RemoteFacilitySerializer) — per #14036, the latter never uses the ValuesViewset serialization path (it makes live HTTP requests).

The Change

Create the kolibri/core/discovery/viewsets/ package (empty __init__.py) and move PinnedDeviceViewSet with PinnedDeviceSerializer inline into kolibri/core/discovery/viewsets/pinned_device.py, and the network-location residue (viewsets, serializers, and NetworkLocationFacilitiesView) into one module per domain. Land each relocation as a pure-move commit, separate from import updates. Update imports (api_urls.py, tests, cross-references), then delete api.py and serializers.py.

Moving code breaks GitHub blame (local git blame -C -C still works), so digest the history the move obscures:

  1. Run blame over the code being moved; flag hunks whose purpose isn't evident from the code or tests (odd guards, magic orderings, special cases).
  2. Chase each flagged hunk to its originating PR/issue; where the rationale is non-obvious and load-bearing, carry it forward as a code comment citing the reference.
  3. Where the rationale turns out to be obsolete, flag the code for removal — but as a pure move, this PR should not remove it; raise it for follow-up instead.

Out of Scope

Acceptance Criteria

  • kolibri/core/discovery/viewsets/pinned_device.py contains PinnedDeviceViewSet with PinnedDeviceSerializer inline; the network-location residue lives in the package, one module per domain
  • api.py and serializers.py are deleted, with all references updated (api_urls.py, tests)
  • Each relocation lands as a pure-move commit, separate from import updates
  • Existing API tests pass unchanged
  • Benchmark comparison passes for PinnedDeviceViewSet (data hash match + no performance regression)
  • Comments citing the originating PR/issue added where blame digestion found non-obvious, load-bearing rationale

Testing

  • Run the benchmark for PinnedDeviceViewSet, baseline with the old dotted path, comparison with the new one:
    python integration_testing/scripts/viewset_serialization_benchmark.py \
        kolibri.core.discovery.api.PinnedDeviceViewSet \
        --inherit-kolibri-home -o pinned_device_baseline.json
    
    # ... move ...
    
    python integration_testing/scripts/viewset_serialization_benchmark.py \
        kolibri.core.discovery.viewsets.pinned_device.PinnedDeviceViewSet \
        --inherit-kolibri-home --compare pinned_device_baseline.json
  • The comparison must pass; include the before/after output in the PR description.
  • Benchmark data setup (run via kolibri manage shell before benchmarking):
    from kolibri.core.discovery.models import PinnedDevice
    import uuid
    
    for i in range(100):
        PinnedDevice.objects.get_or_create(
            instance_id=uuid.uuid4(),
        )

AI usage

Drafted with AI assistance (Claude Code) from an interactive design discussion, section by section, with review and final edits by @rtibbles. Module contents, serialization paths, and the benchmark setup (carried over from #14292) were verified against the codebase during drafting.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DEV: backendPython, databases, networking, filesystem...TAG: tech update / debtChange not visible to user

    Type

    No fields configured for Task.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions