diff --git a/changelog.d/20250718_155657_sirosen_remove_from_transfer_data.rst b/changelog.d/20250718_155657_sirosen_remove_from_transfer_data.rst new file mode 100644 index 000000000..af4444738 --- /dev/null +++ b/changelog.d/20250718_155657_sirosen_remove_from_transfer_data.rst @@ -0,0 +1,6 @@ +Breaking Changes +---------------- + +- The ``TimerJob.from_transfer_data`` classmethod, which was deprecated in + globus-sdk version 3, has been removed. Users should use the ``TransferTimer`` + class to construct timers which submit transfer tasks. (:pr:`NUMBER`) diff --git a/src/globus_sdk/services/timers/client.py b/src/globus_sdk/services/timers/client.py index aef77512f..6f98def1e 100644 --- a/src/globus_sdk/services/timers/client.py +++ b/src/globus_sdk/services/timers/client.py @@ -188,10 +188,12 @@ def create_job( **Examples** >>> from datetime import datetime, timedelta - >>> transfer_data = TransferData(...) + >>> callback_url = ... + >>> data = ... >>> timers_client = globus_sdk.TimersClient(...) - >>> job = TimerJob.from_transfer_data( - ... transfer_data, + >>> job = TimerJob( + ... callback_url, + ... data, ... datetime.utcnow(), ... timedelta(days=14), ... name="my-timer-job" diff --git a/src/globus_sdk/services/timers/data.py b/src/globus_sdk/services/timers/data.py index 18a9f6b4c..a051f5f03 100644 --- a/src/globus_sdk/services/timers/data.py +++ b/src/globus_sdk/services/timers/data.py @@ -6,11 +6,8 @@ import logging import typing as t -from globus_sdk._internal.utils import slash_join from globus_sdk._missing import MISSING, MissingType from globus_sdk._payload import GlobusPayload -from globus_sdk.config import get_service_url -from globus_sdk.exc import warn_deprecated from globus_sdk.services.transfer import TransferData log = logging.getLogger(__name__) @@ -266,69 +263,6 @@ def __init__( if scope is not None: self["scope"] = scope - @classmethod - def from_transfer_data( - cls, - transfer_data: TransferData | dict[str, t.Any], - start: dt.datetime | str, - interval: dt.timedelta | int | None, - *, - name: str | None = None, - stop_after: dt.datetime | None = None, - stop_after_n: int | None = None, - scope: str | None = None, - environment: str | None = None, - ) -> TimerJob: - r""" - Specify data to create a Timers job using the parameters for a transfer. Timers - will use those parameters to run the defined transfer operation, recurring at - the given interval. - - :param transfer_data: A :class:`TransferData ` object. - Construct this object exactly as you would normally; Timers will use this to - run the recurring transfer. - :param start: The datetime at which to start the Timers job. - :param interval: The interval at which the Timers job should recur. Interpreted - as seconds if specified as an integer. If ``stop_after_n == 1``, i.e. the - job is set to run only a single time, then interval *must* be None. - :param name: A (not necessarily unique) name to identify this job in Timers - :param stop_after: A date after which the Timers job will stop running - :param stop_after_n: A number of executions after which the Timers job will stop - :param scope: Timers defaults to the Transfer 'all' scope. Use this parameter to - change the scope used by Timers when calling the Transfer Action Provider. - :param environment: For internal use: because this method needs to generate a - URL for the Transfer Action Provider, this argument can control which - environment the Timers job is sent to. - """ - warn_deprecated( - "TimerJob.from_transfer_data(X, ...) is deprecated. " - "Prefer TransferTimer(body=X, ...) instead." - ) - - transfer_action_url = slash_join( - get_service_url("actions", environment=environment), "transfer/transfer/run" - ) - log.debug( - "Creating TimerJob from TransferData, action_url=%s", transfer_action_url - ) - for key in ("submission_id", "skip_activation_check"): - if transfer_data.get(key, MISSING) is not MISSING: - raise ValueError( - f"cannot create TimerJob from TransferData which has {key} set" - ) - # dict will either convert a `TransferData` object or leave us with a dict here - callback_body = {"body": dict(transfer_data)} - return cls( - transfer_action_url, - callback_body, - start, - interval, - name=name, - stop_after=stop_after, - stop_after_n=stop_after_n, - scope=scope, - ) - def _format_date(date: str | dt.datetime | MissingType) -> str | MissingType: if isinstance(date, dt.datetime): diff --git a/tests/functional/services/timers/test_jobs.py b/tests/functional/services/timers/test_jobs.py index b2d18b989..a69e37c9a 100644 --- a/tests/functional/services/timers/test_jobs.py +++ b/tests/functional/services/timers/test_jobs.py @@ -3,10 +3,8 @@ import pytest -from globus_sdk import TimerJob, TimersAPIError, TransferData, config, exc -from globus_sdk._internal.utils import slash_join +from globus_sdk import TimerJob, TimersAPIError from globus_sdk.testing import get_last_request, load_response -from tests.common import GO_EP1_ID, GO_EP2_ID def test_list_jobs(client): @@ -39,17 +37,14 @@ def test_get_job_errors(client): ) def test_create_job(client, start, interval): meta = load_response(client.create_job).metadata - transfer_data = TransferData(GO_EP1_ID, GO_EP2_ID) - with pytest.warns(exc.RemovedInV4Warning, match="Prefer TransferTimer"): - timer_job = TimerJob.from_transfer_data(transfer_data, start, interval) - response = client.create_job(timer_job) - assert response.http_status == 201 - assert response.data["job_id"] == meta["job_id"] - with pytest.warns(exc.RemovedInV4Warning, match="Prefer TransferTimer"): - timer_job = TimerJob.from_transfer_data(dict(transfer_data), start, interval) + timer_job = TimerJob( + "https://example.bogus/bogus-callback", {"bogus": "bogus_body"}, start, interval + ) + response = client.create_job(timer_job) assert response.http_status == 201 assert response.data["job_id"] == meta["job_id"] + req_body = json.loads(get_last_request().body) if isinstance(start, datetime.datetime): assert req_body["start"] == start.isoformat() @@ -59,18 +54,17 @@ def test_create_job(client, start, interval): assert req_body["interval"] == interval.total_seconds() else: assert req_body["interval"] == interval - assert req_body["callback_url"] == slash_join( - config.get_service_url("actions"), "/transfer/transfer/run" - ) + assert req_body["callback_url"] == "https://example.bogus/bogus-callback" def test_create_job_validation_error(client): meta = load_response(client.create_job, case="validation_error").metadata - transfer_data = TransferData(GO_EP1_ID, GO_EP2_ID) - with pytest.warns(exc.RemovedInV4Warning, match="Prefer TransferTimer"): - timer_job = TimerJob.from_transfer_data( - transfer_data, "2022-04-05T06:00:00", 1800 - ) + timer_job = TimerJob( + "https://example.bogus/bogus-callback", + {"bogus": "bogus_body"}, + "2022-04-05T06:00:00", + 1800, + ) with pytest.raises(TimersAPIError) as excinfo: client.create_job(timer_job) diff --git a/tests/unit/helpers/test_timer.py b/tests/unit/helpers/test_timer.py index c66a0498f..7439df560 100644 --- a/tests/unit/helpers/test_timer.py +++ b/tests/unit/helpers/test_timer.py @@ -5,37 +5,13 @@ from globus_sdk import ( OnceTimerSchedule, RecurringTimerSchedule, - TimerJob, TransferData, TransferTimer, - exc, ) from globus_sdk._missing import filter_missing from tests.common import GO_EP1_ID, GO_EP2_ID -def test_timer_from_transfer_data_ok(): - tdata = TransferData(GO_EP1_ID, GO_EP2_ID) - with pytest.warns(exc.RemovedInV4Warning, match="Prefer TransferTimer"): - job = TimerJob.from_transfer_data(tdata, "2022-01-01T00:00:00Z", 600) - assert "callback_body" in job - assert "body" in job["callback_body"] - assert "source_endpoint" in job["callback_body"]["body"] - assert "destination_endpoint" in job["callback_body"]["body"] - assert job["callback_body"]["body"]["source_endpoint"] == GO_EP1_ID - assert job["callback_body"]["body"]["destination_endpoint"] == GO_EP2_ID - - -@pytest.mark.parametrize( - "badkey, value", (("submission_id", "foo"), ("skip_activation_check", True)) -) -def test_timer_from_transfer_data_rejects_forbidden_keys(badkey, value): - tdata = TransferData(GO_EP1_ID, GO_EP2_ID, **{badkey: value}) - with pytest.raises(ValueError): - with pytest.warns(exc.RemovedInV4Warning, match="Prefer TransferTimer"): - TimerJob.from_transfer_data(tdata, "2022-01-01T00:00:00Z", 600) - - def test_transfer_timer_ok(): tdata = TransferData(GO_EP1_ID, GO_EP2_ID) timer = TransferTimer(body=tdata, name="foo timer", schedule={"type": "once"})