Skip to content

Add serviceapps Django app for Cytoscape Web Service Apps#126

Open
kushvinth wants to merge 1 commit intocytoscape:masterfrom
kushvinth:feature/serviceapps-web-service-apps
Open

Add serviceapps Django app for Cytoscape Web Service Apps#126
kushvinth wants to merge 1 commit intocytoscape:masterfrom
kushvinth:feature/serviceapps-web-service-apps

Conversation

@kushvinth
Copy link
Copy Markdown

PR: Add Cytoscape Web Service Apps Support

Related Issues:

Summary

This PR adds a new serviceapps Django app that brings Cytoscape Web Service App support to the App Store. Service Apps, per the Service App Specification (draft v2), become a first-class app type, discoverable via the App Store UI and consumable via a machine-readable JSON API endpoint for Cytoscape Web.


What's Included

URL Routes

URL Name Description
/submit/service-app/ serviceapps:submit Form to submit & validate a new service app
/service-apps/ serviceapps:list Browse active service apps (filter by ?health=ok or ?q=search)
/service-apps/<id>/ serviceapps:detail Service app detail page
/api/service-apps/config serviceapps:config JSON endpoint returning [{"url": "..."}] for healthy apps, consumed by Cytoscape Web

Submission & Validation Flow

When an author submits a service app URL:

  1. The view fetches the root endpoint (/) and checks for required keys per the spec:
    name, description, version, parameters, serviceInputDefinition, cyWebActions, cyWebMenuItem
  2. The view fetches /status and records the health state
  3. If both checks pass, the ServiceApp record is created/updated with the fetched metadata
  4. If any check fails, the form re-renders with a specific error message

Health Check Command

python manage.py check_service_apps

Iterates over all active ServiceApp records, pings their /status endpoint, and updates last_status (ok, unavailable, or error), last_message, and last_checked. Designed to be run via cron or CI on a schedule.


Django Dual-Import Fix

The Problem

This project has an unusual sys.path setup:

  • manage.py appends .. to sys.path
  • The project root directory contains an __init__.py (making it an appstore Python package)

This means every top-level app is importable via two paths:

  • serviceapps (direct)
  • appstore.serviceapps (via the root package)

When Django's test runner discovers tests, it imports modules via the appstore.serviceapps path. But Django's app registry already loaded the app as serviceapps. This causes the ServiceApp model class to be instantiated twice from two different module identities, leading to:

RuntimeError: Conflicting 'serviceapp' models in application 'serviceapps':
<class 'serviceapps.models.ServiceApp'> and <class 'appstore.serviceapps.models.ServiceApp'>

The existing apps (apps, download, submit_app, etc.) happen to avoid this because they don't have apps.py AppConfig files and Django's legacy app loading resolves them differently.

The Fix

In serviceapps/__init__.py, module canonicalization logic detects when the module is being imported via the alternate appstore.serviceapps path and maps it back to the canonical serviceapps entry in sys.modules. This ensures both import paths resolve to the same module objects, preventing Django from registering duplicate model classes.

_CANONICAL = 'serviceapps'
if __name__ != _CANONICAL and _CANONICAL in sys.modules:
    sys.modules[__name__] = sys.modules[_CANONICAL]
    # ... also maps submodules

This is a targeted fix scoped to serviceapps. A broader fix would be to remove the sys.path.append('..') from manage.py or remove the root __init__.py, but that would affect the entire project and is out of scope for this PR.


Testing

# Run all serviceapps tests
python manage.py test serviceapps

# Run only non-template tests (avoids Django 4.2 + Python 3.14 __copy__ bug)
python manage.py test serviceapps.tests.ServiceAppModelTests \
                      serviceapps.tests.ServiceAppConfigTests \
                      serviceapps.tests.SubmitServiceAppTests.test_submit_valid_service

Test results: 11 tests total, 5 pass, 6 fail due to a pre-existing Django 4.2 + Python 3.14 incompatibility in template context copying (AttributeError: 'super' object has no attribute 'dicts'). This affects any view that renders a template, including tests in the existing apps test suite. It is not caused by this PR.


Post-Merge Steps

  1. Run migrations: python manage.py migrate
  2. (Optional) Schedule the health check: python manage.py check_service_apps via cron
  3. Consider upgrading Django to fix the Python 3.14 template __copy__ bug

Implements support for Cytoscape Web Service Apps as described in the
Service App Specification (draft v2). Service Apps are web services
discoverable and installable via the App Store UI and a machine-readable
API endpoint for Cytoscape Web.

New serviceapps app includes:
- ServiceApp model with URL, metadata, health status tracking
- Submit view that validates endpoints (/ and /status) per the spec
- List and detail views with filtering by health status
- JSON API endpoint at /api/service-apps/config for Cytoscape Web
- Admin integration for managing service apps
- Management command (check_service_apps) for periodic health checks
- Unit tests for submission, listing, detail, and config API

Wired into settings/base.py INSTALLED_APPS and root urls.py.
Added requests to requirements.txt.

Closes cytoscape#115
@kushvinth
Copy link
Copy Markdown
Author

PTAL @coleslaw481

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant