File: thread.R

package info (click to toggle)
r-cran-reticulate 1.41.0.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,088 kB
  • sloc: cpp: 5,154; python: 620; sh: 13; makefile: 2
file content (98 lines) | stat: -rw-r--r-- 3,515 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98


#' [Deprecated] Create a Python function that will always be called on the main thread
#'
#' Beginning with reticulate v1.39.0, every R function is a "main thread func". Usage of `py_main_thread_func()`
#' is no longer necessary.
#'
#' This function is helpful when you need to provide a callback to a Python
#' library which may invoke the callback on a background thread. As R functions
#' must run on the main thread, wrapping the R function with `py_main_thread_func()`
#' will ensure that R code is only executed on the main thread.
#'
#' @param f An R function with arbitrary arguments
#' @return A Python function that delegates to the passed R function, which
#'  is guaranteed to always be called on the main thread.
#'
#'
#' @export
#' @keywords internal
py_main_thread_func <- function(f) {
  r_to_py(f, TRUE) # every R func is a main thread func.
}


py_allow_threads <- function(allow = TRUE) {
  if (allow) {
    reticulate_ns <- environment(sys.function())
    for (f in sys.frames()) {
      if (identical(parent.env(f), reticulate_ns) &&
          !identical(f, environment()))
        # Can't release the gil as unlocked while we're holding it
        # elsewhere on the callstack.
        stop("Python threads can only be unblocked from a top-level reticulate call")
    }
  }

  if (!was_python_initialized_by_reticulate())
    stop("Can't safely unblock threads when R is running embedded")

  invisible(py_allow_threads_impl(allow))
}



## TODO: document how to use sys.unraisablehook() to customize handling of exceptions
## from background threads. Or, switch to using the threading module, which
## has more options for customizing exceptions hooks, and document that.
## TODO: give a meaningful name for the thread that appears in tracebacks.
## Either use the threading module and pass name=,
##   or do something like
##     f = lambda file: run_file(file)
##     f.__name__ = "run: " + os.path.basename(file)
py_run_file_on_thread <- function(file, ..., args = NULL) {
  if (!is.null(args))
    args <- as.list(as.character(args))

  # TODO: we should have a dedicated entry point in reticulate for this.
  # Needs to be updated in ark and positron.
  launching_lsp <- (basename(file) == 'positron_language_server.py' &&
                      is_positron() &&
                      basename(dirname(file)) == "positron")

  if (launching_lsp) {
    main_dict <- py_eval("__import__('__main__').__dict__.copy()", FALSE)
    py_get_attr(main_dict, "pop")("__annotations__")
    # IPykernel will create a thread that redirects all output from fileno of
    # the current sys.stdout and sys.stderr to its IO channels.
    # This is not correctly cleaned up when IPykernel closes.
    # To fix that, we set the IO streams to /dev/null before launching the kernel.
    import("rpytools.run")$set_blank_io_streams()
  }

  import("rpytools.run")$run_file_on_thread(file, args, ...)

  if (launching_lsp) {

    PositronIPKernelApp <- import("positron_ipykernel.positron_ipkernel")$PositronIPKernelApp
    for(i in 1:40) { # Positron timeout is 20 seconds
      if (PositronIPKernelApp$initialized()) break
      Sys.sleep(.5)
    }
    Sys.sleep(1)

    py_eval("__import__('__main__').__dict__.update", FALSE)(main_dict)
  }
  invisible()
}

## used in Positron:
# reticulate:::py_run_file_on_thread(
#   file = "${kernelPath}",
#   args = c(
#     "-f", "${connnectionFile}",
#     "--logfile", "${logFile}",
#     "--loglevel", "${logLevel}",
#     "--session-mode", "console"
#   )
# )