Skip to content

Commit 367131a

Browse files
Merge pull request #60 from renan-r-santos/configurable_fallback_env
Add support for configurable fallback environment
2 parents b3db4e1 + 5e8bea5 commit 367131a

File tree

5 files changed

+41
-24
lines changed

5 files changed

+41
-24
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ environment, use JupyterLab property inspector, save your notebook and restart y
5050

5151
![JupyterLab property inspector showing Pixi environment selector](https://raw.githubusercontent.com/renan-r-santos/pixi-kernel/main/assets/env-selector-light.png)
5252

53+
If an environment cannot be determined, Pixi kernel will fallback to the value in the
54+
`PIXI_KERNEL_DEFAULT_ENVIRONMENT` environment variable, if specified. Otherwise, the `default` Pixi
55+
environment will be used.
56+
5357
## JupyterHub deployments with limited permissions
5458

5559
If you're using pixi-kernel on JupyterHub and cannot access the environment where JupyterLab is

pixi_kernel/env.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from .async_subprocess import subprocess_exec
77
from .types import PixiInfo
88

9-
DEFAULT_ENVIRONMENT_NAME = "default"
9+
DEFAULT_ENVIRONMENT = "default"
1010

1111

1212
async def envs_from_path(path: Path) -> list[str]:
@@ -17,14 +17,14 @@ async def envs_from_path(path: Path) -> list[str]:
1717

1818
returncode, stdout, stderr = await subprocess_exec("pixi", "info", "--json", cwd=path, env=env)
1919
if returncode != 0:
20-
return [DEFAULT_ENVIRONMENT_NAME]
20+
return [DEFAULT_ENVIRONMENT]
2121

2222
try:
2323
pixi_info = PixiInfo.model_validate_json(stdout, strict=True)
2424
except ValidationError:
25-
return [DEFAULT_ENVIRONMENT_NAME]
25+
return [DEFAULT_ENVIRONMENT]
2626

2727
if len(pixi_info.environments) == 0:
28-
return [DEFAULT_ENVIRONMENT_NAME]
28+
return [DEFAULT_ENVIRONMENT]
2929

30-
return [env.name for env in pixi_info.environments]
30+
return sorted([env.name for env in pixi_info.environments])

pixi_kernel/handlers.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import os
23
from pathlib import Path
34

45
import tornado
@@ -8,7 +9,7 @@
89
from returns.result import Failure
910

1011
from .compatibility import has_compatible_pixi
11-
from .env import envs_from_path
12+
from .env import DEFAULT_ENVIRONMENT, envs_from_path
1213

1314

1415
class EnvHandler(APIHandler):
@@ -30,7 +31,13 @@ async def post(self) -> None:
3031
notebook_path = notebook_path.parent
3132

3233
envs = await envs_from_path(notebook_path)
33-
await self.finish(json.dumps(envs))
34+
35+
default_env = os.environ.get("PIXI_KERNEL_DEFAULT_ENVIRONMENT")
36+
if default_env not in envs:
37+
default_env = DEFAULT_ENVIRONMENT
38+
39+
response = {"environments": envs, "default": default_env}
40+
await self.finish(json.dumps(response))
3441

3542

3643
def setup_handlers(web_app: ServerWebApplication) -> None:

pixi_kernel/provisioner.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,32 +44,27 @@ async def pre_launch(self, **kwargs: Any) -> dict[str, Any]:
4444

4545
env: dict[str, str] = kwargs.get("env", os.environ.copy())
4646

47+
# If a new notebook is saved with the Pixi-kernel environment selection panel opened, the
48+
# environment field in the Notebook metadata could become an empty string.
49+
# https://github.com/renan-r-santos/pixi-kernel/issues/43#issuecomment-2676320749
50+
environment_name = ""
51+
4752
# https://github.com/jupyterlab/jupyterlab/issues/16282
4853
notebook_path = env.get("JPY_SESSION_NAME")
4954
if notebook_path is None:
50-
self.log.error(
51-
"Failed to get notebook path from JPY_SESSION_NAME variable."
52-
"Falling back to the default environment."
53-
)
54-
environment_name = "default"
55+
self.log.error("Failed to get notebook path from JPY_SESSION_NAME variable.")
5556
else:
5657
try:
5758
# Set encoding to utf-8 to avoid issues on Windows
5859
# https://github.com/renan-r-santos/pixi-kernel/issues/55
5960
notebook = json.loads(Path(notebook_path).read_text(encoding="utf-8"))
6061
environment_name = notebook["metadata"]["pixi-kernel"]["environment"]
6162
except Exception:
62-
self.log.exception(
63-
"Failed to get Pixi environment name from notebook metadata."
64-
"Falling back to default environment."
65-
)
66-
environment_name = "default"
63+
self.log.exception("Failed to get Pixi environment name from notebook metadata.")
6764

68-
# If a new notebook is saved with the Pixi-kernel environment selection panel opened, the
69-
# environment field in the Notebook metadata could become an empty string.
70-
# https://github.com/renan-r-santos/pixi-kernel/issues/43#issuecomment-2676320749
7165
if environment_name == "":
72-
environment_name = "default"
66+
environment_name = os.environ.get("PIXI_KERNEL_DEFAULT_ENVIRONMENT", "default")
67+
self.log.info(f"Falling back to the '{environment_name}' Pixi environment.")
7368

7469
result = await verify_env_readiness(
7570
environment_name=environment_name,

src/env.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@ interface IPixiEnvProps extends WidgetProps {
1111
nbTracker: INotebookTracker;
1212
}
1313

14+
interface IEnvironmentResponse {
15+
environments: string[];
16+
default: string;
17+
}
18+
1419
export const PixiEnvWidget = (props: IPixiEnvProps) => {
1520
const [envs, setEnvs] = useState(['']);
21+
const [defaultEnv, setDefaultEnv] = useState('');
1622

1723
useEffect(() => {
1824
const fetchEnvironments = async () => {
@@ -25,12 +31,17 @@ export const PixiEnvWidget = (props: IPixiEnvProps) => {
2531
props.app.serviceManager.contents.localPath(relativePath);
2632
const serverRoot = PageConfig.getOption('serverRoot') || '';
2733

28-
const environments = await requestAPI<string[]>('envs', {
34+
const response = await requestAPI<IEnvironmentResponse>('envs', {
2935
method: 'POST',
3036
body: JSON.stringify({ localPath, serverRoot })
3137
});
3238

33-
setEnvs(environments);
39+
setEnvs(response.environments);
40+
setDefaultEnv(response.default);
41+
42+
if (!props.value && response.default) {
43+
props.onChange(response.default);
44+
}
3445
} catch (error) {
3546
console.error('Failed to fetch environments:', error);
3647
setEnvs(['']);
@@ -44,7 +55,7 @@ export const PixiEnvWidget = (props: IPixiEnvProps) => {
4455
<select
4556
id={props.id}
4657
className="form-control"
47-
value={props.value || ''}
58+
value={props.value || defaultEnv}
4859
onChange={e => props.onChange(e.target.value)}
4960
required={props.required}
5061
>

0 commit comments

Comments
 (0)