Windows is such a tremendous pain about everything...

This commit is contained in:
Brennen Raimer
2024-05-14 14:12:06 -04:00
parent c9c5e3756f
commit 7444564cb6
4 changed files with 51 additions and 18 deletions

View File

@@ -1,20 +1,20 @@
# App Mode Jupyter Environment and Shortcut
Adds a shortcut for running [JupyterLab](https://jupyter.org/) in a Chromium-based browser's "app" mode (i.e. The application takes up the full browser window and has no browser UI e.g. the address bar, as if Jupyter Lab were a native application) for an existing environment with Jupyter Lab installed or creating one for you.
Adds a shortcut for running [JupyterLab](https://jupyter.org/) in a Chromium-based browser's "app" mode (i.e. The application takes up the full browser window and has no browser UI e.g. the address bar, as if Jupyter Lab were a native application) for an existing environment with Jupyter Lab installed or creating one for you.
## Requirements
* An conda-based installation of [Anaconda](https://anaconda.org/), [Miniconda](https://docs.conda.io/en/latest/miniconda.html) or [Miniforge](https://github.com/conda-forge/miniforge). Miniforge is recommended.
* [`menuinst`](https://conda.github.io/menuinst/) >= 2.0.0 must be installed in the `base` environment alongside `conda` or in whichever environment contains conda
* A Chromium-based browser
* On Windows, [Google Chrome](https://www.google.com/chrome/), [Brave](https://brave.com/), and [Microsoft Edge](https://www.microsoft.com/en-us/edge) are supported. Preference will be given to the first one of these browsers found. Microsoft Edge is guaranteed to be installed on Windows 10+ and is a fall-back if no other supported browser is found.
* On Windows, [Google Chrome](https://www.google.com/chrome/), [Brave](https://brave.com/), and [Microsoft Edge](https://www.microsoft.com/en-us/edge) are supported. Preference will be given to your default browser, if it appears to be a Chromium-based browser, or to the first one of these browsers found. Microsoft Edge is guaranteed to be installed on Windows 10+ and is a fall-back if no other supported browser is found.
* On MacOS, [Google Chrome](https://www.google.com/chrome/), [Microsoft Edge](https://www.microsoft.com/en-us/edge), [Brave](https://brave.com/), and [Chromium](https://www.chromium.org/getting-involved/download-chromium/) are preferred in that order.
* On Linux, [Google Chrome](https://flathub.org/apps/com.google.Chrome), [Microsoft Edge](https://flathub.org/apps/com.microsoft.Edge), [Brave](https://flathub.org/apps/com.brave.Browser), and [Chromium](https://flathub.org/apps/org.chromium.Chromium) are supported and preferred in that order. If [flatpak](https://flatpak.org/) is installed and one of these browsers is installed with Flatpak (recommended), it will be preferred over any snap-installed or package manager-installed versions of any of these browsers.
## Setup
1. Clone or download this repository
2. From a terminal, activate your `base` conda environment (or whichever environment conda is installed in)
2. From a terminal, activate your `base` conda environment (or whichever environment conda is installed in)
3. Run `python ./setup_jupyter.py your_jupyter_env_name_here`
## Remove Shortcut
@@ -24,12 +24,12 @@ To remove the shortcut created by this script, run `python ./setup_jupyter.py --
## FAQ
1. Why don't you support Mozilla Firefox or Safari?
To my knowledge, neither have an "app-mode" like Chromium-based browsers do. When/if they ever do, they will be supported.
2. Why am I being prompted for admin permissions?
By default, `menuinst` tries to install/remove the shortcut from a system-level location. You can safely cancel/ignore that prompt(s) (it may prompt you multiple times) which will cause `menuinst` to fallback to a user-specific location instead. Unfortunately, there does not seem to be a way to have `menuinst` prefer to install/remove shortcuts for the current user rather than system-wide.
By default, `menuinst` tries to install/remove the shortcut from a system-level location. You can safely cancel/ignore that prompt(s) (it may prompt you multiple times) which will cause `menuinst` to fallback to a user-specific location instead. Unfortunately, there does not seem to be a way to have `menuinst` prefer to install/remove shortcuts for the current user rather than system-wide.
3. What about other Chromium-based browsers?
@@ -49,8 +49,8 @@ To remove the shortcut created by this script, run `python ./setup_jupyter.py --
7. What is `nb_conda_kernels` and why does this script want to install it in my Jupyter environment.
`nb_conda_kernels` allows JupyterLab to run kernels in **any** installed conda environment which has a Jupyter kernel (e.g. ipykernel for Python) installed in it without having to install Jupyter and all its dependencies into that conda environment. It allows you to have a single version of JupyterLab installed in a single, purpose-made environment so you are not maintaining multiple JupyterLab versions or configurations.
`nb_conda_kernels` allows JupyterLab to run kernels in **any** installed conda environment which has a Jupyter kernel (e.g. ipykernel for Python) installed in it without having to install Jupyter and all its dependencies into that conda environment. It allows you to have a single version of JupyterLab installed in a single, purpose-made environment so you are not maintaining multiple JupyterLab versions or configurations.
8. How should I update my Jupyter environment?
That's up to you. I will periodically run `conda update -n jupyter --all && conda update -n jupyter python` to update everything in my Jupyter environment (named `jupyter`).
That's up to you. I will periodically run `conda update -n jupyter --all && conda update -n jupyter python` to update everything in my Jupyter environment (named `jupyter`).

View File

@@ -3,8 +3,9 @@ import platform
from io import StringIO
from itertools import product
from os import environ
from os import environ, pathsep
from pathlib import Path
from re import search
from subprocess import CalledProcessError, run
logging.getLogger(__name__).propagate=True
@@ -12,7 +13,7 @@ logging.getLogger(__name__).propagate=True
def find_flatpak_browser():
if platform.system() != "Linux":
return
for path_element in map(Path, environ["PATH"].split(":")):
if (path_element/"flatpak").is_file():
flatpak_bin = path_element/"flatpak"
@@ -20,7 +21,7 @@ def find_flatpak_browser():
else:
# flatpak is not installed
return
flatpak_apps = ("com.google.Chrome", "com.microsoft.Edge", "com.brave.Browser", "org.chromium.Chromium")
try:
@@ -39,15 +40,17 @@ def find_flatpak_browser():
else:
with StringIO(flatpak_process.stdout.decode()) as flatpak_output:
installed_flatpaks = flatpak_output.readlines()[1:]
for flatpak_app in flatpak_apps:
if flatpak_app in [_.strip() for _ in installed_flatpaks]:
return f"flatpak run --filesystem={Path.home()/'.local/share/jupyter/runtime'} {flatpak_app} --start-maximized --profile-directory=Default --app=%s"
def find_browser():
# find a chromium-based browser on the system to use.
# find a chromium-based browser on the system to use.
if platform.system() == "Windows":
from winreg import HKEY_CLASSES_ROOT, OpenKey, QueryValue
cmds = (
"Google/Chrome/Application/chrome.exe",
"BraveSoftware/Brave-Browser/Application/brave.exe",
@@ -55,6 +58,17 @@ def find_browser():
)
path_elements = map(Path, (environ["ProgramFiles"], environ["ProgramFiles(x86)"]))
# do a lookup of default browser command in windows registry
try:
with OpenKey(HKEY_CLASSES_ROOT, r"http\shell\open") as k:
default_browser_cmd = QueryValue(k, "command").replace('"%1"', "").replace('"', "").strip()
except FileNotFoundError:
pass
else:
# if the command looks like one of the known chromium browsers or even vaguely resembles one, return immediately with a browser command
if any(default_browser_cmd.endswith(cmd.replace("/", pathsep)) for cmd in cmds) or search(r"\\Application\\\w+\.exe$", default_browser_cmd):
return f'"{default_browser_cmd}" --start-maximized --profile-directory=Default --app=%s'
elif platform.system() == "Linux":
# prefers Google Chrome on Linux due to popularity of the browser
cmds = ("google-chrome", "microsoft-edge", "brave", "chromium")
@@ -63,8 +77,8 @@ def find_browser():
elif platform.system() == "Darwin":
# also prefers Google Chrome on MacOS due to popularity of the browser
cmds = (
"Contents/MacOS/Google Chrome",
"Contents/MacOS/Microsoft Edge",
"Contents/MacOS/Google Chrome",
"Contents/MacOS/Microsoft Edge",
"Contents/MacOS/Brave Browser",
"Contents/MacOS/Chromium",
)

View File

@@ -15,9 +15,18 @@
"icon": "{{ MENU_DIR }}/jupyterlab.{{ ICON_EXT }}",
"platforms": {
"win": {
"file_extensions": [
".ipynb"
],
"precreate": "{{ BASE_PREFIX }}\\condabin\\conda.bat init cmd.exe",
"command": [
"{{ BASE_PREFIX }}\\condabin\\conda.bat",
"run",
"--live-stream",
"--prefix",
"{{ PREFIX }}",
"jupyter",
"lab",
"--config={{ MENU_DIR }}/jupyter_lab_config.py"
],
"activate": false,
"quicklaunch": false
},
"osx": {

View File

@@ -312,9 +312,19 @@ def ensure_env(env_name: str) -> Path:
def main(target_env_name: str, remove_shortcut: bool=False) -> Union[int, None]:
if not in_base_env():
LOGGER.warning("Not in base environment. Re-running this script from the base environment")
# I don't know why, but Windows *really* does not want to resolve conda in PATH if you aren't in the base environment
try:
conda_exe = environ["CONDA_EXE"]
except KeyError:
try:
conda_exe = environ["_CONDA_EXE"]
except KeyError:
conda_exe = "conda"
# call conda run to re-run this in the base prefix
rerun_proces = run(
["conda", "run", "--prefix", str(get_base_prefix()), "--no-capture-output", "python", *argv],
[conda_exe, "run", "--prefix", str(get_base_prefix()), "--no-capture-output", "python", *argv],
capture_output=False,
check=False
)