Skip to content

Fix GET filter parameters being ignored#28

Merged
sfoale merged 5 commits into
mainfrom
update-for-fastapi
May 15, 2026
Merged

Fix GET filter parameters being ignored#28
sfoale merged 5 commits into
mainfrom
update-for-fastapi

Conversation

@sfoale

@sfoale sfoale commented May 6, 2026

Copy link
Copy Markdown
Contributor

This api wrapper needed to be updated for the fastapi implementation. @moira-andrews reported:

The api documentation to get the pointings also doesn't seem to be actually filtering on input parameters. I ran the following:

pointings = gwtm_api.Pointing.get(graceid="S250206dm", instruments=["Las Cumbres 1m"], api_token=API_TOKEN)
with my API token and got returned a list of length 52698 no matter what instrument I input and returned pointings that don't make sense for the event (like from 2019 for an event in 2025):

pointings[2].time
datetime.datetime(2019, 9, 10, 1, 26, 19, 235580)
pointings[-1].time
datetime.datetime(2025, 11, 13, 11, 11, 44)
pointings[1234].time
datetime.datetime(2019, 8, 22, 2, 50, 18, 696000)

The first bullet point addresses the issue, but while I was there I did some tidying up.

  • Fix GET filter parameters being ignored (lists now correctly encoded as query params).
  • Add configure() as single entry point for API credentials and base URL
  • Replace per-method api_token parameter with module-level client but retain backwards compatibility.
  • Add Candidate put, delete, and batch_delete operations.
  • Add unit tests.
  • Add github actions CI workflow.
  • Update README.

sfoale added 2 commits May 6, 2026 15:28
…as query params).

Add configure() as single entry point for API credentials and base URL
Replace per-method api_token parameter with module-level client but retain backwards compatibility.
Add Candidate put, delete, and batch_delete operations.
Add unit tests.
Add github actions CI workflow.
Update README.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Python wrapper to work with the FastAPI-backed GWTM API, primarily by switching GET filtering to proper query parameters (including JSON-encoding list params) and centralizing auth/base URL configuration via a module-level transport client.

Changes:

  • Introduces a new core/_client_factory.py transport layer using httpx plus gwtm_api.configure() as the primary configuration entry point.
  • Refactors wrapper methods (Pointing/Instrument/Candidate/Alert + event_tools) to use the new transport and list query param encoding.
  • Adds unit tests and a GitHub Actions CI workflow; updates README and dependencies.

Reviewed changes

