Skip to content

[Feature Request] Drop 3.8 support, confirm 3.13 support #672

Closed

Description

@cretz

Describe the solution you'd like

See #398 (PR #422) where we did this for 3.7/3.12. Can see the several things that were done there and similar should be done here.

Activity

  1. josh-berry commented on Nov 21, 2024

    @josh-berry
    Contributor

    I happened to discover by accident that grpcio does not yet support Python 3.13 because it apparently depends on some C APIs that have been removed. So it seems unlikely we'd be able to support it without updating grpcio (if a fix is available; it may already be)

  2. cretz commented on Nov 21, 2024

    @cretz
    ContributorAuthor

    grpcio is an optional dependency. We only added it because we do generate the gRPC stubs in the temporalio.api.workflowservice.v1.service_pb2_grpc and technically allow users to use that module if they want pure Python gRPC clients or servers even though we don't use it in the SDK. We do use it in tests to implement a custom gRPC server and figured "why not let users use the generated gRPC stuff too" in addition to protos. We may be able to remove this stuff if we have to (otherwise we may be able to upgrade it, it all depends on how old of a protobuf library we need to support).

  3. sciyoshi commented on Dec 4, 2024

    @sciyoshi

    Tracebacks are currently broken in Python 3.13. The original traceback for an exception happening in a workflow is clobbered and instead the following error is shown:

      File "/code/.venv/lib/python3.13/site-packages/temporalio/worker/_workflow.py", line 260, in _handle_activation
        completion = await asyncio.wait_for(
                     ^^^^^^^^^^^^^^^^^^^^^^^
            activate_task, self._deadlock_timeout_seconds
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        )
        ^
    
      File "/usr/local/lib/python3.13/asyncio/tasks.py", line 507, in wait_for
        return await fut
               ^^^^^^^^^
    
      File "/usr/local/lib/python3.13/concurrent/futures/thread.py", line 58, in run
        result = self.fn(*self.args, **self.kwargs)
    
      File "/code/.venv/lib/python3.13/site-packages/temporalio/worker/workflow_sandbox/_runner.py", line 160, in activate
        self._run_code(
        ~~~~~~~~~~~~~~^
            "with __temporal_importer.applied():\n"
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        ...<2 lines>...
            __temporal_activation=act,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^
        )
        ^
    
      File "/code/.venv/lib/python3.13/site-packages/temporalio/worker/workflow_sandbox/_runner.py", line 176, in _run_code
        exec(code, self.globals_and_locals, self.globals_and_locals)
        ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
      File "<string>", line 2, in <module>
    
      File "/code/.venv/lib/python3.13/site-packages/temporalio/worker/workflow_sandbox/_in_sandbox.py", line 81, in activate
        return self.instance.activate(act)
               ~~~~~~~~~~~~~~~~~~~~~~^^^^^
    
      File "/code/.venv/lib/python3.13/site-packages/temporalio/worker/_workflow_instance.py", line 411, in activate
        logger.warning(
        ~~~~~~~~~~~~~~^
            f"Failed activation on workflow {self._info.workflow_type} with ID {self._info.workflow_id} and run ID {self._info.run_id}",
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            exc_info=activation_err,
            ^^^^^^^^^^^^^^^^^^^^^^^^
            extra={"temporal_workflow": self._info._logger_details()},
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        )
        ^
    
      File "/usr/local/lib/python3.13/logging/__init__.py", line 1531, in warning
        self._log(WARNING, msg, args, **kwargs)
        ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
      File "/usr/local/lib/python3.13/logging/__init__.py", line 1664, in _log
        self.handle(record)
        ~~~~~~~~~~~^^^^^^^^
    
      File "/usr/local/lib/python3.13/logging/__init__.py", line 1680, in handle
        self.callHandlers(record)
        ~~~~~~~~~~~~~~~~~^^^^^^^^
    
      File "/usr/local/lib/python3.13/logging/__init__.py", line 1744, in callHandlers
        lastResort.handle(record)
        ~~~~~~~~~~~~~~~~~^^^^^^^^
    
      File "/usr/local/lib/python3.13/logging/__init__.py", line 1026, in handle
        self.emit(record)
        ~~~~~~~~~^^^^^^^^
    
      File "/usr/local/lib/python3.13/logging/__init__.py", line 1158, in emit
        self.handleError(record)
        ~~~~~~~~~~~~~~~~^^^^^^^^
    
      File "/usr/local/lib/python3.13/logging/__init__.py", line 1075, in handleError
        traceback.print_exception(exc, limit=None, file=sys.stderr)
        ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
      File "/usr/local/lib/python3.13/traceback.py", line 129, in print_exception
        te = TracebackException(type(value), value, tb, limit=limit, compact=True)
    
      File "/usr/local/lib/python3.13/traceback.py", line 1044, in __init__
        self.stack = StackSummary._extract_from_extended_frame_gen(
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
            _walk_tb_with_full_positions(exc_traceback),
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            limit=limit, lookup_lines=lookup_lines,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            capture_locals=capture_locals)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
      File "/usr/local/lib/python3.13/traceback.py", line 492, in _extract_from_extended_frame_gen
        f.line
    
      File "/usr/local/lib/python3.13/traceback.py", line 369, in line
        self._set_lines()
        ~~~~~~~~~~~~~~~^^
    
      File "/usr/local/lib/python3.13/traceback.py", line 350, in _set_lines
        lines.append(linecache.getline(self.filename, lineno).rstrip())
                     ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
    
      File "/usr/local/lib/python3.13/linecache.py", line 25, in getline
        lines = getlines(filename, module_globals)
    
      File "/usr/local/lib/python3.13/linecache.py", line 41, in getlines
        return updatecache(filename, module_globals)
    
      File "/usr/local/lib/python3.13/linecache.py", line 100, in updatecache
        stat = os.stat(fullname)
    
      File "/code/.venv/lib/python3.13/site-packages/temporalio/worker/workflow_sandbox/_restrictions.py", line 964, in __call__
        state.assert_child_not_restricted("__call__")
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
    
      File "/code/.venv/lib/python3.13/site-packages/temporalio/worker/workflow_sandbox/_restrictions.py", line 792, in assert_child_not_restricted
        raise RestrictedWorkflowAccessError(
            f"{self.name}.{name}", override_message=matcher.leaf_message
        )
    

    The error message occurs from an attempt to access linecache inside the original exception, leading to this:

    Cannot access os.stat.__call__ from inside a workflow. If this is code from a module not used in a workflow or known to only be used deterministically from a workflow, mark the import as pass through.
    
  4. cprafullchandra commented on Jan 28, 2025

    @cprafullchandra

    Hi, I am still seeing this issue.

    temporalio.worker.workflow_sandbox._restrictions.RestrictedWorkflowAccessError: Cannot access os.stat.__call__ from inside a workflow. If this is code from a module not used in a workflow or known to only be used deterministically from a workflow, mark the import as pass through.
    

    Python = 3.13.0
    temporalio = 1.9.0
    temporal (server) = 1.2.0

    Reverting to Python 3.12 fixed the tracebacks so I could see the actual error.

  5. FatihKartal commented on Feb 3, 2025

    @FatihKartal

    Also facing what @cprafullchandra mentioned when hosting our workers for Temporal cloud. I hope this can be resolved soon as we are locked into Python 3.13. currently.

  6. cretz commented on Feb 3, 2025

    @cretz
    ContributorAuthor

    3.13 support is in the next release (should not be too long now, though no exact timelines)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions