diff --git a/.vscode/settings.json b/.vscode/settings.json index a4158083..a3dae4b3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,10 @@ "[python]": { "editor.defaultFormatter": "charliermarsh.ruff" }, - "editor.formatOnSave": false, + "editor.codeActionsOnSave": { + "source.organizeImports.ruff": "explicit" + }, + "editor.formatOnSave": true, "mypy-type-checker.importStrategy": "fromEnvironment", "mypy-type-checker.preferDaemon": true, "python.analysis.typeCheckingMode": "basic", diff --git a/inngest/_internal/step_lib/step_async.py b/inngest/_internal/step_lib/step_async.py index 04359758..8c21e5bf 100644 --- a/inngest/_internal/step_lib/step_async.py +++ b/inngest/_internal/step_lib/step_async.py @@ -40,9 +40,9 @@ async def invoke( step_id: str, *, function: function.Function, - data: typing.Optional[types.JSON] = None, + data: typing.Optional[typing.Mapping[str, object]] = None, timeout: typing.Union[int, datetime.timedelta, None] = None, - user: typing.Optional[types.JSON] = None, + user: typing.Optional[typing.Mapping[str, object]] = None, v: typing.Optional[str] = None, ) -> object: """ @@ -79,9 +79,9 @@ async def invoke_by_id( *, app_id: typing.Optional[str] = None, function_id: str, - data: typing.Optional[types.JSON] = None, + data: typing.Optional[typing.Mapping[str, object]] = None, timeout: typing.Union[int, datetime.timedelta, None] = None, - user: typing.Optional[types.JSON] = None, + user: typing.Optional[typing.Mapping[str, object]] = None, v: typing.Optional[str] = None, ) -> object: """ @@ -106,6 +106,9 @@ async def invoke_by_id( v: Will become `event.v` in the invoked function. """ + if app_id is None: + app_id = self._client.app_id + parsed_step_id = self._parse_step_id(step_id) timeout_str = transforms.to_maybe_duration_str(timeout) diff --git a/inngest/_internal/step_lib/step_sync.py b/inngest/_internal/step_lib/step_sync.py index a656b545..89c7b3e5 100644 --- a/inngest/_internal/step_lib/step_sync.py +++ b/inngest/_internal/step_lib/step_sync.py @@ -45,9 +45,9 @@ def invoke( step_id: str, *, function: function.Function, - data: typing.Optional[types.JSON] = None, + data: typing.Optional[typing.Mapping[str, object]] = None, timeout: typing.Union[int, datetime.timedelta, None] = None, - user: typing.Optional[types.JSON] = None, + user: typing.Optional[typing.Mapping[str, object]] = None, v: typing.Optional[str] = None, ) -> object: """ @@ -84,9 +84,9 @@ def invoke_by_id( *, app_id: typing.Optional[str] = None, function_id: str, - data: typing.Optional[types.JSON] = None, + data: typing.Optional[typing.Mapping[str, object]] = None, timeout: typing.Union[int, datetime.timedelta, None] = None, - user: typing.Optional[types.JSON] = None, + user: typing.Optional[typing.Mapping[str, object]] = None, v: typing.Optional[str] = None, ) -> object: """ @@ -111,6 +111,9 @@ def invoke_by_id( v: Will become `event.v` in the invoked function. """ + if app_id is None: + app_id = self._client.app_id + parsed_step_id = self._parse_step_id(step_id) memo = self._get_memo_sync(parsed_step_id.hashed) diff --git a/tests/test_experimental/test_encryption_middleware/cases/__init__.py b/tests/test_experimental/test_encryption_middleware/cases/__init__.py index c59fc6eb..e7d24e09 100644 --- a/tests/test_experimental/test_encryption_middleware/cases/__init__.py +++ b/tests/test_experimental/test_encryption_middleware/cases/__init__.py @@ -8,6 +8,7 @@ decrypt_unexpected_encryption_field, encrypt_overridden_encryption_field, fallback_decryption_key, + invoke, step_and_fn_output, ) @@ -17,6 +18,7 @@ decrypt_unexpected_encryption_field, encrypt_overridden_encryption_field, fallback_decryption_key, + invoke, step_and_fn_output, ) diff --git a/tests/test_experimental/test_encryption_middleware/cases/invoke.py b/tests/test_experimental/test_encryption_middleware/cases/invoke.py new file mode 100644 index 00000000..327cebc7 --- /dev/null +++ b/tests/test_experimental/test_encryption_middleware/cases/invoke.py @@ -0,0 +1,125 @@ +""" +Ensure that invoke works. +""" + +import nacl.encoding +import nacl.hash +import nacl.secret +import nacl.utils + +import inngest +import tests.helper +from inngest._internal import server_lib +from inngest.experimental.encryption_middleware import EncryptionMiddleware + +from . import base + +_secret_key = "my-secret-key" + + +enc = base.Encryptor( + nacl.hash.blake2b( + _secret_key.encode("utf-8"), + digest_size=nacl.secret.SecretBox.KEY_SIZE, + ) +) + + +class _State(base.BaseState): + event: inngest.Event + events: list[inngest.Event] + + +def create( + client: inngest.Inngest, + framework: server_lib.Framework, + is_sync: bool, +) -> base.Case: + test_name = base.create_test_name(__file__) + event_name = base.create_event_name(framework, test_name) + fn_id = base.create_fn_id(test_name) + state = _State() + + @client.create_function( + fn_id=f"{fn_id}/child", + middleware=[EncryptionMiddleware.factory(_secret_key)], + retries=0, + trigger=inngest.TriggerEvent(event="never"), + ) + def child_fn_sync( + ctx: inngest.Context, + step: inngest.StepSync, + ) -> str: + return f"Hello, {ctx.event.data['name']}!" + + @client.create_function( + fn_id=fn_id, + middleware=[EncryptionMiddleware.factory(_secret_key)], + retries=0, + trigger=inngest.TriggerEvent(event=event_name), + ) + def fn_sync( + ctx: inngest.Context, + step: inngest.StepSync, + ) -> None: + state.run_id = ctx.run_id + + result = step.invoke( + "invoke", + function=child_fn_sync, + data={"name": "Alice"}, + ) + assert isinstance(result, str) + assert result == "Hello, Alice!" + + @client.create_function( + fn_id=f"{fn_id}/child", + middleware=[EncryptionMiddleware.factory(_secret_key)], + retries=0, + trigger=inngest.TriggerEvent(event="never"), + ) + async def child_fn_async( + ctx: inngest.Context, + step: inngest.Step, + ) -> str: + return f"Hello, {ctx.event.data['name']}!" + + @client.create_function( + fn_id=fn_id, + middleware=[EncryptionMiddleware.factory(_secret_key)], + retries=0, + trigger=inngest.TriggerEvent(event=event_name), + ) + async def fn_async( + ctx: inngest.Context, + step: inngest.Step, + ) -> None: + state.run_id = ctx.run_id + + result = step.invoke( + "invoke", + function=child_fn_sync, + data={"name": "Alice"}, + ) + assert isinstance(result, str) + assert result == "Hello, Alice!" + + async def run_test(self: base.TestClass) -> None: + self.client.send_sync(inngest.Event(name=event_name)) + + run_id = state.wait_for_run_id() + tests.helper.client.wait_for_run_status( + run_id, + tests.helper.RunStatus.COMPLETED, + ) + + if is_sync: + fn = [child_fn_sync, fn_sync] + else: + fn = [child_fn_async, fn_async] + + return base.Case( + fn=fn, + run_test=run_test, + name=test_name, + ) diff --git a/tests/test_function/test_django.py b/tests/test_function/test_django.py index d16d6046..3c2db9c5 100644 --- a/tests/test_function/test_django.py +++ b/tests/test_function/test_django.py @@ -40,8 +40,10 @@ django.conf.settings.configure( ALLOWED_HOSTS=["*"], - # We send up to 4 MB - DATA_UPLOAD_MAX_MEMORY_SIZE=1024 * 1024 * 5, + # We send up to 5 MB + # TODO: Change this back to 5 MB after we release a Dev Server version with + # the max request size fix (https://github.com/inngest/inngest/pull/2009). + DATA_UPLOAD_MAX_MEMORY_SIZE=1024 * 1024 * 8, DEBUG=True, ROOT_URLCONF=__name__, SECRET_KEY="fake",