Copilot reviewed 19 out of 22 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/gwtm_api/core/_client_factory.py New httpx-based transport + global configure/token/base_url handling
src/gwtm_api/core/util.py Adds _encode_list_param and expands non_none_locals ignore list
src/gwtm_api/core/__init__.py Stops exporting legacy baseapi
src/gwtm_api/__init__.py Exposes configure() at package top-level
src/gwtm_api/pointing.py Refactors Pointing to use transport + query params; adds _to_dict + DOI request changes
src/gwtm_api/instrument.py Refactors Instrument/Footprint to use transport + query params
src/gwtm_api/candidate.py Refactors Candidate to use transport; adds put/delete/batch_delete
src/gwtm_api/alert.py Refactors Alert API calls to use transport + raw FITS fetch
src/gwtm_api/event_tools.py Updates event tools to use configured transport instead of per-call api_token
tests/unit/* Adds unit tests for transport/config/list encoding and wrapper behavior
.github/workflows/ci.yml Adds pytest CI job
.github/workflows/python-publish.yml Updates setup-python action version
README.md Documents new configuration pattern and updated examples
pyproject.toml Replaces requests with httpx, adds dev deps
.gitignore Minor formatting tweak
tests/__init__.py, tests/unit/__init__.py, tests/unit/conftest.py Test package scaffolding + shared transport reset fixture

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/gwtm_api/candidate.py Outdated
Comment thread src/gwtm_api/event_tools.py Outdated
Comment thread src/gwtm_api/event_tools.py Outdated
Comment thread src/gwtm_api/event_tools.py Outdated
Comment thread src/gwtm_api/event_tools.py
Comment thread src/gwtm_api/event_tools.py
Comment thread src/gwtm_api/instrument.py Outdated
Comment thread README.md
Comment thread src/gwtm_api/pointing.py
Comment thread src/gwtm_api/core/_client_factory.py

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 22 changed files in this pull request and generated 12 comments.

Comment thread src/gwtm_api/event_tools.py Outdated
Comment thread src/gwtm_api/event_tools.py Outdated
Comment thread src/gwtm_api/event_tools.py
Comment thread src/gwtm_api/event_tools.py
Comment thread src/gwtm_api/instrument.py
Comment thread src/gwtm_api/candidate.py Outdated
Comment thread README.md
Comment thread src/gwtm_api/core/_client_factory.py
Comment thread src/gwtm_api/alert.py
Comment thread src/gwtm_api/alert.py

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 22 changed files in this pull request and generated 7 comments.

Comment thread README.md
Comment on lines +35 to +38
To point at a different server (e.g. a development instance), pass `base_url`:

```python
gwtm_api.configure(api_token='YOUR_API_TOKEN', base_url='https://dev.treasuremap.space')
Comment thread pyproject.toml
@@ -15,7 +15,7 @@ requires-python = "<3.12"
dependencies = [
"astropy",
"healpy",
"requests",
"httpx>=0.20.0",
"ligo.skymap",
"matplotlib",
"pandas"
Comment on lines +260 to +277
def candidate_coverage(candidate: Candidate, pointings: List[Pointing] = None,
distance_thresh: float = 5.0) -> List[Pointing]:
"""
Find which instrument pointings overlap with a candidate's position.

Args:
candidate: the Candidate to evaluate coverage for
pointings: pre-fetched pointings to evaluate; defaults to all pointings for the event
distance_thresh: search radius in degrees (default 5.0)

#set an arbitarily high nside
Returns all pointings whose footprint contains the candidate position.
"""
skymap_nside = 1024
#find our candidates healpix
candidate_healpix = hp.ang2pix(skymap_nside, candidate.ra, candidate.dec, lonlat=True, nest=True)
candidate_healpix = hp.ang2pix(skymap_nside, candidate.ra, candidate.dec,
lonlat=True, nest=True)

#query for all pointings
if not pointings:
pointings = Pointing.get(api_token=api_token, graceid=candidate.graceid)
pointings = Pointing.get(graceid=candidate.graceid)
Comment thread src/gwtm_api/alert.py
Comment on lines +114 to 126
def fetch_contours(id: int = None, graceid: str = None,
cache=False, api_token: str = None):
if api_token:
transport.configure(api_token=api_token)
request_json = None
if cache:
cache_name = f"{graceid}_gw_contour.json"
contour_cache = TMCache(filename=cache_name, cache_type="json")
request_json = contour_cache.get()
cache_obj = TMCache(filename=f"{graceid}_gw_contour.json", cache_type="json")
request_json = cache_obj.get()

if request_json is None:
api = baseapi.api(target="gw_contour")
req = api._get(r_json=r_json, urlencode=urlencode)

if req.status_code == 200:
request_json = json.loads(req.text)
else:
raise Exception(f"Error in Alert.fetch_contours(). Request: {req.text[0:1000]}")
request_json = transport.get('/gw_contour', params={'graceid': graceid})

if cache:
Comment thread src/gwtm_api/alert.py
Comment on lines +135 to +151
def fetch_skymap(id: int = None, graceid: str = None,
cache=False, api_token: str = None):
if api_token:
transport.configure(api_token=api_token)
request_map = None
if cache:
cache_name = f"{graceid}_gw_skymap.fits"
skymap_cache = TMCache(filename=cache_name, cache_type="fits")
request_map = skymap_cache.get()
cache_obj = TMCache(filename=f"{graceid}_gw_skymap.fits", cache_type="fits")
request_map = cache_obj.get()

if request_map is None:
api = baseapi.api(target="gw_skymap")
req = api._get(r_json=r_json, urlencode=urlencode)
response = transport.get_raw('/gw_skymap', params={'graceid': graceid})
if response.status_code != 200:
raise Exception(f"Error in Alert.fetch_skymap(): status {response.status_code}")
with tempfile.NamedTemporaryFile(suffix=".fits") as tmp:
tmp.write(response.content)
tmp.flush()
request_map = hp.read_map(tmp.name)
@@ -23,7 +23,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v3
uses: actions/setup-python@v5
with:
python-version: '3.x'
def configure(api_token: str = None, base_url: str = None) -> None:
global _token, _base_url
_token = api_token or os.getenv("GWTM_API_TOKEN", "")
_base_url = (base_url or os.getenv("GWTM_BASE_URL", DEFAULT_BASE_URL)).rstrip("/")
@sfoale sfoale merged commit 68363db into main May 15, 2026
2 checks passed
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.

2 participants