refactor: apply codebase review fixes, add type stubs, and offline unit tests - #65
Merged
Conversation
… nightly drift check
…rivilege permissions
Ensembl bumped ENST00000408937 (FOXP2-210) from version 7 to 8, and
/ga4gh/features/{id} rejects stale versions with a 400. This broke
test_getGA4GHFeatures deterministically, so the live-test reruns could
not recover it.
Add a versionedStableId() helper that looks up the current version via
/lookup/id/ and have test_getGA4GHFeatures build its ID at runtime, so
both the reference curl and the library call stay in sync across future
releases. The helper raises rather than returning an unusable value, to
avoid degrading into a vacuous comparison when the lookup fails.
Also bump the hardcoded .7 to .8 in the examples.py and README.md
snippets so they no longer error when copy-pasted.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The /cafe/ endpoints return the whole species tree (~400 taxa, ~100KB) and their latency is driven by server load, not payload size: the same request measured between 9s and 122s across samples, with the smallest response being the slowest. The 60s budget lost that race often enough to make the CAFE tests flaky, and the configured reruns could not help because every attempt hit the same wall. Raise the global TIMEOUT to 90s and add a CAFE_TIMEOUT of 180s, applied to all three CAFE tests on both sides of the comparison via a new optional timeout parameter on launch()/jsonFromCurl(). Only --max-time is extended; --connect-timeout stays on the global value since the handshake is not what is slow here. Also derive the library timeout in setUp() from TIMEOUT rather than repeating the literal, so the two cannot drift apart. Note this does not address the intermittent 503s from the same endpoints, which the existing reruns already handle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
test_getGeneTreeMemberBySymbol hits the same wall the CAFE tests did, measuring 118s and 140s against the 90s global budget. Measuring the neighbouring queries shows the previous commit blamed the wrong thing: the cost is symbol resolution, not payload size or pruning. The same BRCA2 tree returns byte-identical content in 5.6s via /genetree/id but takes 176s via /genetree/member/symbol, and a pruned /genetree/member/id query was the fastest of all at 2.3s. Rename CAFE_TIMEOUT to SLOW_ENDPOINT_TIMEOUT since it is not specific to CAFE, raise it to 300s to clear the 176s worst case with margin, and apply it to test_getGeneTreeMemberBySymbol as well. Correct the comment to record what was actually measured. test_getGeneTreeById and test_getGeneTreeMemberById stay on the global timeout, having measured 5.6s and 13.6s. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The live job timed out at 90 minutes having reached 80%, so raise both live jobs to 120 minutes. The nightly drift check runs the same suite against the same API and would have hit the identical wall. test_getHomologyBySymbol is the last test over the global budget, measuring 104s and 112s on a cold cache, so give it the extended timeout as well. Correct the SLOW_ENDPOINT_TIMEOUT comment. Re-measuring showed these responses are cached by Ensembl, which made some earlier readings look fast on a second sample; with untouched genes as controls the symbol cost holds up, a 929KB homology query by id taking 10.5s against 104s for a smaller 372KB one by symbol. The rest of the suite's symbol endpoints are cheap and stay on the global timeout: /xrefs/symbol and /lookup/symbol both measured around 0.1s. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR addresses all findings from the Staff+ codebase review across architecture, packaging, type safety, error resilience, rate limiting, and test quality, as well as a modernized CI/CD workflow architecture.
Key Changes
CI/CD Pipeline Overhaul:
.github/workflows/pull_request.yaml..github/workflows/nightly.yamlto monitor upstream Ensembl REST API changes/deprecations automatically on a nightly cron without blocking PRs.Rate Limiting & Timing Fixes:
deltacalculation with a rolling 1.0s sliding window usingcollections.deque[float](reqs_per_sec=15,wall_time=1.0s), avoiding false unneeded sleeps when requests are spread out over time.isinstance(retry_after, (int, float))type check inEnsemblRestRateLimitErrorso integerRetry-Afterheaders are formatted properly.Parameter Validation & URL Construction:
PARAM_REGEX = [a-zA-Z0-9_]+so parameters containing0are matched.urllib.parse.quote(..., safe=":").Packaging & Dependency Hygiene:
mypy,ruff,pre-commit,types-requests) from runtime[tool.poetry.dependencies]to[tool.poetry.group.dev.dependencies].responsesto[tool.poetry.group.test.dependencies]for mocked unit tests.poetry.lock.Type Safety & IDE Autocomplete (PEP 561):
py.typedmarker file.ensemblrest.pyitype stub explicitly declaring typed signatures, required/optional parameters, and docstrings for all 106 endpoints.__dir__()and__getattr__()dynamic reflection onEnsemblRest.Error Resilience & Resource Management:
json.loadsin safe decode handlers to prevent unhandledJSONDecodeErroron HTML error pages or empty bodies.close(),__enter__(), and__exit__()context manager support toEnsemblRest.EnsemblRestBadRequestError,EnsemblRestNotFoundError,EnsemblRestTimeoutError).PackageNotFoundErrorfallback in__init__.py.Comprehensive Offline Unit Test Suite:
tests/test_unit.pywith 28 fast, offline, 100% mocked unit tests usingresponses.make unit-testnow runs completely offline in ~2.3 seconds with 91% code coverage.Documentation:
CLAUDE.mdtoAGENTS.mdand added a referencing pointer inCLAUDE.md.Pinned Actions Matrix
actions/checkoutv7.0.13d3c42e5aac5ba805825da76410c181273ba90b1actions/setup-pythonv7.0.05fda3b95a4ea91299a34e894583c3862153e4b97snok/install-poetryv1.4.2a783c322200f0519c7926aa6faa857c4e23e9263actions/cachev6.1.055cc8345863c7cc4c66a329aec7e433d2d1c52a9coverallsapp/github-actionv2.3.88d6379e14d29928660c4ba802d8e85393440b329actions/upload-artifactv7.0.1043fb46d1a93c77aae656e7c1c64a875d1fc6a0aactions/download-artifactv8.0.13e5f45b2cfb9172054b4087a40e8e0b5a5461e7csoftprops/action-gh-releasev3.0.23d0d9888cb7fd7b750713d6e236d1fcb99157228Verification