Skip to content

Commit 51e5cfb

Browse files
authored
Add Pythonx.install_env/0 and Pythonx.install_paths/0 to enable FLAME (#35)
1 parent 7e1da5d commit 51e5cfb

File tree

3 files changed

+85
-4
lines changed

3 files changed

+85
-4
lines changed

lib/pythonx.ex

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

lib/pythonx/application.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ defmodule Pythonx.Application do
3131
Pythonx.Uv.fetch(pyproject_toml, true, opts)
3232
defp maybe_uv_init(), do: Pythonx.Uv.init(unquote(pyproject_toml), true, unquote(opts))
3333
else
34-
defp maybe_uv_init(), do: :noop
34+
defp maybe_uv_init(), do: Pythonx.maybe_init_from_env()
3535
end
3636

3737
defp enable_sigchld() do

lib/pythonx/uv.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ defmodule Pythonx.Uv do
6666
Initializes the interpreter using Python and dependencies previously
6767
fetched by `fetch/3`.
6868
"""
69-
@spec init(String.t(), boolean()) :: :ok
69+
@spec init(String.t(), boolean()) :: list(String.t())
7070
def init(pyproject_toml, priv?, opts \\ []) do
7171
opts = Keyword.validate!(opts, uv_version: default_uv_version())
7272
project_dir = project_dir(pyproject_toml, priv?, opts[:uv_version])
@@ -148,6 +148,8 @@ defmodule Pythonx.Uv do
148148
sys_paths: [venv_packages_path]
149149
)
150150
end
151+
152+
[root_dir, project_dir]
151153
end
152154

153155
defp wildcard_one!(path) do

0 commit comments

Comments
 (0)