@@ -10,6 +10,8 @@ defmodule Pythonx do
1010
1111 alias Pythonx.Object
1212
13+ @ install_env_name "PYTHONX_INIT_STATE"
14+
1315 @ type encoder :: ( term ( ) , encoder ( ) -> Object . t ( ) )
1416
1517 @ doc ~s'''
@@ -58,7 +60,84 @@ defmodule Pythonx do
5860 opts = Keyword . validate! ( opts , force: false , uv_version: Pythonx.Uv . default_uv_version ( ) )
5961
6062 Pythonx.Uv . fetch ( pyproject_toml , false , opts )
61- Pythonx.Uv . init ( pyproject_toml , false , Keyword . take ( opts , [ :uv_version ] ) )
63+ install_paths = Pythonx.Uv . init ( pyproject_toml , false , Keyword . take ( opts , [ :uv_version ] ) )
64+
65+ init_state = % {
66+ type: :uv_init ,
67+ pyproject_toml: pyproject_toml ,
68+ opts: Keyword . drop ( opts , [ :force ] ) ,
69+ install_paths: install_paths
70+ }
71+
72+ :persistent_term . put ( :pythonx_init_state , init_state )
73+ end
74+
75+ @ spec init_state ( ) :: map ( )
76+ defp init_state ( ) do
77+ :persistent_term . get ( :pythonx_init_state )
78+ end
79+
80+ @ spec init_state_from_env ( ) :: String . t ( ) | nil
81+ defp init_state_from_env ( ) , do: System . get_env ( @ install_env_name )
82+
83+ @ doc ~s'''
84+ Returns a map with opaque environment variables to initialize Pythonx in
85+ the same way as the current initialization.
86+
87+ When those environment variables are set, Pythonx is initialized on boot.
88+
89+ In particular, this can be used to make Pythonx initialize on `FLAME` nodes.
90+ '''
91+ @ spec install_env ( ) :: map ( )
92+ def install_env ( ) do
93+ init_state = init_state ( )
94+
95+ if init_state == nil do
96+ raise "before calling Pythonx.install_env/0, you must initialize Pythonx"
97+ end
98+
99+ init_state =
100+ init_state
101+ |> :erlang . term_to_binary ( )
102+ |> Base . encode64 ( )
103+
104+ % { @ install_env_name => init_state }
105+ end
106+
107+ @ doc ~s'''
108+ Returns a list of paths that `install_env/0` initialization depends on.
109+
110+ In particular, this can be used to make Pythonx initialize on `FLAME` nodes.
111+ '''
112+ @ spec install_paths ( ) :: list ( String . t ( ) )
113+ def install_paths ( ) do
114+ init_state = init_state ( )
115+
116+ if init_state == nil do
117+ raise "before calling Pythonx.install_paths/0, you must initialize Pythonx"
118+ end
119+
120+ init_state . install_paths
121+ end
122+
123+ @ doc false
124+ def maybe_init_from_env ( ) do
125+ case init_state_from_env ( ) do
126+ nil ->
127+ :noop
128+
129+ init_state_env_value ->
130+ % {
131+ type: :uv_init ,
132+ pyproject_toml: pyproject_toml ,
133+ opts: opts
134+ } =
135+ init_state_env_value
136+ |> Base . decode64! ( )
137+ |> :erlang . binary_to_term ( )
138+
139+ uv_init ( pyproject_toml , opts )
140+ end
62141 end
63142
64143 # Initializes the Python interpreter.
@@ -90,7 +169,7 @@ defmodule Pythonx do
90169 # (`sys.path`). Defaults to `[]`.
91170 #
92171 @ doc false
93- @ spec init ( String . t ( ) , String . t ( ) , keyword ( ) ) :: :ok
172+ @ spec init ( String . t ( ) , String . t ( ) , String . t ( ) , keyword ( ) ) :: :ok
94173 def init ( python_dl_path , python_home_path , python_executable_path , opts \\ [ ] )
95174 when is_binary ( python_dl_path ) and is_binary ( python_home_path )
96175 when is_binary ( python_executable_path ) and is_list ( opts ) do
0 commit comments