Current section
Files
Jump to
Current section
Files
lib/snakebridge/config.ex
defmodule SnakeBridge.Config do
@moduledoc """
Compile-time configuration for SnakeBridge.
"""
defstruct [
:libraries,
:auto_install,
:generated_dir,
:metadata_dir,
:helper_paths,
:helper_pack_enabled,
:helper_allowlist,
:inline_enabled,
:strict,
:verbose,
:scan_paths,
:scan_exclude,
:introspector,
:docs,
:runtime_client,
:ledger
]
defmodule Library do
@moduledoc """
Configuration struct for a single Python library binding.
"""
defstruct [
:name,
:version,
:module_name,
:python_name,
:pypi_package,
:extras,
include: [],
exclude: [],
streaming: [],
submodules: false
]
@type t :: %__MODULE__{
name: atom(),
version: String.t() | :stdlib | nil,
module_name: module(),
python_name: String.t(),
pypi_package: String.t() | nil,
extras: [String.t()],
include: [String.t()],
exclude: [String.t()],
streaming: [String.t()],
submodules: boolean()
}
end
@type t :: %__MODULE__{
libraries: [Library.t()],
auto_install: :never | :dev | :always,
generated_dir: String.t(),
metadata_dir: String.t(),
helper_paths: [String.t()],
helper_pack_enabled: boolean(),
helper_allowlist: :all | [String.t()],
inline_enabled: boolean(),
strict: boolean(),
verbose: boolean(),
scan_paths: [String.t()],
scan_exclude: [String.t()],
introspector: keyword(),
docs: keyword(),
runtime_client: module(),
ledger: keyword()
}
@doc """
Load config from mix.exs dependency options and Application env.
"""
@spec load() :: t()
def load do
deps = Mix.Project.config()[:deps] || []
opts =
deps
|> Enum.find_value([], fn
{:snakebridge, opts} when is_list(opts) -> opts
{:snakebridge, _req, opts} when is_list(opts) -> opts
_ -> nil
end)
|> List.wrap()
%__MODULE__{
libraries: parse_libraries(Keyword.get(opts, :libraries, [])),
auto_install: Application.get_env(:snakebridge, :auto_install, :dev),
generated_dir: Keyword.get(opts, :generated_dir, "lib/snakebridge_generated"),
metadata_dir: Keyword.get(opts, :metadata_dir, ".snakebridge"),
helper_paths: Application.get_env(:snakebridge, :helper_paths, ["priv/python/helpers"]),
helper_pack_enabled: Application.get_env(:snakebridge, :helper_pack_enabled, true),
helper_allowlist: Application.get_env(:snakebridge, :helper_allowlist, :all),
inline_enabled: Application.get_env(:snakebridge, :inline_enabled, false),
strict: env_flag(:strict, "SNAKEBRIDGE_STRICT", false),
verbose: env_flag(:verbose, "SNAKEBRIDGE_VERBOSE", false),
scan_paths: Application.get_env(:snakebridge, :scan_paths, ["lib"]),
scan_exclude: Application.get_env(:snakebridge, :scan_exclude, []),
introspector: Application.get_env(:snakebridge, :introspector, []),
docs: Application.get_env(:snakebridge, :docs, []),
runtime_client: Application.get_env(:snakebridge, :runtime_client, Snakepit),
ledger: Application.get_env(:snakebridge, :ledger, [])
}
end
@doc false
def parse_libraries(libraries) when is_list(libraries) do
Enum.map(libraries, &parse_library/1)
end
defp parse_library({name, version}) when is_binary(version) or version == :stdlib do
build_library(name, version, [])
end
defp parse_library({name, opts}) when is_list(opts) do
version = Keyword.get(opts, :version)
build_library(name, version, opts)
end
defp parse_library(name) when is_atom(name) do
build_library(name, nil, [])
end
defp parse_library(name) when is_binary(name) do
build_library(String.to_atom(name), nil, [])
end
defp build_library(name, version, opts) do
module_name = Keyword.get(opts, :module_name, default_module_name(name))
python_name = Keyword.get(opts, :python_name, Atom.to_string(name))
extras = Keyword.get(opts, :extras, [])
%Library{
name: name,
version: version,
module_name: module_name,
python_name: python_name,
pypi_package: Keyword.get(opts, :pypi_package),
extras: List.wrap(extras),
include: Keyword.get(opts, :include, []),
exclude: Keyword.get(opts, :exclude, []),
streaming: Keyword.get(opts, :streaming, []),
submodules: Keyword.get(opts, :submodules, false)
}
end
defp default_module_name(name) do
name
|> Atom.to_string()
|> Macro.camelize()
|> then(&Module.concat([&1]))
end
defp env_flag(config_key, env_var, default) do
case System.get_env(env_var) do
nil -> Application.get_env(:snakebridge, config_key, default)
value -> value in ["1", "true", "TRUE", "yes", "YES"]
end
end
end