diff --git a/notebooks/api/0.8/12-custom-api-endpoint.ipynb b/notebooks/api/0.8/12-custom-api-endpoint.ipynb index 4ee59456406..478446bcd17 100644 --- a/notebooks/api/0.8/12-custom-api-endpoint.ipynb +++ b/notebooks/api/0.8/12-custom-api-endpoint.ipynb @@ -21,6 +21,7 @@ "outputs": [], "source": [ "# stdlib\n", + "from typing import Any\n", "\n", "# syft absolute\n", "import syft as sy\n", @@ -68,7 +69,7 @@ "def public_endpoint_method(\n", " context,\n", " query: str,\n", - ") -> bool:\n", + ") -> Any:\n", " return context.settings[\"key\"] == \"value\"\n", "\n", "\n", @@ -396,7 +397,7 @@ "def new_public_function(\n", " context,\n", " query: str,\n", - ") -> bool:\n", + ") -> Any:\n", " return context.settings[\"key\"] == \"value\"\n", "\n", "\n", @@ -561,131 +562,6 @@ ")\n", "assert isinstance(response, SyftError), response" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Syft Function/API Logs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "@sy.api_endpoint_method()\n", - "def public_log_function(\n", - " context,\n", - ") -> str:\n", - " print(\"Logging Public Function Call\")\n", - " return \"Public Function Execution\"\n", - "\n", - "\n", - "@sy.api_endpoint_method()\n", - "def private_log_function(\n", - " context,\n", - ") -> str:\n", - " print(\"Logging Private Function Call\")\n", - " return \"Private Function Execution\"\n", - "\n", - "\n", - "new_endpoint = sy.TwinAPIEndpoint(\n", - " path=\"test.log\",\n", - " mock_function=public_log_function,\n", - " private_function=private_log_function,\n", - " description=\"Lore ipsulum ...\",\n", - ")\n", - "\n", - "# # Add it to the server.\n", - "response = datasite_client.api.services.api.add(endpoint=new_endpoint)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "@sy.syft_function_single_use(endpoint=datasite_client.api.services.test.log)\n", - "def test_log_call(endpoint): # noqa: F811\n", - " print(\"In Syft Function Context\")\n", - " endpoint()\n", - " print(\"After API endpoint call\")\n", - " return True\n", - "\n", - "\n", - "@sy.syft_function_single_use(endpoint=datasite_client.api.services.test.log)\n", - "def test_log_call_mock(endpoint): # noqa: F811\n", - " print(\"In Syft Function Context\")\n", - " endpoint.mock()\n", - " print(\"After API endpoint call\")\n", - " return True\n", - "\n", - "\n", - "@sy.syft_function_single_use(endpoint=datasite_client.api.services.test.log)\n", - "def test_log_call_private(endpoint): # noqa: F811\n", - " print(\"In Syft Function Context\")\n", - " endpoint.private()\n", - " print(\"After API endpoint call\")\n", - " return True\n", - "\n", - "\n", - "# Create a project\n", - "project = sy.Project(\n", - " name=\"My Cool Project\",\n", - " description=\"\"\"Hi, I want to calculate the mean of your private data,\\\n", - " pretty please!\"\"\",\n", - " members=[datasite_client],\n", - ")\n", - "project.create_code_request(test_log_call, datasite_client)\n", - "project.create_code_request(test_log_call_mock, datasite_client)\n", - "project.create_code_request(test_log_call_private, datasite_client)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "log_call_job = datasite_client.code.test_log_call(\n", - " endpoint=datasite_client.api.services.test.log, blocking=False\n", - ")\n", - "log_call_mock_job = datasite_client.code.test_log_call_mock(\n", - " endpoint=datasite_client.api.services.test.log, blocking=False\n", - ")\n", - "log_call_private_job = datasite_client.code.test_log_call_private(\n", - " endpoint=datasite_client.api.services.test.log, blocking=False\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# stdlib\n", - "import time\n", - "\n", - "# Iterate over the Jobs waiting them to finish their pipelines.\n", - "job_pool = [\n", - " (log_call_job, \"Logging Private Function Call\"),\n", - " (log_call_mock_job, \"Logging Public Function Call\"),\n", - " (log_call_private_job, \"Logging Private Function Call\"),\n", - "]\n", - "for job, expected_log in job_pool:\n", - " updated_job = datasite_client.api.services.job.get(job.id)\n", - " while updated_job.status.value != \"completed\":\n", - " updated_job = datasite_client.api.services.job.get(job.id)\n", - " time.sleep(1)\n", - " # If they're completed. Then, check if the TwinAPI print appears in the job logs.\n", - " assert expected_log in datasite_client.api.services.job.get(job.id).logs(\n", - " _print=False\n", - " )" - ] } ], "metadata": { @@ -704,7 +580,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.4" + "version": "3.11.8" } }, "nbformat": 4, diff --git a/packages/syft/src/syft/protocol/protocol_version.json b/packages/syft/src/syft/protocol/protocol_version.json index a2343f039f7..aec411969b2 100644 --- a/packages/syft/src/syft/protocol/protocol_version.json +++ b/packages/syft/src/syft/protocol/protocol_version.json @@ -37,13 +37,6 @@ "hash": "b087d0c62b7d304c6ca80e4fb0e8a7f2a444be8f8cba57490dc09aeb98033105", "action": "add" } - }, - "CustomEndpointActionObject": { - "2": { - "version": 2, - "hash": "846ba36e8737a1bec16853c9de54c4948450009278e0b76fe7e3355ef9e70089", - "action": "add" - } } } } diff --git a/packages/syft/src/syft/server/server.py b/packages/syft/src/syft/server/server.py index 1f3f4201f44..eca1b56a8d8 100644 --- a/packages/syft/src/syft/server/server.py +++ b/packages/syft/src/syft/server/server.py @@ -1233,7 +1233,6 @@ def add_api_endpoint_execution_to_queue( credentials: SyftVerifyKey, method: str, path: str, - log_id: UID, *args: Any, worker_pool: str | None = None, **kwargs: Any, @@ -1267,7 +1266,7 @@ def add_api_endpoint_execution_to_queue( job_id=job_id, worker_settings=worker_settings, args=args, - kwargs={"path": path, "log_id": log_id, **kwargs}, + kwargs={"path": path, **kwargs}, has_execute_permissions=True, worker_pool=worker_pool_ref, # set worker pool reference as part of queue item ) @@ -1278,7 +1277,6 @@ def add_api_endpoint_execution_to_queue( credentials=credentials, action=action, job_type=JobType.TWINAPIJOB, - log_id=log_id, ) def get_worker_pool_ref_by_name( @@ -1362,11 +1360,9 @@ def add_queueitem_to_queue( action: Action | None = None, parent_job_id: UID | None = None, user_id: UID | None = None, - log_id: UID | None = None, job_type: JobType = JobType.JOB, ) -> Job | SyftError: - if log_id is None: - log_id = UID() + log_id = UID() role = self.get_role_for_credentials(credentials=credentials) context = AuthedServiceContext(server=self, credentials=credentials, role=role) diff --git a/packages/syft/src/syft/service/action/action_endpoint.py b/packages/syft/src/syft/service/action/action_endpoint.py index 9c89e9bd4c1..f3be5322191 100644 --- a/packages/syft/src/syft/service/action/action_endpoint.py +++ b/packages/syft/src/syft/service/action/action_endpoint.py @@ -2,19 +2,14 @@ from __future__ import annotations # stdlib -from collections.abc import Callable from enum import Enum from enum import auto from typing import Any # relative from ...serde.serializable import serializable -from ...types.syft_migration import migrate from ...types.syft_object import SYFT_OBJECT_VERSION_1 -from ...types.syft_object import SYFT_OBJECT_VERSION_2 from ...types.syft_object import SyftObject -from ...types.transforms import drop -from ...types.transforms import make_set_default from ...types.uid import UID from ..context import AuthedServiceContext @@ -25,29 +20,16 @@ class EXECUTION_MODE(Enum): PRIVATE = auto() -@serializable() -class CustomEndpointActionObjectV1(SyftObject): - __canonical_name__ = "CustomEndpointActionObject" - __version__ = SYFT_OBJECT_VERSION_1 - - endpoint_id: UID - context: AuthedServiceContext | None = None - - @serializable() class CustomEndpointActionObject(SyftObject): __canonical_name__ = "CustomEndpointActionObject" - __version__ = SYFT_OBJECT_VERSION_2 + __version__ = SYFT_OBJECT_VERSION_1 endpoint_id: UID context: AuthedServiceContext | None = None - log_id: UID | None = None - def add_context( - self, context: AuthedServiceContext, log_id: UID | None = None - ) -> CustomEndpointActionObject: + def add_context(self, context: AuthedServiceContext) -> CustomEndpointActionObject: self.context = context - self.log_id = log_id return self def __call__(self, *args: Any, **kwargs: Any) -> Any: @@ -87,25 +69,10 @@ def __call_function( __endpoint_mode = endpoint_service.execute_server_side_endpoint_by_id return __endpoint_mode( - *args, - context=self.context, - endpoint_uid=self.endpoint_id, - log_id=self.log_id, - **kwargs, + *args, context=self.context, endpoint_uid=self.endpoint_id, **kwargs ) def __check_context(self) -> AuthedServiceContext: if self.context is None: raise Exception("No context provided to CustomEndpointActionObject") return self.context - - -@migrate(CustomEndpointActionObjectV1, CustomEndpointActionObject) -def migrate_custom_endpoint_v1_to_v2() -> list[Callable]: - return [make_set_default("log_id", None)] - - -@migrate(CustomEndpointActionObject, CustomEndpointActionObjectV1) -def migrate_custom_endpoint_v2_to_v1() -> list[Callable]: - # Use drop function on "notifications_enabled" attrubute - return [drop(["log_id"])] diff --git a/packages/syft/src/syft/service/api/api.py b/packages/syft/src/syft/service/api/api.py index 86b8a9837ff..89e19146e99 100644 --- a/packages/syft/src/syft/service/api/api.py +++ b/packages/syft/src/syft/service/api/api.py @@ -38,7 +38,6 @@ from ..response import SyftError from ..user.user import UserView from ..user.user_service import UserService -from .utils import print as log_print NOT_ACCESSIBLE_STRING = "N / A" @@ -439,13 +438,7 @@ def select_code(self, context: AuthedServiceContext) -> Result[Ok, Err]: return Ok(self.private_function) return Ok(self.mock_function) - def exec( - self, - context: AuthedServiceContext, - *args: Any, - log_id: UID | None = None, - **kwargs: Any, - ) -> Any: + def exec(self, context: AuthedServiceContext, *args: Any, **kwargs: Any) -> Any: """Execute the code based on the user's permissions and public code availability. Args: @@ -460,29 +453,19 @@ def exec( return SyftError(message=result.err()) selected_code = result.ok() - return self.exec_code(selected_code, context, *args, log_id=log_id, **kwargs) + return self.exec_code(selected_code, context, *args, **kwargs) def exec_mock_function( - self, - context: AuthedServiceContext, - *args: Any, - log_id: UID | None = None, - **kwargs: Any, + self, context: AuthedServiceContext, *args: Any, **kwargs: Any ) -> Any: """Execute the public code if it exists.""" if self.mock_function: - return self.exec_code( - self.mock_function, context, *args, log_id=log_id, **kwargs - ) + return self.exec_code(self.mock_function, context, *args, **kwargs) return SyftError(message="No public code available") def exec_private_function( - self, - context: AuthedServiceContext, - *args: Any, - log_id: UID | None = None, - **kwargs: Any, + self, context: AuthedServiceContext, *args: Any, **kwargs: Any ) -> Any: """Execute the private code if user is has the proper permissions. @@ -497,9 +480,7 @@ def exec_private_function( return SyftError(message="No private code available") if self.has_permission(context): - return self.exec_code( - self.private_function, context, *args, log_id=log_id, **kwargs - ) + return self.exec_code(self.private_function, context, *args, **kwargs) return SyftError(message="You're not allowed to run this code.") @@ -527,22 +508,9 @@ def exec_code( code: PrivateAPIEndpoint | PublicAPIEndpoint, context: AuthedServiceContext, *args: Any, - log_id: UID | None = None, **kwargs: Any, ) -> Any: - # stdlib - import builtins as __builtin__ - import functools - - original_print = __builtin__.print - # stdlib - try: - if log_id is not None: - print = functools.partial(log_print, context, log_id) - else: - print = original_print # type: ignore - inner_function = ast.parse(code.api_code).body[0] inner_function.decorator_list = [] # compile the function @@ -552,24 +520,16 @@ def exec_code( user_client = self.get_user_client_from_server(context) admin_client = self.get_admin_client_from_server(context) + # load it + exec(raw_byte_code) # nosec + internal_context = code.build_internal_context( context=context, admin_client=admin_client, user_client=user_client ) - _locals = { - "args": args, - "kwargs": kwargs, - "internal_context": internal_context, - } - _globals = {} - evil_string = f"{code.func_name}(*args, **kwargs,context=internal_context)" - _globals["print"] = print - - # load it - exec(raw_byte_code, _globals, _locals) # nosec - # execute it - result = eval(evil_string, _globals, _locals) # nosec + evil_string = f"{code.func_name}(*args, **kwargs,context=internal_context)" + result = eval(evil_string, None, locals()) # nosec # Update code context state code.update_state(internal_context.state) @@ -587,8 +547,6 @@ def exec_code( if upsert_result.is_err(): raise Exception(upsert_result.err()) - print = original_print # type: ignore - # return the results return result except Exception as e: diff --git a/packages/syft/src/syft/service/api/api_service.py b/packages/syft/src/syft/service/api/api_service.py index d445502ab37..87051d9b4b4 100644 --- a/packages/syft/src/syft/service/api/api_service.py +++ b/packages/syft/src/syft/service/api/api_service.py @@ -391,14 +391,13 @@ def _call_in_jobs( ) if isinstance(custom_endpoint, SyftError): return custom_endpoint - log_id = UID() + result = context.server.add_api_endpoint_execution_to_queue( context.credentials, method, path, *args, worker_pool=custom_endpoint.worker_pool, - log_id=log_id, **kwargs, ) if isinstance(result, SyftError): @@ -494,7 +493,6 @@ def call( context: AuthedServiceContext, path: str, *args: Any, - log_id: UID | None = None, **kwargs: Any, ) -> SyftSuccess | SyftError: """Call a Custom API Method""" @@ -505,7 +503,7 @@ def call( if isinstance(custom_endpoint, SyftError): return custom_endpoint - exec_result = custom_endpoint.exec(context, *args, log_id=log_id, **kwargs) + exec_result = custom_endpoint.exec(context, *args, **kwargs) if isinstance(exec_result, SyftError): return Ok(exec_result) @@ -536,7 +534,6 @@ def call_public( context: AuthedServiceContext, path: str, *args: Any, - log_id: UID | None = None, **kwargs: Any, ) -> ActionObject | SyftError: """Call a Custom API Method in public mode""" @@ -546,9 +543,7 @@ def call_public( ) if isinstance(custom_endpoint, SyftError): return custom_endpoint - exec_result = custom_endpoint.exec_mock_function( - context, *args, log_id=log_id, **kwargs - ) + exec_result = custom_endpoint.exec_mock_function(context, *args, **kwargs) if isinstance(exec_result, SyftError): return Ok(exec_result) @@ -581,7 +576,6 @@ def call_private( context: AuthedServiceContext, path: str, *args: Any, - log_id: UID | None = None, **kwargs: Any, ) -> ActionObject | SyftError: """Call a Custom API Method in private mode""" @@ -592,9 +586,7 @@ def call_private( if isinstance(custom_endpoint, SyftError): return custom_endpoint - exec_result = custom_endpoint.exec_private_function( - context, *args, log_id=log_id, **kwargs - ) + exec_result = custom_endpoint.exec_private_function(context, *args, **kwargs) if isinstance(exec_result, SyftError): return Ok(exec_result) @@ -642,7 +634,6 @@ def execute_server_side_endpoint_by_id( context: AuthedServiceContext, endpoint_uid: UID, *args: Any, - log_id: UID | None = None, **kwargs: Any, ) -> Any: endpoint = self.get_endpoint_by_uid(context, endpoint_uid) @@ -652,16 +643,13 @@ def execute_server_side_endpoint_by_id( if not selected_code: selected_code = endpoint.mock_function - return endpoint.exec_code( - selected_code, context, *args, log_id=log_id, **kwargs - ) + return endpoint.exec_code(selected_code, context, *args, **kwargs) def execute_service_side_endpoint_private_by_id( self, context: AuthedServiceContext, endpoint_uid: UID, *args: Any, - log_id: UID | None = None, **kwargs: Any, ) -> Any: endpoint = self.get_endpoint_by_uid(context, endpoint_uid) @@ -669,24 +657,19 @@ def execute_service_side_endpoint_private_by_id( return endpoint if not endpoint.private_function: return SyftError(message="This endpoint does not have a private code") - return endpoint.exec_code( - endpoint.private_function, context, *args, log_id=log_id, **kwargs - ) + return endpoint.exec_code(endpoint.private_function, context, *args, **kwargs) def execute_server_side_endpoint_mock_by_id( self, context: AuthedServiceContext, endpoint_uid: UID, *args: Any, - log_id: UID | None = None, **kwargs: Any, ) -> Any: endpoint = self.get_endpoint_by_uid(context, endpoint_uid) if isinstance(endpoint, SyftError): return endpoint - return endpoint.exec_code( - endpoint.mock_function, context, *args, log_id=log_id, **kwargs - ) + return endpoint.exec_code(endpoint.mock_function, context, *args, **kwargs) def get_endpoint_by_uid( self, context: AuthedServiceContext, uid: UID diff --git a/packages/syft/src/syft/service/api/utils.py b/packages/syft/src/syft/service/api/utils.py deleted file mode 100644 index 5194d7de9cf..00000000000 --- a/packages/syft/src/syft/service/api/utils.py +++ /dev/null @@ -1,45 +0,0 @@ -# stdlib -import builtins as __builtin__ -import datetime -import sys -from typing import Any - -# relative -from ...types.uid import UID -from ..action.action_object import ActionObject -from ..context import AuthedServiceContext -from ..job.job_stash import Job -from ..response import SyftError - - -def print( - context: AuthedServiceContext, - log_id: UID, - *args: Any, - sep: str = " ", - end: str = "\n", -) -> str | None: - def to_str(arg: Any) -> str: - if isinstance(arg, bytes): - return arg.decode("utf-8") - if isinstance(arg, Job): - return f"JOB: {arg.id}" - if isinstance(arg, SyftError): - return f"JOB: {arg.message}" - if isinstance(arg, ActionObject): - return str(arg.syft_action_data) - return str(arg) - - new_args = [to_str(arg) for arg in args] - new_str = sep.join(new_args) + end - if context.server is not None: - log_service = context.server.get_service("LogService") - log_service.append(context=context, uid=log_id, new_str=new_str) - time = datetime.datetime.now().strftime("%d/%m/%y %H:%M:%S") - return __builtin__.print( - f"{time} FUNCTION LOG :", - *new_args, - end=end, - sep=sep, - file=sys.stderr, - ) diff --git a/packages/syft/src/syft/service/code/user_code.py b/packages/syft/src/syft/service/code/user_code.py index 1d0a35f3b83..955005a5895 100644 --- a/packages/syft/src/syft/service/code/user_code.py +++ b/packages/syft/src/syft/service/code/user_code.py @@ -1851,10 +1851,9 @@ def to_str(arg: Any) -> str: if code_item.uses_datasite: kwargs["datasite"] = LocalDatasiteClient() - job_log_id = context.job.log_id if context.job else None for k, v in kwargs.items(): if isinstance(v, CustomEndpointActionObject): - kwargs[k] = v.add_context(context=context, log_id=job_log_id) + kwargs[k] = v.add_context(context=context) stdout = StringIO() stderr = StringIO()