Skip to content

Commit

Permalink
fix: Allow developers to set RESTStream.http_method
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarrmondragon committed Dec 10, 2024
1 parent 2882731 commit 9c46579
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 3 deletions.
38 changes: 35 additions & 3 deletions singer_sdk/streams/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ def __init__(
name: str | None = None,
schema: dict[str, t.Any] | Schema | None = None,
path: str | None = None,
*,
http_method: str | None = None,
) -> None:
"""Initialize the HTTP stream.
Expand All @@ -99,11 +101,13 @@ def __init__(
schema: JSON schema for records in this stream.
name: Name of this stream.
path: URL path for this entity stream.
http_method: HTTP method to use for requests.
"""
super().__init__(name=name, schema=schema, tap=tap)
if path:
self.path = path
self._http_headers: dict = {"User-Agent": self.user_agent}
self._http_method = http_method
self._requests_session = requests.Session()

@staticmethod
Expand Down Expand Up @@ -151,12 +155,37 @@ def rest_method(self) -> str:
.. deprecated:: 0.43.0
Override :meth:`~singer_sdk.RESTStream.http_method` instead.
"""
return "GET"
return self._http_method or "GET"

@rest_method.setter
@deprecated(
"Use `http_method` instead.",
category=SingerSDKDeprecationWarning,
)
def rest_method(self, value: str) -> None:
"""Set the HTTP method for requests.
Args:
value: The HTTP method to use for requests.
.. deprecated:: 0.43.0
Override :meth:`~singer_sdk.RESTStream.http_method` instead.
"""
self._http_method = value

@property
def http_method(self) -> str:
"""HTTP method to use for requests. Defaults to "GET"."""
return self.rest_method
return self._http_method or self.rest_method

@http_method.setter
def http_method(self, value: str) -> None:
"""Set the HTTP method for requests.
Args:
value: The HTTP method to use for requests.
"""
self._http_method = value

@property
def requests_session(self) -> requests.Session:
Expand Down Expand Up @@ -758,6 +787,8 @@ def __init__(
name: str | None = None,
schema: dict[str, t.Any] | Schema | None = None,
path: str | None = None,
*,
http_method: str | None = None,
) -> None:
"""Initialize the REST stream.
Expand All @@ -766,8 +797,9 @@ def __init__(
schema: JSON schema for records in this stream.
name: Name of this stream.
path: URL path for this entity stream.
http_method: HTTP method to use for requests
"""
super().__init__(tap, name, schema, path)
super().__init__(tap, name, schema, path, http_method=http_method)
self._compiled_jsonpath = None
self._next_page_token_compiled_jsonpath = None

Expand Down
49 changes: 49 additions & 0 deletions tests/core/test_streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@

import pytest
import requests
import requests_mock.adapter as requests_mock_adapter

from singer_sdk._singerlib import Catalog, MetadataMapping
from singer_sdk.exceptions import (
FatalAPIError,
InvalidReplicationKeyException,
)
from singer_sdk.helpers._classproperty import classproperty
from singer_sdk.helpers._compat import SingerSDKDeprecationWarning
from singer_sdk.helpers._compat import datetime_fromisoformat as parse
from singer_sdk.helpers.jsonpath import _compile_jsonpath
from singer_sdk.streams.core import REPLICATION_FULL_TABLE, REPLICATION_INCREMENTAL
Expand Down Expand Up @@ -569,6 +572,52 @@ def prepare_request_payload(self, context, next_page_token): # noqa: ARG002
]


def test_mutate_http_method(tap: Tap, requests_mock: requests_mock.Mocker):
"""Test HTTP method can be overridden."""

def callback(request: requests.PreparedRequest, context: requests_mock.Context):
if request.method == "POST":
return {
"data": [
{"id": 1, "value": "abc"},
{"id": 2, "value": "def"},
]
}

# Method not allowed
context.status_code = 405
context.reason = "Method Not Allowed"
return {"error": "Check your method"}

class PostStream(RestTestStream):
records_jsonpath = "$.data[*]"
path = "/endpoint"

stream = PostStream(tap, http_method="PUT")
requests_mock.request(
requests_mock_adapter.ANY,
url="https://example.com/endpoint",
json=callback,
)

with pytest.raises(FatalAPIError, match="Method Not Allowed"):
list(stream.request_records(None))

with pytest.warns(SingerSDKDeprecationWarning):
stream.rest_method = "GET"

with pytest.raises(FatalAPIError, match="Method Not Allowed"):
list(stream.request_records(None))

stream.http_method = "POST"

records = list(stream.request_records(None))
assert records == [
{"id": 1, "value": "abc"},
{"id": 2, "value": "def"},
]


def test_parse_response(tap: Tap):
content = """[
{"id": 1, "value": 3.14159},
Expand Down

0 comments on commit 9c46579

Please sign in to comment.