diff --git a/davos/implementations/ipython_common.py b/davos/implementations/ipython_common.py index d6844470..615b5f83 100644 --- a/davos/implementations/ipython_common.py +++ b/davos/implementations/ipython_common.py @@ -4,10 +4,12 @@ """ -import textwrap +import re import sys +import textwrap from contextlib import redirect_stdout from io import StringIO +from pathlib import Path from subprocess import CalledProcessError from IPython.core.error import UsageError @@ -22,34 +24,55 @@ def _check_conda_avail_helper(): Check whether the `conda` executable is available. `IPython` implementation of the helper function for - `davos.core.core.check_conda`. Tries to access the `conda` - executable by running `conda list IPython` using the `%conda` - IPython line magic. If successful, returns the (suppressed) stdout - generated by the command. Otherwise, returns `None`. + `davos.core.core.check_conda`. Runs a command shell (`conda list + IPython`) whose stdout contains the path to the current conda + environment, which can be parsed by the main `check_conda` function. + Uses the `%conda` IPython line magic, if available (usually if + `IPython>=7.3`). Otherwise, looks for `conda` history file and runs + some logic to determine whether -- if the `conda` exe is available, + whether `davos` is running from the base environment or not, and if + not, passes the `--prefix` to the command. If successful, returns + the (suppressed) stdout generated by the command. Otherwise, returns + `None`. Returns ------- str or None - If the `%conda` line magic is available and `conda list IPython` - runs successfully, the captured stdout. Otherwise, `None`. + If the command runs successfully, the captured stdout. + Otherwise, `None`. See Also -------- davos.core.core.check_conda : core function that calls this helper. """ - try: + if 'conda' in set(config._ipython_shell.magics_manager.magics['line']): + # if the %conda line magic is available (IPython>=7.3), use that + # directly + try: + with redirect_stdout(StringIO()) as conda_list_output: + config._ipython_shell.run_line_magic('conda', 'list IPython') + except ValueError: + # kernel is not running within a conda environment + return None + + else: + conda_history_path = Path(sys.prefix, "conda-meta", "history") + # if conda history file doesn't exist at this location, davos + # isn't running in a conda environment + if not conda_history_path.is_file(): + return None + + cmd = "conda list IPython" + # location we'd expect to find conda executable if davos is + # running in the 'base' environment (and no prefix is needed) + base_exe_loc = Path(sys.executable).parent.joinpath('conda') + + if not base_exe_loc.is_file(): + cmd += f" --prefix {sys.prefix}" + with redirect_stdout(StringIO()) as conda_list_output: - # this specific line magic seems to be the only reliable way - # to *actually* get the kernel environment -- shell (!) - # commands and all conda magic (%) commands other than - # `conda list` run in the base conda environment. Listed - # package is arbitrary, but listing single package is much - # faster than listing all, so using IPython because it's - # guaranteed to be installed - config._ipython_shell.run_line_magic('conda', 'list IPython') - except (UsageError, ValueError): - # %conda line magic is not available - return None + _run_shell_cmd(cmd) + return conda_list_output.getvalue() diff --git a/tests/conftest.py b/tests/conftest.py index f883f6a5..be4eaadd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -358,6 +358,7 @@ def terminate_active_sessions(self) -> None: """terminate all sessions except for the current one""" # click "Manage Sessions" button self.driver.find_element_by_id('ok').click() + time.sleep(3) # get "Active sessions" popup box under first #shadow-root active_sessions_dialog_box = self.driver.find_element_by_tag_name( 'colab-sessions-dialog' diff --git a/tests/test__environment_and_init.ipynb b/tests/test__environment_and_init.ipynb index fb86d8ba..39688548 100644 --- a/tests/test__environment_and_init.ipynb +++ b/tests/test__environment_and_init.ipynb @@ -210,7 +210,9 @@ "source": [ "def test_tqdm_installed():\n", " \"\"\"used as an example package for some tests\"\"\"\n", - " assert is_installed('tqdm==4.41.1')" + " assert is_installed('tqdm')\n", + " import tqdm\n", + " assert tqdm.__version__ != '==4.45.0'" ] }, { diff --git a/tests/test_core.ipynb b/tests/test_core.ipynb index eca492de..008406cd 100644 --- a/tests/test_core.ipynb +++ b/tests/test_core.ipynb @@ -211,11 +211,10 @@ }, "outputs": [], "source": [ - "@mark.ipython_pre7\n", + "@mark.colab\n", "def test_check_conda_ipython_pre7():\n", " \"\"\"\n", - " conda is not available on Google Colaboratory and not yet supported \n", - " for IPython<7.0.0\n", + " conda is not available on Google Colaboratory\n", " \"\"\"\n", " davos.core.core.check_conda()\n", " assert davos.config.conda_avail is False\n", @@ -2676,7 +2675,7 @@ " the current interpreter session\n", " \"\"\"\n", " import tqdm\n", - " assert tqdm.__version__ == '4.41.1'\n", + " assert tqdm.__version__ != '4.45.0'\n", " smuggle tqdm # pip: tqdm==4.45.0\n", " assert is_installed('tqdm==4.45.0')\n", " assert tqdm is sys.modules['tqdm']\n", diff --git a/tests/test_implementations.ipynb b/tests/test_implementations.ipynb index f6651c51..6e1eb1cd 100644 --- a/tests/test_implementations.ipynb +++ b/tests/test_implementations.ipynb @@ -130,7 +130,6 @@ "outputs": [], "source": [ "@mark.jupyter\n", - "@mark.skipif(not (IPython.version_info[0] >= 7 and IPython.version_info[1] >= 3), reason=\"%conda magic not implemented\")\n", "def test_conda_env_fset_raises_noenv():\n", " \"\"\"\n", " check that trying to set the `conda_env` config field to an \n", diff --git a/tests/test_ipython_common.ipynb b/tests/test_ipython_common.ipynb index b8d5a4a8..5e7d9670 100644 --- a/tests/test_ipython_common.ipynb +++ b/tests/test_ipython_common.ipynb @@ -5,8 +5,8 @@ "execution_count": null, "metadata": { "ExecuteTime": { - "end_time": "2021-08-07T22:43:33.461590Z", - "start_time": "2021-08-07T22:43:33.457191Z" + "end_time": "2021-08-11T03:58:39.244632Z", + "start_time": "2021-08-11T03:58:39.239990Z" } }, "outputs": [], @@ -23,8 +23,8 @@ "execution_count": null, "metadata": { "ExecuteTime": { - "end_time": "2021-08-07T22:43:33.694388Z", - "start_time": "2021-08-07T22:43:33.579655Z" + "end_time": "2021-08-11T03:58:39.363193Z", + "start_time": "2021-08-11T03:58:39.246862Z" } }, "outputs": [], @@ -49,8 +49,8 @@ "execution_count": null, "metadata": { "ExecuteTime": { - "end_time": "2021-08-07T22:43:34.155492Z", - "start_time": "2021-08-07T22:43:34.112177Z" + "end_time": "2021-08-11T03:58:39.407764Z", + "start_time": "2021-08-11T03:58:39.364819Z" } }, "outputs": [], @@ -78,8 +78,8 @@ "execution_count": null, "metadata": { "ExecuteTime": { - "end_time": "2021-08-07T21:03:35.066508Z", - "start_time": "2021-08-07T21:03:35.062853Z" + "end_time": "2021-08-11T03:58:39.414142Z", + "start_time": "2021-08-11T03:58:39.409863Z" } }, "outputs": [], @@ -108,22 +108,16 @@ "execution_count": null, "metadata": { "ExecuteTime": { - "end_time": "2021-08-07T22:45:32.547027Z", - "start_time": "2021-08-07T22:45:32.539526Z" + "end_time": "2021-08-11T03:58:39.422479Z", + "start_time": "2021-08-11T03:58:39.416239Z" } }, "outputs": [], "source": [ "@mark.jupyter\n", - "@mark.skipif(not (IPython.version_info[0] >= 7 and IPython.version_info[1] >= 3), reason=\"%conda magic not implemented\")\n", "def test_check_conda_avail_helper():\n", " \"\"\"\n", " test helper function for getting conda-related config fields\n", - " \n", - " NOTE: currently skipping this for IPython<7.3 because the %conda \n", - " magic wasn't implemented before then, and the way \n", - " _check_conda_avail_helper is written causes it to improperly return \n", - " None. Will remove the skip once fixed.\n", " \"\"\"\n", " expected_env_path = \"/usr/share/miniconda/envs/kernel-env\"\n", " # only part of output that matters is line with environment path\n", @@ -142,8 +136,8 @@ "execution_count": null, "metadata": { "ExecuteTime": { - "end_time": "2021-08-07T21:03:35.078797Z", - "start_time": "2021-08-07T21:03:35.075174Z" + "end_time": "2021-08-11T03:58:39.429792Z", + "start_time": "2021-08-11T03:58:39.424739Z" } }, "outputs": [], @@ -166,8 +160,8 @@ "execution_count": null, "metadata": { "ExecuteTime": { - "end_time": "2021-08-07T21:03:35.084814Z", - "start_time": "2021-08-07T21:03:35.080457Z" + "end_time": "2021-08-11T03:58:39.438946Z", + "start_time": "2021-08-11T03:58:39.431759Z" } }, "outputs": [], @@ -197,8 +191,8 @@ "execution_count": null, "metadata": { "ExecuteTime": { - "end_time": "2021-08-07T21:03:35.324254Z", - "start_time": "2021-08-07T21:03:35.087883Z" + "end_time": "2021-08-11T03:58:39.690163Z", + "start_time": "2021-08-11T03:58:39.441202Z" } }, "outputs": [], diff --git a/tests/test_ipython_pre7.ipynb b/tests/test_ipython_pre7.ipynb index 8a5a71dc..4f261b8a 100644 --- a/tests/test_ipython_pre7.ipynb +++ b/tests/test_ipython_pre7.ipynb @@ -2,11 +2,11 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.082844Z", - "start_time": "2021-08-11T00:13:30.077723Z" + "end_time": "2021-08-11T04:09:37.524821Z", + "start_time": "2021-08-11T04:09:37.520041Z" } }, "outputs": [], @@ -20,14 +20,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.212793Z", - "start_time": "2021-08-11T00:13:30.085108Z" + "end_time": "2021-08-11T04:09:37.734695Z", + "start_time": "2021-08-11T04:09:37.527194Z" } }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/paxtonfitzpatrick/opt/anaconda3/envs/colab/lib/python3.7/site-packages/requests/__init__.py:91: RequestsDependencyWarning: urllib3 (1.26.4) or chardet (3.0.4) doesn't match a supported version!\n", + " RequestsDependencyWarning)\n" + ] + } + ], "source": [ "from pathlib import Path\n", "\n", @@ -46,11 +55,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.260376Z", - "start_time": "2021-08-11T00:13:30.214789Z" + "end_time": "2021-08-11T04:09:37.793989Z", + "start_time": "2021-08-11T04:09:37.736429Z" } }, "outputs": [], @@ -63,11 +72,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.264441Z", - "start_time": "2021-08-11T00:13:30.262078Z" + "end_time": "2021-08-11T04:09:37.798351Z", + "start_time": "2021-08-11T04:09:37.796153Z" } }, "outputs": [], @@ -90,11 +99,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.272753Z", - "start_time": "2021-08-11T00:13:30.266835Z" + "end_time": "2021-08-11T04:09:37.807154Z", + "start_time": "2021-08-11T04:09:37.801291Z" } }, "outputs": [], @@ -120,11 +129,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.284719Z", - "start_time": "2021-08-11T00:13:30.275168Z" + "end_time": "2021-08-11T04:09:37.818896Z", + "start_time": "2021-08-11T04:09:37.810472Z" } }, "outputs": [], @@ -164,11 +173,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.297551Z", - "start_time": "2021-08-11T00:13:30.287374Z" + "end_time": "2021-08-11T04:09:37.830215Z", + "start_time": "2021-08-11T04:09:37.821379Z" } }, "outputs": [], @@ -203,11 +212,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.306084Z", - "start_time": "2021-08-11T00:13:30.299573Z" + "end_time": "2021-08-11T04:09:37.838731Z", + "start_time": "2021-08-11T04:09:37.832074Z" } }, "outputs": [], @@ -237,11 +246,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.325071Z", - "start_time": "2021-08-11T00:13:30.308764Z" + "end_time": "2021-08-11T04:09:37.854331Z", + "start_time": "2021-08-11T04:09:37.840753Z" } }, "outputs": [], @@ -287,11 +296,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.336340Z", - "start_time": "2021-08-11T00:13:30.327499Z" + "end_time": "2021-08-11T04:09:37.863635Z", + "start_time": "2021-08-11T04:09:37.856240Z" } }, "outputs": [], @@ -323,11 +332,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.347342Z", - "start_time": "2021-08-11T00:13:30.338748Z" + "end_time": "2021-08-11T04:09:37.873517Z", + "start_time": "2021-08-11T04:09:37.865821Z" } }, "outputs": [], @@ -359,11 +368,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.355173Z", - "start_time": "2021-08-11T00:13:30.349493Z" + "end_time": "2021-08-11T04:09:37.880384Z", + "start_time": "2021-08-11T04:09:37.875769Z" } }, "outputs": [], @@ -388,11 +397,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.362386Z", - "start_time": "2021-08-11T00:13:30.357919Z" + "end_time": "2021-08-11T04:09:37.886085Z", + "start_time": "2021-08-11T04:09:37.882224Z" } }, "outputs": [], @@ -409,14 +418,104 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": { "ExecuteTime": { - "end_time": "2021-08-11T00:13:30.378972Z", - "start_time": "2021-08-11T00:13:30.364012Z" + "end_time": "2021-08-11T04:09:37.900770Z", + "start_time": "2021-08-11T04:09:37.888019Z" } }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "collected 9 items\n", + "\n" + ] + }, + { + "data": { + "text/html": [ + "