From 5b5b45f5c433a7791936a009f98a403852921008 Mon Sep 17 00:00:00 2001 From: Chip Kent <5250374+chipkent@users.noreply.github.com> Date: Fri, 23 Oct 2026 21:39:38 -0600 Subject: [PATCH] fix: stop sending the options argument as a query parameter BaseClient._get_params turns a method's locals() into query parameters, skipping only `params` and `raw`. It did not skip `options`, so any REST method called with a RequestOptionBuilder also sent `options=` in the query string. Skip `options` too. Every endpoint builds its query through _get_params, so this fixes them all. Add regression tests for a GET and a paginated list call. --- massive/rest/base.py | 3 ++- test_rest/test_request_options.py | 35 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test_rest/test_request_options.py diff --git a/massive/rest/base.py b/massive/rest/base.py index 294dd482..7e85be4a 100644 --- a/massive/rest/base.py +++ b/massive/rest/base.py @@ -196,7 +196,8 @@ def _get_params( # https://docs.python.org/3.8/library/inspect.html#inspect.Signature for argname, v in inspect.signature(fn).parameters.items(): # https://docs.python.org/3.8/library/inspect.html#inspect.Parameter - if argname in ["params", "raw"]: + # these configure the request itself and are never query params + if argname in ["params", "raw", "options"]: continue if v.default != v.empty: # timestamp_lt -> timestamp.lt diff --git a/test_rest/test_request_options.py b/test_rest/test_request_options.py new file mode 100644 index 00000000..805b2255 --- /dev/null +++ b/test_rest/test_request_options.py @@ -0,0 +1,35 @@ +from massive.rest.models.request import RequestOptionBuilder +from base import BaseTest + +import pook # type: ignore + + +class RequestOptionsTest(BaseTest): + """`options` sets headers; it must not leak into the query string.""" + + def options(self): + return RequestOptionBuilder(edge_id="test-edge", edge_ip_address="1.2.3.4") + + def assert_no_options_in_query(self, mock): + self.assertEqual(len(mock.matches), 1) + self.assertNotIn("options", mock.matches[0].query or {}) + + def test_get_with_options(self): + mock = pook.get( + self.c.BASE + "/v3/reference/tickers/OPTS", + reply=200, + response_body='{"results": {"ticker": "OPTS"}}', + ) + details = self.c.get_ticker_details("OPTS", options=self.options()) + self.assertEqual(details.ticker, "OPTS") + self.assert_no_options_in_query(mock) + + def test_paginate_with_options(self): + mock = pook.get( + self.c.BASE + "/v3/trades/OPTS", + reply=200, + response_body='{"results": []}', + ) + trades = list(self.c.list_trades("OPTS", options=self.options())) + self.assertEqual(trades, []) + self.assert_no_options_in_query(mock)