feat: add configurable JsonClient class for dependency injection
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 2/5
- Geschätzter Aufwand
- 1-3 Stunden
- Anfängerfreundlichkeit
- 76/100
Rechercherichtung
Beginnen Sie in campus_python/init.py und konzentrieren Sie sich auf die Campus-Klasse sowie deren auth- und api-Eigenschaften. Sehen Sie sich anschließend tests/flask_test/campus_request.py an, um die Struktur des injizierten Clients zu prüfen, und verifizieren Sie dann, dass beide Eigenschaften die konfigurierte Klasse verwenden, während der Standardwert CampusRequest bleibt; das Dokumentationsbeispiel und die Veröffentlichung der Minor-Version sind als zusätzliche Checklistenpunkte aufgeführt.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Feature Request: Configurable JsonClient Class for Dependency Injection
Problem
When testing Campus services that use campus_python.Campus, we need to replace the default CampusRequest with a test-compatible version that routes to Flask test clients instead of making real HTTP requests.
Current Workaround: Monkey-Patching
Currently, we have to monkey-patch the CampusRequest class:
import campus_python
from tests.flask_test import TestCampusRequest
# Replace CampusRequest globally
campus_python.json_client.CampusRequest = TestCampusRequest
campus_python.CampusRequest = TestCampusRequest # Also patch module reference
Problems with this approach:
- ❌ Fragile - requires patching multiple module-level references
- ❌ Hard to debug - changes global state
- ❌ Confusing - not obvious that
CampusRequesthas been replaced - ❌ Brittle - may break if campus-api-python internals change
Proposed Solution
Add a configurable class attribute to allow dependency injection of the JsonClient class:
class Campus:
"""Unified Campus client interface."""
# Configurable JsonClient class
json_client_class: type[JsonClient] = CampusRequest
@property
def auth(self) -> AuthRoot:
if not hasattr(self, "_auth"):
# Use json_client_class instead of hardcoded CampusRequest
self._auth = AuthRoot(
json_client=self.json_client_class(
base_url=base_url,
timeout=self.timeout,
)
)
return self._auth
@property
def api(self) -> ApiRoot:
if not hasattr(self, "_api"):
self._api = ApiRoot(
json_client=self.json_client_class(
base_url=base_url,
timeout=self.timeout,
)
)
return self._api
Usage in Tests
import campus_python
from tests.flask_test import TestCampusRequest
def setup():
# Configure campus_python to use test client
campus_python.Campus.json_client_class = TestCampusRequest
# Now all Campus instances use TestCampusRequest
campus = campus_python.Campus(timeout=60)
campus.auth.root.authenticate(...) # Uses Flask test clients!
Benefits
- ✅ Clean dependency injection - No monkey-patching required
- ✅ Explicit configuration - Clear what JsonClient is being used
- ✅ Backward compatible - Defaults to
CampusRequest - ✅ Test-friendly - Easy to inject test doubles
- ✅ Flexible - Allows custom JsonClient implementations for:
- Testing (Flask test clients)
- Mocking (for unit tests)
- Custom HTTP backends (async, retry logic, etc.)
Implementation Details
Changes Required
File: campus_python/__init__.py
-
Add class attribute:
class Campus: json_client_class: type[JsonClient] = CampusRequest -
Replace hardcoded
CampusRequest(...)withself.json_client_class(...):- In
authproperty (line ~81) - In
apiproperty (line ~107)
- In
Example Custom JsonClient
from campus_python.json_client.interface import JsonClient, JsonResponse
class CustomJsonClient(JsonClient):
"""Custom JsonClient with special behavior."""
def __init__(self, base_url: str | None = None, **kwargs):
self.base_url = base_url or ""
# ... custom initialization ...
def get(self, path: str, query: dict | None = None) -> JsonResponse:
# ... custom implementation ...
pass
# ... implement other methods ...
# Use it
campus_python.Campus.json_client_class = CustomJsonClient
Backward Compatibility
✅ Fully backward compatible - Default value is CampusRequest, so existing code continues to work without changes.
Related
- Campus services repo: https://github.com/nyjc-computing/campus
- Issue #485: Inconsistent HTTP client patterns in tests
- Current workaround in:
tests/flask_test/campus_request.py
Alternatives Considered
-
Constructor parameter (
Campus(json_client_class=...))- ❌ Doesn't work for services that instantiate
Campus()internally (campus.auth, campus.api)
- ❌ Doesn't work for services that instantiate
-
Global function (
set_json_client_class())- ❌ More verbose than class attribute
- ❌ Requires additional function to maintain
-
Keep monkey-patching
- ❌ Fragile and confusing
Implementation Checklist
- Add
json_client_classclass attribute toCampus - Update
authproperty to useself.json_client_class - Update
apiproperty to useself.json_client_class - Add docstring explaining the configuration option
- Add example to README or documentation
- Release as minor version bump (e.g., v2.1.0)
- Vorherrschende Sprache
- Python
- Sterne
- 0
- Forks
- 0
- PR-Merge-Kennzahlen
- Keine gemergten PRs in 30 T.
Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus nyjc-computing/campus-api-python
-
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 48/100
-
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 72/100
-
Add Timetable resource Offen
nyjc-computing/campus-api-python#2 · 1 zugewiesene Person ·
Alle Issues in nyjc-computing/campus-api-python
Ähnliche Issues
-
documentation help wanted
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 90/100
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 90/100
simonw/sqlite-utils#872 ·
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 88/100
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100